@naturalcycles/js-lib 14.256.0 → 14.258.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/cfg/frontend/tsconfig.json +67 -0
- package/dist/browser/adminService.d.ts +69 -0
- package/dist/browser/adminService.js +98 -0
- package/dist/browser/analytics.util.d.ts +12 -0
- package/dist/browser/analytics.util.js +59 -0
- package/dist/browser/i18n/fetchTranslationLoader.d.ts +13 -0
- package/dist/browser/i18n/fetchTranslationLoader.js +17 -0
- package/dist/browser/i18n/translation.service.d.ts +53 -0
- package/dist/browser/i18n/translation.service.js +61 -0
- package/dist/browser/imageFitter.d.ts +60 -0
- package/dist/browser/imageFitter.js +69 -0
- package/dist/browser/script.util.d.ts +14 -0
- package/dist/browser/script.util.js +50 -0
- package/dist/browser/topbar.d.ts +23 -0
- package/dist/browser/topbar.js +137 -0
- package/dist/decorators/memo.util.d.ts +2 -1
- package/dist/decorators/memo.util.js +8 -6
- package/dist/decorators/swarmSafe.decorator.d.ts +9 -0
- package/dist/decorators/swarmSafe.decorator.js +42 -0
- package/dist/deviceIdService.d.ts +65 -0
- package/dist/deviceIdService.js +109 -0
- package/dist/error/assert.d.ts +2 -1
- package/dist/error/assert.js +15 -13
- package/dist/error/error.util.js +9 -6
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -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/web.d.ts +6 -0
- package/dist/web.js +6 -0
- package/dist/zod/zod.util.d.ts +1 -1
- package/dist-esm/browser/adminService.js +94 -0
- package/dist-esm/browser/analytics.util.js +54 -0
- package/dist-esm/browser/i18n/fetchTranslationLoader.js +13 -0
- package/dist-esm/browser/i18n/translation.service.js +56 -0
- package/dist-esm/browser/imageFitter.js +65 -0
- package/dist-esm/browser/script.util.js +46 -0
- package/dist-esm/browser/topbar.js +134 -0
- package/dist-esm/decorators/memo.util.js +3 -1
- package/dist-esm/decorators/swarmSafe.decorator.js +38 -0
- package/dist-esm/deviceIdService.js +105 -0
- package/dist-esm/error/assert.js +3 -1
- package/dist-esm/error/error.util.js +4 -1
- package/dist-esm/index.js +9 -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 +2 -1
- package/src/browser/adminService.ts +157 -0
- package/src/browser/analytics.util.ts +68 -0
- package/src/browser/i18n/fetchTranslationLoader.ts +16 -0
- package/src/browser/i18n/translation.service.ts +102 -0
- package/src/browser/imageFitter.ts +128 -0
- package/src/browser/script.util.ts +52 -0
- package/src/browser/topbar.ts +147 -0
- package/src/datetime/localDate.ts +16 -0
- package/src/datetime/localTime.ts +39 -0
- package/src/decorators/debounce.ts +1 -0
- package/src/decorators/memo.util.ts +4 -1
- package/src/decorators/swarmSafe.decorator.ts +47 -0
- package/src/deviceIdService.ts +137 -0
- package/src/error/assert.ts +5 -11
- package/src/error/error.util.ts +4 -1
- package/src/index.ts +9 -0
- package/src/json-schema/jsonSchemaBuilder.ts +20 -0
- package/src/nanoid.ts +79 -0
- package/src/number/createDeterministicRandom.ts +7 -2
- package/src/semver.ts +2 -0
- package/src/string/hash.util.ts +1 -1
- package/src/web.ts +6 -0
- package/src/zod/zod.util.ts +1 -1
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Modified version of topbar:
|
|
3
|
+
// http://buunguyen.github.io/topbar
|
|
4
|
+
/* eslint-disable */
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.topbar = void 0;
|
|
7
|
+
const browser = typeof window !== 'undefined';
|
|
8
|
+
let canvas;
|
|
9
|
+
let progressTimerId;
|
|
10
|
+
let fadeTimerId;
|
|
11
|
+
let currentProgress;
|
|
12
|
+
let showing;
|
|
13
|
+
const addEvent = (elem, type, handler) => {
|
|
14
|
+
if (elem.addEventListener)
|
|
15
|
+
elem.addEventListener(type, handler, false);
|
|
16
|
+
else if (elem.attachEvent)
|
|
17
|
+
elem.attachEvent('on' + type, handler);
|
|
18
|
+
else
|
|
19
|
+
elem['on' + type] = handler;
|
|
20
|
+
};
|
|
21
|
+
const options = {
|
|
22
|
+
autoRun: true,
|
|
23
|
+
barThickness: 5,
|
|
24
|
+
barColors: {
|
|
25
|
+
'0': 'rgba(26, 188, 156, .9)',
|
|
26
|
+
'.25': 'rgba(52, 152, 219, .9)',
|
|
27
|
+
'.50': 'rgba(241, 196, 15, .9)',
|
|
28
|
+
'.75': 'rgba(230, 126, 34, .9)',
|
|
29
|
+
'1.0': 'rgba(211, 84, 0, .9)',
|
|
30
|
+
},
|
|
31
|
+
shadowBlur: 10,
|
|
32
|
+
shadowColor: 'rgba(0, 0, 0, .6)',
|
|
33
|
+
};
|
|
34
|
+
const repaint = () => {
|
|
35
|
+
canvas.width = window.innerWidth;
|
|
36
|
+
canvas.height = options.barThickness * 5; // need space for shadow
|
|
37
|
+
const ctx = canvas.getContext('2d');
|
|
38
|
+
ctx.shadowBlur = options.shadowBlur;
|
|
39
|
+
ctx.shadowColor = options.shadowColor;
|
|
40
|
+
const lineGradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
|
|
41
|
+
for (const stop in options.barColors) {
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
lineGradient.addColorStop(stop, options.barColors[stop]);
|
|
44
|
+
}
|
|
45
|
+
ctx.lineWidth = options.barThickness;
|
|
46
|
+
ctx.beginPath();
|
|
47
|
+
ctx.moveTo(0, options.barThickness / 2);
|
|
48
|
+
ctx.lineTo(Math.ceil(currentProgress * canvas.width), options.barThickness / 2);
|
|
49
|
+
ctx.strokeStyle = lineGradient;
|
|
50
|
+
ctx.stroke();
|
|
51
|
+
};
|
|
52
|
+
const createCanvas = () => {
|
|
53
|
+
canvas = document.createElement('canvas');
|
|
54
|
+
const style = canvas.style;
|
|
55
|
+
style.position = 'fixed';
|
|
56
|
+
style.top = style.left = style.right = style.margin = style.padding = 0;
|
|
57
|
+
style.zIndex = 100001;
|
|
58
|
+
style.display = 'none';
|
|
59
|
+
document.body.appendChild(canvas);
|
|
60
|
+
addEvent(window, 'resize', repaint);
|
|
61
|
+
};
|
|
62
|
+
exports.topbar = {
|
|
63
|
+
config(opts) {
|
|
64
|
+
for (const key in opts) {
|
|
65
|
+
if (options.hasOwnProperty(key)) {
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
options[key] = opts[key];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
set(show, opts) {
|
|
72
|
+
if (show) {
|
|
73
|
+
exports.topbar.show(opts);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
exports.topbar.hide();
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
show(opts) {
|
|
80
|
+
if (!browser)
|
|
81
|
+
return; // ssr protection
|
|
82
|
+
if (opts)
|
|
83
|
+
exports.topbar.config(opts);
|
|
84
|
+
if (showing)
|
|
85
|
+
return;
|
|
86
|
+
showing = true;
|
|
87
|
+
if (fadeTimerId !== null) {
|
|
88
|
+
window.cancelAnimationFrame(fadeTimerId);
|
|
89
|
+
}
|
|
90
|
+
if (!canvas)
|
|
91
|
+
createCanvas();
|
|
92
|
+
canvas.style.opacity = 1;
|
|
93
|
+
canvas.style.display = 'block';
|
|
94
|
+
exports.topbar.progress(0);
|
|
95
|
+
if (options.autoRun) {
|
|
96
|
+
;
|
|
97
|
+
(function loop() {
|
|
98
|
+
progressTimerId = window.requestAnimationFrame(loop);
|
|
99
|
+
exports.topbar.progress('+' + 0.05 * (1 - Math.sqrt(currentProgress)) ** 2);
|
|
100
|
+
})();
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
progress(to) {
|
|
104
|
+
if (!browser)
|
|
105
|
+
return; // ssr protection
|
|
106
|
+
if (typeof to === 'undefined') {
|
|
107
|
+
return currentProgress;
|
|
108
|
+
}
|
|
109
|
+
if (typeof to === 'string') {
|
|
110
|
+
to = (to.indexOf('+') >= 0 || to.indexOf('-') >= 0 ? currentProgress : 0) + parseFloat(to);
|
|
111
|
+
}
|
|
112
|
+
currentProgress = to > 1 ? 1 : to;
|
|
113
|
+
repaint();
|
|
114
|
+
return currentProgress;
|
|
115
|
+
},
|
|
116
|
+
hide() {
|
|
117
|
+
if (!showing || !browser)
|
|
118
|
+
return;
|
|
119
|
+
showing = false;
|
|
120
|
+
if (progressTimerId != null) {
|
|
121
|
+
window.cancelAnimationFrame(progressTimerId);
|
|
122
|
+
progressTimerId = null;
|
|
123
|
+
}
|
|
124
|
+
;
|
|
125
|
+
(function loop() {
|
|
126
|
+
if (exports.topbar.progress('+.1') >= 1) {
|
|
127
|
+
canvas.style.opacity -= 0.05;
|
|
128
|
+
if (canvas.style.opacity <= 0.05) {
|
|
129
|
+
canvas.style.display = 'none';
|
|
130
|
+
fadeTimerId = null;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
fadeTimerId = window.requestAnimationFrame(loop);
|
|
135
|
+
})();
|
|
136
|
+
},
|
|
137
|
+
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { UnixTimestampNumber } from '../types';
|
|
2
|
+
import { MISS } from '../types';
|
|
2
3
|
export type MemoSerializer = (args: any[]) => any;
|
|
3
4
|
export declare const jsonMemoSerializer: MemoSerializer;
|
|
4
5
|
export interface MemoCacheOptions {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MapAsyncMemoCache = exports.MapMemoCache = exports.jsonMemoSerializer = void 0;
|
|
4
|
-
const
|
|
4
|
+
const is_util_1 = require("../is.util");
|
|
5
|
+
const pDelay_1 = require("../promise/pDelay");
|
|
6
|
+
const types_1 = require("../types");
|
|
5
7
|
const jsonMemoSerializer = args => {
|
|
6
8
|
if (args.length === 0)
|
|
7
9
|
return undefined;
|
|
8
|
-
if (args.length === 1 && (0,
|
|
10
|
+
if (args.length === 1 && (0, is_util_1._isPrimitive)(args[0]))
|
|
9
11
|
return args[0];
|
|
10
12
|
return JSON.stringify(args);
|
|
11
13
|
};
|
|
@@ -84,17 +86,17 @@ class MapAsyncMemoCache {
|
|
|
84
86
|
this.m = new Map();
|
|
85
87
|
}
|
|
86
88
|
async get(k) {
|
|
87
|
-
await (0,
|
|
89
|
+
await (0, pDelay_1.pDelay)(this.delay);
|
|
88
90
|
if (!this.m.has(k))
|
|
89
|
-
return
|
|
91
|
+
return types_1.MISS;
|
|
90
92
|
return this.m.get(k);
|
|
91
93
|
}
|
|
92
94
|
async set(k, v) {
|
|
93
|
-
await (0,
|
|
95
|
+
await (0, pDelay_1.pDelay)(this.delay);
|
|
94
96
|
this.m.set(k, v);
|
|
95
97
|
}
|
|
96
98
|
async clear() {
|
|
97
|
-
await (0,
|
|
99
|
+
await (0, pDelay_1.pDelay)(this.delay);
|
|
98
100
|
this.m.clear();
|
|
99
101
|
}
|
|
100
102
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prevents "swarm" of async calls to the same method.
|
|
3
|
+
* Allows max 1 in-flight promise to exist.
|
|
4
|
+
* If more calls appear, while Promise is not resolved yet - same Promise is returned.
|
|
5
|
+
*
|
|
6
|
+
* Does not support `cacheKey`.
|
|
7
|
+
* So, the same Promise is returned, regardless of the arguments.
|
|
8
|
+
*/
|
|
9
|
+
export declare const _SwarmSafe: () => MethodDecorator;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports._SwarmSafe = void 0;
|
|
4
|
+
const decorator_util_1 = require("./decorator.util");
|
|
5
|
+
/**
|
|
6
|
+
* Prevents "swarm" of async calls to the same method.
|
|
7
|
+
* Allows max 1 in-flight promise to exist.
|
|
8
|
+
* If more calls appear, while Promise is not resolved yet - same Promise is returned.
|
|
9
|
+
*
|
|
10
|
+
* Does not support `cacheKey`.
|
|
11
|
+
* So, the same Promise is returned, regardless of the arguments.
|
|
12
|
+
*/
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
14
|
+
const _SwarmSafe = () => (target, key, descriptor) => {
|
|
15
|
+
if (typeof descriptor.value !== 'function') {
|
|
16
|
+
throw new TypeError('@_SwarmSafe can be applied only to methods');
|
|
17
|
+
}
|
|
18
|
+
const originalFn = descriptor.value;
|
|
19
|
+
const keyStr = String(key);
|
|
20
|
+
const methodSignature = (0, decorator_util_1._getTargetMethodSignature)(target, keyStr);
|
|
21
|
+
const instanceCache = new Map();
|
|
22
|
+
console.log('SwarmSafe constructor called', { key, methodSignature });
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
24
|
+
descriptor.value = function (...args) {
|
|
25
|
+
console.log('SwarmSafe method called', { key, methodSignature, args });
|
|
26
|
+
const ctx = this;
|
|
27
|
+
let inFlightPromise = instanceCache.get(ctx);
|
|
28
|
+
if (inFlightPromise) {
|
|
29
|
+
console.log(`SwarmSafe: returning in-flight promise`);
|
|
30
|
+
return inFlightPromise;
|
|
31
|
+
}
|
|
32
|
+
console.log(`SwarmSafe: first-time call, creating in-flight promise`);
|
|
33
|
+
inFlightPromise = originalFn.apply(ctx, args);
|
|
34
|
+
instanceCache.set(ctx, inFlightPromise);
|
|
35
|
+
void inFlightPromise.finally(() => {
|
|
36
|
+
console.log(`SwarmSafe: in-flight promise resolved`);
|
|
37
|
+
instanceCache.delete(ctx);
|
|
38
|
+
});
|
|
39
|
+
return inFlightPromise;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
exports._SwarmSafe = _SwarmSafe;
|
|
@@ -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/error/assert.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Class } from '../typeFest';
|
|
2
|
+
import type { BackendErrorResponseObject, ErrorData, ErrorObject } from './error.model';
|
|
2
3
|
/**
|
|
3
4
|
* Evaluates the `condition` (casts it to Boolean).
|
|
4
5
|
* Expects it to be truthy, otherwise throws AppError.
|
package/dist/error/assert.js
CHANGED
|
@@ -10,7 +10,9 @@ exports._assertIsBackendErrorResponseObject = _assertIsBackendErrorResponseObjec
|
|
|
10
10
|
exports._assertIsString = _assertIsString;
|
|
11
11
|
exports._assertIsNumber = _assertIsNumber;
|
|
12
12
|
exports._assertTypeOf = _assertTypeOf;
|
|
13
|
-
const
|
|
13
|
+
const deepEquals_1 = require("../object/deepEquals");
|
|
14
|
+
const stringify_1 = require("../string/stringify");
|
|
15
|
+
const error_util_1 = require("./error.util");
|
|
14
16
|
/**
|
|
15
17
|
* Evaluates the `condition` (casts it to Boolean).
|
|
16
18
|
* Expects it to be truthy, otherwise throws AppError.
|
|
@@ -30,7 +32,7 @@ const __1 = require("..");
|
|
|
30
32
|
function _assert(condition, // will be evaluated as Boolean
|
|
31
33
|
message, errorData) {
|
|
32
34
|
if (!condition) {
|
|
33
|
-
throw new
|
|
35
|
+
throw new error_util_1.AssertionError(message || 'condition failed', {
|
|
34
36
|
...errorData,
|
|
35
37
|
});
|
|
36
38
|
}
|
|
@@ -44,10 +46,10 @@ message, errorData) {
|
|
|
44
46
|
function _assertEquals(actual, expected, message, errorData) {
|
|
45
47
|
if (actual !== expected) {
|
|
46
48
|
const msg = message ||
|
|
47
|
-
['not equal', `expected: ${(0,
|
|
49
|
+
['not equal', `expected: ${(0, stringify_1._stringify)(expected)}`, `got : ${(0, stringify_1._stringify)(actual)}`]
|
|
48
50
|
.filter(Boolean)
|
|
49
51
|
.join('\n');
|
|
50
|
-
throw new
|
|
52
|
+
throw new error_util_1.AssertionError(msg, {
|
|
51
53
|
...errorData,
|
|
52
54
|
});
|
|
53
55
|
}
|
|
@@ -59,19 +61,19 @@ function _assertEquals(actual, expected, message, errorData) {
|
|
|
59
61
|
* Does DEEP equality via _deepEquals()
|
|
60
62
|
*/
|
|
61
63
|
function _assertDeepEquals(actual, expected, message, errorData) {
|
|
62
|
-
if (!(0,
|
|
64
|
+
if (!(0, deepEquals_1._deepEquals)(actual, expected)) {
|
|
63
65
|
const msg = message ||
|
|
64
|
-
['not deeply equal', `expected: ${(0,
|
|
66
|
+
['not deeply equal', `expected: ${(0, stringify_1._stringify)(expected)}`, `got : ${(0, stringify_1._stringify)(actual)}`]
|
|
65
67
|
.filter(Boolean)
|
|
66
68
|
.join('\n');
|
|
67
|
-
throw new
|
|
69
|
+
throw new error_util_1.AssertionError(msg, {
|
|
68
70
|
...errorData,
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
function _assertIsError(err, errorClass = Error) {
|
|
73
75
|
if (!(err instanceof errorClass)) {
|
|
74
|
-
throw new
|
|
76
|
+
throw new error_util_1.AssertionError(`Expected to be instanceof ${errorClass.name}, actual typeof: ${typeof err}`);
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
/**
|
|
@@ -86,13 +88,13 @@ function _assertErrorClassOrRethrow(err, errorClass) {
|
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
function _assertIsErrorObject(obj) {
|
|
89
|
-
if (!(0,
|
|
90
|
-
throw new
|
|
91
|
+
if (!(0, error_util_1._isErrorObject)(obj)) {
|
|
92
|
+
throw new error_util_1.AssertionError(`Expected to be ErrorObject, actual typeof: ${typeof obj}`);
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
function _assertIsBackendErrorResponseObject(obj) {
|
|
94
|
-
if (!(0,
|
|
95
|
-
throw new
|
|
96
|
+
if (!(0, error_util_1._isBackendErrorResponseObject)(obj)) {
|
|
97
|
+
throw new error_util_1.AssertionError(`Expected to be BackendErrorResponseObject, actual typeof: ${typeof obj}`);
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
function _assertIsString(v, message) {
|
|
@@ -105,6 +107,6 @@ function _assertTypeOf(v, expectedType, message) {
|
|
|
105
107
|
// biome-ignore lint/suspicious/useValidTypeof: ok
|
|
106
108
|
if (typeof v !== expectedType) {
|
|
107
109
|
const msg = message || `Expected typeof ${expectedType}, actual typeof: ${typeof v}`;
|
|
108
|
-
throw new
|
|
110
|
+
throw new error_util_1.AssertionError(msg);
|
|
109
111
|
}
|
|
110
112
|
}
|
package/dist/error/error.util.js
CHANGED
|
@@ -11,7 +11,10 @@ exports._isHttpRequestErrorObject = _isHttpRequestErrorObject;
|
|
|
11
11
|
exports._isErrorObject = _isErrorObject;
|
|
12
12
|
exports._isErrorLike = _isErrorLike;
|
|
13
13
|
exports._errorDataAppend = _errorDataAppend;
|
|
14
|
-
const
|
|
14
|
+
const env_1 = require("../env");
|
|
15
|
+
const json_util_1 = require("../string/json.util");
|
|
16
|
+
const string_util_1 = require("../string/string.util");
|
|
17
|
+
const stringify_1 = require("../string/stringify");
|
|
15
18
|
/**
|
|
16
19
|
* Useful to ensure that error in `catch (err) { ... }`
|
|
17
20
|
* is indeed an Error (and not e.g `string` or `undefined`).
|
|
@@ -51,7 +54,7 @@ function _anyToErrorObject(o, errorData) {
|
|
|
51
54
|
eo = _errorLikeToErrorObject(o);
|
|
52
55
|
}
|
|
53
56
|
else {
|
|
54
|
-
o = (0,
|
|
57
|
+
o = (0, json_util_1._jsonParseIfPossible)(o);
|
|
55
58
|
if (_isBackendErrorResponseObject(o)) {
|
|
56
59
|
eo = o.error;
|
|
57
60
|
}
|
|
@@ -66,7 +69,7 @@ function _anyToErrorObject(o, errorData) {
|
|
|
66
69
|
// so, fair to return `data: {}` in the end
|
|
67
70
|
// Also we're sure it includes no "error name", e.g no `Error: ...`,
|
|
68
71
|
// so, fair to include `name: 'Error'`
|
|
69
|
-
const message = (0,
|
|
72
|
+
const message = (0, stringify_1._stringify)(o);
|
|
70
73
|
eo = {
|
|
71
74
|
name: 'Error',
|
|
72
75
|
message,
|
|
@@ -166,7 +169,7 @@ function _errorSnippet(err, opt = {}) {
|
|
|
166
169
|
lines.push('Caused by ' + errorObjectToSnippet(cause));
|
|
167
170
|
cause = cause.cause; // insert DiCaprio Inception meme
|
|
168
171
|
}
|
|
169
|
-
return lines.map(line => (0,
|
|
172
|
+
return lines.map(line => (0, string_util_1._truncate)(line, maxLineLength)).join('\n');
|
|
170
173
|
function errorObjectToSnippet(e) {
|
|
171
174
|
// Return snippet if it was already prepared
|
|
172
175
|
if (e.data.snippet)
|
|
@@ -247,7 +250,7 @@ class AppError extends Error {
|
|
|
247
250
|
super(message);
|
|
248
251
|
// Here we default to `this.constructor.name` on Node, but to 'AppError' on the Frontend
|
|
249
252
|
// because Frontend tends to minify class names, so `constructor.name` is not reliable
|
|
250
|
-
const { name = (0,
|
|
253
|
+
const { name = (0, env_1.isServerSide)() ? this.constructor.name : 'AppError', cause } = opt;
|
|
251
254
|
Object.defineProperties(this, {
|
|
252
255
|
name: {
|
|
253
256
|
value: name,
|
|
@@ -324,7 +327,7 @@ class AssertionError extends AppError {
|
|
|
324
327
|
exports.AssertionError = AssertionError;
|
|
325
328
|
class JsonParseError extends AppError {
|
|
326
329
|
constructor(data) {
|
|
327
|
-
const message = ['Failed to parse', data.text && (0,
|
|
330
|
+
const message = ['Failed to parse', data.text && (0, string_util_1._truncateMiddle)(data.text, 200)]
|
|
328
331
|
.filter(Boolean)
|
|
329
332
|
.join(': ');
|
|
330
333
|
super(message, data, { name: 'JsonParseError' });
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,13 @@ export * from './abort';
|
|
|
2
2
|
export * from './array/array.util';
|
|
3
3
|
export * from './array/range';
|
|
4
4
|
export * from './bot';
|
|
5
|
+
export * from './browser/adminService';
|
|
6
|
+
export * from './browser/analytics.util';
|
|
7
|
+
export * from './browser/i18n/fetchTranslationLoader';
|
|
8
|
+
export * from './browser/i18n/translation.service';
|
|
9
|
+
export * from './browser/imageFitter';
|
|
10
|
+
export * from './browser/script.util';
|
|
11
|
+
export * from './browser/topbar';
|
|
5
12
|
export * from './datetime/dateInterval';
|
|
6
13
|
export * from './datetime/localDate';
|
|
7
14
|
export * from './datetime/localTime';
|
|
@@ -20,6 +27,7 @@ export * from './decorators/memoFnAsync';
|
|
|
20
27
|
export * from './decorators/retry.decorator';
|
|
21
28
|
export * from './decorators/timeout.decorator';
|
|
22
29
|
export * from './define';
|
|
30
|
+
export * from './deviceIdService';
|
|
23
31
|
export * from './enum.util';
|
|
24
32
|
export * from './env';
|
|
25
33
|
export * from './env/buildInfo';
|
|
@@ -45,6 +53,7 @@ export * from './log/commonLogger';
|
|
|
45
53
|
export * from './math/math.util';
|
|
46
54
|
export * from './math/sma';
|
|
47
55
|
export * from './math/stack.util';
|
|
56
|
+
export * from './nanoid';
|
|
48
57
|
export * from './number/createDeterministicRandom';
|
|
49
58
|
export * from './number/number.util';
|
|
50
59
|
export * from './object/deepEquals';
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,13 @@ tslib_1.__exportStar(require("./abort"), exports);
|
|
|
6
6
|
tslib_1.__exportStar(require("./array/array.util"), exports);
|
|
7
7
|
tslib_1.__exportStar(require("./array/range"), exports);
|
|
8
8
|
tslib_1.__exportStar(require("./bot"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./browser/adminService"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./browser/analytics.util"), exports);
|
|
11
|
+
tslib_1.__exportStar(require("./browser/i18n/fetchTranslationLoader"), exports);
|
|
12
|
+
tslib_1.__exportStar(require("./browser/i18n/translation.service"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./browser/imageFitter"), exports);
|
|
14
|
+
tslib_1.__exportStar(require("./browser/script.util"), exports);
|
|
15
|
+
tslib_1.__exportStar(require("./browser/topbar"), exports);
|
|
9
16
|
tslib_1.__exportStar(require("./datetime/dateInterval"), exports);
|
|
10
17
|
tslib_1.__exportStar(require("./datetime/localDate"), exports);
|
|
11
18
|
tslib_1.__exportStar(require("./datetime/localTime"), exports);
|
|
@@ -24,6 +31,7 @@ tslib_1.__exportStar(require("./decorators/memoFnAsync"), exports);
|
|
|
24
31
|
tslib_1.__exportStar(require("./decorators/retry.decorator"), exports);
|
|
25
32
|
tslib_1.__exportStar(require("./decorators/timeout.decorator"), exports);
|
|
26
33
|
tslib_1.__exportStar(require("./define"), exports);
|
|
34
|
+
tslib_1.__exportStar(require("./deviceIdService"), exports);
|
|
27
35
|
tslib_1.__exportStar(require("./enum.util"), exports);
|
|
28
36
|
tslib_1.__exportStar(require("./env"), exports);
|
|
29
37
|
tslib_1.__exportStar(require("./env/buildInfo"), exports);
|
|
@@ -49,6 +57,7 @@ tslib_1.__exportStar(require("./log/commonLogger"), exports);
|
|
|
49
57
|
tslib_1.__exportStar(require("./math/math.util"), exports);
|
|
50
58
|
tslib_1.__exportStar(require("./math/sma"), exports);
|
|
51
59
|
tslib_1.__exportStar(require("./math/stack.util"), exports);
|
|
60
|
+
tslib_1.__exportStar(require("./nanoid"), exports);
|
|
52
61
|
tslib_1.__exportStar(require("./number/createDeterministicRandom"), exports);
|
|
53
62
|
tslib_1.__exportStar(require("./number/number.util"), exports);
|
|
54
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;
|