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