@authup/errors 1.0.0-beta.69 → 1.0.0-beta.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +106 -0
  2. 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.69",
5
- "description": "Package containing error codes and basic error classes.",
4
+ "version": "1.0.0-beta.70",
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",