npm package: @fwoom/error
Description: A small error utility for creating consistent, safe, and portable application errors.
Author: SUJWN
Latest version: 1.0.0

# @fwoom/error

A small, framework-agnostic error utility for JavaScript and TypeScript applications.

`@fwoom/error` is designed to be **simple, safe by default, and portable**. It helps you create consistent, structured errors without forcing class-based inheritance or framework-specific concepts.

---

## Installation

```bash
npm install @fwoom/error
```

---

## Core Concepts

### Errors are data

Errors are identified by a **stable error code**, not by `instanceof` checks or class inheritance.

This makes errors:

- Portable across runtimes
- Serializable
- Safe to handle in distributed systems

---

## Public API

`@fwoom/error` intentionally exposes only two main APIs:

- `defineError()` – define an error type and get a reusable factory
- `createError()` – create an error by code (zero-config fallback)

In addition, it exports a small set of **standard error factories**.

---

## Defining Custom Errors

Use `defineError` to declare an error type and its defaults. This is usually done once and exported.

```ts
import { defineError } from "@fwoom/error";

export const userNotFound = defineError({
	code: "USER_NOT_FOUND",
	status: 404,
	expose: true,
	message: "User not found",
});
```

`defineError`:

- Registers error metadata
- Returns a callable error factory
- Is safe to import anywhere (module runs once)

---

## Using Error Factories

The returned factory is what you throw at runtime.

### Message only

```ts
throw userNotFound("User not found");
```

### Message with details

```ts
throw userNotFound("User not found", { userId: 123 });
```

### Override options

```ts
throw userNotFound("User not found", {
	status: 410,
	expose: true,
	details: { userId: 123 },
});
```

---

## `createError` (Zero-config usage)

`createError` lets you create errors by code without defining them first.

```ts
import { createError } from "@fwoom/error";

throw createError("SOMETHING_BROKE");
```

With a custom message:

```ts
throw createError("NOT_FOUND", "User not found");
```

With full options:

```ts
throw createError("CUSTOM_ERROR", {
	message: "Something went wrong",
	status: 400,
	expose: false,
	details: { reason: "invalid_state" },
});
```

If the error code was not defined via `defineError`, a **development-only warning** is shown.

---

## Standard Error Factories

`@fwoom/error` provides common HTTP-style errors out of the box.

```ts
import {
	badRequest,
	unauthorized,
	forbidden,
	notFound,
	conflict,
	unprocessableEntity,
	internalError,
} from "@fwoom/error";
```

### Available standard errors

| Factory               | Code                   | Status | Exposed | Default message      |
| --------------------- | ---------------------- | ------ | ------- | -------------------- |
| `badRequest`          | `BAD_REQUEST`          | 400    | true    | Bad request          |
| `unauthorized`        | `UNAUTHORIZED`         | 401    | true    | Unauthorized         |
| `forbidden`           | `FORBIDDEN`            | 403    | true    | Forbidden            |
| `notFound`            | `NOT_FOUND`            | 404    | true    | Not found            |
| `conflict`            | `CONFLICT`             | 409    | true    | Conflict             |
| `unprocessableEntity` | `UNPROCESSABLE_ENTITY` | 422    | true    | Unprocessable entity |
| `internalError`       | `INTERNAL_ERROR`       | 500    | false   | Internal error       |

Example:

```ts
throw notFound("User not found", { userId: 123 });
```

---

## Error Fields

All errors produced by this package share the same shape:

```ts
interface BaseError extends Error {
	code: string;
	message: string;
	status?: number;
	expose: boolean;
	details?: unknown;
	cause?: unknown;
}
```

## Defaults and Safety

- `status` defaults to `500`
- `expose` defaults to `false`
- `message` falls back to the error code

This ensures that **errors are safe by default**, even in zero-config usage.

---

## Development vs Production Behavior

### Development

- Warns when `createError` is used with an undefined error code
- Warns on duplicate `defineError` calls
- Never throws because of misconfiguration

### Production

- No warnings
- Same runtime behavior
- Safe messages only

---

## Why no classes or `instanceof`

`@fwoom/error` intentionally avoids class-based errors.

Instead of:

```ts
if (err instanceof ValidationError) {
}
```

Use:

```ts
if (err.code === "VALIDATION_FAILED") {
}
```

This approach is:

- More portable
- Stable across package boundaries
- Safer in distributed systems

---

## Philosophy

Errors should be:

- Explicit, not implicit
- Data-first, not inheritance-based
- Safe by default
- Easy to create, hard to misuse

---

## License

[MIT](LICENSE)