@naturalcycles/js-lib 14.257.0 → 14.259.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/datetime/localDate.d.ts +3 -3
- package/dist/datetime/localTime.d.ts +9 -9
- package/dist/datetime/timeInterval.d.ts +3 -3
- package/dist/decorators/memo.util.d.ts +2 -2
- package/dist/deviceIdService.d.ts +65 -0
- package/dist/deviceIdService.js +109 -0
- package/dist/env/buildInfo.d.ts +3 -3
- package/dist/error/assert.d.ts +13 -0
- package/dist/error/assert.js +24 -0
- package/dist/http/fetcher.model.d.ts +2 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/nanoid.d.ts +7 -0
- package/dist/nanoid.js +61 -0
- package/dist/number/createDeterministicRandom.d.ts +6 -1
- package/dist/number/createDeterministicRandom.js +1 -2
- package/dist/string/hash.util.d.ts +1 -1
- package/dist/string/hash.util.js +1 -1
- package/dist/time/time.util.d.ts +3 -2
- package/dist/types.d.ts +12 -10
- package/dist/web.d.ts +6 -0
- package/dist/web.js +6 -0
- package/dist-esm/deviceIdService.js +105 -0
- package/dist-esm/error/assert.js +22 -0
- package/dist-esm/index.js +2 -0
- package/dist-esm/nanoid.js +57 -0
- package/dist-esm/number/createDeterministicRandom.js +1 -2
- package/dist-esm/string/hash.util.js +1 -1
- package/dist-esm/web.js +6 -0
- package/package.json +1 -1
- package/src/datetime/localDate.ts +6 -6
- package/src/datetime/localTime.ts +14 -14
- package/src/datetime/timeInterval.ts +6 -6
- package/src/decorators/memo.util.ts +2 -2
- package/src/deviceIdService.ts +137 -0
- package/src/env/buildInfo.ts +3 -3
- package/src/error/assert.ts +25 -0
- package/src/error/tryCatch.ts +2 -2
- package/src/http/fetcher.model.ts +2 -2
- package/src/http/fetcher.ts +3 -3
- package/src/index.ts +2 -0
- package/src/nanoid.ts +79 -0
- package/src/number/createDeterministicRandom.ts +7 -2
- package/src/promise/pRetry.ts +2 -2
- package/src/string/hash.util.ts +1 -1
- package/src/time/time.util.ts +8 -3
- package/src/types.ts +12 -10
- package/src/web.ts +6 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Iterable2 } from '../iter/iterable2';
|
|
2
|
-
import type { Inclusiveness, IsoDateString, IsoDateTimeString, MonthId, SortDirection,
|
|
2
|
+
import type { Inclusiveness, IsoDateString, IsoDateTimeString, MonthId, SortDirection, UnixTimestamp, UnixTimestampMillis } from '../types';
|
|
3
3
|
import { DateObject, ISODayOfWeek, LocalTime } from './localTime';
|
|
4
4
|
export type LocalDateUnit = LocalDateUnitStrict | 'week';
|
|
5
5
|
export type LocalDateUnitStrict = 'year' | 'month' | 'day';
|
|
@@ -142,11 +142,11 @@ export declare class LocalDate {
|
|
|
142
142
|
/**
|
|
143
143
|
* Returns unix timestamp of 00:00:00 of that date (in UTC, because unix timestamp always reflects UTC).
|
|
144
144
|
*/
|
|
145
|
-
get unix():
|
|
145
|
+
get unix(): UnixTimestamp;
|
|
146
146
|
/**
|
|
147
147
|
* Same as .unix(), but in milliseconds.
|
|
148
148
|
*/
|
|
149
|
-
get unixMillis():
|
|
149
|
+
get unixMillis(): UnixTimestampMillis;
|
|
150
150
|
toJSON(): IsoDateString;
|
|
151
151
|
format(fmt: Intl.DateTimeFormat | LocalDateFormatter): string;
|
|
152
152
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Inclusiveness, IsoDateString, IsoDateTimeString, MonthId, NumberOfHours, NumberOfMinutes, SortDirection,
|
|
1
|
+
import type { Inclusiveness, IsoDateString, IsoDateTimeString, MonthId, NumberOfHours, NumberOfMinutes, SortDirection, UnixTimestamp, UnixTimestampMillis } from '../types';
|
|
2
2
|
import { LocalDate } from './localDate';
|
|
3
3
|
import { WallTime } from './wallTime';
|
|
4
4
|
export type LocalTimeUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second';
|
|
@@ -11,7 +11,7 @@ export declare enum ISODayOfWeek {
|
|
|
11
11
|
SATURDAY = 6,
|
|
12
12
|
SUNDAY = 7
|
|
13
13
|
}
|
|
14
|
-
export type LocalTimeInput = LocalTime | Date | IsoDateTimeString |
|
|
14
|
+
export type LocalTimeInput = LocalTime | Date | IsoDateTimeString | UnixTimestamp;
|
|
15
15
|
export type LocalTimeInputNullable = LocalTimeInput | null | undefined;
|
|
16
16
|
export type LocalTimeFormatter = (ld: LocalTime) => string;
|
|
17
17
|
export type DateTimeObject = DateObject & TimeObject;
|
|
@@ -186,9 +186,9 @@ export declare class LocalTime {
|
|
|
186
186
|
toFromNowString(now?: LocalTimeInput): string;
|
|
187
187
|
toDate(): Date;
|
|
188
188
|
clone(): LocalTime;
|
|
189
|
-
get unix():
|
|
190
|
-
get unixMillis():
|
|
191
|
-
valueOf():
|
|
189
|
+
get unix(): UnixTimestamp;
|
|
190
|
+
get unixMillis(): UnixTimestampMillis;
|
|
191
|
+
valueOf(): UnixTimestamp;
|
|
192
192
|
toLocalDate(): LocalDate;
|
|
193
193
|
/**
|
|
194
194
|
* Returns e.g: `1984-06-21 17:56:21`
|
|
@@ -213,7 +213,7 @@ export declare class LocalTime {
|
|
|
213
213
|
*/
|
|
214
214
|
toStringCompact(seconds?: boolean): string;
|
|
215
215
|
toString(): string;
|
|
216
|
-
toJSON():
|
|
216
|
+
toJSON(): UnixTimestamp;
|
|
217
217
|
toMonthId(): MonthId;
|
|
218
218
|
format(fmt: Intl.DateTimeFormat | LocalTimeFormatter): string;
|
|
219
219
|
}
|
|
@@ -233,7 +233,7 @@ declare class LocalTimeFactory {
|
|
|
233
233
|
Convenience function to return current Unix timestamp in seconds.
|
|
234
234
|
Like Date.now(), but in seconds.
|
|
235
235
|
*/
|
|
236
|
-
nowUnix():
|
|
236
|
+
nowUnix(): UnixTimestamp;
|
|
237
237
|
/**
|
|
238
238
|
* Create LocalTime from LocalTimeInput.
|
|
239
239
|
* Input can already be a LocalTime - it is returned as-is in that case.
|
|
@@ -277,11 +277,11 @@ declare class LocalTimeFactory {
|
|
|
277
277
|
isDateTimeObjectValid(o: DateTimeObject): boolean;
|
|
278
278
|
isTimeObjectValid({ hour, minute, second }: TimeObject): boolean;
|
|
279
279
|
fromDate(date: Date): LocalTime;
|
|
280
|
-
fromUnix(ts:
|
|
280
|
+
fromUnix(ts: UnixTimestamp): LocalTime;
|
|
281
281
|
/**
|
|
282
282
|
* Create LocalTime from unixTimestamp in milliseconds (not in seconds).
|
|
283
283
|
*/
|
|
284
|
-
fromMillis(millis:
|
|
284
|
+
fromMillis(millis: UnixTimestampMillis): LocalTime;
|
|
285
285
|
fromDateTimeObject(o: DateTimeObjectInput): LocalTime;
|
|
286
286
|
private createDateFromDateTimeObject;
|
|
287
287
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Inclusiveness,
|
|
1
|
+
import type { Inclusiveness, UnixTimestamp } from '../types';
|
|
2
2
|
import { LocalTime, LocalTimeInput } from './localTime';
|
|
3
3
|
export type TimeIntervalConfig = TimeInterval | TimeIntervalString;
|
|
4
4
|
export type TimeIntervalString = string;
|
|
@@ -13,8 +13,8 @@ export declare class TimeInterval {
|
|
|
13
13
|
private $end;
|
|
14
14
|
private constructor();
|
|
15
15
|
static of(start: LocalTimeInput, end: LocalTimeInput): TimeInterval;
|
|
16
|
-
get start():
|
|
17
|
-
get end():
|
|
16
|
+
get start(): UnixTimestamp;
|
|
17
|
+
get end(): UnixTimestamp;
|
|
18
18
|
get startTime(): LocalTime;
|
|
19
19
|
get endTime(): LocalTime;
|
|
20
20
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnixTimestamp } from '../types';
|
|
2
2
|
import { MISS } from '../types';
|
|
3
3
|
export type MemoSerializer = (args: any[]) => any;
|
|
4
4
|
export declare const jsonMemoSerializer: MemoSerializer;
|
|
@@ -7,7 +7,7 @@ export interface MemoCacheOptions {
|
|
|
7
7
|
* If set (and if it's implemented by the driver) - will set expiry TTL for each key of the batch.
|
|
8
8
|
* E.g EXAT in Redis.
|
|
9
9
|
*/
|
|
10
|
-
expireAt?:
|
|
10
|
+
expireAt?: UnixTimestamp;
|
|
11
11
|
}
|
|
12
12
|
export interface MemoCache<KEY = any, VALUE = any> {
|
|
13
13
|
has: (k: KEY) => boolean;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference lib="dom" preserve="true" />
|
|
2
|
+
/**
|
|
3
|
+
* Service to generate, maintain, persist a stable "device id".
|
|
4
|
+
*
|
|
5
|
+
* It's called "device id" and not userId/visitorId, to indicate that it only identifies a device,
|
|
6
|
+
* and has nothing to do with user identification.
|
|
7
|
+
* User might be logged in or not.
|
|
8
|
+
* User id can be the same on multiple devices.
|
|
9
|
+
* DeviceId is unique per device, same User or not.
|
|
10
|
+
*
|
|
11
|
+
* Service provides methods to deterministically select fraction of devices.
|
|
12
|
+
* For example, select 10% of devices that visit the website to be tracked by Analytics
|
|
13
|
+
* (to reduce Analytics quota usage).
|
|
14
|
+
* DeviceId persistence will ensure that recurring visits from the same device will yield the same
|
|
15
|
+
* DeviceId, and same "selection assignment" (like an assignment in an AB test).
|
|
16
|
+
*
|
|
17
|
+
* @experimental
|
|
18
|
+
*/
|
|
19
|
+
export declare class DeviceIdService {
|
|
20
|
+
constructor(cfg?: DeviceIdServiceCfg);
|
|
21
|
+
cfg: Required<DeviceIdServiceCfg>;
|
|
22
|
+
/**
|
|
23
|
+
* `deviceId` is null only in anomalous cases, e.g when localStorage is not available (due to e.g "out of disk space" on device).
|
|
24
|
+
* In all other cases it should be defined and stable (persisted indefinitely between multiple visits).
|
|
25
|
+
*
|
|
26
|
+
* It is null if the service is run on the server side.
|
|
27
|
+
*/
|
|
28
|
+
deviceId: string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Selects this device based on "deterministic random selection", according to the defined `rate`.
|
|
31
|
+
* Rate is a floating number between 0 and 1.
|
|
32
|
+
* E.g rate of 0.1 means 10% chance of being selected.
|
|
33
|
+
*
|
|
34
|
+
* Selection is based on deviceId, which is generated random and persisted between visits.
|
|
35
|
+
* Persistence ensures that the selection (similar to an AB-test assignment) "sticks" to the device.
|
|
36
|
+
*
|
|
37
|
+
* If deviceId failed to be generated, e.g due to Device running out-of-space to save a string to localStorage,
|
|
38
|
+
* it will NOT be selected.
|
|
39
|
+
*
|
|
40
|
+
* @returns true if the device is selected.
|
|
41
|
+
*/
|
|
42
|
+
select(rate: number): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Deletes the persisted deviceId.
|
|
45
|
+
* Keeps it in the service.
|
|
46
|
+
* To remove it from the service, assign deviceIdService.deviceId = null.
|
|
47
|
+
*/
|
|
48
|
+
clearPersistence(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Generates a stable Device id if it wasn't previously generated on this device.
|
|
51
|
+
* Otherwise, reads a Device id from persistent storage.
|
|
52
|
+
*/
|
|
53
|
+
private init;
|
|
54
|
+
private debug;
|
|
55
|
+
}
|
|
56
|
+
export interface DeviceIdServiceCfg {
|
|
57
|
+
/**
|
|
58
|
+
* Default: deviceId
|
|
59
|
+
*/
|
|
60
|
+
localStorageKey?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Set to true to enable debug logging.
|
|
63
|
+
*/
|
|
64
|
+
debug?: boolean;
|
|
65
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/// <reference lib="dom" preserve="true" />
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.DeviceIdService = void 0;
|
|
5
|
+
const env_1 = require("./env");
|
|
6
|
+
const nanoid_1 = require("./nanoid");
|
|
7
|
+
const hash_util_1 = require("./string/hash.util");
|
|
8
|
+
// This is in sync with the default length in Nanoid.
|
|
9
|
+
const deviceIdLength = 21;
|
|
10
|
+
/**
|
|
11
|
+
* Service to generate, maintain, persist a stable "device id".
|
|
12
|
+
*
|
|
13
|
+
* It's called "device id" and not userId/visitorId, to indicate that it only identifies a device,
|
|
14
|
+
* and has nothing to do with user identification.
|
|
15
|
+
* User might be logged in or not.
|
|
16
|
+
* User id can be the same on multiple devices.
|
|
17
|
+
* DeviceId is unique per device, same User or not.
|
|
18
|
+
*
|
|
19
|
+
* Service provides methods to deterministically select fraction of devices.
|
|
20
|
+
* For example, select 10% of devices that visit the website to be tracked by Analytics
|
|
21
|
+
* (to reduce Analytics quota usage).
|
|
22
|
+
* DeviceId persistence will ensure that recurring visits from the same device will yield the same
|
|
23
|
+
* DeviceId, and same "selection assignment" (like an assignment in an AB test).
|
|
24
|
+
*
|
|
25
|
+
* @experimental
|
|
26
|
+
*/
|
|
27
|
+
class DeviceIdService {
|
|
28
|
+
constructor(cfg = {}) {
|
|
29
|
+
this.cfg = {
|
|
30
|
+
localStorageKey: 'deviceId',
|
|
31
|
+
debug: false,
|
|
32
|
+
...cfg,
|
|
33
|
+
};
|
|
34
|
+
this.init();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Selects this device based on "deterministic random selection", according to the defined `rate`.
|
|
38
|
+
* Rate is a floating number between 0 and 1.
|
|
39
|
+
* E.g rate of 0.1 means 10% chance of being selected.
|
|
40
|
+
*
|
|
41
|
+
* Selection is based on deviceId, which is generated random and persisted between visits.
|
|
42
|
+
* Persistence ensures that the selection (similar to an AB-test assignment) "sticks" to the device.
|
|
43
|
+
*
|
|
44
|
+
* If deviceId failed to be generated, e.g due to Device running out-of-space to save a string to localStorage,
|
|
45
|
+
* it will NOT be selected.
|
|
46
|
+
*
|
|
47
|
+
* @returns true if the device is selected.
|
|
48
|
+
*/
|
|
49
|
+
select(rate) {
|
|
50
|
+
if (!this.deviceId) {
|
|
51
|
+
this.debug(`deviceId is null, skipping selection`);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const mod = Math.trunc(rate * 1000);
|
|
55
|
+
// console.log('hash: ', hashCode(this.deviceId)) // todo
|
|
56
|
+
return (0, hash_util_1.hashCode)(this.deviceId) % 1000 < mod;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Deletes the persisted deviceId.
|
|
60
|
+
* Keeps it in the service.
|
|
61
|
+
* To remove it from the service, assign deviceIdService.deviceId = null.
|
|
62
|
+
*/
|
|
63
|
+
clearPersistence() {
|
|
64
|
+
try {
|
|
65
|
+
globalThis.localStorage.removeItem(this.cfg.localStorageKey);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
console.log(err);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generates a stable Device id if it wasn't previously generated on this device.
|
|
73
|
+
* Otherwise, reads a Device id from persistent storage.
|
|
74
|
+
*/
|
|
75
|
+
init() {
|
|
76
|
+
this.deviceId = null;
|
|
77
|
+
if ((0, env_1.isServerSide)())
|
|
78
|
+
return;
|
|
79
|
+
try {
|
|
80
|
+
this.deviceId = globalThis.localStorage.getItem(this.cfg.localStorageKey);
|
|
81
|
+
if (this.deviceId)
|
|
82
|
+
this.debug(`loaded deviceId: ${this.deviceId}`);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
console.log(err);
|
|
86
|
+
this.deviceId = null;
|
|
87
|
+
}
|
|
88
|
+
if (this.deviceId && this.deviceId.length !== deviceIdLength) {
|
|
89
|
+
console.warn(`[DeviceIdService] unexpected deviceIdLength (${this.deviceId.length}), will re-generate the id`, { deviceId: this.deviceId });
|
|
90
|
+
this.deviceId = null;
|
|
91
|
+
}
|
|
92
|
+
if (!this.deviceId) {
|
|
93
|
+
try {
|
|
94
|
+
this.deviceId = (0, nanoid_1.nanoidBrowser)(deviceIdLength);
|
|
95
|
+
this.debug(`generated new deviceId: ${this.deviceId}`);
|
|
96
|
+
globalThis.localStorage.setItem(this.cfg.localStorageKey, this.deviceId);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.log(err);
|
|
100
|
+
this.deviceId = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
debug(...args) {
|
|
105
|
+
if (this.cfg.debug)
|
|
106
|
+
console.log('[DeviceIdService]', ...args);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.DeviceIdService = DeviceIdService;
|
package/dist/env/buildInfo.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UnixTimestamp } from '../types';
|
|
2
2
|
export interface BuildInfo {
|
|
3
3
|
/**
|
|
4
4
|
* Unix timestamp of when the build was made.
|
|
5
5
|
*/
|
|
6
|
-
ts:
|
|
6
|
+
ts: UnixTimestamp;
|
|
7
7
|
/**
|
|
8
8
|
* Unix timestamp of commit ("committer date", not "author date")
|
|
9
9
|
*/
|
|
10
|
-
tsCommit:
|
|
10
|
+
tsCommit: UnixTimestamp;
|
|
11
11
|
repoName: string;
|
|
12
12
|
branchName: string;
|
|
13
13
|
/**
|
package/dist/error/assert.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Class } from '../typeFest';
|
|
2
|
+
import type { UnixTimestamp } from '../types';
|
|
2
3
|
import type { BackendErrorResponseObject, ErrorData, ErrorObject } from './error.model';
|
|
3
4
|
/**
|
|
4
5
|
* Evaluates the `condition` (casts it to Boolean).
|
|
@@ -44,3 +45,15 @@ export declare function _assertIsBackendErrorResponseObject<DATA_TYPE extends Er
|
|
|
44
45
|
export declare function _assertIsString(v: any, message?: string): asserts v is string;
|
|
45
46
|
export declare function _assertIsNumber(v: any, message?: string): asserts v is number;
|
|
46
47
|
export declare function _assertTypeOf<T>(v: any, expectedType: string, message?: string): asserts v is T;
|
|
48
|
+
/**
|
|
49
|
+
* Casts an arbitrary number as UnixTimestamp.
|
|
50
|
+
* Right now does not perform any validation (unlike `asUnixTimestamp2000`),
|
|
51
|
+
* but only type casting.
|
|
52
|
+
*/
|
|
53
|
+
export declare function asUnixTimestamp(n: number): UnixTimestamp;
|
|
54
|
+
/**
|
|
55
|
+
* Casts an arbitrary number as UnixTimestamp2000.
|
|
56
|
+
* Throws if the number is not inside 2000-01-01 and 2500-01-01 time interval,
|
|
57
|
+
* which would indicate a bug.
|
|
58
|
+
*/
|
|
59
|
+
export declare function asUnixTimestamp2000(n: number): UnixTimestamp;
|
package/dist/error/assert.js
CHANGED
|
@@ -10,8 +10,11 @@ exports._assertIsBackendErrorResponseObject = _assertIsBackendErrorResponseObjec
|
|
|
10
10
|
exports._assertIsString = _assertIsString;
|
|
11
11
|
exports._assertIsNumber = _assertIsNumber;
|
|
12
12
|
exports._assertTypeOf = _assertTypeOf;
|
|
13
|
+
exports.asUnixTimestamp = asUnixTimestamp;
|
|
14
|
+
exports.asUnixTimestamp2000 = asUnixTimestamp2000;
|
|
13
15
|
const deepEquals_1 = require("../object/deepEquals");
|
|
14
16
|
const stringify_1 = require("../string/stringify");
|
|
17
|
+
const zod_shared_schemas_1 = require("../zod/zod.shared.schemas");
|
|
15
18
|
const error_util_1 = require("./error.util");
|
|
16
19
|
/**
|
|
17
20
|
* Evaluates the `condition` (casts it to Boolean).
|
|
@@ -110,3 +113,24 @@ function _assertTypeOf(v, expectedType, message) {
|
|
|
110
113
|
throw new error_util_1.AssertionError(msg);
|
|
111
114
|
}
|
|
112
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Casts an arbitrary number as UnixTimestamp.
|
|
118
|
+
* Right now does not perform any validation (unlike `asUnixTimestamp2000`),
|
|
119
|
+
* but only type casting.
|
|
120
|
+
*/
|
|
121
|
+
function asUnixTimestamp(n) {
|
|
122
|
+
return n;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Casts an arbitrary number as UnixTimestamp2000.
|
|
126
|
+
* Throws if the number is not inside 2000-01-01 and 2500-01-01 time interval,
|
|
127
|
+
* which would indicate a bug.
|
|
128
|
+
*/
|
|
129
|
+
function asUnixTimestamp2000(n) {
|
|
130
|
+
if (!n || n < zod_shared_schemas_1.TS_2000 || n > zod_shared_schemas_1.TS_2500) {
|
|
131
|
+
throw new error_util_1.AssertionError(`Number is not a valid UnixTimestamp2000: ${n}`, {
|
|
132
|
+
fingerprint: 'asUnixTimestamp2000',
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
return n;
|
|
136
|
+
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { ErrorData } from '../error/error.model';
|
|
4
4
|
import type { CommonLogger } from '../log/commonLogger';
|
|
5
5
|
import type { Promisable } from '../typeFest';
|
|
6
|
-
import type { AnyObject, NumberOfMilliseconds, Reviver,
|
|
6
|
+
import type { AnyObject, NumberOfMilliseconds, Reviver, UnixTimestampMillis } from '../types';
|
|
7
7
|
import type { HttpMethod, HttpStatusFamily } from './http.model';
|
|
8
8
|
export interface FetcherNormalizedCfg extends Required<FetcherCfg>, Omit<FetcherRequest, 'started' | 'fullUrl' | 'logRequest' | 'logRequestBody' | 'logResponse' | 'logResponseBody' | 'debug' | 'redirect' | 'credentials' | 'throwHttpErrors' | 'errorData'> {
|
|
9
9
|
logger: CommonLogger;
|
|
@@ -114,7 +114,7 @@ export interface FetcherRequest extends Omit<FetcherOptions, 'method' | 'headers
|
|
|
114
114
|
retry3xx: boolean;
|
|
115
115
|
retry4xx: boolean;
|
|
116
116
|
retry5xx: boolean;
|
|
117
|
-
started:
|
|
117
|
+
started: UnixTimestampMillis;
|
|
118
118
|
}
|
|
119
119
|
export interface FetcherOptions {
|
|
120
120
|
method?: HttpMethod;
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export * from './decorators/memoFnAsync';
|
|
|
27
27
|
export * from './decorators/retry.decorator';
|
|
28
28
|
export * from './decorators/timeout.decorator';
|
|
29
29
|
export * from './define';
|
|
30
|
+
export * from './deviceIdService';
|
|
30
31
|
export * from './enum.util';
|
|
31
32
|
export * from './env';
|
|
32
33
|
export * from './env/buildInfo';
|
|
@@ -52,6 +53,7 @@ export * from './log/commonLogger';
|
|
|
52
53
|
export * from './math/math.util';
|
|
53
54
|
export * from './math/sma';
|
|
54
55
|
export * from './math/stack.util';
|
|
56
|
+
export * from './nanoid';
|
|
55
57
|
export * from './number/createDeterministicRandom';
|
|
56
58
|
export * from './number/number.util';
|
|
57
59
|
export * from './object/deepEquals';
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,7 @@ tslib_1.__exportStar(require("./decorators/memoFnAsync"), exports);
|
|
|
31
31
|
tslib_1.__exportStar(require("./decorators/retry.decorator"), exports);
|
|
32
32
|
tslib_1.__exportStar(require("./decorators/timeout.decorator"), exports);
|
|
33
33
|
tslib_1.__exportStar(require("./define"), exports);
|
|
34
|
+
tslib_1.__exportStar(require("./deviceIdService"), exports);
|
|
34
35
|
tslib_1.__exportStar(require("./enum.util"), exports);
|
|
35
36
|
tslib_1.__exportStar(require("./env"), exports);
|
|
36
37
|
tslib_1.__exportStar(require("./env/buildInfo"), exports);
|
|
@@ -56,6 +57,7 @@ tslib_1.__exportStar(require("./log/commonLogger"), exports);
|
|
|
56
57
|
tslib_1.__exportStar(require("./math/math.util"), exports);
|
|
57
58
|
tslib_1.__exportStar(require("./math/sma"), exports);
|
|
58
59
|
tslib_1.__exportStar(require("./math/stack.util"), exports);
|
|
60
|
+
tslib_1.__exportStar(require("./nanoid"), exports);
|
|
59
61
|
tslib_1.__exportStar(require("./number/createDeterministicRandom"), exports);
|
|
60
62
|
tslib_1.__exportStar(require("./number/number.util"), exports);
|
|
61
63
|
tslib_1.__exportStar(require("./object/deepEquals"), exports);
|
package/dist/nanoid.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference lib="dom" preserve="true" />
|
|
2
|
+
/**
|
|
3
|
+
* Function that takes a length (defaults to 21) and generates a random string id of that length.
|
|
4
|
+
*/
|
|
5
|
+
export type NanoidFunction = (length?: number) => string;
|
|
6
|
+
export declare function nanoidBrowser(length?: number): string;
|
|
7
|
+
export declare function nanoidBrowserCustomAlphabet(alphabet: string, length?: number): NanoidFunction;
|
package/dist/nanoid.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Vendored from https://github.com/ai/nanoid/blob/main/index.browser.js
|
|
3
|
+
// All credit to nanoid authors: https://github.com/ai/nanoid
|
|
4
|
+
// Reason for vendoring: (still) cannot import esm, and Nanoid went ESM-only since 4.0
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.nanoidBrowser = nanoidBrowser;
|
|
7
|
+
exports.nanoidBrowserCustomAlphabet = nanoidBrowserCustomAlphabet;
|
|
8
|
+
/// <reference lib="dom" preserve="true" />
|
|
9
|
+
/* eslint-disable no-bitwise */
|
|
10
|
+
// "0-9a-zA-Z-_", same as base64url alphabet
|
|
11
|
+
const urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
|
|
12
|
+
function nanoidBrowser(length = 21) {
|
|
13
|
+
let id = '';
|
|
14
|
+
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(length));
|
|
15
|
+
while (length--) {
|
|
16
|
+
// Using the bitwise AND operator to "cap" the value of
|
|
17
|
+
// the random byte from 255 to 63, in that way we can make sure
|
|
18
|
+
// that the value will be a valid index for the "chars" string.
|
|
19
|
+
id += urlAlphabet[bytes[length] & 63];
|
|
20
|
+
}
|
|
21
|
+
return id;
|
|
22
|
+
}
|
|
23
|
+
const defaultRandomFunction = (bytes) => globalThis.crypto.getRandomValues(new Uint8Array(bytes));
|
|
24
|
+
function nanoidBrowserCustomAlphabet(alphabet, length = 21) {
|
|
25
|
+
return customRandom(alphabet, length, defaultRandomFunction);
|
|
26
|
+
}
|
|
27
|
+
function customRandom(alphabet, defaultSize, getRandom) {
|
|
28
|
+
// First, a bitmask is necessary to generate the ID. The bitmask makes bytes
|
|
29
|
+
// values closer to the alphabet size. The bitmask calculates the closest
|
|
30
|
+
// `2^31 - 1` number, which exceeds the alphabet size.
|
|
31
|
+
// For example, the bitmask for the alphabet size 30 is 31 (00011111).
|
|
32
|
+
// `Math.clz32` is not used, because it is not available in browsers.
|
|
33
|
+
const mask = (2 << Math.log2(alphabet.length - 1)) - 1;
|
|
34
|
+
// Though, the bitmask solution is not perfect since the bytes exceeding
|
|
35
|
+
// the alphabet size are refused. Therefore, to reliably generate the ID,
|
|
36
|
+
// the random bytes redundancy has to be satisfied.
|
|
37
|
+
// Note: every hardware random generator call is performance expensive,
|
|
38
|
+
// because the system call for entropy collection takes a lot of time.
|
|
39
|
+
// So, to avoid additional system calls, extra bytes are requested in advance.
|
|
40
|
+
// Next, a step determines how many random bytes to generate.
|
|
41
|
+
// The number of random bytes gets decided upon the ID size, mask,
|
|
42
|
+
// alphabet size, and magic number 1.6 (using 1.6 peaks at performance
|
|
43
|
+
// according to benchmarks).
|
|
44
|
+
// `-~f => Math.ceil(f)` if f is a float
|
|
45
|
+
// `-~i => i + 1` if i is an integer
|
|
46
|
+
const step = -~((1.6 * mask * defaultSize) / alphabet.length);
|
|
47
|
+
return (size = defaultSize) => {
|
|
48
|
+
let id = '';
|
|
49
|
+
while (true) {
|
|
50
|
+
const bytes = getRandom(step);
|
|
51
|
+
// A compact alternative for `for (var i = 0; i < step; i++)`.
|
|
52
|
+
let j = step;
|
|
53
|
+
while (j--) {
|
|
54
|
+
// Adding `|| ''` refuses a random byte that exceeds the alphabet size.
|
|
55
|
+
id += alphabet[bytes[j] & mask] || '';
|
|
56
|
+
if (id.length === size)
|
|
57
|
+
return id;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function that returns a random number between 0 and 1.
|
|
3
|
+
* Exactly same signature as Math.random function.
|
|
4
|
+
*/
|
|
5
|
+
export type RandomFunction = () => number;
|
|
1
6
|
/**
|
|
2
7
|
* Returns a "deterministic Math.random() function"
|
|
3
8
|
*
|
|
4
9
|
* Based on: https://gist.github.com/mathiasbynens/5670917
|
|
5
10
|
*/
|
|
6
|
-
export declare function _createDeterministicRandom():
|
|
11
|
+
export declare function _createDeterministicRandom(seed?: number): RandomFunction;
|
|
@@ -7,8 +7,7 @@ exports._createDeterministicRandom = _createDeterministicRandom;
|
|
|
7
7
|
*
|
|
8
8
|
* Based on: https://gist.github.com/mathiasbynens/5670917
|
|
9
9
|
*/
|
|
10
|
-
function _createDeterministicRandom() {
|
|
11
|
-
let seed = 0x2f6e2b1;
|
|
10
|
+
function _createDeterministicRandom(seed = 0x2f6e2b1) {
|
|
12
11
|
return () => {
|
|
13
12
|
// Robert Jenkins’ 32 bit integer hash function
|
|
14
13
|
seed = (seed + 0x7ed55d16 + (seed << 12)) & 0xffffffff;
|
|
@@ -6,7 +6,7 @@ import { Integer } from '../types';
|
|
|
6
6
|
*
|
|
7
7
|
* 1. Performance
|
|
8
8
|
* 2. For non-cryptographic use (where accidental collision is not the end-of-the-world)
|
|
9
|
-
* 3. Compact size (32 bits max, versus 128 in md5; presented in
|
|
9
|
+
* 3. Compact size (32 bits max, versus 128 in md5; presented in smaller number of string json-safe characters)
|
|
10
10
|
*
|
|
11
11
|
* Basically, these functions are as simple as they can be, but still "random enough" for
|
|
12
12
|
* normal non-cryptographic use cases.
|
package/dist/string/hash.util.js
CHANGED
|
@@ -14,7 +14,7 @@ const BASE64URL = BASE62 + '-_';
|
|
|
14
14
|
*
|
|
15
15
|
* 1. Performance
|
|
16
16
|
* 2. For non-cryptographic use (where accidental collision is not the end-of-the-world)
|
|
17
|
-
* 3. Compact size (32 bits max, versus 128 in md5; presented in
|
|
17
|
+
* 3. Compact size (32 bits max, versus 128 in md5; presented in smaller number of string json-safe characters)
|
|
18
18
|
*
|
|
19
19
|
* Basically, these functions are as simple as they can be, but still "random enough" for
|
|
20
20
|
* normal non-cryptographic use cases.
|
package/dist/time/time.util.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { NumberOfMilliseconds, UnixTimestampMillis } from '../types';
|
|
1
2
|
/**
|
|
2
3
|
* using _ = blockTimer()
|
|
3
4
|
* // will log "took 1.234 sec" on dispose
|
|
@@ -11,7 +12,7 @@ export declare function _blockTimer(name?: string): Disposable;
|
|
|
11
12
|
/**
|
|
12
13
|
* Returns time passed since `from` until `until` (default to Date.now())
|
|
13
14
|
*/
|
|
14
|
-
export declare function _since(from:
|
|
15
|
+
export declare function _since(from: UnixTimestampMillis, until?: UnixTimestampMillis): string;
|
|
15
16
|
/**
|
|
16
17
|
* Returns, e.g:
|
|
17
18
|
* 125 ms
|
|
@@ -21,4 +22,4 @@ export declare function _since(from: number, until?: number): string;
|
|
|
21
22
|
* 59m2s
|
|
22
23
|
* 1h3m12s
|
|
23
24
|
*/
|
|
24
|
-
export declare function _ms(millis:
|
|
25
|
+
export declare function _ms(millis: NumberOfMilliseconds): string;
|
package/dist/types.d.ts
CHANGED
|
@@ -54,24 +54,24 @@ export type BaseDBEntity = {
|
|
|
54
54
|
/**
|
|
55
55
|
* unixTimestamp of when the entity was first created (in the DB).
|
|
56
56
|
*/
|
|
57
|
-
created:
|
|
57
|
+
created: UnixTimestamp;
|
|
58
58
|
/**
|
|
59
59
|
* unixTimestamp of when the entity was last updated (in the DB).
|
|
60
60
|
*/
|
|
61
|
-
updated:
|
|
61
|
+
updated: UnixTimestamp;
|
|
62
62
|
};
|
|
63
63
|
export type Saved<T> = T & {
|
|
64
64
|
id: string;
|
|
65
|
-
created:
|
|
66
|
-
updated:
|
|
65
|
+
created: UnixTimestamp;
|
|
66
|
+
updated: UnixTimestamp;
|
|
67
67
|
};
|
|
68
68
|
export type SavedId<T> = T & {
|
|
69
69
|
id: string;
|
|
70
70
|
};
|
|
71
71
|
export type Unsaved<T> = Omit<T, 'id' | 'created' | 'updated'> & {
|
|
72
72
|
id?: string;
|
|
73
|
-
created?:
|
|
74
|
-
updated?:
|
|
73
|
+
created?: UnixTimestamp;
|
|
74
|
+
updated?: UnixTimestamp;
|
|
75
75
|
};
|
|
76
76
|
export type UnsavedId<T> = Omit<T, 'id'> & {
|
|
77
77
|
id?: string;
|
|
@@ -191,17 +191,19 @@ export type IsoDateTimeString = string;
|
|
|
191
191
|
*/
|
|
192
192
|
export type MonthId = string;
|
|
193
193
|
/**
|
|
194
|
-
*
|
|
194
|
+
* Branded UnixTimestamp in seconds.
|
|
195
|
+
* Extends (compatible with) `number`.
|
|
195
196
|
*
|
|
196
197
|
* @example 1628945450
|
|
197
198
|
*/
|
|
198
|
-
export type
|
|
199
|
+
export type UnixTimestamp = Branded<number, 'UnixTimestamp'>;
|
|
199
200
|
/**
|
|
200
|
-
*
|
|
201
|
+
* Branded UnixTimestamp in milliseconds (not seconds).
|
|
202
|
+
* Extends (compatible with) `number`.
|
|
201
203
|
*
|
|
202
204
|
* @example 1628945450000
|
|
203
205
|
*/
|
|
204
|
-
export type
|
|
206
|
+
export type UnixTimestampMillis = Branded<number, 'UnixTimestampMillis'>;
|
|
205
207
|
export type NumberOfHours = number;
|
|
206
208
|
export type NumberOfMinutes = number;
|
|
207
209
|
export type NumberOfSeconds = number;
|
package/dist/web.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ import { StringMap } from './types';
|
|
|
5
5
|
* Implements WebStorage API by using in-memory storage.
|
|
6
6
|
* Can be useful in SSR environment or unit tests.
|
|
7
7
|
*
|
|
8
|
+
* This is how localStorage can be mocked in Node:
|
|
9
|
+
*
|
|
10
|
+
* Object.assign(globalThis, {
|
|
11
|
+
* localStorage: new InMemoryWebStorage(),
|
|
12
|
+
* })
|
|
13
|
+
*
|
|
8
14
|
* @experimental
|
|
9
15
|
*/
|
|
10
16
|
export declare class InMemoryWebStorage implements Storage {
|
package/dist/web.js
CHANGED
|
@@ -7,6 +7,12 @@ exports.InMemoryWebStorage = void 0;
|
|
|
7
7
|
* Implements WebStorage API by using in-memory storage.
|
|
8
8
|
* Can be useful in SSR environment or unit tests.
|
|
9
9
|
*
|
|
10
|
+
* This is how localStorage can be mocked in Node:
|
|
11
|
+
*
|
|
12
|
+
* Object.assign(globalThis, {
|
|
13
|
+
* localStorage: new InMemoryWebStorage(),
|
|
14
|
+
* })
|
|
15
|
+
*
|
|
10
16
|
* @experimental
|
|
11
17
|
*/
|
|
12
18
|
class InMemoryWebStorage {
|