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 getPasswordStatus(token: AccessToken): Promise<PasswordStatus> {
544 return xrpc("_account.getPasswordStatus", { token });
545 },
546
547 getLegacyLoginPreference(token: AccessToken): Promise<LegacyLoginPreference> {
548 return xrpc("_account.getLegacyLoginPreference", { token });
549 },
550
551 updateLegacyLoginPreference(
552 token: AccessToken,
553 allowLegacyLogin: boolean,
554 ): Promise<UpdateLegacyLoginResponse> {
555 return xrpc("_account.updateLegacyLoginPreference", {
556 method: "POST",
557 token,
558 body: { allowLegacyLogin },
559 });
560 },
561
562 updateLocale(
563 token: AccessToken,
564 preferredLocale: string,
565 ): Promise<UpdateLocaleResponse> {
566 return xrpc("_account.updateLocale", {
567 method: "POST",
568 token,
569 body: { preferredLocale },
570 });
571 },
572
573 listSessions(token: AccessToken): Promise<ListSessionsResponse> {
574 return xrpc("_account.listSessions", { token });
575 },
576
577 async revokeSession(token: AccessToken, sessionId: string): Promise<void> {
578 await xrpc("_account.revokeSession", {
579 method: "POST",
580 token,
581 body: { sessionId },
582 });
583 },
584
585 revokeAllSessions(token: AccessToken): Promise<{ revokedCount: number }> {
586 return xrpc("_account.revokeAllSessions", {
587 method: "POST",
588 token,
589 });
590 },
591
592 searchAccounts(token: AccessToken, options?: {
593 handle?: string;
594 cursor?: string;
595 limit?: number;
596 }): Promise<SearchAccountsResponse> {
597 const params: Record<string, string> = {};
598 if (options?.handle) params.handle = options.handle;
599 if (options?.cursor) params.cursor = options.cursor;
600 if (options?.limit) params.limit = String(options.limit);
601 return xrpc("com.atproto.admin.searchAccounts", { token, params });
602 },
603
604 getInviteCodes(token: AccessToken, options?: {
605 sort?: "recent" | "usage";
606 cursor?: string;
607 limit?: number;
608 }): Promise<GetInviteCodesResponse> {
609 const params: Record<string, string> = {};
610 if (options?.sort) params.sort = options.sort;
611 if (options?.cursor) params.cursor = options.cursor;
612 if (options?.limit) params.limit = String(options.limit);
613 return xrpc("com.atproto.admin.getInviteCodes", { token, params });
614 },
615
616 async disableInviteCodes(
617 token: AccessToken,
618 codes?: string[],
619 accounts?: string[],
620 ): Promise<void> {
621 await xrpc("com.atproto.admin.disableInviteCodes", {
622 method: "POST",
623 token,
624 body: { codes, accounts },
625 });
626 },
627
628 getAccountInfo(token: AccessToken, did: Did): Promise<AccountInfo> {
629 return xrpc("com.atproto.admin.getAccountInfo", { token, params: { did } });
630 },
631
632 async disableAccountInvites(token: AccessToken, account: Did): Promise<void> {
633 await xrpc("com.atproto.admin.disableAccountInvites", {
634 method: "POST",
635 token,
636 body: { account },
637 });
638 },
639
640 async enableAccountInvites(token: AccessToken, account: Did): Promise<void> {
641 await xrpc("com.atproto.admin.enableAccountInvites", {
642 method: "POST",
643 token,
644 body: { account },
645 });
646 },
647
648 async adminDeleteAccount(token: AccessToken, did: Did): Promise<void> {
649 await xrpc("com.atproto.admin.deleteAccount", {
650 method: "POST",
651 token,
652 body: { did },
653 });
654 },
655
656 describeRepo(token: AccessToken, repo: Did): Promise<RepoDescription> {
657 return xrpc("com.atproto.repo.describeRepo", {
658 token,
659 params: { repo },
660 });
661 },
662
663 listRecords(token: AccessToken, repo: Did, collection: Nsid, options?: {
664 limit?: number;
665 cursor?: string;
666 reverse?: boolean;
667 }): Promise<ListRecordsResponse> {
668 const params: Record<string, string> = { repo, collection };
669 if (options?.limit) params.limit = String(options.limit);
670 if (options?.cursor) params.cursor = options.cursor;
671 if (options?.reverse) params.reverse = "true";
672 return xrpc("com.atproto.repo.listRecords", { token, params });
673 },
674
675 getRecord(
676 token: AccessToken,
677 repo: Did,
678 collection: Nsid,
679 rkey: Rkey,
680 ): Promise<RecordResponse> {
681 return xrpc("com.atproto.repo.getRecord", {
682 token,
683 params: { repo, collection, rkey },
684 });
685 },
686
687 createRecord(
688 token: AccessToken,
689 repo: Did,
690 collection: Nsid,
691 record: unknown,
692 rkey?: Rkey,
693 ): Promise<CreateRecordResponse> {
694 return xrpc("com.atproto.repo.createRecord", {
695 method: "POST",
696 token,
697 body: { repo, collection, record, rkey },
698 });
699 },
700
701 putRecord(
702 token: AccessToken,
703 repo: Did,
704 collection: Nsid,
705 rkey: Rkey,
706 record: unknown,
707 ): Promise<CreateRecordResponse> {
708 return xrpc("com.atproto.repo.putRecord", {
709 method: "POST",
710 token,
711 body: { repo, collection, rkey, record },
712 });
713 },
714
715 async deleteRecord(
716 token: AccessToken,
717 repo: Did,
718 collection: Nsid,
719 rkey: Rkey,
720 ): Promise<void> {
721 await xrpc("com.atproto.repo.deleteRecord", {
722 method: "POST",
723 token,
724 body: { repo, collection, rkey },
725 });
726 },
727
728 getTotpStatus(token: AccessToken): Promise<TotpStatus> {
729 return xrpc("com.atproto.server.getTotpStatus", { token });
730 },
731
732 createTotpSecret(token: AccessToken): Promise<TotpSecret> {
733 return xrpc("com.atproto.server.createTotpSecret", {
734 method: "POST",
735 token,
736 });
737 },
738
739 enableTotp(token: AccessToken, code: string): Promise<EnableTotpResponse> {
740 return xrpc("com.atproto.server.enableTotp", {
741 method: "POST",
742 token,
743 body: { code },
744 });
745 },
746
747 disableTotp(
748 token: AccessToken,
749 password: string,
750 code: string,
751 ): Promise<SuccessResponse> {
752 return xrpc("com.atproto.server.disableTotp", {
753 method: "POST",
754 token,
755 body: { password, code },
756 });
757 },
758
759 regenerateBackupCodes(
760 token: AccessToken,
761 password: string,
762 code: string,
763 ): Promise<RegenerateBackupCodesResponse> {
764 return xrpc("com.atproto.server.regenerateBackupCodes", {
765 method: "POST",
766 token,
767 body: { password, code },
768 });
769 },
770
771 startPasskeyRegistration(
772 token: AccessToken,
773 friendlyName?: string,
774 ): Promise<StartPasskeyRegistrationResponse> {
775 return xrpc("com.atproto.server.startPasskeyRegistration", {
776 method: "POST",
777 token,
778 body: { friendlyName },
779 });
780 },
781
782 finishPasskeyRegistration(
783 token: AccessToken,
784 credential: unknown,
785 friendlyName?: string,
786 ): Promise<FinishPasskeyRegistrationResponse> {
787 return xrpc("com.atproto.server.finishPasskeyRegistration", {
788 method: "POST",
789 token,
790 body: { credential, friendlyName },
791 });
792 },
793
794 listPasskeys(token: AccessToken): Promise<ListPasskeysResponse> {
795 return xrpc("com.atproto.server.listPasskeys", { token });
796 },
797
798 async deletePasskey(token: AccessToken, id: string): Promise<void> {
799 await xrpc("com.atproto.server.deletePasskey", {
800 method: "POST",
801 token,
802 body: { id },
803 });
804 },
805
806 async updatePasskey(
807 token: AccessToken,
808 id: string,
809 friendlyName: string,
810 ): Promise<void> {
811 await xrpc("com.atproto.server.updatePasskey", {
812 method: "POST",
813 token,
814 body: { id, friendlyName },
815 });
816 },
817
818 listTrustedDevices(token: AccessToken): Promise<ListTrustedDevicesResponse> {
819 return xrpc("_account.listTrustedDevices", { token });
820 },
821
822 revokeTrustedDevice(
823 token: AccessToken,
824 deviceId: string,
825 ): Promise<SuccessResponse> {
826 return xrpc("_account.revokeTrustedDevice", {
827 method: "POST",
828 token,
829 body: { deviceId },
830 });
831 },
832
833 updateTrustedDevice(
834 token: AccessToken,
835 deviceId: string,
836 friendlyName: string,
837 ): Promise<SuccessResponse> {
838 return xrpc("_account.updateTrustedDevice", {
839 method: "POST",
840 token,
841 body: { deviceId, friendlyName },
842 });
843 },
844
845 getReauthStatus(token: AccessToken): Promise<ReauthStatus> {
846 return xrpc("_account.getReauthStatus", { token });
847 },
848
849 reauthPassword(
850 token: AccessToken,
851 password: string,
852 ): Promise<ReauthResponse> {
853 return xrpc("_account.reauthPassword", {
854 method: "POST",
855 token,
856 body: { password },
857 });
858 },
859
860 reauthTotp(token: AccessToken, code: string): Promise<ReauthResponse> {
861 return xrpc("_account.reauthTotp", {
862 method: "POST",
863 token,
864 body: { code },
865 });
866 },
867
868 reauthPasskeyStart(token: AccessToken): Promise<ReauthPasskeyStartResponse> {
869 return xrpc("_account.reauthPasskeyStart", {
870 method: "POST",
871 token,
872 });
873 },
874
875 reauthPasskeyFinish(
876 token: AccessToken,
877 credential: unknown,
878 ): Promise<ReauthResponse> {
879 return xrpc("_account.reauthPasskeyFinish", {
880 method: "POST",
881 token,
882 body: { credential },
883 });
884 },
885
886 reserveSigningKey(did?: Did): Promise<ReserveSigningKeyResponse> {
887 return xrpc("com.atproto.server.reserveSigningKey", {
888 method: "POST",
889 body: { did },
890 });
891 },
892
893 getRecommendedDidCredentials(
894 token: AccessToken,
895 ): Promise<RecommendedDidCredentials> {
896 return xrpc("com.atproto.identity.getRecommendedDidCredentials", { token });
897 },
898
899 async activateAccount(token: AccessToken): Promise<void> {
900 await xrpc("com.atproto.server.activateAccount", {
901 method: "POST",
902 token,
903 });
904 },
905
906 async createPasskeyAccount(params: {
907 handle: Handle;
908 email?: EmailAddress;
909 inviteCode?: string;
910 didType?: DidType;
911 did?: Did;
912 signingKey?: string;
913 verificationChannel?: VerificationChannel;
914 discordId?: string;
915 telegramUsername?: string;
916 signalNumber?: string;
917 }, byodToken?: string): Promise<PasskeyAccountCreateResponse> {
918 const url = `${API_BASE}/_account.createPasskeyAccount`;
919 const headers: Record<string, string> = {
920 "Content-Type": "application/json",
921 };
922 if (byodToken) {
923 headers["Authorization"] = `Bearer ${byodToken}`;
924 }
925 const res = await fetch(url, {
926 method: "POST",
927 headers,
928 body: JSON.stringify(params),
929 });
930 if (!res.ok) {
931 const errData = await res.json().catch(() => ({
932 error: "Unknown",
933 message: res.statusText,
934 }));
935 throw new ApiError(res.status, errData.error, errData.message);
936 }
937 return res.json();
938 },
939
940 startPasskeyRegistrationForSetup(
941 did: Did,
942 setupToken: string,
943 friendlyName?: string,
944 ): Promise<StartPasskeyRegistrationResponse> {
945 return xrpc("_account.startPasskeyRegistrationForSetup", {
946 method: "POST",
947 body: { did, setupToken, friendlyName },
948 });
949 },
950
951 completePasskeySetup(
952 did: Did,
953 setupToken: string,
954 passkeyCredential: unknown,
955 passkeyFriendlyName?: string,
956 ): Promise<CompletePasskeySetupResponse> {
957 return xrpc("_account.completePasskeySetup", {
958 method: "POST",
959 body: { did, setupToken, passkeyCredential, passkeyFriendlyName },
960 });
961 },
962
963 requestPasskeyRecovery(email: EmailAddress): Promise<SuccessResponse> {
964 return xrpc("_account.requestPasskeyRecovery", {
965 method: "POST",
966 body: { email },
967 });
968 },
969
970 recoverPasskeyAccount(
971 did: Did,
972 recoveryToken: string,
973 newPassword: string,
974 ): Promise<SuccessResponse> {
975 return xrpc("_account.recoverPasskeyAccount", {
976 method: "POST",
977 body: { did, recoveryToken, newPassword },
978 });
979 },
980
981 verifyMigrationEmail(
982 token: string,
983 email: EmailAddress,
984 ): Promise<VerifyMigrationEmailResponse> {
985 return xrpc("com.atproto.server.verifyMigrationEmail", {
986 method: "POST",
987 body: { token, email },
988 });
989 },
990
991 resendMigrationVerification(
992 email: EmailAddress,
993 ): Promise<ResendMigrationVerificationResponse> {
994 return xrpc("com.atproto.server.resendMigrationVerification", {
995 method: "POST",
996 body: { email },
997 });
998 },
999
1000 verifyToken(
1001 token: string,
1002 identifier: string,
1003 accessToken?: AccessToken,
1004 ): Promise<VerifyTokenResponse> {
1005 return xrpc("_account.verifyToken", {
1006 method: "POST",
1007 body: { token, identifier },
1008 token: accessToken,
1009 });
1010 },
1011
1012 getDidDocument(token: AccessToken): Promise<DidDocument> {
1013 return xrpc("_account.getDidDocument", { token });
1014 },
1015
1016 updateDidDocument(
1017 token: AccessToken,
1018 params: {
1019 verificationMethods?: VerificationMethod[];
1020 alsoKnownAs?: string[];
1021 serviceEndpoint?: string;
1022 },
1023 ): Promise<SuccessResponse> {
1024 return xrpc("_account.updateDidDocument", {
1025 method: "POST",
1026 token,
1027 body: params,
1028 });
1029 },
1030
1031 async deactivateAccount(
1032 token: AccessToken,
1033 deleteAfter?: string,
1034 ): Promise<void> {
1035 await xrpc("com.atproto.server.deactivateAccount", {
1036 method: "POST",
1037 token,
1038 body: { deleteAfter },
1039 });
1040 },
1041
1042 async getRepo(token: AccessToken, did: Did): Promise<ArrayBuffer> {
1043 const url = `${API_BASE}/com.atproto.sync.getRepo?did=${
1044 encodeURIComponent(did)
1045 }`;
1046 const res = await fetch(url, {
1047 headers: { Authorization: `Bearer ${token}` },
1048 });
1049 if (!res.ok) {
1050 const errData = await res.json().catch(() => ({
1051 error: "Unknown",
1052 message: res.statusText,
1053 }));
1054 throw new ApiError(res.status, errData.error, errData.message);
1055 }
1056 return res.arrayBuffer();
1057 },
1058
1059 listBackups(token: AccessToken): Promise<ListBackupsResponse> {
1060 return xrpc("_backup.listBackups", { token });
1061 },
1062
1063 async getBackup(token: AccessToken, id: string): Promise<Blob> {
1064 const url = `${API_BASE}/_backup.getBackup?id=${encodeURIComponent(id)}`;
1065 const res = await fetch(url, {
1066 headers: { Authorization: `Bearer ${token}` },
1067 });
1068 if (!res.ok) {
1069 const errData = await res.json().catch(() => ({
1070 error: "Unknown",
1071 message: res.statusText,
1072 }));
1073 throw new ApiError(res.status, errData.error, errData.message);
1074 }
1075 return res.blob();
1076 },
1077
1078 createBackup(token: AccessToken): Promise<CreateBackupResponse> {
1079 return xrpc("_backup.createBackup", {
1080 method: "POST",
1081 token,
1082 });
1083 },
1084
1085 async deleteBackup(token: AccessToken, id: string): Promise<void> {
1086 await xrpc("_backup.deleteBackup", {
1087 method: "POST",
1088 token,
1089 params: { id },
1090 });
1091 },
1092
1093 setBackupEnabled(
1094 token: AccessToken,
1095 enabled: boolean,
1096 ): Promise<SetBackupEnabledResponse> {
1097 return xrpc("_backup.setEnabled", {
1098 method: "POST",
1099 token,
1100 body: { enabled },
1101 });
1102 },
1103
1104 async importRepo(token: AccessToken, car: Uint8Array): Promise<void> {
1105 const url = `${API_BASE}/com.atproto.repo.importRepo`;
1106 const res = await fetch(url, {
1107 method: "POST",
1108 headers: {
1109 Authorization: `Bearer ${token}`,
1110 "Content-Type": "application/vnd.ipld.car",
1111 },
1112 body: car as unknown as BodyInit,
1113 });
1114 if (!res.ok) {
1115 const errData = await res.json().catch(() => ({
1116 error: "Unknown",
1117 message: res.statusText,
1118 }));
1119 throw new ApiError(res.status, errData.error, errData.message);
1120 }
1121 },
1122};
1123
1124export const typedApi = {
1125 createSession(
1126 identifier: string,
1127 password: string,
1128 ): Promise<Result<Session, ApiError>> {
1129 return xrpcResult<Session>("com.atproto.server.createSession", {
1130 method: "POST",
1131 body: { identifier, password },
1132 }).then((r) => r.ok ? ok(castSession(r.value)) : r);
1133 },
1134
1135 getSession(token: AccessToken): Promise<Result<Session, ApiError>> {
1136 return xrpcResult<Session>("com.atproto.server.getSession", { token })
1137 .then((r) => r.ok ? ok(castSession(r.value)) : r);
1138 },
1139
1140 refreshSession(refreshJwt: RefreshToken): Promise<Result<Session, ApiError>> {
1141 return xrpcResult<Session>("com.atproto.server.refreshSession", {
1142 method: "POST",
1143 token: refreshJwt,
1144 }).then((r) => r.ok ? ok(castSession(r.value)) : r);
1145 },
1146
1147 describeServer(): Promise<Result<ServerDescription, ApiError>> {
1148 return xrpcResult("com.atproto.server.describeServer");
1149 },
1150
1151 listAppPasswords(
1152 token: AccessToken,
1153 ): Promise<Result<{ passwords: AppPassword[] }, ApiError>> {
1154 return xrpcResult("com.atproto.server.listAppPasswords", { token });
1155 },
1156
1157 createAppPassword(
1158 token: AccessToken,
1159 name: string,
1160 scopes?: string,
1161 ): Promise<Result<CreatedAppPassword, ApiError>> {
1162 return xrpcResult("com.atproto.server.createAppPassword", {
1163 method: "POST",
1164 token,
1165 body: { name, scopes },
1166 });
1167 },
1168
1169 revokeAppPassword(
1170 token: AccessToken,
1171 name: string,
1172 ): Promise<Result<void, ApiError>> {
1173 return xrpcResult<void>("com.atproto.server.revokeAppPassword", {
1174 method: "POST",
1175 token,
1176 body: { name },
1177 });
1178 },
1179
1180 listSessions(
1181 token: AccessToken,
1182 ): Promise<Result<ListSessionsResponse, ApiError>> {
1183 return xrpcResult("_account.listSessions", { token });
1184 },
1185
1186 revokeSession(
1187 token: AccessToken,
1188 sessionId: string,
1189 ): Promise<Result<void, ApiError>> {
1190 return xrpcResult<void>("_account.revokeSession", {
1191 method: "POST",
1192 token,
1193 body: { sessionId },
1194 });
1195 },
1196
1197 getTotpStatus(token: AccessToken): Promise<Result<TotpStatus, ApiError>> {
1198 return xrpcResult("com.atproto.server.getTotpStatus", { token });
1199 },
1200
1201 createTotpSecret(token: AccessToken): Promise<Result<TotpSecret, ApiError>> {
1202 return xrpcResult("com.atproto.server.createTotpSecret", {
1203 method: "POST",
1204 token,
1205 });
1206 },
1207
1208 enableTotp(
1209 token: AccessToken,
1210 code: string,
1211 ): Promise<Result<EnableTotpResponse, ApiError>> {
1212 return xrpcResult("com.atproto.server.enableTotp", {
1213 method: "POST",
1214 token,
1215 body: { code },
1216 });
1217 },
1218
1219 disableTotp(
1220 token: AccessToken,
1221 password: string,
1222 code: string,
1223 ): Promise<Result<SuccessResponse, ApiError>> {
1224 return xrpcResult("com.atproto.server.disableTotp", {
1225 method: "POST",
1226 token,
1227 body: { password, code },
1228 });
1229 },
1230
1231 listPasskeys(
1232 token: AccessToken,
1233 ): Promise<Result<ListPasskeysResponse, ApiError>> {
1234 return xrpcResult("com.atproto.server.listPasskeys", { token });
1235 },
1236
1237 deletePasskey(
1238 token: AccessToken,
1239 id: string,
1240 ): Promise<Result<void, ApiError>> {
1241 return xrpcResult<void>("com.atproto.server.deletePasskey", {
1242 method: "POST",
1243 token,
1244 body: { id },
1245 });
1246 },
1247
1248 listTrustedDevices(
1249 token: AccessToken,
1250 ): Promise<Result<ListTrustedDevicesResponse, ApiError>> {
1251 return xrpcResult("_account.listTrustedDevices", { token });
1252 },
1253
1254 getReauthStatus(token: AccessToken): Promise<Result<ReauthStatus, ApiError>> {
1255 return xrpcResult("_account.getReauthStatus", { token });
1256 },
1257
1258 getNotificationPrefs(
1259 token: AccessToken,
1260 ): Promise<Result<NotificationPrefs, ApiError>> {
1261 return xrpcResult("_account.getNotificationPrefs", { token });
1262 },
1263
1264 updateHandle(
1265 token: AccessToken,
1266 handle: Handle,
1267 ): Promise<Result<void, ApiError>> {
1268 return xrpcResult<void>("com.atproto.identity.updateHandle", {
1269 method: "POST",
1270 token,
1271 body: { handle },
1272 });
1273 },
1274
1275 describeRepo(
1276 token: AccessToken,
1277 repo: Did,
1278 ): Promise<Result<RepoDescription, ApiError>> {
1279 return xrpcResult("com.atproto.repo.describeRepo", {
1280 token,
1281 params: { repo },
1282 });
1283 },
1284
1285 listRecords(
1286 token: AccessToken,
1287 repo: Did,
1288 collection: Nsid,
1289 options?: { limit?: number; cursor?: string; reverse?: boolean },
1290 ): Promise<Result<ListRecordsResponse, ApiError>> {
1291 const params: Record<string, string> = { repo, collection };
1292 if (options?.limit) params.limit = String(options.limit);
1293 if (options?.cursor) params.cursor = options.cursor;
1294 if (options?.reverse) params.reverse = "true";
1295 return xrpcResult("com.atproto.repo.listRecords", { token, params });
1296 },
1297
1298 getRecord(
1299 token: AccessToken,
1300 repo: Did,
1301 collection: Nsid,
1302 rkey: Rkey,
1303 ): Promise<Result<RecordResponse, ApiError>> {
1304 return xrpcResult("com.atproto.repo.getRecord", {
1305 token,
1306 params: { repo, collection, rkey },
1307 });
1308 },
1309
1310 deleteRecord(
1311 token: AccessToken,
1312 repo: Did,
1313 collection: Nsid,
1314 rkey: Rkey,
1315 ): Promise<Result<void, ApiError>> {
1316 return xrpcResult<void>("com.atproto.repo.deleteRecord", {
1317 method: "POST",
1318 token,
1319 body: { repo, collection, rkey },
1320 });
1321 },
1322
1323 searchAccounts(
1324 token: AccessToken,
1325 options?: { handle?: string; cursor?: string; limit?: number },
1326 ): Promise<Result<SearchAccountsResponse, ApiError>> {
1327 const params: Record<string, string> = {};
1328 if (options?.handle) params.handle = options.handle;
1329 if (options?.cursor) params.cursor = options.cursor;
1330 if (options?.limit) params.limit = String(options.limit);
1331 return xrpcResult("com.atproto.admin.searchAccounts", { token, params });
1332 },
1333
1334 getAccountInfo(
1335 token: AccessToken,
1336 did: Did,
1337 ): Promise<Result<AccountInfo, ApiError>> {
1338 return xrpcResult("com.atproto.admin.getAccountInfo", {
1339 token,
1340 params: { did },
1341 });
1342 },
1343
1344 getServerStats(token: AccessToken): Promise<Result<ServerStats, ApiError>> {
1345 return xrpcResult("_admin.getServerStats", { token });
1346 },
1347
1348 listBackups(
1349 token: AccessToken,
1350 ): Promise<Result<ListBackupsResponse, ApiError>> {
1351 return xrpcResult("_backup.listBackups", { token });
1352 },
1353
1354 createBackup(
1355 token: AccessToken,
1356 ): Promise<Result<CreateBackupResponse, ApiError>> {
1357 return xrpcResult("_backup.createBackup", {
1358 method: "POST",
1359 token,
1360 });
1361 },
1362
1363 getDidDocument(token: AccessToken): Promise<Result<DidDocument, ApiError>> {
1364 return xrpcResult("_account.getDidDocument", { token });
1365 },
1366
1367 deleteSession(token: AccessToken): Promise<Result<void, ApiError>> {
1368 return xrpcResult<void>("com.atproto.server.deleteSession", {
1369 method: "POST",
1370 token,
1371 });
1372 },
1373
1374 revokeAllSessions(
1375 token: AccessToken,
1376 ): Promise<Result<{ revokedCount: number }, ApiError>> {
1377 return xrpcResult("_account.revokeAllSessions", {
1378 method: "POST",
1379 token,
1380 });
1381 },
1382
1383 getAccountInviteCodes(
1384 token: AccessToken,
1385 ): Promise<Result<{ codes: InviteCodeInfo[] }, ApiError>> {
1386 return xrpcResult("com.atproto.server.getAccountInviteCodes", { token });
1387 },
1388
1389 createInviteCode(
1390 token: AccessToken,
1391 useCount: number = 1,
1392 ): Promise<Result<{ code: string }, ApiError>> {
1393 return xrpcResult("com.atproto.server.createInviteCode", {
1394 method: "POST",
1395 token,
1396 body: { useCount },
1397 });
1398 },
1399
1400 changePassword(
1401 token: AccessToken,
1402 currentPassword: string,
1403 newPassword: string,
1404 ): Promise<Result<void, ApiError>> {
1405 return xrpcResult<void>("_account.changePassword", {
1406 method: "POST",
1407 token,
1408 body: { currentPassword, newPassword },
1409 });
1410 },
1411
1412 getPasswordStatus(
1413 token: AccessToken,
1414 ): Promise<Result<PasswordStatus, ApiError>> {
1415 return xrpcResult("_account.getPasswordStatus", { token });
1416 },
1417
1418 getServerConfig(): Promise<Result<ServerConfig, ApiError>> {
1419 return xrpcResult("_server.getConfig");
1420 },
1421
1422 getLegacyLoginPreference(
1423 token: AccessToken,
1424 ): Promise<Result<LegacyLoginPreference, ApiError>> {
1425 return xrpcResult("_account.getLegacyLoginPreference", { token });
1426 },
1427
1428 updateLegacyLoginPreference(
1429 token: AccessToken,
1430 allowLegacyLogin: boolean,
1431 ): Promise<Result<UpdateLegacyLoginResponse, ApiError>> {
1432 return xrpcResult("_account.updateLegacyLoginPreference", {
1433 method: "POST",
1434 token,
1435 body: { allowLegacyLogin },
1436 });
1437 },
1438
1439 getNotificationHistory(
1440 token: AccessToken,
1441 ): Promise<Result<NotificationHistoryResponse, ApiError>> {
1442 return xrpcResult("_account.getNotificationHistory", { token });
1443 },
1444
1445 updateNotificationPrefs(
1446 token: AccessToken,
1447 prefs: {
1448 preferredChannel?: string;
1449 discordId?: string;
1450 telegramUsername?: string;
1451 signalNumber?: string;
1452 },
1453 ): Promise<Result<SuccessResponse, ApiError>> {
1454 return xrpcResult("_account.updateNotificationPrefs", {
1455 method: "POST",
1456 token,
1457 body: prefs,
1458 });
1459 },
1460
1461 revokeTrustedDevice(
1462 token: AccessToken,
1463 deviceId: string,
1464 ): Promise<Result<SuccessResponse, ApiError>> {
1465 return xrpcResult("_account.revokeTrustedDevice", {
1466 method: "POST",
1467 token,
1468 body: { deviceId },
1469 });
1470 },
1471
1472 updateTrustedDevice(
1473 token: AccessToken,
1474 deviceId: string,
1475 friendlyName: string,
1476 ): Promise<Result<SuccessResponse, ApiError>> {
1477 return xrpcResult("_account.updateTrustedDevice", {
1478 method: "POST",
1479 token,
1480 body: { deviceId, friendlyName },
1481 });
1482 },
1483
1484 reauthPassword(
1485 token: AccessToken,
1486 password: string,
1487 ): Promise<Result<ReauthResponse, ApiError>> {
1488 return xrpcResult("_account.reauthPassword", {
1489 method: "POST",
1490 token,
1491 body: { password },
1492 });
1493 },
1494
1495 reauthTotp(
1496 token: AccessToken,
1497 code: string,
1498 ): Promise<Result<ReauthResponse, ApiError>> {
1499 return xrpcResult("_account.reauthTotp", {
1500 method: "POST",
1501 token,
1502 body: { code },
1503 });
1504 },
1505
1506 reauthPasskeyStart(
1507 token: AccessToken,
1508 ): Promise<Result<ReauthPasskeyStartResponse, ApiError>> {
1509 return xrpcResult("_account.reauthPasskeyStart", {
1510 method: "POST",
1511 token,
1512 });
1513 },
1514
1515 reauthPasskeyFinish(
1516 token: AccessToken,
1517 credential: unknown,
1518 ): Promise<Result<ReauthResponse, ApiError>> {
1519 return xrpcResult("_account.reauthPasskeyFinish", {
1520 method: "POST",
1521 token,
1522 body: { credential },
1523 });
1524 },
1525
1526 confirmSignup(
1527 did: Did,
1528 verificationCode: string,
1529 ): Promise<Result<ConfirmSignupResult, ApiError>> {
1530 return xrpcResult("com.atproto.server.confirmSignup", {
1531 method: "POST",
1532 body: { did, verificationCode },
1533 });
1534 },
1535
1536 resendVerification(
1537 did: Did,
1538 ): Promise<Result<{ success: boolean }, ApiError>> {
1539 return xrpcResult("com.atproto.server.resendVerification", {
1540 method: "POST",
1541 body: { did },
1542 });
1543 },
1544
1545 requestEmailUpdate(
1546 token: AccessToken,
1547 ): Promise<Result<EmailUpdateResponse, ApiError>> {
1548 return xrpcResult("com.atproto.server.requestEmailUpdate", {
1549 method: "POST",
1550 token,
1551 });
1552 },
1553
1554 updateEmail(
1555 token: AccessToken,
1556 email: string,
1557 emailToken?: string,
1558 ): Promise<Result<void, ApiError>> {
1559 return xrpcResult<void>("com.atproto.server.updateEmail", {
1560 method: "POST",
1561 token,
1562 body: { email, token: emailToken },
1563 });
1564 },
1565
1566 requestAccountDelete(token: AccessToken): Promise<Result<void, ApiError>> {
1567 return xrpcResult<void>("com.atproto.server.requestAccountDelete", {
1568 method: "POST",
1569 token,
1570 });
1571 },
1572
1573 deleteAccount(
1574 did: Did,
1575 password: string,
1576 deleteToken: string,
1577 ): Promise<Result<void, ApiError>> {
1578 return xrpcResult<void>("com.atproto.server.deleteAccount", {
1579 method: "POST",
1580 body: { did, password, token: deleteToken },
1581 });
1582 },
1583
1584 updateDidDocument(
1585 token: AccessToken,
1586 params: {
1587 verificationMethods?: VerificationMethod[];
1588 alsoKnownAs?: string[];
1589 serviceEndpoint?: string;
1590 },
1591 ): Promise<Result<SuccessResponse, ApiError>> {
1592 return xrpcResult("_account.updateDidDocument", {
1593 method: "POST",
1594 token,
1595 body: params,
1596 });
1597 },
1598
1599 deactivateAccount(
1600 token: AccessToken,
1601 deleteAfter?: string,
1602 ): Promise<Result<void, ApiError>> {
1603 return xrpcResult<void>("com.atproto.server.deactivateAccount", {
1604 method: "POST",
1605 token,
1606 body: { deleteAfter },
1607 });
1608 },
1609
1610 activateAccount(token: AccessToken): Promise<Result<void, ApiError>> {
1611 return xrpcResult<void>("com.atproto.server.activateAccount", {
1612 method: "POST",
1613 token,
1614 });
1615 },
1616
1617 setBackupEnabled(
1618 token: AccessToken,
1619 enabled: boolean,
1620 ): Promise<Result<SetBackupEnabledResponse, ApiError>> {
1621 return xrpcResult("_backup.setEnabled", {
1622 method: "POST",
1623 token,
1624 body: { enabled },
1625 });
1626 },
1627
1628 deleteBackup(
1629 token: AccessToken,
1630 id: string,
1631 ): Promise<Result<void, ApiError>> {
1632 return xrpcResult<void>("_backup.deleteBackup", {
1633 method: "POST",
1634 token,
1635 params: { id },
1636 });
1637 },
1638
1639 createRecord(
1640 token: AccessToken,
1641 repo: Did,
1642 collection: Nsid,
1643 record: unknown,
1644 rkey?: Rkey,
1645 ): Promise<Result<CreateRecordResponse, ApiError>> {
1646 return xrpcResult("com.atproto.repo.createRecord", {
1647 method: "POST",
1648 token,
1649 body: { repo, collection, record, rkey },
1650 });
1651 },
1652
1653 putRecord(
1654 token: AccessToken,
1655 repo: Did,
1656 collection: Nsid,
1657 rkey: Rkey,
1658 record: unknown,
1659 ): Promise<Result<CreateRecordResponse, ApiError>> {
1660 return xrpcResult("com.atproto.repo.putRecord", {
1661 method: "POST",
1662 token,
1663 body: { repo, collection, rkey, record },
1664 });
1665 },
1666
1667 getInviteCodes(
1668 token: AccessToken,
1669 options?: { sort?: "recent" | "usage"; cursor?: string; limit?: number },
1670 ): Promise<Result<GetInviteCodesResponse, ApiError>> {
1671 const params: Record<string, string> = {};
1672 if (options?.sort) params.sort = options.sort;
1673 if (options?.cursor) params.cursor = options.cursor;
1674 if (options?.limit) params.limit = String(options.limit);
1675 return xrpcResult("com.atproto.admin.getInviteCodes", { token, params });
1676 },
1677
1678 disableAccountInvites(
1679 token: AccessToken,
1680 account: Did,
1681 ): Promise<Result<void, ApiError>> {
1682 return xrpcResult<void>("com.atproto.admin.disableAccountInvites", {
1683 method: "POST",
1684 token,
1685 body: { account },
1686 });
1687 },
1688
1689 enableAccountInvites(
1690 token: AccessToken,
1691 account: Did,
1692 ): Promise<Result<void, ApiError>> {
1693 return xrpcResult<void>("com.atproto.admin.enableAccountInvites", {
1694 method: "POST",
1695 token,
1696 body: { account },
1697 });
1698 },
1699
1700 adminDeleteAccount(
1701 token: AccessToken,
1702 did: Did,
1703 ): Promise<Result<void, ApiError>> {
1704 return xrpcResult<void>("com.atproto.admin.deleteAccount", {
1705 method: "POST",
1706 token,
1707 body: { did },
1708 });
1709 },
1710
1711 startPasskeyRegistration(
1712 token: AccessToken,
1713 friendlyName?: string,
1714 ): Promise<Result<StartPasskeyRegistrationResponse, ApiError>> {
1715 return xrpcResult("com.atproto.server.startPasskeyRegistration", {
1716 method: "POST",
1717 token,
1718 body: { friendlyName },
1719 });
1720 },
1721
1722 finishPasskeyRegistration(
1723 token: AccessToken,
1724 credential: unknown,
1725 friendlyName?: string,
1726 ): Promise<Result<FinishPasskeyRegistrationResponse, ApiError>> {
1727 return xrpcResult("com.atproto.server.finishPasskeyRegistration", {
1728 method: "POST",
1729 token,
1730 body: { credential, friendlyName },
1731 });
1732 },
1733
1734 updatePasskey(
1735 token: AccessToken,
1736 id: string,
1737 friendlyName: string,
1738 ): Promise<Result<void, ApiError>> {
1739 return xrpcResult<void>("com.atproto.server.updatePasskey", {
1740 method: "POST",
1741 token,
1742 body: { id, friendlyName },
1743 });
1744 },
1745
1746 regenerateBackupCodes(
1747 token: AccessToken,
1748 password: string,
1749 code: string,
1750 ): Promise<Result<RegenerateBackupCodesResponse, ApiError>> {
1751 return xrpcResult("com.atproto.server.regenerateBackupCodes", {
1752 method: "POST",
1753 token,
1754 body: { password, code },
1755 });
1756 },
1757
1758 updateLocale(
1759 token: AccessToken,
1760 preferredLocale: string,
1761 ): Promise<Result<UpdateLocaleResponse, ApiError>> {
1762 return xrpcResult("_account.updateLocale", {
1763 method: "POST",
1764 token,
1765 body: { preferredLocale },
1766 });
1767 },
1768
1769 confirmChannelVerification(
1770 token: AccessToken,
1771 channel: string,
1772 identifier: string,
1773 code: string,
1774 ): Promise<Result<SuccessResponse, ApiError>> {
1775 return xrpcResult("_account.confirmChannelVerification", {
1776 method: "POST",
1777 token,
1778 body: { channel, identifier, code },
1779 });
1780 },
1781
1782 removePassword(
1783 token: AccessToken,
1784 ): Promise<Result<SuccessResponse, ApiError>> {
1785 return xrpcResult("_account.removePassword", {
1786 method: "POST",
1787 token,
1788 });
1789 },
1790};