Client side atproto account migrator in your web browser, along with services for backups and adversarial migrations. pdsmoover.com
pds atproto migrations moo cow

feat: various qols #9

merged opened by baileytownsend.dev targeting main from feat/batch-two-qol
  • By pass migrate blobs if it's a retry, does do migrate missing blobs so it does not miss any
  • UI Tweaks to hide inputs during migration along with a bit of a message on what to do if the migration fails
  • Moved blob uploads to shared logic for rate limits update later
Labels

None yet.

Participants 1
AT URI
at://did:plc:rnpkyqnmsw4ipey6eotbdnnf/sh.tangled.repo.pull/3mf6qdjs42n22
+872 -661
Diff #0
+1 -1
.oxlintrc.json
··· 1 1 { 2 2 "$schema": "https://unpkg.com/oxlint/configuration_schema.json", 3 - "plugins": ["unicorn", "typescript", "oxc", "vue", "vitest"], 3 + "plugins": ["unicorn", "typescript", "oxc"], 4 4 "jsPlugins": ["@e18e/eslint-plugin", "eslint-plugin-regexp"], 5 5 "categories": { 6 6 "correctness": "error",
+1 -1
justfile
··· 27 27 docker buildx build \ 28 28 --platform linux/arm64,linux/amd64 \ 29 29 --tag fatfingers23/moover_ui:latest \ 30 - --tag fatfingers23/moover_ui:0.0.7 \ 30 + --tag fatfingers23/moover_ui:0.0.8 \ 31 31 --file Dockerfiles/web-ui.Dockerfile \ 32 32 --builder desktop-linux \ 33 33 --push .
+64 -45
packages/moover/lib/pdsmoover.js
··· 32 32 this.migratePrefs = true 33 33 /** @type {boolean} */ 34 34 this.migratePlcRecord = true 35 + /** 36 + * How many blobs have been uploaded to the new PDS in the current step 37 + @type {number} */ 38 + this.uploadedBlobsCount = 0 39 + } 40 + 41 + /** 42 + * Uploads blobs to the new PDS 43 + * @param {AtpAgent} oldAgent 44 + * @param {AtpAgent} newAgent 45 + * @param {string} usersDid 46 + * @param {[string]} cids 47 + * @param {number} totalBlobs 48 + * @param {function|null} statusUpdateHandler 49 + */ 50 + async uploadBlobs(oldAgent, newAgent, usersDid, cids, totalBlobs, statusUpdateHandler) { 51 + for (const cid of cids) { 52 + try { 53 + const blobRes = await oldAgent.com.atproto.sync.getBlob({ 54 + did: usersDid, 55 + cid, 56 + }) 57 + await newAgent.com.atproto.repo.uploadBlob(blobRes.data, { 58 + encoding: blobRes.headers['content-type'], 59 + }) 60 + this.uploadedBlobsCount++ 61 + if (this.uploadedBlobsCount % 10 === 0) { 62 + safeStatusUpdate( 63 + statusUpdateHandler, 64 + `Migrating blobs: ${this.uploadedBlobsCount}/${totalBlobs}`, 65 + ) 66 + } 67 + } catch (error) { 68 + console.error(error) 69 + } 70 + } 35 71 } 36 72 37 73 /** ··· 61 97 twoFactorCode = null, 62 98 verificationCode = null, 63 99 ) { 64 - //Leaving this logic that either sets the agent to bsky.social, or the PDS since it's what I found worked best for migrations. 65 - // handleAndPDSResolver should be able to handle it, but there have been edge cases and this was what worked best 66 100 oldHandle = cleanHandle(oldHandle) 67 101 let oldAgent 68 102 let usersDid ··· 143 177 } catch (error) { 144 178 // Ideally should catch if the repo already exists, and if so silently log it and move along to the next step 145 179 if (error?.error === 'AlreadyExists') { 180 + // Sets the migrate blobs flag to false so it moves on to just migrate missing blobs in the event of a retry 181 + this.migrateBlobs = false 146 182 console.log('Repo already exists, logging in') 147 183 } else { 148 184 // Catches any other error and stops the migration process ··· 186 222 limit: 100, 187 223 }) 188 224 189 - for (const cid of listedBlobs.data.cids) { 190 - try { 191 - const blobRes = await oldAgent.com.atproto.sync.getBlob({ 192 - did: usersDid, 193 - cid, 194 - }) 195 - await newAgent.com.atproto.repo.uploadBlob(blobRes.data, { 196 - encoding: blobRes.headers['content-type'], 197 - }) 198 - uploadedBlobs++ 199 - if (uploadedBlobs % 10 === 0) { 200 - safeStatusUpdate( 201 - statusUpdateHandler, 202 - `Migrating blobs: ${uploadedBlobs}/${newAccountStatus.data.expectedBlobs}`, 203 - ) 204 - } 205 - } catch (error) { 206 - console.error(error) 207 - } 208 - } 225 + await this.uploadBlobs( 226 + oldAgent, 227 + newAgent, 228 + usersDid, 229 + listedBlobs.data.cids, 230 + newAccountStatus.data.expectedBlobs, 231 + statusUpdateHandler, 232 + ) 209 233 blobCursor = listedBlobs.data.cursor 210 234 } while (blobCursor) 235 + // Resets since this is a shared state with missing blobs job 236 + this.uploadedBlobsCount = 0 211 237 } 212 238 213 239 if (this.migrateMissingBlobs) { ··· 233 259 limit: 100, 234 260 }) 235 261 236 - for (const recordBlob of missingBlobs.data.blobs) { 237 - try { 238 - const blobRes = await oldAgent.com.atproto.sync.getBlob({ 239 - did: usersDid, 240 - cid: recordBlob.cid, 241 - }) 242 - await newAgent.com.atproto.repo.uploadBlob(blobRes.data, { 243 - encoding: blobRes.headers['content-type'], 244 - }) 245 - if (missingUploadedBlobs % 10 === 0) { 246 - safeStatusUpdate( 247 - statusUpdateHandler, 248 - `Migrating blobs: ${missingUploadedBlobs}/${totalMissingBlobs}`, 249 - ) 250 - } 251 - missingUploadedBlobs++ 252 - } catch (error) { 253 - //TODO silently logging prob should list them so user can manually download 254 - console.error(error) 255 - this.missingBlobs.push(recordBlob.cid) 256 - } 257 - } 262 + let missingCids = missingBlobs.data.blobs.map(blob => blob.cid) 263 + await this.uploadBlobs( 264 + oldAgent, 265 + newAgent, 266 + usersDid, 267 + missingCids, 268 + totalMissingBlobs, 269 + statusUpdateHandler, 270 + ) 271 + 258 272 missingBlobCursor = missingBlobs.data.cursor 259 273 } while (missingBlobCursor) 274 + // Resets since this is a shared state with the migrate blobs job 275 + this.uploadedBlobsCount = 0 260 276 } 261 277 } 262 278 if (this.migratePrefs) { ··· 269 285 270 286 if (this.migratePlcRecord) { 271 287 await oldAgent.com.atproto.identity.requestPlcOperationSignature() 272 - safeStatusUpdate(statusUpdateHandler, 'Please check your email for a PLC token') 288 + safeStatusUpdate( 289 + statusUpdateHandler, 290 + 'Please check your email attached to your previous account for a PLC token', 291 + ) 273 292 } 274 293 } 275 294
+3 -3
packages/moover/package.json
··· 1 1 { 2 2 "name": "@pds-moover/moover", 3 - "version": "1.0.6", 3 + "version": "1.0.7", 4 4 "description": "Utilities for ATProto PDS migrations and recovery", 5 5 "repository": { 6 6 "type": "git", ··· 34 34 "scripts": { 35 35 "dev": "vite", 36 36 "build": "vite build", 37 + "build:watch": "vite build --watch", 37 38 "gen:types": "tsc -p .", 38 - "preview": "vite preview", 39 - "generate:lexicons": "lex build --lexicons lexicons --out lib/lexicons --clear" 39 + "preview": "vite preview" 40 40 }, 41 41 "devDependencies": { 42 42 "eslint": "^9.34.0",
+10 -10
packages/moover/types/atprotoUtils.d.ts
··· 1 - export const handleResolver: CompositeHandleResolver 2 - export const docResolver: CompositeDidDocumentResolver<'plc' | 'web'> 1 + export const handleResolver: CompositeHandleResolver; 2 + export const docResolver: CompositeDidDocumentResolver<"plc" | "web">; 3 3 /** 4 4 * Cleans the handle of @ and some other unicode characters that used to show up when copied from the profile 5 5 * @param handle {string} 6 6 * @returns {string} 7 7 */ 8 - export function cleanHandle(handle: string): string 8 + export function cleanHandle(handle: string): string; 9 9 /** 10 10 * Convince helper to resolve a handle to a did and then find the PDS url from the did document. 11 11 * ··· 13 13 * @returns {Promise<{usersDid: string, pds: string}>} 14 14 */ 15 15 export function handleAndPDSResolver(handle: any): Promise<{ 16 - usersDid: string 17 - pds: string 18 - }> 16 + usersDid: string; 17 + pds: string; 18 + }>; 19 19 /** 20 20 * Fetches the DID Web from the .well-known/did.json endpoint of the server. 21 21 * Legacy and was helpful if the web ui and server are on the same domain, not as useful now 22 22 * @param baseUrl 23 23 * @returns {Promise<*>} 24 24 */ 25 - export function fetchPDSMooverDIDWeb(baseUrl: any): Promise<any> 26 - import { CompositeHandleResolver } from '@atcute/identity-resolver' 27 - import { CompositeDidDocumentResolver } from '@atcute/identity-resolver' 28 - //# sourceMappingURL=atprotoUtils.d.ts.map 25 + export function fetchPDSMooverDIDWeb(baseUrl: any): Promise<any>; 26 + import { CompositeHandleResolver } from '@atcute/identity-resolver'; 27 + import { CompositeDidDocumentResolver } from '@atcute/identity-resolver'; 28 + //# sourceMappingURL=atprotoUtils.d.ts.map
+1 -1
packages/moover/types/atprotoUtils.d.ts.map
··· 1 - {"version":3,"file":"atprotoUtils.d.ts","sourceRoot":"","sources":["../lib/atprotoUtils.js"],"names":[],"mappings":"AAOA,qDAQG;AAEH,sEAKG;AAEH;;;;GAIG;AACH,oCAHkB,MAAM,GACX,MAAM,CAMd;AAGL;;;;;GAKG;AACH,mDAFa,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,CAAC,CAqBpD;AAGD;;;;;GAKG;AACH,oDAFa,OAAO,CAAC,GAAC,CAAC,CAStB;wCAxEM,2BAA2B;6CAA3B,2BAA2B"} 1 + {"version":3,"file":"atprotoUtils.d.ts","sourceRoot":"","sources":["../lib/atprotoUtils.js"],"names":[],"mappings":"AASA,qDAQE;AAEF,sEAKE;AAkBF;;;;GAIG;AACH,oCAHkB,MAAM,GACX,MAAM,CAMyC;AAE5D;;;;;GAKG;AACH,mDAFa,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAC,CAAC,CA0BpD;AAED;;;;;GAKG;AACH,oDAFa,OAAO,CAAC,GAAC,CAAC,CAStB;wCA3FM,2BAA2B;6CAA3B,2BAA2B"}
+82 -89
packages/moover/types/backup.d.ts
··· 1 1 /** 2 2 * JSDoc type-only import to avoid runtime import errors in the browser. 3 3 */ 4 - export type InferXRPCBodyOutput = any 4 + export type InferXRPCBodyOutput = any; 5 5 /** 6 6 * JSDoc type-only import to avoid runtime import errors in the browser. 7 7 * @typedef {import('@atcute/lexicons').InferXRPCBodyOutput} InferXRPCBodyOutput ··· 10 10 * Logic to sign up and manage backups for pdsmoover.com (or your own selfhosted instance) 11 11 */ 12 12 export class BackupService { 13 - /** 14 - * 15 - * @param backupDidWeb {string} - The did:web for the xrpc service for backups, defaults to did:web:pdsmoover.com 16 - */ 17 - constructor(backupDidWeb?: string) 18 - /** 19 - * 20 - * @type {Client} 21 - */ 22 - atCuteClient: Client 23 - /** 24 - * 25 - * @type {CredentialManager} 26 - */ 27 - atCuteCredentialManager: CredentialManager 28 - /** 29 - * The did:web for the xrpc service for backups, defaults to pdsmoover.com 30 - * @type {string} 31 - */ 32 - backupDidWeb: string 33 - /** 34 - * Logs in and returns the backup status. 35 - * To use the rest of the BackupService, it is assumed that this has ran first, 36 - * and the user has successfully signed up. A successful login is a returned null if the user has not signed up. 37 - * or the backup status if they are 38 - * 39 - * If the server requires 2FA, 40 - * it will throw with error.error === 'AuthFactorTokenRequired'. 41 - * @param identifier {string} handle or did 42 - * @param password {string} 43 - * @param {function|null} onStatus - a function that takes a string used to update the UI. 44 - * Like (status) => console.log(status) 45 - * @param twoFactorCode {string|null} 46 - * 47 - * @returns {Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema['output']>|null>} 48 - */ 49 - loginAndStatus( 50 - identifier: string, 51 - password: string, 52 - onStatus?: Function | null, 53 - twoFactorCode?: string | null, 54 - ): Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema['output']> | null> 55 - /** 56 - * Signs the user up for backups with the service 57 - * @param onStatus 58 - * @returns {Promise<void>} 59 - */ 60 - signUp(onStatus?: any): Promise<void> 61 - /** 62 - * Requests a PLC token to be sent to the user's email, needed to add a new rotation key 63 - * @returns {Promise<void>} 64 - */ 65 - requestAPlcToken(): Promise<void> 66 - /** 67 - * Adds a new rotation to the users did document. Assumes you are already signed in. 68 - * 69 - * WARNING: This will overwrite any existing rotation keys with the new one at the top, and the PDS key as the second one 70 - * @param plcToken {string} - PLC token from the user's email that was sent from requestAPlcToken 71 - * @param rotationKey {string} - The new rotation key to add to the user's did document 72 - * @returns {Promise<void>} 73 - */ 74 - addANewRotationKey(plcToken: string, rotationKey: string): Promise<void> 75 - /** 76 - * 77 - * Gets the current status of the user's backup repository. 78 - * 79 - * @param onStatus {function|null} - a function that takes a string used to update the UI. 80 - * @returns {Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema['output']>>} 81 - */ 82 - getUsersRepoStatus( 83 - onStatus?: Function | null, 84 - ): Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema['output']>> 85 - /** 86 - * Requests a backup to be run immediately for the signed-in user. Usually does, depend on the server's backup queue 87 - * @param onStatus 88 - * @returns {Promise<boolean>} 89 - */ 90 - runBackupNow(onStatus?: any): Promise<boolean> 91 - /** 92 - * Remove (delete) the signed-in user's backup repository. this also deletes all the user's backup data. 93 - * @param onStatus 94 - * @returns {Promise<boolean>} 95 - */ 96 - removeRepo(onStatus?: any): Promise<boolean> 13 + /** 14 + * 15 + * @param backupDidWeb {string} - The did:web for the xrpc service for backups, defaults to did:web:pdsmoover.com 16 + */ 17 + constructor(backupDidWeb?: string); 18 + /** 19 + * 20 + * @type {Client} 21 + */ 22 + atCuteClient: Client; 23 + /** 24 + * 25 + * @type {CredentialManager} 26 + */ 27 + atCuteCredentialManager: CredentialManager; 28 + /** 29 + * The did:web for the xrpc service for backups, defaults to pdsmoover.com 30 + * @type {string} 31 + */ 32 + backupDidWeb: string; 33 + /** 34 + * Logs in and returns the backup status. 35 + * To use the rest of the BackupService, it is assumed that this has ran first, 36 + * and the user has successfully signed up. A successful login is a returned null if the user has not signed up. 37 + * or the backup status if they are 38 + * 39 + * If the server requires 2FA, 40 + * it will throw with error.error === 'AuthFactorTokenRequired'. 41 + * @param identifier {string} handle or did 42 + * @param password {string} 43 + * @param {function|null} onStatus - a function that takes a string used to update the UI. 44 + * Like (status) => console.log(status) 45 + * @param twoFactorCode {string|null} 46 + * 47 + * @returns {Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema['output']>|null>} 48 + */ 49 + loginAndStatus(identifier: string, password: string, onStatus?: Function | null, twoFactorCode?: string | null): Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema["output"]> | null>; 50 + /** 51 + * Signs the user up for backups with the service 52 + * @param onStatus 53 + * @returns {Promise<void>} 54 + */ 55 + signUp(onStatus?: any): Promise<void>; 56 + /** 57 + * Requests a PLC token to be sent to the user's email, needed to add a new rotation key 58 + * @returns {Promise<void>} 59 + */ 60 + requestAPlcToken(): Promise<void>; 61 + /** 62 + * Adds a new rotation to the users did document. Assumes you are already signed in. 63 + * 64 + * WARNING: This will overwrite any existing rotation keys with the new one at the top, and the PDS key as the second one 65 + * @param plcToken {string} - PLC token from the user's email that was sent from requestAPlcToken 66 + * @param rotationKey {string} - The new rotation key to add to the user's did document 67 + * @returns {Promise<void>} 68 + */ 69 + addANewRotationKey(plcToken: string, rotationKey: string): Promise<void>; 70 + /** 71 + * 72 + * Gets the current status of the user's backup repository. 73 + * 74 + * @param onStatus {function|null} - a function that takes a string used to update the UI. 75 + * @returns {Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema['output']>>} 76 + */ 77 + getUsersRepoStatus(onStatus?: Function | null): Promise<InferXRPCBodyOutput<ComPdsmooverBackupDescribeServer.mainSchema["output"]>>; 78 + /** 79 + * Requests a backup to be run immediately for the signed-in user. Usually does, depend on the server's backup queue 80 + * @param onStatus 81 + * @returns {Promise<boolean>} 82 + */ 83 + runBackupNow(onStatus?: any): Promise<boolean>; 84 + /** 85 + * Remove (delete) the signed-in user's backup repository. this also deletes all the user's backup data. 86 + * @param onStatus 87 + * @returns {Promise<boolean>} 88 + */ 89 + removeRepo(onStatus?: any): Promise<boolean>; 97 90 } 98 - import { Client } from '@atcute/client' 99 - import { CredentialManager } from '@atcute/client' 100 - import { ComPdsmooverBackupDescribeServer } from '@pds-moover/lexicons' 101 - //# sourceMappingURL=backup.d.ts.map 91 + import { Client } from '@atcute/client'; 92 + import { CredentialManager } from '@atcute/client'; 93 + import { ComPdsmooverBackupDescribeServer } from '@pds-moover/lexicons'; 94 + //# sourceMappingURL=backup.d.ts.map
+1 -1
packages/moover/types/backup.d.ts.map
··· 1 - {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../lib/backup.js"],"names":[],"mappings":";;;;AAKA;;;GAGG;AAGH;;GAEG;AACH;IACI;;;OAGG;IACH,2BAFwB,MAAM,EAmB7B;IAhBG;;;OAGG;IACH,cAFU,MAAM,CAEQ;IACxB;;;OAGG;IACH,yBAFU,iBAAiB,CAEQ;IAEnC;;;OAGG;IACH,cAFU,MAAM,CAEgB;IAIpC;;;;;;;;;;;;;;;OAeG;IACH,2BARsB,MAAM,YACR,MAAM,aACf,WAAS,IAAI,kBAEC,MAAM,GAAC,IAAI,GAEvB,OAAO,CAAC,mBAAmB,CAAC,gCAAgC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAC,IAAI,CAAC,CAyDpG;IAED;;;;OAIG;IACH,wBAFa,OAAO,CAAC,IAAI,CAAC,CAczB;IAED;;;OAGG;IACH,oBAFa,OAAO,CAAC,IAAI,CAAC,CAgBzB;IAED;;;;;;;OAOG;IACH,6BAJoB,MAAM,eACH,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAgDzB;IAGD;;;;;;OAMG;IACH,8BAHoB,WAAS,IAAI,GACpB,OAAO,CAAC,mBAAmB,CAAC,gCAAgC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAe/F;IAED;;;;OAIG;IACH,8BAFa,OAAO,CAAC,OAAO,CAAC,CAkB5B;IAED;;;;OAIG;IACH,4BAFa,OAAO,CAAC,OAAO,CAAC,CAe5B;CACJ;uBAhR2C,gBAAgB;kCAAhB,gBAAgB;iDAGb,sBAAsB"} 1 + {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../lib/backup.js"],"names":[],"mappings":";;;;AAKA;;;GAGG;AAEH;;GAEG;AACH;IACE;;;OAGG;IACH,2BAFwB,MAAM,EAmB7B;IAhBC;;;OAGG;IACH,cAFU,MAAM,CAEQ;IACxB;;;OAGG;IACH,yBAFU,iBAAiB,CAEQ;IAEnC;;;OAGG;IACH,cAFU,MAAM,CAEgB;IAGlC;;;;;;;;;;;;;;;OAeG;IACH,2BARsB,MAAM,YACR,MAAM,aACf,WAAS,IAAI,kBAEC,MAAM,GAAC,IAAI,GAEvB,OAAO,CAAC,mBAAmB,CAAC,gCAAgC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAC,IAAI,CAAC,CAoDpG;IAED;;;;OAIG;IACH,wBAFa,OAAO,CAAC,IAAI,CAAC,CAczB;IAED;;;OAGG;IACH,oBAFa,OAAO,CAAC,IAAI,CAAC,CAgBzB;IAED;;;;;;;OAOG;IACH,6BAJoB,MAAM,eACH,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA4CzB;IAED;;;;;;OAMG;IACH,8BAHoB,WAAS,IAAI,GACpB,OAAO,CAAC,mBAAmB,CAAC,gCAAgC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAe/F;IAED;;;;OAIG;IACH,8BAFa,OAAO,CAAC,OAAO,CAAC,CAwB5B;IAED;;;;OAIG;IACH,4BAFa,OAAO,CAAC,OAAO,CAAC,CAkB5B;CACF;uBA7Q6C,gBAAgB;kCAAhB,gBAAgB;iDAGb,sBAAsB"}
+8 -8
packages/moover/types/main.d.ts
··· 1 - import { Migrator } from './pdsmoover.js' 2 - import { MissingBlobs } from './missingBlobs.js' 3 - import { BackupService } from './backup.js' 4 - import { PlcOps } from './plc-ops.js' 5 - import { Restore } from './restore.js' 6 - import { handleAndPDSResolver } from './atprotoUtils.js' 7 - export { Migrator, MissingBlobs, BackupService, PlcOps, Restore, handleAndPDSResolver } 8 - //# sourceMappingURL=main.d.ts.map 1 + import { Migrator } from './pdsmoover.js'; 2 + import { MissingBlobs } from './missingBlobs.js'; 3 + import { BackupService } from './backup.js'; 4 + import { PlcOps } from './plc-ops.js'; 5 + import { Restore } from './restore.js'; 6 + import { handleAndPDSResolver } from './atprotoUtils.js'; 7 + export { Migrator, MissingBlobs, BackupService, PlcOps, Restore, handleAndPDSResolver }; 8 + //# sourceMappingURL=main.d.ts.map
+1 -1
packages/moover/types/main.d.ts.map
··· 1 - {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../lib/main.js"],"names":[],"mappings":"yBAAuB,gBAAgB;6BACZ,mBAAmB;8BAClB,aAAa;uBACpB,cAAc;wBACb,cAAc;qCACD,mBAAmB"} 1 + {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../lib/main.js"],"names":[],"mappings":"yBAAyB,gBAAgB;6BACZ,mBAAmB;8BAClB,aAAa;uBACpB,cAAc;wBACb,cAAc;qCACD,mBAAmB"}
+57 -65
packages/moover/types/missingBlobs.d.ts
··· 2 2 * Class to help find missing blobs from the did's previous PDS and import them into the current PDS 3 3 */ 4 4 export class MissingBlobs { 5 - /** 6 - * The user's current PDS agent 7 - * @type {AtpAgent} 8 - */ 9 - currentPdsAgent: AtpAgent 10 - /** 11 - * The user's old PDS agent 12 - * @type {AtpAgent} 13 - */ 14 - oldPdsAgent: AtpAgent 15 - /** 16 - * the user's did 17 - * @type {string|null} 18 - */ 19 - did: string | null 20 - /** 21 - * The user's current PDS url 22 - * @type {null} 23 - */ 24 - currentPdsUrl: any 25 - /** 26 - * A list of the missing cids blobs from the old PDS. In this case if a retry upload fails it gets put in this array for the ui 27 - * @type {string[]} 28 - */ 29 - missingBlobs: string[] 30 - /** 31 - * Logs the user into the current PDS and gets the account status 32 - * @param handle {string} 33 - * @param password {string} 34 - * @param twoFactorCode {string|null} 35 - * @returns {Promise<{accountStatus: OutputSchema, missingBlobsCount: number}>} 36 - */ 37 - currentAgentLogin( 38 - handle: string, 39 - password: string, 40 - twoFactorCode?: string | null, 41 - ): Promise<{ 42 - accountStatus: OutputSchema 43 - missingBlobsCount: number 44 - }> 45 - /** 46 - * Logs into the old PDS and gets the account status. 47 - * Does not need a handle 48 - * since it is assumed the user has already logged in with the current PDS and we are using their did 49 - * @param password {string} 50 - * @param twoFactorCode {string|null} 51 - * @param pdsUrl {string|null} - If you know the url of the old PDS you can pass it in here. If not it will be guessed at from plc ops 52 - * @returns {Promise<void>} 53 - */ 54 - oldAgentLogin( 55 - password: string, 56 - twoFactorCode?: string | null, 57 - pdsUrl?: string | null, 58 - ): Promise<void> 59 - /** 60 - * Gets the missing blobs from the old PDS and uploads them to the current PDS 61 - * @param statusUpdateHandler {function} - A function to update the status of the migration. This is useful for showing the user the progress of the migration 62 - * @returns {Promise<{accountStatus: OutputSchema, missingBlobsCount: number}>} 63 - */ 64 - migrateMissingBlobs(statusUpdateHandler: Function): Promise<{ 65 - accountStatus: OutputSchema 66 - missingBlobsCount: number 67 - }> 5 + /** 6 + * The user's current PDS agent 7 + * @type {AtpAgent} 8 + */ 9 + currentPdsAgent: AtpAgent; 10 + /** 11 + * The user's old PDS agent 12 + * @type {AtpAgent} 13 + */ 14 + oldPdsAgent: AtpAgent; 15 + /** 16 + * the user's did 17 + * @type {string|null} 18 + */ 19 + did: string | null; 20 + /** 21 + * The user's current PDS url 22 + * @type {null} 23 + */ 24 + currentPdsUrl: any; 25 + /** 26 + * A list of the missing cids blobs from the old PDS. In this case if a retry upload fails it gets put in this array for the ui 27 + * @type {string[]} 28 + */ 29 + missingBlobs: string[]; 30 + /** 31 + * Logs the user into the current PDS and gets the account status 32 + * @param handle {string} 33 + * @param password {string} 34 + * @param twoFactorCode {string|null} 35 + * @returns {Promise<{accountStatus: OutputSchema, missingBlobsCount: number}>} 36 + */ 37 + currentAgentLogin(handle: string, password: string, twoFactorCode?: string | null): Promise<{ 38 + accountStatus: OutputSchema; 39 + missingBlobsCount: number; 40 + }>; 41 + /** 42 + * Logs into the old PDS and gets the account status. 43 + * Does not need a handle 44 + * since it is assumed the user has already logged in with the current PDS and we are using their did 45 + * @param password {string} 46 + * @param twoFactorCode {string|null} 47 + * @param pdsUrl {string|null} - If you know the url of the old PDS you can pass it in here. If not it will be guessed at from plc ops 48 + * @returns {Promise<void>} 49 + */ 50 + oldAgentLogin(password: string, twoFactorCode?: string | null, pdsUrl?: string | null): Promise<void>; 51 + /** 52 + * Gets the missing blobs from the old PDS and uploads them to the current PDS 53 + * @param statusUpdateHandler {function} - A function to update the status of the migration. This is useful for showing the user the progress of the migration 54 + * @returns {Promise<{accountStatus: OutputSchema, missingBlobsCount: number}>} 55 + */ 56 + migrateMissingBlobs(statusUpdateHandler: Function): Promise<{ 57 + accountStatus: OutputSchema; 58 + missingBlobsCount: number; 59 + }>; 68 60 } 69 - import { AtpAgent } from '@atproto/api' 70 - //# sourceMappingURL=missingBlobs.d.ts.map 61 + import { AtpAgent } from '@atproto/api'; 62 + //# sourceMappingURL=missingBlobs.d.ts.map
+1 -1
packages/moover/types/missingBlobs.d.ts.map
··· 1 - {"version":3,"file":"missingBlobs.d.ts","sourceRoot":"","sources":["../lib/missingBlobs.js"],"names":[],"mappings":"AAIA;;GAEG;AACH;IAGQ;;;OAGG;IACH,iBAFU,QAAQ,CAES;IAC3B;;;OAGG;IACH,aAFU,QAAQ,CAEK;IACvB;;;OAGG;IACH,KAFU,MAAM,GAAC,IAAI,CAEN;IACf;;;OAGG;IACH,mBAAyB;IACzB;;;OAGG;IACH,cAFU,MAAM,EAAE,CAEI;IAI1B;;;;;;OAMG;IACH,0BALkB,MAAM,YACJ,MAAM,kBACD,MAAM,GAAC,IAAI,GACvB,OAAO,CAAC;QAAC,aAAa,EAAE,YAAY,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAC,CAAC,CA2B7E;IAED;;;;;;;;OAQG;IACH,wBALoB,MAAM,kBACD,MAAM,GAAC,IAAI,WAClB,MAAM,GAAC,IAAI,GAChB,OAAO,CAAC,IAAI,CAAC,CA+CzB;IAED;;;;OAIG;IACH,oDAFa,OAAO,CAAC;QAAC,aAAa,EAAE,YAAY,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAC,CAAC,CAyD7E;CAEJ;yBA9LsB,cAAc"} 1 + {"version":3,"file":"missingBlobs.d.ts","sourceRoot":"","sources":["../lib/missingBlobs.js"],"names":[],"mappings":"AAGA;;GAEG;AACH;IAEI;;;OAGG;IACH,iBAFU,QAAQ,CAES;IAC3B;;;OAGG;IACH,aAFU,QAAQ,CAEK;IACvB;;;OAGG;IACH,KAFU,MAAM,GAAC,IAAI,CAEN;IACf;;;OAGG;IACH,mBAAyB;IACzB;;;OAGG;IACH,cAFU,MAAM,EAAE,CAEI;IAGxB;;;;;;OAMG;IACH,0BALkB,MAAM,YACJ,MAAM,kBACD,MAAM,GAAC,IAAI,GACvB,OAAO,CAAC;QAAC,aAAa,EAAE,YAAY,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAC,CAAC,CA2B7E;IAED;;;;;;;;OAQG;IACH,wBALoB,MAAM,kBACD,MAAM,GAAC,IAAI,WAClB,MAAM,GAAC,IAAI,GAChB,OAAO,CAAC,IAAI,CAAC,CA+CzB;IAED;;;;OAIG;IACH,oDAFa,OAAO,CAAC;QAAC,aAAa,EAAE,YAAY,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAA;KAAC,CAAC,CAyD7E;CACF;yBA1LwB,cAAc"}
+78 -79
packages/moover/types/pdsmoover.d.ts
··· 3 3 * On pdsmoover.com this is the logic for the MOOver 4 4 */ 5 5 export class Migrator { 6 - /** @type {AtpAgent} */ 7 - oldAgent: AtpAgent 8 - /** @type {AtpAgent} */ 9 - newAgent: AtpAgent 10 - /** @type {[string]} */ 11 - missingBlobs: [string] 12 - /** @type {boolean} */ 13 - createNewAccount: boolean 14 - /** @type {boolean} */ 15 - migrateRepo: boolean 16 - /** @type {boolean} */ 17 - migrateBlobs: boolean 18 - /** @type {boolean} */ 19 - migrateMissingBlobs: boolean 20 - /** @type {boolean} */ 21 - migratePrefs: boolean 22 - /** @type {boolean} */ 23 - migratePlcRecord: boolean 24 - /** 25 - * This migrator is pretty cut and dry and makes a few assumptions 26 - * 1. You are using the same password between each account 27 - * 2. If this command fails for something like oauth 2fa code it throws an error and expects the same values when ran again. 28 - * 3. You can control which "actions" happen by setting the class variables to false. 29 - * 4. Each instance of the class is assumed to be for a single migration 30 - * @param {string} oldHandle - The handle you use on your old pds, something like alice.bsky.social 31 - * @param {string} password - Your password for your current login. Has to be your real password, no app password. When setting up a new account we reuse it as well for that account 32 - * @param {string} newPdsUrl - The new URL for your pds. Like https://coolnewpds.com 33 - * @param {string} newEmail - The email you want to use on the new pds (can be the same as the previous one as long as it's not already being used on the new pds) 34 - * @param {string} newHandle - The new handle you want, like alice.bsky.social, or if you already have a domain name set as a handle can use it myname.com. 35 - * @param {string|null} inviteCode - The invite code you got from the PDS you are migrating to. If null does not include one 36 - * @param {function|null} statusUpdateHandler - a function that takes a string used to update the UI. Like (status) => console.log(status) 37 - * @param {string|null} twoFactorCode - Optional, but needed if it fails with 2fa required 38 - * @param verificationCode - Optional verification captcha code for account creation if the PDS requires it 39 - */ 40 - migrate( 41 - oldHandle: string, 42 - password: string, 43 - newPdsUrl: string, 44 - newEmail: string, 45 - newHandle: string, 46 - inviteCode: string | null, 47 - statusUpdateHandler?: Function | null, 48 - twoFactorCode?: string | null, 49 - verificationCode?: any, 50 - ): Promise<void> 51 - /** 52 - * Sign and submits the PLC operation to officially migrate the account 53 - * @param {string} token - the PLC token sent in the email. If you're just wanting to run this rerun migrate with all the flags set as false except for migratePlcRecord 54 - * @param additionalRotationKeysToAdd {string[]} - additional rotation keys to add in addition to the ones provided by the new PDS. 55 - * @returns {Promise<void>} 56 - */ 57 - signPlcOperation(token: string, additionalRotationKeysToAdd?: string[]): Promise<void> 58 - /** 59 - * Using this method assumes the Migrator class was constructed new and this was called. 60 - * Find the user's previous PDS from the PLC op logs, 61 - * logs in and deactivates their old account if it was found still active. 62 - * 63 - * @param oldHandle {string} 64 - * @param oldPassword {string} 65 - * @param {function|null} statusUpdateHandler - a function that takes a string used to update the UI. 66 - * Like (status) => console.log(status) 67 - * @param {string|null} twoFactorCode - Optional, but needed if it fails with 2fa required 68 - * @returns {Promise<void>} 69 - */ 70 - deactivateOldAccount( 71 - oldHandle: string, 72 - oldPassword: string, 73 - statusUpdateHandler?: Function | null, 74 - twoFactorCode?: string | null, 75 - ): Promise<void> 76 - /** 77 - * Signs the logged-in user in this.newAgent for backups with PDS MOOver. This is usually called after migrate and signPlcOperation are successful 78 - * 79 - * @param {string} didWeb 80 - * @returns {Promise<void>} 81 - */ 82 - signUpForBackupsFromMigration(didWeb?: string): Promise<void> 6 + /** @type {AtpAgent} */ 7 + oldAgent: AtpAgent; 8 + /** @type {AtpAgent} */ 9 + newAgent: AtpAgent; 10 + /** @type {[string]} */ 11 + missingBlobs: [string]; 12 + /** @type {boolean} */ 13 + createNewAccount: boolean; 14 + /** @type {boolean} */ 15 + migrateRepo: boolean; 16 + /** @type {boolean} */ 17 + migrateBlobs: boolean; 18 + /** @type {boolean} */ 19 + migrateMissingBlobs: boolean; 20 + /** @type {boolean} */ 21 + migratePrefs: boolean; 22 + /** @type {boolean} */ 23 + migratePlcRecord: boolean; 24 + /** 25 + * How many blobs have been uploaded to the new PDS in the current step 26 + @type {number} */ 27 + uploadedBlobsCount: number; 28 + /** 29 + * Uploads blobs to the new PDS 30 + * @param {AtpAgent} oldAgent 31 + * @param {AtpAgent} newAgent 32 + * @param {string} usersDid 33 + * @param {[string]} cids 34 + * @param {number} totalBlobs 35 + * @param {function|null} statusUpdateHandler 36 + */ 37 + uploadBlobs(oldAgent: AtpAgent, newAgent: AtpAgent, usersDid: string, cids: [string], totalBlobs: number, statusUpdateHandler: Function | null): Promise<void>; 38 + /** 39 + * This migrator is pretty cut and dry and makes a few assumptions 40 + * 1. You are using the same password between each account 41 + * 2. If this command fails for something like oauth 2fa code it throws an error and expects the same values when ran again. 42 + * 3. You can control which "actions" happen by setting the class variables to false. 43 + * 4. Each instance of the class is assumed to be for a single migration 44 + * @param {string} oldHandle - The handle you use on your old pds, something like alice.bsky.social 45 + * @param {string} password - Your password for your current login. Has to be your real password, no app password. When setting up a new account we reuse it as well for that account 46 + * @param {string} newPdsUrl - The new URL for your pds. Like https://coolnewpds.com 47 + * @param {string} newEmail - The email you want to use on the new pds (can be the same as the previous one as long as it's not already being used on the new pds) 48 + * @param {string} newHandle - The new handle you want, like alice.bsky.social, or if you already have a domain name set as a handle can use it myname.com. 49 + * @param {string|null} inviteCode - The invite code you got from the PDS you are migrating to. If null does not include one 50 + * @param {function|null} statusUpdateHandler - a function that takes a string used to update the UI. Like (status) => console.log(status) 51 + * @param {string|null} twoFactorCode - Optional, but needed if it fails with 2fa required 52 + * @param verificationCode - Optional verification captcha code for account creation if the PDS requires it 53 + */ 54 + migrate(oldHandle: string, password: string, newPdsUrl: string, newEmail: string, newHandle: string, inviteCode: string | null, statusUpdateHandler?: Function | null, twoFactorCode?: string | null, verificationCode?: any): Promise<void>; 55 + /** 56 + * Sign and submits the PLC operation to officially migrate the account 57 + * @param {string} token - the PLC token sent in the email. If you're just wanting to run this rerun migrate with all the flags set as false except for migratePlcRecord 58 + * @param additionalRotationKeysToAdd {string[]} - additional rotation keys to add in addition to the ones provided by the new PDS. 59 + * @returns {Promise<void>} 60 + */ 61 + signPlcOperation(token: string, additionalRotationKeysToAdd?: string[]): Promise<void>; 62 + /** 63 + * Using this method assumes the Migrator class was constructed new and this was called. 64 + * Find the user's previous PDS from the PLC op logs, 65 + * logs in and deactivates their old account if it was found still active. 66 + * 67 + * @param oldHandle {string} 68 + * @param oldPassword {string} 69 + * @param {function|null} statusUpdateHandler - a function that takes a string used to update the UI. 70 + * Like (status) => console.log(status) 71 + * @param {string|null} twoFactorCode - Optional, but needed if it fails with 2fa required 72 + * @returns {Promise<void>} 73 + */ 74 + deactivateOldAccount(oldHandle: string, oldPassword: string, statusUpdateHandler?: Function | null, twoFactorCode?: string | null): Promise<void>; 75 + /** 76 + * Signs the logged-in user in this.newAgent for backups with PDS MOOver. This is usually called after migrate and signPlcOperation are successful 77 + * 78 + * @param {string} didWeb 79 + * @returns {Promise<void>} 80 + */ 81 + signUpForBackupsFromMigration(didWeb?: string): Promise<void>; 83 82 } 84 - import { AtpAgent } from '@atproto/api' 85 - //# sourceMappingURL=pdsmoover.d.ts.map 83 + import { AtpAgent } from '@atproto/api'; 84 + //# sourceMappingURL=pdsmoover.d.ts.map
+1 -1
packages/moover/types/pdsmoover.d.ts.map
··· 1 - {"version":3,"file":"pdsmoover.d.ts","sourceRoot":"","sources":["../lib/pdsmoover.js"],"names":[],"mappings":"AAUA;;;GAGG;AACH;IAEQ,uBAAuB;IACvB,UADW,QAAQ,CACC;IACpB,uBAAuB;IACvB,UADW,QAAQ,CACC;IACpB,uBAAuB;IACvB,cADW,CAAC,MAAM,CAAC,CACG;IAEtB,sBAAsB;IACtB,kBADW,OAAO,CACU;IAC5B,sBAAsB;IACtB,aADW,OAAO,CACK;IACvB,sBAAsB;IACtB,cADW,OAAO,CACM;IACxB,sBAAsB;IACtB,qBADW,OAAO,CACa;IAC/B,sBAAsB;IACtB,cADW,OAAO,CACM;IACxB,sBAAsB;IACtB,kBADW,OAAO,CACU;IAGhC;;;;;;;;;;;;;;;OAeG;IACH,mBAVW,MAAM,YACN,MAAM,aACN,MAAM,YACN,MAAM,aACN,MAAM,cACN,MAAM,GAAC,IAAI,wBACX,WAAS,IAAI,kBACb,MAAM,GAAC,IAAI,yCA2LrB;IAED;;;;;OAKG;IACH,wBAJW,MAAM,gCACsB,MAAM,EAAE,GAClC,OAAO,CAAC,IAAI,CAAC,CA4BzB;IAED;;;;;;;;;;;OAWG;IACH,gCAPqB,MAAM,eACJ,MAAM,wBAClB,WAAS,IAAI,kBAEb,MAAM,GAAC,IAAI,GACT,OAAO,CAAC,IAAI,CAAC,CAiEzB;IAED;;;;;OAKG;IACH,uCAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAkCzB;CACJ;yBApYsB,cAAc"} 1 + {"version":3,"file":"pdsmoover.d.ts","sourceRoot":"","sources":["../lib/pdsmoover.js"],"names":[],"mappings":"AASA;;;GAGG;AACH;IAEI,uBAAuB;IACvB,UADW,QAAQ,CACC;IACpB,uBAAuB;IACvB,UADW,QAAQ,CACC;IACpB,uBAAuB;IACvB,cADW,CAAC,MAAM,CAAC,CACG;IAEtB,sBAAsB;IACtB,kBADW,OAAO,CACU;IAC5B,sBAAsB;IACtB,aADW,OAAO,CACK;IACvB,sBAAsB;IACtB,cADW,OAAO,CACM;IACxB,sBAAsB;IACtB,qBADW,OAAO,CACa;IAC/B,sBAAsB;IACtB,cADW,OAAO,CACM;IACxB,sBAAsB;IACtB,kBADW,OAAO,CACU;IAC5B;;sBAEkB;IAClB,oBADQ,MAAM,CACa;IAG7B;;;;;;;;OAQG;IACH,sBAPW,QAAQ,YACR,QAAQ,YACR,MAAM,QACN,CAAC,MAAM,CAAC,cACR,MAAM,uBACN,WAAS,IAAI,iBAuBvB;IAED;;;;;;;;;;;;;;;OAeG;IACH,mBAVW,MAAM,YACN,MAAM,aACN,MAAM,YACN,MAAM,aACN,MAAM,cACN,MAAM,GAAC,IAAI,wBACX,WAAS,IAAI,kBACb,MAAM,GAAC,IAAI,yCA+MrB;IAED;;;;;OAKG;IACH,wBAJW,MAAM,gCACsB,MAAM,EAAE,GAClC,OAAO,CAAC,IAAI,CAAC,CA2BzB;IAED;;;;;;;;;;;OAWG;IACH,gCAPqB,MAAM,eACJ,MAAM,wBAClB,WAAS,IAAI,kBAEb,MAAM,GAAC,IAAI,GACT,OAAO,CAAC,IAAI,CAAC,CA+EzB;IAED;;;;;OAKG;IACH,uCAHW,MAAM,GACJ,OAAO,CAAC,IAAI,CAAC,CAkCzB;CACF;yBAxcwB,cAAc"}
+98 -109
packages/moover/types/plc-ops.d.ts
··· 1 1 /** 2 2 * JSDoc type-only import to avoid runtime import errors in the browser. 3 3 */ 4 - export type defs = typeof defs 4 + export type defs = typeof defs; 5 5 /** 6 6 * JSDoc type-only import to avoid runtime import errors in the browser. 7 7 */ 8 - export type normalizeOp = any 8 + export type normalizeOp = any; 9 9 /** 10 10 * JSDoc type-only import to avoid runtime import errors in the browser. 11 11 */ 12 - export type Operation = import('@atcute/did-plc').Operation 12 + export type Operation = import("@atcute/did-plc").Operation; 13 13 /** 14 14 * JSDoc type-only import to avoid runtime import errors in the browser. 15 15 */ 16 - export type CompatibleOperation = import('@atcute/did-plc').CompatibleOperation 16 + export type CompatibleOperation = import("@atcute/did-plc").CompatibleOperation; 17 17 /** 18 18 * JSDoc type-only import to avoid runtime import errors in the browser. 19 19 */ 20 - export type IndexedEntryLog = import('@atcute/did-plc').IndexedEntryLog 20 + export type IndexedEntryLog = import("@atcute/did-plc").IndexedEntryLog; 21 21 /** 22 22 * JSDoc type-only import to avoid runtime import errors in the browser. 23 23 */ 24 - export type IndexedEntry = import('@atcute/did-plc').IndexedEntry 24 + export type IndexedEntry = import("@atcute/did-plc").IndexedEntry; 25 25 /** 26 26 * Class to help with various PLC operations 27 27 */ 28 28 export class PlcOps { 29 - /** 30 - * 31 - * @param plcDirectoryUrl {string} - The url of the plc directory, defaults to https://plc.directory 32 - */ 33 - constructor(plcDirectoryUrl?: string) 34 - /** 35 - * The url of the plc directory 36 - * @type {string} 37 - */ 38 - plcDirectoryUrl: string 39 - /** 40 - * Gets the current rotation keys for a user via their last PlC operation 41 - * @param did 42 - * @returns {Promise<string[]>} 43 - */ 44 - getCurrentRotationKeysForUser(did: any): Promise<string[]> 45 - /** 46 - * Gets the last PlC operation for a user from the plc directory 47 - * @param did 48 - * @returns {Promise<{lastOperation: Operation, base: any}>} 49 - */ 50 - getLastPlcOpFromPlc(did: any): Promise<{ 51 - lastOperation: Operation 52 - base: any 53 - }> 54 - /** 55 - * 56 - * @param logs {IndexedEntryLog} 57 - * @returns {{lastOperation: Operation, base: IndexedEntry}} 58 - */ 59 - getLastPlcOp(logs: IndexedEntryLog): { 60 - lastOperation: Operation 61 - base: IndexedEntry 62 - } 63 - /** 64 - * Gets the plc audit logs for a user from the plc directory 65 - * @param did 66 - * @returns {Promise<IndexedEntryLog>} 67 - */ 68 - getPlcAuditLogs(did: any): Promise<IndexedEntryLog> 69 - /** 70 - * Creates a new secp256k1 key that can be used for either rotation or verification key 71 - * @returns {Promise<{privateKey: string, publicKey: `did:key:${string}`}>} 72 - */ 73 - createANewSecp256k1(): Promise<{ 74 - privateKey: string 75 - publicKey: `did:key:${string}` 76 - }> 77 - /** 78 - * Signs a new operation with the provided signing key, and information and submits it to the plc directory 79 - * @param did {string} - The user's did 80 - * @param signingRotationKey { P256PrivateKey|Secp256k1PrivateKey} - The keypair to sign the op with 81 - * @param alsoKnownAs {string[]} 82 - * @param rotationKeys {string[]} 83 - * @param pds {string} 84 - * @param verificationKey {string} - The public verification key 85 - * @param prev {string} - The previous valid operation's cid. 86 - * @returns {Promise<void>} 87 - */ 88 - signAndPublishNewOp( 89 - did: string, 90 - signingRotationKey: P256PrivateKey | Secp256k1PrivateKey, 91 - alsoKnownAs: string[], 92 - rotationKeys: string[], 93 - pds: string, 94 - verificationKey: string, 95 - prev: string, 96 - ): Promise<void> 97 - /** 98 - * Takes a multi or hex based private key and returns a keypair 99 - * @param privateKeyString {string} 100 - * @param type {string} - secp256k1 or p256, needed if the private key is hex based, can be assumed if it's a multikey 101 - * @returns {Promise<{type: string, didPublicKey: `did:key:${string}`, keypair: P256PrivateKey|Secp256k1PrivateKey}>} 102 - */ 103 - getKeyPair( 104 - privateKeyString: string, 105 - type?: string, 106 - ): Promise<{ 107 - type: string 108 - didPublicKey: `did:key:${string}` 109 - keypair: P256PrivateKey | Secp256k1PrivateKey 110 - }> 111 - /** 112 - * Submits a new operation to the plc directory 113 - * @param did {string} - The user's did 114 - * @param operation 115 - * @returns {Promise<void>} 116 - */ 117 - pushPlcOperation(did: string, operation: any): Promise<void> 118 - /** 119 - * Creates a new service auth token for a user. This is what is used to create a new account on a PDS for your did 120 - * 121 - * @param iss The user's did 122 - * @param aud The did:web, if it's a PDS it's usually from /xrpc/com.atproto.server.describeServer 123 - * @param keypair The keypair to sign with only supporting ES256K atm 124 - * @param lxm The lxm which is usually com.atproto.server.createAccount for creating a new account 125 - * @returns {Promise<string>} 126 - */ 127 - createANewServiceAuthToken(iss: any, aud: any, keypair: any, lxm: any): Promise<string> 29 + /** 30 + * 31 + * @param plcDirectoryUrl {string} - The url of the plc directory, defaults to https://plc.directory 32 + */ 33 + constructor(plcDirectoryUrl?: string); 34 + /** 35 + * The url of the plc directory 36 + * @type {string} 37 + */ 38 + plcDirectoryUrl: string; 39 + /** 40 + * Gets the current rotation keys for a user via their last PlC operation 41 + * @param did 42 + * @returns {Promise<string[]>} 43 + */ 44 + getCurrentRotationKeysForUser(did: any): Promise<string[]>; 45 + /** 46 + * Gets the last PlC operation for a user from the plc directory 47 + * @param did 48 + * @returns {Promise<{lastOperation: Operation, base: any}>} 49 + */ 50 + getLastPlcOpFromPlc(did: any): Promise<{ 51 + lastOperation: Operation; 52 + base: any; 53 + }>; 54 + /** 55 + * 56 + * @param logs {IndexedEntryLog} 57 + * @returns {{lastOperation: Operation, base: IndexedEntry}} 58 + */ 59 + getLastPlcOp(logs: IndexedEntryLog): { 60 + lastOperation: Operation; 61 + base: IndexedEntry; 62 + }; 63 + /** 64 + * Gets the plc audit logs for a user from the plc directory 65 + * @param did 66 + * @returns {Promise<IndexedEntryLog>} 67 + */ 68 + getPlcAuditLogs(did: any): Promise<IndexedEntryLog>; 69 + /** 70 + * Creates a new secp256k1 key that can be used for either rotation or verification key 71 + * @returns {Promise<{privateKey: string, publicKey: `did:key:${string}`}>} 72 + */ 73 + createANewSecp256k1(): Promise<{ 74 + privateKey: string; 75 + publicKey: `did:key:${string}`; 76 + }>; 77 + /** 78 + * Signs a new operation with the provided signing key, and information and submits it to the plc directory 79 + * @param did {string} - The user's did 80 + * @param signingRotationKey { P256PrivateKey|Secp256k1PrivateKey} - The keypair to sign the op with 81 + * @param alsoKnownAs {string[]} 82 + * @param rotationKeys {string[]} 83 + * @param pds {string} 84 + * @param verificationKey {string} - The public verification key 85 + * @param prev {string} - The previous valid operation's cid. 86 + * @returns {Promise<void>} 87 + */ 88 + signAndPublishNewOp(did: string, signingRotationKey: P256PrivateKey | Secp256k1PrivateKey, alsoKnownAs: string[], rotationKeys: string[], pds: string, verificationKey: string, prev: string): Promise<void>; 89 + /** 90 + * Takes a multi or hex based private key and returns a keypair 91 + * @param privateKeyString {string} 92 + * @param type {string} - secp256k1 or p256, needed if the private key is hex based, can be assumed if it's a multikey 93 + * @returns {Promise<{type: string, didPublicKey: `did:key:${string}`, keypair: P256PrivateKey|Secp256k1PrivateKey}>} 94 + */ 95 + getKeyPair(privateKeyString: string, type?: string): Promise<{ 96 + type: string; 97 + didPublicKey: `did:key:${string}`; 98 + keypair: P256PrivateKey | Secp256k1PrivateKey; 99 + }>; 100 + /** 101 + * Submits a new operation to the plc directory 102 + * @param did {string} - The user's did 103 + * @param operation 104 + * @returns {Promise<void>} 105 + */ 106 + pushPlcOperation(did: string, operation: any): Promise<void>; 107 + /** 108 + * Creates a new service auth token for a user. This is what is used to create a new account on a PDS for your did 109 + * 110 + * @param iss The user's did 111 + * @param aud The did:web, if it's a PDS it's usually from /xrpc/com.atproto.server.describeServer 112 + * @param keypair The keypair to sign with only supporting ES256K atm 113 + * @param lxm The lxm which is usually com.atproto.server.createAccount for creating a new account 114 + * @returns {Promise<string>} 115 + */ 116 + createANewServiceAuthToken(iss: any, aud: any, keypair: any, lxm: any): Promise<string>; 128 117 } 129 - import { defs } from '@atcute/did-plc' 130 - import { P256PrivateKey } from '@atcute/crypto' 131 - import { Secp256k1PrivateKey } from '@atcute/crypto' 132 - //# sourceMappingURL=plc-ops.d.ts.map 118 + import { defs } from '@atcute/did-plc'; 119 + import { P256PrivateKey } from '@atcute/crypto'; 120 + import { Secp256k1PrivateKey } from '@atcute/crypto'; 121 + //# sourceMappingURL=plc-ops.d.ts.map
+1 -1
packages/moover/types/plc-ops.d.ts.map
··· 1 - {"version":3,"file":"plc-ops.d.ts","sourceRoot":"","sources":["../lib/plc-ops.js"],"names":[],"mappings":";;;;;;;;;;;wBAIa,OAAO,iBAAiB,EAAE,SAAS;;;;kCACnC,OAAO,iBAAiB,EAAE,mBAAmB;;;;8BAC7C,OAAO,iBAAiB,EAAE,eAAe;;;;2BACzC,OAAO,iBAAiB,EAAE,YAAY;AAgBnD;;GAEG;AACH;IACI;;;OAGG;IACH,8BAF2B,MAAM,EAQhC;IALG;;;OAGG;IACH,iBAFU,MAAM,CAEsB;IAG1C;;;;OAIG;IACH,yCAFa,OAAO,CAAC,MAAM,EAAE,CAAC,CAM7B;IAED;;;;OAIG;IACH,+BAFa,OAAO,CAAC;QAAC,aAAa,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAC,CAAC,CAK1D;IAED;;;;OAIG;IACH,mBAHgB,eAAe,GAClB;QAAC,aAAa,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,YAAY,CAAA;KAAC,CAK1D;IAGD;;;;OAIG;IACH,2BAFa,OAAO,CAAC,eAAe,CAAC,CAUpC;IAED;;;OAGG;IACH,uBAFa,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,WAAW,MAAM,EAAE,CAAA;KAAC,CAAC,CAUzE;IAGD;;;;;;;;;;OAUG;IACH,yBATe,MAAM,sBACU,cAAc,GAAC,mBAAmB,eAC1C,MAAM,EAAE,gBACP,MAAM,EAAE,OACjB,MAAM,mBACM,MAAM,QACjB,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CAuCzB;IAED;;;;;OAKG;IACH,6BAJ4B,MAAM,SAClB,MAAM,GACT,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,WAAW,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,cAAc,GAAC,mBAAmB,CAAA;KAAC,CAAC,CAkDnH;IAED;;;;;OAKG;IACH,sBAJe,MAAM,mBAER,OAAO,CAAC,IAAI,CAAC,CAwBzB;IAGD;;;;;;;;OAQG;IACH,wEAFa,OAAO,CAAC,MAAM,CAAC,CAwC3B;CAGJ;qBAtR+B,iBAAiB;+BACsD,gBAAgB;oCAAhB,gBAAgB"} 1 + {"version":3,"file":"plc-ops.d.ts","sourceRoot":"","sources":["../lib/plc-ops.js"],"names":[],"mappings":";;;;;;;;;;;wBAIa,OAAO,iBAAiB,EAAE,SAAS;;;;kCACnC,OAAO,iBAAiB,EAAE,mBAAmB;;;;8BAC7C,OAAO,iBAAiB,EAAE,eAAe;;;;2BACzC,OAAO,iBAAiB,EAAE,YAAY;AAoBnD;;GAEG;AACH;IACE;;;OAGG;IACH,8BAF2B,MAAM,EAQhC;IALC;;;OAGG;IACH,iBAFU,MAAM,CAEsB;IAGxC;;;;OAIG;IACH,yCAFa,OAAO,CAAC,MAAM,EAAE,CAAC,CAM7B;IAED;;;;OAIG;IACH,+BAFa,OAAO,CAAC;QAAC,aAAa,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAC,CAAC,CAK1D;IAED;;;;OAIG;IACH,mBAHgB,eAAe,GAClB;QAAC,aAAa,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,YAAY,CAAA;KAAC,CAK1D;IAED;;;;OAIG;IACH,2BAFa,OAAO,CAAC,eAAe,CAAC,CAUpC;IAED;;;OAGG;IACH,uBAFa,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,WAAW,MAAM,EAAE,CAAA;KAAC,CAAC,CAUzE;IAED;;;;;;;;;;OAUG;IACH,yBATe,MAAM,sBACU,cAAc,GAAC,mBAAmB,eAC1C,MAAM,EAAE,gBACP,MAAM,EAAE,OACjB,MAAM,mBACM,MAAM,QACjB,MAAM,GACT,OAAO,CAAC,IAAI,CAAC,CA8CzB;IAED;;;;;OAKG;IACH,6BAJ4B,MAAM,SAClB,MAAM,GACT,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,WAAW,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,cAAc,GAAC,mBAAmB,CAAA;KAAC,CAAC,CAiDnH;IAED;;;;;OAKG;IACH,sBAJe,MAAM,mBAER,OAAO,CAAC,IAAI,CAAC,CAwBzB;IAED;;;;;;;;OAQG;IACH,wEAFa,OAAO,CAAC,MAAM,CAAC,CAuC3B;CACF;qBA1RiC,iBAAiB;+BAM5C,gBAAgB;oCAAhB,gBAAgB"}
+77 -92
packages/moover/types/restore.d.ts
··· 1 - export type Operation = import('@atcute/did-plc').Operation 1 + export type Operation = import("@atcute/did-plc").Operation; 2 2 export class Restore { 3 - /** 4 - * 5 - * @param pdsMooverInstance {string} - The url of the pds moover instance to restore from. Defaults to https://pdsmover.com 6 - */ 7 - constructor(pdsMooverInstance?: string) 8 - /** 9 - * If you want to use a different plc directory create your own instance of the plc ops class and pass it in here 10 - * @type {PlcOps} */ 11 - plcOps: PlcOps 12 - /** 13 - * This is the base url for the pds moover instance used to restore the files from a backup. 14 - * @type {string} 15 - */ 16 - pdsMooverInstance: string 17 - /** 18 - * To keep it simple, only uses secp256k for the temp verification key that is used to create the new account on the new PDS 19 - * and is temporarily assigned to the user's account on PLC 20 - * @type {null|Secp256k1PrivateKeyExportable} 21 - */ 22 - tempVerificationKeypair: null | Secp256k1PrivateKeyExportable 23 - /** @type {AtpAgent} */ 24 - atpAgent: AtpAgent 25 - /** 26 - * The keypair that is used to sign the plc operation 27 - * @type {null|{type: string, didPublicKey: `did:key:${string}`, keypair: P256PrivateKey|Secp256k1PrivateKey}} 28 - */ 29 - recoveryRotationKeyPair: null | { 30 - type: string 31 - didPublicKey: `did:key:${string}` 32 - keypair: P256PrivateKey | Secp256k1PrivateKey 33 - } 34 - /** 35 - * If this is true we are just restoring the repo and blobs. Ideally for rerunning a restore process after account recovery 36 - * @type {boolean} 37 - */ 38 - RestoreFromBackup: boolean 39 - /** 40 - * If set to true then it will do the account recovery. Writes a temp key to the did doc, 41 - * create a new account on the new pds, and then submit a new plc op for the pds to have control (finishes the migration, can always restore the backup later) 42 - * @type {boolean} 43 - */ 44 - AccountRecovery: boolean 45 - /** 46 - * Recovers an account with the users rotation key and restores the repo from a PDS MOOver backup 47 - * This method can fail, and the account was still recovered, it's best to check the PLC logs to see where an account stands before reruns 48 - * @param rotationKey {string} - The users private rotation key, can be a multi key or hex key 49 - * @param rotationKeyType {string} - The type of the key, secp256k1 or p256. Required if the key is in hex format, defaults to secp256k1 50 - * @param currentHandleOrDid {string} - The users current handle or did, if they don't have a DNS record it will have to be their did for success 51 - * @param newPDS {string} - The new PDS url, like https://coolnewpds.com 52 - * @param newHandle {string} - Can be the users DNS handle if it is already setup with their did, if not it's bob.mypds.com 53 - * @param newPassword {string} - The new password for the new account 54 - * @param newEmail {string} - The new email for the new account 55 - * @param inviteCode {string|null} - The invite code for the new PDS if it requires one 56 - * @param cidToRestoreTo {string|null} - The cid of the plc op to restore to, used mostly to revert a fraudulent plc op. Want to give it the last valid operations cid 57 - * @param onStatus {function|null} - A function that takes a string used to update the UI. Like (status) => console.log(status) 58 - * @returns {Promise<void>} If there is a failure during restoring the back up (after the status Success! Restoring your repo...) then your account is most likely 59 - * recovered and future runs need to have the RestoreFromBackup flag set to true and AccountRecovery set to false. 60 - */ 61 - recover( 62 - rotationKey: string, 63 - rotationKeyType: string, 64 - currentHandleOrDid: string, 65 - newPDS: string, 66 - newHandle: string, 67 - newPassword: string, 68 - newEmail: string, 69 - inviteCode: string | null, 70 - cidToRestoreTo?: string | null, 71 - onStatus?: Function | null, 72 - ): Promise<void> 73 - /** 74 - * This method signs the plc operation over to the new PDS and activates the account 75 - * Assumes you have already created a new account during the recovery process and logged in 76 - * Uses the recommended did doc from the PDS as a base and adds the users rotation key to the rotation keys array 77 - * 78 - * @param usersDid 79 - * @param additionalRotationKeysToAdd 80 - * @param prevCid 81 - * @returns {Promise<void>} 82 - */ 83 - signRestorePlcOperation( 84 - usersDid: any, 85 - additionalRotationKeysToAdd: any[], 86 - prevCid: any, 87 - ): Promise<void> 3 + /** 4 + * 5 + * @param pdsMooverInstance {string} - The url of the pds moover instance to restore from. Defaults to https://pdsmover.com 6 + */ 7 + constructor(pdsMooverInstance?: string); 8 + /** 9 + * If you want to use a different plc directory create your own instance of the plc ops class and pass it in here 10 + * @type {PlcOps} */ 11 + plcOps: PlcOps; 12 + /** 13 + * This is the base url for the pds moover instance used to restore the files from a backup. 14 + * @type {string} 15 + */ 16 + pdsMooverInstance: string; 17 + /** 18 + * To keep it simple, only uses secp256k for the temp verification key that is used to create the new account on the new PDS 19 + * and is temporarily assigned to the user's account on PLC 20 + * @type {null|Secp256k1PrivateKeyExportable} 21 + */ 22 + tempVerificationKeypair: null | Secp256k1PrivateKeyExportable; 23 + /** @type {AtpAgent} */ 24 + atpAgent: AtpAgent; 25 + /** 26 + * The keypair that is used to sign the plc operation 27 + * @type {null|{type: string, didPublicKey: `did:key:${string}`, keypair: P256PrivateKey|Secp256k1PrivateKey}} 28 + */ 29 + recoveryRotationKeyPair: null | { 30 + type: string; 31 + didPublicKey: `did:key:${string}`; 32 + keypair: P256PrivateKey | Secp256k1PrivateKey; 33 + }; 34 + /** 35 + * If this is true we are just restoring the repo and blobs. Ideally for rerunning a restore process after account recovery 36 + * @type {boolean} 37 + */ 38 + RestoreFromBackup: boolean; 39 + /** 40 + * If set to true then it will do the account recovery. Writes a temp key to the did doc, 41 + * create a new account on the new pds, and then submit a new plc op for the pds to have control (finishes the migration, can always restore the backup later) 42 + * @type {boolean} 43 + */ 44 + AccountRecovery: boolean; 45 + /** 46 + * Recovers an account with the users rotation key and restores the repo from a PDS MOOver backup 47 + * This method can fail, and the account was still recovered, it's best to check the PLC logs to see where an account stands before reruns 48 + * @param rotationKey {string} - The users private rotation key, can be a multi key or hex key 49 + * @param rotationKeyType {string} - The type of the key, secp256k1 or p256. Required if the key is in hex format, defaults to secp256k1 50 + * @param currentHandleOrDid {string} - The users current handle or did, if they don't have a DNS record it will have to be their did for success 51 + * @param newPDS {string} - The new PDS url, like https://coolnewpds.com 52 + * @param newHandle {string} - Can be the users DNS handle if it is already setup with their did, if not it's bob.mypds.com 53 + * @param newPassword {string} - The new password for the new account 54 + * @param newEmail {string} - The new email for the new account 55 + * @param inviteCode {string|null} - The invite code for the new PDS if it requires one 56 + * @param cidToRestoreTo {string|null} - The cid of the plc op to restore to, used mostly to revert a fraudulent plc op. Want to give it the last valid operations cid 57 + * @param onStatus {function|null} - A function that takes a string used to update the UI. Like (status) => console.log(status) 58 + * @returns {Promise<void>} If there is a failure during restoring the back up (after the status Success! Restoring your repo...) then your account is most likely 59 + * recovered and future runs need to have the RestoreFromBackup flag set to true and AccountRecovery set to false. 60 + */ 61 + recover(rotationKey: string, rotationKeyType: string, currentHandleOrDid: string, newPDS: string, newHandle: string, newPassword: string, newEmail: string, inviteCode: string | null, cidToRestoreTo?: string | null, onStatus?: Function | null): Promise<void>; 62 + /** 63 + * This method signs the plc operation over to the new PDS and activates the account 64 + * Assumes you have already created a new account during the recovery process and logged in 65 + * Uses the recommended did doc from the PDS as a base and adds the users rotation key to the rotation keys array 66 + * 67 + * @param usersDid 68 + * @param additionalRotationKeysToAdd 69 + * @param prevCid 70 + * @returns {Promise<void>} 71 + */ 72 + signRestorePlcOperation(usersDid: any, additionalRotationKeysToAdd: any[], prevCid: any): Promise<void>; 88 73 } 89 - import { PlcOps } from './plc-ops.js' 90 - import { Secp256k1PrivateKeyExportable } from '@atcute/crypto' 91 - import { AtpAgent } from '@atproto/api' 92 - import { P256PrivateKey } from '@atcute/crypto' 93 - import { Secp256k1PrivateKey } from '@atcute/crypto' 94 - //# sourceMappingURL=restore.d.ts.map 74 + import { PlcOps } from './plc-ops.js'; 75 + import { Secp256k1PrivateKeyExportable } from '@atcute/crypto'; 76 + import { AtpAgent } from '@atproto/api'; 77 + import { P256PrivateKey } from '@atcute/crypto'; 78 + import { Secp256k1PrivateKey } from '@atcute/crypto'; 79 + //# sourceMappingURL=restore.d.ts.map
+1 -1
packages/moover/types/restore.d.ts.map
··· 1 - {"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../lib/restore.js"],"names":[],"mappings":"wBACa,OAAO,iBAAiB,EAAE,SAAS;AAWhD;IAEI;;;OAGG;IACH,gCAF6B,MAAM,EA0ClC;IAvCG;;wBAEoB;IACpB,QADU,MAAM,CACU;IAE1B;;;OAGG;IACH,mBAFU,MAAM,CAE0B;IAE1C;;;;OAIG;IACH,yBAFU,IAAI,GAAC,6BAA6B,CAET;IAEnC,uBAAuB;IACvB,UADW,QAAQ,CACC;IAEpB;;;OAGG;IACH,yBAFU,IAAI,GAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,WAAW,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,cAAc,GAAC,mBAAmB,CAAA;KAAC,CAE1E;IAEnC;;;OAGG;IACH,mBAFU,OAAO,CAEY;IAE7B;;;;OAIG;IACH,iBAFU,OAAO,CAEU;IAG/B;;;;;;;;;;;;;;;OAeG;IACH,qBAbuB,MAAM,mBACF,MAAM,sBACH,MAAM,UAClB,MAAM,aACH,MAAM,eACJ,MAAM,YACT,MAAM,cACJ,MAAM,GAAC,IAAI,mBACP,MAAM,GAAC,IAAI,aACjB,WAAS,IAAI,GACpB,OAAO,CAAC,IAAI,CAAC,CA4MzB;IAGD;;;;;;;;;OASG;IACH,0FAFa,OAAO,CAAC,IAAI,CAAC,CAuCzB;CACJ;uBAnUoB,cAAc;8CAGS,gBAAgB;yBADrC,cAAc;+BAJa,gBAAgB;oCAAhB,gBAAgB"} 1 + {"version":3,"file":"restore.d.ts","sourceRoot":"","sources":["../lib/restore.js"],"names":[],"mappings":"wBACa,OAAO,iBAAiB,EAAE,SAAS;AAWhD;IACE;;;OAGG;IACH,gCAF6B,MAAM,EA0ClC;IAvCC;;wBAEoB;IACpB,QADU,MAAM,CACU;IAE1B;;;OAGG;IACH,mBAFU,MAAM,CAE0B;IAE1C;;;;OAIG;IACH,yBAFU,IAAI,GAAC,6BAA6B,CAET;IAEnC,uBAAuB;IACvB,UADW,QAAQ,CACC;IAEpB;;;OAGG;IACH,yBAFU,IAAI,GAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,WAAW,MAAM,EAAE,CAAC;QAAC,OAAO,EAAE,cAAc,GAAC,mBAAmB,CAAA;KAAC,CAE1E;IAEnC;;;OAGG;IACH,mBAFU,OAAO,CAEY;IAE7B;;;;OAIG;IACH,iBAFU,OAAO,CAEU;IAG7B;;;;;;;;;;;;;;;OAeG;IACH,qBAbuB,MAAM,mBACF,MAAM,sBACH,MAAM,UAClB,MAAM,aACH,MAAM,eACJ,MAAM,YACT,MAAM,cACJ,MAAM,GAAC,IAAI,mBACP,MAAM,GAAC,IAAI,aACjB,WAAS,IAAI,GACpB,OAAO,CAAC,IAAI,CAAC,CAiNzB;IAED;;;;;;;;;OASG;IACH,0FAFa,OAAO,CAAC,IAAI,CAAC,CAsCzB;CACF;uBArUsB,cAAc;8CAGS,gBAAgB;yBADrC,cAAc;+BAJa,gBAAgB;oCAAhB,gBAAgB"}
+2 -1
web-ui/package.json
··· 17 17 "@atcute/client": "^4.0.5", 18 18 "@atcute/lexicons": "^1.2.2", 19 19 "@pds-moover/lexicons": "^1.0.1", 20 - "@pds-moover/moover": "^1.0.6" 20 + "@pds-moover/moover": "^1.0.7" 21 21 }, 22 22 "devDependencies": { 23 23 "@eslint/compat": "^1.4.0", ··· 30 30 "eslint": "^9.36.0", 31 31 "eslint-plugin-svelte": "^3.12.4", 32 32 "globals": "^16.4.0", 33 + "oxlint": "^1.48.0", 33 34 "svelte": "^5.39.5", 34 35 "svelte-check": "^4.3.2", 35 36 "typescript": "^5.9.2",
+211 -5
web-ui/pnpm-lock.yaml
··· 21 21 specifier: ^1.0.1 22 22 version: 1.0.1 23 23 '@pds-moover/moover': 24 - specifier: ^1.0.6 25 - version: 1.0.6(@atcute/identity@1.1.1)(vite@7.1.12(@types/node@22.19.0)) 24 + specifier: ^1.0.7 25 + version: 1.0.7(@atcute/identity@1.1.1)(vite@7.1.12(@types/node@22.19.0)) 26 26 devDependencies: 27 27 '@eslint/compat': 28 28 specifier: ^1.4.0 ··· 54 54 globals: 55 55 specifier: ^16.4.0 56 56 version: 16.5.0 57 + oxlint: 58 + specifier: ^1.48.0 59 + version: 1.48.0 57 60 svelte: 58 61 specifier: ^5.39.5 59 62 version: 5.43.2 ··· 389 392 resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 390 393 engines: {node: '>= 8'} 391 394 395 + '@oxlint/binding-android-arm-eabi@1.48.0': 396 + resolution: {integrity: sha512-1Pz/stJvveO9ZO7ll4ZoEY3f6j2FiUgBLBcCRCiW6ylId9L9UKs+gn3X28m3eTnoiFCkhKwmJJ+VO6vwsu7Qtg==} 397 + engines: {node: ^20.19.0 || >=22.12.0} 398 + cpu: [arm] 399 + os: [android] 400 + 401 + '@oxlint/binding-android-arm64@1.48.0': 402 + resolution: {integrity: sha512-Zc42RWGE8huo6Ht0lXKjd0NH2lWNmimQHUmD0JFcvShLOuwN+RSEE/kRakc2/0LIgOUuU/R7PaDMCOdQlPgNUQ==} 403 + engines: {node: ^20.19.0 || >=22.12.0} 404 + cpu: [arm64] 405 + os: [android] 406 + 407 + '@oxlint/binding-darwin-arm64@1.48.0': 408 + resolution: {integrity: sha512-jgZs563/4vaG5jH2RSt2TSh8A2jwsFdmhLXrElMdm3Mmto0HPf85FgInLSNi9HcwzQFvkYV8JofcoUg2GH1HTA==} 409 + engines: {node: ^20.19.0 || >=22.12.0} 410 + cpu: [arm64] 411 + os: [darwin] 412 + 413 + '@oxlint/binding-darwin-x64@1.48.0': 414 + resolution: {integrity: sha512-kvo87BujEUjCJREuWDC4aPh1WoXCRFFWE4C7uF6wuoMw2f6N2hypA/cHHcYn9DdL8R2RrgUZPefC8JExyeIMKA==} 415 + engines: {node: ^20.19.0 || >=22.12.0} 416 + cpu: [x64] 417 + os: [darwin] 418 + 419 + '@oxlint/binding-freebsd-x64@1.48.0': 420 + resolution: {integrity: sha512-eyzzPaHQKn0RIM+ueDfgfJF2RU//Wp4oaKs2JVoVYcM5HjbCL36+O0S3wO5Xe1NWpcZIG3cEHc/SuOCDRqZDSg==} 421 + engines: {node: ^20.19.0 || >=22.12.0} 422 + cpu: [x64] 423 + os: [freebsd] 424 + 425 + '@oxlint/binding-linux-arm-gnueabihf@1.48.0': 426 + resolution: {integrity: sha512-p3kSloztK7GRO7FyO3u38UCjZxQTl92VaLDsMQAq0eGoiNmeeEF1KPeE4+Fr+LSkQhF8WvJKSuls6TwOlurdPA==} 427 + engines: {node: ^20.19.0 || >=22.12.0} 428 + cpu: [arm] 429 + os: [linux] 430 + 431 + '@oxlint/binding-linux-arm-musleabihf@1.48.0': 432 + resolution: {integrity: sha512-uWM+wiTqLW/V0ZmY/eyTWs8ykhIkzU+K2tz/8m35YepYEzohiUGRbnkpAFXj2ioXpQL+GUe5vmM3SLH6ozlfFw==} 433 + engines: {node: ^20.19.0 || >=22.12.0} 434 + cpu: [arm] 435 + os: [linux] 436 + 437 + '@oxlint/binding-linux-arm64-gnu@1.48.0': 438 + resolution: {integrity: sha512-OhQNPjs/OICaYqxYJjKKMaIY7p3nJ9IirXcFoHKD+CQE1BZFCeUUAknMzUeLclDCfudH9Vb/UgjFm8+ZM5puAg==} 439 + engines: {node: ^20.19.0 || >=22.12.0} 440 + cpu: [arm64] 441 + os: [linux] 442 + 443 + '@oxlint/binding-linux-arm64-musl@1.48.0': 444 + resolution: {integrity: sha512-adu5txuwGvQ4C4fjYHJD+vnY+OCwCixBzn7J3KF3iWlVHBBImcosSv+Ye+fbMMJui4HGjifNXzonjKm9pXmOiw==} 445 + engines: {node: ^20.19.0 || >=22.12.0} 446 + cpu: [arm64] 447 + os: [linux] 448 + 449 + '@oxlint/binding-linux-ppc64-gnu@1.48.0': 450 + resolution: {integrity: sha512-inlQQRUnHCny/7b7wA6NjEoJSSZPNea4qnDhWyeqBYWx8ukf2kzNDSiamfhOw6bfAYPm/PVlkVRYaNXQbkLeTQ==} 451 + engines: {node: ^20.19.0 || >=22.12.0} 452 + cpu: [ppc64] 453 + os: [linux] 454 + 455 + '@oxlint/binding-linux-riscv64-gnu@1.48.0': 456 + resolution: {integrity: sha512-YiJx6sW6bYebQDZRVWLKm/Drswx/hcjIgbLIhULSn0rRcBKc7d9V6mkqPjKDbhcxJgQD5Zi0yVccJiOdF40AWA==} 457 + engines: {node: ^20.19.0 || >=22.12.0} 458 + cpu: [riscv64] 459 + os: [linux] 460 + 461 + '@oxlint/binding-linux-riscv64-musl@1.48.0': 462 + resolution: {integrity: sha512-zwSqxMgmb2ITamNfDv9Q9EKBc/4ZhCBP9gkg2hhcgR6sEVGPUDl1AKPC89CBKMxkmPUi3685C38EvqtZn5OtHw==} 463 + engines: {node: ^20.19.0 || >=22.12.0} 464 + cpu: [riscv64] 465 + os: [linux] 466 + 467 + '@oxlint/binding-linux-s390x-gnu@1.48.0': 468 + resolution: {integrity: sha512-c/+2oUWAOsQB5JTem0rW8ODlZllF6pAtGSGXoLSvPTonKI1vAwaKhD9Qw1X36jRbcI3Etkpu/9z/RRjMba8vFQ==} 469 + engines: {node: ^20.19.0 || >=22.12.0} 470 + cpu: [s390x] 471 + os: [linux] 472 + 473 + '@oxlint/binding-linux-x64-gnu@1.48.0': 474 + resolution: {integrity: sha512-PhauDqeFW5DGed6QxCY5lXZYKSlcBdCXJnH03ZNU6QmDZ0BFM/zSy1oPT2MNb1Afx1G6yOOVk8ErjWsQ7c59ng==} 475 + engines: {node: ^20.19.0 || >=22.12.0} 476 + cpu: [x64] 477 + os: [linux] 478 + 479 + '@oxlint/binding-linux-x64-musl@1.48.0': 480 + resolution: {integrity: sha512-6d7LIFFZGiavbHndhf1cK9kG9qmy2Dmr37sV9Ep7j3H+ciFdKSuOzdLh85mEUYMih+b+esMDlF5DU0WQRZPQjw==} 481 + engines: {node: ^20.19.0 || >=22.12.0} 482 + cpu: [x64] 483 + os: [linux] 484 + 485 + '@oxlint/binding-openharmony-arm64@1.48.0': 486 + resolution: {integrity: sha512-r+0KK9lK6vFp3tXAgDMOW32o12dxvKS3B9La1uYMGdWAMoSeu2RzG34KmzSpXu6MyLDl4aSVyZLFM8KGdEjwaw==} 487 + engines: {node: ^20.19.0 || >=22.12.0} 488 + cpu: [arm64] 489 + os: [openharmony] 490 + 491 + '@oxlint/binding-win32-arm64-msvc@1.48.0': 492 + resolution: {integrity: sha512-Nkw/MocyT3HSp0OJsKPXrcbxZqSPMTYnLLfsqsoiFKoL1ppVNL65MFa7vuTxJehPlBkjy+95gUgacZtuNMECrg==} 493 + engines: {node: ^20.19.0 || >=22.12.0} 494 + cpu: [arm64] 495 + os: [win32] 496 + 497 + '@oxlint/binding-win32-ia32-msvc@1.48.0': 498 + resolution: {integrity: sha512-reO1SpefvRmeZSP+WeyWkQd1ArxxDD1MyKgMUKuB8lNuUoxk9QEohYtKnsfsxJuFwMT0JTr7p9wZjouA85GzGQ==} 499 + engines: {node: ^20.19.0 || >=22.12.0} 500 + cpu: [ia32] 501 + os: [win32] 502 + 503 + '@oxlint/binding-win32-x64-msvc@1.48.0': 504 + resolution: {integrity: sha512-T6zwhfcsrorqAybkOglZdPkTLlEwipbtdO1qjE+flbawvwOMsISoyiuaa7vM7zEyfq1hmDvMq1ndvkYFioranA==} 505 + engines: {node: ^20.19.0 || >=22.12.0} 506 + cpu: [x64] 507 + os: [win32] 508 + 392 509 '@pds-moover/lexicons@1.0.1': 393 510 resolution: {integrity: sha512-fv5b/DtHM7FEo/JklyF9gdK0ainlb6mWjWrBe6cmSAeg9G/4O2jBlQUOqfOAICY9gOcrCpkOrk9PHgGw//JQ2A==} 394 511 395 - '@pds-moover/moover@1.0.6': 396 - resolution: {integrity: sha512-Zy+wcrZwoyne7NhuG+5MDFoJ+lpteCpfS6w2pmma9F2IKrVTj2G3Pca7ZVDaibGmCMTJMo21XYaPg+9nLXFD4Q==} 512 + '@pds-moover/moover@1.0.7': 513 + resolution: {integrity: sha512-sIyNejsVFMFqg0SyLMQGTde/4kMF+HyitDRPQn7nIgQdctPi2Nzm1pPeVfec2WeAiquXAYdKDWjawolqrKSPSw==} 397 514 398 515 '@polka/url@1.0.0-next.29': 399 516 resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} ··· 1062 1179 resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} 1063 1180 engines: {node: '>= 0.8.0'} 1064 1181 1182 + oxlint@1.48.0: 1183 + resolution: {integrity: sha512-m5vyVBgPtPhVCJc3xI//8je9lRc8bYuYB4R/1PH3VPGOjA4vjVhkHtyJukdEjYEjwrw4Qf1eIf+pP9xvfhfMow==} 1184 + engines: {node: ^20.19.0 || >=22.12.0} 1185 + hasBin: true 1186 + peerDependencies: 1187 + oxlint-tsgolint: '>=0.12.2' 1188 + peerDependenciesMeta: 1189 + oxlint-tsgolint: 1190 + optional: true 1191 + 1065 1192 p-limit@3.1.0: 1066 1193 resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} 1067 1194 engines: {node: '>=10'} ··· 1644 1771 '@nodelib/fs.scandir': 2.1.5 1645 1772 fastq: 1.19.1 1646 1773 1774 + '@oxlint/binding-android-arm-eabi@1.48.0': 1775 + optional: true 1776 + 1777 + '@oxlint/binding-android-arm64@1.48.0': 1778 + optional: true 1779 + 1780 + '@oxlint/binding-darwin-arm64@1.48.0': 1781 + optional: true 1782 + 1783 + '@oxlint/binding-darwin-x64@1.48.0': 1784 + optional: true 1785 + 1786 + '@oxlint/binding-freebsd-x64@1.48.0': 1787 + optional: true 1788 + 1789 + '@oxlint/binding-linux-arm-gnueabihf@1.48.0': 1790 + optional: true 1791 + 1792 + '@oxlint/binding-linux-arm-musleabihf@1.48.0': 1793 + optional: true 1794 + 1795 + '@oxlint/binding-linux-arm64-gnu@1.48.0': 1796 + optional: true 1797 + 1798 + '@oxlint/binding-linux-arm64-musl@1.48.0': 1799 + optional: true 1800 + 1801 + '@oxlint/binding-linux-ppc64-gnu@1.48.0': 1802 + optional: true 1803 + 1804 + '@oxlint/binding-linux-riscv64-gnu@1.48.0': 1805 + optional: true 1806 + 1807 + '@oxlint/binding-linux-riscv64-musl@1.48.0': 1808 + optional: true 1809 + 1810 + '@oxlint/binding-linux-s390x-gnu@1.48.0': 1811 + optional: true 1812 + 1813 + '@oxlint/binding-linux-x64-gnu@1.48.0': 1814 + optional: true 1815 + 1816 + '@oxlint/binding-linux-x64-musl@1.48.0': 1817 + optional: true 1818 + 1819 + '@oxlint/binding-openharmony-arm64@1.48.0': 1820 + optional: true 1821 + 1822 + '@oxlint/binding-win32-arm64-msvc@1.48.0': 1823 + optional: true 1824 + 1825 + '@oxlint/binding-win32-ia32-msvc@1.48.0': 1826 + optional: true 1827 + 1828 + '@oxlint/binding-win32-x64-msvc@1.48.0': 1829 + optional: true 1830 + 1647 1831 '@pds-moover/lexicons@1.0.1': 1648 1832 dependencies: 1649 1833 '@atproto/lexicon': 0.5.1 1650 1834 '@atproto/xrpc': 0.7.5 1651 1835 1652 - '@pds-moover/moover@1.0.6(@atcute/identity@1.1.1)(vite@7.1.12(@types/node@22.19.0))': 1836 + '@pds-moover/moover@1.0.7(@atcute/identity@1.1.1)(vite@7.1.12(@types/node@22.19.0))': 1653 1837 dependencies: 1654 1838 '@atcute/cbor': 2.3.2 1655 1839 '@atcute/client': 4.0.5 ··· 2328 2512 prelude-ls: 1.2.1 2329 2513 type-check: 0.4.0 2330 2514 word-wrap: 1.2.5 2515 + 2516 + oxlint@1.48.0: 2517 + optionalDependencies: 2518 + '@oxlint/binding-android-arm-eabi': 1.48.0 2519 + '@oxlint/binding-android-arm64': 1.48.0 2520 + '@oxlint/binding-darwin-arm64': 1.48.0 2521 + '@oxlint/binding-darwin-x64': 1.48.0 2522 + '@oxlint/binding-freebsd-x64': 1.48.0 2523 + '@oxlint/binding-linux-arm-gnueabihf': 1.48.0 2524 + '@oxlint/binding-linux-arm-musleabihf': 1.48.0 2525 + '@oxlint/binding-linux-arm64-gnu': 1.48.0 2526 + '@oxlint/binding-linux-arm64-musl': 1.48.0 2527 + '@oxlint/binding-linux-ppc64-gnu': 1.48.0 2528 + '@oxlint/binding-linux-riscv64-gnu': 1.48.0 2529 + '@oxlint/binding-linux-riscv64-musl': 1.48.0 2530 + '@oxlint/binding-linux-s390x-gnu': 1.48.0 2531 + '@oxlint/binding-linux-x64-gnu': 1.48.0 2532 + '@oxlint/binding-linux-x64-musl': 1.48.0 2533 + '@oxlint/binding-openharmony-arm64': 1.48.0 2534 + '@oxlint/binding-win32-arm64-msvc': 1.48.0 2535 + '@oxlint/binding-win32-ia32-msvc': 1.48.0 2536 + '@oxlint/binding-win32-x64-msvc': 1.48.0 2331 2537 2332 2538 p-limit@3.1.0: 2333 2539 dependencies:
+15 -6
web-ui/src/lib/assets/style.css
··· 138 138 justify-content: center; 139 139 } 140 140 141 - 142 141 .section { 143 142 margin-top: 30px; 144 143 } ··· 179 178 } 180 179 181 180 .form-checkbox { 182 - 183 181 font-size: 2rem; 184 182 font-weight: bold; 185 183 line-height: 1.1; ··· 244 242 text-decoration: none; 245 243 padding: 6px 10px; 246 244 border-radius: 8px; 247 - transition: background-color 0.2s ease, color 0.2s ease; 245 + transition: 246 + background-color 0.2s ease, 247 + color 0.2s ease; 248 248 } 249 249 250 250 .nav-links a:hover, ··· 326 326 flex-direction: column; 327 327 gap: 4px; 328 328 padding: 10px 16px 12px 16px; 329 - background: rgba(36, 36, 36, 0.95); /* solid enough to not bleed into title */ 329 + background: rgba( 330 + 36, 331 + 36, 332 + 36, 333 + 0.95 334 + ); /* solid enough to not bleed into title */ 330 335 backdrop-filter: saturate(180%) blur(10px); 331 336 border-bottom: 1px solid rgba(255, 255, 255, 0.08); 332 337 z-index: 1001; /* above page content */ ··· 426 431 } 427 432 } 428 433 429 - 430 434 /* Stats grid and cards for the index page */ 431 435 .stats-grid { 432 436 display: grid; ··· 462 466 font-size: 0.85rem; 463 467 opacity: 0.7; 464 468 margin-top: 6px; 465 - } 469 + } 470 + 471 + .warning { 472 + /*text-decoration: underline;*/ 473 + font-weight: bold; 474 + }
+118
web-ui/src/lib/components/Captcha.svelte
··· 1 + <script lang="ts"> 2 + import {onMount} from 'svelte'; 3 + import { browser } from '$app/environment'; 4 + 5 + interface CaptchaProps { 6 + pdsUrl: string; 7 + handle: string; 8 + onSuccess: (code: string) => void; 9 + onError?: (error: string) => void; 10 + } 11 + 12 + let {pdsUrl, handle, onSuccess, onError}: CaptchaProps = $props(); 13 + 14 + function generateState(): string { 15 + const array = new Uint8Array(32); 16 + crypto.getRandomValues(array); 17 + return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(''); 18 + } 19 + 20 + let captcha_state = $state(generateState()); 21 + let iframeRef: HTMLIFrameElement | null = $state(null); 22 + let isLoading = $state(true); 23 + 24 + 25 + 26 + const gateUrl = $derived( 27 + `${pdsUrl}/gate/signup?state=${encodeURIComponent(captcha_state)}&handle=${encodeURIComponent(handle)}&redirect_url=${encodeURIComponent(browser ? window.location.origin : 'https://pdsmoover.com')}`, 28 + ); 29 + 30 + // Monitor iframe for URL changes 31 + function checkIframeUrl() { 32 + if (!iframeRef) return; 33 + 34 + try { 35 + const iframeUrl = new URL(iframeRef.contentWindow?.location.href ?? ''); 36 + 37 + // Check if the iframe has been redirected with code and state parameters 38 + // This indicates the captcha was completed 39 + const urlState = iframeUrl.searchParams.get('state'); 40 + const code = iframeUrl.searchParams.get('code'); 41 + 42 + // Only process if we have at least a state parameter (indicates redirect happened) 43 + if (urlState) { 44 + 45 + // Verify state matches 46 + if (urlState !== captcha_state) { 47 + const stateError = 'State mismatch - possible security issue'; 48 + onError?.(stateError); 49 + return; 50 + } 51 + if (!code) { 52 + const codeError = 'No code returned from captcha'; 53 + onError?.(codeError); 54 + return; 55 + 56 + } 57 + 58 + onSuccess(code); 59 + } 60 + } catch { 61 + /* empty */ 62 + } 63 + } 64 + 65 + onMount(() => { 66 + // Poll for URL changes 67 + const interval = setInterval(checkIframeUrl, 100); 68 + 69 + return () => clearInterval(interval); 70 + }); 71 + </script> 72 + 73 + <div class="iframe-wrapper"> 74 + <iframe 75 + bind:this={iframeRef} 76 + src={gateUrl} 77 + title="Captcha Verification" 78 + onload={() => isLoading = false} 79 + ></iframe> 80 + {#if isLoading} 81 + <div class="loading-overlay"> 82 + <p>Loading verification...</p> 83 + </div> 84 + {/if} 85 + </div> 86 + 87 + <style> 88 + 89 + .iframe-wrapper { 90 + position: relative; 91 + width: 100%; 92 + height: 500px; 93 + background: white; 94 + border: 1px solid #ddd; 95 + border-radius: 4px; 96 + overflow: hidden; 97 + } 98 + 99 + iframe { 100 + width: 100%; 101 + height: 100%; 102 + border: none; 103 + } 104 + 105 + .loading-overlay { 106 + position: absolute; 107 + top: 0; 108 + left: 0; 109 + right: 0; 110 + bottom: 0; 111 + background: rgba(255, 255, 255, 0.9); 112 + display: flex; 113 + align-items: center; 114 + justify-content: center; 115 + color: #666; 116 + } 117 + 118 + </style>
+33 -18
web-ui/src/routes/moover/[[pds]]/+page.svelte
··· 4 4 import {resolve} from '$app/paths'; 5 5 import {Migrator} from '@pds-moover/moover'; 6 6 import SignThePapers from './SignThePapers.svelte'; 7 - import Captcha from './Captcha.svelte'; 7 + import Captcha from '$lib/components/Captcha.svelte'; 8 + 8 9 9 10 let {data} = $props(); 10 11 ··· 66 67 let askForPlcToken = $state(false); 67 68 let disableSubmit = $state(false); 68 69 let showCaptcha = $state(false); 70 + let migrationInProgress = $state(false); 69 71 70 72 let errorMessage: null | string = $state(null); 71 73 let statusMessage: null | string = $state(null); ··· 134 136 135 137 async function performMigration() { 136 138 try { 137 - 139 + migrationInProgress = true; 138 140 if (showTwoFactorCodeInput) { 139 141 if (showTwoFactorCodeInput === null) { 140 142 errorMessage = 'Please enter the 2FA that was sent to your email.' ··· 151 153 migrator.migratePrefs = formData.migratePrefs; 152 154 migrator.migratePlcRecord = formData.migratePlcRecord; 153 155 154 - console.log(formData.newPds, newHandle); 155 156 156 157 updateStatusHandler('Starting migration...'); 157 158 showStatusMessage = true; ··· 183 184 } 184 185 //@ts-expect-error: JS being js. doesn't like not having the type' 185 186 errorMessage = error.message; 187 + // migrationInProgress = false; 186 188 } 187 189 } 190 + 188 191 </script> 189 192 190 193 <svelte:head> ··· 194 197 </svelte:head> 195 198 196 199 <div class="container"> 197 - <MooHeader title="PDS MOOver"/> 198 - {#if !askForPlcToken} 200 + <MooHeader title="PDS MOOver"/> 201 + {#if !migrationInProgress} 199 202 <a href={resolve('/info')}>Idk if I trust a cow to move my atproto account to a new PDS</a> 200 203 <br/> 201 204 <a href="https://blacksky.community/profile/did:plc:g7j6qok5us4hjqlwjxwrrkjm/post/3lw3hcuojck2u">Video guide for 202 205 joining blacksky.app</a> 203 206 {#if showCaptcha} 204 207 <Captcha 205 - pdsUrl={formData.newPds} 208 + pdsUrl={`https://${cleanSelectedPds}`} 206 209 handle={newHandle} 207 210 onSuccess={handleCaptchaSuccess} 208 211 onError={handleCaptchaError} ··· 388 391 <span>I understand</span> 389 392 </label> 390 393 </div> 394 + <div> 395 + <button disabled={disableSubmit} 396 + type="submit">{selectedPds ? `MOOve to ${cleanSelectedPds}` : 'MOOve'}</button> 397 + </div> 398 + 399 + </form> 400 + {/if} 401 + {:else} 402 + {#if !askForPlcToken} 403 + <div id="messageBoxes"> 404 + <div class="warning">***Please make sure to stay on this page during the MOOve for the 405 + best result.*** 406 + </div> 407 + 391 408 {#if errorMessage !== null} 392 409 <div class="error-message">{errorMessage}</div> 410 + 411 + <div id="status-message" class="status-message">A error has occurred. Please take a screenshot of this screen for support. You can also retry by refreshing the page, it will not harm your account.</div> 412 + 393 413 {/if} 394 414 395 415 {#if showStatusMessage} 396 - <div id="warning">*Please make sure to stay on this page during the MOOve for the 397 - best result 398 - </div> 399 416 <div id="status-message" class="status-message">{statusMessage}</div> 400 417 {/if} 418 + </div> 419 + {/if} 420 + {/if} 401 421 402 422 403 - <div> 404 - <button disabled={disableSubmit} 405 - type="submit">{selectedPds ? `MOOve to ${cleanSelectedPds}` : 'MOOve'}</button> 406 - </div> 407 - 408 - </form> 409 - {/if} 410 - {:else} 423 + {#if askForPlcToken} 411 424 <SignThePapers migrator={migrator} newHandle={newHandle}/> 412 425 {/if} 413 - </div> 426 + 427 + 428 + </div>
-116
web-ui/src/routes/moover/[[pds]]/Captcha.svelte
··· 1 - <script lang="ts"> 2 - import {onMount} from 'svelte'; 3 - 4 - interface CaptchaProps { 5 - pdsUrl: string; 6 - handle: string; 7 - onSuccess: (code: string) => void; 8 - onError?: (error: string) => void; 9 - } 10 - 11 - let {pdsUrl, handle, onSuccess, onError}: CaptchaProps = $props(); 12 - 13 - function generateState(): string { 14 - const array = new Uint8Array(32); 15 - crypto.getRandomValues(array); 16 - return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join(''); 17 - } 18 - 19 - let captcha_state = $state(generateState()); 20 - let iframeRef: HTMLIFrameElement | null = $state(null); 21 - let isLoading = $state(true); 22 - 23 - 24 - const gateUrl = $derived( 25 - `${pdsUrl}/gate/signup?state=${encodeURIComponent(captcha_state)}&handle=${encodeURIComponent(handle)}&redirect_url=${encodeURIComponent(window.location.origin)}`, 26 - ); 27 - 28 - // Monitor iframe for URL changes 29 - function checkIframeUrl() { 30 - if (!iframeRef) return; 31 - 32 - try { 33 - const iframeUrl = new URL(iframeRef.contentWindow?.location.href ?? ''); 34 - 35 - // Check if the iframe has been redirected with code and state parameters 36 - // This indicates the captcha was completed 37 - const urlState = iframeUrl.searchParams.get('state'); 38 - const code = iframeUrl.searchParams.get('code'); 39 - 40 - // Only process if we have at least a state parameter (indicates redirect happened) 41 - if (urlState) { 42 - 43 - // Verify state matches 44 - if (urlState !== captcha_state) { 45 - const stateError = 'State mismatch - possible security issue'; 46 - onError?.(stateError); 47 - return; 48 - } 49 - if (!code) { 50 - const codeError = 'No code returned from captcha'; 51 - onError?.(codeError); 52 - return; 53 - 54 - } 55 - 56 - onSuccess(code); 57 - } 58 - } catch { 59 - /* empty */ 60 - } 61 - } 62 - 63 - onMount(() => { 64 - // Poll for URL changes 65 - const interval = setInterval(checkIframeUrl, 100); 66 - 67 - return () => clearInterval(interval); 68 - }); 69 - </script> 70 - 71 - <div class="iframe-wrapper"> 72 - <iframe 73 - bind:this={iframeRef} 74 - src={gateUrl} 75 - title="Captcha Verification" 76 - onload={() => isLoading = false} 77 - ></iframe> 78 - {#if isLoading} 79 - <div class="loading-overlay"> 80 - <p>Loading verification...</p> 81 - </div> 82 - {/if} 83 - </div> 84 - 85 - <style> 86 - 87 - .iframe-wrapper { 88 - position: relative; 89 - width: 100%; 90 - height: 500px; 91 - background: white; 92 - border: 1px solid #ddd; 93 - border-radius: 4px; 94 - overflow: hidden; 95 - } 96 - 97 - iframe { 98 - width: 100%; 99 - height: 100%; 100 - border: none; 101 - } 102 - 103 - .loading-overlay { 104 - position: absolute; 105 - top: 0; 106 - left: 0; 107 - right: 0; 108 - bottom: 0; 109 - background: rgba(255, 255, 255, 0.9); 110 - display: flex; 111 - align-items: center; 112 - justify-content: center; 113 - color: #666; 114 - } 115 - 116 - </style>
+7 -6
web-ui/src/routes/moover/[[pds]]/SignThePapers.svelte
··· 80 80 <form onsubmit="{signPlcOperation}"> 81 81 {#if !done} 82 82 <div> 83 - <h2>Please enter your PLC Token you received in an email</h2> 83 + <h2>Please check your email attached to your previous account for a PLC token to enter below</h2> 84 84 <div class="form-group"> 85 85 <label for="plc-token">PLC Token:</label> 86 86 <input type="text" id="plc-token" name="plc-token" bind:value={plcToken} required> 87 87 </div> 88 - <p style="text-align: left">You can now select to add a new Rotation Key during migration and sign up 89 - for PDS MOOver's free backup service. With a Rotation Key and backups if your new PDS ever goes down 90 - you can recover your account and it's data.</p> 88 + <p style="text-align: left"> 89 + Please check the boxes below if you would like to add a Rotation Key to your account and to sign up for PDS MOOver's free backup service. 90 + With a Rotation Key and backups if your new PDS ever goes down 91 + you can recover your account and it's data. This is not required but highly recommended.</p> 91 92 <div class="form-group"> 92 93 <label for="rotation-key" class="moove-checkbox-label"> 93 94 <input bind:checked={createANewRotationKey} type="checkbox" id="rotation-key" ··· 165 166 166 167 {#if done} 167 168 <div class="status-message">Congratulations! You have MOOved to a new PDS! Remember to use 168 - your new PDS URL under "Hosting provider" when logging in on Bluesky. Can find more detail information 169 + your new PDS URL under "Hosting provider" when logging in on Bluesky. If you cannot login or see "Your account is deactivated" please follow the directions here 169 170 <a href={resolve('/info#cant-login')}>here.</a></div> 170 171 {:else } 171 172 <div> ··· 175 176 176 177 177 178 </form> 178 - </div> 179 + </div>

History

1 round 0 comments
sign up or login to add to the discussion
3 commits
expand
some small qol
get ready for release
lockdown
expand 0 comments
pull request successfully merged