@naturalcycles/js-lib 14.255.0 → 14.257.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/bot.d.ts +60 -0
- package/dist/bot.js +129 -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/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 +8 -0
- package/dist/index.js +8 -0
- package/dist/zod/zod.util.d.ts +1 -1
- package/dist-esm/bot.js +125 -0
- 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/error/assert.js +3 -1
- package/dist-esm/error/error.util.js +4 -1
- package/dist-esm/index.js +8 -0
- package/package.json +2 -1
- package/src/bot.ts +155 -0
- 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/error/assert.ts +5 -11
- package/src/error/error.util.ts +4 -1
- package/src/index.ts +8 -0
- package/src/json-schema/jsonSchemaBuilder.ts +20 -0
- package/src/semver.ts +2 -0
- package/src/zod/zod.util.ts +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface FitImagesCfg {
|
|
2
|
+
/**
|
|
3
|
+
* Container of the images
|
|
4
|
+
*/
|
|
5
|
+
containerElement: HTMLElement;
|
|
6
|
+
/**
|
|
7
|
+
* Array of image metadatas (most notably: aspectRatio).
|
|
8
|
+
*/
|
|
9
|
+
images: FitImage[];
|
|
10
|
+
/**
|
|
11
|
+
* Will be called on each layout change.
|
|
12
|
+
* Should be listened to to update the width/height of the images in your DOM.
|
|
13
|
+
*/
|
|
14
|
+
onChange: (images: FitImage[]) => any;
|
|
15
|
+
/**
|
|
16
|
+
* Max image height in pixels.
|
|
17
|
+
*
|
|
18
|
+
* @default 300
|
|
19
|
+
*/
|
|
20
|
+
maxHeight?: number;
|
|
21
|
+
/**
|
|
22
|
+
* Margin between images.
|
|
23
|
+
*
|
|
24
|
+
* @default 8
|
|
25
|
+
*/
|
|
26
|
+
margin?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface FitImage {
|
|
29
|
+
src: string;
|
|
30
|
+
/**
|
|
31
|
+
* width divided by height
|
|
32
|
+
*/
|
|
33
|
+
aspectRatio: number;
|
|
34
|
+
/**
|
|
35
|
+
* Calculated image width to fit the layout.
|
|
36
|
+
*/
|
|
37
|
+
fitWidth?: number;
|
|
38
|
+
/**
|
|
39
|
+
* Calculated image height to fit the layout.
|
|
40
|
+
*/
|
|
41
|
+
fitHeight?: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Calculates the width/height of the images to fit in the layout.
|
|
45
|
+
*
|
|
46
|
+
* Currently does not mutate the cfg.images array, but DOES mutate individual images with .fitWidth, .fitHeight properties.
|
|
47
|
+
*
|
|
48
|
+
* @experimental
|
|
49
|
+
*/
|
|
50
|
+
export declare class ImageFitter {
|
|
51
|
+
constructor(cfg: FitImagesCfg);
|
|
52
|
+
cfg: Required<FitImagesCfg>;
|
|
53
|
+
resizeObserver: ResizeObserver;
|
|
54
|
+
containerWidth: number;
|
|
55
|
+
stop(): void;
|
|
56
|
+
private update;
|
|
57
|
+
private doLayout;
|
|
58
|
+
private getHeigth;
|
|
59
|
+
private setHeight;
|
|
60
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ImageFitter = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Calculates the width/height of the images to fit in the layout.
|
|
6
|
+
*
|
|
7
|
+
* Currently does not mutate the cfg.images array, but DOES mutate individual images with .fitWidth, .fitHeight properties.
|
|
8
|
+
*
|
|
9
|
+
* @experimental
|
|
10
|
+
*/
|
|
11
|
+
class ImageFitter {
|
|
12
|
+
constructor(cfg) {
|
|
13
|
+
this.containerWidth = -1;
|
|
14
|
+
this.cfg = {
|
|
15
|
+
maxHeight: 300,
|
|
16
|
+
margin: 8,
|
|
17
|
+
...cfg,
|
|
18
|
+
};
|
|
19
|
+
this.resizeObserver = new ResizeObserver(entries => this.update(entries));
|
|
20
|
+
this.resizeObserver.observe(cfg.containerElement);
|
|
21
|
+
}
|
|
22
|
+
stop() {
|
|
23
|
+
this.resizeObserver.disconnect();
|
|
24
|
+
}
|
|
25
|
+
update(entries) {
|
|
26
|
+
const width = Math.floor(entries[0].contentRect.width);
|
|
27
|
+
if (width === this.containerWidth)
|
|
28
|
+
return; // we're only interested in width changes
|
|
29
|
+
this.containerWidth = width;
|
|
30
|
+
console.log(`resize ${width}`);
|
|
31
|
+
this.doLayout(this.cfg.images);
|
|
32
|
+
this.cfg.onChange(this.cfg.images);
|
|
33
|
+
}
|
|
34
|
+
doLayout(imgs) {
|
|
35
|
+
if (imgs.length === 0)
|
|
36
|
+
return; // nothing to do
|
|
37
|
+
const { maxHeight } = this.cfg;
|
|
38
|
+
let imgNodes = imgs.slice(0);
|
|
39
|
+
w: while (imgNodes.length > 0) {
|
|
40
|
+
let slice;
|
|
41
|
+
let h;
|
|
42
|
+
for (let i = 1; i <= imgNodes.length; i++) {
|
|
43
|
+
slice = imgNodes.slice(0, i);
|
|
44
|
+
h = this.getHeigth(slice);
|
|
45
|
+
if (h < maxHeight) {
|
|
46
|
+
this.setHeight(slice, h);
|
|
47
|
+
imgNodes = imgNodes.slice(i);
|
|
48
|
+
continue w;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.setHeight(slice, Math.min(maxHeight, h));
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
getHeigth(images) {
|
|
56
|
+
const width = this.containerWidth - images.length * this.cfg.margin;
|
|
57
|
+
let r = 0;
|
|
58
|
+
images.forEach(img => (r += img.aspectRatio));
|
|
59
|
+
return width / r; // have to round down because Firefox will automatically roundup value with number of decimals > 3
|
|
60
|
+
}
|
|
61
|
+
// mutates/sets images' fitWidth, fitHeight properties
|
|
62
|
+
setHeight(images, height) {
|
|
63
|
+
images.forEach(img => {
|
|
64
|
+
img.fitWidth = Math.floor(height * img.aspectRatio);
|
|
65
|
+
img.fitHeight = Math.floor(height);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.ImageFitter = ImageFitter;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type LoadScriptOptions = Partial<HTMLScriptElement>;
|
|
2
|
+
export type LoadCSSOptions = Partial<HTMLLinkElement>;
|
|
3
|
+
/**
|
|
4
|
+
* opt.async defaults to `true`.
|
|
5
|
+
* No other options are set by default.
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadScript(src: string, opt?: LoadScriptOptions): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Default options:
|
|
10
|
+
* rel: 'stylesheet'
|
|
11
|
+
*
|
|
12
|
+
* No other options are set by default.
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadCSS(href: string, opt?: LoadCSSOptions): Promise<void>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadScript = loadScript;
|
|
4
|
+
exports.loadCSS = loadCSS;
|
|
5
|
+
const env_1 = require("../env");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
/**
|
|
8
|
+
* opt.async defaults to `true`.
|
|
9
|
+
* No other options are set by default.
|
|
10
|
+
*/
|
|
11
|
+
async function loadScript(src, opt) {
|
|
12
|
+
if ((0, env_1.isServerSide)())
|
|
13
|
+
return;
|
|
14
|
+
return await new Promise((resolve, reject) => {
|
|
15
|
+
const s = (0, types_1._objectAssign)(document.createElement('script'), {
|
|
16
|
+
src,
|
|
17
|
+
async: true,
|
|
18
|
+
...opt,
|
|
19
|
+
onload: resolve,
|
|
20
|
+
onerror: (_event, _source, _lineno, _colno, err) => {
|
|
21
|
+
reject(err || new Error(`loadScript failed: ${src}`));
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
document.head.append(s);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Default options:
|
|
29
|
+
* rel: 'stylesheet'
|
|
30
|
+
*
|
|
31
|
+
* No other options are set by default.
|
|
32
|
+
*/
|
|
33
|
+
async function loadCSS(href, opt) {
|
|
34
|
+
if ((0, env_1.isServerSide)())
|
|
35
|
+
return;
|
|
36
|
+
return await new Promise((resolve, reject) => {
|
|
37
|
+
const link = (0, types_1._objectAssign)(document.createElement('link'), {
|
|
38
|
+
href,
|
|
39
|
+
rel: 'stylesheet',
|
|
40
|
+
// type seems to be unnecessary: https://stackoverflow.com/a/5409146/4919972
|
|
41
|
+
// type: 'text/css',
|
|
42
|
+
...opt,
|
|
43
|
+
onload: resolve,
|
|
44
|
+
onerror: (_event, _source, _lineno, _colno, err) => {
|
|
45
|
+
reject(err || new Error(`loadCSS failed: ${href}`));
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
document.head.append(link);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface TopBarOptions {
|
|
2
|
+
/**
|
|
3
|
+
* @default true
|
|
4
|
+
*/
|
|
5
|
+
autoRun?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* @default 5
|
|
8
|
+
*/
|
|
9
|
+
barThickness?: number;
|
|
10
|
+
barColors?: any;
|
|
11
|
+
shadowColor?: any;
|
|
12
|
+
/**
|
|
13
|
+
* @default 10
|
|
14
|
+
*/
|
|
15
|
+
shadowBlur?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare const topbar: {
|
|
18
|
+
config(opts: TopBarOptions): void;
|
|
19
|
+
set(show: boolean, opts?: TopBarOptions): void;
|
|
20
|
+
show(opts?: TopBarOptions): void;
|
|
21
|
+
progress(to: number | string): any;
|
|
22
|
+
hide(): void;
|
|
23
|
+
};
|
|
@@ -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;
|
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
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
export * from './abort';
|
|
2
2
|
export * from './array/array.util';
|
|
3
3
|
export * from './array/range';
|
|
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';
|
|
4
12
|
export * from './datetime/dateInterval';
|
|
5
13
|
export * from './datetime/localDate';
|
|
6
14
|
export * from './datetime/localTime';
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,14 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
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
|
+
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);
|
|
8
16
|
tslib_1.__exportStar(require("./datetime/dateInterval"), exports);
|
|
9
17
|
tslib_1.__exportStar(require("./datetime/localDate"), exports);
|
|
10
18
|
tslib_1.__exportStar(require("./datetime/localTime"), exports);
|
package/dist/zod/zod.util.d.ts
CHANGED