@vpmedia/simplify 1.74.0 → 1.76.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/CHANGELOG.md +75 -0
- package/dist/const/http_status.d.ts +66 -0
- package/dist/const/http_status.d.ts.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1119 -0
- package/dist/index.js.map +1 -0
- package/dist/logging/AbstractLogHandler.d.ts +17 -0
- package/dist/logging/AbstractLogHandler.d.ts.map +1 -0
- package/dist/logging/ConsoleLogHandler.d.ts +13 -0
- package/dist/logging/ConsoleLogHandler.d.ts.map +1 -0
- package/dist/logging/Logger.d.ts +19 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/OpenTelemetryLogHandler.d.ts +15 -0
- package/dist/logging/OpenTelemetryLogHandler.d.ts.map +1 -0
- package/dist/logging/SentryLogHandler.d.ts +13 -0
- package/dist/logging/SentryLogHandler.d.ts.map +1 -0
- package/dist/logging/const.d.ts +14 -0
- package/dist/logging/const.d.ts.map +1 -0
- package/dist/logging/util.d.ts +14 -0
- package/dist/logging/util.d.ts.map +1 -0
- package/dist/pagelifecycle/const.d.ts +15 -0
- package/dist/pagelifecycle/const.d.ts.map +1 -0
- package/dist/pagelifecycle/typedef.d.ts +4 -0
- package/dist/pagelifecycle/typedef.d.ts.map +1 -0
- package/dist/pagelifecycle/util.d.ts +31 -0
- package/dist/pagelifecycle/util.d.ts.map +1 -0
- package/dist/typecheck/TypeCheckError.d.ts +11 -0
- package/dist/typecheck/TypeCheckError.d.ts.map +1 -0
- package/dist/typecheck/TypeChecker.d.ts +27 -0
- package/dist/typecheck/TypeChecker.d.ts.map +1 -0
- package/dist/typecheck/util.d.ts +17 -0
- package/dist/typecheck/util.d.ts.map +1 -0
- package/dist/util/async.d.ts +13 -0
- package/dist/util/async.d.ts.map +1 -0
- package/dist/util/error.d.ts +16 -0
- package/dist/util/error.d.ts.map +1 -0
- package/dist/util/event_emitter.d.ts +42 -0
- package/dist/util/event_emitter.d.ts.map +1 -0
- package/dist/util/fetch.d.ts +22 -0
- package/dist/util/fetch.d.ts.map +1 -0
- package/dist/util/number.d.ts +23 -0
- package/dist/util/number.d.ts.map +1 -0
- package/dist/util/object.d.ts +24 -0
- package/dist/util/object.d.ts.map +1 -0
- package/dist/util/query.d.ts +11 -0
- package/dist/util/query.d.ts.map +1 -0
- package/dist/util/state.d.ts +5 -0
- package/dist/util/state.d.ts.map +1 -0
- package/dist/util/string.d.ts +25 -0
- package/dist/util/string.d.ts.map +1 -0
- package/dist/util/uuid.d.ts +13 -0
- package/dist/util/uuid.d.ts.map +1 -0
- package/dist/util/validate.d.ts +106 -0
- package/dist/util/validate.d.ts.map +1 -0
- package/package.json +32 -16
- package/src/const/http_status.test.ts +7 -0
- package/src/const/{http_status.js → http_status.ts} +1 -1
- package/src/{index.js → index.ts} +8 -0
- package/src/logging/AbstractLogHandler.ts +31 -0
- package/src/logging/{ConsoleLogHandler.js → ConsoleLogHandler.ts} +15 -13
- package/src/logging/Logger.test.ts +69 -0
- package/src/logging/Logger.ts +77 -0
- package/src/logging/OpenTelemetryLogHandler.ts +40 -0
- package/src/logging/SentryLogHandler.ts +44 -0
- package/src/logging/{const.js → const.ts} +1 -1
- package/src/logging/util.test.ts +33 -0
- package/src/logging/util.ts +36 -0
- package/src/pagelifecycle/{const.js → const.ts} +2 -2
- package/src/pagelifecycle/typedef.ts +5 -0
- package/src/pagelifecycle/util.test.ts +99 -0
- package/src/pagelifecycle/{util.js → util.ts} +14 -27
- package/src/typecheck/{TypeCheckError.js → TypeCheckError.ts} +7 -3
- package/src/typecheck/TypeChecker.test.ts +70 -0
- package/src/typecheck/{TypeChecker.js → TypeChecker.ts} +10 -27
- package/src/typecheck/util.test.ts +36 -0
- package/src/typecheck/util.ts +50 -0
- package/src/util/async.test.ts +74 -0
- package/src/util/{async.js → async.ts} +3 -12
- package/src/util/error.test.ts +32 -0
- package/src/util/error.ts +37 -0
- package/src/util/event_emitter.test.ts +228 -0
- package/src/util/event_emitter.ts +147 -0
- package/src/util/fetch.test.ts +62 -0
- package/src/util/{fetch.js → fetch.ts} +40 -31
- package/src/util/number.test.ts +124 -0
- package/src/util/number.ts +58 -0
- package/src/util/object.test.ts +203 -0
- package/src/util/{object.js → object.ts} +14 -21
- package/src/util/query.test.ts +71 -0
- package/src/util/query.ts +35 -0
- package/src/util/state.test.ts +47 -0
- package/src/util/{state.js → state.ts} +3 -6
- package/src/util/string.test.ts +64 -0
- package/src/util/string.ts +65 -0
- package/src/util/uuid.test.ts +53 -0
- package/src/util/uuid.ts +31 -0
- package/src/util/validate.test.ts +309 -0
- package/src/util/validate.ts +230 -0
- package/.vscode/extensions.json +0 -6
- package/.vscode/settings.json +0 -27
- package/src/logging/AbstractLogHandler.js +0 -23
- package/src/logging/Logger.js +0 -115
- package/src/logging/OpenTelemetryLogHandler.js +0 -30
- package/src/logging/SentryLogHandler.js +0 -46
- package/src/logging/util.js +0 -41
- package/src/pagelifecycle/typedef.js +0 -9
- package/src/typecheck/util.js +0 -60
- package/src/util/error.js +0 -33
- package/src/util/event_emitter.js +0 -196
- package/src/util/number.js +0 -118
- package/src/util/query.js +0 -32
- package/src/util/string.js +0 -76
- package/src/util/uuid.js +0 -35
- package/src/util/validate.js +0 -247
- package/types/const/http_status.d.ts +0 -131
- package/types/const/http_status.d.ts.map +0 -1
- package/types/index.d.ts +0 -26
- package/types/index.d.ts.map +0 -1
- package/types/logging/AbstractLogHandler.d.ts +0 -20
- package/types/logging/AbstractLogHandler.d.ts.map +0 -1
- package/types/logging/ConsoleLogHandler.d.ts +0 -9
- package/types/logging/ConsoleLogHandler.d.ts.map +0 -1
- package/types/logging/Logger.d.ts +0 -66
- package/types/logging/Logger.d.ts.map +0 -1
- package/types/logging/OpenTelemetryLogHandler.d.ts +0 -11
- package/types/logging/OpenTelemetryLogHandler.d.ts.map +0 -1
- package/types/logging/SentryLogHandler.d.ts +0 -9
- package/types/logging/SentryLogHandler.d.ts.map +0 -1
- package/types/logging/const.d.ts +0 -14
- package/types/logging/const.d.ts.map +0 -1
- package/types/logging/util.d.ts +0 -4
- package/types/logging/util.d.ts.map +0 -1
- package/types/pagelifecycle/const.d.ts +0 -15
- package/types/pagelifecycle/const.d.ts.map +0 -1
- package/types/pagelifecycle/typedef.d.ts +0 -4
- package/types/pagelifecycle/typedef.d.ts.map +0 -1
- package/types/pagelifecycle/util.d.ts +0 -8
- package/types/pagelifecycle/util.d.ts.map +0 -1
- package/types/typecheck/TypeCheckError.d.ts +0 -13
- package/types/typecheck/TypeCheckError.d.ts.map +0 -1
- package/types/typecheck/TypeChecker.d.ts +0 -40
- package/types/typecheck/TypeChecker.d.ts.map +0 -1
- package/types/typecheck/util.d.ts +0 -4
- package/types/typecheck/util.d.ts.map +0 -1
- package/types/util/async.d.ts +0 -4
- package/types/util/async.d.ts.map +0 -1
- package/types/util/error.d.ts +0 -3
- package/types/util/error.d.ts.map +0 -1
- package/types/util/event_emitter.d.ts +0 -69
- package/types/util/event_emitter.d.ts.map +0 -1
- package/types/util/fetch.d.ts +0 -22
- package/types/util/fetch.d.ts.map +0 -1
- package/types/util/number.d.ts +0 -11
- package/types/util/number.d.ts.map +0 -1
- package/types/util/object.d.ts +0 -6
- package/types/util/object.d.ts.map +0 -1
- package/types/util/query.d.ts +0 -3
- package/types/util/query.d.ts.map +0 -1
- package/types/util/state.d.ts +0 -2
- package/types/util/state.d.ts.map +0 -1
- package/types/util/string.d.ts +0 -7
- package/types/util/string.d.ts.map +0 -1
- package/types/util/uuid.d.ts +0 -4
- package/types/util/uuid.d.ts.map +0 -1
- package/types/util/validate.d.ts +0 -45
- package/types/util/validate.d.ts.map +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,1119 @@
|
|
|
1
|
+
import { addBreadcrumb, captureException, captureMessage } from "@sentry/browser";
|
|
2
|
+
//#region src/const/http_status.ts
|
|
3
|
+
const HTTP_100_CONTINUE = 100;
|
|
4
|
+
const HTTP_101_SWITCHING_PROTOCOLS = 101;
|
|
5
|
+
const HTTP_102_PROCESSING = 102;
|
|
6
|
+
const HTTP_103_EARLY_HINTS = 103;
|
|
7
|
+
const HTTP_200_OK = 200;
|
|
8
|
+
const HTTP_201_CREATED = 201;
|
|
9
|
+
const HTTP_202_ACCEPTED = 202;
|
|
10
|
+
const HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203;
|
|
11
|
+
const HTTP_204_NO_CONTENT = 204;
|
|
12
|
+
const HTTP_205_RESET_CONTENT = 205;
|
|
13
|
+
const HTTP_206_PARTIAL_CONTENT = 206;
|
|
14
|
+
const HTTP_207_MULTI_STATUS = 207;
|
|
15
|
+
const HTTP_208_ALREADY_REPORTED = 208;
|
|
16
|
+
const HTTP_226_IM_USED = 226;
|
|
17
|
+
const HTTP_300_MULTIPLE_CHOICES = 300;
|
|
18
|
+
const HTTP_301_MOVED_PERMANENTLY = 301;
|
|
19
|
+
const HTTP_302_FOUND = 302;
|
|
20
|
+
const HTTP_303_SEE_OTHER = 303;
|
|
21
|
+
const HTTP_304_NOT_MODIFIED = 304;
|
|
22
|
+
const HTTP_305_USE_PROXY = 305;
|
|
23
|
+
const HTTP_306_RESERVED = 306;
|
|
24
|
+
const HTTP_307_TEMPORARY_REDIRECT = 307;
|
|
25
|
+
const HTTP_308_PERMANENT_REDIRECT = 308;
|
|
26
|
+
const HTTP_400_BAD_REQUEST = 400;
|
|
27
|
+
const HTTP_401_UNAUTHORIZED = 401;
|
|
28
|
+
const HTTP_402_PAYMENT_REQUIRED = 402;
|
|
29
|
+
const HTTP_403_FORBIDDEN = 403;
|
|
30
|
+
const HTTP_404_NOT_FOUND = 404;
|
|
31
|
+
const HTTP_405_METHOD_NOT_ALLOWED = 405;
|
|
32
|
+
const HTTP_406_NOT_ACCEPTABLE = 406;
|
|
33
|
+
const HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407;
|
|
34
|
+
const HTTP_408_REQUEST_TIMEOUT = 408;
|
|
35
|
+
const HTTP_409_CONFLICT = 409;
|
|
36
|
+
const HTTP_410_GONE = 410;
|
|
37
|
+
const HTTP_411_LENGTH_REQUIRED = 411;
|
|
38
|
+
const HTTP_412_PRECONDITION_FAILED = 412;
|
|
39
|
+
const HTTP_413_CONTENT_TOO_LARGE = 413;
|
|
40
|
+
const HTTP_414_URI_TOO_LONG = 414;
|
|
41
|
+
const HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415;
|
|
42
|
+
const HTTP_416_RANGE_NOT_SATISFIABLE = 416;
|
|
43
|
+
const HTTP_417_EXPECTATION_FAILED = 417;
|
|
44
|
+
const HTTP_418_IM_A_TEAPOT = 418;
|
|
45
|
+
const HTTP_421_MISDIRECTED_REQUEST = 421;
|
|
46
|
+
const HTTP_422_UNPROCESSABLE_CONTENT = 422;
|
|
47
|
+
const HTTP_423_LOCKED = 423;
|
|
48
|
+
const HTTP_424_FAILED_DEPENDENCY = 424;
|
|
49
|
+
const HTTP_425_TOO_EARLY = 425;
|
|
50
|
+
const HTTP_426_UPGRADE_REQUIRED = 426;
|
|
51
|
+
const HTTP_428_PRECONDITION_REQUIRED = 428;
|
|
52
|
+
const HTTP_429_TOO_MANY_REQUESTS = 429;
|
|
53
|
+
const HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431;
|
|
54
|
+
const HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451;
|
|
55
|
+
const HTTP_499_CLIENT_CLOSED_CONNECTION = 499;
|
|
56
|
+
const HTTP_500_INTERNAL_SERVER_ERROR = 500;
|
|
57
|
+
const HTTP_501_NOT_IMPLEMENTED = 501;
|
|
58
|
+
const HTTP_502_BAD_GATEWAY = 502;
|
|
59
|
+
const HTTP_503_SERVICE_UNAVAILABLE = 503;
|
|
60
|
+
const HTTP_504_GATEWAY_TIMEOUT = 504;
|
|
61
|
+
const HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505;
|
|
62
|
+
const HTTP_506_VARIANT_ALSO_NEGOTIATES = 506;
|
|
63
|
+
const HTTP_507_INSUFFICIENT_STORAGE = 507;
|
|
64
|
+
const HTTP_508_LOOP_DETECTED = 508;
|
|
65
|
+
const HTTP_510_NOT_EXTENDED = 510;
|
|
66
|
+
const HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511;
|
|
67
|
+
const HTTP_STATUS_MAP = {
|
|
68
|
+
[100]: "HTTP_100_CONTINUE",
|
|
69
|
+
[101]: "HTTP_101_SWITCHING_PROTOCOLS",
|
|
70
|
+
[102]: "HTTP_102_PROCESSING",
|
|
71
|
+
[103]: "HTTP_103_EARLY_HINTS",
|
|
72
|
+
[200]: "HTTP_200_OK",
|
|
73
|
+
[201]: "HTTP_201_CREATED",
|
|
74
|
+
[202]: "HTTP_202_ACCEPTED",
|
|
75
|
+
[203]: "HTTP_203_NON_AUTHORITATIVE_INFORMATION",
|
|
76
|
+
[204]: "HTTP_204_NO_CONTENT",
|
|
77
|
+
[205]: "HTTP_205_RESET_CONTENT",
|
|
78
|
+
[206]: "HTTP_206_PARTIAL_CONTENT",
|
|
79
|
+
[207]: "HTTP_207_MULTI_STATUS",
|
|
80
|
+
[208]: "HTTP_208_ALREADY_REPORTED",
|
|
81
|
+
[226]: "HTTP_226_IM_USED",
|
|
82
|
+
[300]: "HTTP_300_MULTIPLE_CHOICES",
|
|
83
|
+
[301]: "HTTP_301_MOVED_PERMANENTLY",
|
|
84
|
+
[302]: "HTTP_302_FOUND",
|
|
85
|
+
[303]: "HTTP_303_SEE_OTHER",
|
|
86
|
+
[304]: "HTTP_304_NOT_MODIFIED",
|
|
87
|
+
[305]: "HTTP_305_USE_PROXY",
|
|
88
|
+
[306]: "HTTP_306_RESERVED",
|
|
89
|
+
[307]: "HTTP_307_TEMPORARY_REDIRECT",
|
|
90
|
+
[308]: "HTTP_308_PERMANENT_REDIRECT",
|
|
91
|
+
[400]: "HTTP_400_BAD_REQUEST",
|
|
92
|
+
[401]: "HTTP_401_UNAUTHORIZED",
|
|
93
|
+
[402]: "HTTP_402_PAYMENT_REQUIRED",
|
|
94
|
+
[403]: "HTTP_403_FORBIDDEN",
|
|
95
|
+
[404]: "HTTP_404_NOT_FOUND",
|
|
96
|
+
[405]: "HTTP_405_METHOD_NOT_ALLOWED",
|
|
97
|
+
[406]: "HTTP_406_NOT_ACCEPTABLE",
|
|
98
|
+
[407]: "HTTP_407_PROXY_AUTHENTICATION_REQUIRED",
|
|
99
|
+
[408]: "HTTP_408_REQUEST_TIMEOUT",
|
|
100
|
+
[409]: "HTTP_409_CONFLICT",
|
|
101
|
+
[410]: "HTTP_410_GONE",
|
|
102
|
+
[411]: "HTTP_411_LENGTH_REQUIRED",
|
|
103
|
+
[412]: "HTTP_412_PRECONDITION_FAILED",
|
|
104
|
+
[413]: "HTTP_413_CONTENT_TOO_LARGE",
|
|
105
|
+
[414]: "HTTP_414_URI_TOO_LONG",
|
|
106
|
+
[415]: "HTTP_415_UNSUPPORTED_MEDIA_TYPE",
|
|
107
|
+
[416]: "HTTP_416_RANGE_NOT_SATISFIABLE",
|
|
108
|
+
[417]: "HTTP_417_EXPECTATION_FAILED",
|
|
109
|
+
[418]: "HTTP_418_IM_A_TEAPOT",
|
|
110
|
+
[421]: "HTTP_421_MISDIRECTED_REQUEST",
|
|
111
|
+
[422]: "HTTP_422_UNPROCESSABLE_CONTENT",
|
|
112
|
+
[423]: "HTTP_423_LOCKED",
|
|
113
|
+
[424]: "HTTP_424_FAILED_DEPENDENCY",
|
|
114
|
+
[425]: "HTTP_425_TOO_EARLY",
|
|
115
|
+
[426]: "HTTP_426_UPGRADE_REQUIRED",
|
|
116
|
+
[428]: "HTTP_428_PRECONDITION_REQUIRED",
|
|
117
|
+
[429]: "HTTP_429_TOO_MANY_REQUESTS",
|
|
118
|
+
[431]: "HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE",
|
|
119
|
+
[451]: "HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS",
|
|
120
|
+
[499]: "HTTP_499_CLIENT_CLOSED_CONNECTION",
|
|
121
|
+
[500]: "HTTP_500_INTERNAL_SERVER_ERROR",
|
|
122
|
+
[501]: "HTTP_501_NOT_IMPLEMENTED",
|
|
123
|
+
[502]: "HTTP_502_BAD_GATEWAY",
|
|
124
|
+
[503]: "HTTP_503_SERVICE_UNAVAILABLE",
|
|
125
|
+
[504]: "HTTP_504_GATEWAY_TIMEOUT",
|
|
126
|
+
[505]: "HTTP_505_HTTP_VERSION_NOT_SUPPORTED",
|
|
127
|
+
[506]: "HTTP_506_VARIANT_ALSO_NEGOTIATES",
|
|
128
|
+
[507]: "HTTP_507_INSUFFICIENT_STORAGE",
|
|
129
|
+
[508]: "HTTP_508_LOOP_DETECTED",
|
|
130
|
+
[510]: "HTTP_510_NOT_EXTENDED",
|
|
131
|
+
[511]: "HTTP_511_NETWORK_AUTHENTICATION_REQUIRED"
|
|
132
|
+
};
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/logging/AbstractLogHandler.ts
|
|
135
|
+
var AbstractLogHandler = class {
|
|
136
|
+
level;
|
|
137
|
+
/**
|
|
138
|
+
* Abstract log handler.
|
|
139
|
+
*/
|
|
140
|
+
constructor(level) {
|
|
141
|
+
this.level = level;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Emit log record.
|
|
145
|
+
*/
|
|
146
|
+
emit(_logger, _timestamp, _level, _message, _extra, _error) {
|
|
147
|
+
throw new Error("Not implemented.");
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/logging/const.ts
|
|
152
|
+
const LOG_LEVEL_SILENT = 0;
|
|
153
|
+
const LOG_LEVEL_FATAL = 1;
|
|
154
|
+
const LOG_LEVEL_ERROR = 2;
|
|
155
|
+
const LOG_LEVEL_WARNING = 3;
|
|
156
|
+
const LOG_LEVEL_INFO = 4;
|
|
157
|
+
const LOG_LEVEL_DEBUG = 5;
|
|
158
|
+
const LOG_LEVEL_NAME_SILENT = "silent";
|
|
159
|
+
const LOG_LEVEL_NAME_FATAL = "fatal";
|
|
160
|
+
const LOG_LEVEL_NAME_ERROR = "error";
|
|
161
|
+
const LOG_LEVEL_NAME_WARNING = "warning";
|
|
162
|
+
const LOG_LEVEL_NAME_INFO = "info";
|
|
163
|
+
const LOG_LEVEL_NAME_DEBUG = "debug";
|
|
164
|
+
const LOG_LEVEL_NAMES = [
|
|
165
|
+
LOG_LEVEL_NAME_SILENT,
|
|
166
|
+
LOG_LEVEL_NAME_FATAL,
|
|
167
|
+
LOG_LEVEL_NAME_ERROR,
|
|
168
|
+
LOG_LEVEL_NAME_WARNING,
|
|
169
|
+
LOG_LEVEL_NAME_INFO,
|
|
170
|
+
LOG_LEVEL_NAME_DEBUG
|
|
171
|
+
];
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/logging/util.ts
|
|
174
|
+
/**
|
|
175
|
+
* Format log message.
|
|
176
|
+
*/
|
|
177
|
+
const formatLogMessage = (logger, timestamp, _level, message) => `${timestamp} [${logger.name}] ${message}`;
|
|
178
|
+
/**
|
|
179
|
+
* Get log level name.
|
|
180
|
+
*/
|
|
181
|
+
const getLogLevelName = (level) => LOG_LEVEL_NAMES[level];
|
|
182
|
+
/**
|
|
183
|
+
* Returns the application environment identifier.
|
|
184
|
+
*/
|
|
185
|
+
const getAppEnvironment = () => {
|
|
186
|
+
let appEnvironment = "local";
|
|
187
|
+
try {
|
|
188
|
+
const { env } = import.meta;
|
|
189
|
+
if (env?.["VITE_APP_ENVIRONMENT"]) appEnvironment = env["VITE_APP_ENVIRONMENT"];
|
|
190
|
+
} catch {}
|
|
191
|
+
try {
|
|
192
|
+
if (process.env["APP_ENVIRONMENT"]) appEnvironment = process.env["APP_ENVIRONMENT"];
|
|
193
|
+
} catch {}
|
|
194
|
+
return appEnvironment;
|
|
195
|
+
};
|
|
196
|
+
//#endregion
|
|
197
|
+
//#region src/logging/ConsoleLogHandler.ts
|
|
198
|
+
const CONSOLE_FUNCTIONS = [
|
|
199
|
+
null,
|
|
200
|
+
console.error,
|
|
201
|
+
console.error,
|
|
202
|
+
console.warn,
|
|
203
|
+
console.info,
|
|
204
|
+
console.debug
|
|
205
|
+
];
|
|
206
|
+
var ConsoleLogHandler = class extends AbstractLogHandler {
|
|
207
|
+
/**
|
|
208
|
+
* Console log handler.
|
|
209
|
+
*/
|
|
210
|
+
constructor(level = 5) {
|
|
211
|
+
super(level);
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Emit log record.
|
|
215
|
+
*/
|
|
216
|
+
emit(logger, timestamp, level, message, extra, error) {
|
|
217
|
+
if (logger.level < level) return;
|
|
218
|
+
const logMessage = formatLogMessage(logger, timestamp, level, message);
|
|
219
|
+
const consoleFunction = CONSOLE_FUNCTIONS[level];
|
|
220
|
+
if (consoleFunction === null || consoleFunction === void 0) return;
|
|
221
|
+
if (error) {
|
|
222
|
+
extra === void 0 ? consoleFunction(logMessage, error) : consoleFunction(logMessage, error, extra);
|
|
223
|
+
if (error.cause) consoleFunction("Error cause", error.cause);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
extra === void 0 ? consoleFunction(logMessage) : consoleFunction(logMessage, extra);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/util/query.ts
|
|
231
|
+
const urlSearchParams = new URLSearchParams(globalThis.location?.search);
|
|
232
|
+
function sanitizeURLParam(input) {
|
|
233
|
+
if (!input) return input;
|
|
234
|
+
return input.replaceAll(/[^\w-]/giu, "");
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Get a URL parameter value.
|
|
238
|
+
*/
|
|
239
|
+
function getURLParam(key, defaultValue, isSanitize) {
|
|
240
|
+
if (!key) return defaultValue ?? null;
|
|
241
|
+
const paramValue = urlSearchParams.get(key);
|
|
242
|
+
if (paramValue === null || paramValue === void 0) return defaultValue ?? null;
|
|
243
|
+
if (isSanitize !== false) return sanitizeURLParam(paramValue);
|
|
244
|
+
return paramValue;
|
|
245
|
+
}
|
|
246
|
+
//#endregion
|
|
247
|
+
//#region src/logging/Logger.ts
|
|
248
|
+
const ROOT_LOGGER_NAME = "root";
|
|
249
|
+
var Logger = class Logger {
|
|
250
|
+
static handlers = [];
|
|
251
|
+
name;
|
|
252
|
+
level;
|
|
253
|
+
/**
|
|
254
|
+
* Creates a new Logger instance.
|
|
255
|
+
*/
|
|
256
|
+
constructor(name = ROOT_LOGGER_NAME) {
|
|
257
|
+
this.name = name ?? ROOT_LOGGER_NAME;
|
|
258
|
+
const appEnvironment = getAppEnvironment();
|
|
259
|
+
const defaultLevel = appEnvironment === "production" || appEnvironment === "release" ? 0 : 5;
|
|
260
|
+
const paramLevel = getURLParam(`log_${this.name.toLowerCase()}`, getURLParam("log_all", defaultLevel.toString())) ?? defaultLevel.toString();
|
|
261
|
+
this.level = Number.parseInt(paramLevel, 10);
|
|
262
|
+
}
|
|
263
|
+
static addHandler = (handler) => {
|
|
264
|
+
Logger.handlers.push(handler);
|
|
265
|
+
};
|
|
266
|
+
static emit = (logger, level, message, extra, error) => {
|
|
267
|
+
const timestamp = Date.now();
|
|
268
|
+
for (const handler of Logger.handlers) if (handler.level >= level) handler.emit(logger, timestamp, level, message, extra, error);
|
|
269
|
+
};
|
|
270
|
+
debug(message, extra) {
|
|
271
|
+
Logger.emit(this, 5, message, extra);
|
|
272
|
+
}
|
|
273
|
+
info(message, extra) {
|
|
274
|
+
Logger.emit(this, 4, message, extra);
|
|
275
|
+
}
|
|
276
|
+
warn(message, extra) {
|
|
277
|
+
Logger.emit(this, 3, message, extra);
|
|
278
|
+
}
|
|
279
|
+
warning(message, extra) {
|
|
280
|
+
Logger.emit(this, 3, message, extra);
|
|
281
|
+
}
|
|
282
|
+
error(message, extra) {
|
|
283
|
+
Logger.emit(this, 2, message, extra);
|
|
284
|
+
}
|
|
285
|
+
exception(message, error, extra) {
|
|
286
|
+
Logger.emit(this, 1, message, extra, error);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
//#endregion
|
|
290
|
+
//#region src/logging/OpenTelemetryLogHandler.ts
|
|
291
|
+
var OpenTelemetryLogHandler = class extends AbstractLogHandler {
|
|
292
|
+
emitter;
|
|
293
|
+
/**
|
|
294
|
+
* Open Telemetry log handler.
|
|
295
|
+
*/
|
|
296
|
+
constructor(level, emitter) {
|
|
297
|
+
super(level);
|
|
298
|
+
this.emitter = emitter;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Emit log record.
|
|
302
|
+
*/
|
|
303
|
+
emit(logger, timestamp, level, message, extra, error) {
|
|
304
|
+
if (!this.emitter) return;
|
|
305
|
+
this.emitter(logger, timestamp, level, message, extra, error);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region src/logging/SentryLogHandler.ts
|
|
310
|
+
var SentryLogHandler = class extends AbstractLogHandler {
|
|
311
|
+
/**
|
|
312
|
+
* Sentry log handler.
|
|
313
|
+
*/
|
|
314
|
+
constructor(level = 5) {
|
|
315
|
+
super(level);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Emit log record.
|
|
319
|
+
*/
|
|
320
|
+
emit(logger, _timestamp, level, message, extra, error) {
|
|
321
|
+
const levelName = getLogLevelName(level);
|
|
322
|
+
const logMessage = `[${logger.name}] ${message}`;
|
|
323
|
+
addBreadcrumb({
|
|
324
|
+
type: "default",
|
|
325
|
+
category: "console",
|
|
326
|
+
message: logMessage,
|
|
327
|
+
level: levelName,
|
|
328
|
+
data: extra ?? void 0
|
|
329
|
+
});
|
|
330
|
+
if (error) extra?.tags ? captureException(error, { tags: extra.tags }) : captureException(error);
|
|
331
|
+
else if (level === 3) extra?.tags ? captureMessage(logMessage, {
|
|
332
|
+
level: "warning",
|
|
333
|
+
tags: extra.tags
|
|
334
|
+
}) : captureMessage(logMessage, { level: "warning" });
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/pagelifecycle/const.ts
|
|
339
|
+
const PAGE_LIFECYCLE_STATE_HIDDEN = "hidden";
|
|
340
|
+
const PAGE_LIFECYCLE_STATE_ACTIVE = "active";
|
|
341
|
+
const PAGE_LIFECYCLE_STATE_PASSIVE = "passive";
|
|
342
|
+
const PAGE_LIFECYCLE_STATE_FROZEN = "frozen";
|
|
343
|
+
const PAGE_LIFECYCLE_STATE_TERMINATED = "terminated";
|
|
344
|
+
const PAGE_LIFECYCLE_STATES = new Set([
|
|
345
|
+
PAGE_LIFECYCLE_STATE_ACTIVE,
|
|
346
|
+
PAGE_LIFECYCLE_STATE_FROZEN,
|
|
347
|
+
PAGE_LIFECYCLE_STATE_HIDDEN,
|
|
348
|
+
PAGE_LIFECYCLE_STATE_PASSIVE,
|
|
349
|
+
PAGE_LIFECYCLE_STATE_TERMINATED
|
|
350
|
+
]);
|
|
351
|
+
const DOCUMENT_STATE_DOM_LOADED = "domLoaded";
|
|
352
|
+
const DOCUMENT_STATE_FULLY_LOADED = "fullyLoaded";
|
|
353
|
+
const DOCUMENT_STATE_COMPLETE = "complete";
|
|
354
|
+
const DOCUMENT_STATE_INTERACTIVE = "interactive";
|
|
355
|
+
const DOCUMENT_STATE_LOADING = "loading";
|
|
356
|
+
const DOCUMENT_STATES = new Set([
|
|
357
|
+
DOCUMENT_STATE_COMPLETE,
|
|
358
|
+
DOCUMENT_STATE_DOM_LOADED,
|
|
359
|
+
DOCUMENT_STATE_FULLY_LOADED,
|
|
360
|
+
DOCUMENT_STATE_INTERACTIVE,
|
|
361
|
+
DOCUMENT_STATE_LOADING
|
|
362
|
+
]);
|
|
363
|
+
const PAGE_LIFECYCLE_STATE_CHANGE_EVENT = "pageLifecycleStateChange";
|
|
364
|
+
const DOCUMENT_STATE_CHANGE_EVENT = "documentStateChange";
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region src/pagelifecycle/typedef.ts
|
|
367
|
+
const TYPEDEF = true;
|
|
368
|
+
//#endregion
|
|
369
|
+
//#region src/util/event_emitter.ts
|
|
370
|
+
/**
|
|
371
|
+
* Internal listener wrapper that stores metadata
|
|
372
|
+
* about a registered event listener.
|
|
373
|
+
*/
|
|
374
|
+
var Listener = class {
|
|
375
|
+
fn;
|
|
376
|
+
context;
|
|
377
|
+
once;
|
|
378
|
+
constructor(fn, context, once = false) {
|
|
379
|
+
this.fn = fn;
|
|
380
|
+
this.context = context;
|
|
381
|
+
this.once = once;
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
/**
|
|
385
|
+
* Event emitter implementation inspired by Node.js/EventEmitter3.
|
|
386
|
+
*/
|
|
387
|
+
var EventEmitter = class {
|
|
388
|
+
#events;
|
|
389
|
+
constructor() {
|
|
390
|
+
this.#events = /* @__PURE__ */ new Map();
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get all registered event names.
|
|
394
|
+
*/
|
|
395
|
+
eventNames() {
|
|
396
|
+
return [...this.#events.keys()];
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Get all listener functions registered for an event.
|
|
400
|
+
*/
|
|
401
|
+
listeners(event) {
|
|
402
|
+
const listeners = this.#events.get(event);
|
|
403
|
+
return listeners ? listeners.map((l) => l.fn) : [];
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Get the number of listeners registered for an event.
|
|
407
|
+
*/
|
|
408
|
+
listenerCount(event) {
|
|
409
|
+
const listeners = this.#events.get(event);
|
|
410
|
+
return listeners ? listeners.length : 0;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Emit an event, invoking all registered listeners.
|
|
414
|
+
*/
|
|
415
|
+
emit(event, ...args) {
|
|
416
|
+
const listeners = this.#events.get(event);
|
|
417
|
+
if (!listeners || listeners.length === 0) return false;
|
|
418
|
+
for (const listener of [...listeners]) {
|
|
419
|
+
listener.fn.apply(listener.context, args);
|
|
420
|
+
if (listener.once) this.off(event, listener.fn, listener.context);
|
|
421
|
+
}
|
|
422
|
+
return true;
|
|
423
|
+
}
|
|
424
|
+
#addListener(event, fn, context, once) {
|
|
425
|
+
if (typeof fn !== "function") throw new TypeError("Listener must be a function");
|
|
426
|
+
const listener = new Listener(fn, context ?? this, once);
|
|
427
|
+
const listeners = this.#events.get(event);
|
|
428
|
+
if (listeners) listeners.push(listener);
|
|
429
|
+
else this.#events.set(event, [listener]);
|
|
430
|
+
return this;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Register a persistent listener for an event.
|
|
434
|
+
*/
|
|
435
|
+
on(event, fn, context) {
|
|
436
|
+
return this.#addListener(event, fn, context, false);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Register a one-time listener for an event.
|
|
440
|
+
*/
|
|
441
|
+
once(event, fn, context) {
|
|
442
|
+
return this.#addListener(event, fn, context, true);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Remove a specific listener, or all listeners for an event.
|
|
446
|
+
*/
|
|
447
|
+
off(event, fn, context) {
|
|
448
|
+
if (!this.#events.has(event)) return this;
|
|
449
|
+
if (!fn) {
|
|
450
|
+
this.#events.delete(event);
|
|
451
|
+
return this;
|
|
452
|
+
}
|
|
453
|
+
const filtered = this.#events.get(event).filter((listener) => {
|
|
454
|
+
if (listener.fn !== fn) return true;
|
|
455
|
+
if (context !== void 0 && listener.context !== context) return true;
|
|
456
|
+
return false;
|
|
457
|
+
});
|
|
458
|
+
if (filtered.length > 0) this.#events.set(event, filtered);
|
|
459
|
+
else this.#events.delete(event);
|
|
460
|
+
return this;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Remove all listeners from the emitter,
|
|
464
|
+
* or all listeners for a specific event.
|
|
465
|
+
*/
|
|
466
|
+
removeAllListeners(event) {
|
|
467
|
+
if (event === void 0) this.#events.clear();
|
|
468
|
+
else this.#events.delete(event);
|
|
469
|
+
return this;
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/pagelifecycle/util.ts
|
|
474
|
+
/**
|
|
475
|
+
* Page lifecycle helper.
|
|
476
|
+
* @see https://developer.chrome.com/docs/web-platform/page-lifecycle-api
|
|
477
|
+
*/
|
|
478
|
+
const logger$2 = new Logger("pagelifecycle");
|
|
479
|
+
const eventEmitter = new EventEmitter();
|
|
480
|
+
let currentPageLifecycleState = null;
|
|
481
|
+
let currentDocumentState = null;
|
|
482
|
+
let isInitialized = false;
|
|
483
|
+
const callbacks = {};
|
|
484
|
+
/**
|
|
485
|
+
* Run callbacks for a specific state change.
|
|
486
|
+
*/
|
|
487
|
+
const processCallbacks = (state) => {
|
|
488
|
+
const stateCallbacks = callbacks[state];
|
|
489
|
+
if (!stateCallbacks) return;
|
|
490
|
+
for (const callback of stateCallbacks) callback();
|
|
491
|
+
stateCallbacks.length = 0;
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* Detects the current page lifecycle state.
|
|
495
|
+
*/
|
|
496
|
+
const detectPageLifecycleState = () => {
|
|
497
|
+
if (document.visibilityState === "hidden") return PAGE_LIFECYCLE_STATE_HIDDEN;
|
|
498
|
+
if (document.hasFocus()) return PAGE_LIFECYCLE_STATE_ACTIVE;
|
|
499
|
+
return PAGE_LIFECYCLE_STATE_PASSIVE;
|
|
500
|
+
};
|
|
501
|
+
/**
|
|
502
|
+
* Handles page lifecycle state change.
|
|
503
|
+
*/
|
|
504
|
+
const onPageLifecycleStateChange = (nextState) => {
|
|
505
|
+
const previousState = currentPageLifecycleState;
|
|
506
|
+
if (nextState !== previousState) {
|
|
507
|
+
currentPageLifecycleState = nextState;
|
|
508
|
+
const eventData = {
|
|
509
|
+
previousState,
|
|
510
|
+
nextState
|
|
511
|
+
};
|
|
512
|
+
logger$2.info(PAGE_LIFECYCLE_STATE_CHANGE_EVENT, eventData);
|
|
513
|
+
eventEmitter.emit(PAGE_LIFECYCLE_STATE_CHANGE_EVENT, eventData);
|
|
514
|
+
processCallbacks(currentPageLifecycleState);
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
/**
|
|
518
|
+
* Handles document state change.
|
|
519
|
+
*/
|
|
520
|
+
const onDocumentStateChange = (nextState) => {
|
|
521
|
+
const previousState = currentDocumentState;
|
|
522
|
+
if (nextState !== previousState) {
|
|
523
|
+
currentDocumentState = nextState;
|
|
524
|
+
const eventData = {
|
|
525
|
+
previousState,
|
|
526
|
+
nextState
|
|
527
|
+
};
|
|
528
|
+
logger$2.info(DOCUMENT_STATE_CHANGE_EVENT, eventData);
|
|
529
|
+
eventEmitter.emit(DOCUMENT_STATE_CHANGE_EVENT, eventData);
|
|
530
|
+
processCallbacks(currentDocumentState);
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
/**
|
|
534
|
+
* Initialize page lifecycle observer.
|
|
535
|
+
*/
|
|
536
|
+
const initPageLifecycle = () => {
|
|
537
|
+
if (isInitialized) return;
|
|
538
|
+
logger$2.info("initPageLifecycle");
|
|
539
|
+
onPageLifecycleStateChange(detectPageLifecycleState());
|
|
540
|
+
onDocumentStateChange(document.readyState);
|
|
541
|
+
const options = { capture: true };
|
|
542
|
+
document.addEventListener("visibilitychange", () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
543
|
+
globalThis.addEventListener("pageshow", () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
544
|
+
globalThis.addEventListener("focus", () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
545
|
+
globalThis.addEventListener("blur", () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
546
|
+
document.addEventListener("resume", () => onPageLifecycleStateChange(detectPageLifecycleState()), options);
|
|
547
|
+
document.addEventListener("freeze", () => onPageLifecycleStateChange(PAGE_LIFECYCLE_STATE_FROZEN), options);
|
|
548
|
+
globalThis.addEventListener("pagehide", (event) => onPageLifecycleStateChange(event.persisted ? PAGE_LIFECYCLE_STATE_FROZEN : PAGE_LIFECYCLE_STATE_TERMINATED), options);
|
|
549
|
+
document.addEventListener("DOMContentLoaded", () => onDocumentStateChange(DOCUMENT_STATE_DOM_LOADED), options);
|
|
550
|
+
document.addEventListener("readystatechange", () => onDocumentStateChange(document.readyState), options);
|
|
551
|
+
globalThis.addEventListener("load", () => onDocumentStateChange(DOCUMENT_STATE_FULLY_LOADED), options);
|
|
552
|
+
isInitialized = true;
|
|
553
|
+
};
|
|
554
|
+
/**
|
|
555
|
+
* Returns the current page lifecycle state.
|
|
556
|
+
*/
|
|
557
|
+
const getPageLifecycleState = () => currentPageLifecycleState;
|
|
558
|
+
/**
|
|
559
|
+
* Returns the current document state.
|
|
560
|
+
*/
|
|
561
|
+
const getDocumentState = () => currentDocumentState;
|
|
562
|
+
/**
|
|
563
|
+
* Returns the event emitter instance.
|
|
564
|
+
*/
|
|
565
|
+
const getPageLifecycleEventEmitter = () => {
|
|
566
|
+
if (!isInitialized) initPageLifecycle();
|
|
567
|
+
return eventEmitter;
|
|
568
|
+
};
|
|
569
|
+
/**
|
|
570
|
+
* Returns the page lifecycle observer initialized state.
|
|
571
|
+
*/
|
|
572
|
+
const isPageLifecycleInitialized = () => isInitialized;
|
|
573
|
+
/**
|
|
574
|
+
* Add callback for a specific state change.
|
|
575
|
+
*/
|
|
576
|
+
const addPageLifecycleCallback = (state, callback) => {
|
|
577
|
+
const stateCallbacks = callbacks[state] ?? [];
|
|
578
|
+
stateCallbacks.push(callback);
|
|
579
|
+
callbacks[state] = stateCallbacks;
|
|
580
|
+
};
|
|
581
|
+
//#endregion
|
|
582
|
+
//#region src/typecheck/TypeCheckError.ts
|
|
583
|
+
var TypeCheckError = class extends TypeError {
|
|
584
|
+
value;
|
|
585
|
+
/**
|
|
586
|
+
* Creates a new `TypeCheckError` instance.
|
|
587
|
+
*/
|
|
588
|
+
constructor(message, options) {
|
|
589
|
+
super(message, options);
|
|
590
|
+
this.name = "TypeCheckError";
|
|
591
|
+
this.value = options?.value;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
//#endregion
|
|
595
|
+
//#region src/util/string.ts
|
|
596
|
+
/**
|
|
597
|
+
* Add leading zeros to a value to ensure it has a minimum width.
|
|
598
|
+
*/
|
|
599
|
+
const addLeadingZero = (value, size = 2) => {
|
|
600
|
+
if (value === null || value === void 0) return null;
|
|
601
|
+
let str = value.toString();
|
|
602
|
+
while (str.length < size) str = `0${str}`;
|
|
603
|
+
return str;
|
|
604
|
+
};
|
|
605
|
+
/**
|
|
606
|
+
* Capitalize a string.
|
|
607
|
+
*/
|
|
608
|
+
const capitalize = (value) => {
|
|
609
|
+
if (value === null || value === void 0) return null;
|
|
610
|
+
if (!value || value.length === 0) return value;
|
|
611
|
+
const normValue = value.toLowerCase();
|
|
612
|
+
return normValue.charAt(0).toUpperCase() + normValue.slice(1);
|
|
613
|
+
};
|
|
614
|
+
/**
|
|
615
|
+
* Converts underscore case string to camel case.
|
|
616
|
+
*/
|
|
617
|
+
const underscoreToCamelCase = (value) => value.replaceAll(/(_\w)/gu, (m) => m[1].toUpperCase());
|
|
618
|
+
/**
|
|
619
|
+
* Saves text file.
|
|
620
|
+
*/
|
|
621
|
+
const saveAsFile = (filename, text) => {
|
|
622
|
+
const element = document.createElement("a");
|
|
623
|
+
element.setAttribute("href", `data:text/plain;charset=utf-8,${encodeURIComponent(text)}`);
|
|
624
|
+
element.setAttribute("download", filename);
|
|
625
|
+
element.style.display = "none";
|
|
626
|
+
document.body.append(element);
|
|
627
|
+
element.click();
|
|
628
|
+
element.remove();
|
|
629
|
+
};
|
|
630
|
+
/**
|
|
631
|
+
* Get type from value in human readable format.
|
|
632
|
+
*/
|
|
633
|
+
const getTypeFromValue = (value) => Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
|
|
634
|
+
/**
|
|
635
|
+
* Get value in human readable format.
|
|
636
|
+
*/
|
|
637
|
+
const getDisplayValue = (value) => {
|
|
638
|
+
if (typeof value === "string") return `"${value}"`;
|
|
639
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
640
|
+
return String(value);
|
|
641
|
+
};
|
|
642
|
+
//#endregion
|
|
643
|
+
//#region src/util/number.ts
|
|
644
|
+
const DEG_TO_RAD = Math.PI / 180;
|
|
645
|
+
const RAD_TO_DEG = 180 / Math.PI;
|
|
646
|
+
const PRECISION = 12;
|
|
647
|
+
const EPSILON = 1e-11;
|
|
648
|
+
/**
|
|
649
|
+
* Converts degrees to radians.
|
|
650
|
+
*/
|
|
651
|
+
const deg2rad = (degrees) => {
|
|
652
|
+
if (!Number.isFinite(degrees)) throw new TypeCheckError("Argument degrees must be a finite number", { value: degrees });
|
|
653
|
+
return degrees * DEG_TO_RAD;
|
|
654
|
+
};
|
|
655
|
+
/**
|
|
656
|
+
* Converts radians to degrees.
|
|
657
|
+
*/
|
|
658
|
+
const rad2deg = (radians) => {
|
|
659
|
+
if (!Number.isFinite(radians)) throw new TypeCheckError("Argument radians must be a finite number", { value: radians });
|
|
660
|
+
return radians * RAD_TO_DEG;
|
|
661
|
+
};
|
|
662
|
+
/**
|
|
663
|
+
* Returns random integer in range.
|
|
664
|
+
*/
|
|
665
|
+
const getRandomInt = (min, max) => {
|
|
666
|
+
if (!Number.isFinite(min)) throw new TypeCheckError("Argument min must be finite number", { value: min });
|
|
667
|
+
if (!Number.isFinite(max)) throw new TypeCheckError("Argument max must be finite number", { value: max });
|
|
668
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
669
|
+
};
|
|
670
|
+
/**
|
|
671
|
+
* Normalizes floating point precision (e.g. 0.20000000000000004 → 0.2).
|
|
672
|
+
*/
|
|
673
|
+
const fixFloatPrecision = (value) => {
|
|
674
|
+
const parsedValue = typeof value === "string" ? Number(value) : value;
|
|
675
|
+
if (parsedValue === null || parsedValue === void 0 || !Number.isFinite(parsedValue)) return NaN;
|
|
676
|
+
return Math.abs(parsedValue) < EPSILON ? 0 : Number(parsedValue.toPrecision(PRECISION));
|
|
677
|
+
};
|
|
678
|
+
const isGreater = (value, min) => value > min;
|
|
679
|
+
const isGreaterOrEqual = (value, min) => value >= min;
|
|
680
|
+
const isLess = (value, min) => value < min;
|
|
681
|
+
const isLessOrEqual = (value, min) => value <= min;
|
|
682
|
+
const isInRange = (value, min, max) => value >= min && value <= max;
|
|
683
|
+
const isEqual = (value, expected) => value === expected;
|
|
684
|
+
//#endregion
|
|
685
|
+
//#region src/util/validate.ts
|
|
686
|
+
/**
|
|
687
|
+
* Validates `value` as `boolean`.
|
|
688
|
+
*/
|
|
689
|
+
const isBoolean = (value) => typeof value === "boolean";
|
|
690
|
+
/**
|
|
691
|
+
* Validates `value` as `number`.
|
|
692
|
+
*/
|
|
693
|
+
const isNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
694
|
+
/**
|
|
695
|
+
* Validates `value` as positive `number`.
|
|
696
|
+
*/
|
|
697
|
+
const isPositiveNumber = (value) => isNumber(value) && value > 0;
|
|
698
|
+
/**
|
|
699
|
+
* Validates `value` as non-negative `number`.
|
|
700
|
+
*/
|
|
701
|
+
const isNonNegativeNumber = (value) => isNumber(value) && value >= 0;
|
|
702
|
+
/**
|
|
703
|
+
* Validates `value` as `integer`.
|
|
704
|
+
*/
|
|
705
|
+
const isInteger = (value) => isNumber(value) && Number.isInteger(value);
|
|
706
|
+
/**
|
|
707
|
+
* Validates `value` as positive `integer`.
|
|
708
|
+
*/
|
|
709
|
+
const isPositiveInteger = (value) => isInteger(value) && value > 0;
|
|
710
|
+
/**
|
|
711
|
+
* Validates `value` as non-negative `integer`.
|
|
712
|
+
*/
|
|
713
|
+
const isNonNegativeInteger = (value) => isInteger(value) && value >= 0;
|
|
714
|
+
/**
|
|
715
|
+
* Validates `value` as `string`.
|
|
716
|
+
*/
|
|
717
|
+
const isString = (value) => typeof value === "string";
|
|
718
|
+
/**
|
|
719
|
+
* Validates `value` as `array`.
|
|
720
|
+
*/
|
|
721
|
+
const isArray = (value) => Array.isArray(value);
|
|
722
|
+
/**
|
|
723
|
+
* Validates `value` as `null`.
|
|
724
|
+
*/
|
|
725
|
+
const isNull = (value) => value === null;
|
|
726
|
+
/**
|
|
727
|
+
* Validates `value` as `undefined`.
|
|
728
|
+
*/
|
|
729
|
+
const isUndefined = (value) => value === void 0;
|
|
730
|
+
/**
|
|
731
|
+
* Validates `value` as `null` or `undefined`.
|
|
732
|
+
*/
|
|
733
|
+
const isNullOrUndefined = (value) => isNull(value) || isUndefined(value);
|
|
734
|
+
/**
|
|
735
|
+
* Validates `value` as plain `object`.
|
|
736
|
+
*/
|
|
737
|
+
const isPlainObject = (value) => Object.prototype.toString.call(value) === "[object Object]";
|
|
738
|
+
/**
|
|
739
|
+
* Validates `value` as `function`.
|
|
740
|
+
*/
|
|
741
|
+
const isFunction = (value) => typeof value === "function";
|
|
742
|
+
/**
|
|
743
|
+
* Validates `value` as `type`.
|
|
744
|
+
*/
|
|
745
|
+
const isInstance = (value, type) => isFunction(type) && value instanceof type;
|
|
746
|
+
/**
|
|
747
|
+
* Validates `value` as `enum`.
|
|
748
|
+
*/
|
|
749
|
+
const isEnum = (value, choices) => {
|
|
750
|
+
if (!isString(value) && !isNumber(value)) return false;
|
|
751
|
+
return isArray(choices) && choices.includes(value) || isPlainObject(choices) && Object.values(choices).includes(value) || isInstance(choices, Set) && choices.has(value);
|
|
752
|
+
};
|
|
753
|
+
/**
|
|
754
|
+
* Type check an array of values using a validator.
|
|
755
|
+
*/
|
|
756
|
+
const isArrayOf = (values, validator) => {
|
|
757
|
+
if (!isArray(values)) return false;
|
|
758
|
+
for (const value of values) if (!validator(value)) return false;
|
|
759
|
+
return true;
|
|
760
|
+
};
|
|
761
|
+
/**
|
|
762
|
+
* Type check a plain object of values using a validator.
|
|
763
|
+
*/
|
|
764
|
+
const isPlainObjectOf = (record, validator) => {
|
|
765
|
+
if (!isPlainObject(record)) return false;
|
|
766
|
+
for (const value of Object.values(record)) if (!validator(value)) return false;
|
|
767
|
+
return true;
|
|
768
|
+
};
|
|
769
|
+
/**
|
|
770
|
+
* Refine a base validator with an extra condition.
|
|
771
|
+
*/
|
|
772
|
+
const refineValidator = (base, predicate, name = null) => {
|
|
773
|
+
const refinedValidator = (value) => base(value) && predicate(value);
|
|
774
|
+
Object.defineProperty(refinedValidator, "name", { value: isString(name) ? name : `${base.name}Refined` });
|
|
775
|
+
return refinedValidator;
|
|
776
|
+
};
|
|
777
|
+
/**
|
|
778
|
+
* Logical OR of two validators.
|
|
779
|
+
*/
|
|
780
|
+
const isAnyOf = (a, b) => (value) => a(value) || b(value);
|
|
781
|
+
const isNumberGreater = (min) => refineValidator(isNumber, (value) => isGreater(value, min));
|
|
782
|
+
const isNumberGreaterOrEqual = (min) => refineValidator(isNumber, (value) => isGreaterOrEqual(value, min));
|
|
783
|
+
const isNumberLess = (min) => refineValidator(isNumber, (value) => isLess(value, min));
|
|
784
|
+
const isNumberLessOrEqual = (min) => refineValidator(isNumber, (value) => isLessOrEqual(value, min));
|
|
785
|
+
const isNumberInRange = (min, max) => refineValidator(isNumber, (value) => isInRange(value, min, max));
|
|
786
|
+
const isNumberEqual = (expected) => refineValidator(isNumber, (value) => isEqual(value, expected));
|
|
787
|
+
const isIntegerGreater = (min) => refineValidator(isInteger, (value) => isGreater(value, min));
|
|
788
|
+
const isIntegerGreaterOrEqual = (min) => refineValidator(isInteger, (value) => isGreaterOrEqual(value, min));
|
|
789
|
+
const isIntegerLess = (min) => refineValidator(isInteger, (value) => isLess(value, min));
|
|
790
|
+
const isIntegerLessOrEqual = (min) => refineValidator(isInteger, (value) => isLessOrEqual(value, min));
|
|
791
|
+
const isIntegerInRange = (min, max) => refineValidator(isInteger, (value) => isInRange(value, min, max));
|
|
792
|
+
const isIntegerEqual = (expected) => refineValidator(isInteger, (value) => isEqual(value, expected));
|
|
793
|
+
const isStringLengthGreater = (min) => refineValidator(isString, (value) => isGreater(value.length, min));
|
|
794
|
+
const isStringLengthGreaterOrEqual = (min) => refineValidator(isString, (value) => isGreaterOrEqual(value.length, min));
|
|
795
|
+
const isStringLengthLess = (min) => refineValidator(isString, (value) => isLess(value.length, min));
|
|
796
|
+
const isStringLengthLessOrEqual = (min) => refineValidator(isString, (value) => isLessOrEqual(value.length, min));
|
|
797
|
+
const isStringLengthInRange = (min, max) => refineValidator(isString, (value) => isInRange(value.length, min, max));
|
|
798
|
+
const isStringLengthEqual = (expected) => refineValidator(isString, (value) => isEqual(value.length, expected));
|
|
799
|
+
const isArrayLengthGreater = (min) => refineValidator(isArray, (value) => isGreater(value.length, min));
|
|
800
|
+
const isArrayLengthGreaterOrEqual = (min) => refineValidator(isArray, (value) => isGreaterOrEqual(value.length, min));
|
|
801
|
+
const isArrayLengthLess = (min) => refineValidator(isArray, (value) => isLess(value.length, min));
|
|
802
|
+
const isArrayLengthLessOrEqual = (min) => refineValidator(isArray, (value) => isLessOrEqual(value.length, min));
|
|
803
|
+
const isArrayLengthInRange = (min, max) => refineValidator(isArray, (value) => isInRange(value.length, min, max));
|
|
804
|
+
const isArrayLengthEqual = (expected) => refineValidator(isArray, (value) => isEqual(value.length, expected));
|
|
805
|
+
//#endregion
|
|
806
|
+
//#region src/typecheck/util.ts
|
|
807
|
+
/**
|
|
808
|
+
* Get error message for validator exceptions.
|
|
809
|
+
*/
|
|
810
|
+
const getErrorMessage = (validatorName, value) => {
|
|
811
|
+
const displayValue = getDisplayValue(value);
|
|
812
|
+
const displayType = getTypeFromValue(value);
|
|
813
|
+
throw new TypeCheckError(`Validation failed: ${validatorName || "<anonymous>"} - ${displayValue} (${displayType})`);
|
|
814
|
+
};
|
|
815
|
+
/**
|
|
816
|
+
* Type check a value using a validator.
|
|
817
|
+
* @throws {TypeCheckError}
|
|
818
|
+
*/
|
|
819
|
+
const typeCheck = (value, validator) => {
|
|
820
|
+
if (!validator(value)) getErrorMessage(validator.name, value);
|
|
821
|
+
return value;
|
|
822
|
+
};
|
|
823
|
+
/**
|
|
824
|
+
* Type check an array of values using a validator.
|
|
825
|
+
* @throws {TypeCheckError}
|
|
826
|
+
*/
|
|
827
|
+
const typeCheckArray = (value, validator) => {
|
|
828
|
+
if (!isArrayOf(value, validator)) getErrorMessage(validator.name, value);
|
|
829
|
+
return value;
|
|
830
|
+
};
|
|
831
|
+
/**
|
|
832
|
+
* Type check an enum.
|
|
833
|
+
* @throws {TypeCheckError}
|
|
834
|
+
*/
|
|
835
|
+
const typeCheckEnum = (value, choices) => {
|
|
836
|
+
if (!isEnum(value, choices)) getErrorMessage("isEnum", value);
|
|
837
|
+
return value;
|
|
838
|
+
};
|
|
839
|
+
//#endregion
|
|
840
|
+
//#region src/typecheck/TypeChecker.ts
|
|
841
|
+
const logger$1 = new Logger("typechecker");
|
|
842
|
+
/**
|
|
843
|
+
* Export a single shared instance.
|
|
844
|
+
*/
|
|
845
|
+
const typeChecker = new class TypeChecker {
|
|
846
|
+
static #instance;
|
|
847
|
+
#swallowErrors = false;
|
|
848
|
+
constructor() {
|
|
849
|
+
if (TypeChecker.#instance === void 0) TypeChecker.#instance = this;
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Enable or disable swallowing of TypeCheckErrors.
|
|
853
|
+
*/
|
|
854
|
+
setSwallowErrors(value) {
|
|
855
|
+
this.#swallowErrors = Boolean(value);
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Type check a single value.
|
|
859
|
+
*/
|
|
860
|
+
check(value, validator) {
|
|
861
|
+
try {
|
|
862
|
+
return typeCheck(value, validator);
|
|
863
|
+
} catch (error) {
|
|
864
|
+
if (this.#swallowErrors && error instanceof TypeCheckError) {
|
|
865
|
+
logger$1.exception("check", error);
|
|
866
|
+
return value;
|
|
867
|
+
}
|
|
868
|
+
throw error;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* Type check an array of values.
|
|
873
|
+
*/
|
|
874
|
+
checkArray(value, validator) {
|
|
875
|
+
try {
|
|
876
|
+
return typeCheckArray(value, validator);
|
|
877
|
+
} catch (error) {
|
|
878
|
+
if (this.#swallowErrors && error instanceof TypeCheckError) {
|
|
879
|
+
logger$1.exception("checkArray", error);
|
|
880
|
+
return value;
|
|
881
|
+
}
|
|
882
|
+
throw error;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Type check an enum.
|
|
887
|
+
*/
|
|
888
|
+
checkEnum(value, choices) {
|
|
889
|
+
try {
|
|
890
|
+
return typeCheckEnum(value, choices);
|
|
891
|
+
} catch (error) {
|
|
892
|
+
if (this.#swallowErrors && error instanceof TypeCheckError) {
|
|
893
|
+
logger$1.exception("checkEnum", error);
|
|
894
|
+
return value;
|
|
895
|
+
}
|
|
896
|
+
throw error;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
}();
|
|
900
|
+
//#endregion
|
|
901
|
+
//#region src/util/error.ts
|
|
902
|
+
const DEFAULT_EXCLUDES = new Set(["stack"]);
|
|
903
|
+
/**
|
|
904
|
+
* Retrieves detailed information from an error object.
|
|
905
|
+
*/
|
|
906
|
+
const getErrorDetails = (error, excludes) => {
|
|
907
|
+
const errorDetails = {
|
|
908
|
+
name: error.name,
|
|
909
|
+
type: error.constructor?.name ?? typeof error
|
|
910
|
+
};
|
|
911
|
+
if (error.message) errorDetails.message = error.message;
|
|
912
|
+
if (error.cause) errorDetails.cause = error.cause;
|
|
913
|
+
for (const key of Object.getOwnPropertyNames(error)) if (!excludes?.includes(key) && !DEFAULT_EXCLUDES.has(key)) errorDetails[key] = error[key];
|
|
914
|
+
return errorDetails;
|
|
915
|
+
};
|
|
916
|
+
/**
|
|
917
|
+
* Get typed error from an unknown type.
|
|
918
|
+
*/
|
|
919
|
+
const getTypedError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
920
|
+
//#endregion
|
|
921
|
+
//#region src/util/async.ts
|
|
922
|
+
/**
|
|
923
|
+
* Returns a promise with delayed resolve.
|
|
924
|
+
*/
|
|
925
|
+
const delayPromise = (delayMS) => new Promise((resolve) => {
|
|
926
|
+
setTimeout(resolve, delayMS);
|
|
927
|
+
});
|
|
928
|
+
/**
|
|
929
|
+
* Async method call retry helper.
|
|
930
|
+
*/
|
|
931
|
+
const retryAsync = async (method, numTries = 1, delayMs = 100) => {
|
|
932
|
+
for (let attempt = 0; attempt <= numTries; attempt += 1) try {
|
|
933
|
+
return await method();
|
|
934
|
+
} catch (error) {
|
|
935
|
+
if (attempt === numTries) throw getTypedError(error);
|
|
936
|
+
if (delayMs > 0) await delayPromise(delayMs);
|
|
937
|
+
}
|
|
938
|
+
throw new Error("Unknown error");
|
|
939
|
+
};
|
|
940
|
+
/**
|
|
941
|
+
* Load JSON file using a fetch GET request.
|
|
942
|
+
*/
|
|
943
|
+
const loadJSON = async (url) => {
|
|
944
|
+
const response = await fetch(url);
|
|
945
|
+
if (!response.ok) throw new DOMException(`Fetch error ${response.status}`, "FetchError");
|
|
946
|
+
return response.json();
|
|
947
|
+
};
|
|
948
|
+
//#endregion
|
|
949
|
+
//#region src/util/fetch.ts
|
|
950
|
+
const logger = new Logger("fetch");
|
|
951
|
+
const HTTP_0_ANY = 0;
|
|
952
|
+
var FetchError = class extends Error {
|
|
953
|
+
resource;
|
|
954
|
+
fetchOptions;
|
|
955
|
+
response;
|
|
956
|
+
cause;
|
|
957
|
+
/**
|
|
958
|
+
* Creates a new FetchError instance.
|
|
959
|
+
*/
|
|
960
|
+
constructor(message, resource, fetchOptions, response) {
|
|
961
|
+
super(message);
|
|
962
|
+
this.name = "FetchError";
|
|
963
|
+
this.resource = resource;
|
|
964
|
+
this.fetchOptions = fetchOptions;
|
|
965
|
+
this.response = response;
|
|
966
|
+
this.cause = response?.status ?? null;
|
|
967
|
+
}
|
|
968
|
+
};
|
|
969
|
+
/**
|
|
970
|
+
* Fetch with retry.
|
|
971
|
+
*/
|
|
972
|
+
const fetchRetry = async (resource, fetchOptions, retryOptions) => {
|
|
973
|
+
const opts = {
|
|
974
|
+
timeout: Math.max(retryOptions?.timeout ?? 3e4, 1),
|
|
975
|
+
delay: Math.max(retryOptions?.delay ?? 1e3, 1),
|
|
976
|
+
numTries: Math.max(retryOptions?.numTries ?? 1, 1),
|
|
977
|
+
statusExcludes: retryOptions?.statusExcludes ?? [
|
|
978
|
+
401,
|
|
979
|
+
403,
|
|
980
|
+
405,
|
|
981
|
+
422
|
|
982
|
+
]
|
|
983
|
+
};
|
|
984
|
+
while (opts.numTries > 0) {
|
|
985
|
+
const isOnline = globalThis.navigator?.onLine;
|
|
986
|
+
logger.info("request", {
|
|
987
|
+
resource: String(resource),
|
|
988
|
+
fetchOptions,
|
|
989
|
+
retryOptions: { ...opts },
|
|
990
|
+
isOnline
|
|
991
|
+
});
|
|
992
|
+
const controller = new AbortController();
|
|
993
|
+
const timeoutId = setTimeout(() => controller.abort(new DOMException("Fetch timed out", "AbortError")), opts.timeout);
|
|
994
|
+
const options = {
|
|
995
|
+
...fetchOptions,
|
|
996
|
+
signal: controller.signal
|
|
997
|
+
};
|
|
998
|
+
try {
|
|
999
|
+
const response = await fetch(resource, options);
|
|
1000
|
+
if (!response.ok) throw new FetchError(`Fetch error ${response.status}`, resource, options, response);
|
|
1001
|
+
logger.info("response", { status: response.status });
|
|
1002
|
+
return response;
|
|
1003
|
+
} catch (error) {
|
|
1004
|
+
const typedError = error instanceof Error ? error : new Error(String(error));
|
|
1005
|
+
logger.debug("error", getErrorDetails(typedError));
|
|
1006
|
+
opts.numTries -= 1;
|
|
1007
|
+
if (opts.numTries === 0 || typedError instanceof FetchError && (opts.statusExcludes.includes(typedError.response?.status ?? -1) || opts.statusExcludes.includes(0))) throw error;
|
|
1008
|
+
await delayPromise(opts.delay);
|
|
1009
|
+
opts.delay *= 2;
|
|
1010
|
+
} finally {
|
|
1011
|
+
clearTimeout(timeoutId);
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
throw new Error("Fetch failed");
|
|
1015
|
+
};
|
|
1016
|
+
//#endregion
|
|
1017
|
+
//#region src/util/object.ts
|
|
1018
|
+
const PROHIBITED_KEYS = new Set([
|
|
1019
|
+
"__proto__",
|
|
1020
|
+
"constructor",
|
|
1021
|
+
"prototype"
|
|
1022
|
+
]);
|
|
1023
|
+
/**
|
|
1024
|
+
* Purges object properties to free up memory.
|
|
1025
|
+
*/
|
|
1026
|
+
const purgeObject = (target) => {
|
|
1027
|
+
if (!target) return;
|
|
1028
|
+
for (const entry of Object.keys(target)) target[entry] = null;
|
|
1029
|
+
};
|
|
1030
|
+
/**
|
|
1031
|
+
* Merge two objects.
|
|
1032
|
+
*/
|
|
1033
|
+
const deepMerge = (target, source) => {
|
|
1034
|
+
if (typeof target !== "object" || target === null) return source;
|
|
1035
|
+
if (typeof source !== "object" || source === null) return target;
|
|
1036
|
+
for (const key of Object.keys(source)) {
|
|
1037
|
+
if (PROHIBITED_KEYS.has(key)) throw new SyntaxError(`Security violation error. Cannot use "${key}" as object key.`);
|
|
1038
|
+
if (typeof source[key] === "object" && source[key] !== null) {
|
|
1039
|
+
if (!target[key] || typeof target[key] !== "object") target[key] = {};
|
|
1040
|
+
deepMerge(target[key], source[key]);
|
|
1041
|
+
} else target[key] = source[key];
|
|
1042
|
+
}
|
|
1043
|
+
return target;
|
|
1044
|
+
};
|
|
1045
|
+
/**
|
|
1046
|
+
* Returns the sum value of an array of objects field.
|
|
1047
|
+
*/
|
|
1048
|
+
const getObjArrayPropSum = (arr, prop) => arr.reduce((accumulator, object) => accumulator + object[prop], 0);
|
|
1049
|
+
/**
|
|
1050
|
+
* Get object value by path.
|
|
1051
|
+
*/
|
|
1052
|
+
const getObjValueByPath = (obj, path) => {
|
|
1053
|
+
if (!obj || !path) return null;
|
|
1054
|
+
const keyParts = path.split(".");
|
|
1055
|
+
const nextKey = keyParts[0];
|
|
1056
|
+
if (keyParts.length === 1) return obj[nextKey] === void 0 ? null : obj[nextKey];
|
|
1057
|
+
if (obj[nextKey] === void 0 || obj[nextKey] === null) return null;
|
|
1058
|
+
return getObjValueByPath(obj[nextKey], keyParts.slice(1).join("."));
|
|
1059
|
+
};
|
|
1060
|
+
/**
|
|
1061
|
+
* Set object value by path.
|
|
1062
|
+
* @throws {SyntaxError} Error when illegal path value has been provided.
|
|
1063
|
+
*/
|
|
1064
|
+
const setObjValueByPath = (obj, path, value) => {
|
|
1065
|
+
if (!obj || !path) return;
|
|
1066
|
+
const keyParts = path.split(".");
|
|
1067
|
+
const nextKey = keyParts[0];
|
|
1068
|
+
if (PROHIBITED_KEYS.has(nextKey)) throw new SyntaxError(`Security violation error. Cannot use "${nextKey}" as parameter.`);
|
|
1069
|
+
if (keyParts.length === 1) obj[nextKey] = value;
|
|
1070
|
+
else {
|
|
1071
|
+
if (obj[nextKey] === void 0 || obj[nextKey] === null) obj[nextKey] = {};
|
|
1072
|
+
setObjValueByPath(obj[nextKey], keyParts.slice(1).join("."), value);
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
//#endregion
|
|
1076
|
+
//#region src/util/state.ts
|
|
1077
|
+
/**
|
|
1078
|
+
* Maps server data to client data.
|
|
1079
|
+
*/
|
|
1080
|
+
const serverDataToState = (data, isRecursive = false) => {
|
|
1081
|
+
if (Array.isArray(data)) return data.map((entry) => serverDataToState(entry, isRecursive));
|
|
1082
|
+
if (data !== null && typeof data === "object") {
|
|
1083
|
+
const result = {};
|
|
1084
|
+
for (const [key, value] of Object.entries(data)) {
|
|
1085
|
+
const clientKey = underscoreToCamelCase(key);
|
|
1086
|
+
result[clientKey] = isRecursive ? serverDataToState(value, isRecursive) : value;
|
|
1087
|
+
}
|
|
1088
|
+
return result;
|
|
1089
|
+
}
|
|
1090
|
+
return data;
|
|
1091
|
+
};
|
|
1092
|
+
//#endregion
|
|
1093
|
+
//#region src/util/uuid.ts
|
|
1094
|
+
/**
|
|
1095
|
+
* Convert a byte (0–255) to a 2-character hex string.
|
|
1096
|
+
*/
|
|
1097
|
+
const byteToHex = (byte) => (byte >>> 4).toString(16) + (byte & 15).toString(16);
|
|
1098
|
+
/**
|
|
1099
|
+
* UUIDv4 fallback generator (RFC 4122 compliant).
|
|
1100
|
+
*/
|
|
1101
|
+
const randomUUIDFallback = () => {
|
|
1102
|
+
const bytes = crypto.getRandomValues ? crypto.getRandomValues(new Uint8Array(16)) : Array.from({ length: 16 }, () => Math.floor(Math.random() * 256));
|
|
1103
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
1104
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
1105
|
+
let uuid = "";
|
|
1106
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
1107
|
+
if (index === 4 || index === 6 || index === 8 || index === 10) uuid += "-";
|
|
1108
|
+
uuid += byteToHex(bytes[index]);
|
|
1109
|
+
}
|
|
1110
|
+
return uuid;
|
|
1111
|
+
};
|
|
1112
|
+
/**
|
|
1113
|
+
* Crypto UUIDv4 wrapper with fallback.
|
|
1114
|
+
*/
|
|
1115
|
+
const uuidv4 = () => typeof crypto.randomUUID === "function" ? crypto.randomUUID() : randomUUIDFallback();
|
|
1116
|
+
//#endregion
|
|
1117
|
+
export { AbstractLogHandler, ConsoleLogHandler, DOCUMENT_STATES, DOCUMENT_STATE_CHANGE_EVENT, DOCUMENT_STATE_COMPLETE, DOCUMENT_STATE_DOM_LOADED, DOCUMENT_STATE_FULLY_LOADED, DOCUMENT_STATE_INTERACTIVE, DOCUMENT_STATE_LOADING, EventEmitter, FetchError, HTTP_0_ANY, HTTP_100_CONTINUE, HTTP_101_SWITCHING_PROTOCOLS, HTTP_102_PROCESSING, HTTP_103_EARLY_HINTS, HTTP_200_OK, HTTP_201_CREATED, HTTP_202_ACCEPTED, HTTP_203_NON_AUTHORITATIVE_INFORMATION, HTTP_204_NO_CONTENT, HTTP_205_RESET_CONTENT, HTTP_206_PARTIAL_CONTENT, HTTP_207_MULTI_STATUS, HTTP_208_ALREADY_REPORTED, HTTP_226_IM_USED, HTTP_300_MULTIPLE_CHOICES, HTTP_301_MOVED_PERMANENTLY, HTTP_302_FOUND, HTTP_303_SEE_OTHER, HTTP_304_NOT_MODIFIED, HTTP_305_USE_PROXY, HTTP_306_RESERVED, HTTP_307_TEMPORARY_REDIRECT, HTTP_308_PERMANENT_REDIRECT, HTTP_400_BAD_REQUEST, HTTP_401_UNAUTHORIZED, HTTP_402_PAYMENT_REQUIRED, HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND, HTTP_405_METHOD_NOT_ALLOWED, HTTP_406_NOT_ACCEPTABLE, HTTP_407_PROXY_AUTHENTICATION_REQUIRED, HTTP_408_REQUEST_TIMEOUT, HTTP_409_CONFLICT, HTTP_410_GONE, HTTP_411_LENGTH_REQUIRED, HTTP_412_PRECONDITION_FAILED, HTTP_413_CONTENT_TOO_LARGE, HTTP_414_URI_TOO_LONG, HTTP_415_UNSUPPORTED_MEDIA_TYPE, HTTP_416_RANGE_NOT_SATISFIABLE, HTTP_417_EXPECTATION_FAILED, HTTP_418_IM_A_TEAPOT, HTTP_421_MISDIRECTED_REQUEST, HTTP_422_UNPROCESSABLE_CONTENT, HTTP_423_LOCKED, HTTP_424_FAILED_DEPENDENCY, HTTP_425_TOO_EARLY, HTTP_426_UPGRADE_REQUIRED, HTTP_428_PRECONDITION_REQUIRED, HTTP_429_TOO_MANY_REQUESTS, HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE, HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS, HTTP_499_CLIENT_CLOSED_CONNECTION, HTTP_500_INTERNAL_SERVER_ERROR, HTTP_501_NOT_IMPLEMENTED, HTTP_502_BAD_GATEWAY, HTTP_503_SERVICE_UNAVAILABLE, HTTP_504_GATEWAY_TIMEOUT, HTTP_505_HTTP_VERSION_NOT_SUPPORTED, HTTP_506_VARIANT_ALSO_NEGOTIATES, HTTP_507_INSUFFICIENT_STORAGE, HTTP_508_LOOP_DETECTED, HTTP_510_NOT_EXTENDED, HTTP_511_NETWORK_AUTHENTICATION_REQUIRED, HTTP_STATUS_MAP, LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR, LOG_LEVEL_FATAL, LOG_LEVEL_INFO, LOG_LEVEL_NAMES, LOG_LEVEL_NAME_DEBUG, LOG_LEVEL_NAME_ERROR, LOG_LEVEL_NAME_FATAL, LOG_LEVEL_NAME_INFO, LOG_LEVEL_NAME_SILENT, LOG_LEVEL_NAME_WARNING, LOG_LEVEL_SILENT, LOG_LEVEL_WARNING, Logger, OpenTelemetryLogHandler, PAGE_LIFECYCLE_STATES, PAGE_LIFECYCLE_STATE_ACTIVE, PAGE_LIFECYCLE_STATE_CHANGE_EVENT, PAGE_LIFECYCLE_STATE_FROZEN, PAGE_LIFECYCLE_STATE_HIDDEN, PAGE_LIFECYCLE_STATE_PASSIVE, PAGE_LIFECYCLE_STATE_TERMINATED, SentryLogHandler, TYPEDEF, TypeCheckError, addLeadingZero, addPageLifecycleCallback, capitalize, deepMerge, deg2rad, delayPromise, fetchRetry, fixFloatPrecision, formatLogMessage, getDocumentState, getErrorDetails, getLogLevelName, getObjArrayPropSum, getObjValueByPath, getPageLifecycleEventEmitter, getPageLifecycleState, getRandomInt, getTypeFromValue, getTypedError, getURLParam, initPageLifecycle, isAnyOf, isArray, isArrayLengthEqual, isArrayLengthGreater, isArrayLengthGreaterOrEqual, isArrayLengthInRange, isArrayLengthLess, isArrayLengthLessOrEqual, isArrayOf, isBoolean, isEnum, isEqual, isFunction, isGreater, isGreaterOrEqual, isInRange, isInstance, isInteger, isIntegerEqual, isIntegerGreater, isIntegerGreaterOrEqual, isIntegerInRange, isIntegerLess, isIntegerLessOrEqual, isLess, isLessOrEqual, isNonNegativeInteger, isNonNegativeNumber, isNull, isNullOrUndefined, isNumber, isNumberEqual, isNumberGreater, isNumberGreaterOrEqual, isNumberInRange, isNumberLess, isNumberLessOrEqual, isPageLifecycleInitialized, isPlainObject, isPlainObjectOf, isPositiveInteger, isPositiveNumber, isString, isStringLengthEqual, isStringLengthGreater, isStringLengthGreaterOrEqual, isStringLengthInRange, isStringLengthLess, isStringLengthLessOrEqual, isUndefined, loadJSON, purgeObject, rad2deg, refineValidator, retryAsync, sanitizeURLParam, saveAsFile, serverDataToState, setObjValueByPath, typeCheck, typeCheckArray, typeCheckEnum, typeChecker, underscoreToCamelCase, uuidv4 };
|
|
1118
|
+
|
|
1119
|
+
//# sourceMappingURL=index.js.map
|