a tool for shared writing and social publishing

handle migrating users

+46 -4
+31 -4
app/api/inngest/functions/migrate_user_to_standard.ts
··· 44 }; 45 46 // Step 1: Verify OAuth session is valid 47 - await step.run("verify-oauth-session", async () => { 48 const result = await restoreOAuthSession(did); 49 if (!result.ok) { 50 - throw new Error( 51 - `Failed to restore OAuth session: ${result.error.message}`, 52 - ); 53 } 54 return { success: true }; 55 }); 56 57 // Step 2: Get user's pub.leaflet.publication records 58 const oldPublications = await step.run( ··· 471 // 2. External references (e.g., from other AT Proto apps) to old URIs continue to work 472 // 3. The normalization layer handles both schemas transparently for reads 473 // Old records are also kept on the user's PDS so existing AT-URI references remain valid. 474 475 return { 476 success: stats.errors.length === 0,
··· 44 }; 45 46 // Step 1: Verify OAuth session is valid 47 + const oauthValid = await step.run("verify-oauth-session", async () => { 48 const result = await restoreOAuthSession(did); 49 if (!result.ok) { 50 + // Mark identity as needing migration so we can retry later 51 + await supabaseServerClient 52 + .from("identities") 53 + .update({ 54 + metadata: { needsStandardSiteMigration: true }, 55 + }) 56 + .eq("atp_did", did); 57 + 58 + return { success: false, error: result.error.message }; 59 } 60 return { success: true }; 61 }); 62 + 63 + if (!oauthValid.success) { 64 + return { 65 + success: false, 66 + error: `Failed to restore OAuth session`, 67 + stats, 68 + publicationUriMap: {}, 69 + documentUriMap: {}, 70 + userSubscriptionUriMap: {}, 71 + }; 72 + } 73 74 // Step 2: Get user's pub.leaflet.publication records 75 const oldPublications = await step.run( ··· 488 // 2. External references (e.g., from other AT Proto apps) to old URIs continue to work 489 // 3. The normalization layer handles both schemas transparently for reads 490 // Old records are also kept on the user's PDS so existing AT-URI references remain valid. 491 + 492 + // Clear the migration flag on success 493 + if (stats.errors.length === 0) { 494 + await step.run("clear-migration-flag", async () => { 495 + await supabaseServerClient 496 + .from("identities") 497 + .update({ metadata: null }) 498 + .eq("atp_did", did); 499 + }); 500 + } 501 502 return { 503 success: stats.errors.length === 0,
+11
app/api/oauth/[route]/route.ts
··· 11 ActionAfterSignIn, 12 parseActionFromSearchParam, 13 } from "./afterSignInActions"; 14 15 type OauthRequestClientState = { 16 redirect: string | null; ··· 84 .single(); 85 identity = data; 86 } 87 let { data: token } = await supabaseServerClient 88 .from("email_auth_tokens") 89 .insert({
··· 11 ActionAfterSignIn, 12 parseActionFromSearchParam, 13 } from "./afterSignInActions"; 14 + import { inngest } from "app/api/inngest/client"; 15 16 type OauthRequestClientState = { 17 redirect: string | null; ··· 85 .single(); 86 identity = data; 87 } 88 + 89 + // Trigger migration if identity needs it 90 + const metadata = identity?.metadata as Record<string, unknown> | null; 91 + if (metadata?.needsStandardSiteMigration) { 92 + await inngest.send({ 93 + name: "user/migrate-to-standard", 94 + data: { did: session.did }, 95 + }); 96 + } 97 + 98 let { data: token } = await supabaseServerClient 99 .from("email_auth_tokens") 100 .insert({
+1
drizzle/schema.ts
··· 140 email: text("email"), 141 atp_did: text("atp_did"), 142 interface_state: jsonb("interface_state"), 143 }, 144 (table) => { 145 return {
··· 140 email: text("email"), 141 atp_did: text("atp_did"), 142 interface_state: jsonb("interface_state"), 143 + metadata: jsonb("metadata"), 144 }, 145 (table) => { 146 return {
+3
supabase/database.types.ts
··· 551 home_page: string 552 id: string 553 interface_state: Json | null 554 } 555 Insert: { 556 atp_did?: string | null ··· 559 home_page?: string 560 id?: string 561 interface_state?: Json | null 562 } 563 Update: { 564 atp_did?: string | null ··· 567 home_page?: string 568 id?: string 569 interface_state?: Json | null 570 } 571 Relationships: [ 572 {
··· 551 home_page: string 552 id: string 553 interface_state: Json | null 554 + metadata: Json | null 555 } 556 Insert: { 557 atp_did?: string | null ··· 560 home_page?: string 561 id?: string 562 interface_state?: Json | null 563 + metadata?: Json | null 564 } 565 Update: { 566 atp_did?: string | null ··· 569 home_page?: string 570 id?: string 571 interface_state?: Json | null 572 + metadata?: Json | null 573 } 574 Relationships: [ 575 {