@atproto/lex-password-session 0.0.2 → 0.0.3
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 +8 -0
- package/LICENSE.txt +1 -1
- package/README.md +2 -2
- package/dist/error.d.ts +3 -3
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/lexicons/com/atproto/server/createAccount.defs.d.ts +22 -18
- package/dist/lexicons/com/atproto/server/createAccount.defs.d.ts.map +1 -1
- package/dist/lexicons/com/atproto/server/createSession.defs.d.ts +16 -16
- package/dist/lexicons/com/atproto/server/getSession.defs.d.ts +12 -12
- package/dist/lexicons/com/atproto/server/refreshSession.defs.d.ts +12 -12
- package/dist/password-session.d.ts +5 -5
- package/dist/password-session.d.ts.map +1 -1
- package/dist/password-session.js +5 -5
- package/dist/password-session.js.map +1 -1
- package/dist/util.d.ts +1 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +2 -2
- package/dist/util.js.map +1 -1
- package/package.json +5 -5
- package/src/error.ts +2 -2
- package/src/password-session.test.ts +2 -2
- package/src/password-session.ts +10 -10
- package/src/util.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @atproto/lex-password-session
|
|
2
2
|
|
|
3
|
+
## 0.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`99963d0`](https://github.com/bluesky-social/atproto/commit/99963d002a9e030e79aed5fba700e0a68f31e101), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`99963d0`](https://github.com/bluesky-social/atproto/commit/99963d002a9e030e79aed5fba700e0a68f31e101), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b), [`7310b97`](https://github.com/bluesky-social/atproto/commit/7310b9704de678a3b389a741784d58bb7f79b10b)]:
|
|
8
|
+
- @atproto/lex-schema@0.0.10
|
|
9
|
+
- @atproto/lex-client@0.0.10
|
|
10
|
+
|
|
3
11
|
## 0.0.2
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/LICENSE.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Dual MIT/Apache-2.0 License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2022-
|
|
3
|
+
Copyright (c) 2022-2026 Bluesky Social PBC, and Contributors
|
|
4
4
|
|
|
5
5
|
Except as otherwise noted in individual files, this software is licensed under the MIT license (<http://opensource.org/licenses/MIT>), or the Apache License, Version 2.0 (<http://www.apache.org/licenses/LICENSE-2.0>).
|
|
6
6
|
|
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ if (result.success) {
|
|
|
139
139
|
The `login()` method returns a discriminated union:
|
|
140
140
|
|
|
141
141
|
- On success: `{ success: true, value: PasswordAgent }`
|
|
142
|
-
- On expected errors: `
|
|
142
|
+
- On expected errors: `XrpcResponseError` with `success: false`
|
|
143
143
|
- On unexpected errors: throws the error
|
|
144
144
|
|
|
145
145
|
### Two-Factor Authentication
|
|
@@ -329,7 +329,7 @@ type Session = {
|
|
|
329
329
|
|
|
330
330
|
## Error Handling
|
|
331
331
|
|
|
332
|
-
Login errors are returned as `
|
|
332
|
+
Login errors are returned as `XrpcResponseError` objects:
|
|
333
333
|
|
|
334
334
|
```typescript
|
|
335
335
|
const result = await PasswordAgent.login({
|
package/dist/error.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { LexError,
|
|
1
|
+
import { LexError, XrpcResponseError } from '@atproto/lex-client';
|
|
2
2
|
import { com } from './lexicons';
|
|
3
3
|
export declare class LexAuthFactorError extends LexError {
|
|
4
|
-
readonly response:
|
|
4
|
+
readonly response: XrpcResponseError<typeof com.atproto.server.createSession.main>;
|
|
5
5
|
name: string;
|
|
6
|
-
constructor(response:
|
|
6
|
+
constructor(response: XrpcResponseError<typeof com.atproto.server.createSession.main>);
|
|
7
7
|
}
|
|
8
8
|
//# sourceMappingURL=error.d.ts.map
|
package/dist/error.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,
|
|
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"}
|
package/dist/error.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":";;;AAAA,oDAAiE;AAGjE,MAAa,kBAAmB,SAAQ,qBAAQ;IAInC;IAHX,IAAI,GAAG,oBAAoB,CAAA;IAE3B,YACW,QAER;QAED,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;QAJ1D,aAAQ,GAAR,QAAQ,CAEhB;IAGH,CAAC;CACF;AAVD,gDAUC","sourcesContent":["import { LexError, XrpcResponseError } from '@atproto/lex-client'\nimport { com } from './lexicons'\n\nexport class LexAuthFactorError extends LexError {\n name = 'LexAuthFactorError'\n\n constructor(\n readonly response: XrpcResponseError<\n typeof com.atproto.server.createSession.main\n >,\n ) {\n super(response.error, response.message, { cause: response.reason })\n }\n}\n"]}
|
|
@@ -3,17 +3,19 @@ declare const $nsid = "com.atproto.server.createAccount";
|
|
|
3
3
|
export { $nsid };
|
|
4
4
|
/** Create an account. Implemented by PDS. */
|
|
5
5
|
declare const main: l.Procedure<"com.atproto.server.createAccount", l.ParamsSchema<{}>, l.Payload<"application/json", l.ObjectSchema<{
|
|
6
|
-
readonly email: l.OptionalSchema<
|
|
6
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
7
7
|
readonly handle: l.StringSchema<{
|
|
8
8
|
readonly format: "handle";
|
|
9
9
|
}>;
|
|
10
|
-
readonly did: l.OptionalSchema
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
readonly
|
|
14
|
-
readonly
|
|
15
|
-
readonly
|
|
16
|
-
readonly
|
|
10
|
+
readonly did: l.OptionalSchema<l.StringSchema<{
|
|
11
|
+
readonly format: "did";
|
|
12
|
+
}>>;
|
|
13
|
+
readonly inviteCode: l.OptionalSchema<l.StringSchema<{}>>;
|
|
14
|
+
readonly verificationCode: l.OptionalSchema<l.StringSchema<{}>>;
|
|
15
|
+
readonly verificationPhone: l.OptionalSchema<l.StringSchema<{}>>;
|
|
16
|
+
readonly password: l.OptionalSchema<l.StringSchema<{}>>;
|
|
17
|
+
readonly recoveryKey: l.OptionalSchema<l.StringSchema<{}>>;
|
|
18
|
+
readonly plcOp: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
17
19
|
}>>, l.Payload<"application/json", l.ObjectSchema<{
|
|
18
20
|
readonly accessJwt: l.StringSchema<{}>;
|
|
19
21
|
readonly refreshJwt: l.StringSchema<{}>;
|
|
@@ -23,7 +25,7 @@ declare const main: l.Procedure<"com.atproto.server.createAccount", l.ParamsSche
|
|
|
23
25
|
readonly did: l.StringSchema<{
|
|
24
26
|
readonly format: "did";
|
|
25
27
|
}>;
|
|
26
|
-
readonly didDoc: l.OptionalSchema<
|
|
28
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
27
29
|
}>>, readonly ["InvalidHandle", "InvalidPassword", "InvalidInviteCode", "HandleNotAvailable", "UnsupportedDomain", "UnresolvableDid", "IncompatibleDidDoc"]>;
|
|
28
30
|
export { main };
|
|
29
31
|
export type Params = l.InferMethodParams<typeof main>;
|
|
@@ -32,17 +34,19 @@ export type InputBody = l.InferMethodInputBody<typeof main>;
|
|
|
32
34
|
export type Output = l.InferMethodOutput<typeof main>;
|
|
33
35
|
export type OutputBody = l.InferMethodOutputBody<typeof main>;
|
|
34
36
|
export declare const $lxm: "com.atproto.server.createAccount", $params: l.ParamsSchema<{}>, $input: l.Payload<"application/json", l.ObjectSchema<{
|
|
35
|
-
readonly email: l.OptionalSchema<
|
|
37
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
36
38
|
readonly handle: l.StringSchema<{
|
|
37
39
|
readonly format: "handle";
|
|
38
40
|
}>;
|
|
39
|
-
readonly did: l.OptionalSchema
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
readonly
|
|
43
|
-
readonly
|
|
44
|
-
readonly
|
|
45
|
-
readonly
|
|
41
|
+
readonly did: l.OptionalSchema<l.StringSchema<{
|
|
42
|
+
readonly format: "did";
|
|
43
|
+
}>>;
|
|
44
|
+
readonly inviteCode: l.OptionalSchema<l.StringSchema<{}>>;
|
|
45
|
+
readonly verificationCode: l.OptionalSchema<l.StringSchema<{}>>;
|
|
46
|
+
readonly verificationPhone: l.OptionalSchema<l.StringSchema<{}>>;
|
|
47
|
+
readonly password: l.OptionalSchema<l.StringSchema<{}>>;
|
|
48
|
+
readonly recoveryKey: l.OptionalSchema<l.StringSchema<{}>>;
|
|
49
|
+
readonly plcOp: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
46
50
|
}>>, $output: l.Payload<"application/json", l.ObjectSchema<{
|
|
47
51
|
readonly accessJwt: l.StringSchema<{}>;
|
|
48
52
|
readonly refreshJwt: l.StringSchema<{}>;
|
|
@@ -52,6 +56,6 @@ export declare const $lxm: "com.atproto.server.createAccount", $params: l.Params
|
|
|
52
56
|
readonly did: l.StringSchema<{
|
|
53
57
|
readonly format: "did";
|
|
54
58
|
}>;
|
|
55
|
-
readonly didDoc: l.OptionalSchema<
|
|
59
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
56
60
|
}>>;
|
|
57
61
|
//# sourceMappingURL=createAccount.defs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createAccount.defs.d.ts","sourceRoot":"","sources":["../../../../../src/lexicons/com/atproto/server/createAccount.defs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,qBAAqB,CAAA;AAEvC,QAAA,MAAM,KAAK,qCAAqC,CAAA;AAEhD,OAAO,EAAE,KAAK,EAAE,CAAA;AAEhB,6CAA6C;AAC7C,QAAA,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"createAccount.defs.d.ts","sourceRoot":"","sources":["../../../../../src/lexicons/com/atproto/server/createAccount.defs.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,qBAAqB,CAAA;AAEvC,QAAA,MAAM,KAAK,qCAAqC,CAAA;AAEhD,OAAO,EAAE,KAAK,EAAE,CAAA;AAEhB,6CAA6C;AAC7C,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;4JAgCP,CAAA;AACH,OAAO,EAAE,IAAI,EAAE,CAAA;AAEf,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,iBAAiB,CAAC,OAAO,IAAI,CAAC,CAAA;AACrD,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,gBAAgB,CAAC,OAAO,IAAI,CAAC,CAAA;AACnD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,oBAAoB,CAAC,OAAO,IAAI,CAAC,CAAA;AAC3D,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,iBAAiB,CAAC,OAAO,IAAI,CAAC,CAAA;AACrD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,qBAAqB,CAAC,OAAO,IAAI,CAAC,CAAA;AAE7D,eAAO,MAAM,IAAI,oCAA0B,EACzC,OAAO,oBAAgC,EACvC,MAAM;;;;;;;;;;;;;;GAA2B,EACjC,OAAO;;;;;;;;;;GAA4B,CAAA"}
|
|
@@ -5,8 +5,8 @@ export { $nsid };
|
|
|
5
5
|
declare const main: l.Procedure<"com.atproto.server.createSession", l.ParamsSchema<{}>, l.Payload<"application/json", l.ObjectSchema<{
|
|
6
6
|
readonly identifier: l.StringSchema<{}>;
|
|
7
7
|
readonly password: l.StringSchema<{}>;
|
|
8
|
-
readonly authFactorToken: l.OptionalSchema<
|
|
9
|
-
readonly allowTakendown: l.OptionalSchema<
|
|
8
|
+
readonly authFactorToken: l.OptionalSchema<l.StringSchema<{}>>;
|
|
9
|
+
readonly allowTakendown: l.OptionalSchema<l.BooleanSchema>;
|
|
10
10
|
}>>, l.Payload<"application/json", l.ObjectSchema<{
|
|
11
11
|
readonly accessJwt: l.StringSchema<{}>;
|
|
12
12
|
readonly refreshJwt: l.StringSchema<{}>;
|
|
@@ -16,12 +16,12 @@ declare const main: l.Procedure<"com.atproto.server.createSession", l.ParamsSche
|
|
|
16
16
|
readonly did: l.StringSchema<{
|
|
17
17
|
readonly format: "did";
|
|
18
18
|
}>;
|
|
19
|
-
readonly didDoc: l.OptionalSchema<
|
|
20
|
-
readonly email: l.OptionalSchema<
|
|
21
|
-
readonly emailConfirmed: l.OptionalSchema<
|
|
22
|
-
readonly emailAuthFactor: l.OptionalSchema<
|
|
23
|
-
readonly active: l.OptionalSchema<
|
|
24
|
-
readonly status: l.OptionalSchema<
|
|
19
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
20
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
21
|
+
readonly emailConfirmed: l.OptionalSchema<l.BooleanSchema>;
|
|
22
|
+
readonly emailAuthFactor: l.OptionalSchema<l.BooleanSchema>;
|
|
23
|
+
readonly active: l.OptionalSchema<l.BooleanSchema>;
|
|
24
|
+
readonly status: l.OptionalSchema<l.StringSchema<{}>>;
|
|
25
25
|
}>>, readonly ["AccountTakedown", "AuthFactorTokenRequired"]>;
|
|
26
26
|
export { main };
|
|
27
27
|
export type Params = l.InferMethodParams<typeof main>;
|
|
@@ -32,8 +32,8 @@ export type OutputBody = l.InferMethodOutputBody<typeof main>;
|
|
|
32
32
|
export declare const $lxm: "com.atproto.server.createSession", $params: l.ParamsSchema<{}>, $input: l.Payload<"application/json", l.ObjectSchema<{
|
|
33
33
|
readonly identifier: l.StringSchema<{}>;
|
|
34
34
|
readonly password: l.StringSchema<{}>;
|
|
35
|
-
readonly authFactorToken: l.OptionalSchema<
|
|
36
|
-
readonly allowTakendown: l.OptionalSchema<
|
|
35
|
+
readonly authFactorToken: l.OptionalSchema<l.StringSchema<{}>>;
|
|
36
|
+
readonly allowTakendown: l.OptionalSchema<l.BooleanSchema>;
|
|
37
37
|
}>>, $output: l.Payload<"application/json", l.ObjectSchema<{
|
|
38
38
|
readonly accessJwt: l.StringSchema<{}>;
|
|
39
39
|
readonly refreshJwt: l.StringSchema<{}>;
|
|
@@ -43,11 +43,11 @@ export declare const $lxm: "com.atproto.server.createSession", $params: l.Params
|
|
|
43
43
|
readonly did: l.StringSchema<{
|
|
44
44
|
readonly format: "did";
|
|
45
45
|
}>;
|
|
46
|
-
readonly didDoc: l.OptionalSchema<
|
|
47
|
-
readonly email: l.OptionalSchema<
|
|
48
|
-
readonly emailConfirmed: l.OptionalSchema<
|
|
49
|
-
readonly emailAuthFactor: l.OptionalSchema<
|
|
50
|
-
readonly active: l.OptionalSchema<
|
|
51
|
-
readonly status: l.OptionalSchema<
|
|
46
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
47
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
48
|
+
readonly emailConfirmed: l.OptionalSchema<l.BooleanSchema>;
|
|
49
|
+
readonly emailAuthFactor: l.OptionalSchema<l.BooleanSchema>;
|
|
50
|
+
readonly active: l.OptionalSchema<l.BooleanSchema>;
|
|
51
|
+
readonly status: l.OptionalSchema<l.StringSchema<{}>>;
|
|
52
52
|
}>>;
|
|
53
53
|
//# sourceMappingURL=createSession.defs.d.ts.map
|
|
@@ -9,12 +9,12 @@ declare const main: l.Query<"com.atproto.server.getSession", l.ParamsSchema<{}>,
|
|
|
9
9
|
readonly did: l.StringSchema<{
|
|
10
10
|
readonly format: "did";
|
|
11
11
|
}>;
|
|
12
|
-
readonly didDoc: l.OptionalSchema<
|
|
13
|
-
readonly email: l.OptionalSchema<
|
|
14
|
-
readonly emailConfirmed: l.OptionalSchema<
|
|
15
|
-
readonly emailAuthFactor: l.OptionalSchema<
|
|
16
|
-
readonly active: l.OptionalSchema<
|
|
17
|
-
readonly status: l.OptionalSchema<
|
|
12
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
13
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
14
|
+
readonly emailConfirmed: l.OptionalSchema<l.BooleanSchema>;
|
|
15
|
+
readonly emailAuthFactor: l.OptionalSchema<l.BooleanSchema>;
|
|
16
|
+
readonly active: l.OptionalSchema<l.BooleanSchema>;
|
|
17
|
+
readonly status: l.OptionalSchema<l.StringSchema<{}>>;
|
|
18
18
|
}>>, undefined>;
|
|
19
19
|
export { main };
|
|
20
20
|
export type Params = l.InferMethodParams<typeof main>;
|
|
@@ -27,11 +27,11 @@ export declare const $lxm: "com.atproto.server.getSession", $params: l.ParamsSch
|
|
|
27
27
|
readonly did: l.StringSchema<{
|
|
28
28
|
readonly format: "did";
|
|
29
29
|
}>;
|
|
30
|
-
readonly didDoc: l.OptionalSchema<
|
|
31
|
-
readonly email: l.OptionalSchema<
|
|
32
|
-
readonly emailConfirmed: l.OptionalSchema<
|
|
33
|
-
readonly emailAuthFactor: l.OptionalSchema<
|
|
34
|
-
readonly active: l.OptionalSchema<
|
|
35
|
-
readonly status: l.OptionalSchema<
|
|
30
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
31
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
32
|
+
readonly emailConfirmed: l.OptionalSchema<l.BooleanSchema>;
|
|
33
|
+
readonly emailAuthFactor: l.OptionalSchema<l.BooleanSchema>;
|
|
34
|
+
readonly active: l.OptionalSchema<l.BooleanSchema>;
|
|
35
|
+
readonly status: l.OptionalSchema<l.StringSchema<{}>>;
|
|
36
36
|
}>>;
|
|
37
37
|
//# sourceMappingURL=getSession.defs.d.ts.map
|
|
@@ -11,12 +11,12 @@ declare const main: l.Procedure<"com.atproto.server.refreshSession", l.ParamsSch
|
|
|
11
11
|
readonly did: l.StringSchema<{
|
|
12
12
|
readonly format: "did";
|
|
13
13
|
}>;
|
|
14
|
-
readonly didDoc: l.OptionalSchema<
|
|
15
|
-
readonly email: l.OptionalSchema<
|
|
16
|
-
readonly emailConfirmed: l.OptionalSchema<
|
|
17
|
-
readonly emailAuthFactor: l.OptionalSchema<
|
|
18
|
-
readonly active: l.OptionalSchema<
|
|
19
|
-
readonly status: l.OptionalSchema<
|
|
14
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
15
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
16
|
+
readonly emailConfirmed: l.OptionalSchema<l.BooleanSchema>;
|
|
17
|
+
readonly emailAuthFactor: l.OptionalSchema<l.BooleanSchema>;
|
|
18
|
+
readonly active: l.OptionalSchema<l.BooleanSchema>;
|
|
19
|
+
readonly status: l.OptionalSchema<l.StringSchema<{}>>;
|
|
20
20
|
}>>, readonly ["AccountTakedown", "InvalidToken", "ExpiredToken"]>;
|
|
21
21
|
export { main };
|
|
22
22
|
export type Params = l.InferMethodParams<typeof main>;
|
|
@@ -33,11 +33,11 @@ export declare const $lxm: "com.atproto.server.refreshSession", $params: l.Param
|
|
|
33
33
|
readonly did: l.StringSchema<{
|
|
34
34
|
readonly format: "did";
|
|
35
35
|
}>;
|
|
36
|
-
readonly didDoc: l.OptionalSchema<
|
|
37
|
-
readonly email: l.OptionalSchema<
|
|
38
|
-
readonly emailConfirmed: l.OptionalSchema<
|
|
39
|
-
readonly emailAuthFactor: l.OptionalSchema<
|
|
40
|
-
readonly active: l.OptionalSchema<
|
|
41
|
-
readonly status: l.OptionalSchema<
|
|
36
|
+
readonly didDoc: l.OptionalSchema<l.UnknownObjectSchema>;
|
|
37
|
+
readonly email: l.OptionalSchema<l.StringSchema<{}>>;
|
|
38
|
+
readonly emailConfirmed: l.OptionalSchema<l.BooleanSchema>;
|
|
39
|
+
readonly emailAuthFactor: l.OptionalSchema<l.BooleanSchema>;
|
|
40
|
+
readonly active: l.OptionalSchema<l.BooleanSchema>;
|
|
41
|
+
readonly status: l.OptionalSchema<l.StringSchema<{}>>;
|
|
42
42
|
}>>;
|
|
43
43
|
//# sourceMappingURL=refreshSession.defs.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Agent,
|
|
1
|
+
import { Agent, XrpcFailure } from '@atproto/lex-client';
|
|
2
2
|
import { com } from './lexicons/index.js';
|
|
3
|
-
export type RefreshFailure =
|
|
4
|
-
export type DeleteFailure =
|
|
3
|
+
export type RefreshFailure = XrpcFailure<typeof com.atproto.server.refreshSession.main>;
|
|
4
|
+
export type DeleteFailure = XrpcFailure<typeof com.atproto.server.deleteSession.main>;
|
|
5
5
|
export type SessionData = com.atproto.server.createSession.OutputBody & {
|
|
6
6
|
service: string;
|
|
7
7
|
};
|
|
@@ -74,7 +74,7 @@ export declare class PasswordSession implements Agent {
|
|
|
74
74
|
* use-cases.
|
|
75
75
|
*
|
|
76
76
|
* @throws If unable to create a session. In particular, if the server
|
|
77
|
-
* requires a 2FA token, a {@link
|
|
77
|
+
* requires a 2FA token, a {@link XrpcResponseError} with the
|
|
78
78
|
* `AuthFactorTokenRequired` error code will be thrown.
|
|
79
79
|
*
|
|
80
80
|
*
|
|
@@ -88,7 +88,7 @@ export declare class PasswordSession implements Agent {
|
|
|
88
88
|
* password: 'correct horse battery staple',
|
|
89
89
|
* })
|
|
90
90
|
* } catch (err) {
|
|
91
|
-
* if (err instanceof
|
|
91
|
+
* if (err instanceof XrpcResponseError && err.error === 'AuthFactorTokenRequired') {
|
|
92
92
|
* // Prompt user for 2FA token and re-attempt session creation
|
|
93
93
|
* }
|
|
94
94
|
* }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password-session.d.ts","sourceRoot":"","sources":["../src/password-session.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAEL,
|
|
1
|
+
{"version":3,"file":"password-session.d.ts","sourceRoot":"","sources":["../src/password-session.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAEL,WAAW,EAGZ,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AAGzC,MAAM,MAAM,cAAc,GAAG,WAAW,CACtC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAC9C,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,WAAW,CACrC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAC7C,CAAA;AAED,MAAM,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,GAAG;IACtE,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAE/B;;;;;;;;;OASG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7E;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,CAChB,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,cAAc,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzB;;;;;;;OAOG;IACH,SAAS,EAAE,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7E;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,CAChB,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,WAAW,EACjB,GAAG,EAAE,aAAa,KACf,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B,CAAA;AAED,qBAAa,eAAgB,YAAW,KAAK;;IAYzC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,sBAAsB;gBADlD,WAAW,EAAE,WAAW,EACL,OAAO,EAAE,sBAAsB;IAWpD,IAAI,GAAG,8BAEN;IAED,IAAI,MAAM,0BAET;IAED,IAAI,OAAO,gBAGV;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAEK,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAkEhE,OAAO,IAAI,OAAO,CAAC,WAAW,CAAC;IAwD/B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC7B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;WACU,MAAM,CAAC,EAClB,OAAO,EACP,UAAU,EACV,QAAQ,EACR,cAAc,EACd,eAAe,EACf,GAAG,OAAO,EACX,EAAE,sBAAsB,GAAG;QAC1B,OAAO,EAAE,MAAM,GAAG,GAAG,CAAA;QACrB,UAAU,EAAE,MAAM,CAAA;QAClB,QAAQ,EAAE,MAAM,CAAA;QAChB,cAAc,CAAC,EAAE,OAAO,CAAA;QACxB,eAAe,CAAC,EAAE,MAAM,CAAA;KACzB,GAAG,OAAO,CAAC,eAAe,CAAC;IA6B5B;;;;;;;;;;;;OAYG;WACU,MAAM,CACjB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC;IAM3B;;;;;;OAMG;WACU,MAAM,CACjB,IAAI,EAAE,WAAW,EACjB,OAAO,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,GACxC,OAAO,CAAC,IAAI,CAAC;CAQjB"}
|
package/dist/password-session.js
CHANGED
|
@@ -32,7 +32,7 @@ class PasswordSession {
|
|
|
32
32
|
get session() {
|
|
33
33
|
if (this.#sessionData)
|
|
34
34
|
return this.#sessionData;
|
|
35
|
-
throw new lex_client_1.
|
|
35
|
+
throw new lex_client_1.XrpcError('AuthenticationRequired', 'Logged out');
|
|
36
36
|
}
|
|
37
37
|
get destroyed() {
|
|
38
38
|
return this.#sessionData === null;
|
|
@@ -52,7 +52,7 @@ class PasswordSession {
|
|
|
52
52
|
});
|
|
53
53
|
const refreshNeeded = initialRes.status === 401 ||
|
|
54
54
|
(initialRes.status === 400 &&
|
|
55
|
-
(await (0, util_js_1.
|
|
55
|
+
(await (0, util_js_1.extractXrpcErrorCode)(initialRes)) === 'ExpiredToken');
|
|
56
56
|
if (!refreshNeeded) {
|
|
57
57
|
return initialRes;
|
|
58
58
|
}
|
|
@@ -133,7 +133,7 @@ class PasswordSession {
|
|
|
133
133
|
await this.options.onDeleted.call(this, sessionData);
|
|
134
134
|
// Update the session promise to a rejected state
|
|
135
135
|
this.#sessionData = null;
|
|
136
|
-
throw new lex_client_1.
|
|
136
|
+
throw new lex_client_1.XrpcError('AuthenticationRequired', 'Logged out');
|
|
137
137
|
}
|
|
138
138
|
else {
|
|
139
139
|
// Capture the reason for the failure to re-throw in the outer promise
|
|
@@ -160,7 +160,7 @@ class PasswordSession {
|
|
|
160
160
|
* use-cases.
|
|
161
161
|
*
|
|
162
162
|
* @throws If unable to create a session. In particular, if the server
|
|
163
|
-
* requires a 2FA token, a {@link
|
|
163
|
+
* requires a 2FA token, a {@link XrpcResponseError} with the
|
|
164
164
|
* `AuthFactorTokenRequired` error code will be thrown.
|
|
165
165
|
*
|
|
166
166
|
*
|
|
@@ -174,7 +174,7 @@ class PasswordSession {
|
|
|
174
174
|
* password: 'correct horse battery staple',
|
|
175
175
|
* })
|
|
176
176
|
* } catch (err) {
|
|
177
|
-
* if (err instanceof
|
|
177
|
+
* if (err instanceof XrpcResponseError && err.error === 'AuthFactorTokenRequired') {
|
|
178
178
|
* // Prompt user for 2FA token and re-attempt session creation
|
|
179
179
|
* }
|
|
180
180
|
* }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password-session.js","sourceRoot":"","sources":["../src/password-session.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Agent,\n LexRpcError,\n LexRpcFailure,\n buildAgent,\n xrpcSafe,\n} from '@atproto/lex-client'\nimport { LexAuthFactorError } from './error.js'\nimport { com } from './lexicons/index.js'\nimport { extractLexRpcErrorCode, extractPdsUrl, noop } from './util.js'\n\nexport type RefreshFailure = LexRpcFailure<\n typeof com.atproto.server.refreshSession.main\n>\n\nexport type DeleteFailure = LexRpcFailure<\n typeof com.atproto.server.deleteSession.main\n>\n\nexport type SessionData = com.atproto.server.createSession.OutputBody & {\n service: string\n}\n\nexport type PasswordSessionOptions = {\n /**\n * Custom fetch implementation to use for network requests\n */\n fetch?: typeof globalThis.fetch\n\n /**\n * Called whenever the session is successfully created/refreshed, and new\n * credentials have been obtained. Use this hook to persist the updated\n * session information.\n *\n * If this callback returns a promise, this function will never be called\n * again (on the same process) until the promise resolves.\n *\n * @note this function **must** not throw\n */\n onUpdated: (this: PasswordSession, data: SessionData) => void | Promise<void>\n\n /**\n * Called whenever the session update fails due to an expected error, such as\n * a network issue or server unavailability. This function can be used to log\n * the error or notify the user, but should not assume that the session is\n * invalid.\n *\n * @note this function **must** not throw\n */\n onUpdateFailure?: (\n this: PasswordSession,\n data: SessionData,\n err: RefreshFailure,\n ) => void | Promise<void>\n\n /**\n * Called whenever the session is deleted, either due to an explicit logout or\n * because the refresh operation indicated that the session is no longer\n * valid. Use this hook to clean up any persisted session information and\n * update the application state accordingly.\n *\n * @note this function **must** not throw\n */\n onDeleted: (this: PasswordSession, data: SessionData) => void | Promise<void>\n\n /**\n * Called whenever a session deletion fails due to an unexpected error, such\n * as a network issue or server unavailability. This function can be used to\n * log the error or notify the user. When this function is called, the session\n * might still be valid on the server. It is up to the implementation to\n * decide whether to retry the deletion or keep the session active. Ignoring\n * these errors is not recommended as it can lead to orphaned sessions on the\n * server, or security issues if the user believes they have logged out when a\n * bad actor is still using the session. The implementation should consider\n * keeping track of failed deletions and retrying them later, until they\n * succeed.\n *\n * @note this function **must** not throw\n */\n onDeleteFailure?: (\n this: PasswordSession,\n data: SessionData,\n err: DeleteFailure,\n ) => void | Promise<void>\n}\n\nexport class PasswordSession implements Agent {\n /**\n * Internal {@link Agent} used for session management towards the\n * authentication service only.\n */\n #serviceAgent: Agent\n\n #sessionData: null | SessionData\n #sessionPromise: Promise<SessionData>\n\n constructor(\n sessionData: SessionData,\n protected readonly options: PasswordSessionOptions,\n ) {\n this.#serviceAgent = buildAgent({\n service: sessionData.service,\n fetch: options.fetch,\n })\n\n this.#sessionData = sessionData\n this.#sessionPromise = Promise.resolve(this.#sessionData)\n }\n\n get did() {\n return this.session.did\n }\n\n get handle() {\n return this.session.handle\n }\n\n get session() {\n if (this.#sessionData) return this.#sessionData\n throw new LexRpcError('AuthenticationRequired', 'Logged out')\n }\n\n get destroyed(): boolean {\n return this.#sessionData === null\n }\n\n async fetchHandler(path: string, init: RequestInit): Promise<Response> {\n const headers = new Headers(init.headers)\n if (headers.has('authorization')) {\n throw new TypeError(\"Unexpected 'authorization' header set\")\n }\n\n const sessionPromise = this.#sessionPromise\n const sessionData = await sessionPromise\n\n const fetch = this.options.fetch ?? globalThis.fetch\n\n headers.set('authorization', `Bearer ${sessionData.accessJwt}`)\n const initialRes = await fetch(fetchUrl(sessionData, path), {\n ...init,\n headers,\n })\n\n const refreshNeeded =\n initialRes.status === 401 ||\n (initialRes.status === 400 &&\n (await extractLexRpcErrorCode(initialRes)) === 'ExpiredToken')\n\n if (!refreshNeeded) {\n return initialRes\n }\n\n // Refresh session (unless it was already refreshed in the meantime)\n const newSessionPromise =\n this.#sessionPromise === sessionPromise\n ? this.refresh()\n : this.#sessionPromise\n\n // Error should have been propagated through hooks\n const newSessionData = await newSessionPromise.catch((_err) => null)\n if (!newSessionData) {\n return initialRes\n }\n\n // refresh silently failed, no point in retrying.\n if (newSessionData.accessJwt === sessionData.accessJwt) {\n return initialRes\n }\n\n if (init?.signal?.aborted) {\n return initialRes\n }\n\n // The stream was already consumed. We cannot retry the request. A solution\n // would be to tee() the input stream but that would bufferize the entire\n // stream in memory which can lead to memory starvation. Instead, we will\n // return the original response and let the calling code handle retries.\n if (ReadableStream && init?.body instanceof ReadableStream) {\n return initialRes\n }\n\n // Make sure the initial request is cancelled to avoid leaking resources\n // (NodeJS 👀): https://undici.nodejs.org/#/?id=garbage-collection\n if (!initialRes.bodyUsed) {\n await initialRes.body?.cancel()\n }\n\n // Finally, retry the request with the new access token\n headers.set('authorization', `Bearer ${newSessionData.accessJwt}`)\n return fetch(fetchUrl(newSessionData, path), { ...init, headers })\n }\n\n async refresh(): Promise<SessionData> {\n this.#sessionPromise = this.#sessionPromise.then(async (sessionData) => {\n const response = await xrpcSafe(\n this.#serviceAgent,\n com.atproto.server.refreshSession.main,\n { headers: { Authorization: `Bearer ${sessionData.refreshJwt}` } },\n )\n\n if (!response.success && response.matchesSchema()) {\n // Expected errors that indicate the session is no longer valid\n await this.options.onDeleted.call(this, sessionData)\n\n // Update the session promise to a rejected state\n this.#sessionData = null\n throw response\n }\n\n if (!response.success) {\n // We failed to refresh the token, assume the session might still be\n // valid by returning the existing session.\n await this.options.onUpdateFailure?.call(this, sessionData, response)\n\n return sessionData\n }\n\n const data = response.body\n\n // Historically, refreshSession did not return all the fields from\n // getSession. In particular, emailConfirmed and didDoc were missing.\n // Similarly, some servers might not return the didDoc in refreshSession.\n // We fetch them via getSession if missing, allowing to ensure that we are\n // always talking with the right PDS.\n if (data.emailConfirmed == null || data.didDoc == null) {\n const extraData = await xrpcSafe(\n this.#serviceAgent,\n com.atproto.server.getSession.main,\n { headers: { Authorization: `Bearer ${data.accessJwt}` } },\n )\n if (extraData.success && extraData.body.did === data.did) {\n Object.assign(data, extraData.body)\n }\n }\n\n const newSession: SessionData = {\n ...data,\n service: sessionData.service,\n }\n\n await this.options.onUpdated.call(this, newSession)\n\n return (this.#sessionData = newSession)\n })\n\n return this.#sessionPromise\n }\n\n async logout(): Promise<void> {\n let reason: DeleteFailure | null = null\n\n this.#sessionPromise = this.#sessionPromise.then(async (sessionData) => {\n const result = await xrpcSafe(\n this.#serviceAgent,\n com.atproto.server.deleteSession.main,\n { headers: { Authorization: `Bearer ${sessionData.refreshJwt}` } },\n )\n\n if (result.success || result.matchesSchema()) {\n await this.options.onDeleted.call(this, sessionData)\n\n // Update the session promise to a rejected state\n this.#sessionData = null\n throw new LexRpcError('AuthenticationRequired', 'Logged out')\n } else {\n // Capture the reason for the failure to re-throw in the outer promise\n reason = result\n\n // An unknown/unexpected error occurred (network, server down, etc)\n await this.options.onDeleteFailure?.call(this, sessionData, result)\n\n // Keep the session in an active state\n return sessionData\n }\n })\n\n return this.#sessionPromise.then(\n (_session) => {\n // If the promise above resolved, then logout failed. Re-throw the\n // reason captured earlier.\n throw reason!\n },\n (_err) => {\n // Successful logout\n },\n )\n }\n\n /**\n * @note It is **not** recommended to use {@link PasswordSession} with main\n * account credentials. Instead, it is strongly advised to use OAuth based\n * authentication for main username/password credentials and use\n * {@link PasswordSession} with an app-password, for bots, scripts, or similar\n * use-cases.\n *\n * @throws If unable to create a session. In particular, if the server\n * requires a 2FA token, a {@link LexRpcResponseError} with the\n * `AuthFactorTokenRequired` error code will be thrown.\n *\n *\n * @example Handling 2FA errors\n *\n * ```ts\n * try {\n * const session = await PasswordSession.create({\n * service: 'https://example.com',\n * identifier: 'alice',\n * password: 'correct horse battery staple',\n * })\n * } catch (err) {\n * if (err instanceof LexRpcResponseError && err.error === 'AuthFactorTokenRequired') {\n * // Prompt user for 2FA token and re-attempt session creation\n * }\n * }\n * ```\n */\n static async create({\n service,\n identifier,\n password,\n allowTakendown,\n authFactorToken,\n ...options\n }: PasswordSessionOptions & {\n service: string | URL\n identifier: string\n password: string\n allowTakendown?: boolean\n authFactorToken?: string\n }): Promise<PasswordSession> {\n const xrpcAgent = buildAgent({\n service,\n fetch: options.fetch,\n })\n\n const response = await xrpcSafe(\n xrpcAgent,\n com.atproto.server.createSession.main,\n { body: { identifier, password, allowTakendown, authFactorToken } },\n )\n\n if (!response.success) {\n if (response.error === 'AuthFactorTokenRequired') {\n throw new LexAuthFactorError(response)\n }\n throw response.reason\n }\n\n const data: SessionData = {\n ...response.body,\n service: String(service),\n }\n\n const agent = new PasswordSession(data, options)\n await options.onUpdated.call(agent, data)\n return agent\n }\n\n /**\n * Resume an existing session, ensuring it is still valid by refreshing it.\n * Any error thrown here indicates that the session is definitely no longer\n * valid. Network errors will be propagated through the\n * {@link PasswordSessionOptions.onUpdateFailure} hook, and not re-thrown\n * here. This means that a resolved promise does not necessarily indicate a\n * valid session, only that it's refresh did not definitively fail.\n *\n * This is the same as calling {@link PasswordSession.refresh} after\n * constructing the {@link PasswordSession} manually.\n *\n * @throws If, and only if, the session is definitely no longer valid.\n */\n static async resume(\n data: SessionData,\n options: PasswordSessionOptions,\n ): Promise<PasswordSession> {\n const agent = new PasswordSession(data, options)\n await agent.refresh()\n return agent\n }\n\n /**\n * Delete a session without having to {@link resume resume()} it first, or\n * provide hooks.\n *\n * @throws In case of unexpected error (network issue, server down, etc)\n * meaning that the session may still be valid.\n */\n static async delete(\n data: SessionData,\n options?: Partial<PasswordSessionOptions>,\n ): Promise<void> {\n const agent = new PasswordSession(data, {\n ...options,\n onUpdated: options?.onUpdated ?? noop,\n onDeleted: options?.onDeleted ?? noop,\n })\n await agent.logout()\n }\n}\n\nfunction fetchUrl(sessionData: SessionData, path: string): URL {\n const pdsUrl = extractPdsUrl(sessionData.didDoc)\n return new URL(path, pdsUrl ?? sessionData.service)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"password-session.js","sourceRoot":"","sources":["../src/password-session.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Agent,\n XrpcError,\n XrpcFailure,\n buildAgent,\n xrpcSafe,\n} from '@atproto/lex-client'\nimport { LexAuthFactorError } from './error.js'\nimport { com } from './lexicons/index.js'\nimport { extractPdsUrl, extractXrpcErrorCode, noop } from './util.js'\n\nexport type RefreshFailure = XrpcFailure<\n typeof com.atproto.server.refreshSession.main\n>\n\nexport type DeleteFailure = XrpcFailure<\n typeof com.atproto.server.deleteSession.main\n>\n\nexport type SessionData = com.atproto.server.createSession.OutputBody & {\n service: string\n}\n\nexport type PasswordSessionOptions = {\n /**\n * Custom fetch implementation to use for network requests\n */\n fetch?: typeof globalThis.fetch\n\n /**\n * Called whenever the session is successfully created/refreshed, and new\n * credentials have been obtained. Use this hook to persist the updated\n * session information.\n *\n * If this callback returns a promise, this function will never be called\n * again (on the same process) until the promise resolves.\n *\n * @note this function **must** not throw\n */\n onUpdated: (this: PasswordSession, data: SessionData) => void | Promise<void>\n\n /**\n * Called whenever the session update fails due to an expected error, such as\n * a network issue or server unavailability. This function can be used to log\n * the error or notify the user, but should not assume that the session is\n * invalid.\n *\n * @note this function **must** not throw\n */\n onUpdateFailure?: (\n this: PasswordSession,\n data: SessionData,\n err: RefreshFailure,\n ) => void | Promise<void>\n\n /**\n * Called whenever the session is deleted, either due to an explicit logout or\n * because the refresh operation indicated that the session is no longer\n * valid. Use this hook to clean up any persisted session information and\n * update the application state accordingly.\n *\n * @note this function **must** not throw\n */\n onDeleted: (this: PasswordSession, data: SessionData) => void | Promise<void>\n\n /**\n * Called whenever a session deletion fails due to an unexpected error, such\n * as a network issue or server unavailability. This function can be used to\n * log the error or notify the user. When this function is called, the session\n * might still be valid on the server. It is up to the implementation to\n * decide whether to retry the deletion or keep the session active. Ignoring\n * these errors is not recommended as it can lead to orphaned sessions on the\n * server, or security issues if the user believes they have logged out when a\n * bad actor is still using the session. The implementation should consider\n * keeping track of failed deletions and retrying them later, until they\n * succeed.\n *\n * @note this function **must** not throw\n */\n onDeleteFailure?: (\n this: PasswordSession,\n data: SessionData,\n err: DeleteFailure,\n ) => void | Promise<void>\n}\n\nexport class PasswordSession implements Agent {\n /**\n * Internal {@link Agent} used for session management towards the\n * authentication service only.\n */\n #serviceAgent: Agent\n\n #sessionData: null | SessionData\n #sessionPromise: Promise<SessionData>\n\n constructor(\n sessionData: SessionData,\n protected readonly options: PasswordSessionOptions,\n ) {\n this.#serviceAgent = buildAgent({\n service: sessionData.service,\n fetch: options.fetch,\n })\n\n this.#sessionData = sessionData\n this.#sessionPromise = Promise.resolve(this.#sessionData)\n }\n\n get did() {\n return this.session.did\n }\n\n get handle() {\n return this.session.handle\n }\n\n get session() {\n if (this.#sessionData) return this.#sessionData\n throw new XrpcError('AuthenticationRequired', 'Logged out')\n }\n\n get destroyed(): boolean {\n return this.#sessionData === null\n }\n\n async fetchHandler(path: string, init: RequestInit): Promise<Response> {\n const headers = new Headers(init.headers)\n if (headers.has('authorization')) {\n throw new TypeError(\"Unexpected 'authorization' header set\")\n }\n\n const sessionPromise = this.#sessionPromise\n const sessionData = await sessionPromise\n\n const fetch = this.options.fetch ?? globalThis.fetch\n\n headers.set('authorization', `Bearer ${sessionData.accessJwt}`)\n const initialRes = await fetch(fetchUrl(sessionData, path), {\n ...init,\n headers,\n })\n\n const refreshNeeded =\n initialRes.status === 401 ||\n (initialRes.status === 400 &&\n (await extractXrpcErrorCode(initialRes)) === 'ExpiredToken')\n\n if (!refreshNeeded) {\n return initialRes\n }\n\n // Refresh session (unless it was already refreshed in the meantime)\n const newSessionPromise =\n this.#sessionPromise === sessionPromise\n ? this.refresh()\n : this.#sessionPromise\n\n // Error should have been propagated through hooks\n const newSessionData = await newSessionPromise.catch((_err) => null)\n if (!newSessionData) {\n return initialRes\n }\n\n // refresh silently failed, no point in retrying.\n if (newSessionData.accessJwt === sessionData.accessJwt) {\n return initialRes\n }\n\n if (init?.signal?.aborted) {\n return initialRes\n }\n\n // The stream was already consumed. We cannot retry the request. A solution\n // would be to tee() the input stream but that would bufferize the entire\n // stream in memory which can lead to memory starvation. Instead, we will\n // return the original response and let the calling code handle retries.\n if (ReadableStream && init?.body instanceof ReadableStream) {\n return initialRes\n }\n\n // Make sure the initial request is cancelled to avoid leaking resources\n // (NodeJS 👀): https://undici.nodejs.org/#/?id=garbage-collection\n if (!initialRes.bodyUsed) {\n await initialRes.body?.cancel()\n }\n\n // Finally, retry the request with the new access token\n headers.set('authorization', `Bearer ${newSessionData.accessJwt}`)\n return fetch(fetchUrl(newSessionData, path), { ...init, headers })\n }\n\n async refresh(): Promise<SessionData> {\n this.#sessionPromise = this.#sessionPromise.then(async (sessionData) => {\n const response = await xrpcSafe(\n this.#serviceAgent,\n com.atproto.server.refreshSession.main,\n { headers: { Authorization: `Bearer ${sessionData.refreshJwt}` } },\n )\n\n if (!response.success && response.matchesSchema()) {\n // Expected errors that indicate the session is no longer valid\n await this.options.onDeleted.call(this, sessionData)\n\n // Update the session promise to a rejected state\n this.#sessionData = null\n throw response\n }\n\n if (!response.success) {\n // We failed to refresh the token, assume the session might still be\n // valid by returning the existing session.\n await this.options.onUpdateFailure?.call(this, sessionData, response)\n\n return sessionData\n }\n\n const data = response.body\n\n // Historically, refreshSession did not return all the fields from\n // getSession. In particular, emailConfirmed and didDoc were missing.\n // Similarly, some servers might not return the didDoc in refreshSession.\n // We fetch them via getSession if missing, allowing to ensure that we are\n // always talking with the right PDS.\n if (data.emailConfirmed == null || data.didDoc == null) {\n const extraData = await xrpcSafe(\n this.#serviceAgent,\n com.atproto.server.getSession.main,\n { headers: { Authorization: `Bearer ${data.accessJwt}` } },\n )\n if (extraData.success && extraData.body.did === data.did) {\n Object.assign(data, extraData.body)\n }\n }\n\n const newSession: SessionData = {\n ...data,\n service: sessionData.service,\n }\n\n await this.options.onUpdated.call(this, newSession)\n\n return (this.#sessionData = newSession)\n })\n\n return this.#sessionPromise\n }\n\n async logout(): Promise<void> {\n let reason: DeleteFailure | null = null\n\n this.#sessionPromise = this.#sessionPromise.then(async (sessionData) => {\n const result = await xrpcSafe(\n this.#serviceAgent,\n com.atproto.server.deleteSession.main,\n { headers: { Authorization: `Bearer ${sessionData.refreshJwt}` } },\n )\n\n if (result.success || result.matchesSchema()) {\n await this.options.onDeleted.call(this, sessionData)\n\n // Update the session promise to a rejected state\n this.#sessionData = null\n throw new XrpcError('AuthenticationRequired', 'Logged out')\n } else {\n // Capture the reason for the failure to re-throw in the outer promise\n reason = result\n\n // An unknown/unexpected error occurred (network, server down, etc)\n await this.options.onDeleteFailure?.call(this, sessionData, result)\n\n // Keep the session in an active state\n return sessionData\n }\n })\n\n return this.#sessionPromise.then(\n (_session) => {\n // If the promise above resolved, then logout failed. Re-throw the\n // reason captured earlier.\n throw reason!\n },\n (_err) => {\n // Successful logout\n },\n )\n }\n\n /**\n * @note It is **not** recommended to use {@link PasswordSession} with main\n * account credentials. Instead, it is strongly advised to use OAuth based\n * authentication for main username/password credentials and use\n * {@link PasswordSession} with an app-password, for bots, scripts, or similar\n * use-cases.\n *\n * @throws If unable to create a session. In particular, if the server\n * requires a 2FA token, a {@link XrpcResponseError} with the\n * `AuthFactorTokenRequired` error code will be thrown.\n *\n *\n * @example Handling 2FA errors\n *\n * ```ts\n * try {\n * const session = await PasswordSession.create({\n * service: 'https://example.com',\n * identifier: 'alice',\n * password: 'correct horse battery staple',\n * })\n * } catch (err) {\n * if (err instanceof XrpcResponseError && err.error === 'AuthFactorTokenRequired') {\n * // Prompt user for 2FA token and re-attempt session creation\n * }\n * }\n * ```\n */\n static async create({\n service,\n identifier,\n password,\n allowTakendown,\n authFactorToken,\n ...options\n }: PasswordSessionOptions & {\n service: string | URL\n identifier: string\n password: string\n allowTakendown?: boolean\n authFactorToken?: string\n }): Promise<PasswordSession> {\n const xrpcAgent = buildAgent({\n service,\n fetch: options.fetch,\n })\n\n const response = await xrpcSafe(\n xrpcAgent,\n com.atproto.server.createSession.main,\n { body: { identifier, password, allowTakendown, authFactorToken } },\n )\n\n if (!response.success) {\n if (response.error === 'AuthFactorTokenRequired') {\n throw new LexAuthFactorError(response)\n }\n throw response.reason\n }\n\n const data: SessionData = {\n ...response.body,\n service: String(service),\n }\n\n const agent = new PasswordSession(data, options)\n await options.onUpdated.call(agent, data)\n return agent\n }\n\n /**\n * Resume an existing session, ensuring it is still valid by refreshing it.\n * Any error thrown here indicates that the session is definitely no longer\n * valid. Network errors will be propagated through the\n * {@link PasswordSessionOptions.onUpdateFailure} hook, and not re-thrown\n * here. This means that a resolved promise does not necessarily indicate a\n * valid session, only that it's refresh did not definitively fail.\n *\n * This is the same as calling {@link PasswordSession.refresh} after\n * constructing the {@link PasswordSession} manually.\n *\n * @throws If, and only if, the session is definitely no longer valid.\n */\n static async resume(\n data: SessionData,\n options: PasswordSessionOptions,\n ): Promise<PasswordSession> {\n const agent = new PasswordSession(data, options)\n await agent.refresh()\n return agent\n }\n\n /**\n * Delete a session without having to {@link resume resume()} it first, or\n * provide hooks.\n *\n * @throws In case of unexpected error (network issue, server down, etc)\n * meaning that the session may still be valid.\n */\n static async delete(\n data: SessionData,\n options?: Partial<PasswordSessionOptions>,\n ): Promise<void> {\n const agent = new PasswordSession(data, {\n ...options,\n onUpdated: options?.onUpdated ?? noop,\n onDeleted: options?.onDeleted ?? noop,\n })\n await agent.logout()\n }\n}\n\nfunction fetchUrl(sessionData: SessionData, path: string): URL {\n const pdsUrl = extractPdsUrl(sessionData.didDoc)\n return new URL(path, pdsUrl ?? sessionData.service)\n}\n"]}
|
package/dist/util.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LexMap } from '@atproto/lex-client';
|
|
2
2
|
export declare const noop: () => void;
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function extractXrpcErrorCode(response: Response): Promise<string | null>;
|
|
4
4
|
export declare function extractPdsUrl(didDoc?: LexMap): string | null;
|
|
5
5
|
//# sourceMappingURL=util.d.ts.map
|
package/dist/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,qBAAqB,CAAA;AAGtD,eAAO,MAAM,IAAI,YAAW,CAAA;AAE5B,wBAAsB,
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,qBAAqB,CAAA;AAGtD,eAAO,MAAM,IAAI,YAAW,CAAA;AAE5B,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAKxB;AA4BD,wBAAgB,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM5D"}
|
package/dist/util.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.noop = void 0;
|
|
4
|
-
exports.
|
|
4
|
+
exports.extractXrpcErrorCode = extractXrpcErrorCode;
|
|
5
5
|
exports.extractPdsUrl = extractPdsUrl;
|
|
6
6
|
const lex_schema_1 = require("@atproto/lex-schema");
|
|
7
7
|
const noop = () => { };
|
|
8
8
|
exports.noop = noop;
|
|
9
|
-
async function
|
|
9
|
+
async function extractXrpcErrorCode(response) {
|
|
10
10
|
const json = await peekJson(response, 10 * 1024); // Avoid reading large bodies
|
|
11
11
|
if (json === undefined)
|
|
12
12
|
return null;
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAKA,
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;AAKA,oDAOC;AA4BD,sCAMC;AA7CD,oDAAuC;AAEhC,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAA;AAAf,QAAA,IAAI,QAAW;AAErB,KAAK,UAAU,oBAAoB,CACxC,QAAkB;IAElB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,CAAA,CAAC,6BAA6B;IAC9E,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACnC,IAAI,CAAC,cAAC,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAA;AACnB,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,QAAkB,EAClB,OAAO,GAAG,QAAQ;IAElB,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;IAClC,IAAI,IAAI,KAAK,kBAAkB;QAAE,OAAO,SAAS,CAAA;IACjD,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;IACtC,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,GAAG,OAAO;QAAE,OAAO,SAAS,CAAA;IAExD,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAsB,CAAA;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,EAAE,OAAO,EAAY;IAC1C,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAClC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QACvC,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,OAAO,EAAY;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;AACzE,CAAC;AAED,SAAgB,aAAa,CAAC,MAAe;IAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAC5D,QAAQ,CAAE,OAAe,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CACzD,CAAA;IACD,MAAM,WAAW,GAAG,QAAQ,CAAE,UAAkB,EAAE,eAAe,CAAC,CAAA;IAClE,OAAO,WAAW,IAAI,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAA;AACtE,CAAC;AAED,MAAM,QAAQ,GAAG,CAAI,CAAI,EAAE,EAAE,CAC3B,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAIvB,CAAA;AAEjB,MAAM,OAAO,GAAG,CAAI,CAAI,EAAE,EAAE,CAC1B,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAIlB,CAAA","sourcesContent":["import { LexMap, LexValue } from '@atproto/lex-client'\nimport { l } from '@atproto/lex-schema'\n\nexport const noop = () => {}\n\nexport async function extractXrpcErrorCode(\n response: Response,\n): Promise<string | null> {\n const json = await peekJson(response, 10 * 1024) // Avoid reading large bodies\n if (json === undefined) return null\n if (!l.lexErrorData.matches(json)) return null\n return json.error\n}\n\nasync function peekJson(\n response: Response,\n maxSize = Infinity,\n): Promise<undefined | LexValue> {\n const type = extractType(response)\n if (type !== 'application/json') return undefined\n const length = extractLength(response)\n if (length != null && length > maxSize) return undefined\n\n try {\n return (await response.clone().json()) as Promise<LexValue>\n } catch {\n return undefined\n }\n}\n\nfunction extractLength({ headers }: Response) {\n return headers.get('Content-Length')\n ? Number(headers.get('Content-Length'))\n : undefined\n}\n\nfunction extractType({ headers }: Response) {\n return headers.get('Content-Type')?.split(';')[0]?.trim().toLowerCase()\n}\n\nexport function extractPdsUrl(didDoc?: LexMap): string | null {\n const pdsService = ifArray(didDoc?.service)?.find((service) =>\n ifString((service as any)?.id)?.endsWith('#atproto_pds'),\n )\n const pdsEndpoint = ifString((pdsService as any)?.serviceEndpoint)\n return pdsEndpoint && URL.canParse(pdsEndpoint) ? pdsEndpoint : null\n}\n\nconst ifString = <T>(v: T) =>\n (typeof v === 'string' ? v : undefined) as unknown extends T\n ? undefined | string\n : T extends string\n ? string\n : undefined\n\nconst ifArray = <T>(v: T) =>\n (Array.isArray(v) ? v : undefined) as unknown extends T\n ? undefined | unknown[]\n : T extends unknown[]\n ? Extract<T, unknown[]>\n : undefined\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lex-password-session",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Password based client authentication for AT Lexicons",
|
|
6
6
|
"keywords": [
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"tslib": "^2.8.1",
|
|
39
|
-
"@atproto/lex-client": "0.0.
|
|
40
|
-
"@atproto/lex-schema": "0.0.
|
|
39
|
+
"@atproto/lex-client": "0.0.10",
|
|
40
|
+
"@atproto/lex-schema": "0.0.10"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"vitest": "^4.0.16",
|
|
44
|
-
"@atproto/lex-builder": "0.0.
|
|
45
|
-
"@atproto/lex-server": "0.0.
|
|
44
|
+
"@atproto/lex-builder": "0.0.12",
|
|
45
|
+
"@atproto/lex-server": "0.0.6"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"prebuild": "node ./scripts/lex-build.mjs",
|
package/src/error.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { LexError,
|
|
1
|
+
import { LexError, XrpcResponseError } from '@atproto/lex-client'
|
|
2
2
|
import { com } from './lexicons'
|
|
3
3
|
|
|
4
4
|
export class LexAuthFactorError extends LexError {
|
|
5
5
|
name = 'LexAuthFactorError'
|
|
6
6
|
|
|
7
7
|
constructor(
|
|
8
|
-
readonly response:
|
|
8
|
+
readonly response: XrpcResponseError<
|
|
9
9
|
typeof com.atproto.server.createSession.main
|
|
10
10
|
>,
|
|
11
11
|
) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-namespace */
|
|
2
2
|
|
|
3
3
|
import { afterAll, assert, beforeAll, describe, expect, it, vi } from 'vitest'
|
|
4
|
-
import { Client,
|
|
4
|
+
import { Client, XrpcResponseError } from '@atproto/lex-client'
|
|
5
5
|
import { l } from '@atproto/lex-schema'
|
|
6
6
|
import { LexRouter, LexServerAuthError } from '@atproto/lex-server'
|
|
7
7
|
import { Server, serve } from '@atproto/lex-server/nodejs'
|
|
@@ -263,7 +263,7 @@ describe(PasswordSession, () => {
|
|
|
263
263
|
})
|
|
264
264
|
|
|
265
265
|
assert(result.success === false)
|
|
266
|
-
assert(result instanceof
|
|
266
|
+
assert(result instanceof XrpcResponseError)
|
|
267
267
|
expect(result).toMatchObject({
|
|
268
268
|
success: false,
|
|
269
269
|
status: 401,
|
package/src/password-session.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Agent,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
XrpcError,
|
|
4
|
+
XrpcFailure,
|
|
5
5
|
buildAgent,
|
|
6
6
|
xrpcSafe,
|
|
7
7
|
} from '@atproto/lex-client'
|
|
8
8
|
import { LexAuthFactorError } from './error.js'
|
|
9
9
|
import { com } from './lexicons/index.js'
|
|
10
|
-
import {
|
|
10
|
+
import { extractPdsUrl, extractXrpcErrorCode, noop } from './util.js'
|
|
11
11
|
|
|
12
|
-
export type RefreshFailure =
|
|
12
|
+
export type RefreshFailure = XrpcFailure<
|
|
13
13
|
typeof com.atproto.server.refreshSession.main
|
|
14
14
|
>
|
|
15
15
|
|
|
16
|
-
export type DeleteFailure =
|
|
16
|
+
export type DeleteFailure = XrpcFailure<
|
|
17
17
|
typeof com.atproto.server.deleteSession.main
|
|
18
18
|
>
|
|
19
19
|
|
|
@@ -117,7 +117,7 @@ export class PasswordSession implements Agent {
|
|
|
117
117
|
|
|
118
118
|
get session() {
|
|
119
119
|
if (this.#sessionData) return this.#sessionData
|
|
120
|
-
throw new
|
|
120
|
+
throw new XrpcError('AuthenticationRequired', 'Logged out')
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
get destroyed(): boolean {
|
|
@@ -144,7 +144,7 @@ export class PasswordSession implements Agent {
|
|
|
144
144
|
const refreshNeeded =
|
|
145
145
|
initialRes.status === 401 ||
|
|
146
146
|
(initialRes.status === 400 &&
|
|
147
|
-
(await
|
|
147
|
+
(await extractXrpcErrorCode(initialRes)) === 'ExpiredToken')
|
|
148
148
|
|
|
149
149
|
if (!refreshNeeded) {
|
|
150
150
|
return initialRes
|
|
@@ -261,7 +261,7 @@ export class PasswordSession implements Agent {
|
|
|
261
261
|
|
|
262
262
|
// Update the session promise to a rejected state
|
|
263
263
|
this.#sessionData = null
|
|
264
|
-
throw new
|
|
264
|
+
throw new XrpcError('AuthenticationRequired', 'Logged out')
|
|
265
265
|
} else {
|
|
266
266
|
// Capture the reason for the failure to re-throw in the outer promise
|
|
267
267
|
reason = result
|
|
@@ -294,7 +294,7 @@ export class PasswordSession implements Agent {
|
|
|
294
294
|
* use-cases.
|
|
295
295
|
*
|
|
296
296
|
* @throws If unable to create a session. In particular, if the server
|
|
297
|
-
* requires a 2FA token, a {@link
|
|
297
|
+
* requires a 2FA token, a {@link XrpcResponseError} with the
|
|
298
298
|
* `AuthFactorTokenRequired` error code will be thrown.
|
|
299
299
|
*
|
|
300
300
|
*
|
|
@@ -308,7 +308,7 @@ export class PasswordSession implements Agent {
|
|
|
308
308
|
* password: 'correct horse battery staple',
|
|
309
309
|
* })
|
|
310
310
|
* } catch (err) {
|
|
311
|
-
* if (err instanceof
|
|
311
|
+
* if (err instanceof XrpcResponseError && err.error === 'AuthFactorTokenRequired') {
|
|
312
312
|
* // Prompt user for 2FA token and re-attempt session creation
|
|
313
313
|
* }
|
|
314
314
|
* }
|
package/src/util.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { l } from '@atproto/lex-schema'
|
|
|
3
3
|
|
|
4
4
|
export const noop = () => {}
|
|
5
5
|
|
|
6
|
-
export async function
|
|
6
|
+
export async function extractXrpcErrorCode(
|
|
7
7
|
response: Response,
|
|
8
8
|
): Promise<string | null> {
|
|
9
9
|
const json = await peekJson(response, 10 * 1024) // Avoid reading large bodies
|