@naturalcycles/js-lib 15.100.0 → 15.101.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/dist/asyncManager.js +3 -2
- package/dist/browser/analytics.util.js +3 -2
- package/dist/datetime/localTime.d.ts +21 -0
- package/dist/datetime/localTime.js +29 -2
- package/dist/datetime/time.util.js +4 -1
- package/dist/decorators/createPromiseDecorator.js +2 -1
- package/dist/decorators/debounce.js +7 -6
- package/dist/decorators/logMethod.decorator.js +3 -2
- package/dist/enum.util.js +1 -0
- package/dist/error/tryCatch.js +2 -1
- package/dist/http/fetcher.js +8 -6
- package/dist/object/deepEquals.js +2 -0
- package/dist/promise/pGradualQueue.js +3 -2
- package/dist/promise/pRetry.js +2 -1
- package/package.json +2 -2
- package/src/asyncManager.ts +3 -2
- package/src/browser/analytics.util.ts +3 -2
- package/src/datetime/localDate.ts +2 -0
- package/src/datetime/localTime.ts +34 -2
- package/src/datetime/time.util.ts +2 -0
- package/src/decorators/createPromiseDecorator.ts +2 -1
- package/src/decorators/debounce.ts +7 -6
- package/src/decorators/logMethod.decorator.ts +3 -2
- package/src/enum.util.ts +1 -0
- package/src/error/tryCatch.ts +3 -2
- package/src/http/fetcher.ts +9 -12
- package/src/object/deepEquals.ts +2 -0
- package/src/promise/pGradualQueue.ts +3 -2
- package/src/promise/pRetry.ts +3 -2
package/dist/asyncManager.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from './datetime/localTime.js';
|
|
1
2
|
import { consoleLogger } from './log/commonLogger.js';
|
|
2
3
|
class AsyncManagerImpl {
|
|
3
4
|
logger = consoleLogger;
|
|
@@ -24,7 +25,7 @@ class AsyncManagerImpl {
|
|
|
24
25
|
if (!size)
|
|
25
26
|
return;
|
|
26
27
|
const { logger } = this;
|
|
27
|
-
const started =
|
|
28
|
+
const started = nowUnixMillis();
|
|
28
29
|
if (timeout) {
|
|
29
30
|
const result = await Promise.race([
|
|
30
31
|
Promise.allSettled(this.pendingOps),
|
|
@@ -38,7 +39,7 @@ class AsyncManagerImpl {
|
|
|
38
39
|
else {
|
|
39
40
|
await Promise.allSettled(this.pendingOps);
|
|
40
41
|
}
|
|
41
|
-
logger.log(`AsyncManager.allDone for ${size} op(s) in ${
|
|
42
|
+
logger.log(`AsyncManager.allDone for ${size} op(s) in ${nowUnixMillis() - started} ms`);
|
|
42
43
|
}
|
|
43
44
|
reset() {
|
|
44
45
|
this.pendingOps.clear();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { newDate, nowUnixMillis } from '../datetime/localTime.js';
|
|
1
2
|
import { isServerSide } from '../env.js';
|
|
2
3
|
import { loadScript } from './script.util.js';
|
|
3
4
|
/**
|
|
@@ -10,7 +11,7 @@ export async function loadGTag(gtagId, enabled = true) {
|
|
|
10
11
|
globalThis.gtag ||= function gtag() {
|
|
11
12
|
globalThis.dataLayer.push(arguments);
|
|
12
13
|
};
|
|
13
|
-
globalThis.gtag('js',
|
|
14
|
+
globalThis.gtag('js', newDate());
|
|
14
15
|
globalThis.gtag('config', gtagId);
|
|
15
16
|
if (!enabled)
|
|
16
17
|
return;
|
|
@@ -21,7 +22,7 @@ export async function loadGTM(gtmId, enabled = true) {
|
|
|
21
22
|
return;
|
|
22
23
|
globalThis.dataLayer ||= [];
|
|
23
24
|
globalThis.dataLayer.push({
|
|
24
|
-
'gtm.start':
|
|
25
|
+
'gtm.start': nowUnixMillis(),
|
|
25
26
|
event: 'gtm.js',
|
|
26
27
|
});
|
|
27
28
|
if (!enabled)
|
|
@@ -257,10 +257,14 @@ declare class LocalTimeFactory {
|
|
|
257
257
|
/**
|
|
258
258
|
Convenience function to return current Unix timestamp in seconds.
|
|
259
259
|
Like Date.now(), but in seconds.
|
|
260
|
+
|
|
261
|
+
Import nowUnix function individually in places where importing localTime is too heavy.
|
|
260
262
|
*/
|
|
261
263
|
nowUnix(): UnixTimestamp;
|
|
262
264
|
/**
|
|
263
265
|
Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
|
|
266
|
+
|
|
267
|
+
Import nowUnixMillis function individually in places where importing localTime is too heavy.
|
|
264
268
|
*/
|
|
265
269
|
nowUnixMillis(): UnixTimestampMillis;
|
|
266
270
|
/**
|
|
@@ -331,4 +335,21 @@ interface LocalTimeFn extends LocalTimeFactory {
|
|
|
331
335
|
(d: LocalTimeInput): LocalTime;
|
|
332
336
|
}
|
|
333
337
|
export declare const localTime: LocalTimeFn;
|
|
338
|
+
/**
|
|
339
|
+
* Can be used instead of `oxlint-disable ...` in places where Date is intentionally needed
|
|
340
|
+
*/
|
|
341
|
+
export declare function newDate(): Date;
|
|
342
|
+
/**
|
|
343
|
+
Convenience function to return current Unix timestamp in seconds.
|
|
344
|
+
Like Date.now(), but in seconds.
|
|
345
|
+
|
|
346
|
+
Import nowUnix function individually in places where importing localTime is too heavy.
|
|
347
|
+
*/
|
|
348
|
+
export declare function nowUnix(): UnixTimestamp;
|
|
349
|
+
/**
|
|
350
|
+
Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
|
|
351
|
+
|
|
352
|
+
Import nowUnixMillis function individually in places where importing localTime is too heavy.
|
|
353
|
+
*/
|
|
354
|
+
export declare function nowUnixMillis(): UnixTimestampMillis;
|
|
334
355
|
export {};
|
|
@@ -676,15 +676,19 @@ class LocalTimeFactory {
|
|
|
676
676
|
/**
|
|
677
677
|
Convenience function to return current Unix timestamp in seconds.
|
|
678
678
|
Like Date.now(), but in seconds.
|
|
679
|
+
|
|
680
|
+
Import nowUnix function individually in places where importing localTime is too heavy.
|
|
679
681
|
*/
|
|
680
682
|
nowUnix() {
|
|
681
|
-
return
|
|
683
|
+
return nowUnix();
|
|
682
684
|
}
|
|
683
685
|
/**
|
|
684
686
|
Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
|
|
687
|
+
|
|
688
|
+
Import nowUnixMillis function individually in places where importing localTime is too heavy.
|
|
685
689
|
*/
|
|
686
690
|
nowUnixMillis() {
|
|
687
|
-
return
|
|
691
|
+
return nowUnixMillis();
|
|
688
692
|
}
|
|
689
693
|
/**
|
|
690
694
|
* Create LocalTime from LocalTimeInput.
|
|
@@ -1032,3 +1036,26 @@ export const localTime = localTimeFactory.fromInput.bind(localTimeFactory);
|
|
|
1032
1036
|
// The line below is the blackest of black magic I have ever written in 2024.
|
|
1033
1037
|
// And probably 2023 as well.
|
|
1034
1038
|
Object.setPrototypeOf(localTime, localTimeFactory);
|
|
1039
|
+
/**
|
|
1040
|
+
* Can be used instead of `oxlint-disable ...` in places where Date is intentionally needed
|
|
1041
|
+
*/
|
|
1042
|
+
export function newDate() {
|
|
1043
|
+
return new Date();
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
Convenience function to return current Unix timestamp in seconds.
|
|
1047
|
+
Like Date.now(), but in seconds.
|
|
1048
|
+
|
|
1049
|
+
Import nowUnix function individually in places where importing localTime is too heavy.
|
|
1050
|
+
*/
|
|
1051
|
+
export function nowUnix() {
|
|
1052
|
+
return Math.floor(Date.now() / 1000);
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
|
|
1056
|
+
|
|
1057
|
+
Import nowUnixMillis function individually in places where importing localTime is too heavy.
|
|
1058
|
+
*/
|
|
1059
|
+
export function nowUnixMillis() {
|
|
1060
|
+
return Date.now();
|
|
1061
|
+
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @experimental
|
|
9
9
|
*/
|
|
10
10
|
export function _blockTimer(name) {
|
|
11
|
+
// oxlint-disable-next-line no-restricted-globals -- localTime imports this module, so it can't import localTime back
|
|
11
12
|
const started = Date.now();
|
|
12
13
|
return {
|
|
13
14
|
[Symbol.dispose]() {
|
|
@@ -18,7 +19,9 @@ export function _blockTimer(name) {
|
|
|
18
19
|
/**
|
|
19
20
|
* Returns time passed since `from` until `until` (default to Date.now())
|
|
20
21
|
*/
|
|
21
|
-
export function _since(from,
|
|
22
|
+
export function _since(from,
|
|
23
|
+
// oxlint-disable-next-line no-restricted-globals -- localTime imports this module, so it can't import localTime back
|
|
24
|
+
until = Date.now()) {
|
|
22
25
|
return _ms(until - from);
|
|
23
26
|
}
|
|
24
27
|
/**
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js';
|
|
1
2
|
import { _getTargetMethodSignature } from './decorator.util.js';
|
|
2
3
|
/**
|
|
3
4
|
* @example
|
|
@@ -19,7 +20,7 @@ export function _createPromiseDecorator(cfg, decoratorParams = {}) {
|
|
|
19
20
|
const methodSignature = _getTargetMethodSignature(target, key);
|
|
20
21
|
pd.value = async function (...args) {
|
|
21
22
|
// console.log(`@${cfg.decoratorName} called inside function`)
|
|
22
|
-
const started =
|
|
23
|
+
const started = nowUnixMillis();
|
|
23
24
|
try {
|
|
24
25
|
// Before function
|
|
25
26
|
// console.log(`@${cfg.decoratorName} Before`)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js';
|
|
1
2
|
import { _anyToError } from '../error/error.util.js';
|
|
2
3
|
import { pDefer } from '../promise/pDefer.js';
|
|
3
4
|
export function _debounce(func, wait, opt = {}) {
|
|
@@ -31,7 +32,7 @@ export function _debounce(func, wait, opt = {}) {
|
|
|
31
32
|
return leading ? invokeFunc(time) : result;
|
|
32
33
|
}
|
|
33
34
|
function timerExpired() {
|
|
34
|
-
const time =
|
|
35
|
+
const time = nowUnixMillis();
|
|
35
36
|
if (shouldInvoke(time, state)) {
|
|
36
37
|
trailingEdge(time);
|
|
37
38
|
return;
|
|
@@ -58,13 +59,13 @@ export function _debounce(func, wait, opt = {}) {
|
|
|
58
59
|
lastArgs = lastThis = timerId = undefined;
|
|
59
60
|
}
|
|
60
61
|
function flush() {
|
|
61
|
-
return timerId === undefined ? result : trailingEdge(
|
|
62
|
+
return timerId === undefined ? result : trailingEdge(nowUnixMillis());
|
|
62
63
|
}
|
|
63
64
|
function pending() {
|
|
64
65
|
return timerId !== undefined;
|
|
65
66
|
}
|
|
66
67
|
function debounced(...args) {
|
|
67
|
-
const time =
|
|
68
|
+
const time = nowUnixMillis();
|
|
68
69
|
const isInvoking = shouldInvoke(time, state);
|
|
69
70
|
lastArgs = args;
|
|
70
71
|
lastThis = this;
|
|
@@ -151,7 +152,7 @@ export function _asyncDebounce(func, wait, opt = {}) {
|
|
|
151
152
|
return d;
|
|
152
153
|
}
|
|
153
154
|
function timerExpired() {
|
|
154
|
-
const time =
|
|
155
|
+
const time = nowUnixMillis();
|
|
155
156
|
if (shouldInvoke(time, state)) {
|
|
156
157
|
void trailingEdge(time);
|
|
157
158
|
return;
|
|
@@ -195,14 +196,14 @@ export function _asyncDebounce(func, wait, opt = {}) {
|
|
|
195
196
|
}
|
|
196
197
|
const d = deferred;
|
|
197
198
|
cancelTimer(timerId);
|
|
198
|
-
await trailingEdge(
|
|
199
|
+
await trailingEdge(nowUnixMillis());
|
|
199
200
|
return d;
|
|
200
201
|
}
|
|
201
202
|
function pending() {
|
|
202
203
|
return timerId !== undefined;
|
|
203
204
|
}
|
|
204
205
|
async function debounced(...args) {
|
|
205
|
-
const time =
|
|
206
|
+
const time = nowUnixMillis();
|
|
206
207
|
const isInvoking = shouldInvoke(time, state);
|
|
207
208
|
lastArgs = args;
|
|
208
209
|
lastThis = this;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js';
|
|
1
2
|
import { _ms } from '../datetime/time.util.js';
|
|
2
3
|
import { _assert } from '../error/assert.js';
|
|
3
4
|
import { consoleLogger } from '../log/commonLogger.js';
|
|
@@ -35,7 +36,7 @@ export function _LogMethod(opt = {}) {
|
|
|
35
36
|
const sma = avg ? new SimpleMovingAverage(avg) : undefined;
|
|
36
37
|
let count = 0;
|
|
37
38
|
descriptor.value = function (...args) {
|
|
38
|
-
const started =
|
|
39
|
+
const started = nowUnixMillis();
|
|
39
40
|
const ctx = this;
|
|
40
41
|
// e.g `NameOfYourClass.methodName`
|
|
41
42
|
// or `NameOfYourClass(instanceId).methodName`
|
|
@@ -72,7 +73,7 @@ export function _LogMethod(opt = {}) {
|
|
|
72
73
|
}
|
|
73
74
|
// oxlint-disable-next-line max-params
|
|
74
75
|
function logFinished(logger, callSignature, started, sma, logResultFn, res, err) {
|
|
75
|
-
const millis =
|
|
76
|
+
const millis = nowUnixMillis() - started;
|
|
76
77
|
const t = ['<<', callSignature, 'took', _ms(millis)];
|
|
77
78
|
if (sma) {
|
|
78
79
|
t.push(`(avg ${_ms(sma.pushGetAvg(millis))})`);
|
package/dist/enum.util.js
CHANGED
|
@@ -234,6 +234,7 @@ export function _numberEnumKeyOrUndefined(en, v) {
|
|
|
234
234
|
export function _numberEnumKey(en, v) {
|
|
235
235
|
const key = en[v];
|
|
236
236
|
// This prevents passing a Key (not a Value) of enum here, which returns unexpected result (number, not string)
|
|
237
|
+
// oxlint-disable-next-line unicorn/prefer-type-error
|
|
237
238
|
if (typeof key !== 'string')
|
|
238
239
|
throw new Error(`_numberEnumKey not found for: ${v}`);
|
|
239
240
|
return key;
|
package/dist/error/tryCatch.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js';
|
|
1
2
|
import { _since } from '../datetime/time.util.js';
|
|
2
3
|
import { consoleLogger } from '../log/commonLogger.js';
|
|
3
4
|
import { _anyToError } from './error.util.js';
|
|
@@ -13,7 +14,7 @@ export function _tryCatch(fn, opt = {}) {
|
|
|
13
14
|
const { onError, logError = true, logSuccess = false, logger = consoleLogger } = opt;
|
|
14
15
|
const fname = fn.name || 'anonymous';
|
|
15
16
|
return async function (...args) {
|
|
16
|
-
const started =
|
|
17
|
+
const started = nowUnixMillis();
|
|
17
18
|
try {
|
|
18
19
|
const r = await fn.apply(this, args);
|
|
19
20
|
if (logSuccess) {
|
package/dist/http/fetcher.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
/// <reference lib="dom" preserve="true" />
|
|
3
3
|
/// <reference lib="dom.iterable" preserve="true" />
|
|
4
4
|
import { abortSignalAnyOrUndefined, abortSignalTimeoutOrUndefined } from '../abort.js';
|
|
5
|
+
import { nowUnixMillis } from '../datetime/localTime.js';
|
|
5
6
|
import { _ms, _since } from '../datetime/time.util.js';
|
|
6
7
|
import { isServerSide } from '../env.js';
|
|
7
8
|
import { _assert, _assertErrorClassOrRethrow, _assertIsError } from '../error/assert.js';
|
|
@@ -184,7 +185,7 @@ export class Fetcher {
|
|
|
184
185
|
requestSignature: res.signature,
|
|
185
186
|
requestName: res.req.requestName,
|
|
186
187
|
fetcherName: this.cfg.name,
|
|
187
|
-
requestDuration:
|
|
188
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
188
189
|
});
|
|
189
190
|
}
|
|
190
191
|
const { data } = res.body;
|
|
@@ -314,7 +315,7 @@ export class Fetcher {
|
|
|
314
315
|
signature,
|
|
315
316
|
};
|
|
316
317
|
while (!res.retryStatus.retryStopped) {
|
|
317
|
-
req.started =
|
|
318
|
+
req.started = nowUnixMillis();
|
|
318
319
|
res.body = undefined;
|
|
319
320
|
req.init.signal = abortSignalAnyOrUndefined([
|
|
320
321
|
abortSignalTimeoutOrUndefined(timeoutMillis),
|
|
@@ -532,7 +533,7 @@ export class Fetcher {
|
|
|
532
533
|
requestSignature: res.signature,
|
|
533
534
|
requestName: res.req.requestName,
|
|
534
535
|
fetcherName: this.cfg.name,
|
|
535
|
-
requestDuration:
|
|
536
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
536
537
|
}), {
|
|
537
538
|
cause,
|
|
538
539
|
});
|
|
@@ -609,16 +610,17 @@ export class Fetcher {
|
|
|
609
610
|
if (retryAfterNumber > 10 ** 9) {
|
|
610
611
|
// Value is too large to be a "seconds from now" delay,
|
|
611
612
|
// treat it as a UnixTimestamp instead (e.g GitHub sends `x-ratelimit-reset` like that)
|
|
612
|
-
timeout = retryAfterNumber * 1000 -
|
|
613
|
+
timeout = retryAfterNumber * 1000 - nowUnixMillis();
|
|
613
614
|
}
|
|
614
615
|
else {
|
|
615
616
|
timeout = retryAfterNumber * 1000;
|
|
616
617
|
}
|
|
617
618
|
}
|
|
618
619
|
else {
|
|
620
|
+
// oxlint-disable-next-line no-restricted-globals -- parses an HTTP-date, which localTime doesn't support
|
|
619
621
|
const date = new Date(retryAfterStr);
|
|
620
622
|
if (!Number.isNaN(date.getTime())) {
|
|
621
|
-
timeout = date.getTime() -
|
|
623
|
+
timeout = date.getTime() - nowUnixMillis();
|
|
622
624
|
}
|
|
623
625
|
}
|
|
624
626
|
this.cfg.logger.log(`retry-after: ${retryAfterStr}`);
|
|
@@ -778,7 +780,7 @@ export class Fetcher {
|
|
|
778
780
|
'fetchFn',
|
|
779
781
|
'overrideFetchFn',
|
|
780
782
|
]),
|
|
781
|
-
started:
|
|
783
|
+
started: nowUnixMillis(),
|
|
782
784
|
..._omit(opt, ['method', 'headers', 'credentials']),
|
|
783
785
|
inputUrl: opt.url || '',
|
|
784
786
|
fullUrl: opt.url || '',
|
|
@@ -115,6 +115,7 @@ export function _deepJsonEquals(a, b) {
|
|
|
115
115
|
a = undefined;
|
|
116
116
|
}
|
|
117
117
|
else if (a && typeof a === 'object') {
|
|
118
|
+
// oxlint-disable-next-line no-restricted-globals -- Date instances are compared by value
|
|
118
119
|
if (a instanceof Date) {
|
|
119
120
|
;
|
|
120
121
|
a = a.valueOf();
|
|
@@ -132,6 +133,7 @@ export function _deepJsonEquals(a, b) {
|
|
|
132
133
|
b = undefined;
|
|
133
134
|
}
|
|
134
135
|
else if (b && typeof b === 'object') {
|
|
136
|
+
// oxlint-disable-next-line no-restricted-globals -- Date instances are compared by value
|
|
135
137
|
if (b instanceof Date) {
|
|
136
138
|
;
|
|
137
139
|
b = b.valueOf();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js';
|
|
1
2
|
import { ErrorMode } from '../error/errorMode.js';
|
|
2
3
|
import { createCommonLoggerAtLevel } from '../log/commonLogger.js';
|
|
3
4
|
import { pDefer } from './pDefer.js';
|
|
@@ -34,7 +35,7 @@ export class PGradualQueue {
|
|
|
34
35
|
// Fast-path: warmup complete
|
|
35
36
|
if (this.warmupComplete)
|
|
36
37
|
return this.cfg.concurrency;
|
|
37
|
-
const elapsed =
|
|
38
|
+
const elapsed = nowUnixMillis() - this.startTime;
|
|
38
39
|
if (elapsed >= this.warmupMs) {
|
|
39
40
|
this.warmupComplete = true;
|
|
40
41
|
this.logger.debug('warmup complete');
|
|
@@ -51,7 +52,7 @@ export class PGradualQueue {
|
|
|
51
52
|
async push(fn) {
|
|
52
53
|
// Initialize start time on first push
|
|
53
54
|
if (this.startTime === 0) {
|
|
54
|
-
this.startTime =
|
|
55
|
+
this.startTime = nowUnixMillis();
|
|
55
56
|
}
|
|
56
57
|
const job = { fn, defer: pDefer() };
|
|
57
58
|
const concurrency = this.getCurrentConcurrency();
|
package/dist/promise/pRetry.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js';
|
|
1
2
|
import { _since } from '../datetime/time.util.js';
|
|
2
3
|
import { _errorDataAppend } from '../error/error.util.js';
|
|
3
4
|
import { consoleLogger } from '../log/commonLogger.js';
|
|
@@ -26,7 +27,7 @@ export async function pRetry(fn, opt = {}) {
|
|
|
26
27
|
let delay = initialDelay;
|
|
27
28
|
let attempt = 0;
|
|
28
29
|
while (true) {
|
|
29
|
-
const started =
|
|
30
|
+
const started = nowUnixMillis();
|
|
30
31
|
try {
|
|
31
32
|
attempt++;
|
|
32
33
|
if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/js-lib",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "15.
|
|
4
|
+
"version": "15.101.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"tslib": "^2"
|
|
7
7
|
},
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@naturalcycles/dev-lib": "20.
|
|
17
|
+
"@naturalcycles/dev-lib": "20.71.0",
|
|
18
18
|
"@types/node": "^26",
|
|
19
19
|
"@types/semver": "^7",
|
|
20
20
|
"typescript": "^7",
|
package/src/asyncManager.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from './datetime/localTime.js'
|
|
1
2
|
import { consoleLogger } from './log/commonLogger.js'
|
|
2
3
|
import type { CommonLogger } from './log/commonLogger.js'
|
|
3
4
|
import type { NumberOfMilliseconds } from './types.js'
|
|
@@ -32,7 +33,7 @@ class AsyncManagerImpl {
|
|
|
32
33
|
if (!size) return
|
|
33
34
|
const { logger } = this
|
|
34
35
|
|
|
35
|
-
const started =
|
|
36
|
+
const started = nowUnixMillis()
|
|
36
37
|
if (timeout) {
|
|
37
38
|
const result = await Promise.race([
|
|
38
39
|
Promise.allSettled(this.pendingOps),
|
|
@@ -47,7 +48,7 @@ class AsyncManagerImpl {
|
|
|
47
48
|
} else {
|
|
48
49
|
await Promise.allSettled(this.pendingOps)
|
|
49
50
|
}
|
|
50
|
-
logger.log(`AsyncManager.allDone for ${size} op(s) in ${
|
|
51
|
+
logger.log(`AsyncManager.allDone for ${size} op(s) in ${nowUnixMillis() - started} ms`)
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
reset(): void {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { newDate, nowUnixMillis } from '../datetime/localTime.js'
|
|
1
2
|
import { isServerSide } from '../env.js'
|
|
2
3
|
import { loadScript } from './script.util.js'
|
|
3
4
|
|
|
@@ -17,7 +18,7 @@ export async function loadGTag(gtagId: string, enabled = true): Promise<void> {
|
|
|
17
18
|
globalThis.gtag ||= function gtag() {
|
|
18
19
|
globalThis.dataLayer.push(arguments)
|
|
19
20
|
}
|
|
20
|
-
globalThis.gtag('js',
|
|
21
|
+
globalThis.gtag('js', newDate())
|
|
21
22
|
globalThis.gtag('config', gtagId)
|
|
22
23
|
|
|
23
24
|
if (!enabled) return
|
|
@@ -30,7 +31,7 @@ export async function loadGTM(gtmId: string, enabled = true): Promise<void> {
|
|
|
30
31
|
|
|
31
32
|
globalThis.dataLayer ||= []
|
|
32
33
|
globalThis.dataLayer.push({
|
|
33
|
-
'gtm.start':
|
|
34
|
+
'gtm.start': nowUnixMillis(),
|
|
34
35
|
event: 'gtm.js',
|
|
35
36
|
})
|
|
36
37
|
|
|
@@ -14,6 +14,8 @@ import type {
|
|
|
14
14
|
import type { DateObject, ISODayOfWeek, LocalTime } from './localTime.js'
|
|
15
15
|
import { localTime, VALID_DAYS_OF_WEEK } from './localTime.js'
|
|
16
16
|
|
|
17
|
+
// oxlint-disable no-restricted-globals -- LocalDate wraps the native Date
|
|
18
|
+
|
|
17
19
|
export type LocalDateUnit = LocalDateUnitStrict | 'week'
|
|
18
20
|
export type LocalDateUnitStrict = 'year' | 'month' | 'day'
|
|
19
21
|
|
|
@@ -21,6 +21,8 @@ import { _ms } from './time.util.js'
|
|
|
21
21
|
// oxlint-disable-next-line import/no-cycle -- intentional cycle
|
|
22
22
|
import { WallTime } from './wallTime.js'
|
|
23
23
|
|
|
24
|
+
// oxlint-disable no-restricted-globals -- LocalTime wraps the native Date
|
|
25
|
+
|
|
24
26
|
export type LocalTimeUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second'
|
|
25
27
|
|
|
26
28
|
export enum ISODayOfWeek {
|
|
@@ -814,16 +816,20 @@ class LocalTimeFactory {
|
|
|
814
816
|
/**
|
|
815
817
|
Convenience function to return current Unix timestamp in seconds.
|
|
816
818
|
Like Date.now(), but in seconds.
|
|
819
|
+
|
|
820
|
+
Import nowUnix function individually in places where importing localTime is too heavy.
|
|
817
821
|
*/
|
|
818
822
|
nowUnix(): UnixTimestamp {
|
|
819
|
-
return
|
|
823
|
+
return nowUnix()
|
|
820
824
|
}
|
|
821
825
|
|
|
822
826
|
/**
|
|
823
827
|
Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
|
|
828
|
+
|
|
829
|
+
Import nowUnixMillis function individually in places where importing localTime is too heavy.
|
|
824
830
|
*/
|
|
825
831
|
nowUnixMillis(): UnixTimestampMillis {
|
|
826
|
-
return
|
|
832
|
+
return nowUnixMillis()
|
|
827
833
|
}
|
|
828
834
|
|
|
829
835
|
/**
|
|
@@ -1213,3 +1219,29 @@ export const localTime = localTimeFactory.fromInput.bind(localTimeFactory) as Lo
|
|
|
1213
1219
|
// The line below is the blackest of black magic I have ever written in 2024.
|
|
1214
1220
|
// And probably 2023 as well.
|
|
1215
1221
|
Object.setPrototypeOf(localTime, localTimeFactory)
|
|
1222
|
+
|
|
1223
|
+
/**
|
|
1224
|
+
* Can be used instead of `oxlint-disable ...` in places where Date is intentionally needed
|
|
1225
|
+
*/
|
|
1226
|
+
export function newDate(): Date {
|
|
1227
|
+
return new Date()
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
/**
|
|
1231
|
+
Convenience function to return current Unix timestamp in seconds.
|
|
1232
|
+
Like Date.now(), but in seconds.
|
|
1233
|
+
|
|
1234
|
+
Import nowUnix function individually in places where importing localTime is too heavy.
|
|
1235
|
+
*/
|
|
1236
|
+
export function nowUnix(): UnixTimestamp {
|
|
1237
|
+
return Math.floor(Date.now() / 1000) as UnixTimestamp
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
/**
|
|
1241
|
+
Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
|
|
1242
|
+
|
|
1243
|
+
Import nowUnixMillis function individually in places where importing localTime is too heavy.
|
|
1244
|
+
*/
|
|
1245
|
+
export function nowUnixMillis(): UnixTimestampMillis {
|
|
1246
|
+
return Date.now() as UnixTimestampMillis
|
|
1247
|
+
}
|
|
@@ -10,6 +10,7 @@ import type { NumberOfMilliseconds, UnixTimestampMillis } from '../types.js'
|
|
|
10
10
|
* @experimental
|
|
11
11
|
*/
|
|
12
12
|
export function _blockTimer(name?: string): Disposable {
|
|
13
|
+
// oxlint-disable-next-line no-restricted-globals -- localTime imports this module, so it can't import localTime back
|
|
13
14
|
const started = Date.now() as UnixTimestampMillis
|
|
14
15
|
return {
|
|
15
16
|
[Symbol.dispose](): void {
|
|
@@ -23,6 +24,7 @@ export function _blockTimer(name?: string): Disposable {
|
|
|
23
24
|
*/
|
|
24
25
|
export function _since(
|
|
25
26
|
from: UnixTimestampMillis,
|
|
27
|
+
// oxlint-disable-next-line no-restricted-globals -- localTime imports this module, so it can't import localTime back
|
|
26
28
|
until: UnixTimestampMillis = Date.now() as UnixTimestampMillis,
|
|
27
29
|
): string {
|
|
28
30
|
return _ms(until - from)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js'
|
|
1
2
|
import { _getTargetMethodSignature } from './decorator.util.js'
|
|
2
3
|
|
|
3
4
|
export interface PromiseDecoratorCfg<RES = any, PARAMS = any> {
|
|
@@ -72,7 +73,7 @@ export function _createPromiseDecorator<RES = any, PARAMS = any>(
|
|
|
72
73
|
|
|
73
74
|
pd.value = async function (this: typeof target, ...args: any[]): Promise<any> {
|
|
74
75
|
// console.log(`@${cfg.decoratorName} called inside function`)
|
|
75
|
-
const started =
|
|
76
|
+
const started = nowUnixMillis()
|
|
76
77
|
|
|
77
78
|
try {
|
|
78
79
|
// Before function
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js'
|
|
1
2
|
import { _anyToError } from '../error/error.util.js'
|
|
2
3
|
import { pDefer } from '../promise/pDefer.js'
|
|
3
4
|
import type { DeferredPromise } from '../promise/pDefer.js'
|
|
@@ -43,7 +44,7 @@ export function _debounce<T extends AnyFunction>(
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
function timerExpired(): void {
|
|
46
|
-
const time =
|
|
47
|
+
const time = nowUnixMillis()
|
|
47
48
|
if (shouldInvoke(time, state)) {
|
|
48
49
|
trailingEdge(time)
|
|
49
50
|
return
|
|
@@ -74,7 +75,7 @@ export function _debounce<T extends AnyFunction>(
|
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
function flush(): ReturnType<T> {
|
|
77
|
-
return timerId === undefined ? result : trailingEdge(
|
|
78
|
+
return timerId === undefined ? result : trailingEdge(nowUnixMillis())
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
function pending(): boolean {
|
|
@@ -82,7 +83,7 @@ export function _debounce<T extends AnyFunction>(
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
function debounced(this: ThisParameterType<T>, ...args: Parameters<T>): ReturnType<T> {
|
|
85
|
-
const time =
|
|
86
|
+
const time = nowUnixMillis()
|
|
86
87
|
const isInvoking = shouldInvoke(time, state)
|
|
87
88
|
|
|
88
89
|
lastArgs = args
|
|
@@ -189,7 +190,7 @@ export function _asyncDebounce<T extends AnyAsyncFunction>(
|
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
function timerExpired(): void {
|
|
192
|
-
const time =
|
|
193
|
+
const time = nowUnixMillis()
|
|
193
194
|
if (shouldInvoke(time, state)) {
|
|
194
195
|
void trailingEdge(time)
|
|
195
196
|
return
|
|
@@ -237,7 +238,7 @@ export function _asyncDebounce<T extends AnyAsyncFunction>(
|
|
|
237
238
|
}
|
|
238
239
|
const d = deferred
|
|
239
240
|
cancelTimer(timerId)
|
|
240
|
-
await trailingEdge(
|
|
241
|
+
await trailingEdge(nowUnixMillis())
|
|
241
242
|
return d
|
|
242
243
|
}
|
|
243
244
|
|
|
@@ -249,7 +250,7 @@ export function _asyncDebounce<T extends AnyAsyncFunction>(
|
|
|
249
250
|
this: ThisParameterType<T>,
|
|
250
251
|
...args: Parameters<T>
|
|
251
252
|
): Promise<Awaited<ReturnType<T>> | undefined> {
|
|
252
|
-
const time =
|
|
253
|
+
const time = nowUnixMillis()
|
|
253
254
|
const isInvoking = shouldInvoke(time, state)
|
|
254
255
|
|
|
255
256
|
lastArgs = args
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js'
|
|
1
2
|
import { _ms } from '../datetime/time.util.js'
|
|
2
3
|
import { _assert } from '../error/assert.js'
|
|
3
4
|
import { consoleLogger } from '../log/commonLogger.js'
|
|
@@ -100,7 +101,7 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
|
100
101
|
let count = 0
|
|
101
102
|
|
|
102
103
|
descriptor.value = function (this: typeof _target, ...args: any[]) {
|
|
103
|
-
const started =
|
|
104
|
+
const started = nowUnixMillis()
|
|
104
105
|
const ctx = this
|
|
105
106
|
|
|
106
107
|
// e.g `NameOfYourClass.methodName`
|
|
@@ -148,7 +149,7 @@ function logFinished(
|
|
|
148
149
|
res?: any,
|
|
149
150
|
err?: any,
|
|
150
151
|
): void {
|
|
151
|
-
const millis =
|
|
152
|
+
const millis = nowUnixMillis() - started
|
|
152
153
|
|
|
153
154
|
const t = ['<<', callSignature, 'took', _ms(millis)]
|
|
154
155
|
|
package/src/enum.util.ts
CHANGED
|
@@ -284,6 +284,7 @@ export function _numberEnumKey<T extends NumberEnum>(
|
|
|
284
284
|
): keyof T {
|
|
285
285
|
const key = (en as any)[v]
|
|
286
286
|
// This prevents passing a Key (not a Value) of enum here, which returns unexpected result (number, not string)
|
|
287
|
+
// oxlint-disable-next-line unicorn/prefer-type-error
|
|
287
288
|
if (typeof key !== 'string') throw new Error(`_numberEnumKey not found for: ${v}`)
|
|
288
289
|
return key
|
|
289
290
|
}
|
package/src/error/tryCatch.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js'
|
|
1
2
|
import { _since } from '../datetime/time.util.js'
|
|
2
3
|
import { consoleLogger } from '../log/commonLogger.js'
|
|
3
4
|
import type { CommonLogger } from '../log/commonLogger.js'
|
|
4
|
-
import type { AnyFunction
|
|
5
|
+
import type { AnyFunction } from '../types.js'
|
|
5
6
|
import { _anyToError } from './error.util.js'
|
|
6
7
|
|
|
7
8
|
export interface TryCatchOptions {
|
|
@@ -41,7 +42,7 @@ export function _tryCatch<T extends AnyFunction>(fn: T, opt: TryCatchOptions = {
|
|
|
41
42
|
const fname = fn.name || 'anonymous'
|
|
42
43
|
|
|
43
44
|
return async function (this: any, ...args: any[]) {
|
|
44
|
-
const started =
|
|
45
|
+
const started = nowUnixMillis()
|
|
45
46
|
|
|
46
47
|
try {
|
|
47
48
|
const r = await fn.apply(this, args)
|
package/src/http/fetcher.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import type { ReadableStream as WebReadableStream } from 'node:stream/web'
|
|
6
6
|
import { abortSignalAnyOrUndefined, abortSignalTimeoutOrUndefined } from '../abort.js'
|
|
7
|
+
import { nowUnixMillis } from '../datetime/localTime.js'
|
|
7
8
|
import { _ms, _since } from '../datetime/time.util.js'
|
|
8
9
|
import { isServerSide } from '../env.js'
|
|
9
10
|
import { _assert, _assertErrorClassOrRethrow, _assertIsError } from '../error/assert.js'
|
|
@@ -31,12 +32,7 @@ import { pDelaySignal } from '../promise/pDelay.js'
|
|
|
31
32
|
import { pTimeout } from '../promise/pTimeout.js'
|
|
32
33
|
import { _toUrlOrNull } from '../string/index.js'
|
|
33
34
|
import { _jsonParse, _jsonParseIfPossible } from '../string/json.util.js'
|
|
34
|
-
import type {
|
|
35
|
-
AnyObject,
|
|
36
|
-
ErrorDataTuple,
|
|
37
|
-
NumberOfMilliseconds,
|
|
38
|
-
UnixTimestampMillis,
|
|
39
|
-
} from '../types.js'
|
|
35
|
+
import type { AnyObject, ErrorDataTuple, NumberOfMilliseconds } from '../types.js'
|
|
40
36
|
import type {
|
|
41
37
|
FetcherAfterResponseHook,
|
|
42
38
|
FetcherBeforeRequestHook,
|
|
@@ -250,7 +246,7 @@ export class Fetcher {
|
|
|
250
246
|
requestSignature: res.signature,
|
|
251
247
|
requestName: res.req.requestName,
|
|
252
248
|
fetcherName: this.cfg.name,
|
|
253
|
-
requestDuration:
|
|
249
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
254
250
|
})
|
|
255
251
|
}
|
|
256
252
|
|
|
@@ -400,7 +396,7 @@ export class Fetcher {
|
|
|
400
396
|
} as FetcherResponse<any>
|
|
401
397
|
|
|
402
398
|
while (!res.retryStatus.retryStopped) {
|
|
403
|
-
req.started =
|
|
399
|
+
req.started = nowUnixMillis()
|
|
404
400
|
res.body = undefined
|
|
405
401
|
|
|
406
402
|
req.init.signal = abortSignalAnyOrUndefined([
|
|
@@ -653,7 +649,7 @@ export class Fetcher {
|
|
|
653
649
|
requestSignature: res.signature,
|
|
654
650
|
requestName: res.req.requestName,
|
|
655
651
|
fetcherName: this.cfg.name,
|
|
656
|
-
requestDuration:
|
|
652
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
657
653
|
}),
|
|
658
654
|
{
|
|
659
655
|
cause,
|
|
@@ -746,14 +742,15 @@ export class Fetcher {
|
|
|
746
742
|
if (retryAfterNumber > 10 ** 9) {
|
|
747
743
|
// Value is too large to be a "seconds from now" delay,
|
|
748
744
|
// treat it as a UnixTimestamp instead (e.g GitHub sends `x-ratelimit-reset` like that)
|
|
749
|
-
timeout = retryAfterNumber * 1000 -
|
|
745
|
+
timeout = retryAfterNumber * 1000 - nowUnixMillis()
|
|
750
746
|
} else {
|
|
751
747
|
timeout = retryAfterNumber * 1000
|
|
752
748
|
}
|
|
753
749
|
} else {
|
|
750
|
+
// oxlint-disable-next-line no-restricted-globals -- parses an HTTP-date, which localTime doesn't support
|
|
754
751
|
const date = new Date(retryAfterStr)
|
|
755
752
|
if (!Number.isNaN(date.getTime())) {
|
|
756
|
-
timeout = date.getTime() -
|
|
753
|
+
timeout = date.getTime() - nowUnixMillis()
|
|
757
754
|
}
|
|
758
755
|
}
|
|
759
756
|
|
|
@@ -928,7 +925,7 @@ export class Fetcher {
|
|
|
928
925
|
'fetchFn',
|
|
929
926
|
'overrideFetchFn',
|
|
930
927
|
]),
|
|
931
|
-
started:
|
|
928
|
+
started: nowUnixMillis(),
|
|
932
929
|
..._omit(opt, ['method', 'headers', 'credentials']),
|
|
933
930
|
inputUrl: opt.url || '',
|
|
934
931
|
fullUrl: opt.url || '',
|
package/src/object/deepEquals.ts
CHANGED
|
@@ -112,6 +112,7 @@ export function _deepJsonEquals<T>(a: T, b: T): boolean {
|
|
|
112
112
|
} else if (typeof a === 'function') {
|
|
113
113
|
;(a as any) = undefined
|
|
114
114
|
} else if (a && typeof a === 'object') {
|
|
115
|
+
// oxlint-disable-next-line no-restricted-globals -- Date instances are compared by value
|
|
115
116
|
if (a instanceof Date) {
|
|
116
117
|
;(a as any) = a.valueOf()
|
|
117
118
|
} else if ('toJSON' in a) {
|
|
@@ -123,6 +124,7 @@ export function _deepJsonEquals<T>(a: T, b: T): boolean {
|
|
|
123
124
|
} else if (typeof b === 'function') {
|
|
124
125
|
;(b as any) = undefined
|
|
125
126
|
} else if (b && typeof b === 'object') {
|
|
127
|
+
// oxlint-disable-next-line no-restricted-globals -- Date instances are compared by value
|
|
126
128
|
if (b instanceof Date) {
|
|
127
129
|
;(b as any) = b.valueOf()
|
|
128
130
|
} else if ('toJSON' in b) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js'
|
|
1
2
|
import { ErrorMode } from '../error/errorMode.js'
|
|
2
3
|
import { createCommonLoggerAtLevel } from '../log/commonLogger.js'
|
|
3
4
|
import type { CommonLogger, CommonLogLevel } from '../log/commonLogger.js'
|
|
@@ -73,7 +74,7 @@ export class PGradualQueue {
|
|
|
73
74
|
// Fast-path: warmup complete
|
|
74
75
|
if (this.warmupComplete) return this.cfg.concurrency
|
|
75
76
|
|
|
76
|
-
const elapsed =
|
|
77
|
+
const elapsed = nowUnixMillis() - this.startTime
|
|
77
78
|
if (elapsed >= this.warmupMs) {
|
|
78
79
|
this.warmupComplete = true
|
|
79
80
|
this.logger.debug('warmup complete')
|
|
@@ -92,7 +93,7 @@ export class PGradualQueue {
|
|
|
92
93
|
async push<R>(fn: AsyncFunction<R>): Promise<R> {
|
|
93
94
|
// Initialize start time on first push
|
|
94
95
|
if (this.startTime === 0) {
|
|
95
|
-
this.startTime =
|
|
96
|
+
this.startTime = nowUnixMillis()
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
const job: PGradualQueueJob<R> = { fn, defer: pDefer<R>() }
|
package/src/promise/pRetry.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/localTime.js'
|
|
1
2
|
import { _since } from '../datetime/time.util.js'
|
|
2
3
|
import type { ErrorData } from '../error/error.model.js'
|
|
3
4
|
import { _errorDataAppend } from '../error/error.util.js'
|
|
4
5
|
import { consoleLogger } from '../log/commonLogger.js'
|
|
5
6
|
import type { CommonLogger } from '../log/commonLogger.js'
|
|
6
|
-
import type { AnyAsyncFunction
|
|
7
|
+
import type { AnyAsyncFunction } from '../types.js'
|
|
7
8
|
import { pDelay } from './pDelay.js'
|
|
8
9
|
import { pTimeout } from './pTimeout.js'
|
|
9
10
|
|
|
@@ -141,7 +142,7 @@ export async function pRetry<T>(
|
|
|
141
142
|
let attempt = 0
|
|
142
143
|
|
|
143
144
|
while (true) {
|
|
144
|
-
const started =
|
|
145
|
+
const started = nowUnixMillis()
|
|
145
146
|
|
|
146
147
|
try {
|
|
147
148
|
attempt++
|