@hardlydifficult/poller 1.0.17 → 1.0.18

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 +112 -23
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/poller
2
2
 
3
- A lightweight polling utility with debounced manual triggers, overlapping request handling, and deep equality change detection.
3
+ A generic polling utility with debounced triggers, overlapping request handling, and deep equality change detection.
4
4
 
5
5
  ## Installation
6
6
 
@@ -29,41 +29,130 @@ poller.trigger();
29
29
  poller.stop();
30
30
  ```
31
31
 
32
- ## Options
32
+ ## Poller Creation
33
+
34
+ The `Poller` class supports two constructor styles: a modern options-based approach and a deprecated positional constructor for backward compatibility.
35
+
36
+ ### Options-based constructor (recommended)
33
37
 
34
38
  ```typescript
35
- interface PollerOptions<T> {
36
- fetch: () => Promise<T>;
37
- onChange: (current: T, previous: T | undefined) => void;
38
- intervalMs: number;
39
- onError?: (error: unknown) => void;
40
- debounceMs?: number; // default 1000
41
- comparator?: (current: T, previous: T | undefined) => boolean;
42
- }
39
+ import { Poller } from "@hardlydifficult/poller";
40
+
41
+ const poller = Poller.create({
42
+ fetch: async () => fetch("/api/data").then(r => r.json()),
43
+ onChange: (current, previous) => console.log("Changed:", current),
44
+ intervalMs: 3000,
45
+ debounceMs: 1000, // optional, defaults to 1000
46
+ onError: (error) => console.error("Poll error:", error), // optional
47
+ comparator: (curr, prev) => curr.id === prev?.id, // optional
48
+ });
43
49
  ```
44
50
 
45
- `comparator` should return `true` when values are considered equal (no change). By default Poller compares values using `JSON.stringify`.
51
+ | Option | Type | Description |
52
+ |--------|------|-------------|
53
+ | `fetch` | `() => Promise<T>` | Async function to fetch data |
54
+ | `onChange` | `(current: T, previous: T \| undefined) => void` | Callback when data changes |
55
+ | `intervalMs` | `number` | Polling interval in milliseconds |
56
+ | `debounceMs` | `number` | Debounce delay for manual triggers (default: `1000`) |
57
+ | `onError` | `(error: unknown) => void` | Error handler (optional) |
58
+ | `comparator` | `(current: T, previous: T \| undefined) => boolean` | Custom change detection (default: deep equality) |
46
59
 
47
- ## Error Handling
60
+ ### Deprecated positional constructor
48
61
 
49
62
  ```typescript
50
- const poller = new Poller({
51
- fetch: async () => {
52
- throw new Error("Network failure");
53
- },
54
- onChange: () => {},
63
+ const poller = new Poller(
64
+ async () => fetch("/api/data").then(r => r.json()),
65
+ (current, previous) => console.log("Changed:", current),
66
+ 3000,
67
+ (error) => console.error("Poll error:", error)
68
+ );
69
+ ```
70
+
71
+ > Note: This style is deprecated; use `Poller.create(options)` or `new Poller(options)` instead.
72
+
73
+ ## Polling Control
74
+
75
+ ### `start()`
76
+ Starts polling at the configured interval. Returns immediately after the first fetch completes.
77
+
78
+ ```typescript
79
+ await poller.start();
80
+ ```
81
+
82
+ ### `stop()`
83
+ Stops all timers and prevents further polling.
84
+
85
+ ```typescript
86
+ poller.stop();
87
+ ```
88
+
89
+ ### `trigger(debounceMs?)`
90
+ Manually triggers a poll, debouncing multiple calls.
91
+
92
+ ```typescript
93
+ poller.trigger(); // Uses default debounceMs
94
+ poller.trigger(2000); // Override debounce delay
95
+ ```
96
+
97
+ ## Change Detection
98
+
99
+ By default, the `Poller` uses deep equality to detect changes, supporting primitives, arrays, and plain objects—even when new references are returned.
100
+
101
+ ```typescript
102
+ const poller = Poller.create({
103
+ fetch: async () => ({ count: 42 }),
104
+ onChange: (data, prev) => console.log("Changed:", data),
55
105
  intervalMs: 2000,
56
- onError: (error) => console.error("Poll failed:", error),
57
106
  });
107
+
108
+ // Even if fetch returns a new object with same content, onChange won't fire
58
109
  ```
59
110
 
60
- ## Custom Comparator
111
+ ### Custom comparator
112
+
113
+ You can supply a custom comparator to control change detection logic:
61
114
 
62
115
  ```typescript
63
- const poller = new Poller({
64
- fetch: async () => ({ id: "123", updatedAt: Date.now() }),
65
- onChange: (current) => console.log("Changed", current),
116
+ const poller = Poller.create({
117
+ fetch: async () => ({ id: 1, name: "Alice" }),
118
+ onChange: (data, prev) => console.log("Changed:", data.name),
119
+ intervalMs: 2000,
120
+ comparator: (current, previous) => current.name === previous?.name,
121
+ });
122
+ ```
123
+
124
+ ## Error Handling
125
+
126
+ Errors during fetch or comparator execution are routed to the `onError` callback, if provided. Polling continues after errors.
127
+
128
+ ```typescript
129
+ const poller = Poller.create({
130
+ fetch: async () => { throw new Error("Network issue"); },
131
+ onChange: () => {},
66
132
  intervalMs: 1000,
67
- comparator: (current, previous) => current.id === previous?.id,
133
+ onError: (err) => console.warn("Caught error:", err),
134
+ });
135
+
136
+ await poller.start(); // Continues polling despite error
137
+ ```
138
+
139
+ ## Overlapping Request Handling
140
+
141
+ If a fetch is still pending when the next interval arrives, the new poll is skipped to avoid overlapping requests.
142
+
143
+ ```typescript
144
+ const poller = Poller.create({
145
+ fetch: async () => {
146
+ await new Promise(r => setTimeout(r, 2000)); // Simulate slow fetch
147
+ return "data";
148
+ },
149
+ onChange: () => {},
150
+ intervalMs: 1000, // Won't trigger overlapping fetch
68
151
  });
69
152
  ```
153
+
154
+ ## API Reference
155
+
156
+ - `Poller<T>`: Generic polling class
157
+ - `PollerOptions<T>`: Options interface for configuring the poller
158
+ - `Poller.create<T>(options: PollerOptions<T>): Poller<T>`: Static factory method (recommended)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/poller",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [