@atproto/pds 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/account-manager/account-manager.d.ts.map +1 -1
- package/dist/account-manager/account-manager.js +16 -19
- package/dist/account-manager/account-manager.js.map +1 -1
- package/dist/account-manager/oauth-store.d.ts.map +1 -1
- package/dist/account-manager/oauth-store.js +46 -26
- package/dist/account-manager/oauth-store.js.map +1 -1
- package/dist/api/com/atproto/admin/deleteAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/admin/deleteAccount.js +9 -4
- package/dist/api/com/atproto/admin/deleteAccount.js.map +1 -1
- package/dist/api/com/atproto/admin/updateSubjectStatus.js +1 -1
- package/dist/api/com/atproto/admin/updateSubjectStatus.js.map +1 -1
- package/dist/api/com/atproto/identity/submitPlcOperation.js +1 -1
- package/dist/api/com/atproto/identity/submitPlcOperation.js.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.js +1 -3
- package/dist/api/com/atproto/server/activateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/createAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/createAccount.js +61 -45
- package/dist/api/com/atproto/server/createAccount.js.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.js +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/deleteAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/deleteAccount.js +9 -4
- package/dist/api/com/atproto/server/deleteAccount.js.map +1 -1
- package/dist/api/com/atproto/sync/getRepo.d.ts.map +1 -1
- package/dist/api/com/atproto/sync/getRepo.js +21 -9
- package/dist/api/com/atproto/sync/getRepo.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -39
- package/dist/index.js.map +1 -1
- package/dist/lexicons/chat/bsky/convo/defs.defs.d.ts +4 -0
- package/dist/lexicons/chat/bsky/convo/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky/convo/defs.defs.js +1 -0
- package/dist/lexicons/chat/bsky/convo/defs.defs.js.map +1 -1
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.d.ts +3 -0
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.defs.d.ts +23 -0
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.defs.d.ts.map +1 -0
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.defs.js +19 -0
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.defs.js.map +1 -0
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.js +6 -0
- package/dist/lexicons/chat/bsky/convo/getUnreadCounts.js.map +1 -0
- package/dist/lexicons/chat/bsky/convo/unlockConvo.defs.d.ts +1 -1
- package/dist/lexicons/chat/bsky/convo/unlockConvo.defs.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky/convo/unlockConvo.defs.js +1 -0
- package/dist/lexicons/chat/bsky/convo/unlockConvo.defs.js.map +1 -1
- package/dist/lexicons/chat/bsky/convo.d.ts +1 -0
- package/dist/lexicons/chat/bsky/convo.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky/convo.js +1 -0
- package/dist/lexicons/chat/bsky/convo.js.map +1 -1
- package/dist/lexicons/chat/bsky/embed/joinLink.defs.d.ts +1 -1
- package/dist/lexicons/chat/bsky/embed/joinLink.defs.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky/embed/joinLink.defs.js +5 -1
- package/dist/lexicons/chat/bsky/embed/joinLink.defs.js.map +1 -1
- package/dist/lexicons/chat/bsky/group/createGroup.defs.d.ts +5 -5
- package/dist/lexicons/chat/bsky/group/createGroup.defs.js +3 -3
- package/dist/lexicons/chat/bsky/group/createGroup.defs.js.map +1 -1
- package/dist/lexicons/chat/bsky/group/defs.defs.d.ts +26 -2
- package/dist/lexicons/chat/bsky/group/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky/group/defs.defs.js +15 -2
- package/dist/lexicons/chat/bsky/group/defs.defs.js.map +1 -1
- package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.d.ts +3 -3
- package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.js +6 -2
- package/dist/lexicons/chat/bsky/group/getJoinLinkPreviews.defs.js.map +1 -1
- package/dist/lexicons/chat/bsky/moderation/subscribeModEvents.defs.d.ts +1 -1
- package/dist/lexicons/chat/bsky/moderation/subscribeModEvents.defs.d.ts.map +1 -1
- package/dist/lexicons/chat/bsky/moderation/subscribeModEvents.defs.js.map +1 -1
- package/dist/lexicons/index.d.ts +1 -0
- package/dist/lexicons/index.d.ts.map +1 -1
- package/dist/lexicons/index.js +1 -0
- package/dist/lexicons/index.js.map +1 -1
- package/dist/lexicons/internal/bsky/actor/getProfiles.d.ts +3 -0
- package/dist/lexicons/internal/bsky/actor/getProfiles.d.ts.map +1 -0
- package/dist/lexicons/internal/bsky/actor/getProfiles.defs.d.ts +38 -0
- package/dist/lexicons/internal/bsky/actor/getProfiles.defs.d.ts.map +1 -0
- package/dist/lexicons/internal/bsky/actor/getProfiles.defs.js +26 -0
- package/dist/lexicons/internal/bsky/actor/getProfiles.defs.js.map +1 -0
- package/dist/lexicons/internal/bsky/actor/getProfiles.js +6 -0
- package/dist/lexicons/internal/bsky/actor/getProfiles.js.map +1 -0
- package/dist/lexicons/internal/bsky/actor.d.ts +2 -0
- package/dist/lexicons/internal/bsky/actor.d.ts.map +1 -0
- package/dist/lexicons/internal/bsky/actor.js +5 -0
- package/dist/lexicons/internal/bsky/actor.js.map +1 -0
- package/dist/lexicons/internal/bsky.d.ts +2 -0
- package/dist/lexicons/internal/bsky.d.ts.map +1 -0
- package/dist/lexicons/internal/bsky.js +5 -0
- package/dist/lexicons/internal/bsky.js.map +1 -0
- package/dist/lexicons/internal.d.ts +2 -0
- package/dist/lexicons/internal.d.ts.map +1 -0
- package/dist/lexicons/internal.js +5 -0
- package/dist/lexicons/internal.js.map +1 -0
- package/dist/rate-limits.d.ts +7 -0
- package/dist/rate-limits.d.ts.map +1 -0
- package/dist/rate-limits.js +50 -0
- package/dist/rate-limits.js.map +1 -0
- package/dist/scripts/publish-identity.js +1 -1
- package/dist/scripts/publish-identity.js.map +1 -1
- package/dist/scripts/rebuild-repo.js +1 -1
- package/dist/scripts/rebuild-repo.js.map +1 -1
- package/dist/scripts/rotate-keys.js +2 -2
- package/dist/scripts/rotate-keys.js.map +1 -1
- package/dist/scripts/sequencer-recovery/recoverer.js +7 -5
- package/dist/scripts/sequencer-recovery/recoverer.js.map +1 -1
- package/dist/sequencer/sequencer.d.ts +8 -6
- package/dist/sequencer/sequencer.d.ts.map +1 -1
- package/dist/sequencer/sequencer.js +40 -21
- package/dist/sequencer/sequencer.js.map +1 -1
- package/package.json +10 -10
- package/src/account-manager/account-manager.ts +26 -23
- package/src/account-manager/oauth-store.ts +55 -36
- package/src/api/com/atproto/admin/deleteAccount.ts +9 -7
- package/src/api/com/atproto/admin/updateSubjectStatus.ts +1 -1
- package/src/api/com/atproto/identity/submitPlcOperation.ts +1 -1
- package/src/api/com/atproto/server/activateAccount.ts +3 -3
- package/src/api/com/atproto/server/createAccount.ts +72 -63
- package/src/api/com/atproto/server/deactivateAccount.ts +1 -1
- package/src/api/com/atproto/server/deleteAccount.ts +9 -7
- package/src/api/com/atproto/sync/getRepo.ts +26 -9
- package/src/index.ts +3 -42
- package/src/rate-limits.ts +59 -0
- package/src/scripts/publish-identity.ts +1 -1
- package/src/scripts/rebuild-repo.ts +1 -1
- package/src/scripts/rotate-keys.ts +2 -2
- package/src/scripts/sequencer-recovery/recoverer.ts +9 -5
- package/src/sequencer/sequencer.ts +52 -23
- package/tests/account-manager.test.ts +78 -0
- package/tsconfig.build.json +2 -2
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +2 -2
- package/tsconfig.tests.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recoverer.js","sourceRoot":"","sources":["../../../src/scripts/sequencer-recovery/recoverer.ts"],"names":[],"mappings":"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","sourcesContent":["import { rmIfExists } from '@atproto/common'\nimport { Secp256k1Keypair } from '@atproto/crypto'\nimport { DidString, isNsidString, isRecordKeyString } from '@atproto/lex'\nimport {\n BlockMap,\n CidSet,\n CommitData,\n WriteOpAction,\n cborToLexRecord,\n parseDataKey,\n readCar,\n} from '@atproto/repo'\nimport {\n AccountManager,\n AccountStatus,\n} from '../../account-manager/account-manager.js'\nimport { ActorStoreTransactor } from '../../actor-store/actor-store-transactor.js'\nimport { ActorStore } from '../../actor-store/actor-store.js'\nimport { countAll } from '../../db/index.js'\nimport {\n PreparedWrite,\n prepareCreate,\n prepareDelete,\n prepareUpdate,\n} from '../../repo/index.js'\nimport {\n AccountEvt,\n CommitEvt,\n SeqEvt,\n Sequencer,\n} from '../../sequencer/index.js'\nimport { RecoveryDb } from './recovery-db.js'\nimport { UserQueues } from './user-queues.js'\n\nexport type RecovererContextNoDb = {\n sequencer: Sequencer\n accountManager: AccountManager\n actorStore: ActorStore\n}\n\nexport type RecovererContext = RecovererContextNoDb & {\n recoveryDb: RecoveryDb\n}\n\nconst PAGE_SIZE = 5000\n\nexport class Recoverer {\n queues: UserQueues\n failed: Set<string>\n\n constructor(\n public ctx: RecovererContext,\n opts: { concurrency: number },\n ) {\n this.queues = new UserQueues(opts.concurrency)\n this.failed = new Set()\n }\n\n async run(startCursor = 0) {\n const failed = await this.ctx.recoveryDb.db\n .selectFrom('failed')\n .select('did')\n .execute()\n for (const row of failed) {\n this.failed.add(row.did)\n }\n\n const totalRes = await this.ctx.sequencer.db.db\n .selectFrom('repo_seq')\n .select(countAll.as('count'))\n .executeTakeFirstOrThrow()\n const totalEvts = totalRes.count\n let completed = 0\n\n let cursor: number | undefined = startCursor\n while (cursor !== undefined) {\n const page = await this.ctx.sequencer.requestSeqRange({\n earliestSeq: cursor,\n limit: PAGE_SIZE,\n })\n page.forEach((evt) => this.processEvent(evt))\n cursor = page.at(-1)?.seq\n\n await this.queues.onEmpty()\n\n completed += PAGE_SIZE\n const percentComplete = (completed / totalEvts) * 100\n console.log(`${percentComplete.toFixed(2)}% - ${cursor}`)\n }\n\n await this.queues.processAll()\n }\n\n async processAll() {\n await this.queues.processAll()\n }\n\n async destroy() {\n await this.queues.destroy()\n }\n\n processEvent(evt: SeqEvt) {\n const did = didFromEvt(evt)\n if (!did) {\n return\n }\n this.queues.addToUser(did, async () => {\n if (this.failed.has(did)) {\n return\n }\n await processSeqEvt(this.ctx, evt).catch(async (err) => {\n this.failed.add(did)\n await trackFailure(this.ctx.recoveryDb, did, err)\n })\n })\n }\n}\n\nexport const processSeqEvt = async (ctx: RecovererContext, evt: SeqEvt) => {\n // only need to process commits & tombstones\n if (evt.type === 'account') {\n await processAccountEvt(ctx, evt.evt)\n }\n if (evt.type === 'commit') {\n await processCommit(ctx, evt.evt).catch()\n }\n}\n\nconst processCommit = async (ctx: RecovererContext, evt: CommitEvt) => {\n const did = evt.repo\n const { writes, blocks } = await parseCommitEvt(evt)\n if (evt.since === null) {\n const actorExists = await ctx.actorStore.exists(did)\n if (!actorExists) {\n await processRepoCreation(ctx, evt, writes, blocks)\n return\n }\n }\n await ctx.actorStore.transact(did, async (actorTxn) => {\n const root = await actorTxn.repo.storage.getRootDetailed()\n if (root.rev >= evt.rev) {\n return\n }\n const commit = await actorTxn.repo.formatCommit(writes)\n commit.newBlocks = blocks\n commit.cid = evt.commit\n commit.rev = evt.rev\n await actorTxn.repo.storage.applyCommit(commit)\n await actorTxn.repo.indexWrites(writes, commit.rev)\n await trackBlobs(actorTxn, writes)\n })\n}\n\nconst processRepoCreation = async (\n ctx: RecovererContext,\n evt: CommitEvt,\n writes: PreparedWrite[],\n blocks: BlockMap,\n) => {\n const did = evt.repo\n const keypair = await Secp256k1Keypair.create({ exportable: true })\n await ctx.actorStore.create(did, keypair)\n const commit: CommitData = {\n cid: evt.commit,\n rev: evt.rev,\n since: evt.since,\n prev: null,\n newBlocks: blocks,\n relevantBlocks: new BlockMap(),\n removedCids: new CidSet(),\n }\n await ctx.actorStore.transact(did, async (actorTxn) => {\n await actorTxn.repo.storage.applyCommit(commit, true)\n await actorTxn.repo.indexWrites(writes, commit.rev)\n await actorTxn.repo.blob.processWriteBlobs(commit.rev, writes)\n })\n await trackNewAccount(ctx.recoveryDb, did)\n}\n\nconst processAccountEvt = async (ctx: RecovererContext, evt: AccountEvt) => {\n // do not need to process deactivation/takedowns because we backup account DB as well\n if (evt.status !== AccountStatus.Deleted) {\n return\n }\n const { directory } = await ctx.actorStore.getLocation(evt.did)\n await rmIfExists(directory, true)\n await ctx.accountManager.deleteAccount(evt.did)\n}\n\nconst trackBlobs = async (\n store: ActorStoreTransactor,\n writes: PreparedWrite[],\n) => {\n await store.repo.blob.deleteDereferencedBlobs(writes)\n\n for (const write of writes) {\n if (\n write.action === WriteOpAction.Create ||\n write.action === WriteOpAction.Update\n ) {\n for (const blob of write.blobs) {\n await store.repo.blob.insertBlobMetadata(blob)\n await store.repo.blob.associateBlob(blob, write.uri)\n }\n }\n }\n}\n\nconst trackFailure = async (\n recoveryDb: RecoveryDb,\n did: DidString,\n err: unknown,\n) => {\n await recoveryDb.db\n .insertInto('failed')\n .values({\n did,\n error: err?.toString(),\n fixed: 0,\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n}\n\nconst trackNewAccount = async (recoveryDb: RecoveryDb, did: DidString) => {\n await recoveryDb.db\n .insertInto('new_account')\n .values({\n did,\n published: 0,\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n}\n\nconst parseCommitEvt = async (\n evt: CommitEvt,\n): Promise<{\n writes: PreparedWrite[]\n blocks: BlockMap\n}> => {\n const did = evt.repo\n const evtCar = await readCar(evt.blocks, { skipCidVerification: true })\n const writesUnfiltered = await Promise.all(\n evt.ops.map(async (op) => {\n const { collection, rkey } = parseDataKey(op.path)\n if (!isNsidString(collection)) return undefined\n if (!isRecordKeyString(rkey)) return undefined\n\n if (op.action === 'delete') {\n return prepareDelete({ did, collection, rkey })\n }\n if (!op.cid) return undefined\n\n const recordBytes = evtCar.blocks.get(op.cid)\n if (!recordBytes) return undefined\n const record = cborToLexRecord(recordBytes)\n\n if (op.action === 'create') {\n return prepareCreate({\n did,\n collection,\n rkey,\n record,\n validate: false,\n })\n } else {\n return prepareUpdate({\n did,\n collection,\n rkey,\n record,\n validate: false,\n })\n }\n }),\n )\n\n return {\n writes: writesUnfiltered.filter((w) => w != null),\n blocks: evtCar.blocks,\n }\n}\n\nconst didFromEvt = (evt: SeqEvt): DidString | null => {\n if (evt.type === 'account') {\n return evt.evt.did\n } else if (evt.type === 'commit') {\n return evt.evt.repo\n } else {\n return null\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"recoverer.js","sourceRoot":"","sources":["../../../src/scripts/sequencer-recovery/recoverer.ts"],"names":[],"mappings":"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","sourcesContent":["import { rmIfExists } from '@atproto/common'\nimport { Secp256k1Keypair } from '@atproto/crypto'\nimport { DidString, isNsidString, isRecordKeyString } from '@atproto/lex'\nimport {\n BlockMap,\n CidSet,\n CommitData,\n WriteOpAction,\n cborToLexRecord,\n parseDataKey,\n readCar,\n} from '@atproto/repo'\nimport {\n AccountManager,\n AccountStatus,\n} from '../../account-manager/account-manager.js'\nimport { ActorStoreTransactor } from '../../actor-store/actor-store-transactor.js'\nimport { ActorStore } from '../../actor-store/actor-store.js'\nimport { countAll } from '../../db/index.js'\nimport {\n PreparedWrite,\n prepareCreate,\n prepareDelete,\n prepareUpdate,\n} from '../../repo/index.js'\nimport {\n AccountEvt,\n CommitEvt,\n SeqEvt,\n Sequencer,\n} from '../../sequencer/index.js'\nimport { RecoveryDb } from './recovery-db.js'\nimport { UserQueues } from './user-queues.js'\n\nexport type RecovererContextNoDb = {\n sequencer: Sequencer\n accountManager: AccountManager\n actorStore: ActorStore\n}\n\nexport type RecovererContext = RecovererContextNoDb & {\n recoveryDb: RecoveryDb\n}\n\nconst PAGE_SIZE = 5000\n\nexport class Recoverer {\n queues: UserQueues\n failed: Set<string>\n\n constructor(\n public ctx: RecovererContext,\n opts: { concurrency: number },\n ) {\n this.queues = new UserQueues(opts.concurrency)\n this.failed = new Set()\n }\n\n async run(startCursor = 0) {\n const failed = await this.ctx.recoveryDb.db\n .selectFrom('failed')\n .select('did')\n .execute()\n for (const row of failed) {\n this.failed.add(row.did)\n }\n\n const totalRes = await this.ctx.sequencer.db.db\n .selectFrom('repo_seq')\n .select(countAll.as('count'))\n .executeTakeFirstOrThrow()\n const totalEvts = totalRes.count\n let completed = 0\n\n let cursor: number | undefined = startCursor\n while (cursor !== undefined) {\n const page = await this.ctx.sequencer.requestSeqRange({\n earliestSeq: cursor,\n limit: PAGE_SIZE,\n })\n page.forEach((evt) => this.processEvent(evt))\n cursor = page.at(-1)?.seq\n\n await this.queues.onEmpty()\n\n completed += PAGE_SIZE\n const percentComplete = (completed / totalEvts) * 100\n console.log(`${percentComplete.toFixed(2)}% - ${cursor}`)\n }\n\n await this.queues.processAll()\n }\n\n async processAll() {\n await this.queues.processAll()\n }\n\n async destroy() {\n await this.queues.destroy()\n }\n\n processEvent(evt: SeqEvt) {\n const did = didFromEvt(evt)\n if (!did) {\n return\n }\n this.queues.addToUser(did, async () => {\n if (this.failed.has(did)) {\n return\n }\n await processSeqEvt(this.ctx, evt).catch(async (err) => {\n this.failed.add(did)\n await trackFailure(this.ctx.recoveryDb, did, err)\n })\n })\n }\n}\n\nexport const processSeqEvt = async (ctx: RecovererContext, evt: SeqEvt) => {\n // only need to process commits & tombstones\n if (evt.type === 'account') {\n await processAccountEvt(ctx, evt.evt)\n }\n if (evt.type === 'commit') {\n await processCommit(ctx, evt.evt).catch()\n }\n}\n\nconst processCommit = async (ctx: RecovererContext, evt: CommitEvt) => {\n const did = evt.repo\n const { writes, blocks } = await parseCommitEvt(evt)\n if (evt.since === null) {\n const actorExists = await ctx.actorStore.exists(did)\n if (!actorExists) {\n await processRepoCreation(ctx, evt, writes, blocks)\n return\n }\n }\n await ctx.actorStore.transact(did, async (actorTxn) => {\n const root = await actorTxn.repo.storage.getRootDetailed()\n if (root.rev >= evt.rev) {\n return\n }\n const commit = await actorTxn.repo.formatCommit(writes)\n commit.newBlocks = blocks\n commit.cid = evt.commit\n commit.rev = evt.rev\n await actorTxn.repo.storage.applyCommit(commit)\n await actorTxn.repo.indexWrites(writes, commit.rev)\n await trackBlobs(actorTxn, writes)\n })\n}\n\nconst processRepoCreation = async (\n ctx: RecovererContext,\n evt: CommitEvt,\n writes: PreparedWrite[],\n blocks: BlockMap,\n) => {\n const did = evt.repo\n const keypair = await Secp256k1Keypair.create({ exportable: true })\n await ctx.actorStore.create(did, keypair)\n const commit: CommitData = {\n cid: evt.commit,\n rev: evt.rev,\n since: evt.since,\n prev: null,\n newBlocks: blocks,\n relevantBlocks: new BlockMap(),\n removedCids: new CidSet(),\n }\n await ctx.actorStore.transact(did, async (actorTxn) => {\n await actorTxn.repo.storage.applyCommit(commit, true)\n await actorTxn.repo.indexWrites(writes, commit.rev)\n await actorTxn.repo.blob.processWriteBlobs(commit.rev, writes)\n })\n await trackNewAccount(ctx.recoveryDb, did)\n}\n\nconst processAccountEvt = async (ctx: RecovererContext, evt: AccountEvt) => {\n // do not need to process deactivation/takedowns because we backup account DB as well\n\n if (evt.status === AccountStatus.Deleted) {\n // In case an account deletion was sequenced, let's make sure to (first)\n // delete the accounts database, and (then) unlink the actor store from the\n // file system. Order matters here.\n await ctx.accountManager.deleteAccount(evt.did)\n\n const { directory } = await ctx.actorStore.getLocation(evt.did)\n await rmIfExists(directory, true)\n }\n}\n\nconst trackBlobs = async (\n store: ActorStoreTransactor,\n writes: PreparedWrite[],\n) => {\n await store.repo.blob.deleteDereferencedBlobs(writes)\n\n for (const write of writes) {\n if (\n write.action === WriteOpAction.Create ||\n write.action === WriteOpAction.Update\n ) {\n for (const blob of write.blobs) {\n await store.repo.blob.insertBlobMetadata(blob)\n await store.repo.blob.associateBlob(blob, write.uri)\n }\n }\n }\n}\n\nconst trackFailure = async (\n recoveryDb: RecoveryDb,\n did: DidString,\n err: unknown,\n) => {\n await recoveryDb.db\n .insertInto('failed')\n .values({\n did,\n error: err?.toString(),\n fixed: 0,\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n}\n\nconst trackNewAccount = async (recoveryDb: RecoveryDb, did: DidString) => {\n await recoveryDb.db\n .insertInto('new_account')\n .values({\n did,\n published: 0,\n })\n .onConflict((oc) => oc.doNothing())\n .execute()\n}\n\nconst parseCommitEvt = async (\n evt: CommitEvt,\n): Promise<{\n writes: PreparedWrite[]\n blocks: BlockMap\n}> => {\n const did = evt.repo\n const evtCar = await readCar(evt.blocks, { skipCidVerification: true })\n const writesUnfiltered = await Promise.all(\n evt.ops.map(async (op) => {\n const { collection, rkey } = parseDataKey(op.path)\n if (!isNsidString(collection)) return undefined\n if (!isRecordKeyString(rkey)) return undefined\n\n if (op.action === 'delete') {\n return prepareDelete({ did, collection, rkey })\n }\n if (!op.cid) return undefined\n\n const recordBytes = evtCar.blocks.get(op.cid)\n if (!recordBytes) return undefined\n const record = cborToLexRecord(recordBytes)\n\n if (op.action === 'create') {\n return prepareCreate({\n did,\n collection,\n rkey,\n record,\n validate: false,\n })\n } else {\n return prepareUpdate({\n did,\n collection,\n rkey,\n record,\n validate: false,\n })\n }\n }),\n )\n\n return {\n writes: writesUnfiltered.filter((w) => w != null),\n blocks: evtCar.blocks,\n }\n}\n\nconst didFromEvt = (evt: SeqEvt): DidString | null => {\n if (evt.type === 'account') {\n return evt.evt.did\n } else if (evt.type === 'commit') {\n return evt.evt.repo\n } else {\n return null\n }\n}\n"]}
|
|
@@ -29,12 +29,14 @@ export declare class Sequencer extends Sequencer_base {
|
|
|
29
29
|
}): Promise<SeqEvt[]>;
|
|
30
30
|
private pollDb;
|
|
31
31
|
private exponentialBackoff;
|
|
32
|
-
|
|
33
|
-
sequenceCommit(did: DidString, commitData: CommitDataWithOps): Promise<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
protected sequenceEvts(events: readonly RepoSeqInsert[]): Promise<number[]>;
|
|
33
|
+
sequenceCommit(did: DidString, commitData: CommitDataWithOps): Promise<void>;
|
|
34
|
+
sequenceSync(did: DidString, data: SyncEvtData): Promise<void>;
|
|
35
|
+
sequenceIdentity(did: DidString, handle?: HandleString): Promise<void>;
|
|
36
|
+
sequenceAccount(did: DidString, status: AccountStatus): Promise<void>;
|
|
37
|
+
sequenceAccountCreation(did: DidString, handle: HandleString, commit: CommitDataWithOps): Promise<void>;
|
|
38
|
+
sequenceAccountActivation(did: DidString, handle: HandleString, status: AccountStatus, syncData: SyncEvtData): Promise<void>;
|
|
39
|
+
sequenceAccountDeletion(did: DidString): Promise<void>;
|
|
38
40
|
}
|
|
39
41
|
export declare const parseRepoSeqRows: (rows: RepoSeqEntry[]) => SeqEvt[];
|
|
40
42
|
type SeqRow = RepoSeqEntry;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer.d.ts","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,YAAY,MAAM,eAAe,CAAA;AAG7C,OAAO,EAAkB,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,EACL,YAAY,EACZ,aAAa,EACb,WAAW,EAGZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAIL,MAAM,
|
|
1
|
+
{"version":3,"file":"sequencer.d.ts","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,YAAY,MAAM,eAAe,CAAA;AAG7C,OAAO,EAAkB,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AACrE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACjE,OAAO,EACL,YAAY,EACZ,aAAa,EACb,WAAW,EAGZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAIL,MAAM,EAOP,MAAM,aAAa,CAAA;AAEpB,cAAc,aAAa,CAAA;8BAEqB,UAAU,gBAAgB;AAA1E,qBAAa,SAAU,SAAQ,cAA4C;IAOhE,UAAU,EAAE,MAAM;IAClB,QAAQ,EAAE,QAAQ;IAClB,QAAQ;IARjB,EAAE,EAAE,WAAW,CAAA;IACf,SAAS,UAAQ;IACjB,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAO;IACxC,kBAAkB,SAAI;gBAGb,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,SAAI,EACnB,wBAAwB,UAAQ;IAQ5B,KAAK;IAWL,OAAO;IAQP,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAU9B,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW5C,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAWvD,eAAe,CAAC,IAAI,EAAE;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YA6BP,MAAM;YAwBN,kBAAkB;cAMhB,YAAY,CAC1B,MAAM,EAAE,SAAS,aAAa,EAAE,GAC/B,OAAO,CAAC,MAAM,EAAE,CAAC;IASP,cAAc,CACzB,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,iBAAiB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAIH,YAAY,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,gBAAgB,CAC3B,GAAG,EAAE,SAAS,EACd,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC;IAIH,eAAe,CAC1B,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC;IAIH,uBAAuB,CAClC,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,IAAI,CAAC;IAUH,yBAAyB,CACpC,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,WAAW,GACpB,OAAO,CAAC,IAAI,CAAC;IASH,uBAAuB,CAAC,GAAG,EAAE,SAAS;CAWpD;AAED,eAAO,MAAM,gBAAgB,GAAI,MAAM,YAAY,EAAE,KAAG,MAAM,EAuC7D,CAAA;AAED,KAAK,MAAM,GAAG,YAAY,CAAA;AAE1B,KAAK,eAAe,GAAG;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IAChC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;AAEpE,eAAe,SAAS,CAAA"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import EventEmitter from 'node:events';
|
|
2
2
|
import { SECOND, wait } from '@atproto/common';
|
|
3
3
|
import { decode as cborDecode } from '@atproto/lex-cbor';
|
|
4
|
+
import { AccountStatus } from '../account-manager/helpers/account.js';
|
|
4
5
|
import { seqLogger as log } from '../logger.js';
|
|
5
6
|
import { getDb, getMigrator, } from './db/index.js';
|
|
6
|
-
import { formatSeqAccountEvt, formatSeqCommit, formatSeqIdentityEvt, formatSeqSyncEvt, } from './events.js';
|
|
7
|
+
import { formatSeqAccountEvt, formatSeqCommit, formatSeqIdentityEvt, formatSeqSyncEvt, syncEvtDataFromCommit, } from './events.js';
|
|
7
8
|
export * from './events.js';
|
|
8
9
|
export class Sequencer extends EventEmitter {
|
|
9
10
|
constructor(dbLocation, crawlers, lastSeen = 0, disableWalAutoCheckpoint = false) {
|
|
@@ -120,32 +121,50 @@ export class Sequencer extends EventEmitter {
|
|
|
120
121
|
const waitTime = Math.min(Math.pow(2, this.triesWithNoResults), SECOND);
|
|
121
122
|
await wait(waitTime);
|
|
122
123
|
}
|
|
123
|
-
async
|
|
124
|
-
|
|
124
|
+
async sequenceEvts(events) {
|
|
125
|
+
if (!events.length)
|
|
126
|
+
return [];
|
|
127
|
+
const rows = await this.db.executeWithRetry(this.db.db.insertInto('repo_seq').values(events).returning('seq'));
|
|
125
128
|
this.crawlers.notifyOfUpdate();
|
|
126
|
-
return seq;
|
|
129
|
+
return rows.map((row) => row.seq);
|
|
127
130
|
}
|
|
128
131
|
async sequenceCommit(did, commitData) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
async
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
132
|
+
await this.sequenceEvts([await formatSeqCommit(did, commitData)]);
|
|
133
|
+
}
|
|
134
|
+
async sequenceSync(did, data) {
|
|
135
|
+
await this.sequenceEvts([await formatSeqSyncEvt(did, data)]);
|
|
136
|
+
}
|
|
137
|
+
async sequenceIdentity(did, handle) {
|
|
138
|
+
await this.sequenceEvts([await formatSeqIdentityEvt(did, handle)]);
|
|
139
|
+
}
|
|
140
|
+
async sequenceAccount(did, status) {
|
|
141
|
+
await this.sequenceEvts([await formatSeqAccountEvt(did, status)]);
|
|
142
|
+
}
|
|
143
|
+
async sequenceAccountCreation(did, handle, commit) {
|
|
144
|
+
// Atomically sequence all events
|
|
145
|
+
await this.sequenceEvts([
|
|
146
|
+
await formatSeqIdentityEvt(did, handle),
|
|
147
|
+
await formatSeqAccountEvt(did, AccountStatus.Active),
|
|
148
|
+
await formatSeqCommit(did, commit),
|
|
149
|
+
await formatSeqSyncEvt(did, syncEvtDataFromCommit(commit)),
|
|
150
|
+
]);
|
|
151
|
+
}
|
|
152
|
+
async sequenceAccountActivation(did, handle, status, syncData) {
|
|
153
|
+
// Atomically sequence all events
|
|
154
|
+
await this.sequenceEvts([
|
|
155
|
+
await formatSeqAccountEvt(did, status),
|
|
156
|
+
await formatSeqIdentityEvt(did, handle),
|
|
157
|
+
await formatSeqSyncEvt(did, syncData),
|
|
158
|
+
]);
|
|
159
|
+
}
|
|
160
|
+
async sequenceAccountDeletion(did) {
|
|
161
|
+
const [seq] = await this.sequenceEvts([
|
|
162
|
+
await formatSeqAccountEvt(did, AccountStatus.Deleted),
|
|
163
|
+
]);
|
|
145
164
|
await this.db.executeWithRetry(this.db.db
|
|
146
165
|
.deleteFrom('repo_seq')
|
|
147
166
|
.where('did', '=', did)
|
|
148
|
-
.
|
|
167
|
+
.where('seq', '!=', seq));
|
|
149
168
|
}
|
|
150
169
|
}
|
|
151
170
|
export const parseRepoSeqRows = (rows) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer.js","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"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","sourcesContent":["import EventEmitter from 'node:events'\nimport type TypedEmitter from 'typed-emitter'\nimport { SECOND, wait } from '@atproto/common'\nimport { decode as cborDecode } from '@atproto/lex-cbor'\nimport { DatetimeString, DidString, HandleString } from '@atproto/syntax'\nimport { AccountStatus } from '../account-manager/helpers/account.js'\nimport { Crawlers } from '../crawlers.js'\nimport { seqLogger as log } from '../logger.js'\nimport { CommitDataWithOps, SyncEvtData } from '../repo/index.js'\nimport {\n RepoSeqEntry,\n RepoSeqInsert,\n SequencerDb,\n getDb,\n getMigrator,\n} from './db/index.js'\nimport {\n AccountEvt,\n CommitEvt,\n IdentityEvt,\n SeqEvt,\n SyncEvt,\n formatSeqAccountEvt,\n formatSeqCommit,\n formatSeqIdentityEvt,\n formatSeqSyncEvt,\n} from './events.js'\n\nexport * from './events.js'\n\nexport class Sequencer extends (EventEmitter as new () => SequencerEmitter) {\n db: SequencerDb\n destroyed = false\n pollPromise: Promise<void> | null = null\n triesWithNoResults = 0\n\n constructor(\n public dbLocation: string,\n public crawlers: Crawlers,\n public lastSeen = 0,\n disableWalAutoCheckpoint = false,\n ) {\n super()\n // note: this does not err when surpassed, just prints a warning to stderr\n this.setMaxListeners(100)\n this.db = getDb(dbLocation, disableWalAutoCheckpoint)\n }\n\n async start() {\n await this.db.ensureWal()\n const migrator = getMigrator(this.db)\n await migrator.migrateToLatestOrThrow()\n const curr = await this.curr()\n this.lastSeen = curr ?? 0\n if (this.pollPromise === null) {\n this.pollPromise = this.pollDb()\n }\n }\n\n async destroy() {\n this.destroyed = true\n if (this.pollPromise) {\n await this.pollPromise\n }\n this.emit('close')\n }\n\n async curr(): Promise<number | null> {\n const got = await this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .orderBy('seq', 'desc')\n .limit(1)\n .executeTakeFirst()\n return got?.seq ?? null\n }\n\n async next(cursor: number): Promise<SeqRow | null> {\n const got = await this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .where('seq', '>', cursor)\n .limit(1)\n .orderBy('seq', 'asc')\n .executeTakeFirst()\n return got || null\n }\n\n async earliestAfterTime(time: string): Promise<SeqRow | null> {\n const got = await this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .where('sequencedAt', '>=', time)\n .orderBy('sequencedAt', 'asc')\n .limit(1)\n .executeTakeFirst()\n return got || null\n }\n\n async requestSeqRange(opts: {\n earliestSeq?: number\n latestSeq?: number\n earliestTime?: string\n limit?: number\n }): Promise<SeqEvt[]> {\n const { earliestSeq, latestSeq, earliestTime, limit } = opts\n\n let seqQb = this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .orderBy('seq', 'asc')\n .where('invalidated', '=', 0)\n if (earliestSeq !== undefined) {\n seqQb = seqQb.where('seq', '>', earliestSeq)\n }\n if (latestSeq !== undefined) {\n seqQb = seqQb.where('seq', '<=', latestSeq)\n }\n if (earliestTime !== undefined) {\n seqQb = seqQb.where('sequencedAt', '>=', earliestTime)\n }\n if (limit !== undefined) {\n seqQb = seqQb.limit(limit)\n }\n\n const rows = await seqQb.execute()\n if (rows.length < 1) {\n return []\n }\n\n return parseRepoSeqRows(rows)\n }\n\n private async pollDb(): Promise<void> {\n if (this.destroyed) return\n // if already polling, do not start another poll\n try {\n const evts = await this.requestSeqRange({\n earliestSeq: this.lastSeen,\n limit: 1000,\n })\n if (evts.length > 0) {\n this.triesWithNoResults = 0\n this.emit('events', evts)\n this.lastSeen = evts.at(-1)?.seq ?? this.lastSeen\n } else {\n await this.exponentialBackoff()\n }\n this.pollPromise = this.pollDb()\n } catch (err) {\n log.error({ err, lastSeen: this.lastSeen }, 'sequencer failed to poll db')\n await this.exponentialBackoff()\n this.pollPromise = this.pollDb()\n }\n }\n\n // when no results, exponential backoff on pulling, with a max of a second wait\n private async exponentialBackoff(): Promise<void> {\n this.triesWithNoResults++\n const waitTime = Math.min(Math.pow(2, this.triesWithNoResults), SECOND)\n await wait(waitTime)\n }\n\n async sequenceEvt(evt: RepoSeqInsert): Promise<number> {\n const [{ seq }] = await this.db.executeWithRetry(\n this.db.db.insertInto('repo_seq').values(evt).returning('seq'),\n )\n this.crawlers.notifyOfUpdate()\n return seq\n }\n\n async sequenceCommit(\n did: DidString,\n commitData: CommitDataWithOps,\n ): Promise<number> {\n const evt = await formatSeqCommit(did, commitData)\n return this.sequenceEvt(evt)\n }\n\n async sequenceSyncEvt(did: DidString, data: SyncEvtData) {\n const evt = await formatSeqSyncEvt(did, data)\n return this.sequenceEvt(evt)\n }\n\n async sequenceIdentityEvt(\n did: DidString,\n handle?: HandleString,\n ): Promise<number> {\n const evt = await formatSeqIdentityEvt(did, handle)\n return this.sequenceEvt(evt)\n }\n\n async sequenceAccountEvt(\n did: DidString,\n status: AccountStatus,\n ): Promise<number> {\n const evt = await formatSeqAccountEvt(did, status)\n return this.sequenceEvt(evt)\n }\n\n async deleteAllForUser(did: string, excludingSeqs: number[] = []) {\n await this.db.executeWithRetry(\n this.db.db\n .deleteFrom('repo_seq')\n .where('did', '=', did)\n .if(excludingSeqs.length > 0, (qb) =>\n qb.where('seq', 'not in', excludingSeqs),\n ),\n )\n }\n}\n\nexport const parseRepoSeqRows = (rows: RepoSeqEntry[]): SeqEvt[] => {\n const seqEvts: SeqEvt[] = []\n for (const row of rows) {\n // should never hit this because of WHERE clause\n if (row.seq === null) {\n continue\n }\n const evt = cborDecode(row.event)\n if (row.eventType === 'append') {\n seqEvts.push({\n type: 'commit',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as CommitEvt,\n })\n } else if (row.eventType === 'sync') {\n seqEvts.push({\n type: 'sync',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as SyncEvt,\n })\n } else if (row.eventType === 'identity') {\n seqEvts.push({\n type: 'identity',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as IdentityEvt,\n })\n } else if (row.eventType === 'account') {\n seqEvts.push({\n type: 'account',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as AccountEvt,\n })\n }\n }\n return seqEvts\n}\n\ntype SeqRow = RepoSeqEntry\n\ntype SequencerEvents = {\n events: (evts: SeqEvt[]) => void\n close: () => void\n}\n\nexport type SequencerEmitter = TypedEmitter.default<SequencerEvents>\n\nexport default Sequencer\n"]}
|
|
1
|
+
{"version":3,"file":"sequencer.js","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"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","sourcesContent":["import EventEmitter from 'node:events'\nimport type TypedEmitter from 'typed-emitter'\nimport { SECOND, wait } from '@atproto/common'\nimport { decode as cborDecode } from '@atproto/lex-cbor'\nimport { DatetimeString, DidString, HandleString } from '@atproto/syntax'\nimport { AccountStatus } from '../account-manager/helpers/account.js'\nimport { Crawlers } from '../crawlers.js'\nimport { seqLogger as log } from '../logger.js'\nimport { CommitDataWithOps, SyncEvtData } from '../repo/index.js'\nimport {\n RepoSeqEntry,\n RepoSeqInsert,\n SequencerDb,\n getDb,\n getMigrator,\n} from './db/index.js'\nimport {\n AccountEvt,\n CommitEvt,\n IdentityEvt,\n SeqEvt,\n SyncEvt,\n formatSeqAccountEvt,\n formatSeqCommit,\n formatSeqIdentityEvt,\n formatSeqSyncEvt,\n syncEvtDataFromCommit,\n} from './events.js'\n\nexport * from './events.js'\n\nexport class Sequencer extends (EventEmitter as new () => SequencerEmitter) {\n db: SequencerDb\n destroyed = false\n pollPromise: Promise<void> | null = null\n triesWithNoResults = 0\n\n constructor(\n public dbLocation: string,\n public crawlers: Crawlers,\n public lastSeen = 0,\n disableWalAutoCheckpoint = false,\n ) {\n super()\n // note: this does not err when surpassed, just prints a warning to stderr\n this.setMaxListeners(100)\n this.db = getDb(dbLocation, disableWalAutoCheckpoint)\n }\n\n async start() {\n await this.db.ensureWal()\n const migrator = getMigrator(this.db)\n await migrator.migrateToLatestOrThrow()\n const curr = await this.curr()\n this.lastSeen = curr ?? 0\n if (this.pollPromise === null) {\n this.pollPromise = this.pollDb()\n }\n }\n\n async destroy() {\n this.destroyed = true\n if (this.pollPromise) {\n await this.pollPromise\n }\n this.emit('close')\n }\n\n async curr(): Promise<number | null> {\n const got = await this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .orderBy('seq', 'desc')\n .limit(1)\n .executeTakeFirst()\n return got?.seq ?? null\n }\n\n async next(cursor: number): Promise<SeqRow | null> {\n const got = await this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .where('seq', '>', cursor)\n .limit(1)\n .orderBy('seq', 'asc')\n .executeTakeFirst()\n return got || null\n }\n\n async earliestAfterTime(time: string): Promise<SeqRow | null> {\n const got = await this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .where('sequencedAt', '>=', time)\n .orderBy('sequencedAt', 'asc')\n .limit(1)\n .executeTakeFirst()\n return got || null\n }\n\n async requestSeqRange(opts: {\n earliestSeq?: number\n latestSeq?: number\n earliestTime?: string\n limit?: number\n }): Promise<SeqEvt[]> {\n const { earliestSeq, latestSeq, earliestTime, limit } = opts\n\n let seqQb = this.db.db\n .selectFrom('repo_seq')\n .selectAll()\n .orderBy('seq', 'asc')\n .where('invalidated', '=', 0)\n if (earliestSeq !== undefined) {\n seqQb = seqQb.where('seq', '>', earliestSeq)\n }\n if (latestSeq !== undefined) {\n seqQb = seqQb.where('seq', '<=', latestSeq)\n }\n if (earliestTime !== undefined) {\n seqQb = seqQb.where('sequencedAt', '>=', earliestTime)\n }\n if (limit !== undefined) {\n seqQb = seqQb.limit(limit)\n }\n\n const rows = await seqQb.execute()\n if (rows.length < 1) {\n return []\n }\n\n return parseRepoSeqRows(rows)\n }\n\n private async pollDb(): Promise<void> {\n if (this.destroyed) return\n // if already polling, do not start another poll\n try {\n const evts = await this.requestSeqRange({\n earliestSeq: this.lastSeen,\n limit: 1000,\n })\n if (evts.length > 0) {\n this.triesWithNoResults = 0\n this.emit('events', evts)\n this.lastSeen = evts.at(-1)?.seq ?? this.lastSeen\n } else {\n await this.exponentialBackoff()\n }\n this.pollPromise = this.pollDb()\n } catch (err) {\n log.error({ err, lastSeen: this.lastSeen }, 'sequencer failed to poll db')\n await this.exponentialBackoff()\n this.pollPromise = this.pollDb()\n }\n }\n\n // when no results, exponential backoff on pulling, with a max of a second wait\n private async exponentialBackoff(): Promise<void> {\n this.triesWithNoResults++\n const waitTime = Math.min(Math.pow(2, this.triesWithNoResults), SECOND)\n await wait(waitTime)\n }\n\n protected async sequenceEvts(\n events: readonly RepoSeqInsert[],\n ): Promise<number[]> {\n if (!events.length) return []\n const rows = await this.db.executeWithRetry(\n this.db.db.insertInto('repo_seq').values(events).returning('seq'),\n )\n this.crawlers.notifyOfUpdate()\n return rows.map((row) => row.seq)\n }\n\n public async sequenceCommit(\n did: DidString,\n commitData: CommitDataWithOps,\n ): Promise<void> {\n await this.sequenceEvts([await formatSeqCommit(did, commitData)])\n }\n\n public async sequenceSync(did: DidString, data: SyncEvtData): Promise<void> {\n await this.sequenceEvts([await formatSeqSyncEvt(did, data)])\n }\n\n public async sequenceIdentity(\n did: DidString,\n handle?: HandleString,\n ): Promise<void> {\n await this.sequenceEvts([await formatSeqIdentityEvt(did, handle)])\n }\n\n public async sequenceAccount(\n did: DidString,\n status: AccountStatus,\n ): Promise<void> {\n await this.sequenceEvts([await formatSeqAccountEvt(did, status)])\n }\n\n public async sequenceAccountCreation(\n did: DidString,\n handle: HandleString,\n commit: CommitDataWithOps,\n ): Promise<void> {\n // Atomically sequence all events\n await this.sequenceEvts([\n await formatSeqIdentityEvt(did, handle),\n await formatSeqAccountEvt(did, AccountStatus.Active),\n await formatSeqCommit(did, commit),\n await formatSeqSyncEvt(did, syncEvtDataFromCommit(commit)),\n ])\n }\n\n public async sequenceAccountActivation(\n did: DidString,\n handle: HandleString,\n status: AccountStatus,\n syncData: SyncEvtData,\n ): Promise<void> {\n // Atomically sequence all events\n await this.sequenceEvts([\n await formatSeqAccountEvt(did, status),\n await formatSeqIdentityEvt(did, handle),\n await formatSeqSyncEvt(did, syncData),\n ])\n }\n\n public async sequenceAccountDeletion(did: DidString) {\n const [seq] = await this.sequenceEvts([\n await formatSeqAccountEvt(did, AccountStatus.Deleted),\n ])\n await this.db.executeWithRetry(\n this.db.db\n .deleteFrom('repo_seq')\n .where('did', '=', did)\n .where('seq', '!=', seq),\n )\n }\n}\n\nexport const parseRepoSeqRows = (rows: RepoSeqEntry[]): SeqEvt[] => {\n const seqEvts: SeqEvt[] = []\n for (const row of rows) {\n // should never hit this because of WHERE clause\n if (row.seq === null) {\n continue\n }\n const evt = cborDecode(row.event)\n if (row.eventType === 'append') {\n seqEvts.push({\n type: 'commit',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as CommitEvt,\n })\n } else if (row.eventType === 'sync') {\n seqEvts.push({\n type: 'sync',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as SyncEvt,\n })\n } else if (row.eventType === 'identity') {\n seqEvts.push({\n type: 'identity',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as IdentityEvt,\n })\n } else if (row.eventType === 'account') {\n seqEvts.push({\n type: 'account',\n seq: row.seq,\n time: row.sequencedAt as DatetimeString,\n evt: evt as AccountEvt,\n })\n }\n }\n return seqEvts\n}\n\ntype SeqRow = RepoSeqEntry\n\ntype SequencerEvents = {\n events: (evts: SeqEvt[]) => void\n close: () => void\n}\n\nexport type SequencerEmitter = TypedEmitter.default<SequencerEvents>\n\nexport default Sequencer\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/pds",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Reference implementation of atproto Personal Data Server (PDS)",
|
|
6
6
|
"keywords": [
|
|
@@ -43,25 +43,25 @@
|
|
|
43
43
|
"undici": "^6.19.8",
|
|
44
44
|
"zod": "^3.23.8",
|
|
45
45
|
"@atproto-labs/fetch-node": "^0.3.0",
|
|
46
|
-
"@atproto-labs/simple-store": "^0.4.0",
|
|
47
46
|
"@atproto-labs/simple-store-memory": "^0.2.0",
|
|
48
47
|
"@atproto-labs/simple-store-redis": "^0.1.0",
|
|
49
48
|
"@atproto-labs/xrpc-utils": "^0.1.0",
|
|
50
49
|
"@atproto/aws": "^0.3.0",
|
|
51
|
-
"@atproto/common": "^0.6.1",
|
|
52
50
|
"@atproto/crypto": "^0.5.0",
|
|
53
51
|
"@atproto/did": "^0.5.0",
|
|
54
52
|
"@atproto/identity": "^0.5.0",
|
|
53
|
+
"@atproto-labs/simple-store": "^0.4.0",
|
|
55
54
|
"@atproto/lex": "^0.1.3",
|
|
56
55
|
"@atproto/lex-cbor": "^0.1.0",
|
|
57
56
|
"@atproto/lex-data": "^0.1.1",
|
|
58
57
|
"@atproto/lex-json": "^0.1.0",
|
|
59
|
-
"@atproto/oauth-provider": "^0.18.
|
|
58
|
+
"@atproto/oauth-provider": "^0.18.3",
|
|
59
|
+
"@atproto/common": "^0.6.2",
|
|
60
60
|
"@atproto/oauth-scopes": "^0.5.0",
|
|
61
61
|
"@atproto/repo": "^0.10.0",
|
|
62
|
+
"@atproto/xrpc-server": "^0.11.1",
|
|
62
63
|
"@atproto/syntax": "^0.6.1",
|
|
63
|
-
"@atproto/xrpc": "^0.8.0"
|
|
64
|
-
"@atproto/xrpc-server": "^0.11.1"
|
|
64
|
+
"@atproto/xrpc": "^0.8.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@did-plc/server": "^0.0.1",
|
|
@@ -79,10 +79,10 @@
|
|
|
79
79
|
"ts-node": "^10.8.2",
|
|
80
80
|
"typescript": "^6.0.3",
|
|
81
81
|
"ws": "^8.12.0",
|
|
82
|
-
"@atproto/api": "^0.20.
|
|
83
|
-
"@atproto/bsky": "^0.0.
|
|
84
|
-
"@atproto/
|
|
85
|
-
"@atproto/
|
|
82
|
+
"@atproto/api": "^0.20.14",
|
|
83
|
+
"@atproto/bsky": "^0.0.241",
|
|
84
|
+
"@atproto/oauth-client-browser-example": "^0.1.1",
|
|
85
|
+
"@atproto/lex-document": "^0.1.0"
|
|
86
86
|
},
|
|
87
87
|
"type": "module",
|
|
88
88
|
"exports": {
|
|
@@ -221,33 +221,36 @@ export class AccountManager {
|
|
|
221
221
|
throw new InvalidRequestError('Password too long')
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
const passwordScrypt =
|
|
225
|
-
? await scrypt.genSaltAndHash(password)
|
|
226
|
-
: undefined
|
|
224
|
+
const passwordScrypt =
|
|
225
|
+
email && password ? await scrypt.genSaltAndHash(password) : undefined
|
|
227
226
|
|
|
228
227
|
const now = currentDatetimeString()
|
|
229
|
-
|
|
228
|
+
return this.db.transaction(async (dbTxn) => {
|
|
230
229
|
if (inviteCode) {
|
|
231
230
|
await invite.ensureInviteIsAvailable(dbTxn, inviteCode)
|
|
232
231
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
232
|
+
|
|
233
|
+
await account.registerActor(dbTxn, { did, handle, deactivated })
|
|
234
|
+
|
|
235
|
+
if (email && passwordScrypt) {
|
|
236
|
+
await account.registerAccount(dbTxn, { did, email, passwordScrypt })
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
await invite.recordInviteUse(dbTxn, {
|
|
240
|
+
did,
|
|
241
|
+
inviteCode,
|
|
242
|
+
now,
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
if (refreshJwt) {
|
|
246
|
+
await auth.storeRefreshToken(
|
|
247
|
+
dbTxn,
|
|
248
|
+
auth.decodeRefreshToken(refreshJwt),
|
|
249
|
+
null,
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
await repo.updateRoot(dbTxn, did, repoCid, repoRev)
|
|
251
254
|
})
|
|
252
255
|
}
|
|
253
256
|
|
|
@@ -359,7 +362,7 @@ export class AccountManager {
|
|
|
359
362
|
await account.updateHandle(this.db, did, handle)
|
|
360
363
|
|
|
361
364
|
try {
|
|
362
|
-
await this.sequencer.
|
|
365
|
+
await this.sequencer.sequenceIdentity(did, handle)
|
|
363
366
|
} catch (err) {
|
|
364
367
|
httpLogger.error({ err, did, handle }, 'failed to sequence handle update')
|
|
365
368
|
}
|
|
@@ -3,6 +3,7 @@ import { Client, createOp as createPlcOp } from '@did-plc/lib'
|
|
|
3
3
|
import { Selectable } from 'kysely'
|
|
4
4
|
import { Keypair, Secp256k1Keypair } from '@atproto/crypto'
|
|
5
5
|
import {
|
|
6
|
+
DidString,
|
|
6
7
|
HandleString,
|
|
7
8
|
asAtIdentifierString,
|
|
8
9
|
getBlobCidString,
|
|
@@ -60,15 +61,11 @@ import { fromDateISO } from '../db/index.js'
|
|
|
60
61
|
import { ImageUrlBuilder } from '../image/image-url-builder.js'
|
|
61
62
|
import { dbLogger } from '../logger.js'
|
|
62
63
|
import { ServerMailer } from '../mailer/index.js'
|
|
63
|
-
import { Sequencer
|
|
64
|
+
import { Sequencer } from '../sequencer/index.js'
|
|
64
65
|
import { AccountManager, InvalidPasswordError } from './account-manager.js'
|
|
65
66
|
import * as schemas from './db/schema/index.js'
|
|
66
67
|
import * as accountDeviceHelper from './helpers/account-device.js'
|
|
67
|
-
import {
|
|
68
|
-
AccountStatus,
|
|
69
|
-
ActorAccount,
|
|
70
|
-
UserAlreadyExistsError,
|
|
71
|
-
} from './helpers/account.js'
|
|
68
|
+
import { ActorAccount, UserAlreadyExistsError } from './helpers/account.js'
|
|
72
69
|
import * as authRequestHelper from './helpers/authorization-request.js'
|
|
73
70
|
import * as authorizedClientHelper from './helpers/authorized-client.js'
|
|
74
71
|
import * as deviceHelper from './helpers/device.js'
|
|
@@ -157,7 +154,13 @@ export class OAuthStore
|
|
|
157
154
|
const signingKey = await Secp256k1Keypair.create({ exportable: true })
|
|
158
155
|
const signingKeyDid = signingKey.did()
|
|
159
156
|
|
|
160
|
-
const
|
|
157
|
+
const canTombstone =
|
|
158
|
+
// @NOTE IMPORTANT We don't support "bring your own DID" here (yet?). If
|
|
159
|
+
// we ever do, make sure to update the computation of canTombstone so that
|
|
160
|
+
// the user's did don't get tombstoned.
|
|
161
|
+
true
|
|
162
|
+
|
|
163
|
+
const plc = await createPlcOp({
|
|
161
164
|
signingKey: signingKeyDid,
|
|
162
165
|
rotationKeys: this.recoveryDidKey
|
|
163
166
|
? [this.recoveryDidKey, this.plcRotationKey.did()]
|
|
@@ -167,44 +170,60 @@ export class OAuthStore
|
|
|
167
170
|
signer: this.plcRotationKey,
|
|
168
171
|
})
|
|
169
172
|
|
|
170
|
-
const
|
|
171
|
-
assert(isDidString(did), 'Generated DID is not a valid DidString')
|
|
173
|
+
const did = plc.did as DidString
|
|
172
174
|
|
|
173
175
|
try {
|
|
174
176
|
await this.actorStore.create(did, signingKey)
|
|
177
|
+
|
|
175
178
|
try {
|
|
176
|
-
const commit = await this.actorStore.transact(did, (actorTxn) =>
|
|
177
|
-
actorTxn.repo.createRepo([])
|
|
178
|
-
)
|
|
179
|
+
const commit = await this.actorStore.transact(did, (actorTxn) => {
|
|
180
|
+
return actorTxn.repo.createRepo([])
|
|
181
|
+
})
|
|
179
182
|
|
|
180
|
-
await this.plcClient.sendOperation(did, op)
|
|
183
|
+
await this.plcClient.sendOperation(did, plc.op)
|
|
181
184
|
|
|
182
|
-
await this.accountManager.createAccount({
|
|
183
|
-
did,
|
|
184
|
-
handle,
|
|
185
|
-
email,
|
|
186
|
-
password,
|
|
187
|
-
inviteCode,
|
|
188
|
-
repoCid: commit.cid,
|
|
189
|
-
repoRev: commit.rev,
|
|
190
|
-
})
|
|
191
185
|
try {
|
|
192
|
-
await this.
|
|
193
|
-
await this.sequencer.sequenceAccountEvt(did, AccountStatus.Active)
|
|
194
|
-
await this.sequencer.sequenceCommit(did, commit)
|
|
195
|
-
await this.sequencer.sequenceSyncEvt(
|
|
186
|
+
await this.accountManager.createAccount({
|
|
196
187
|
did,
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
188
|
+
handle,
|
|
189
|
+
email,
|
|
190
|
+
password,
|
|
191
|
+
inviteCode,
|
|
192
|
+
repoCid: commit.cid,
|
|
193
|
+
repoRev: commit.rev,
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
await this.sequencer.sequenceAccountCreation(did, handle, commit)
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
await this.actorStore
|
|
201
|
+
.clearReservedKeypair(signingKeyDid, did)
|
|
202
|
+
.catch((err) => {
|
|
203
|
+
// @NOTE This is a cleanup operation so we won't fail the
|
|
204
|
+
// whole flow if it fails, but we log it just in case
|
|
205
|
+
dbLogger.error(
|
|
206
|
+
{ did, signingKeyDid, err },
|
|
207
|
+
'Failed to clear reserved keypair',
|
|
208
|
+
)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
const account = await this.accountManager.getAccount(did)
|
|
212
|
+
assert(account, 'Account not found after creation')
|
|
213
|
+
|
|
214
|
+
return await this.buildAccount(account)
|
|
215
|
+
} catch (err) {
|
|
216
|
+
await this.sequencer.sequenceAccountDeletion(did)
|
|
217
|
+
throw err
|
|
218
|
+
}
|
|
219
|
+
} catch (err) {
|
|
220
|
+
await this.accountManager.deleteAccount(did)
|
|
221
|
+
throw err
|
|
222
|
+
}
|
|
206
223
|
} catch (err) {
|
|
207
|
-
|
|
224
|
+
if (canTombstone) {
|
|
225
|
+
await this.plcClient.tombstone(did, this.plcRotationKey)
|
|
226
|
+
}
|
|
208
227
|
throw err
|
|
209
228
|
}
|
|
210
229
|
} catch (err) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Server } from '@atproto/xrpc-server'
|
|
2
|
-
import { AccountStatus } from '../../../../account-manager/account-manager.js'
|
|
3
2
|
import { AppContext } from '../../../../context.js'
|
|
4
3
|
import { com } from '../../../../lexicons/index.js'
|
|
5
4
|
|
|
@@ -8,13 +7,16 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
8
7
|
auth: ctx.authVerifier.adminToken,
|
|
9
8
|
handler: async ({ input }) => {
|
|
10
9
|
const { did } = input.body
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
// @NOTE Order matters here: first "unlink" the account by removing it
|
|
12
|
+
// from the account manager database ("source of truth"), then notify the
|
|
13
|
+
// sequencer, and finally cleanup files from the file system.
|
|
12
14
|
await ctx.accountManager.deleteAccount(did)
|
|
13
|
-
|
|
14
|
-
did
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
try {
|
|
16
|
+
await ctx.sequencer.sequenceAccountDeletion(did)
|
|
17
|
+
} finally {
|
|
18
|
+
await ctx.actorStore.destroy(did)
|
|
19
|
+
}
|
|
18
20
|
},
|
|
19
21
|
})
|
|
20
22
|
}
|
|
@@ -41,7 +41,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
41
41
|
|
|
42
42
|
if (com.atproto.admin.defs.repoRef.$isTypeOf(subject)) {
|
|
43
43
|
const status = await ctx.accountManager.getAccountStatus(subject.did)
|
|
44
|
-
await ctx.sequencer.
|
|
44
|
+
await ctx.sequencer.sequenceAccount(subject.did, status)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
return {
|
|
@@ -50,7 +50,7 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
await ctx.plcClient.sendOperation(requester, op)
|
|
53
|
-
await ctx.sequencer.
|
|
53
|
+
await ctx.sequencer.sequenceIdentity(requester)
|
|
54
54
|
|
|
55
55
|
try {
|
|
56
56
|
await ctx.idResolver.did.resolve(requester, true)
|
|
@@ -48,12 +48,12 @@ export default function (server: Server, ctx: AppContext) {
|
|
|
48
48
|
|
|
49
49
|
// @NOTE: we're over-emitting for now for backwards compatibility, can reduce this in the future
|
|
50
50
|
const status = await ctx.accountManager.getAccountStatus(requester)
|
|
51
|
-
await ctx.sequencer.
|
|
52
|
-
await ctx.sequencer.sequenceIdentityEvt(
|
|
51
|
+
await ctx.sequencer.sequenceAccountActivation(
|
|
53
52
|
requester,
|
|
54
53
|
account.handle ?? INVALID_HANDLE,
|
|
54
|
+
status,
|
|
55
|
+
syncData,
|
|
55
56
|
)
|
|
56
|
-
await ctx.sequencer.sequenceSyncEvt(requester, syncData)
|
|
57
57
|
},
|
|
58
58
|
})
|
|
59
59
|
}
|