Skip to content

Releases: jpbaking/error-extender

v2.0.1 — merge type-safety & CI cleanup

Choose a tag to compare

@jpbaking jpbaking released this 15 Jun 20:00

Patch release. No public API or runtime behavior changes — safe drop-in upgrade from 2.0.0.

Changes since v2.0.0

Internal

  • merge() refactor (d9ed6d2) — hoisted result[key]/obj[key] into locals so the isPlainObject type guard narrows them, removing the as Record<string, unknown> casts. Behavior unchanged: deep-merge plain objects, last-write-wins otherwise.

CI / tooling

  • Renamed workflow to ci.yml; dropped the publish-on-release job and OIDC permissions (39aae1a).
  • Node version bumped to 22 in CI.

Quality

  • Lint clean; 19/19 tests passing; 100% coverage (statements/branches/functions/lines).

Note: npm publishing is now manual (npm publish) — the release no longer triggers an automated publish.

npm: https://www.npmjs.com/package/error-extender/v/2.0.1

v2.0.0 — TypeScript rewrite

Choose a tag to compare

@jpbaking jpbaking released this 15 Jun 19:24

Breaking Changes

  • Factory-without-new removed. Errors must now be constructed with new:
    // Before (v1.x)
    throw CustomError({ message: 'oops' });
    
    // After (v2.0.0)
    throw new CustomError({ message: 'oops' });
  • Entry point moved to dist/. Package exports are dist/index.js and dist/index.d.ts. Do not import from src/.

What's New

Full TypeScript rewrite

The entire source has been rewritten in TypeScript (src/). Compiled output ships as CommonJS targeting ES2020 via tsc.

Typed public API

import extendError, {
  ExtendOptions,
  ErrorConstructorOptions,
  ExtendedError,
  ExtendedErrorConstructor,
} from 'error-extender';

interface HttpErrorData { status: number; body?: string }

const HttpError = extendError<HttpErrorData>('HttpError', {
  defaultData: { status: 500 },
});

const err = new HttpError({ data: { status: 404, body: 'Not Found' } });
err.data?.status; // typed as number
Exported type Description
ExtendOptions<TData> Options passed to extendError()
ErrorConstructorOptions<TData> Options passed to new CustomError()
ExtendedError<TData> Instance interface with typed data and cause
ExtendedErrorConstructor<TData> Constructor interface returned by extendError()

Prototype-based inheritance (no class extends)

The factory uses Object.create() to wire the prototype chain directly, avoiding the constructor-chaining issues that affect class extends Error patterns in transpiled environments. instanceof checks work correctly across deep hierarchies.

Default inheritance and deep-merge

  • defaultMessage is inherited from the parent if the child does not set one.
  • defaultData deep-merges with the parent's defaultData when both are plain objects; otherwise the child's value replaces the parent's.
const BaseError = extendError('BaseError', { defaultMessage: 'Something went wrong' });
const ChildError = extendError('ChildError', { parent: BaseError });

new ChildError().message; // 'Something went wrong' — inherited

Short-form constructor aliases

All constructor options have single-letter aliases to reduce boilerplate at call sites:

Short Long
m message
d data
c cause
throw new HttpError({ m: 'Not Found', d: { status: 404 }, c: originalError });

cause chain in stack traces

When a cause is provided, its stack is appended to the thrown error's stack as Caused by: ..., giving full chain visibility in logs without any extra tooling.

CI/CD: automated npm publish

A GitHub Actions workflow now publishes to npmjs automatically on every GitHub release (NPM_TOKEN secret required).


License change

Relicensed from MIT to 0BSD (Zero-Clause BSD). No attribution required, no conditions — maximally permissive.


Test results

Test Files  3 passed (3)
     Tests  19 passed (19)
  Duration  539ms
Metric Coverage
Statements 100% (42/42)
Branches 100% (47/47)
Functions 100% (5/5)
Lines 100% (42/42)

Commits since v1.0.2

Commit Description
27f19d6 feat: Migrate to TypeScript with Vitest
8035b9f docs: Rewrite README for TypeScript migration
2ec704a chore: Release 2.0.0 — version bump, AGENTS.md DOX hierarchy, updated README
4eb7bc5 chore: Relicense from MIT to 0BSD
9d1458f chore: Remove email address from package.json author field
adfb1c4 chore: Upgrade all devDependencies to latest
9683020 fix: Quote test glob so mocha resolves ** recursively
739cfb4 chore: Add GitHub Actions publish workflow
0a28999 chore: Rename publish workflow to npm-publish-on-github-release.yml

v1.0.2 — npm listing fix

Choose a tag to compare

@jpbaking jpbaking released this 15 Jun 01:49

Patch release to fix the npm registry listing. No functional code changes.

Change list

  • README: added "100% Code Coverage" callout section — notes that coverage is verifiable via npm test
  • package.json: version bump 1.0.11.0.2 to force a clean republish and restore the correct npm registry listing

v1.0.1 — README improvements

Choose a tag to compare

@jpbaking jpbaking released this 15 Jun 01:49

Documentation-only release. No code changes.

Change list

  • README: added stacktrace demo at the top of the file — a full end-to-end example showing Caused by: output when a cause is supplied
  • README: fixed copy-paste error — two code snippets used extendError('ServiceError', ...) where the variable was named AppError; both now correctly read extendError('AppError', ...)
  • package.json: version bump 1.0.01.0.1

v1.0.0 — Initial release

Choose a tag to compare

@jpbaking jpbaking released this 15 Jun 01:49

Initial release of error-extender — a utility for creating custom Error subclasses in Node.js with first-class support for error chaining, default context, and deep data merging.

Features

extendError(name, options?)

Creates a named custom error class. The returned constructor is a proper Error subclass — instanceof works up the full chain.

const extendError = require('error-extender');

const AppError     = extendError('AppError');
const ServiceError = extendError('ServiceError', { parent: AppError });
const DbError      = extendError('DbError',      { parent: ServiceError });

new DbError() instanceof ServiceError // true
new DbError() instanceof AppError     // true
new DbError() instanceof Error        // true

options at class-definition time

key type description
parent Error constructor Error class to extend (default: Error)
defaultMessage string Fallback message when none is provided at construction
defaultData any Fallback data; plain-object values deep-merge down the inheritance chain

Constructor options

Each extended error accepts an object literal with short aliases:

key alias type
message m string
data d any
cause c Error

data merging

Instance data deep-merges with defaultData when both are plain objects:

const AppError = extendError('AppError', {
  defaultData: { status: 503, body: { message: 'Unhandled error.' } }
});

new AppError({ d: { status: 401 } }).data
// → { status: 401, body: { message: 'Unhandled error.' } }

cause chaining

Attaching a cause appends its full stack as Caused by:, mirroring Java exception chaining:

const rootCause = new Error('connection refused');
const err = new ServiceError({ message: 'Service unavailable', cause: rootCause });

console.log(err.stack);
// ServiceError: Service unavailable
//     at ...
// Caused by: Error: connection refused
//     at ...

100% test coverage