@atproto/pds 0.5.5 → 0.5.6
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 +15 -0
- package/dist/account-manager/account-manager.d.ts +51 -13
- package/dist/account-manager/account-manager.d.ts.map +1 -1
- package/dist/account-manager/account-manager.js +86 -26
- package/dist/account-manager/account-manager.js.map +1 -1
- package/dist/account-manager/db/migrations/005-oauth-account-management.d.ts.map +1 -1
- package/dist/account-manager/db/migrations/005-oauth-account-management.js +3 -4
- package/dist/account-manager/db/migrations/005-oauth-account-management.js.map +1 -1
- package/dist/account-manager/db/schema/authorization-request.d.ts +2 -2
- package/dist/account-manager/db/schema/authorization-request.d.ts.map +1 -1
- package/dist/account-manager/db/schema/authorization-request.js.map +1 -1
- package/dist/account-manager/db/schema/authorized-client.d.ts +2 -2
- package/dist/account-manager/db/schema/authorized-client.d.ts.map +1 -1
- package/dist/account-manager/db/schema/authorized-client.js.map +1 -1
- package/dist/account-manager/db/schema/token.d.ts +2 -2
- package/dist/account-manager/db/schema/token.d.ts.map +1 -1
- package/dist/account-manager/db/schema/token.js.map +1 -1
- package/dist/account-manager/helpers/account-device.d.ts +23 -196
- package/dist/account-manager/helpers/account-device.d.ts.map +1 -1
- package/dist/account-manager/helpers/account-device.js +3 -3
- package/dist/account-manager/helpers/account-device.js.map +1 -1
- package/dist/account-manager/helpers/account.d.ts +14 -4
- package/dist/account-manager/helpers/account.d.ts.map +1 -1
- package/dist/account-manager/helpers/account.js +17 -11
- package/dist/account-manager/helpers/account.js.map +1 -1
- package/dist/account-manager/helpers/auth.js +1 -1
- package/dist/account-manager/helpers/auth.js.map +1 -1
- package/dist/account-manager/helpers/authorization-request.d.ts +83 -5
- package/dist/account-manager/helpers/authorization-request.d.ts.map +1 -1
- package/dist/account-manager/helpers/authorization-request.js +8 -8
- package/dist/account-manager/helpers/authorization-request.js.map +1 -1
- package/dist/account-manager/helpers/authorized-client.d.ts +5 -4
- package/dist/account-manager/helpers/authorized-client.d.ts.map +1 -1
- package/dist/account-manager/helpers/authorized-client.js +3 -0
- package/dist/account-manager/helpers/authorized-client.js.map +1 -1
- package/dist/account-manager/helpers/device.d.ts +9 -3
- package/dist/account-manager/helpers/device.d.ts.map +1 -1
- package/dist/account-manager/helpers/device.js +4 -4
- package/dist/account-manager/helpers/device.js.map +1 -1
- package/dist/account-manager/helpers/invite.d.ts +35 -2
- package/dist/account-manager/helpers/invite.d.ts.map +1 -1
- package/dist/account-manager/helpers/lexicon.d.ts.map +1 -1
- package/dist/account-manager/helpers/lexicon.js +6 -0
- package/dist/account-manager/helpers/lexicon.js.map +1 -1
- package/dist/account-manager/helpers/password.d.ts +1 -0
- package/dist/account-manager/helpers/password.d.ts.map +1 -1
- package/dist/account-manager/helpers/password.js +3 -0
- package/dist/account-manager/helpers/password.js.map +1 -1
- package/dist/account-manager/helpers/token.d.ts +72 -1031
- package/dist/account-manager/helpers/token.d.ts.map +1 -1
- package/dist/account-manager/helpers/token.js +13 -10
- package/dist/account-manager/helpers/token.js.map +1 -1
- package/dist/account-manager/helpers/used-refresh-token.d.ts +6 -2
- package/dist/account-manager/helpers/used-refresh-token.d.ts.map +1 -1
- package/dist/account-manager/oauth-store.d.ts +17 -13
- package/dist/account-manager/oauth-store.d.ts.map +1 -1
- package/dist/account-manager/oauth-store.js +89 -39
- package/dist/account-manager/oauth-store.js.map +1 -1
- package/dist/actor-store/blob/reader.d.ts.map +1 -1
- package/dist/actor-store/blob/reader.js +2 -3
- package/dist/actor-store/blob/reader.js.map +1 -1
- package/dist/actor-store/record/reader.js +3 -3
- package/dist/actor-store/record/reader.js.map +1 -1
- package/dist/actor-store/repo/sql-repo-reader.d.ts +5 -1
- package/dist/actor-store/repo/sql-repo-reader.d.ts.map +1 -1
- package/dist/actor-store/repo/sql-repo-reader.js.map +1 -1
- package/dist/api/com/atproto/admin/updateSubjectStatus.d.ts.map +1 -1
- package/dist/api/com/atproto/admin/updateSubjectStatus.js +12 -4
- package/dist/api/com/atproto/admin/updateSubjectStatus.js.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/activateAccount.js +25 -31
- package/dist/api/com/atproto/server/activateAccount.js.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.d.ts.map +1 -1
- package/dist/api/com/atproto/server/deactivateAccount.js +3 -4
- 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 +51 -37
- package/dist/api/com/atproto/server/deleteAccount.js.map +1 -1
- package/dist/api/com/atproto/server/util.d.ts +25 -6
- package/dist/api/com/atproto/server/util.d.ts.map +1 -1
- package/dist/api/com/atproto/server/util.js.map +1 -1
- package/dist/config/config.d.ts +2 -1
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +4 -1
- package/dist/config/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +1 -1
- package/dist/context.js.map +1 -1
- package/dist/db/migrator.d.ts +4 -3
- package/dist/db/migrator.d.ts.map +1 -1
- package/dist/db/migrator.js +1 -1
- package/dist/db/migrator.js.map +1 -1
- package/dist/db/pagination.d.ts +2 -1
- package/dist/db/pagination.d.ts.map +1 -1
- package/dist/db/pagination.js +2 -2
- package/dist/db/pagination.js.map +1 -1
- package/dist/db/util.d.ts +3 -3
- package/dist/db/util.d.ts.map +1 -1
- package/dist/db/util.js.map +1 -1
- package/dist/mailer/index.d.ts +2 -0
- package/dist/mailer/index.d.ts.map +1 -1
- package/dist/mailer/index.js +2 -0
- package/dist/mailer/index.js.map +1 -1
- package/dist/scripts/sequencer-recovery/recovery-db.js.map +1 -1
- package/dist/sequencer/events.d.ts.map +1 -1
- package/dist/sequencer/events.js +6 -13
- package/dist/sequencer/events.js.map +1 -1
- package/dist/sequencer/sequencer.d.ts +1 -1
- package/dist/sequencer/sequencer.d.ts.map +1 -1
- package/dist/sequencer/sequencer.js.map +1 -1
- package/package.json +13 -13
- package/src/account-manager/account-manager.ts +135 -36
- package/src/account-manager/db/migrations/005-oauth-account-management.ts +6 -5
- package/src/account-manager/db/schema/authorization-request.ts +2 -1
- package/src/account-manager/db/schema/authorized-client.ts +6 -2
- package/src/account-manager/db/schema/token.ts +2 -2
- package/src/account-manager/helpers/account-device.ts +5 -11
- package/src/account-manager/helpers/account.ts +39 -16
- package/src/account-manager/helpers/auth.ts +2 -2
- package/src/account-manager/helpers/authorization-request.ts +12 -8
- package/src/account-manager/helpers/authorized-client.ts +12 -6
- package/src/account-manager/helpers/device.ts +4 -4
- package/src/account-manager/helpers/lexicon.ts +8 -3
- package/src/account-manager/helpers/password.ts +6 -0
- package/src/account-manager/helpers/token.ts +17 -11
- package/src/account-manager/oauth-store.ts +129 -61
- package/src/actor-store/blob/reader.ts +8 -5
- package/src/actor-store/record/reader.ts +3 -3
- package/src/actor-store/repo/sql-repo-reader.ts +1 -1
- package/src/api/com/atproto/admin/updateSubjectStatus.ts +16 -4
- package/src/api/com/atproto/server/activateAccount.ts +27 -49
- package/src/api/com/atproto/server/deactivateAccount.ts +3 -7
- package/src/api/com/atproto/server/deleteAccount.ts +60 -43
- package/src/api/com/atproto/server/util.ts +24 -7
- package/src/config/config.ts +7 -2
- package/src/context.ts +2 -3
- package/src/db/migrator.ts +2 -1
- package/src/db/pagination.ts +7 -7
- package/src/db/util.ts +5 -2
- package/src/mailer/index.ts +4 -2
- package/src/scripts/sequencer-recovery/recovery-db.ts +1 -1
- package/src/sequencer/events.ts +8 -13
- package/src/sequencer/sequencer.ts +1 -3
- package/tests/account-manager.test.ts +79 -0
- package/tests/account-status.test.ts +206 -0
- package/tests/db.test.ts +3 -3
- package/tests/oauth.test.ts +91 -0
|
@@ -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 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"]}
|
|
1
|
+
{"version":3,"file":"sequencer.js","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,aAAa,CAAA;AAEtC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AAErE,OAAO,EAAE,SAAS,IAAI,GAAG,EAAE,MAAM,cAAc,CAAA;AAE/C,OAAO,EAIL,KAAK,EACL,WAAW,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAML,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,aAAa,CAAA;AAEpB,cAAc,aAAa,CAAA;AAE3B,MAAM,OAAO,SAAU,SAAS,YAA2C;IAMzE,YACS,UAAkB,EAClB,QAAkB,EAClB,QAAQ,GAAG,CAAC,EACnB,wBAAwB,GAAG,KAAK;QAEhC,KAAK,EAAE,CAAA;QALA,eAAU,GAAV,UAAU,CAAQ;QAClB,aAAQ,GAAR,QAAQ,CAAU;QAClB,aAAQ,GAAR,QAAQ,CAAI;QAPrB,cAAS,GAAG,KAAK,CAAA;QACjB,gBAAW,GAAyB,IAAI,CAAA;QACxC,uBAAkB,GAAG,CAAC,CAAA;QASpB,0EAA0E;QAC1E,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;QACzB,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAA;IACvD,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAA;QACzB,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACrC,MAAM,QAAQ,CAAC,sBAAsB,EAAE,CAAA;QACvC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;QAC9B,IAAI,CAAC,QAAQ,GAAG,IAAI,IAAI,CAAC,CAAA;QACzB,IAAI,IAAI,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YAC9B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAClC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QACrB,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,CAAC,WAAW,CAAA;QACxB,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACzB,UAAU,CAAC,UAAU,CAAC;aACtB,SAAS,EAAE;aACX,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;aACtB,KAAK,CAAC,CAAC,CAAC;aACR,gBAAgB,EAAE,CAAA;QACrB,OAAO,GAAG,EAAE,GAAG,IAAI,IAAI,CAAA;IACzB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAc;QACvB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACzB,UAAU,CAAC,UAAU,CAAC;aACtB,SAAS,EAAE;aACX,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC;aACzB,KAAK,CAAC,CAAC,CAAC;aACR,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;aACrB,gBAAgB,EAAE,CAAA;QACrB,OAAO,GAAG,IAAI,IAAI,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,IAAY;QAClC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,EAAE;aACzB,UAAU,CAAC,UAAU,CAAC;aACtB,SAAS,EAAE;aACX,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC;aAChC,OAAO,CAAC,aAAa,EAAE,KAAK,CAAC;aAC7B,KAAK,CAAC,CAAC,CAAC;aACR,gBAAgB,EAAE,CAAA;QACrB,OAAO,GAAG,IAAI,IAAI,CAAA;IACpB,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,IAKrB;QACC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;QAE5D,IAAI,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE;aACnB,UAAU,CAAC,UAAU,CAAC;aACtB,SAAS,EAAE;aACX,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC;aACrB,KAAK,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;QAC/B,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,WAAW,CAAC,CAAA;QAC9C,CAAC;QACD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAA;QAC7C,CAAC;QACD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC/B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,YAAY,CAAC,CAAA;QACxD,CAAC;QACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QAC5B,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,OAAO,EAAE,CAAA;QAClC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO,EAAE,CAAA;QACX,CAAC;QAED,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAA;IAC/B,CAAC;IAEO,KAAK,CAAC,MAAM;QAClB,IAAI,IAAI,CAAC,SAAS;YAAE,OAAM;QAC1B,gDAAgD;QAChD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC;gBACtC,WAAW,EAAE,IAAI,CAAC,QAAQ;gBAC1B,KAAK,EAAE,IAAI;aACZ,CAAC,CAAA;YACF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpB,IAAI,CAAC,kBAAkB,GAAG,CAAC,CAAA;gBAC3B,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;gBACzB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAA;YACnD,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;YACjC,CAAC;YACD,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,6BAA6B,CAAC,CAAA;YAC1E,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAA;YAC/B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;QAClC,CAAC;IACH,CAAC;IAED,+EAA+E;IACvE,KAAK,CAAC,kBAAkB;QAC9B,IAAI,CAAC,kBAAkB,EAAE,CAAA;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,CAAA;QACvE,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAA;IACtB,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,MAAgC;QACjD,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,OAAO,EAAE,CAAA;QAC7B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,EAAE,CAAC,gBAAgB,CACzC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAClE,CAAA;QACD,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,CAAA;QAC9B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACnC,CAAC;IAEM,KAAK,CAAC,cAAc,CACzB,GAAc,EACd,UAA6B;QAE7B,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,eAAe,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;IACnE,CAAC;IAEM,KAAK,CAAC,YAAY,CAAC,GAAc,EAAE,IAAiB;QACzD,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;IAC9D,CAAC;IAEM,KAAK,CAAC,gBAAgB,CAC3B,GAAc,EACd,MAAqB;QAErB,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IACpE,CAAC;IAEM,KAAK,CAAC,eAAe,CAC1B,GAAc,EACd,MAAqB;QAErB,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IACnE,CAAC;IAEM,KAAK,CAAC,uBAAuB,CAClC,GAAc,EACd,MAAoB,EACpB,MAAyB;QAEzB,iCAAiC;QACjC,MAAM,IAAI,CAAC,YAAY,CAAC;YACtB,MAAM,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC;YACvC,MAAM,mBAAmB,CAAC,GAAG,EAAE,aAAa,CAAC,MAAM,CAAC;YACpD,MAAM,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC;YAClC,MAAM,gBAAgB,CAAC,GAAG,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC;SAC3D,CAAC,CAAA;IACJ,CAAC;IAEM,KAAK,CAAC,yBAAyB,CACpC,GAAc,EACd,MAAoB,EACpB,MAAqB,EACrB,QAAqB;QAErB,iCAAiC;QACjC,MAAM,IAAI,CAAC,YAAY,CAAC;YACtB,MAAM,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC;YACtC,MAAM,oBAAoB,CAAC,GAAG,EAAE,MAAM,CAAC;YACvC,MAAM,gBAAgB,CAAC,GAAG,EAAE,QAAQ,CAAC;SACtC,CAAC,CAAA;IACJ,CAAC;IAEM,KAAK,CAAC,uBAAuB,CAAC,GAAc;QACjD,MAAM,CAAC,GAAG,CAAC,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;YACpC,MAAM,mBAAmB,CAAC,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC;SACtD,CAAC,CAAA;QACF,MAAM,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAC5B,IAAI,CAAC,EAAE,CAAC,EAAE;aACP,UAAU,CAAC,UAAU,CAAC;aACtB,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;aACtB,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,CAC3B,CAAA;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,IAAoB,EAAY,EAAE;IACjE,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,gDAAgD;QAChD,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;YACrB,SAAQ;QACV,CAAC;QACD,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACjC,IAAI,GAAG,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,QAAQ;gBACd,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,IAAI,EAAE,GAAG,CAAC,WAA6B;gBACvC,GAAG,EAAE,GAAgB;aACtB,CAAC,CAAA;QACJ,CAAC;aAAM,IAAI,GAAG,CAAC,SAAS,KAAK,MAAM,EAAE,CAAC;YACpC,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM;gBACZ,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,IAAI,EAAE,GAAG,CAAC,WAA6B;gBACvC,GAAG,EAAE,GAAc;aACpB,CAAC,CAAA;QACJ,CAAC;aAAM,IAAI,GAAG,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,UAAU;gBAChB,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,IAAI,EAAE,GAAG,CAAC,WAA6B;gBACvC,GAAG,EAAE,GAAkB;aACxB,CAAC,CAAA;QACJ,CAAC;aAAM,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YACvC,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,SAAS;gBACf,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,IAAI,EAAE,GAAG,CAAC,WAA6B;gBACvC,GAAG,EAAE,GAAiB;aACvB,CAAC,CAAA;QACJ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAWD,eAAe,SAAS,CAAA","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 async sequenceEvts(events: readonly RepoSeqInsert[]): 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.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Reference implementation of atproto Personal Data Server (PDS)",
|
|
6
6
|
"keywords": [
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"ioredis": "^5.3.2",
|
|
33
33
|
"jose": "^5.0.1",
|
|
34
34
|
"key-encoder": "^2.0.3",
|
|
35
|
-
"kysely": "^0.
|
|
35
|
+
"kysely": "^0.29.2",
|
|
36
36
|
"nodemailer": "^6.8.0",
|
|
37
37
|
"nodemailer-html-to-text": "^3.2.0",
|
|
38
38
|
"p-queue": "^8.0.0",
|
|
@@ -44,24 +44,24 @@
|
|
|
44
44
|
"zod": "^3.23.8",
|
|
45
45
|
"@atproto-labs/fetch-node": "^0.3.1",
|
|
46
46
|
"@atproto-labs/simple-store": "^0.4.1",
|
|
47
|
-
"@atproto-labs/simple-store-
|
|
47
|
+
"@atproto-labs/simple-store-memory": "^0.2.1",
|
|
48
48
|
"@atproto-labs/xrpc-utils": "^0.1.1",
|
|
49
|
+
"@atproto-labs/simple-store-redis": "^0.1.1",
|
|
49
50
|
"@atproto/common": "^0.6.3",
|
|
51
|
+
"@atproto/aws": "^0.3.1",
|
|
50
52
|
"@atproto/crypto": "^0.5.1",
|
|
51
|
-
"@atproto-labs/simple-store-memory": "^0.2.1",
|
|
52
53
|
"@atproto/did": "^0.5.1",
|
|
53
54
|
"@atproto/identity": "^0.5.1",
|
|
54
|
-
"@atproto/
|
|
55
|
+
"@atproto/lex": "^0.1.4",
|
|
55
56
|
"@atproto/lex-cbor": "^0.1.1",
|
|
56
57
|
"@atproto/lex-data": "^0.1.2",
|
|
57
|
-
"@atproto/lex": "^0.1.4",
|
|
58
|
-
"@atproto/lex-json": "^0.1.1",
|
|
59
|
-
"@atproto/oauth-provider": "^0.18.4",
|
|
60
58
|
"@atproto/oauth-scopes": "^0.5.1",
|
|
61
59
|
"@atproto/repo": "^0.10.1",
|
|
60
|
+
"@atproto/lex-json": "^0.1.1",
|
|
61
|
+
"@atproto/syntax": "^0.6.2",
|
|
62
62
|
"@atproto/xrpc": "^0.8.1",
|
|
63
|
-
"@atproto/
|
|
64
|
-
"@atproto/
|
|
63
|
+
"@atproto/oauth-provider": "^0.19.0",
|
|
64
|
+
"@atproto/xrpc-server": "^0.11.2"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@did-plc/server": "^0.0.1",
|
|
@@ -78,10 +78,10 @@
|
|
|
78
78
|
"puppeteer": "^23.11.1",
|
|
79
79
|
"ts-node": "^10.8.2",
|
|
80
80
|
"ws": "^8.12.0",
|
|
81
|
-
"@atproto/
|
|
82
|
-
"@atproto/bsky": "^0.0.242",
|
|
81
|
+
"@atproto/bsky": "^0.0.243",
|
|
83
82
|
"@atproto/lex-document": "^0.1.1",
|
|
84
|
-
"@atproto/oauth-client-browser-example": "^0.1.1"
|
|
83
|
+
"@atproto/oauth-client-browser-example": "^0.1.1",
|
|
84
|
+
"@atproto/api": "^0.20.16"
|
|
85
85
|
},
|
|
86
86
|
"type": "module",
|
|
87
87
|
"exports": {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import assert from 'node:assert'
|
|
1
2
|
import { KeyObject } from 'node:crypto'
|
|
2
3
|
import { Client as PlcClient } from '@did-plc/lib'
|
|
3
4
|
import { isEmailValid } from '@hapi/address'
|
|
@@ -12,9 +13,16 @@ import {
|
|
|
12
13
|
isAtIdentifierString,
|
|
13
14
|
} from '@atproto/lex'
|
|
14
15
|
import { Cid } from '@atproto/lex-data'
|
|
15
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
INVALID_HANDLE,
|
|
18
|
+
currentDatetimeString,
|
|
19
|
+
isValidTld,
|
|
20
|
+
} from '@atproto/syntax'
|
|
16
21
|
import { AuthRequiredError, InvalidRequestError } from '@atproto/xrpc-server'
|
|
22
|
+
import { ActorStore } from '../actor-store/actor-store.js'
|
|
23
|
+
import { assertValidDidDocumentForService } from '../api/com/atproto/server/util.js'
|
|
17
24
|
import { AuthScope } from '../auth-scope.js'
|
|
25
|
+
import { ServerConfig } from '../config/config.js'
|
|
18
26
|
import { softDeleted } from '../db/index.js'
|
|
19
27
|
import { hasExplicitSlur } from '../handle/explicit-slurs.js'
|
|
20
28
|
import {
|
|
@@ -27,9 +35,10 @@ import { httpLogger } from '../logger.js'
|
|
|
27
35
|
import { ServerMailer } from '../mailer/index.js'
|
|
28
36
|
import { Sequencer } from '../sequencer/index.js'
|
|
29
37
|
import { AccountDb, EmailTokenPurpose, getDb, getMigrator } from './db/index.js'
|
|
30
|
-
import * as
|
|
38
|
+
import * as accountHelpers from './helpers/account.js'
|
|
31
39
|
import { AccountStatus, ActorAccount } from './helpers/account.js'
|
|
32
40
|
import * as auth from './helpers/auth.js'
|
|
41
|
+
import * as authorizedClientHelper from './helpers/authorized-client.js'
|
|
33
42
|
import * as emailToken from './helpers/email-token.js'
|
|
34
43
|
import * as invite from './helpers/invite.js'
|
|
35
44
|
import * as password from './helpers/password.js'
|
|
@@ -53,7 +62,7 @@ export { AccountStatus, formatAccountStatus } from './helpers/account.js'
|
|
|
53
62
|
*/
|
|
54
63
|
export class InvalidPasswordError extends AuthRequiredError {
|
|
55
64
|
constructor(
|
|
56
|
-
public readonly did:
|
|
65
|
+
public readonly did: DidString,
|
|
57
66
|
errorMessage = 'Invalid identifier or password',
|
|
58
67
|
) {
|
|
59
68
|
super(errorMessage)
|
|
@@ -69,17 +78,24 @@ export class AccountManager {
|
|
|
69
78
|
readonly db: AccountDb
|
|
70
79
|
|
|
71
80
|
constructor(
|
|
81
|
+
readonly cfg: ServerConfig,
|
|
82
|
+
readonly actorStore: ActorStore,
|
|
72
83
|
readonly idResolver: IdResolver,
|
|
73
84
|
readonly jwtKey: KeyObject,
|
|
74
85
|
readonly mailer: ServerMailer,
|
|
75
86
|
readonly sequencer: Sequencer,
|
|
76
87
|
readonly plcClient: PlcClient,
|
|
77
88
|
readonly plcRotationKey: Keypair,
|
|
78
|
-
readonly serviceDid: string,
|
|
79
|
-
readonly serviceHandleDomains: string[],
|
|
80
|
-
db: AccountManagerDbConfig,
|
|
81
89
|
) {
|
|
82
|
-
this.db = getDb(db.accountDbLoc, db.disableWalAutoCheckpoint)
|
|
90
|
+
this.db = getDb(cfg.db.accountDbLoc, cfg.db.disableWalAutoCheckpoint)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get serviceDid(): DidString {
|
|
94
|
+
return this.cfg.service.did
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get serviceHandleDomains(): string[] {
|
|
98
|
+
return this.cfg.identity.serviceHandleDomains
|
|
83
99
|
}
|
|
84
100
|
|
|
85
101
|
async migrateOrThrow() {
|
|
@@ -96,23 +112,23 @@ export class AccountManager {
|
|
|
96
112
|
|
|
97
113
|
async getAccount(
|
|
98
114
|
handleOrDid: AtIdentifierString,
|
|
99
|
-
flags?:
|
|
115
|
+
flags?: accountHelpers.AvailabilityFlags,
|
|
100
116
|
): Promise<ActorAccount | null> {
|
|
101
|
-
return
|
|
117
|
+
return accountHelpers.getAccount(this.db, handleOrDid, flags)
|
|
102
118
|
}
|
|
103
119
|
|
|
104
120
|
async getAccounts(
|
|
105
121
|
dids: DidString[],
|
|
106
|
-
flags?:
|
|
122
|
+
flags?: accountHelpers.AvailabilityFlags,
|
|
107
123
|
): Promise<Map<string, ActorAccount>> {
|
|
108
|
-
return
|
|
124
|
+
return accountHelpers.getAccounts(this.db, dids, flags)
|
|
109
125
|
}
|
|
110
126
|
|
|
111
127
|
async getAccountByEmail(
|
|
112
128
|
email: string,
|
|
113
|
-
flags?:
|
|
129
|
+
flags?: accountHelpers.AvailabilityFlags,
|
|
114
130
|
): Promise<ActorAccount | null> {
|
|
115
|
-
return
|
|
131
|
+
return accountHelpers.getAccountByEmail(this.db, email, flags)
|
|
116
132
|
}
|
|
117
133
|
|
|
118
134
|
async isAccountActivated(did: DidString): Promise<boolean> {
|
|
@@ -123,22 +139,26 @@ export class AccountManager {
|
|
|
123
139
|
|
|
124
140
|
async getDidForActor(
|
|
125
141
|
handleOrDid: AtIdentifierString,
|
|
126
|
-
flags?:
|
|
142
|
+
flags?: accountHelpers.AvailabilityFlags,
|
|
127
143
|
): Promise<DidString | null> {
|
|
128
144
|
const got = await this.getAccount(handleOrDid, flags)
|
|
129
145
|
return got?.did ?? null
|
|
130
146
|
}
|
|
131
147
|
|
|
132
|
-
async getAccountStatus(
|
|
133
|
-
handleOrDid: AtIdentifierString,
|
|
134
|
-
): Promise<AccountStatus> {
|
|
148
|
+
async getAccountStatus(handleOrDid: AtIdentifierString) {
|
|
135
149
|
const got = await this.getAccount(handleOrDid, {
|
|
136
150
|
includeDeactivated: true,
|
|
137
151
|
includeTakenDown: true,
|
|
138
152
|
})
|
|
139
153
|
|
|
140
|
-
const
|
|
141
|
-
|
|
154
|
+
const { active, status = active ? AccountStatus.Active : undefined } =
|
|
155
|
+
accountHelpers.formatAccountStatus(got)
|
|
156
|
+
assert(status != null)
|
|
157
|
+
return { status, account: got } as
|
|
158
|
+
| { status: AccountStatus.Deleted; account: null }
|
|
159
|
+
| { status: AccountStatus.Takendown; account: ActorAccount }
|
|
160
|
+
| { status: AccountStatus.Deactivated; account: ActorAccount }
|
|
161
|
+
| { status: AccountStatus.Active; account: ActorAccount }
|
|
142
162
|
}
|
|
143
163
|
|
|
144
164
|
async normalizeAndValidateHandle(
|
|
@@ -230,10 +250,14 @@ export class AccountManager {
|
|
|
230
250
|
await invite.ensureInviteIsAvailable(dbTxn, inviteCode)
|
|
231
251
|
}
|
|
232
252
|
|
|
233
|
-
await
|
|
253
|
+
await accountHelpers.registerActor(dbTxn, { did, handle, deactivated })
|
|
234
254
|
|
|
235
255
|
if (email && passwordScrypt) {
|
|
236
|
-
await
|
|
256
|
+
await accountHelpers.registerAccount(dbTxn, {
|
|
257
|
+
did,
|
|
258
|
+
email,
|
|
259
|
+
passwordScrypt,
|
|
260
|
+
})
|
|
237
261
|
}
|
|
238
262
|
|
|
239
263
|
await invite.recordInviteUse(dbTxn, {
|
|
@@ -359,7 +383,7 @@ export class AccountManager {
|
|
|
359
383
|
did: DidString,
|
|
360
384
|
handle: HandleString,
|
|
361
385
|
): Promise<void> {
|
|
362
|
-
await
|
|
386
|
+
await accountHelpers.updateHandle(this.db, did, handle)
|
|
363
387
|
|
|
364
388
|
try {
|
|
365
389
|
await this.sequencer.sequenceIdentity(did, handle)
|
|
@@ -369,36 +393,105 @@ export class AccountManager {
|
|
|
369
393
|
}
|
|
370
394
|
|
|
371
395
|
async deleteAccount(did: DidString) {
|
|
372
|
-
return
|
|
396
|
+
return accountHelpers.deleteAccount(this.db, did)
|
|
373
397
|
}
|
|
374
398
|
|
|
375
399
|
async takedownAccount(
|
|
376
400
|
did: DidString,
|
|
377
401
|
takedown: com.atproto.admin.defs.StatusAttr,
|
|
378
402
|
) {
|
|
379
|
-
await this.db.transaction(async (dbTxn) =>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
)
|
|
403
|
+
await this.db.transaction(async (dbTxn) => {
|
|
404
|
+
await accountHelpers.updateAccountTakedownStatus(dbTxn, did, takedown)
|
|
405
|
+
await auth.revokeRefreshTokensByDid(dbTxn, did)
|
|
406
|
+
await token.removeByDid(dbTxn, did)
|
|
407
|
+
})
|
|
408
|
+
|
|
409
|
+
await this.sequenceAccountStatus(did)
|
|
386
410
|
}
|
|
387
411
|
|
|
388
412
|
async getAccountAdminStatus(did: DidString) {
|
|
389
|
-
return
|
|
413
|
+
return accountHelpers.getAccountAdminStatus(this.db, did)
|
|
390
414
|
}
|
|
391
415
|
|
|
392
416
|
async updateRepoRoot(did: DidString, cid: Cid, rev: string) {
|
|
393
417
|
return repo.updateRoot(this.db, did, cid, rev)
|
|
394
418
|
}
|
|
395
419
|
|
|
396
|
-
async deactivateAccount(
|
|
397
|
-
|
|
420
|
+
async deactivateAccount(
|
|
421
|
+
did: DidString,
|
|
422
|
+
options?: {
|
|
423
|
+
deleteCredentials?: boolean
|
|
424
|
+
deleteAfter?: string | null
|
|
425
|
+
},
|
|
426
|
+
) {
|
|
427
|
+
const wasUpdated = await this.db.transaction(async (dbTxn) => {
|
|
428
|
+
if (options?.deleteCredentials) {
|
|
429
|
+
await token.removeByDid(dbTxn, did)
|
|
430
|
+
await authorizedClientHelper.deleteAllAuthorizedClients(dbTxn, did)
|
|
431
|
+
await password.deleteAllAppPasswords(dbTxn, did)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return accountHelpers.deactivateAccount(
|
|
435
|
+
dbTxn,
|
|
436
|
+
did,
|
|
437
|
+
options?.deleteAfter ?? null,
|
|
438
|
+
)
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
if (!wasUpdated) {
|
|
442
|
+
throw new InvalidRequestError('Account not found')
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const accountStatus = await this.getAccountStatus(did)
|
|
446
|
+
|
|
447
|
+
// Account is likely soft-deleted (takendown)
|
|
448
|
+
if (accountStatus.status === AccountStatus.Deleted) {
|
|
449
|
+
throw new InvalidRequestError('Account not found')
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
await this.sequencer.sequenceAccount(did, accountStatus.status)
|
|
453
|
+
|
|
454
|
+
return accountStatus
|
|
398
455
|
}
|
|
399
456
|
|
|
400
457
|
async activateAccount(did: DidString) {
|
|
401
|
-
|
|
458
|
+
await assertValidDidDocumentForService(this, did)
|
|
459
|
+
|
|
460
|
+
const found = await accountHelpers.activateAccount(this.db, did, {
|
|
461
|
+
// We cannot activate a takendown account
|
|
462
|
+
includeTakenDown: false,
|
|
463
|
+
includeDeactivated: true,
|
|
464
|
+
})
|
|
465
|
+
if (!found) {
|
|
466
|
+
throw new InvalidRequestError('user not found', 'AccountNotFound')
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const accountStatus = await this.getAccountStatus(did)
|
|
470
|
+
|
|
471
|
+
const { account, status } = accountStatus
|
|
472
|
+
|
|
473
|
+
if (status === AccountStatus.Deleted) {
|
|
474
|
+
// A concurrent operation deleted the account
|
|
475
|
+
throw new InvalidRequestError('user not found', 'AccountNotFound')
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const syncData = await this.actorStore.read(did, (store) => {
|
|
479
|
+
return store.repo.getSyncEventData()
|
|
480
|
+
})
|
|
481
|
+
|
|
482
|
+
await this.sequencer.sequenceAccountActivation(
|
|
483
|
+
did,
|
|
484
|
+
account.handle ?? INVALID_HANDLE,
|
|
485
|
+
status,
|
|
486
|
+
syncData,
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
return accountStatus
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
async sequenceAccountStatus(did: DidString) {
|
|
493
|
+
const { status } = await this.getAccountStatus(did)
|
|
494
|
+
await this.sequencer.sequenceAccount(did, status)
|
|
402
495
|
}
|
|
403
496
|
|
|
404
497
|
// Auth
|
|
@@ -556,6 +649,12 @@ export class AccountManager {
|
|
|
556
649
|
did: DidString,
|
|
557
650
|
passwordStr: string,
|
|
558
651
|
): Promise<boolean> {
|
|
652
|
+
if (passwordStr.length > scrypt.OLD_PASSWORD_MAX_LENGTH) {
|
|
653
|
+
// @NOTE Avoid throwing from here to avoid leaking account email validity
|
|
654
|
+
// through error messages.
|
|
655
|
+
return false
|
|
656
|
+
}
|
|
657
|
+
|
|
559
658
|
return password.verifyAccountPassword(this.db, did, passwordStr)
|
|
560
659
|
}
|
|
561
660
|
|
|
@@ -691,7 +790,7 @@ export class AccountManager {
|
|
|
691
790
|
const now = currentDatetimeString()
|
|
692
791
|
await this.db.transaction(async (dbTxn) => {
|
|
693
792
|
await emailToken.deleteEmailToken(dbTxn, did, 'confirm_email')
|
|
694
|
-
await
|
|
793
|
+
await accountHelpers.setEmailConfirmedAt(dbTxn, did, now)
|
|
695
794
|
})
|
|
696
795
|
|
|
697
796
|
user.emailConfirmedAt = now
|
|
@@ -787,7 +886,7 @@ export class AccountManager {
|
|
|
787
886
|
async updateAccountEmail(opts: { did: DidString; email: string }) {
|
|
788
887
|
const { did, email } = opts
|
|
789
888
|
await this.db.transaction(async (dbTxn) => {
|
|
790
|
-
await
|
|
889
|
+
await accountHelpers.updateEmail(dbTxn, did, email)
|
|
791
890
|
await emailToken.deleteAllEmailTokens(dbTxn, did)
|
|
792
891
|
})
|
|
793
892
|
}
|
|
@@ -85,13 +85,14 @@ export async function up(
|
|
|
85
85
|
.select('authenticatedAt as createdAt') // Best we can do
|
|
86
86
|
.select('authenticatedAt as updatedAt')
|
|
87
87
|
.where('remember', '=', 1)
|
|
88
|
-
.
|
|
88
|
+
.where(({ exists, selectFrom }) =>
|
|
89
89
|
// device_account does not have fkey on account.did,
|
|
90
90
|
// so we satisfy account_device_did_fk with this condition.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
exists(
|
|
92
|
+
selectFrom('account')
|
|
93
|
+
.selectAll()
|
|
94
|
+
.whereRef('account.did', '=', 'device_account.did'),
|
|
95
|
+
),
|
|
95
96
|
),
|
|
96
97
|
)
|
|
97
98
|
.onConflict((oc) => oc.doNothing())
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
ClientAuthLegacy,
|
|
5
5
|
Code,
|
|
6
6
|
DeviceId,
|
|
7
|
+
Did,
|
|
7
8
|
OAuthAuthorizationRequestParameters,
|
|
8
9
|
OAuthClientId,
|
|
9
10
|
RequestId,
|
|
@@ -12,7 +13,7 @@ import { DateISO, JsonEncoded } from '../../../db/index.js'
|
|
|
12
13
|
|
|
13
14
|
export interface AuthorizationRequest {
|
|
14
15
|
id: RequestId
|
|
15
|
-
did:
|
|
16
|
+
did: Did | null
|
|
16
17
|
deviceId: DeviceId | null
|
|
17
18
|
|
|
18
19
|
clientId: OAuthClientId
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { Selectable } from 'kysely'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AuthorizedClientData,
|
|
4
|
+
Did,
|
|
5
|
+
OAuthClientId,
|
|
6
|
+
} from '@atproto/oauth-provider'
|
|
3
7
|
import { DateISO, JsonEncoded } from '../../../db/index.js'
|
|
4
8
|
|
|
5
9
|
export interface AuthorizedClient {
|
|
6
|
-
did:
|
|
10
|
+
did: Did
|
|
7
11
|
clientId: OAuthClientId
|
|
8
12
|
|
|
9
13
|
createdAt: DateISO
|
|
@@ -4,18 +4,18 @@ import {
|
|
|
4
4
|
ClientAuthLegacy,
|
|
5
5
|
Code,
|
|
6
6
|
DeviceId,
|
|
7
|
+
Did,
|
|
7
8
|
OAuthAuthorizationDetails,
|
|
8
9
|
OAuthAuthorizationRequestParameters,
|
|
9
10
|
OAuthClientId,
|
|
10
11
|
RefreshToken,
|
|
11
|
-
Sub,
|
|
12
12
|
TokenId,
|
|
13
13
|
} from '@atproto/oauth-provider'
|
|
14
14
|
import { DateISO, JsonEncoded } from '../../../db/cast.js'
|
|
15
15
|
|
|
16
16
|
export interface Token {
|
|
17
17
|
id: Generated<number>
|
|
18
|
-
did:
|
|
18
|
+
did: Did
|
|
19
19
|
|
|
20
20
|
tokenId: TokenId
|
|
21
21
|
createdAt: DateISO
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import assert from 'node:assert'
|
|
2
|
-
import { DeviceId } from '@atproto/oauth-provider'
|
|
3
|
-
import { DidString } from '@atproto/syntax'
|
|
2
|
+
import { DeviceId, Did } from '@atproto/oauth-provider'
|
|
4
3
|
import { toDateISO } from '../../db/index.js'
|
|
5
4
|
import { AccountDb } from '../db/index.js'
|
|
6
5
|
import { selectAccountQB } from './account.js'
|
|
@@ -26,13 +25,10 @@ export function upsertQB(db: AccountDb, deviceId: DeviceId, did: string) {
|
|
|
26
25
|
|
|
27
26
|
export function selectQB(
|
|
28
27
|
db: AccountDb,
|
|
29
|
-
filter: {
|
|
30
|
-
sub?: string
|
|
31
|
-
deviceId?: DeviceId
|
|
32
|
-
},
|
|
28
|
+
filter: { did?: Did; deviceId?: DeviceId },
|
|
33
29
|
) {
|
|
34
30
|
assert(
|
|
35
|
-
filter.
|
|
31
|
+
filter.did != null || filter.deviceId != null,
|
|
36
32
|
'Either sub or deviceId must be provided',
|
|
37
33
|
)
|
|
38
34
|
|
|
@@ -52,10 +48,8 @@ export function selectQB(
|
|
|
52
48
|
'device.ipAddress',
|
|
53
49
|
'device.lastSeenAt',
|
|
54
50
|
])
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
)
|
|
58
|
-
.if(filter.deviceId != null, (qb) =>
|
|
51
|
+
.$if(filter.did != null, (qb) => qb.where('actor.did', '=', filter.did!))
|
|
52
|
+
.$if(filter.deviceId != null, (qb) =>
|
|
59
53
|
qb.where('account_device.deviceId', '=', filter.deviceId!),
|
|
60
54
|
)
|
|
61
55
|
)
|
|
@@ -46,8 +46,10 @@ export const selectAccountQB = (db: AccountDb, flags?: AvailabilityFlags) => {
|
|
|
46
46
|
return db.db
|
|
47
47
|
.selectFrom('actor')
|
|
48
48
|
.leftJoin('account', 'actor.did', 'account.did')
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
.$if(!includeTakenDown, (qb) =>
|
|
50
|
+
qb.where(notSoftDeletedClause(ref('actor'))),
|
|
51
|
+
)
|
|
52
|
+
.$if(!includeDeactivated, (qb) =>
|
|
51
53
|
qb.where('actor.deactivatedAt', 'is', null),
|
|
52
54
|
)
|
|
53
55
|
.select([
|
|
@@ -69,11 +71,11 @@ export const getAccount = async (
|
|
|
69
71
|
flags?: AvailabilityFlags,
|
|
70
72
|
): Promise<ActorAccount | null> => {
|
|
71
73
|
const found = await selectAccountQB(db, flags)
|
|
72
|
-
.where((
|
|
74
|
+
.where((eb) => {
|
|
73
75
|
if (isDidIdentifier(handleOrDid)) {
|
|
74
|
-
return
|
|
76
|
+
return eb('actor.did', '=', handleOrDid)
|
|
75
77
|
} else {
|
|
76
|
-
return
|
|
78
|
+
return eb('actor.handle', '=', handleOrDid)
|
|
77
79
|
}
|
|
78
80
|
})
|
|
79
81
|
.executeTakeFirst()
|
|
@@ -202,12 +204,16 @@ export const updateHandle = async (
|
|
|
202
204
|
.updateTable('actor')
|
|
203
205
|
.set({ handle })
|
|
204
206
|
.where('did', '=', did)
|
|
205
|
-
.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
.where(({ not, exists }) =>
|
|
208
|
+
not(
|
|
209
|
+
exists(
|
|
210
|
+
db.db
|
|
211
|
+
.selectFrom('actor')
|
|
212
|
+
.where('handle', '=', handle)
|
|
213
|
+
.where('did', '!=', did)
|
|
214
|
+
.selectAll(),
|
|
215
|
+
),
|
|
216
|
+
),
|
|
211
217
|
),
|
|
212
218
|
)
|
|
213
219
|
if (res.numUpdatedRows < 1) {
|
|
@@ -290,8 +296,8 @@ export const deactivateAccount = async (
|
|
|
290
296
|
db: AccountDb,
|
|
291
297
|
did: DidString,
|
|
292
298
|
deleteAfter: string | null,
|
|
293
|
-
) => {
|
|
294
|
-
await db.executeWithRetry(
|
|
299
|
+
): Promise<boolean> => {
|
|
300
|
+
const [res] = await db.executeWithRetry(
|
|
295
301
|
db.db
|
|
296
302
|
.updateTable('actor')
|
|
297
303
|
.set({
|
|
@@ -300,18 +306,35 @@ export const deactivateAccount = async (
|
|
|
300
306
|
})
|
|
301
307
|
.where('did', '=', did),
|
|
302
308
|
)
|
|
309
|
+
|
|
310
|
+
return res.numUpdatedRows > 0
|
|
303
311
|
}
|
|
304
312
|
|
|
305
|
-
export const activateAccount = async (
|
|
306
|
-
|
|
313
|
+
export const activateAccount = async (
|
|
314
|
+
db: AccountDb,
|
|
315
|
+
did: DidString,
|
|
316
|
+
flags?: AvailabilityFlags,
|
|
317
|
+
): Promise<boolean> => {
|
|
318
|
+
const { includeTakenDown = false, includeDeactivated = true } = flags ?? {}
|
|
319
|
+
const { ref } = db.db.dynamic
|
|
320
|
+
|
|
321
|
+
const [res] = await db.executeWithRetry(
|
|
307
322
|
db.db
|
|
308
323
|
.updateTable('actor')
|
|
309
324
|
.set({
|
|
310
325
|
deactivatedAt: null,
|
|
311
326
|
deleteAfter: null,
|
|
312
327
|
})
|
|
313
|
-
.where('did', '=', did)
|
|
328
|
+
.where('did', '=', did)
|
|
329
|
+
.$if(!includeTakenDown, (q) =>
|
|
330
|
+
q.where(notSoftDeletedClause(ref('actor'))),
|
|
331
|
+
)
|
|
332
|
+
.$if(!includeDeactivated, (q) =>
|
|
333
|
+
q.where('actor.deactivatedAt', 'is not', null),
|
|
334
|
+
),
|
|
314
335
|
)
|
|
336
|
+
|
|
337
|
+
return res.numUpdatedRows > 0
|
|
315
338
|
}
|
|
316
339
|
|
|
317
340
|
export const formatAccountStatus = (
|