qznt 1.0.37 → 2.0.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/README.md +29 -58
- package/dist/index.cjs +497 -646
- package/dist/index.d.cts +368 -530
- package/dist/index.d.ts +368 -530
- package/dist/index.js +453 -607
- package/package.json +3 -4
package/dist/index.js
CHANGED
|
@@ -1,47 +1,254 @@
|
|
|
1
|
-
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
// src/Cache.ts
|
|
2
|
+
var Cache = class {
|
|
3
|
+
cache = /* @__PURE__ */ new Map();
|
|
4
|
+
interval;
|
|
5
|
+
/**
|
|
6
|
+
* A lightweight, high-performant in-memory cache.
|
|
7
|
+
* Uses Map for O(1) lookups and an optional cleanup interval.
|
|
8
|
+
* @param cleanupMs The interval in milliseconds to run the cleanup function. [default: 60000 (1 minute)]
|
|
9
|
+
*/
|
|
10
|
+
constructor(cleanupMs = 6e4) {
|
|
11
|
+
if (cleanupMs > 0) {
|
|
12
|
+
this.interval = setInterval(() => this.cleanup(), cleanupMs);
|
|
13
|
+
if (this.interval.unref) this.interval.unref();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
set(key, value, ttlMs) {
|
|
17
|
+
this.cache.set(key, {
|
|
18
|
+
value,
|
|
19
|
+
expiresAt: ttlMs ? Date.now() + ttlMs : null
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
get(key) {
|
|
23
|
+
const data = this.cache.get(key);
|
|
24
|
+
if (!data) return null;
|
|
25
|
+
if (data.expiresAt && Date.now() > data.expiresAt) {
|
|
26
|
+
this.cache.delete(key);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return data.value;
|
|
30
|
+
}
|
|
31
|
+
cleanup() {
|
|
32
|
+
if (this.cache.size === 0) return;
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
let keysProcessed = 0;
|
|
35
|
+
const maxKeysToScan = 20;
|
|
36
|
+
for (const [key, data] of this.cache) {
|
|
37
|
+
if (data.expiresAt && now > data.expiresAt) {
|
|
38
|
+
this.cache.delete(key);
|
|
39
|
+
}
|
|
40
|
+
keysProcessed++;
|
|
41
|
+
if (keysProcessed >= maxKeysToScan) break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
clear() {
|
|
45
|
+
this.cache.clear();
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/Loop.ts
|
|
50
|
+
import EventEmitter from "events";
|
|
51
|
+
var TypedEmitterBase = EventEmitter;
|
|
52
|
+
var Loop = class extends TypedEmitterBase {
|
|
53
|
+
_state = "stopped";
|
|
54
|
+
timeoutId = null;
|
|
55
|
+
delay;
|
|
56
|
+
fn;
|
|
57
|
+
startTime = 0;
|
|
58
|
+
remaining = 0;
|
|
59
|
+
async run() {
|
|
60
|
+
const currentState = this._state;
|
|
61
|
+
if (currentState === "stopped" || currentState === "paused") return;
|
|
62
|
+
try {
|
|
63
|
+
const result = await this.fn(this);
|
|
64
|
+
this.emit("tick", result);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
try {
|
|
67
|
+
this.emit("error", err);
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (this._state === "running") {
|
|
72
|
+
this.startTime = Date.now();
|
|
73
|
+
this.remaining = 0;
|
|
74
|
+
this.clearTimer();
|
|
75
|
+
this.timeoutId = setTimeout(() => this.run(), this.delay);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
clearTimer() {
|
|
79
|
+
if (this.timeoutId) {
|
|
80
|
+
clearTimeout(this.timeoutId);
|
|
81
|
+
this.timeoutId = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Creates an interval. If the function is async, it will wait for it to complete before scheduling the next run.
|
|
86
|
+
* @param fn The function to run.
|
|
87
|
+
* @param delay The delay between runs in milliseconds.
|
|
88
|
+
* @param immediate Whether to start the loop immediately. [default: true]
|
|
89
|
+
*/
|
|
90
|
+
constructor(fn, delay, immediate = true) {
|
|
91
|
+
super();
|
|
92
|
+
this.fn = fn;
|
|
93
|
+
this.delay = delay;
|
|
94
|
+
if (immediate) this.start();
|
|
95
|
+
}
|
|
96
|
+
get state() {
|
|
97
|
+
return this._state;
|
|
98
|
+
}
|
|
99
|
+
/** Starts the loop. */
|
|
100
|
+
start() {
|
|
101
|
+
if (this._state !== "stopped") return;
|
|
102
|
+
this._state = "running";
|
|
103
|
+
this.emit("start");
|
|
104
|
+
this.run();
|
|
105
|
+
}
|
|
106
|
+
/** Resumes a paused loop. */
|
|
107
|
+
resume() {
|
|
108
|
+
if (this._state !== "paused") return;
|
|
109
|
+
this._state = "running";
|
|
110
|
+
this.emit("resume");
|
|
111
|
+
if (this.remaining <= 0) {
|
|
112
|
+
this.run();
|
|
113
|
+
} else {
|
|
114
|
+
this.timeoutId = setTimeout(() => this.run(), this.remaining);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** Stops the loop. */
|
|
118
|
+
stop() {
|
|
119
|
+
const wasRunning = this._state !== "stopped";
|
|
120
|
+
this._state = "stopped";
|
|
121
|
+
this.remaining = 0;
|
|
122
|
+
this.clearTimer();
|
|
123
|
+
if (wasRunning) this.emit("stop");
|
|
124
|
+
}
|
|
125
|
+
/** Pauses the execution. */
|
|
126
|
+
pause() {
|
|
127
|
+
if (this._state !== "running") return;
|
|
128
|
+
this._state = "paused";
|
|
129
|
+
const elapsed = Date.now() - this.startTime;
|
|
130
|
+
this.remaining = Math.max(0, this.delay - elapsed);
|
|
131
|
+
this.emit("pause", { remaining: this.remaining });
|
|
132
|
+
this.clearTimer();
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Sets the delay between runs
|
|
136
|
+
* @param ms The new delay in milliseconds.
|
|
137
|
+
*/
|
|
138
|
+
setDelay(ms) {
|
|
139
|
+
this.delay = ms;
|
|
140
|
+
}
|
|
141
|
+
/** Manually trigger the function once without affecting the loop. */
|
|
142
|
+
async execute() {
|
|
143
|
+
await this.fn(this);
|
|
144
|
+
}
|
|
5
145
|
};
|
|
6
146
|
|
|
7
|
-
// src/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
147
|
+
// src/Pipe.ts
|
|
148
|
+
function Pipe(value, ...fns) {
|
|
149
|
+
return fns.reduce((acc, fn) => fn(acc), value);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/Storage.ts
|
|
153
|
+
import fs from "fs";
|
|
154
|
+
import path from "path";
|
|
155
|
+
var Storage = class {
|
|
156
|
+
isNode = typeof window === "undefined";
|
|
157
|
+
filePath = null;
|
|
158
|
+
memoryCache = /* @__PURE__ */ new Map();
|
|
159
|
+
loadFromFile() {
|
|
160
|
+
if (this.filePath && fs.existsSync(this.filePath)) {
|
|
161
|
+
try {
|
|
162
|
+
const data = JSON.parse(fs.readFileSync(this.filePath, "utf-8"));
|
|
163
|
+
Object.entries(data).forEach(([k, v]) => this.memoryCache.set(k, JSON.stringify(v)));
|
|
164
|
+
} catch (err) {
|
|
165
|
+
console.error(`Store: Failed to load file '${this.filePath}'`, err);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
persist() {
|
|
170
|
+
if (this.isNode && this.filePath) {
|
|
171
|
+
const out = {};
|
|
172
|
+
this.memoryCache.forEach((v, k) => out[k] = JSON.parse(v));
|
|
173
|
+
fs.writeFileSync(this.filePath, JSON.stringify(out, null, 2));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* A lightweight, high-performant persistent storage system.
|
|
178
|
+
* Uses JSON files in Node.js, localStorage in the browser
|
|
179
|
+
* @param fileName Only used in Node.js to create a persistent .json file
|
|
180
|
+
* @param directory The directory for the file. Defaults to current working directory
|
|
181
|
+
*/
|
|
182
|
+
constructor(fileName, directory = process.cwd()) {
|
|
183
|
+
if (this.isNode && fileName) {
|
|
184
|
+
this.filePath = path.join(directory, fileName.endsWith(".json") ? fileName : `${fileName}.json`);
|
|
185
|
+
this.loadFromFile();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
has(key) {
|
|
189
|
+
if (!this.isNode && window.localStorage) {
|
|
190
|
+
return localStorage.getItem(key) !== null;
|
|
191
|
+
}
|
|
192
|
+
return this.memoryCache.has(key);
|
|
193
|
+
}
|
|
194
|
+
get(key) {
|
|
195
|
+
let raw = null;
|
|
196
|
+
if (!this.isNode && window.localStorage) {
|
|
197
|
+
raw = localStorage.getItem(key);
|
|
198
|
+
} else {
|
|
199
|
+
raw = this.memoryCache.get(key) || null;
|
|
200
|
+
}
|
|
201
|
+
if (!raw) return null;
|
|
202
|
+
const payload = JSON.parse(raw);
|
|
203
|
+
if (payload.expiry && Date.now() > payload.expiry) {
|
|
204
|
+
this.remove(key);
|
|
205
|
+
this.persist();
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return payload.value;
|
|
209
|
+
}
|
|
210
|
+
set(key, value, ttl) {
|
|
211
|
+
const payload = {
|
|
212
|
+
value,
|
|
213
|
+
expiry: ttl ? Date.now() + ttl : null
|
|
214
|
+
};
|
|
215
|
+
const serialized = JSON.stringify(payload);
|
|
216
|
+
if (!this.isNode && window.localStorage) {
|
|
217
|
+
localStorage.setItem(key, serialized);
|
|
218
|
+
} else {
|
|
219
|
+
this.memoryCache.set(key, serialized);
|
|
220
|
+
this.persist();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
remove(key) {
|
|
224
|
+
if (!this.isNode && window.localStorage) {
|
|
225
|
+
localStorage.removeItem(key);
|
|
226
|
+
} else {
|
|
227
|
+
this.memoryCache.delete(key);
|
|
228
|
+
this.persist();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
clear() {
|
|
232
|
+
if (!this.isNode && window.localStorage) {
|
|
233
|
+
localStorage.clear();
|
|
234
|
+
} else {
|
|
235
|
+
this.memoryCache.clear();
|
|
236
|
+
this.persist();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
21
240
|
|
|
22
|
-
// src/
|
|
23
|
-
var rnd_exports = {};
|
|
24
|
-
__export(rnd_exports, {
|
|
25
|
-
chance: () => chance,
|
|
26
|
-
choice: () => choice,
|
|
27
|
-
float: () => float,
|
|
28
|
-
index: () => index,
|
|
29
|
-
int: () => int,
|
|
30
|
-
prng: () => prng,
|
|
31
|
-
sampler: () => sampler,
|
|
32
|
-
str: () => str,
|
|
33
|
-
weighted: () => weighted
|
|
34
|
-
});
|
|
241
|
+
// src/random.ts
|
|
35
242
|
var LOWER = "abcdefghijklmnopqrstuvwxyz";
|
|
36
243
|
var UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
37
244
|
var NUM = "0123456789";
|
|
38
|
-
function
|
|
245
|
+
function rndChance(percent2 = 0.5, seed) {
|
|
39
246
|
if (percent2 <= 0) return false;
|
|
40
247
|
if (percent2 >= 1) return true;
|
|
41
248
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
42
249
|
return random() < percent2;
|
|
43
250
|
}
|
|
44
|
-
function
|
|
251
|
+
function rndChoice(array, options = {}) {
|
|
45
252
|
const { seed, not, maxRerolls = 10 } = options;
|
|
46
253
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
47
254
|
const rnd = () => array[Math.floor(random() * array.length)];
|
|
@@ -56,19 +263,19 @@ function choice(array, options = {}) {
|
|
|
56
263
|
}
|
|
57
264
|
return result;
|
|
58
265
|
}
|
|
59
|
-
function
|
|
266
|
+
function weightedRnd(array, predicate, seed) {
|
|
60
267
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
61
268
|
const cumulativeWeights = [];
|
|
62
269
|
let currentSum = 0;
|
|
63
270
|
for (const item of array) {
|
|
64
|
-
const weight =
|
|
271
|
+
const weight = predicate(item);
|
|
65
272
|
currentSum += weight;
|
|
66
273
|
cumulativeWeights.push(currentSum);
|
|
67
274
|
}
|
|
68
275
|
const decider = random() * currentSum;
|
|
69
|
-
let
|
|
276
|
+
let index;
|
|
70
277
|
if (array.length < 20) {
|
|
71
|
-
|
|
278
|
+
index = cumulativeWeights.findIndex((w) => w >= decider);
|
|
72
279
|
} else {
|
|
73
280
|
let low = 0;
|
|
74
281
|
let high = cumulativeWeights.length - 1;
|
|
@@ -80,16 +287,16 @@ function weighted(array, selector, seed) {
|
|
|
80
287
|
high = mid;
|
|
81
288
|
}
|
|
82
289
|
}
|
|
83
|
-
|
|
290
|
+
index = low;
|
|
84
291
|
}
|
|
85
|
-
return array[
|
|
292
|
+
return array[index];
|
|
86
293
|
}
|
|
87
|
-
function
|
|
294
|
+
function createSampler(items, predicate, seed) {
|
|
88
295
|
const callRandom = seed ? prng(seed) : void 0;
|
|
89
296
|
const len = items.length;
|
|
90
297
|
const prob = new Array(len);
|
|
91
298
|
const alias = new Array(len);
|
|
92
|
-
const weights = items.map(
|
|
299
|
+
const weights = items.map(predicate);
|
|
93
300
|
const totalWeight = weights.reduce((a, b) => a + b, 0);
|
|
94
301
|
const scaledWeights = weights.map((w) => w * len / totalWeight);
|
|
95
302
|
const small = [];
|
|
@@ -107,8 +314,8 @@ function sampler(items, selector, seed) {
|
|
|
107
314
|
while (small.length) prob[small.pop()] = 1;
|
|
108
315
|
return {
|
|
109
316
|
/**
|
|
110
|
-
* Returns a random item from the given array in O(1) time
|
|
111
|
-
* @param seed Optional seed for RNG
|
|
317
|
+
* Returns a random item from the given array in O(1) time
|
|
318
|
+
* @param seed Optional seed for RNG
|
|
112
319
|
*/
|
|
113
320
|
pick: (seed2) => {
|
|
114
321
|
const random = seed2 !== void 0 ? prng(seed2) : callRandom || Math.random;
|
|
@@ -125,11 +332,11 @@ function prng(seed) {
|
|
|
125
332
|
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
126
333
|
};
|
|
127
334
|
}
|
|
128
|
-
function
|
|
335
|
+
function rndFloat(min, max, seed) {
|
|
129
336
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
130
337
|
return random() * (max - min) + min;
|
|
131
338
|
}
|
|
132
|
-
function
|
|
339
|
+
function rndIndex(array, options = {}) {
|
|
133
340
|
const { seed, not, maxRerolls = 10 } = options;
|
|
134
341
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
135
342
|
const rnd = () => Math.floor(random() * array.length);
|
|
@@ -144,11 +351,11 @@ function index(array, options = {}) {
|
|
|
144
351
|
}
|
|
145
352
|
return result;
|
|
146
353
|
}
|
|
147
|
-
function
|
|
354
|
+
function rndInt(min, max, seed) {
|
|
148
355
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
149
356
|
return Math.floor(random() * (max - min + 1)) + min;
|
|
150
357
|
}
|
|
151
|
-
function
|
|
358
|
+
function rndString(len, mode, options = {}) {
|
|
152
359
|
const { casing = "lower", seed, customChars = "", exclude = "" } = options;
|
|
153
360
|
const random = seed !== void 0 ? prng(seed) : Math.random;
|
|
154
361
|
const alphaPool = { lower: LOWER, upper: UPPER, mixed: LOWER + UPPER }[casing];
|
|
@@ -166,7 +373,7 @@ function str(len, mode, options = {}) {
|
|
|
166
373
|
return result.join("");
|
|
167
374
|
}
|
|
168
375
|
|
|
169
|
-
// src/
|
|
376
|
+
// src/array.ts
|
|
170
377
|
function chunk(array, size) {
|
|
171
378
|
if (size <= 0) throw new Error("chunk: Size must be a positive integer.");
|
|
172
379
|
const result = [];
|
|
@@ -217,7 +424,7 @@ function cluster(array, iteratee, maxChunkSize) {
|
|
|
217
424
|
}
|
|
218
425
|
return result;
|
|
219
426
|
}
|
|
220
|
-
function
|
|
427
|
+
function compactArray(array, mode = "nullable") {
|
|
221
428
|
if (mode === "falsy") {
|
|
222
429
|
return array.filter(Boolean);
|
|
223
430
|
}
|
|
@@ -226,7 +433,7 @@ function compact(array, mode = "nullable") {
|
|
|
226
433
|
function forceArray(item) {
|
|
227
434
|
return Array.isArray(item) ? item : [item];
|
|
228
435
|
}
|
|
229
|
-
function
|
|
436
|
+
function searchSorted(array, target, comparator = (a, b) => a > b ? 1 : a < b ? -1 : 0) {
|
|
230
437
|
let low = 0;
|
|
231
438
|
let high = array.length - 1;
|
|
232
439
|
while (low <= high) {
|
|
@@ -289,13 +496,8 @@ function unique(array, key) {
|
|
|
289
496
|
}
|
|
290
497
|
|
|
291
498
|
// src/async.ts
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
retry: () => retry,
|
|
295
|
-
wait: () => wait
|
|
296
|
-
});
|
|
297
|
-
async function retry(fn, options = {}) {
|
|
298
|
-
const { retries = 3, delay = 500, timeout, signal } = options;
|
|
499
|
+
async function retryPromise(fn, options = {}) {
|
|
500
|
+
const { attempts = 3, delay = 500, timeout, signal } = options;
|
|
299
501
|
if (signal?.aborted) throw new Error("Operation aborted");
|
|
300
502
|
const executeWithTimeout = async () => {
|
|
301
503
|
if (!timeout) return fn(signal);
|
|
@@ -314,7 +516,7 @@ async function retry(fn, options = {}) {
|
|
|
314
516
|
return await executeWithTimeout();
|
|
315
517
|
} catch (error) {
|
|
316
518
|
if (signal?.aborted) throw error;
|
|
317
|
-
if (
|
|
519
|
+
if (attempts <= 0) throw error;
|
|
318
520
|
const jitter = Math.random() * 200;
|
|
319
521
|
const totalDelay = delay + jitter;
|
|
320
522
|
await new Promise((resolve, reject) => {
|
|
@@ -328,51 +530,14 @@ async function retry(fn, options = {}) {
|
|
|
328
530
|
{ once: true }
|
|
329
531
|
);
|
|
330
532
|
});
|
|
331
|
-
return
|
|
533
|
+
return retryPromise(fn, { ...options, attempts: attempts - 1, delay: delay * 2 });
|
|
332
534
|
}
|
|
333
535
|
}
|
|
334
|
-
function wait(
|
|
335
|
-
return new Promise(
|
|
336
|
-
(resolve) => setTimeout(() => {
|
|
337
|
-
resolve(true);
|
|
338
|
-
}, ms2)
|
|
339
|
-
);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// src/fn.ts
|
|
343
|
-
var fn_exports = {};
|
|
344
|
-
__export(fn_exports, {
|
|
345
|
-
memoize: () => memoize
|
|
346
|
-
});
|
|
347
|
-
function memoize(fn, options = {}) {
|
|
348
|
-
const cache = /* @__PURE__ */ new Map();
|
|
349
|
-
const { resolver, maxAge } = options;
|
|
350
|
-
const memoized = function(...args) {
|
|
351
|
-
const key = resolver ? resolver(...args) : JSON.stringify(args);
|
|
352
|
-
const now = Date.now();
|
|
353
|
-
const entry = cache.get(key);
|
|
354
|
-
if (entry) {
|
|
355
|
-
if (!maxAge || now - entry.timestamp < maxAge) {
|
|
356
|
-
return entry.value;
|
|
357
|
-
}
|
|
358
|
-
cache.delete(key);
|
|
359
|
-
}
|
|
360
|
-
const result = fn.apply(this, args);
|
|
361
|
-
cache.set(key, { value: result, timestamp: now });
|
|
362
|
-
return result;
|
|
363
|
-
};
|
|
364
|
-
memoized.clear = () => cache.clear();
|
|
365
|
-
return memoized;
|
|
536
|
+
function wait(ms) {
|
|
537
|
+
return new Promise((resolve) => setTimeout(() => resolve(true), ms));
|
|
366
538
|
}
|
|
367
539
|
|
|
368
540
|
// src/date.ts
|
|
369
|
-
var date_exports = {};
|
|
370
|
-
__export(date_exports, {
|
|
371
|
-
duration: () => duration,
|
|
372
|
-
eta: () => eta,
|
|
373
|
-
getAge: () => getAge,
|
|
374
|
-
parse: () => parse
|
|
375
|
-
});
|
|
376
541
|
var MS_MAP = {
|
|
377
542
|
ms: 1,
|
|
378
543
|
s: 1e3,
|
|
@@ -383,64 +548,18 @@ var MS_MAP = {
|
|
|
383
548
|
mth: 24192e5,
|
|
384
549
|
y: 31536e6
|
|
385
550
|
};
|
|
386
|
-
function duration(target, style = "hms", options = {}) {
|
|
387
|
-
const targetMs = target instanceof Date ? target.getTime() : Number(target);
|
|
388
|
-
const sinceMs = options.since instanceof Date ? options.since.getTime() : Number(options.since) || Date.now();
|
|
389
|
-
const diff = Math.abs(targetMs - sinceMs);
|
|
390
|
-
if (diff === 0) return style === "digital" ? "00:00" : "now";
|
|
391
|
-
const s = Math.floor(diff / 1e3) % 60;
|
|
392
|
-
const m = Math.floor(diff / 6e4) % 60;
|
|
393
|
-
const h = Math.floor(diff / 36e5) % 24;
|
|
394
|
-
const d = Math.floor(diff / 864e5);
|
|
395
|
-
if (style === "digital") {
|
|
396
|
-
const parts = [m, s].map((v) => String(v).padStart(2, "0"));
|
|
397
|
-
if (h > 0 || d > 0) parts.unshift(String(h).padStart(2, "0"));
|
|
398
|
-
if (d > 0) parts.unshift(String(d));
|
|
399
|
-
return parts.join(":");
|
|
400
|
-
}
|
|
401
|
-
const result = [];
|
|
402
|
-
const push = (val, label) => {
|
|
403
|
-
if (val > 0) result.push(`${val} ${label}${val === 1 ? "" : "s"}`);
|
|
404
|
-
};
|
|
405
|
-
if (style === "ymdhms") push(d, "day");
|
|
406
|
-
push(h, "hour");
|
|
407
|
-
push(m, "minute");
|
|
408
|
-
push(s, "second");
|
|
409
|
-
if (result.length === 0) return "0 seconds";
|
|
410
|
-
if (result.length === 1) return result[0];
|
|
411
|
-
const last = result.pop();
|
|
412
|
-
return `${result.join(", ")} and ${last}`;
|
|
413
|
-
}
|
|
414
|
-
function eta(date, locale) {
|
|
415
|
-
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
416
|
-
const elapsed = (typeof date === "number" ? date : date.getTime()) - Date.now();
|
|
417
|
-
const units = [
|
|
418
|
-
{ unit: "year", ms: 31536e6 },
|
|
419
|
-
{ unit: "month", ms: 2628e6 },
|
|
420
|
-
{ unit: "day", ms: 864e5 },
|
|
421
|
-
{ unit: "hour", ms: 36e5 },
|
|
422
|
-
{ unit: "minute", ms: 6e4 },
|
|
423
|
-
{ unit: "second", ms: 1e3 }
|
|
424
|
-
];
|
|
425
|
-
for (const { unit, ms: ms2 } of units) {
|
|
426
|
-
if (Math.abs(elapsed) >= ms2 || unit === "second") {
|
|
427
|
-
return rtf.format(Math.round(elapsed / ms2), unit);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
return "";
|
|
431
|
-
}
|
|
432
551
|
function getAge(birthdate) {
|
|
433
|
-
const
|
|
434
|
-
let age =
|
|
435
|
-
const monthDiff =
|
|
436
|
-
if (monthDiff < 0 || monthDiff === 0 &&
|
|
552
|
+
const today = /* @__PURE__ */ new Date();
|
|
553
|
+
let age = today.getFullYear() - birthdate.getFullYear();
|
|
554
|
+
const monthDiff = today.getMonth() - birthdate.getMonth();
|
|
555
|
+
if (monthDiff < 0 || monthDiff === 0 && today.getDate() < birthdate.getDate()) {
|
|
437
556
|
age--;
|
|
438
557
|
}
|
|
439
558
|
return age;
|
|
440
559
|
}
|
|
441
|
-
function
|
|
442
|
-
if (typeof
|
|
443
|
-
const matches =
|
|
560
|
+
function parseTime(str, options = {}) {
|
|
561
|
+
if (typeof str === "number") return str;
|
|
562
|
+
const matches = str.matchAll(/(-?\d+)([a-z]+)/gi);
|
|
444
563
|
let totalMs = 0;
|
|
445
564
|
let found = false;
|
|
446
565
|
for (const [_, value, unit] of matches) {
|
|
@@ -451,39 +570,85 @@ function parse(str2, options = {}) {
|
|
|
451
570
|
found = true;
|
|
452
571
|
}
|
|
453
572
|
}
|
|
454
|
-
if (!found) throw new Error(`parse: Invalid time format: "${
|
|
573
|
+
if (!found) throw new Error(`parse: Invalid time format: "${str}"`);
|
|
455
574
|
const result = options.unit === "s" ? totalMs / 1e3 : totalMs;
|
|
456
575
|
return options.fromNow ? Date.now() + result : result;
|
|
457
576
|
}
|
|
458
577
|
|
|
578
|
+
// src/exec.ts
|
|
579
|
+
function debounce(fn, wait2, options = {}) {
|
|
580
|
+
let timeoutId;
|
|
581
|
+
const leading = options.immediate ?? false;
|
|
582
|
+
const debounced = function(...args) {
|
|
583
|
+
const callNow = leading && !timeoutId;
|
|
584
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
585
|
+
timeoutId = setTimeout(() => {
|
|
586
|
+
timeoutId = void 0;
|
|
587
|
+
if (!leading) fn.apply(this, args);
|
|
588
|
+
}, wait2);
|
|
589
|
+
if (callNow) fn.apply(this, args);
|
|
590
|
+
};
|
|
591
|
+
debounced.cancel = () => {
|
|
592
|
+
if (timeoutId) {
|
|
593
|
+
clearTimeout(timeoutId);
|
|
594
|
+
timeoutId = void 0;
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
return debounced;
|
|
598
|
+
}
|
|
599
|
+
function throttle(fn, limit) {
|
|
600
|
+
let inThrottle = false;
|
|
601
|
+
return function(...args) {
|
|
602
|
+
if (!inThrottle) {
|
|
603
|
+
fn.apply(this, args);
|
|
604
|
+
inThrottle = true;
|
|
605
|
+
setTimeout(() => inThrottle = false, limit);
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// src/fn.ts
|
|
611
|
+
function memoize(fn, options = {}) {
|
|
612
|
+
const cache = /* @__PURE__ */ new Map();
|
|
613
|
+
const { resolver, maxAge } = options;
|
|
614
|
+
const memoized = function(...args) {
|
|
615
|
+
const key = resolver ? resolver(...args) : JSON.stringify(args);
|
|
616
|
+
const now = Date.now();
|
|
617
|
+
const entry = cache.get(key);
|
|
618
|
+
if (entry) {
|
|
619
|
+
if (!maxAge || now - entry.timestamp < maxAge) {
|
|
620
|
+
return entry.value;
|
|
621
|
+
}
|
|
622
|
+
cache.delete(key);
|
|
623
|
+
}
|
|
624
|
+
const result = fn.apply(this, args);
|
|
625
|
+
cache.set(key, { value: result, timestamp: now });
|
|
626
|
+
return result;
|
|
627
|
+
};
|
|
628
|
+
memoized.clear = () => cache.clear();
|
|
629
|
+
return memoized;
|
|
630
|
+
}
|
|
631
|
+
|
|
459
632
|
// src/format.ts
|
|
460
|
-
|
|
461
|
-
__export(format_exports, {
|
|
462
|
-
compactNumber: () => compactNumber,
|
|
463
|
-
currency: () => currency,
|
|
464
|
-
memory: () => memory,
|
|
465
|
-
number: () => number,
|
|
466
|
-
ordinal: () => ordinal
|
|
467
|
-
});
|
|
468
|
-
function currency(num, options = {}) {
|
|
633
|
+
function formatCurrency(num, options = {}) {
|
|
469
634
|
return new Intl.NumberFormat(options.locale, {
|
|
470
635
|
style: "currency",
|
|
471
636
|
currency: options.currency
|
|
472
637
|
}).format(num);
|
|
473
638
|
}
|
|
474
|
-
function
|
|
639
|
+
function formatNumber(num, options = {}) {
|
|
475
640
|
return new Intl.NumberFormat(options.locale, {
|
|
476
641
|
minimumFractionDigits: options.precision,
|
|
477
642
|
maximumFractionDigits: options.precision
|
|
478
643
|
}).format(num);
|
|
479
644
|
}
|
|
480
|
-
function
|
|
645
|
+
function formatMemory(bytes, decimals = 1, units = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]) {
|
|
481
646
|
if (bytes <= 0) return `0 ${units[0]}`;
|
|
482
647
|
const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
|
|
483
648
|
const val = bytes / Math.pow(1024, i);
|
|
484
649
|
return `${val.toFixed(i === 0 ? 0 : decimals)} ${units[i]}`;
|
|
485
650
|
}
|
|
486
|
-
function
|
|
651
|
+
function formatOrdinal(num, locale) {
|
|
487
652
|
const _num = Number(num);
|
|
488
653
|
if (isNaN(_num)) throw new TypeError("Invalid input");
|
|
489
654
|
const pr = new Intl.PluralRules(locale, { type: "ordinal" });
|
|
@@ -497,19 +662,61 @@ function ordinal(num, locale) {
|
|
|
497
662
|
const suffix = suffixes[rule] || "th";
|
|
498
663
|
return _num.toLocaleString(locale) + suffix;
|
|
499
664
|
}
|
|
500
|
-
function
|
|
665
|
+
function FormatNumberCompact(num, locale) {
|
|
501
666
|
return new Intl.NumberFormat(locale, {
|
|
502
667
|
notation: "compact",
|
|
503
668
|
compactDisplay: "short",
|
|
504
669
|
maximumFractionDigits: 1
|
|
505
670
|
}).format(num);
|
|
506
671
|
}
|
|
672
|
+
function formatDuration(target, style = "hms", options = {}) {
|
|
673
|
+
const targetMs = target instanceof Date ? target.getTime() : Number(target);
|
|
674
|
+
const sinceMs = options.since instanceof Date ? options.since.getTime() : Number(options.since) || Date.now();
|
|
675
|
+
const diff = Math.abs(targetMs - sinceMs);
|
|
676
|
+
if (diff === 0) return style === "digital" ? "00:00" : "now";
|
|
677
|
+
const s = Math.floor(diff / 1e3) % 60;
|
|
678
|
+
const m = Math.floor(diff / 6e4) % 60;
|
|
679
|
+
const h = Math.floor(diff / 36e5) % 24;
|
|
680
|
+
const d = Math.floor(diff / 864e5);
|
|
681
|
+
if (style === "digital") {
|
|
682
|
+
const parts = [m, s].map((v) => String(v).padStart(2, "0"));
|
|
683
|
+
if (h > 0 || d > 0) parts.unshift(String(h).padStart(2, "0"));
|
|
684
|
+
if (d > 0) parts.unshift(String(d));
|
|
685
|
+
return parts.join(":");
|
|
686
|
+
}
|
|
687
|
+
const result = [];
|
|
688
|
+
const push = (val, label) => {
|
|
689
|
+
if (val > 0) result.push(`${val} ${label}${val === 1 ? "" : "s"}`);
|
|
690
|
+
};
|
|
691
|
+
if (style === "ymdhms") push(d, "day");
|
|
692
|
+
push(h, "hour");
|
|
693
|
+
push(m, "minute");
|
|
694
|
+
push(s, "second");
|
|
695
|
+
if (result.length === 0) return "0 seconds";
|
|
696
|
+
if (result.length === 1) return result[0];
|
|
697
|
+
const last = result.pop();
|
|
698
|
+
return `${result.join(", ")} and ${last}`;
|
|
699
|
+
}
|
|
700
|
+
function formatETA(date, locale) {
|
|
701
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
702
|
+
const elapsed = (typeof date === "number" ? date : date.getTime()) - Date.now();
|
|
703
|
+
const units = [
|
|
704
|
+
{ unit: "year", ms: 31536e6 },
|
|
705
|
+
{ unit: "month", ms: 2628e6 },
|
|
706
|
+
{ unit: "day", ms: 864e5 },
|
|
707
|
+
{ unit: "hour", ms: 36e5 },
|
|
708
|
+
{ unit: "minute", ms: 6e4 },
|
|
709
|
+
{ unit: "second", ms: 1e3 }
|
|
710
|
+
];
|
|
711
|
+
for (const { unit, ms } of units) {
|
|
712
|
+
if (Math.abs(elapsed) >= ms || unit === "second") {
|
|
713
|
+
return rtf.format(Math.round(elapsed / ms), unit);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return "";
|
|
717
|
+
}
|
|
507
718
|
|
|
508
719
|
// src/fs.ts
|
|
509
|
-
var fs_exports = {};
|
|
510
|
-
__export(fs_exports, {
|
|
511
|
-
readDir: () => readDir
|
|
512
|
-
});
|
|
513
720
|
import _fs from "fs";
|
|
514
721
|
import { join } from "path";
|
|
515
722
|
function readDir(path2, options = {}) {
|
|
@@ -538,77 +745,58 @@ function readDir(path2, options = {}) {
|
|
|
538
745
|
}
|
|
539
746
|
|
|
540
747
|
// src/is.ts
|
|
541
|
-
|
|
542
|
-
__export(is_exports, {
|
|
543
|
-
defined: () => defined,
|
|
544
|
-
empty: () => empty,
|
|
545
|
-
inRange: () => inRange,
|
|
546
|
-
object: () => object,
|
|
547
|
-
sorted: () => sorted,
|
|
548
|
-
string: () => string,
|
|
549
|
-
today: () => today
|
|
550
|
-
});
|
|
551
|
-
function defined(val) {
|
|
748
|
+
function isDefined(val) {
|
|
552
749
|
return val !== void 0 && val !== null;
|
|
553
750
|
}
|
|
554
|
-
function
|
|
555
|
-
if (!
|
|
556
|
-
if (
|
|
557
|
-
if (
|
|
751
|
+
function isEmpty(val) {
|
|
752
|
+
if (!isDefined(val)) return true;
|
|
753
|
+
if (isString(val) || Array.isArray(val)) return val.length === 0;
|
|
754
|
+
if (isObject(val)) return Object.keys(val).length === 0;
|
|
558
755
|
return false;
|
|
559
756
|
}
|
|
560
|
-
function
|
|
757
|
+
function isObject(val) {
|
|
758
|
+
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
759
|
+
}
|
|
760
|
+
function isString(val) {
|
|
761
|
+
return typeof val === "string";
|
|
762
|
+
}
|
|
763
|
+
function isInRange(num, a, b) {
|
|
561
764
|
let min = b !== void 0 ? a : 0;
|
|
562
765
|
let max = b !== void 0 ? b : a;
|
|
563
766
|
if (min > max) [min, max] = [max, min];
|
|
564
767
|
return num >= min && num <= max;
|
|
565
768
|
}
|
|
566
|
-
function
|
|
567
|
-
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
568
|
-
}
|
|
569
|
-
function sorted(arr, comparator) {
|
|
769
|
+
function isSortedArray(arr, comparator) {
|
|
570
770
|
for (let i = 0; i < arr.length - 1; i++) {
|
|
571
771
|
const comp = comparator ? comparator(arr[i], arr[i + 1]) : arr[i] > arr[i + 1] ? 1 : -1;
|
|
572
772
|
if (comp > 0) return false;
|
|
573
773
|
}
|
|
574
774
|
return true;
|
|
575
775
|
}
|
|
576
|
-
function
|
|
577
|
-
return typeof val === "string";
|
|
578
|
-
}
|
|
579
|
-
function today(date) {
|
|
776
|
+
function isToday(date) {
|
|
580
777
|
const d = date instanceof Date ? date : new Date(date);
|
|
581
|
-
const
|
|
582
|
-
return d.getDate() ===
|
|
778
|
+
const today = /* @__PURE__ */ new Date();
|
|
779
|
+
return d.getDate() === today.getDate() && d.getMonth() === today.getMonth() && d.getFullYear() === today.getFullYear();
|
|
583
780
|
}
|
|
584
781
|
|
|
585
782
|
// src/math.ts
|
|
586
|
-
|
|
587
|
-
__export(math_exports, {
|
|
588
|
-
clamp: () => clamp,
|
|
589
|
-
invLerp: () => invLerp,
|
|
590
|
-
lerp: () => lerp,
|
|
591
|
-
ms: () => ms,
|
|
592
|
-
percent: () => percent,
|
|
593
|
-
remap: () => remap,
|
|
594
|
-
secs: () => secs,
|
|
595
|
-
sum: () => sum,
|
|
596
|
-
wrap: () => wrap
|
|
597
|
-
});
|
|
598
|
-
function clamp(num, a, b) {
|
|
783
|
+
function clampNumber(num, a, b) {
|
|
599
784
|
let min = b !== void 0 ? a : 0;
|
|
600
785
|
let max = b !== void 0 ? b : a;
|
|
601
786
|
if (min > max) [min, max] = [max, min];
|
|
602
787
|
return Math.max(min, Math.min(num, max));
|
|
603
788
|
}
|
|
604
|
-
function
|
|
789
|
+
function lerp(start, end, t) {
|
|
790
|
+
return start + (end - start) * t;
|
|
791
|
+
}
|
|
792
|
+
function inverseLerp(start, end, value) {
|
|
605
793
|
if (start === end) return 0;
|
|
606
794
|
return (value - start) / (end - start);
|
|
607
795
|
}
|
|
608
|
-
function
|
|
609
|
-
return
|
|
796
|
+
function msToSecs(num) {
|
|
797
|
+
return Math.floor(num / 1e3);
|
|
610
798
|
}
|
|
611
|
-
function
|
|
799
|
+
function secsToMs(num) {
|
|
612
800
|
return Math.floor(num * 1e3);
|
|
613
801
|
}
|
|
614
802
|
function percent(a, b, round = true) {
|
|
@@ -616,36 +804,19 @@ function percent(a, b, round = true) {
|
|
|
616
804
|
return round ? Math.floor(result) : result;
|
|
617
805
|
}
|
|
618
806
|
function remap(value, inMin, inMax, outMin, outMax) {
|
|
619
|
-
const t =
|
|
807
|
+
const t = inverseLerp(inMin, inMax, value);
|
|
620
808
|
return lerp(outMin, outMax, t);
|
|
621
809
|
}
|
|
622
|
-
function secs(num) {
|
|
623
|
-
return Math.floor(num / 1e3);
|
|
624
|
-
}
|
|
625
810
|
function sum(array, selector) {
|
|
626
811
|
const _array = selector ? array.map(selector) : array;
|
|
627
|
-
|
|
628
|
-
throw new TypeError(`sum: Array must only contain numbers.`);
|
|
629
|
-
}
|
|
630
|
-
return _array.reduce((a, b) => {
|
|
631
|
-
return (isNaN(b) ? 0 : b) < 0 ? a - -b : a + (b || 0);
|
|
632
|
-
}, 0);
|
|
812
|
+
return _array.reduce((a, b) => b < 0 ? a - -b : a + (b || 0), 0);
|
|
633
813
|
}
|
|
634
814
|
function wrap(num, max) {
|
|
635
815
|
return (num % max + max) % max;
|
|
636
816
|
}
|
|
637
817
|
|
|
638
818
|
// src/obj.ts
|
|
639
|
-
|
|
640
|
-
__export(obj_exports, {
|
|
641
|
-
get: () => get,
|
|
642
|
-
has: () => has,
|
|
643
|
-
merge: () => merge,
|
|
644
|
-
omit: () => omit,
|
|
645
|
-
pick: () => pick,
|
|
646
|
-
set: () => set
|
|
647
|
-
});
|
|
648
|
-
function get(obj, path2, defaultValue) {
|
|
819
|
+
function getProp(obj, path2, defaultValue) {
|
|
649
820
|
if (!obj) throw new Error("get: Target object is null or undefined");
|
|
650
821
|
const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
651
822
|
let current = obj;
|
|
@@ -664,7 +835,7 @@ function get(obj, path2, defaultValue) {
|
|
|
664
835
|
}
|
|
665
836
|
return current;
|
|
666
837
|
}
|
|
667
|
-
function
|
|
838
|
+
function hasProp(obj, path2) {
|
|
668
839
|
if (!obj || !path2) return false;
|
|
669
840
|
const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
670
841
|
let current = obj;
|
|
@@ -680,7 +851,7 @@ function has(obj, path2) {
|
|
|
680
851
|
}
|
|
681
852
|
return true;
|
|
682
853
|
}
|
|
683
|
-
function
|
|
854
|
+
function setProp(obj, path2, value) {
|
|
684
855
|
const parts = path2.replace(/\[(\d+)\]/g, ".$1").split(".");
|
|
685
856
|
let current = obj;
|
|
686
857
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -732,36 +903,32 @@ function omit(obj, keys) {
|
|
|
732
903
|
}
|
|
733
904
|
|
|
734
905
|
// src/str.ts
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
escapeRegex: () => escapeRegex,
|
|
738
|
-
getFlag: () => getFlag,
|
|
739
|
-
hasFlag: () => hasFlag,
|
|
740
|
-
toTitleCase: () => toTitleCase
|
|
741
|
-
});
|
|
742
|
-
function escapeRegex(str2) {
|
|
743
|
-
return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
906
|
+
function escapeRegex(str) {
|
|
907
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
744
908
|
}
|
|
745
|
-
function getFlag(
|
|
909
|
+
function getFlag(str, flag, length) {
|
|
746
910
|
const regex = flag instanceof RegExp ? flag : new RegExp(`${escapeRegex(flag)}\\b`, "g");
|
|
747
|
-
const match = regex.exec(
|
|
911
|
+
const match = regex.exec(str);
|
|
748
912
|
if (!match) return null;
|
|
749
913
|
const startIndex = match.index + match[0].length;
|
|
750
|
-
let result =
|
|
914
|
+
let result = str.slice(startIndex).trimStart();
|
|
751
915
|
if (length !== void 0) {
|
|
752
916
|
return result.split(/\s+/).slice(0, length).join(" ");
|
|
753
917
|
}
|
|
754
918
|
return result || null;
|
|
755
919
|
}
|
|
756
|
-
function hasFlag(
|
|
757
|
-
if (flag instanceof RegExp) return flag.test(
|
|
920
|
+
function hasFlag(str, flag) {
|
|
921
|
+
if (flag instanceof RegExp) return flag.test(str);
|
|
758
922
|
const pattern = new RegExp(`${escapeRegex(flag)}\\b`);
|
|
759
|
-
return pattern.test(
|
|
923
|
+
return pattern.test(str);
|
|
760
924
|
}
|
|
761
|
-
function
|
|
925
|
+
function pluralize(count, singular, plural = `${singular}s`) {
|
|
926
|
+
return count === 1 ? singular : plural;
|
|
927
|
+
}
|
|
928
|
+
function toTitleCase(str, smart = true) {
|
|
762
929
|
const minorWords = /^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|v\.?|via)$/i;
|
|
763
|
-
return
|
|
764
|
-
if (smart &&
|
|
930
|
+
return str.replace(/\w\S*/g, (txt, index) => {
|
|
931
|
+
if (smart && index !== 0 && minorWords.test(txt)) {
|
|
765
932
|
return txt.toLowerCase();
|
|
766
933
|
}
|
|
767
934
|
if (smart && txt.length > 1 && txt === txt.toUpperCase()) {
|
|
@@ -770,391 +937,70 @@ function toTitleCase(str2, smart = true) {
|
|
|
770
937
|
return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
|
|
771
938
|
});
|
|
772
939
|
}
|
|
773
|
-
|
|
774
|
-
// src/timing.ts
|
|
775
|
-
var timing_exports = {};
|
|
776
|
-
__export(timing_exports, {
|
|
777
|
-
debounce: () => debounce,
|
|
778
|
-
throttle: () => throttle
|
|
779
|
-
});
|
|
780
|
-
function debounce(fn, wait2, options = {}) {
|
|
781
|
-
let timeoutId;
|
|
782
|
-
const leading = options.immediate ?? false;
|
|
783
|
-
const debounced = function(...args) {
|
|
784
|
-
const callNow = leading && !timeoutId;
|
|
785
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
786
|
-
timeoutId = setTimeout(() => {
|
|
787
|
-
timeoutId = void 0;
|
|
788
|
-
if (!leading) fn.apply(this, args);
|
|
789
|
-
}, wait2);
|
|
790
|
-
if (callNow) fn.apply(this, args);
|
|
791
|
-
};
|
|
792
|
-
debounced.cancel = () => {
|
|
793
|
-
if (timeoutId) {
|
|
794
|
-
clearTimeout(timeoutId);
|
|
795
|
-
timeoutId = void 0;
|
|
796
|
-
}
|
|
797
|
-
};
|
|
798
|
-
return debounced;
|
|
799
|
-
}
|
|
800
|
-
function throttle(fn, limit) {
|
|
801
|
-
let inThrottle = false;
|
|
802
|
-
return function(...args) {
|
|
803
|
-
if (!inThrottle) {
|
|
804
|
-
fn.apply(this, args);
|
|
805
|
-
inThrottle = true;
|
|
806
|
-
setTimeout(() => inThrottle = false, limit);
|
|
807
|
-
}
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
// src/to.ts
|
|
812
|
-
var to_exports = {};
|
|
813
|
-
__export(to_exports, {
|
|
814
|
-
record: () => record
|
|
815
|
-
});
|
|
816
|
-
function record(array, callback) {
|
|
817
|
-
const result = {};
|
|
818
|
-
let lastValue = void 0;
|
|
819
|
-
for (let i = 0; i < array.length; i++) {
|
|
820
|
-
const { key, value } = callback(array[i], {
|
|
821
|
-
index: i,
|
|
822
|
-
lastValue,
|
|
823
|
-
// NOTE: This is a reference to the object currently being built
|
|
824
|
-
newRecord: result,
|
|
825
|
-
originalArray: array
|
|
826
|
-
});
|
|
827
|
-
result[key] = value;
|
|
828
|
-
lastValue = value;
|
|
829
|
-
}
|
|
830
|
-
return result;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
// src/Pipe.ts
|
|
834
|
-
function Pipe(value, ...fns) {
|
|
835
|
-
return fns.reduce((acc, fn) => fn(acc), value);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
// src/Storage.ts
|
|
839
|
-
import fs from "fs";
|
|
840
|
-
import path from "path";
|
|
841
|
-
var Storage = class {
|
|
842
|
-
isNode = typeof window === "undefined";
|
|
843
|
-
filePath = null;
|
|
844
|
-
memoryCache = /* @__PURE__ */ new Map();
|
|
845
|
-
loadFromFile() {
|
|
846
|
-
if (this.filePath && fs.existsSync(this.filePath)) {
|
|
847
|
-
try {
|
|
848
|
-
const data = JSON.parse(fs.readFileSync(this.filePath, "utf-8"));
|
|
849
|
-
Object.entries(data).forEach(([k, v]) => this.memoryCache.set(k, JSON.stringify(v)));
|
|
850
|
-
} catch (err) {
|
|
851
|
-
console.error(`Store: Failed to load file '${this.filePath}'`, err);
|
|
852
|
-
}
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
persist() {
|
|
856
|
-
if (this.isNode && this.filePath) {
|
|
857
|
-
const out = {};
|
|
858
|
-
this.memoryCache.forEach((v, k) => out[k] = JSON.parse(v));
|
|
859
|
-
fs.writeFileSync(this.filePath, JSON.stringify(out, null, 2));
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* A lightweight, high-performant persistent storage system.
|
|
864
|
-
* Uses JSON files in Node.js, localStorage in the browser.
|
|
865
|
-
* @param fileName Only used in Node.js to create a persistent .json file.
|
|
866
|
-
* @param directory The directory for the file. Defaults to current working directory.
|
|
867
|
-
*/
|
|
868
|
-
constructor(fileName, directory = process.cwd()) {
|
|
869
|
-
if (this.isNode && fileName) {
|
|
870
|
-
this.filePath = path.join(directory, fileName.endsWith(".json") ? fileName : `${fileName}.json`);
|
|
871
|
-
this.loadFromFile();
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
has(key) {
|
|
875
|
-
if (!this.isNode && window.localStorage) {
|
|
876
|
-
return localStorage.getItem(key) !== null;
|
|
877
|
-
}
|
|
878
|
-
return this.memoryCache.has(key);
|
|
879
|
-
}
|
|
880
|
-
get(key) {
|
|
881
|
-
let raw = null;
|
|
882
|
-
if (!this.isNode && window.localStorage) {
|
|
883
|
-
raw = localStorage.getItem(key);
|
|
884
|
-
} else {
|
|
885
|
-
raw = this.memoryCache.get(key) || null;
|
|
886
|
-
}
|
|
887
|
-
if (!raw) return null;
|
|
888
|
-
const payload = JSON.parse(raw);
|
|
889
|
-
if (payload.expiry && Date.now() > payload.expiry) {
|
|
890
|
-
this.remove(key);
|
|
891
|
-
this.persist();
|
|
892
|
-
return null;
|
|
893
|
-
}
|
|
894
|
-
return payload.value;
|
|
895
|
-
}
|
|
896
|
-
set(key, value, ttl) {
|
|
897
|
-
const payload = {
|
|
898
|
-
value,
|
|
899
|
-
expiry: ttl ? Date.now() + ttl : null
|
|
900
|
-
};
|
|
901
|
-
const serialized = JSON.stringify(payload);
|
|
902
|
-
if (!this.isNode && window.localStorage) {
|
|
903
|
-
localStorage.setItem(key, serialized);
|
|
904
|
-
} else {
|
|
905
|
-
this.memoryCache.set(key, serialized);
|
|
906
|
-
this.persist();
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
remove(key) {
|
|
910
|
-
if (!this.isNode && window.localStorage) {
|
|
911
|
-
localStorage.removeItem(key);
|
|
912
|
-
} else {
|
|
913
|
-
this.memoryCache.delete(key);
|
|
914
|
-
this.persist();
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
clear() {
|
|
918
|
-
if (!this.isNode && window.localStorage) {
|
|
919
|
-
localStorage.clear();
|
|
920
|
-
} else {
|
|
921
|
-
this.memoryCache.clear();
|
|
922
|
-
this.persist();
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
};
|
|
926
|
-
|
|
927
|
-
// src/Cache.ts
|
|
928
|
-
var Cache = class {
|
|
929
|
-
cache = /* @__PURE__ */ new Map();
|
|
930
|
-
interval;
|
|
931
|
-
/**
|
|
932
|
-
* A lightweight, high-performant in-memory cache.
|
|
933
|
-
* Uses Map for O(1) lookups and an optional cleanup interval.
|
|
934
|
-
* @param cleanupMs The interval in milliseconds to run the cleanup function. [default: 60000 (1 minute)]
|
|
935
|
-
*/
|
|
936
|
-
constructor(cleanupMs = 6e4) {
|
|
937
|
-
if (cleanupMs > 0) {
|
|
938
|
-
this.interval = setInterval(() => this.cleanup(), cleanupMs);
|
|
939
|
-
if (this.interval.unref) this.interval.unref();
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
set(key, value, ttlMs) {
|
|
943
|
-
this.cache.set(key, {
|
|
944
|
-
value,
|
|
945
|
-
expiresAt: ttlMs ? Date.now() + ttlMs : null
|
|
946
|
-
});
|
|
947
|
-
}
|
|
948
|
-
get(key) {
|
|
949
|
-
const data = this.cache.get(key);
|
|
950
|
-
if (!data) return null;
|
|
951
|
-
if (data.expiresAt && Date.now() > data.expiresAt) {
|
|
952
|
-
this.cache.delete(key);
|
|
953
|
-
return null;
|
|
954
|
-
}
|
|
955
|
-
return data.value;
|
|
956
|
-
}
|
|
957
|
-
cleanup() {
|
|
958
|
-
if (this.cache.size === 0) return;
|
|
959
|
-
const now = Date.now();
|
|
960
|
-
let keysProcessed = 0;
|
|
961
|
-
const maxKeysToScan = 20;
|
|
962
|
-
for (const [key, data] of this.cache) {
|
|
963
|
-
if (data.expiresAt && now > data.expiresAt) {
|
|
964
|
-
this.cache.delete(key);
|
|
965
|
-
}
|
|
966
|
-
keysProcessed++;
|
|
967
|
-
if (keysProcessed >= maxKeysToScan) break;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
clear() {
|
|
971
|
-
this.cache.clear();
|
|
972
|
-
}
|
|
973
|
-
};
|
|
974
|
-
|
|
975
|
-
// src/Loop.ts
|
|
976
|
-
import EventEmitter from "events";
|
|
977
|
-
var TypedEmitterBase = EventEmitter;
|
|
978
|
-
var Loop = class extends TypedEmitterBase {
|
|
979
|
-
_state = "stopped";
|
|
980
|
-
timeoutId = null;
|
|
981
|
-
delay;
|
|
982
|
-
fn;
|
|
983
|
-
startTime = 0;
|
|
984
|
-
remaining = 0;
|
|
985
|
-
async run() {
|
|
986
|
-
const currentState = this._state;
|
|
987
|
-
if (currentState === "stopped" || currentState === "paused") return;
|
|
988
|
-
try {
|
|
989
|
-
const result = await this.fn(this);
|
|
990
|
-
this.emit("tick", result);
|
|
991
|
-
} catch (err) {
|
|
992
|
-
this.emit("error", err);
|
|
993
|
-
}
|
|
994
|
-
if (this._state === "running") {
|
|
995
|
-
this.startTime = Date.now();
|
|
996
|
-
this.remaining = 0;
|
|
997
|
-
this.clearTimer();
|
|
998
|
-
this.timeoutId = setTimeout(() => this.run(), this.delay);
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
clearTimer() {
|
|
1002
|
-
if (this.timeoutId) {
|
|
1003
|
-
clearTimeout(this.timeoutId);
|
|
1004
|
-
this.timeoutId = null;
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
/**
|
|
1008
|
-
* Creates an interval. If the function is async, it will wait for it to complete before scheduling the next run.
|
|
1009
|
-
* @param fn The function to run.
|
|
1010
|
-
* @param delay The delay between runs in milliseconds.
|
|
1011
|
-
* @param immediate Whether to start the loop immediately. [default: true]
|
|
1012
|
-
*/
|
|
1013
|
-
constructor(fn, delay, immediate = true) {
|
|
1014
|
-
super();
|
|
1015
|
-
this.fn = fn;
|
|
1016
|
-
this.delay = delay;
|
|
1017
|
-
if (immediate) this.start();
|
|
1018
|
-
}
|
|
1019
|
-
get state() {
|
|
1020
|
-
return this._state;
|
|
1021
|
-
}
|
|
1022
|
-
/** Starts the loop. */
|
|
1023
|
-
start() {
|
|
1024
|
-
if (this._state !== "stopped") return;
|
|
1025
|
-
this._state = "running";
|
|
1026
|
-
this.emit("start");
|
|
1027
|
-
this.run();
|
|
1028
|
-
}
|
|
1029
|
-
/** Resumes a paused loop. */
|
|
1030
|
-
resume() {
|
|
1031
|
-
if (this._state !== "paused") return;
|
|
1032
|
-
this._state = "running";
|
|
1033
|
-
this.emit("resume");
|
|
1034
|
-
if (this.remaining <= 0) {
|
|
1035
|
-
this.run();
|
|
1036
|
-
} else {
|
|
1037
|
-
this.timeoutId = setTimeout(() => this.run(), this.remaining);
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
/** Stops the loop. */
|
|
1041
|
-
stop() {
|
|
1042
|
-
const wasRunning = this._state !== "stopped";
|
|
1043
|
-
this._state = "stopped";
|
|
1044
|
-
this.remaining = 0;
|
|
1045
|
-
this.clearTimer();
|
|
1046
|
-
if (wasRunning) this.emit("stop");
|
|
1047
|
-
}
|
|
1048
|
-
/** Pauses the execution. */
|
|
1049
|
-
pause() {
|
|
1050
|
-
if (this._state !== "running") return;
|
|
1051
|
-
this._state = "paused";
|
|
1052
|
-
const elapsed = Date.now() - this.startTime;
|
|
1053
|
-
this.remaining = Math.max(0, this.delay - elapsed);
|
|
1054
|
-
this.emit("pause", { remaining: this.remaining });
|
|
1055
|
-
this.clearTimer();
|
|
1056
|
-
}
|
|
1057
|
-
/**
|
|
1058
|
-
* Sets the delay between runs
|
|
1059
|
-
* @param ms The new delay in milliseconds.
|
|
1060
|
-
*/
|
|
1061
|
-
setDelay(ms2) {
|
|
1062
|
-
this.delay = ms2;
|
|
1063
|
-
}
|
|
1064
|
-
/** Manually trigger the function once without affecting the loop. */
|
|
1065
|
-
async execute() {
|
|
1066
|
-
await this.fn(this);
|
|
1067
|
-
}
|
|
1068
|
-
};
|
|
1069
|
-
|
|
1070
|
-
// src/index.ts
|
|
1071
|
-
var qznt = {
|
|
1072
|
-
arr: arr_exports,
|
|
1073
|
-
async: async_exports,
|
|
1074
|
-
fn: fn_exports,
|
|
1075
|
-
date: date_exports,
|
|
1076
|
-
format: format_exports,
|
|
1077
|
-
fs: fs_exports,
|
|
1078
|
-
is: is_exports,
|
|
1079
|
-
math: math_exports,
|
|
1080
|
-
obj: obj_exports,
|
|
1081
|
-
timing: timing_exports,
|
|
1082
|
-
rnd: rnd_exports,
|
|
1083
|
-
str: str_exports,
|
|
1084
|
-
to: to_exports,
|
|
1085
|
-
Pipe,
|
|
1086
|
-
Storage,
|
|
1087
|
-
Cache,
|
|
1088
|
-
Loop
|
|
1089
|
-
};
|
|
1090
|
-
var $ = qznt;
|
|
1091
|
-
var index_default = qznt;
|
|
1092
940
|
export {
|
|
1093
|
-
$,
|
|
1094
941
|
Cache,
|
|
942
|
+
FormatNumberCompact,
|
|
1095
943
|
Loop,
|
|
1096
944
|
Pipe,
|
|
1097
945
|
Storage,
|
|
1098
|
-
chance,
|
|
1099
|
-
choice,
|
|
1100
946
|
chunk,
|
|
1101
947
|
chunkAdj,
|
|
1102
|
-
|
|
948
|
+
clampNumber,
|
|
1103
949
|
cluster,
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
currency,
|
|
950
|
+
compactArray,
|
|
951
|
+
createSampler,
|
|
1107
952
|
debounce,
|
|
1108
|
-
index_default as default,
|
|
1109
|
-
defined,
|
|
1110
|
-
duration,
|
|
1111
|
-
empty,
|
|
1112
953
|
escapeRegex,
|
|
1113
|
-
eta,
|
|
1114
|
-
float,
|
|
1115
954
|
forceArray,
|
|
1116
|
-
|
|
955
|
+
formatCurrency,
|
|
956
|
+
formatDuration,
|
|
957
|
+
formatETA,
|
|
958
|
+
formatMemory,
|
|
959
|
+
formatNumber,
|
|
960
|
+
formatOrdinal,
|
|
1117
961
|
getAge,
|
|
1118
962
|
getFlag,
|
|
1119
|
-
|
|
963
|
+
getProp,
|
|
1120
964
|
hasFlag,
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
965
|
+
hasProp,
|
|
966
|
+
inverseLerp,
|
|
967
|
+
isDefined,
|
|
968
|
+
isEmpty,
|
|
969
|
+
isInRange,
|
|
970
|
+
isObject,
|
|
971
|
+
isSortedArray,
|
|
972
|
+
isString,
|
|
973
|
+
isToday,
|
|
1125
974
|
lerp,
|
|
1126
975
|
memoize,
|
|
1127
|
-
memory,
|
|
1128
976
|
merge,
|
|
1129
|
-
|
|
1130
|
-
number,
|
|
1131
|
-
object,
|
|
977
|
+
msToSecs,
|
|
1132
978
|
omit,
|
|
1133
|
-
|
|
1134
|
-
parse,
|
|
979
|
+
parseTime,
|
|
1135
980
|
percent,
|
|
1136
981
|
pick,
|
|
982
|
+
pluralize,
|
|
1137
983
|
prng,
|
|
1138
984
|
readDir,
|
|
1139
|
-
record,
|
|
1140
985
|
remap,
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
986
|
+
retryPromise,
|
|
987
|
+
rndChance,
|
|
988
|
+
rndChoice,
|
|
989
|
+
rndFloat,
|
|
990
|
+
rndIndex,
|
|
991
|
+
rndInt,
|
|
992
|
+
rndString,
|
|
993
|
+
searchSorted,
|
|
994
|
+
secsToMs,
|
|
1145
995
|
seqMap,
|
|
1146
|
-
|
|
996
|
+
setProp,
|
|
1147
997
|
shuffle,
|
|
1148
998
|
sortBy,
|
|
1149
|
-
sorted,
|
|
1150
|
-
str,
|
|
1151
|
-
string,
|
|
1152
999
|
sum,
|
|
1153
1000
|
throttle,
|
|
1154
1001
|
toTitleCase,
|
|
1155
|
-
today,
|
|
1156
1002
|
unique,
|
|
1157
1003
|
wait,
|
|
1158
|
-
|
|
1004
|
+
weightedRnd,
|
|
1159
1005
|
wrap
|
|
1160
1006
|
};
|