@atproto/pds 0.5.11 → 0.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/api/app/bsky/notification/index.d.ts.map +1 -1
  3. package/dist/api/app/bsky/notification/index.js +2 -0
  4. package/dist/api/app/bsky/notification/index.js.map +1 -1
  5. package/dist/api/app/bsky/notification/unregisterPush.d.ts +4 -0
  6. package/dist/api/app/bsky/notification/unregisterPush.d.ts.map +1 -0
  7. package/dist/api/app/bsky/notification/unregisterPush.js +48 -0
  8. package/dist/api/app/bsky/notification/unregisterPush.js.map +1 -0
  9. package/package.json +42 -38
  10. package/build.templates.cjs +0 -22
  11. package/example.env +0 -42
  12. package/jest.config.cjs +0 -27
  13. package/src/account-manager/account-manager.ts +0 -916
  14. package/src/account-manager/db/index.ts +0 -21
  15. package/src/account-manager/db/migrations/001-init.ts +0 -115
  16. package/src/account-manager/db/migrations/002-account-deactivation.ts +0 -17
  17. package/src/account-manager/db/migrations/003-privileged-app-passwords.ts +0 -12
  18. package/src/account-manager/db/migrations/004-oauth.ts +0 -122
  19. package/src/account-manager/db/migrations/005-oauth-account-management.ts +0 -136
  20. package/src/account-manager/db/migrations/006-oauth-permission-sets.ts +0 -20
  21. package/src/account-manager/db/migrations/007-lexicon-failures-index.ts +0 -14
  22. package/src/account-manager/db/migrations/index.ts +0 -17
  23. package/src/account-manager/db/schema/account-device.ts +0 -14
  24. package/src/account-manager/db/schema/account.ts +0 -16
  25. package/src/account-manager/db/schema/actor.ts +0 -17
  26. package/src/account-manager/db/schema/app-password.ts +0 -13
  27. package/src/account-manager/db/schema/authorization-request.ts +0 -30
  28. package/src/account-manager/db/schema/authorized-client.ts +0 -23
  29. package/src/account-manager/db/schema/device.ts +0 -18
  30. package/src/account-manager/db/schema/email-token.ts +0 -19
  31. package/src/account-manager/db/schema/index.ts +0 -43
  32. package/src/account-manager/db/schema/invite-code.ts +0 -24
  33. package/src/account-manager/db/schema/lexicon.ts +0 -15
  34. package/src/account-manager/db/schema/refresh-token.ts +0 -11
  35. package/src/account-manager/db/schema/repo-root.ts +0 -12
  36. package/src/account-manager/db/schema/token.ts +0 -38
  37. package/src/account-manager/db/schema/used-refresh-token.ts +0 -13
  38. package/src/account-manager/helpers/account-device.ts +0 -63
  39. package/src/account-manager/helpers/account.ts +0 -355
  40. package/src/account-manager/helpers/auth.ts +0 -222
  41. package/src/account-manager/helpers/authorization-request.ts +0 -90
  42. package/src/account-manager/helpers/authorized-client.ts +0 -75
  43. package/src/account-manager/helpers/device.ts +0 -47
  44. package/src/account-manager/helpers/email-token.ts +0 -87
  45. package/src/account-manager/helpers/invite.ts +0 -263
  46. package/src/account-manager/helpers/lexicon.ts +0 -67
  47. package/src/account-manager/helpers/password.ts +0 -136
  48. package/src/account-manager/helpers/repo.ts +0 -24
  49. package/src/account-manager/helpers/scrypt.ts +0 -53
  50. package/src/account-manager/helpers/token.ts +0 -158
  51. package/src/account-manager/helpers/used-refresh-token.ts +0 -30
  52. package/src/account-manager/oauth-store.ts +0 -880
  53. package/src/account-manager/scope-reference-getter.ts +0 -106
  54. package/src/actor-store/actor-store-reader.ts +0 -45
  55. package/src/actor-store/actor-store-resources.ts +0 -8
  56. package/src/actor-store/actor-store-transactor.ts +0 -31
  57. package/src/actor-store/actor-store-writer.ts +0 -17
  58. package/src/actor-store/actor-store.ts +0 -210
  59. package/src/actor-store/blob/reader.ts +0 -160
  60. package/src/actor-store/blob/transactor.ts +0 -383
  61. package/src/actor-store/db/index.ts +0 -20
  62. package/src/actor-store/db/migrations/001-init.ts +0 -105
  63. package/src/actor-store/db/migrations/index.ts +0 -5
  64. package/src/actor-store/db/schema/account-pref.ts +0 -11
  65. package/src/actor-store/db/schema/backlink.ts +0 -9
  66. package/src/actor-store/db/schema/blob.ts +0 -14
  67. package/src/actor-store/db/schema/index.ts +0 -23
  68. package/src/actor-store/db/schema/record-blob.ts +0 -8
  69. package/src/actor-store/db/schema/record.ts +0 -14
  70. package/src/actor-store/db/schema/repo-block.ts +0 -10
  71. package/src/actor-store/db/schema/repo-root.ts +0 -10
  72. package/src/actor-store/migrate.ts +0 -39
  73. package/src/actor-store/preference/reader.ts +0 -48
  74. package/src/actor-store/preference/transactor.ts +0 -55
  75. package/src/actor-store/preference/util.ts +0 -39
  76. package/src/actor-store/record/reader.ts +0 -374
  77. package/src/actor-store/record/transactor.ts +0 -111
  78. package/src/actor-store/repo/reader.ts +0 -31
  79. package/src/actor-store/repo/sql-repo-reader.ts +0 -150
  80. package/src/actor-store/repo/sql-repo-transactor.ts +0 -105
  81. package/src/actor-store/repo/transactor.ts +0 -227
  82. package/src/api/app/bsky/actor/getPreferences.ts +0 -57
  83. package/src/api/app/bsky/actor/getProfile.ts +0 -41
  84. package/src/api/app/bsky/actor/getProfiles.ts +0 -51
  85. package/src/api/app/bsky/actor/index.ts +0 -13
  86. package/src/api/app/bsky/actor/putPreferences.ts +0 -62
  87. package/src/api/app/bsky/feed/getActorLikes.ts +0 -63
  88. package/src/api/app/bsky/feed/getAuthorFeed.ts +0 -84
  89. package/src/api/app/bsky/feed/getFeed.ts +0 -47
  90. package/src/api/app/bsky/feed/getPostThread.ts +0 -251
  91. package/src/api/app/bsky/feed/getTimeline.ts +0 -50
  92. package/src/api/app/bsky/feed/index.ts +0 -15
  93. package/src/api/app/bsky/index.ts +0 -11
  94. package/src/api/app/bsky/notification/index.ts +0 -7
  95. package/src/api/app/bsky/notification/registerPush.ts +0 -71
  96. package/src/api/app/bsky/util/resolver.ts +0 -20
  97. package/src/api/com/atproto/admin/deleteAccount.ts +0 -22
  98. package/src/api/com/atproto/admin/disableAccountInvites.ts +0 -18
  99. package/src/api/com/atproto/admin/disableInviteCodes.ts +0 -21
  100. package/src/api/com/atproto/admin/enableAccountInvites.ts +0 -18
  101. package/src/api/com/atproto/admin/getAccountInfo.ts +0 -32
  102. package/src/api/com/atproto/admin/getAccountInfos.ts +0 -34
  103. package/src/api/com/atproto/admin/getInviteCodes.ts +0 -126
  104. package/src/api/com/atproto/admin/getSubjectStatus.ts +0 -76
  105. package/src/api/com/atproto/admin/index.ts +0 -31
  106. package/src/api/com/atproto/admin/sendEmail.ts +0 -47
  107. package/src/api/com/atproto/admin/updateAccountEmail.ts +0 -32
  108. package/src/api/com/atproto/admin/updateAccountHandle.ts +0 -47
  109. package/src/api/com/atproto/admin/updateAccountPassword.ts +0 -34
  110. package/src/api/com/atproto/admin/updateSubjectStatus.ts +0 -68
  111. package/src/api/com/atproto/admin/util.ts +0 -66
  112. package/src/api/com/atproto/identity/getRecommendedDidCredentials.ts +0 -50
  113. package/src/api/com/atproto/identity/index.ts +0 -17
  114. package/src/api/com/atproto/identity/requestPlcOperationSignature.ts +0 -59
  115. package/src/api/com/atproto/identity/resolveHandle.ts +0 -50
  116. package/src/api/com/atproto/identity/signPlcOperation.ts +0 -85
  117. package/src/api/com/atproto/identity/submitPlcOperation.ts +0 -65
  118. package/src/api/com/atproto/identity/updateHandle.ts +0 -66
  119. package/src/api/com/atproto/index.ts +0 -19
  120. package/src/api/com/atproto/moderation/createReport.ts +0 -41
  121. package/src/api/com/atproto/moderation/index.ts +0 -7
  122. package/src/api/com/atproto/repo/applyWrites.ts +0 -226
  123. package/src/api/com/atproto/repo/createRecord.ts +0 -143
  124. package/src/api/com/atproto/repo/deleteRecord.ts +0 -122
  125. package/src/api/com/atproto/repo/describeRepo.ts +0 -43
  126. package/src/api/com/atproto/repo/getRecord.ts +0 -40
  127. package/src/api/com/atproto/repo/importRepo.ts +0 -101
  128. package/src/api/com/atproto/repo/index.ts +0 -25
  129. package/src/api/com/atproto/repo/listMissingBlobs.ts +0 -29
  130. package/src/api/com/atproto/repo/listRecords.ts +0 -36
  131. package/src/api/com/atproto/repo/putRecord.ts +0 -211
  132. package/src/api/com/atproto/repo/uploadBlob.ts +0 -60
  133. package/src/api/com/atproto/server/activateAccount.ts +0 -37
  134. package/src/api/com/atproto/server/checkAccountStatus.ts +0 -51
  135. package/src/api/com/atproto/server/confirmEmail.ts +0 -39
  136. package/src/api/com/atproto/server/createAccount.ts +0 -327
  137. package/src/api/com/atproto/server/createAppPassword.ts +0 -53
  138. package/src/api/com/atproto/server/createInviteCode.ts +0 -38
  139. package/src/api/com/atproto/server/createInviteCodes.ts +0 -42
  140. package/src/api/com/atproto/server/createSession.ts +0 -97
  141. package/src/api/com/atproto/server/deactivateAccount.ts +0 -41
  142. package/src/api/com/atproto/server/deleteAccount.ts +0 -85
  143. package/src/api/com/atproto/server/deleteSession.ts +0 -23
  144. package/src/api/com/atproto/server/describeServer.ts +0 -29
  145. package/src/api/com/atproto/server/getAccountInviteCodes.ts +0 -142
  146. package/src/api/com/atproto/server/getServiceAuth.ts +0 -111
  147. package/src/api/com/atproto/server/getSession.ts +0 -80
  148. package/src/api/com/atproto/server/index.ts +0 -55
  149. package/src/api/com/atproto/server/listAppPasswords.ts +0 -45
  150. package/src/api/com/atproto/server/refreshSession.ts +0 -72
  151. package/src/api/com/atproto/server/requestAccountDelete.ts +0 -66
  152. package/src/api/com/atproto/server/requestEmailConfirmation.ts +0 -68
  153. package/src/api/com/atproto/server/requestEmailUpdate.ts +0 -86
  154. package/src/api/com/atproto/server/requestPasswordReset.ts +0 -52
  155. package/src/api/com/atproto/server/reserveSigningKey.ts +0 -15
  156. package/src/api/com/atproto/server/resetPassword.ts +0 -50
  157. package/src/api/com/atproto/server/revokeAppPassword.ts +0 -42
  158. package/src/api/com/atproto/server/updateEmail.ts +0 -52
  159. package/src/api/com/atproto/server/util.ts +0 -136
  160. package/src/api/com/atproto/sync/deprecated/getCheckout.ts +0 -27
  161. package/src/api/com/atproto/sync/deprecated/getHead.ts +0 -33
  162. package/src/api/com/atproto/sync/getBlob.ts +0 -61
  163. package/src/api/com/atproto/sync/getBlocks.ts +0 -37
  164. package/src/api/com/atproto/sync/getLatestCommit.ts +0 -33
  165. package/src/api/com/atproto/sync/getRecord.ts +0 -49
  166. package/src/api/com/atproto/sync/getRepo.ts +0 -75
  167. package/src/api/com/atproto/sync/getRepoStatus.ts +0 -34
  168. package/src/api/com/atproto/sync/index.ts +0 -27
  169. package/src/api/com/atproto/sync/listBlobs.ts +0 -33
  170. package/src/api/com/atproto/sync/listRepos.ts +0 -74
  171. package/src/api/com/atproto/sync/subscribeRepos.ts +0 -73
  172. package/src/api/com/atproto/sync/util.ts +0 -37
  173. package/src/api/com/atproto/temp/checkSignupQueue.ts +0 -34
  174. package/src/api/com/atproto/temp/index.ts +0 -7
  175. package/src/api/index.ts +0 -10
  176. package/src/api/proxy.ts +0 -44
  177. package/src/app-view.ts +0 -24
  178. package/src/auth-output.ts +0 -52
  179. package/src/auth-routes.ts +0 -64
  180. package/src/auth-scope.ts +0 -40
  181. package/src/auth-verifier.ts +0 -668
  182. package/src/background.ts +0 -65
  183. package/src/basic-routes.ts +0 -52
  184. package/src/bsky-app-view.ts +0 -33
  185. package/src/config/config.ts +0 -553
  186. package/src/config/env.ts +0 -167
  187. package/src/config/index.ts +0 -3
  188. package/src/config/secrets.ts +0 -54
  189. package/src/context.ts +0 -523
  190. package/src/crawlers.ts +0 -46
  191. package/src/db/cast.ts +0 -52
  192. package/src/db/db.ts +0 -140
  193. package/src/db/index.ts +0 -4
  194. package/src/db/migrator.ts +0 -40
  195. package/src/db/pagination.ts +0 -132
  196. package/src/db/tables/moderation.ts +0 -80
  197. package/src/db/util.ts +0 -108
  198. package/src/did-cache/db/index.ts +0 -21
  199. package/src/did-cache/db/migrations.ts +0 -17
  200. package/src/did-cache/db/schema.ts +0 -9
  201. package/src/did-cache/index.ts +0 -131
  202. package/src/disk-blobstore.ts +0 -172
  203. package/src/error.ts +0 -19
  204. package/src/handle/explicit-slurs.ts +0 -22
  205. package/src/handle/index.ts +0 -49
  206. package/src/handle/reserved.ts +0 -1059
  207. package/src/image/image-url-builder.ts +0 -16
  208. package/src/index.ts +0 -189
  209. package/src/lexicons.ts +0 -4
  210. package/src/logger.ts +0 -35
  211. package/src/mailer/index.ts +0 -111
  212. package/src/mailer/moderation.ts +0 -33
  213. package/src/mailer/templates/confirm-email.d.ts +0 -4
  214. package/src/mailer/templates/confirm-email.hbs +0 -158
  215. package/src/mailer/templates/delete-account.d.ts +0 -4
  216. package/src/mailer/templates/delete-account.hbs +0 -156
  217. package/src/mailer/templates/plc-operation.d.ts +0 -4
  218. package/src/mailer/templates/plc-operation.hbs +0 -153
  219. package/src/mailer/templates/reset-password.d.ts +0 -4
  220. package/src/mailer/templates/reset-password.hbs +0 -154
  221. package/src/mailer/templates/update-email.d.ts +0 -4
  222. package/src/mailer/templates/update-email.hbs +0 -153
  223. package/src/mailer/templates.ts +0 -17
  224. package/src/pipethrough.ts +0 -716
  225. package/src/rate-limits.ts +0 -59
  226. package/src/read-after-write/index.ts +0 -3
  227. package/src/read-after-write/types.ts +0 -35
  228. package/src/read-after-write/util.ts +0 -101
  229. package/src/read-after-write/viewer.ts +0 -290
  230. package/src/redis.ts +0 -25
  231. package/src/repo/index.ts +0 -2
  232. package/src/repo/prepare.ts +0 -266
  233. package/src/repo/types.ts +0 -65
  234. package/src/scripts/README.md +0 -40
  235. package/src/scripts/index.ts +0 -20
  236. package/src/scripts/publish-identity.ts +0 -60
  237. package/src/scripts/rebuild-repo.ts +0 -119
  238. package/src/scripts/rotate-keys.ts +0 -146
  239. package/src/scripts/sequencer-recovery/index.ts +0 -23
  240. package/src/scripts/sequencer-recovery/recoverer.ts +0 -297
  241. package/src/scripts/sequencer-recovery/recovery-db.ts +0 -65
  242. package/src/scripts/sequencer-recovery/repair-repos.ts +0 -49
  243. package/src/scripts/sequencer-recovery/user-queues.ts +0 -44
  244. package/src/scripts/util.ts +0 -7
  245. package/src/sequencer/db/index.ts +0 -21
  246. package/src/sequencer/db/migrations/001-init.ts +0 -35
  247. package/src/sequencer/db/migrations/index.ts +0 -5
  248. package/src/sequencer/db/schema.ts +0 -19
  249. package/src/sequencer/events.ts +0 -199
  250. package/src/sequencer/index.ts +0 -3
  251. package/src/sequencer/outbox.ts +0 -123
  252. package/src/sequencer/sequencer.ts +0 -290
  253. package/src/util/compression.ts +0 -16
  254. package/src/util/debug.ts +0 -10
  255. package/src/util/http.ts +0 -31
  256. package/src/util/types.ts +0 -7
  257. package/src/well-known.ts +0 -30
  258. package/test.env +0 -2
  259. package/tests/__snapshots__/takedown-appeal.test.ts.snap +0 -43
  260. package/tests/_oauth_client_assets_middleware.ts +0 -23
  261. package/tests/_puppeteer.ts +0 -147
  262. package/tests/_types.d.ts +0 -16
  263. package/tests/_util.ts +0 -191
  264. package/tests/account-deactivation.test.ts +0 -204
  265. package/tests/account-deletion.test.ts +0 -300
  266. package/tests/account-manager.test.ts +0 -462
  267. package/tests/account-migration.test.ts +0 -221
  268. package/tests/account-status.test.ts +0 -206
  269. package/tests/account.test.ts +0 -595
  270. package/tests/app-passwords.test.ts +0 -262
  271. package/tests/auth.test.ts +0 -405
  272. package/tests/blob-deletes.test.ts +0 -204
  273. package/tests/create-post.test.ts +0 -79
  274. package/tests/crud.test.ts +0 -1595
  275. package/tests/db.test.ts +0 -170
  276. package/tests/email-confirmation.test.ts +0 -227
  277. package/tests/entryway-mock.ts +0 -323
  278. package/tests/entryway.test.ts +0 -145
  279. package/tests/file-uploads.test.ts +0 -301
  280. package/tests/get-service-auth.test.ts +0 -81
  281. package/tests/handle-validation.test.ts +0 -56
  282. package/tests/handles.test.ts +0 -274
  283. package/tests/invite-codes.test.ts +0 -367
  284. package/tests/invites-admin.test.ts +0 -252
  285. package/tests/moderation.test.ts +0 -280
  286. package/tests/moderator-auth.test.ts +0 -177
  287. package/tests/oauth.test.ts +0 -334
  288. package/tests/plc-operations.test.ts +0 -239
  289. package/tests/preferences.test.ts +0 -352
  290. package/tests/proxied/__snapshots__/admin.test.ts.snap +0 -516
  291. package/tests/proxied/__snapshots__/feedgen.test.ts.snap +0 -215
  292. package/tests/proxied/__snapshots__/views.test.ts.snap +0 -4456
  293. package/tests/proxied/admin.test.ts +0 -340
  294. package/tests/proxied/feedgen.test.ts +0 -66
  295. package/tests/proxied/notif.test.ts +0 -85
  296. package/tests/proxied/procedures.test.ts +0 -175
  297. package/tests/proxied/proxy-catchall.test.ts +0 -256
  298. package/tests/proxied/proxy-header.test.ts +0 -239
  299. package/tests/proxied/proxy-oauth-aud.test.ts +0 -182
  300. package/tests/proxied/read-after-write.test.ts +0 -382
  301. package/tests/proxied/views.test.ts +0 -608
  302. package/tests/races.test.ts +0 -89
  303. package/tests/rate-limits.test.ts +0 -70
  304. package/tests/recovery.test.ts +0 -180
  305. package/tests/seeds/basic.ts +0 -165
  306. package/tests/seeds/follows.ts +0 -57
  307. package/tests/seeds/likes.ts +0 -14
  308. package/tests/seeds/reposts.ts +0 -18
  309. package/tests/seeds/thread.ts +0 -40
  310. package/tests/seeds/users-bulk.ts +0 -246
  311. package/tests/seeds/users.ts +0 -67
  312. package/tests/sequencer.test.ts +0 -251
  313. package/tests/server.test.ts +0 -151
  314. package/tests/sync/invertible-ops.test.ts +0 -99
  315. package/tests/sync/list.test.ts +0 -43
  316. package/tests/sync/subscribe-repos.test.ts +0 -672
  317. package/tests/sync/sync.test.ts +0 -316
  318. package/tests/takedown-appeal.test.ts +0 -166
  319. package/tsconfig.build.json +0 -9
  320. package/tsconfig.build.tsbuildinfo +0 -1
  321. package/tsconfig.json +0 -7
  322. package/tsconfig.tests.json +0 -8
@@ -1,672 +0,0 @@
1
- import { WebSocket } from 'ws'
2
- import { AtpAgent } from '@atproto/api'
3
- import {
4
- HOUR,
5
- MINUTE,
6
- cborDecode,
7
- readFromGenerator,
8
- wait,
9
- } from '@atproto/common'
10
- import { randomStr } from '@atproto/crypto'
11
- import { SeedClient, TestNetworkNoAppView } from '@atproto/dev-env'
12
- import { Cid } from '@atproto/lex-data'
13
- import * as repo from '@atproto/repo'
14
- import { readCar } from '@atproto/repo'
15
- import type { DidString } from '@atproto/syntax'
16
- import { ErrorFrame, Frame, MessageFrame, byFrame } from '@atproto/xrpc-server'
17
- import { AccountStatus } from '../../src/account-manager/account-manager.js'
18
- import { AppContext } from '../../src/index.js'
19
- import { com } from '../../src/lexicons.js'
20
- import basicSeed from '../seeds/basic.js'
21
-
22
- describe('repo subscribe repos', () => {
23
- let serverHost: string
24
-
25
- let network: TestNetworkNoAppView
26
- let ctx: AppContext
27
-
28
- let agent: AtpAgent
29
- let sc: SeedClient
30
- let alice: DidString
31
- let bob: DidString
32
- let carol: DidString
33
- let dan: DidString
34
-
35
- beforeAll(async () => {
36
- network = await TestNetworkNoAppView.create({
37
- dbPostgresSchema: 'repo_subscribe_repos',
38
- pds: {
39
- repoBackfillLimitMs: HOUR,
40
- },
41
- })
42
- serverHost = network.pds.url.replace('http://', '')
43
- // @ts-expect-error Error due to circular dependency with the dev-env package
44
- ctx = network.pds.ctx
45
- agent = network.pds.getAgent()
46
- sc = network.getSeedClient()
47
- await basicSeed(sc)
48
- alice = sc.dids.alice
49
- bob = sc.dids.bob
50
- carol = sc.dids.carol
51
- dan = sc.dids.dan
52
- })
53
-
54
- afterAll(async () => {
55
- await network?.close()
56
- })
57
-
58
- const getRepo = async (did: string): Promise<repo.VerifiedRepo> => {
59
- const carRes = await agent.api.com.atproto.sync.getRepo({ did })
60
- const car = await repo.readCarWithRoot(carRes.data)
61
- const signingKey = await network.pds.ctx.actorStore.keypair(did)
62
- return repo.verifyRepo(car.blocks, car.root, did, signingKey.did())
63
- }
64
-
65
- const getAllEvents = (userDid: string, frames: Frame[]) => {
66
- const types: unknown[] = []
67
- for (const frame of frames) {
68
- if (frame instanceof MessageFrame) {
69
- if (
70
- (frame.header.t === '#commit' &&
71
- (frame.body as com.atproto.sync.subscribeRepos.Commit).repo ===
72
- userDid) ||
73
- (frame.header.t === '#sync' &&
74
- (frame.body as com.atproto.sync.subscribeRepos.Sync).did ===
75
- userDid) ||
76
- (frame.header.t === '#identity' &&
77
- (frame.body as com.atproto.sync.subscribeRepos.Identity).did ===
78
- userDid) ||
79
- (frame.header.t === '#account' &&
80
- (frame.body as com.atproto.sync.subscribeRepos.Account).did ===
81
- userDid)
82
- ) {
83
- types.push(frame.body)
84
- }
85
- }
86
- }
87
- return types
88
- }
89
-
90
- const getEventType = <T>(frames: Frame[], type: string): T[] => {
91
- const evts: T[] = []
92
- for (const frame of frames) {
93
- if (frame instanceof MessageFrame && frame.header.t === type) {
94
- evts.push(frame.body)
95
- }
96
- }
97
- return evts
98
- }
99
-
100
- const getSyncEvts = (
101
- frames: Frame[],
102
- ): com.atproto.sync.subscribeRepos.Sync[] => {
103
- return getEventType(frames, '#sync')
104
- }
105
-
106
- const getAccountEvts = (
107
- frames: Frame[],
108
- ): com.atproto.sync.subscribeRepos.Account[] => {
109
- return getEventType(frames, '#account')
110
- }
111
-
112
- const getIdentityEvts = (
113
- frames: Frame[],
114
- ): com.atproto.sync.subscribeRepos.Identity[] => {
115
- return getEventType(frames, '#identity')
116
- }
117
-
118
- const getCommitEvents = (
119
- frames: Frame[],
120
- ): com.atproto.sync.subscribeRepos.Commit[] => {
121
- return getEventType(frames, '#commit')
122
- }
123
-
124
- const verifyIdentityEvent = (
125
- evt: com.atproto.sync.subscribeRepos.Identity,
126
- did: string,
127
- handle?: string,
128
- ) => {
129
- expect(typeof evt.seq).toBe('number')
130
- expect(evt.did).toBe(did)
131
- expect(typeof evt.time).toBe('string')
132
- expect(evt.handle).toEqual(handle)
133
- }
134
-
135
- const verifyAccountEvent = (
136
- evt: com.atproto.sync.subscribeRepos.Account,
137
- did: string,
138
- active: boolean,
139
- status?: AccountStatus,
140
- ) => {
141
- expect(typeof evt.seq).toBe('number')
142
- expect(evt.did).toBe(did)
143
- expect(typeof evt.time).toBe('string')
144
- expect(evt.active).toBe(active)
145
- expect(evt.status).toBe(status)
146
- }
147
-
148
- const verifySyncEvent = async (
149
- evt: com.atproto.sync.subscribeRepos.Sync,
150
- did: string,
151
- commit: Cid,
152
- rev: string,
153
- ) => {
154
- expect(typeof evt.seq).toBe('number')
155
- expect(evt.did).toBe(did)
156
- expect(typeof evt.time).toBe('string')
157
- expect(evt.rev).toBe(rev)
158
- const car = await repo.readCarWithRoot(evt.blocks)
159
- expect(car.root.equals(commit)).toBe(true)
160
- expect(car.blocks.size).toBe(1)
161
- expect(car.blocks.has(car.root)).toBe(true)
162
- }
163
-
164
- const verifyCommitEvents = async (frames: Frame[]) => {
165
- const forUser =
166
- (user: string) => (commit: com.atproto.sync.subscribeRepos.Commit) =>
167
- commit.repo === user
168
- const commits = getCommitEvents(frames)
169
- await verifyRepo(alice, commits.filter(forUser(alice)))
170
- await verifyRepo(bob, commits.filter(forUser(bob)))
171
- await verifyRepo(carol, commits.filter(forUser(carol)))
172
- await verifyRepo(dan, commits.filter(forUser(dan)))
173
- }
174
-
175
- const verifyRepo = async (
176
- did: string,
177
- evts: com.atproto.sync.subscribeRepos.Commit[],
178
- ) => {
179
- const fromRpc = await getRepo(did)
180
- const contents = {} as Record<string, Record<string, Cid>>
181
- const allBlocks = new repo.BlockMap()
182
- for (const evt of evts) {
183
- const car = await readCar(evt.blocks)
184
- allBlocks.addMap(car.blocks)
185
- for (const op of evt.ops) {
186
- const { collection, rkey } = repo.parseDataKey(op.path)
187
- if (op.action === 'delete') {
188
- delete contents[collection][rkey]
189
- } else {
190
- if (op.cid) {
191
- contents[collection] ??= {}
192
- contents[collection][rkey] ??= op.cid
193
- }
194
- }
195
- }
196
- }
197
- for (const write of fromRpc.creates) {
198
- expect(contents[write.collection][write.rkey].equals(write.cid)).toBe(
199
- true,
200
- )
201
- }
202
- const lastCommit = evts.at(-1)?.commit
203
- if (!lastCommit) {
204
- throw new Error('no last commit')
205
- }
206
- const signingKey = await network.pds.ctx.actorStore.keypair(did)
207
- const fromStream = await repo.verifyRepo(
208
- allBlocks,
209
- lastCommit,
210
- did,
211
- signingKey.did(),
212
- )
213
- const fromRpcOps = fromRpc.creates
214
- const fromStreamOps = fromStream.creates
215
- expect(fromStreamOps.length).toEqual(fromRpcOps.length)
216
- for (let i = 0; i < fromRpcOps.length; i++) {
217
- expect(fromStreamOps[i].collection).toEqual(fromRpcOps[i].collection)
218
- expect(fromStreamOps[i].rkey).toEqual(fromRpcOps[i].rkey)
219
- expect(fromStreamOps[i].cid).toEqual(fromRpcOps[i].cid)
220
- }
221
- }
222
-
223
- const randomPost = (by: DidString) => sc.post(by, randomStr(8, 'base32'))
224
- const makePosts = async () => {
225
- for (let i = 0; i < 10; i++) {
226
- await Promise.all([
227
- randomPost(alice),
228
- randomPost(bob),
229
- randomPost(carol),
230
- randomPost(dan),
231
- ])
232
- }
233
- }
234
-
235
- const readTillCaughtUp = async <T>(
236
- gen: AsyncGenerator<T>,
237
- waitFor?: Promise<unknown>,
238
- ) => {
239
- const isDone = async (evt: any) => {
240
- if (evt === undefined) return false
241
- if (evt instanceof ErrorFrame) return true
242
- const curr = await ctx.sequencer.curr()
243
- return evt.body.seq === curr
244
- }
245
-
246
- return readFromGenerator(gen, isDone, waitFor)
247
- }
248
-
249
- it('emits sync event on account creation, matching temporary commit event.', async () => {
250
- const ws = new WebSocket(
251
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
252
- )
253
-
254
- const gen = byFrame(ws)
255
- const evts = await readTillCaughtUp(gen)
256
- ws.terminate()
257
-
258
- const syncEvts = getSyncEvts(evts)
259
- const commitEvts = getCommitEvents(evts).slice(0, 4)
260
- expect(syncEvts.length).toBe(4)
261
-
262
- let i = 0
263
- for (const did of [alice, bob, carol, dan]) {
264
- const syncEvt = syncEvts[i]
265
- const commitEvt = commitEvts[i]
266
- await verifySyncEvent(syncEvt, did, commitEvt.commit, commitEvt.rev)
267
- i++
268
- }
269
- })
270
-
271
- it('sync backfilled events', async () => {
272
- const ws = new WebSocket(
273
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
274
- )
275
-
276
- const gen = byFrame(ws)
277
- const evts = await readTillCaughtUp(gen)
278
- ws.terminate()
279
-
280
- await verifyCommitEvents(evts)
281
-
282
- const accountEvts = getAccountEvts(evts)
283
- expect(accountEvts.length).toBe(4)
284
- verifyAccountEvent(accountEvts[0], alice, true)
285
- verifyAccountEvent(accountEvts[1], bob, true)
286
- verifyAccountEvent(accountEvts[2], carol, true)
287
- verifyAccountEvent(accountEvts[3], dan, true)
288
- const identityEvts = getIdentityEvts(evts)
289
- expect(identityEvts.length).toBe(4)
290
- verifyIdentityEvent(identityEvts[0], alice, 'alice.test')
291
- verifyIdentityEvent(identityEvts[1], bob, 'bob.test')
292
- verifyIdentityEvent(identityEvts[2], carol, 'carol.test')
293
- verifyIdentityEvent(identityEvts[3], dan, 'dan.test')
294
- })
295
-
296
- it('syncs new events', async () => {
297
- const postPromise = makePosts()
298
-
299
- const readAfterDelay = async () => {
300
- await wait(200) // wait just a hair so that we catch it during cutover
301
- const ws = new WebSocket(
302
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
303
- )
304
- const evts = await readTillCaughtUp(byFrame(ws), postPromise)
305
- ws.terminate()
306
- return evts
307
- }
308
-
309
- const [evts] = await Promise.all([readAfterDelay(), postPromise])
310
-
311
- await verifyCommitEvents(evts)
312
- })
313
-
314
- it('handles no backfill', async () => {
315
- const ws = new WebSocket(
316
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos`,
317
- )
318
-
319
- const makePostsAfterWait = async () => {
320
- // give them just a second to get subscriptions set up
321
- await wait(200)
322
- await makePosts()
323
- }
324
-
325
- const postPromise = makePostsAfterWait()
326
-
327
- const [evts] = await Promise.all([
328
- readTillCaughtUp(byFrame(ws), postPromise),
329
- postPromise,
330
- ])
331
-
332
- ws.terminate()
333
-
334
- expect(evts.length).toBe(40)
335
-
336
- await wait(100) // Let cleanup occur on server
337
- expect(ctx.sequencer.listeners('events').length).toEqual(0)
338
- })
339
-
340
- it('backfills only from provided cursor', async () => {
341
- const seqs = await ctx.sequencer.db.db
342
- .selectFrom('repo_seq')
343
- .selectAll()
344
- .orderBy('seq', 'asc')
345
- .execute()
346
- const midPoint = Math.floor(seqs.length / 2)
347
- const midPointSeq = seqs[midPoint].seq
348
-
349
- const ws = new WebSocket(
350
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${midPointSeq}`,
351
- )
352
- const evts = await readTillCaughtUp(byFrame(ws))
353
- ws.terminate()
354
- const seqSlice = seqs.slice(midPoint + 1)
355
- expect(evts.length).toBe(seqSlice.length)
356
- for (let i = 0; i < evts.length; i++) {
357
- const evt = evts[i]
358
- .body as unknown as com.atproto.sync.subscribeRepos.Commit
359
- const seq = seqSlice[i]
360
- const seqEvt = cborDecode(seq.event) as { commit: Cid }
361
- expect(evt.time).toEqual(seq.sequencedAt)
362
- expect(evt.commit.equals(seqEvt.commit)).toBeTruthy()
363
- expect(evt.repo).toEqual(seq.did)
364
- }
365
- })
366
-
367
- it('syncs handle changes (identity evts)', async () => {
368
- await sc.updateHandle(alice, 'alice2.test')
369
- await sc.updateHandle(bob, 'bob2.test')
370
- await sc.updateHandle(bob, 'bob2.test') // idempotent update re-sends
371
-
372
- const ws = new WebSocket(
373
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
374
- )
375
-
376
- const gen = byFrame(ws)
377
- const evts = await readTillCaughtUp(gen)
378
- ws.terminate()
379
-
380
- await verifyCommitEvents(evts)
381
-
382
- const identityEvts = getIdentityEvts(evts.slice(-3))
383
- expect(identityEvts.length).toBe(3)
384
- verifyIdentityEvent(identityEvts[0], alice, 'alice2.test')
385
- verifyIdentityEvent(identityEvts[1], bob, 'bob2.test')
386
- verifyIdentityEvent(identityEvts[2], bob, 'bob2.test')
387
- })
388
-
389
- it('resends identity events on idempotent updates', async () => {
390
- const update = sc.updateHandle(bob, 'bob2.test')
391
-
392
- const ws = new WebSocket(
393
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos`,
394
- )
395
-
396
- const gen = byFrame(ws)
397
- const evts = await readTillCaughtUp(gen, update)
398
- ws.terminate()
399
-
400
- const identityEvts = getIdentityEvts(evts.slice(-1))
401
- verifyIdentityEvent(identityEvts[0], bob, 'bob2.test')
402
- })
403
-
404
- it('syncs account events', async () => {
405
- // deactivate then reactivate alice
406
- await agent.api.com.atproto.server.deactivateAccount(
407
- {},
408
- {
409
- encoding: 'application/json',
410
- headers: sc.getHeaders(alice),
411
- },
412
- )
413
- await agent.api.com.atproto.server.activateAccount(undefined, {
414
- headers: sc.getHeaders(alice),
415
- })
416
-
417
- // takedown then restore bob
418
- await agent.api.com.atproto.admin.updateSubjectStatus(
419
- {
420
- subject: {
421
- $type: 'com.atproto.admin.defs#repoRef',
422
- did: bob,
423
- },
424
- takedown: { applied: true },
425
- },
426
- {
427
- encoding: 'application/json',
428
- headers: network.pds.adminAuthHeaders(),
429
- },
430
- )
431
- await agent.api.com.atproto.admin.updateSubjectStatus(
432
- {
433
- subject: {
434
- $type: 'com.atproto.admin.defs#repoRef',
435
- did: bob,
436
- },
437
- takedown: { applied: false },
438
- },
439
- {
440
- encoding: 'application/json',
441
- headers: network.pds.adminAuthHeaders(),
442
- },
443
- )
444
-
445
- const ws = new WebSocket(
446
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
447
- )
448
-
449
- const gen = byFrame(ws)
450
- const evts = await readTillCaughtUp(gen)
451
- ws.terminate()
452
-
453
- // @NOTE requires a larger slice because of over-emission on activateAccount - see note on route
454
- const accountEvts = getAccountEvts(evts.slice(-6))
455
- expect(accountEvts.length).toBe(4)
456
- verifyAccountEvent(accountEvts[0], alice, false, AccountStatus.Deactivated)
457
- verifyAccountEvent(accountEvts[1], alice, true)
458
- verifyAccountEvent(accountEvts[2], bob, false, AccountStatus.Takendown)
459
- verifyAccountEvent(accountEvts[3], bob, true)
460
- })
461
-
462
- it('syncs interleaved account events', async () => {
463
- // deactivate -> takedown -> restore -> activate
464
- // deactivate then reactivate alice
465
- await agent.api.com.atproto.server.deactivateAccount(
466
- {},
467
- {
468
- encoding: 'application/json',
469
- headers: sc.getHeaders(alice),
470
- },
471
- )
472
- await agent.api.com.atproto.admin.updateSubjectStatus(
473
- {
474
- subject: {
475
- $type: 'com.atproto.admin.defs#repoRef',
476
- did: alice,
477
- },
478
- takedown: { applied: true },
479
- },
480
- {
481
- encoding: 'application/json',
482
- headers: network.pds.adminAuthHeaders(),
483
- },
484
- )
485
- await agent.api.com.atproto.admin.updateSubjectStatus(
486
- {
487
- subject: {
488
- $type: 'com.atproto.admin.defs#repoRef',
489
- did: alice,
490
- },
491
- takedown: { applied: false },
492
- },
493
- {
494
- encoding: 'application/json',
495
- headers: network.pds.adminAuthHeaders(),
496
- },
497
- )
498
- await agent.api.com.atproto.server.activateAccount(undefined, {
499
- headers: sc.getHeaders(alice),
500
- })
501
-
502
- const ws = new WebSocket(
503
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
504
- )
505
-
506
- const gen = byFrame(ws)
507
- const evts = await readTillCaughtUp(gen)
508
- ws.terminate()
509
-
510
- // @NOTE requires a larger slice because of over-emission on activateAccount - see note on route
511
- const accountEvts = getAccountEvts(evts.slice(-6))
512
- expect(accountEvts.length).toBe(4)
513
- verifyAccountEvent(accountEvts[0], alice, false, AccountStatus.Deactivated)
514
- verifyAccountEvent(accountEvts[1], alice, false, AccountStatus.Takendown)
515
- verifyAccountEvent(accountEvts[2], alice, false, AccountStatus.Deactivated)
516
- verifyAccountEvent(accountEvts[3], alice, true)
517
- })
518
-
519
- it('emits sync event on account activation', async () => {
520
- await agent.api.com.atproto.server.deactivateAccount(
521
- {},
522
- {
523
- encoding: 'application/json',
524
- headers: sc.getHeaders(alice),
525
- },
526
- )
527
- await agent.api.com.atproto.server.activateAccount(undefined, {
528
- headers: sc.getHeaders(alice),
529
- })
530
-
531
- const ws = new WebSocket(
532
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
533
- )
534
-
535
- const gen = byFrame(ws)
536
- const evts = await readTillCaughtUp(gen)
537
- ws.terminate()
538
-
539
- const syncEvts = getSyncEvts(evts.slice(-1))
540
- expect(syncEvts.length).toBe(1)
541
- const root = await ctx.actorStore.read(alice, (store) =>
542
- store.repo.storage.getRootDetailed(),
543
- )
544
- await verifySyncEvent(syncEvts[0], alice, root.cid, root.rev)
545
- })
546
-
547
- it('syncs account deletions (account evt)', async () => {
548
- const baddie1 = (
549
- await sc.createAccount('baddie1.test', {
550
- email: 'baddie1@test.com',
551
- handle: 'baddie1.test',
552
- password: 'baddie1-pass',
553
- })
554
- ).did
555
- const baddie2 = (
556
- await sc.createAccount('baddie2.test', {
557
- email: 'baddie2@test.com',
558
- handle: 'baddie2.test',
559
- password: 'baddie2-pass',
560
- })
561
- ).did
562
- const deleteToken = await ctx.accountManager.createEmailToken(
563
- baddie1,
564
- 'delete_account',
565
- )
566
- await agent.api.com.atproto.server.deleteAccount({
567
- did: baddie1,
568
- password: 'baddie1-pass',
569
- token: deleteToken,
570
- })
571
- await agent.api.com.atproto.admin.deleteAccount(
572
- {
573
- did: baddie2,
574
- },
575
- {
576
- encoding: 'application/json',
577
- headers: network.pds.adminAuthHeaders(),
578
- },
579
- )
580
-
581
- const ws = new WebSocket(
582
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
583
- )
584
-
585
- const gen = byFrame(ws)
586
- const evts = await readTillCaughtUp(gen)
587
- ws.terminate()
588
-
589
- const accountEvts = getAccountEvts(evts.slice(-2))
590
- expect(accountEvts.length).toBe(2)
591
- verifyAccountEvent(accountEvts[0], baddie1, false, AccountStatus.Deleted)
592
- verifyAccountEvent(accountEvts[1], baddie2, false, AccountStatus.Deleted)
593
- })
594
-
595
- it('account deletions invalidate all seq ops', async () => {
596
- const baddie3 = (
597
- await sc.createAccount('baddie3', {
598
- email: 'baddie3@test.com',
599
- handle: 'baddie3.test',
600
- password: 'baddie3-pass',
601
- })
602
- ).did
603
-
604
- await randomPost(baddie3)
605
- await sc.updateHandle(baddie3, 'baddie3-update.test')
606
- const token = await network.pds.ctx.accountManager.createEmailToken(
607
- baddie3,
608
- 'delete_account',
609
- )
610
- await agent.api.com.atproto.server.deleteAccount({
611
- token,
612
- did: baddie3,
613
- password: sc.accounts[baddie3].password,
614
- })
615
-
616
- const ws = new WebSocket(
617
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
618
- )
619
-
620
- const gen = byFrame(ws)
621
- const evts = await readTillCaughtUp(gen)
622
- ws.terminate()
623
-
624
- const didEvts = getAllEvents(baddie3, evts)
625
- expect(didEvts.length).toBe(1)
626
- verifyAccountEvent(
627
- didEvts[0] as com.atproto.sync.subscribeRepos.Account,
628
- baddie3,
629
- false,
630
- AccountStatus.Deleted,
631
- )
632
- })
633
-
634
- it('sends info frame on out of date cursor', async () => {
635
- // we rewrite the sequenceAt time for existing seqs to be past the backfill cutoff
636
- // then we create some new posts
637
- const overAnHourAgo = new Date(Date.now() - HOUR - MINUTE).toISOString()
638
- await ctx.sequencer.db.db
639
- .updateTable('repo_seq')
640
- .set({ sequencedAt: overAnHourAgo })
641
- .execute()
642
-
643
- await makePosts()
644
-
645
- const ws = new WebSocket(
646
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
647
- )
648
- const [info, ...evts] = await readTillCaughtUp(byFrame(ws))
649
- ws.terminate()
650
-
651
- if (!(info instanceof MessageFrame)) {
652
- throw new Error('Expected first frame to be a MessageFrame')
653
- }
654
- expect(info.header.t).toBe('#info')
655
- const body = info.body as Record<string, unknown>
656
- expect(body.name).toEqual('OutdatedCursor')
657
- expect(evts.length).toBe(40)
658
- })
659
-
660
- it('errors on future cursor', async () => {
661
- const ws = new WebSocket(
662
- `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${100000}`,
663
- )
664
- const frames = await readTillCaughtUp(byFrame(ws))
665
- ws.terminate()
666
- expect(frames.length).toBe(1)
667
- if (!(frames[0] instanceof ErrorFrame)) {
668
- throw new Error('Expected ErrorFrame')
669
- }
670
- expect(frames[0].body.error).toBe('FutureCursor')
671
- })
672
- })