first commit
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
# oauth-client-error
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Defines the stable error-code registry and typed error class for `@suaveplan/oauth-client`. All runtime failures thrown by this package originate from `OAuthClientError`, which extends `SuaveplanError` to provide deterministic error codes, cause-chain traversal, structured context, and OTel span-event integration inherited from `@suaveplan/error`.
|
||||
|
||||
Having a single error hierarchy makes it straightforward for callers to distinguish OAuth-specific failures (via `instanceof OAuthClientError`) from other application errors and to map codes to user-facing messages without pattern-matching raw strings.
|
||||
|
||||
## Features
|
||||
|
||||
- `OAUTH_CLIENT_CODES` — stable, tree-shakeable code registry produced by `defineCodes("OAUTH_CLIENT", …)`.
|
||||
- Codes for every failure domain: authorization, token exchange, token refresh, token revocation, token expiry, state/PKCE mismatch, OIDC discovery, config validation, ID-token validation, and unknown-provider lookups.
|
||||
- `OAuthClientErrorCode` — union type derived directly from the registry, providing exhaustive narrowing.
|
||||
- `OAuthClientError` — public constructor extending `SuaveplanError<OAuthClientErrorCode>` with `name = "OAuthClientError"`.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { OAuthClientError, OAUTH_CLIENT_CODES } from "@suaveplan/oauth-client/errors";
|
||||
|
||||
throw new OAuthClientError(
|
||||
OAUTH_CLIENT_CODES.INVALID_STATE,
|
||||
"oauth.state.mismatch",
|
||||
);
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { OAuthClientError, OAUTH_CLIENT_CODES } from "@suaveplan/oauth-client/errors";
|
||||
|
||||
try {
|
||||
const tokens = await client.handleCallback(code, state, storedState, verifier);
|
||||
} catch (err) {
|
||||
if (err instanceof OAuthClientError) {
|
||||
switch (err.code) {
|
||||
case OAUTH_CLIENT_CODES.INVALID_STATE:
|
||||
// CSRF attack or stale session — abort
|
||||
break;
|
||||
case OAUTH_CLIENT_CODES.TOKEN_EXCHANGE_FAILED:
|
||||
// Show user-facing error with err.context?.statusCode
|
||||
break;
|
||||
default:
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `OAUTH_CLIENT_CODES`
|
||||
|
||||
```ts
|
||||
const OAUTH_CLIENT_CODES: {
|
||||
AUTHORIZATION_FAILED: string;
|
||||
TOKEN_EXCHANGE_FAILED: string;
|
||||
TOKEN_REQUEST_FAILED: string;
|
||||
TOKEN_REFRESH_FAILED: string;
|
||||
TOKEN_REVOKE_FAILED: string;
|
||||
TOKEN_EXPIRED: string;
|
||||
INVALID_STATE: string;
|
||||
PKCE_MISMATCH: string;
|
||||
DISCOVERY_FAILED: string;
|
||||
INVALID_CONFIG: string;
|
||||
INVALID_ID_TOKEN: string;
|
||||
UNKNOWN_PROVIDER: string;
|
||||
}
|
||||
```
|
||||
|
||||
Stable code registry. Each value is a namespaced string such as `"OAUTH_CLIENT.INVALID_STATE"`.
|
||||
|
||||
### `OAuthClientErrorCode`
|
||||
|
||||
Union type of all values in `OAUTH_CLIENT_CODES`. Useful for exhaustive `switch` statements.
|
||||
|
||||
### `OAuthClientError`
|
||||
|
||||
```ts
|
||||
class OAuthClientError extends SuaveplanError<OAuthClientErrorCode> {
|
||||
constructor(code: OAuthClientErrorCode, messageKey: string, options?: SuaveplanErrorOptions): void;
|
||||
}
|
||||
```
|
||||
|
||||
- `code` — one of `OAUTH_CLIENT_CODES` values.
|
||||
- `messageKey` — i18n message key (e.g. `"oauth.state.mismatch"`).
|
||||
- `options.cause` — original error to attach as the causal chain.
|
||||
- `options.context` — arbitrary structured metadata surfaced by `@suaveplan/error`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`defineCodes` produces a frozen object whose values are stable across builds and minifiers — no runtime reflection or `Object.keys` enumeration is needed by callers. The `noUselessConstructor` biome lint suppression is intentional: the explicit `public constructor` widens the protected base constructor to public access, which is a meaningful API contract not enforced by inheritance alone.
|
||||
Reference in New Issue
Block a user