Skip to content

release: v2.0.5 - accept task-level postDelay/startDelay, keep… - #58

Merged
cldmv-bot[bot] merged 25 commits into
masterfrom
next
Oct 5, 2026
Merged

cldmv-bot[bot] merged 25 commits into
masterfrom
next

Conversation

@cldmv-bot

@cldmv-bot cldmv-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

HoldMyTask v2.0.5 Changelog

Release Date: October 2026
Release Type: Patch
Branch: release/2.0.5


Overview

v2.0.5 fixes three long-standing problems in how the queue reads its options and reports failures. The documented task-level postDelay / startDelay options now actually work (the old delay / start names become deprecated aliases), a callback-style task failure no longer crashes the process when no error listener is attached, and a priorities key that is not an integer is now reported instead of being dropped silently. The README was rewritten to the CLDMV layout and every example now uses the current API.

Runtime behavior changes in a few observable ways, all described below: code that still passes delay or start to enqueue() now receives a deprecation warning event, a task-level completion delay is now enforced even when the task's priority has no postDelay of its own, a callback-style task failure is no longer thrown as an unhandled error event, and a non-integer priority key now produces an invalid-priority warning. No option was removed and no exported signature changed.


🐛 Bug Fixes

Task-level postDelay / startDelay are honored; delay / start are deprecated aliases (#55)

enqueue() only read the task-level delay and start options, although its JSDoc already pointed at postDelay. Passing the documented name gave no delay at all. enqueue() now treats postDelay and startDelay as the current task-level names, matching the names already used in priorities, coalescing.defaults and coalescing.keys. delay and start still work and map onto the new names; when both forms are given, the current name wins. postDelay: -1 bypasses an active delay period exactly as delay: -1 did, and the caller's options object is never mutated. getPriorityConfig() and getCoalescingConfig() accept both names in their taskOptions argument.

New warning: each deprecated task-level alias now emits a warning event of type "deprecation" (with deprecated and replacement fields), in the same shape the priority and coalescing levels already used. The warning fires once per alias per queue instance, not once per task, so a hot enqueue path does not flood listeners. No warning is emitted when the replacement name is also present.

Scheduler fix: the delay gate between tasks used to require the completed task's priority to have a positive postDelay. A task-level completion delay on a priority without one was recorded but never enforced, which was true of the old delay name as well. The gate now relies on the computed next-available time alone, so a task-level postDelay (or delay) takes effect regardless of the priority's configuration. Code that relied on a task-level delay being ignored in that situation will now see the delay applied. Closes #51.

Callback-style task failures no longer require an error listener (#56)

When a callback-style task failed, timed out, was aborted or expired, the queue emitted error. HoldMyTask is an EventEmitter, so with no error listener that emit threw: the process crashed (an unhandled rejection for failures, an uncaught exception from the scheduler for expiry), and for failures the task's callback never ran. Task-failure error events are now emitted only when at least one error listener is attached. The failure always reaches the task's callback with the documented payload ({ type: "error", error }, { type: "timeout", message }, { type: "canceled", message: "Task was aborted" }, or the expiry error).

Listeners that are attached see the same events as before. The difference is for queues without one: a callback task failure is no longer thrown. An error thrown by the callback itself is still emitted unconditionally, so a bug inside a callback is not silently swallowed, and the error events for invalid enqueue() arguments and rejected configurePriority() / configureCoalescingKey() input are unchanged. Promise-style tasks are unchanged and report failures only through the rejected promise. Closes #53.

Non-integer priority keys are reported instead of dropped silently (#57)

The constructor ran priorities (and the deprecated delays) keys through parseInt and discarded anything that came back NaN, so a config such as priorities: { high: { postDelay: 100 } } did nothing, and a key such as "2.5" was truncated without notice. Any non-integer key now emits a warning event of type "invalid-priority" with message, option ("priorities" or "delays"), key and priority fields. A key that cannot be read as a number is still ignored (priority: null); a fractional key keeps its historical meaning, the truncated priority, but is reported. Integer keys, including negative ones, are unaffected. The constructor still never throws for configuration, so a config that constructed fine on v2.0.4 still constructs fine. Closes #54.


🧪 Tests

  • New suites: TaskLevelDelayNames (#55), CallbackErrorWithoutListener (#56) and PriorityKeyValidation (#57).
  • PostDelayAfterAwait (#59) adds deterministic fake-timer coverage for postDelay when the next task is enqueued after awaiting the previous one: promise API after await, promise API in the resolving microtask, and callback API enqueuing from the completion callback, in both smart-scheduling and polling modes. All cases pass on the current code; the report in #52 could not be reproduced, and the issue is closed with these tests as regression coverage.

📚 Documentation

  • The README was restructured to the CLDMV layout and every example was updated from deprecated option names to the current API (#50). It now documents the task-level postDelay / startDelay options, the optional error listener for callback-style tasks, both warning event types (deprecation and invalid-priority), and a table of every deprecated option with its replacement.
  • The JSDoc and generated types/ declarations for enqueue() list postDelay and startDelay, with delay and start marked deprecated.
  • NEW: docs/changelog/v2/v2.0.5.md — this changelog.

🔧 Dependencies

Both are dev dependencies and affect only the npm run fix:headers script, which extends @cldmv/configs/fix-headers.json. Only package.json and the lockfile changed; no file headers were restamped and the published package is unaffected.

  • @cldmv/fix-headers ^2.1.1 → ^2.2.0, in two steps. 2.1.4 (#61) no longer writes a JavaScript comment into JSON or Markdown files, processes every repeated --input, and never walks dependency folders such as node_modules. 2.2.0 (#62) makes @Last modified by follow edits to a file's content only, so a run that merely rewrites a header keeps the recorded editor.
  • @cldmv/configs ^1.2.0 → ^1.2.4 (#62). The shared fix-headers config now sets forceAuthorUpdate and forceLastModifiedAuthorUpdate to false, so @Author keeps the file's creator and @Last modified by changes only with real content edits. The 1.2.1 and 1.2.2 releases of that package only changed its own CI.

Upgrade notes

No breaking API changes — drop-in for v2.0.4, with these behavior differences to check:

  • Replace task-level delay with postDelay and start with startDelay in enqueue() calls. The old names keep working, but each emits one deprecation warning per queue instance.
  • A task-level postDelay (or delay) is now enforced even when the task's priority has no postDelay. If a queue depended on that delay being ignored, remove it from the task options.
  • A callback-style task failure is no longer thrown when no error listener is attached; handle failures in the task callback, or attach an error listener if the queue-level event is wanted.
  • Check priorities / delays configs for non-integer keys. They behave as before, but now emit an invalid-priority warning.
👥 Contributors

coverage

Metric Coverage
Statements 80.7%
Branches 75.2%
Functions 72.7%
Lines 81.8%

Avg: 77.6% · 9e5a70b · Node lts/*

Co-authored-by: Shinrai Shinrai@users.noreply.github.com

Shinrai and others added 3 commits October 3, 2026 17:19
…t as deprecated aliases

enqueue() only read the task-level `delay` and `start` options, although
the JSDoc already pointed at `postDelay`. Passing the documented name gave
no delay at all.

- enqueue() now normalizes task options: `postDelay` / `startDelay` are the
  current names, `delay` / `start` map onto them and emit a `warning` event
  in the same deprecation shape the priority and coalescing levels use
  (once per name per queue instance, so a hot enqueue path isn't flooded).
  The current name wins when both are given; caller options are never
  mutated. `postDelay: -1` bypasses an active delay like `delay: -1` did.
- getPriorityConfig() / getCoalescingConfig() accept both names in
  taskOptions.
- The scheduler's delay gate now uses nextAvailableTime alone. It used to
  require the completed task's *priority* postDelay to be positive, so a
  task-level completion delay on a priority without a postDelay was set
  but never enforced (true for the old `delay` name as well).
- JSDoc, generated types and the README task-option list use the new names.

Fixes #51
@cldmv-bot cldmv-bot Bot added ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: patch This release contains only backwards-compatible bug fixes type: bug Something is broken or not behaving as expected labels Oct 4, 2026
@cldmv-bot

cldmv-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor Author

🔒 Dependency Review

  • ✅ 0 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ✅ 0 package(s) with unknown licenses
  • ✅ 0 denied package(s)
  • ✅ 0 package(s) with OpenSSF Scorecard score < 3

Full job summary

@cldmv-bot cldmv-bot Bot added area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure type: dependencies Relates to dependency updates, version bumps, or package management type: documentation Relates to docs, README updates, guides, or inline code comments labels Oct 4, 2026
…g an error listener

When a callback-style task failed, timed out, was aborted or expired, the
queue emitted `error` (before the callback for failures, after it for
expiry). HoldMyTask is an EventEmitter, so with no `error` listener the
emit threw: the process crashed (an unhandled rejection from _startTask,
an uncaught exception from the scheduler for expiry) and, for failures,
the callback never ran.

Task-failure `error` events are now emitted only when a listener is
attached (listenerCount("error") > 0). The failure always reaches the
task's callback with the documented payload ({ type: "error", error },
{ type: "timeout", message }, { type: "canceled", message: "Task was
aborted" }, or the expire Error). Promise-API behaviour is unchanged.

Errors thrown by the user's own callback are still emitted
unconditionally, so a bug in a callback is not silently swallowed.

Fixes #53
@cldmv-bot

cldmv-bot Bot commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor Author

⚠️ Bundle size increased

File Raw Δ Raw Gzipped Δ Gzipped
dist/hold-my-task.mjs 98.7 kB +4.6 kB (+4.9%) ⚠️ 20.8 kB +1.4 kB
dist/utils.mjs 3.3 kB — 1.2 kB —
index.cjs 1.6 kB — 813 B —
index.mjs 2.4 kB — 937 B —
types/index.d.mts 1.7 kB — 564 B —
types/index.d.mts.map 834 B — 299 B —
Total 108.5 kB +4.6 kB 24.5 kB +1.4 kB

📊 Generated by bundle-size. Brotli sizes also measured but omitted from the table for brevity.

Shinrai and others added 16 commits October 3, 2026 17:33
…em silently

The constructor ran `priorities` (and the deprecated `delays`) keys through
parseInt and silently discarded anything that came back NaN, so a config
such as `priorities: { high: { postDelay: 100 } }` simply did nothing.
Keys parseInt could only partly read ("2.5") were silently truncated.

Non-integer keys now emit a `warning` event:
  { type: "invalid-priority", message, option, key, priority }
A key parseInt can't read is still ignored (priority: null); a truncated
key keeps its historical meaning (the truncated priority) but is reported.
Integer keys, including negative ones, are unaffected.

A warning rather than a thrown TypeError, for consistency with how the
library treats other questionable configuration: the constructor never
throws for config, deprecated names are reported through `warning`
events, and invalid runtime config (configurePriority /
configureCoalescingKey) is reported through events rather than thrown.
Throwing would also turn configs that currently construct fine into a
crash on a patch upgrade.

Fixes #54
Deterministic fake-timer tests (promise API after await, promise API in the
resolving microtask, callback API enqueuing from the completion callback) in
both scheduling modes. All pass on the current code; #52 could not be
reproduced.

Closes #52
Reorganize the README into the standard section order: intro and
tagline, reference-style badge row with definitions at the bottom
(adds the coverage badge from the badges branch), What's New, Key
Features, Installation with Node.js requirements (including the
require(esm) floor), Quick Start, then the existing usage and API
sections, Documentation, quality badges, Contributing, Links and
License.

Also fixes content that disagreed with the code:
- the mangled "Import Options" heading emoji
- the "@cldmv/holdmytask/src" import, which is not an exported
  subpath; replaced with the holdmytask-dev export condition
- configurePriority/configureCoalescingKey and coalescing defaults
  now list postDelay/startDelay (delay/start are deprecated aliases;
  configurePriority never accepted maxDelay)
- Quick Start uses priorities/coalescing instead of the deprecated
  delays/coalescingWindowDuration options
- Testing section names the actual npm scripts (coverage,
  test:watch, build:ci)
Rewrite all README examples and option descriptions that used
deprecated options:
- delays -> priorities: { [priority]: { postDelay } }
- delay/start in priority, coalescing defaults/keys and the
  configure* methods -> postDelay/startDelay
- coalescingWindowDuration/MaxDelay/ResolveAllPromises constructor
  options -> coalescing.defaults.*
- the alias example used a non-numeric priority key, which the
  constructor silently drops

Add a Deprecated Options table (old -> new) and make clear that the
task-level delay/start and coalescing* overrides are current names.

Fix content that disagreed with the code:
- Deprecation Warning Events: warnings carry type/message/deprecated/
  replacement (there is no `source`); output now matches the real
  messages and emission order
- Async Initialization: sync:false returns a plain Promise with no
  .on(); attach listeners to the awaited instance
- resolveAllPromises:false rejects the non-representative tasks with
  "Task was coalesced with a newer task" instead of resolving them
  with undefined, and the newest task is the representative
- callback-style failures emit an "error" event that throws when no
  listener is attached; document it, add a listener to Quick Start,
  and describe the callback error payload shape
- options list: drop onError (not implemented), add healingInterval
  and sync
Warnings are no longer only deprecations: #57 reports non-integer priority
keys as type "invalid-priority". Describe both warning shapes.
Bumps @cldmv/fix-headers to 2.1.4 and re-runs npm run fix:headers. 0 files' headers were restamped.
Covers #55 (task-level postDelay/startDelay, deprecated delay/start aliases, delay-gate fix), #56 (callback failures without an error listener), #57 (invalid-priority warning), #59 (regression tests for #52) and #50 (README restructure).
Shinrai and others added 5 commits October 4, 2026 16:40
Bumps @cldmv/fix-headers from ^2.1.4 to 2.2.0. No file headers changed.
Bump @cldmv/configs ^1.2.0 (locked 1.2.0-1.2.2) to ^1.2.4 (1.2.4). The older shared fix-headers.json forced forceAuthorUpdate and forceLastModifiedAuthorUpdate on; 1.2.4 sets both false, so with fix-headers 2.2.0 @author is never rewritten and @last modified by changes only on real content edits. Restamped files: 0.
@cldmv-bot
cldmv-bot Bot merged commit c988b5b into master Oct 5, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: patch This release contains only backwards-compatible bug fixes type: bug Something is broken or not behaving as expected type: dependencies Relates to dependency updates, version bumps, or package management type: documentation Relates to docs, README updates, guides, or inline code comments

Projects

None yet

2 participants