Graphical PDS migrator for AT Protocol
1import { getSessionAgent } from "../../../lib/sessions.ts";
2import { checkDidsMatch } from "../../../lib/check-dids.ts";
3import { define } from "../../../utils.ts";
4import { assertMigrationAllowed } from "../../../lib/migration-state.ts";
5
6export const handler = define.handlers({
7 async POST(ctx) {
8 const res = new Response();
9 try {
10 // Check if migrations are currently allowed
11 assertMigrationAllowed();
12
13 const oldAgent = await getSessionAgent(ctx.req);
14 const newAgent = await getSessionAgent(ctx.req, res, true);
15
16 if (!oldAgent) return new Response("Unauthorized", { status: 401 });
17 if (!newAgent) {
18 return new Response("Migration session not found or invalid", {
19 status: 400,
20 });
21 }
22
23 // Verify DIDs match between sessions
24 const didsMatch = await checkDidsMatch(ctx.req);
25 if (!didsMatch) {
26 return new Response(
27 JSON.stringify({
28 success: false,
29 message: "Invalid state, original and target DIDs do not match",
30 }),
31 { status: 400, headers: { "Content-Type": "application/json" } },
32 );
33 }
34
35 // Activate new account and deactivate old account
36 await newAgent.com.atproto.server.activateAccount();
37 await oldAgent.com.atproto.server.deactivateAccount({});
38
39 return new Response(
40 JSON.stringify({
41 success: true,
42 message: "Migration finalized successfully",
43 }),
44 {
45 status: 200,
46 headers: {
47 "Content-Type": "application/json",
48 ...Object.fromEntries(res.headers), // Include session cookie headers
49 },
50 },
51 );
52 } catch (error) {
53 console.error("Finalize error:", error);
54 return new Response(
55 JSON.stringify({
56 success: false,
57 message: error instanceof Error
58 ? error.message
59 : "Failed to finalize migration",
60 }),
61 {
62 status: 400,
63 headers: { "Content-Type": "application/json" },
64 },
65 );
66 }
67 },
68});