@atproto/pds 0.4.27 → 0.4.29

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/account-manager/helpers/account.d.ts +7 -0
  3. package/dist/account-manager/helpers/account.d.ts.map +1 -1
  4. package/dist/account-manager/helpers/account.js +9 -1
  5. package/dist/account-manager/helpers/account.js.map +1 -1
  6. package/dist/account-manager/index.d.ts +3 -1
  7. package/dist/account-manager/index.d.ts.map +1 -1
  8. package/dist/account-manager/index.js +22 -6
  9. package/dist/account-manager/index.js.map +1 -1
  10. package/dist/api/com/atproto/admin/deleteAccount.d.ts.map +1 -1
  11. package/dist/api/com/atproto/admin/deleteAccount.js +4 -2
  12. package/dist/api/com/atproto/admin/deleteAccount.js.map +1 -1
  13. package/dist/api/com/atproto/admin/updateAccountHandle.js +1 -1
  14. package/dist/api/com/atproto/admin/updateAccountHandle.js.map +1 -1
  15. package/dist/api/com/atproto/admin/updateSubjectStatus.d.ts.map +1 -1
  16. package/dist/api/com/atproto/admin/updateSubjectStatus.js +2 -0
  17. package/dist/api/com/atproto/admin/updateSubjectStatus.js.map +1 -1
  18. package/dist/api/com/atproto/identity/submitPlcOperation.d.ts.map +1 -1
  19. package/dist/api/com/atproto/identity/submitPlcOperation.js.map +1 -1
  20. package/dist/api/com/atproto/identity/updateHandle.js +1 -1
  21. package/dist/api/com/atproto/identity/updateHandle.js.map +1 -1
  22. package/dist/api/com/atproto/repo/describeRepo.d.ts.map +1 -1
  23. package/dist/api/com/atproto/repo/describeRepo.js +2 -4
  24. package/dist/api/com/atproto/repo/describeRepo.js.map +1 -1
  25. package/dist/api/com/atproto/server/activateAccount.d.ts.map +1 -1
  26. package/dist/api/com/atproto/server/activateAccount.js +2 -1
  27. package/dist/api/com/atproto/server/activateAccount.js.map +1 -1
  28. package/dist/api/com/atproto/server/createAccount.d.ts.map +1 -1
  29. package/dist/api/com/atproto/server/createAccount.js +4 -2
  30. package/dist/api/com/atproto/server/createAccount.js.map +1 -1
  31. package/dist/api/com/atproto/server/deactivateAccount.d.ts.map +1 -1
  32. package/dist/api/com/atproto/server/deactivateAccount.js +2 -0
  33. package/dist/api/com/atproto/server/deactivateAccount.js.map +1 -1
  34. package/dist/api/com/atproto/server/deleteAccount.d.ts.map +1 -1
  35. package/dist/api/com/atproto/server/deleteAccount.js +4 -3
  36. package/dist/api/com/atproto/server/deleteAccount.js.map +1 -1
  37. package/dist/api/com/atproto/server/util.d.ts +1 -0
  38. package/dist/api/com/atproto/server/util.d.ts.map +1 -1
  39. package/dist/api/com/atproto/server/util.js +9 -6
  40. package/dist/api/com/atproto/server/util.js.map +1 -1
  41. package/dist/api/com/atproto/sync/deprecated/getCheckout.d.ts.map +1 -1
  42. package/dist/api/com/atproto/sync/deprecated/getCheckout.js +2 -8
  43. package/dist/api/com/atproto/sync/deprecated/getCheckout.js.map +1 -1
  44. package/dist/api/com/atproto/sync/deprecated/getHead.d.ts.map +1 -1
  45. package/dist/api/com/atproto/sync/deprecated/getHead.js +2 -7
  46. package/dist/api/com/atproto/sync/deprecated/getHead.js.map +1 -1
  47. package/dist/api/com/atproto/sync/getBlob.d.ts.map +1 -1
  48. package/dist/api/com/atproto/sync/getBlob.js +3 -6
  49. package/dist/api/com/atproto/sync/getBlob.js.map +1 -1
  50. package/dist/api/com/atproto/sync/getBlocks.d.ts.map +1 -1
  51. package/dist/api/com/atproto/sync/getBlocks.js +2 -7
  52. package/dist/api/com/atproto/sync/getBlocks.js.map +1 -1
  53. package/dist/api/com/atproto/sync/getLatestCommit.d.ts.map +1 -1
  54. package/dist/api/com/atproto/sync/getLatestCommit.js +2 -7
  55. package/dist/api/com/atproto/sync/getLatestCommit.js.map +1 -1
  56. package/dist/api/com/atproto/sync/getRecord.d.ts.map +1 -1
  57. package/dist/api/com/atproto/sync/getRecord.js +2 -7
  58. package/dist/api/com/atproto/sync/getRecord.js.map +1 -1
  59. package/dist/api/com/atproto/sync/getRepo.d.ts.map +1 -1
  60. package/dist/api/com/atproto/sync/getRepo.js +2 -7
  61. package/dist/api/com/atproto/sync/getRepo.js.map +1 -1
  62. package/dist/api/com/atproto/sync/getRepoStatus.d.ts +4 -0
  63. package/dist/api/com/atproto/sync/getRepoStatus.d.ts.map +1 -0
  64. package/dist/api/com/atproto/sync/getRepoStatus.js +28 -0
  65. package/dist/api/com/atproto/sync/getRepoStatus.js.map +1 -0
  66. package/dist/api/com/atproto/sync/index.d.ts.map +1 -1
  67. package/dist/api/com/atproto/sync/index.js +2 -0
  68. package/dist/api/com/atproto/sync/index.js.map +1 -1
  69. package/dist/api/com/atproto/sync/listBlobs.d.ts.map +1 -1
  70. package/dist/api/com/atproto/sync/listBlobs.js +2 -8
  71. package/dist/api/com/atproto/sync/listBlobs.js.map +1 -1
  72. package/dist/api/com/atproto/sync/listRepos.d.ts.map +1 -1
  73. package/dist/api/com/atproto/sync/listRepos.js +13 -8
  74. package/dist/api/com/atproto/sync/listRepos.js.map +1 -1
  75. package/dist/api/com/atproto/sync/subscribeRepos.d.ts.map +1 -1
  76. package/dist/api/com/atproto/sync/subscribeRepos.js +8 -0
  77. package/dist/api/com/atproto/sync/subscribeRepos.js.map +1 -1
  78. package/dist/api/com/atproto/sync/util.d.ts +11 -0
  79. package/dist/api/com/atproto/sync/util.d.ts.map +1 -0
  80. package/dist/api/com/atproto/sync/util.js +41 -0
  81. package/dist/api/com/atproto/sync/util.js.map +1 -0
  82. package/dist/index.d.ts +1 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +4 -2
  85. package/dist/index.js.map +1 -1
  86. package/dist/lexicon/index.d.ts +2 -0
  87. package/dist/lexicon/index.d.ts.map +1 -1
  88. package/dist/lexicon/index.js +4 -0
  89. package/dist/lexicon/index.js.map +1 -1
  90. package/dist/lexicon/lexicons.d.ts +105 -0
  91. package/dist/lexicon/lexicons.d.ts.map +1 -1
  92. package/dist/lexicon/lexicons.js +185 -4
  93. package/dist/lexicon/lexicons.js.map +1 -1
  94. package/dist/lexicon/types/chat/bsky/convo/defs.d.ts +1 -1
  95. package/dist/lexicon/types/com/atproto/sync/getBlob.d.ts +1 -0
  96. package/dist/lexicon/types/com/atproto/sync/getBlob.d.ts.map +1 -1
  97. package/dist/lexicon/types/com/atproto/sync/getBlocks.d.ts +1 -0
  98. package/dist/lexicon/types/com/atproto/sync/getBlocks.d.ts.map +1 -1
  99. package/dist/lexicon/types/com/atproto/sync/getLatestCommit.d.ts +1 -1
  100. package/dist/lexicon/types/com/atproto/sync/getLatestCommit.d.ts.map +1 -1
  101. package/dist/lexicon/types/com/atproto/sync/getRecord.d.ts +1 -0
  102. package/dist/lexicon/types/com/atproto/sync/getRecord.d.ts.map +1 -1
  103. package/dist/lexicon/types/com/atproto/sync/getRepo.d.ts +1 -0
  104. package/dist/lexicon/types/com/atproto/sync/getRepo.d.ts.map +1 -1
  105. package/dist/lexicon/types/com/atproto/sync/getRepoStatus.d.ts +42 -0
  106. package/dist/lexicon/types/com/atproto/sync/getRepoStatus.d.ts.map +1 -0
  107. package/dist/lexicon/types/com/atproto/sync/getRepoStatus.js +3 -0
  108. package/dist/lexicon/types/com/atproto/sync/getRepoStatus.js.map +1 -0
  109. package/dist/lexicon/types/com/atproto/sync/listBlobs.d.ts +1 -0
  110. package/dist/lexicon/types/com/atproto/sync/listBlobs.d.ts.map +1 -1
  111. package/dist/lexicon/types/com/atproto/sync/listRepos.d.ts +3 -0
  112. package/dist/lexicon/types/com/atproto/sync/listRepos.d.ts.map +1 -1
  113. package/dist/lexicon/types/com/atproto/sync/listRepos.js.map +1 -1
  114. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.d.ts +19 -4
  115. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.d.ts.map +1 -1
  116. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.js +11 -1
  117. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.js.map +1 -1
  118. package/dist/scripts/index.d.ts +4 -0
  119. package/dist/scripts/index.d.ts.map +1 -0
  120. package/dist/scripts/index.js +8 -0
  121. package/dist/scripts/index.js.map +1 -0
  122. package/dist/scripts/rebuild-repo.d.ts +3 -0
  123. package/dist/scripts/rebuild-repo.d.ts.map +1 -0
  124. package/dist/scripts/rebuild-repo.js +121 -0
  125. package/dist/scripts/rebuild-repo.js.map +1 -0
  126. package/dist/sequencer/db/schema.d.ts +1 -1
  127. package/dist/sequencer/db/schema.d.ts.map +1 -1
  128. package/dist/sequencer/events.d.ts +27 -2
  129. package/dist/sequencer/events.d.ts.map +1 -1
  130. package/dist/sequencer/events.js +35 -2
  131. package/dist/sequencer/events.js.map +1 -1
  132. package/dist/sequencer/sequencer.d.ts +8 -6
  133. package/dist/sequencer/sequencer.d.ts.map +1 -1
  134. package/dist/sequencer/sequencer.js +22 -9
  135. package/dist/sequencer/sequencer.js.map +1 -1
  136. package/package.json +4 -4
  137. package/src/account-manager/helpers/account.ts +8 -0
  138. package/src/account-manager/index.ts +19 -6
  139. package/src/api/com/atproto/admin/deleteAccount.ts +7 -2
  140. package/src/api/com/atproto/admin/updateAccountHandle.ts +1 -1
  141. package/src/api/com/atproto/admin/updateSubjectStatus.ts +2 -0
  142. package/src/api/com/atproto/identity/submitPlcOperation.ts +1 -0
  143. package/src/api/com/atproto/identity/updateHandle.ts +1 -1
  144. package/src/api/com/atproto/repo/describeRepo.ts +2 -4
  145. package/src/api/com/atproto/server/activateAccount.ts +2 -1
  146. package/src/api/com/atproto/server/createAccount.ts +6 -3
  147. package/src/api/com/atproto/server/deactivateAccount.ts +2 -0
  148. package/src/api/com/atproto/server/deleteAccount.ts +7 -3
  149. package/src/api/com/atproto/server/util.ts +12 -5
  150. package/src/api/com/atproto/sync/deprecated/getCheckout.ts +6 -8
  151. package/src/api/com/atproto/sync/deprecated/getHead.ts +7 -10
  152. package/src/api/com/atproto/sync/getBlob.ts +8 -6
  153. package/src/api/com/atproto/sync/getBlocks.ts +6 -7
  154. package/src/api/com/atproto/sync/getLatestCommit.ts +7 -10
  155. package/src/api/com/atproto/sync/getRecord.ts +7 -7
  156. package/src/api/com/atproto/sync/getRepo.ts +6 -7
  157. package/src/api/com/atproto/sync/getRepoStatus.ts +31 -0
  158. package/src/api/com/atproto/sync/index.ts +2 -0
  159. package/src/api/com/atproto/sync/listBlobs.ts +6 -8
  160. package/src/api/com/atproto/sync/listRepos.ts +13 -8
  161. package/src/api/com/atproto/sync/subscribeRepos.ts +7 -0
  162. package/src/api/com/atproto/sync/util.ts +59 -0
  163. package/src/index.ts +3 -2
  164. package/src/lexicon/index.ts +12 -0
  165. package/src/lexicon/lexicons.ts +193 -7
  166. package/src/lexicon/types/chat/bsky/convo/defs.ts +1 -1
  167. package/src/lexicon/types/com/atproto/sync/getBlob.ts +6 -0
  168. package/src/lexicon/types/com/atproto/sync/getBlocks.ts +6 -0
  169. package/src/lexicon/types/com/atproto/sync/getLatestCommit.ts +1 -1
  170. package/src/lexicon/types/com/atproto/sync/getRecord.ts +6 -0
  171. package/src/lexicon/types/com/atproto/sync/getRepo.ts +1 -0
  172. package/src/lexicon/types/com/atproto/sync/getRepoStatus.ts +52 -0
  173. package/src/lexicon/types/com/atproto/sync/listBlobs.ts +1 -0
  174. package/src/lexicon/types/com/atproto/sync/listRepos.ts +3 -0
  175. package/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +30 -3
  176. package/src/scripts/index.ts +5 -0
  177. package/src/scripts/rebuild-repo.ts +143 -0
  178. package/src/sequencer/db/schema.ts +1 -0
  179. package/src/sequencer/events.ts +47 -0
  180. package/src/sequencer/sequencer.ts +35 -14
  181. package/tests/account-deactivation.test.ts +36 -10
  182. package/tests/account-deletion.test.ts +10 -2
  183. package/tests/moderation.test.ts +2 -2
  184. package/tests/proxied/notif.test.ts +1 -0
  185. package/tests/sequencer.test.ts +2 -2
  186. package/tests/sync/list.test.ts +1 -0
  187. package/tests/sync/subscribe-repos.test.ts +224 -40
  188. package/tests/sync/sync.test.ts +48 -4
@@ -16,10 +16,13 @@ import {
16
16
  Commit as CommitEvt,
17
17
  Handle as HandleEvt,
18
18
  Tombstone as TombstoneEvt,
19
+ Account as AccountEvt,
20
+ Identity as IdentityEvt,
19
21
  } from '../../src/lexicon/types/com/atproto/sync/subscribeRepos'
20
22
  import { AppContext } from '../../src'
21
23
  import basicSeed from '../seeds/basic'
22
24
  import { CID } from 'multiformats/cid'
25
+ import { AccountStatus } from '../../src/account-manager'
23
26
 
24
27
  describe('repo subscribe repos', () => {
25
28
  let serverHost: string
@@ -64,16 +67,6 @@ describe('repo subscribe repos', () => {
64
67
  return repo.verifyRepo(car.blocks, car.root, did, signingKey.did())
65
68
  }
66
69
 
67
- const getHandleEvts = (frames: Frame[]): HandleEvt[] => {
68
- const evts: HandleEvt[] = []
69
- for (const frame of frames) {
70
- if (frame instanceof MessageFrame && frame.header.t === '#handle') {
71
- evts.push(frame.body)
72
- }
73
- }
74
- return evts
75
- }
76
-
77
70
  const getAllEvents = (userDid: string, frames: Frame[]) => {
78
71
  const types: unknown[] = []
79
72
  for (const frame of frames) {
@@ -93,21 +86,65 @@ describe('repo subscribe repos', () => {
93
86
  return types
94
87
  }
95
88
 
96
- const getTombstoneEvts = (frames: Frame[]): TombstoneEvt[] => {
97
- const evts: TombstoneEvt[] = []
89
+ const getEventType = <T>(frames: Frame[], type: string): T[] => {
90
+ const evts: T[] = []
98
91
  for (const frame of frames) {
99
- if (frame instanceof MessageFrame && frame.header.t === '#tombstone') {
92
+ if (frame instanceof MessageFrame && frame.header.t === type) {
100
93
  evts.push(frame.body)
101
94
  }
102
95
  }
103
96
  return evts
104
97
  }
105
98
 
106
- const verifyHandleEvent = (evt: unknown, did: string, handle: string) => {
107
- expect(evt?.['did']).toBe(did)
108
- expect(evt?.['handle']).toBe(handle)
109
- expect(typeof evt?.['time']).toBe('string')
110
- expect(typeof evt?.['seq']).toBe('number')
99
+ const getAccountEvts = (frames: Frame[]): AccountEvt[] => {
100
+ return getEventType(frames, '#account')
101
+ }
102
+
103
+ const getIdentityEvts = (frames: Frame[]): IdentityEvt[] => {
104
+ return getEventType(frames, '#identity')
105
+ }
106
+
107
+ const getHandleEvts = (frames: Frame[]): HandleEvt[] => {
108
+ return getEventType(frames, '#handle')
109
+ }
110
+
111
+ const getTombstoneEvts = (frames: Frame[]): TombstoneEvt[] => {
112
+ return getEventType(frames, '#tombstone')
113
+ }
114
+
115
+ const getCommitEvents = (frames: Frame[]): CommitEvt[] => {
116
+ return getEventType(frames, '#commit')
117
+ }
118
+
119
+ const verifyIdentityEvent = (
120
+ evt: IdentityEvt,
121
+ did: string,
122
+ handle?: string,
123
+ ) => {
124
+ expect(typeof evt.seq).toBe('number')
125
+ expect(evt.did).toBe(did)
126
+ expect(typeof evt.time).toBe('string')
127
+ expect(evt.handle).toEqual(handle)
128
+ }
129
+
130
+ const verifyHandleEvent = (evt: HandleEvt, did: string, handle: string) => {
131
+ expect(typeof evt.seq).toBe('number')
132
+ expect(evt.did).toBe(did)
133
+ expect(evt.handle).toBe(handle)
134
+ expect(typeof evt.time).toBe('string')
135
+ }
136
+
137
+ const verifyAccountEvent = (
138
+ evt: AccountEvt,
139
+ did: string,
140
+ active: boolean,
141
+ status?: AccountStatus,
142
+ ) => {
143
+ expect(typeof evt.seq).toBe('number')
144
+ expect(evt.did).toBe(did)
145
+ expect(typeof evt.time).toBe('string')
146
+ expect(evt.active).toBe(active)
147
+ expect(evt.status).toBe(status)
111
148
  }
112
149
 
113
150
  const verifyTombstoneEvent = (evt: unknown, did: string) => {
@@ -116,24 +153,14 @@ describe('repo subscribe repos', () => {
116
153
  expect(typeof evt?.['seq']).toBe('number')
117
154
  }
118
155
 
119
- const getCommitEvents = (userDid: string, frames: Frame[]) => {
120
- const evts: CommitEvt[] = []
121
- for (const frame of frames) {
122
- if (frame instanceof MessageFrame && frame.header.t === '#commit') {
123
- const body = frame.body as CommitEvt
124
- if (body.repo === userDid) {
125
- evts.push(frame.body)
126
- }
127
- }
128
- }
129
- return evts
130
- }
131
-
132
156
  const verifyCommitEvents = async (frames: Frame[]) => {
133
- await verifyRepo(alice, getCommitEvents(alice, frames))
134
- await verifyRepo(bob, getCommitEvents(bob, frames))
135
- await verifyRepo(carol, getCommitEvents(carol, frames))
136
- await verifyRepo(dan, getCommitEvents(dan, frames))
157
+ const forUser = (user: string) => (commit: CommitEvt) =>
158
+ commit.repo === user
159
+ const commits = getCommitEvents(frames)
160
+ await verifyRepo(alice, commits.filter(forUser(alice)))
161
+ await verifyRepo(bob, commits.filter(forUser(bob)))
162
+ await verifyRepo(carol, commits.filter(forUser(carol)))
163
+ await verifyRepo(dan, commits.filter(forUser(dan)))
137
164
  }
138
165
 
139
166
  const verifyRepo = async (did: string, evts: CommitEvt[]) => {
@@ -217,6 +244,19 @@ describe('repo subscribe repos', () => {
217
244
  ws.terminate()
218
245
 
219
246
  await verifyCommitEvents(evts)
247
+
248
+ const accountEvts = getAccountEvts(evts)
249
+ expect(accountEvts.length).toBe(4)
250
+ verifyAccountEvent(accountEvts[0], alice, true)
251
+ verifyAccountEvent(accountEvts[1], bob, true)
252
+ verifyAccountEvent(accountEvts[2], carol, true)
253
+ verifyAccountEvent(accountEvts[3], dan, true)
254
+ const identityEvts = getIdentityEvts(evts)
255
+ expect(identityEvts.length).toBe(4)
256
+ verifyIdentityEvent(identityEvts[0], alice, 'alice.test')
257
+ verifyIdentityEvent(identityEvts[1], bob, 'bob.test')
258
+ verifyIdentityEvent(identityEvts[2], carol, 'carol.test')
259
+ verifyIdentityEvent(identityEvts[3], dan, 'dan.test')
220
260
  })
221
261
 
222
262
  it('syncs new events', async () => {
@@ -303,9 +343,18 @@ describe('repo subscribe repos', () => {
303
343
  ws.terminate()
304
344
 
305
345
  await verifyCommitEvents(evts)
346
+
306
347
  const handleEvts = getHandleEvts(evts.slice(-6))
348
+ expect(handleEvts.length).toBe(3)
307
349
  verifyHandleEvent(handleEvts[0], alice, 'alice2.test')
308
350
  verifyHandleEvent(handleEvts[1], bob, 'bob2.test')
351
+ verifyHandleEvent(handleEvts[2], bob, 'bob2.test')
352
+
353
+ const identityEvts = getIdentityEvts(evts.slice(-6))
354
+ expect(identityEvts.length).toBe(3)
355
+ verifyIdentityEvent(identityEvts[0], alice, 'alice2.test')
356
+ verifyIdentityEvent(identityEvts[1], bob, 'bob2.test')
357
+ verifyIdentityEvent(identityEvts[2], bob, 'bob2.test')
309
358
  })
310
359
 
311
360
  it('resends handle events on idempotent updates', async () => {
@@ -323,6 +372,121 @@ describe('repo subscribe repos', () => {
323
372
  verifyHandleEvent(handleEvts[0], bob, 'bob2.test')
324
373
  })
325
374
 
375
+ it('syncs account events', async () => {
376
+ // deactivate then reactivate alice
377
+ await agent.api.com.atproto.server.deactivateAccount(
378
+ {},
379
+ {
380
+ encoding: 'application/json',
381
+ headers: sc.getHeaders(alice),
382
+ },
383
+ )
384
+ await agent.api.com.atproto.server.activateAccount(undefined, {
385
+ headers: sc.getHeaders(alice),
386
+ })
387
+
388
+ // takedown then restore bob
389
+ await agent.api.com.atproto.admin.updateSubjectStatus(
390
+ {
391
+ subject: {
392
+ $type: 'com.atproto.admin.defs#repoRef',
393
+ did: bob,
394
+ },
395
+ takedown: { applied: true },
396
+ },
397
+ {
398
+ encoding: 'application/json',
399
+ headers: network.pds.adminAuthHeaders(),
400
+ },
401
+ )
402
+ await agent.api.com.atproto.admin.updateSubjectStatus(
403
+ {
404
+ subject: {
405
+ $type: 'com.atproto.admin.defs#repoRef',
406
+ did: bob,
407
+ },
408
+ takedown: { applied: false },
409
+ },
410
+ {
411
+ encoding: 'application/json',
412
+ headers: network.pds.adminAuthHeaders(),
413
+ },
414
+ )
415
+
416
+ const ws = new WebSocket(
417
+ `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
418
+ )
419
+
420
+ const gen = byFrame(ws)
421
+ const evts = await readTillCaughtUp(gen)
422
+ ws.terminate()
423
+
424
+ // @NOTE requires a larger slice because of over-emission on activateAccount - see note on route
425
+ const accountEvts = getAccountEvts(evts.slice(-6))
426
+ expect(accountEvts.length).toBe(4)
427
+ verifyAccountEvent(accountEvts[0], alice, false, AccountStatus.Deactivated)
428
+ verifyAccountEvent(accountEvts[1], alice, true)
429
+ verifyAccountEvent(accountEvts[2], bob, false, AccountStatus.Takendown)
430
+ verifyAccountEvent(accountEvts[3], bob, true)
431
+ })
432
+
433
+ it('syncs interleaved account events', async () => {
434
+ // deactivate -> takedown -> restore -> activate
435
+ // deactivate then reactivate alice
436
+ await agent.api.com.atproto.server.deactivateAccount(
437
+ {},
438
+ {
439
+ encoding: 'application/json',
440
+ headers: sc.getHeaders(alice),
441
+ },
442
+ )
443
+ await agent.api.com.atproto.admin.updateSubjectStatus(
444
+ {
445
+ subject: {
446
+ $type: 'com.atproto.admin.defs#repoRef',
447
+ did: alice,
448
+ },
449
+ takedown: { applied: true },
450
+ },
451
+ {
452
+ encoding: 'application/json',
453
+ headers: network.pds.adminAuthHeaders(),
454
+ },
455
+ )
456
+ await agent.api.com.atproto.admin.updateSubjectStatus(
457
+ {
458
+ subject: {
459
+ $type: 'com.atproto.admin.defs#repoRef',
460
+ did: alice,
461
+ },
462
+ takedown: { applied: false },
463
+ },
464
+ {
465
+ encoding: 'application/json',
466
+ headers: network.pds.adminAuthHeaders(),
467
+ },
468
+ )
469
+ await agent.api.com.atproto.server.activateAccount(undefined, {
470
+ headers: sc.getHeaders(alice),
471
+ })
472
+
473
+ const ws = new WebSocket(
474
+ `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
475
+ )
476
+
477
+ const gen = byFrame(ws)
478
+ const evts = await readTillCaughtUp(gen)
479
+ ws.terminate()
480
+
481
+ // @NOTE requires a larger slice because of over-emission on activateAccount - see note on route
482
+ const accountEvts = getAccountEvts(evts.slice(-6))
483
+ expect(accountEvts.length).toBe(4)
484
+ verifyAccountEvent(accountEvts[0], alice, false, AccountStatus.Deactivated)
485
+ verifyAccountEvent(accountEvts[1], alice, false, AccountStatus.Takendown)
486
+ verifyAccountEvent(accountEvts[2], alice, false, AccountStatus.Deactivated)
487
+ verifyAccountEvent(accountEvts[3], alice, true)
488
+ })
489
+
326
490
  it('syncs tombstones', async () => {
327
491
  const baddie1 = (
328
492
  await sc.createAccount('baddie1.test', {
@@ -338,10 +502,24 @@ describe('repo subscribe repos', () => {
338
502
  password: 'baddie2-pass',
339
503
  })
340
504
  ).did
341
-
342
- for (const did of [baddie1, baddie2]) {
343
- await ctx.sequencer.sequenceTombstone(did)
344
- }
505
+ const deleteToken = await ctx.accountManager.createEmailToken(
506
+ baddie1,
507
+ 'delete_account',
508
+ )
509
+ await agent.api.com.atproto.server.deleteAccount({
510
+ did: baddie1,
511
+ password: 'baddie1-pass',
512
+ token: deleteToken,
513
+ })
514
+ await agent.api.com.atproto.admin.deleteAccount(
515
+ {
516
+ did: baddie2,
517
+ },
518
+ {
519
+ encoding: 'application/json',
520
+ headers: network.pds.adminAuthHeaders(),
521
+ },
522
+ )
345
523
 
346
524
  const ws = new WebSocket(
347
525
  `ws://${serverHost}/xrpc/com.atproto.sync.subscribeRepos?cursor=${-1}`,
@@ -351,9 +529,15 @@ describe('repo subscribe repos', () => {
351
529
  const evts = await readTillCaughtUp(gen)
352
530
  ws.terminate()
353
531
 
354
- const tombstoneEvts = getTombstoneEvts(evts.slice(-2))
532
+ const tombstoneEvts = getTombstoneEvts(evts.slice(-4))
533
+ expect(tombstoneEvts.length).toBe(2)
355
534
  verifyTombstoneEvent(tombstoneEvts[0], baddie1)
356
535
  verifyTombstoneEvent(tombstoneEvts[1], baddie2)
536
+
537
+ const accountEvts = getAccountEvts(evts.slice(-4))
538
+ expect(accountEvts.length).toBe(2)
539
+ verifyAccountEvent(accountEvts[0], baddie1, false, AccountStatus.Deleted)
540
+ verifyAccountEvent(accountEvts[1], baddie2, false, AccountStatus.Deleted)
357
541
  })
358
542
 
359
543
  it('account deletions invalidate all seq ops', async () => {
@@ -18,6 +18,7 @@ describe('repo sync', () => {
18
18
  const uris: AtUri[] = []
19
19
  const storage = new MemoryBlockstore()
20
20
  let currRoot: CID | undefined
21
+ let currRev: string | undefined
21
22
 
22
23
  beforeAll(async () => {
23
24
  network = await TestNetworkNoAppView.create({
@@ -64,6 +65,7 @@ describe('repo sync', () => {
64
65
  expect(contents).toEqual(repoData)
65
66
 
66
67
  currRoot = car.root
68
+ currRev = loaded.commit.rev
67
69
  })
68
70
 
69
71
  it('syncs creates and deletes', async () => {
@@ -101,6 +103,16 @@ describe('repo sync', () => {
101
103
  expect(contents).toEqual(repoData)
102
104
 
103
105
  currRoot = car.root
106
+ currRev = loaded.commit.rev
107
+ })
108
+
109
+ it('syncs repo status', async () => {
110
+ const status = await agent.api.com.atproto.sync.getRepoStatus({ did })
111
+ expect(status.data).toEqual({
112
+ did,
113
+ active: true,
114
+ rev: currRev,
115
+ })
104
116
  })
105
117
 
106
118
  it('syncs latest repo commit', async () => {
@@ -211,15 +223,47 @@ describe('repo sync', () => {
211
223
  )
212
224
  })
213
225
 
226
+ afterAll(async () => {
227
+ await agent.api.com.atproto.admin.updateSubjectStatus(
228
+ {
229
+ subject: {
230
+ $type: 'com.atproto.admin.defs#repoRef',
231
+ did,
232
+ },
233
+ takedown: { applied: false },
234
+ },
235
+ {
236
+ encoding: 'application/json',
237
+ headers: network.pds.adminAuthHeaders(),
238
+ },
239
+ )
240
+ })
241
+
242
+ it('returns takendown status', async () => {
243
+ const res = await agent.api.com.atproto.sync.getRepoStatus({ did })
244
+ expect(res.data).toEqual({
245
+ did,
246
+ active: false,
247
+ status: 'takendown',
248
+ })
249
+ })
250
+
251
+ it('lists as takendown in listRepos', async () => {
252
+ const res = await agent.api.com.atproto.sync.listRepos()
253
+ const found = res.data.repos.find((r) => r.did === did)
254
+ expect(found?.active).toBe(false)
255
+ expect(found?.status).toBe('takendown')
256
+ })
257
+
214
258
  it('does not sync repo unauthed', async () => {
215
259
  const tryGetRepo = agent.api.com.atproto.sync.getRepo({ did })
216
- await expect(tryGetRepo).rejects.toThrow(/Could not find repo for DID/)
260
+ await expect(tryGetRepo).rejects.toThrow(/Repo has been takendown/)
217
261
  })
218
262
 
219
263
  it('syncs repo to owner or admin', async () => {
220
264
  const tryGetRepoOwner = agent.api.com.atproto.sync.getRepo(
221
265
  { did },
222
- { headers: { authorization: `Bearer ${sc.accounts[did].accessJwt}` } },
266
+ { headers: sc.getHeaders(did) },
223
267
  )
224
268
  await expect(tryGetRepoOwner).resolves.toBeDefined()
225
269
  const tryGetRepoAdmin = agent.api.com.atproto.sync.getRepo(
@@ -231,7 +275,7 @@ describe('repo sync', () => {
231
275
 
232
276
  it('does not sync latest commit unauthed', async () => {
233
277
  const tryGetLatest = agent.api.com.atproto.sync.getLatestCommit({ did })
234
- await expect(tryGetLatest).rejects.toThrow(/Could not find root for DID/)
278
+ await expect(tryGetLatest).rejects.toThrow(/Repo has been takendown/)
235
279
  })
236
280
 
237
281
  it('does not sync a record proof unauthed', async () => {
@@ -242,7 +286,7 @@ describe('repo sync', () => {
242
286
  collection,
243
287
  rkey,
244
288
  })
245
- await expect(tryGetRecord).rejects.toThrow(/Could not find repo for DID/)
289
+ await expect(tryGetRecord).rejects.toThrow(/Repo has been takendown/)
246
290
  })
247
291
  })
248
292
  })