Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
62c8081
docs(rfc): add 0001 - promote StandardSchemaV1 to runtime validation
martyy-code Aug 5, 2026
2888b17
docs(rfc): resolve Q1-Q4 open questions in 0001
martyy-code Aug 5, 2026
39dd892
feat(errors): implement RFC 0001 Standard Schema validation + message…
martyy-code Aug 5, 2026
3b59103
style(errors): apply prettier to RFC 0001 implementation
martyy-code Aug 5, 2026
684777f
test(errors): add zod/valibot/arktype vendor tests for RFC 0001
martyy-code Aug 5, 2026
0083fc4
test(errors): split vendor tests into integration/zod, /valibot, /ark…
martyy-code Aug 5, 2026
de449d2
test(errors): add vendor-valibot, vendor-arktype, contract-parity tests
martyy-code Aug 5, 2026
90639e6
test(errors): move vendor tests into tests/integration/<vendor>/ subf…
martyy-code Aug 5, 2026
603ade8
test(errors): drop placeholder legacy-warn test
martyy-code Aug 5, 2026
ccaf230
docs(site): align docs with RFC 0001 standard-schema API
martyy-code Aug 5, 2026
c1e6a02
feat(errors): re-export ArgsValidationError and add type tests (RFC 0…
martyy-code Aug 5, 2026
8072983
test(errors): add edge-case coverage for standard-schema runtime
martyy-code Aug 5, 2026
3685783
test(errors): add public-surface snapshot and instantiation benchmarks
martyy-code Aug 5, 2026
565d270
ci: matrix the test and type-check jobs across Node 20, 22, 24
martyy-code Aug 5, 2026
c6a286e
test(errors): exclude benchmarks from test:run and use correct relati…
martyy-code Aug 5, 2026
7e28adf
docs(site): fix MDX parse error in api-reference table
martyy-code Aug 5, 2026
678e91c
style: apply prettier to RFC 0001 new files
martyy-code Aug 5, 2026
93389bd
chore: add changeset for RFC 0001 (1.4.0 release)
martyy-code Aug 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/rfc-0001-standard-schema.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@deessejs/errors': minor
---

Add `StandardSchemaV1` runtime validation and message-as-function mode to `error()` (RFC 0001).

- New API: pass `fields: StandardSchemaV1` (Zod, Valibot, ArkType, etc.) and a function `message: (data) => string`. Args are validated at instantiation; invalid inputs throw `ArgsValidationError`.
- The function form receives the **parsed** (post-transform) data, so schemas that brand, coerce, or refine work as expected.
- New export `ArgsValidationError` with `source`, `vendor`, `issues`. Re-exported from `@deessejs/errors` so consumers can `instanceof`-check.
- `ErrorFactory.schema` has been removed. The duplication between `fields` and `schema` is gone.
- The legacy string-template form (`message: "Field {field}"`) keeps working in 1.x and emits a single deprecation warning per call site. Set `DEESSEJS_ERRORS_LEGACY_TEMPLATES=1` to silence. The legacy form will be removed in 2.0.0.

See [RFC 0001](https://github.com/deessejs/errors/blob/main/docs/internal/engineering/rfcs/0001-standard-schema-fields.md) for the full design discussion.
14 changes: 10 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ concurrency:

jobs:
test:
name: Tests
runs-on: ubuntu-latest
name: Tests (${{ matrix.os }} / node ${{ matrix.node }})
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
node: [20, 22, 24]

steps:
- name: Checkout
Expand All @@ -25,14 +31,14 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
node-version: ${{ matrix.node }}
cache: 'pnpm'

- name: Cache Turborepo
uses: actions/cache@v4
with:
path: .turbo
key: turbo-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
key: turbo-${{ matrix.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}

- name: Install dependencies
run: pnpm install
Expand Down
11 changes: 8 additions & 3 deletions .github/workflows/types.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ concurrency:

jobs:
type-check:
name: Type Check
name: Type Check (node ${{ matrix.node }})
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
node: [20, 22, 24]

steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -25,14 +30,14 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
node-version: ${{ matrix.node }}
cache: 'pnpm'

- name: Cache Turborepo
uses: actions/cache@v4
with:
path: .turbo
key: turbo-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
key: turbo-${{ matrix.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}

- name: Install dependencies
run: pnpm install
Expand Down
184 changes: 126 additions & 58 deletions apps/web/content/docs/api-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,76 +3,81 @@ title: API Reference
description: Complete API reference for all exports from @deessejs/errors.
---

This page documents all public exports from @deessejs/errors. Use this as a comprehensive reference for the library's API.
This page documents all public exports from @deessejs/errors.

## error()

Creates an error factory function for defining typed, structured errors.

```ts title="title="${f%.mdx}.ts""
const errorFactory = error<T>(config)
```ts title="factory.ts"
const errorFactory = error<TFields>(config)
```

### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `config.name` | `string` | Error name identifier (required) |
| `config.message` | `string` | Message template with `{field}` placeholders |
| `config.fields` | `StandardSchemaV1` | Field schema for validation (Zod, Valibot, etc.) |
| `config.inherits` | `ErrorFactory \| ErrorFactory[]` | Parent error(s) to inherit from |
| config.name | string | Error name identifier (required) |
| config.message | string or function | Legacy template, or a function (data) => string taking the validated fields |
| config.fields | StandardSchemaV1 | Field validation schema (Zod, Valibot, ArkType, etc.) |
| config.inherits | ErrorFactory or ErrorFactory[] | Parent error(s) to inherit from |

When fields is supplied, the input is validated against the schema at every call. Invalid inputs throw an ArgsValidationError. When message is a function, it receives the parsed (post-transform) data as its argument.

### Returns

An `ErrorFactory` function that creates error instances. The factory has these properties:
An ErrorFactory function that creates error instances. The factory has these properties:

| Property | Type | Description |
|----------|------|-------------|
| `name` | `string` | The error name |
| `inherits` | `ErrorFactory \| ErrorFactory[] \| undefined` | Parent error types |
| `schema` | `StandardSchemaV1 \| undefined` | Field validation schema |
| `rawMessage` | `string \| undefined` | Original message template |
| name | string | The error name |
| inherits | ErrorFactory or ErrorFactory[] or undefined | Parent error types |
| fields | StandardSchemaV1 or undefined | The validation schema (exposed via the factory) |
| rawMessage | string or undefined | Original message template, only set when message is a string |

### Example

```ts title="title="${f%.mdx}.ts""
import { error } from '@deessejs/errors';
```ts title="factory.ts"
import { z } from "zod";
import { error } from "@deessejs/errors";

const ValidationError = error<{ field: string }>({
name: 'ValidationError',
message: 'Field "{field}" is invalid',
const ValidationError = error({
name: "ValidationError",
fields: z.object({ field: z.string() }),
message: (data) => 'Field "' + data.field + '" is invalid',
inherits: AppError,
});

const err = ValidationError({ field: 'email' });
const err = ValidationError({ field: "email" });
```


---

## raise()

Throws an error instance. This is the primary mechanism for throwing errors in @deessejs/errors.
Throws an error instance. The primary mechanism for throwing errors in @deessejs/errors.

```ts title="title="${f%.mdx}.ts""
```ts title="raise.ts"
raise(error: ErrorInstance): never
```

### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `error` | `ErrorInstance` | The error to throw |
| error | ErrorInstance | The error to throw |

### Returns

`never` — This function always throws.
never - this function always throws.

### Example

```ts title="title="${f%.mdx}.ts""
import { error, raise } from '@deessejs/errors';
```ts title="raise.ts"
import { error, raise } from "@deessejs/errors";

const ValidationError = error({ name: 'ValidationError' });
const ValidationError = error({ name: "ValidationError" });

raise(ValidationError({}));
```
Expand All @@ -81,98 +86,158 @@ raise(ValidationError({}));

## is()

Type guard function to check if an error is an instance of a specific error type.
Type guard function to check if an error is an instance of a specific error type. Supports single and multiple inheritance hierarchies.

```ts title="title="${f%.mdx}.ts""
const result = is(error, ErrorType)
```ts title="is.ts"
const result = is(error: unknown, ErrorType): error is ErrorInstance
```

### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `error` | `unknown` | The error to check |
| `ErrorType` | `ErrorFactory \| ErrorClass` | The error type to check against |
| error | unknown | The error to check |
| ErrorType | ErrorFactory or ErrorClass | The error type to check against |

### Returns

`boolean` — `true` if the error matches or inherits from the type.
boolean - true if the error matches or inherits from the type. Narrows the input type for TypeScript.

### Example

```ts title="title="${f%.mdx}.ts""
import { error, is } from '@deessejs/errors';
```ts title="is.ts"
import { error, is } from "@deessejs/errors";

const AppError = error({ name: 'AppError' });
const AppError = error({ name: "AppError" });
const ValidationError = error({
name: 'ValidationError',
name: "ValidationError",
inherits: AppError,
});

const err = ValidationError({});

is(err, ValidationError); // true
is(err, AppError); // true (through inheritance)
if (is(err, ValidationError)) {
console.log("ValidationError matched");
}
if (is(err, AppError)) {
console.log("AppError matched via inheritance");
}
```

---

## causes()

Returns all causes in an error chain.
Returns all causes in an error chain, ordered newest to oldest.

```ts title="title="${f%.mdx}.ts""
```ts title="causes.ts"
const chain = causes(error: unknown): Error[]
```

### Parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `error` | `unknown` | The error to get causes from |
| error | unknown | The error to get causes from |

### Returns

`Error[]` — Array of errors in the cause chain, ordered newest to oldest. Returns an empty array for null, undefined, or errors without causes.
Error[] - array of errors in the cause chain. Returns an empty array for null, undefined, or errors without causes.

### Example

```ts title="title="${f%.mdx}.ts""
import { error, causes } from '@deessejs/errors';
```ts title="causes.ts"
import { error, causes } from "@deessejs/errors";

const AppError = error({ name: 'AppError' });
const AppError = error({ name: "AppError" });
const appErr = AppError({});
appErr.from(new Error('Original error'));
appErr.from(new Error("Original error"));

const chain = causes(appErr);
console.log(chain.length); // 1
console.log(chain.length);
```


---

## ArgsValidationError

Thrown when input data fails a Standard Schema validator attached to fields. The error carries the original validator failure information, branded as an @deessejs/errors instance.

```ts title="args-validation.ts"
class ArgsValidationError extends Error
```

### Constructor

| Parameter | Type | Description |
|-----------|------|-------------|
| source | string | Name of the originating factory |
| issues | ReadonlyArray&lt;StandardSchemaV1.Issue&gt; | Read-only array of validator issues (per Standard Schema spec) |
| vendor | string | Vendor identifier (e.g. zod, valibot, arktype) |

### Instance properties

| Property | Type | Description |
|----------|------|-------------|
| source | string | The originating factory name |
| issues | ReadonlyArray&lt;StandardSchemaV1.Issue&gt; | Validator issues |
| vendor | string | Vendor identifier |

### Message format

```
Argument validation failed for "<source>": see .issues
```

### Example

```ts title="args-validation.ts"
import { z } from "zod";
import { error, ArgsValidationError } from "@deessejs/errors";

const ValidationError = error({
name: "ValidationError",
fields: z.object({ field: z.string().min(1) }),
message: (data) => "Field " + data.field,
});

try {
ValidationError({ field: "" });
} catch (err) {
if (err instanceof ArgsValidationError) {
console.log(err.vendor);
console.log(err.issues);
}
}
```

---

## ErrorInstance

The type of object returned by error factories. It extends the native `Error` type.
The type of object returned by error factories. It extends the native Error type.

### Properties

| Property | Type | Description |
|----------|------|-------------|
| `name` | `string` | Error name identifier |
| `message` | `string` | Human-readable error message |
| `stack` | `string` | Stack trace string |
| `fields` | `T` | User-defined fields |
| `notes` | `string[]` | Additional notes |
| `cause` | `Error \| null` | Direct cause of this error |
| `causes` | `Error[]` | Full cause chain |
| `context` | `Record<string, unknown> \| null` | Injected context data |
| `inherits` | `ErrorFactory \| ErrorFactory[] \| undefined` | Parent error factories |
| name | string | Error name identifier |
| message | string | Human-readable error message |
| stack | string | Stack trace string |
| fields | T | Validated fields |
| notes | string[] | Additional notes (PEP 678) |
| cause | Error or null | Direct cause of this error |
| causes | Error[] | Full cause chain |
| context | Record&lt;string, unknown&gt; or null | Injected context data |
| inherits | ErrorFactory or ErrorFactory[] or undefined | Parent error factories |

### Methods

| Method | Description |
|--------|-------------|
| `from(cause: Error)` | Chains a cause error to this error |
| from(cause: Error or ErrorInstance) | Chains a cause error to this error. Returns this for chaining. |
| addNote(note: string) | Appends a runtime context note (PEP 678). Returns this for chaining. |

---

Expand All @@ -188,4 +253,7 @@ The type of object returned by error factories. It extends the native `Error` ty
<Card title="Exception Chaining" href="/docs/from-method">
Chain errors with from().
</Card>
</Cards>
<Card title="Fields and Schema" href="/docs/fields-schema">
Field validation with Standard Schema.
</Card>
</Cards>
Loading
Loading