- 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
+1
-1
.oxlintrc.json
+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
+1
-1
justfile
+64
-45
packages/moover/lib/pdsmoover.js
+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
+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
+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
-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
+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
-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
+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
-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
+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
-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
+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
-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
+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
-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
+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
-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
+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
+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
+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
+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
+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
-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
+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>