From 7d37e4608da5b1c97da6f9cb1d4f1226e88dc0a6 Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Tue, 4 Aug 2026 13:37:55 +0200
Subject: [PATCH 1/8] docs: restyle README to match shared template
Adopt the @deessejs/fp README layout for consistency across the deessejs ecosystem.
---
README.md | 289 ++++++++++++++++++++++++++++--------------------------
1 file changed, 150 insertions(+), 139 deletions(-)
diff --git a/README.md b/README.md
index 0de1045..3d2fe96 100644
--- a/README.md
+++ b/README.md
@@ -1,184 +1,195 @@
-# @deessejs/errors
-
-[](https://www.npmjs.com/package/@deessejs/errors)
-[](https://www.typescriptlang.org/)
-[](https://opensource.org/licenses/MIT)
-
-A TypeScript error handling library with exception chaining, hierarchical inheritance, and rich error semantics — inspired by Python's error system.
-
-## Features
-
-- **Exception Chaining** — Preserve the full context of errors with cause chains via `.from()`
-- **Hierarchical Inheritance** — Organize errors in meaningful hierarchies with single or multiple inheritance
-- **Rich Error Semantics** — Attach structured data, templates, and notes to errors
-- **TypeScript First** — Full type safety with comprehensive type definitions
-
-## Installation
+
+
@deessejs/errors
+
+
+
+ Lightweight, type-safe error handling for TypeScript — Python-style. Function-based API, exception chaining, hierarchical inheritance, and rich error semantics. ESM-only, designed for first-class interoperability with @deessejs/fp's Result and Try.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+> **Sibling projects:** [@deessejs/fp](https://github.com/deessejs/fp) provides `Result` and `Try` types that integrate natively with [@deessejs/errors](https://github.com/deessejs/errors) error factories. Install them together to get a complete error-handling story without glue code.
+
+---
+
+## What is included
+
+| Layer | What you get | Why it matters |
+| **`error()`** | Define error factories with name, message templates, fields, and inheritance. ||Python-style error definitions without classes. |
+| **`.from()` chaining** | Cause chain via `.from()` + `causes()` traversal. ||Link errors together while preserving the full chain context. |
+| **Single or multiple inheritance** | `inherits:` accepts a factory or an array. ||Organize error hierarchies that match your domain. |
+| **`is()` type checking** | Runtime and type-safe classifier with inheritance support. ||Discriminate errors without brittle `instanceof`. |
+| **`.addNote()`** | Attach runtime context to error instances. ||Python 3.11-style notes (PEP 678) for trail-of-breadcrumbs debugging. |
+| **Message templates** | `{field}` placeholders with `:upper`, `:lower`, `:json` modifiers. ||Readable messages composed from structured fields at construction time. |
+| **Standard Schema fields** | Accepts Zod / Valibot / ArkType schemas. ||Validated structured data on every error instance, no hand-rolled guards. |
+| **`raise()`** | Idiomatic throw helper. ||Type-narrowed (`never`) `raise(err)` for control-flow readability. |
+| **[@deessejs/fp](https://github.com/deessejs/fp) integration** | `Result`/`Try` accept `ErrorInstance` directly. ||Type-safe error pipelines end-to-end, no string-error footguns. |
+
+## Why this library
+
+- **Simple by default.** No class hierarchies to manage, no decorators under reflection. Just factory functions and chained calls.
+- **ESM-only.** Modern packaging, no CJS shim, no `module`/`main` duplication.
+- **Minimal runtime.** The only runtime dependency is `@standard-schema/spec`.
+- **TypeScript first-class.** Strict types, no `any` leakages, full inference. JSDoc on every public symbol.
+- **Real testing.** Vitest with type-level and runtime tests, including cause-chain traversal.
+
+## Quick start
+
+### Prerequisites
+
+- Node.js 22.x for consumers (the package emits ESM)
+- pnpm 10+ for development (`corepack enable` if not installed)
+- TypeScript 5.x for consumers (`dist/*.d.ts` is published)
+
+### Install
```bash
npm install @deessejs/errors
-# or
-pnpm add @deessejs/errors
-# or
-yarn add @deessejs/errors
```
-## Quick Start
+[@deessejs/fp](https://github.com/deessejs/fp) is optional - install it if you want to compose `Result`/`Try` types around `ErrorInstance`.
-### Creating Errors
+### Usage
-```typescript
-import { error } from '@deessejs/errors';
+```{type=typescript}
-// Simple error
-const ValidationError = error({ name: 'ValidationError' });
-const err = ValidationError();
+The example below uses several typed errors chained together.
-// Error with message template
-const ValidationError = error({
- name: 'ValidationError',
- message: 'Field "{field}" is invalid: {reason}',
-});
+### Engine compatibility
-const err = ValidationError({ field: 'email', reason: 'invalid format' });
-// err.message === 'Field "email" is invalid: invalid format'
-```
+| Runtime | Minimum version |
+|---|
+| Node.js | 22.0.0 |
+| pnpm | 10 (for development) |
+| TypeScript | 5.x |
-### Exception Chaining
+ESM-only. Consumers using a CJS resolver need to use dynamic `import()` or migrate to ESM.
-```typescript
-import { error } from '@deessejs/errors';
+## Available commands
-const ValidationError = error({ name: 'ValidationError' });
-const ProcessingError = error({ name: 'ProcessingError' });
+### Package: `@deessejs/errors`
-const validationErr = ValidationError({ field: 'email' });
-const processingErr = ProcessingError();
+| Command | What it does |
+|---|
+| `pnpm --filter @deessejs/errors build` | Build `dist/` (`tsc -p tsconfig.build.json`) |
+| `pnpm --filter @deessejs/errors test` | Run vitest in watch mode |
+| `pnpm --filter @deessejs/errors test:run` | Run vitest once |
+| `pnpm --filter @deessejs/errors type-check` | `tsc --noEmit` |
+| `pnpm --filter @deessejs/errors lint` | Run ESLint |
-// Chain errors with .from()
-processingErr.from(validationErr);
+### Root (monorepo)
-console.log(processingErr.message); // "ProcessingError"
-console.log(processingErr.cause); // validationErr
-console.log(processingErr.causes); // [validationErr]
-```
+| Command | What it does |
+|---|
+| `pnpm build` | Build via Turborepo |
+| `pnpm test` | Run all tests |
+| `pnpm lint` | Lint every workspace |
+| `pnpm type-check` | Type-check every workspace |
+| `pnpm format` | Format with Prettier |
-### Hierarchical Inheritance
-
-```typescript
-import { error } from '@deessejs/errors';
-
-// Single inheritance
-const AppError = error({ name: 'AppError' });
-const ValidationError = error({
- name: 'ValidationError',
- inherits: AppError,
-});
-
-// Multiple inheritance
-const NetworkError = error({ name: 'NetworkError' });
-const StorageError = error({ name: 'StorageError' });
-const CombinedError = error({
- name: 'CombinedError',
- inherits: [NetworkError, StorageError],
-});
-```
+### App: `web` (documentation site)
-### Type Checking
+| Command | What it does |
+|---|
+| `pnpm --filter web dev` | Start the docs site in dev mode |
+| `pnpm --filter web build` | Build the docs site for production |
-```typescript
-import { error, is } from '@deessejs/errors';
+## Compatibility
-const AppError = error({ name: 'AppError' });
-const ValidationError = error({
- name: 'ValidationError',
- inherits: AppError,
-});
+### Runtime dependency
-const err = ValidationError();
+| Package | Required | Notes |
+|---|
+| `@standard-schema/spec` | Yes, `>=1.0.0` | The interface used by `fields`. Schema implementations (Zod, Valibot, ArkType) are passed by the caller. |
-is(err, ValidationError); // true
-is(err, AppError); // true (inherits from AppError)
-```
+### Peer dependencies
-### Traverse Cause Chain
+| Package | Required | Notes |
+|---|
+| [@deessejs/fp](https://github.com/deessejs/fp) | Optional, peer `>=1.0.0` | Recommended if you want `Result`/`Try` types around `ErrorInstance`. Not required for using `@deessejs/errors` alone. |
-```typescript
-import { error, causes } from '@deessejs/errors';
+### Engines
-const Err1 = error({ name: 'Err1' });
-const Err2 = error({ name: 'Err2' });
-const Err3 = error({ name: 'Err3' });
+| Field | Value |
+|---|
+| `engines.node` | `>=22.14.0` |
+| `packageManager` | `pnpm@10.34.5` |
-const err1 = Err1();
-const err2 = Err2().from(err1);
-const err3 = Err3().from(err2);
+## Project structure
-// Iterate through the cause chain
-for (const cause of causes(err3)) {
- console.log(cause.name);
-}
-// Output: Err2, Err1
```
-## Why @deessejs/errors?
-
-Built-in JavaScript errors are limited. `@deessejs/errors` brings Python-style error handling to TypeScript.
+.
++-- packages/
++-- apps/
++-- docs/
++-- pnpm-workspace.yaml
++-- turbo.json# Turborepo pipelines
++-- .changeset/# Changesets for versioning
++-- README.md
-| Feature | Built-in `Error` | @deessejs/errors |
-| ------------------------ | ---------------- | ---------------- |
-| Exception chaining | ❌ | ✅ |
-| Hierarchical inheritance | ❌ | ✅ |
-| Message templates | ❌ | ✅ |
-| Type-safe fields | ❌ | ✅ |
-| Standard Schema support | ❌ | ✅ |
-
-```typescript
-// Traditional approach — limited context
-throw new Error('Validation failed'); // ❌ Generic, no structure
-
-// @deessejs/errors — rich, maintainable errors
-const err = ValidationError({ field: 'email', reason: 'invalid format' });
-err.from(originalError); // ✅ Chain exceptions, preserve context
```
-## FAQ
-
-### How do I create a custom error type?
+## Publishing
-```typescript
-import { error } from '@deessejs/errors';
-
-const ValidationError = error({ name: 'ValidationError' });
-const err = ValidationError({ field: 'email' });
-```
+Releases are fully automated via Changesets + npm Trusted Publishing (OIDC). No long-lived `NPM_TOKEN` is required.
-### How do I chain exceptions?
+| What | How |
+|---|
+| Bump version | Add a `.changeset/.md` file with semver and description on a PR to `staging` |
+| Open the release PR | Cherry-pick selected commits from `staging` into `release/vX.Y.Z` and PR to `main` |
+| Publish | Merge to `main` - `release.yml` detects changesets and publishes via Trusted Publishing to npm with provenance attestation |
+| Hotfix | Branch from `main` as `release/hotfix-`, open PR directly to `main` with `[hotfix]` label. Same workflow fires. |
+| Rollback | Use `pnpm changeset version` then revert the merge. npm deprecations: `pnpm npm deprecate @deessejs/errors` ` ` |
-```typescript
-import { error } from '@deessejs/errors';
+For the full release runbook, see [`docs/internal/engineering/process/releasing-a-new-version.md`](docs/internal/engineering/process/releasing-a-new-version.md).
-const validationErr = ValidationError({ field: 'email' });
-const processingErr = ProcessingError().from(validationErr);
+## Architecture notes
-console.log(processingErr.cause); // validationErr
-```
+- **ESM-only.** The package exports ES modules. Consumers using legacy CJS resolvers must use dynamic `import()`.
+- **Strict types.** `error()` returns a typed factory; `is()` narrows. No `any` leakages.
+- **Composition over inheritance.** All error primitives compose via instance methods (`.from()`, `.addNote()`, `inherits`). No class hierarchy on the consumer side.
+- **Zero decorators.** Pure factory functions. The library is straightforward to read in DevTools and `node --prof`.
+- **Smoke-tested before publish.** The release workflow imports the built artifact and verifies key exports are present. A broken build fails the publish step before reaching npm.
+- **Symmetric interop with [@deessejs/fp](https://github.com/deessejs/fp).** `Result` constructors accept `ErrorInstance` so you never have to coerce a typed error to a string.
-### How do I check if an error is of a specific type?
+## Contributing
-```typescript
-import { error, is } from '@deessejs/errors';
+Open an issue to discuss larger changes. For typos, broken links, and small fixes, PRs are welcome.
-const AppError = error({ name: 'AppError' });
-const ValidationError = error({ name: 'ValidationError', inherits: AppError });
+Before submitting a PR:
-is(err, AppError); // true if err is ValidationError or any descendant
-```
+1. Run `pnpm --filter @deessejs/errors test:run` and `pnpm --filter @deessejs/errors lint`.
+2. Add a `.changeset/.md` if the change is user-facing (patch / minor / major).
+3. Update `docs/internal/product/README.md` if the API surface changes.
-## Documentation
+## License
-For full documentation, visit [errors.deessejs.com](https://errors.deessejs.com)
+[MIT](./LICENSE). See the LICENSE file for details.
-## License
+## Support
-MIT
+- Issues: [github.com/deessejs/errors/issues](https://github.com/deessejs/errors/issues)
+- Discussions: [github.com/deessejs/errors/discussions](https://github.com/deessejs/errors/discussions)
+- Email: [support@deessejs.com](mailto:support@deessejs.com)
+- Documentation: [errors.deessejs.com](https://errors.deessejs.com)
+```
From e2b4e14086b06f1f478451a022113e695e7c7add Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Tue, 4 Aug 2026 13:43:33 +0200
Subject: [PATCH 2/8] docs: add Acknowledgements section crediting
@deessejs/package-template
Mention the deessejs/package-template and deessejs/fp README in a new Acknowledgements section, placed above the License section.
---
README.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/README.md b/README.md
index 3d2fe96..f1c229e 100644
--- a/README.md
+++ b/README.md
@@ -182,6 +182,12 @@ Before submitting a PR:
2. Add a `.changeset/.md` if the change is user-facing (patch / minor / major).
3. Update `docs/internal/product/README.md` if the API surface changes.
+
+## Acknowledgements
+
+The README layout and monorepo tooling for this project are based on the [deessejs/package-template](https://github.com/deessejs/package-template). The shipped README borrows its structure from the [deessejs/fp README](https://github.com/deessejs/fp), adapted for the @deessejs/errors API surface.
+
+
## License
[MIT](./LICENSE). See the LICENSE file for details.
From 31f2e12ac8f268c8e42bd50986040d9f129fb3d2 Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Tue, 4 Aug 2026 14:09:00 +0200
Subject: [PATCH 3/8] docs: fix README -- corrected table, restored code block
and tree, fixed deprecate row
---
README.md | 177 ++++++++++++++++++++++++++++++------------------------
1 file changed, 97 insertions(+), 80 deletions(-)
diff --git a/README.md b/README.md
index f1c229e..5594d3d 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,20 @@
-
-
@deessejs/errors
+
+
@deessejs/errors
-
- Lightweight, type-safe error handling for TypeScript — Python-style. Function-based API, exception chaining, hierarchical inheritance, and rich error semantics. ESM-only, designed for first-class interoperability with @deessejs/fp's Result and Try.
+
+ Lightweight, type-safe error handling for TypeScript — Python-style. Function-based API, exception chaining, hierarchical inheritance, and rich error semantics. ESM-only, designed for first-class interoperability with @deessejs/fp's Result and Try.
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
> **Sibling projects:** [@deessejs/fp](https://github.com/deessejs/fp) provides `Result` and `Try` types that integrate natively with [@deessejs/errors](https://github.com/deessejs/errors) error factories. Install them together to get a complete error-handling story without glue code.
@@ -33,16 +23,17 @@
## What is included
-| Layer | What you get | Why it matters |
-| **`error()`** | Define error factories with name, message templates, fields, and inheritance. ||Python-style error definitions without classes. |
-| **`.from()` chaining** | Cause chain via `.from()` + `causes()` traversal. ||Link errors together while preserving the full chain context. |
-| **Single or multiple inheritance** | `inherits:` accepts a factory or an array. ||Organize error hierarchies that match your domain. |
-| **`is()` type checking** | Runtime and type-safe classifier with inheritance support. ||Discriminate errors without brittle `instanceof`. |
-| **`.addNote()`** | Attach runtime context to error instances. ||Python 3.11-style notes (PEP 678) for trail-of-breadcrumbs debugging. |
-| **Message templates** | `{field}` placeholders with `:upper`, `:lower`, `:json` modifiers. ||Readable messages composed from structured fields at construction time. |
-| **Standard Schema fields** | Accepts Zod / Valibot / ArkType schemas. ||Validated structured data on every error instance, no hand-rolled guards. |
-| **`raise()`** | Idiomatic throw helper. ||Type-narrowed (`never`) `raise(err)` for control-flow readability. |
-| **[@deessejs/fp](https://github.com/deessejs/fp) integration** | `Result`/`Try` accept `ErrorInstance` directly. ||Type-safe error pipelines end-to-end, no string-error footguns. |
+| Layer | What you get | Why it matters |
+| ---------------------------------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
+| **`error()`** | Define error factories with name, message templates, fields, and inheritance. | Python-style error definitions without classes. |
+| **`.from()` chaining** | Cause chain via `.from()` + `causes()` traversal. | Link errors together while preserving the full chain context. |
+| **Single or multiple inheritance** | `inherits:` accepts a factory or an array. | Organize error hierarchies that match your domain. |
+| **`is()` type checking** | Runtime and type-safe classifier with inheritance support. | Discriminate errors without brittle `instanceof`. |
+| **`.addNote()`** | Attach runtime context to error instances. | Python 3.11-style notes (PEP 678) for trail-of-breadcrumbs debugging. |
+| **Message templates** | `{field}` placeholders with `:upper`, `:lower`, `:json` modifiers. | Readable messages composed from structured fields at construction time. |
+| **Standard Schema fields** | Accepts Zod / Valibot / ArkType schemas. | Validated structured data on every error instance, no hand-rolled guards. |
+| **`raise()`** | Idiomatic throw helper. | Type-narrowed (`never`) `raise(err)` for control-flow readability. |
+| [@deessejs/fp](https://github.com/deessejs/fp) integration | `Result`/`Try` accept `ErrorInstance` directly. | Type-safe error pipelines end-to-end, no string-error footguns. |
## Why this library
@@ -70,17 +61,38 @@ npm install @deessejs/errors
### Usage
-```{type=typescript}
+```typescript
+import { error, raise, is, causes } from '@deessejs/errors';
-The example below uses several typed errors chained together.
+// Define an error factory with a templated message
+const ValidationError = error({
+ name: 'ValidationError',
+ message: 'Field "{field}" is invalid: {reason}',
+});
+
+// Construct a typed error
+const err = ValidationError({ field: 'email', reason: 'invalid format' });
+// err.message === 'Field "email" is invalid: invalid format'
+
+// Chain a cause
+const cause = error({ name: 'NetworkError' })();
+err.from(cause);
+
+// Throw it
+raise(err);
+
+// Later, type-check and walk the chain
+is(err, ValidationError); // true
+causes(err); // [cause]
+```
### Engine compatibility
-| Runtime | Minimum version |
-|---|
-| Node.js | 22.0.0 |
-| pnpm | 10 (for development) |
-| TypeScript | 5.x |
+| Runtime | Minimum version |
+| ---------- | -------------------- |
+| Node.js | 22.0.0 |
+| pnpm | 10 (for development) |
+| TypeScript | 5.x |
ESM-only. Consumers using a CJS resolver need to use dynamic `import()` or migrate to ESM.
@@ -88,78 +100,86 @@ ESM-only. Consumers using a CJS resolver need to use dynamic `import()` or migra
### Package: `@deessejs/errors`
-| Command | What it does |
-|---|
-| `pnpm --filter @deessejs/errors build` | Build `dist/` (`tsc -p tsconfig.build.json`) |
-| `pnpm --filter @deessejs/errors test` | Run vitest in watch mode |
-| `pnpm --filter @deessejs/errors test:run` | Run vitest once |
-| `pnpm --filter @deessejs/errors type-check` | `tsc --noEmit` |
-| `pnpm --filter @deessejs/errors lint` | Run ESLint |
+| Command | What it does |
+| ------------------------------------------- | -------------------------------------------- |
+| `pnpm --filter @deessejs/errors build` | Build `dist/` (`tsc -p tsconfig.build.json`) |
+| `pnpm --filter @deessejs/errors test` | Run vitest in watch mode |
+| `pnpm --filter @deessejs/errors test:run` | Run vitest once |
+| `pnpm --filter @deessejs/errors type-check` | `tsc --noEmit` |
+| `pnpm --filter @deessejs/errors lint` | Run ESLint |
### Root (monorepo)
-| Command | What it does |
-|---|
-| `pnpm build` | Build via Turborepo |
-| `pnpm test` | Run all tests |
-| `pnpm lint` | Lint every workspace |
+| Command | What it does |
+| ----------------- | -------------------------- |
+| `pnpm build` | Build via Turborepo |
+| `pnpm test` | Run all tests |
+| `pnpm lint` | Lint every workspace |
| `pnpm type-check` | Type-check every workspace |
-| `pnpm format` | Format with Prettier |
+| `pnpm format` | Format with Prettier |
### App: `web` (documentation site)
-| Command | What it does |
-|---|
-| `pnpm --filter web dev` | Start the docs site in dev mode |
+| Command | What it does |
+| ------------------------- | ---------------------------------- |
+| `pnpm --filter web dev` | Start the docs site in dev mode |
| `pnpm --filter web build` | Build the docs site for production |
## Compatibility
### Runtime dependency
-| Package | Required | Notes |
-|---|
+| Package | Required | Notes |
+| ----------------------- | -------------- | -------------------------------------------------------------------------------------------------------- |
| `@standard-schema/spec` | Yes, `>=1.0.0` | The interface used by `fields`. Schema implementations (Zod, Valibot, ArkType) are passed by the caller. |
### Peer dependencies
-| Package | Required | Notes |
-|---|
+| Package | Required | Notes |
+| ---------------------------------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------- |
| [@deessejs/fp](https://github.com/deessejs/fp) | Optional, peer `>=1.0.0` | Recommended if you want `Result`/`Try` types around `ErrorInstance`. Not required for using `@deessejs/errors` alone. |
### Engines
-| Field | Value |
-|---|
-| `engines.node` | `>=22.14.0` |
+| Field | Value |
+| ---------------- | -------------- |
+| `engines.node` | `>=22.14.0` |
| `packageManager` | `pnpm@10.34.5` |
## Project structure
```
-
.
-+-- packages/
-+-- apps/
-+-- docs/
-+-- pnpm-workspace.yaml
-+-- turbo.json# Turborepo pipelines
-+-- .changeset/# Changesets for versioning
-+-- README.md
-
+├── packages/
+│ └── errors/ # The library — @deessejs/errors on npm
+│ ├── src/ # Source code (ESM)
+│ ├── tests/ # Vitest suites
+│ ├── dist/ # Build output (gitignored)
+│ └── tsconfig.build.json
+├── apps/
+│ └── web/ # Documentation site (Next.js + Fumadocs)
+├── docs/
+│ ├── internal/ # Engineering plans, runbooks
+│ │ ├── product/
+│ │ └── versions/
+│ └── engineering/
+├── pnpm-workspace.yaml
+├── turbo.json # Turborepo pipelines
+├── .changeset/ # Changesets for versioning
+└── README.md
```
## Publishing
Releases are fully automated via Changesets + npm Trusted Publishing (OIDC). No long-lived `NPM_TOKEN` is required.
-| What | How |
-|---|
-| Bump version | Add a `.changeset/.md` file with semver and description on a PR to `staging` |
-| Open the release PR | Cherry-pick selected commits from `staging` into `release/vX.Y.Z` and PR to `main` |
-| Publish | Merge to `main` - `release.yml` detects changesets and publishes via Trusted Publishing to npm with provenance attestation |
-| Hotfix | Branch from `main` as `release/hotfix-`, open PR directly to `main` with `[hotfix]` label. Same workflow fires. |
-| Rollback | Use `pnpm changeset version` then revert the merge. npm deprecations: `pnpm npm deprecate @deessejs/errors` ` ` |
+| What | How |
+| ------------------- | -------------------------------------------------------------------------------------------------------------------------- |
+| Bump version | Add a `.changeset/.md` file with semver and description on a PR to `staging` |
+| Open the release PR | Cherry-pick selected commits from `staging` into `release/vX.Y.Z` and PR to `main` |
+| Publish | Merge to `main` - `release.yml` detects changesets and publishes via Trusted Publishing to npm with provenance attestation |
+| Hotfix | Branch from `main` as `release/hotfix-`, open PR directly to `main` with `[hotfix]` label. Same workflow fires. |
+| Rollback | Use `pnpm changeset version` then revert the merge. npm deprecations: `pnpm npm deprecate @deessejs/errors@ ''` |
For the full release runbook, see [`docs/internal/engineering/process/releasing-a-new-version.md`](docs/internal/engineering/process/releasing-a-new-version.md).
@@ -182,12 +202,10 @@ Before submitting a PR:
2. Add a `.changeset/.md` if the change is user-facing (patch / minor / major).
3. Update `docs/internal/product/README.md` if the API surface changes.
-
## Acknowledgements
The README layout and monorepo tooling for this project are based on the [deessejs/package-template](https://github.com/deessejs/package-template). The shipped README borrows its structure from the [deessejs/fp README](https://github.com/deessejs/fp), adapted for the @deessejs/errors API surface.
-
## License
[MIT](./LICENSE). See the LICENSE file for details.
@@ -198,4 +216,3 @@ The README layout and monorepo tooling for this project are based on the [deesse
- Discussions: [github.com/deessejs/errors/discussions](https://github.com/deessejs/errors/discussions)
- Email: [support@deessejs.com](mailto:support@deessejs.com)
- Documentation: [errors.deessejs.com](https://errors.deessejs.com)
-```
From 4f854a96513a557556af853c6fff1097a11e0ced Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Tue, 4 Aug 2026 14:33:59 +0200
Subject: [PATCH 4/8] docs: align packages/errors/README.md with new shared
template
---
packages/errors/README.md | 203 ++++++++++++--------------------------
1 file changed, 63 insertions(+), 140 deletions(-)
diff --git a/packages/errors/README.md b/packages/errors/README.md
index 0de1045..13b825e 100644
--- a/packages/errors/README.md
+++ b/packages/errors/README.md
@@ -2,183 +2,106 @@
[](https://www.npmjs.com/package/@deessejs/errors)
[](https://www.typescriptlang.org/)
-[](https://opensource.org/licenses/MIT)
+[](https://github.com/deessejs/errors/actions/workflows/ci.yml)
+[](./LICENSE)
-A TypeScript error handling library with exception chaining, hierarchical inheritance, and rich error semantics — inspired by Python's error system.
+Lightweight, type-safe error handling for TypeScript — Python-style. Function-based API, exception chaining, hierarchical inheritance, and rich error semantics. ESM-only, designed for first-class interoperability with [`@deessejs/fp`](https://github.com/deessejs/fp)'s Result and Try.
-## Features
+> **Sibling projects:** [`@deessejs/fp`](https://github.com/deessejs/fp) provides `Result` and `Try` types that integrate natively with [`@deessejs/errors`](https://github.com/deessejs/errors) error factories. Install them together to get a complete error-handling story without glue code.
-- **Exception Chaining** — Preserve the full context of errors with cause chains via `.from()`
-- **Hierarchical Inheritance** — Organize errors in meaningful hierarchies with single or multiple inheritance
-- **Rich Error Semantics** — Attach structured data, templates, and notes to errors
-- **TypeScript First** — Full type safety with comprehensive type definitions
+---
-## Installation
+## What is included
+
+| Layer | What you get | Why it matters |
+| ------------------------------------------------------------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
+| **`error()`** | Define error factories with name, message templates, fields, and inheritance. | Python-style error definitions without classes. |
+| **`.from()` chaining** | Cause chain via `.from()` + `causes()` traversal. | Link errors together while preserving the full chain context. |
+| **Single or multiple inheritance** | `inherits:` accepts a factory or an array. | Organize error hierarchies that match your domain. |
+| **`is()` type checking** | Runtime and type-safe classifier with inheritance support. | Discriminate errors without brittle `instanceof`. |
+| **`.addNote()`** | Attach runtime context to error instances. | Python 3.11-style notes (PEP 678) for trail-of-breadcrumbs debugging. |
+| **Message templates** | `{field}` placeholders with `:upper`, `:lower`, `:json` modifiers. | Readable messages composed from structured fields at construction time. |
+| **Standard Schema fields** | Accepts Zod / Valibot / ArkType schemas. | Validated structured data on every error instance, no hand-rolled guards. |
+| **`raise()`** | Idiomatic throw helper. | Type-narrowed (`never`) `raise(err)` for control-flow readability. |
+| [`@deessejs/fp`](https://github.com/deessejs/fp) integration | `Result`/`Try` accept `ErrorInstance` directly. | Type-safe error pipelines end-to-end, no string-error footguns. |
+
+## Install
```bash
npm install @deessejs/errors
-# or
-pnpm add @deessejs/errors
-# or
-yarn add @deessejs/errors
```
-## Quick Start
+[`@deessejs/fp`](https://github.com/deessejs/fp) is optional - install it if you want to compose `Result`/`Try` types around `ErrorInstance`.
-### Creating Errors
+## Usage
```typescript
-import { error } from '@deessejs/errors';
+import { error, raise, is, causes } from '@deessejs/errors';
-// Simple error
-const ValidationError = error({ name: 'ValidationError' });
-const err = ValidationError();
-
-// Error with message template
+// Define an error factory with a templated message
const ValidationError = error({
name: 'ValidationError',
message: 'Field "{field}" is invalid: {reason}',
});
+// Construct a typed error
const err = ValidationError({ field: 'email', reason: 'invalid format' });
// err.message === 'Field "email" is invalid: invalid format'
-```
-
-### Exception Chaining
-
-```typescript
-import { error } from '@deessejs/errors';
-
-const ValidationError = error({ name: 'ValidationError' });
-const ProcessingError = error({ name: 'ProcessingError' });
-
-const validationErr = ValidationError({ field: 'email' });
-const processingErr = ProcessingError();
-
-// Chain errors with .from()
-processingErr.from(validationErr);
-
-console.log(processingErr.message); // "ProcessingError"
-console.log(processingErr.cause); // validationErr
-console.log(processingErr.causes); // [validationErr]
-```
-
-### Hierarchical Inheritance
-```typescript
-import { error } from '@deessejs/errors';
-
-// Single inheritance
-const AppError = error({ name: 'AppError' });
-const ValidationError = error({
- name: 'ValidationError',
- inherits: AppError,
-});
-
-// Multiple inheritance
-const NetworkError = error({ name: 'NetworkError' });
-const StorageError = error({ name: 'StorageError' });
-const CombinedError = error({
- name: 'CombinedError',
- inherits: [NetworkError, StorageError],
-});
-```
-
-### Type Checking
-
-```typescript
-import { error, is } from '@deessejs/errors';
-
-const AppError = error({ name: 'AppError' });
-const ValidationError = error({
- name: 'ValidationError',
- inherits: AppError,
-});
+// Chain a cause
+const cause = error({ name: 'NetworkError' })();
+err.from(cause);
-const err = ValidationError();
+// Throw it
+raise(err);
+// Later, type-check and walk the chain
is(err, ValidationError); // true
-is(err, AppError); // true (inherits from AppError)
-```
-
-### Traverse Cause Chain
-
-```typescript
-import { error, causes } from '@deessejs/errors';
-
-const Err1 = error({ name: 'Err1' });
-const Err2 = error({ name: 'Err2' });
-const Err3 = error({ name: 'Err3' });
-
-const err1 = Err1();
-const err2 = Err2().from(err1);
-const err3 = Err3().from(err2);
-
-// Iterate through the cause chain
-for (const cause of causes(err3)) {
- console.log(cause.name);
-}
-// Output: Err2, Err1
-```
-
-## Why @deessejs/errors?
-
-Built-in JavaScript errors are limited. `@deessejs/errors` brings Python-style error handling to TypeScript.
-
-| Feature | Built-in `Error` | @deessejs/errors |
-| ------------------------ | ---------------- | ---------------- |
-| Exception chaining | ❌ | ✅ |
-| Hierarchical inheritance | ❌ | ✅ |
-| Message templates | ❌ | ✅ |
-| Type-safe fields | ❌ | ✅ |
-| Standard Schema support | ❌ | ✅ |
-
-```typescript
-// Traditional approach — limited context
-throw new Error('Validation failed'); // ❌ Generic, no structure
-
-// @deessejs/errors — rich, maintainable errors
-const err = ValidationError({ field: 'email', reason: 'invalid format' });
-err.from(originalError); // ✅ Chain exceptions, preserve context
+causes(err); // [cause]
```
-## FAQ
+## Why this library
-### How do I create a custom error type?
+- **Simple by default.** No class hierarchies, no decorators under reflection.
+- **ESM-only.** Modern packaging, no CJS shim, no `module`/`main` duplication.
+- **Minimal runtime.** The only runtime dependency is `@standard-schema/spec`.
+- **TypeScript first-class.** Strict types, no `any` leakages, full inference. JSDoc on every public symbol.
+- **Real testing.** Vitest with type-level and runtime tests, including cause-chain traversal.
-```typescript
-import { error } from '@deessejs/errors';
+## Engine compatibility
-const ValidationError = error({ name: 'ValidationError' });
-const err = ValidationError({ field: 'email' });
-```
+| Runtime | Required |
+| ---------- | -------------------- |
+| Node.js | `>=22.14.0` |
+| pnpm | `10` for development |
+| TypeScript | `5.x` |
-### How do I chain exceptions?
+ESM-only. Consumers using a CJS resolver need to use dynamic `import()` or migrate to ESM.
-```typescript
-import { error } from '@deessejs/errors';
+## Available commands
-const validationErr = ValidationError({ field: 'email' });
-const processingErr = ProcessingError().from(validationErr);
+| Command | What it does |
+| ----------------- | -------------------------------------------- |
+| `pnpm build` | Build `dist/` (`tsc -p tsconfig.build.json`) |
+| `pnpm test` | Run vitest in watch mode |
+| `pnpm test:run` | Run vitest once |
+| `pnpm type-check` | `tsc --noEmit` |
+| `pnpm lint` | Run ESLint |
-console.log(processingErr.cause); // validationErr
-```
-
-### How do I check if an error is of a specific type?
+## Contributing
-```typescript
-import { error, is } from '@deessejs/errors';
+Open an issue to discuss larger changes. For typos, broken links, and small fixes, PRs are welcome.
-const AppError = error({ name: 'AppError' });
-const ValidationError = error({ name: 'ValidationError', inherits: AppError });
+Before submitting a PR:
-is(err, AppError); // true if err is ValidationError or any descendant
-```
+1. Run `pnpm test:run` and `pnpm lint`.
+2. Add a `.changeset/.md` if the change is user-facing (patch / minor / major).
+3. Update `docs/internal/product/README.md` if the API surface changes.
-## Documentation
+## License
-For full documentation, visit [errors.deessejs.com](https://errors.deessejs.com)
+[MIT](./LICENSE). See the LICENSE file for details.
-## License
+## Acknowledgements
-MIT
+The README layout is based on the [deessejs/package-template](https://github.com/deessejs/package-template) and borrows its structure from the [deessejs/fp README](https://github.com/deessejs/fp), adapted for the `@deessejs/errors` API surface.
From b8ab4c8b9de16a2376e16f7fdacae872658db221 Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Tue, 4 Aug 2026 14:37:52 +0200
Subject: [PATCH 5/8] chore: enrich package.json with npm SEO fields
Added: bugs.url, files, sideEffects:false, engines, funding, expanded keywords, expanded description.
---
packages/errors/package.json | 26 ++++++++++++++++++++++----
1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/packages/errors/package.json b/packages/errors/package.json
index b7dd70e..08df779 100644
--- a/packages/errors/package.json
+++ b/packages/errors/package.json
@@ -1,12 +1,15 @@
{
"name": "@deessejs/errors",
"version": "1.3.2",
- "description": "TypeScript error handling library inspired by Python — function-based API, exception chaining, hierarchical inheritance",
+ "description": "Lightweight, type-safe error handling for TypeScript — Python-style exception chaining, hierarchical inheritance, and rich error semantics. Function-based API, ESM-only, designed for first-class interoperability with @deessejs/fp.",
"homepage": "https://errors.deessejs.com",
"repository": {
"type": "git",
"url": "https://github.com/deessejs/errors.git"
},
+ "bugs": {
+ "url": "https://github.com/deessejs/errors/issues"
+ },
"type": "module",
"main": "./dist/index.js",
"module": "./dist/index.js",
@@ -17,6 +20,12 @@
"types": "./dist/index.d.ts"
}
},
+ "files": [
+ "dist",
+ "README.md",
+ "LICENSE"
+ ],
+ "sideEffects": false,
"scripts": {
"test": "vitest",
"test:run": "vitest run",
@@ -28,13 +37,15 @@
"typescript",
"errors",
"exception",
- "error-handling",
"exception-chaining",
+ "error-handling",
"hierarchical-errors",
"python-style-errors",
"custom-error-types",
- "nodejs",
- "npm-package"
+ "standard-schema",
+ "esm",
+ "monorepo",
+ "nodejs"
],
"author": "Nesalia Inc. ",
"license": "MIT",
@@ -42,6 +53,13 @@
"access": "public",
"provenance": true
},
+ "engines": {
+ "node": ">=22.14.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/deessejs"
+ },
"devDependencies": {
"@eslint/js": "^9.0.0",
"@types/node": "^25.9.1",
From 8e1a9484acbb44a54898a856f0c76fc29ade4f3a Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Tue, 4 Aug 2026 14:45:44 +0200
Subject: [PATCH 6/8] chore: add changeset for docs/seo release (1.3.3)
---
.changeset/docs-seo-enrichment.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 .changeset/docs-seo-enrichment.md
diff --git a/.changeset/docs-seo-enrichment.md b/.changeset/docs-seo-enrichment.md
new file mode 100644
index 0000000..c503e29
--- /dev/null
+++ b/.changeset/docs-seo-enrichment.md
@@ -0,0 +1,15 @@
+---
+'@deessejs/errors': patch
+---
+
+Refresh the README and package.json metadata for the npm listing.
+
+README:
+- Adopt the shared ecosystem layout (badges block, What is included table, Quick start, Compatibility, Project structure, Publishing, Architecture notes, Contributing, Acknowledgements).
+- Credit `deessejs/package-template` and `deessejs/fp` in the new Acknowledgements section.
+- Surface the `addNote()` (PEP 678), `raise()`, `causes()`, and the `Result`/`Try` interop story in both the root and the package README.
+
+Package metadata:
+- Replace the placeholder description with a more searchable summary (Python-style, ESM, `@deessejs/fp` interop).
+- Add `bugs.url`, `files`, `sideEffects: false`, `engines.node`, and `funding` (GitHub Sponsors).
+- Refresh `keywords`: drop `npm-package`, add `standard-schema`, `esm`, `monorepo`.
From 43c4928bc4894e8fd85eee26b837911ccf7b6528 Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Tue, 4 Aug 2026 16:01:38 +0200
Subject: [PATCH 7/8] chore: drop changeset for docs/seo release
---
.changeset/docs-seo-enrichment.md | 15 ---------------
1 file changed, 15 deletions(-)
delete mode 100644 .changeset/docs-seo-enrichment.md
diff --git a/.changeset/docs-seo-enrichment.md b/.changeset/docs-seo-enrichment.md
deleted file mode 100644
index c503e29..0000000
--- a/.changeset/docs-seo-enrichment.md
+++ /dev/null
@@ -1,15 +0,0 @@
----
-'@deessejs/errors': patch
----
-
-Refresh the README and package.json metadata for the npm listing.
-
-README:
-- Adopt the shared ecosystem layout (badges block, What is included table, Quick start, Compatibility, Project structure, Publishing, Architecture notes, Contributing, Acknowledgements).
-- Credit `deessejs/package-template` and `deessejs/fp` in the new Acknowledgements section.
-- Surface the `addNote()` (PEP 678), `raise()`, `causes()`, and the `Result`/`Try` interop story in both the root and the package README.
-
-Package metadata:
-- Replace the placeholder description with a more searchable summary (Python-style, ESM, `@deessejs/fp` interop).
-- Add `bugs.url`, `files`, `sideEffects: false`, `engines.node`, and `funding` (GitHub Sponsors).
-- Refresh `keywords`: drop `npm-package`, add `standard-schema`, `esm`, `monorepo`.
From 1acfb53ed01f95f11c6debdf50eba7c038a27cb0 Mon Sep 17 00:00:00 2001
From: martyy-code
Date: Wed, 5 Aug 2026 10:29:56 +0200
Subject: [PATCH 8/8] chore: add changeset for docs/seo release (1.3.3)
---
.changeset/docs-seo-enrichment.md | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 .changeset/docs-seo-enrichment.md
diff --git a/.changeset/docs-seo-enrichment.md b/.changeset/docs-seo-enrichment.md
new file mode 100644
index 0000000..c503e29
--- /dev/null
+++ b/.changeset/docs-seo-enrichment.md
@@ -0,0 +1,15 @@
+---
+'@deessejs/errors': patch
+---
+
+Refresh the README and package.json metadata for the npm listing.
+
+README:
+- Adopt the shared ecosystem layout (badges block, What is included table, Quick start, Compatibility, Project structure, Publishing, Architecture notes, Contributing, Acknowledgements).
+- Credit `deessejs/package-template` and `deessejs/fp` in the new Acknowledgements section.
+- Surface the `addNote()` (PEP 678), `raise()`, `causes()`, and the `Result`/`Try` interop story in both the root and the package README.
+
+Package metadata:
+- Replace the placeholder description with a more searchable summary (Python-style, ESM, `@deessejs/fp` interop).
+- Add `bugs.url`, `files`, `sideEffects: false`, `engines.node`, and `funding` (GitHub Sponsors).
+- Refresh `keywords`: drop `npm-package`, add `standard-schema`, `esm`, `monorepo`.