@atproto/lex-server 0.0.7 → 0.0.9
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 +30 -0
- package/dist/errors.d.ts +94 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +94 -0
- package/dist/errors.js.map +1 -1
- package/dist/lex-server.d.ts +481 -2
- package/dist/lex-server.d.ts.map +1 -1
- package/dist/lex-server.js +103 -0
- package/dist/lex-server.js.map +1 -1
- package/dist/lib/www-authenticate.d.ts +66 -0
- package/dist/lib/www-authenticate.d.ts.map +1 -1
- package/dist/lib/www-authenticate.js +28 -0
- package/dist/lib/www-authenticate.js.map +1 -1
- package/dist/nodejs.d.ts +279 -0
- package/dist/nodejs.d.ts.map +1 -1
- package/dist/nodejs.js +184 -1
- package/dist/nodejs.js.map +1 -1
- package/dist/service-auth.d.ts +151 -9
- package/dist/service-auth.d.ts.map +1 -1
- package/dist/service-auth.js +41 -2
- package/dist/service-auth.js.map +1 -1
- package/package.json +11 -11
- package/src/errors.ts +94 -0
- package/src/lex-server.test.ts +3 -2
- package/src/lex-server.ts +482 -2
- package/src/lib/www-authenticate.ts +66 -0
- package/src/nodejs.ts +280 -2
- package/src/service-auth.ts +151 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @atproto/lex-server
|
|
2
2
|
|
|
3
|
+
## 0.0.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#4603](https://github.com/bluesky-social/atproto/pull/4603) [`7b9a98a`](https://github.com/bluesky-social/atproto/commit/7b9a98a763636c5f66a06da11fe6013f29dd9157) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Fix flaky test
|
|
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)! - Fix `exports` field in package.json
|
|
10
|
+
|
|
11
|
+
- [#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
|
|
12
|
+
|
|
13
|
+
- 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)]:
|
|
14
|
+
- @atproto/lex-schema@0.0.12
|
|
15
|
+
- @atproto/lex-json@0.0.11
|
|
16
|
+
- @atproto/lex-cbor@0.0.11
|
|
17
|
+
- @atproto/lex-data@0.0.11
|
|
18
|
+
|
|
19
|
+
## 0.0.8
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
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 `LexRouter.handlers` property public
|
|
24
|
+
|
|
25
|
+
- [#4589](https://github.com/bluesky-social/atproto/pull/4589) [`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Expose `sendResponse` for writing a `Response` object to a NodeJS `ServerResponse`
|
|
26
|
+
|
|
27
|
+
- Updated dependencies [[`369bb02`](https://github.com/bluesky-social/atproto/commit/369bb02b9f80f0e15e5242e54f09bd4e01117f3a)]:
|
|
28
|
+
- @atproto/lex-data@0.0.10
|
|
29
|
+
- @atproto/lex-cbor@0.0.10
|
|
30
|
+
- @atproto/lex-json@0.0.10
|
|
31
|
+
- @atproto/lex-schema@0.0.11
|
|
32
|
+
|
|
3
33
|
## 0.0.7
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,13 +1,107 @@
|
|
|
1
1
|
import { LexError, LexErrorCode } from '@atproto/lex-data';
|
|
2
2
|
import { WWWAuthenticate } from './lib/www-authenticate.js';
|
|
3
3
|
export type { WWWAuthenticate };
|
|
4
|
+
/**
|
|
5
|
+
* Error class for authentication failures in XRPC server handlers.
|
|
6
|
+
*
|
|
7
|
+
* Extends {@link LexError} to include WWW-Authenticate header support,
|
|
8
|
+
* which is required by HTTP authentication standards (RFC 7235).
|
|
9
|
+
* The error automatically generates the appropriate 401 response with
|
|
10
|
+
* the WWW-Authenticate header when converted to a Response.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam N - The Lexicon error code type
|
|
13
|
+
*
|
|
14
|
+
* @example Throwing an auth error
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { LexServerAuthError } from '@atproto/lex-server'
|
|
17
|
+
*
|
|
18
|
+
* throw new LexServerAuthError(
|
|
19
|
+
* 'AuthenticationRequired',
|
|
20
|
+
* 'Invalid or expired token',
|
|
21
|
+
* { Bearer: { error: 'InvalidToken', realm: 'api.example.com' } }
|
|
22
|
+
* )
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example Converting from a LexError
|
|
26
|
+
* ```typescript
|
|
27
|
+
* try {
|
|
28
|
+
* await validateToken(token)
|
|
29
|
+
* } catch (error) {
|
|
30
|
+
* if (error instanceof LexError) {
|
|
31
|
+
* throw LexServerAuthError.from(error, {
|
|
32
|
+
* Bearer: { error: 'InvalidToken' }
|
|
33
|
+
* })
|
|
34
|
+
* }
|
|
35
|
+
* throw error
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
4
39
|
export declare class LexServerAuthError<N extends LexErrorCode = LexErrorCode> extends LexError<N> {
|
|
5
40
|
readonly wwwAuthenticate: WWWAuthenticate;
|
|
6
41
|
name: string;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new authentication error.
|
|
44
|
+
*
|
|
45
|
+
* @param error - The Lexicon error code (e.g., 'AuthenticationRequired')
|
|
46
|
+
* @param message - Human-readable error message
|
|
47
|
+
* @param wwwAuthenticate - WWW-Authenticate header parameters
|
|
48
|
+
* @param options - Standard Error options including `cause`
|
|
49
|
+
*/
|
|
7
50
|
constructor(error: N, message: string, wwwAuthenticate?: WWWAuthenticate, options?: ErrorOptions);
|
|
51
|
+
/**
|
|
52
|
+
* Gets the formatted WWW-Authenticate header value.
|
|
53
|
+
*
|
|
54
|
+
* @returns The formatted header string for the 401 response
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const error = new LexServerAuthError('AuthenticationRequired', 'Token required', {
|
|
59
|
+
* Bearer: { realm: 'api.example.com', error: 'MissingToken' }
|
|
60
|
+
* })
|
|
61
|
+
* console.log(error.wwwAuthenticateHeader)
|
|
62
|
+
* // Output: 'Bearer realm="api.example.com", error="MissingToken"'
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
8
65
|
get wwwAuthenticateHeader(): string;
|
|
66
|
+
/**
|
|
67
|
+
* Converts the error to a JSON representation suitable for response bodies.
|
|
68
|
+
*
|
|
69
|
+
* If the error was created from another LexError (via `from()`), returns
|
|
70
|
+
* the original error's JSON representation.
|
|
71
|
+
*
|
|
72
|
+
* @returns JSON object with error code and message
|
|
73
|
+
*/
|
|
9
74
|
toJSON(): import("@atproto/lex-data").LexErrorData<any>;
|
|
75
|
+
/**
|
|
76
|
+
* Converts the error to an HTTP 401 Response with WWW-Authenticate header.
|
|
77
|
+
*
|
|
78
|
+
* The response includes:
|
|
79
|
+
* - Status code 401 (Unauthorized)
|
|
80
|
+
* - WWW-Authenticate header (if parameters were provided)
|
|
81
|
+
* - Access-Control-Expose-Headers for CORS compatibility
|
|
82
|
+
* - JSON body with error details
|
|
83
|
+
*
|
|
84
|
+
* @returns HTTP Response object ready to be sent to the client
|
|
85
|
+
*/
|
|
10
86
|
toResponse(): Response;
|
|
87
|
+
/**
|
|
88
|
+
* Creates a LexServerAuthError from an existing LexError.
|
|
89
|
+
*
|
|
90
|
+
* If the input is already a LexServerAuthError, returns it unchanged.
|
|
91
|
+
* Otherwise, wraps the error with the provided WWW-Authenticate parameters.
|
|
92
|
+
*
|
|
93
|
+
* @param cause - The original LexError to wrap
|
|
94
|
+
* @param wwwAuthenticate - WWW-Authenticate header parameters
|
|
95
|
+
* @returns A LexServerAuthError instance
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const lexError = new LexError('AuthenticationRequired', 'Token expired')
|
|
100
|
+
* const authError = LexServerAuthError.from(lexError, {
|
|
101
|
+
* Bearer: { error: 'ExpiredToken' }
|
|
102
|
+
* })
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
11
105
|
static from(cause: LexError, wwwAuthenticate?: WWWAuthenticate): LexServerAuthError;
|
|
12
106
|
}
|
|
13
107
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EACL,eAAe,EAEhB,MAAM,2BAA2B,CAAA;AAElC,YAAY,EAAE,eAAe,EAAE,CAAA;AAE/B,qBAAa,kBAAkB,CAC7B,CAAC,SAAS,YAAY,GAAG,YAAY,CACrC,SAAQ,QAAQ,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,EACL,eAAe,EAEhB,MAAM,2BAA2B,CAAA;AAElC,YAAY,EAAE,eAAe,EAAE,CAAA;AAE/B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,kBAAkB,CAC7B,CAAC,SAAS,YAAY,GAAG,YAAY,CACrC,SAAQ,QAAQ,CAAC,CAAC,CAAC;IAcjB,QAAQ,CAAC,eAAe,EAAE,eAAe;IAb3C,IAAI,SAAuB;IAE3B;;;;;;;OAOG;gBAED,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,MAAM,EACN,eAAe,GAAE,eAAoB,EAC9C,OAAO,CAAC,EAAE,YAAY;IAKxB;;;;;;;;;;;;;OAaG;IACH,IAAI,qBAAqB,IAAI,MAAM,CAElC;IAED;;;;;;;OAOG;IACH,MAAM;IAKN;;;;;;;;;;OAUG;IACH,UAAU,IAAI,QAAQ;IAatB;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,IAAI,CACT,KAAK,EAAE,QAAQ,EACf,eAAe,CAAC,EAAE,eAAe,GAChC,kBAAkB;CAMtB"}
|
package/dist/errors.js
CHANGED
|
@@ -3,20 +3,96 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.LexServerAuthError = void 0;
|
|
4
4
|
const lex_data_1 = require("@atproto/lex-data");
|
|
5
5
|
const www_authenticate_js_1 = require("./lib/www-authenticate.js");
|
|
6
|
+
/**
|
|
7
|
+
* Error class for authentication failures in XRPC server handlers.
|
|
8
|
+
*
|
|
9
|
+
* Extends {@link LexError} to include WWW-Authenticate header support,
|
|
10
|
+
* which is required by HTTP authentication standards (RFC 7235).
|
|
11
|
+
* The error automatically generates the appropriate 401 response with
|
|
12
|
+
* the WWW-Authenticate header when converted to a Response.
|
|
13
|
+
*
|
|
14
|
+
* @typeParam N - The Lexicon error code type
|
|
15
|
+
*
|
|
16
|
+
* @example Throwing an auth error
|
|
17
|
+
* ```typescript
|
|
18
|
+
* import { LexServerAuthError } from '@atproto/lex-server'
|
|
19
|
+
*
|
|
20
|
+
* throw new LexServerAuthError(
|
|
21
|
+
* 'AuthenticationRequired',
|
|
22
|
+
* 'Invalid or expired token',
|
|
23
|
+
* { Bearer: { error: 'InvalidToken', realm: 'api.example.com' } }
|
|
24
|
+
* )
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Converting from a LexError
|
|
28
|
+
* ```typescript
|
|
29
|
+
* try {
|
|
30
|
+
* await validateToken(token)
|
|
31
|
+
* } catch (error) {
|
|
32
|
+
* if (error instanceof LexError) {
|
|
33
|
+
* throw LexServerAuthError.from(error, {
|
|
34
|
+
* Bearer: { error: 'InvalidToken' }
|
|
35
|
+
* })
|
|
36
|
+
* }
|
|
37
|
+
* throw error
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
6
41
|
class LexServerAuthError extends lex_data_1.LexError {
|
|
7
42
|
wwwAuthenticate;
|
|
8
43
|
name = 'LexServerAuthError';
|
|
44
|
+
/**
|
|
45
|
+
* Creates a new authentication error.
|
|
46
|
+
*
|
|
47
|
+
* @param error - The Lexicon error code (e.g., 'AuthenticationRequired')
|
|
48
|
+
* @param message - Human-readable error message
|
|
49
|
+
* @param wwwAuthenticate - WWW-Authenticate header parameters
|
|
50
|
+
* @param options - Standard Error options including `cause`
|
|
51
|
+
*/
|
|
9
52
|
constructor(error, message, wwwAuthenticate = {}, options) {
|
|
10
53
|
super(error, message, options);
|
|
11
54
|
this.wwwAuthenticate = wwwAuthenticate;
|
|
12
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Gets the formatted WWW-Authenticate header value.
|
|
58
|
+
*
|
|
59
|
+
* @returns The formatted header string for the 401 response
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const error = new LexServerAuthError('AuthenticationRequired', 'Token required', {
|
|
64
|
+
* Bearer: { realm: 'api.example.com', error: 'MissingToken' }
|
|
65
|
+
* })
|
|
66
|
+
* console.log(error.wwwAuthenticateHeader)
|
|
67
|
+
* // Output: 'Bearer realm="api.example.com", error="MissingToken"'
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
13
70
|
get wwwAuthenticateHeader() {
|
|
14
71
|
return (0, www_authenticate_js_1.formatWWWAuthenticateHeader)(this.wwwAuthenticate);
|
|
15
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Converts the error to a JSON representation suitable for response bodies.
|
|
75
|
+
*
|
|
76
|
+
* If the error was created from another LexError (via `from()`), returns
|
|
77
|
+
* the original error's JSON representation.
|
|
78
|
+
*
|
|
79
|
+
* @returns JSON object with error code and message
|
|
80
|
+
*/
|
|
16
81
|
toJSON() {
|
|
17
82
|
const { cause } = this;
|
|
18
83
|
return cause instanceof lex_data_1.LexError ? cause.toJSON() : super.toJSON();
|
|
19
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Converts the error to an HTTP 401 Response with WWW-Authenticate header.
|
|
87
|
+
*
|
|
88
|
+
* The response includes:
|
|
89
|
+
* - Status code 401 (Unauthorized)
|
|
90
|
+
* - WWW-Authenticate header (if parameters were provided)
|
|
91
|
+
* - Access-Control-Expose-Headers for CORS compatibility
|
|
92
|
+
* - JSON body with error details
|
|
93
|
+
*
|
|
94
|
+
* @returns HTTP Response object ready to be sent to the client
|
|
95
|
+
*/
|
|
20
96
|
toResponse() {
|
|
21
97
|
const { wwwAuthenticateHeader } = this;
|
|
22
98
|
const headers = wwwAuthenticateHeader
|
|
@@ -27,6 +103,24 @@ class LexServerAuthError extends lex_data_1.LexError {
|
|
|
27
103
|
: undefined;
|
|
28
104
|
return Response.json(this.toJSON(), { status: 401, headers });
|
|
29
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Creates a LexServerAuthError from an existing LexError.
|
|
108
|
+
*
|
|
109
|
+
* If the input is already a LexServerAuthError, returns it unchanged.
|
|
110
|
+
* Otherwise, wraps the error with the provided WWW-Authenticate parameters.
|
|
111
|
+
*
|
|
112
|
+
* @param cause - The original LexError to wrap
|
|
113
|
+
* @param wwwAuthenticate - WWW-Authenticate header parameters
|
|
114
|
+
* @returns A LexServerAuthError instance
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const lexError = new LexError('AuthenticationRequired', 'Token expired')
|
|
119
|
+
* const authError = LexServerAuthError.from(lexError, {
|
|
120
|
+
* Bearer: { error: 'ExpiredToken' }
|
|
121
|
+
* })
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
30
124
|
static from(cause, wwwAuthenticate) {
|
|
31
125
|
if (cause instanceof LexServerAuthError)
|
|
32
126
|
return cause;
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,gDAA0D;AAC1D,mEAGkC;AAIlC,MAAa,kBAEX,SAAQ,mBAAW;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAAA,gDAA0D;AAC1D,mEAGkC;AAIlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAa,kBAEX,SAAQ,mBAAW;IAcR;IAbX,IAAI,GAAG,oBAAoB,CAAA;IAE3B;;;;;;;OAOG;IACH,YACE,KAAQ,EACR,OAAe,EACN,kBAAmC,EAAE,EAC9C,OAAsB;QAEtB,KAAK,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;QAHrB,oBAAe,GAAf,eAAe,CAAsB;IAIhD,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,IAAI,qBAAqB;QACvB,OAAO,IAAA,iDAA2B,EAAC,IAAI,CAAC,eAAe,CAAC,CAAA;IAC1D,CAAC;IAED;;;;;;;OAOG;IACH,MAAM;QACJ,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAA;QACtB,OAAO,KAAK,YAAY,mBAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAA;IACpE,CAAC;IAED;;;;;;;;;;OAUG;IACH,UAAU;QACR,MAAM,EAAE,qBAAqB,EAAE,GAAG,IAAI,CAAA;QAEtC,MAAM,OAAO,GAAG,qBAAqB;YACnC,CAAC,CAAC,IAAI,OAAO,CAAC;gBACV,kBAAkB,EAAE,qBAAqB;gBACzC,+BAA+B,EAAE,kBAAkB,EAAE,OAAO;aAC7D,CAAC;YACJ,CAAC,CAAC,SAAS,CAAA;QAEb,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAA;IAC/D,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,IAAI,CACT,KAAe,EACf,eAAiC;QAEjC,IAAI,KAAK,YAAY,kBAAkB;YAAE,OAAO,KAAK,CAAA;QACrD,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE;YACzE,KAAK;SACN,CAAC,CAAA;IACJ,CAAC;CACF;AAxGD,gDAwGC","sourcesContent":["import { LexError, LexErrorCode } from '@atproto/lex-data'\nimport {\n WWWAuthenticate,\n formatWWWAuthenticateHeader,\n} from './lib/www-authenticate.js'\n\nexport type { WWWAuthenticate }\n\n/**\n * Error class for authentication failures in XRPC server handlers.\n *\n * Extends {@link LexError} to include WWW-Authenticate header support,\n * which is required by HTTP authentication standards (RFC 7235).\n * The error automatically generates the appropriate 401 response with\n * the WWW-Authenticate header when converted to a Response.\n *\n * @typeParam N - The Lexicon error code type\n *\n * @example Throwing an auth error\n * ```typescript\n * import { LexServerAuthError } from '@atproto/lex-server'\n *\n * throw new LexServerAuthError(\n * 'AuthenticationRequired',\n * 'Invalid or expired token',\n * { Bearer: { error: 'InvalidToken', realm: 'api.example.com' } }\n * )\n * ```\n *\n * @example Converting from a LexError\n * ```typescript\n * try {\n * await validateToken(token)\n * } catch (error) {\n * if (error instanceof LexError) {\n * throw LexServerAuthError.from(error, {\n * Bearer: { error: 'InvalidToken' }\n * })\n * }\n * throw error\n * }\n * ```\n */\nexport class LexServerAuthError<\n N extends LexErrorCode = LexErrorCode,\n> extends LexError<N> {\n name = 'LexServerAuthError'\n\n /**\n * Creates a new authentication error.\n *\n * @param error - The Lexicon error code (e.g., 'AuthenticationRequired')\n * @param message - Human-readable error message\n * @param wwwAuthenticate - WWW-Authenticate header parameters\n * @param options - Standard Error options including `cause`\n */\n constructor(\n error: N,\n message: string,\n readonly wwwAuthenticate: WWWAuthenticate = {},\n options?: ErrorOptions,\n ) {\n super(error, message, options)\n }\n\n /**\n * Gets the formatted WWW-Authenticate header value.\n *\n * @returns The formatted header string for the 401 response\n *\n * @example\n * ```typescript\n * const error = new LexServerAuthError('AuthenticationRequired', 'Token required', {\n * Bearer: { realm: 'api.example.com', error: 'MissingToken' }\n * })\n * console.log(error.wwwAuthenticateHeader)\n * // Output: 'Bearer realm=\"api.example.com\", error=\"MissingToken\"'\n * ```\n */\n get wwwAuthenticateHeader(): string {\n return formatWWWAuthenticateHeader(this.wwwAuthenticate)\n }\n\n /**\n * Converts the error to a JSON representation suitable for response bodies.\n *\n * If the error was created from another LexError (via `from()`), returns\n * the original error's JSON representation.\n *\n * @returns JSON object with error code and message\n */\n toJSON() {\n const { cause } = this\n return cause instanceof LexError ? cause.toJSON() : super.toJSON()\n }\n\n /**\n * Converts the error to an HTTP 401 Response with WWW-Authenticate header.\n *\n * The response includes:\n * - Status code 401 (Unauthorized)\n * - WWW-Authenticate header (if parameters were provided)\n * - Access-Control-Expose-Headers for CORS compatibility\n * - JSON body with error details\n *\n * @returns HTTP Response object ready to be sent to the client\n */\n toResponse(): Response {\n const { wwwAuthenticateHeader } = this\n\n const headers = wwwAuthenticateHeader\n ? new Headers({\n 'WWW-Authenticate': wwwAuthenticateHeader,\n 'Access-Control-Expose-Headers': 'WWW-Authenticate', // CORS\n })\n : undefined\n\n return Response.json(this.toJSON(), { status: 401, headers })\n }\n\n /**\n * Creates a LexServerAuthError from an existing LexError.\n *\n * If the input is already a LexServerAuthError, returns it unchanged.\n * Otherwise, wraps the error with the provided WWW-Authenticate parameters.\n *\n * @param cause - The original LexError to wrap\n * @param wwwAuthenticate - WWW-Authenticate header parameters\n * @returns A LexServerAuthError instance\n *\n * @example\n * ```typescript\n * const lexError = new LexError('AuthenticationRequired', 'Token expired')\n * const authError = LexServerAuthError.from(lexError, {\n * Bearer: { error: 'ExpiredToken' }\n * })\n * ```\n */\n static from(\n cause: LexError,\n wwwAuthenticate?: WWWAuthenticate,\n ): LexServerAuthError {\n if (cause instanceof LexServerAuthError) return cause\n return new LexServerAuthError(cause.error, cause.message, wwwAuthenticate, {\n cause,\n })\n }\n}\n"]}
|