node-events-batcher 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Egor Kushnarev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # node-events-batcher
2
+
3
+ Universal events batcher for NodeJS. Collects events and flushes them in batches via configurable strategies (size-based or time-based) with array or set accumulation.
4
+
5
+ ## Install
6
+
7
+ > [!NOTE]
8
+ > It's highly recommended to use with [volta.sh](https://volta.sh).
9
+
10
+ ```bash
11
+ npm install node-events-batcher
12
+ ```
13
+
14
+ ## Quick start
15
+
16
+ ```ts
17
+ import { EventsBatcher } from 'node-events-batcher';
18
+
19
+ const batcher = new EventsBatcher<string>(
20
+ (events) => {
21
+ console.log('Flushed:', events);
22
+ },
23
+ (err) => console.error(err),
24
+ { size: 5, accumulatorType: 'array', timeoutMs: 5000 }
25
+ );
26
+
27
+ batcher.add('a');
28
+ batcher.add('b');
29
+ batcher.add('c');
30
+ batcher.add('d');
31
+ batcher.add('e'); // callback runs with ['a','b','c','d','e']
32
+
33
+ batcher.flush(); // flush any remaining events manually
34
+ ```
35
+
36
+ ## API
37
+
38
+ ### `EventsBatcher<EventType>`
39
+
40
+ **Constructor**
41
+
42
+ ```ts
43
+ new EventsBatcher<EventType>(
44
+ callback: (events: ReadonlyArray<EventType>) => void | Promise<void>,
45
+ errorHandler?: ((error: unknown) => void) | null,
46
+ options?: SizeOptions | DebounceOptions
47
+ )
48
+ ```
49
+
50
+ - **callback** — Called with the batched events when a flush occurs. May return a Promise; rejections are passed to `errorHandler`.
51
+ - **errorHandler** — Optional. If provided, callback errors are passed here; otherwise they are rethrown.
52
+ - **options** — Flush strategy and accumulator. Defaults to `{ accumulatorType: 'array', timeoutMs: 2000, debounceMs: 50 }` (debounce strategy).
53
+
54
+ **Methods**
55
+
56
+ - **`add(event: EventType): void`** — Add an event. May trigger a flush depending on the strategy.
57
+ - **`flush(): void`** — Flush all accumulated events immediately.
58
+
59
+ ### Options
60
+
61
+ Two strategy types:
62
+
63
+ | Option | Type | Description |
64
+ |--------|------|-------------|
65
+ | **Size strategy** | `SizeOptions` | Flush when the batch reaches `size` events. |
66
+ | **Debounce strategy** | `DebounceOptions` | Flush after `debounceMs` ms of no new events. |
67
+
68
+ **Common options**
69
+
70
+ | Option | Type | Description |
71
+ |--------|------|-------------|
72
+ | `accumulatorType` | `'array'` \| `'set'` | `'array'` — order preserved, duplicates allowed. `'set'` — unique events only, order not guaranteed. |
73
+ | `timeoutMs` | `number` \| `null` | Max wait (ms) before flushing; `null` disables. |
74
+
75
+ **Size strategy** (`SizeOptions`)
76
+
77
+ | Option | Type | Description |
78
+ |--------|------|-------------|
79
+ | `size` | `number` | Flush when batch size reaches this value. |
80
+
81
+ **Debounce strategy** (`DebounceOptions`)
82
+
83
+ | Option | Type | Description |
84
+ |--------|------|-------------|
85
+ | `debounceMs` | `number` | Flush after this many ms without a new event. Must be &lt; `timeoutMs` when `timeoutMs` is set. |
86
+
87
+ ### Examples
88
+
89
+ **Size-based batching (e.g. send when 10 items):**
90
+
91
+ ```ts
92
+ const batcher = new EventsBatcher<Payload>(
93
+ sendToServer,
94
+ null,
95
+ {
96
+ size: 10,
97
+ accumulatorType: 'array',
98
+ timeoutMs: 3000,
99
+ }
100
+ );
101
+ ```
102
+
103
+ **Time-based debounce (e.g. persist after 100 ms idle):**
104
+
105
+ ```ts
106
+ const batcher = new EventsBatcher<WindowId>(
107
+ persistWindowState,
108
+ console.error,
109
+ {
110
+ debounceMs: 100,
111
+ timeoutMs: 2000,
112
+ accumulatorType: 'set',
113
+ }
114
+ );
115
+ ```
116
+
117
+ **Exports**
118
+
119
+ ```ts
120
+ import { EventsBatcher } from 'node-events-batcher';
121
+ import type { SizeOptions, DebounceOptions } from 'node-events-batcher';
122
+ ```
123
+
124
+ ## Example app
125
+
126
+ The `example/` folder contains an Electron app that uses the batcher to persist window state when windows are closed. Run it from the repo root:
127
+
128
+ ```bash
129
+ cd example && pnpm install && pnpm start
130
+ ```
131
+
132
+ ## License
133
+
134
+ MIT
package/accumulator.js ADDED
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Accumulator = void 0;
37
+ const Errors = __importStar(require("./errors"));
38
+ class Accumulator {
39
+ addWrapper;
40
+ cleatWrapper;
41
+ lengthWrapper;
42
+ getWrapper;
43
+ constructor(type) {
44
+ if (type === 'array') {
45
+ const accumulator = new Array();
46
+ this.addWrapper = function (value) {
47
+ accumulator.push(value);
48
+ };
49
+ this.cleatWrapper = function () {
50
+ accumulator.splice(0, accumulator.length);
51
+ };
52
+ this.lengthWrapper = function () {
53
+ return accumulator.length;
54
+ };
55
+ this.getWrapper = function () {
56
+ return Array.from(accumulator);
57
+ };
58
+ return;
59
+ }
60
+ if (type === 'set') {
61
+ const accumulator = new Set();
62
+ this.addWrapper = function (value) {
63
+ accumulator.add(value);
64
+ };
65
+ this.cleatWrapper = function () {
66
+ accumulator.clear();
67
+ };
68
+ this.lengthWrapper = function () {
69
+ return accumulator.size;
70
+ };
71
+ this.getWrapper = function () {
72
+ return Array.from(accumulator.values());
73
+ };
74
+ return;
75
+ }
76
+ throw Errors.unsupportedAccumulatorType(type);
77
+ }
78
+ add(value) {
79
+ this.addWrapper(value);
80
+ }
81
+ clear() {
82
+ this.cleatWrapper();
83
+ }
84
+ length() {
85
+ return this.lengthWrapper();
86
+ }
87
+ get() {
88
+ return this.getWrapper();
89
+ }
90
+ }
91
+ exports.Accumulator = Accumulator;
92
+ //# sourceMappingURL=accumulator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accumulator.js","sourceRoot":"","sources":["../src/accumulator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAmC;AAInC,MAAa,WAAW;IACf,UAAU,CAAqB;IAC/B,YAAY,CAAa;IACzB,aAAa,CAAe;IAC5B,UAAU,CAAyB;IAE3C,YAAY,IAAqB;QAChC,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;YACtB,MAAM,WAAW,GAAG,IAAI,KAAK,EAAK,CAAC;YAEnC,IAAI,CAAC,UAAU,GAAG,UAAS,KAAQ;gBAClC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACzB,CAAC,CAAC;YAEF,IAAI,CAAC,YAAY,GAAG;gBACnB,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;YAC3C,CAAC,CAAC;YAEF,IAAI,CAAC,aAAa,GAAG;gBACpB,OAAO,WAAW,CAAC,MAAM,CAAC;YAC3B,CAAC,CAAC;YAEF,IAAI,CAAC,UAAU,GAAG;gBACjB,OAAO,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAChC,CAAC,CAAC;YAEF,OAAO;QACR,CAAC;QAED,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACpB,MAAM,WAAW,GAAG,IAAI,GAAG,EAAK,CAAC;YAEjC,IAAI,CAAC,UAAU,GAAG,UAAS,KAAQ;gBAClC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC,CAAC;YAEF,IAAI,CAAC,YAAY,GAAG;gBACnB,WAAW,CAAC,KAAK,EAAE,CAAC;YACrB,CAAC,CAAC;YAEF,IAAI,CAAC,aAAa,GAAG;gBACpB,OAAO,WAAW,CAAC,IAAI,CAAC;YACzB,CAAC,CAAC;YAEF,IAAI,CAAC,UAAU,GAAG;gBACjB,OAAO,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC;YACzC,CAAC,CAAC;YAEF,OAAO;QACR,CAAC;QAED,MAAM,MAAM,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,GAAG,CAAC,KAAQ;QACX,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,YAAY,EAAE,CAAC;IACrB,CAAC;IAED,MAAM;QACL,OAAO,IAAI,CAAC,aAAa,EAAE,CAAC;IAC7B,CAAC;IAED,GAAG;QACF,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;IAC1B,CAAC;CACD;AArED,kCAqEC"}
package/errors.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unknownOptionsType = unknownOptionsType;
4
+ exports.unsupportedAccumulatorType = unsupportedAccumulatorType;
5
+ exports.nonPositiveTimeout = nonPositiveTimeout;
6
+ exports.nonPositiveSize = nonPositiveSize;
7
+ exports.nonPositiveDebounce = nonPositiveDebounce;
8
+ exports.debounceGreaterThanTimeout = debounceGreaterThanTimeout;
9
+ exports.shouldNotBeExecuted = shouldNotBeExecuted;
10
+ function unknownOptionsType() {
11
+ return Error('EventsBatcher: unknown options type');
12
+ }
13
+ function unsupportedAccumulatorType(type) {
14
+ return Error(`EventsBatcher: unsupported accumulator type '${type}'. 'set' or 'array' expected`);
15
+ }
16
+ function nonPositiveTimeout(timeout) {
17
+ return Error(`EventsBatcher: 'timeout' must be positive. Got timeoutMs=${timeout}`);
18
+ }
19
+ function nonPositiveSize(size) {
20
+ return Error(`EventsBatcher: 'size' must be positive. Got size=${size}`);
21
+ }
22
+ function nonPositiveDebounce(debounce) {
23
+ return Error(`EventsBatcher: 'debounce' must be positive. Got debounceMs=${debounce}`);
24
+ }
25
+ function debounceGreaterThanTimeout(debounce, timeout) {
26
+ return Error(`EventsBatcher: 'debounce' must be less than 'timeout'. Got debounceMs=${debounce}, timeoutMs=${timeout}`);
27
+ }
28
+ function shouldNotBeExecuted() {
29
+ return Error('EventsBatcher: this should not be executed. Check your configuration');
30
+ }
31
+ //# sourceMappingURL=errors.js.map
package/errors.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;AAAA,gDAEC;AAED,gEAEC;AAED,gDAEC;AAED,0CAEC;AAED,kDAEC;AAED,gEAEC;AAED,kDAEC;AA1BD,SAAgB,kBAAkB;IACjC,OAAO,KAAK,CAAC,qCAAqC,CAAC,CAAC;AACrD,CAAC;AAED,SAAgB,0BAA0B,CAAC,IAAY;IACtD,OAAO,KAAK,CAAC,gDAAiD,IAAK,8BAA8B,CAAC,CAAC;AACpG,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAAe;IACjD,OAAO,KAAK,CAAC,4DAA6D,OAAQ,EAAE,CAAC,CAAC;AACvF,CAAC;AAED,SAAgB,eAAe,CAAC,IAAY;IAC3C,OAAO,KAAK,CAAC,oDAAqD,IAAK,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,SAAgB,mBAAmB,CAAC,QAAgB;IACnD,OAAO,KAAK,CAAC,8DAA+D,QAAS,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,SAAgB,0BAA0B,CAAC,QAAgB,EAAE,OAAe;IAC3E,OAAO,KAAK,CAAC,yEAA0E,QAAS,eAAgB,OAAQ,EAAE,CAAC,CAAC;AAC7H,CAAC;AAED,SAAgB,mBAAmB;IAClC,OAAO,KAAK,CAAC,sEAAsE,CAAC,CAAC;AACtF,CAAC"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventsBatcher = void 0;
4
+ const accumulator_1 = require("./accumulator");
5
+ const options_1 = require("./options");
6
+ const strategy_1 = require("./strategy");
7
+ class EventsBatcher {
8
+ cb;
9
+ errorHandler;
10
+ options;
11
+ accumulator;
12
+ strategy;
13
+ constructor(cb, errorHandler = null, options = options_1.defaultOptions) {
14
+ this.cb = cb;
15
+ this.errorHandler = errorHandler;
16
+ this.options = options;
17
+ const err = (0, options_1.validateOptions)(options);
18
+ if (err !== null) {
19
+ throw err;
20
+ }
21
+ this.accumulator = new accumulator_1.Accumulator(this.options.accumulatorType);
22
+ this.strategy = (0, strategy_1.NewStrategy)(options, this.accumulator, this.fire.bind(this));
23
+ }
24
+ add(object) {
25
+ this.strategy.add(object);
26
+ }
27
+ flush() {
28
+ this.fire();
29
+ }
30
+ fire() {
31
+ const events = this.accumulator.get();
32
+ if (events.length === 0) {
33
+ this.strategy.reset();
34
+ return;
35
+ }
36
+ try {
37
+ const mayBePromise = this.cb(events);
38
+ if (mayBePromise instanceof Promise) {
39
+ mayBePromise.catch(error => {
40
+ this.handleError(error);
41
+ });
42
+ }
43
+ }
44
+ catch (error) {
45
+ this.handleError(error);
46
+ }
47
+ finally {
48
+ this.strategy.reset();
49
+ }
50
+ }
51
+ handleError(error) {
52
+ if (this.errorHandler !== null) {
53
+ this.errorHandler(error);
54
+ }
55
+ else {
56
+ throw error;
57
+ }
58
+ }
59
+ }
60
+ exports.EventsBatcher = EventsBatcher;
61
+ //# sourceMappingURL=events-batcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events-batcher.js","sourceRoot":"","sources":["../src/events-batcher.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAC5C,uCAA0F;AAC1F,yCAAmD;AAKnD,MAAa,aAAa;IAKP;IACA;IACA;IANV,WAAW,CAAyB;IACpC,QAAQ,CAAsB;IAEtC,YACkB,EAA2B,EAC3B,eAAoC,IAAI,EACxC,UAAyC,wBAAc;QAFvD,OAAE,GAAF,EAAE,CAAyB;QAC3B,iBAAY,GAAZ,YAAY,CAA4B;QACxC,YAAO,GAAP,OAAO,CAAgD;QACxE,MAAM,GAAG,GAAG,IAAA,yBAAe,EAAC,OAAO,CAAC,CAAC;QAErC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,GAAG,CAAC;QACX,CAAC;QAED,IAAI,CAAC,WAAW,GAAG,IAAI,yBAAW,CAAY,IAAI,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAC5E,IAAI,CAAC,QAAQ,GAAG,IAAA,sBAAW,EAAY,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACzF,CAAC;IAEM,GAAG,CAAC,MAAiB;QAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAEM,KAAK;QACX,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAEO,IAAI;QACX,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QAEtC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO;QACR,CAAC;QAED,IAAI,CAAC;YACJ,MAAM,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;YAErC,IAAI,YAAY,YAAY,OAAO,EAAE,CAAC;gBACrC,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;oBAC1B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;gBACzB,CAAC,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACd,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;gBACO,CAAC;YACR,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACF,CAAC;IAEO,WAAW,CAAC,KAAc;QACjC,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;YAChC,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;aACI,CAAC;YACL,MAAM,KAAK,CAAC;QACb,CAAC;IACF,CAAC;CACD;AA3DD,sCA2DC"}
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EventsBatcher = void 0;
4
+ var events_batcher_1 = require("./events-batcher");
5
+ Object.defineProperty(exports, "EventsBatcher", { enumerable: true, get: function () { return events_batcher_1.EventsBatcher; } });
6
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,mDAAiD;AAAxC,+GAAA,aAAa,OAAA"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeAwaiter = makeAwaiter;
4
+ function makeAwaiter() {
5
+ let resolver = null;
6
+ let rejecter = null;
7
+ const awaiter = new Promise((resolve, reject) => {
8
+ resolver = resolve;
9
+ rejecter = reject;
10
+ });
11
+ if (resolver && rejecter) {
12
+ return [resolver, awaiter, rejecter];
13
+ }
14
+ throw Error('MakeAwaiter: should not be executed');
15
+ }
16
+ //# sourceMappingURL=make-awaiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make-awaiter.js","sourceRoot":"","sources":["../src/make-awaiter.ts"],"names":[],"mappings":";;AAAA,kCAcC;AAdD,SAAgB,WAAW;IAC1B,IAAI,QAAQ,GAAiD,IAAI,CAAC;IAClE,IAAI,QAAQ,GAAwC,IAAI,CAAC;IAEzD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAClD,QAAQ,GAAG,OAAO,CAAC;QACnB,QAAQ,GAAG,MAAM,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,IAAI,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAC1B,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,KAAK,CAAC,qCAAqC,CAAC,CAAC;AACpD,CAAC"}
package/options.js ADDED
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.defaultOptions = void 0;
37
+ exports.isSizeOptions = isSizeOptions;
38
+ exports.isDebounceOptions = isDebounceOptions;
39
+ exports.validateOptions = validateOptions;
40
+ exports.validateBaseOptions = validateBaseOptions;
41
+ const Errors = __importStar(require("./errors"));
42
+ function isSizeOptions(options) {
43
+ return options !== null &&
44
+ typeof options === 'object' &&
45
+ 'size' in options &&
46
+ options.size !== null &&
47
+ typeof options.size === 'number';
48
+ }
49
+ function isDebounceOptions(options) {
50
+ return options !== null &&
51
+ typeof options === 'object' &&
52
+ 'debounceMs' in options &&
53
+ options.debounceMs !== null &&
54
+ typeof options.debounceMs === 'number';
55
+ }
56
+ function validateOptions(options) {
57
+ const err = validateBaseOptions(options);
58
+ if (err !== null) {
59
+ return err;
60
+ }
61
+ if (isSizeOptions(options)) {
62
+ return validateSizeOptions(options);
63
+ }
64
+ if (isDebounceOptions(options)) {
65
+ return validateDebounceOptions(options);
66
+ }
67
+ throw Errors.unknownOptionsType();
68
+ }
69
+ function validateBaseOptions(options) {
70
+ if (options.accumulatorType !== 'array' && options.accumulatorType !== 'set') {
71
+ return Errors.unsupportedAccumulatorType(options.accumulatorType);
72
+ }
73
+ if (options.timeoutMs !== null && options.timeoutMs <= 0) {
74
+ return Errors.nonPositiveTimeout(options.timeoutMs);
75
+ }
76
+ return null;
77
+ }
78
+ function validateSizeOptions(options) {
79
+ if (options.size <= 0) {
80
+ return Errors.nonPositiveSize(options.size);
81
+ }
82
+ return null;
83
+ }
84
+ function validateDebounceOptions(options) {
85
+ if (options.debounceMs <= 0) {
86
+ return Errors.nonPositiveDebounce(options.debounceMs);
87
+ }
88
+ if (options.timeoutMs !== null && options.debounceMs >= options.timeoutMs) {
89
+ return Errors.debounceGreaterThanTimeout(options.debounceMs, options.timeoutMs);
90
+ }
91
+ return null;
92
+ }
93
+ exports.defaultOptions = {
94
+ accumulatorType: 'array',
95
+ timeoutMs: 2000,
96
+ debounceMs: 50,
97
+ };
98
+ //# sourceMappingURL=options.js.map
package/options.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,sCAMC;AAED,8CAMC;AAED,0CAgBC;AAED,kDAUC;AA3DD,iDAAmC;AAenC,SAAgB,aAAa,CAAC,OAAgB;IAC7C,OAAO,OAAO,KAAK,IAAI;QACtB,OAAO,OAAO,KAAK,QAAQ;QAC3B,MAAM,IAAI,OAAO;QACjB,OAAO,CAAC,IAAI,KAAK,IAAI;QACrB,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,CAAC;AACnC,CAAC;AAED,SAAgB,iBAAiB,CAAC,OAAgB;IACjD,OAAO,OAAO,KAAK,IAAI;QACtB,OAAO,OAAO,KAAK,QAAQ;QAC3B,YAAY,IAAI,OAAO;QACvB,OAAO,CAAC,UAAU,KAAK,IAAI;QAC3B,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ,CAAC;AACzC,CAAC;AAED,SAAgB,eAAe,CAAC,OAAsC;IACrE,MAAM,GAAG,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAEzC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,IAAI,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,OAAO,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,MAAM,CAAC,kBAAkB,EAAE,CAAC;AACnC,CAAC;AAED,SAAgB,mBAAmB,CAAC,OAAoB;IACvD,IAAI,OAAO,CAAC,eAAe,KAAK,OAAO,IAAI,OAAO,CAAC,eAAe,KAAK,KAAK,EAAE,CAAC;QAC9E,OAAO,MAAM,CAAC,0BAA0B,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACnE,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI,IAAI,OAAO,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC;QAC1D,OAAO,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAoB;IAChD,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,uBAAuB,CAAC,OAAwB;IACxD,IAAI,OAAO,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,OAAO,CAAC,SAAS,KAAK,IAAI,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QAC3E,OAAO,MAAM,CAAC,0BAA0B,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IACjF,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC;AAEY,QAAA,cAAc,GAAoB;IAC9C,eAAe,EAAE,OAAO;IACxB,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,EAAE;CACd,CAAC"}
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "node-events-batcher",
3
+ "version": "1.0.0",
4
+ "author": "Egor Kushnarev",
5
+ "description": "Universal events batcher for NodeJS",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "events-batcher",
9
+ "batcher",
10
+ "nodejs"
11
+ ],
12
+ "homepage": "https://github.com/origin-yaropolk/node-events-batcher",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/origin-yaropolk/node-events-batcher"
16
+ },
17
+ "exports": "./index.js"
18
+ }
package/strategy.js ADDED
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.SizeStrategy = exports.DebounceStrategy = void 0;
37
+ exports.NewStrategy = NewStrategy;
38
+ const Errors = __importStar(require("./errors"));
39
+ const options_1 = require("./options");
40
+ function NewStrategy(options, accumulator, fire) {
41
+ if ((0, options_1.isDebounceOptions)(options)) {
42
+ return new DebounceStrategy(options, accumulator, fire);
43
+ }
44
+ if ((0, options_1.isSizeOptions)(options)) {
45
+ return new SizeStrategy(options, accumulator, fire);
46
+ }
47
+ throw Errors.shouldNotBeExecuted();
48
+ }
49
+ class DebounceStrategy {
50
+ options;
51
+ accumulator;
52
+ fire;
53
+ debounceTimeout = null;
54
+ timeout = null;
55
+ constructor(options, accumulator, fire) {
56
+ this.options = options;
57
+ this.accumulator = accumulator;
58
+ this.fire = fire;
59
+ }
60
+ reset() {
61
+ if (this.debounceTimeout) {
62
+ clearTimeout(this.debounceTimeout);
63
+ this.debounceTimeout = null;
64
+ }
65
+ if (this.timeout) {
66
+ clearTimeout(this.timeout);
67
+ this.timeout = null;
68
+ }
69
+ this.accumulator.clear();
70
+ }
71
+ add(event) {
72
+ this.accumulator.add(event);
73
+ if (this.debounceTimeout !== null) {
74
+ this.debounceTimeout.refresh();
75
+ return;
76
+ }
77
+ if (this.timeout === null && this.options.timeoutMs !== null) {
78
+ this.timeout = setTimeout(this.fire, this.options.timeoutMs);
79
+ }
80
+ this.debounceTimeout = setTimeout(this.fire, this.options.debounceMs);
81
+ }
82
+ }
83
+ exports.DebounceStrategy = DebounceStrategy;
84
+ class SizeStrategy {
85
+ options;
86
+ accumulator;
87
+ fire;
88
+ timeout = null;
89
+ constructor(options, accumulator, fire) {
90
+ this.options = options;
91
+ this.accumulator = accumulator;
92
+ this.fire = fire;
93
+ }
94
+ reset() {
95
+ if (this.timeout) {
96
+ clearTimeout(this.timeout);
97
+ this.timeout = null;
98
+ }
99
+ this.accumulator.clear();
100
+ }
101
+ add(event) {
102
+ this.accumulator.add(event);
103
+ if (this.accumulator.length() >= this.options.size) {
104
+ this.fire();
105
+ return;
106
+ }
107
+ if (this.timeout === null && this.options.timeoutMs !== null) {
108
+ this.timeout = setTimeout(this.fire, this.options.timeoutMs);
109
+ }
110
+ }
111
+ }
112
+ exports.SizeStrategy = SizeStrategy;
113
+ //# sourceMappingURL=strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../src/strategy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"root":["../src/accumulator.ts","../src/errors.ts","../src/events-batcher.ts","../src/index.ts","../src/make-awaiter.ts","../src/options.ts","../src/strategy.ts"],"version":"5.9.3"}