desktopr 1.3.1 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist-sdk/_companion_context.js +10 -5
  2. package/dist-sdk/_helpers.js +1 -1
  3. package/dist-sdk/desktopr/_helpers.js +1 -1
  4. package/dist-sdk/desktopr/_types.d.ts +2 -2
  5. package/dist-sdk/modules/rs/app/_types.d.ts +1 -1
  6. package/dist-sdk/modules/rs/badge/_types.d.ts +1 -1
  7. package/dist-sdk/modules/rs/contextMenu/_helpers.js +1 -1
  8. package/dist-sdk/modules/rs/diagnostics/_helpers.js +1 -1
  9. package/dist-sdk/modules/rs/diagnostics/_types.d.ts +1 -1
  10. package/dist-sdk/modules/rs/files/_types.d.ts +1 -1
  11. package/dist-sdk/modules/rs/fs/_main.js +44 -1
  12. package/dist-sdk/modules/rs/fs/_types.d.ts +7 -1
  13. package/dist-sdk/modules/rs/menu/_helpers.js +1 -1
  14. package/dist-sdk/modules/rs/network/_types.d.ts +1 -1
  15. package/dist-sdk/modules/rs/plugins/_helpers.d.ts +1 -0
  16. package/dist-sdk/modules/rs/plugins/_helpers.js +9 -0
  17. package/dist-sdk/modules/rs/plugins/_main.d.ts +5 -0
  18. package/dist-sdk/modules/rs/plugins/_main.js +15 -0
  19. package/dist-sdk/modules/rs/plugins/_types.d.ts +38 -0
  20. package/dist-sdk/modules/rs/plugins/_types.js +2 -0
  21. package/dist-sdk/modules/rs/window/_helpers.js +1 -1
  22. package/dist-sdk/modules/rs/window/_main.js +0 -5
  23. package/dist-sdk/modules/rs/window/_types.d.ts +0 -5
  24. package/dist-sdk/modules/rs/worker/_main.d.ts +1 -1
  25. package/dist-sdk/modules/rs/worker/_types.d.ts +1 -1
  26. package/dist-sdk/utils/crypto/_crypto.d.ts +31 -0
  27. package/dist-sdk/utils/crypto/_crypto.js +116 -0
  28. package/dist-sdk/utils/crypto/index.d.ts +1 -0
  29. package/dist-sdk/utils/crypto/index.js +17 -0
  30. package/dist-sdk/utils/index.d.ts +2 -0
  31. package/dist-sdk/utils/index.js +18 -0
  32. package/dist-sdk/utils/shared/_types.d.ts +64 -0
  33. package/dist-sdk/utils/shared/_types.js +2 -0
  34. package/dist-sdk/utils/utils/_browserStorage.d.ts +22 -0
  35. package/dist-sdk/utils/utils/_browserStorage.js +149 -0
  36. package/dist-sdk/utils/utils/_integerUtils.d.ts +50 -0
  37. package/dist-sdk/utils/utils/_integerUtils.js +74 -0
  38. package/dist-sdk/utils/utils/_jitter.d.ts +4 -0
  39. package/dist-sdk/utils/utils/_jitter.js +25 -0
  40. package/dist-sdk/utils/utils/_json.d.ts +63 -0
  41. package/dist-sdk/utils/utils/_json.js +510 -0
  42. package/dist-sdk/utils/utils/_logger.d.ts +16 -0
  43. package/dist-sdk/utils/utils/_logger.js +43 -0
  44. package/dist-sdk/utils/utils/_pageStore.d.ts +37 -0
  45. package/dist-sdk/utils/utils/_pageStore.js +61 -0
  46. package/dist-sdk/utils/utils/_regexPatterns.d.ts +113 -0
  47. package/dist-sdk/utils/utils/_regexPatterns.js +150 -0
  48. package/dist-sdk/utils/utils/_typesValidation.d.ts +50 -0
  49. package/dist-sdk/utils/utils/_typesValidation.js +125 -0
  50. package/dist-sdk/utils/utils/_utils.d.ts +201 -0
  51. package/dist-sdk/utils/utils/_utils.js +1200 -0
  52. package/dist-sdk/utils/utils/index.d.ts +9 -0
  53. package/dist-sdk/utils/utils/index.js +25 -0
  54. package/package.json +1 -1
@@ -0,0 +1,1200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dropdownOptionsFromStrings = exports.wait = exports.componentCallbackDispatcher = exports.toggleHiddenStatus = exports.setHiddenStatus = exports.removeWWW = exports.redirectOrReload = exports.getSubdomain = exports.isDev = exports.isWindowAvailable = exports.isBrowser = void 0;
4
+ exports.stringStartsWith = stringStartsWith;
5
+ exports.validateFile = validateFile;
6
+ exports.imageExistsAtURL = imageExistsAtURL;
7
+ exports.clearUrl = clearUrl;
8
+ exports.checkPasswordStrength = checkPasswordStrength;
9
+ exports.capitalize = capitalize;
10
+ exports.formSubmit = formSubmit;
11
+ exports.capitalizeEachWord = capitalizeEachWord;
12
+ exports.parseCookie = parseCookie;
13
+ exports.isLocalhost = isLocalhost;
14
+ exports.getUrlParam = getUrlParam;
15
+ exports.sleep = sleep;
16
+ exports.mapToObject = mapToObject;
17
+ exports.getRandomNumber = getRandomNumber;
18
+ exports.getRandomString = getRandomString;
19
+ exports.arrrayGetLast = arrrayGetLast;
20
+ exports.getPathList = getPathList;
21
+ exports.getCurrentPath = getCurrentPath;
22
+ exports.buildPath = buildPath;
23
+ exports.detectAnalysisFileType = detectAnalysisFileType;
24
+ exports.scrollToElement = scrollToElement;
25
+ exports.clickOutside = clickOutside;
26
+ exports.toHtmlId = toHtmlId;
27
+ exports.toggleArrayItem = toggleArrayItem;
28
+ exports.updateUniqueArray = updateUniqueArray;
29
+ exports.updateArrayByKey = updateArrayByKey;
30
+ exports.toCamelCase = toCamelCase;
31
+ exports.toSnakeCase = toSnakeCase;
32
+ exports.portal = portal;
33
+ exports.isValidTimeStr = isValidTimeStr;
34
+ exports.isValidDate = isValidDate;
35
+ exports.formatDateForInput = formatDateForInput;
36
+ exports.addMinutesToTime = addMinutesToTime;
37
+ exports.setTimeForDate = setTimeForDate;
38
+ exports.addMinutesToDate = addMinutesToDate;
39
+ exports.parseDate = parseDate;
40
+ exports.dateToTime24h = dateToTime24h;
41
+ exports.dateToTime12h = dateToTime12h;
42
+ exports.URLGetParam = URLGetParam;
43
+ exports.isSameMonth = isSameMonth;
44
+ exports.isSameYear = isSameYear;
45
+ exports.getMidpointDate = getMidpointDate;
46
+ exports.getYearBounds = getYearBounds;
47
+ exports.callerName = callerName;
48
+ exports.arrayGetByKey = arrayGetByKey;
49
+ exports.checkFileSize = checkFileSize;
50
+ exports.getMatchScore = getMatchScore;
51
+ exports.objectsDiffer = objectsDiffer;
52
+ exports.removeNullish = removeNullish;
53
+ exports.flattenObject = flattenObject;
54
+ exports.getTimeBounds = getTimeBounds;
55
+ exports.listMonthsInRange = listMonthsInRange;
56
+ exports.getMonthBoundsByYearMonthString = getMonthBoundsByYearMonthString;
57
+ exports.getYearMonthStringFromDate = getYearMonthStringFromDate;
58
+ exports.getMonthBounds = getMonthBounds;
59
+ exports.mergeByKey = mergeByKey;
60
+ exports.removeFromArrayByKey = removeFromArrayByKey;
61
+ exports.hexToRgb = hexToRgb;
62
+ exports.copyToClipboard = copyToClipboard;
63
+ exports.URLReload = URLReload;
64
+ exports.flagEmojiToCountryCode = flagEmojiToCountryCode;
65
+ exports.sanitizeMessageSensitiveData = sanitizeMessageSensitiveData;
66
+ exports.getErrorInfo = getErrorInfo;
67
+ exports.serializeToString = serializeToString;
68
+ exports.createHashInput = createHashInput;
69
+ exports.arrayIncludesString = arrayIncludesString;
70
+ const _logger_1 = require("./_logger");
71
+ const _regexPatterns_1 = require("./_regexPatterns");
72
+ const _typesValidation_1 = require("./_typesValidation");
73
+ const isBrowser = () => {
74
+ return typeof window !== "undefined" && typeof document !== "undefined";
75
+ };
76
+ exports.isBrowser = isBrowser;
77
+ const isWindowAvailable = () => {
78
+ return typeof window !== "undefined";
79
+ };
80
+ exports.isWindowAvailable = isWindowAvailable;
81
+ const isDev = () => {
82
+ const isLocalhost = typeof window !== "undefined" &&
83
+ ["localhost", "127.0.0.1"].includes(window.location.hostname);
84
+ const nodeEnv = process?.env?.NODE_ENV;
85
+ return nodeEnv !== "production" || isLocalhost;
86
+ };
87
+ exports.isDev = isDev;
88
+ function stringStartsWith(input, prefix, caseSensitive = false) {
89
+ if (!caseSensitive) {
90
+ return input.toLowerCase().startsWith(prefix.toLowerCase());
91
+ }
92
+ return input.startsWith(prefix);
93
+ }
94
+ /**
95
+ * Validates a file by checking its MIME type and maximum size.
96
+ * @param file - The file to validate (can be null or undefined).
97
+ * @param maxSizeMB - Maximum allowed size in MB (default: 2).
98
+ * @param allowedTypes - Allowed MIME types (default: empty = all types allowed).
99
+ * @returns Validation result object.
100
+ */
101
+ function validateFile(file, maxSizeMB = 2, allowedTypes = []) {
102
+ if (!file) {
103
+ return { valid: false, error: "No file provided." };
104
+ }
105
+ const maxSizeBytes = maxSizeMB * 1024 * 1024;
106
+ // MIME type check (only if allowedTypes is not empty)
107
+ if (allowedTypes.length > 0 && !allowedTypes.includes(file.type)) {
108
+ return {
109
+ valid: false,
110
+ error: `Invalid file type. Allowed types: ${allowedTypes.join(", ")}.`
111
+ };
112
+ }
113
+ // File size check
114
+ if (file.size > maxSizeBytes) {
115
+ return { valid: false, error: `File is too large. Max ${maxSizeMB} MB allowed.` };
116
+ }
117
+ return { valid: true };
118
+ }
119
+ function imageExistsAtURL(url, bustCache = true) {
120
+ return new Promise((resolve) => {
121
+ const img = new Image();
122
+ img.onload = () => resolve(true);
123
+ img.onerror = () => resolve(false);
124
+ img.referrerPolicy = "no-referrer";
125
+ img.src = bustCache
126
+ ? `${url}${url.includes("?") ? "&" : "?"}_=${Date.now()}`
127
+ : url;
128
+ });
129
+ }
130
+ function clearUrl(input, domainOnly = false) {
131
+ if (!_typesValidation_1.validate.nonEmptyString(input)) {
132
+ console.error(`[invalid url string] ${input}`);
133
+ return null;
134
+ }
135
+ // Rimuove spazi iniziali/finali
136
+ let url = input.trim();
137
+ if (stringStartsWith(url, "http://"))
138
+ url = url?.replace("http://", "https://");
139
+ // Se manca lo schema, aggiunge "https://"
140
+ if (!stringStartsWith(url, "https://"))
141
+ url = "https://" + url;
142
+ try {
143
+ _logger_1.logger.log(`[url to clear] ${url}`);
144
+ const parsed = new URL(url);
145
+ // Facoltativo: normalizza schema e host in lowercase
146
+ parsed.protocol = parsed.protocol.toLowerCase();
147
+ parsed.hostname = parsed.hostname.toLowerCase();
148
+ // Rimuove slash finale superfluo
149
+ if (parsed.pathname.endsWith("/") && parsed.pathname !== "/") {
150
+ parsed.pathname = parsed.pathname.slice(0, -1);
151
+ }
152
+ const urlParsed = parsed.toString();
153
+ if (!domainOnly)
154
+ return urlParsed;
155
+ else
156
+ return urlParsed?.replace("https://", "");
157
+ }
158
+ catch {
159
+ console.error(`[invalid url] ${input}`);
160
+ return null; // URL non valido
161
+ }
162
+ }
163
+ /**
164
+ * Estrae il sottodominio da un URL o dal dominio corrente (es. builder.bubbledesk.app → "builder").
165
+ *
166
+ * ⚠️ Restituisce `null` se non è presente alcun sottodominio (es. bubbledesk.app o localhost).
167
+ *
168
+ * @param url - (opzionale) Una stringa URL da cui estrarre il sottodominio. Se non fornita, usa `window.location.hostname`.
169
+ * @returns Il sottodominio come stringa, oppure `null` se non rilevabile.
170
+ *
171
+ * @example
172
+ * getSubdomain("https://auth.bubbledesk.app"); // "auth"
173
+ * getSubdomain(); // se eseguito su builder.bubbledesk.app → "builder"
174
+ * getSubdomain("https://bubbledesk.app"); // null
175
+ * getSubdomain("http://localhost:5173"); // null
176
+ */
177
+ const getSubdomain = (url) => {
178
+ const hostname = url ? new URL(url).hostname : window.location.hostname;
179
+ const parts = hostname.split(".");
180
+ // Gestisce casi tipo: "builder.bubbledesk.app"
181
+ // Evita problemi su "localhost" o "bubbledesk.app"
182
+ if (parts.length >= 3)
183
+ return parts[0];
184
+ return null;
185
+ };
186
+ exports.getSubdomain = getSubdomain;
187
+ /**
188
+ *
189
+ * @param options.reload If true, redirect url and related logic will be ignored
190
+ */
191
+ const redirectOrReload = (options) => {
192
+ if (options?.reload)
193
+ window.location.reload();
194
+ if (!options?.reload && _typesValidation_1.validate.nonEmptyString(options?.redirectUrl)) {
195
+ const redirectUrl = new URL(options?.redirectUrl);
196
+ if (redirectUrl?.href) {
197
+ switch (options?.redirectReplace) {
198
+ case true:
199
+ window.location.replace(redirectUrl?.href);
200
+ break;
201
+ default:
202
+ window.location.href = redirectUrl?.href;
203
+ break;
204
+ }
205
+ }
206
+ }
207
+ };
208
+ exports.redirectOrReload = redirectOrReload;
209
+ function checkPasswordStrength(password) {
210
+ if (password.length < 8)
211
+ return { text: "very weak", score: 0 };
212
+ let score = 0;
213
+ if (/[a-z]/.test(password))
214
+ score++; // lettere minuscole
215
+ if (/[A-Z]/.test(password))
216
+ score++; // lettere maiuscole
217
+ if (/\d/.test(password))
218
+ score++; // numeri
219
+ if (/[^A-Za-z0-9]/.test(password))
220
+ score++; // simboli
221
+ if (password.length >= 12)
222
+ score++; // lunghezza
223
+ switch (score) {
224
+ case 0:
225
+ case 1:
226
+ return { text: "weak", score: 1 };
227
+ case 2:
228
+ return { text: "medium", score: 2 };
229
+ case 3:
230
+ return { text: "strong", score: 3 };
231
+ case 4:
232
+ case 5:
233
+ return { text: "very strong", score: 4 };
234
+ default:
235
+ return { text: "very weak", score: 0 };
236
+ }
237
+ }
238
+ function capitalize(str) {
239
+ if (!str)
240
+ return "";
241
+ return str.charAt(0).toUpperCase() + str.slice(1);
242
+ }
243
+ function formSubmit(callback) {
244
+ return async (event) => {
245
+ event.preventDefault();
246
+ await callback();
247
+ };
248
+ }
249
+ function capitalizeEachWord(input) {
250
+ return input
251
+ .toLowerCase()
252
+ .split(" ")
253
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
254
+ .join(" ");
255
+ }
256
+ function parseCookie(header) {
257
+ return Object.fromEntries(header.split("; ").map((c) => c.split("=")));
258
+ }
259
+ function isLocalhost() {
260
+ if (typeof window === "undefined")
261
+ return false;
262
+ return window.location.hostname.startsWith("localhost");
263
+ }
264
+ function getUrlParam(param) {
265
+ if (typeof window === "undefined")
266
+ return null;
267
+ const urlParams = new URLSearchParams(window.location.search);
268
+ return urlParams.get(param);
269
+ }
270
+ function sleep(seconds) {
271
+ return new Promise((resolve) => setTimeout(resolve, seconds * 1000));
272
+ }
273
+ const removeWWW = (host) => {
274
+ if (host && typeof host == "string")
275
+ return host.replace(/^www\./, "");
276
+ else
277
+ return null;
278
+ };
279
+ exports.removeWWW = removeWWW;
280
+ function mapToObject(value) {
281
+ try {
282
+ if (value instanceof Map) {
283
+ const obj = {};
284
+ for (const [key, val] of value.entries()) {
285
+ obj[key] = mapToObject(val);
286
+ }
287
+ return obj;
288
+ }
289
+ else if (Array.isArray(value)) {
290
+ return value.map(mapToObject);
291
+ }
292
+ else if (typeof value === "object" && value !== null) {
293
+ const obj = {};
294
+ for (const key in value) {
295
+ obj[key] = mapToObject(value[key]);
296
+ }
297
+ return obj;
298
+ }
299
+ else {
300
+ return value;
301
+ }
302
+ }
303
+ catch (error) {
304
+ _logger_1.logger.error(error);
305
+ return value;
306
+ }
307
+ }
308
+ function getRandomNumber(min = 0, max = 10000, integer = true) {
309
+ const rand = Math.random() * (max - min) + min;
310
+ return integer ? Math.floor(rand) : rand;
311
+ }
312
+ function getRandomString(options) {
313
+ const length = options?.length || 6;
314
+ const includeUppercase = options?.includeUppercase || true;
315
+ const lower = "abcdefghijklmnopqrstuvwxyz";
316
+ const digits = "0123456789";
317
+ const upper = includeUppercase ? lower.toUpperCase() : "";
318
+ const chars = lower + digits + upper;
319
+ let result = "";
320
+ for (let i = 0; i < length; i++) {
321
+ const randIndex = Math.floor(Math.random() * chars.length);
322
+ result += chars[randIndex];
323
+ }
324
+ if (options?.prefix)
325
+ return `${options?.prefix}${result}`;
326
+ else
327
+ return result;
328
+ }
329
+ function arrrayGetLast(arr) {
330
+ return arr.length > 0 ? arr[arr.length - 1] : undefined;
331
+ }
332
+ function getPathList(path) {
333
+ try {
334
+ if (path)
335
+ return path.split("/");
336
+ return window.location.pathname.split("/");
337
+ }
338
+ catch (error) {
339
+ _logger_1.logger.error(error);
340
+ return null;
341
+ }
342
+ }
343
+ function getCurrentPath(path) {
344
+ try {
345
+ let pathList = getPathList(path);
346
+ if (pathList)
347
+ return arrrayGetLast(pathList);
348
+ else
349
+ return null;
350
+ }
351
+ catch (error) {
352
+ _logger_1.logger.error(error);
353
+ return null;
354
+ }
355
+ }
356
+ function buildPath(parts, endIndex) {
357
+ const sliced = endIndex !== undefined ? parts.slice(0, endIndex + 1) : parts;
358
+ return "/" + sliced.filter(Boolean).join("/");
359
+ }
360
+ function detectAnalysisFileType(filename) {
361
+ const ext = filename.split(".").pop()?.toLowerCase();
362
+ switch (ext) {
363
+ case "vcf":
364
+ case "fasta":
365
+ case "fa":
366
+ case "fastq":
367
+ case "fq":
368
+ case "gtf":
369
+ case "gff":
370
+ case "bed":
371
+ case "csv":
372
+ case "tsv":
373
+ return ext;
374
+ default:
375
+ return "unknown";
376
+ }
377
+ }
378
+ function scrollToElement(target, offset = 0, scrollBehavior = "auto") {
379
+ let element = null;
380
+ if (typeof target == "string") {
381
+ const normalizedId = target.startsWith("#") ? target.slice(1) : target;
382
+ element = document.getElementById(normalizedId);
383
+ }
384
+ else if (target instanceof HTMLElement) {
385
+ element = target;
386
+ }
387
+ if (!element)
388
+ return;
389
+ const y = element.getBoundingClientRect().top + window.pageYOffset + offset;
390
+ window.scrollTo({
391
+ top: y,
392
+ behavior: scrollBehavior,
393
+ });
394
+ }
395
+ function clickOutside(node, callback) {
396
+ const handleClick = (event) => {
397
+ if (!node.contains(event.target)) {
398
+ callback();
399
+ }
400
+ };
401
+ document.addEventListener("click", handleClick, true);
402
+ return {
403
+ destroy() {
404
+ document.removeEventListener("click", handleClick, true);
405
+ },
406
+ };
407
+ }
408
+ const setHiddenStatus = (element, hidden) => {
409
+ let el;
410
+ if (typeof element === "string") {
411
+ el = document.getElementById(element);
412
+ }
413
+ else {
414
+ el = element;
415
+ }
416
+ if (!el) {
417
+ _logger_1.logger.error("Element is null running setHiddenStatus()");
418
+ return;
419
+ }
420
+ if (hidden) {
421
+ el?.classList.add("hidden");
422
+ }
423
+ else {
424
+ el?.classList.remove("hidden");
425
+ setTimeout(() => {
426
+ if (!el)
427
+ return;
428
+ el.focus();
429
+ }, 100);
430
+ }
431
+ };
432
+ exports.setHiddenStatus = setHiddenStatus;
433
+ const toggleHiddenStatus = (element) => {
434
+ let el;
435
+ if (typeof element === "string") {
436
+ el = document.getElementById(element);
437
+ }
438
+ else {
439
+ el = element;
440
+ }
441
+ if (!el) {
442
+ _logger_1.logger.error("Element is null running toggleHiddenStatus()");
443
+ return;
444
+ }
445
+ const hasHidden = el?.classList.contains("hidden");
446
+ if (!hasHidden) {
447
+ el?.classList.add("hidden");
448
+ }
449
+ else {
450
+ el?.classList.remove("hidden");
451
+ setTimeout(() => {
452
+ if (!el)
453
+ return;
454
+ el.focus();
455
+ }, 100);
456
+ }
457
+ };
458
+ exports.toggleHiddenStatus = toggleHiddenStatus;
459
+ function toHtmlId(str) {
460
+ return str
461
+ .toLowerCase()
462
+ .trim()
463
+ .replace(/\s+/g, "-") // replace spaces with hyphens
464
+ .replace(/[^a-z0-9\-_]/g, "") // remove invalid characters
465
+ .replace(/^-+|-+$/g, ""); // remove leading/trailing hyphens
466
+ }
467
+ function toggleArrayItem(array, item) {
468
+ return array.includes(item)
469
+ ? array.filter((i) => i !== item) // remove if exists
470
+ : [...array, item]; // add if not present
471
+ }
472
+ function updateUniqueArray(array, item, action) {
473
+ if (action === "add") {
474
+ return array.includes(item) ? array : [...array, item];
475
+ }
476
+ else {
477
+ return array.filter((i) => i !== item);
478
+ }
479
+ }
480
+ function updateArrayByKey(array, item, action, key) {
481
+ const referenceKey = (key || "id");
482
+ const index = array.findIndex((el) => el[referenceKey] === item[referenceKey]);
483
+ if (action === "add") {
484
+ if (index === -1) {
485
+ return [...array, item];
486
+ }
487
+ return array;
488
+ }
489
+ if (action === "remove") {
490
+ if (index > -1) {
491
+ return [...array.slice(0, index), ...array.slice(index + 1)];
492
+ }
493
+ return array;
494
+ }
495
+ throw new Error(`Unknown action: ${action}`);
496
+ }
497
+ function toCamelCase(input) {
498
+ // Normalize separators to space
499
+ const normalized = input.replace(/[_\-\s]+/g, " ").trim();
500
+ // Split by space first
501
+ const roughWords = normalized.split(" ");
502
+ const words = [];
503
+ for (const segment of roughWords) {
504
+ // Split segment by camel case and acronym boundaries
505
+ const parts = segment.match(/([A-Z]+(?=[A-Z][a-z]))|([A-Z]?[a-z]+)|([A-Z]+)|(\d+)/g);
506
+ if (parts)
507
+ words.push(...parts);
508
+ }
509
+ // Rebuild into camelCase
510
+ return words
511
+ .map((word, i) => i === 0
512
+ ? word.toLowerCase()
513
+ : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
514
+ .join("");
515
+ }
516
+ function toSnakeCase(input) {
517
+ // Normalize separators to space
518
+ const normalized = input.replace(/[_\-\s]+/g, " ").trim();
519
+ // Split by space
520
+ const roughWords = normalized.split(" ");
521
+ const words = [];
522
+ for (const segment of roughWords) {
523
+ // Split segment by camelCase / PascalCase / acronym transitions
524
+ const parts = segment.match(/([A-Z]+(?=[A-Z][a-z]))|([A-Z]?[a-z]+)|([A-Z]+)|(\d+)/g);
525
+ if (parts)
526
+ words.push(...parts);
527
+ }
528
+ return words.map((w) => w.toLowerCase()).join("_");
529
+ }
530
+ function portal(node, target = document.body) {
531
+ target.appendChild(node);
532
+ return {
533
+ destroy() {
534
+ if (node.parentNode) {
535
+ node.parentNode.removeChild(node);
536
+ }
537
+ },
538
+ };
539
+ }
540
+ function isValidTimeStr(timeStr) {
541
+ if (timeStr.trim() == "")
542
+ return false;
543
+ if (typeof timeStr !== "string")
544
+ return false;
545
+ const parts = timeStr.trim().split(":");
546
+ if (parts.length !== 2)
547
+ return false;
548
+ const [hStr, mStr] = parts;
549
+ if (!/^\d+$/.test(hStr) || !/^\d+$/.test(mStr))
550
+ return false;
551
+ const hours = Number(hStr);
552
+ const minutes = Number(mStr);
553
+ return hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59;
554
+ }
555
+ function isValidDate(date) {
556
+ return date && date instanceof Date && !isNaN(date.getTime());
557
+ }
558
+ function formatDateForInput(date) {
559
+ if (!isValidDate(date)) {
560
+ _logger_1.logger.warn("Invalid 'date' in function 'formatDateForInput(date: Date)'");
561
+ return;
562
+ }
563
+ const year = date.getFullYear();
564
+ const month = String(date.getMonth() + 1).padStart(2, "0"); // mesi 0-indexed
565
+ const day = String(date.getDate()).padStart(2, "0");
566
+ return `${year}-${month}-${day}`;
567
+ }
568
+ function addMinutesToTime(timeStr, minutesToAdd) {
569
+ if (!isValidTimeStr(timeStr)) {
570
+ _logger_1.logger.error("Invalid 'timeStr' at ddMinutesToTime(timeStr: string, minutesToAdd: number).");
571
+ return;
572
+ }
573
+ const [hours, minutes] = timeStr.split(":").map(Number);
574
+ const date = new Date();
575
+ date.setHours(hours, minutes, 0, 0); // set to today, with given time
576
+ date.setMinutes(date.getMinutes() + minutesToAdd); // add minutes
577
+ const newHours = String(date.getHours()).padStart(2, "0");
578
+ const newMinutes = String(date.getMinutes()).padStart(2, "0");
579
+ return `${newHours}:${newMinutes}`;
580
+ }
581
+ function setTimeForDate(date, timeStr) {
582
+ /*if(!isValidDate(date)) {
583
+ logger.error("Invalid 'date' at setTimeForDate(date: Date, timeStr: string).")
584
+ return;
585
+ };*/
586
+ if (!isValidTimeStr(timeStr)) {
587
+ _logger_1.logger.error("Invalid 'timeStr' at setTimeForDate(date: Date, timeStr: string).");
588
+ return date;
589
+ }
590
+ const [hours, minutes] = timeStr.split(":").map(Number);
591
+ const newDate = new Date(date); // clone to avoid mutating original
592
+ newDate.setHours(hours, minutes, 0, 0);
593
+ newDate.setMinutes(newDate.getMinutes());
594
+ return newDate;
595
+ }
596
+ function addMinutesToDate(date, minutesToAdd, dateTimeStr) {
597
+ if (!isValidDate(date)) {
598
+ _logger_1.logger.error("Invalid 'date' at addMinutesToDate(date: Date, minutesToAdd: number, dateTimeStr?: string).");
599
+ return;
600
+ }
601
+ let newDate = new Date(date); // clone to avoid mutating original
602
+ if (dateTimeStr && isValidTimeStr(dateTimeStr))
603
+ newDate = setTimeForDate(newDate, dateTimeStr);
604
+ newDate.setMinutes(newDate.getMinutes() + minutesToAdd);
605
+ return newDate;
606
+ }
607
+ function parseDate(dateStr, fallbackToToday) {
608
+ try {
609
+ if (typeof dateStr !== "string")
610
+ return null;
611
+ // ISO 8601 (safe and recommended)
612
+ if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}(:\d{2})?)?/.test(dateStr)) {
613
+ const isoDate = new Date(dateStr);
614
+ return isNaN(isoDate.getTime()) ? null : isoDate;
615
+ }
616
+ // US format MM/DD/YYYY
617
+ if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(dateStr)) {
618
+ const [month, day, year] = dateStr.split("/").map(Number);
619
+ const date = new Date(year, month - 1, day);
620
+ return isNaN(date.getTime()) ? null : date;
621
+ }
622
+ // Optional: support DD/MM/YYYY format
623
+ if (/^\d{1,2}-\d{1,2}-\d{4}$/.test(dateStr)) {
624
+ const [day, month, year] = dateStr.split("-").map(Number);
625
+ const date = new Date(year, month - 1, day);
626
+ return isNaN(date.getTime()) ? null : date;
627
+ }
628
+ }
629
+ catch (error) {
630
+ _logger_1.logger.devError(error);
631
+ }
632
+ finally {
633
+ if (fallbackToToday) {
634
+ return new Date();
635
+ }
636
+ else {
637
+ // Fallback attempt (not recommended in general)
638
+ return new Date(dateStr);
639
+ }
640
+ }
641
+ }
642
+ function dateToTime24h(date) {
643
+ if (!_typesValidation_1.validate.date(date))
644
+ return null;
645
+ const hours = String(date.getHours()).padStart(2, "0");
646
+ const minutes = String(date.getMinutes()).padStart(2, "0");
647
+ return `${hours}:${minutes}`;
648
+ }
649
+ function dateToTime12h(date) {
650
+ if (!(date instanceof Date) || isNaN(date.getTime()))
651
+ return null;
652
+ let hours = date.getHours();
653
+ const minutes = String(date.getMinutes()).padStart(2, "0");
654
+ const ampm = hours >= 12 ? "PM" : "AM";
655
+ hours = hours % 12;
656
+ hours = hours === 0 ? 12 : hours; // 0 => 12
657
+ return `${String(hours).padStart(2, "0")}:${minutes} ${ampm}`;
658
+ }
659
+ function URLGetParam(paramName, url = window.location.href) {
660
+ try {
661
+ const parsedUrl = new URL(url);
662
+ return parsedUrl.searchParams.get(paramName);
663
+ }
664
+ catch (e) {
665
+ return null; // URL malformato
666
+ }
667
+ }
668
+ function isSameMonth(date1, date2) {
669
+ if (!_typesValidation_1.validate.date(date1) || !_typesValidation_1.validate.date(date2)) {
670
+ _logger_1.logger.devError("One or more dates are invalid at isSameMonth(date1: Date, date2: Date)");
671
+ return false;
672
+ }
673
+ return (date1.getFullYear() === date2.getFullYear() &&
674
+ date1.getMonth() === date2.getMonth());
675
+ }
676
+ function isSameYear(date1, date2) {
677
+ if (!(date1 instanceof Date) || isNaN(date1.getTime()))
678
+ return false;
679
+ if (!(date2 instanceof Date) || isNaN(date2.getTime()))
680
+ return false;
681
+ return date1.getFullYear() === date2.getFullYear();
682
+ }
683
+ function getMidpointDate(date1, date2) {
684
+ if (!(date1 instanceof Date) ||
685
+ isNaN(date1.getTime()) ||
686
+ !(date2 instanceof Date) ||
687
+ isNaN(date2.getTime())) {
688
+ throw new Error("Invalid date");
689
+ }
690
+ const time1 = date1.getTime();
691
+ const time2 = date2.getTime();
692
+ const midpoint = (time1 + time2) / 2;
693
+ return new Date(midpoint);
694
+ }
695
+ function getYearBounds(date) {
696
+ const d = date instanceof Date && !isNaN(date.getTime()) ? date : new Date();
697
+ const year = d.getFullYear();
698
+ const start = new Date(year, 0, 1, 0, 0, 0, 0); // 1 gennaio alle 00:00
699
+ const end = new Date(year, 11, 31, 23, 59, 59, 999); // 31 dicembre alle 23:59:59.999
700
+ return { start, end };
701
+ }
702
+ function callerName(level = 2) {
703
+ const err = new Error();
704
+ const stack = err.stack?.split("\n");
705
+ if (stack && stack.length > level) {
706
+ const match = stack[level].trim().match(/^at\s+([^\s(]+)/);
707
+ return match?.[1] || "<anonymous>";
708
+ }
709
+ return "<unknown>";
710
+ }
711
+ function arrayGetByKey(array, value, key = "id") {
712
+ if (!value)
713
+ return [];
714
+ if (!key)
715
+ return [];
716
+ if (!array)
717
+ return [];
718
+ return array.filter((item) => item[key] === value);
719
+ }
720
+ function checkFileSize(files, maxSizeMB) {
721
+ const maxSizeBytes = maxSizeMB * 1024 * 1024;
722
+ let iterable = Array.from(files);
723
+ for (const file of iterable) {
724
+ if (file.size > maxSizeBytes) {
725
+ return {
726
+ valid: false,
727
+ message: `Il file "${file.name}" supera la dimensione massima di ${maxSizeMB} MB.`,
728
+ };
729
+ }
730
+ }
731
+ return { valid: true };
732
+ }
733
+ function getMatchScore(text, term) {
734
+ if (text === term)
735
+ return 100;
736
+ if (text.startsWith(term))
737
+ return 80;
738
+ if (text.includes(` ${term}`))
739
+ return 60;
740
+ if (text.includes(term))
741
+ return 40;
742
+ return 0;
743
+ }
744
+ const componentCallbackDispatcher = (callback, data) => {
745
+ if (callback)
746
+ callback(data);
747
+ };
748
+ exports.componentCallbackDispatcher = componentCallbackDispatcher;
749
+ function objectsDiffer(a, b, strict = false) {
750
+ const clean = (obj) => {
751
+ // Rimuove Proxy, getter, reactive wrapper ecc.
752
+ try {
753
+ return structuredClone(obj);
754
+ }
755
+ catch {
756
+ return JSON.parse(JSON.stringify(obj));
757
+ }
758
+ };
759
+ const cleanA = clean(a);
760
+ const cleanB = clean(b);
761
+ return deepCompare(cleanA, cleanB, strict);
762
+ }
763
+ function deepCompare(a, b, strict) {
764
+ if (a === b)
765
+ return false;
766
+ if (typeof a !== "object" ||
767
+ a === null ||
768
+ typeof b !== "object" ||
769
+ b === null) {
770
+ return a !== b;
771
+ }
772
+ const keys = strict
773
+ ? new Set([...Object.keys(a), ...Object.keys(b)])
774
+ : new Set([...Object.keys(a)].filter((key) => key in b));
775
+ for (const key of keys) {
776
+ const valA = a[key];
777
+ const valB = b[key];
778
+ const bothObjects = typeof valA === "object" &&
779
+ valA !== null &&
780
+ typeof valB === "object" &&
781
+ valB !== null;
782
+ if (bothObjects) {
783
+ if (deepCompare(valA, valB, strict))
784
+ return true;
785
+ }
786
+ else if (valA !== valB) {
787
+ return true;
788
+ }
789
+ }
790
+ return false;
791
+ }
792
+ function removeNullish(obj) {
793
+ return Object.fromEntries(Object.entries(obj).filter(([_, value]) => value != null));
794
+ }
795
+ function flattenObject(obj, options = {}) {
796
+ return _flattenObject(obj, options, "", {}, new Set());
797
+ }
798
+ function _flattenObject(obj, options, _parentKey, _result, _seen) {
799
+ const { useDotNotation = false } = options;
800
+ if (_seen.has(obj)) {
801
+ _result[_parentKey || "[Circular]"] = "[Circular]";
802
+ return _result;
803
+ }
804
+ _seen.add(obj);
805
+ for (const [key, value] of Object.entries(obj)) {
806
+ const isPlainObject = value !== null &&
807
+ typeof value === "object" &&
808
+ !Array.isArray(value) &&
809
+ !(value instanceof Date);
810
+ const fullKey = useDotNotation && _parentKey ? `${_parentKey}.${key}` : key;
811
+ if (isPlainObject) {
812
+ _flattenObject(value, options, fullKey, _result, _seen);
813
+ }
814
+ else {
815
+ if (useDotNotation) {
816
+ _result[fullKey] = value;
817
+ }
818
+ else {
819
+ _result[key] = value;
820
+ }
821
+ }
822
+ }
823
+ _seen.delete(obj);
824
+ return _result;
825
+ }
826
+ /**
827
+ * @param normalizeMonthly If true and units is months or years, it will normalize the start and end date to the first and last day of the first and last month.
828
+ */
829
+ function getTimeBounds(midpoint, before, after, unit, normalizeMonthly) {
830
+ const center = new Date(midpoint);
831
+ const start = new Date(center);
832
+ const end = new Date(center);
833
+ switch (unit) {
834
+ case "minutes":
835
+ start.setMinutes(start.getMinutes() - before);
836
+ end.setMinutes(end.getMinutes() + after);
837
+ break;
838
+ case "days":
839
+ start.setDate(start.getDate() - before);
840
+ end.setDate(end.getDate() + after);
841
+ start.setHours(0, 0, 0, 0);
842
+ end.setHours(23, 59, 59, 999);
843
+ break;
844
+ case "months":
845
+ if (normalizeMonthly)
846
+ start.setDate(1); // sicurezza (primo del mese)
847
+ start.setMonth(start.getMonth() - before);
848
+ end.setMonth(end.getMonth() + after);
849
+ if (normalizeMonthly) {
850
+ start.setDate(1);
851
+ end.setMonth(end.getMonth() + 1, 0); // ultimo giorno del mese
852
+ }
853
+ start.setHours(0, 0, 0, 0);
854
+ end.setHours(23, 59, 59, 999);
855
+ break;
856
+ case "years":
857
+ if (normalizeMonthly)
858
+ start.setMonth(0, 1); // sicurezza (1 gennaio)
859
+ start.setFullYear(start.getFullYear() - before);
860
+ end.setFullYear(end.getFullYear() + after);
861
+ if (normalizeMonthly) {
862
+ start.setMonth(0, 1); // 1 gennaio
863
+ end.setMonth(12, 0); // 31 dicembre
864
+ }
865
+ start.setHours(0, 0, 0, 0);
866
+ end.setHours(23, 59, 59, 999);
867
+ break;
868
+ default:
869
+ throw new Error(`Unsupported unit: ${unit}`);
870
+ }
871
+ return { start, end };
872
+ }
873
+ function listMonthsInRange(start, end, format = "YYYY-MM", options) {
874
+ const { locale = "en-US", excludeStart = false, excludeEnd = false, descending = false, } = options || {};
875
+ let startDate = new Date(start);
876
+ let endDate = new Date(end);
877
+ if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
878
+ throw new Error("Invalid start or end date");
879
+ }
880
+ // Normalizza inizio e fine al primo giorno del mese
881
+ startDate = new Date(startDate.getFullYear(), startDate.getMonth(), 1);
882
+ endDate = new Date(endDate.getFullYear(), endDate.getMonth(), 1);
883
+ const months = [];
884
+ let current = new Date(startDate);
885
+ while (current <= endDate) {
886
+ const isStart = current.getTime() === startDate.getTime();
887
+ const isEnd = current.getTime() === endDate.getTime();
888
+ if ((excludeStart && isStart) || (excludeEnd && isEnd)) {
889
+ // salta questo mese
890
+ }
891
+ else {
892
+ const year = current.getFullYear();
893
+ const month = current.getMonth();
894
+ let formatted;
895
+ switch (format) {
896
+ case "YYYY-MM":
897
+ formatted = `${year}-${String(month + 1).padStart(2, "0")}`;
898
+ break;
899
+ case "YYYY-MMM":
900
+ formatted = `${year}-${current.toLocaleString(locale, {
901
+ month: "short",
902
+ })}`;
903
+ break;
904
+ case "YYYY-MMMM":
905
+ formatted = `${year}-${current.toLocaleString(locale, {
906
+ month: "long",
907
+ })}`;
908
+ break;
909
+ default:
910
+ throw new Error(`Unsupported format: ${format}`);
911
+ }
912
+ months.push(formatted);
913
+ }
914
+ current.setMonth(current.getMonth() + 1);
915
+ }
916
+ return descending ? months.reverse() : months;
917
+ }
918
+ /**
919
+ * @param monthKey (deve essere in formato YYYY-MM)
920
+ * @returns Restituisce un oggetto contente start e end
921
+ */
922
+ function getMonthBoundsByYearMonthString(monthKey) {
923
+ const [year, month] = monthKey.split("-").map(Number); // es. 2025, 6
924
+ const start = new Date(Date.UTC(year, month, 1, 0, 0, 0, 0)); // primo giorno del mese
925
+ const end = new Date(Date.UTC(year, month + 1, 0, 23, 59, 59, 999)); // ultimo giorno del mese
926
+ return { start, end };
927
+ }
928
+ /**
929
+ * @returns The month of the passed date as string in the format YYYY-MM (eg. 2025-05), in UTC
930
+ */
931
+ function getYearMonthStringFromDate(date) {
932
+ const year = date.getUTCFullYear();
933
+ const month = (date.getUTCMonth() + 1).toString().padStart(2, "0");
934
+ return `${year}-${month}`;
935
+ }
936
+ /**
937
+ * @returns Restituisce un oggetto contente start e end
938
+ */
939
+ function getMonthBounds(date) {
940
+ const year = date.getUTCFullYear();
941
+ const month = date.getUTCMonth(); // 0-based
942
+ const start = new Date(Date.UTC(year, month, 1, 0, 0, 0, 0)); // primo giorno del mese
943
+ const end = new Date(Date.UTC(year, month + 1, 0, 23, 59, 59, 999)); // ultimo giorno del mese
944
+ return { start, end };
945
+ }
946
+ /**
947
+ * Unisce l'array originale con nuovi oggetti, sovrascrivendo quelli con la stessa chiave.
948
+ * @param original Array originale
949
+ * @param updates Nuovi oggetti da aggiungere o aggiornare
950
+ * @param key Chiave identificativa (default: "id")
951
+ * @returns Nuovo array aggiornato
952
+ */
953
+ function mergeByKey(original, updates, key = "id") {
954
+ const map = new Map();
955
+ for (const item of original) {
956
+ map.set(item[key], item);
957
+ }
958
+ for (const item of updates) {
959
+ map.set(item[key], item);
960
+ }
961
+ return Array.from(map.values());
962
+ }
963
+ /**
964
+ * Rimuove un elemento da un array di oggetti confrontando un campo chiave.
965
+ *
966
+ * @param array - L'array di oggetti da cui rimuovere l'elemento
967
+ * @param value - Il valore da confrontare per la rimozione
968
+ * @param key - Il campo su cui fare il confronto (default: "id")
969
+ * @returns Un nuovo array senza l'elemento corrispondente
970
+ */
971
+ function removeFromArrayByKey(array, value, key = "id") {
972
+ if (!_typesValidation_1.validate.array(array))
973
+ throw new Error("Invalid array");
974
+ return array.filter((item) => item[key] !== value);
975
+ }
976
+ function hexToRgb(hexString) {
977
+ const hex = hexString || "#000000";
978
+ const cleaned = hex.replace(/^#/, "");
979
+ if (![3, 6].includes(cleaned.length))
980
+ return "(0,0,0)";
981
+ const fullHex = cleaned.length === 3
982
+ ? cleaned
983
+ .split("")
984
+ .map((c) => c + c)
985
+ .join("")
986
+ : cleaned;
987
+ const num = parseInt(fullHex, 16);
988
+ return `(${(num >> 16) & 255 || 0},${(num >> 8) & 255 || 0},${num & 255 || 0})`;
989
+ }
990
+ async function copyToClipboard(text, callback) {
991
+ try {
992
+ await navigator.clipboard.writeText(text);
993
+ _logger_1.logger.log("Text copied to clipboard");
994
+ if (callback)
995
+ callback();
996
+ }
997
+ catch (err) {
998
+ _logger_1.logger.error("Failed to copy text: ", err);
999
+ }
1000
+ }
1001
+ /**
1002
+ * Reloads the page with the given query parameters if they are not already present or different.
1003
+ * Prevents infinite loops by comparing current parameters with target ones.
1004
+ * Optionally appends a hash anchor (e.g., #section) for native browser scrolling.
1005
+ *
1006
+ * @param newParams An object containing key-value pairs to be added to the URL.
1007
+ * @param anchor Optional ID of the element to scroll to after reload (e.g. 'comments')
1008
+ */
1009
+ function URLReload(newParams, anchor) {
1010
+ const current = new URLSearchParams(window.location.search);
1011
+ let changed = false;
1012
+ if (!_typesValidation_1.validate.object(newParams)) {
1013
+ const hash = anchor ? `#${anchor}` : "";
1014
+ location.replace(`${window.location.pathname}${window.location.search}${hash}`);
1015
+ return location.reload();
1016
+ }
1017
+ for (const [key, value] of Object.entries(newParams)) {
1018
+ if (current.get(key) !== value) {
1019
+ current.set(key, value);
1020
+ changed = true;
1021
+ }
1022
+ }
1023
+ const hash = anchor ? `#${anchor}` : "";
1024
+ const query = current.toString();
1025
+ const newUrl = `${window.location.pathname}?${query}${hash}`;
1026
+ window.location.replace(newUrl);
1027
+ return location.reload();
1028
+ }
1029
+ function flagEmojiToCountryCode(flag) {
1030
+ const countryCode = [...flag]
1031
+ .map((char) => String.fromCharCode(char.codePointAt(0) - 0x1f1e6 + 0x61))
1032
+ .join("");
1033
+ return countryCode.trim().toLowerCase();
1034
+ }
1035
+ const wait = (timeout = 100, callback) => {
1036
+ return new Promise((resolve) => {
1037
+ setTimeout(() => {
1038
+ callback?.();
1039
+ resolve();
1040
+ }, timeout);
1041
+ });
1042
+ };
1043
+ exports.wait = wait;
1044
+ const dropdownOptionsFromStrings = (strings) => {
1045
+ const options = [];
1046
+ const optionsIds = [];
1047
+ for (const str of strings) {
1048
+ if (!str.trim() || !_typesValidation_1.validate.nonEmptyString(str))
1049
+ continue;
1050
+ const sluggifiedStr = str
1051
+ .trim()
1052
+ ?.replaceAll(" ", "_")
1053
+ .toLowerCase();
1054
+ if (optionsIds?.includes(sluggifiedStr))
1055
+ continue;
1056
+ optionsIds.push(sluggifiedStr);
1057
+ const option = {
1058
+ label: str,
1059
+ value: sluggifiedStr,
1060
+ id: sluggifiedStr,
1061
+ };
1062
+ options.push(option);
1063
+ }
1064
+ return options || [];
1065
+ };
1066
+ exports.dropdownOptionsFromStrings = dropdownOptionsFromStrings;
1067
+ /** Redact likely-sensitive data and normalize message */
1068
+ function sanitizeMessageSensitiveData(msg, maxLen = 300) {
1069
+ let s = typeof msg === "string" ? msg : String(msg);
1070
+ // Normalize whitespace (flattens multi-line content)
1071
+ s = s.replace(_regexPatterns_1.RE_WS, " ").trim();
1072
+ // Redactions
1073
+ s = s.replace(_regexPatterns_1.RE_EMAIL, "[EMAIL]");
1074
+ s = s.replace(_regexPatterns_1.RE_QUERY_SENSITIVE, (_m, sep, k) => `${sep}${k}=[REDACTED]`);
1075
+ s = s.replace(_regexPatterns_1.RE_AUTH, (_m, k) => `${k} [REDACTED]`);
1076
+ s = s.replace(_regexPatterns_1.RE_AWS_ACCESS_KEY, "[AWS_ACCESS_KEY]");
1077
+ s = s.replace(_regexPatterns_1.RE_SECRET40, "[SECRET_40]");
1078
+ s = s.replace(_regexPatterns_1.RE_JWT, "[JWT]");
1079
+ s = s.replace(_regexPatterns_1.RE_LONG_DIGITS, "[NUMBER]");
1080
+ s = s.replace(_regexPatterns_1.RE_PEM_BLOCK, "[PEM]");
1081
+ // IPv4 without lookbehind: keep the prefix char (group 1) intact
1082
+ s = s.replace(_regexPatterns_1.RE_IPV4_NOLB, (_m, pre) => `${pre}[IP]`);
1083
+ // Secrets in URL path segments
1084
+ s = s.replace(_regexPatterns_1.RE_PATH_SECRET, (m) => {
1085
+ const i = m.lastIndexOf("/");
1086
+ return m.slice(0, i + 1) + "[REDACTED]";
1087
+ });
1088
+ // Truncate
1089
+ if (s.length > maxLen)
1090
+ s = s.slice(0, maxLen) + "… (truncated)";
1091
+ return s;
1092
+ }
1093
+ /**
1094
+ *
1095
+ * @param err The error to extract message and code from
1096
+ * @param sanitize Wether to sanitize the error message, removing potential sensitive data
1097
+ * @returns Error info in the format of { message, code}
1098
+ */
1099
+ function getErrorInfo(err, sanitize = true) {
1100
+ let message;
1101
+ let code;
1102
+ const pull = (e, depth = 0) => {
1103
+ if (!e || depth > 3)
1104
+ return;
1105
+ // Message from common spots (never use String(e) here)
1106
+ if (!message && typeof e.message === "string")
1107
+ message = e.message;
1108
+ // Common code fields across runtimes/libs
1109
+ if (code == null) {
1110
+ code =
1111
+ e.code ??
1112
+ e.status ??
1113
+ e.statusCode ??
1114
+ e.errorCode ??
1115
+ e.response?.status ??
1116
+ e.body?.status;
1117
+ }
1118
+ // HTTP/API payload shapes
1119
+ if (!message) {
1120
+ const m = e.response?.data?.message ??
1121
+ e.response?.data?.error?.message ??
1122
+ e.data?.message ??
1123
+ e.error?.message ??
1124
+ e.body?.message;
1125
+ if (typeof m === "string")
1126
+ message = m;
1127
+ }
1128
+ // Aggregate/cause chains
1129
+ if (!message && Array.isArray(e.errors) && e.errors.length)
1130
+ pull(e.errors[0], depth + 1);
1131
+ if (!message && e.cause)
1132
+ pull(e.cause, depth + 1);
1133
+ };
1134
+ if (err instanceof Error || (typeof err === "object" && err !== null)) {
1135
+ pull(err);
1136
+ }
1137
+ else if (typeof err === "string") {
1138
+ // Only case where we accept String(err): it's already a string.
1139
+ message = err;
1140
+ }
1141
+ // Final fallback: never fabricate by stringifying (could include stack).
1142
+ if (!message)
1143
+ message = "Unknown error";
1144
+ let finalMessage = "";
1145
+ if (sanitize)
1146
+ finalMessage = sanitizeMessageSensitiveData(message);
1147
+ else
1148
+ finalMessage = message;
1149
+ return code != null ? { message: finalMessage, code } : { message: finalMessage };
1150
+ }
1151
+ /**
1152
+ * Serializes an arbitrary values into a deterministic, hash-friendly string.
1153
+ *
1154
+ * - Objects are serialized with sorted keys to ensure stable ordering.
1155
+ * - Arrays are serialized by preserving element order.
1156
+ * - Dates are converted to ISO strings.
1157
+ * - Files are represented by stable metadata (name, size, lastModified).
1158
+ *
1159
+ * @param value - The value or values to serialize.
1160
+ * @returns A deterministic string representation.
1161
+ */
1162
+ function serializeToString(value) {
1163
+ if (value === null || value === undefined)
1164
+ return '';
1165
+ if (typeof value === 'string')
1166
+ return value;
1167
+ if (typeof value === 'number' || typeof value === 'boolean')
1168
+ return String(value);
1169
+ if (value instanceof Date)
1170
+ return value.toISOString();
1171
+ if (value instanceof File) {
1172
+ // Represent File by stable metadata only, not by its binary content
1173
+ return `file:${value.name}:${value.size}:${value.lastModified}`;
1174
+ }
1175
+ if (Array.isArray(value)) {
1176
+ // Serialize each element and preserve order
1177
+ return `[${value.map(serializeToString).join(',')}]`;
1178
+ }
1179
+ if (typeof value === 'object') {
1180
+ // Ensure deterministic key order for object properties
1181
+ const entries = Object.entries(value).sort(([a], [b]) => a.localeCompare(b));
1182
+ return `{${entries
1183
+ .map(([k, v]) => `${k}:${serializeToString(v)}`)
1184
+ .join(',')}}`;
1185
+ }
1186
+ // Fallback for other types
1187
+ return String(value);
1188
+ }
1189
+ // Build a deterministic string from an array of values
1190
+ function createHashInput(values, separator = '|') {
1191
+ return values.map(serializeToString).join(separator);
1192
+ }
1193
+ function arrayIncludesString(arr, needle, caseSensitive = false) {
1194
+ if (!Array.isArray(arr) || typeof needle !== "string")
1195
+ return false;
1196
+ if (caseSensitive)
1197
+ return arr.includes(needle);
1198
+ const n = needle.toLowerCase();
1199
+ return arr.some((s) => typeof s === "string" && s.toLowerCase() === n);
1200
+ }