@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.
Files changed (57) hide show
  1. package/dist/abort.d.ts +0 -8
  2. package/dist/abort.js +2 -19
  3. package/dist/array/array.util.d.ts +1 -3
  4. package/dist/array/array.util.js +1 -3
  5. package/dist/array/sort.js +1 -1
  6. package/dist/array/sortedSet.d.ts +1 -1
  7. package/dist/array/sortedSet.js +1 -1
  8. package/dist/asyncManager.js +5 -4
  9. package/dist/browser/analytics.util.js +3 -2
  10. package/dist/browser/topbar.js +1 -1
  11. package/dist/datetime/localDate.js +10 -5
  12. package/dist/datetime/localTime.d.ts +4 -0
  13. package/dist/datetime/localTime.js +17 -8
  14. package/dist/datetime/time.util.d.ts +18 -1
  15. package/dist/datetime/time.util.js +28 -2
  16. package/dist/decorators/createPromiseDecorator.js +2 -1
  17. package/dist/decorators/debounce.js +7 -6
  18. package/dist/decorators/logMethod.decorator.js +3 -3
  19. package/dist/enum.util.js +1 -0
  20. package/dist/error/tryCatch.js +2 -2
  21. package/dist/http/fetcher.js +13 -13
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +0 -1
  24. package/dist/object/deepEquals.js +2 -0
  25. package/dist/object/keySortedMap.js +1 -1
  26. package/dist/object/lazyKeySortedMap.js +1 -1
  27. package/dist/object/object.util.js +2 -2
  28. package/dist/promise/pGradualQueue.js +3 -2
  29. package/dist/promise/pRetry.js +2 -2
  30. package/dist/semver.js +10 -5
  31. package/dist/string/stringify.js +1 -2
  32. package/package.json +4 -2
  33. package/src/abort.ts +2 -21
  34. package/src/array/array.util.ts +1 -3
  35. package/src/array/sort.ts +1 -1
  36. package/src/array/sortedSet.ts +1 -1
  37. package/src/asyncManager.ts +5 -4
  38. package/src/browser/analytics.util.ts +3 -2
  39. package/src/browser/topbar.ts +1 -1
  40. package/src/datetime/localDate.ts +12 -6
  41. package/src/datetime/localTime.ts +19 -9
  42. package/src/datetime/time.util.ts +32 -3
  43. package/src/decorators/createPromiseDecorator.ts +2 -1
  44. package/src/decorators/debounce.ts +7 -6
  45. package/src/decorators/logMethod.decorator.ts +3 -3
  46. package/src/enum.util.ts +1 -0
  47. package/src/error/tryCatch.ts +3 -3
  48. package/src/http/fetcher.ts +15 -20
  49. package/src/index.ts +1 -1
  50. package/src/object/deepEquals.ts +2 -0
  51. package/src/object/keySortedMap.ts +1 -1
  52. package/src/object/lazyKeySortedMap.ts +1 -1
  53. package/src/object/object.util.ts +2 -2
  54. package/src/promise/pGradualQueue.ts +3 -2
  55. package/src/promise/pRetry.ts +3 -3
  56. package/src/semver.ts +11 -7
  57. 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
- const semverFactory = new SemverFactory();
130
- export const semver2 = semverFactory.fromInput.bind(semverFactory);
131
- // The line below is the blackest of black magic I have ever written in 2024.
132
- // And probably 2023 as well.
133
- Object.setPrototypeOf(semver2, semverFactory);
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
@@ -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 (supportsAggregateError && obj instanceof AggregateError && obj.errors.length) {
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.100.0",
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.70.0",
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 ? abortSignalTimeout(ms) : undefined
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)
@@ -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, which is supported:
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
@@ -55,7 +55,7 @@ class Comparators {
55
55
  }
56
56
  }
57
57
 
58
- export const comparators = new Comparators()
58
+ export const comparators = /* @__PURE__ */ new Comparators()
59
59
 
60
60
  interface ComparatorByOptions {
61
61
  /**
@@ -1,4 +1,4 @@
1
- import { Set2 } from '../object/index.js'
1
+ import { Set2 } from '../object/set2.js'
2
2
  import type { Comparator } from '../types.js'
3
3
 
4
4
  export interface SortedSetOptions<T> {
@@ -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 = Date.now()
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 ${Date.now() - started} ms`)
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', new Date())
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': Date.now(),
34
+ 'gtm.start': nowUnixMillis(),
34
35
  event: 'gtm.js',
35
36
  })
36
37
 
@@ -82,7 +82,7 @@ const createCanvas = () => {
82
82
  export const topbar = {
83
83
  config(opts: TopBarOptions) {
84
84
  for (const key in opts) {
85
- if (options.hasOwnProperty(key)) {
85
+ if (Object.hasOwn(options, key)) {
86
86
  // @ts-expect-error
87
87
  options[key] = opts[key]
88
88
  }
@@ -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
- const localDateFactory = new LocalDateFactory()
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
- // The line below is the blackest of black magic I have ever written in 2024.
859
- // And probably 2023 as well.
860
- Object.setPrototypeOf(localDate, localDateFactory)
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 Math.floor(Date.now() / 1000) as UnixTimestamp
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 Date.now() as UnixTimestampMillis
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
- const localTimeFactory = new LocalTimeFactory()
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
- export const localTime = localTimeFactory.fromInput.bind(localTimeFactory) as LocalTimeFn
1212
-
1213
- // The line below is the blackest of black magic I have ever written in 2024.
1214
- // And probably 2023 as well.
1215
- Object.setPrototypeOf(localTime, localTimeFactory)
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 = Date.now() as UnixTimestampMillis
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 = Date.now() as 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 = Date.now()
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 = Date.now()
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(Date.now())
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 = Date.now()
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 = Date.now()
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(Date.now())
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 = Date.now()
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 = Date.now()
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 = Date.now() - started
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
  }
@@ -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, UnixTimestampMillis } from '../types.js'
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 = Date.now() as UnixTimestampMillis
44
+ const started = nowUnixMillis()
45
45
 
46
46
  try {
47
47
  const r = await fn.apply(this, args)
@@ -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 type {
35
- AnyObject,
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 = 5
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
- static userAgent = isServerSide() ? `fetcher/${this.VERSION}` : undefined
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: Date.now() - res.req.started,
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 = Date.now() as UnixTimestampMillis
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: Date.now() - res.req.started,
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 - Date.now()
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() - Date.now()
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: Date.now() as UnixTimestampMillis,
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'
@@ -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,4 +1,4 @@
1
- import { _assert } from '../error/index.js'
1
+ import { _assert } from '../error/assert.js'
2
2
  import type { Comparator } from '../types.js'
3
3
 
4
4
  export interface KeySortedMapOptions<K> {
@@ -1,4 +1,4 @@
1
- import { _assert } from '../error/index.js'
1
+ import { _assert } from '../error/assert.js'
2
2
  import type { Comparator } from '../types.js'
3
3
 
4
4
  export interface LazyKeySortedMapOptions<K> {
@@ -452,7 +452,7 @@ export function _unset<T extends AnyObject>(obj: T, prop: string): void {
452
452
  return
453
453
  }
454
454
 
455
- if (obj.hasOwnProperty(prop)) {
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
- o.hasOwnProperty(prop) &&
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])