@naturalcycles/js-lib 15.99.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/array/array.util.js +5 -10
- package/dist/array/array2.js +3 -4
- 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/assert.js +2 -0
- package/dist/error/tryCatch.js +2 -1
- package/dist/http/fetcher.js +11 -11
- package/dist/object/deepEquals.js +2 -0
- package/dist/object/set2.js +2 -2
- package/dist/promise/pGradualQueue.js +3 -2
- package/dist/promise/pRetry.js +2 -1
- package/package.json +2 -2
- package/src/array/array.util.ts +5 -5
- package/src/array/array2.ts +3 -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/assert.ts +2 -0
- package/src/error/tryCatch.ts +3 -2
- package/src/http/fetcher.ts +12 -17
- package/src/object/deepEquals.ts +2 -0
- package/src/object/set2.ts +3 -1
- package/src/promise/pGradualQueue.ts +3 -2
- package/src/promise/pRetry.ts +3 -2
package/dist/array/array.util.js
CHANGED
|
@@ -369,8 +369,7 @@ export function _shuffle(array, opt = {}) {
|
|
|
369
369
|
return a;
|
|
370
370
|
}
|
|
371
371
|
export function _firstLast(array) {
|
|
372
|
-
|
|
373
|
-
throw new Error('_firstLast called on empty array');
|
|
372
|
+
_assert(array.length, '_firstLast called on empty array');
|
|
374
373
|
return [array[0], array[array.length - 1]];
|
|
375
374
|
}
|
|
376
375
|
export function _firstLastOrUndefined(array) {
|
|
@@ -383,8 +382,7 @@ export function _firstLastOrUndefined(array) {
|
|
|
383
382
|
* Throws if array is empty.
|
|
384
383
|
*/
|
|
385
384
|
export function _last(array) {
|
|
386
|
-
|
|
387
|
-
throw new Error('_last called on empty array');
|
|
385
|
+
_assert(array.length, '_last called on empty array');
|
|
388
386
|
return array[array.length - 1];
|
|
389
387
|
}
|
|
390
388
|
/**
|
|
@@ -398,8 +396,7 @@ export function _lastOrUndefined(array) {
|
|
|
398
396
|
* Throws if array is empty.
|
|
399
397
|
*/
|
|
400
398
|
export function _first(array) {
|
|
401
|
-
|
|
402
|
-
throw new Error('_first called on empty array');
|
|
399
|
+
_assert(array.length, '_first called on empty array');
|
|
403
400
|
return array[0];
|
|
404
401
|
}
|
|
405
402
|
/**
|
|
@@ -482,8 +479,7 @@ export function _minBy(array, mapper) {
|
|
|
482
479
|
return min;
|
|
483
480
|
}
|
|
484
481
|
export function _minMax(array) {
|
|
485
|
-
|
|
486
|
-
throw new Error('_minMax called on empty array');
|
|
482
|
+
_assert(array.length, '_minMax called on empty array');
|
|
487
483
|
const result = _minMaxOrUndefined(array);
|
|
488
484
|
_assert(result !== undefined, '_minBy returned undefined');
|
|
489
485
|
return result;
|
|
@@ -510,8 +506,7 @@ export function _minMaxOrUndefined(array) {
|
|
|
510
506
|
return [min, max];
|
|
511
507
|
}
|
|
512
508
|
export function _minMaxBy(array, mapper) {
|
|
513
|
-
|
|
514
|
-
throw new Error('_minMaxBy called on empty array');
|
|
509
|
+
_assert(array.length, '_minMaxBy called on empty array');
|
|
515
510
|
const result = _minMaxByOrUndefined(array, mapper);
|
|
516
511
|
_assert(result !== undefined, '_minMaxBy returned undefined');
|
|
517
512
|
return result;
|
package/dist/array/array2.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { _assert } from '../error/assert.js';
|
|
1
2
|
import { _shuffle } from './array.util.js';
|
|
2
3
|
/**
|
|
3
4
|
* Better Array.
|
|
@@ -16,8 +17,7 @@ export class Array2 extends Array {
|
|
|
16
17
|
return this[0];
|
|
17
18
|
}
|
|
18
19
|
first() {
|
|
19
|
-
|
|
20
|
-
throw new Error('Array.first called on empty array');
|
|
20
|
+
_assert(this.length, 'Array.first called on empty array');
|
|
21
21
|
return this[0];
|
|
22
22
|
}
|
|
23
23
|
lastOrUndefined() {
|
|
@@ -25,8 +25,7 @@ export class Array2 extends Array {
|
|
|
25
25
|
}
|
|
26
26
|
last() {
|
|
27
27
|
const { length } = this;
|
|
28
|
-
|
|
29
|
-
throw new Error('Array.last called on empty array');
|
|
28
|
+
_assert(length, 'Array.last called on empty array');
|
|
30
29
|
return this[length - 1];
|
|
31
30
|
}
|
|
32
31
|
uniq() {
|
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/assert.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// `_assert` and friends are implemented by throwing in an if
|
|
2
|
+
// oxlint-disable nc/prefer-assert
|
|
1
3
|
import { _deepEquals } from '../object/deepEquals.js';
|
|
2
4
|
import { _stringify } from '../string/stringify.js';
|
|
3
5
|
import { _isBackendErrorResponseObject, _isErrorObject, AssertionError } from './error.util.js';
|
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,9 +2,10 @@
|
|
|
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
|
-
import { _assertErrorClassOrRethrow, _assertIsError } from '../error/assert.js';
|
|
8
|
+
import { _assert, _assertErrorClassOrRethrow, _assertIsError } from '../error/assert.js';
|
|
8
9
|
import { _anyToError, _anyToErrorObject, _errorDataAppend, _errorLikeToErrorObject, HttpRequestError, UnexpectedPassError, } from '../error/error.util.js';
|
|
9
10
|
import { consoleLogger } from '../log/commonLogger.js';
|
|
10
11
|
import { _clamp } from '../number/number.util.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),
|
|
@@ -454,10 +455,8 @@ export class Fetcher {
|
|
|
454
455
|
}
|
|
455
456
|
else if (responseType === 'readableStream') {
|
|
456
457
|
res.body = res.fetchResponse.body;
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
throw new Error('fetchResponse.body is null');
|
|
460
|
-
}
|
|
458
|
+
// Error is to be handled upstream
|
|
459
|
+
_assert(res.body !== null, 'fetchResponse.body is null');
|
|
461
460
|
}
|
|
462
461
|
res.retryStatus.retryStopped = true;
|
|
463
462
|
if (req.logResponse) {
|
|
@@ -534,7 +533,7 @@ export class Fetcher {
|
|
|
534
533
|
requestSignature: res.signature,
|
|
535
534
|
requestName: res.req.requestName,
|
|
536
535
|
fetcherName: this.cfg.name,
|
|
537
|
-
requestDuration:
|
|
536
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
538
537
|
}), {
|
|
539
538
|
cause,
|
|
540
539
|
});
|
|
@@ -611,16 +610,17 @@ export class Fetcher {
|
|
|
611
610
|
if (retryAfterNumber > 10 ** 9) {
|
|
612
611
|
// Value is too large to be a "seconds from now" delay,
|
|
613
612
|
// treat it as a UnixTimestamp instead (e.g GitHub sends `x-ratelimit-reset` like that)
|
|
614
|
-
timeout = retryAfterNumber * 1000 -
|
|
613
|
+
timeout = retryAfterNumber * 1000 - nowUnixMillis();
|
|
615
614
|
}
|
|
616
615
|
else {
|
|
617
616
|
timeout = retryAfterNumber * 1000;
|
|
618
617
|
}
|
|
619
618
|
}
|
|
620
619
|
else {
|
|
620
|
+
// oxlint-disable-next-line no-restricted-globals -- parses an HTTP-date, which localTime doesn't support
|
|
621
621
|
const date = new Date(retryAfterStr);
|
|
622
622
|
if (!Number.isNaN(date.getTime())) {
|
|
623
|
-
timeout = date.getTime() -
|
|
623
|
+
timeout = date.getTime() - nowUnixMillis();
|
|
624
624
|
}
|
|
625
625
|
}
|
|
626
626
|
this.cfg.logger.log(`retry-after: ${retryAfterStr}`);
|
|
@@ -780,7 +780,7 @@ export class Fetcher {
|
|
|
780
780
|
'fetchFn',
|
|
781
781
|
'overrideFetchFn',
|
|
782
782
|
]),
|
|
783
|
-
started:
|
|
783
|
+
started: nowUnixMillis(),
|
|
784
784
|
..._omit(opt, ['method', 'headers', 'credentials']),
|
|
785
785
|
inputUrl: opt.url || '',
|
|
786
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();
|
package/dist/object/set2.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { _assert } from '../error/assert.js';
|
|
1
2
|
/**
|
|
2
3
|
* Like Set, but serializes to JSON as an array.
|
|
3
4
|
*
|
|
@@ -20,8 +21,7 @@ export class Set2 extends Set {
|
|
|
20
21
|
return this;
|
|
21
22
|
}
|
|
22
23
|
first() {
|
|
23
|
-
|
|
24
|
-
throw new Error('Set.first called on empty set');
|
|
24
|
+
_assert(this.size, 'Set.first called on empty set');
|
|
25
25
|
return this.firstOrUndefined();
|
|
26
26
|
}
|
|
27
27
|
firstOrUndefined() {
|
|
@@ -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": "
|
|
17
|
+
"@naturalcycles/dev-lib": "20.71.0",
|
|
18
18
|
"@types/node": "^26",
|
|
19
19
|
"@types/semver": "^7",
|
|
20
20
|
"typescript": "^7",
|
package/src/array/array.util.ts
CHANGED
|
@@ -435,7 +435,7 @@ export function _shuffle<T>(array: T[], opt: MutateOptions = {}): T[] {
|
|
|
435
435
|
}
|
|
436
436
|
|
|
437
437
|
export function _firstLast<T>(array: readonly T[]): [first: T, last: T] {
|
|
438
|
-
|
|
438
|
+
_assert(array.length, '_firstLast called on empty array')
|
|
439
439
|
return [array[0]!, array[array.length - 1]!]
|
|
440
440
|
}
|
|
441
441
|
|
|
@@ -449,7 +449,7 @@ export function _firstLastOrUndefined<T>(array: readonly T[]): [first: T, last:
|
|
|
449
449
|
* Throws if array is empty.
|
|
450
450
|
*/
|
|
451
451
|
export function _last<T>(array: readonly T[]): T {
|
|
452
|
-
|
|
452
|
+
_assert(array.length, '_last called on empty array')
|
|
453
453
|
return array[array.length - 1]!
|
|
454
454
|
}
|
|
455
455
|
|
|
@@ -465,7 +465,7 @@ export function _lastOrUndefined<T>(array: readonly T[]): T | undefined {
|
|
|
465
465
|
* Throws if array is empty.
|
|
466
466
|
*/
|
|
467
467
|
export function _first<T>(array: readonly T[]): T {
|
|
468
|
-
|
|
468
|
+
_assert(array.length, '_first called on empty array')
|
|
469
469
|
return array[0]!
|
|
470
470
|
}
|
|
471
471
|
|
|
@@ -561,7 +561,7 @@ export function _minBy<T>(array: readonly T[], mapper: Mapper<T, number | string
|
|
|
561
561
|
}
|
|
562
562
|
|
|
563
563
|
export function _minMax<T>(array: readonly T[]): [min: NonNullable<T>, max: NonNullable<T>] {
|
|
564
|
-
|
|
564
|
+
_assert(array.length, '_minMax called on empty array')
|
|
565
565
|
const result = _minMaxOrUndefined(array)
|
|
566
566
|
_assert(result !== undefined, '_minBy returned undefined')
|
|
567
567
|
return result
|
|
@@ -592,7 +592,7 @@ export function _minMaxBy<T>(
|
|
|
592
592
|
array: readonly T[],
|
|
593
593
|
mapper: Mapper<T, number | string | undefined>,
|
|
594
594
|
): [min: NonNullable<T>, max: NonNullable<T>] {
|
|
595
|
-
|
|
595
|
+
_assert(array.length, '_minMaxBy called on empty array')
|
|
596
596
|
const result = _minMaxByOrUndefined(array, mapper)
|
|
597
597
|
_assert(result !== undefined, '_minMaxBy returned undefined')
|
|
598
598
|
return result
|
package/src/array/array2.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { _assert } from '../error/assert.js'
|
|
1
2
|
import { _shuffle } from './array.util.js'
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -20,7 +21,7 @@ export class Array2<T> extends Array<T> {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
first(): T {
|
|
23
|
-
|
|
24
|
+
_assert(this.length, 'Array.first called on empty array')
|
|
24
25
|
return this[0]!
|
|
25
26
|
}
|
|
26
27
|
|
|
@@ -30,7 +31,7 @@ export class Array2<T> extends Array<T> {
|
|
|
30
31
|
|
|
31
32
|
last(): T {
|
|
32
33
|
const { length } = this
|
|
33
|
-
|
|
34
|
+
_assert(length, 'Array.last called on empty array')
|
|
34
35
|
return this[length - 1]!
|
|
35
36
|
}
|
|
36
37
|
|
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/assert.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// `_assert` and friends are implemented by throwing in an if
|
|
2
|
+
// oxlint-disable nc/prefer-assert
|
|
1
3
|
import { _deepEquals } from '../object/deepEquals.js'
|
|
2
4
|
import { _stringify } from '../string/stringify.js'
|
|
3
5
|
import type { Class, NonEmptyArray, UnixTimestamp } from '../types.js'
|
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,9 +4,10 @@
|
|
|
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
|
-
import { _assertErrorClassOrRethrow, _assertIsError } from '../error/assert.js'
|
|
10
|
+
import { _assert, _assertErrorClassOrRethrow, _assertIsError } from '../error/assert.js'
|
|
10
11
|
import type { ErrorLike, ErrorObject } from '../error/error.model.js'
|
|
11
12
|
import {
|
|
12
13
|
_anyToError,
|
|
@@ -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([
|
|
@@ -560,10 +556,8 @@ export class Fetcher {
|
|
|
560
556
|
} else if (responseType === 'readableStream') {
|
|
561
557
|
res.body = res.fetchResponse.body
|
|
562
558
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
throw new Error('fetchResponse.body is null')
|
|
566
|
-
}
|
|
559
|
+
// Error is to be handled upstream
|
|
560
|
+
_assert(res.body !== null, 'fetchResponse.body is null')
|
|
567
561
|
}
|
|
568
562
|
|
|
569
563
|
res.retryStatus.retryStopped = true
|
|
@@ -655,7 +649,7 @@ export class Fetcher {
|
|
|
655
649
|
requestSignature: res.signature,
|
|
656
650
|
requestName: res.req.requestName,
|
|
657
651
|
fetcherName: this.cfg.name,
|
|
658
|
-
requestDuration:
|
|
652
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
659
653
|
}),
|
|
660
654
|
{
|
|
661
655
|
cause,
|
|
@@ -748,14 +742,15 @@ export class Fetcher {
|
|
|
748
742
|
if (retryAfterNumber > 10 ** 9) {
|
|
749
743
|
// Value is too large to be a "seconds from now" delay,
|
|
750
744
|
// treat it as a UnixTimestamp instead (e.g GitHub sends `x-ratelimit-reset` like that)
|
|
751
|
-
timeout = retryAfterNumber * 1000 -
|
|
745
|
+
timeout = retryAfterNumber * 1000 - nowUnixMillis()
|
|
752
746
|
} else {
|
|
753
747
|
timeout = retryAfterNumber * 1000
|
|
754
748
|
}
|
|
755
749
|
} else {
|
|
750
|
+
// oxlint-disable-next-line no-restricted-globals -- parses an HTTP-date, which localTime doesn't support
|
|
756
751
|
const date = new Date(retryAfterStr)
|
|
757
752
|
if (!Number.isNaN(date.getTime())) {
|
|
758
|
-
timeout = date.getTime() -
|
|
753
|
+
timeout = date.getTime() - nowUnixMillis()
|
|
759
754
|
}
|
|
760
755
|
}
|
|
761
756
|
|
|
@@ -930,7 +925,7 @@ export class Fetcher {
|
|
|
930
925
|
'fetchFn',
|
|
931
926
|
'overrideFetchFn',
|
|
932
927
|
]),
|
|
933
|
-
started:
|
|
928
|
+
started: nowUnixMillis(),
|
|
934
929
|
..._omit(opt, ['method', 'headers', 'credentials']),
|
|
935
930
|
inputUrl: opt.url || '',
|
|
936
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) {
|
package/src/object/set2.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { _assert } from '../error/assert.js'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Like Set, but serializes to JSON as an array.
|
|
3
5
|
*
|
|
@@ -22,7 +24,7 @@ export class Set2<T = any> extends Set<T> {
|
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
first(): T {
|
|
25
|
-
|
|
27
|
+
_assert(this.size, 'Set.first called on empty set')
|
|
26
28
|
return this.firstOrUndefined()!
|
|
27
29
|
}
|
|
28
30
|
|
|
@@ -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++
|