@ix-xs/node-comfort 1.0.57 → 1.1.1

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/src/utils.js DELETED
@@ -1,225 +0,0 @@
1
- const logger = require("./logger");
2
-
3
- module.exports = {
4
- /**
5
- * @param {number} ms
6
- */
7
- async wait(ms) {
8
- return new Promise((resolve) => setTimeout(resolve, ms));
9
- },
10
- /**
11
- * Polls a predicate at a given interval and emits events when it matches or times out.
12
- *
13
- * The predicate is evaluated every `options.interval` milliseconds (default: 50 ms).
14
- * Be careful with the default interval: 50 ms is very frequent polling and can be
15
- * unnecessarily CPU‑intensive if your predicate or trigger handlers are heavy.
16
- * When `options.max` is `null`, the predicate can match indefinitely (infinite triggers),
17
- * so you should choose an interval that makes sense for your use‑case.
18
- *
19
- * @param {boolean|Promise<boolean>|(() => boolean|Promise<boolean>)} predicate
20
- * Condition to evaluate at each tick, or a function returning it.
21
- * @param {*} payload
22
- * Value passed to listeners when events are emitted (e.g. an object or message).
23
- * @param {object} [options]
24
- * @param {number} [options.interval=50]
25
- * Polling interval in milliseconds. Increase this value if your predicate is
26
- * expensive or you expect many triggers without a `max` limit.
27
- * @param {number|null} [options.timeout=null]
28
- * Maximum time in milliseconds before emitting a "timeout" event and stopping.
29
- * If `null`, no timeout is applied.
30
- * @param {number|null} [options.max=null]
31
- * Maximum number of successful predicate evaluations ("trigger" events) before
32
- * automatically stopping. If `null`, triggers are infinite until `stop()` is called.
33
- *
34
- * @example
35
- * // Basic usage: infinite triggers every 50 ms (default interval) – use with caution.
36
- * const task = when(() => true, { message: "Ok" });
37
- *
38
- * task.on("trigger", (payload) => {
39
- * console.log(payload.message);
40
- * // task.stop(); // stop when you’re done
41
- * });
42
- *
43
- * task.start();
44
- *
45
- * @example
46
- * // Safer usage: limit triggers and/or lower polling frequency.
47
- * when(() => true, { message: "Ok" }, { max: 1, interval: 500 }) // one trigger max, every 500 ms
48
- * .on("trigger", (payload) => {
49
- * console.log(payload.message);
50
- * })
51
- * .start();
52
- */
53
- when(predicate, payload = {}, options) {
54
- const interval = options?.interval ?? 50;
55
- const timeout = options?.timeout ?? null;
56
- const max = options?.max ?? null;
57
-
58
- const listeners = {
59
- trigger: new Set(),
60
- error: new Set(),
61
- timeout: new Set(),
62
- };
63
-
64
- let _timer = null;
65
- let _timeoutTimer = null;
66
- let _stopped = false;
67
- let _count = 0;
68
-
69
- function emit(event, p) {
70
- for (const fn of listeners[event]) {
71
- try {
72
- fn(p);
73
- } catch (error) {
74
- throw error;
75
- }
76
- }
77
- }
78
-
79
- async function evalPredicate() {
80
- if (typeof predicate === "function") {
81
- return await predicate();
82
- }
83
- return Boolean(predicate);
84
- }
85
-
86
- async function tick() {
87
- if (_stopped) return;
88
-
89
- try {
90
- const ok = await evalPredicate();
91
-
92
- if (ok) {
93
- _count++;
94
- emit("trigger", payload);
95
-
96
- if (max != null && _count >= max) {
97
- _stopInternal();
98
- return;
99
- }
100
- }
101
-
102
- if (!_stopped) {
103
- _timer = setTimeout(tick, interval);
104
- }
105
- } catch (error) {
106
- emit("error", error);
107
- if (!_stopped) {
108
- _timer = setTimeout(tick, interval);
109
- }
110
- }
111
- }
112
-
113
- function _stopInternal() {
114
- _stopped = true;
115
- if (_timer) {
116
- clearTimeout(_timer);
117
- _timer = null;
118
- }
119
- if (_timeoutTimer) {
120
- clearTimeout(_timeoutTimer);
121
- _timeoutTimer = null;
122
- }
123
- }
124
-
125
- const _ = {
126
- start() {
127
- if (_stopped) return _;
128
-
129
- if (!_timer) {
130
- _timer = setTimeout(tick, 0);
131
- }
132
-
133
- if (timeout != null && !_timeoutTimer) {
134
- _timeoutTimer = setTimeout(() => {
135
- if (_stopped) return;
136
- emit("timeout", payload);
137
- _stopInternal();
138
- }, timeout);
139
- }
140
-
141
- return _;
142
- },
143
- stop() {
144
- _stopInternal();
145
- return _;
146
- },
147
- /**
148
- * @typedef { "error" | "trigger" | "timeout" } EventNames
149
- * @typedef {{
150
- * error: (error) => void|Promise<void>,
151
- * trigger: (payload) => void|Promise<void>,
152
- * timeout: (payload) => void|Promise<void>,
153
- * }} EventHandlers
154
- */
155
- /**
156
- * @template {EventNames} E
157
- * @param {E} event
158
- * @param {EventHandlers[E]} handler
159
- */
160
- on(event, handler) {
161
- listeners[event]?.add(handler);
162
- return _;
163
- },
164
- };
165
-
166
- return _;
167
- },
168
- dontCrash() {
169
- const defaults = {
170
- error: (error) => {
171
- logger.log(`<% red [@ix-xs/node-comfort] Process Error %>\n<% gray ${error.stack ?? error} %>`);
172
- },
173
- exit: (code) => {
174
- logger.log(`<% yellow [@ix-xs/node-comfort] Process Exit %>\n→ Code: <% gray ${code} %>`);
175
- },
176
- sig: (signal) => {
177
- logger.log(`<% yellow [@ix-xs/node-comfort] Process SIG* %>\n→ Signal: <% gray ${signal} %>`);
178
- process.exit(0);
179
- },
180
- beforeExit: (code) => {},
181
- };
182
-
183
- const _ = {
184
- /**
185
- * @template { "error" | "exit" | "sig" | "beforeExit" } E
186
- * @param { E } event
187
- * @param { { error: (error: Error | unknown) => void | Promise<void>, exit: (code: number) => void | Promise<void>, sig: (signal: "SIGINT" | "SIGTERM" | "SIGQUIT") => void | Promise<void>, beforeExit: (code: number) => void|Promise<void> }[E] } handler
188
- */
189
- on(event, handler) {
190
- if (event === "error") {
191
- process.removeAllListeners("uncaughtException");
192
- process.removeAllListeners("unhandledRejection");
193
- process.on("uncaughtException", handler ?? defaults.error);
194
- process.on("unhandledRejection", handler ?? defaults.error);
195
- } else if (event === "exit") {
196
- process.removeAllListeners("exit");
197
- process.on("exit", handler ?? defaults.exit);
198
- } else if (event === "sig") {
199
- for (const signal of ["SIGINT", "SIGTERM", "SIGQUIT"]) {
200
- process.removeAllListeners(signal);
201
- process.on(signal, handler ?? defaults.sig);
202
- }
203
- } else if (event === "beforeExit") {
204
- process.removeAllListeners("beforeExit");
205
- process.on("beforeExit", handler ?? defaults.beforeExit);
206
- }
207
-
208
- return _;
209
- },
210
- };
211
-
212
- _.on("error").on("exit").on("sig");
213
-
214
- return _;
215
- },
216
- /**
217
- * @param {*} value
218
- */
219
- JSONString(value) {
220
- return JSON.stringify(value, null, 4);
221
- },
222
- JSONParse(value) {
223
- return JSON.parse(value);
224
- },
225
- };