@atproto/pds 0.5.11 → 0.5.14
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 +46 -0
- package/dist/api/app/bsky/notification/index.d.ts.map +1 -1
- package/dist/api/app/bsky/notification/index.js +2 -0
- package/dist/api/app/bsky/notification/index.js.map +1 -1
- package/dist/api/app/bsky/notification/unregisterPush.d.ts +4 -0
- package/dist/api/app/bsky/notification/unregisterPush.d.ts.map +1 -0
- package/dist/api/app/bsky/notification/unregisterPush.js +48 -0
- package/dist/api/app/bsky/notification/unregisterPush.js.map +1 -0
- package/package.json +42 -38
- package/build.templates.cjs +0 -22
- package/example.env +0 -42
- package/jest.config.cjs +0 -27
- package/src/account-manager/account-manager.ts +0 -916
- package/src/account-manager/db/index.ts +0 -21
- package/src/account-manager/db/migrations/001-init.ts +0 -115
- package/src/account-manager/db/migrations/002-account-deactivation.ts +0 -17
- package/src/account-manager/db/migrations/003-privileged-app-passwords.ts +0 -12
- package/src/account-manager/db/migrations/004-oauth.ts +0 -122
- package/src/account-manager/db/migrations/005-oauth-account-management.ts +0 -136
- package/src/account-manager/db/migrations/006-oauth-permission-sets.ts +0 -20
- package/src/account-manager/db/migrations/007-lexicon-failures-index.ts +0 -14
- package/src/account-manager/db/migrations/index.ts +0 -17
- package/src/account-manager/db/schema/account-device.ts +0 -14
- package/src/account-manager/db/schema/account.ts +0 -16
- package/src/account-manager/db/schema/actor.ts +0 -17
- package/src/account-manager/db/schema/app-password.ts +0 -13
- package/src/account-manager/db/schema/authorization-request.ts +0 -30
- package/src/account-manager/db/schema/authorized-client.ts +0 -23
- package/src/account-manager/db/schema/device.ts +0 -18
- package/src/account-manager/db/schema/email-token.ts +0 -19
- package/src/account-manager/db/schema/index.ts +0 -43
- package/src/account-manager/db/schema/invite-code.ts +0 -24
- package/src/account-manager/db/schema/lexicon.ts +0 -15
- package/src/account-manager/db/schema/refresh-token.ts +0 -11
- package/src/account-manager/db/schema/repo-root.ts +0 -12
- package/src/account-manager/db/schema/token.ts +0 -38
- package/src/account-manager/db/schema/used-refresh-token.ts +0 -13
- package/src/account-manager/helpers/account-device.ts +0 -63
- package/src/account-manager/helpers/account.ts +0 -355
- package/src/account-manager/helpers/auth.ts +0 -222
- package/src/account-manager/helpers/authorization-request.ts +0 -90
- package/src/account-manager/helpers/authorized-client.ts +0 -75
- package/src/account-manager/helpers/device.ts +0 -47
- package/src/account-manager/helpers/email-token.ts +0 -87
- package/src/account-manager/helpers/invite.ts +0 -263
- package/src/account-manager/helpers/lexicon.ts +0 -67
- package/src/account-manager/helpers/password.ts +0 -136
- package/src/account-manager/helpers/repo.ts +0 -24
- package/src/account-manager/helpers/scrypt.ts +0 -53
- package/src/account-manager/helpers/token.ts +0 -158
- package/src/account-manager/helpers/used-refresh-token.ts +0 -30
- package/src/account-manager/oauth-store.ts +0 -880
- package/src/account-manager/scope-reference-getter.ts +0 -106
- package/src/actor-store/actor-store-reader.ts +0 -45
- package/src/actor-store/actor-store-resources.ts +0 -8
- package/src/actor-store/actor-store-transactor.ts +0 -31
- package/src/actor-store/actor-store-writer.ts +0 -17
- package/src/actor-store/actor-store.ts +0 -210
- package/src/actor-store/blob/reader.ts +0 -160
- package/src/actor-store/blob/transactor.ts +0 -383
- package/src/actor-store/db/index.ts +0 -20
- package/src/actor-store/db/migrations/001-init.ts +0 -105
- package/src/actor-store/db/migrations/index.ts +0 -5
- package/src/actor-store/db/schema/account-pref.ts +0 -11
- package/src/actor-store/db/schema/backlink.ts +0 -9
- package/src/actor-store/db/schema/blob.ts +0 -14
- package/src/actor-store/db/schema/index.ts +0 -23
- package/src/actor-store/db/schema/record-blob.ts +0 -8
- package/src/actor-store/db/schema/record.ts +0 -14
- package/src/actor-store/db/schema/repo-block.ts +0 -10
- package/src/actor-store/db/schema/repo-root.ts +0 -10
- package/src/actor-store/migrate.ts +0 -39
- package/src/actor-store/preference/reader.ts +0 -48
- package/src/actor-store/preference/transactor.ts +0 -55
- package/src/actor-store/preference/util.ts +0 -39
- package/src/actor-store/record/reader.ts +0 -374
- package/src/actor-store/record/transactor.ts +0 -111
- package/src/actor-store/repo/reader.ts +0 -31
- package/src/actor-store/repo/sql-repo-reader.ts +0 -150
- package/src/actor-store/repo/sql-repo-transactor.ts +0 -105
- package/src/actor-store/repo/transactor.ts +0 -227
- package/src/api/app/bsky/actor/getPreferences.ts +0 -57
- package/src/api/app/bsky/actor/getProfile.ts +0 -41
- package/src/api/app/bsky/actor/getProfiles.ts +0 -51
- package/src/api/app/bsky/actor/index.ts +0 -13
- package/src/api/app/bsky/actor/putPreferences.ts +0 -62
- package/src/api/app/bsky/feed/getActorLikes.ts +0 -63
- package/src/api/app/bsky/feed/getAuthorFeed.ts +0 -84
- package/src/api/app/bsky/feed/getFeed.ts +0 -47
- package/src/api/app/bsky/feed/getPostThread.ts +0 -251
- package/src/api/app/bsky/feed/getTimeline.ts +0 -50
- package/src/api/app/bsky/feed/index.ts +0 -15
- package/src/api/app/bsky/index.ts +0 -11
- package/src/api/app/bsky/notification/index.ts +0 -7
- package/src/api/app/bsky/notification/registerPush.ts +0 -71
- package/src/api/app/bsky/util/resolver.ts +0 -20
- package/src/api/com/atproto/admin/deleteAccount.ts +0 -22
- package/src/api/com/atproto/admin/disableAccountInvites.ts +0 -18
- package/src/api/com/atproto/admin/disableInviteCodes.ts +0 -21
- package/src/api/com/atproto/admin/enableAccountInvites.ts +0 -18
- package/src/api/com/atproto/admin/getAccountInfo.ts +0 -32
- package/src/api/com/atproto/admin/getAccountInfos.ts +0 -34
- package/src/api/com/atproto/admin/getInviteCodes.ts +0 -126
- package/src/api/com/atproto/admin/getSubjectStatus.ts +0 -76
- package/src/api/com/atproto/admin/index.ts +0 -31
- package/src/api/com/atproto/admin/sendEmail.ts +0 -47
- package/src/api/com/atproto/admin/updateAccountEmail.ts +0 -32
- package/src/api/com/atproto/admin/updateAccountHandle.ts +0 -47
- package/src/api/com/atproto/admin/updateAccountPassword.ts +0 -34
- package/src/api/com/atproto/admin/updateSubjectStatus.ts +0 -68
- package/src/api/com/atproto/admin/util.ts +0 -66
- package/src/api/com/atproto/identity/getRecommendedDidCredentials.ts +0 -50
- package/src/api/com/atproto/identity/index.ts +0 -17
- package/src/api/com/atproto/identity/requestPlcOperationSignature.ts +0 -59
- package/src/api/com/atproto/identity/resolveHandle.ts +0 -50
- package/src/api/com/atproto/identity/signPlcOperation.ts +0 -85
- package/src/api/com/atproto/identity/submitPlcOperation.ts +0 -65
- package/src/api/com/atproto/identity/updateHandle.ts +0 -66
- package/src/api/com/atproto/index.ts +0 -19
- package/src/api/com/atproto/moderation/createReport.ts +0 -41
- package/src/api/com/atproto/moderation/index.ts +0 -7
- package/src/api/com/atproto/repo/applyWrites.ts +0 -226
- package/src/api/com/atproto/repo/createRecord.ts +0 -143
- package/src/api/com/atproto/repo/deleteRecord.ts +0 -122
- package/src/api/com/atproto/repo/describeRepo.ts +0 -43
- package/src/api/com/atproto/repo/getRecord.ts +0 -40
- package/src/api/com/atproto/repo/importRepo.ts +0 -101
- package/src/api/com/atproto/repo/index.ts +0 -25
- package/src/api/com/atproto/repo/listMissingBlobs.ts +0 -29
- package/src/api/com/atproto/repo/listRecords.ts +0 -36
- package/src/api/com/atproto/repo/putRecord.ts +0 -211
- package/src/api/com/atproto/repo/uploadBlob.ts +0 -60
- package/src/api/com/atproto/server/activateAccount.ts +0 -37
- package/src/api/com/atproto/server/checkAccountStatus.ts +0 -51
- package/src/api/com/atproto/server/confirmEmail.ts +0 -39
- package/src/api/com/atproto/server/createAccount.ts +0 -327
- package/src/api/com/atproto/server/createAppPassword.ts +0 -53
- package/src/api/com/atproto/server/createInviteCode.ts +0 -38
- package/src/api/com/atproto/server/createInviteCodes.ts +0 -42
- package/src/api/com/atproto/server/createSession.ts +0 -97
- package/src/api/com/atproto/server/deactivateAccount.ts +0 -41
- package/src/api/com/atproto/server/deleteAccount.ts +0 -85
- package/src/api/com/atproto/server/deleteSession.ts +0 -23
- package/src/api/com/atproto/server/describeServer.ts +0 -29
- package/src/api/com/atproto/server/getAccountInviteCodes.ts +0 -142
- package/src/api/com/atproto/server/getServiceAuth.ts +0 -111
- package/src/api/com/atproto/server/getSession.ts +0 -80
- package/src/api/com/atproto/server/index.ts +0 -55
- package/src/api/com/atproto/server/listAppPasswords.ts +0 -45
- package/src/api/com/atproto/server/refreshSession.ts +0 -72
- package/src/api/com/atproto/server/requestAccountDelete.ts +0 -66
- package/src/api/com/atproto/server/requestEmailConfirmation.ts +0 -68
- package/src/api/com/atproto/server/requestEmailUpdate.ts +0 -86
- package/src/api/com/atproto/server/requestPasswordReset.ts +0 -52
- package/src/api/com/atproto/server/reserveSigningKey.ts +0 -15
- package/src/api/com/atproto/server/resetPassword.ts +0 -50
- package/src/api/com/atproto/server/revokeAppPassword.ts +0 -42
- package/src/api/com/atproto/server/updateEmail.ts +0 -52
- package/src/api/com/atproto/server/util.ts +0 -136
- package/src/api/com/atproto/sync/deprecated/getCheckout.ts +0 -27
- package/src/api/com/atproto/sync/deprecated/getHead.ts +0 -33
- package/src/api/com/atproto/sync/getBlob.ts +0 -61
- package/src/api/com/atproto/sync/getBlocks.ts +0 -37
- package/src/api/com/atproto/sync/getLatestCommit.ts +0 -33
- package/src/api/com/atproto/sync/getRecord.ts +0 -49
- package/src/api/com/atproto/sync/getRepo.ts +0 -75
- package/src/api/com/atproto/sync/getRepoStatus.ts +0 -34
- package/src/api/com/atproto/sync/index.ts +0 -27
- package/src/api/com/atproto/sync/listBlobs.ts +0 -33
- package/src/api/com/atproto/sync/listRepos.ts +0 -74
- package/src/api/com/atproto/sync/subscribeRepos.ts +0 -73
- package/src/api/com/atproto/sync/util.ts +0 -37
- package/src/api/com/atproto/temp/checkSignupQueue.ts +0 -34
- package/src/api/com/atproto/temp/index.ts +0 -7
- package/src/api/index.ts +0 -10
- package/src/api/proxy.ts +0 -44
- package/src/app-view.ts +0 -24
- package/src/auth-output.ts +0 -52
- package/src/auth-routes.ts +0 -64
- package/src/auth-scope.ts +0 -40
- package/src/auth-verifier.ts +0 -668
- package/src/background.ts +0 -65
- package/src/basic-routes.ts +0 -52
- package/src/bsky-app-view.ts +0 -33
- package/src/config/config.ts +0 -553
- package/src/config/env.ts +0 -167
- package/src/config/index.ts +0 -3
- package/src/config/secrets.ts +0 -54
- package/src/context.ts +0 -523
- package/src/crawlers.ts +0 -46
- package/src/db/cast.ts +0 -52
- package/src/db/db.ts +0 -140
- package/src/db/index.ts +0 -4
- package/src/db/migrator.ts +0 -40
- package/src/db/pagination.ts +0 -132
- package/src/db/tables/moderation.ts +0 -80
- package/src/db/util.ts +0 -108
- package/src/did-cache/db/index.ts +0 -21
- package/src/did-cache/db/migrations.ts +0 -17
- package/src/did-cache/db/schema.ts +0 -9
- package/src/did-cache/index.ts +0 -131
- package/src/disk-blobstore.ts +0 -172
- package/src/error.ts +0 -19
- package/src/handle/explicit-slurs.ts +0 -22
- package/src/handle/index.ts +0 -49
- package/src/handle/reserved.ts +0 -1059
- package/src/image/image-url-builder.ts +0 -16
- package/src/index.ts +0 -189
- package/src/lexicons.ts +0 -4
- package/src/logger.ts +0 -35
- package/src/mailer/index.ts +0 -111
- package/src/mailer/moderation.ts +0 -33
- package/src/mailer/templates/confirm-email.d.ts +0 -4
- package/src/mailer/templates/confirm-email.hbs +0 -158
- package/src/mailer/templates/delete-account.d.ts +0 -4
- package/src/mailer/templates/delete-account.hbs +0 -156
- package/src/mailer/templates/plc-operation.d.ts +0 -4
- package/src/mailer/templates/plc-operation.hbs +0 -153
- package/src/mailer/templates/reset-password.d.ts +0 -4
- package/src/mailer/templates/reset-password.hbs +0 -154
- package/src/mailer/templates/update-email.d.ts +0 -4
- package/src/mailer/templates/update-email.hbs +0 -153
- package/src/mailer/templates.ts +0 -17
- package/src/pipethrough.ts +0 -716
- package/src/rate-limits.ts +0 -59
- package/src/read-after-write/index.ts +0 -3
- package/src/read-after-write/types.ts +0 -35
- package/src/read-after-write/util.ts +0 -101
- package/src/read-after-write/viewer.ts +0 -290
- package/src/redis.ts +0 -25
- package/src/repo/index.ts +0 -2
- package/src/repo/prepare.ts +0 -266
- package/src/repo/types.ts +0 -65
- package/src/scripts/README.md +0 -40
- package/src/scripts/index.ts +0 -20
- package/src/scripts/publish-identity.ts +0 -60
- package/src/scripts/rebuild-repo.ts +0 -119
- package/src/scripts/rotate-keys.ts +0 -146
- package/src/scripts/sequencer-recovery/index.ts +0 -23
- package/src/scripts/sequencer-recovery/recoverer.ts +0 -297
- package/src/scripts/sequencer-recovery/recovery-db.ts +0 -65
- package/src/scripts/sequencer-recovery/repair-repos.ts +0 -49
- package/src/scripts/sequencer-recovery/user-queues.ts +0 -44
- package/src/scripts/util.ts +0 -7
- package/src/sequencer/db/index.ts +0 -21
- package/src/sequencer/db/migrations/001-init.ts +0 -35
- package/src/sequencer/db/migrations/index.ts +0 -5
- package/src/sequencer/db/schema.ts +0 -19
- package/src/sequencer/events.ts +0 -199
- package/src/sequencer/index.ts +0 -3
- package/src/sequencer/outbox.ts +0 -123
- package/src/sequencer/sequencer.ts +0 -290
- package/src/util/compression.ts +0 -16
- package/src/util/debug.ts +0 -10
- package/src/util/http.ts +0 -31
- package/src/util/types.ts +0 -7
- package/src/well-known.ts +0 -30
- package/test.env +0 -2
- package/tests/__snapshots__/takedown-appeal.test.ts.snap +0 -43
- package/tests/_oauth_client_assets_middleware.ts +0 -23
- package/tests/_puppeteer.ts +0 -147
- package/tests/_types.d.ts +0 -16
- package/tests/_util.ts +0 -191
- package/tests/account-deactivation.test.ts +0 -204
- package/tests/account-deletion.test.ts +0 -300
- package/tests/account-manager.test.ts +0 -462
- package/tests/account-migration.test.ts +0 -221
- package/tests/account-status.test.ts +0 -206
- package/tests/account.test.ts +0 -595
- package/tests/app-passwords.test.ts +0 -262
- package/tests/auth.test.ts +0 -405
- package/tests/blob-deletes.test.ts +0 -204
- package/tests/create-post.test.ts +0 -79
- package/tests/crud.test.ts +0 -1595
- package/tests/db.test.ts +0 -170
- package/tests/email-confirmation.test.ts +0 -227
- package/tests/entryway-mock.ts +0 -323
- package/tests/entryway.test.ts +0 -145
- package/tests/file-uploads.test.ts +0 -301
- package/tests/get-service-auth.test.ts +0 -81
- package/tests/handle-validation.test.ts +0 -56
- package/tests/handles.test.ts +0 -274
- package/tests/invite-codes.test.ts +0 -367
- package/tests/invites-admin.test.ts +0 -252
- package/tests/moderation.test.ts +0 -280
- package/tests/moderator-auth.test.ts +0 -177
- package/tests/oauth.test.ts +0 -334
- package/tests/plc-operations.test.ts +0 -239
- package/tests/preferences.test.ts +0 -352
- package/tests/proxied/__snapshots__/admin.test.ts.snap +0 -516
- package/tests/proxied/__snapshots__/feedgen.test.ts.snap +0 -215
- package/tests/proxied/__snapshots__/views.test.ts.snap +0 -4456
- package/tests/proxied/admin.test.ts +0 -340
- package/tests/proxied/feedgen.test.ts +0 -66
- package/tests/proxied/notif.test.ts +0 -85
- package/tests/proxied/procedures.test.ts +0 -175
- package/tests/proxied/proxy-catchall.test.ts +0 -256
- package/tests/proxied/proxy-header.test.ts +0 -239
- package/tests/proxied/proxy-oauth-aud.test.ts +0 -182
- package/tests/proxied/read-after-write.test.ts +0 -382
- package/tests/proxied/views.test.ts +0 -608
- package/tests/races.test.ts +0 -89
- package/tests/rate-limits.test.ts +0 -70
- package/tests/recovery.test.ts +0 -180
- package/tests/seeds/basic.ts +0 -165
- package/tests/seeds/follows.ts +0 -57
- package/tests/seeds/likes.ts +0 -14
- package/tests/seeds/reposts.ts +0 -18
- package/tests/seeds/thread.ts +0 -40
- package/tests/seeds/users-bulk.ts +0 -246
- package/tests/seeds/users.ts +0 -67
- package/tests/sequencer.test.ts +0 -251
- package/tests/server.test.ts +0 -151
- package/tests/sync/invertible-ops.test.ts +0 -99
- package/tests/sync/list.test.ts +0 -43
- package/tests/sync/subscribe-repos.test.ts +0 -672
- package/tests/sync/sync.test.ts +0 -316
- package/tests/takedown-appeal.test.ts +0 -166
- package/tsconfig.build.json +0 -9
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
import crypto from 'node:crypto'
|
|
2
|
-
import stream from 'node:stream'
|
|
3
|
-
// eslint-disable-next-line import/default, import/no-named-as-default-member
|
|
4
|
-
import fileType from 'file-type'
|
|
5
|
-
const { fromStream: fileTypeFromStream } = fileType
|
|
6
|
-
import PQueue from 'p-queue'
|
|
7
|
-
import { SECOND, cloneStream, streamSize } from '@atproto/common'
|
|
8
|
-
import {
|
|
9
|
-
BlobRef,
|
|
10
|
-
Cid,
|
|
11
|
-
TypedBlobRef,
|
|
12
|
-
cidForRawHash,
|
|
13
|
-
getBlobCidString,
|
|
14
|
-
parseCid,
|
|
15
|
-
} from '@atproto/lex-data'
|
|
16
|
-
import { BlobNotFoundError, BlobStore, WriteOpAction } from '@atproto/repo'
|
|
17
|
-
import { AtUri, currentDatetimeString } from '@atproto/syntax'
|
|
18
|
-
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
19
|
-
import { BackgroundQueue } from '../../background.js'
|
|
20
|
-
import { com } from '../../lexicons/index.js'
|
|
21
|
-
import { blobStoreLogger as log } from '../../logger.js'
|
|
22
|
-
import { PreparedWrite } from '../../repo/types.js'
|
|
23
|
-
import { ActorDb, Blob as BlobTable } from '../db/index.js'
|
|
24
|
-
import { BlobReader } from './reader.js'
|
|
25
|
-
|
|
26
|
-
export type BlobMetadata = {
|
|
27
|
-
tempKey: string
|
|
28
|
-
size: number
|
|
29
|
-
cid: Cid
|
|
30
|
-
mimeType: string
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class BlobTransactor extends BlobReader {
|
|
34
|
-
constructor(
|
|
35
|
-
public db: ActorDb,
|
|
36
|
-
public blobstore: BlobStore,
|
|
37
|
-
public backgroundQueue: BackgroundQueue,
|
|
38
|
-
) {
|
|
39
|
-
super(db, blobstore)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async insertBlobs(recordUri: string, blobs: Iterable<BlobRef>) {
|
|
43
|
-
const values = Array.from(blobs, (blob) => ({
|
|
44
|
-
recordUri,
|
|
45
|
-
blobCid: getBlobCidString(blob),
|
|
46
|
-
}))
|
|
47
|
-
|
|
48
|
-
if (values.length) {
|
|
49
|
-
await this.db.db
|
|
50
|
-
.insertInto('record_blob')
|
|
51
|
-
.values(values)
|
|
52
|
-
.onConflict((oc) => oc.doNothing())
|
|
53
|
-
.execute()
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async uploadBlobAndGetMetadata(
|
|
58
|
-
userSuggestedMime: string,
|
|
59
|
-
blobStream: stream.Readable,
|
|
60
|
-
): Promise<BlobMetadata> {
|
|
61
|
-
const [tempKey, size, sha256, sniffedMime] = await Promise.all([
|
|
62
|
-
this.blobstore.putTemp(cloneStream(blobStream)),
|
|
63
|
-
streamSize(cloneStream(blobStream)),
|
|
64
|
-
sha256Stream(cloneStream(blobStream)),
|
|
65
|
-
mimeTypeFromStream(cloneStream(blobStream)),
|
|
66
|
-
])
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
tempKey,
|
|
70
|
-
size,
|
|
71
|
-
cid: cidForRawHash(sha256),
|
|
72
|
-
mimeType: sniffedMime || userSuggestedMime,
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async trackUntetheredBlob(metadata: BlobMetadata): Promise<TypedBlobRef> {
|
|
77
|
-
const { tempKey, size, cid, mimeType } = metadata
|
|
78
|
-
const cidStr = cid.toString()
|
|
79
|
-
|
|
80
|
-
const found = await this.db.db
|
|
81
|
-
.selectFrom('blob')
|
|
82
|
-
.selectAll()
|
|
83
|
-
.where('cid', '=', cidStr)
|
|
84
|
-
.executeTakeFirst()
|
|
85
|
-
if (found?.takedownRef) {
|
|
86
|
-
throw new InvalidRequestError('Blob has been takendown, cannot re-upload')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
await this.db.db
|
|
90
|
-
.insertInto('blob')
|
|
91
|
-
.values({
|
|
92
|
-
cid: cidStr,
|
|
93
|
-
mimeType,
|
|
94
|
-
size,
|
|
95
|
-
tempKey,
|
|
96
|
-
createdAt: currentDatetimeString(),
|
|
97
|
-
})
|
|
98
|
-
.onConflict((oc) =>
|
|
99
|
-
oc
|
|
100
|
-
.column('cid')
|
|
101
|
-
.doUpdateSet({ tempKey })
|
|
102
|
-
.where('blob.tempKey', 'is not', null),
|
|
103
|
-
)
|
|
104
|
-
.execute()
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
$type: 'blob',
|
|
108
|
-
ref: cid,
|
|
109
|
-
mimeType,
|
|
110
|
-
size,
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async processWriteBlobs(rev: string, writes: PreparedWrite[]) {
|
|
115
|
-
await this.deleteDereferencedBlobs(writes)
|
|
116
|
-
|
|
117
|
-
const ac = new AbortController()
|
|
118
|
-
|
|
119
|
-
// Limit the number of parallel requests made to the BlobStore by using a
|
|
120
|
-
// a queue with concurrency management.
|
|
121
|
-
type Task = () => Promise<void>
|
|
122
|
-
const tasks: Task[] = []
|
|
123
|
-
|
|
124
|
-
for (const write of writes) {
|
|
125
|
-
if (isCreate(write) || isUpdate(write)) {
|
|
126
|
-
for (const blob of write.blobs) {
|
|
127
|
-
tasks.push(async () => {
|
|
128
|
-
if (ac.signal.aborted) return
|
|
129
|
-
await this.associateBlob(blob, write.uri)
|
|
130
|
-
await this.verifyBlobAndMakePermanent(blob, ac.signal)
|
|
131
|
-
})
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const queue = new PQueue({
|
|
138
|
-
concurrency: 20,
|
|
139
|
-
// The blob store should already limit the time of every operation. We
|
|
140
|
-
// add a timeout here as an extra precaution.
|
|
141
|
-
timeout: 60 * SECOND,
|
|
142
|
-
throwOnTimeout: true,
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
// Will reject as soon as any task fails, causing the "finally" block
|
|
146
|
-
// below to run, aborting every other pending tasks.
|
|
147
|
-
await queue.addAll(tasks)
|
|
148
|
-
} finally {
|
|
149
|
-
ac.abort()
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
async updateBlobTakedownStatus(
|
|
154
|
-
cid: Cid,
|
|
155
|
-
takedown: com.atproto.admin.defs.StatusAttr,
|
|
156
|
-
) {
|
|
157
|
-
const takedownRef = takedown.applied
|
|
158
|
-
? takedown.ref ?? currentDatetimeString()
|
|
159
|
-
: null
|
|
160
|
-
await this.db.db
|
|
161
|
-
.updateTable('blob')
|
|
162
|
-
.set({ takedownRef })
|
|
163
|
-
.where('cid', '=', cid.toString())
|
|
164
|
-
.executeTakeFirst()
|
|
165
|
-
|
|
166
|
-
try {
|
|
167
|
-
// @NOTE find a way to not perform i/o operations during the transaction
|
|
168
|
-
// (typically by using a state in the "blob" table, and another process to
|
|
169
|
-
// handle the actual i/o)
|
|
170
|
-
if (takedown.applied) {
|
|
171
|
-
await this.blobstore.quarantine(cid)
|
|
172
|
-
} else {
|
|
173
|
-
await this.blobstore.unquarantine(cid)
|
|
174
|
-
}
|
|
175
|
-
} catch (err) {
|
|
176
|
-
if (!(err instanceof BlobNotFoundError)) {
|
|
177
|
-
log.error(
|
|
178
|
-
{ err, cid: cid.toString() },
|
|
179
|
-
'could not update blob takedown status',
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
throw err
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async deleteDereferencedBlobs(
|
|
188
|
-
writes: PreparedWrite[],
|
|
189
|
-
skipBlobStore?: boolean,
|
|
190
|
-
) {
|
|
191
|
-
const deletes = writes.filter(isDelete)
|
|
192
|
-
const updates = writes.filter(isUpdate)
|
|
193
|
-
const uris = [...deletes, ...updates].map((w) => w.uri.toString())
|
|
194
|
-
if (uris.length === 0) return
|
|
195
|
-
|
|
196
|
-
const deletedRepoBlobs = await this.db.db
|
|
197
|
-
.deleteFrom('record_blob')
|
|
198
|
-
.where('recordUri', 'in', uris)
|
|
199
|
-
.returning('blobCid')
|
|
200
|
-
.execute()
|
|
201
|
-
if (deletedRepoBlobs.length === 0) return
|
|
202
|
-
|
|
203
|
-
const deletedRepoBlobCids = deletedRepoBlobs.map((row) => row.blobCid)
|
|
204
|
-
const duplicateCids = await this.db.db
|
|
205
|
-
.selectFrom('record_blob')
|
|
206
|
-
.where('blobCid', 'in', deletedRepoBlobCids)
|
|
207
|
-
.select('blobCid')
|
|
208
|
-
.execute()
|
|
209
|
-
|
|
210
|
-
const newBlobCids = writes
|
|
211
|
-
.filter((w) => isUpdate(w) || isCreate(w))
|
|
212
|
-
.flatMap((w) => w.blobs.map((b) => b.ref.toString()))
|
|
213
|
-
|
|
214
|
-
const cidsToKeep = [
|
|
215
|
-
...newBlobCids,
|
|
216
|
-
...duplicateCids.map((row) => row.blobCid),
|
|
217
|
-
]
|
|
218
|
-
|
|
219
|
-
const cidsToDelete = deletedRepoBlobCids.filter(
|
|
220
|
-
(cid) => !cidsToKeep.includes(cid),
|
|
221
|
-
)
|
|
222
|
-
if (cidsToDelete.length === 0) return
|
|
223
|
-
|
|
224
|
-
await this.db.db
|
|
225
|
-
.deleteFrom('blob')
|
|
226
|
-
.where('cid', 'in', cidsToDelete)
|
|
227
|
-
.execute()
|
|
228
|
-
|
|
229
|
-
if (!skipBlobStore) {
|
|
230
|
-
this.db.onCommit(() => {
|
|
231
|
-
this.backgroundQueue.add(async () => {
|
|
232
|
-
try {
|
|
233
|
-
const cids = cidsToDelete.map((cid) => parseCid(cid))
|
|
234
|
-
await this.blobstore.deleteMany(cids)
|
|
235
|
-
} catch (err) {
|
|
236
|
-
log.error(
|
|
237
|
-
{ err, cids: cidsToDelete },
|
|
238
|
-
'could not delete blobs from blobstore',
|
|
239
|
-
)
|
|
240
|
-
}
|
|
241
|
-
})
|
|
242
|
-
})
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async verifyBlobAndMakePermanent(
|
|
247
|
-
blob: TypedBlobRef,
|
|
248
|
-
signal?: AbortSignal,
|
|
249
|
-
): Promise<void> {
|
|
250
|
-
const found = await this.db.db
|
|
251
|
-
.selectFrom('blob')
|
|
252
|
-
.select(['tempKey', 'size', 'mimeType'])
|
|
253
|
-
.where('cid', '=', blob.ref.toString())
|
|
254
|
-
.where('takedownRef', 'is', null)
|
|
255
|
-
.executeTakeFirst()
|
|
256
|
-
|
|
257
|
-
signal?.throwIfAborted()
|
|
258
|
-
|
|
259
|
-
if (!found) {
|
|
260
|
-
throw new InvalidRequestError(
|
|
261
|
-
`Could not find blob: ${blob.ref.toString()}`,
|
|
262
|
-
'BlobNotFound',
|
|
263
|
-
)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
if (found.tempKey) {
|
|
267
|
-
verifyBlob(blob, found)
|
|
268
|
-
|
|
269
|
-
// @NOTE it is less than ideal to perform async (i/o) operations during a
|
|
270
|
-
// transaction. Especially since there have been instances of the actor-db
|
|
271
|
-
// being locked, requiring to kick the processes.
|
|
272
|
-
|
|
273
|
-
// The better solution would be to update the blob state in the database
|
|
274
|
-
// (e.g. "makeItPermanent") and to process those updates outside of the
|
|
275
|
-
// transaction.
|
|
276
|
-
|
|
277
|
-
await this.blobstore
|
|
278
|
-
.makePermanent(found.tempKey, blob.ref)
|
|
279
|
-
.catch((err) => {
|
|
280
|
-
log.error(
|
|
281
|
-
{ err, cid: blob.ref.toString() },
|
|
282
|
-
'could not make blob permanent',
|
|
283
|
-
)
|
|
284
|
-
|
|
285
|
-
throw err
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
signal?.throwIfAborted()
|
|
289
|
-
|
|
290
|
-
await this.db.db
|
|
291
|
-
.updateTable('blob')
|
|
292
|
-
.set({ tempKey: null })
|
|
293
|
-
.where('tempKey', '=', found.tempKey)
|
|
294
|
-
.execute()
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
async insertBlobMetadata(blob: TypedBlobRef): Promise<void> {
|
|
299
|
-
await this.db.db
|
|
300
|
-
.insertInto('blob')
|
|
301
|
-
.values({
|
|
302
|
-
cid: blob.ref.toString(),
|
|
303
|
-
mimeType: blob.mimeType,
|
|
304
|
-
size: blob.size,
|
|
305
|
-
createdAt: currentDatetimeString(),
|
|
306
|
-
})
|
|
307
|
-
.onConflict((oc) => oc.doNothing())
|
|
308
|
-
.execute()
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async associateBlob(blob: TypedBlobRef, recordUri: AtUri): Promise<void> {
|
|
312
|
-
await this.db.db
|
|
313
|
-
.insertInto('record_blob')
|
|
314
|
-
.values({
|
|
315
|
-
blobCid: blob.ref.toString(),
|
|
316
|
-
recordUri: recordUri.toString(),
|
|
317
|
-
})
|
|
318
|
-
.onConflict((oc) => oc.doNothing())
|
|
319
|
-
.execute()
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
export class CidNotFound extends Error {
|
|
324
|
-
cid: Cid
|
|
325
|
-
constructor(cid: Cid) {
|
|
326
|
-
super(`cid not found: ${cid.toString()}`)
|
|
327
|
-
this.cid = cid
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
async function sha256Stream(toHash: stream.Readable): Promise<Uint8Array> {
|
|
332
|
-
const hash = crypto.createHash('sha256')
|
|
333
|
-
try {
|
|
334
|
-
for await (const chunk of toHash) {
|
|
335
|
-
hash.write(chunk)
|
|
336
|
-
}
|
|
337
|
-
} catch (err) {
|
|
338
|
-
hash.end()
|
|
339
|
-
throw err
|
|
340
|
-
}
|
|
341
|
-
hash.end()
|
|
342
|
-
return hash.read()
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
async function mimeTypeFromStream(
|
|
346
|
-
blobStream: stream.Readable,
|
|
347
|
-
): Promise<string | undefined> {
|
|
348
|
-
const fileType = await fileTypeFromStream(blobStream)
|
|
349
|
-
blobStream.destroy()
|
|
350
|
-
return fileType?.mime
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Ensures that the blob referenced in the record matches the stored blob.
|
|
355
|
-
*/
|
|
356
|
-
function verifyBlob(
|
|
357
|
-
blob: TypedBlobRef,
|
|
358
|
-
found: Pick<BlobTable, 'size' | 'mimeType'>,
|
|
359
|
-
) {
|
|
360
|
-
if (blob.mimeType !== found.mimeType) {
|
|
361
|
-
throw new InvalidRequestError(
|
|
362
|
-
`Referenced Mimetype does not match stored blob. Expected: ${found.mimeType}, Got: ${blob.mimeType}`,
|
|
363
|
-
'InvalidMimeType',
|
|
364
|
-
)
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (blob.size !== found.size) {
|
|
368
|
-
throw new InvalidRequestError(
|
|
369
|
-
`Referenced Size does not match stored blob. Expected: ${found.size}, Got: ${blob.size}`,
|
|
370
|
-
'InvalidSize',
|
|
371
|
-
)
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
function isCreate(write: PreparedWrite) {
|
|
376
|
-
return write.action === WriteOpAction.Create
|
|
377
|
-
}
|
|
378
|
-
function isUpdate(write: PreparedWrite) {
|
|
379
|
-
return write.action === WriteOpAction.Update
|
|
380
|
-
}
|
|
381
|
-
function isDelete(write: PreparedWrite) {
|
|
382
|
-
return write.action === WriteOpAction.Delete
|
|
383
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Database, Migrator } from '../../db/index.js'
|
|
2
|
-
import migrations from './migrations/index.js'
|
|
3
|
-
import { DatabaseSchema } from './schema/index.js'
|
|
4
|
-
export * from './schema/index.js'
|
|
5
|
-
|
|
6
|
-
export type ActorDb = Database<DatabaseSchema>
|
|
7
|
-
|
|
8
|
-
export const getDb = (
|
|
9
|
-
location: string,
|
|
10
|
-
disableWalAutoCheckpoint = false,
|
|
11
|
-
): ActorDb => {
|
|
12
|
-
const pragmas: Record<string, string> = disableWalAutoCheckpoint
|
|
13
|
-
? { wal_autocheckpoint: '0' }
|
|
14
|
-
: {}
|
|
15
|
-
return Database.sqlite(location, { pragmas })
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const getMigrator = (db: Database<DatabaseSchema>) => {
|
|
19
|
-
return new Migrator(db.db, migrations)
|
|
20
|
-
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { Kysely } from 'kysely'
|
|
2
|
-
|
|
3
|
-
export async function up(db: Kysely<unknown>): Promise<void> {
|
|
4
|
-
await db.schema
|
|
5
|
-
.createTable('repo_root')
|
|
6
|
-
.addColumn('did', 'varchar', (col) => col.primaryKey())
|
|
7
|
-
.addColumn('cid', 'varchar', (col) => col.notNull())
|
|
8
|
-
.addColumn('rev', 'varchar', (col) => col.notNull())
|
|
9
|
-
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
|
10
|
-
.execute()
|
|
11
|
-
|
|
12
|
-
await db.schema
|
|
13
|
-
.createTable('repo_block')
|
|
14
|
-
.addColumn('cid', 'varchar', (col) => col.primaryKey())
|
|
15
|
-
.addColumn('repoRev', 'varchar', (col) => col.notNull())
|
|
16
|
-
.addColumn('size', 'integer', (col) => col.notNull())
|
|
17
|
-
.addColumn('content', 'blob', (col) => col.notNull())
|
|
18
|
-
.execute()
|
|
19
|
-
|
|
20
|
-
await db.schema
|
|
21
|
-
.createIndex('repo_block_repo_rev_idx')
|
|
22
|
-
.on('repo_block')
|
|
23
|
-
.columns(['repoRev', 'cid'])
|
|
24
|
-
.execute()
|
|
25
|
-
|
|
26
|
-
await db.schema
|
|
27
|
-
.createTable('record')
|
|
28
|
-
.addColumn('uri', 'varchar', (col) => col.primaryKey())
|
|
29
|
-
.addColumn('cid', 'varchar', (col) => col.notNull())
|
|
30
|
-
.addColumn('collection', 'varchar', (col) => col.notNull())
|
|
31
|
-
.addColumn('rkey', 'varchar', (col) => col.notNull())
|
|
32
|
-
.addColumn('repoRev', 'varchar', (col) => col.notNull())
|
|
33
|
-
.addColumn('indexedAt', 'varchar', (col) => col.notNull())
|
|
34
|
-
.addColumn('takedownRef', 'varchar')
|
|
35
|
-
.execute()
|
|
36
|
-
await db.schema
|
|
37
|
-
.createIndex('record_cid_idx')
|
|
38
|
-
.on('record')
|
|
39
|
-
.column('cid')
|
|
40
|
-
.execute()
|
|
41
|
-
await db.schema
|
|
42
|
-
.createIndex('record_collection_idx')
|
|
43
|
-
.on('record')
|
|
44
|
-
.column('collection')
|
|
45
|
-
.execute()
|
|
46
|
-
await db.schema
|
|
47
|
-
.createIndex('record_repo_rev_idx')
|
|
48
|
-
.on('record')
|
|
49
|
-
.column('repoRev')
|
|
50
|
-
.execute()
|
|
51
|
-
|
|
52
|
-
await db.schema
|
|
53
|
-
.createTable('blob')
|
|
54
|
-
.addColumn('cid', 'varchar', (col) => col.primaryKey())
|
|
55
|
-
.addColumn('mimeType', 'varchar', (col) => col.notNull())
|
|
56
|
-
.addColumn('size', 'integer', (col) => col.notNull())
|
|
57
|
-
.addColumn('tempKey', 'varchar')
|
|
58
|
-
.addColumn('width', 'integer')
|
|
59
|
-
.addColumn('height', 'integer')
|
|
60
|
-
.addColumn('createdAt', 'varchar', (col) => col.notNull())
|
|
61
|
-
.addColumn('takedownRef', 'varchar')
|
|
62
|
-
.execute()
|
|
63
|
-
await db.schema
|
|
64
|
-
.createIndex('blob_tempkey_idx')
|
|
65
|
-
.on('blob')
|
|
66
|
-
.column('tempKey')
|
|
67
|
-
.execute()
|
|
68
|
-
|
|
69
|
-
await db.schema
|
|
70
|
-
.createTable('record_blob')
|
|
71
|
-
.addColumn('blobCid', 'varchar', (col) => col.notNull())
|
|
72
|
-
.addColumn('recordUri', 'varchar', (col) => col.notNull())
|
|
73
|
-
.addPrimaryKeyConstraint(`record_blob_pkey`, ['blobCid', 'recordUri'])
|
|
74
|
-
.execute()
|
|
75
|
-
|
|
76
|
-
await db.schema
|
|
77
|
-
.createTable('backlink')
|
|
78
|
-
.addColumn('uri', 'varchar', (col) => col.notNull())
|
|
79
|
-
.addColumn('path', 'varchar', (col) => col.notNull())
|
|
80
|
-
.addColumn('linkTo', 'varchar', (col) => col.notNull())
|
|
81
|
-
.addPrimaryKeyConstraint('backlinks_pkey', ['uri', 'path'])
|
|
82
|
-
.execute()
|
|
83
|
-
await db.schema
|
|
84
|
-
.createIndex('backlink_link_to_idx')
|
|
85
|
-
.on('backlink')
|
|
86
|
-
.columns(['path', 'linkTo'])
|
|
87
|
-
.execute()
|
|
88
|
-
|
|
89
|
-
await db.schema
|
|
90
|
-
.createTable('account_pref')
|
|
91
|
-
.addColumn('id', 'integer', (col) => col.autoIncrement().primaryKey())
|
|
92
|
-
.addColumn('name', 'varchar', (col) => col.notNull())
|
|
93
|
-
.addColumn('valueJson', 'text', (col) => col.notNull())
|
|
94
|
-
.execute()
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export async function down(db: Kysely<unknown>): Promise<void> {
|
|
98
|
-
await db.schema.dropTable('account_pref').execute()
|
|
99
|
-
await db.schema.dropTable('backlink').execute()
|
|
100
|
-
await db.schema.dropTable('record_blob').execute()
|
|
101
|
-
await db.schema.dropTable('blob').execute()
|
|
102
|
-
await db.schema.dropTable('record').execute()
|
|
103
|
-
await db.schema.dropTable('repo_block').execute()
|
|
104
|
-
await db.schema.dropTable('repo_root').execute()
|
|
105
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export interface Blob {
|
|
2
|
-
cid: string
|
|
3
|
-
mimeType: string
|
|
4
|
-
size: number
|
|
5
|
-
tempKey: string | null
|
|
6
|
-
// width: number | null // @TODO: actually drop these columns from the db
|
|
7
|
-
// height: number | null
|
|
8
|
-
createdAt: string
|
|
9
|
-
takedownRef: string | null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const tableName = 'blob'
|
|
13
|
-
|
|
14
|
-
export type PartialDB = { [tableName]: Blob }
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import * as accountPref from './account-pref.js'
|
|
2
|
-
import * as backlink from './backlink.js'
|
|
3
|
-
import * as blob from './blob.js'
|
|
4
|
-
import * as recordBlob from './record-blob.js'
|
|
5
|
-
import * as record from './record.js'
|
|
6
|
-
import * as repoBlock from './repo-block.js'
|
|
7
|
-
import * as repoRoot from './repo-root.js'
|
|
8
|
-
|
|
9
|
-
export type DatabaseSchema = accountPref.PartialDB &
|
|
10
|
-
repoRoot.PartialDB &
|
|
11
|
-
record.PartialDB &
|
|
12
|
-
backlink.PartialDB &
|
|
13
|
-
repoBlock.PartialDB &
|
|
14
|
-
blob.PartialDB &
|
|
15
|
-
recordBlob.PartialDB
|
|
16
|
-
|
|
17
|
-
export type { AccountPref } from './account-pref.js'
|
|
18
|
-
export type { RepoRoot } from './repo-root.js'
|
|
19
|
-
export type { Record } from './record.js'
|
|
20
|
-
export type { Backlink } from './backlink.js'
|
|
21
|
-
export type { RepoBlock } from './repo-block.js'
|
|
22
|
-
export type { Blob } from './blob.js'
|
|
23
|
-
export type { RecordBlob } from './record-blob.js'
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// @NOTE also used by app-view (moderation)
|
|
2
|
-
export interface Record {
|
|
3
|
-
uri: string
|
|
4
|
-
cid: string
|
|
5
|
-
collection: string
|
|
6
|
-
rkey: string
|
|
7
|
-
repoRev: string
|
|
8
|
-
indexedAt: string
|
|
9
|
-
takedownRef: string | null
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const tableName = 'record'
|
|
13
|
-
|
|
14
|
-
export type PartialDB = { [tableName]: Record }
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { sql } from 'kysely'
|
|
2
|
-
import PQueue from 'p-queue'
|
|
3
|
-
import { AppContext } from '../context.js'
|
|
4
|
-
|
|
5
|
-
export const forEachActorStore = async (
|
|
6
|
-
ctx: AppContext,
|
|
7
|
-
opts: { concurrency?: number },
|
|
8
|
-
fn: (ctx: AppContext, did: string) => Promise<string>,
|
|
9
|
-
) => {
|
|
10
|
-
const { concurrency = 1 } = opts
|
|
11
|
-
|
|
12
|
-
const queue = new PQueue({ concurrency })
|
|
13
|
-
const actorQb = ctx.accountManager.db.db
|
|
14
|
-
.selectFrom('actor')
|
|
15
|
-
.selectAll()
|
|
16
|
-
.limit(2 * concurrency)
|
|
17
|
-
let cursor: { createdAt: string; did: string } | undefined
|
|
18
|
-
do {
|
|
19
|
-
const actors = cursor
|
|
20
|
-
? await actorQb
|
|
21
|
-
.where(
|
|
22
|
-
sql`("createdAt", "did")`,
|
|
23
|
-
'>',
|
|
24
|
-
sql`(${cursor.createdAt}, ${cursor.did})`,
|
|
25
|
-
)
|
|
26
|
-
.execute()
|
|
27
|
-
: await actorQb.execute()
|
|
28
|
-
queue.addAll(
|
|
29
|
-
actors.map(({ did }) => {
|
|
30
|
-
return () => fn(ctx, did)
|
|
31
|
-
}),
|
|
32
|
-
)
|
|
33
|
-
cursor = actors.at(-1)
|
|
34
|
-
await queue.onEmpty() // wait for all remaining items to be in process, then move on to next page
|
|
35
|
-
} while (cursor)
|
|
36
|
-
|
|
37
|
-
// finalize remaining work
|
|
38
|
-
await queue.onIdle()
|
|
39
|
-
}
|