@authup/errors 1.0.0-beta.69 → 1.0.0-beta.71
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/README.md +106 -0
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/authup/authup/master/.github/assets/logo.svg" alt="Authup logo" width="96" height="96" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">@authup/errors</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<b>Authup's error classes, error codes and code-to-HTTP-status mapping, with guards that survive JSON.</b><br>
|
|
9
|
+
One error vocabulary for the server, the HTTP client and the consoles, so a caller branches on a code, not a message.
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
<p align="center">
|
|
13
|
+
<a href="https://www.npmjs.com/package/@authup/errors"><img src="https://img.shields.io/npm/v/@authup/errors" alt="npm version" /></a>
|
|
14
|
+
<a href="https://github.com/authup/authup/actions/workflows/main.yml"><img src="https://github.com/authup/authup/actions/workflows/main.yml/badge.svg" alt="CI" /></a>
|
|
15
|
+
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue" alt="License: Apache-2.0" /></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="#installation"><b>Installation</b></a> · <a href="#usage">Usage</a> · <a href="#api">API</a> · <a href="https://authup.org">Documentation</a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Where it fits
|
|
25
|
+
|
|
26
|
+
Every Authup workspace that throws or inspects an error imports this package: the server throws its classes, the HTTP error middleware maps their `code` to a status, and [`@authup/core-http-kit`](https://github.com/authup/authup/tree/master/packages/core-http-kit) and the consoles read the same codes back out of response bodies. Install it directly when your own code calls the Authup API and wants to branch on what went wrong (`isEntityNotFoundError(error)`, `error.code === ErrorCode.JWT_EXPIRED`), or when you build a service on Authup's server packages and want to throw errors the same middleware understands.
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```shell
|
|
31
|
+
npm install @authup/errors
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
ESM only. Node.js `^22.13.0 || ^23.5.0 || >=24.0.0`. It has one runtime dependency, `@ebec/core`, and no Node-specific APIs.
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Throw and map to a status
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { EntityNotFoundError, ErrorCode, httpStatusFromCode } from '@authup/errors';
|
|
42
|
+
|
|
43
|
+
const error = new EntityNotFoundError({ entity: 'user' });
|
|
44
|
+
|
|
45
|
+
error.message; // 'The user was not found.'
|
|
46
|
+
error.code === ErrorCode.ENTITY_NOT_FOUND; // true
|
|
47
|
+
httpStatusFromCode(error.code); // 404
|
|
48
|
+
httpStatusFromCode(ErrorCode.REGISTRATION_DISABLED); // 400, the fallback
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- Every class extends `AuthupError` and sets its own `code` and default message. Pass a string to replace the message, or an options object (`message`, `code`, `data`, `cause`, and `entity` on the entity classes).
|
|
52
|
+
- `data` is merged into the JSON form, which is how `LoginThrottledError`, `MfaThrottledError` and `DeviceVerificationThrottledError` carry `retryAfter` (seconds) to the client.
|
|
53
|
+
- `httpStatusFromCode(code, fallback = 400)` answers from `ERROR_CODE_TO_STATUS`; any code not listed there gets the fallback. `codeFromHttpStatus` goes the other way for errors from a foreign source.
|
|
54
|
+
|
|
55
|
+
### Recognize an error that crossed the wire
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { isAuthupError, isEntityNotFoundError, serializeError } from '@authup/errors';
|
|
59
|
+
|
|
60
|
+
declare const error: Error;
|
|
61
|
+
|
|
62
|
+
const body = JSON.parse(JSON.stringify(serializeError(error)));
|
|
63
|
+
|
|
64
|
+
if (isEntityNotFoundError(body)) {
|
|
65
|
+
// body.code === 'entity_not_found'
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (isAuthupError(body)) {
|
|
69
|
+
console.log(body.code, body.message);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- `serializeError` calls `toJSON()` when the error has one and otherwise spreads its own properties plus `name` and `message`. Use it wherever an error becomes a response body.
|
|
74
|
+
- The guards do not need `instanceof`. Each class stamps a `Symbol.for(...)` marker, and `toJSON()` writes the marker chain as strings under the same key, so a guard recognizes the live error and the parsed JSON alike.
|
|
75
|
+
- `normalizeError(value)` turns anything thrown (a string, a number, an object) into a real `Error`.
|
|
76
|
+
|
|
77
|
+
## API
|
|
78
|
+
|
|
79
|
+
| Export | Kind | Purpose |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `AuthupError` | class | Base class: a `BaseError` from `@ebec/core` with an optional `data` record merged into `toJSON()` |
|
|
82
|
+
| `BadRequestError`, `ValidationError` | class | `bad_request` (400) |
|
|
83
|
+
| `UnauthorizedError`, `AuthHeaderError`, `BearerTokenMalformedError` | class | `identity_unauthorized`, `unsupported_auth_header_type`, `bearer_token_malformed` (401) |
|
|
84
|
+
| `EntityNotFoundError`, `EntityConflictError`, `EntityInactiveError`, `EntityCredentialsInvalidError` | class | `entity_not_found` (404), `entity_conflict` (409), `entity_inactive`, `invalid_credentials` (400); option `entity` names the entity in the message |
|
|
85
|
+
| `LoginThrottledError`, `MfaThrottledError`, `DeviceVerificationThrottledError` | class | 429 with `data.retryAfter` |
|
|
86
|
+
| `InternalError` | class | `internal_error` (500) |
|
|
87
|
+
| `isError`, `isAuthupError`, `is<Class>Error` | function | Duck-type guards, one per class |
|
|
88
|
+
| `ErrorCode` | enum | Every code Authup emits: generic, entity, identity, JWT, JWK, OAuth2, permission and policy codes |
|
|
89
|
+
| `ERROR_CODE_TO_STATUS`, `httpStatusFromCode`, `codeFromHttpStatus` | const, function | Code-to-status mapping |
|
|
90
|
+
| `serializeError`, `normalizeError` | function | JSON boundary and unknown-value normalization |
|
|
91
|
+
| `AuthupErrorOptions`, `AuthupErrorInput`, `AuthupEntityErrorOptions`, `AuthupEntityErrorInput` | type | Constructor input types |
|
|
92
|
+
| `matchesInstanceof`, `hasInstanceof`, `markInstanceof`, `serializeInstanceofChain`, `INSTANCEOF_PROPERTY`, `BASE_ERROR_INSTANCE` | re-export | The `@ebec/core` marker primitives, for your own error classes |
|
|
93
|
+
|
|
94
|
+
Each class also exports its marker symbol (`ENTITY_NOT_FOUND_ERROR_INSTANCE`, ...).
|
|
95
|
+
|
|
96
|
+
## Notes
|
|
97
|
+
|
|
98
|
+
- **`isAuthupError` needs the marker chain.** An object without the `@instanceof` list (a hand-built `{ code, message }`, or a body from an older server) is not an `AuthupError`, even when it carries an Authup code. Read `body.code` directly in that case.
|
|
99
|
+
- **A class guard also accepts the plain code.** `isEntityNotFoundError` is true for any `AuthupError` whose `code` is `entity_not_found`, not only for instances of that class. `ValidationError` and `BadRequestError` share `bad_request`, so `isValidationError` and `isBadRequestError` are both true for either class.
|
|
100
|
+
- **The status lives in the mapping, not on the error.** No class carries an HTTP status; codes not in `ERROR_CODE_TO_STATUS` map to 400 by default.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
Made with 💚
|
|
105
|
+
|
|
106
|
+
Published under the [Apache 2.0 License](./LICENSE).
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authup/errors",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.0-beta.
|
|
5
|
-
"description": "
|
|
4
|
+
"version": "1.0.0-beta.71",
|
|
5
|
+
"description": "Authup's error classes, error codes and code-to-HTTP-status mapping, with guards that survive JSON.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"exports": {
|
|
8
8
|
"./package.json": "./package.json",
|