@atproto/pds 0.5.12 → 0.5.15
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 +53 -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/dist/lexicons/app/bsky/actor/defs.defs.d.ts +6 -0
- package/dist/lexicons/app/bsky/actor/defs.defs.d.ts.map +1 -1
- package/dist/lexicons/app/bsky/actor/defs.defs.js +1 -0
- package/dist/lexicons/app/bsky/actor/defs.defs.js.map +1 -1
- 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
package/tests/crud.test.ts
DELETED
|
@@ -1,1595 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert'
|
|
2
|
-
import fs from 'node:fs/promises'
|
|
3
|
-
import {
|
|
4
|
-
AppBskyEmbedImages,
|
|
5
|
-
AppBskyFeedPost,
|
|
6
|
-
AppBskyFeedPostRecord,
|
|
7
|
-
AtpAgent,
|
|
8
|
-
BlobRef,
|
|
9
|
-
} from '@atproto/api'
|
|
10
|
-
import { TID, cidForCbor, ui8ToArrayBuffer } from '@atproto/common'
|
|
11
|
-
import { TestNetworkNoAppView } from '@atproto/dev-env'
|
|
12
|
-
import { BlobNotFoundError } from '@atproto/repo'
|
|
13
|
-
import { AtUri } from '@atproto/syntax'
|
|
14
|
-
import { AppContext } from '../src/context.js'
|
|
15
|
-
import { forSnapshot, paginateAll } from './_util.js'
|
|
16
|
-
|
|
17
|
-
describe('crud operations', () => {
|
|
18
|
-
let network: TestNetworkNoAppView
|
|
19
|
-
let ctx: AppContext
|
|
20
|
-
let agent: AtpAgent
|
|
21
|
-
let aliceAgent: AtpAgent
|
|
22
|
-
let bobAgent: AtpAgent
|
|
23
|
-
|
|
24
|
-
beforeAll(async () => {
|
|
25
|
-
network = await TestNetworkNoAppView.create({
|
|
26
|
-
dbPostgresSchema: 'crud',
|
|
27
|
-
})
|
|
28
|
-
// @ts-expect-error Error due to circular dependency with the dev-env package
|
|
29
|
-
ctx = network.pds.ctx
|
|
30
|
-
agent = network.pds.getAgent()
|
|
31
|
-
aliceAgent = network.pds.getAgent()
|
|
32
|
-
bobAgent = network.pds.getAgent()
|
|
33
|
-
|
|
34
|
-
await aliceAgent.createAccount({
|
|
35
|
-
email: 'alice@test.com',
|
|
36
|
-
handle: 'alice.test',
|
|
37
|
-
password: 'alice-pass',
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
await bobAgent.createAccount({
|
|
41
|
-
email: 'bob@test.com',
|
|
42
|
-
handle: 'bob.test',
|
|
43
|
-
password: 'bob-pass',
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
expect(bobAgent.assertDid).not.toBe(aliceAgent.assertDid)
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
afterAll(async () => {
|
|
50
|
-
await network?.close()
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('registers users', async () => {
|
|
54
|
-
const res = await agent.com.atproto.server.createAccount({
|
|
55
|
-
handle: 'user1.test',
|
|
56
|
-
email: 'user1@test.com',
|
|
57
|
-
password: 'password',
|
|
58
|
-
})
|
|
59
|
-
expect(res.data.handle).toBe('user1.test')
|
|
60
|
-
expect(res.data.accessJwt).toBeDefined()
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
it('describes repo', async () => {
|
|
64
|
-
const description = await agent.com.atproto.repo.describeRepo({
|
|
65
|
-
repo: aliceAgent.assertDid,
|
|
66
|
-
})
|
|
67
|
-
expect(description.data.handle).toBe('alice.test')
|
|
68
|
-
expect(description.data.did).toBe(aliceAgent.assertDid)
|
|
69
|
-
const description2 = await agent.com.atproto.repo.describeRepo({
|
|
70
|
-
repo: bobAgent.assertDid,
|
|
71
|
-
})
|
|
72
|
-
expect(description2.data.handle).toBe('bob.test')
|
|
73
|
-
expect(description2.data.did).toBe(bobAgent.assertDid)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('creates records', async () => {
|
|
77
|
-
const res = await aliceAgent.com.atproto.repo.createRecord({
|
|
78
|
-
repo: aliceAgent.assertDid,
|
|
79
|
-
collection: 'app.bsky.feed.post',
|
|
80
|
-
record: {
|
|
81
|
-
$type: 'app.bsky.feed.post',
|
|
82
|
-
text: 'Hello, world!',
|
|
83
|
-
createdAt: new Date().toISOString(),
|
|
84
|
-
},
|
|
85
|
-
})
|
|
86
|
-
const uri = new AtUri(res.data.uri)
|
|
87
|
-
expect(res.data.uri).toBe(
|
|
88
|
-
`at://${aliceAgent.assertDid}/app.bsky.feed.post/${uri.rkey}`,
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
const res1 = await agent.com.atproto.repo.listRecords({
|
|
92
|
-
repo: aliceAgent.assertDid,
|
|
93
|
-
collection: 'app.bsky.feed.post',
|
|
94
|
-
})
|
|
95
|
-
expect(res1.data.records.length).toBe(1)
|
|
96
|
-
expect(res1.data.records[0].uri).toBe(uri.toString())
|
|
97
|
-
const { value } = res1.data.records[0]
|
|
98
|
-
assert(AppBskyFeedPost.isMain(value))
|
|
99
|
-
expect(value.text).toBe('Hello, world!')
|
|
100
|
-
|
|
101
|
-
const res2 = await agent.app.bsky.feed.post.list({
|
|
102
|
-
repo: aliceAgent.assertDid,
|
|
103
|
-
})
|
|
104
|
-
expect(res2.records.length).toBe(1)
|
|
105
|
-
expect(res2.records[0].uri).toBe(uri.toString())
|
|
106
|
-
expect(res2.records[0].value.text).toBe('Hello, world!')
|
|
107
|
-
|
|
108
|
-
const res3 = await agent.com.atproto.repo.getRecord({
|
|
109
|
-
repo: aliceAgent.assertDid,
|
|
110
|
-
collection: 'app.bsky.feed.post',
|
|
111
|
-
rkey: uri.rkey,
|
|
112
|
-
})
|
|
113
|
-
expect(res3.data.uri).toBe(uri.toString())
|
|
114
|
-
assert(AppBskyFeedPost.isMain(res3.data.value))
|
|
115
|
-
expect(res3.data.value.text).toBe('Hello, world!')
|
|
116
|
-
|
|
117
|
-
const res4 = await agent.app.bsky.feed.post.get({
|
|
118
|
-
repo: aliceAgent.assertDid,
|
|
119
|
-
rkey: uri.rkey,
|
|
120
|
-
})
|
|
121
|
-
expect(res4.uri).toBe(uri.toString())
|
|
122
|
-
expect(res4.value.text).toBe('Hello, world!')
|
|
123
|
-
|
|
124
|
-
await aliceAgent.com.atproto.repo.deleteRecord({
|
|
125
|
-
repo: aliceAgent.assertDid,
|
|
126
|
-
collection: 'app.bsky.feed.post',
|
|
127
|
-
rkey: uri.rkey,
|
|
128
|
-
})
|
|
129
|
-
const res5 = await agent.com.atproto.repo.listRecords({
|
|
130
|
-
repo: aliceAgent.assertDid,
|
|
131
|
-
collection: 'app.bsky.feed.post',
|
|
132
|
-
})
|
|
133
|
-
expect(res5.data.records.length).toBe(0)
|
|
134
|
-
})
|
|
135
|
-
|
|
136
|
-
it('CRUDs records with the semantic sugars', async () => {
|
|
137
|
-
const res1 = await aliceAgent.app.bsky.feed.post.create(
|
|
138
|
-
{ repo: aliceAgent.assertDid },
|
|
139
|
-
{
|
|
140
|
-
$type: 'app.bsky.feed.post',
|
|
141
|
-
text: 'Hello, world!',
|
|
142
|
-
createdAt: new Date().toISOString(),
|
|
143
|
-
},
|
|
144
|
-
)
|
|
145
|
-
const uri = new AtUri(res1.uri)
|
|
146
|
-
|
|
147
|
-
const res2 = await agent.app.bsky.feed.post.list({
|
|
148
|
-
repo: aliceAgent.assertDid,
|
|
149
|
-
})
|
|
150
|
-
expect(res2.records.length).toBe(1)
|
|
151
|
-
|
|
152
|
-
await aliceAgent.app.bsky.feed.post.delete({
|
|
153
|
-
repo: aliceAgent.assertDid,
|
|
154
|
-
rkey: uri.rkey,
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
const res3 = await agent.app.bsky.feed.post.list({
|
|
158
|
-
repo: aliceAgent.assertDid,
|
|
159
|
-
})
|
|
160
|
-
expect(res3.records.length).toBe(0)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
it('attaches images to a post', async () => {
|
|
164
|
-
const file = await fs.readFile('../dev-env/assets/key-landscape-small.jpg')
|
|
165
|
-
const uploadedRes = await aliceAgent.com.atproto.repo.uploadBlob(file, {
|
|
166
|
-
encoding: 'image/jpeg',
|
|
167
|
-
})
|
|
168
|
-
const uploaded = uploadedRes.data.blob
|
|
169
|
-
// Expect blobstore not to have image yet
|
|
170
|
-
await expect(
|
|
171
|
-
ctx.blobstore(aliceAgent.assertDid).getBytes(uploaded.ref),
|
|
172
|
-
).rejects.toThrow(BlobNotFoundError)
|
|
173
|
-
// Associate image with post, image should be placed in blobstore
|
|
174
|
-
const res = await aliceAgent.app.bsky.feed.post.create(
|
|
175
|
-
{ repo: aliceAgent.assertDid },
|
|
176
|
-
{
|
|
177
|
-
$type: 'app.bsky.feed.post',
|
|
178
|
-
text: "Here's a key!",
|
|
179
|
-
createdAt: new Date().toISOString(),
|
|
180
|
-
embed: {
|
|
181
|
-
$type: 'app.bsky.embed.images',
|
|
182
|
-
images: [{ image: uploaded, alt: '' }],
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
)
|
|
186
|
-
// Ensure image is on post record
|
|
187
|
-
const postUri = new AtUri(res.uri)
|
|
188
|
-
const post = await aliceAgent.app.bsky.feed.post.get({
|
|
189
|
-
rkey: postUri.rkey,
|
|
190
|
-
repo: aliceAgent.assertDid,
|
|
191
|
-
})
|
|
192
|
-
assert(AppBskyEmbedImages.isMain(post.value.embed))
|
|
193
|
-
const images = post.value.embed.images
|
|
194
|
-
expect(images.length).toEqual(1)
|
|
195
|
-
expect(uploaded.ref.equals(images[0].image.ref)).toBeTruthy()
|
|
196
|
-
// Ensure that the uploaded image is now in the blobstore, i.e. doesn't throw BlobNotFoundError
|
|
197
|
-
await ctx.blobstore(aliceAgent.assertDid).getBytes(uploaded.ref)
|
|
198
|
-
// Cleanup
|
|
199
|
-
await aliceAgent.app.bsky.feed.post.delete({
|
|
200
|
-
rkey: postUri.rkey,
|
|
201
|
-
repo: aliceAgent.assertDid,
|
|
202
|
-
})
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('creates records with the correct key described by the schema', async () => {
|
|
206
|
-
const res1 = await aliceAgent.app.bsky.actor.profile.create(
|
|
207
|
-
{ repo: aliceAgent.assertDid },
|
|
208
|
-
{
|
|
209
|
-
displayName: 'alice',
|
|
210
|
-
createdAt: new Date().toISOString(),
|
|
211
|
-
},
|
|
212
|
-
)
|
|
213
|
-
const uri = new AtUri(res1.uri)
|
|
214
|
-
expect(uri.rkey).toBe('self')
|
|
215
|
-
})
|
|
216
|
-
|
|
217
|
-
describe('paginates', () => {
|
|
218
|
-
let uri1: AtUri
|
|
219
|
-
let uri2: AtUri
|
|
220
|
-
let uri3: AtUri
|
|
221
|
-
let uri4: AtUri
|
|
222
|
-
let uri5: AtUri
|
|
223
|
-
|
|
224
|
-
beforeAll(async () => {
|
|
225
|
-
const createPost = async (text: string) => {
|
|
226
|
-
const res = await aliceAgent.app.bsky.feed.post.create(
|
|
227
|
-
{ repo: aliceAgent.assertDid },
|
|
228
|
-
{
|
|
229
|
-
$type: 'app.bsky.feed.post',
|
|
230
|
-
text,
|
|
231
|
-
createdAt: new Date().toISOString(),
|
|
232
|
-
},
|
|
233
|
-
)
|
|
234
|
-
return new AtUri(res.uri)
|
|
235
|
-
}
|
|
236
|
-
uri1 = await createPost('Post 1')
|
|
237
|
-
uri2 = await createPost('Post 2')
|
|
238
|
-
uri3 = await createPost('Post 3')
|
|
239
|
-
uri4 = await createPost('Post 4')
|
|
240
|
-
uri5 = await createPost('Post 5')
|
|
241
|
-
})
|
|
242
|
-
|
|
243
|
-
afterAll(async () => {
|
|
244
|
-
for (const uri of [uri1, uri2, uri3, uri4, uri5]) {
|
|
245
|
-
await aliceAgent.app.bsky.feed.post.delete({
|
|
246
|
-
repo: aliceAgent.assertDid,
|
|
247
|
-
rkey: uri.rkey,
|
|
248
|
-
})
|
|
249
|
-
}
|
|
250
|
-
})
|
|
251
|
-
|
|
252
|
-
it('in forwards order', async () => {
|
|
253
|
-
const paginator = async (cursor?: string) => {
|
|
254
|
-
return agent.app.bsky.feed.post.list({
|
|
255
|
-
repo: aliceAgent.assertDid,
|
|
256
|
-
cursor,
|
|
257
|
-
limit: 2,
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const paginatedAll = await paginateAll(paginator)
|
|
262
|
-
paginatedAll.forEach((res) =>
|
|
263
|
-
expect(res.records.length).toBeLessThanOrEqual(2),
|
|
264
|
-
)
|
|
265
|
-
|
|
266
|
-
const full = await agent.app.bsky.feed.post.list({
|
|
267
|
-
repo: aliceAgent.assertDid,
|
|
268
|
-
})
|
|
269
|
-
|
|
270
|
-
expect(full.records.length).toEqual(5)
|
|
271
|
-
expect(paginatedAll.flatMap((res) => res.records)).toEqual(full.records)
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
it('in reverse order', async () => {
|
|
275
|
-
const results = (
|
|
276
|
-
results: Awaited<ReturnType<AppBskyFeedPostRecord['list']>>[],
|
|
277
|
-
) => results.flatMap((res) => res.records)
|
|
278
|
-
const paginator = async (cursor?: string) => {
|
|
279
|
-
const res = await agent.app.bsky.feed.post.list({
|
|
280
|
-
repo: aliceAgent.assertDid,
|
|
281
|
-
reverse: true,
|
|
282
|
-
cursor,
|
|
283
|
-
limit: 2,
|
|
284
|
-
})
|
|
285
|
-
return res
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const paginatedAll = await paginateAll(paginator)
|
|
289
|
-
paginatedAll.forEach((res) =>
|
|
290
|
-
expect(res.records.length).toBeLessThanOrEqual(2),
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
const full = await agent.app.bsky.feed.post.list({
|
|
294
|
-
repo: aliceAgent.assertDid,
|
|
295
|
-
reverse: true,
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
expect(full.records.length).toEqual(5)
|
|
299
|
-
expect(results(paginatedAll)).toEqual(results([full]))
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
it('reverses', async () => {
|
|
303
|
-
const forwards = await agent.app.bsky.feed.post.list({
|
|
304
|
-
repo: aliceAgent.assertDid,
|
|
305
|
-
})
|
|
306
|
-
const reverse = await agent.app.bsky.feed.post.list({
|
|
307
|
-
repo: aliceAgent.assertDid,
|
|
308
|
-
reverse: true,
|
|
309
|
-
})
|
|
310
|
-
expect(forwards.cursor).toEqual(uri1.rkey)
|
|
311
|
-
expect(reverse.cursor).toEqual(uri5.rkey)
|
|
312
|
-
expect(forwards.records.length).toEqual(5)
|
|
313
|
-
expect(reverse.records.length).toEqual(5)
|
|
314
|
-
expect(forwards.records.reverse()).toEqual(reverse.records)
|
|
315
|
-
})
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
describe('deleteRecord', () => {
|
|
319
|
-
it('deletes a record if it exists', async () => {
|
|
320
|
-
const { repo } = aliceAgent.com.atproto
|
|
321
|
-
const { data: post } = await repo.createRecord({
|
|
322
|
-
repo: aliceAgent.assertDid,
|
|
323
|
-
collection: 'app.bsky.feed.post',
|
|
324
|
-
record: { text: 'post', createdAt: new Date().toISOString() },
|
|
325
|
-
})
|
|
326
|
-
const uri = new AtUri(post.uri)
|
|
327
|
-
await repo.deleteRecord({
|
|
328
|
-
repo: uri.host,
|
|
329
|
-
collection: uri.collection,
|
|
330
|
-
rkey: uri.rkey,
|
|
331
|
-
})
|
|
332
|
-
const checkPost = repo.getRecord({
|
|
333
|
-
repo: uri.host,
|
|
334
|
-
collection: uri.collection,
|
|
335
|
-
rkey: uri.rkey,
|
|
336
|
-
})
|
|
337
|
-
await expect(checkPost).rejects.toThrow('Could not locate record')
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
it("no-ops if record doesn't exist", async () => {
|
|
341
|
-
const { repo } = aliceAgent.com.atproto
|
|
342
|
-
const { data: post } = await repo.createRecord({
|
|
343
|
-
repo: aliceAgent.assertDid,
|
|
344
|
-
collection: 'app.bsky.feed.post',
|
|
345
|
-
record: { text: 'post', createdAt: new Date().toISOString() },
|
|
346
|
-
})
|
|
347
|
-
const uri = new AtUri(post.uri)
|
|
348
|
-
await repo.deleteRecord({
|
|
349
|
-
repo: uri.host,
|
|
350
|
-
collection: uri.collection,
|
|
351
|
-
rkey: uri.rkey,
|
|
352
|
-
})
|
|
353
|
-
const checkPost = repo.getRecord({
|
|
354
|
-
repo: uri.host,
|
|
355
|
-
collection: uri.collection,
|
|
356
|
-
rkey: uri.rkey,
|
|
357
|
-
})
|
|
358
|
-
await expect(checkPost).rejects.toThrow('Could not locate record')
|
|
359
|
-
const attemptDelete = repo.deleteRecord({
|
|
360
|
-
repo: uri.host,
|
|
361
|
-
collection: uri.collection,
|
|
362
|
-
rkey: uri.rkey,
|
|
363
|
-
})
|
|
364
|
-
await expect(attemptDelete).resolves.toBeDefined()
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
it('does not delete the underlying block if it is referenced elsewhere', async () => {
|
|
368
|
-
const { repo } = aliceAgent.com.atproto
|
|
369
|
-
const record = { text: 'post', createdAt: new Date().toISOString() }
|
|
370
|
-
const { data: post1 } = await repo.createRecord({
|
|
371
|
-
repo: aliceAgent.assertDid,
|
|
372
|
-
collection: 'app.bsky.feed.post',
|
|
373
|
-
record,
|
|
374
|
-
})
|
|
375
|
-
const { data: post2 } = await repo.createRecord({
|
|
376
|
-
repo: aliceAgent.assertDid,
|
|
377
|
-
collection: 'app.bsky.feed.post',
|
|
378
|
-
record,
|
|
379
|
-
})
|
|
380
|
-
const uri1 = new AtUri(post1.uri)
|
|
381
|
-
await repo.deleteRecord({
|
|
382
|
-
repo: uri1.host,
|
|
383
|
-
collection: uri1.collection,
|
|
384
|
-
rkey: uri1.rkey,
|
|
385
|
-
})
|
|
386
|
-
const uri2 = new AtUri(post2.uri)
|
|
387
|
-
const checkPost2 = await repo.getRecord({
|
|
388
|
-
repo: uri2.host,
|
|
389
|
-
collection: uri2.collection,
|
|
390
|
-
rkey: uri2.rkey,
|
|
391
|
-
})
|
|
392
|
-
expect(checkPost2).toBeDefined()
|
|
393
|
-
expect(checkPost2.data.value).toMatchObject(record)
|
|
394
|
-
})
|
|
395
|
-
})
|
|
396
|
-
|
|
397
|
-
describe('putRecord', () => {
|
|
398
|
-
const profilePath = {
|
|
399
|
-
collection: 'app.bsky.actor.profile',
|
|
400
|
-
rkey: 'self',
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
it("creates a new record if it doesn't already exist", async () => {
|
|
404
|
-
const { repo } = bobAgent.com.atproto
|
|
405
|
-
const exists = repo.getRecord({
|
|
406
|
-
...profilePath,
|
|
407
|
-
repo: bobAgent.assertDid,
|
|
408
|
-
})
|
|
409
|
-
await expect(exists).rejects.toThrow('Could not locate record')
|
|
410
|
-
|
|
411
|
-
const { data: put } = await repo.putRecord({
|
|
412
|
-
...profilePath,
|
|
413
|
-
repo: bobAgent.assertDid,
|
|
414
|
-
record: {
|
|
415
|
-
displayName: 'Robert',
|
|
416
|
-
},
|
|
417
|
-
})
|
|
418
|
-
expect(put.uri).toEqual(
|
|
419
|
-
`at://${bobAgent.assertDid}/app.bsky.actor.profile/self`,
|
|
420
|
-
)
|
|
421
|
-
|
|
422
|
-
const { data: profile } = await repo.getRecord({
|
|
423
|
-
...profilePath,
|
|
424
|
-
repo: bobAgent.assertDid,
|
|
425
|
-
})
|
|
426
|
-
expect(profile.value).toEqual({
|
|
427
|
-
$type: 'app.bsky.actor.profile',
|
|
428
|
-
displayName: 'Robert',
|
|
429
|
-
})
|
|
430
|
-
})
|
|
431
|
-
|
|
432
|
-
it('updates a record if it already exists', async () => {
|
|
433
|
-
const { repo } = bobAgent.com.atproto
|
|
434
|
-
const { data: put } = await repo.putRecord({
|
|
435
|
-
...profilePath,
|
|
436
|
-
repo: bobAgent.assertDid,
|
|
437
|
-
record: {
|
|
438
|
-
displayName: 'Robert',
|
|
439
|
-
description: 'Dog lover',
|
|
440
|
-
},
|
|
441
|
-
})
|
|
442
|
-
expect(put.uri).toEqual(
|
|
443
|
-
`at://${bobAgent.assertDid}/app.bsky.actor.profile/self`,
|
|
444
|
-
)
|
|
445
|
-
|
|
446
|
-
const { data: profile } = await repo.getRecord({
|
|
447
|
-
...profilePath,
|
|
448
|
-
repo: bobAgent.assertDid,
|
|
449
|
-
})
|
|
450
|
-
expect(profile.value).toEqual({
|
|
451
|
-
$type: 'app.bsky.actor.profile',
|
|
452
|
-
displayName: 'Robert',
|
|
453
|
-
description: 'Dog lover',
|
|
454
|
-
})
|
|
455
|
-
})
|
|
456
|
-
|
|
457
|
-
it('still works if repo is specified by handle', async () => {
|
|
458
|
-
await bobAgent.com.atproto.repo.putRecord({
|
|
459
|
-
repo: 'bob.test',
|
|
460
|
-
collection: 'app.bsky.graph.follow',
|
|
461
|
-
rkey: TID.nextStr(),
|
|
462
|
-
record: {
|
|
463
|
-
subject: aliceAgent.assertDid,
|
|
464
|
-
createdAt: new Date().toISOString(),
|
|
465
|
-
},
|
|
466
|
-
})
|
|
467
|
-
})
|
|
468
|
-
|
|
469
|
-
it('does not produce commit on no-op update', async () => {
|
|
470
|
-
const { repo } = bobAgent.com.atproto
|
|
471
|
-
const rootRes1 = await bobAgent.com.atproto.sync.getLatestCommit({
|
|
472
|
-
did: bobAgent.assertDid,
|
|
473
|
-
})
|
|
474
|
-
const { data: put } = await repo.putRecord({
|
|
475
|
-
...profilePath,
|
|
476
|
-
repo: bobAgent.assertDid,
|
|
477
|
-
record: {
|
|
478
|
-
displayName: 'Robert',
|
|
479
|
-
description: 'Dog lover',
|
|
480
|
-
},
|
|
481
|
-
})
|
|
482
|
-
expect(put.uri).toEqual(
|
|
483
|
-
`at://${bobAgent.assertDid}/app.bsky.actor.profile/self`,
|
|
484
|
-
)
|
|
485
|
-
|
|
486
|
-
const rootRes2 = await bobAgent.com.atproto.sync.getLatestCommit({
|
|
487
|
-
did: bobAgent.assertDid,
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
expect(rootRes2.data.cid).toEqual(rootRes1.data.cid)
|
|
491
|
-
expect(rootRes2.data.rev).toEqual(rootRes1.data.rev)
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
it('fails on user mismatch', async () => {
|
|
495
|
-
const { repo } = aliceAgent.com.atproto
|
|
496
|
-
const put = repo.putRecord({
|
|
497
|
-
repo: bobAgent.assertDid,
|
|
498
|
-
collection: 'app.bsky.graph.follow',
|
|
499
|
-
rkey: TID.nextStr(),
|
|
500
|
-
record: {
|
|
501
|
-
subject: aliceAgent.assertDid,
|
|
502
|
-
createdAt: new Date().toISOString(),
|
|
503
|
-
},
|
|
504
|
-
})
|
|
505
|
-
await expect(put).rejects.toThrow('Authentication Required')
|
|
506
|
-
})
|
|
507
|
-
|
|
508
|
-
it('fails on invalid record', async () => {
|
|
509
|
-
const { repo } = bobAgent.com.atproto
|
|
510
|
-
const put = repo.putRecord({
|
|
511
|
-
...profilePath,
|
|
512
|
-
repo: bobAgent.assertDid,
|
|
513
|
-
record: {
|
|
514
|
-
displayName: 'Robert',
|
|
515
|
-
description: 3.141,
|
|
516
|
-
},
|
|
517
|
-
})
|
|
518
|
-
await expect(put).rejects.toMatchObject({
|
|
519
|
-
error: 'InvalidRequest',
|
|
520
|
-
message: expect.stringContaining('description'),
|
|
521
|
-
// Invalid app.bsky.actor.profile record: Record/description must be a string
|
|
522
|
-
// Expected one of null, boolean, integer, string, cid, bytes, array or object value type at $.record.description (got float)
|
|
523
|
-
})
|
|
524
|
-
const { data: profile } = await repo.getRecord({
|
|
525
|
-
...profilePath,
|
|
526
|
-
repo: bobAgent.assertDid,
|
|
527
|
-
})
|
|
528
|
-
expect(profile.value).toEqual({
|
|
529
|
-
$type: 'app.bsky.actor.profile',
|
|
530
|
-
displayName: 'Robert',
|
|
531
|
-
description: 'Dog lover',
|
|
532
|
-
})
|
|
533
|
-
})
|
|
534
|
-
|
|
535
|
-
// @TODO remove after migrating legacy blobs
|
|
536
|
-
it('updates a legacy blob ref when updating profile', async () => {
|
|
537
|
-
const { repo } = bobAgent.api.com.atproto
|
|
538
|
-
const file = await fs.readFile('../dev-env/assets/key-portrait-small.jpg')
|
|
539
|
-
const uploadedRes = await repo.uploadBlob(file, {
|
|
540
|
-
encoding: 'image/jpeg',
|
|
541
|
-
})
|
|
542
|
-
|
|
543
|
-
await repo.putRecord({
|
|
544
|
-
...profilePath,
|
|
545
|
-
repo: bobAgent.accountDid,
|
|
546
|
-
record: {
|
|
547
|
-
displayName: 'Robert',
|
|
548
|
-
avatar: BlobRef.fromJsonRef({
|
|
549
|
-
mimeType: uploadedRes.data.blob.mimeType,
|
|
550
|
-
cid: uploadedRes.data.blob.ref.toString(),
|
|
551
|
-
}),
|
|
552
|
-
},
|
|
553
|
-
})
|
|
554
|
-
|
|
555
|
-
const got = await repo.getRecord({
|
|
556
|
-
...profilePath,
|
|
557
|
-
repo: bobAgent.accountDid,
|
|
558
|
-
})
|
|
559
|
-
const gotAvatar = got.data.value['avatar'] as BlobRef
|
|
560
|
-
expect(gotAvatar.original).toEqual(uploadedRes.data.blob.original)
|
|
561
|
-
})
|
|
562
|
-
})
|
|
563
|
-
|
|
564
|
-
// Validation
|
|
565
|
-
// --------------
|
|
566
|
-
|
|
567
|
-
it('defaults an undefined $type on records', async () => {
|
|
568
|
-
const res = await aliceAgent.com.atproto.repo.createRecord({
|
|
569
|
-
repo: aliceAgent.assertDid,
|
|
570
|
-
collection: 'app.bsky.feed.post',
|
|
571
|
-
record: {
|
|
572
|
-
text: 'blah',
|
|
573
|
-
createdAt: new Date().toISOString(),
|
|
574
|
-
},
|
|
575
|
-
})
|
|
576
|
-
const uri = new AtUri(res.data.uri)
|
|
577
|
-
const got = await agent.com.atproto.repo.getRecord({
|
|
578
|
-
repo: aliceAgent.assertDid,
|
|
579
|
-
collection: uri.collection,
|
|
580
|
-
rkey: uri.rkey,
|
|
581
|
-
})
|
|
582
|
-
expect(got.data.value['$type']).toBe(uri.collection)
|
|
583
|
-
})
|
|
584
|
-
|
|
585
|
-
it('requires the schema to be known if explicitly validating', async () => {
|
|
586
|
-
const prom = aliceAgent.com.atproto.repo.createRecord({
|
|
587
|
-
validate: true,
|
|
588
|
-
repo: aliceAgent.assertDid,
|
|
589
|
-
collection: 'com.example.foobar',
|
|
590
|
-
record: { $type: 'com.example.foobar' },
|
|
591
|
-
})
|
|
592
|
-
await expect(prom).rejects.toMatchObject({
|
|
593
|
-
message: expect.stringContaining('com.example.foobar'),
|
|
594
|
-
// Lexicon not found: lex:com.example.foobar
|
|
595
|
-
// Unknown lexicon type: com.example.foobar
|
|
596
|
-
})
|
|
597
|
-
})
|
|
598
|
-
|
|
599
|
-
it('does not require the schema to be known if not explicitly validating', async () => {
|
|
600
|
-
const prom = await aliceAgent.com.atproto.repo.createRecord({
|
|
601
|
-
// validate not set
|
|
602
|
-
repo: aliceAgent.assertDid,
|
|
603
|
-
collection: 'com.example.foobar',
|
|
604
|
-
record: { $type: 'com.example.foobar' },
|
|
605
|
-
})
|
|
606
|
-
expect(prom.data.validationStatus).toBe('unknown')
|
|
607
|
-
})
|
|
608
|
-
|
|
609
|
-
it('requires the $type to match the schema', async () => {
|
|
610
|
-
await expect(
|
|
611
|
-
aliceAgent.com.atproto.repo.createRecord({
|
|
612
|
-
repo: aliceAgent.assertDid,
|
|
613
|
-
collection: 'app.bsky.feed.post',
|
|
614
|
-
record: { $type: 'app.bsky.feed.like' },
|
|
615
|
-
}),
|
|
616
|
-
).rejects.toThrow(
|
|
617
|
-
'Invalid $type: expected app.bsky.feed.post, got app.bsky.feed.like',
|
|
618
|
-
)
|
|
619
|
-
})
|
|
620
|
-
|
|
621
|
-
it('requires valid rkey', async () => {
|
|
622
|
-
await expect(
|
|
623
|
-
aliceAgent.com.atproto.repo.createRecord({
|
|
624
|
-
repo: aliceAgent.assertDid,
|
|
625
|
-
collection: 'app.bsky.feed.generator',
|
|
626
|
-
record: {
|
|
627
|
-
$type: 'app.bsky.feed.generator',
|
|
628
|
-
did: 'did:web:dummy.example.com',
|
|
629
|
-
displayName: 'dummy',
|
|
630
|
-
createdAt: new Date().toISOString(),
|
|
631
|
-
},
|
|
632
|
-
rkey: '..',
|
|
633
|
-
}),
|
|
634
|
-
).rejects.toMatchObject({
|
|
635
|
-
error: 'InvalidRequest',
|
|
636
|
-
message: expect.stringContaining('rkey'),
|
|
637
|
-
// Input/rkey must be a valid Record Key
|
|
638
|
-
// Invalid record key at $.rkey (got \"..\")
|
|
639
|
-
})
|
|
640
|
-
})
|
|
641
|
-
|
|
642
|
-
it('validates the record on write', async () => {
|
|
643
|
-
await expect(
|
|
644
|
-
aliceAgent.com.atproto.repo.createRecord({
|
|
645
|
-
repo: aliceAgent.assertDid,
|
|
646
|
-
collection: 'app.bsky.feed.post',
|
|
647
|
-
record: { $type: 'app.bsky.feed.post' },
|
|
648
|
-
}),
|
|
649
|
-
).rejects.toMatchObject({
|
|
650
|
-
error: 'InvalidRequest',
|
|
651
|
-
message: expect.stringContaining('Invalid app.bsky.feed.post record'),
|
|
652
|
-
// Invalid app.bsky.feed.post record: Record must have the property "text"
|
|
653
|
-
// Invalid app.bsky.feed.post record: Missing required key \"text\" at $.record
|
|
654
|
-
})
|
|
655
|
-
})
|
|
656
|
-
|
|
657
|
-
it('validates datetimes rigorously', async () => {
|
|
658
|
-
const postRecord = {
|
|
659
|
-
$type: 'app.bsky.feed.post',
|
|
660
|
-
text: 'test',
|
|
661
|
-
createdAt: '0000-00-12T23:20:50.123Z',
|
|
662
|
-
}
|
|
663
|
-
await expect(
|
|
664
|
-
aliceAgent.com.atproto.repo.createRecord({
|
|
665
|
-
repo: aliceAgent.assertDid,
|
|
666
|
-
collection: 'app.bsky.feed.post',
|
|
667
|
-
record: postRecord,
|
|
668
|
-
}),
|
|
669
|
-
).rejects.toMatchObject({
|
|
670
|
-
error: 'InvalidRequest',
|
|
671
|
-
message: expect.stringContaining('Invalid app.bsky.feed.post record'),
|
|
672
|
-
// Invalid app.bsky.feed.post record: createdAt must be an valid atproto datetime (both RFC-3339 and ISO-8601)
|
|
673
|
-
})
|
|
674
|
-
})
|
|
675
|
-
|
|
676
|
-
describe('unvalidated writes', () => {
|
|
677
|
-
it('disallows creation of unknown lexicons when validate is set to true', async () => {
|
|
678
|
-
const attempt = aliceAgent.com.atproto.repo.createRecord({
|
|
679
|
-
validate: true,
|
|
680
|
-
repo: aliceAgent.assertDid,
|
|
681
|
-
collection: 'com.example.record',
|
|
682
|
-
record: {
|
|
683
|
-
blah: 'thing',
|
|
684
|
-
},
|
|
685
|
-
})
|
|
686
|
-
await expect(attempt).rejects.toMatchObject({
|
|
687
|
-
error: 'InvalidRequest',
|
|
688
|
-
message: expect.stringContaining('com.example.record'),
|
|
689
|
-
// Lexicon not found: lex:com.example.record
|
|
690
|
-
// Unknown lexicon type: com.example.record
|
|
691
|
-
})
|
|
692
|
-
})
|
|
693
|
-
|
|
694
|
-
it('allows creation of unknown lexicons when validate is not set to true', async () => {
|
|
695
|
-
// validate: default
|
|
696
|
-
const res1 = await aliceAgent.com.atproto.repo.createRecord({
|
|
697
|
-
repo: aliceAgent.assertDid,
|
|
698
|
-
collection: 'com.example.record',
|
|
699
|
-
record: {
|
|
700
|
-
blah: 'thing1',
|
|
701
|
-
},
|
|
702
|
-
})
|
|
703
|
-
expect(res1.data.validationStatus).toBe('unknown')
|
|
704
|
-
const record1 = await ctx.actorStore.read(aliceAgent.assertDid, (store) =>
|
|
705
|
-
store.record.getRecord(new AtUri(res1.data.uri), res1.data.cid),
|
|
706
|
-
)
|
|
707
|
-
expect(record1?.value).toEqual({
|
|
708
|
-
$type: 'com.example.record',
|
|
709
|
-
blah: 'thing1',
|
|
710
|
-
})
|
|
711
|
-
// validate: false
|
|
712
|
-
const res2 = await aliceAgent.com.atproto.repo.createRecord({
|
|
713
|
-
validate: false,
|
|
714
|
-
repo: aliceAgent.assertDid,
|
|
715
|
-
collection: 'com.example.record',
|
|
716
|
-
record: {
|
|
717
|
-
blah: 'thing2',
|
|
718
|
-
},
|
|
719
|
-
})
|
|
720
|
-
expect(res2.data.validationStatus).toBeUndefined()
|
|
721
|
-
const record2 = await ctx.actorStore.read(aliceAgent.assertDid, (store) =>
|
|
722
|
-
store.record.getRecord(new AtUri(res2.data.uri), res2.data.cid),
|
|
723
|
-
)
|
|
724
|
-
expect(record2?.value).toEqual({
|
|
725
|
-
$type: 'com.example.record',
|
|
726
|
-
blah: 'thing2',
|
|
727
|
-
})
|
|
728
|
-
})
|
|
729
|
-
|
|
730
|
-
it('allows update of unknown lexicons when validate is set to false', async () => {
|
|
731
|
-
const createRes = await aliceAgent.com.atproto.repo.createRecord({
|
|
732
|
-
validate: false,
|
|
733
|
-
repo: aliceAgent.assertDid,
|
|
734
|
-
collection: 'com.example.record',
|
|
735
|
-
record: {
|
|
736
|
-
blah: 'thing',
|
|
737
|
-
},
|
|
738
|
-
})
|
|
739
|
-
const uri = new AtUri(createRes.data.uri)
|
|
740
|
-
// validate: default
|
|
741
|
-
const updateRes1 = await aliceAgent.com.atproto.repo.putRecord({
|
|
742
|
-
repo: aliceAgent.assertDid,
|
|
743
|
-
collection: 'com.example.record',
|
|
744
|
-
rkey: uri.rkey,
|
|
745
|
-
record: {
|
|
746
|
-
blah: 'something else',
|
|
747
|
-
},
|
|
748
|
-
})
|
|
749
|
-
const record1 = await ctx.actorStore.read(aliceAgent.assertDid, (store) =>
|
|
750
|
-
store.record.getRecord(uri, updateRes1.data.cid),
|
|
751
|
-
)
|
|
752
|
-
expect(record1?.value).toEqual({
|
|
753
|
-
$type: 'com.example.record',
|
|
754
|
-
blah: 'something else',
|
|
755
|
-
})
|
|
756
|
-
// validate: false
|
|
757
|
-
const updateRes2 = await aliceAgent.com.atproto.repo.putRecord({
|
|
758
|
-
validate: false,
|
|
759
|
-
repo: aliceAgent.assertDid,
|
|
760
|
-
collection: 'com.example.record',
|
|
761
|
-
rkey: uri.rkey,
|
|
762
|
-
record: {
|
|
763
|
-
blah: 'something else',
|
|
764
|
-
},
|
|
765
|
-
})
|
|
766
|
-
const record2 = await ctx.actorStore.read(aliceAgent.assertDid, (store) =>
|
|
767
|
-
store.record.getRecord(uri, updateRes2.data.cid),
|
|
768
|
-
)
|
|
769
|
-
expect(record2?.value).toEqual({
|
|
770
|
-
$type: 'com.example.record',
|
|
771
|
-
blah: 'something else',
|
|
772
|
-
})
|
|
773
|
-
})
|
|
774
|
-
|
|
775
|
-
it('applyWrites returns results with validation status', async () => {
|
|
776
|
-
const existing1 = await aliceAgent.com.atproto.repo.createRecord({
|
|
777
|
-
validate: false,
|
|
778
|
-
repo: aliceAgent.assertDid,
|
|
779
|
-
collection: 'com.example.record',
|
|
780
|
-
record: {
|
|
781
|
-
blah: 'thing1',
|
|
782
|
-
},
|
|
783
|
-
})
|
|
784
|
-
const existing1Uri = new AtUri(existing1.data.uri)
|
|
785
|
-
const existing2 = await aliceAgent.com.atproto.repo.createRecord({
|
|
786
|
-
validate: false,
|
|
787
|
-
repo: aliceAgent.assertDid,
|
|
788
|
-
collection: 'com.example.record',
|
|
789
|
-
record: {
|
|
790
|
-
blah: 'thing2',
|
|
791
|
-
},
|
|
792
|
-
})
|
|
793
|
-
const existing2Uri = new AtUri(existing2.data.uri)
|
|
794
|
-
const {
|
|
795
|
-
data: { results },
|
|
796
|
-
} = await aliceAgent.com.atproto.repo.applyWrites({
|
|
797
|
-
repo: aliceAgent.assertDid,
|
|
798
|
-
writes: [
|
|
799
|
-
{
|
|
800
|
-
$type: 'com.atproto.repo.applyWrites#create',
|
|
801
|
-
collection: 'app.bsky.feed.post',
|
|
802
|
-
value: {
|
|
803
|
-
$type: 'app.bsky.feed.post',
|
|
804
|
-
text: '👋',
|
|
805
|
-
createdAt: new Date().toISOString(),
|
|
806
|
-
},
|
|
807
|
-
},
|
|
808
|
-
{
|
|
809
|
-
$type: 'com.atproto.repo.applyWrites#update',
|
|
810
|
-
collection: existing1Uri.collectionSafe,
|
|
811
|
-
rkey: existing1Uri.rkey,
|
|
812
|
-
value: {},
|
|
813
|
-
},
|
|
814
|
-
{
|
|
815
|
-
$type: `com.atproto.repo.applyWrites#delete`,
|
|
816
|
-
collection: existing2Uri.collectionSafe,
|
|
817
|
-
rkey: existing2Uri.rkey,
|
|
818
|
-
},
|
|
819
|
-
],
|
|
820
|
-
})
|
|
821
|
-
expect(forSnapshot(results)).toEqual([
|
|
822
|
-
{
|
|
823
|
-
$type: `com.atproto.repo.applyWrites#createResult`,
|
|
824
|
-
cid: 'cids(0)',
|
|
825
|
-
uri: 'record(0)',
|
|
826
|
-
validationStatus: 'valid',
|
|
827
|
-
},
|
|
828
|
-
{
|
|
829
|
-
$type: `com.atproto.repo.applyWrites#updateResult`,
|
|
830
|
-
cid: 'cids(1)',
|
|
831
|
-
uri: 'record(1)',
|
|
832
|
-
validationStatus: 'unknown',
|
|
833
|
-
},
|
|
834
|
-
{ $type: `com.atproto.repo.applyWrites#deleteResult` },
|
|
835
|
-
])
|
|
836
|
-
})
|
|
837
|
-
|
|
838
|
-
it('correctly associates images with unknown record types', async () => {
|
|
839
|
-
const file = await fs.readFile('../dev-env/assets/key-portrait-small.jpg')
|
|
840
|
-
const uploadedRes = await aliceAgent.com.atproto.repo.uploadBlob(file, {
|
|
841
|
-
encoding: 'image/jpeg',
|
|
842
|
-
})
|
|
843
|
-
|
|
844
|
-
const res = await aliceAgent.com.atproto.repo.createRecord({
|
|
845
|
-
repo: aliceAgent.assertDid,
|
|
846
|
-
collection: 'com.example.record',
|
|
847
|
-
record: {
|
|
848
|
-
blah: 'thing',
|
|
849
|
-
image: uploadedRes.data.blob,
|
|
850
|
-
},
|
|
851
|
-
validate: false,
|
|
852
|
-
})
|
|
853
|
-
const record = await ctx.actorStore.read(aliceAgent.assertDid, (store) =>
|
|
854
|
-
store.record.getRecord(new AtUri(res.data.uri), res.data.cid),
|
|
855
|
-
)
|
|
856
|
-
assert(record)
|
|
857
|
-
expect(record.value).toMatchObject({
|
|
858
|
-
$type: 'com.example.record',
|
|
859
|
-
blah: 'thing',
|
|
860
|
-
})
|
|
861
|
-
const recordBlobs = await ctx.actorStore.read(
|
|
862
|
-
aliceAgent.assertDid,
|
|
863
|
-
(store) => store.repo.blob.getBlobsForRecord(record.uri),
|
|
864
|
-
)
|
|
865
|
-
expect(recordBlobs.length).toBe(1)
|
|
866
|
-
expect(recordBlobs.at(0)).toBe(uploadedRes.data.blob.ref.toString())
|
|
867
|
-
})
|
|
868
|
-
|
|
869
|
-
it('enforces record type constraint even when unvalidated', async () => {
|
|
870
|
-
const attempt = aliceAgent.com.atproto.repo.createRecord({
|
|
871
|
-
repo: aliceAgent.assertDid,
|
|
872
|
-
collection: 'com.example.record',
|
|
873
|
-
record: {
|
|
874
|
-
$type: 'com.example.other',
|
|
875
|
-
blah: 'thing',
|
|
876
|
-
},
|
|
877
|
-
})
|
|
878
|
-
await expect(attempt).rejects.toThrow(
|
|
879
|
-
'Invalid $type: expected com.example.record, got com.example.other',
|
|
880
|
-
)
|
|
881
|
-
})
|
|
882
|
-
|
|
883
|
-
it('enforces blob ref format even when unvalidated', async () => {
|
|
884
|
-
const file = await fs.readFile('../dev-env/assets/key-portrait-small.jpg')
|
|
885
|
-
const uploadedRes = await aliceAgent.com.atproto.repo.uploadBlob(file, {
|
|
886
|
-
encoding: 'image/jpeg',
|
|
887
|
-
})
|
|
888
|
-
|
|
889
|
-
await expect(
|
|
890
|
-
aliceAgent.com.atproto.repo.createRecord({
|
|
891
|
-
repo: aliceAgent.assertDid,
|
|
892
|
-
collection: 'com.example.record',
|
|
893
|
-
record: {
|
|
894
|
-
blah: 'thing',
|
|
895
|
-
image: {
|
|
896
|
-
cid: uploadedRes.data.blob.ref.toString(),
|
|
897
|
-
mimeType: uploadedRes.data.blob.mimeType,
|
|
898
|
-
},
|
|
899
|
-
},
|
|
900
|
-
validate: false,
|
|
901
|
-
}),
|
|
902
|
-
).rejects.toMatchObject({
|
|
903
|
-
error: 'InvalidRequest',
|
|
904
|
-
message: expect.stringContaining('Legacy blobs are not allowed'),
|
|
905
|
-
})
|
|
906
|
-
})
|
|
907
|
-
})
|
|
908
|
-
|
|
909
|
-
describe('compare-and-swap', () => {
|
|
910
|
-
let recordCount = 0 // Ensures unique cids
|
|
911
|
-
const postRecord = () => ({
|
|
912
|
-
text: `post (${++recordCount})`,
|
|
913
|
-
createdAt: new Date().toISOString(),
|
|
914
|
-
})
|
|
915
|
-
const profileRecord = () => ({
|
|
916
|
-
displayName: `ali (${++recordCount})`,
|
|
917
|
-
})
|
|
918
|
-
|
|
919
|
-
it('createRecord succeeds on proper commit cas', async () => {
|
|
920
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
921
|
-
const { data: commit } = await sync.getLatestCommit({
|
|
922
|
-
did: aliceAgent.assertDid,
|
|
923
|
-
})
|
|
924
|
-
const { data: post } = await repo.createRecord({
|
|
925
|
-
repo: aliceAgent.assertDid,
|
|
926
|
-
collection: 'app.bsky.feed.post',
|
|
927
|
-
swapCommit: commit.cid,
|
|
928
|
-
record: postRecord(),
|
|
929
|
-
})
|
|
930
|
-
const uri = new AtUri(post.uri)
|
|
931
|
-
const checkPost = repo.getRecord({
|
|
932
|
-
repo: uri.host,
|
|
933
|
-
collection: uri.collection,
|
|
934
|
-
rkey: uri.rkey,
|
|
935
|
-
})
|
|
936
|
-
await expect(checkPost).resolves.toBeDefined()
|
|
937
|
-
})
|
|
938
|
-
|
|
939
|
-
it('createRecord fails on bad commit cas', async () => {
|
|
940
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
941
|
-
const { data: staleCommit } = await sync.getLatestCommit({
|
|
942
|
-
did: aliceAgent.assertDid,
|
|
943
|
-
})
|
|
944
|
-
// Update repo, change head
|
|
945
|
-
await repo.createRecord({
|
|
946
|
-
repo: aliceAgent.assertDid,
|
|
947
|
-
collection: 'app.bsky.feed.post',
|
|
948
|
-
record: postRecord(),
|
|
949
|
-
})
|
|
950
|
-
const attemptCreate = repo.createRecord({
|
|
951
|
-
repo: aliceAgent.assertDid,
|
|
952
|
-
collection: 'app.bsky.feed.post',
|
|
953
|
-
swapCommit: staleCommit.cid,
|
|
954
|
-
record: postRecord(),
|
|
955
|
-
})
|
|
956
|
-
await expect(attemptCreate).rejects.toMatchObject({
|
|
957
|
-
error: 'InvalidSwap',
|
|
958
|
-
})
|
|
959
|
-
})
|
|
960
|
-
|
|
961
|
-
it('deleteRecord succeeds on proper commit cas', async () => {
|
|
962
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
963
|
-
const { data: post } = await repo.createRecord({
|
|
964
|
-
repo: aliceAgent.assertDid,
|
|
965
|
-
collection: 'app.bsky.feed.post',
|
|
966
|
-
record: postRecord(),
|
|
967
|
-
})
|
|
968
|
-
const { data: commit } = await sync.getLatestCommit({
|
|
969
|
-
did: aliceAgent.assertDid,
|
|
970
|
-
})
|
|
971
|
-
const uri = new AtUri(post.uri)
|
|
972
|
-
await repo.deleteRecord({
|
|
973
|
-
repo: uri.host,
|
|
974
|
-
collection: uri.collection,
|
|
975
|
-
rkey: uri.rkey,
|
|
976
|
-
swapCommit: commit.cid,
|
|
977
|
-
})
|
|
978
|
-
const checkPost = repo.getRecord({
|
|
979
|
-
repo: uri.host,
|
|
980
|
-
collection: uri.collection,
|
|
981
|
-
rkey: uri.rkey,
|
|
982
|
-
})
|
|
983
|
-
await expect(checkPost).rejects.toThrow('Could not locate record')
|
|
984
|
-
})
|
|
985
|
-
|
|
986
|
-
it('deleteRecord fails on bad commit cas', async () => {
|
|
987
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
988
|
-
const { data: staleCommit } = await sync.getLatestCommit({
|
|
989
|
-
did: aliceAgent.assertDid,
|
|
990
|
-
})
|
|
991
|
-
const { data: post } = await repo.createRecord({
|
|
992
|
-
repo: aliceAgent.assertDid,
|
|
993
|
-
collection: 'app.bsky.feed.post',
|
|
994
|
-
record: postRecord(),
|
|
995
|
-
})
|
|
996
|
-
const uri = new AtUri(post.uri)
|
|
997
|
-
const attemptDelete = repo.deleteRecord({
|
|
998
|
-
repo: uri.host,
|
|
999
|
-
collection: uri.collection,
|
|
1000
|
-
rkey: uri.rkey,
|
|
1001
|
-
swapCommit: staleCommit.cid,
|
|
1002
|
-
})
|
|
1003
|
-
await expect(attemptDelete).rejects.toMatchObject({
|
|
1004
|
-
error: 'InvalidSwap',
|
|
1005
|
-
})
|
|
1006
|
-
const checkPost = repo.getRecord({
|
|
1007
|
-
repo: uri.host,
|
|
1008
|
-
collection: uri.collection,
|
|
1009
|
-
rkey: uri.rkey,
|
|
1010
|
-
})
|
|
1011
|
-
await expect(checkPost).resolves.toBeDefined()
|
|
1012
|
-
})
|
|
1013
|
-
|
|
1014
|
-
it('deleteRecord succeeds on proper record cas', async () => {
|
|
1015
|
-
const { repo } = aliceAgent.com.atproto
|
|
1016
|
-
const { data: post } = await repo.createRecord({
|
|
1017
|
-
repo: aliceAgent.assertDid,
|
|
1018
|
-
collection: 'app.bsky.feed.post',
|
|
1019
|
-
record: postRecord(),
|
|
1020
|
-
})
|
|
1021
|
-
const uri = new AtUri(post.uri)
|
|
1022
|
-
await repo.deleteRecord({
|
|
1023
|
-
repo: uri.host,
|
|
1024
|
-
collection: uri.collection,
|
|
1025
|
-
rkey: uri.rkey,
|
|
1026
|
-
swapRecord: post.cid,
|
|
1027
|
-
})
|
|
1028
|
-
const checkPost = repo.getRecord({
|
|
1029
|
-
repo: uri.host,
|
|
1030
|
-
collection: uri.collection,
|
|
1031
|
-
rkey: uri.rkey,
|
|
1032
|
-
})
|
|
1033
|
-
await expect(checkPost).rejects.toThrow('Could not locate record')
|
|
1034
|
-
})
|
|
1035
|
-
|
|
1036
|
-
it('deleteRecord fails on bad record cas', async () => {
|
|
1037
|
-
const { repo } = aliceAgent.com.atproto
|
|
1038
|
-
const { data: post } = await repo.createRecord({
|
|
1039
|
-
repo: aliceAgent.assertDid,
|
|
1040
|
-
collection: 'app.bsky.feed.post',
|
|
1041
|
-
record: postRecord(),
|
|
1042
|
-
})
|
|
1043
|
-
const uri = new AtUri(post.uri)
|
|
1044
|
-
const attemptDelete = repo.deleteRecord({
|
|
1045
|
-
repo: uri.host,
|
|
1046
|
-
collection: uri.collection,
|
|
1047
|
-
rkey: uri.rkey,
|
|
1048
|
-
swapRecord: (await cidForCbor({})).toString(),
|
|
1049
|
-
})
|
|
1050
|
-
await expect(attemptDelete).rejects.toMatchObject({
|
|
1051
|
-
error: 'InvalidSwap',
|
|
1052
|
-
})
|
|
1053
|
-
const checkPost = repo.getRecord({
|
|
1054
|
-
repo: uri.host,
|
|
1055
|
-
collection: uri.collection,
|
|
1056
|
-
rkey: uri.rkey,
|
|
1057
|
-
})
|
|
1058
|
-
await expect(checkPost).resolves.toBeDefined()
|
|
1059
|
-
})
|
|
1060
|
-
|
|
1061
|
-
it('putRecord succeeds on proper commit cas', async () => {
|
|
1062
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
1063
|
-
const { data: commit } = await sync.getLatestCommit({
|
|
1064
|
-
did: aliceAgent.assertDid,
|
|
1065
|
-
})
|
|
1066
|
-
const { data: profile } = await repo.putRecord({
|
|
1067
|
-
repo: aliceAgent.assertDid,
|
|
1068
|
-
collection: 'app.bsky.actor.profile',
|
|
1069
|
-
rkey: 'self',
|
|
1070
|
-
swapCommit: commit.cid,
|
|
1071
|
-
record: profileRecord(),
|
|
1072
|
-
})
|
|
1073
|
-
const { data: checkProfile } = await repo.getRecord({
|
|
1074
|
-
repo: aliceAgent.assertDid,
|
|
1075
|
-
collection: 'app.bsky.actor.profile',
|
|
1076
|
-
rkey: 'self',
|
|
1077
|
-
})
|
|
1078
|
-
expect(checkProfile.cid).toEqual(profile.cid)
|
|
1079
|
-
})
|
|
1080
|
-
|
|
1081
|
-
it('putRecord fails on bad commit cas', async () => {
|
|
1082
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
1083
|
-
const { data: staleCommit } = await sync.getLatestCommit({
|
|
1084
|
-
did: aliceAgent.assertDid,
|
|
1085
|
-
})
|
|
1086
|
-
// Update repo, change head
|
|
1087
|
-
await repo.createRecord({
|
|
1088
|
-
repo: aliceAgent.assertDid,
|
|
1089
|
-
collection: 'app.bsky.feed.post',
|
|
1090
|
-
record: postRecord(),
|
|
1091
|
-
})
|
|
1092
|
-
const attemptPut = repo.putRecord({
|
|
1093
|
-
repo: aliceAgent.assertDid,
|
|
1094
|
-
collection: 'app.bsky.actor.profile',
|
|
1095
|
-
rkey: 'self',
|
|
1096
|
-
swapCommit: staleCommit.cid,
|
|
1097
|
-
record: profileRecord(),
|
|
1098
|
-
})
|
|
1099
|
-
await expect(attemptPut).rejects.toMatchObject({ error: 'InvalidSwap' })
|
|
1100
|
-
})
|
|
1101
|
-
|
|
1102
|
-
it('putRecord succeeds on proper record cas', async () => {
|
|
1103
|
-
const { repo } = aliceAgent.com.atproto
|
|
1104
|
-
// Start with missing profile record, to test swapRecord=null
|
|
1105
|
-
await repo.deleteRecord({
|
|
1106
|
-
repo: aliceAgent.assertDid,
|
|
1107
|
-
collection: 'app.bsky.actor.profile',
|
|
1108
|
-
rkey: 'self',
|
|
1109
|
-
})
|
|
1110
|
-
// Test swapRecord w/ null (ensures create)
|
|
1111
|
-
const { data: profile1 } = await repo.putRecord({
|
|
1112
|
-
repo: aliceAgent.assertDid,
|
|
1113
|
-
collection: 'app.bsky.actor.profile',
|
|
1114
|
-
rkey: 'self',
|
|
1115
|
-
swapRecord: null,
|
|
1116
|
-
record: profileRecord(),
|
|
1117
|
-
})
|
|
1118
|
-
const { data: checkProfile1 } = await repo.getRecord({
|
|
1119
|
-
repo: aliceAgent.assertDid,
|
|
1120
|
-
collection: 'app.bsky.actor.profile',
|
|
1121
|
-
rkey: 'self',
|
|
1122
|
-
})
|
|
1123
|
-
expect(checkProfile1.cid).toEqual(profile1.cid)
|
|
1124
|
-
// Test swapRecord w/ cid (ensures update)
|
|
1125
|
-
const { data: profile2 } = await repo.putRecord({
|
|
1126
|
-
repo: aliceAgent.assertDid,
|
|
1127
|
-
collection: 'app.bsky.actor.profile',
|
|
1128
|
-
rkey: 'self',
|
|
1129
|
-
swapRecord: profile1.cid,
|
|
1130
|
-
record: profileRecord(),
|
|
1131
|
-
})
|
|
1132
|
-
const { data: checkProfile2 } = await repo.getRecord({
|
|
1133
|
-
repo: aliceAgent.assertDid,
|
|
1134
|
-
collection: 'app.bsky.actor.profile',
|
|
1135
|
-
rkey: 'self',
|
|
1136
|
-
})
|
|
1137
|
-
expect(checkProfile2.cid).toEqual(profile2.cid)
|
|
1138
|
-
})
|
|
1139
|
-
|
|
1140
|
-
it('putRecord fails on bad record cas', async () => {
|
|
1141
|
-
const { repo } = aliceAgent.com.atproto
|
|
1142
|
-
// Test swapRecord w/ null (ensures create)
|
|
1143
|
-
const attemptPut1 = repo.putRecord({
|
|
1144
|
-
repo: aliceAgent.assertDid,
|
|
1145
|
-
collection: 'app.bsky.actor.profile',
|
|
1146
|
-
rkey: 'self',
|
|
1147
|
-
swapRecord: null,
|
|
1148
|
-
record: profileRecord(),
|
|
1149
|
-
})
|
|
1150
|
-
await expect(attemptPut1).rejects.toMatchObject({ error: 'InvalidSwap' })
|
|
1151
|
-
// Test swapRecord w/ cid (ensures update)
|
|
1152
|
-
const attemptPut2 = repo.putRecord({
|
|
1153
|
-
repo: aliceAgent.assertDid,
|
|
1154
|
-
collection: 'app.bsky.actor.profile',
|
|
1155
|
-
rkey: 'self',
|
|
1156
|
-
swapRecord: (await cidForCbor({})).toString(),
|
|
1157
|
-
record: profileRecord(),
|
|
1158
|
-
})
|
|
1159
|
-
await expect(attemptPut2).rejects.toMatchObject({ error: 'InvalidSwap' })
|
|
1160
|
-
})
|
|
1161
|
-
|
|
1162
|
-
it('applyWrites succeeds on proper commit cas', async () => {
|
|
1163
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
1164
|
-
const { data: commit } = await sync.getLatestCommit({
|
|
1165
|
-
did: aliceAgent.assertDid,
|
|
1166
|
-
})
|
|
1167
|
-
await repo.applyWrites({
|
|
1168
|
-
repo: aliceAgent.assertDid,
|
|
1169
|
-
swapCommit: commit.cid,
|
|
1170
|
-
writes: [
|
|
1171
|
-
{
|
|
1172
|
-
$type: `com.atproto.repo.applyWrites#create`,
|
|
1173
|
-
collection: 'app.bsky.feed.post',
|
|
1174
|
-
value: { $type: 'app.bsky.feed.post', ...postRecord() },
|
|
1175
|
-
},
|
|
1176
|
-
],
|
|
1177
|
-
})
|
|
1178
|
-
})
|
|
1179
|
-
|
|
1180
|
-
it('applyWrites fails on bad commit cas', async () => {
|
|
1181
|
-
const { repo, sync } = aliceAgent.com.atproto
|
|
1182
|
-
const { data: staleCommit } = await sync.getLatestCommit({
|
|
1183
|
-
did: aliceAgent.assertDid,
|
|
1184
|
-
})
|
|
1185
|
-
// Update repo, change head
|
|
1186
|
-
await repo.createRecord({
|
|
1187
|
-
repo: aliceAgent.assertDid,
|
|
1188
|
-
collection: 'app.bsky.feed.post',
|
|
1189
|
-
record: postRecord(),
|
|
1190
|
-
})
|
|
1191
|
-
const attemptApplyWrite = repo.applyWrites({
|
|
1192
|
-
repo: aliceAgent.assertDid,
|
|
1193
|
-
swapCommit: staleCommit.cid,
|
|
1194
|
-
writes: [
|
|
1195
|
-
{
|
|
1196
|
-
$type: `com.atproto.repo.applyWrites#create`,
|
|
1197
|
-
collection: 'app.bsky.feed.post',
|
|
1198
|
-
value: { $type: 'app.bsky.feed.post', ...postRecord() },
|
|
1199
|
-
},
|
|
1200
|
-
],
|
|
1201
|
-
})
|
|
1202
|
-
await expect(attemptApplyWrite).rejects.toMatchObject({
|
|
1203
|
-
error: 'InvalidSwap',
|
|
1204
|
-
})
|
|
1205
|
-
})
|
|
1206
|
-
|
|
1207
|
-
it("writes fail on values that can't reliably transform between cbor to lex", async () => {
|
|
1208
|
-
const passthroughBody = (data: unknown) =>
|
|
1209
|
-
ui8ToArrayBuffer(new TextEncoder().encode(JSON.stringify(data)))
|
|
1210
|
-
|
|
1211
|
-
const result = aliceAgent.call(
|
|
1212
|
-
'com.atproto.repo.createRecord',
|
|
1213
|
-
{},
|
|
1214
|
-
passthroughBody({
|
|
1215
|
-
repo: aliceAgent.assertDid,
|
|
1216
|
-
collection: 'app.bsky.feed.post',
|
|
1217
|
-
record: {
|
|
1218
|
-
text: 'x',
|
|
1219
|
-
createdAt: new Date().toISOString(),
|
|
1220
|
-
deepObject: createDeepObject(4000),
|
|
1221
|
-
},
|
|
1222
|
-
}),
|
|
1223
|
-
{
|
|
1224
|
-
encoding: 'application/json',
|
|
1225
|
-
},
|
|
1226
|
-
)
|
|
1227
|
-
|
|
1228
|
-
await expect(result).rejects.toMatchObject({
|
|
1229
|
-
status: 400,
|
|
1230
|
-
error: 'InvalidRequest',
|
|
1231
|
-
})
|
|
1232
|
-
})
|
|
1233
|
-
})
|
|
1234
|
-
|
|
1235
|
-
it('prevents duplicate likes', async () => {
|
|
1236
|
-
const now = new Date().toISOString()
|
|
1237
|
-
const uriA = AtUri.make(
|
|
1238
|
-
bobAgent.assertDid,
|
|
1239
|
-
'app.bsky.feed.post',
|
|
1240
|
-
TID.nextStr(),
|
|
1241
|
-
)
|
|
1242
|
-
const cidA = await cidForCbor({ post: 'a' })
|
|
1243
|
-
const uriB = AtUri.make(
|
|
1244
|
-
bobAgent.assertDid,
|
|
1245
|
-
'app.bsky.feed.post',
|
|
1246
|
-
TID.nextStr(),
|
|
1247
|
-
)
|
|
1248
|
-
const cidB = await cidForCbor({ post: 'b' })
|
|
1249
|
-
|
|
1250
|
-
const { data: like1 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1251
|
-
repo: aliceAgent.assertDid,
|
|
1252
|
-
collection: 'app.bsky.feed.like',
|
|
1253
|
-
record: {
|
|
1254
|
-
$type: 'app.bsky.feed.like',
|
|
1255
|
-
subject: { uri: uriA.toString(), cid: cidA.toString() },
|
|
1256
|
-
createdAt: now,
|
|
1257
|
-
},
|
|
1258
|
-
})
|
|
1259
|
-
const { data: like2 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1260
|
-
repo: aliceAgent.assertDid,
|
|
1261
|
-
collection: 'app.bsky.feed.like',
|
|
1262
|
-
record: {
|
|
1263
|
-
$type: 'app.bsky.feed.like',
|
|
1264
|
-
subject: { uri: uriB.toString(), cid: cidB.toString() },
|
|
1265
|
-
createdAt: now,
|
|
1266
|
-
},
|
|
1267
|
-
})
|
|
1268
|
-
const { data: like3 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1269
|
-
repo: aliceAgent.assertDid,
|
|
1270
|
-
collection: 'app.bsky.feed.like',
|
|
1271
|
-
record: {
|
|
1272
|
-
$type: 'app.bsky.feed.like',
|
|
1273
|
-
subject: { uri: uriA.toString(), cid: cidA.toString() },
|
|
1274
|
-
createdAt: now,
|
|
1275
|
-
},
|
|
1276
|
-
})
|
|
1277
|
-
|
|
1278
|
-
const getLike1 = aliceAgent.com.atproto.repo.getRecord({
|
|
1279
|
-
repo: aliceAgent.assertDid,
|
|
1280
|
-
collection: 'app.bsky.feed.like',
|
|
1281
|
-
rkey: new AtUri(like1.uri).rkey,
|
|
1282
|
-
})
|
|
1283
|
-
|
|
1284
|
-
await expect(getLike1).rejects.toThrow('Could not locate record:')
|
|
1285
|
-
|
|
1286
|
-
const getLike2 = aliceAgent.com.atproto.repo.getRecord({
|
|
1287
|
-
repo: aliceAgent.assertDid,
|
|
1288
|
-
collection: 'app.bsky.feed.like',
|
|
1289
|
-
rkey: new AtUri(like2.uri).rkey,
|
|
1290
|
-
})
|
|
1291
|
-
|
|
1292
|
-
await expect(getLike2).resolves.toBeDefined()
|
|
1293
|
-
|
|
1294
|
-
const getLike3 = aliceAgent.com.atproto.repo.getRecord({
|
|
1295
|
-
repo: aliceAgent.assertDid,
|
|
1296
|
-
collection: 'app.bsky.feed.like',
|
|
1297
|
-
rkey: new AtUri(like3.uri).rkey,
|
|
1298
|
-
})
|
|
1299
|
-
|
|
1300
|
-
await expect(getLike3).resolves.toBeDefined()
|
|
1301
|
-
})
|
|
1302
|
-
|
|
1303
|
-
it('prevents duplicate reposts', async () => {
|
|
1304
|
-
const now = new Date().toISOString()
|
|
1305
|
-
const uriA = AtUri.make(
|
|
1306
|
-
bobAgent.assertDid,
|
|
1307
|
-
'app.bsky.feed.post',
|
|
1308
|
-
TID.nextStr(),
|
|
1309
|
-
)
|
|
1310
|
-
const cidA = await cidForCbor({ post: 'a' })
|
|
1311
|
-
const uriB = AtUri.make(
|
|
1312
|
-
bobAgent.assertDid,
|
|
1313
|
-
'app.bsky.feed.post',
|
|
1314
|
-
TID.nextStr(),
|
|
1315
|
-
)
|
|
1316
|
-
const cidB = await cidForCbor({ post: 'b' })
|
|
1317
|
-
|
|
1318
|
-
const { data: repost1 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1319
|
-
repo: aliceAgent.assertDid,
|
|
1320
|
-
collection: 'app.bsky.feed.repost',
|
|
1321
|
-
record: {
|
|
1322
|
-
$type: 'app.bsky.feed.repost',
|
|
1323
|
-
subject: { uri: uriA.toString(), cid: cidA.toString() },
|
|
1324
|
-
createdAt: now,
|
|
1325
|
-
},
|
|
1326
|
-
})
|
|
1327
|
-
const { data: repost2 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1328
|
-
repo: aliceAgent.assertDid,
|
|
1329
|
-
collection: 'app.bsky.feed.repost',
|
|
1330
|
-
record: {
|
|
1331
|
-
$type: 'app.bsky.feed.repost',
|
|
1332
|
-
subject: { uri: uriB.toString(), cid: cidB.toString() },
|
|
1333
|
-
createdAt: now,
|
|
1334
|
-
},
|
|
1335
|
-
})
|
|
1336
|
-
const { data: repost3 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1337
|
-
repo: aliceAgent.assertDid,
|
|
1338
|
-
collection: 'app.bsky.feed.repost',
|
|
1339
|
-
record: {
|
|
1340
|
-
$type: 'app.bsky.feed.repost',
|
|
1341
|
-
subject: { uri: uriA.toString(), cid: cidA.toString() },
|
|
1342
|
-
createdAt: now,
|
|
1343
|
-
},
|
|
1344
|
-
})
|
|
1345
|
-
|
|
1346
|
-
const getRepost1 = aliceAgent.com.atproto.repo.getRecord({
|
|
1347
|
-
repo: aliceAgent.assertDid,
|
|
1348
|
-
collection: 'app.bsky.feed.repost',
|
|
1349
|
-
rkey: new AtUri(repost1.uri).rkey,
|
|
1350
|
-
})
|
|
1351
|
-
|
|
1352
|
-
await expect(getRepost1).rejects.toThrow('Could not locate record:')
|
|
1353
|
-
|
|
1354
|
-
const getRepost2 = aliceAgent.com.atproto.repo.getRecord({
|
|
1355
|
-
repo: aliceAgent.assertDid,
|
|
1356
|
-
collection: 'app.bsky.feed.repost',
|
|
1357
|
-
rkey: new AtUri(repost2.uri).rkey,
|
|
1358
|
-
})
|
|
1359
|
-
|
|
1360
|
-
await expect(getRepost2).resolves.toBeDefined()
|
|
1361
|
-
|
|
1362
|
-
const getRepost3 = aliceAgent.com.atproto.repo.getRecord({
|
|
1363
|
-
repo: aliceAgent.assertDid,
|
|
1364
|
-
collection: 'app.bsky.feed.repost',
|
|
1365
|
-
rkey: new AtUri(repost3.uri).rkey,
|
|
1366
|
-
})
|
|
1367
|
-
|
|
1368
|
-
await expect(getRepost3).resolves.toBeDefined()
|
|
1369
|
-
})
|
|
1370
|
-
|
|
1371
|
-
it('prevents duplicate blocks', async () => {
|
|
1372
|
-
const now = new Date().toISOString()
|
|
1373
|
-
|
|
1374
|
-
const { data: block1 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1375
|
-
repo: aliceAgent.assertDid,
|
|
1376
|
-
collection: 'app.bsky.graph.block',
|
|
1377
|
-
record: {
|
|
1378
|
-
$type: 'app.bsky.graph.block',
|
|
1379
|
-
subject: bobAgent.assertDid,
|
|
1380
|
-
createdAt: now,
|
|
1381
|
-
},
|
|
1382
|
-
})
|
|
1383
|
-
|
|
1384
|
-
const { data: block2 } = await bobAgent.com.atproto.repo.createRecord({
|
|
1385
|
-
repo: bobAgent.assertDid,
|
|
1386
|
-
collection: 'app.bsky.graph.block',
|
|
1387
|
-
record: {
|
|
1388
|
-
$type: 'app.bsky.graph.block',
|
|
1389
|
-
subject: aliceAgent.assertDid,
|
|
1390
|
-
createdAt: now,
|
|
1391
|
-
},
|
|
1392
|
-
})
|
|
1393
|
-
|
|
1394
|
-
const { data: block3 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1395
|
-
repo: aliceAgent.assertDid,
|
|
1396
|
-
collection: 'app.bsky.graph.block',
|
|
1397
|
-
record: {
|
|
1398
|
-
$type: 'app.bsky.graph.block',
|
|
1399
|
-
subject: bobAgent.assertDid,
|
|
1400
|
-
createdAt: now,
|
|
1401
|
-
},
|
|
1402
|
-
})
|
|
1403
|
-
|
|
1404
|
-
const getBlock1 = aliceAgent.com.atproto.repo.getRecord({
|
|
1405
|
-
repo: aliceAgent.assertDid,
|
|
1406
|
-
collection: 'app.bsky.graph.block',
|
|
1407
|
-
rkey: new AtUri(block1.uri).rkey,
|
|
1408
|
-
})
|
|
1409
|
-
|
|
1410
|
-
await expect(getBlock1).rejects.toThrow('Could not locate record:')
|
|
1411
|
-
|
|
1412
|
-
const getBlock2 = aliceAgent.com.atproto.repo.getRecord({
|
|
1413
|
-
repo: bobAgent.assertDid,
|
|
1414
|
-
collection: 'app.bsky.graph.block',
|
|
1415
|
-
rkey: new AtUri(block2.uri).rkey,
|
|
1416
|
-
})
|
|
1417
|
-
|
|
1418
|
-
await expect(getBlock2).resolves.toBeDefined()
|
|
1419
|
-
|
|
1420
|
-
const getBlock3 = aliceAgent.com.atproto.repo.getRecord({
|
|
1421
|
-
repo: aliceAgent.assertDid,
|
|
1422
|
-
collection: 'app.bsky.graph.block',
|
|
1423
|
-
rkey: new AtUri(block3.uri).rkey,
|
|
1424
|
-
})
|
|
1425
|
-
|
|
1426
|
-
await expect(getBlock3).resolves.toBeDefined()
|
|
1427
|
-
})
|
|
1428
|
-
|
|
1429
|
-
it('prevents duplicate follows', async () => {
|
|
1430
|
-
const now = new Date().toISOString()
|
|
1431
|
-
|
|
1432
|
-
const { data: follow1 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1433
|
-
repo: aliceAgent.assertDid,
|
|
1434
|
-
collection: 'app.bsky.graph.follow',
|
|
1435
|
-
record: {
|
|
1436
|
-
$type: 'app.bsky.graph.follow',
|
|
1437
|
-
subject: bobAgent.assertDid,
|
|
1438
|
-
createdAt: now,
|
|
1439
|
-
},
|
|
1440
|
-
})
|
|
1441
|
-
const { data: follow2 } = await bobAgent.com.atproto.repo.createRecord({
|
|
1442
|
-
repo: bobAgent.assertDid,
|
|
1443
|
-
collection: 'app.bsky.graph.follow',
|
|
1444
|
-
record: {
|
|
1445
|
-
$type: 'app.bsky.graph.follow',
|
|
1446
|
-
subject: aliceAgent.assertDid,
|
|
1447
|
-
createdAt: now,
|
|
1448
|
-
},
|
|
1449
|
-
})
|
|
1450
|
-
const { data: follow3 } = await aliceAgent.com.atproto.repo.createRecord({
|
|
1451
|
-
repo: aliceAgent.assertDid,
|
|
1452
|
-
collection: 'app.bsky.graph.follow',
|
|
1453
|
-
record: {
|
|
1454
|
-
$type: 'app.bsky.graph.follow',
|
|
1455
|
-
subject: bobAgent.assertDid,
|
|
1456
|
-
createdAt: now,
|
|
1457
|
-
},
|
|
1458
|
-
})
|
|
1459
|
-
|
|
1460
|
-
const getFollow1 = aliceAgent.com.atproto.repo.getRecord({
|
|
1461
|
-
repo: aliceAgent.assertDid,
|
|
1462
|
-
collection: 'app.bsky.graph.follow',
|
|
1463
|
-
rkey: new AtUri(follow1.uri).rkey,
|
|
1464
|
-
})
|
|
1465
|
-
|
|
1466
|
-
await expect(getFollow1).rejects.toThrow('Could not locate record:')
|
|
1467
|
-
|
|
1468
|
-
const getFollow2 = aliceAgent.com.atproto.repo.getRecord({
|
|
1469
|
-
repo: bobAgent.assertDid,
|
|
1470
|
-
collection: 'app.bsky.graph.follow',
|
|
1471
|
-
rkey: new AtUri(follow2.uri).rkey,
|
|
1472
|
-
})
|
|
1473
|
-
|
|
1474
|
-
await expect(getFollow2).resolves.toBeDefined()
|
|
1475
|
-
|
|
1476
|
-
const getFollow3 = aliceAgent.com.atproto.repo.getRecord({
|
|
1477
|
-
repo: aliceAgent.assertDid,
|
|
1478
|
-
collection: 'app.bsky.graph.follow',
|
|
1479
|
-
rkey: new AtUri(follow3.uri).rkey,
|
|
1480
|
-
})
|
|
1481
|
-
|
|
1482
|
-
await expect(getFollow3).resolves.toBeDefined()
|
|
1483
|
-
})
|
|
1484
|
-
|
|
1485
|
-
// Moderation
|
|
1486
|
-
// --------------
|
|
1487
|
-
|
|
1488
|
-
it("doesn't serve taken-down record", async () => {
|
|
1489
|
-
const created = await aliceAgent.app.bsky.feed.post.create(
|
|
1490
|
-
{ repo: aliceAgent.assertDid },
|
|
1491
|
-
{
|
|
1492
|
-
$type: 'app.bsky.feed.post',
|
|
1493
|
-
text: 'Hello, world!',
|
|
1494
|
-
createdAt: new Date().toISOString(),
|
|
1495
|
-
},
|
|
1496
|
-
)
|
|
1497
|
-
const postUri = new AtUri(created.uri)
|
|
1498
|
-
const post = await agent.app.bsky.feed.post.get({
|
|
1499
|
-
repo: aliceAgent.assertDid,
|
|
1500
|
-
rkey: postUri.rkey,
|
|
1501
|
-
})
|
|
1502
|
-
const posts = await agent.app.bsky.feed.post.list({
|
|
1503
|
-
repo: aliceAgent.assertDid,
|
|
1504
|
-
})
|
|
1505
|
-
expect(posts.records.map((r) => r.uri)).toContain(post.uri)
|
|
1506
|
-
|
|
1507
|
-
const subject = {
|
|
1508
|
-
$type: 'com.atproto.repo.strongRef',
|
|
1509
|
-
uri: created.uri,
|
|
1510
|
-
cid: created.cid,
|
|
1511
|
-
}
|
|
1512
|
-
await agent.com.atproto.admin.updateSubjectStatus(
|
|
1513
|
-
{
|
|
1514
|
-
subject,
|
|
1515
|
-
takedown: { applied: true },
|
|
1516
|
-
},
|
|
1517
|
-
{
|
|
1518
|
-
encoding: 'application/json',
|
|
1519
|
-
headers: { authorization: network.pds.adminAuth() },
|
|
1520
|
-
},
|
|
1521
|
-
)
|
|
1522
|
-
|
|
1523
|
-
const postTakedownPromise = agent.app.bsky.feed.post.get({
|
|
1524
|
-
repo: aliceAgent.assertDid,
|
|
1525
|
-
rkey: postUri.rkey,
|
|
1526
|
-
})
|
|
1527
|
-
await expect(postTakedownPromise).rejects.toThrow('Could not locate record')
|
|
1528
|
-
const postsTakedown = await agent.app.bsky.feed.post.list({
|
|
1529
|
-
repo: aliceAgent.assertDid,
|
|
1530
|
-
})
|
|
1531
|
-
expect(postsTakedown.records.map((r) => r.uri)).not.toContain(post.uri)
|
|
1532
|
-
|
|
1533
|
-
// Cleanup
|
|
1534
|
-
await agent.com.atproto.admin.updateSubjectStatus(
|
|
1535
|
-
{
|
|
1536
|
-
subject,
|
|
1537
|
-
takedown: { applied: false },
|
|
1538
|
-
},
|
|
1539
|
-
{
|
|
1540
|
-
encoding: 'application/json',
|
|
1541
|
-
headers: { authorization: network.pds.adminAuth() },
|
|
1542
|
-
},
|
|
1543
|
-
)
|
|
1544
|
-
})
|
|
1545
|
-
|
|
1546
|
-
it("doesn't serve taken-down actor", async () => {
|
|
1547
|
-
const posts = await agent.app.bsky.feed.post.list({
|
|
1548
|
-
repo: aliceAgent.assertDid,
|
|
1549
|
-
})
|
|
1550
|
-
expect(posts.records.length).toBeGreaterThan(0)
|
|
1551
|
-
|
|
1552
|
-
const subject = {
|
|
1553
|
-
$type: 'com.atproto.admin.defs#repoRef',
|
|
1554
|
-
did: aliceAgent.assertDid,
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
await agent.com.atproto.admin.updateSubjectStatus(
|
|
1558
|
-
{
|
|
1559
|
-
subject,
|
|
1560
|
-
takedown: { applied: true },
|
|
1561
|
-
},
|
|
1562
|
-
{
|
|
1563
|
-
encoding: 'application/json',
|
|
1564
|
-
headers: { authorization: network.pds.adminAuth() },
|
|
1565
|
-
},
|
|
1566
|
-
)
|
|
1567
|
-
|
|
1568
|
-
const tryListPosts = agent.app.bsky.feed.post.list({
|
|
1569
|
-
repo: aliceAgent.assertDid,
|
|
1570
|
-
})
|
|
1571
|
-
await expect(tryListPosts).rejects.toThrow(/Could not find repo/)
|
|
1572
|
-
|
|
1573
|
-
// Cleanup
|
|
1574
|
-
await agent.com.atproto.admin.updateSubjectStatus(
|
|
1575
|
-
{
|
|
1576
|
-
subject,
|
|
1577
|
-
takedown: { applied: false },
|
|
1578
|
-
},
|
|
1579
|
-
{
|
|
1580
|
-
encoding: 'application/json',
|
|
1581
|
-
headers: { authorization: network.pds.adminAuth() },
|
|
1582
|
-
},
|
|
1583
|
-
)
|
|
1584
|
-
})
|
|
1585
|
-
})
|
|
1586
|
-
|
|
1587
|
-
function createDeepObject(depth: number) {
|
|
1588
|
-
const obj: any = {}
|
|
1589
|
-
let iter = obj
|
|
1590
|
-
for (let i = 0; i < depth; ++i) {
|
|
1591
|
-
iter.x = {}
|
|
1592
|
-
iter = iter.x
|
|
1593
|
-
}
|
|
1594
|
-
return obj
|
|
1595
|
-
}
|