@naturalcycles/js-lib 15.100.0 → 15.102.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/abort.d.ts +0 -8
- package/dist/abort.js +2 -19
- package/dist/array/array.util.d.ts +1 -3
- package/dist/array/array.util.js +1 -3
- package/dist/array/sort.js +1 -1
- package/dist/array/sortedSet.d.ts +1 -1
- package/dist/array/sortedSet.js +1 -1
- package/dist/asyncManager.js +5 -4
- package/dist/browser/analytics.util.js +3 -2
- package/dist/browser/topbar.js +1 -1
- package/dist/datetime/localDate.js +10 -5
- package/dist/datetime/localTime.d.ts +4 -0
- package/dist/datetime/localTime.js +17 -8
- package/dist/datetime/time.util.d.ts +18 -1
- package/dist/datetime/time.util.js +28 -2
- package/dist/decorators/createPromiseDecorator.js +2 -1
- package/dist/decorators/debounce.js +7 -6
- package/dist/decorators/logMethod.decorator.js +3 -3
- package/dist/enum.util.js +1 -0
- package/dist/error/tryCatch.js +2 -2
- package/dist/http/fetcher.js +13 -13
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -1
- package/dist/object/deepEquals.js +2 -0
- package/dist/object/keySortedMap.js +1 -1
- package/dist/object/lazyKeySortedMap.js +1 -1
- package/dist/object/object.util.js +2 -2
- package/dist/promise/pGradualQueue.js +3 -2
- package/dist/promise/pRetry.js +2 -2
- package/dist/semver.js +10 -5
- package/dist/string/stringify.js +1 -2
- package/package.json +4 -2
- package/src/abort.ts +2 -21
- package/src/array/array.util.ts +1 -3
- package/src/array/sort.ts +1 -1
- package/src/array/sortedSet.ts +1 -1
- package/src/asyncManager.ts +5 -4
- package/src/browser/analytics.util.ts +3 -2
- package/src/browser/topbar.ts +1 -1
- package/src/datetime/localDate.ts +12 -6
- package/src/datetime/localTime.ts +19 -9
- package/src/datetime/time.util.ts +32 -3
- package/src/decorators/createPromiseDecorator.ts +2 -1
- package/src/decorators/debounce.ts +7 -6
- package/src/decorators/logMethod.decorator.ts +3 -3
- package/src/enum.util.ts +1 -0
- package/src/error/tryCatch.ts +3 -3
- package/src/http/fetcher.ts +15 -20
- package/src/index.ts +1 -1
- package/src/object/deepEquals.ts +2 -0
- package/src/object/keySortedMap.ts +1 -1
- package/src/object/lazyKeySortedMap.ts +1 -1
- package/src/object/object.util.ts +2 -2
- package/src/promise/pGradualQueue.ts +3 -2
- package/src/promise/pRetry.ts +3 -3
- package/src/semver.ts +11 -7
- package/src/string/stringify.ts +2 -4
package/dist/semver.js
CHANGED
|
@@ -126,11 +126,16 @@ class SemverFactory {
|
|
|
126
126
|
return opt.mutate ? items.sort(cmp) : items.toSorted(cmp);
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
|
|
130
|
-
export const semver2 =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
// Built inside a function, so the whole construct can be marked pure and tree-shaken (see treeshake.test.ts)
|
|
130
|
+
export const semver2 = /* @__PURE__ */ createSemverFn();
|
|
131
|
+
function createSemverFn() {
|
|
132
|
+
const semverFactory = new SemverFactory();
|
|
133
|
+
const fn = semverFactory.fromInput.bind(semverFactory);
|
|
134
|
+
// The line below is the blackest of black magic I have ever written in 2024.
|
|
135
|
+
// And probably 2023 as well.
|
|
136
|
+
Object.setPrototypeOf(fn, semverFactory);
|
|
137
|
+
return fn;
|
|
138
|
+
}
|
|
134
139
|
/**
|
|
135
140
|
* Returns 1 if a > b
|
|
136
141
|
* returns 0 if they are equal
|
package/dist/string/stringify.js
CHANGED
|
@@ -4,7 +4,6 @@ import { _isBackendErrorResponseObject, _isErrorLike, _isErrorObject } from '../
|
|
|
4
4
|
import { _jsonParseIfPossible } from './json.util.js';
|
|
5
5
|
import { _safeJsonStringify } from './safeJsonStringify.js';
|
|
6
6
|
import { _truncateMiddle } from './string.util.js';
|
|
7
|
-
const supportsAggregateError = typeof globalThis.AggregateError === 'function';
|
|
8
7
|
let globalStringifyFunction = _safeJsonStringify;
|
|
9
8
|
/**
|
|
10
9
|
* Allows to set Global "stringifyFunction" that will be used to "pretty-print" objects
|
|
@@ -127,7 +126,7 @@ function stringifyErrorLike(obj, opt) {
|
|
|
127
126
|
const sLines = s.split('\n').length;
|
|
128
127
|
s = [s, ...obj.stack.split('\n').slice(sLines)].join('\n');
|
|
129
128
|
}
|
|
130
|
-
if (
|
|
129
|
+
if (obj instanceof AggregateError && obj.errors.length) {
|
|
131
130
|
s = [
|
|
132
131
|
s,
|
|
133
132
|
`${obj.errors.length} error(s):`,
|
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.102.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"tslib": "^2"
|
|
7
7
|
},
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"@naturalcycles/dev-lib": "20.
|
|
17
|
+
"@naturalcycles/dev-lib": "20.72.0",
|
|
18
18
|
"@types/node": "^26",
|
|
19
19
|
"@types/semver": "^7",
|
|
20
|
+
"rolldown": "^1",
|
|
20
21
|
"typescript": "^7",
|
|
21
22
|
"dayjs": "^1"
|
|
22
23
|
},
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
"./decorators": "./dist/decorators/index.js",
|
|
36
37
|
"./decorators/*.js": "./dist/decorators/*.js",
|
|
37
38
|
"./deviceIdService": "./dist/deviceIdService.js",
|
|
39
|
+
"./env/*.js": "./dist/env/*.js",
|
|
38
40
|
"./error": "./dist/error/index.js",
|
|
39
41
|
"./error/*.js": "./dist/error/*.js",
|
|
40
42
|
"./http": "./dist/http/index.js",
|
package/src/abort.ts
CHANGED
|
@@ -39,27 +39,7 @@ export function createAbortableSignal(): AbortableSignal {
|
|
|
39
39
|
export function abortSignalTimeoutOrUndefined(
|
|
40
40
|
ms: NumberOfMilliseconds | undefined,
|
|
41
41
|
): AbortSignal | undefined {
|
|
42
|
-
return ms ?
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Returns an AbortSignal that aborts after the given number of milliseconds.
|
|
47
|
-
* Uses native `AbortSignal.timeout()` when available, falls back to a polyfill.
|
|
48
|
-
*
|
|
49
|
-
* The abort reason is a DOMException with name "TimeoutError".
|
|
50
|
-
*/
|
|
51
|
-
export function abortSignalTimeout(ms: NumberOfMilliseconds): AbortSignal {
|
|
52
|
-
return typeof AbortSignal.timeout === 'function'
|
|
53
|
-
? AbortSignal.timeout(ms)
|
|
54
|
-
: polyfilledAbortSignalTimeout(ms)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function polyfilledAbortSignalTimeout(ms: NumberOfMilliseconds): AbortSignal {
|
|
58
|
-
const ac = new AbortController()
|
|
59
|
-
setTimeout(() => {
|
|
60
|
-
ac.abort(new DOMException('The operation was aborted due to timeout', 'TimeoutError'))
|
|
61
|
-
}, ms)
|
|
62
|
-
return ac.signal
|
|
42
|
+
return ms ? AbortSignal.timeout(ms) : undefined
|
|
63
43
|
}
|
|
64
44
|
|
|
65
45
|
/**
|
|
@@ -87,6 +67,7 @@ export function abortSignalAny(signals: readonly AbortSignal[]): AbortSignal {
|
|
|
87
67
|
return signals[0]!
|
|
88
68
|
}
|
|
89
69
|
|
|
70
|
+
// AbortSignal.any needs Chrome 116+ / Safari 17.4+, above our browser floor (Chrome 110, iOS 16.7)
|
|
90
71
|
return typeof AbortSignal.any === 'function'
|
|
91
72
|
? AbortSignal.any(signals as AbortSignal[]) // lib.dom types require a mutable array, but it is only read
|
|
92
73
|
: polyfilledAbortSignalAny(signals)
|
package/src/array/array.util.ts
CHANGED
|
@@ -195,9 +195,7 @@ export function _find<T>(items: readonly T[], predicate: AbortablePredicate<T>):
|
|
|
195
195
|
/**
|
|
196
196
|
* Similar to `Array.findLast`, but the `predicate` may return `END` to stop the iteration early.
|
|
197
197
|
*
|
|
198
|
-
* Use `Array.findLast` if you don't need to stop the iteration early
|
|
199
|
-
* - in Node since 18+
|
|
200
|
-
* - in iOS Safari since 15.4
|
|
198
|
+
* Use `Array.findLast` if you don't need to stop the iteration early.
|
|
201
199
|
*/
|
|
202
200
|
export function _findLast<T>(items: readonly T[], predicate: AbortablePredicate<T>): T | undefined {
|
|
203
201
|
return _find(items.toReversed(), predicate)
|
package/src/array/sort.ts
CHANGED
package/src/array/sortedSet.ts
CHANGED
package/src/asyncManager.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from './datetime/time.util.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 {
|
|
@@ -92,9 +93,9 @@ class AsyncManagerImpl {
|
|
|
92
93
|
*
|
|
93
94
|
* @experimental
|
|
94
95
|
*/
|
|
95
|
-
export const AsyncManager = new AsyncManagerImpl()
|
|
96
|
+
export const AsyncManager = /* @__PURE__ */ new AsyncManagerImpl()
|
|
96
97
|
|
|
97
98
|
// Shorthand alias
|
|
98
|
-
export const runInBackground = AsyncManager.runInBackground.bind(AsyncManager)
|
|
99
|
+
export const runInBackground = /* @__PURE__ */ AsyncManager.runInBackground.bind(AsyncManager)
|
|
99
100
|
|
|
100
101
|
export type OnErrorHook = (err: Error) => any
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { newDate, nowUnixMillis } from '../datetime/time.util.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
|
|
package/src/browser/topbar.ts
CHANGED
|
@@ -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
|
|
|
@@ -851,10 +853,14 @@ interface LocalDateFn extends LocalDateFactory {
|
|
|
851
853
|
(d: LocalDateInput): LocalDate
|
|
852
854
|
}
|
|
853
855
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
export const localDate = localDateFactory.fromInput.bind(localDateFactory) as LocalDateFn
|
|
856
|
+
// Built inside a function, so the whole construct can be marked pure and tree-shaken (see treeshake.test.ts)
|
|
857
|
+
export const localDate = /* @__PURE__ */ createLocalDateFn()
|
|
857
858
|
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
859
|
+
function createLocalDateFn(): LocalDateFn {
|
|
860
|
+
const localDateFactory = new LocalDateFactory()
|
|
861
|
+
const fn = localDateFactory.fromInput.bind(localDateFactory) as LocalDateFn
|
|
862
|
+
// The line below is the blackest of black magic I have ever written in 2024.
|
|
863
|
+
// And probably 2023 as well.
|
|
864
|
+
Object.setPrototypeOf(fn, localDateFactory)
|
|
865
|
+
return fn
|
|
866
|
+
}
|
|
@@ -17,10 +17,12 @@ import type {
|
|
|
17
17
|
// oxlint-disable-next-line import/no-cycle -- intentional cycle
|
|
18
18
|
import type { LocalDate } from './localDate.js'
|
|
19
19
|
import { localDate } from './localDate.js'
|
|
20
|
-
import { _ms } from './time.util.js'
|
|
20
|
+
import { _ms, nowUnix, nowUnixMillis } 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 from time.util.js 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 from time.util.js 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
|
/**
|
|
@@ -1206,10 +1212,14 @@ interface LocalTimeFn extends LocalTimeFactory {
|
|
|
1206
1212
|
(d: LocalTimeInput): LocalTime
|
|
1207
1213
|
}
|
|
1208
1214
|
|
|
1209
|
-
|
|
1215
|
+
// Built inside a function, so the whole construct can be marked pure and tree-shaken (see treeshake.test.ts)
|
|
1216
|
+
export const localTime = /* @__PURE__ */ createLocalTimeFn()
|
|
1210
1217
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
//
|
|
1215
|
-
|
|
1218
|
+
function createLocalTimeFn(): LocalTimeFn {
|
|
1219
|
+
const localTimeFactory = new LocalTimeFactory()
|
|
1220
|
+
const fn = localTimeFactory.fromInput.bind(localTimeFactory) as LocalTimeFn
|
|
1221
|
+
// The line below is the blackest of black magic I have ever written in 2024.
|
|
1222
|
+
// And probably 2023 as well.
|
|
1223
|
+
Object.setPrototypeOf(fn, localTimeFactory)
|
|
1224
|
+
return fn
|
|
1225
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NumberOfMilliseconds, UnixTimestampMillis } from '../types.js'
|
|
1
|
+
import type { NumberOfMilliseconds, UnixTimestamp, UnixTimestampMillis } from '../types.js'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* using _ = blockTimer()
|
|
@@ -10,7 +10,7 @@ import type { NumberOfMilliseconds, UnixTimestampMillis } from '../types.js'
|
|
|
10
10
|
* @experimental
|
|
11
11
|
*/
|
|
12
12
|
export function _blockTimer(name?: string): Disposable {
|
|
13
|
-
const started =
|
|
13
|
+
const started = nowUnixMillis()
|
|
14
14
|
return {
|
|
15
15
|
[Symbol.dispose](): void {
|
|
16
16
|
console.log(`${name ? name + ' ' : ''}took ${_since(started)}`)
|
|
@@ -23,7 +23,7 @@ export function _blockTimer(name?: string): Disposable {
|
|
|
23
23
|
*/
|
|
24
24
|
export function _since(
|
|
25
25
|
from: UnixTimestampMillis,
|
|
26
|
-
until: UnixTimestampMillis =
|
|
26
|
+
until: UnixTimestampMillis = nowUnixMillis(),
|
|
27
27
|
): string {
|
|
28
28
|
return _ms(until - from)
|
|
29
29
|
}
|
|
@@ -72,3 +72,32 @@ export function _ms(millis: NumberOfMilliseconds): string {
|
|
|
72
72
|
const days = Math.floor(hrs / 24)
|
|
73
73
|
return `${days} days`
|
|
74
74
|
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Can be used instead of `oxlint-disable ...` in places where Date is intentionally needed
|
|
78
|
+
*/
|
|
79
|
+
export function newDate(): Date {
|
|
80
|
+
// oxlint-disable-next-line no-restricted-globals -- the one sanctioned way to get a native Date
|
|
81
|
+
return new Date()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
Convenience function to return current Unix timestamp in seconds.
|
|
86
|
+
Like Date.now(), but in seconds.
|
|
87
|
+
|
|
88
|
+
Lives here rather than in localTime.ts, so importing it doesn't pull LocalTime into browser bundles.
|
|
89
|
+
*/
|
|
90
|
+
export function nowUnix(): UnixTimestamp {
|
|
91
|
+
// oxlint-disable-next-line no-restricted-globals -- the one sanctioned way to read the clock
|
|
92
|
+
return Math.floor(Date.now() / 1000) as UnixTimestamp
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
Convenience function that retuns the same as Date.now(), but with proper type of UnixTimestampMillis.
|
|
97
|
+
|
|
98
|
+
Lives here rather than in localTime.ts, so importing it doesn't pull LocalTime into browser bundles.
|
|
99
|
+
*/
|
|
100
|
+
export function nowUnixMillis(): UnixTimestampMillis {
|
|
101
|
+
// oxlint-disable-next-line no-restricted-globals -- the one sanctioned way to read the clock
|
|
102
|
+
return Date.now() as UnixTimestampMillis
|
|
103
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { nowUnixMillis } from '../datetime/time.util.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/time.util.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,4 +1,4 @@
|
|
|
1
|
-
import { _ms } from '../datetime/time.util.js'
|
|
1
|
+
import { _ms, nowUnixMillis } from '../datetime/time.util.js'
|
|
2
2
|
import { _assert } from '../error/assert.js'
|
|
3
3
|
import { consoleLogger } from '../log/commonLogger.js'
|
|
4
4
|
import type { CommonLogger } from '../log/commonLogger.js'
|
|
@@ -100,7 +100,7 @@ export function _LogMethod(opt: LogMethodOptions = {}): MethodDecorator {
|
|
|
100
100
|
let count = 0
|
|
101
101
|
|
|
102
102
|
descriptor.value = function (this: typeof _target, ...args: any[]) {
|
|
103
|
-
const started =
|
|
103
|
+
const started = nowUnixMillis()
|
|
104
104
|
const ctx = this
|
|
105
105
|
|
|
106
106
|
// e.g `NameOfYourClass.methodName`
|
|
@@ -148,7 +148,7 @@ function logFinished(
|
|
|
148
148
|
res?: any,
|
|
149
149
|
err?: any,
|
|
150
150
|
): void {
|
|
151
|
-
const millis =
|
|
151
|
+
const millis = nowUnixMillis() - started
|
|
152
152
|
|
|
153
153
|
const t = ['<<', callSignature, 'took', _ms(millis)]
|
|
154
154
|
|
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,7 @@
|
|
|
1
|
-
import { _since } from '../datetime/time.util.js'
|
|
1
|
+
import { _since, nowUnixMillis } from '../datetime/time.util.js'
|
|
2
2
|
import { consoleLogger } from '../log/commonLogger.js'
|
|
3
3
|
import type { CommonLogger } from '../log/commonLogger.js'
|
|
4
|
-
import type { AnyFunction
|
|
4
|
+
import type { AnyFunction } from '../types.js'
|
|
5
5
|
import { _anyToError } from './error.util.js'
|
|
6
6
|
|
|
7
7
|
export interface TryCatchOptions {
|
|
@@ -41,7 +41,7 @@ export function _tryCatch<T extends AnyFunction>(fn: T, opt: TryCatchOptions = {
|
|
|
41
41
|
const fname = fn.name || 'anonymous'
|
|
42
42
|
|
|
43
43
|
return async function (this: any, ...args: any[]) {
|
|
44
|
-
const started =
|
|
44
|
+
const started = nowUnixMillis()
|
|
45
45
|
|
|
46
46
|
try {
|
|
47
47
|
const r = await fn.apply(this, args)
|
package/src/http/fetcher.ts
CHANGED
|
@@ -4,7 +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 { _ms, _since } from '../datetime/time.util.js'
|
|
7
|
+
import { _ms, _since, nowUnixMillis } from '../datetime/time.util.js'
|
|
8
8
|
import { isServerSide } from '../env.js'
|
|
9
9
|
import { _assert, _assertErrorClassOrRethrow, _assertIsError } from '../error/assert.js'
|
|
10
10
|
import type { ErrorLike, ErrorObject } from '../error/error.model.js'
|
|
@@ -29,14 +29,9 @@ import {
|
|
|
29
29
|
} from '../object/object.util.js'
|
|
30
30
|
import { pDelaySignal } from '../promise/pDelay.js'
|
|
31
31
|
import { pTimeout } from '../promise/pTimeout.js'
|
|
32
|
-
import { _toUrlOrNull } from '../string/index.js'
|
|
33
32
|
import { _jsonParse, _jsonParseIfPossible } from '../string/json.util.js'
|
|
34
|
-
import
|
|
35
|
-
|
|
36
|
-
ErrorDataTuple,
|
|
37
|
-
NumberOfMilliseconds,
|
|
38
|
-
UnixTimestampMillis,
|
|
39
|
-
} from '../types.js'
|
|
33
|
+
import { _toUrlOrNull } from '../string/url.util.js'
|
|
34
|
+
import type { AnyObject, ErrorDataTuple, NumberOfMilliseconds } from '../types.js'
|
|
40
35
|
import type {
|
|
41
36
|
FetcherAfterResponseHook,
|
|
42
37
|
FetcherBeforeRequestHook,
|
|
@@ -60,6 +55,8 @@ import type {
|
|
|
60
55
|
import type { HttpStatusFamily } from './http.model.js'
|
|
61
56
|
import { HTTP_METHODS } from './http.model.js'
|
|
62
57
|
|
|
58
|
+
const FETCHER_VERSION = 5
|
|
59
|
+
|
|
63
60
|
/**
|
|
64
61
|
* Experimental wrapper around Fetch.
|
|
65
62
|
* Works in both Browser and Node, using `globalThis.fetch`.
|
|
@@ -71,18 +68,15 @@ export class Fetcher {
|
|
|
71
68
|
*
|
|
72
69
|
* Version is to be incremented every time a difference in behaviour (or a bugfix) is done.
|
|
73
70
|
*/
|
|
74
|
-
static readonly VERSION =
|
|
71
|
+
static readonly VERSION = FETCHER_VERSION
|
|
75
72
|
/**
|
|
76
73
|
* userAgent is statically exposed as Fetcher.userAgent.
|
|
77
74
|
* It can be modified globally, and will be used (read) at the start of every request.
|
|
78
75
|
*/
|
|
79
|
-
|
|
76
|
+
// Pure, and not reading `this.VERSION`, so bundlers can drop Fetcher when unused (see treeshake.test.ts)
|
|
77
|
+
static userAgent = /* @__PURE__ */ isServerSide() ? `fetcher/${FETCHER_VERSION}` : undefined
|
|
80
78
|
|
|
81
79
|
private constructor(cfg: FetcherCfg & FetcherOptions = {}) {
|
|
82
|
-
if (typeof globalThis.fetch !== 'function') {
|
|
83
|
-
throw new TypeError('globalThis.fetch is not available')
|
|
84
|
-
}
|
|
85
|
-
|
|
86
80
|
this.cfg = this.normalizeCfg(cfg)
|
|
87
81
|
|
|
88
82
|
// Dynamically create all helper methods
|
|
@@ -250,7 +244,7 @@ export class Fetcher {
|
|
|
250
244
|
requestSignature: res.signature,
|
|
251
245
|
requestName: res.req.requestName,
|
|
252
246
|
fetcherName: this.cfg.name,
|
|
253
|
-
requestDuration:
|
|
247
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
254
248
|
})
|
|
255
249
|
}
|
|
256
250
|
|
|
@@ -400,7 +394,7 @@ export class Fetcher {
|
|
|
400
394
|
} as FetcherResponse<any>
|
|
401
395
|
|
|
402
396
|
while (!res.retryStatus.retryStopped) {
|
|
403
|
-
req.started =
|
|
397
|
+
req.started = nowUnixMillis()
|
|
404
398
|
res.body = undefined
|
|
405
399
|
|
|
406
400
|
req.init.signal = abortSignalAnyOrUndefined([
|
|
@@ -653,7 +647,7 @@ export class Fetcher {
|
|
|
653
647
|
requestSignature: res.signature,
|
|
654
648
|
requestName: res.req.requestName,
|
|
655
649
|
fetcherName: this.cfg.name,
|
|
656
|
-
requestDuration:
|
|
650
|
+
requestDuration: nowUnixMillis() - res.req.started,
|
|
657
651
|
}),
|
|
658
652
|
{
|
|
659
653
|
cause,
|
|
@@ -746,14 +740,15 @@ export class Fetcher {
|
|
|
746
740
|
if (retryAfterNumber > 10 ** 9) {
|
|
747
741
|
// Value is too large to be a "seconds from now" delay,
|
|
748
742
|
// treat it as a UnixTimestamp instead (e.g GitHub sends `x-ratelimit-reset` like that)
|
|
749
|
-
timeout = retryAfterNumber * 1000 -
|
|
743
|
+
timeout = retryAfterNumber * 1000 - nowUnixMillis()
|
|
750
744
|
} else {
|
|
751
745
|
timeout = retryAfterNumber * 1000
|
|
752
746
|
}
|
|
753
747
|
} else {
|
|
748
|
+
// oxlint-disable-next-line no-restricted-globals -- parses an HTTP-date, which localTime doesn't support
|
|
754
749
|
const date = new Date(retryAfterStr)
|
|
755
750
|
if (!Number.isNaN(date.getTime())) {
|
|
756
|
-
timeout = date.getTime() -
|
|
751
|
+
timeout = date.getTime() - nowUnixMillis()
|
|
757
752
|
}
|
|
758
753
|
}
|
|
759
754
|
|
|
@@ -928,7 +923,7 @@ export class Fetcher {
|
|
|
928
923
|
'fetchFn',
|
|
929
924
|
'overrideFetchFn',
|
|
930
925
|
]),
|
|
931
|
-
started:
|
|
926
|
+
started: nowUnixMillis(),
|
|
932
927
|
..._omit(opt, ['method', 'headers', 'credentials']),
|
|
933
928
|
inputUrl: opt.url || '',
|
|
934
929
|
fullUrl: opt.url || '',
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ export * from './bot.model.js'
|
|
|
4
4
|
export * from './define.js'
|
|
5
5
|
export * from './enum.util.js'
|
|
6
6
|
export * from './env.js'
|
|
7
|
-
export * from './env/buildInfo.js'
|
|
7
|
+
export type * from './env/buildInfo.js'
|
|
8
8
|
export * from './form.util.js'
|
|
9
9
|
export * from './is.util.js'
|
|
10
10
|
export * from './iter/asyncIterable2.js'
|
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) {
|
|
@@ -452,7 +452,7 @@ export function _unset<T extends AnyObject>(obj: T, prop: string): void {
|
|
|
452
452
|
return
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
-
if (
|
|
455
|
+
if (Object.hasOwn(obj, prop)) {
|
|
456
456
|
delete obj[prop]
|
|
457
457
|
return
|
|
458
458
|
}
|
|
@@ -599,7 +599,7 @@ export function _deepFreeze(o: any): void {
|
|
|
599
599
|
|
|
600
600
|
Object.getOwnPropertyNames(o).forEach(prop => {
|
|
601
601
|
if (
|
|
602
|
-
|
|
602
|
+
Object.hasOwn(o, prop) &&
|
|
603
603
|
o[prop] !== null &&
|
|
604
604
|
(typeof o[prop] === 'object' || typeof o[prop] === 'function') &&
|
|
605
605
|
!Object.isFrozen(o[prop])
|