@atproto/lex-password-session 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @atproto/lex-password-session
2
2
 
3
+ ## 0.0.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Fix `exports` field in package.json
8
+
9
+ - [#4601](https://github.com/bluesky-social/atproto/pull/4601) [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add JSDoc
10
+
11
+ - Updated dependencies [[`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015), [`ed61c62`](https://github.com/bluesky-social/atproto/commit/ed61c62f3161fcde85ee9a93f8ed339c7e06c015)]:
12
+ - @atproto/lex-schema@0.0.12
13
+ - @atproto/lex-client@0.0.12
14
+
15
+ ## 0.0.4
16
+
17
+ ### Patch Changes
18
+
19
+ - [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add `PasswordSession.createAccount` static method
20
+
21
+ - [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Rename `PasswordSession.create` to `PasswordSession.login`
22
+
23
+ - [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Make all `PasswordSessionOptions` optional
24
+
25
+ - Updated dependencies [[`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a), [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a), [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a)]:
26
+ - @atproto/lex-client@0.0.11
27
+ - @atproto/lex-schema@0.0.11
28
+
3
29
  ## 0.0.3
4
30
 
5
31
  ### Patch Changes
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
- # @atproto/lex-password-agent
1
+ # @atproto/lex-password-session
2
2
 
3
- Password-based client authentication for AT Protocol Lexicons. See the [Changelog](./CHANGELOG.md) for version history.
3
+ Password-based session authentication for AT Protocol Lexicons. See the [Changelog](./CHANGELOG.md) for version history.
4
4
 
5
5
  ```bash
6
- npm install @atproto/lex-password-agent
6
+ npm install @atproto/lex-password-session
7
7
  ```
8
8
 
9
9
  - Session management with automatic token refresh
@@ -17,7 +17,7 @@ npm install @atproto/lex-password-agent
17
17
 
18
18
  **What is this?**
19
19
 
20
- `@atproto/lex-password-agent` provides a `PasswordAgent` class that implements the `Agent` interface from `@atproto/lex-client`. It handles password-based authentication with AT Protocol services, including:
20
+ `@atproto/lex-password-session` provides a `PasswordSession` class that implements the `Agent` interface from `@atproto/lex-client`. It handles password-based authentication with AT Protocol services, including:
21
21
 
22
22
  1. Creating sessions with username/password credentials
23
23
  2. Automatic token refresh when access tokens expire
@@ -26,28 +26,23 @@ npm install @atproto/lex-password-agent
26
26
 
27
27
  ```typescript
28
28
  import { Client } from '@atproto/lex-client'
29
- import { PasswordAgent } from '@atproto/lex-password-agent'
29
+ import { PasswordSession } from '@atproto/lex-password-session'
30
30
  import * as app from './lexicons/app.js'
31
31
 
32
32
  // Login with credentials
33
- const result = await PasswordAgent.login({
33
+ const session = await PasswordSession.login({
34
34
  service: 'https://bsky.social',
35
35
  identifier: 'alice.bsky.social',
36
36
  password: 'app-password',
37
- hooks: {
38
- onRefreshed: (session) => saveToStorage(session),
39
- onDeleted: (session) => clearStorage(session),
40
- },
37
+ onUpdated: (data) => saveToStorage(data),
38
+ onDeleted: (data) => clearStorage(data.did),
41
39
  })
42
40
 
43
- if (!result.success) throw result.error
44
-
45
- const agent = result.value
46
- const client = new Client(agent)
41
+ const client = new Client(session)
47
42
 
48
43
  // Make authenticated requests
49
44
  const profile = await client.call(app.bsky.actor.getProfile, {
50
- actor: agent.did,
45
+ actor: session.did,
51
46
  })
52
47
  ```
53
48
 
@@ -55,18 +50,19 @@ const profile = await client.call(app.bsky.actor.getProfile, {
55
50
  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
56
51
 
57
52
  - [Quick Start](#quick-start)
58
- - [PasswordAgent](#passwordagent)
53
+ - [PasswordSession](#passwordsession)
59
54
  - [Login](#login)
60
55
  - [Two-Factor Authentication](#two-factor-authentication)
61
56
  - [Resume Session](#resume-session)
62
57
  - [Logout](#logout)
63
58
  - [Static Delete](#static-delete)
59
+ - [Create Account](#create-account)
64
60
  - [Session Hooks](#session-hooks)
65
- - [onRefreshed](#onrefreshed)
66
- - [onRefreshFailure](#onrefreshfailure)
61
+ - [onUpdated](#onupdated)
62
+ - [onUpdateFailure](#onupdatefailure)
67
63
  - [onDeleted](#ondeleted)
68
64
  - [onDeleteFailure](#ondeletefailure)
69
- - [Session Object](#session-object)
65
+ - [Session Data](#session-data)
70
66
  - [Error Handling](#error-handling)
71
67
  - [Using with Client](#using-with-client)
72
68
  - [License](#license)
@@ -78,91 +74,92 @@ const profile = await client.call(app.bsky.actor.getProfile, {
78
74
  **1. Install the package**
79
75
 
80
76
  ```bash
81
- npm install @atproto/lex-password-agent @atproto/lex-client
77
+ npm install @atproto/lex-password-session @atproto/lex-client
82
78
  ```
83
79
 
84
80
  **2. Login and make requests**
85
81
 
86
82
  ```typescript
87
83
  import { Client } from '@atproto/lex-client'
88
- import { PasswordAgent } from '@atproto/lex-password-agent'
84
+ import { PasswordSession } from '@atproto/lex-password-session'
89
85
 
90
- const result = await PasswordAgent.login({
86
+ const session = await PasswordSession.login({
91
87
  service: 'https://bsky.social',
92
88
  identifier: 'your-handle.bsky.social',
93
89
  password: 'your-app-password',
94
90
  })
95
91
 
96
- if (result.success) {
97
- const agent = result.value
98
- const client = new Client(agent)
92
+ const client = new Client(session)
99
93
 
100
- // Make authenticated API calls
101
- console.log('Logged in as:', agent.did)
102
- }
94
+ // Make authenticated API calls
95
+ console.log('Logged in as:', session.did)
103
96
  ```
104
97
 
105
- ## PasswordAgent
98
+ ## PasswordSession
106
99
 
107
- The `PasswordAgent` class manages password-based authentication sessions.
100
+ The `PasswordSession` class manages password-based authentication sessions.
108
101
 
109
102
  ### Login
110
103
 
111
104
  Create a new session with username and password:
112
105
 
113
106
  ```typescript
114
- import { PasswordAgent } from '@atproto/lex-password-agent'
107
+ import { PasswordSession } from '@atproto/lex-password-session'
115
108
 
116
- const result = await PasswordAgent.login({
109
+ const session = await PasswordSession.login({
117
110
  service: 'https://bsky.social',
118
111
  identifier: 'alice.bsky.social', // handle or email
119
112
  password: 'app-password',
120
- hooks: {
121
- onRefreshed: (session) => {
122
- // Persist session for later restoration
123
- localStorage.setItem('session', JSON.stringify(session))
124
- },
125
- onDeleted: () => {
126
- localStorage.removeItem('session')
127
- },
113
+ onUpdated: (data) => {
114
+ // Persist session for later restoration
115
+ localStorage.setItem('session', JSON.stringify(data))
116
+ },
117
+ onDeleted: () => {
118
+ localStorage.removeItem('session')
128
119
  },
129
120
  })
130
121
 
131
- if (result.success) {
132
- const agent = result.value
133
- console.log('Logged in as:', agent.did)
134
- } else {
135
- console.error('Login failed:', result.error, result.message)
136
- }
122
+ console.log('Logged in as:', session.did)
137
123
  ```
138
124
 
139
- The `login()` method returns a discriminated union:
140
-
141
- - On success: `{ success: true, value: PasswordAgent }`
142
- - On expected errors: `XrpcResponseError` with `success: false`
143
- - On unexpected errors: throws the error
125
+ The `login()` method throws on failure. For expected errors like invalid credentials, an `XrpcResponseError` is thrown. For 2FA requirements, a `LexAuthFactorError` is thrown.
144
126
 
145
127
  ### Two-Factor Authentication
146
128
 
147
- If the account has 2FA enabled, login will return an `AuthFactorTokenRequired` error:
148
-
149
- ```typescript
150
- const result = await PasswordAgent.login({
151
- service: 'https://bsky.social',
152
- identifier: 'alice.bsky.social',
153
- password: 'app-password',
154
- })
129
+ > [!CAUTION]
130
+ >
131
+ > Two-factor authentication only applies when using **main account credentials**, which is **strongly discouraged**. Password authentication should be used with [app passwords](https://bsky.app/settings/app-passwords) only because they are designed for programmatic access (bots, scripts, CLI tools). For user-facing applications, use OAuth via [@atproto/oauth-client](../../../oauth/oauth-client) which provides better security and user control.
155
132
 
156
- if (!result.success && result.error === 'AuthFactorTokenRequired') {
157
- // Prompt user for 2FA code, then retry
158
- const code = await prompt2FACode()
133
+ If the account has 2FA enabled, login will throw a `LexAuthFactorError`:
159
134
 
160
- const retryResult = await PasswordAgent.login({
161
- service: 'https://bsky.social',
162
- identifier: 'alice.bsky.social',
163
- password: 'app-password',
164
- authFactorToken: code,
165
- })
135
+ ```typescript
136
+ import {
137
+ PasswordSession,
138
+ LexAuthFactorError,
139
+ } from '@atproto/lex-password-session'
140
+
141
+ async function loginWith2FA(
142
+ identifier: string,
143
+ password: string,
144
+ authFactorToken?: string,
145
+ ): Promise<PasswordSession> {
146
+ try {
147
+ return await PasswordSession.login({
148
+ service: 'https://bsky.social',
149
+ identifier,
150
+ password,
151
+ authFactorToken,
152
+ onUpdated: (data) => saveToStorage(data),
153
+ onDeleted: (data) => removeFromStorage(data.did),
154
+ })
155
+ } catch (err) {
156
+ if (err instanceof LexAuthFactorError && !authFactorToken) {
157
+ // 2FA required - prompt user for code
158
+ const token = await promptUserFor2FACode(err.message)
159
+ return loginWith2FA(identifier, password, token)
160
+ }
161
+ throw err
162
+ }
166
163
  }
167
164
  ```
168
165
 
@@ -171,24 +168,27 @@ if (!result.success && result.error === 'AuthFactorTokenRequired') {
171
168
  Restore a previously saved session:
172
169
 
173
170
  ```typescript
174
- import { PasswordAgent, Session } from '@atproto/lex-password-agent'
171
+ import { PasswordSession, SessionData } from '@atproto/lex-password-session'
175
172
 
176
173
  // Load session from storage
177
- const savedSession: Session = JSON.parse(localStorage.getItem('session')!)
174
+ const savedSession: SessionData = JSON.parse(localStorage.getItem('session')!)
178
175
 
179
176
  // Resume the session (automatically refreshes tokens)
180
- const agent = await PasswordAgent.resume(savedSession, {
181
- hooks: {
182
- onRefreshed: (session) => {
183
- localStorage.setItem('session', JSON.stringify(session))
184
- },
185
- onDeleted: () => {
186
- localStorage.removeItem('session')
187
- },
177
+ const session = await PasswordSession.resume(savedSession, {
178
+ onUpdated: (data) => {
179
+ localStorage.setItem('session', JSON.stringify(data))
180
+ },
181
+ onDeleted: () => {
182
+ localStorage.removeItem('session')
188
183
  },
189
184
  })
190
185
 
191
- console.log('Session resumed for:', agent.did)
186
+ console.log('Session resumed for:', session.did)
187
+
188
+ // Access session properties
189
+ console.log(session.did) // User's DID
190
+ console.log(session.handle) // User's handle
191
+ console.log(session.destroyed) // false (session is active)
192
192
  ```
193
193
 
194
194
  > [!NOTE]
@@ -200,66 +200,87 @@ console.log('Session resumed for:', agent.did)
200
200
  End the session and notify the server:
201
201
 
202
202
  ```typescript
203
- await agent.logout()
203
+ await session.logout()
204
204
  ```
205
205
 
206
206
  After logout:
207
207
 
208
208
  - The `onDeleted` hook is called
209
- - The agent is marked as destroyed (`agent.destroyed === true`)
209
+ - The session is marked as destroyed (`session.destroyed === true`)
210
210
  - Further requests will throw `'Logged out'`
211
211
 
212
212
  ### Static Delete
213
213
 
214
- Delete a session without creating an agent instance:
214
+ Delete a session without creating a session instance:
215
215
 
216
216
  ```typescript
217
- import { PasswordAgent, Session } from '@atproto/lex-password-agent'
217
+ import { PasswordSession, SessionData } from '@atproto/lex-password-session'
218
218
 
219
- const session: Session = JSON.parse(localStorage.getItem('session')!)
219
+ const data: SessionData = JSON.parse(localStorage.getItem('session')!)
220
220
 
221
221
  // Delete the session on the server
222
- await PasswordAgent.delete(session)
222
+ await PasswordSession.delete(data)
223
223
  ```
224
224
 
225
225
  This is useful for cleanup scenarios where you don't need to make additional requests.
226
226
 
227
+ ### Create Account
228
+
229
+ Create a new account and get an authenticated session:
230
+
231
+ ```typescript
232
+ import { PasswordSession } from '@atproto/lex-password-session'
233
+
234
+ const session = await PasswordSession.createAccount(
235
+ {
236
+ handle: 'alice.bsky.social',
237
+ email: 'alice@example.com',
238
+ password: 'secure-password',
239
+ },
240
+ {
241
+ service: 'https://bsky.social',
242
+ onUpdated: (data) => saveToStorage(data),
243
+ onDeleted: (data) => removeFromStorage(data.did),
244
+ },
245
+ )
246
+
247
+ console.log('Account created:', session.did)
248
+ ```
249
+
227
250
  ## Session Hooks
228
251
 
229
- Hooks provide callbacks for session lifecycle events. All hooks receive the agent as `this` context.
252
+ Hooks provide callbacks for session lifecycle events. All hooks receive the session instance as `this` context.
230
253
 
231
- ### onRefreshed
254
+ ### onUpdated
232
255
 
233
- Called when tokens are successfully refreshed:
256
+ Called when the session is successfully created or refreshed:
234
257
 
235
258
  ```typescript
236
- const result = await PasswordAgent.login({
259
+ const session = await PasswordSession.login({
237
260
  service: 'https://bsky.social',
238
261
  identifier: 'alice.bsky.social',
239
262
  password: 'app-password',
240
- hooks: {
241
- onRefreshed(session) {
242
- // `this` is the PasswordAgent instance
243
- console.log('Session refreshed for:', this.did)
244
-
245
- // Persist the updated session
246
- saveSession(session)
247
- },
263
+ onUpdated(data) {
264
+ // `this` is the PasswordSession instance
265
+ console.log('Session updated for:', this.did)
266
+
267
+ // Persist the updated session
268
+ saveSession(data)
248
269
  },
249
270
  })
250
271
  ```
251
272
 
252
273
  > [!IMPORTANT]
253
274
  >
254
- > Requests are blocked while `onRefreshed` is running. Keep this callback fast to avoid delays.
275
+ > Requests are blocked while `onUpdated` is running. Keep this callback fast to avoid delays.
255
276
 
256
- ### onRefreshFailure
277
+ ### onUpdateFailure
257
278
 
258
279
  Called when token refresh fails due to transient errors (network issues, server unavailability):
259
280
 
260
281
  ```typescript
261
- hooks: {
262
- onRefreshFailure(session, error) {
282
+ {
283
+ onUpdateFailure(data, error) {
263
284
  console.warn('Token refresh failed:', error.message)
264
285
  // Session may still be valid - consider retry logic
265
286
  }
@@ -271,10 +292,10 @@ hooks: {
271
292
  Called when the session is terminated (logout or server-side invalidation):
272
293
 
273
294
  ```typescript
274
- hooks: {
275
- onDeleted(session) {
276
- console.log('Session ended for:', session.data.did)
277
- clearPersistedSession(session.data.did)
295
+ {
296
+ onDeleted(data) {
297
+ console.log('Session ended for:', data.did)
298
+ clearPersistedSession(data.did)
278
299
  redirectToLogin()
279
300
  }
280
301
  }
@@ -285,11 +306,11 @@ hooks: {
285
306
  Called when logout fails due to transient errors:
286
307
 
287
308
  ```typescript
288
- hooks: {
289
- onDeleteFailure(session, error) {
309
+ {
310
+ onDeleteFailure(data, error) {
290
311
  console.error('Logout failed:', error.message)
291
312
  // Consider queuing for retry to avoid orphaned sessions
292
- queueLogoutRetry(session)
313
+ queueLogoutRetry(data)
293
314
  }
294
315
  }
295
316
  ```
@@ -298,29 +319,21 @@ hooks: {
298
319
  >
299
320
  > Ignoring delete failures can leave sessions active on the server. Implement retry logic for security-sensitive applications.
300
321
 
301
- ## Session Object
322
+ ## Session Data
302
323
 
303
- The `Session` type contains all data needed to authenticate and restore sessions:
324
+ The `SessionData` type contains all data needed to authenticate and restore sessions:
304
325
 
305
326
  ```typescript
306
- type Session = {
327
+ type SessionData = {
307
328
  // Session credentials and user info from createSession response
308
- data: {
309
- accessJwt: string
310
- refreshJwt: string
311
- did: string
312
- handle: string
313
- email?: string
314
- emailConfirmed?: boolean
315
- didDoc?: object
316
- // ... other fields from createSession
317
- }
318
-
319
- // When tokens were last refreshed
320
- refreshedAt: string // ISO 8601 datetime
321
-
322
- // PDS URL extracted from DID document (for routing requests)
323
- pdsUrl: string | null
329
+ accessJwt: string
330
+ refreshJwt: string
331
+ did: string
332
+ handle: string
333
+ email?: string
334
+ emailConfirmed?: boolean
335
+ didDoc?: object
336
+ // ... other fields from createSession
324
337
 
325
338
  // Original service URL used for login
326
339
  service: string
@@ -329,28 +342,37 @@ type Session = {
329
342
 
330
343
  ## Error Handling
331
344
 
332
- Login errors are returned as `XrpcResponseError` objects:
345
+ The `PasswordSession` class uses exception-based error handling:
333
346
 
334
347
  ```typescript
335
- const result = await PasswordAgent.login({
336
- service: 'https://bsky.social',
337
- identifier: 'alice.bsky.social',
338
- password: 'wrong-password',
339
- })
340
-
341
- if (!result.success) {
342
- switch (result.error) {
343
- case 'AuthenticationRequired':
344
- console.error('Invalid credentials')
345
- break
346
- case 'AuthFactorTokenRequired':
347
- console.error('2FA required')
348
- break
349
- case 'AccountTakedown':
350
- console.error('Account has been suspended')
351
- break
352
- default:
353
- console.error('Login failed:', result.message)
348
+ import {
349
+ PasswordSession,
350
+ LexAuthFactorError,
351
+ } from '@atproto/lex-password-session'
352
+ import { XrpcResponseError } from '@atproto/lex-client'
353
+
354
+ try {
355
+ const session = await PasswordSession.login({
356
+ service: 'https://bsky.social',
357
+ identifier: 'alice.bsky.social',
358
+ password: 'wrong-password',
359
+ })
360
+ } catch (err) {
361
+ if (err instanceof LexAuthFactorError) {
362
+ console.error('2FA required')
363
+ } else if (err instanceof XrpcResponseError) {
364
+ switch (err.error) {
365
+ case 'AuthenticationRequired':
366
+ console.error('Invalid credentials')
367
+ break
368
+ case 'AccountTakedown':
369
+ console.error('Account has been suspended')
370
+ break
371
+ default:
372
+ console.error('Login failed:', err.message)
373
+ }
374
+ } else {
375
+ throw err
354
376
  }
355
377
  }
356
378
  ```
@@ -367,41 +389,39 @@ Common error codes:
367
389
 
368
390
  ## Using with Client
369
391
 
370
- The `PasswordAgent` implements the `Agent` interface and can be used directly with `Client`:
392
+ The `PasswordSession` implements the `Agent` interface and can be used directly with `Client`:
371
393
 
372
394
  ```typescript
373
395
  import { Client } from '@atproto/lex-client'
374
- import { PasswordAgent } from '@atproto/lex-password-agent'
396
+ import { PasswordSession } from '@atproto/lex-password-session'
375
397
  import * as app from './lexicons/app.js'
376
398
 
377
- const result = await PasswordAgent.login({
399
+ const session = await PasswordSession.login({
378
400
  service: 'https://bsky.social',
379
401
  identifier: 'alice.bsky.social',
380
402
  password: 'app-password',
381
403
  })
382
404
 
383
- if (result.success) {
384
- const client = new Client(result.value)
405
+ const client = new Client(session)
385
406
 
386
- // The client automatically uses the agent for authentication
387
- const profile = await client.call(app.bsky.actor.getProfile, {
388
- actor: client.assertDid,
389
- })
407
+ // The client automatically uses the session for authentication
408
+ const profile = await client.call(app.bsky.actor.getProfile, {
409
+ actor: client.assertDid,
410
+ })
390
411
 
391
- // Tokens are automatically refreshed when expired
392
- const timeline = await client.call(app.bsky.feed.getTimeline, {
393
- limit: 50,
394
- })
412
+ // Tokens are automatically refreshed when expired
413
+ const timeline = await client.call(app.bsky.feed.getTimeline, {
414
+ limit: 50,
415
+ })
395
416
 
396
- // Create records
397
- await client.create(app.bsky.feed.post, {
398
- text: 'Hello from lex-password-agent!',
399
- createdAt: new Date().toISOString(),
400
- })
401
- }
417
+ // Create records
418
+ await client.create(app.bsky.feed.post, {
419
+ text: 'Hello from lex-password-session!',
420
+ createdAt: new Date().toISOString(),
421
+ })
402
422
  ```
403
423
 
404
- The agent handles:
424
+ The session handles:
405
425
 
406
426
  - Adding `Authorization` headers to requests
407
427
  - Detecting expired tokens (401 responses or `ExpiredToken` errors)
package/dist/error.d.ts CHANGED
@@ -1,8 +1,55 @@
1
- import { LexError, XrpcResponseError } from '@atproto/lex-client';
2
- import { com } from './lexicons';
1
+ import { LexError, XrpcFailure } from '@atproto/lex-client';
2
+ /**
3
+ * Error thrown when two-factor authentication (2FA) is required.
4
+ *
5
+ * This error is thrown by {@link PasswordSession.login} when the server
6
+ * requires an additional authentication factor (e.g., email code). Catch this
7
+ * error to prompt the user for their 2FA code and retry the login with the
8
+ * `authFactorToken` parameter.
9
+ *
10
+ * @example Handling 2FA requirement
11
+ * ```ts
12
+ * import { PasswordSession, LexAuthFactorError } from '@atproto/lex-password-session'
13
+ *
14
+ * try {
15
+ * const session = await PasswordSession.login({
16
+ * service: 'https://bsky.social',
17
+ * identifier: 'alice.bsky.social',
18
+ * password: 'xxxx-xxxx-xxxx-xxxx',
19
+ * })
20
+ * } catch (err) {
21
+ * if (err instanceof LexAuthFactorError) {
22
+ * // Prompt user for 2FA code
23
+ * const token = await promptUser('Enter 2FA code from email:')
24
+ *
25
+ * // Retry with the 2FA token
26
+ * const session = await PasswordSession.login({
27
+ * service: 'https://bsky.social',
28
+ * identifier: 'alice.bsky.social',
29
+ * password: 'xxxx-xxxx-xxxx-xxxx',
30
+ * authFactorToken: token,
31
+ * })
32
+ * }
33
+ * }
34
+ * ```
35
+ *
36
+ * @extends LexError
37
+ */
3
38
  export declare class LexAuthFactorError extends LexError {
4
- readonly response: XrpcResponseError<typeof com.atproto.server.createSession.main>;
39
+ readonly cause: XrpcFailure;
5
40
  name: string;
6
- constructor(response: XrpcResponseError<typeof com.atproto.server.createSession.main>);
41
+ /**
42
+ * Creates a new LexAuthFactorError.
43
+ *
44
+ * @param cause - The underlying XRPC failure response from the server
45
+ */
46
+ constructor(cause: XrpcFailure);
47
+ /**
48
+ * Converts this error to an HTTP Response.
49
+ *
50
+ * @returns A 500 Internal Server Error response (2FA errors should not be
51
+ * exposed to end users in server contexts)
52
+ */
53
+ toResponse(): Response;
7
54
  }
8
55
  //# sourceMappingURL=error.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAA;AAEhC,qBAAa,kBAAmB,SAAQ,QAAQ;IAI5C,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAClC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAC7C;IALH,IAAI,SAAuB;gBAGhB,QAAQ,EAAE,iBAAiB,CAClC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAC7C;CAIJ"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,qBAAa,kBAAmB,SAAQ,QAAQ;IAQlC,QAAQ,CAAC,KAAK,EAAE,WAAW;IAPvC,IAAI,SAAuB;IAE3B;;;;OAIG;gBACkB,KAAK,EAAE,WAAW;IAIvC;;;;;OAKG;IACM,UAAU,IAAI,QAAQ;CAGhC"}