From 19eb75b4bbb91c8a9f0b286c9b70a7d8d35def05 Mon Sep 17 00:00:00 2001 From: coji Date: Mon, 16 Mar 2026 22:49:16 +0900 Subject: [PATCH] chore: release v0.14.0 - Bump version to 0.14.0 in both packages - Add CHANGELOG entry for v0.14.0 - Fix events.md: error handling docs were incorrect (exceptions don't interrupt subsequent listeners) - Add run:lease-renewed event to events.md - Add error class exports to index.md and llms.md - Regenerate llms.txt Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 36 +++++++++++++++++++++++++++++ packages/durably-react/package.json | 2 +- packages/durably/docs/llms.md | 17 ++++++++++++++ packages/durably/package.json | 2 +- website/api/events.md | 22 +++++++++++++++++- website/api/index.md | 11 ++++++++- website/public/llms.txt | 17 ++++++++++++++ 7 files changed, 103 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d36d55..8c577ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +## [0.14.0] - 2026-03-16 + +### Added + +#### @coji/durably + +- **Export error classes**: `DurablyError`, `NotFoundError`, `ValidationError`, `ConflictError` now exported for programmatic error handling (#129) + +### Fixed + +#### @coji/durably + +- **Prevent completed step from being written to cancelled run** (#128) +- **Return proper HTTP status codes and stop coercing input** (#129) +- **Separate maintenance from processOne to fix idle contract**: `processOne()` is now pure claim-execute-return. Lease normalization and auto-purge run only during idle cycles via worker `onIdle` callback (#134) +- **Catch rejected promises from async event listeners**: Async listener rejections are now forwarded to `onError` instead of being silently dropped. `withLogPersistence()` fixed to use explicit fire-and-forget (#137) + +### Performance + +#### @coji/durably + +- **Skip write mutex for PostgreSQL backend**: PostgreSQL doesn't need the serialization mutex used for SQLite (#130) +- **Denormalize step_count and remove labels JSON fallback**: Avoids subqueries and JSON parsing in hot paths (#132) + +### Internal + +- Extract `claim-postgres.ts`, `claim-sqlite.ts`, `transformers.ts` from `storage.ts` for better separation of concerns (#133) +- Extract `toError()` helper in `errors.ts` to deduplicate error coercion pattern (#137) + +### Documentation + +- Document synchronous event listener behavior with best practices (#135) +- Add `run:lease-renewed` event to Events API reference +- Add error classes to Quick Reference and LLM documentation +- PostgreSQL example, database comparison guide, expanded LLM docs (#114-#120) + ## [0.13.0] - 2026-03-16 ### Breaking Changes diff --git a/packages/durably-react/package.json b/packages/durably-react/package.json index 120e72e..a6e4ddb 100644 --- a/packages/durably-react/package.json +++ b/packages/durably-react/package.json @@ -1,6 +1,6 @@ { "name": "@coji/durably-react", - "version": "0.13.0", + "version": "0.14.0", "description": "React bindings for Durably - step-oriented resumable batch execution", "type": "module", "main": "./dist/index.js", diff --git a/packages/durably/docs/llms.md b/packages/durably/docs/llms.md index 5e0d259..339caef 100644 --- a/packages/durably/docs/llms.md +++ b/packages/durably/docs/llms.md @@ -657,6 +657,23 @@ interface RunFilter< } ``` +## Error Classes + +Durably exports typed error classes for programmatic error handling: + +```ts +import { + DurablyError, // Base class with statusCode (extends Error) + NotFoundError, // 404 — resource not found + ValidationError, // 400 — invalid input or request + ConflictError, // 409 — operation conflicts with current state + CancelledError, // Run was cancelled during execution + LeaseLostError, // Worker lost lease ownership +} from '@coji/durably' +``` + +`DurablyError` subclasses (`NotFoundError`, `ValidationError`, `ConflictError`) carry a `statusCode` property and are used by the HTTP handler to return appropriate responses. + ## License MIT diff --git a/packages/durably/package.json b/packages/durably/package.json index 8feaf81..44ddc5f 100644 --- a/packages/durably/package.json +++ b/packages/durably/package.json @@ -1,6 +1,6 @@ { "name": "@coji/durably", - "version": "0.13.0", + "version": "0.14.0", "description": "Step-oriented resumable batch execution for Node.js and browsers using SQLite", "type": "module", "main": "./dist/index.js", diff --git a/website/api/events.md b/website/api/events.md index 2514db3..1503ee4 100644 --- a/website/api/events.md +++ b/website/api/events.md @@ -50,6 +50,25 @@ durably.on('run:leased', (event) => { }) ``` +#### `run:lease-renewed` + +Fired when a run's lease is renewed during execution. + +```ts +durably.on('run:lease-renewed', (event) => { + // event: { + // type: 'run:lease-renewed', + // runId: string, + // jobName: string, + // leaseOwner: string, + // leaseExpiresAt: string, + // labels: Record, + // timestamp: string, + // sequence: number + // } +}) +``` + #### `run:complete` Fired when a run completes successfully. @@ -295,7 +314,7 @@ durably.on('run:complete', (e) => { ## Error Handling -Exceptions thrown in event listeners are caught and forwarded to the error handler — they do not crash the worker or abort the current run. However, because listeners run synchronously, an exception still interrupts subsequent listeners for the same event. Use `onError` to catch these: +Exceptions thrown in event listeners are caught and forwarded to the error handler — they do not crash the worker, abort the current run, or interrupt subsequent listeners for the same event. If a listener returns a rejected Promise (async listener), the rejection is also forwarded to `onError`. Use `onError` to catch both: ```ts durably.onError((error, event) => { @@ -317,6 +336,7 @@ interface BaseEvent { type DurablyEvent = | RunTriggerEvent | RunLeasedEvent + | RunLeaseRenewedEvent | RunCompleteEvent | RunFailEvent | RunCancelEvent diff --git a/website/api/index.md b/website/api/index.md index d5f67a0..c5bcc20 100644 --- a/website/api/index.md +++ b/website/api/index.md @@ -265,7 +265,16 @@ import type { DurablyEvent, EventType, } from '@coji/durably' -import { createDurablyHandler, toClientRun } from '@coji/durably' +import { + createDurablyHandler, + toClientRun, + DurablyError, + NotFoundError, + ValidationError, + ConflictError, + CancelledError, + LeaseLostError, +} from '@coji/durably' ``` ### `Run` Type diff --git a/website/public/llms.txt b/website/public/llms.txt index 835f3e4..bd4a009 100644 --- a/website/public/llms.txt +++ b/website/public/llms.txt @@ -657,6 +657,23 @@ interface RunFilter< } ``` +## Error Classes + +Durably exports typed error classes for programmatic error handling: + +```ts +import { + DurablyError, // Base class with statusCode (extends Error) + NotFoundError, // 404 — resource not found + ValidationError, // 400 — invalid input or request + ConflictError, // 409 — operation conflicts with current state + CancelledError, // Run was cancelled during execution + LeaseLostError, // Worker lost lease ownership +} from '@coji/durably' +``` + +`DurablyError` subclasses (`NotFoundError`, `ValidationError`, `ConflictError`) carry a `statusCode` property and are used by the HTTP handler to return appropriate responses. + ## License MIT