@atproto/pds 0.5.12 → 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 +36 -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,106 +0,0 @@
|
|
|
1
|
-
import { Redis } from 'ioredis'
|
|
2
|
-
import { DAY, backoffMs, retry } from '@atproto/common'
|
|
3
|
-
import { Client, XrpcError } from '@atproto/lex'
|
|
4
|
-
import { InvalidTokenError, OAuthScope } from '@atproto/oauth-provider'
|
|
5
|
-
import { UpstreamFailureError } from '@atproto/xrpc-server'
|
|
6
|
-
import { CachedGetter, GetterOptions } from '@atproto-labs/simple-store'
|
|
7
|
-
import { SimpleStoreMemory } from '@atproto-labs/simple-store-memory'
|
|
8
|
-
import { SimpleStoreRedis } from '@atproto-labs/simple-store-redis'
|
|
9
|
-
import { com } from '../lexicons.js'
|
|
10
|
-
import { oauthLogger } from '../logger.js'
|
|
11
|
-
|
|
12
|
-
const PREFIX = 'ref:'
|
|
13
|
-
|
|
14
|
-
type ScopeReference = `${typeof PREFIX}${string}`
|
|
15
|
-
const isScopeReference = (scope?: OAuthScope): scope is ScopeReference =>
|
|
16
|
-
scope != null && scope.startsWith(PREFIX) && !scope.includes(' ')
|
|
17
|
-
|
|
18
|
-
const identity = <T>(value: T): T => value
|
|
19
|
-
|
|
20
|
-
export class ScopeReferenceGetter extends CachedGetter<
|
|
21
|
-
ScopeReference,
|
|
22
|
-
OAuthScope
|
|
23
|
-
> {
|
|
24
|
-
constructor(
|
|
25
|
-
protected readonly entryway: Client,
|
|
26
|
-
redis?: Redis,
|
|
27
|
-
) {
|
|
28
|
-
super(
|
|
29
|
-
async (ref, options) => {
|
|
30
|
-
return retry(async () => this.fetchDereferencedScope(ref, options), {
|
|
31
|
-
maxRetries: 3,
|
|
32
|
-
getWaitMs: (n) => backoffMs(n, 250, 2000),
|
|
33
|
-
retryable: (err) =>
|
|
34
|
-
!options?.signal?.aborted &&
|
|
35
|
-
err instanceof XrpcError &&
|
|
36
|
-
err.shouldRetry(),
|
|
37
|
-
})
|
|
38
|
-
},
|
|
39
|
-
redis
|
|
40
|
-
? new SimpleStoreRedis(redis, {
|
|
41
|
-
// tradeoff between wasted memory usage (by no longer used scopes)
|
|
42
|
-
// and amount of requests to entryway:
|
|
43
|
-
ttl: 1 * DAY,
|
|
44
|
-
|
|
45
|
-
keyPrefix: `auth-scope-${PREFIX}`,
|
|
46
|
-
encode: identity,
|
|
47
|
-
decode: identity,
|
|
48
|
-
})
|
|
49
|
-
: new SimpleStoreMemory({ max: 1000 }),
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
protected async fetchDereferencedScope(
|
|
54
|
-
ref: ScopeReference,
|
|
55
|
-
opts?: GetterOptions,
|
|
56
|
-
): Promise<OAuthScope> {
|
|
57
|
-
oauthLogger.info({ ref }, 'Fetching scope reference')
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
const { scope } = await this.entryway.call(
|
|
61
|
-
com.atproto.temp.dereferenceScope,
|
|
62
|
-
{ scope: ref },
|
|
63
|
-
{
|
|
64
|
-
signal: opts?.signal,
|
|
65
|
-
headers: opts?.noCache ? { 'Cache-Control': 'no-cache' } : undefined,
|
|
66
|
-
},
|
|
67
|
-
)
|
|
68
|
-
|
|
69
|
-
oauthLogger.info({ ref, scope }, 'Successfully fetched scope reference')
|
|
70
|
-
|
|
71
|
-
// @NOTE the part after `PREFIX` (in the input scope) is the CID of the
|
|
72
|
-
// scope string returned by entryway. Since there is a trust
|
|
73
|
-
// relationship with the entryway, we don't need to verify or enforce
|
|
74
|
-
// that here.
|
|
75
|
-
|
|
76
|
-
return scope
|
|
77
|
-
} catch (err) {
|
|
78
|
-
oauthLogger.error({ err, ref }, 'Failed to fetch scope reference')
|
|
79
|
-
|
|
80
|
-
throw err
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async dereference(scope?: OAuthScope): Promise<undefined | OAuthScope> {
|
|
85
|
-
oauthLogger.debug({ scope }, 'Dereferencing scope')
|
|
86
|
-
|
|
87
|
-
if (!isScopeReference(scope)) return scope
|
|
88
|
-
return this.get(scope).catch(handleDereferenceError)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function handleDereferenceError(cause: unknown): never {
|
|
93
|
-
if (cause instanceof XrpcError && cause.error === 'InvalidScopeReference') {
|
|
94
|
-
// The scope reference cannot be found on the server.
|
|
95
|
-
// Consider the session as invalid, allowing entryway to
|
|
96
|
-
// re-build the scope as the user re-authenticates. This
|
|
97
|
-
// should never happen though.
|
|
98
|
-
throw InvalidTokenError.from(cause, 'DPoP')
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
throw new UpstreamFailureError(
|
|
102
|
-
'Failed to fetch token permissions',
|
|
103
|
-
undefined,
|
|
104
|
-
{ cause },
|
|
105
|
-
)
|
|
106
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { Keypair } from '@atproto/crypto'
|
|
2
|
-
import { ActorStoreResources } from './actor-store-resources.js'
|
|
3
|
-
import { ActorStoreTransactor } from './actor-store-transactor.js'
|
|
4
|
-
import { ActorDb } from './db/index.js'
|
|
5
|
-
import { PreferenceReader } from './preference/reader.js'
|
|
6
|
-
import { RecordReader } from './record/reader.js'
|
|
7
|
-
import { RepoReader } from './repo/reader.js'
|
|
8
|
-
|
|
9
|
-
export class ActorStoreReader {
|
|
10
|
-
public readonly repo: RepoReader
|
|
11
|
-
public readonly record: RecordReader
|
|
12
|
-
public readonly pref: PreferenceReader
|
|
13
|
-
|
|
14
|
-
constructor(
|
|
15
|
-
public readonly did: string,
|
|
16
|
-
protected readonly db: ActorDb,
|
|
17
|
-
protected readonly resources: ActorStoreResources,
|
|
18
|
-
public readonly keypair: () => Promise<Keypair>,
|
|
19
|
-
) {
|
|
20
|
-
const blobstore = resources.blobstore(did)
|
|
21
|
-
|
|
22
|
-
this.repo = new RepoReader(db, blobstore)
|
|
23
|
-
this.record = new RecordReader(db)
|
|
24
|
-
this.pref = new PreferenceReader(db)
|
|
25
|
-
|
|
26
|
-
// Invoke "keypair" once. Also avoids leaking "this" as keypair context.
|
|
27
|
-
let keypairPromise: Promise<Keypair>
|
|
28
|
-
this.keypair = () => (keypairPromise ??= Promise.resolve().then(keypair))
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async transact<T>(
|
|
32
|
-
fn: (fn: ActorStoreTransactor) => T | PromiseLike<T>,
|
|
33
|
-
): Promise<T> {
|
|
34
|
-
const keypair = await this.keypair()
|
|
35
|
-
return this.db.transaction((dbTxn) => {
|
|
36
|
-
const store = new ActorStoreTransactor(
|
|
37
|
-
this.did,
|
|
38
|
-
dbTxn,
|
|
39
|
-
keypair,
|
|
40
|
-
this.resources,
|
|
41
|
-
)
|
|
42
|
-
return fn(store)
|
|
43
|
-
})
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { Keypair } from '@atproto/crypto'
|
|
2
|
-
import { ActorStoreResources } from './actor-store-resources.js'
|
|
3
|
-
import { ActorDb } from './db/index.js'
|
|
4
|
-
import { PreferenceTransactor } from './preference/transactor.js'
|
|
5
|
-
import { RecordTransactor } from './record/transactor.js'
|
|
6
|
-
import { RepoTransactor } from './repo/transactor.js'
|
|
7
|
-
|
|
8
|
-
export class ActorStoreTransactor {
|
|
9
|
-
public readonly record: RecordTransactor
|
|
10
|
-
public readonly repo: RepoTransactor
|
|
11
|
-
public readonly pref: PreferenceTransactor
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
public readonly did: string,
|
|
15
|
-
protected readonly db: ActorDb,
|
|
16
|
-
protected readonly keypair: Keypair,
|
|
17
|
-
protected readonly resources: ActorStoreResources,
|
|
18
|
-
) {
|
|
19
|
-
const blobstore = resources.blobstore(did)
|
|
20
|
-
|
|
21
|
-
this.record = new RecordTransactor(db, blobstore)
|
|
22
|
-
this.pref = new PreferenceTransactor(db)
|
|
23
|
-
this.repo = new RepoTransactor(
|
|
24
|
-
db,
|
|
25
|
-
blobstore,
|
|
26
|
-
did,
|
|
27
|
-
keypair,
|
|
28
|
-
resources.backgroundQueue,
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { ActorStoreTransactor } from './actor-store-transactor.js'
|
|
2
|
-
|
|
3
|
-
export class ActorStoreWriter extends ActorStoreTransactor {
|
|
4
|
-
async transact<T>(
|
|
5
|
-
fn: (fn: ActorStoreTransactor) => T | PromiseLike<T>,
|
|
6
|
-
): Promise<T> {
|
|
7
|
-
return this.db.transaction((dbTxn) => {
|
|
8
|
-
const transactor = new ActorStoreTransactor(
|
|
9
|
-
this.did,
|
|
10
|
-
dbTxn,
|
|
11
|
-
this.keypair,
|
|
12
|
-
this.resources,
|
|
13
|
-
)
|
|
14
|
-
return fn(transactor)
|
|
15
|
-
})
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import fs, { mkdir } from 'node:fs/promises'
|
|
3
|
-
import path from 'node:path'
|
|
4
|
-
import { fileExists, readIfExists, rmIfExists } from '@atproto/common'
|
|
5
|
-
import * as crypto from '@atproto/crypto'
|
|
6
|
-
import { ExportableKeypair, Keypair } from '@atproto/crypto'
|
|
7
|
-
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
8
|
-
import { ActorStoreConfig } from '../config/index.js'
|
|
9
|
-
import { retrySqlite } from '../db/index.js'
|
|
10
|
-
import { DiskBlobStore } from '../disk-blobstore.js'
|
|
11
|
-
import { blobStoreLogger } from '../logger.js'
|
|
12
|
-
import { ActorStoreReader } from './actor-store-reader.js'
|
|
13
|
-
import { ActorStoreResources } from './actor-store-resources.js'
|
|
14
|
-
import { ActorStoreTransactor } from './actor-store-transactor.js'
|
|
15
|
-
import { ActorStoreWriter } from './actor-store-writer.js'
|
|
16
|
-
import { ActorDb, getDb, getMigrator } from './db/index.js'
|
|
17
|
-
|
|
18
|
-
export class ActorStore {
|
|
19
|
-
reservedKeyDir: string
|
|
20
|
-
|
|
21
|
-
constructor(
|
|
22
|
-
public cfg: ActorStoreConfig,
|
|
23
|
-
public resources: ActorStoreResources,
|
|
24
|
-
) {
|
|
25
|
-
this.reservedKeyDir = path.join(cfg.directory, 'reserved_keys')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async getLocation(did: string) {
|
|
29
|
-
const didHash = await crypto.sha256Hex(did)
|
|
30
|
-
const directory = path.join(this.cfg.directory, didHash.slice(0, 2), did)
|
|
31
|
-
const dbLocation = path.join(directory, `store.sqlite`)
|
|
32
|
-
const keyLocation = path.join(directory, `key`)
|
|
33
|
-
return { directory, dbLocation, keyLocation }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async exists(did: string): Promise<boolean> {
|
|
37
|
-
const location = await this.getLocation(did)
|
|
38
|
-
return await fileExists(location.dbLocation)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async keypair(did: string): Promise<Keypair> {
|
|
42
|
-
const { keyLocation } = await this.getLocation(did)
|
|
43
|
-
const privKey = await fs.readFile(keyLocation)
|
|
44
|
-
return crypto.Secp256k1Keypair.import(privKey)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async openDb(did: string): Promise<ActorDb> {
|
|
48
|
-
const { dbLocation } = await this.getLocation(did)
|
|
49
|
-
const exists = await fileExists(dbLocation)
|
|
50
|
-
if (!exists) {
|
|
51
|
-
throw new InvalidRequestError('Repo not found', 'NotFound')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const db = getDb(dbLocation, this.cfg.disableWalAutoCheckpoint)
|
|
55
|
-
|
|
56
|
-
// run a simple select with retry logic to ensure the db is ready (not in wal recovery mode)
|
|
57
|
-
try {
|
|
58
|
-
await retrySqlite(() =>
|
|
59
|
-
db.db.selectFrom('repo_root').selectAll().execute(),
|
|
60
|
-
)
|
|
61
|
-
} catch (err) {
|
|
62
|
-
db.close()
|
|
63
|
-
throw err
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return db
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async read<T>(did: string, fn: (fn: ActorStoreReader) => T | PromiseLike<T>) {
|
|
70
|
-
const db = await this.openDb(did)
|
|
71
|
-
try {
|
|
72
|
-
const getKeypair = () => this.keypair(did)
|
|
73
|
-
return await fn(new ActorStoreReader(did, db, this.resources, getKeypair))
|
|
74
|
-
} finally {
|
|
75
|
-
db.close()
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async transact<T>(
|
|
80
|
-
did: string,
|
|
81
|
-
fn: (fn: ActorStoreTransactor) => T | PromiseLike<T>,
|
|
82
|
-
) {
|
|
83
|
-
const keypair = await this.keypair(did)
|
|
84
|
-
const db = await this.openDb(did)
|
|
85
|
-
try {
|
|
86
|
-
return await db.transaction((dbTxn) => {
|
|
87
|
-
return fn(new ActorStoreTransactor(did, dbTxn, keypair, this.resources))
|
|
88
|
-
})
|
|
89
|
-
} finally {
|
|
90
|
-
db.close()
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async writeNoTransaction<T>(
|
|
95
|
-
did: string,
|
|
96
|
-
fn: (fn: ActorStoreWriter) => T | PromiseLike<T>,
|
|
97
|
-
) {
|
|
98
|
-
const keypair = await this.keypair(did)
|
|
99
|
-
const db = await this.openDb(did)
|
|
100
|
-
try {
|
|
101
|
-
return await fn(new ActorStoreWriter(did, db, keypair, this.resources))
|
|
102
|
-
} finally {
|
|
103
|
-
db.close()
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async create(did: string, keypair: ExportableKeypair) {
|
|
108
|
-
const { directory, dbLocation, keyLocation } = await this.getLocation(did)
|
|
109
|
-
// ensure subdir exists
|
|
110
|
-
await mkdir(directory, { recursive: true })
|
|
111
|
-
const exists = await fileExists(dbLocation)
|
|
112
|
-
if (exists) {
|
|
113
|
-
throw new InvalidRequestError('Repo already exists', 'AlreadyExists')
|
|
114
|
-
}
|
|
115
|
-
const privKey = await keypair.export()
|
|
116
|
-
await fs.writeFile(keyLocation, privKey)
|
|
117
|
-
|
|
118
|
-
const db: ActorDb = getDb(dbLocation, this.cfg.disableWalAutoCheckpoint)
|
|
119
|
-
try {
|
|
120
|
-
await db.ensureWal()
|
|
121
|
-
const migrator = getMigrator(db)
|
|
122
|
-
await migrator.migrateToLatestOrThrow()
|
|
123
|
-
} finally {
|
|
124
|
-
db.close()
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async destroy(did: string) {
|
|
129
|
-
const blobstore = this.resources.blobstore(did)
|
|
130
|
-
if (blobstore instanceof DiskBlobStore) {
|
|
131
|
-
await blobstore.deleteAll()
|
|
132
|
-
} else {
|
|
133
|
-
const cids = await this.read(did, async (store) =>
|
|
134
|
-
store.repo.blob.getBlobCids(),
|
|
135
|
-
)
|
|
136
|
-
await blobstore.deleteMany(cids).catch((err) => {
|
|
137
|
-
blobStoreLogger.error({ did, cids, err }, 'Failed to delete blobs')
|
|
138
|
-
})
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const { directory } = await this.getLocation(did)
|
|
142
|
-
await rmIfExists(directory, true)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async reserveKeypair(did?: string): Promise<string> {
|
|
146
|
-
let keyLoc: string | undefined
|
|
147
|
-
if (did) {
|
|
148
|
-
assertSafePathPart(did)
|
|
149
|
-
keyLoc = path.join(this.reservedKeyDir, did)
|
|
150
|
-
const maybeKey = await loadKey(keyLoc)
|
|
151
|
-
if (maybeKey) {
|
|
152
|
-
return maybeKey.did()
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
const keypair = await crypto.Secp256k1Keypair.create({ exportable: true })
|
|
156
|
-
const keyDid = keypair.did()
|
|
157
|
-
keyLoc = keyLoc ?? path.join(this.reservedKeyDir, keyDid)
|
|
158
|
-
await mkdir(this.reservedKeyDir, { recursive: true })
|
|
159
|
-
await fs.writeFile(keyLoc, await keypair.export())
|
|
160
|
-
return keyDid
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async getReservedKeypair(
|
|
164
|
-
signingKeyOrDid: string,
|
|
165
|
-
): Promise<ExportableKeypair | undefined> {
|
|
166
|
-
return loadKey(path.join(this.reservedKeyDir, signingKeyOrDid))
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async clearReservedKeypair(keyDid: string, did?: string) {
|
|
170
|
-
await rmIfExists(path.join(this.reservedKeyDir, keyDid))
|
|
171
|
-
if (did) {
|
|
172
|
-
await rmIfExists(path.join(this.reservedKeyDir, did))
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async storePlcOp(did: string, op: Uint8Array) {
|
|
177
|
-
const { directory } = await this.getLocation(did)
|
|
178
|
-
const opLoc = path.join(directory, `did-op`)
|
|
179
|
-
await fs.writeFile(opLoc, op)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
async getPlcOp(did: string): Promise<Uint8Array> {
|
|
183
|
-
const { directory } = await this.getLocation(did)
|
|
184
|
-
const opLoc = path.join(directory, `did-op`)
|
|
185
|
-
return await fs.readFile(opLoc)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async clearPlcOp(did: string) {
|
|
189
|
-
const { directory } = await this.getLocation(did)
|
|
190
|
-
const opLoc = path.join(directory, `did-op`)
|
|
191
|
-
await rmIfExists(opLoc)
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const loadKey = async (loc: string): Promise<ExportableKeypair | undefined> => {
|
|
196
|
-
const privKey = await readIfExists(loc)
|
|
197
|
-
if (!privKey) return undefined
|
|
198
|
-
return crypto.Secp256k1Keypair.import(privKey, { exportable: true })
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function assertSafePathPart(part: string) {
|
|
202
|
-
const normalized = path.normalize(part)
|
|
203
|
-
assert(
|
|
204
|
-
part === normalized &&
|
|
205
|
-
!part.startsWith('.') &&
|
|
206
|
-
!part.includes('/') &&
|
|
207
|
-
!part.includes('\\'),
|
|
208
|
-
`unsafe path part: ${part}`,
|
|
209
|
-
)
|
|
210
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import stream from 'node:stream'
|
|
2
|
-
import { Cid, parseCid } from '@atproto/lex-data'
|
|
3
|
-
import { BlobNotFoundError, BlobStore } from '@atproto/repo'
|
|
4
|
-
import { AtUriString } from '@atproto/syntax'
|
|
5
|
-
import { InvalidRequestError } from '@atproto/xrpc-server'
|
|
6
|
-
import { countAll, countDistinct, notSoftDeletedClause } from '../../db/util.js'
|
|
7
|
-
import { com } from '../../lexicons/index.js'
|
|
8
|
-
import { ActorDb } from '../db/index.js'
|
|
9
|
-
|
|
10
|
-
export class BlobReader {
|
|
11
|
-
constructor(
|
|
12
|
-
public db: ActorDb,
|
|
13
|
-
public blobstore: BlobStore,
|
|
14
|
-
) {}
|
|
15
|
-
|
|
16
|
-
async getBlobMetadata(
|
|
17
|
-
cid: Cid,
|
|
18
|
-
): Promise<{ size: number; mimeType?: `${string}/${string}` }> {
|
|
19
|
-
const { ref } = this.db.db.dynamic
|
|
20
|
-
const found = await this.db.db
|
|
21
|
-
.selectFrom('blob')
|
|
22
|
-
.selectAll()
|
|
23
|
-
.where('blob.cid', '=', cid.toString())
|
|
24
|
-
.where(notSoftDeletedClause(ref('blob')))
|
|
25
|
-
.executeTakeFirst()
|
|
26
|
-
if (!found) {
|
|
27
|
-
throw new InvalidRequestError('Blob not found')
|
|
28
|
-
}
|
|
29
|
-
return {
|
|
30
|
-
size: found.size,
|
|
31
|
-
mimeType: found.mimeType as `${string}/${string}` | undefined,
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async getBlob(cid: Cid): Promise<{
|
|
36
|
-
size: number
|
|
37
|
-
mimeType?: `${string}/${string}`
|
|
38
|
-
stream: stream.Readable
|
|
39
|
-
}> {
|
|
40
|
-
const metadata = await this.getBlobMetadata(cid)
|
|
41
|
-
const stream = await this.blobstore.getStream(cid).catch((err) => {
|
|
42
|
-
if (err instanceof BlobNotFoundError) {
|
|
43
|
-
throw new InvalidRequestError('Blob not found')
|
|
44
|
-
}
|
|
45
|
-
throw err
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
return { ...metadata, stream }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async listBlobs(opts: {
|
|
52
|
-
since?: string
|
|
53
|
-
cursor?: string
|
|
54
|
-
limit: number
|
|
55
|
-
}): Promise<string[]> {
|
|
56
|
-
const { since, cursor, limit } = opts
|
|
57
|
-
let builder = this.db.db
|
|
58
|
-
.selectFrom('record_blob')
|
|
59
|
-
.select('blobCid')
|
|
60
|
-
.orderBy('blobCid', 'asc')
|
|
61
|
-
.groupBy('blobCid')
|
|
62
|
-
.limit(limit)
|
|
63
|
-
if (since) {
|
|
64
|
-
builder = builder
|
|
65
|
-
.innerJoin('record', 'record.uri', 'record_blob.recordUri')
|
|
66
|
-
.where('record.repoRev', '>', since)
|
|
67
|
-
}
|
|
68
|
-
if (cursor) {
|
|
69
|
-
builder = builder.where('blobCid', '>', cursor)
|
|
70
|
-
}
|
|
71
|
-
const res = await builder.execute()
|
|
72
|
-
return res.map((row) => row.blobCid)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async getBlobTakedownStatus(
|
|
76
|
-
cid: Cid,
|
|
77
|
-
): Promise<com.atproto.admin.defs.StatusAttr | null> {
|
|
78
|
-
const res = await this.db.db
|
|
79
|
-
.selectFrom('blob')
|
|
80
|
-
.select('takedownRef')
|
|
81
|
-
.where('cid', '=', cid.toString())
|
|
82
|
-
.executeTakeFirst()
|
|
83
|
-
if (!res) return null
|
|
84
|
-
return res.takedownRef
|
|
85
|
-
? { applied: true, ref: res.takedownRef }
|
|
86
|
-
: { applied: false }
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async hasRecordsForBlob(cid: Cid): Promise<boolean> {
|
|
90
|
-
const res = await this.db.db
|
|
91
|
-
.selectFrom('record_blob')
|
|
92
|
-
.where('blobCid', '=', cid.toString())
|
|
93
|
-
.select('blobCid')
|
|
94
|
-
.limit(1)
|
|
95
|
-
.executeTakeFirst()
|
|
96
|
-
return res != null
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async getBlobsForRecord(recordUri: string): Promise<string[]> {
|
|
100
|
-
const res = await this.db.db
|
|
101
|
-
.selectFrom('blob')
|
|
102
|
-
.innerJoin('record_blob', 'record_blob.blobCid', 'blob.cid')
|
|
103
|
-
.where('recordUri', '=', recordUri)
|
|
104
|
-
.select('blob.cid')
|
|
105
|
-
.execute()
|
|
106
|
-
return res.map((row) => row.cid)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async blobCount(): Promise<number> {
|
|
110
|
-
const res = await this.db.db
|
|
111
|
-
.selectFrom('blob')
|
|
112
|
-
.select(countAll.as('count'))
|
|
113
|
-
.executeTakeFirst()
|
|
114
|
-
return res?.count ?? 0
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async recordBlobCount(): Promise<number> {
|
|
118
|
-
const { ref } = this.db.db.dynamic
|
|
119
|
-
const res = await this.db.db
|
|
120
|
-
.selectFrom('record_blob')
|
|
121
|
-
.select(countDistinct(ref('blobCid')).as('count'))
|
|
122
|
-
.executeTakeFirst()
|
|
123
|
-
return res?.count ?? 0
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
async listMissingBlobs(opts: {
|
|
127
|
-
cursor?: string
|
|
128
|
-
limit: number
|
|
129
|
-
}): Promise<{ cid: string; recordUri: AtUriString }[]> {
|
|
130
|
-
const { cursor, limit } = opts
|
|
131
|
-
let builder = this.db.db
|
|
132
|
-
.selectFrom('record_blob')
|
|
133
|
-
.where(({ not, exists, selectFrom }) =>
|
|
134
|
-
not(
|
|
135
|
-
exists(
|
|
136
|
-
selectFrom('blob')
|
|
137
|
-
.selectAll()
|
|
138
|
-
.whereRef('blob.cid', '=', 'record_blob.blobCid'),
|
|
139
|
-
),
|
|
140
|
-
),
|
|
141
|
-
)
|
|
142
|
-
.selectAll()
|
|
143
|
-
.orderBy('blobCid', 'asc')
|
|
144
|
-
.groupBy('blobCid')
|
|
145
|
-
.limit(limit)
|
|
146
|
-
if (cursor) {
|
|
147
|
-
builder = builder.where('blobCid', '>', cursor)
|
|
148
|
-
}
|
|
149
|
-
const res = await builder.execute()
|
|
150
|
-
return res.map((row) => ({
|
|
151
|
-
cid: row.blobCid,
|
|
152
|
-
recordUri: row.recordUri as AtUriString,
|
|
153
|
-
}))
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async getBlobCids() {
|
|
157
|
-
const blobRows = await this.db.db.selectFrom('blob').select('cid').execute()
|
|
158
|
-
return blobRows.map((row) => parseCid(row.cid))
|
|
159
|
-
}
|
|
160
|
-
}
|