Graphical PDS migrator for AT Protocol

fix: migrations failures due to duplicate PLC signature requests (#8)

* fix: allow dids as handle

* Fix duplicate identity migration requests and prevent auto-verification of step 2

- Remove redundant direct calls to next migration steps after verification
- Add duplicate call prevention in startIdentityMigration
- Skip automatic verification for identity migration step (requires manual token)
- Simplify control flow to use only verifyStep->continueToNextStep chain
- Fix issue where identity migration was being called multiple times causing errors

* Add proper verification after identity migration token submission

- Call /api/migrate/status after submitting identity token to verify success
- Add isManualSubmission parameter to verifyStep to allow verification for step 2 after token
- Update retryVerification to handle identity migration verification correctly
- Ensure identity migration is properly verified before continuing to finalization

authored by Turtlepaw and committed by GitHub 51920ada 4d62ca70

Changed files
+39 -17
islands
routes
api
cred
+30 -11
islands/MigrationProgress.tsx
··· 247 247 return; 248 248 } 249 249 250 - // If verification succeeds, continue to data migration 251 - await startDataMigration(); 250 + // verifyStep will handle continuing to the next step via continueToNextStep 251 + // No need to call startDataMigration here 252 252 } catch (error) { 253 253 updateStepStatus( 254 254 0, ··· 298 298 throw new Error("Invalid response from server"); 299 299 } 300 300 301 + // Verify the identity migration succeeded 301 302 updateStepStatus(2, "verifying"); 302 - const verified = await verifyStep(2); 303 + const verified = await verifyStep(2, true); // Pass true to allow verification for manual submission 303 304 if (!verified) { 304 305 console.log( 305 - "Identity migration: Verification failed, waiting for user action", 306 + "Identity migration: Verification failed after token submission", 306 307 ); 307 308 return; 308 309 } 309 - 310 - // If verification succeeds, continue to finalization 310 + 311 + // If verification succeeds, mark as completed and continue 312 + updateStepStatus(2, "completed"); 311 313 await startFinalization(); 312 314 } catch (error) { 313 315 console.error("Identity migration error:", error); ··· 396 398 }; 397 399 398 400 // Helper to verify a step after completion 399 - const verifyStep = async (stepNum: number) => { 401 + const verifyStep = async (stepNum: number, isManualSubmission: boolean = false) => { 400 402 console.log(`Verification: Starting step ${stepNum + 1}`); 403 + 404 + // Skip automatic verification for step 2 (identity migration) unless it's after manual token submission 405 + if (stepNum === 2 && !isManualSubmission) { 406 + console.log(`Verification: Skipping automatic verification for identity migration step`); 407 + return false; 408 + } 409 + 401 410 updateStepStatus(stepNum, "verifying"); 402 411 try { 403 412 console.log(`Verification: Fetching status for step ${stepNum + 1}`); ··· 481 490 482 491 const retryVerification = async (stepNum: number) => { 483 492 console.log(`Retrying verification for step ${stepNum + 1}`); 484 - await verifyStep(stepNum); 493 + // For identity migration step, pass true if it's after manual submission 494 + const isManualSubmission = stepNum === 2 && steps[2].name === "Enter the token sent to your email to complete identity migration"; 495 + await verifyStep(stepNum, isManualSubmission); 485 496 }; 486 497 487 498 const continueAnyway = (stepNum: number) => { ··· 601 612 return; 602 613 } 603 614 604 - // If verification succeeds, continue to next step 605 - await startIdentityMigration(); 615 + // verifyStep will handle continuing to the next step via continueToNextStep 616 + // No need to call startIdentityMigration here 606 617 } catch (error) { 607 618 console.error("Data migration: Error caught:", error); 608 619 updateStepStatus( ··· 616 627 617 628 const startIdentityMigration = async () => { 618 629 // Step 3: Request Identity Migration 630 + // Check if already in progress to prevent duplicate calls 631 + if (steps[2].status === "in-progress" || steps[2].status === "completed") { 632 + console.log("Identity migration already in progress or completed, skipping duplicate call"); 633 + return; 634 + } 635 + 619 636 updateStepStatus(2, "in-progress"); 620 637 console.log("Requesting identity migration..."); 621 638 ··· 663 680 : step 664 681 ) 665 682 ); 666 - // Don't continue with migration - wait for token input 683 + // Don't verify or continue - wait for token input 684 + // Skip automatic verification for identity migration step 685 + console.log("Identity migration: Waiting for user token input, skipping auto-verification"); 667 686 return; 668 687 } catch (e) { 669 688 console.error("Failed to parse identity request response:", e);
+9 -6
routes/api/cred/login.ts
··· 25 25 { 26 26 status: 400, 27 27 headers: { "Content-Type": "application/json" }, 28 - }, 28 + } 29 29 ); 30 30 } 31 31 32 32 console.log("Resolving handle:", handle); 33 - const did = await resolver.resolveHandleToDid(handle); 33 + const did = 34 + typeof handle == "string" && handle.startsWith("did:") 35 + ? handle 36 + : await resolver.resolveHandleToDid(handle); 34 37 const service = await resolver.resolveDidToPdsUrl(did); 35 38 console.log("Resolved service:", service); 36 39 ··· 42 45 }), 43 46 { 44 47 status: 400, 45 - }, 48 + } 46 49 ); 47 50 } 48 51 ··· 70 73 { 71 74 status: 200, 72 75 headers: { "Content-Type": "application/json" }, 73 - }, 76 + } 74 77 ); 75 78 76 79 // Create and save our client session with tokens ··· 100 103 { 101 104 status: 401, 102 105 headers: { "Content-Type": "application/json" }, 103 - }, 106 + } 104 107 ); 105 108 } 106 109 } catch (error) { ··· 114 117 { 115 118 status: 500, 116 119 headers: { "Content-Type": "application/json" }, 117 - }, 120 + } 118 121 ); 119 122 } 120 123 },