@mrjacket/ahko 0.5.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,53 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.0.0] - 2026-09-23 — Stable Scheduler Release
9
+
10
+ ### Added
11
+ - Comprehensive End-to-End stress and integration test suite (`src/__tests__/e2e.test.ts`) verifying:
12
+ - High-concurrency bursts under rate-limited temporal pacing (`minIntervalMs`) and jittered backoff retries.
13
+ - Interleaved interactive debounce and throttle streams under queue contention.
14
+ - Cooperative cancellation waves simulating document switches or build cancellations (VS Code / CLI scenarios).
15
+ - Graceful shutdown workflows clearing pending queues while allowing in-flight tasks to settle cleanly (`ahko.chill()`).
16
+ - Full lifecycle telemetry stream validation and microservice uncooperative timeout handling.
17
+ - Standalone runnable examples suite (`examples/`) with dedicated `examples/README.md`:
18
+ - `01-concurrency-and-pacing.mjs`: concurrency limits and temporal pacing.
19
+ - `02-debounce-search.mjs`: debounced interactive search with Promise coalescing.
20
+ - `03-throttle-events.mjs`: high-frequency event stream throttling.
21
+ - `04-retry-backoff-jitter.mjs`: resilient retries with exponential backoff and full jitter.
22
+ - `05-idle-telemetry.mjs`: non-blocking background tasks and lifecycle event logging.
23
+ - `06-graceful-shutdown.mjs`: safe process termination sequence.
24
+ - Dedicated npm script `"test:e2e"` for focused integration testing.
25
+ - Documentation restructuring into domain guides (`docs/guides/`) and specifications (`docs/architecture/`), including production architectural recipes (`recipes.md`).
26
+
27
+ ### Changed
28
+ - Connected `DebounceCoordinator` and `ThrottleCoordinator` settlement lifecycles directly to `TaskQueue.checkIdle()`, ensuring that window expirations and coordinator deletions deterministically resolve idle promises and emit `"idle"` events.
29
+ - Transitioned version to stable 1.0.0 baseline with frozen zero-dependency architecture.
30
+
31
+ ---
32
+
33
+ ## [0.6.0] - 2026-09-23 — Telemetry & DX
34
+
35
+ ### Added
36
+ - Type-safe lifecycle event emitter (`AhkoEventEmitter`) with dedicated `IAhkoEventMap` events:
37
+ - `task:start`: emitted when a task begins execution with `taskId` and `attempt`.
38
+ - `task:complete`: emitted on task success with `taskId`, `attempt`, `durationMs`, and `result`.
39
+ - `task:fail`: emitted on failure with `taskId`, `attempt`, `error`, and `willRetry` boolean indicator.
40
+ - `task:cancel`: emitted on task cancellation with `taskId` and `reason`.
41
+ - `task:timeout`: emitted when execution exceeds configured deadline with `taskId` and `timeoutMs`.
42
+ - `idle`: emitted when all tasks settle and queue reaches idle state with `timestamp`.
43
+ - Event subscription methods `ahko.on(event, handler)` returning an unsubscribe function, and `ahko.off(event, handler)`.
44
+ - Listener error containment: listener exceptions are safely isolated without crashing the scheduler loop or sibling listeners.
45
+ - Idle lifecycle promises via `ahko.isIdle()`, `ahko.onIdle()`, and chill alias `ahko.chill()`.
46
+ - Queue clearance method `ahko.clear()` to cancel queued, delayed, and coalesced tasks cleanly.
47
+ - Ahko mascot battery telemetry via `ahko.battery()` reporting chill status.
48
+ - Extended telemetry snapshot in `ahko.stats()` with `retriedTasks` and `totalDispatched`.
49
+
50
+ ### Fixed
51
+ - Fixed 2 CodeQL security alerts by iterating over map values (`this.entries.values()`) in `DebounceCoordinator.clear()` and `ThrottleCoordinator.clear()`.
52
+
53
+ ---
54
+
8
55
  ## [0.5.0] - 2026-09-22 — Throttle, Debounce & Rate Limiting
9
56
 
10
57
  ### Added
package/README.md CHANGED
@@ -12,9 +12,6 @@
12
12
  <a href="https://www.npmjs.com/package/@mrjacket/ahko">
13
13
  <img src="https://img.shields.io/npm/v/@mrjacket/ahko.svg?color=success" alt="npm version">
14
14
  </a>
15
- <a href="https://www.npmjs.com/package/@mrjacket/ahko">
16
- <img src="https://img.shields.io/npm/dm/@mrjacket/ahko.svg" alt="npm downloads">
17
- </a>
18
15
  <a href="https://www.npmjs.com/package/@mrjacket/ahko">
19
16
  <img src="https://img.shields.io/node/v/@mrjacket/ahko.svg" alt="node">
20
17
  </a>
@@ -27,6 +24,12 @@
27
24
  <a href="https://github.com/x-name15/ahko/blob/main/LICENSE">
28
25
  <img src="https://img.shields.io/npm/l/@mrjacket/ahko.svg" alt="license">
29
26
  </a>
27
+ <a href="https://www.npmjs.com/package/@mrjacket/ahko">
28
+ <img src="https://img.shields.io/badge/dependencies-0-success" alt="zero dependencies">
29
+ </a>
30
+ <a href="https://github.com/x-name15/ahko/issues">
31
+ <img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs Welcome">
32
+ </a>
30
33
  </p>
31
34
 
32
35
  `ahko` is a low-energy task scheduler for JavaScript and TypeScript.
@@ -219,10 +222,65 @@ console.log(stats);
219
222
  // failedTasks: 1,
220
223
  // cancelledTasks: 2,
221
224
  // timedOutTasks: 1,
225
+ // retriedTasks: 3,
226
+ // totalDispatched: 45,
222
227
  // capacity: 3
223
228
  // }
224
229
  ```
225
230
 
231
+ ### 10. Lifecycle Events (`on` / `off`)
232
+
233
+ Listen to typed lifecycle events with isolated callback safety:
234
+
235
+ ```typescript
236
+ const unsubscribe = ahko.on("task:start", ({ taskId, attempt }) => {
237
+ console.log(`Task ${taskId} started attempt #${attempt}`);
238
+ });
239
+
240
+ ahko.on("task:complete", ({ taskId, durationMs, result }) => {
241
+ console.log(`Task ${taskId} completed in ${durationMs}ms:`, result);
242
+ });
243
+
244
+ ahko.on("task:fail", ({ taskId, attempt, error, willRetry }) => {
245
+ console.warn(`Task ${taskId} attempt #${attempt} failed (willRetry: ${willRetry})`, error);
246
+ });
247
+
248
+ ahko.on("task:timeout", ({ taskId, timeoutMs }) => {
249
+ console.warn(`Task ${taskId} exceeded ${timeoutMs}ms deadline`);
250
+ });
251
+
252
+ ahko.on("task:cancel", ({ taskId, reason }) => {
253
+ console.info(`Task ${taskId} was cancelled:`, reason);
254
+ });
255
+
256
+ ahko.on("idle", ({ timestamp }) => {
257
+ console.log("Scheduler transitioned to idle at", timestamp);
258
+ });
259
+ ```
260
+
261
+ ### 11. Idle & Chill Developer Experience
262
+
263
+ Wait for all work to settle or clear the queue cleanly:
264
+
265
+ ```typescript
266
+ // Wait for all active and pending tasks to finish
267
+ await ahko.onIdle();
268
+ // Or use the completely chill alias:
269
+ await ahko.chill();
270
+
271
+ // Check if scheduler is currently idle
272
+ if (ahko.isIdle()) {
273
+ console.log("Completely chill. No tasks running or queued.");
274
+ }
275
+
276
+ // Clear all queued, delayed, and coalesced tasks
277
+ ahko.clear();
278
+
279
+ // Check Ahko mascot battery telemetry
280
+ console.log(ahko.battery());
281
+ // { level: 3, chill: true, status: "low-energy", quote: "Mwee... my battery is low, but all your tasks are handled completely chill." }
282
+ ```
283
+
226
284
  ---
227
285
 
228
286
  ## Documentation
@@ -231,10 +289,15 @@ Comprehensive guides and technical documentation are available in the [`docs/`](
231
289
 
232
290
  | Document | Description |
233
291
  |---|---|
234
- | [**Getting Started**](./docs/getting-started.md) | Quickstart guide, installation, and fundamental usage patterns. |
235
- | [**Library API**](./docs/library.md) | Complete programmatic API reference, TypeScript interfaces, and options. |
236
- | [**Architecture**](./docs/architecture.md) | Architectural specifications, lifecycle state machine, and design decisions. |
237
- | [**Roadmap**](./docs/roadmap.md) | Milestone progression from 0.1.0 through 1.0.0. |
292
+ | [**Documentation Portal**](./docs/README.md) | Master overview and index of all guides and specifications. |
293
+ | [**Getting Started**](./docs/guides/getting-started.md) | Quickstart guide, installation, and fundamental usage patterns. |
294
+ | [**Library API**](./docs/guides/library.md) | Complete programmatic API reference, TypeScript interfaces, and options. |
295
+ | [**Production Recipes**](./docs/guides/recipes.md) | Battle-tested recipes (paced API client, debounced search, throttled scroll, graceful shutdown). |
296
+ | [**Architecture**](./docs/architecture/ARCHITECTURE.md) | Architectural specifications, lifecycle state machine, and design decisions. |
297
+ | [**Roadmap**](./docs/architecture/ROADMAP.md) | Milestone progression from 0.1.0 through 1.0.0. |
298
+ | [**Engineering Log**](./docs/architecture/LOG.md) | Chronological log of engineering decisions and ADRs. |
299
+
300
+ > **Runnable Examples:** A comprehensive suite of standalone, runnable Node.js scripts is available in the [`examples/`](./examples/) folder. See [`examples/README.md`](./examples/README.md) for details.
238
301
 
239
302
  ---
240
303
 
@@ -242,7 +305,7 @@ Comprehensive guides and technical documentation are available in the [`docs/`](
242
305
 
243
306
  ### `new Ahko(options?: IAhkoOptions)`
244
307
 
245
- Creates an AHKO scheduler instance.
308
+ Creates an ahko scheduler instance.
246
309
 
247
310
  | Option | Type | Default | Description |
248
311
  |---|---|---|---|
@@ -276,9 +339,37 @@ Convenience method scheduling a throttled task with leading execution and coales
276
339
 
277
340
  Convenience method scheduling a task under `strategy: "idle"`.
278
341
 
342
+ ### `ahko.on(event, handler)`
343
+
344
+ Subscribes to scheduler lifecycle events (`task:start`, `task:complete`, `task:fail`, `task:cancel`, `task:timeout`, `idle`). Returns an unsubscribe function.
345
+
346
+ ### `ahko.off(event, handler)`
347
+
348
+ Unsubscribes an event listener callback.
349
+
350
+ ### `ahko.isIdle(): boolean`
351
+
352
+ Returns whether the scheduler is currently idle (no active or pending tasks).
353
+
354
+ ### `ahko.onIdle(): Promise<void>`
355
+
356
+ Returns a Promise that resolves when all active and pending tasks have settled.
357
+
358
+ ### `ahko.chill(): Promise<void>`
359
+
360
+ Alias for `ahko.onIdle()`.
361
+
362
+ ### `ahko.clear(): void`
363
+
364
+ Cancels all pending, delayed, and throttled/debounced tasks cleanly.
365
+
366
+ ### `ahko.battery()`
367
+
368
+ Returns mascot battery status and quote.
369
+
279
370
  ### `ahko.stats(): IAhkoStats`
280
371
 
281
- Returns a snapshot of current task counters and queue capacity.
372
+ Returns a snapshot of current task counters, retry counts, total dispatches, and queue capacity.
282
373
 
283
374
  ---
284
375
 
package/dist/ahko.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { TAhkoEventName, TAhkoEventHandler, TAhkoUnsubscribe } from "./models/events.model.js";
1
2
  import type { IAhkoOptions, IScheduleOptions } from "./models/options.model.js";
2
3
  import type { IAhkoStats } from "./models/stats.model.js";
3
4
  import type { ITask } from "./models/task.model.js";
@@ -110,4 +111,67 @@ export declare class Ahko {
110
111
  * ```
111
112
  */
112
113
  stats(): IAhkoStats;
114
+ /**
115
+ * Subscribes to a scheduler lifecycle event.
116
+ *
117
+ * @param event - Event name to listen for.
118
+ * @param handler - Callback function invoked when the event is emitted.
119
+ * @returns Unsubscribe function to remove the listener.
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const unsubscribe = ahko.on("task:start", ({ taskId, attempt }) => {
124
+ * console.log(`Task ${taskId} started attempt ${attempt}`);
125
+ * });
126
+ * ```
127
+ */
128
+ on<K extends TAhkoEventName>(event: K, handler: TAhkoEventHandler<K>): TAhkoUnsubscribe;
129
+ /**
130
+ * Unsubscribes an event listener from a scheduler lifecycle event.
131
+ *
132
+ * @param event - Event name.
133
+ * @param handler - The exact listener callback to remove.
134
+ */
135
+ off<K extends TAhkoEventName>(event: K, handler: TAhkoEventHandler<K>): void;
136
+ /**
137
+ * Checks whether the scheduler is currently idle (no active runners and no pending tasks).
138
+ *
139
+ * @returns True if completely idle, false otherwise.
140
+ */
141
+ isIdle(): boolean;
142
+ /**
143
+ * Returns a promise that resolves once the scheduler has completed all tasks and is idle.
144
+ *
145
+ * @returns Promise resolving when the scheduler is idle.
146
+ *
147
+ * @example
148
+ * ```typescript
149
+ * ahko.schedule(doWork);
150
+ * await ahko.onIdle();
151
+ * console.log("All work finished!");
152
+ * ```
153
+ */
154
+ onIdle(): Promise<void>;
155
+ /**
156
+ * Clears all pending, delayed, and throttled/debounced tasks from the scheduler.
157
+ * In-flight active tasks will continue executing to completion or abort via signal.
158
+ */
159
+ clear(): void;
160
+ /**
161
+ * Returns the delightful Ahko mascot battery telemetry status.
162
+ *
163
+ * Low energy, completely chill.
164
+ */
165
+ battery(): {
166
+ level: number;
167
+ chill: boolean;
168
+ status: string;
169
+ quote: string;
170
+ };
171
+ /**
172
+ * Delightful alias for `onIdle()`: wait for all tasks to settle chill and relaxed.
173
+ *
174
+ * @returns Promise resolving when all tasks have finished.
175
+ */
176
+ chill(): Promise<void>;
113
177
  }
@@ -0,0 +1,34 @@
1
+ import type { IAhkoEventMap, TAhkoEventHandler, TAhkoEventName, TAhkoUnsubscribe } from "../models/events.model.js";
2
+ /**
3
+ * Lightweight, zero-dependency typed event emitter with safe error containment.
4
+ */
5
+ export declare class AhkoEventEmitter {
6
+ private readonly listeners;
7
+ /**
8
+ * Subscribes a listener to a specific Ahko lifecycle event.
9
+ *
10
+ * @param event - The event name to subscribe to.
11
+ * @param handler - The callback function to invoke when the event is emitted.
12
+ * @returns An unsubscribe function to remove the listener.
13
+ */
14
+ on<K extends TAhkoEventName>(event: K, handler: TAhkoEventHandler<K>): TAhkoUnsubscribe;
15
+ /**
16
+ * Unsubscribes a listener from a specific Ahko lifecycle event.
17
+ *
18
+ * @param event - The event name.
19
+ * @param handler - The callback function to remove.
20
+ */
21
+ off<K extends TAhkoEventName>(event: K, handler: TAhkoEventHandler<K>): void;
22
+ /**
23
+ * Emits an event with the corresponding typed payload to all subscribed listeners.
24
+ * Listener invocations are safely isolated in try/catch to protect scheduler integrity.
25
+ *
26
+ * @param event - The event name to emit.
27
+ * @param payload - The event-specific payload data.
28
+ */
29
+ emit<K extends TAhkoEventName>(event: K, payload: IAhkoEventMap[K]): void;
30
+ /**
31
+ * Removes all registered event listeners.
32
+ */
33
+ clear(): void;
34
+ }
@@ -0,0 +1 @@
1
+ export * from "./event-emitter.js";