this repo has no description
1import { ok, err, type Result } from './types/result'
2import type {
3 Did,
4 Handle,
5 AccessToken,
6 RefreshToken,
7 Cid,
8 Rkey,
9 AtUri,
10 Nsid,
11 ISODateString,
12 EmailAddress,
13 InviteCode as InviteCodeBrand,
14} from './types/branded'
15import {
16 unsafeAsDid,
17 unsafeAsHandle,
18 unsafeAsAccessToken,
19 unsafeAsRefreshToken,
20 unsafeAsCid,
21 unsafeAsISODate,
22 unsafeAsEmail,
23 unsafeAsInviteCode,
24} from './types/branded'
25import type {
26 Session,
27 DidDocument,
28 AppPassword,
29 CreatedAppPassword,
30 InviteCodeInfo,
31 ServerDescription,
32 NotificationPrefs,
33 NotificationHistoryResponse,
34 ServerStats,
35 ServerConfig,
36 UploadBlobResponse,
37 ListSessionsResponse,
38 SearchAccountsResponse,
39 GetInviteCodesResponse,
40 AccountInfo,
41 RepoDescription,
42 ListRecordsResponse,
43 RecordResponse,
44 CreateRecordResponse,
45 TotpStatus,
46 TotpSecret,
47 EnableTotpResponse,
48 RegenerateBackupCodesResponse,
49 ListPasskeysResponse,
50 StartPasskeyRegistrationResponse,
51 FinishPasskeyRegistrationResponse,
52 ListTrustedDevicesResponse,
53 ReauthStatus,
54 ReauthResponse,
55 ReauthPasskeyStartResponse,
56 ReserveSigningKeyResponse,
57 RecommendedDidCredentials,
58 PasskeyAccountCreateResponse,
59 CompletePasskeySetupResponse,
60 VerifyTokenResponse,
61 ListBackupsResponse,
62 CreateBackupResponse,
63 SetBackupEnabledResponse,
64 EmailUpdateResponse,
65 LegacyLoginPreference,
66 UpdateLegacyLoginResponse,
67 UpdateLocaleResponse,
68 PasswordStatus,
69 SuccessResponse,
70 CheckEmailVerifiedResponse,
71 VerifyMigrationEmailResponse,
72 ResendMigrationVerificationResponse,
73 ListReposResponse,
74 VerificationChannel,
75 DidType,
76 ApiErrorCode,
77 VerificationMethod as VerificationMethodType,
78 CreateAccountParams,
79 CreateAccountResult,
80 ConfirmSignupResult,
81} from './types/api'
82
83const API_BASE = '/xrpc'
84
85export class ApiError extends Error {
86 public did?: Did
87 public reauthMethods?: string[]
88 constructor(
89 public status: number,
90 public error: ApiErrorCode,
91 message: string,
92 did?: string,
93 reauthMethods?: string[],
94 ) {
95 super(message)
96 this.name = 'ApiError'
97 this.did = did ? unsafeAsDid(did) : undefined
98 this.reauthMethods = reauthMethods
99 }
100}
101
102let tokenRefreshCallback: (() => Promise<string | null>) | null = null
103
104export function setTokenRefreshCallback(
105 callback: () => Promise<string | null>,
106) {
107 tokenRefreshCallback = callback
108}
109
110interface XrpcOptions {
111 method?: 'GET' | 'POST'
112 params?: Record<string, string>
113 body?: unknown
114 token?: string
115 skipRetry?: boolean
116}
117
118async function xrpc<T>(method: string, options?: XrpcOptions): Promise<T> {
119 const { method: httpMethod = 'GET', params, body, token, skipRetry } =
120 options ?? {}
121 let url = `${API_BASE}/${method}`
122 if (params) {
123 const searchParams = new URLSearchParams(params)
124 url += `?${searchParams}`
125 }
126 const headers: Record<string, string> = {}
127 if (token) {
128 headers['Authorization'] = `Bearer ${token}`
129 }
130 if (body) {
131 headers['Content-Type'] = 'application/json'
132 }
133 const res = await fetch(url, {
134 method: httpMethod,
135 headers,
136 body: body ? JSON.stringify(body) : undefined,
137 })
138 if (!res.ok) {
139 const errData = await res.json().catch(() => ({
140 error: 'Unknown',
141 message: res.statusText,
142 }))
143 if (
144 res.status === 401 &&
145 (errData.error === 'AuthenticationFailed' || errData.error === 'ExpiredToken') &&
146 token && tokenRefreshCallback && !skipRetry
147 ) {
148 const newToken = await tokenRefreshCallback()
149 if (newToken && newToken !== token) {
150 return xrpc(method, { ...options, token: newToken, skipRetry: true })
151 }
152 }
153 throw new ApiError(
154 res.status,
155 errData.error as ApiErrorCode,
156 errData.message,
157 errData.did,
158 errData.reauthMethods,
159 )
160 }
161 return res.json()
162}
163
164async function xrpcResult<T>(
165 method: string,
166 options?: XrpcOptions
167): Promise<Result<T, ApiError>> {
168 try {
169 const value = await xrpc<T>(method, options)
170 return ok(value)
171 } catch (e) {
172 if (e instanceof ApiError) {
173 return err(e)
174 }
175 return err(new ApiError(0, 'Unknown', e instanceof Error ? e.message : String(e)))
176 }
177}
178
179export interface VerificationMethod {
180 id: string
181 type: string
182 publicKeyMultibase: string
183}
184
185export type { Session, DidDocument, AppPassword, InviteCodeInfo as InviteCode }
186export type { VerificationChannel, DidType, CreateAccountParams, CreateAccountResult, ConfirmSignupResult }
187
188function castSession(raw: unknown): Session {
189 const s = raw as Record<string, unknown>
190 return {
191 did: unsafeAsDid(s.did as string),
192 handle: unsafeAsHandle(s.handle as string),
193 email: s.email ? unsafeAsEmail(s.email as string) : undefined,
194 emailConfirmed: s.emailConfirmed as boolean | undefined,
195 preferredChannel: s.preferredChannel as VerificationChannel | undefined,
196 preferredChannelVerified: s.preferredChannelVerified as boolean | undefined,
197 isAdmin: s.isAdmin as boolean | undefined,
198 active: s.active as boolean | undefined,
199 status: s.status as Session['status'],
200 migratedToPds: s.migratedToPds as string | undefined,
201 migratedAt: s.migratedAt ? unsafeAsISODate(s.migratedAt as string) : undefined,
202 accessJwt: unsafeAsAccessToken(s.accessJwt as string),
203 refreshJwt: unsafeAsRefreshToken(s.refreshJwt as string),
204 }
205}
206
207export const api = {
208 async createAccount(
209 params: CreateAccountParams,
210 byodToken?: string,
211 ): Promise<CreateAccountResult> {
212 const url = `${API_BASE}/com.atproto.server.createAccount`
213 const headers: Record<string, string> = {
214 'Content-Type': 'application/json',
215 }
216 if (byodToken) {
217 headers['Authorization'] = `Bearer ${byodToken}`
218 }
219 const response = await fetch(url, {
220 method: 'POST',
221 headers,
222 body: JSON.stringify({
223 handle: params.handle,
224 email: params.email,
225 password: params.password,
226 inviteCode: params.inviteCode,
227 didType: params.didType,
228 did: params.did,
229 signingKey: params.signingKey,
230 verificationChannel: params.verificationChannel,
231 discordId: params.discordId,
232 telegramUsername: params.telegramUsername,
233 signalNumber: params.signalNumber,
234 }),
235 })
236 const data = await response.json()
237 if (!response.ok) {
238 throw new ApiError(response.status, data.error, data.message)
239 }
240 return data
241 },
242
243 async createAccountWithServiceAuth(
244 serviceAuthToken: string,
245 params: {
246 did: Did
247 handle: Handle
248 email: EmailAddress
249 password: string
250 inviteCode?: string
251 },
252 ): Promise<Session> {
253 const url = `${API_BASE}/com.atproto.server.createAccount`
254 const response = await fetch(url, {
255 method: 'POST',
256 headers: {
257 'Content-Type': 'application/json',
258 'Authorization': `Bearer ${serviceAuthToken}`,
259 },
260 body: JSON.stringify({
261 did: params.did,
262 handle: params.handle,
263 email: params.email,
264 password: params.password,
265 inviteCode: params.inviteCode,
266 }),
267 })
268 const data = await response.json()
269 if (!response.ok) {
270 throw new ApiError(response.status, data.error, data.message)
271 }
272 return castSession(data)
273 },
274
275 confirmSignup(
276 did: Did,
277 verificationCode: string,
278 ): Promise<ConfirmSignupResult> {
279 return xrpc('com.atproto.server.confirmSignup', {
280 method: 'POST',
281 body: { did, verificationCode },
282 })
283 },
284
285 resendVerification(did: Did): Promise<{ success: boolean }> {
286 return xrpc('com.atproto.server.resendVerification', {
287 method: 'POST',
288 body: { did },
289 })
290 },
291
292 async createSession(identifier: string, password: string): Promise<Session> {
293 const raw = await xrpc<unknown>('com.atproto.server.createSession', {
294 method: 'POST',
295 body: { identifier, password },
296 })
297 return castSession(raw)
298 },
299
300 checkEmailVerified(identifier: string): Promise<{ verified: boolean }> {
301 return xrpc('_checkEmailVerified', {
302 method: 'POST',
303 body: { identifier },
304 })
305 },
306
307 async getSession(token: AccessToken): Promise<Session> {
308 const raw = await xrpc<unknown>('com.atproto.server.getSession', { token })
309 return castSession(raw)
310 },
311
312 async refreshSession(refreshJwt: RefreshToken): Promise<Session> {
313 const raw = await xrpc<unknown>('com.atproto.server.refreshSession', {
314 method: 'POST',
315 token: refreshJwt,
316 })
317 return castSession(raw)
318 },
319
320 async deleteSession(token: AccessToken): Promise<void> {
321 await xrpc('com.atproto.server.deleteSession', {
322 method: 'POST',
323 token,
324 })
325 },
326
327 listAppPasswords(token: AccessToken): Promise<{ passwords: AppPassword[] }> {
328 return xrpc('com.atproto.server.listAppPasswords', { token })
329 },
330
331 createAppPassword(
332 token: AccessToken,
333 name: string,
334 scopes?: string,
335 ): Promise<CreatedAppPassword> {
336 return xrpc('com.atproto.server.createAppPassword', {
337 method: 'POST',
338 token,
339 body: { name, scopes },
340 })
341 },
342
343 async revokeAppPassword(token: AccessToken, name: string): Promise<void> {
344 await xrpc('com.atproto.server.revokeAppPassword', {
345 method: 'POST',
346 token,
347 body: { name },
348 })
349 },
350
351 getAccountInviteCodes(token: AccessToken): Promise<{ codes: InviteCodeInfo[] }> {
352 return xrpc('com.atproto.server.getAccountInviteCodes', { token })
353 },
354
355 createInviteCode(
356 token: AccessToken,
357 useCount: number = 1,
358 ): Promise<{ code: string }> {
359 return xrpc('com.atproto.server.createInviteCode', {
360 method: 'POST',
361 token,
362 body: { useCount },
363 })
364 },
365
366 async requestPasswordReset(email: EmailAddress): Promise<void> {
367 await xrpc('com.atproto.server.requestPasswordReset', {
368 method: 'POST',
369 body: { email },
370 })
371 },
372
373 async resetPassword(token: string, password: string): Promise<void> {
374 await xrpc('com.atproto.server.resetPassword', {
375 method: 'POST',
376 body: { token, password },
377 })
378 },
379
380 requestEmailUpdate(token: AccessToken): Promise<EmailUpdateResponse> {
381 return xrpc('com.atproto.server.requestEmailUpdate', {
382 method: 'POST',
383 token,
384 })
385 },
386
387 async updateEmail(
388 token: AccessToken,
389 email: string,
390 emailToken?: string,
391 ): Promise<void> {
392 await xrpc('com.atproto.server.updateEmail', {
393 method: 'POST',
394 token,
395 body: { email, token: emailToken },
396 })
397 },
398
399 async updateHandle(token: AccessToken, handle: Handle): Promise<void> {
400 await xrpc('com.atproto.identity.updateHandle', {
401 method: 'POST',
402 token,
403 body: { handle },
404 })
405 },
406
407 async requestAccountDelete(token: AccessToken): Promise<void> {
408 await xrpc('com.atproto.server.requestAccountDelete', {
409 method: 'POST',
410 token,
411 })
412 },
413
414 async deleteAccount(
415 did: Did,
416 password: string,
417 deleteToken: string,
418 ): Promise<void> {
419 await xrpc('com.atproto.server.deleteAccount', {
420 method: 'POST',
421 body: { did, password, token: deleteToken },
422 })
423 },
424
425 describeServer(): Promise<ServerDescription> {
426 return xrpc('com.atproto.server.describeServer')
427 },
428
429 listRepos(limit?: number): Promise<ListReposResponse> {
430 const params: Record<string, string> = {}
431 if (limit) params.limit = String(limit)
432 return xrpc('com.atproto.sync.listRepos', { params })
433 },
434
435 getNotificationPrefs(token: AccessToken): Promise<NotificationPrefs> {
436 return xrpc('_account.getNotificationPrefs', { token })
437 },
438
439 updateNotificationPrefs(token: AccessToken, prefs: {
440 preferredChannel?: string
441 discordId?: string
442 telegramUsername?: string
443 signalNumber?: string
444 }): Promise<SuccessResponse> {
445 return xrpc('_account.updateNotificationPrefs', {
446 method: 'POST',
447 token,
448 body: prefs,
449 })
450 },
451
452 confirmChannelVerification(
453 token: AccessToken,
454 channel: string,
455 identifier: string,
456 code: string,
457 ): Promise<SuccessResponse> {
458 return xrpc('_account.confirmChannelVerification', {
459 method: 'POST',
460 token,
461 body: { channel, identifier, code },
462 })
463 },
464
465 getNotificationHistory(token: AccessToken): Promise<NotificationHistoryResponse> {
466 return xrpc('_account.getNotificationHistory', { token })
467 },
468
469 getServerStats(token: AccessToken): Promise<ServerStats> {
470 return xrpc('_admin.getServerStats', { token })
471 },
472
473 getServerConfig(): Promise<ServerConfig> {
474 return xrpc('_server.getConfig')
475 },
476
477 updateServerConfig(
478 token: AccessToken,
479 config: {
480 serverName?: string
481 primaryColor?: string
482 primaryColorDark?: string
483 secondaryColor?: string
484 secondaryColorDark?: string
485 logoCid?: string
486 },
487 ): Promise<SuccessResponse> {
488 return xrpc('_admin.updateServerConfig', {
489 method: 'POST',
490 token,
491 body: config,
492 })
493 },
494
495 async uploadBlob(token: AccessToken, file: File): Promise<UploadBlobResponse> {
496 const res = await fetch('/xrpc/com.atproto.repo.uploadBlob', {
497 method: 'POST',
498 headers: {
499 'Authorization': `Bearer ${token}`,
500 'Content-Type': file.type,
501 },
502 body: file,
503 })
504 if (!res.ok) {
505 const errData = await res.json().catch(() => ({
506 error: 'Unknown',
507 message: res.statusText,
508 }))
509 throw new ApiError(res.status, errData.error, errData.message)
510 }
511 return res.json()
512 },
513
514 async changePassword(
515 token: AccessToken,
516 currentPassword: string,
517 newPassword: string,
518 ): Promise<void> {
519 await xrpc('_account.changePassword', {
520 method: 'POST',
521 token,
522 body: { currentPassword, newPassword },
523 })
524 },
525
526 removePassword(token: AccessToken): Promise<SuccessResponse> {
527 return xrpc('_account.removePassword', {
528 method: 'POST',
529 token,
530 })
531 },
532
533 getPasswordStatus(token: AccessToken): Promise<PasswordStatus> {
534 return xrpc('_account.getPasswordStatus', { token })
535 },
536
537 getLegacyLoginPreference(token: AccessToken): Promise<LegacyLoginPreference> {
538 return xrpc('_account.getLegacyLoginPreference', { token })
539 },
540
541 updateLegacyLoginPreference(
542 token: AccessToken,
543 allowLegacyLogin: boolean,
544 ): Promise<UpdateLegacyLoginResponse> {
545 return xrpc('_account.updateLegacyLoginPreference', {
546 method: 'POST',
547 token,
548 body: { allowLegacyLogin },
549 })
550 },
551
552 updateLocale(token: AccessToken, preferredLocale: string): Promise<UpdateLocaleResponse> {
553 return xrpc('_account.updateLocale', {
554 method: 'POST',
555 token,
556 body: { preferredLocale },
557 })
558 },
559
560 listSessions(token: AccessToken): Promise<ListSessionsResponse> {
561 return xrpc('_account.listSessions', { token })
562 },
563
564 async revokeSession(token: AccessToken, sessionId: string): Promise<void> {
565 await xrpc('_account.revokeSession', {
566 method: 'POST',
567 token,
568 body: { sessionId },
569 })
570 },
571
572 revokeAllSessions(token: AccessToken): Promise<{ revokedCount: number }> {
573 return xrpc('_account.revokeAllSessions', {
574 method: 'POST',
575 token,
576 })
577 },
578
579 searchAccounts(token: AccessToken, options?: {
580 handle?: string
581 cursor?: string
582 limit?: number
583 }): Promise<SearchAccountsResponse> {
584 const params: Record<string, string> = {}
585 if (options?.handle) params.handle = options.handle
586 if (options?.cursor) params.cursor = options.cursor
587 if (options?.limit) params.limit = String(options.limit)
588 return xrpc('com.atproto.admin.searchAccounts', { token, params })
589 },
590
591 getInviteCodes(token: AccessToken, options?: {
592 sort?: 'recent' | 'usage'
593 cursor?: string
594 limit?: number
595 }): Promise<GetInviteCodesResponse> {
596 const params: Record<string, string> = {}
597 if (options?.sort) params.sort = options.sort
598 if (options?.cursor) params.cursor = options.cursor
599 if (options?.limit) params.limit = String(options.limit)
600 return xrpc('com.atproto.admin.getInviteCodes', { token, params })
601 },
602
603 async disableInviteCodes(
604 token: AccessToken,
605 codes?: string[],
606 accounts?: string[],
607 ): Promise<void> {
608 await xrpc('com.atproto.admin.disableInviteCodes', {
609 method: 'POST',
610 token,
611 body: { codes, accounts },
612 })
613 },
614
615 getAccountInfo(token: AccessToken, did: Did): Promise<AccountInfo> {
616 return xrpc('com.atproto.admin.getAccountInfo', { token, params: { did } })
617 },
618
619 async disableAccountInvites(token: AccessToken, account: Did): Promise<void> {
620 await xrpc('com.atproto.admin.disableAccountInvites', {
621 method: 'POST',
622 token,
623 body: { account },
624 })
625 },
626
627 async enableAccountInvites(token: AccessToken, account: Did): Promise<void> {
628 await xrpc('com.atproto.admin.enableAccountInvites', {
629 method: 'POST',
630 token,
631 body: { account },
632 })
633 },
634
635 async adminDeleteAccount(token: AccessToken, did: Did): Promise<void> {
636 await xrpc('com.atproto.admin.deleteAccount', {
637 method: 'POST',
638 token,
639 body: { did },
640 })
641 },
642
643 describeRepo(token: AccessToken, repo: Did): Promise<RepoDescription> {
644 return xrpc('com.atproto.repo.describeRepo', {
645 token,
646 params: { repo },
647 })
648 },
649
650 listRecords(token: AccessToken, repo: Did, collection: Nsid, options?: {
651 limit?: number
652 cursor?: string
653 reverse?: boolean
654 }): Promise<ListRecordsResponse> {
655 const params: Record<string, string> = { repo, collection }
656 if (options?.limit) params.limit = String(options.limit)
657 if (options?.cursor) params.cursor = options.cursor
658 if (options?.reverse) params.reverse = 'true'
659 return xrpc('com.atproto.repo.listRecords', { token, params })
660 },
661
662 getRecord(
663 token: AccessToken,
664 repo: Did,
665 collection: Nsid,
666 rkey: Rkey,
667 ): Promise<RecordResponse> {
668 return xrpc('com.atproto.repo.getRecord', {
669 token,
670 params: { repo, collection, rkey },
671 })
672 },
673
674 createRecord(
675 token: AccessToken,
676 repo: Did,
677 collection: Nsid,
678 record: unknown,
679 rkey?: Rkey,
680 ): Promise<CreateRecordResponse> {
681 return xrpc('com.atproto.repo.createRecord', {
682 method: 'POST',
683 token,
684 body: { repo, collection, record, rkey },
685 })
686 },
687
688 putRecord(
689 token: AccessToken,
690 repo: Did,
691 collection: Nsid,
692 rkey: Rkey,
693 record: unknown,
694 ): Promise<CreateRecordResponse> {
695 return xrpc('com.atproto.repo.putRecord', {
696 method: 'POST',
697 token,
698 body: { repo, collection, rkey, record },
699 })
700 },
701
702 async deleteRecord(
703 token: AccessToken,
704 repo: Did,
705 collection: Nsid,
706 rkey: Rkey,
707 ): Promise<void> {
708 await xrpc('com.atproto.repo.deleteRecord', {
709 method: 'POST',
710 token,
711 body: { repo, collection, rkey },
712 })
713 },
714
715 getTotpStatus(token: AccessToken): Promise<TotpStatus> {
716 return xrpc('com.atproto.server.getTotpStatus', { token })
717 },
718
719 createTotpSecret(token: AccessToken): Promise<TotpSecret> {
720 return xrpc('com.atproto.server.createTotpSecret', {
721 method: 'POST',
722 token,
723 })
724 },
725
726 enableTotp(token: AccessToken, code: string): Promise<EnableTotpResponse> {
727 return xrpc('com.atproto.server.enableTotp', {
728 method: 'POST',
729 token,
730 body: { code },
731 })
732 },
733
734 disableTotp(
735 token: AccessToken,
736 password: string,
737 code: string,
738 ): Promise<SuccessResponse> {
739 return xrpc('com.atproto.server.disableTotp', {
740 method: 'POST',
741 token,
742 body: { password, code },
743 })
744 },
745
746 regenerateBackupCodes(
747 token: AccessToken,
748 password: string,
749 code: string,
750 ): Promise<RegenerateBackupCodesResponse> {
751 return xrpc('com.atproto.server.regenerateBackupCodes', {
752 method: 'POST',
753 token,
754 body: { password, code },
755 })
756 },
757
758 startPasskeyRegistration(
759 token: AccessToken,
760 friendlyName?: string,
761 ): Promise<StartPasskeyRegistrationResponse> {
762 return xrpc('com.atproto.server.startPasskeyRegistration', {
763 method: 'POST',
764 token,
765 body: { friendlyName },
766 })
767 },
768
769 finishPasskeyRegistration(
770 token: AccessToken,
771 credential: unknown,
772 friendlyName?: string,
773 ): Promise<FinishPasskeyRegistrationResponse> {
774 return xrpc('com.atproto.server.finishPasskeyRegistration', {
775 method: 'POST',
776 token,
777 body: { credential, friendlyName },
778 })
779 },
780
781 listPasskeys(token: AccessToken): Promise<ListPasskeysResponse> {
782 return xrpc('com.atproto.server.listPasskeys', { token })
783 },
784
785 async deletePasskey(token: AccessToken, id: string): Promise<void> {
786 await xrpc('com.atproto.server.deletePasskey', {
787 method: 'POST',
788 token,
789 body: { id },
790 })
791 },
792
793 async updatePasskey(
794 token: AccessToken,
795 id: string,
796 friendlyName: string,
797 ): Promise<void> {
798 await xrpc('com.atproto.server.updatePasskey', {
799 method: 'POST',
800 token,
801 body: { id, friendlyName },
802 })
803 },
804
805 listTrustedDevices(token: AccessToken): Promise<ListTrustedDevicesResponse> {
806 return xrpc('_account.listTrustedDevices', { token })
807 },
808
809 revokeTrustedDevice(token: AccessToken, deviceId: string): Promise<SuccessResponse> {
810 return xrpc('_account.revokeTrustedDevice', {
811 method: 'POST',
812 token,
813 body: { deviceId },
814 })
815 },
816
817 updateTrustedDevice(
818 token: AccessToken,
819 deviceId: string,
820 friendlyName: string,
821 ): Promise<SuccessResponse> {
822 return xrpc('_account.updateTrustedDevice', {
823 method: 'POST',
824 token,
825 body: { deviceId, friendlyName },
826 })
827 },
828
829 getReauthStatus(token: AccessToken): Promise<ReauthStatus> {
830 return xrpc('_account.getReauthStatus', { token })
831 },
832
833 reauthPassword(token: AccessToken, password: string): Promise<ReauthResponse> {
834 return xrpc('_account.reauthPassword', {
835 method: 'POST',
836 token,
837 body: { password },
838 })
839 },
840
841 reauthTotp(token: AccessToken, code: string): Promise<ReauthResponse> {
842 return xrpc('_account.reauthTotp', {
843 method: 'POST',
844 token,
845 body: { code },
846 })
847 },
848
849 reauthPasskeyStart(token: AccessToken): Promise<ReauthPasskeyStartResponse> {
850 return xrpc('_account.reauthPasskeyStart', {
851 method: 'POST',
852 token,
853 })
854 },
855
856 reauthPasskeyFinish(token: AccessToken, credential: unknown): Promise<ReauthResponse> {
857 return xrpc('_account.reauthPasskeyFinish', {
858 method: 'POST',
859 token,
860 body: { credential },
861 })
862 },
863
864 reserveSigningKey(did?: Did): Promise<ReserveSigningKeyResponse> {
865 return xrpc('com.atproto.server.reserveSigningKey', {
866 method: 'POST',
867 body: { did },
868 })
869 },
870
871 getRecommendedDidCredentials(token: AccessToken): Promise<RecommendedDidCredentials> {
872 return xrpc('com.atproto.identity.getRecommendedDidCredentials', { token })
873 },
874
875 async activateAccount(token: AccessToken): Promise<void> {
876 await xrpc('com.atproto.server.activateAccount', {
877 method: 'POST',
878 token,
879 })
880 },
881
882 async createPasskeyAccount(params: {
883 handle: Handle
884 email?: EmailAddress
885 inviteCode?: string
886 didType?: DidType
887 did?: Did
888 signingKey?: string
889 verificationChannel?: VerificationChannel
890 discordId?: string
891 telegramUsername?: string
892 signalNumber?: string
893 }, byodToken?: string): Promise<PasskeyAccountCreateResponse> {
894 const url = `${API_BASE}/_account.createPasskeyAccount`
895 const headers: Record<string, string> = {
896 'Content-Type': 'application/json',
897 }
898 if (byodToken) {
899 headers['Authorization'] = `Bearer ${byodToken}`
900 }
901 const res = await fetch(url, {
902 method: 'POST',
903 headers,
904 body: JSON.stringify(params),
905 })
906 if (!res.ok) {
907 const errData = await res.json().catch(() => ({
908 error: 'Unknown',
909 message: res.statusText,
910 }))
911 throw new ApiError(res.status, errData.error, errData.message)
912 }
913 return res.json()
914 },
915
916 startPasskeyRegistrationForSetup(
917 did: Did,
918 setupToken: string,
919 friendlyName?: string,
920 ): Promise<StartPasskeyRegistrationResponse> {
921 return xrpc('_account.startPasskeyRegistrationForSetup', {
922 method: 'POST',
923 body: { did, setupToken, friendlyName },
924 })
925 },
926
927 completePasskeySetup(
928 did: Did,
929 setupToken: string,
930 passkeyCredential: unknown,
931 passkeyFriendlyName?: string,
932 ): Promise<CompletePasskeySetupResponse> {
933 return xrpc('_account.completePasskeySetup', {
934 method: 'POST',
935 body: { did, setupToken, passkeyCredential, passkeyFriendlyName },
936 })
937 },
938
939 requestPasskeyRecovery(email: EmailAddress): Promise<SuccessResponse> {
940 return xrpc('_account.requestPasskeyRecovery', {
941 method: 'POST',
942 body: { email },
943 })
944 },
945
946 recoverPasskeyAccount(
947 did: Did,
948 recoveryToken: string,
949 newPassword: string,
950 ): Promise<SuccessResponse> {
951 return xrpc('_account.recoverPasskeyAccount', {
952 method: 'POST',
953 body: { did, recoveryToken, newPassword },
954 })
955 },
956
957 verifyMigrationEmail(token: string, email: EmailAddress): Promise<VerifyMigrationEmailResponse> {
958 return xrpc('com.atproto.server.verifyMigrationEmail', {
959 method: 'POST',
960 body: { token, email },
961 })
962 },
963
964 resendMigrationVerification(email: EmailAddress): Promise<ResendMigrationVerificationResponse> {
965 return xrpc('com.atproto.server.resendMigrationVerification', {
966 method: 'POST',
967 body: { email },
968 })
969 },
970
971 verifyToken(
972 token: string,
973 identifier: string,
974 accessToken?: AccessToken,
975 ): Promise<VerifyTokenResponse> {
976 return xrpc('_account.verifyToken', {
977 method: 'POST',
978 body: { token, identifier },
979 token: accessToken,
980 })
981 },
982
983 getDidDocument(token: AccessToken): Promise<DidDocument> {
984 return xrpc('_account.getDidDocument', { token })
985 },
986
987 updateDidDocument(
988 token: AccessToken,
989 params: {
990 verificationMethods?: VerificationMethod[]
991 alsoKnownAs?: string[]
992 serviceEndpoint?: string
993 },
994 ): Promise<SuccessResponse> {
995 return xrpc('_account.updateDidDocument', {
996 method: 'POST',
997 token,
998 body: params,
999 })
1000 },
1001
1002 async deactivateAccount(token: AccessToken, deleteAfter?: string): Promise<void> {
1003 await xrpc('com.atproto.server.deactivateAccount', {
1004 method: 'POST',
1005 token,
1006 body: { deleteAfter },
1007 })
1008 },
1009
1010 async getRepo(token: AccessToken, did: Did): Promise<ArrayBuffer> {
1011 const url = `${API_BASE}/com.atproto.sync.getRepo?did=${encodeURIComponent(did)}`
1012 const res = await fetch(url, {
1013 headers: { Authorization: `Bearer ${token}` },
1014 })
1015 if (!res.ok) {
1016 const errData = await res.json().catch(() => ({
1017 error: 'Unknown',
1018 message: res.statusText,
1019 }))
1020 throw new ApiError(res.status, errData.error, errData.message)
1021 }
1022 return res.arrayBuffer()
1023 },
1024
1025 listBackups(token: AccessToken): Promise<ListBackupsResponse> {
1026 return xrpc('_backup.listBackups', { token })
1027 },
1028
1029 async getBackup(token: AccessToken, id: string): Promise<Blob> {
1030 const url = `${API_BASE}/_backup.getBackup?id=${encodeURIComponent(id)}`
1031 const res = await fetch(url, {
1032 headers: { Authorization: `Bearer ${token}` },
1033 })
1034 if (!res.ok) {
1035 const errData = await res.json().catch(() => ({
1036 error: 'Unknown',
1037 message: res.statusText,
1038 }))
1039 throw new ApiError(res.status, errData.error, errData.message)
1040 }
1041 return res.blob()
1042 },
1043
1044 createBackup(token: AccessToken): Promise<CreateBackupResponse> {
1045 return xrpc('_backup.createBackup', {
1046 method: 'POST',
1047 token,
1048 })
1049 },
1050
1051 async deleteBackup(token: AccessToken, id: string): Promise<void> {
1052 await xrpc('_backup.deleteBackup', {
1053 method: 'POST',
1054 token,
1055 params: { id },
1056 })
1057 },
1058
1059 setBackupEnabled(token: AccessToken, enabled: boolean): Promise<SetBackupEnabledResponse> {
1060 return xrpc('_backup.setEnabled', {
1061 method: 'POST',
1062 token,
1063 body: { enabled },
1064 })
1065 },
1066
1067 async importRepo(token: AccessToken, car: Uint8Array): Promise<void> {
1068 const url = `${API_BASE}/com.atproto.repo.importRepo`
1069 const res = await fetch(url, {
1070 method: 'POST',
1071 headers: {
1072 Authorization: `Bearer ${token}`,
1073 'Content-Type': 'application/vnd.ipld.car',
1074 },
1075 body: car,
1076 })
1077 if (!res.ok) {
1078 const errData = await res.json().catch(() => ({
1079 error: 'Unknown',
1080 message: res.statusText,
1081 }))
1082 throw new ApiError(res.status, errData.error, errData.message)
1083 }
1084 },
1085}
1086
1087export const typedApi = {
1088 createSession(
1089 identifier: string,
1090 password: string
1091 ): Promise<Result<Session, ApiError>> {
1092 return xrpcResult<Session>('com.atproto.server.createSession', {
1093 method: 'POST',
1094 body: { identifier, password },
1095 }).then(r => r.ok ? ok(castSession(r.value)) : r)
1096 },
1097
1098 getSession(token: AccessToken): Promise<Result<Session, ApiError>> {
1099 return xrpcResult<Session>('com.atproto.server.getSession', { token })
1100 .then(r => r.ok ? ok(castSession(r.value)) : r)
1101 },
1102
1103 refreshSession(refreshJwt: RefreshToken): Promise<Result<Session, ApiError>> {
1104 return xrpcResult<Session>('com.atproto.server.refreshSession', {
1105 method: 'POST',
1106 token: refreshJwt,
1107 }).then(r => r.ok ? ok(castSession(r.value)) : r)
1108 },
1109
1110 describeServer(): Promise<Result<ServerDescription, ApiError>> {
1111 return xrpcResult('com.atproto.server.describeServer')
1112 },
1113
1114 listAppPasswords(token: AccessToken): Promise<Result<{ passwords: AppPassword[] }, ApiError>> {
1115 return xrpcResult('com.atproto.server.listAppPasswords', { token })
1116 },
1117
1118 createAppPassword(
1119 token: AccessToken,
1120 name: string,
1121 scopes?: string
1122 ): Promise<Result<CreatedAppPassword, ApiError>> {
1123 return xrpcResult('com.atproto.server.createAppPassword', {
1124 method: 'POST',
1125 token,
1126 body: { name, scopes },
1127 })
1128 },
1129
1130 revokeAppPassword(token: AccessToken, name: string): Promise<Result<void, ApiError>> {
1131 return xrpcResult<void>('com.atproto.server.revokeAppPassword', {
1132 method: 'POST',
1133 token,
1134 body: { name },
1135 })
1136 },
1137
1138 listSessions(token: AccessToken): Promise<Result<ListSessionsResponse, ApiError>> {
1139 return xrpcResult('_account.listSessions', { token })
1140 },
1141
1142 revokeSession(token: AccessToken, sessionId: string): Promise<Result<void, ApiError>> {
1143 return xrpcResult<void>('_account.revokeSession', {
1144 method: 'POST',
1145 token,
1146 body: { sessionId },
1147 })
1148 },
1149
1150 getTotpStatus(token: AccessToken): Promise<Result<TotpStatus, ApiError>> {
1151 return xrpcResult('com.atproto.server.getTotpStatus', { token })
1152 },
1153
1154 createTotpSecret(token: AccessToken): Promise<Result<TotpSecret, ApiError>> {
1155 return xrpcResult('com.atproto.server.createTotpSecret', {
1156 method: 'POST',
1157 token,
1158 })
1159 },
1160
1161 enableTotp(token: AccessToken, code: string): Promise<Result<EnableTotpResponse, ApiError>> {
1162 return xrpcResult('com.atproto.server.enableTotp', {
1163 method: 'POST',
1164 token,
1165 body: { code },
1166 })
1167 },
1168
1169 disableTotp(
1170 token: AccessToken,
1171 password: string,
1172 code: string
1173 ): Promise<Result<SuccessResponse, ApiError>> {
1174 return xrpcResult('com.atproto.server.disableTotp', {
1175 method: 'POST',
1176 token,
1177 body: { password, code },
1178 })
1179 },
1180
1181 listPasskeys(token: AccessToken): Promise<Result<ListPasskeysResponse, ApiError>> {
1182 return xrpcResult('com.atproto.server.listPasskeys', { token })
1183 },
1184
1185 deletePasskey(token: AccessToken, id: string): Promise<Result<void, ApiError>> {
1186 return xrpcResult<void>('com.atproto.server.deletePasskey', {
1187 method: 'POST',
1188 token,
1189 body: { id },
1190 })
1191 },
1192
1193 listTrustedDevices(token: AccessToken): Promise<Result<ListTrustedDevicesResponse, ApiError>> {
1194 return xrpcResult('_account.listTrustedDevices', { token })
1195 },
1196
1197 getReauthStatus(token: AccessToken): Promise<Result<ReauthStatus, ApiError>> {
1198 return xrpcResult('_account.getReauthStatus', { token })
1199 },
1200
1201 getNotificationPrefs(token: AccessToken): Promise<Result<NotificationPrefs, ApiError>> {
1202 return xrpcResult('_account.getNotificationPrefs', { token })
1203 },
1204
1205 updateHandle(token: AccessToken, handle: Handle): Promise<Result<void, ApiError>> {
1206 return xrpcResult<void>('com.atproto.identity.updateHandle', {
1207 method: 'POST',
1208 token,
1209 body: { handle },
1210 })
1211 },
1212
1213 describeRepo(token: AccessToken, repo: Did): Promise<Result<RepoDescription, ApiError>> {
1214 return xrpcResult('com.atproto.repo.describeRepo', {
1215 token,
1216 params: { repo },
1217 })
1218 },
1219
1220 listRecords(
1221 token: AccessToken,
1222 repo: Did,
1223 collection: Nsid,
1224 options?: { limit?: number; cursor?: string; reverse?: boolean }
1225 ): Promise<Result<ListRecordsResponse, ApiError>> {
1226 const params: Record<string, string> = { repo, collection }
1227 if (options?.limit) params.limit = String(options.limit)
1228 if (options?.cursor) params.cursor = options.cursor
1229 if (options?.reverse) params.reverse = 'true'
1230 return xrpcResult('com.atproto.repo.listRecords', { token, params })
1231 },
1232
1233 getRecord(
1234 token: AccessToken,
1235 repo: Did,
1236 collection: Nsid,
1237 rkey: Rkey
1238 ): Promise<Result<RecordResponse, ApiError>> {
1239 return xrpcResult('com.atproto.repo.getRecord', {
1240 token,
1241 params: { repo, collection, rkey },
1242 })
1243 },
1244
1245 deleteRecord(
1246 token: AccessToken,
1247 repo: Did,
1248 collection: Nsid,
1249 rkey: Rkey
1250 ): Promise<Result<void, ApiError>> {
1251 return xrpcResult<void>('com.atproto.repo.deleteRecord', {
1252 method: 'POST',
1253 token,
1254 body: { repo, collection, rkey },
1255 })
1256 },
1257
1258 searchAccounts(
1259 token: AccessToken,
1260 options?: { handle?: string; cursor?: string; limit?: number }
1261 ): Promise<Result<SearchAccountsResponse, ApiError>> {
1262 const params: Record<string, string> = {}
1263 if (options?.handle) params.handle = options.handle
1264 if (options?.cursor) params.cursor = options.cursor
1265 if (options?.limit) params.limit = String(options.limit)
1266 return xrpcResult('com.atproto.admin.searchAccounts', { token, params })
1267 },
1268
1269 getAccountInfo(token: AccessToken, did: Did): Promise<Result<AccountInfo, ApiError>> {
1270 return xrpcResult('com.atproto.admin.getAccountInfo', { token, params: { did } })
1271 },
1272
1273 getServerStats(token: AccessToken): Promise<Result<ServerStats, ApiError>> {
1274 return xrpcResult('_admin.getServerStats', { token })
1275 },
1276
1277 listBackups(token: AccessToken): Promise<Result<ListBackupsResponse, ApiError>> {
1278 return xrpcResult('_backup.listBackups', { token })
1279 },
1280
1281 createBackup(token: AccessToken): Promise<Result<CreateBackupResponse, ApiError>> {
1282 return xrpcResult('_backup.createBackup', {
1283 method: 'POST',
1284 token,
1285 })
1286 },
1287
1288 getDidDocument(token: AccessToken): Promise<Result<DidDocument, ApiError>> {
1289 return xrpcResult('_account.getDidDocument', { token })
1290 },
1291
1292 deleteSession(token: AccessToken): Promise<Result<void, ApiError>> {
1293 return xrpcResult<void>('com.atproto.server.deleteSession', {
1294 method: 'POST',
1295 token,
1296 })
1297 },
1298
1299 revokeAllSessions(token: AccessToken): Promise<Result<{ revokedCount: number }, ApiError>> {
1300 return xrpcResult('_account.revokeAllSessions', {
1301 method: 'POST',
1302 token,
1303 })
1304 },
1305
1306 getAccountInviteCodes(token: AccessToken): Promise<Result<{ codes: InviteCodeInfo[] }, ApiError>> {
1307 return xrpcResult('com.atproto.server.getAccountInviteCodes', { token })
1308 },
1309
1310 createInviteCode(token: AccessToken, useCount: number = 1): Promise<Result<{ code: string }, ApiError>> {
1311 return xrpcResult('com.atproto.server.createInviteCode', {
1312 method: 'POST',
1313 token,
1314 body: { useCount },
1315 })
1316 },
1317
1318 changePassword(
1319 token: AccessToken,
1320 currentPassword: string,
1321 newPassword: string
1322 ): Promise<Result<void, ApiError>> {
1323 return xrpcResult<void>('_account.changePassword', {
1324 method: 'POST',
1325 token,
1326 body: { currentPassword, newPassword },
1327 })
1328 },
1329
1330 getPasswordStatus(token: AccessToken): Promise<Result<PasswordStatus, ApiError>> {
1331 return xrpcResult('_account.getPasswordStatus', { token })
1332 },
1333
1334 getServerConfig(): Promise<Result<ServerConfig, ApiError>> {
1335 return xrpcResult('_server.getConfig')
1336 },
1337
1338 getLegacyLoginPreference(token: AccessToken): Promise<Result<LegacyLoginPreference, ApiError>> {
1339 return xrpcResult('_account.getLegacyLoginPreference', { token })
1340 },
1341
1342 updateLegacyLoginPreference(
1343 token: AccessToken,
1344 allowLegacyLogin: boolean
1345 ): Promise<Result<UpdateLegacyLoginResponse, ApiError>> {
1346 return xrpcResult('_account.updateLegacyLoginPreference', {
1347 method: 'POST',
1348 token,
1349 body: { allowLegacyLogin },
1350 })
1351 },
1352
1353 getNotificationHistory(token: AccessToken): Promise<Result<NotificationHistoryResponse, ApiError>> {
1354 return xrpcResult('_account.getNotificationHistory', { token })
1355 },
1356
1357 updateNotificationPrefs(
1358 token: AccessToken,
1359 prefs: {
1360 preferredChannel?: string
1361 discordId?: string
1362 telegramUsername?: string
1363 signalNumber?: string
1364 }
1365 ): Promise<Result<SuccessResponse, ApiError>> {
1366 return xrpcResult('_account.updateNotificationPrefs', {
1367 method: 'POST',
1368 token,
1369 body: prefs,
1370 })
1371 },
1372
1373 revokeTrustedDevice(token: AccessToken, deviceId: string): Promise<Result<SuccessResponse, ApiError>> {
1374 return xrpcResult('_account.revokeTrustedDevice', {
1375 method: 'POST',
1376 token,
1377 body: { deviceId },
1378 })
1379 },
1380
1381 updateTrustedDevice(
1382 token: AccessToken,
1383 deviceId: string,
1384 friendlyName: string
1385 ): Promise<Result<SuccessResponse, ApiError>> {
1386 return xrpcResult('_account.updateTrustedDevice', {
1387 method: 'POST',
1388 token,
1389 body: { deviceId, friendlyName },
1390 })
1391 },
1392
1393 reauthPassword(token: AccessToken, password: string): Promise<Result<ReauthResponse, ApiError>> {
1394 return xrpcResult('_account.reauthPassword', {
1395 method: 'POST',
1396 token,
1397 body: { password },
1398 })
1399 },
1400
1401 reauthTotp(token: AccessToken, code: string): Promise<Result<ReauthResponse, ApiError>> {
1402 return xrpcResult('_account.reauthTotp', {
1403 method: 'POST',
1404 token,
1405 body: { code },
1406 })
1407 },
1408
1409 reauthPasskeyStart(token: AccessToken): Promise<Result<ReauthPasskeyStartResponse, ApiError>> {
1410 return xrpcResult('_account.reauthPasskeyStart', {
1411 method: 'POST',
1412 token,
1413 })
1414 },
1415
1416 reauthPasskeyFinish(token: AccessToken, credential: unknown): Promise<Result<ReauthResponse, ApiError>> {
1417 return xrpcResult('_account.reauthPasskeyFinish', {
1418 method: 'POST',
1419 token,
1420 body: { credential },
1421 })
1422 },
1423
1424 confirmSignup(did: Did, verificationCode: string): Promise<Result<ConfirmSignupResult, ApiError>> {
1425 return xrpcResult('com.atproto.server.confirmSignup', {
1426 method: 'POST',
1427 body: { did, verificationCode },
1428 })
1429 },
1430
1431 resendVerification(did: Did): Promise<Result<{ success: boolean }, ApiError>> {
1432 return xrpcResult('com.atproto.server.resendVerification', {
1433 method: 'POST',
1434 body: { did },
1435 })
1436 },
1437
1438 requestEmailUpdate(token: AccessToken): Promise<Result<EmailUpdateResponse, ApiError>> {
1439 return xrpcResult('com.atproto.server.requestEmailUpdate', {
1440 method: 'POST',
1441 token,
1442 })
1443 },
1444
1445 updateEmail(token: AccessToken, email: string, emailToken?: string): Promise<Result<void, ApiError>> {
1446 return xrpcResult<void>('com.atproto.server.updateEmail', {
1447 method: 'POST',
1448 token,
1449 body: { email, token: emailToken },
1450 })
1451 },
1452
1453 requestAccountDelete(token: AccessToken): Promise<Result<void, ApiError>> {
1454 return xrpcResult<void>('com.atproto.server.requestAccountDelete', {
1455 method: 'POST',
1456 token,
1457 })
1458 },
1459
1460 deleteAccount(did: Did, password: string, deleteToken: string): Promise<Result<void, ApiError>> {
1461 return xrpcResult<void>('com.atproto.server.deleteAccount', {
1462 method: 'POST',
1463 body: { did, password, token: deleteToken },
1464 })
1465 },
1466
1467 updateDidDocument(
1468 token: AccessToken,
1469 params: {
1470 verificationMethods?: VerificationMethod[]
1471 alsoKnownAs?: string[]
1472 serviceEndpoint?: string
1473 }
1474 ): Promise<Result<SuccessResponse, ApiError>> {
1475 return xrpcResult('_account.updateDidDocument', {
1476 method: 'POST',
1477 token,
1478 body: params,
1479 })
1480 },
1481
1482 deactivateAccount(token: AccessToken, deleteAfter?: string): Promise<Result<void, ApiError>> {
1483 return xrpcResult<void>('com.atproto.server.deactivateAccount', {
1484 method: 'POST',
1485 token,
1486 body: { deleteAfter },
1487 })
1488 },
1489
1490 activateAccount(token: AccessToken): Promise<Result<void, ApiError>> {
1491 return xrpcResult<void>('com.atproto.server.activateAccount', {
1492 method: 'POST',
1493 token,
1494 })
1495 },
1496
1497 setBackupEnabled(token: AccessToken, enabled: boolean): Promise<Result<SetBackupEnabledResponse, ApiError>> {
1498 return xrpcResult('_backup.setEnabled', {
1499 method: 'POST',
1500 token,
1501 body: { enabled },
1502 })
1503 },
1504
1505 deleteBackup(token: AccessToken, id: string): Promise<Result<void, ApiError>> {
1506 return xrpcResult<void>('_backup.deleteBackup', {
1507 method: 'POST',
1508 token,
1509 params: { id },
1510 })
1511 },
1512
1513 createRecord(
1514 token: AccessToken,
1515 repo: Did,
1516 collection: Nsid,
1517 record: unknown,
1518 rkey?: Rkey
1519 ): Promise<Result<CreateRecordResponse, ApiError>> {
1520 return xrpcResult('com.atproto.repo.createRecord', {
1521 method: 'POST',
1522 token,
1523 body: { repo, collection, record, rkey },
1524 })
1525 },
1526
1527 putRecord(
1528 token: AccessToken,
1529 repo: Did,
1530 collection: Nsid,
1531 rkey: Rkey,
1532 record: unknown
1533 ): Promise<Result<CreateRecordResponse, ApiError>> {
1534 return xrpcResult('com.atproto.repo.putRecord', {
1535 method: 'POST',
1536 token,
1537 body: { repo, collection, rkey, record },
1538 })
1539 },
1540
1541 getInviteCodes(
1542 token: AccessToken,
1543 options?: { sort?: 'recent' | 'usage'; cursor?: string; limit?: number }
1544 ): Promise<Result<GetInviteCodesResponse, ApiError>> {
1545 const params: Record<string, string> = {}
1546 if (options?.sort) params.sort = options.sort
1547 if (options?.cursor) params.cursor = options.cursor
1548 if (options?.limit) params.limit = String(options.limit)
1549 return xrpcResult('com.atproto.admin.getInviteCodes', { token, params })
1550 },
1551
1552 disableAccountInvites(token: AccessToken, account: Did): Promise<Result<void, ApiError>> {
1553 return xrpcResult<void>('com.atproto.admin.disableAccountInvites', {
1554 method: 'POST',
1555 token,
1556 body: { account },
1557 })
1558 },
1559
1560 enableAccountInvites(token: AccessToken, account: Did): Promise<Result<void, ApiError>> {
1561 return xrpcResult<void>('com.atproto.admin.enableAccountInvites', {
1562 method: 'POST',
1563 token,
1564 body: { account },
1565 })
1566 },
1567
1568 adminDeleteAccount(token: AccessToken, did: Did): Promise<Result<void, ApiError>> {
1569 return xrpcResult<void>('com.atproto.admin.deleteAccount', {
1570 method: 'POST',
1571 token,
1572 body: { did },
1573 })
1574 },
1575
1576 startPasskeyRegistration(
1577 token: AccessToken,
1578 friendlyName?: string
1579 ): Promise<Result<StartPasskeyRegistrationResponse, ApiError>> {
1580 return xrpcResult('com.atproto.server.startPasskeyRegistration', {
1581 method: 'POST',
1582 token,
1583 body: { friendlyName },
1584 })
1585 },
1586
1587 finishPasskeyRegistration(
1588 token: AccessToken,
1589 credential: unknown,
1590 friendlyName?: string
1591 ): Promise<Result<FinishPasskeyRegistrationResponse, ApiError>> {
1592 return xrpcResult('com.atproto.server.finishPasskeyRegistration', {
1593 method: 'POST',
1594 token,
1595 body: { credential, friendlyName },
1596 })
1597 },
1598
1599 updatePasskey(
1600 token: AccessToken,
1601 id: string,
1602 friendlyName: string
1603 ): Promise<Result<void, ApiError>> {
1604 return xrpcResult<void>('com.atproto.server.updatePasskey', {
1605 method: 'POST',
1606 token,
1607 body: { id, friendlyName },
1608 })
1609 },
1610
1611 regenerateBackupCodes(
1612 token: AccessToken,
1613 password: string,
1614 code: string
1615 ): Promise<Result<RegenerateBackupCodesResponse, ApiError>> {
1616 return xrpcResult('com.atproto.server.regenerateBackupCodes', {
1617 method: 'POST',
1618 token,
1619 body: { password, code },
1620 })
1621 },
1622
1623 updateLocale(token: AccessToken, preferredLocale: string): Promise<Result<UpdateLocaleResponse, ApiError>> {
1624 return xrpcResult('_account.updateLocale', {
1625 method: 'POST',
1626 token,
1627 body: { preferredLocale },
1628 })
1629 },
1630
1631 confirmChannelVerification(
1632 token: AccessToken,
1633 channel: string,
1634 identifier: string,
1635 code: string
1636 ): Promise<Result<SuccessResponse, ApiError>> {
1637 return xrpcResult('_account.confirmChannelVerification', {
1638 method: 'POST',
1639 token,
1640 body: { channel, identifier, code },
1641 })
1642 },
1643
1644 removePassword(token: AccessToken): Promise<Result<SuccessResponse, ApiError>> {
1645 return xrpcResult('_account.removePassword', {
1646 method: 'POST',
1647 token,
1648 })
1649 },
1650}