@atproto/pds 0.4.104 → 0.4.105

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 (206) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/account-manager/{index.d.ts → account-manager.d.ts} +26 -35
  3. package/dist/account-manager/account-manager.d.ts.map +1 -0
  4. package/dist/account-manager/{index.js → account-manager.js} +52 -207
  5. package/dist/account-manager/account-manager.js.map +1 -0
  6. package/dist/account-manager/helpers/account.d.ts +3 -3
  7. package/dist/account-manager/helpers/device-account.d.ts +15 -15
  8. package/dist/account-manager/helpers/device-account.d.ts.map +1 -1
  9. package/dist/account-manager/helpers/device-account.js +2 -1
  10. package/dist/account-manager/helpers/device-account.js.map +1 -1
  11. package/dist/account-manager/helpers/token.d.ts +98 -98
  12. package/dist/account-manager/oauth-store.d.ts +58 -0
  13. package/dist/account-manager/oauth-store.d.ts.map +1 -0
  14. package/dist/account-manager/oauth-store.js +417 -0
  15. package/dist/account-manager/oauth-store.js.map +1 -0
  16. package/dist/actor-store/record/reader.d.ts +3 -3
  17. package/dist/actor-store/repo/reader.d.ts +2 -0
  18. package/dist/actor-store/repo/reader.d.ts.map +1 -1
  19. package/dist/actor-store/repo/reader.js +9 -0
  20. package/dist/actor-store/repo/reader.js.map +1 -1
  21. package/dist/actor-store/repo/sql-repo-reader.d.ts +1 -1
  22. package/dist/actor-store/repo/transactor.d.ts.map +1 -1
  23. package/dist/actor-store/repo/transactor.js +13 -4
  24. package/dist/actor-store/repo/transactor.js.map +1 -1
  25. package/dist/api/com/atproto/admin/deleteAccount.d.ts.map +1 -1
  26. package/dist/api/com/atproto/admin/deleteAccount.js +2 -3
  27. package/dist/api/com/atproto/admin/deleteAccount.js.map +1 -1
  28. package/dist/api/com/atproto/admin/updateAccountHandle.d.ts.map +1 -1
  29. package/dist/api/com/atproto/admin/updateAccountHandle.js +2 -6
  30. package/dist/api/com/atproto/admin/updateAccountHandle.js.map +1 -1
  31. package/dist/api/com/atproto/identity/resolveHandle.d.ts.map +1 -1
  32. package/dist/api/com/atproto/identity/resolveHandle.js +2 -36
  33. package/dist/api/com/atproto/identity/resolveHandle.js.map +1 -1
  34. package/dist/api/com/atproto/identity/updateHandle.d.ts.map +1 -1
  35. package/dist/api/com/atproto/identity/updateHandle.js +1 -7
  36. package/dist/api/com/atproto/identity/updateHandle.js.map +1 -1
  37. package/dist/api/com/atproto/server/activateAccount.d.ts.map +1 -1
  38. package/dist/api/com/atproto/server/activateAccount.js +2 -18
  39. package/dist/api/com/atproto/server/activateAccount.js.map +1 -1
  40. package/dist/api/com/atproto/server/createAccount.d.ts.map +1 -1
  41. package/dist/api/com/atproto/server/createAccount.js +5 -7
  42. package/dist/api/com/atproto/server/createAccount.js.map +1 -1
  43. package/dist/api/com/atproto/server/createSession.js +1 -1
  44. package/dist/api/com/atproto/server/createSession.js.map +1 -1
  45. package/dist/api/com/atproto/server/deleteAccount.d.ts.map +1 -1
  46. package/dist/api/com/atproto/server/deleteAccount.js +2 -3
  47. package/dist/api/com/atproto/server/deleteAccount.js.map +1 -1
  48. package/dist/api/com/atproto/server/getSession.js +1 -1
  49. package/dist/api/com/atproto/server/getSession.js.map +1 -1
  50. package/dist/api/com/atproto/server/refreshSession.js +1 -1
  51. package/dist/api/com/atproto/server/refreshSession.js.map +1 -1
  52. package/dist/api/com/atproto/sync/getRecord.d.ts.map +1 -1
  53. package/dist/api/com/atproto/sync/getRecord.js.map +1 -1
  54. package/dist/api/com/atproto/sync/getRepoStatus.js +1 -1
  55. package/dist/api/com/atproto/sync/getRepoStatus.js.map +1 -1
  56. package/dist/api/com/atproto/sync/listRepos.js +1 -1
  57. package/dist/api/com/atproto/sync/listRepos.js.map +1 -1
  58. package/dist/api/com/atproto/sync/subscribeRepos.d.ts.map +1 -1
  59. package/dist/api/com/atproto/sync/subscribeRepos.js +2 -10
  60. package/dist/api/com/atproto/sync/subscribeRepos.js.map +1 -1
  61. package/dist/app-view.d.ts +14 -0
  62. package/dist/app-view.d.ts.map +1 -0
  63. package/dist/app-view.js +36 -0
  64. package/dist/app-view.js.map +1 -0
  65. package/dist/auth-routes.d.ts +1 -1
  66. package/dist/auth-routes.d.ts.map +1 -1
  67. package/dist/auth-routes.js +9 -3
  68. package/dist/auth-routes.js.map +1 -1
  69. package/dist/auth-verifier.d.ts +1 -1
  70. package/dist/auth-verifier.d.ts.map +1 -1
  71. package/dist/config/config.d.ts +3 -2
  72. package/dist/config/config.d.ts.map +1 -1
  73. package/dist/config/config.js +17 -7
  74. package/dist/config/config.js.map +1 -1
  75. package/dist/config/env.d.ts +4 -0
  76. package/dist/config/env.d.ts.map +1 -1
  77. package/dist/config/env.js +5 -0
  78. package/dist/config/env.js.map +1 -1
  79. package/dist/context.d.ts +4 -4
  80. package/dist/context.d.ts.map +1 -1
  81. package/dist/context.js +24 -18
  82. package/dist/context.js.map +1 -1
  83. package/dist/handle/index.d.ts +0 -7
  84. package/dist/handle/index.d.ts.map +1 -1
  85. package/dist/handle/index.js +4 -58
  86. package/dist/handle/index.js.map +1 -1
  87. package/dist/image/image-url.d.ts +8 -0
  88. package/dist/image/image-url.d.ts.map +1 -0
  89. package/dist/image/image-url.js +26 -0
  90. package/dist/image/image-url.js.map +1 -0
  91. package/dist/lexicon/index.d.ts +6 -0
  92. package/dist/lexicon/index.d.ts.map +1 -1
  93. package/dist/lexicon/index.js +12 -0
  94. package/dist/lexicon/index.js.map +1 -1
  95. package/dist/lexicon/lexicons.d.ts +304 -130
  96. package/dist/lexicon/lexicons.d.ts.map +1 -1
  97. package/dist/lexicon/lexicons.js +168 -67
  98. package/dist/lexicon/lexicons.js.map +1 -1
  99. package/dist/lexicon/types/app/bsky/embed/video.d.ts +1 -0
  100. package/dist/lexicon/types/app/bsky/embed/video.d.ts.map +1 -1
  101. package/dist/lexicon/types/app/bsky/embed/video.js.map +1 -1
  102. package/dist/lexicon/types/com/atproto/identity/defs.d.ts +17 -0
  103. package/dist/lexicon/types/com/atproto/identity/defs.d.ts.map +1 -0
  104. package/dist/lexicon/types/com/atproto/identity/defs.js +16 -0
  105. package/dist/lexicon/types/com/atproto/identity/defs.js.map +1 -0
  106. package/dist/lexicon/types/com/atproto/identity/refreshIdentity.d.ts +39 -0
  107. package/dist/lexicon/types/com/atproto/identity/refreshIdentity.d.ts.map +1 -0
  108. package/dist/lexicon/types/com/atproto/identity/refreshIdentity.js +7 -0
  109. package/dist/lexicon/types/com/atproto/identity/refreshIdentity.js.map +1 -0
  110. package/dist/lexicon/types/com/atproto/identity/resolveDid.d.ts +40 -0
  111. package/dist/lexicon/types/com/atproto/identity/resolveDid.d.ts.map +1 -0
  112. package/dist/lexicon/types/com/atproto/identity/resolveDid.js +7 -0
  113. package/dist/lexicon/types/com/atproto/identity/resolveDid.js.map +1 -0
  114. package/dist/lexicon/types/com/atproto/identity/resolveHandle.d.ts +1 -0
  115. package/dist/lexicon/types/com/atproto/identity/resolveHandle.d.ts.map +1 -1
  116. package/dist/lexicon/types/com/atproto/identity/resolveIdentity.d.ts +36 -0
  117. package/dist/lexicon/types/com/atproto/identity/resolveIdentity.d.ts.map +1 -0
  118. package/dist/lexicon/types/com/atproto/identity/resolveIdentity.js +7 -0
  119. package/dist/lexicon/types/com/atproto/identity/resolveIdentity.js.map +1 -0
  120. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.d.ts +1 -30
  121. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.d.ts.map +1 -1
  122. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.js +0 -27
  123. package/dist/lexicon/types/com/atproto/sync/subscribeRepos.js.map +1 -1
  124. package/dist/mailer/index.d.ts +5 -5
  125. package/dist/mailer/index.d.ts.map +1 -1
  126. package/dist/mailer/index.js +6 -5
  127. package/dist/mailer/index.js.map +1 -1
  128. package/dist/read-after-write/viewer.d.ts +1 -1
  129. package/dist/read-after-write/viewer.d.ts.map +1 -1
  130. package/dist/repo/types.d.ts +6 -2
  131. package/dist/repo/types.d.ts.map +1 -1
  132. package/dist/repo/types.js.map +1 -1
  133. package/dist/scripts/rebuild-repo.d.ts.map +1 -1
  134. package/dist/scripts/rebuild-repo.js +2 -1
  135. package/dist/scripts/rebuild-repo.js.map +1 -1
  136. package/dist/sequencer/db/schema.d.ts +1 -1
  137. package/dist/sequencer/db/schema.d.ts.map +1 -1
  138. package/dist/sequencer/events.d.ts +29 -41
  139. package/dist/sequencer/events.d.ts.map +1 -1
  140. package/dist/sequencer/events.js +24 -58
  141. package/dist/sequencer/events.js.map +1 -1
  142. package/dist/sequencer/sequencer.d.ts +2 -3
  143. package/dist/sequencer/sequencer.d.ts.map +1 -1
  144. package/dist/sequencer/sequencer.js +5 -17
  145. package/dist/sequencer/sequencer.js.map +1 -1
  146. package/package.json +15 -15
  147. package/src/account-manager/{index.ts → account-manager.ts} +107 -307
  148. package/src/account-manager/helpers/device-account.ts +1 -0
  149. package/src/account-manager/oauth-store.ts +494 -0
  150. package/src/actor-store/repo/reader.ts +11 -0
  151. package/src/actor-store/repo/transactor.ts +15 -4
  152. package/src/api/com/atproto/admin/deleteAccount.ts +2 -3
  153. package/src/api/com/atproto/admin/updateAccountHandle.ts +7 -8
  154. package/src/api/com/atproto/identity/resolveHandle.ts +2 -11
  155. package/src/api/com/atproto/identity/updateHandle.ts +4 -7
  156. package/src/api/com/atproto/server/activateAccount.ts +4 -18
  157. package/src/api/com/atproto/server/createAccount.ts +10 -11
  158. package/src/api/com/atproto/server/createSession.ts +1 -1
  159. package/src/api/com/atproto/server/deleteAccount.ts +2 -3
  160. package/src/api/com/atproto/server/getSession.ts +1 -1
  161. package/src/api/com/atproto/server/refreshSession.ts +1 -1
  162. package/src/api/com/atproto/sync/getRecord.ts +0 -1
  163. package/src/api/com/atproto/sync/getRepoStatus.ts +1 -1
  164. package/src/api/com/atproto/sync/listRepos.ts +1 -1
  165. package/src/api/com/atproto/sync/subscribeRepos.ts +2 -9
  166. package/src/app-view.ts +24 -0
  167. package/src/auth-routes.ts +9 -3
  168. package/src/auth-verifier.ts +1 -1
  169. package/src/config/config.ts +25 -13
  170. package/src/config/env.ts +12 -0
  171. package/src/context.ts +44 -24
  172. package/src/handle/index.ts +6 -52
  173. package/src/image/image-url.ts +16 -0
  174. package/src/lexicon/index.ts +36 -0
  175. package/src/lexicon/lexicons.ts +183 -67
  176. package/src/lexicon/types/app/bsky/embed/video.ts +1 -0
  177. package/src/lexicon/types/com/atproto/identity/defs.ts +30 -0
  178. package/src/lexicon/types/com/atproto/identity/refreshIdentity.ts +52 -0
  179. package/src/lexicon/types/com/atproto/identity/resolveDid.ts +52 -0
  180. package/src/lexicon/types/com/atproto/identity/resolveHandle.ts +1 -0
  181. package/src/lexicon/types/com/atproto/identity/resolveIdentity.ts +48 -0
  182. package/src/lexicon/types/com/atproto/sync/subscribeRepos.ts +0 -59
  183. package/src/mailer/index.ts +7 -5
  184. package/src/read-after-write/viewer.ts +1 -1
  185. package/src/repo/types.ts +7 -2
  186. package/src/scripts/rebuild-repo.ts +4 -1
  187. package/src/sequencer/db/schema.ts +1 -8
  188. package/src/sequencer/events.ts +29 -75
  189. package/src/sequencer/sequencer.ts +9 -23
  190. package/tests/account-deletion.test.ts +3 -5
  191. package/tests/oauth.test.ts +286 -71
  192. package/tests/sequencer.test.ts +18 -27
  193. package/tests/sync/subscribe-repos.test.ts +67 -45
  194. package/tsconfig.build.tsbuildinfo +1 -1
  195. package/dist/account-manager/index.d.ts.map +0 -1
  196. package/dist/account-manager/index.js.map +0 -1
  197. package/dist/actor-store/repo/util.d.ts +0 -5
  198. package/dist/actor-store/repo/util.d.ts.map +0 -1
  199. package/dist/actor-store/repo/util.js +0 -25
  200. package/dist/actor-store/repo/util.js.map +0 -1
  201. package/dist/oauth/provider.d.ts +0 -10
  202. package/dist/oauth/provider.d.ts.map +0 -1
  203. package/dist/oauth/provider.js +0 -38
  204. package/dist/oauth/provider.js.map +0 -1
  205. package/src/actor-store/repo/util.ts +0 -22
  206. package/src/oauth/provider.ts +0 -59
@@ -1,33 +1,99 @@
1
1
  import assert from 'node:assert'
2
2
  import { once } from 'node:events'
3
- import { Server, createServer } from 'node:http'
3
+ import {
4
+ IncomingMessage,
5
+ Server,
6
+ ServerResponse,
7
+ createServer,
8
+ } from 'node:http'
4
9
  import { AddressInfo } from 'node:net'
5
- import { Browser, Page, launch } from 'puppeteer'
10
+ import { type Browser, type Page, launch } from 'puppeteer'
6
11
  import { TestNetworkNoAppView } from '@atproto/dev-env'
7
12
  // @ts-expect-error (json file)
8
13
  import files from '@atproto/oauth-client-browser-example'
9
14
 
10
- const getVisibleElement = async (page: Page, selector: string) => {
11
- const elementHandle = await page.waitForSelector(selector)
15
+ class PageHelper implements AsyncDisposable {
16
+ constructor(protected readonly page: Page) {}
12
17
 
13
- expect(elementHandle).not.toBeNull()
14
- assert(elementHandle)
18
+ async goto(url: string) {
19
+ await this.page.goto(url)
20
+ }
15
21
 
16
- await expect(elementHandle.isVisible()).resolves.toBe(true)
22
+ async waitForNetworkIdle() {
23
+ await this.page.waitForNetworkIdle()
24
+ }
17
25
 
18
- return elementHandle
26
+ async navigationAction(run: () => Promise<unknown>): Promise<void> {
27
+ const promise = this.page.waitForNavigation()
28
+ await run()
29
+ await promise
30
+ await this.waitForNetworkIdle()
31
+ }
32
+
33
+ async checkTitle(expected: string) {
34
+ await this.waitForNetworkIdle()
35
+ await expect(this.page.title()).resolves.toBe(expected)
36
+ }
37
+
38
+ async clickOn(selector: string) {
39
+ const elementHandle = await this.getVisibleElement(selector)
40
+ await elementHandle.click()
41
+ return elementHandle
42
+ }
43
+
44
+ async clickOnButton(text: string) {
45
+ return this.clickOn(`button::-p-text(${text})`)
46
+ }
47
+
48
+ async typeIn(selector: string, text: string) {
49
+ const elementHandle = await this.getVisibleElement(selector)
50
+ elementHandle.focus()
51
+ await elementHandle.type(text)
52
+ return elementHandle
53
+ }
54
+
55
+ async typeInInput(name: string, text: string) {
56
+ return this.typeIn(`input[name="${name}"]`, text)
57
+ }
58
+
59
+ async ensureTextVisibility(text: string, tag = 'p') {
60
+ await this.page.waitForSelector(`${tag}::-p-text(${text})`)
61
+ }
62
+
63
+ protected async getVisibleElement(selector: string) {
64
+ const elementHandle = await this.page.waitForSelector(selector)
65
+
66
+ expect(elementHandle).not.toBeNull()
67
+ assert(elementHandle)
68
+
69
+ await expect(elementHandle.isVisible()).resolves.toBe(true)
70
+
71
+ return elementHandle
72
+ }
73
+
74
+ async [Symbol.asyncDispose]() {
75
+ return this.page.close()
76
+ }
77
+
78
+ static async from(browser: Browser) {
79
+ const page = await browser.newPage()
80
+ return new PageHelper(page)
81
+ }
19
82
  }
20
83
 
21
84
  describe('oauth', () => {
22
85
  let browser: Browser
23
86
  let network: TestNetworkNoAppView
24
- let server: Server
87
+ let client: Server
25
88
 
26
89
  let appUrl: string
27
90
 
28
91
  beforeAll(async () => {
29
92
  browser = await launch({
30
93
  browser: 'chrome',
94
+ // @NOTE We are using another language than "en" as default language to
95
+ // test the language negotiation.
96
+ args: ['--accept-lang=fr-BE,en-GB,en'],
31
97
 
32
98
  // For debugging:
33
99
  // headless: false,
@@ -47,106 +113,255 @@ describe('oauth', () => {
47
113
  password: 'alice-pass',
48
114
  })
49
115
 
50
- server = await createClientServer()
116
+ client = createServer(clientHandler)
117
+ client.listen(0)
118
+ await once(client, 'listening')
51
119
 
52
- const { port } = server.address() as AddressInfo
120
+ const { port } = client.address() as AddressInfo
53
121
 
54
122
  appUrl = `http://127.0.0.1:${port}?${new URLSearchParams({
55
123
  plc_directory_url: network.plc.url,
56
124
  handle_resolver: network.pds.url,
125
+ sign_up_url: network.pds.url,
57
126
  env: 'test',
58
127
  })}`
59
128
  })
60
129
 
61
130
  afterAll(async () => {
62
- await server?.close()
131
+ await client?.close()
63
132
  await network?.close()
64
133
  await browser?.close()
65
134
  })
66
135
 
67
- it('starts', async () => {
68
- const page = await browser.newPage()
136
+ it('Allows to sign-up trough OAuth', async () => {
137
+ const page = await PageHelper.from(browser)
69
138
 
70
139
  await page.goto(appUrl)
71
140
 
72
- await expect(page.title()).resolves.toBe('OAuth Client Example')
141
+ await page.checkTitle('OAuth Client Example')
73
142
 
74
- const handleInput = await getVisibleElement(
75
- page,
76
- 'input[placeholder="@handle, DID or PDS url"]',
77
- )
143
+ await page.navigationAction(async () => {
144
+ await page.clickOnButton('Sign up')
145
+ })
78
146
 
79
- await handleInput.focus()
147
+ await page.checkTitle('Authentification')
80
148
 
81
- await handleInput.type('alice.test')
149
+ await page.clickOnButton('Créer un nouveau compte')
82
150
 
83
- await Promise.all([
84
- //
85
- handleInput.press('Enter'),
86
- page.waitForNavigation(),
87
- ])
151
+ await page.typeInInput('handle', 'bob')
88
152
 
89
- await expect(page.title()).resolves.toBe('Authorize')
153
+ await page.clickOnButton('Suivant')
90
154
 
91
- const passwordInput = await getVisibleElement(
92
- page,
93
- 'input[type="password"]',
94
- )
155
+ await page.typeInInput('email', 'bob@test.com')
156
+ await page.typeInInput('password', 'bob-pass')
95
157
 
96
- await passwordInput.focus()
158
+ await page.clickOnButton("S'inscrire")
97
159
 
98
- // Make sure the warning is visible
99
- await getVisibleElement(page, 'p::-p-text(Warning)')
160
+ // Make sure the new account is propagated to the PLC directory, allowing
161
+ // the client to resolve the account's did
162
+ await network.processAll()
100
163
 
101
- await passwordInput.type('alice-pass')
164
+ await page.navigationAction(async () => {
165
+ await page.clickOnButton("Authoriser l'accès")
166
+ })
102
167
 
103
- const rememberCheckbox = await getVisibleElement(
104
- page,
105
- 'label::-p-text(Remember this account on this device)',
106
- )
168
+ await page.checkTitle('OAuth Client Example')
169
+
170
+ await page.ensureTextVisibility('Logged in!')
171
+
172
+ await page.clickOnButton('Sign-out')
173
+
174
+ await page.waitForNetworkIdle()
175
+
176
+ // TODO: Find out why we can't use "using" here
177
+ await page[Symbol.asyncDispose]()
178
+ })
179
+
180
+ it('allows resetting the password', async () => {
181
+ const sendTemplateMock = await withMokedMailer(network)
182
+
183
+ const page = await PageHelper.from(browser)
184
+
185
+ await page.goto(appUrl)
186
+
187
+ await page.checkTitle('OAuth Client Example')
188
+
189
+ await page.navigationAction(async () => {
190
+ const input = await page.typeIn(
191
+ 'input[placeholder="@handle, DID or PDS url"]',
192
+ 'alice.test',
193
+ )
194
+
195
+ await input.press('Enter')
196
+ })
197
+
198
+ await page.checkTitle('Se connecter')
199
+
200
+ await page.clickOnButton('Oublié ?')
201
+
202
+ await page.checkTitle('Mot de passe oublié')
203
+
204
+ await page.typeInInput('email', 'alice@test.com')
205
+
206
+ expect(sendTemplateMock).toHaveBeenCalledTimes(0)
207
+
208
+ await page.clickOnButton('Suivant')
209
+
210
+ await page.checkTitle('Réinitialiser le mot de passe')
211
+
212
+ expect(sendTemplateMock).toHaveBeenCalledTimes(1)
213
+
214
+ const [templateName, params] = sendTemplateMock.mock.calls[0]
215
+
216
+ expect(templateName).toBe('resetPassword')
217
+ expect(params).toEqual({
218
+ handle: 'alice.test',
219
+ token: expect.any(String),
220
+ })
221
+
222
+ const { token } = params as { token: string }
223
+
224
+ await page.typeInInput('code', token)
225
+
226
+ await page.typeInInput('password', 'alice-new-pass')
227
+
228
+ await page.clickOnButton('Suivant')
229
+
230
+ await page.checkTitle('Mot de passe mis à jour')
231
+
232
+ await page.ensureTextVisibility('Mot de passe mis à jour !', 'h2')
233
+
234
+ // TODO: Find out why we can't use "using" here
235
+ await page[Symbol.asyncDispose]()
236
+
237
+ // TODO: Find out why we can't use "using" here
238
+ sendTemplateMock[Symbol.dispose]()
239
+ })
107
240
 
108
- await rememberCheckbox.click()
241
+ it('Allows to sign-in trough OAuth', async () => {
242
+ const page = await PageHelper.from(browser)
109
243
 
110
- const nextButton = await getVisibleElement(page, 'button::-p-text(Next)')
244
+ await page.goto(appUrl)
245
+
246
+ await page.checkTitle('OAuth Client Example')
247
+
248
+ await page.navigationAction(async () => {
249
+ const input = await page.typeIn(
250
+ 'input[placeholder="@handle, DID or PDS url"]',
251
+ 'alice.test',
252
+ )
253
+
254
+ await input.press('Enter')
255
+ })
256
+
257
+ await page.checkTitle('Se connecter')
111
258
 
112
- await nextButton.click()
259
+ await page.typeIn('input[type="password"]', 'alice-new-pass')
113
260
 
114
- const acceptButton = await getVisibleElement(
115
- page,
116
- 'button::-p-text(Accept)',
261
+ // Make sure the warning is visible
262
+ await page.ensureTextVisibility('Avertissement')
263
+
264
+ await page.clickOn(
265
+ 'label::-p-text(Se souvenir de ce compte sur cet appareil)',
117
266
  )
118
267
 
119
- await Promise.all([
120
- //
121
- acceptButton.click(),
122
- page.waitForNavigation(),
123
- ])
268
+ await page.clickOnButton('Se connecter')
269
+
270
+ await page.checkTitle("Authoriser l'accès")
271
+
272
+ await page.navigationAction(async () => {
273
+ await page.clickOnButton("Authoriser l'accès")
274
+ })
275
+
276
+ await page.checkTitle('OAuth Client Example')
277
+
278
+ await page.ensureTextVisibility('Logged in!')
124
279
 
125
- await expect(page.title()).resolves.toBe('OAuth Client Example')
280
+ await page.clickOnButton('Sign-out')
126
281
 
127
- // Check that the "Logged in!" message is visible
128
- await getVisibleElement(page, 'p::-p-text(Logged in!)')
282
+ await page.waitForNetworkIdle()
283
+
284
+ // TODO: Find out why we can't use "using" here
285
+ await page[Symbol.asyncDispose]()
129
286
  })
130
- })
131
287
 
132
- async function createClientServer() {
133
- const server = createServer((req, res) => {
134
- const path = req.url?.split('?')[0].slice(1) || 'index.html'
135
- const file = Object.hasOwn(files, path) ? files[path] : null
136
-
137
- if (file) {
138
- res
139
- .writeHead(200, 'OK', { 'content-type': file.type })
140
- .end(Buffer.from(file.data, 'base64'))
141
- } else {
142
- res
143
- .writeHead(404, 'Not Found', { 'content-type': 'text/plain' })
144
- .end('Page not found')
145
- }
288
+ it('remembers the session', async () => {
289
+ const page = await PageHelper.from(browser)
290
+
291
+ await page.goto(appUrl)
292
+
293
+ await page.checkTitle('OAuth Client Example')
294
+
295
+ await page.navigationAction(async () => {
296
+ const input = await page.typeIn(
297
+ 'input[placeholder="@handle, DID or PDS url"]',
298
+ 'alice.test',
299
+ )
300
+
301
+ await input.press('Enter')
302
+ })
303
+
304
+ await page.checkTitle("Authoriser l'accès")
305
+
306
+ await page.navigationAction(async () => {
307
+ await page.clickOnButton("Authoriser l'accès")
308
+ })
309
+
310
+ await page.checkTitle('OAuth Client Example')
311
+
312
+ await page.ensureTextVisibility('Logged in!')
313
+
314
+ await page.clickOnButton('Sign-out')
315
+
316
+ await page.waitForNetworkIdle()
317
+
318
+ // TODO: Find out why we can't use "using" here
319
+ await page[Symbol.asyncDispose]()
146
320
  })
321
+ })
147
322
 
148
- server.listen(0)
149
- await once(server, 'listening')
323
+ async function withMokedMailer(network: TestNetworkNoAppView) {
324
+ // @ts-expect-error
325
+ const sendTemplateOrig = network.pds.ctx.mailer.sendTemplate
326
+ const sendTemplateMock = jest.fn(
327
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
328
+ async (templateName: unknown, params: unknown, mailOpts: unknown) => {
329
+ //
330
+ },
331
+ ) as jest.Mock<
332
+ Promise<void>,
333
+ [templateName: unknown, params: unknown, mailOpts: unknown]
334
+ > &
335
+ Disposable
336
+
337
+ sendTemplateMock[Symbol.dispose] = () => {
338
+ // @ts-expect-error
339
+ network.pds.ctx.mailer.sendTemplate = sendTemplateOrig
340
+ }
341
+
342
+ // @ts-expect-error
343
+ network.pds.ctx.mailer.sendTemplate = sendTemplateMock
344
+
345
+ return sendTemplateMock
346
+ }
150
347
 
151
- return server
348
+ function clientHandler(
349
+ req: IncomingMessage,
350
+ res: ServerResponse,
351
+ next?: (err?: unknown) => void,
352
+ ): void {
353
+ const path = req.url?.split('?')[0].slice(1) || 'index.html'
354
+ const file = Object.hasOwn(files, path) ? files[path] : null
355
+
356
+ if (file) {
357
+ res
358
+ .writeHead(200, 'OK', { 'content-type': file.type })
359
+ .end(Buffer.from(file.data, 'base64'))
360
+ } else if (next) {
361
+ next()
362
+ } else {
363
+ res
364
+ .writeHead(404, 'Not Found', { 'content-type': 'text/plain' })
365
+ .end('Page not found')
366
+ }
152
367
  }
@@ -7,9 +7,8 @@ import {
7
7
  import { randomStr } from '@atproto/crypto'
8
8
  import { SeedClient, TestNetworkNoAppView } from '@atproto/dev-env'
9
9
  import { readCarWithRoot } from '@atproto/repo'
10
- import { repoPrepare, sequencer } from '../../pds'
11
- import { ids } from '../src/lexicon/lexicons'
12
- import { SeqEvt, Sequencer, formatSeqCommit } from '../src/sequencer'
10
+ import { sequencer } from '../../pds'
11
+ import { SeqEvt, Sequencer, formatSeqSyncEvt } from '../src/sequencer'
13
12
  import { Outbox } from '../src/sequencer/outbox'
14
13
  import userSeed from './seeds/users'
15
14
 
@@ -220,35 +219,27 @@ describe('sequencer', () => {
220
219
  lastSeen = results[0].at(-1)?.seq ?? lastSeen
221
220
  })
222
221
 
223
- it('root block must be returned in tooBig seq commit', async () => {
224
- // Create good records to exceed the event limit (the current limit is 200 events)
225
- // it creates events completely locally, so it doesn't need to be in the network
226
- const eventsToCreate = 250
227
- const createPostRecord = () =>
228
- repoPrepare.prepareCreate({
229
- did: sc.dids.alice,
230
- collection: ids.AppBskyFeedPost,
231
- record: { text: 'valid', createdAt: new Date().toISOString() },
232
- })
233
- const writesPromises = Array.from(
234
- { length: eventsToCreate },
235
- createPostRecord,
236
- )
237
- const writes = await Promise.all(writesPromises)
238
- // just format commit without processing writes
239
- const writeCommit = await network.pds.ctx.actorStore.transact(
222
+ it('root block must be returned in sync event', async () => {
223
+ const syncData = await network.pds.ctx.actorStore.read(
240
224
  sc.dids.alice,
241
- (store) => store.repo.formatCommit(writes),
225
+ async (store) => {
226
+ const root = await store.repo.storage.getRootDetailed()
227
+ const { blocks } = await store.repo.storage.getBlocks([root.cid])
228
+ return {
229
+ cid: root.cid,
230
+ rev: root.rev,
231
+ blocks,
232
+ }
233
+ },
242
234
  )
243
235
 
244
- const repoSeqInsert = await formatSeqCommit(sc.dids.alice, writeCommit)
245
-
246
- const evt = cborDecode<sequencer.CommitEvt>(repoSeqInsert.event)
247
- expect(evt.tooBig).toBe(true)
248
-
236
+ const dbEvt = await formatSeqSyncEvt(sc.dids.alice, syncData)
237
+ const evt = cborDecode<sequencer.SyncEvt>(dbEvt.event)
238
+ expect(evt.did).toBe(sc.dids.alice)
249
239
  const car = await readCarWithRoot(evt.blocks)
250
- expect(car.root.toString()).toBe(writeCommit.cid.toString())
240
+ expect(car.root.toString()).toBe(syncData.cid.toString())
251
241
  // in the case of tooBig, the blocks must contain the root block only
252
242
  expect(car.blocks.size).toBe(1)
243
+ expect(car.blocks.has(syncData.cid)).toBeTruthy()
253
244
  })
254
245
  })