@hardlydifficult/poller 1.0.6 → 1.0.7

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.
Files changed (2) hide show
  1. package/README.md +92 -38
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/poller
2
2
 
3
- A generic polling utility that periodically fetches data and invokes a callback only when the result changes, using JSON-based deep equality comparison.
3
+ A generic polling utility that periodically fetches data, detects changes via deep equality comparison, and supports debounced manual triggers with overlap handling.
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,24 +13,25 @@ npm install @hardlydifficult/poller
13
13
  ```typescript
14
14
  import { Poller } from "@hardlydifficult/poller";
15
15
 
16
- // Create a poller that fetches mock API data every 5 seconds
17
16
  const poller = new Poller(
18
17
  async () => {
19
- const response = await fetch("https://api.example.com/status");
20
- return await response.json();
18
+ const res = await fetch("https://api.example.com/status");
19
+ return res.json();
21
20
  },
22
21
  (current, previous) => {
23
22
  console.log("Status changed:", current);
24
23
  },
25
- 5000,
26
- (error) => {
27
- console.error("Polling error:", error);
28
- }
24
+ 5000 // poll every 5 seconds
29
25
  );
30
26
 
31
- await poller.start(); // Begins polling immediately
32
- // ... later
33
- poller.stop(); // Stops polling
27
+ await poller.start();
28
+ // Polls start immediately
29
+
30
+ // Optionally, manually trigger a debounced poll
31
+ poller.trigger(1000); // fires once after 1s of inactivity
32
+
33
+ // Stop polling when done
34
+ poller.stop();
34
35
  ```
35
36
 
36
37
  ### Basic Usage
@@ -53,27 +54,62 @@ poller.trigger(1000);
53
54
  poller.stop();
54
55
  ```
55
56
 
56
- ## Polling
57
+ ## Polling Behavior
57
58
 
58
- The `Poller` class fetches data at a configurable interval and invokes a callback when the result changes. It fetches immediately on `start()`, then at the configured interval.
59
+ The `Poller` executes a fetch function at a fixed interval and invokes a callback only when the returned value changes.
60
+
61
+ - Starts polling immediately on `start()`
62
+ - Fetches at the configured `intervalMs`
63
+ - Skips overlapping fetches (if a previous fetch is still in progress)
59
64
 
60
65
  ```typescript
61
- import { Poller } from "@hardlydifficult/poller";
66
+ const poller = new Poller(
67
+ async () => fetchJson("/api/data"),
68
+ (current, previous) => console.log("Changed:", current),
69
+ 10_000
70
+ );
71
+ await poller.start();
72
+ ```
62
73
 
74
+ ## Change Detection
75
+
76
+ Changes are detected using deep equality via `JSON.stringify`. Structural equality means that objects with identical content—even different references—won’t trigger unnecessary callbacks.
77
+
78
+ ```typescript
63
79
  const poller = new Poller(
64
- async () => {
65
- const response = await fetch("/api/status");
66
- return response.json();
67
- },
80
+ async () => ({ items: [1, 2, 3] }),
81
+ (current, previous) => console.log("Changed:", current),
82
+ 1000
83
+ );
84
+
85
+ // Even if a new object instance is returned, same structure = no change
86
+ await poller.start();
87
+ // onChange fires only when structure changes
88
+ ```
89
+
90
+ - On first poll, `onChange(current, undefined)` is invoked.
91
+ - On subsequent polls, `onChange(current, previous)` is invoked only if the new value differs structurally.
92
+
93
+ ```typescript
94
+ const poller = new Poller(
95
+ async () => ({ count: 5, items: [1, 2, 3] }),
68
96
  (current, previous) => {
69
- console.log("Previous:", previous);
70
- console.log("Current:", current);
97
+ // Only fires when the JSON representation changes
98
+ console.log("Changed from", previous, "to", current);
71
99
  },
72
- 10000 // poll every 10 seconds
100
+ 5000
73
101
  );
74
102
 
75
103
  await poller.start();
76
- // Fetches immediately, then every 10 seconds
104
+ ```
105
+
106
+ ## Lifecycle Management
107
+
108
+ Polling can be started and stopped at any time. The `stop()` method cancels both the periodic timer and any pending debounced triggers.
109
+
110
+ ```typescript
111
+ await poller.start(); // begins polling
112
+ poller.stop(); // cancels all timers, stops future polls
77
113
  ```
78
114
 
79
115
  ### `start()`
@@ -94,29 +130,28 @@ poller.stop();
94
130
  // No more polls will fire
95
131
  ```
96
132
 
97
- ## Change Detection
133
+ ## Manual Triggers
98
134
 
99
- Changes are detected using JSON serialization for deep equality. Structurally identical objects are considered unchanged—even if they are different references.
135
+ You can manually trigger a debounced poll to force an immediate check after a period of inactivity.
100
136
 
101
- - On first poll, `onChange(current, undefined)` is invoked.
102
- - On subsequent polls, `onChange(current, previous)` is invoked only if the new value differs structurally.
137
+ | Parameter | Type | Default | Description |
138
+ |-------------|----------|---------|----------------------------------------|
139
+ | `debounceMs`| `number` | `1000` | Milliseconds to wait before polling |
103
140
 
104
141
  ```typescript
105
- const poller = new Poller(
106
- async () => ({ count: 5, items: [1, 2, 3] }),
107
- (current, previous) => {
108
- // Only fires when the JSON representation changes
109
- console.log("Changed from", previous, "to", current);
110
- },
111
- 5000
112
- );
142
+ // Immediate trigger with default debounce
143
+ poller.trigger();
113
144
 
114
- await poller.start();
115
- ```
145
+ // Custom debounce
146
+ poller.trigger(500);
116
147
 
117
- ## Manual Triggers
148
+ // If multiple triggers occur within debounceMs, only the last one fires
149
+ poller.trigger();
150
+ poller.trigger();
151
+ poller.trigger(); // only this one will poll after 1s
152
+ ```
118
153
 
119
- Call `trigger()` to manually poll immediately, with optional debouncing. Multiple rapid triggers are coalesced into a single poll.
154
+ ### Behavior
120
155
 
121
156
  - Accepts a `debounceMs` parameter (default: `1000`).
122
157
  - Multiple rapid calls reset the debounce timer — only the last trigger fires.
@@ -145,6 +180,25 @@ poller.trigger(500); // Only one poll fires after 500ms
145
180
 
146
181
  ## Error Handling
147
182
 
183
+ Fetch errors do not halt polling. An optional `onError` callback receives any errors, and polling continues at the next interval.
184
+
185
+ ```typescript
186
+ const poller = new Poller(
187
+ async () => {
188
+ if (Math.random() < 0.5) throw new Error("Network fail");
189
+ return "ok";
190
+ },
191
+ (current) => console.log(current),
192
+ 1000,
193
+ (error) => console.error("Fetch failed:", error)
194
+ );
195
+
196
+ await poller.start();
197
+ // Continues polling even after errors
198
+ ```
199
+
200
+ ### Error Handling Details
201
+
148
202
  - Errors during fetch are caught and passed to the optional `onError` callback.
149
203
  - Polling continues after errors — no automatic retry logic is applied.
150
204
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/poller",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [