@arex95/vue-core 1.1.43 → 3.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 (74) hide show
  1. package/README.md +90 -57
  2. package/dist/composables/auth/useAuth.d.ts +20 -6
  3. package/dist/composables/axios/axiosFetch.d.ts +7 -5
  4. package/dist/composables/axios/index.d.ts +0 -1
  5. package/dist/composables/axios/useFetch.d.ts +14 -5
  6. package/dist/composables/breakpoints/useBreakpoint.d.ts +11 -2
  7. package/dist/composables/filters/useFilter.d.ts +13 -8
  8. package/dist/composables/monitoring/useApiActivity.d.ts +17 -6
  9. package/dist/composables/monitoring/useUserActivity.d.ts +20 -5
  10. package/dist/composables/paginators/usePaginator.d.ts +13 -5
  11. package/dist/composables/sorters/useSorter.d.ts +13 -7
  12. package/dist/config/auth/authFetcher.d.ts +30 -0
  13. package/dist/config/auth/index.d.ts +1 -0
  14. package/dist/config/axios/axiosConfig.d.ts +30 -0
  15. package/dist/config/axios/axiosInstance.d.ts +15 -1
  16. package/dist/config/global/endpointsConfig.d.ts +9 -13
  17. package/dist/config/global/keyConfig.d.ts +7 -10
  18. package/dist/config/global/sessionConfig.d.ts +15 -17
  19. package/dist/config/global/tokenPathsConfig.d.ts +17 -18
  20. package/dist/config/global/tokensConfig.d.ts +9 -9
  21. package/dist/config/index.d.ts +1 -0
  22. package/dist/enums/breakpointsEnums.d.ts +7 -4
  23. package/dist/enums/errorsEnums.d.ts +26 -19
  24. package/dist/enums/fileTypesEnums.d.ts +33 -1
  25. package/dist/enums/httpExceptionsEnums.d.ts +3 -1
  26. package/dist/enums/keyCodesEnums.d.ts +2 -4
  27. package/dist/enums/storageEnums.d.ts +4 -4
  28. package/dist/errors/AuthError.d.ts +10 -0
  29. package/dist/errors/BaseError.d.ts +16 -0
  30. package/dist/errors/NetworkError.d.ts +9 -0
  31. package/dist/errors/ServerError.d.ts +10 -0
  32. package/dist/errors/ValidationError.d.ts +14 -0
  33. package/dist/errors/index.d.ts +5 -0
  34. package/dist/fetchers/axios.d.ts +22 -0
  35. package/dist/fetchers/index.d.ts +2 -0
  36. package/dist/fetchers/ofetch.d.ts +33 -0
  37. package/dist/index.d.ts +8 -6
  38. package/dist/index.mjs +1631 -875
  39. package/dist/rest/RestStd.d.ts +146 -102
  40. package/dist/services/credentials.d.ts +24 -29
  41. package/dist/services/extractTokens.d.ts +7 -6
  42. package/dist/services/refreshTokens.d.ts +11 -12
  43. package/dist/services/storeTokens.d.ts +8 -6
  44. package/dist/types/AppKeyConfig.d.ts +7 -0
  45. package/dist/types/ArexVueCoreOptions.d.ts +20 -0
  46. package/dist/types/Auth.d.ts +15 -0
  47. package/dist/types/AxiosOptionsParameter.d.ts +14 -7
  48. package/dist/types/AxiosServiceOptions.d.ts +9 -0
  49. package/dist/types/DecodedJwtPayload.d.ts +12 -0
  50. package/dist/types/EndpointsConfig.d.ts +7 -0
  51. package/dist/types/ErrorType.d.ts +4 -2
  52. package/dist/types/ExtendedQueryOptions.d.ts +10 -0
  53. package/dist/types/Fetcher.d.ts +24 -0
  54. package/dist/types/RestStdOptions.d.ts +62 -0
  55. package/dist/types/SessionConfig.d.ts +25 -1
  56. package/dist/types/TokenConfig.d.ts +7 -0
  57. package/dist/types/TokenValidationResult.d.ts +7 -0
  58. package/dist/types/index.d.ts +2 -0
  59. package/dist/utils/browser.d.ts +20 -14
  60. package/dist/utils/dates.d.ts +47 -34
  61. package/dist/utils/debounces.d.ts +54 -32
  62. package/dist/utils/encryption.d.ts +28 -24
  63. package/dist/utils/errors.d.ts +27 -8
  64. package/dist/utils/exports.d.ts +24 -19
  65. package/dist/utils/files.d.ts +33 -25
  66. package/dist/utils/index.d.ts +3 -0
  67. package/dist/utils/io.d.ts +70 -54
  68. package/dist/utils/objects.d.ts +78 -60
  69. package/dist/utils/retry.d.ts +8 -0
  70. package/dist/utils/ssr.d.ts +27 -0
  71. package/dist/utils/storage.d.ts +20 -14
  72. package/dist/utils/strings.d.ts +42 -31
  73. package/dist/utils/validations.d.ts +76 -57
  74. package/package.json +7 -16
package/dist/index.mjs CHANGED
@@ -1,24 +1,23 @@
1
- import axios from 'axios';
1
+ import axios, { AxiosError } from 'axios';
2
2
  import { jwtDecode } from 'jwt-decode';
3
- import { useRouter } from 'vue-router';
4
3
  import { v4 } from 'uuid';
5
4
  import { useTimeoutFn, useBreakpoints, breakpointsTailwind, useWindowSize } from '@vueuse/core';
6
- import { useQuery } from '@tanstack/vue-query';
7
- import { ref, watch, onServerPrefetch, onMounted, computed } from 'vue';
5
+ import { ref, watch, computed } from 'vue';
6
+ import { $fetch } from 'ofetch';
8
7
 
9
8
  let tokensConfig = Object.freeze({
10
9
  ACCESS_TOKEN: "access_token",
11
10
  REFRESH_TOKEN: "refresh_token",
12
11
  });
13
12
  /**
14
- * Configures the global keys for access and refresh tokens.
15
- * Once set, they cannot be modified.
13
+ * Configures the global storage keys for the access and refresh tokens.
14
+ * This function should be called once at application startup to define the keys
15
+ * used for storing tokens in `localStorage` or `sessionStorage`. The configuration
16
+ * is frozen to prevent runtime changes.
16
17
  *
17
- * @param {TokenKeyConfig} config - An object containing the token keys.
18
- * @param {string} config.accessTokenKey - The name of the key for the access token.
19
- * @param {string} config.refreshTokenKey - The name of the key for the refresh token.
20
- *
21
- * @returns {void} Does not return anything, but freezes the token configuration object.
18
+ * @param {TokenKeyConfig} config - An object containing the token storage keys.
19
+ * @param {string} config.accessTokenKey - The key for the access token.
20
+ * @param {string} config.refreshTokenKey - The key for the refresh token.
22
21
  */
23
22
  function configTokenKeys(config) {
24
23
  tokensConfig = Object.freeze({
@@ -27,18 +26,19 @@ function configTokenKeys(config) {
27
26
  });
28
27
  }
29
28
  /**
30
- * Retrieves the current token configuration.
29
+ * Retrieves the configured storage keys for the access and refresh tokens.
31
30
  *
32
- * @returns {TokensConfig} The configuration of the access and refresh token keys.
31
+ * @returns {TokensConfig} A frozen object containing the `ACCESS_TOKEN` and `REFRESH_TOKEN` keys.
33
32
  */
34
33
  function getTokenConfig() {
35
34
  return tokensConfig;
36
35
  }
37
36
 
38
37
  /**
39
- * Converts an ArrayBuffer or Uint8Array to a hexadecimal string.
40
- * @param buffer The ArrayBuffer or Uint8Array to convert.
41
- * @returns The hexadecimal string.
38
+ * Converts an `ArrayBuffer` or `Uint8Array` into a hexadecimal string representation.
39
+ *
40
+ * @param {ArrayBuffer | Uint8Array} buffer - The buffer to convert.
41
+ * @returns {string} The resulting hexadecimal string.
42
42
  */
43
43
  function ab2hex(buffer) {
44
44
  return Array.from(new Uint8Array(buffer))
@@ -46,11 +46,12 @@ function ab2hex(buffer) {
46
46
  .join("");
47
47
  }
48
48
  /**
49
- * Converts a hexadecimal string to a Uint8Array.
50
- * @param hex The hexadecimal string to convert.
51
- * @returns The Uint8Array.
49
+ * Converts a hexadecimal string into a `Uint8Array`.
50
+ *
51
+ * @param {string} hex - The hexadecimal string to convert.
52
+ * @returns {Uint8Array} The resulting `Uint8Array`.
52
53
  * @throws {TypeError} If the input is not a string.
53
- * @throws {Error} If the hexadecimal string format is invalid or has an odd length.
54
+ * @throws {Error} If the hexadecimal string has an invalid format or an odd length.
54
55
  */
55
56
  function hex2ab(hex) {
56
57
  if (typeof hex !== "string") {
@@ -69,10 +70,12 @@ function hex2ab(hex) {
69
70
  return array;
70
71
  }
71
72
  /**
72
- * Derives an encryption key from a secret key.
73
- * @param secretKey The secret key in plain text.
74
- * @returns A promise that resolves with the derived CryptoKey.
75
- * @throws {Error} If the secretKey is null or empty.
73
+ * Derives a `CryptoKey` for AES-CBC encryption from a plain-text secret key.
74
+ * It uses SHA-256 to hash the secret key, ensuring a fixed-length key suitable for the Web Crypto API.
75
+ *
76
+ * @param {string} secretKey - The plain-text secret key.
77
+ * @returns {Promise<CryptoKey>} A promise that resolves with the derived `CryptoKey`.
78
+ * @throws {Error} If the `secretKey` is null or empty.
76
79
  */
77
80
  async function importKey(secretKey) {
78
81
  if (!secretKey) {
@@ -83,11 +86,13 @@ async function importKey(secretKey) {
83
86
  return crypto.subtle.importKey("raw", digest, { name: "AES-CBC", length: 256 }, false, ["encrypt", "decrypt"]);
84
87
  }
85
88
  /**
86
- * Encrypts a value with the provided secret key.
87
- * @param value The value to encrypt.
88
- * @param secretKey The secret key for encryption.
89
- * @returns A promise that resolves with the IV (hex) + ciphertext (hex) string.
90
- * @throws {Error} If the secretKey is null or empty (via importKey).
89
+ * Encrypts a plain-text value using AES-CBC with a given secret key.
90
+ * A random 16-byte initialization vector (IV) is generated for each encryption.
91
+ *
92
+ * @param {string} value - The plain-text string to encrypt.
93
+ * @param {string} secretKey - The secret key to use for encryption.
94
+ * @returns {Promise<string>} A promise that resolves with a concatenated hexadecimal string of the IV and the ciphertext.
95
+ * @throws {Error} If the `secretKey` is null or empty.
91
96
  */
92
97
  async function encrypt(value, secretKey) {
93
98
  const key = await importKey(secretKey);
@@ -97,14 +102,12 @@ async function encrypt(value, secretKey) {
97
102
  return ab2hex(iv) + ab2hex(new Uint8Array(ciphertext));
98
103
  }
99
104
  /**
100
- * Decrypts an encrypted value.
101
- * @param encryptedValue The encrypted string (IV_hex + ciphertext_hex).
102
- * @param secretKey The secret key for decryption.
103
- * @returns A promise that resolves with the decrypted value.
104
- * @throws {Error} If encryptedValue is null or empty, too short,
105
- * or if the IV/ciphertext have incorrect lengths after conversion.
106
- * @throws {Error} If the secretKey is null or empty (via importKey).
107
- * @throws {TypeError} If hex2ab receives an invalid input type.
105
+ * Decrypts a hexadecimal string (IV + ciphertext) using AES-CBC with a given secret key.
106
+ *
107
+ * @param {string} encryptedValue - The concatenated hexadecimal string of the IV and ciphertext.
108
+ * @param {string} secretKey - The secret key to use for decryption.
109
+ * @returns {Promise<string>} A promise that resolves with the decrypted plain-text string.
110
+ * @throws {Error} If the encrypted value is null, empty, or too short, or if the `secretKey` is invalid.
108
111
  */
109
112
  async function decrypt(encryptedValue, secretKey) {
110
113
  if (!encryptedValue) {
@@ -130,55 +133,172 @@ async function decrypt(encryptedValue, secretKey) {
130
133
  return new TextDecoder().decode(decryptedBuffer);
131
134
  }
132
135
 
133
- /**
134
- * Encrypts and stores an item in local or session storage.
135
- * Assumes the `window` environment is available.
136
- * @param key The key under which to store the value.
137
- * @param value The value to encrypt and store.
138
- * @param secretKey The secret key for encryption.
139
- * @param location Determines where the item is stored: 'local' for localStorage, 'session' for sessionStorage.
140
- * @returns A promise that resolves when the item is stored. Throws an error if it fails.
141
- */
142
- async function storeEncryptedItem(key, value, secretKey, location) {
143
- if (typeof window === "undefined") {
144
- throw new Error("Cannot access storage: window is not defined.");
136
+ const isServer = typeof window === 'undefined';
137
+ const isClient = typeof window !== 'undefined';
138
+ function getStorage() {
139
+ if (isServer) {
140
+ return null;
141
+ }
142
+ return window.localStorage;
143
+ }
144
+ function getSessionStorage() {
145
+ if (isServer) {
146
+ return null;
145
147
  }
146
- const storage = location === "local" ? window.localStorage : window.sessionStorage;
148
+ return window.sessionStorage;
149
+ }
150
+ function getCookieStorage() {
151
+ return {
152
+ getItem: (key) => {
153
+ if (isServer)
154
+ return null;
155
+ const cookies = document.cookie.split(';');
156
+ for (const cookie of cookies) {
157
+ const [name, value] = cookie.trim().split('=');
158
+ if (name === key) {
159
+ return decodeURIComponent(value);
160
+ }
161
+ }
162
+ return null;
163
+ },
164
+ setItem: (key, value, options) => {
165
+ if (isServer)
166
+ return;
167
+ let cookie = `${key}=${encodeURIComponent(value)}`;
168
+ if (options?.expires) {
169
+ const date = new Date();
170
+ date.setTime(date.getTime() + options.expires * 24 * 60 * 60 * 1000);
171
+ cookie += `; expires=${date.toUTCString()}`;
172
+ }
173
+ cookie += `; path=${options?.path || '/'}`;
174
+ if (options?.domain) {
175
+ cookie += `; domain=${options.domain}`;
176
+ }
177
+ if (options?.secure !== false) {
178
+ const isSecure = options?.secure ?? (typeof window !== 'undefined' && window.location.protocol === 'https:');
179
+ if (isSecure) {
180
+ cookie += '; Secure';
181
+ }
182
+ }
183
+ if (options?.sameSite) {
184
+ cookie += `; SameSite=${options.sameSite}`;
185
+ }
186
+ else {
187
+ cookie += '; SameSite=Lax';
188
+ }
189
+ if (options?.httpOnly) {
190
+ console.warn('HttpOnly cookies cannot be set from JavaScript. Use server-side code to set HttpOnly cookies.');
191
+ }
192
+ document.cookie = cookie;
193
+ },
194
+ removeItem: (key, options) => {
195
+ if (isServer)
196
+ return;
197
+ const path = options?.path || '/';
198
+ const domain = options?.domain ? `; domain=${options.domain}` : '';
199
+ document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}${domain}`;
200
+ },
201
+ };
202
+ }
203
+ function getPreferredStorage() {
204
+ if (isServer) {
205
+ return getCookieStorage();
206
+ }
207
+ const storage = getStorage();
208
+ if (storage) {
209
+ return storage;
210
+ }
211
+ return getCookieStorage();
212
+ }
213
+
214
+ /**
215
+ * Encrypts and stores a key-value pair in either `localStorage`, `sessionStorage`, or cookies.
216
+ * Cookies are automatically used in SSR environments and can be explicitly requested.
217
+ * Cookies include security options: Secure (HTTPS only), SameSite (CSRF protection), and encryption.
218
+ *
219
+ * @param {string} key - The key for the storage item.
220
+ * @param {string} value - The string value to encrypt and store.
221
+ * @param {string} secretKey - The secret key to use for encryption.
222
+ * @param {LocationPreference} location - The storage location: 'local' for `localStorage`, 'session' for `sessionStorage`, 'cookie' for cookies, or 'any' for retrieval.
223
+ * @param {CookieOptions} [cookieOptions] - Optional cookie-specific options (only used when location is 'cookie').
224
+ * @returns {Promise<void>} A promise that resolves when the item has been stored.
225
+ */
226
+ async function storeEncryptedItem(key, value, secretKey, location, cookieOptions) {
147
227
  const encryptedValue = await encrypt(value, secretKey);
148
- storage.setItem(key, encryptedValue);
228
+ if (location === "cookie" || isServer) {
229
+ const cookieStorage = getCookieStorage();
230
+ const defaultCookieOptions = {
231
+ expires: location === 'local' || isServer ? 365 : undefined,
232
+ path: '/',
233
+ secure: undefined,
234
+ sameSite: 'Lax',
235
+ ...cookieOptions,
236
+ };
237
+ cookieStorage.setItem(key, encryptedValue, defaultCookieOptions);
238
+ return;
239
+ }
240
+ const storage = location === "local" ? getStorage() : getSessionStorage();
241
+ if (storage) {
242
+ storage.setItem(key, encryptedValue);
243
+ }
149
244
  }
150
245
  /**
151
- * Retrieves and decrypts a value from local or session storage.
152
- * Assumes the `window` environment is available.
153
- * @param key The key of the item to retrieve.
154
- * @param secretKey The secret key for decryption.
155
- * @param location Specifies where to search for the item: 'local' for localStorage, 'session' for sessionStorage, or 'any' to check both (session first).
156
- * @returns A promise that resolves with the decrypted value or null if not found or decryption fails.
246
+ * Retrieves and decrypts an item from `localStorage`, `sessionStorage`, or cookies.
247
+ * When location is 'any', checks in order: sessionStorage, localStorage, cookies.
248
+ * Cookies are automatically checked in SSR environments.
249
+ *
250
+ * @param {string} key - The key of the item to retrieve.
251
+ * @param {string} secretKey - The secret key to use for decryption.
252
+ * @param {LocationPreference} location - The storage location to search: 'local', 'session', 'cookie', or 'any' (checks session, local, cookie in that order).
253
+ * @returns {Promise<string | null>} A promise that resolves with the decrypted value, or `null` if the item is not found or decryption fails.
157
254
  */
158
255
  async function getDecryptedItem(key, secretKey, location) {
159
- if (typeof window === "undefined") {
160
- return null;
161
- }
162
256
  let encryptedData = null;
163
- if (location === "session" || location === "any") {
164
- encryptedData = window.sessionStorage.getItem(key);
165
- }
166
- if (!encryptedData && (location === "local" || location === "any")) {
167
- encryptedData = window.localStorage.getItem(key);
168
- }
169
- if (!encryptedData) {
170
- return null;
257
+ if (location === "cookie" || isServer) {
258
+ const cookieStorage = getCookieStorage();
259
+ encryptedData = cookieStorage.getItem(key);
260
+ if (encryptedData) {
261
+ try {
262
+ return await decrypt(encryptedData, secretKey);
263
+ }
264
+ catch (error) {
265
+ return null;
266
+ }
267
+ }
268
+ if (location === "cookie") {
269
+ return null;
270
+ }
171
271
  }
172
- try {
173
- return await decrypt(encryptedData, secretKey);
272
+ if (location === "session" || location === "any") {
273
+ const sessionStorage = getSessionStorage();
274
+ encryptedData = sessionStorage?.getItem(key) || null;
275
+ if (encryptedData) {
276
+ try {
277
+ return await decrypt(encryptedData, secretKey);
278
+ }
279
+ catch (error) {
280
+ return null;
281
+ }
282
+ }
174
283
  }
175
- catch (error) {
176
- return null;
284
+ if (location === "local" || location === "any") {
285
+ const storage = getStorage();
286
+ encryptedData = storage?.getItem(key) || null;
287
+ if (encryptedData) {
288
+ try {
289
+ return await decrypt(encryptedData, secretKey);
290
+ }
291
+ catch (error) {
292
+ return null;
293
+ }
294
+ }
177
295
  }
296
+ return null;
178
297
  }
179
298
 
180
299
  /**
181
- * Enum defining available screen sizes.
300
+ * An enum that defines a set of standardized screen size labels, ranging from extra-small (XS) to extra-extra-large (XXL).
301
+ * These labels are used to create a consistent vocabulary for responsive design across the application.
182
302
  */
183
303
  var ScreenSize;
184
304
  (function (ScreenSize) {
@@ -190,8 +310,8 @@ var ScreenSize;
190
310
  ScreenSize["XXL"] = "XXL";
191
311
  })(ScreenSize || (ScreenSize = {}));
192
312
  /**
193
- * Enum defining breakpoints for design based on screen width.
194
- * Values are in pixels.
313
+ * An enum that establishes specific pixel values for screen width breakpoints, corresponding to the labels in `ScreenSize`.
314
+ * These values are used to implement responsive design changes at standard device widths.
195
315
  */
196
316
  var ScreenBreakpoint;
197
317
  (function (ScreenBreakpoint) {
@@ -203,7 +323,9 @@ var ScreenBreakpoint;
203
323
  ScreenBreakpoint[ScreenBreakpoint["XXL"] = 1600] = "XXL";
204
324
  })(ScreenBreakpoint || (ScreenBreakpoint = {}));
205
325
  /**
206
- * Map that associates each screen size defined in `ScreenSize` with its corresponding pixel value from `ScreenBreakpoint`.
326
+ * A map that associates the symbolic screen size names from the `ScreenSize` enum with their
327
+ * corresponding pixel values from the `ScreenBreakpoint` enum. This provides an easy way to
328
+ * look up the pixel width for a given screen size label.
207
329
  * @type {Map<ScreenSize, number>}
208
330
  */
209
331
  const screenMap = new Map();
@@ -215,7 +337,9 @@ screenMap.set(ScreenSize.XL, ScreenBreakpoint.XL);
215
337
  screenMap.set(ScreenSize.XXL, ScreenBreakpoint.XXL);
216
338
 
217
339
  /**
218
- * Enum representing all HTTP exception codes.
340
+ * An enum that defines a comprehensive set of HTTP status codes, organized by category
341
+ * (Informational, Success, Redirection, Client Errors, Server Errors). It also includes
342
+ * custom error codes for application-specific scenarios like network errors.
219
343
  * @readonly
220
344
  */
221
345
  var ExceptionEnum;
@@ -294,7 +418,7 @@ var ExceptionEnum;
294
418
  })(ExceptionEnum || (ExceptionEnum = {}));
295
419
 
296
420
  /**
297
- * Enum representing various MIME types for different file categories.
421
+ * An enum that defines MIME types for common image formats.
298
422
  * @readonly
299
423
  */
300
424
  var ImageTypes;
@@ -310,14 +434,26 @@ var ImageTypes;
310
434
  ImageTypes["WEBP"] = "image/webp";
311
435
  ImageTypes["XICON"] = "image/x-icon";
312
436
  })(ImageTypes || (ImageTypes = {}));
437
+ /**
438
+ * An enum for generic audio MIME types.
439
+ * @readonly
440
+ */
313
441
  var AudioTypes;
314
442
  (function (AudioTypes) {
315
443
  AudioTypes["Audios"] = "audio/*";
316
444
  })(AudioTypes || (AudioTypes = {}));
445
+ /**
446
+ * An enum for generic video MIME types.
447
+ * @readonly
448
+ */
317
449
  var VideoTypes;
318
450
  (function (VideoTypes) {
319
451
  VideoTypes["Videos"] = "video/*";
320
452
  })(VideoTypes || (VideoTypes = {}));
453
+ /**
454
+ * An enum that defines MIME types for various text-based formats, including plain text, markup, and data serialization formats.
455
+ * @readonly
456
+ */
321
457
  var TextTypes;
322
458
  (function (TextTypes) {
323
459
  TextTypes["PlainText"] = "text/plain";
@@ -328,6 +464,10 @@ var TextTypes;
328
464
  TextTypes["JSON"] = "application/json";
329
465
  TextTypes["XML"] = "application/xml";
330
466
  })(TextTypes || (TextTypes = {}));
467
+ /**
468
+ * An enum that defines MIME types for common document formats, such as PDFs and Microsoft Office files.
469
+ * @readonly
470
+ */
331
471
  var DocumentTypes;
332
472
  (function (DocumentTypes) {
333
473
  DocumentTypes["PDF"] = "application/pdf";
@@ -338,6 +478,10 @@ var DocumentTypes;
338
478
  DocumentTypes["PowerPoint"] = "application/vnd.ms-powerpoint";
339
479
  DocumentTypes["PowerPointOpenXML"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
340
480
  })(DocumentTypes || (DocumentTypes = {}));
481
+ /**
482
+ * An enum that defines MIME types for popular archive and compression formats.
483
+ * @readonly
484
+ */
341
485
  var ArchiveTypes;
342
486
  (function (ArchiveTypes) {
343
487
  ArchiveTypes["ZIP"] = "application/zip";
@@ -345,6 +489,10 @@ var ArchiveTypes;
345
489
  ArchiveTypes["TAR"] = "application/x-tar";
346
490
  ArchiveTypes["RAR"] = "application/x-rar-compressed";
347
491
  })(ArchiveTypes || (ArchiveTypes = {}));
492
+ /**
493
+ * An enum that defines MIME types for different font file formats.
494
+ * @readonly
495
+ */
348
496
  var FontTypes;
349
497
  (function (FontTypes) {
350
498
  FontTypes["TrueType"] = "font/ttf";
@@ -352,12 +500,20 @@ var FontTypes;
352
500
  FontTypes["WebOpenFont"] = "font/woff";
353
501
  FontTypes["WebOpenFont2"] = "font/woff2";
354
502
  })(FontTypes || (FontTypes = {}));
503
+ /**
504
+ * An enum that defines MIME types for application-specific formats, including executables and packages.
505
+ * @readonly
506
+ */
355
507
  var AppTypes;
356
508
  (function (AppTypes) {
357
509
  AppTypes["Executable"] = "application/octet-stream";
358
510
  AppTypes["AndroidAPK"] = "application/vnd.android.package-archive";
359
511
  AppTypes["Java"] = "application/java-archive";
360
512
  })(AppTypes || (AppTypes = {}));
513
+ /**
514
+ * An enum for miscellaneous MIME types that do not fit into the other categories.
515
+ * @readonly
516
+ */
361
517
  var OtherTypes;
362
518
  (function (OtherTypes) {
363
519
  OtherTypes["JSONLD"] = "application/ld+json";
@@ -423,10 +579,8 @@ var ContentTypeEnum;
423
579
  })(ContentTypeEnum || (ContentTypeEnum = {}));
424
580
 
425
581
  /**
426
- * Enum for key codes used in keyboard events.
427
- * This object holds various key codes commonly used for handling keyboard events.
428
- * The keys defined here correspond to specific key codes that can be used to detect
429
- * user input in web applications.
582
+ * An enum that provides a comprehensive mapping of common keyboard keys to their corresponding key codes.
583
+ * This is useful for handling keyboard events in a readable and standardized way, avoiding the use of magic numbers.
430
584
  * @readonly
431
585
  * @enum {number}
432
586
  */
@@ -487,8 +641,8 @@ var KeyCodeEnum;
487
641
  })(KeyCodeEnum || (KeyCodeEnum = {}));
488
642
 
489
643
  /**
490
- * Enum for different storage keys used in the application.
491
- * This enum contains the keys for storing authentication token, locale information, user info, roles, and more.
644
+ * An enum that defines a standardized set of keys for accessing `localStorage` and `sessionStorage`.
645
+ * This helps to avoid magic strings and ensures consistency when managing data persistence in the browser.
492
646
  * @readonly
493
647
  * @enum {string}
494
648
  */
@@ -536,9 +690,9 @@ var StorageKeyEnum;
536
690
  StorageKeyEnum["APP_SESSION_CACHE_KEY"] = "COMMON__SESSION__KEY";
537
691
  })(StorageKeyEnum || (StorageKeyEnum = {}));
538
692
  /**
539
- * Enum defining types of storage.
693
+ * A frozen object that serves as an enum for storage types, distinguishing between `sessionStorage` and `localStorage`.
694
+ * Using this object provides a type-safe way to specify the desired storage mechanism.
540
695
  * @readonly
541
- * @enum {number}
542
696
  */
543
697
  const StorageTypeEnum = {
544
698
  /**
@@ -554,7 +708,9 @@ const StorageTypeEnum = {
554
708
  };
555
709
 
556
710
  /**
557
- * Enum representing different types of errors.
711
+ * An enum that defines a vocabulary of error types, covering a wide range of potential issues
712
+ * from validation and network problems to runtime and syntax errors. This provides a standardized
713
+ * way to classify errors throughout the application.
558
714
  * @readonly
559
715
  */
560
716
  var ErrorEnum;
@@ -575,28 +731,31 @@ var ErrorEnum;
575
731
  ErrorEnum["URI"] = "uri";
576
732
  })(ErrorEnum || (ErrorEnum = {}));
577
733
  /**
578
- * Enum representing different error messages.
734
+ * An enum that provides standardized, user-friendly messages for different error types.
735
+ * These messages are intended to be displayed to the user or used in logs.
579
736
  * @readonly
580
737
  */
581
738
  var ErrorMessages;
582
739
  (function (ErrorMessages) {
583
- ErrorMessages["WARNING"] = "Algo no est\u00E1 del todo bien. Verifica y vuelve a intentar.";
584
- ErrorMessages["ERROR"] = "Ocurri\u00F3 un error inesperado.";
585
- ErrorMessages["CRITICAL"] = "Error cr\u00EDtico. Contacta al soporte t\u00E9cnico.";
586
- ErrorMessages["VALIDATION"] = "Hay errores en el formulario. Revisa los campos.";
587
- ErrorMessages["COMPONENT"] = "Error en la carga del componente. Intenta recargar.";
588
- ErrorMessages["NETWORK"] = "Problema de conexi\u00F3n. Verifica tu internet.";
589
- ErrorMessages["AUTHENTICATION"] = "No tienes permisos para realizar esta acci\u00F3n.";
590
- ErrorMessages["RUNTIME"] = "Error de ejecuci\u00F3n. Intenta nuevamente.";
591
- ErrorMessages["TYPE"] = "Tipo de error no identificado.";
592
- ErrorMessages["REFERENCE"] = "Referencia no v\u00E1lida.";
593
- ErrorMessages["SYNTAX"] = "Error de sintaxis en el c\u00F3digo.";
594
- ErrorMessages["RANGE"] = "Error en el rango de valores.";
595
- ErrorMessages["EVAL"] = "Error en la evaluaci\u00F3n.";
596
- ErrorMessages["URI"] = "URI no v\u00E1lida.";
740
+ ErrorMessages["WARNING"] = "Something is not quite right. Please check and try again.";
741
+ ErrorMessages["ERROR"] = "An unexpected error occurred.";
742
+ ErrorMessages["CRITICAL"] = "Critical error. Please contact technical support.";
743
+ ErrorMessages["VALIDATION"] = "There are errors in the form. Please review the fields.";
744
+ ErrorMessages["COMPONENT"] = "Error loading the component. Try reloading.";
745
+ ErrorMessages["NETWORK"] = "Connection problem. Please check your internet.";
746
+ ErrorMessages["AUTHENTICATION"] = "You do not have permission to perform this action.";
747
+ ErrorMessages["RUNTIME"] = "Execution error. Please try again.";
748
+ ErrorMessages["TYPE"] = "Unidentified error type.";
749
+ ErrorMessages["REFERENCE"] = "Invalid reference.";
750
+ ErrorMessages["SYNTAX"] = "Syntax error in the code.";
751
+ ErrorMessages["RANGE"] = "Error in the range of values.";
752
+ ErrorMessages["EVAL"] = "Error in evaluation.";
753
+ ErrorMessages["URI"] = "Invalid URI.";
597
754
  })(ErrorMessages || (ErrorMessages = {}));
598
755
  /**
599
- * Enum representing different error styles.
756
+ * An enum that defines CSS styles for console log messages, corresponding to each error type in `ErrorEnum`.
757
+ * This allows for visually distinct, styled logging in the browser's console, making it easier to
758
+ * identify the severity and type of logged errors during development.
600
759
  * @readonly
601
760
  */
602
761
  var ErrorStyles;
@@ -617,7 +776,8 @@ var ErrorStyles;
617
776
  ErrorStyles["URI"] = "color: darkcyan; font-weight: bold;";
618
777
  })(ErrorStyles || (ErrorStyles = {}));
619
778
  /**
620
- * A record mapping ErrorEnum to their corresponding error messages.
779
+ * A frozen record that maps each `ErrorEnum` member to its corresponding user-friendly message from `ErrorMessages`.
780
+ * This provides a convenient, type-safe way to look up error messages.
621
781
  */
622
782
  const ERROR_MESSAGES = {
623
783
  [ErrorEnum.WARNING]: ErrorMessages.WARNING,
@@ -636,7 +796,8 @@ const ERROR_MESSAGES = {
636
796
  [ErrorEnum.URI]: ErrorMessages.URI,
637
797
  };
638
798
  /**
639
- * A record mapping ErrorEnum to their corresponding error styles.
799
+ * A frozen record that maps each `ErrorEnum` member to its corresponding CSS style string from `ErrorStyles`.
800
+ * This enables easy retrieval of the correct style for console logging based on the error type.
640
801
  */
641
802
  const ERROR_STYLES = {
642
803
  [ErrorEnum.WARNING]: ErrorStyles.WARNING,
@@ -655,42 +816,202 @@ const ERROR_STYLES = {
655
816
  [ErrorEnum.URI]: ErrorStyles.URI,
656
817
  };
657
818
 
819
+ class BaseError extends Error {
820
+ timestamp;
821
+ context;
822
+ constructor(message, context) {
823
+ super(message);
824
+ this.name = this.constructor.name;
825
+ this.timestamp = new Date();
826
+ this.context = context;
827
+ Error.captureStackTrace?.(this, this.constructor);
828
+ }
829
+ toJSON() {
830
+ return {
831
+ name: this.name,
832
+ message: this.message,
833
+ code: this.code,
834
+ statusCode: this.statusCode,
835
+ timestamp: this.timestamp.toISOString(),
836
+ context: this.context,
837
+ stack: this.stack,
838
+ };
839
+ }
840
+ }
841
+
842
+ class NetworkError extends BaseError {
843
+ code = 'NETWORK_ERROR';
844
+ statusCode;
845
+ originalError;
846
+ constructor(message = 'Network request failed', statusCode, originalError, context) {
847
+ super(message, context);
848
+ this.statusCode = statusCode;
849
+ this.originalError = originalError;
850
+ }
851
+ static fromAxiosError(error) {
852
+ const statusCode = error.response?.status;
853
+ const message = error.response?.data?.message || error.message || 'Network request failed';
854
+ return new NetworkError(message, statusCode, error, {
855
+ url: error.config?.url,
856
+ method: error.config?.method,
857
+ responseData: error.response?.data,
858
+ });
859
+ }
860
+ static fromFetchError(error) {
861
+ return new NetworkError(error.message || 'Network request failed', undefined, error, {
862
+ cause: error.cause,
863
+ });
864
+ }
865
+ }
866
+
867
+ class AuthError extends BaseError {
868
+ code = 'AUTH_ERROR';
869
+ statusCode = 401;
870
+ constructor(message = 'Authentication failed', context) {
871
+ super(message, context);
872
+ }
873
+ static unauthorized(message) {
874
+ return new AuthError(message || 'Unauthorized access');
875
+ }
876
+ static tokenExpired() {
877
+ return new AuthError('Token has expired');
878
+ }
879
+ static tokenInvalid() {
880
+ return new AuthError('Invalid token');
881
+ }
882
+ static tokenMissing() {
883
+ return new AuthError('Authentication token is missing');
884
+ }
885
+ }
886
+
887
+ class ValidationError extends BaseError {
888
+ code = 'VALIDATION_ERROR';
889
+ statusCode = 422;
890
+ issues;
891
+ constructor(message = 'Validation failed', issues = [], context) {
892
+ super(message, context);
893
+ this.issues = issues;
894
+ }
895
+ static fromIssues(issues) {
896
+ return new ValidationError(`Validation failed: ${issues.length} issue(s)`, issues);
897
+ }
898
+ static fromField(field, message, value) {
899
+ return new ValidationError(`Validation failed for field "${field}"`, [{ field, message, value }]);
900
+ }
901
+ }
902
+
903
+ class ServerError extends BaseError {
904
+ code = 'SERVER_ERROR';
905
+ statusCode;
906
+ constructor(message = 'Server error occurred', statusCode = 500, context) {
907
+ super(message, context);
908
+ this.statusCode = statusCode;
909
+ }
910
+ static internal(message) {
911
+ return new ServerError(message || 'Internal server error', 500);
912
+ }
913
+ static badGateway(message) {
914
+ return new ServerError(message || 'Bad gateway', 502);
915
+ }
916
+ static serviceUnavailable(message) {
917
+ return new ServerError(message || 'Service unavailable', 503);
918
+ }
919
+ static gatewayTimeout(message) {
920
+ return new ServerError(message || 'Gateway timeout', 504);
921
+ }
922
+ }
923
+
658
924
  /**
659
- * Maneja y registra errores en la consola, además de permitir redirecciones configurables.
660
- * @param error - Error capturado (string o Error)
661
- * @param redirect - `true` si se quiere redirigir a una página de error
662
- * @param route - Ruta personalizada para la página de error (por defecto: `/error`)
663
- * @param passMethod - Método para pasar el error a la ruta (`query`, `localStorage`, `sessionStorage`)
664
- * @returns Mensaje user-friendly del error
665
- */
666
- function handleError(error, redirect = false, route = '/error', passMethod = 'query') {
925
+ * Handles and logs errors to the console. Supports both standard Error objects and custom error classes
926
+ * (BaseError, NetworkError, etc.). It infers the error type, logs a styled message with detailed information,
927
+ * and returns structured error information for further handling.
928
+ *
929
+ * @param {unknown} error - The captured error, which can be a string, Error object, or custom error class.
930
+ * @returns {ErrorInfo | undefined} An object containing the error message, type, and additional error data,
931
+ * or `undefined` if the error is not an Error instance.
932
+ *
933
+ * @example
934
+ * ```typescript
935
+ * try {
936
+ * await someOperation();
937
+ * } catch (error) {
938
+ * const errorInfo = handleError(error);
939
+ * if (errorInfo) {
940
+ * // Use errorInfo.message, errorInfo.type, errorInfo.errorData
941
+ * // Handle redirect or other actions as needed
942
+ * }
943
+ * }
944
+ * ```
945
+ */
946
+ function handleError(error) {
667
947
  if (!(error instanceof Error)) {
668
948
  console.error("Unrecognized error:", error);
669
- return;
949
+ return undefined;
670
950
  }
671
- const router = useRouter();
672
- const type = inferErrorType(error);
673
- const message = ERROR_MESSAGES[type] || 'Error desconocido.';
674
- console.log(`%c[${type.toUpperCase()}] ${message}`, ERROR_STYLES[type]);
675
- if (redirect) {
676
- if (passMethod === 'query') {
677
- router.push({ path: route, query: { errorMessage: encodeURIComponent(message) } });
951
+ let type;
952
+ let message;
953
+ let errorData = undefined;
954
+ if (error instanceof BaseError) {
955
+ type = inferErrorTypeFromBaseError(error);
956
+ message = error.message || ERROR_MESSAGES[type] || 'Error desconocido.';
957
+ errorData = {
958
+ code: error.code,
959
+ statusCode: error.statusCode,
960
+ context: error.context,
961
+ timestamp: error.timestamp,
962
+ };
963
+ if (error instanceof ValidationError && error.issues.length > 0) {
964
+ errorData.issues = error.issues;
678
965
  }
679
- else if (passMethod === 'localStorage') {
680
- localStorage.setItem('errorMessage', message);
681
- router.push(route);
966
+ }
967
+ else {
968
+ type = inferErrorType(error);
969
+ message = ERROR_MESSAGES[type] || error.message || 'Error desconocido.';
970
+ }
971
+ const logMessage = `%c[${type.toUpperCase()}] ${message}`;
972
+ const logStyle = ERROR_STYLES[type] || ERROR_STYLES.error;
973
+ console.group(logMessage, logStyle);
974
+ console.error('Error details:', error);
975
+ if (errorData) {
976
+ console.error('Error data:', errorData);
977
+ }
978
+ if (error.stack) {
979
+ console.error('Stack trace:', error.stack);
980
+ }
981
+ console.groupEnd();
982
+ return {
983
+ message,
984
+ type,
985
+ ...(errorData && { errorData }),
986
+ };
987
+ }
988
+ function inferErrorTypeFromBaseError(error) {
989
+ if (error instanceof NetworkError) {
990
+ if (error.statusCode === 401 || error.statusCode === 403) {
991
+ return 'authentication';
682
992
  }
683
- else if (passMethod === 'sessionStorage') {
684
- sessionStorage.setItem('errorMessage', message);
685
- router.push(route);
993
+ return 'network';
994
+ }
995
+ if (error instanceof AuthError) {
996
+ return 'authentication';
997
+ }
998
+ if (error instanceof ValidationError) {
999
+ return 'validation';
1000
+ }
1001
+ if (error instanceof ServerError) {
1002
+ if (error.statusCode >= 500) {
1003
+ return 'critical';
686
1004
  }
1005
+ return 'error';
687
1006
  }
688
- return message;
1007
+ return 'error';
689
1008
  }
690
1009
  /**
691
- * Infiera el tipo de error basado en su mensaje o nombre.
692
- * @param error - El error que se desea analizar.
693
- * @returns El tipo de error determinado.
1010
+ * Infers the `ErrorType` of an error by analyzing its name and message content.
1011
+ * This helps in categorizing the error for standardized handling and logging.
1012
+ *
1013
+ * @param {string | Error} error - The error to analyze.
1014
+ * @returns {ErrorType} The inferred error type.
694
1015
  */
695
1016
  function inferErrorType(error) {
696
1017
  const msg = typeof error === 'string' ? error : error.message;
@@ -715,15 +1036,14 @@ let endpointsConfig = {
715
1036
  LOGOUT: "/logout",
716
1037
  };
717
1038
  /**
718
- * Configures authentication endpoint URLs globally.
719
- * This function freezes the object to prevent further modifications.
720
- *
721
- * @param {EndpointConfig} config - An object containing the authentication endpoint URLs.
722
- * @param {string} config.loginEndpoint - URL of the login endpoint.
723
- * @param {string} config.refreshEndpoint - URL of the refresh token endpoint.
724
- * @param {string} config.logoutEndpoint - URL of the logout endpoint.
1039
+ * Configures the global authentication endpoint URLs for the application.
1040
+ * This function should be called once at startup to define the API endpoints for login,
1041
+ * token refresh, and logout. The configuration is then frozen to prevent changes.
725
1042
  *
726
- * @returns {void} Does not return anything but freezes the endpoint configuration object.
1043
+ * @param {EndpointConfig} config - An object containing the URLs for the authentication endpoints.
1044
+ * @param {string} config.loginEndpoint - The URL for the login endpoint.
1045
+ * @param {string} config.refreshEndpoint - The URL for the token refresh endpoint.
1046
+ * @param {string} config.logoutEndpoint - The URL for the logout endpoint.
727
1047
  */
728
1048
  function configEndpoints(config) {
729
1049
  endpointsConfig = Object.freeze({
@@ -733,12 +1053,9 @@ function configEndpoints(config) {
733
1053
  });
734
1054
  }
735
1055
  /**
736
- * Retrieves the configured authentication endpoint URLs.
1056
+ * Retrieves the globally configured authentication endpoint URLs.
737
1057
  *
738
- * @returns {EndpointsConfig} An object containing the configured authentication endpoints.
739
- * @property {string} LOGIN - URL of the login endpoint.
740
- * @property {string} REFRESH - URL of the refresh token endpoint.
741
- * @property {string} LOGOUT - URL of the logout endpoint.
1058
+ * @returns {EndpointsConfig} A frozen object containing the configured `LOGIN`, `REFRESH`, and `LOGOUT` endpoints.
742
1059
  */
743
1060
  function getEndpointsConfig() {
744
1061
  return endpointsConfig;
@@ -746,13 +1063,11 @@ function getEndpointsConfig() {
746
1063
 
747
1064
  let appKey = null;
748
1065
  /**
749
- * Sets the main application encryption key.
750
- * This key is expected to be used for encryption purposes within the application.
1066
+ * Sets the main application key, which is intended for use in encryption and signing operations.
1067
+ * This function should be called once at application startup to configure the key.
751
1068
  *
752
- * @param {AppKeyConfig} config - An object containing the application encryption key.
753
- * @param {string} config.key - The new application encryption key.
754
- *
755
- * @returns {void} Does not return anything, but updates the application key.
1069
+ * @param {AppKeyConfig} config - An object containing the application key.
1070
+ * @param {string} config.appKey - The application key.
756
1071
  * @throws {Error} If the provided key is null, undefined, or an empty string.
757
1072
  */
758
1073
  function configAppKey(config) {
@@ -762,11 +1077,10 @@ function configAppKey(config) {
762
1077
  appKey = config.appKey;
763
1078
  }
764
1079
  /**
765
- * Retrieves the current application encryption key.
766
- * Throws an error if the application key has not been configured.
1080
+ * Retrieves the configured application key.
767
1081
  *
768
- * @returns {string} The configured application encryption key.
769
- * @throws {Error} If the application encryption key has not been set.
1082
+ * @returns {string} The configured application key.
1083
+ * @throws {Error} If the application key has not been set by calling `configAppKey` first.
770
1084
  */
771
1085
  function getAppKey() {
772
1086
  if (appKey === null) {
@@ -830,15 +1144,16 @@ async function loadSessionConfig() {
830
1144
  }
831
1145
  }
832
1146
  /**
833
- * Configures the session identifier and/or data persistence preference
834
- * for the active browser session.
835
- *
836
- * This function is asynchronous because it will always attempt to load the current configuration
837
- * before applying changes and then saving them.
1147
+ * Configures the session ID and persistence preference for the application.
1148
+ * This function allows setting a custom session ID and specifying whether session-related
1149
+ * data should be stored in `localStorage` or `sessionStorage`. The configuration is
1150
+ * then encrypted and saved to the chosen storage.
838
1151
  *
839
- * @param {SessionConfigObject} config - An object containing the unique session identifier and/or
840
- * the persistence preference.
841
- * @returns {Promise<void>} A promise that resolves when the session has been configured and saved.
1152
+ * @param {SessionConfigObject} config - An object containing the session configuration.
1153
+ * @param {string} [config.sessionId] - A unique identifier for the session. If not provided, the existing one is maintained.
1154
+ * @param {LocationPreference} [config.persistencePreference] - The storage location ('local' or 'session').
1155
+ * If not provided, the existing preference is maintained.
1156
+ * @returns {Promise<void>} A promise that resolves once the session has been configured and saved.
842
1157
  */
843
1158
  async function configSession(config) {
844
1159
  if (config.sessionId) {
@@ -851,30 +1166,27 @@ async function configSession(config) {
851
1166
  await saveSessionConfig();
852
1167
  }
853
1168
  /**
854
- * Retrieves the current session identifier.
855
- * Always attempts to load the configuration from storage. If it fails, it uses the internal state.
1169
+ * Retrieves the current session identifier, loading it from storage if available.
856
1170
  *
857
- * @returns {Promise<string>} A promise that resolves with the unique session identifier.
1171
+ * @returns {Promise<string>} A promise that resolves with the session ID.
858
1172
  */
859
1173
  async function getSessionId() {
860
1174
  await loadSessionConfig();
861
1175
  return _sessionConfig.SESSION_ID;
862
1176
  }
863
1177
  /**
864
- * Retrieves the current data persistence preference.
865
- * Always attempts to load the configuration from storage. If it fails, it uses the internal state.
1178
+ * Retrieves the current data persistence preference, loading it from storage if available.
866
1179
  *
867
- * @returns {Promise<SessionPreference>} A promise that resolves with the configured persistence preference ('local' or 'session').
1180
+ * @returns {Promise<LocationPreference>} A promise that resolves with the persistence preference ('local' or 'session').
868
1181
  */
869
1182
  async function getSessionPersistence() {
870
1183
  await loadSessionConfig();
871
1184
  return _sessionConfig.PERSISTENCE;
872
1185
  }
873
1186
  /**
874
- * Retrieves the complete session configuration.
875
- * Always attempts to load the configuration from storage. If it fails, it uses the internal state.
1187
+ * Retrieves the complete session configuration object, loading it from storage if available.
876
1188
  *
877
- * @returns {Promise<SessionConfig>} A promise that resolves with the session configuration object.
1189
+ * @returns {Promise<SessionConfig>} A promise that resolves with the full session configuration.
878
1190
  */
879
1191
  async function getSessionConfig() {
880
1192
  await loadSessionConfig();
@@ -890,14 +1202,12 @@ let refreshTokenPathsConfig = {
890
1202
  refreshTokenPath: "data.refresh_token",
891
1203
  };
892
1204
  /**
893
- * Configures the paths for access and refresh tokens in the authentication response.
894
- * This function freezes the object to prevent further modifications.
1205
+ * Configures the dot-notation paths for extracting access and refresh tokens from the initial login response.
1206
+ * The configuration is frozen to prevent runtime changes.
895
1207
  *
896
- * @param {TokenPathsConfig} config - An object containing the paths for access and refresh tokens.
897
- * @param {string} [config.accessTokenPath="data.access_token"] - Path to the access token in the response.
898
- * @param {string} [config.refreshTokenPath="data.refresh_token"] - Path to the refresh token in the response.
899
- *
900
- * @returns {void} Does not return anything but freezes the token paths configuration object.
1208
+ * @param {TokenPathsConfig} config - An object containing the token paths.
1209
+ * @param {string} [config.accessTokenPath="data.access_token"] - The path to the access token.
1210
+ * @param {string} [config.refreshTokenPath="data.refresh_token"] - The path to the refresh token.
901
1211
  */
902
1212
  function configTokenPaths(config) {
903
1213
  tokenPathsConfig = Object.freeze({
@@ -906,14 +1216,12 @@ function configTokenPaths(config) {
906
1216
  });
907
1217
  }
908
1218
  /**
909
- * Configures the paths for access and refresh tokens in the refresh response.
910
- * This function freezes the object to prevent further modifications.
911
- *
912
- * @param {TokenPathsConfig} config - An object containing the paths for access and refresh tokens.
913
- * @param {string} [config.accessTokenPath="data.access_token"] - Path to the access token in the response.
914
- * @param {string} [config.refreshTokenPath="data.refresh_token"] - Path to the refresh token in the response.
1219
+ * Configures the dot-notation paths for extracting access and refresh tokens from the token refresh response.
1220
+ * The configuration is frozen to prevent runtime changes.
915
1221
  *
916
- * @returns {void} Does not return anything but freezes the refresh token paths configuration object.
1222
+ * @param {TokenPathsConfig} config - An object containing the token paths for the refresh response.
1223
+ * @param {string} [config.accessTokenPath="data.access_token"] - The path to the new access token.
1224
+ * @param {string} [config.refreshTokenPath="data.refresh_token"] - The path to the new refresh token.
917
1225
  */
918
1226
  function configRefreshTokenPaths(config) {
919
1227
  refreshTokenPathsConfig = Object.freeze({
@@ -922,135 +1230,139 @@ function configRefreshTokenPaths(config) {
922
1230
  });
923
1231
  }
924
1232
  /**
925
- * Retrieves the configured authentication token paths.
1233
+ * Retrieves the configured token paths for the initial login response.
926
1234
  *
927
- * @returns {AuthTokenPaths} An object containing the configured authentication token paths.
928
- * @property {string} accessTokenPath - Path to the access token in the response.
929
- * @property {string} refreshTokenPath - Path to the refresh token in the response.
1235
+ * @returns {AuthTokenPaths} A frozen object containing the `accessTokenPath` and `refreshTokenPath`.
930
1236
  */
931
1237
  function getTokenPathsConfig() {
932
1238
  return tokenPathsConfig;
933
1239
  }
1240
+ /**
1241
+ * Retrieves the configured token paths for the token refresh response.
1242
+ *
1243
+ * @returns {AuthTokenPaths} A frozen object containing the `accessTokenPath` and `refreshTokenPath` for the refresh response.
1244
+ */
934
1245
  function getRefreshTokenPathsConfig() {
935
1246
  return refreshTokenPathsConfig;
936
1247
  }
937
1248
 
938
1249
  /**
939
- * Clears all stored authentication data (access and refresh tokens)
940
- * from either sessionStorage, localStorage, or both based on the provided location preference.
1250
+ * Removes all stored authentication credentials (access and refresh tokens) from the specified storage locations.
941
1251
  *
942
- * @param {LocationPreference} location - The storage preference ('local' for localStorage, 'session' for sessionStorage, 'any' for both).
943
- * @returns {Promise<void>} A promise that resolves when all relevant storage items are removed.
1252
+ * @param {LocationPreference} location - The storage location to clear. Can be 'local' for `localStorage`,
1253
+ * 'session' for `sessionStorage`, 'cookie' for cookies, or 'any' to clear all.
1254
+ * @returns {Promise<void>} A promise that resolves when the credentials have been cleared.
944
1255
  */
945
1256
  const cleanCredentials = async (location) => {
946
1257
  const tokensConfig = getTokenConfig();
1258
+ if (location === "cookie" || isServer) {
1259
+ const cookieStorage = getCookieStorage();
1260
+ Object.keys(tokensConfig).forEach((key) => {
1261
+ cookieStorage.removeItem(tokensConfig[key], { path: '/' });
1262
+ });
1263
+ if (location === "cookie") {
1264
+ return;
1265
+ }
1266
+ }
947
1267
  Object.keys(tokensConfig).forEach((key) => {
948
1268
  const itemKey = tokensConfig[key];
949
1269
  if (location === "local" || location === "any") {
950
- localStorage.removeItem(itemKey);
1270
+ const storage = getStorage();
1271
+ storage?.removeItem(itemKey);
951
1272
  }
952
1273
  if (location === "session" || location === "any") {
953
- sessionStorage.removeItem(itemKey);
1274
+ const sessionStorage = getSessionStorage();
1275
+ sessionStorage?.removeItem(itemKey);
954
1276
  }
955
1277
  });
956
1278
  };
957
1279
  /**
958
- * Retrieves the authentication token (access token) from storage, decrypting it
959
- * using the provided secret key and based on the specified session preference.
1280
+ * Retrieves and decrypts the access token from the specified storage location.
960
1281
  *
961
- * @param {string} secretKey - The secret key used for decryption.
962
- * @param {SessionPreference} preference - The storage preference ('local' for localStorage, 'session' for sessionStorage).
963
- * @returns {Promise<string | null>} A promise that resolves with the decrypted access token, or null if not found.
1282
+ * @param {string} secretKey - The secret key to use for decryption.
1283
+ * @param {LocationPreference} location - The storage location to search ('local', 'session', 'cookie', or 'any').
1284
+ * @returns {Promise<string | null>} A promise that resolves with the decrypted access token, or `null` if it's not found.
964
1285
  */
965
1286
  const getAuthToken = async (secretKey, location) => {
966
1287
  const tokensConfig = getTokenConfig();
967
1288
  return await getDecryptedItem(tokensConfig.ACCESS_TOKEN, secretKey, location);
968
1289
  };
969
1290
  /**
970
- * Retrieves the authentication refresh token from storage, decrypting it
971
- * using the provided secret key and based on the specified session preference.
1291
+ * Retrieves and decrypts the refresh token from the specified storage location.
972
1292
  *
973
- * @param {string} secretKey - The secret key used for decryption.
974
- * @param {SessionPreference} preference - The storage preference ('local' for localStorage, 'session' for sessionStorage).
975
- * @returns {Promise<string | null>} A promise that resolves with the decrypted refresh token, or null if not found.
1293
+ * @param {string} secretKey - The secret key to use for decryption.
1294
+ * @param {LocationPreference} location - The storage location to search ('local', 'session', 'cookie', or 'any').
1295
+ * @returns {Promise<string | null>} A promise that resolves with the decrypted refresh token, or `null` if it's not found.
976
1296
  */
977
1297
  const getAuthRefreshToken = async (secretKey, location) => {
978
1298
  const tokensConfig = getTokenConfig();
979
1299
  return await getDecryptedItem(tokensConfig.REFRESH_TOKEN, secretKey, location);
980
1300
  };
981
1301
  /**
982
- * Stores the authentication token (access token) in storage after encrypting it,
983
- * based on the specified session preference.
1302
+ * Encrypts and stores the access token in the specified storage location.
984
1303
  *
985
1304
  * @param {string} token - The access token to store.
986
- * @param {string} secretKey - The secret key used for encryption.
987
- * @param {SessionPreference} preference - The storage preference ('local' for localStorage, 'session' for sessionStorage).
988
- * @returns {Promise<void>} A promise that resolves when the token is successfully stored.
1305
+ * @param {string} secretKey - The secret key to use for encryption.
1306
+ * @param {LocationPreference} location - The storage location ('local', 'session', or 'cookie').
1307
+ * @returns {Promise<void>} A promise that resolves when the token has been stored.
989
1308
  */
990
1309
  const storeAuthToken = async (token, secretKey, location) => {
991
1310
  const tokensConfig = getTokenConfig();
992
1311
  await storeEncryptedItem(tokensConfig.ACCESS_TOKEN, token, secretKey, location);
993
1312
  };
994
1313
  /**
995
- * Stores the authentication refresh token in storage after encrypting it,
996
- * based on the specified session preference.
1314
+ * Encrypts and stores the refresh token in the specified storage location.
997
1315
  *
998
1316
  * @param {string} token - The refresh token to store.
999
- * @param {string} secretKey - The secret key used for encryption.
1000
- * @param {SessionPreference} preference - The storage preference ('local' for localStorage, 'session' for sessionStorage).
1001
- * @returns {Promise<void>} A promise that resolves when the token is successfully stored.
1317
+ * @param {string} secretKey - The secret key to use for encryption.
1318
+ * @param {LocationPreference} location - The storage location ('local', 'session', or 'cookie').
1319
+ * @returns {Promise<void>} A promise that resolves when the token has been stored.
1002
1320
  */
1003
1321
  const storeAuthRefreshToken = async (token, secretKey, location) => {
1004
1322
  const tokensConfig = getTokenConfig();
1005
1323
  await storeEncryptedItem(tokensConfig.REFRESH_TOKEN, token, secretKey, location);
1006
1324
  };
1007
1325
  /**
1008
- * Verifies the validity and expiration of the current authentication token.
1009
- * If the token is missing, invalid, or expired, appropriate errors are thrown and credentials are cleaned.
1326
+ * Verifies the current user's authentication status by checking for a valid, unexpired access token.
1327
+ * It searches for the token in all storage locations (sessionStorage, localStorage, cookies).
1328
+ * If the token is missing, malformed, or expired, it logs the issue, clears credentials, and returns `false`.
1010
1329
  *
1011
- * @returns {Promise<boolean>} True if the token is valid and unexpired.
1012
- * @throws {Error} "TOKEN_MISSING" if no token is found, "TOKEN_EXPIRED" if the token has expired,
1013
- * "TOKEN_INVALID" if the token format is invalid.
1330
+ * @returns {Promise<boolean>} A promise that resolves to `true` if the user is authenticated, and `false` otherwise.
1014
1331
  */
1015
1332
  const verifyAuth = async () => {
1016
1333
  const sessionPersistence = 'any';
1017
1334
  const handleAuthError = async (message, shouldClean = true) => {
1018
- handleError(message, false);
1335
+ handleError(message);
1019
1336
  if (shouldClean) {
1020
1337
  await cleanCredentials(sessionPersistence);
1021
1338
  }
1022
1339
  return false;
1023
1340
  };
1341
+ const token = await getAuthToken(getAppKey(), sessionPersistence);
1342
+ if (!token) {
1343
+ return handleAuthError("TOKEN_MISSING: No valid token found");
1344
+ }
1024
1345
  try {
1025
- const token = await getAuthToken(getAppKey(), sessionPersistence);
1026
- if (!token) {
1027
- return await handleAuthError("TOKEN_MISSING: No valid token found");
1028
- }
1029
- let decoded;
1030
- try {
1031
- decoded = jwtDecode(token);
1032
- }
1033
- catch (decodeError) {
1034
- return await handleAuthError("TOKEN_INVALID: Invalid token format");
1035
- }
1346
+ const decoded = jwtDecode(token);
1036
1347
  const currentTime = Date.now() / 1000;
1037
1348
  if (typeof decoded.exp !== "number") {
1038
- return await handleAuthError("TOKEN_INVALID: Invalid expiration format");
1349
+ return handleAuthError("TOKEN_INVALID: Invalid expiration format");
1039
1350
  }
1040
1351
  if (decoded.exp <= currentTime) {
1041
- return await handleAuthError("TOKEN_EXPIRED: Token is expired");
1352
+ return handleAuthError("TOKEN_EXPIRED: Token is expired");
1042
1353
  }
1043
1354
  return true;
1044
1355
  }
1045
1356
  catch (error) {
1046
- return await handleAuthError("AUTH_ERROR: An unexpected error occurred", true);
1357
+ return handleAuthError("TOKEN_INVALID: Invalid token format");
1047
1358
  }
1048
1359
  };
1049
1360
 
1050
1361
  /**
1051
- * Converts a Proxy object to a plain object.
1052
- * @param {ProxyConstructor} proxy The Proxy object to convert.
1053
- * @returns {Object} The plain object.
1362
+ * Converts a Proxy object into a plain JavaScript object.
1363
+ *
1364
+ * @param {ProxyConstructor} proxy - The Proxy object to convert.
1365
+ * @returns {any} A new object containing the properties of the Proxy.
1054
1366
  */
1055
1367
  function proxyToPlainObject(proxy) {
1056
1368
  if (!proxy)
@@ -1062,10 +1374,11 @@ function proxyToPlainObject(proxy) {
1062
1374
  return plainObject;
1063
1375
  }
1064
1376
  /**
1065
- * Compares two objects to check if they have the same keys.
1066
- * @param {Object} object1 The first object to compare.
1067
- * @param {Object} object2 The second object to compare.
1068
- * @returns {boolean} True if the objects have the same keys, otherwise false.
1377
+ * Performs a shallow comparison to check if two objects have the same keys.
1378
+ *
1379
+ * @param {Record<string, any>} object1 - The first object.
1380
+ * @param {Record<string, any>} object2 - The second object.
1381
+ * @returns {boolean} `true` if both objects have the exact same set of keys, otherwise `false`.
1069
1382
  */
1070
1383
  function compareObject(object1, object2) {
1071
1384
  return Object.keys(object1).every(function (element) {
@@ -1073,10 +1386,11 @@ function compareObject(object1, object2) {
1073
1386
  });
1074
1387
  }
1075
1388
  /**
1076
- * Deeply compares two objects to check if they are equal.
1077
- * @param {Object} object1 The first object to compare.
1078
- * @param {Object} object2 The second object to compare.
1079
- * @returns {boolean} True if the objects are deeply equal, otherwise false.
1389
+ * Performs a deep comparison between two objects to determine if they are structurally and value-wise equal.
1390
+ *
1391
+ * @param {Record<string, any>} object1 - The first object.
1392
+ * @param {Record<string, any>} object2 - The second object.
1393
+ * @returns {boolean} `true` if the objects are deeply equal, otherwise `false`.
1080
1394
  */
1081
1395
  function deepEqual(object1, object2) {
1082
1396
  if (object1 === object2)
@@ -1097,9 +1411,12 @@ function deepEqual(object1, object2) {
1097
1411
  return true;
1098
1412
  }
1099
1413
  /**
1100
- * Deeply clones an object.
1101
- * @param {Object} obj The object to clone.
1102
- * @returns {Object} The cloned object.
1414
+ * Creates a deep clone of a given object, including nested objects and arrays.
1415
+ *
1416
+ * @template T - The type of the object being cloned.
1417
+ * @param {T} obj - The object to clone.
1418
+ * @returns {T} A new object that is a deep clone of the original.
1419
+ * @throws {Error} If the object contains a type that cannot be cloned.
1103
1420
  */
1104
1421
  function deepClone(obj) {
1105
1422
  if (obj === null || typeof obj !== 'object') {
@@ -1123,9 +1440,10 @@ function deepClone(obj) {
1123
1440
  throw new Error('Unable to clone object! Its type is not supported.');
1124
1441
  }
1125
1442
  /**
1126
- * Converts an object to a query string.
1127
- * @param {Object} obj The object to convert.
1128
- * @returns {string} The query string.
1443
+ * Converts a flat object into a URL query string.
1444
+ *
1445
+ * @param {Record<string, any>} obj - The object to convert.
1446
+ * @returns {string} The resulting URL query string.
1129
1447
  */
1130
1448
  function objectToQueryString(obj) {
1131
1449
  return Object.keys(obj)
@@ -1135,10 +1453,11 @@ function objectToQueryString(obj) {
1135
1453
  // Example usage:
1136
1454
  // objectToQueryString({ name: 'John Doe', age: 30 }); // 'name=John%20Doe&age=30'
1137
1455
  /**
1138
- * Gets the differences between two objects.
1139
- * @param {Object} object1 The first object.
1140
- * @param {Object} object2 The second object.
1141
- * @returns {Object} An object containing the differences.
1456
+ * Compares two objects and returns an object containing the keys where their values differ.
1457
+ *
1458
+ * @param {Record<string, any>} object1 - The first object.
1459
+ * @param {Record<string, any>} object2 - The second object.
1460
+ * @returns {Record<string, any>} An object where each key represents a difference, and the value contains the differing values from both objects.
1142
1461
  */
1143
1462
  function getObjectDifferences(object1, object2) {
1144
1463
  const differences = {};
@@ -1151,10 +1470,11 @@ function getObjectDifferences(object1, object2) {
1151
1470
  return differences;
1152
1471
  }
1153
1472
  /**
1154
- * Filters an object by a list of keys.
1155
- * @param {Object} obj The object to filter.
1156
- * @param {Array<string>} keys The keys to keep.
1157
- * @returns {Object} The filtered object.
1473
+ * Creates a new object containing only the specified keys from the original object.
1474
+ *
1475
+ * @param {Record<string, any>} obj - The source object.
1476
+ * @param {string[]} keys - An array of keys to include in the new object.
1477
+ * @returns {Record<string, any>} A new object with the filtered properties.
1158
1478
  */
1159
1479
  function filterObjectByKeys(obj, keys) {
1160
1480
  const filteredObject = {};
@@ -1168,10 +1488,12 @@ function filterObjectByKeys(obj, keys) {
1168
1488
  // Example usage:
1169
1489
  // filterObjectByKeys({ name: 'John', age: 30, job: 'Developer' }, ['name', 'job']); // { name: 'John', job: 'Developer' }
1170
1490
  /**
1171
- * Deeply merges two objects.
1172
- * @param {Object} target The target object to merge into.
1173
- * @param {Object} source The source object to merge from.
1174
- * @returns {Object} The merged object.
1491
+ * Recursively merges the properties of a source object into a target object.
1492
+ *
1493
+ * @template T - The type of the target object.
1494
+ * @param {T} target - The object to merge properties into.
1495
+ * @param {Partial<T>} source - The object from which to merge properties.
1496
+ * @returns {T} The modified target object.
1175
1497
  */
1176
1498
  function deepMerge(target, source) {
1177
1499
  if (target === null || typeof target !== 'object' || typeof source !== 'object') {
@@ -1193,18 +1515,20 @@ function deepMerge(target, source) {
1193
1515
  return target;
1194
1516
  }
1195
1517
  /**
1196
- * Checks if an object is empty.
1197
- * @param {Object} obj The object to check.
1198
- * @returns {boolean} True if the object is empty, otherwise false.
1518
+ * Checks if an object has no own enumerable properties.
1519
+ *
1520
+ * @param {Record<string, any>} obj - The object to check.
1521
+ * @returns {boolean} `true` if the object is empty, otherwise `false`.
1199
1522
  */
1200
1523
  function isEmptyObject(obj) {
1201
1524
  return Object.keys(obj).length === 0;
1202
1525
  }
1203
1526
  /**
1204
- * Safely accesses nested properties in an object.
1205
- * @param {Object} obj The object to access.
1206
- * @param {Array<string>} keys The array of keys representing the path.
1207
- * @returns {any} The value at the nested path, or undefined if not found.
1527
+ * Safely retrieves a nested property from an object using an array of keys as the path.
1528
+ *
1529
+ * @param {Record<string, any>} obj - The object to query.
1530
+ * @param {string[]} keys - An array of keys representing the path to the nested property.
1531
+ * @returns {*} The value of the nested property, or `undefined` if the path is not valid.
1208
1532
  */
1209
1533
  function safeGet(obj, keys) {
1210
1534
  return keys.reduce((acc, key) => (acc && acc[key] !== undefined) ? acc[key] : undefined, obj);
@@ -1213,9 +1537,10 @@ function safeGet(obj, keys) {
1213
1537
  // safeGet({ a: { b: { c: 10 } } }, ['a', 'b', 'c']); // 10
1214
1538
  // safeGet({ a: { b: { c: 10 } } }, ['a', 'x', 'c']); // undefined
1215
1539
  /**
1216
- * Removes empty properties (null, undefined, or empty string) from an object.
1217
- * @param {Object} obj The object to clean.
1218
- * @returns {Object} A new object without empty properties.
1540
+ * Creates a new object with all properties that have `null`, `undefined`, or empty string values removed.
1541
+ *
1542
+ * @param {Record<string, any>} obj - The source object.
1543
+ * @returns {Record<string, any>} A new object containing only the non-empty properties.
1219
1544
  */
1220
1545
  function removeEmptyProperties(obj) {
1221
1546
  return Object.keys(obj)
@@ -1228,9 +1553,10 @@ function removeEmptyProperties(obj) {
1228
1553
  // Example usage:
1229
1554
  // removeEmptyProperties({ a: null, b: 2, c: undefined, d: '', e: 'hello' }); // { b: 2, e: 'hello' }
1230
1555
  /**
1231
- * Retrieves all keys of an object as an array.
1232
- * @param {Object} obj The object to retrieve keys from.
1233
- * @returns {Array<string>} The array of keys.
1556
+ * Returns an array of an object's own enumerable property names.
1557
+ *
1558
+ * @param {Record<string, any>} obj - The object to get the keys from.
1559
+ * @returns {string[]} An array of string keys.
1234
1560
  */
1235
1561
  function getObjectKeys(obj) {
1236
1562
  return Object.keys(obj);
@@ -1238,9 +1564,10 @@ function getObjectKeys(obj) {
1238
1564
  // Example usage:
1239
1565
  // getObjectKeys({ name: 'John', age: 30 }); // ['name', 'age']
1240
1566
  /**
1241
- * Checks if an object has nested properties.
1242
- * @param {Object} obj The object to check.
1243
- * @returns {boolean} True if there are nested properties, false otherwise.
1567
+ * Checks if any of the object's properties are themselves objects (and not null).
1568
+ *
1569
+ * @param {Record<string, any>} obj - The object to inspect.
1570
+ * @returns {boolean} `true` if the object contains at least one nested object, otherwise `false`.
1244
1571
  */
1245
1572
  function hasNestedProperties(obj) {
1246
1573
  return Object.values(obj).some(value => typeof value === 'object' && value !== null);
@@ -1249,11 +1576,12 @@ function hasNestedProperties(obj) {
1249
1576
  // hasNestedProperties({ a: 1, b: { c: 2 } }); // true
1250
1577
  // hasNestedProperties({ a: 1, b: 2 }); // false
1251
1578
  /**
1252
- * Converts an object to FormData, handling nested objects.
1253
- * @param {Object} obj The object to convert.
1254
- * @param {FormData} [formData] The FormData object to append to.
1255
- * @param {string} [parentKey] The parent key for nested objects.
1256
- * @returns {FormData} The FormData object.
1579
+ * Recursively converts a nested object into a `FormData` object.
1580
+ *
1581
+ * @param {Record<string, any>} obj - The object to convert.
1582
+ * @param {FormData} [formData=new FormData()] - An existing `FormData` object to append to.
1583
+ * @param {string} [parentKey=''] - The base key for nested properties.
1584
+ * @returns {FormData} The resulting `FormData` object.
1257
1585
  */
1258
1586
  function objectToFormDataEnhanced(obj, formData = new FormData(), parentKey = '') {
1259
1587
  Object.entries(obj).forEach(([key, value]) => {
@@ -1270,12 +1598,12 @@ function objectToFormDataEnhanced(obj, formData = new FormData(), parentKey = ''
1270
1598
  // Example usage:
1271
1599
  // objectToFormDataEnhanced({ user: { name: 'John', age: 30 } });
1272
1600
  /**
1273
- * Converts a JavaScript object into FormData.
1601
+ * Recursively converts a JavaScript object into a `FormData` object, handling nested objects and boolean conversion.
1274
1602
  *
1275
- * @param obj - The object to be converted.
1276
- * @param form - An optional FormData instance to use.
1277
- * @param namespace - An optional namespace to use for nested objects.
1278
- * @returns The FormData instance with the object's key-value pairs.
1603
+ * @param {any} obj - The object to convert.
1604
+ * @param {FormData} [form] - An optional existing `FormData` object to append to.
1605
+ * @param {string} [namespace] - An optional namespace for keys of nested properties.
1606
+ * @returns {FormData} The resulting `FormData` object.
1279
1607
  */
1280
1608
  const objectToFormData = function (obj, form, namespace) {
1281
1609
  const fd = form || new FormData();
@@ -1305,11 +1633,12 @@ const objectToFormData = function (obj, form, namespace) {
1305
1633
  return fd;
1306
1634
  };
1307
1635
  /**
1308
- * Flattens a nested object, bringing all properties to the top level.
1309
- * @param {Object} obj The object to flatten.
1310
- * @param {string} [parentKey] The parent key for nested properties.
1311
- * @param {Object} [result] The resulting flattened object.
1312
- * @returns {Object} The flattened object.
1636
+ * Flattens a nested object into a single-level object with dot-separated keys.
1637
+ *
1638
+ * @param {Record<string, any>} obj - The object to flatten.
1639
+ * @param {string} [parentKey=''] - The prefix to use for the keys of the flattened properties.
1640
+ * @param {Record<string, any>} [result={}] - An object to merge the flattened properties into.
1641
+ * @returns {Record<string, any>} The flattened object.
1313
1642
  */
1314
1643
  function flattenObject(obj, parentKey = '', result = {}) {
1315
1644
  for (const key in obj) {
@@ -1329,13 +1658,14 @@ function flattenObject(obj, parentKey = '', result = {}) {
1329
1658
  // flattenObject({ a: 1, b: { c: 2, d: { e: 3 } } }); // { 'a': 1, 'b.c': 2, 'b.d.e': 3 }
1330
1659
 
1331
1660
  /**
1332
- * Extracts and validates the access and refresh tokens from a response object.
1333
- * Throws an error if the tokens are not found or are invalid.
1661
+ * Extracts access and refresh tokens from a response object using specified dot-notation paths
1662
+ * and validates their existence and type.
1334
1663
  *
1335
- * @param {any} data - The API response object.
1336
- * @param {AuthTokenPaths} tokenPaths - The paths for the tokens.
1337
- * @param {string} errorSource - A prefix for the error message ("LOGIN" or "REFRESH").
1338
- * @returns {TokenValidationResult} An object with the validated tokens.
1664
+ * @param {any} data - The response object from which to extract the tokens.
1665
+ * @param {AuthTokenPaths} tokenPaths - An object containing the dot-notation paths for the access and refresh tokens.
1666
+ * @param {string} errorSource - A string to identify the source of the operation (e.g., "LOGIN", "REFRESH") for error messages.
1667
+ * @returns {TokenValidationResult} An object containing the extracted `accessToken` and `refreshToken`.
1668
+ * @throws {Error} If the data object is missing, or if the access or refresh tokens cannot be found at the specified paths or are not strings.
1339
1669
  */
1340
1670
  const extractAndValidateTokens = (data, tokenPaths, errorSource) => {
1341
1671
  const accessTokenPath = tokenPaths?.accessTokenPath || "access_token";
@@ -1355,52 +1685,149 @@ const extractAndValidateTokens = (data, tokenPaths, errorSource) => {
1355
1685
  };
1356
1686
 
1357
1687
  /**
1358
- * Stores the access and refresh tokens in the appropriate storage based on the user's preference.
1359
- *
1360
- * @param {string} accessToken - El token de acceso.
1361
- * @param {string} refreshToken - El token de refresco.
1362
- * @param {LocationPreference} persistence - La preferencia de almacenamiento.
1363
- */
1688
+ * Encrypts and stores both the access and refresh tokens in the specified storage location.
1689
+ * Supports localStorage, sessionStorage, and cookies (with encryption and security options).
1690
+ *
1691
+ * @param {string} accessToken - The access token to be stored.
1692
+ * @param {string} refreshToken - The refresh token to be stored.
1693
+ * @param {LocationPreference} persistence - The desired storage location: 'local' for `localStorage`, 'session' for `sessionStorage`, or 'cookie' for cookies.
1694
+ * @returns {Promise<void>} A promise that resolves when both tokens have been successfully stored.
1695
+ */
1364
1696
  const storeTokens = async (accessToken, refreshToken, persistence) => {
1365
1697
  await storeAuthToken(accessToken, getAppKey(), persistence);
1366
1698
  await storeAuthRefreshToken(refreshToken, getAppKey(), persistence);
1367
1699
  };
1368
1700
 
1701
+ let defaultAuthFetcher = null;
1702
+ let createDefaultFetcher = null;
1703
+ /**
1704
+ * Configures a default fetcher for authentication operations.
1705
+ * If not configured, useAuth will use the default Axios fetcher.
1706
+ *
1707
+ * @param fetcher - The fetcher function to use for auth operations
1708
+ *
1709
+ * @example
1710
+ * ```typescript
1711
+ * import { configAuthFetcher, createOfetchFetcher } from '@arex95/vue-core';
1712
+ *
1713
+ * const ofetchFetcher = createOfetchFetcher();
1714
+ * configAuthFetcher(ofetchFetcher);
1715
+ * ```
1716
+ */
1717
+ function configAuthFetcher(fetcher) {
1718
+ defaultAuthFetcher = fetcher;
1719
+ }
1720
+ /**
1721
+ * Configures a factory function to create the default fetcher lazily.
1722
+ * This is used internally to avoid circular dependencies.
1723
+ *
1724
+ * @param factory - Factory function that creates a fetcher
1725
+ */
1726
+ function setDefaultAuthFetcherFactory(factory) {
1727
+ createDefaultFetcher = factory;
1728
+ }
1729
+ /**
1730
+ * Gets the default auth fetcher, creating one from Axios if not configured.
1731
+ * This allows lazy initialization to avoid circular dependencies.
1732
+ *
1733
+ * @returns The fetcher function to use
1734
+ */
1735
+ function getDefaultAuthFetcher() {
1736
+ if (defaultAuthFetcher) {
1737
+ return defaultAuthFetcher;
1738
+ }
1739
+ if (createDefaultFetcher) {
1740
+ defaultAuthFetcher = createDefaultFetcher();
1741
+ return defaultAuthFetcher;
1742
+ }
1743
+ throw new Error('Auth fetcher not configured. Please configure Axios or set a custom auth fetcher.');
1744
+ }
1745
+
1369
1746
  /**
1370
- * Refreshes the authentication tokens using the stored refresh token.
1371
- * This function can also accept optional token paths if the refresh endpoint
1372
- * returns tokens with a different structure than the default login.
1373
- * If no refresh token is found, it throws an error and initiates a logout.
1374
- *
1375
- * @param {AuthTokenPaths} [tokenPaths] - Optional configuration for the paths (in dot notation) of the access and refresh tokens in the refresh endpoint response.
1376
- * @returns {Promise<AuthResponse>} The new authentication response with refreshed tokens.
1377
- * @throws {Error} If the refresh token is missing or the refresh request fails.
1378
- */
1379
- const refreshTokens = async (axiosInstance) => {
1747
+ * Refreshes the access and refresh tokens by making a POST request to the refresh endpoint.
1748
+ * It retrieves the current refresh token from storage, sends it to the refresh endpoint,
1749
+ * and then stores the new tokens upon a successful response. If the refresh process fails
1750
+ * or no refresh token is found, it clears all credentials and reloads the page.
1751
+ *
1752
+ * @param {Fetcher} [fetcher] - Optional fetcher function to use for the refresh request. If not provided, uses the default configured fetcher.
1753
+ * @returns {Promise<AuthResponse>} A promise that resolves with the new authentication response containing the refreshed tokens.
1754
+ * @throws {Error} Throws an error if the refresh token is missing or if the refresh request fails, which is then caught to trigger a logout.
1755
+ */
1756
+ const refreshTokens = async (fetcher) => {
1380
1757
  const tokenPaths = getRefreshTokenPathsConfig();
1381
1758
  const endpoints = getEndpointsConfig();
1382
1759
  const secretKey = getAppKey();
1383
1760
  const persistence = await getSessionPersistence();
1761
+ const getFetcher = () => fetcher || getDefaultAuthFetcher();
1384
1762
  try {
1385
1763
  const refreshTokenFromStorage = await getAuthRefreshToken(secretKey, "any");
1386
1764
  if (!refreshTokenFromStorage) {
1387
1765
  throw new Error("TOKEN_MISSING: No refresh token found in storage.");
1388
1766
  }
1389
- const { data } = await axiosInstance.post(endpoints.REFRESH);
1767
+ const data = await getFetcher()({
1768
+ method: 'POST',
1769
+ url: endpoints.REFRESH,
1770
+ });
1390
1771
  const { accessToken, refreshToken } = extractAndValidateTokens(data, tokenPaths, "REFRESH");
1391
1772
  await storeTokens(accessToken, refreshToken, persistence);
1392
1773
  return data;
1393
1774
  }
1394
1775
  catch (error) {
1395
- handleError(error, false);
1776
+ handleError(error);
1396
1777
  await cleanCredentials(persistence);
1397
- if (window) {
1778
+ if (typeof window !== 'undefined') {
1398
1779
  window.location.reload();
1399
1780
  }
1400
1781
  throw error;
1401
1782
  }
1402
1783
  };
1403
1784
 
1785
+ /**
1786
+ * Creates a fetcher function using Axios.
1787
+ *
1788
+ * @param axiosInstance - The Axios instance to use
1789
+ * @returns A fetcher function compatible with RestStd
1790
+ *
1791
+ * @example
1792
+ * ```typescript
1793
+ * import axios from 'axios';
1794
+ * import { createAxiosFetcher, RestStd } from '@arex95/vue-core';
1795
+ *
1796
+ * const axiosInstance = axios.create({ baseURL: 'https://api.example.com' });
1797
+ *
1798
+ * export class Role extends RestStd {
1799
+ * static override resource = 'roles';
1800
+ * static fetchFn = createAxiosFetcher(axiosInstance);
1801
+ * }
1802
+ * ```
1803
+ */
1804
+ function createAxiosFetcher(axiosInstance) {
1805
+ return async (config) => {
1806
+ try {
1807
+ const response = await axiosInstance({
1808
+ method: config.method,
1809
+ url: config.url,
1810
+ params: config.params,
1811
+ data: config.data,
1812
+ headers: config.headers,
1813
+ });
1814
+ return response.data;
1815
+ }
1816
+ catch (error) {
1817
+ if (error instanceof AxiosError || error?.isAxiosError) {
1818
+ throw NetworkError.fromAxiosError(error);
1819
+ }
1820
+ throw error;
1821
+ }
1822
+ };
1823
+ }
1824
+
1825
+ /**
1826
+ * A service class that encapsulates a customizable Axios instance with built-in interceptors
1827
+ * for handling authentication, token refreshing, and request cancellation. It is designed to
1828
+ * streamline API communication by automatically attaching authorization headers and managing
1829
+ * token refresh logic for 401 Unauthorized responses.
1830
+ */
1404
1831
  class AxiosService {
1405
1832
  instance;
1406
1833
  cancelTokenSource;
@@ -1408,6 +1835,10 @@ class AxiosService {
1408
1835
  refreshTokenUrl;
1409
1836
  isRefreshing = false;
1410
1837
  failedQueue = [];
1838
+ /**
1839
+ * Creates an instance of AxiosService.
1840
+ * @param {AxiosServiceOptions} options - Configuration options for the Axios instance, such as `baseURL`, `timeout`, and custom `headers`.
1841
+ */
1411
1842
  constructor(options) {
1412
1843
  this.cancelTokenSource = axios.CancelToken.source();
1413
1844
  const endpointsConfig = getEndpointsConfig();
@@ -1450,7 +1881,7 @@ class AxiosService {
1450
1881
  this.activeRequests++;
1451
1882
  return config;
1452
1883
  }, (error) => {
1453
- handleError(error, false);
1884
+ handleError(error);
1454
1885
  return Promise.reject(error);
1455
1886
  });
1456
1887
  this.instance.interceptors.response.use((response) => {
@@ -1463,11 +1894,11 @@ class AxiosService {
1463
1894
  const isRefreshCall = originalRequest?.url === this.refreshTokenUrl;
1464
1895
  const isRetry = originalRequest?._retry === true;
1465
1896
  if (!isAuthError || isRefreshCall || isRetry) {
1466
- handleError(error, false);
1897
+ handleError(error);
1467
1898
  return Promise.reject(error);
1468
1899
  }
1469
1900
  if (!originalRequest) {
1470
- handleError(error, false);
1901
+ handleError(error);
1471
1902
  return Promise.reject(error);
1472
1903
  }
1473
1904
  if (this.isRefreshing) {
@@ -1485,7 +1916,8 @@ class AxiosService {
1485
1916
  this.isRefreshing = true;
1486
1917
  originalRequest._retry = true;
1487
1918
  try {
1488
- await refreshTokens(this.instance);
1919
+ const fetcher = createAxiosFetcher(this.instance);
1920
+ await refreshTokens(fetcher);
1489
1921
  const newToken = await getAuthToken(getAppKey(), "any");
1490
1922
  if (newToken) {
1491
1923
  this.processQueue(null, newToken);
@@ -1502,49 +1934,111 @@ class AxiosService {
1502
1934
  catch (refreshError) {
1503
1935
  this.processQueue(refreshError, null);
1504
1936
  this.isRefreshing = false;
1505
- handleError(refreshError, false);
1937
+ handleError(refreshError);
1506
1938
  return Promise.reject(error);
1507
1939
  }
1508
1940
  });
1509
1941
  }
1942
+ /**
1943
+ * Returns the number of active (in-flight) requests.
1944
+ * @returns {number} The number of active requests.
1945
+ */
1510
1946
  getActiveRequests() {
1511
1947
  return this.activeRequests;
1512
1948
  }
1949
+ /**
1950
+ * Returns the underlying Axios instance.
1951
+ * @returns {AxiosInstance} The Axios instance.
1952
+ */
1513
1953
  getAxiosInstance() {
1514
1954
  return this.instance;
1515
1955
  }
1956
+ /**
1957
+ * Cancels all ongoing requests made by this Axios instance.
1958
+ */
1516
1959
  cancelAllRequests() {
1517
1960
  this.cancelTokenSource.cancel("Operation canceled by the user.");
1518
1961
  this.cancelTokenSource = axios.CancelToken.source();
1519
1962
  }
1963
+ /**
1964
+ * Sets a default header for all subsequent requests.
1965
+ * @param {string} key - The header key.
1966
+ * @param {string} value - The header value.
1967
+ */
1520
1968
  setHeader(key, value) {
1521
1969
  this.instance.defaults.headers.common[key] = value;
1522
1970
  }
1971
+ /**
1972
+ * Removes a default header.
1973
+ * @param {string} key - The header key to remove.
1974
+ */
1523
1975
  removeHeader(key) {
1524
1976
  delete this.instance.defaults.headers.common[key];
1525
1977
  }
1526
1978
  }
1527
1979
 
1528
- let axiosServiceInstance;
1980
+ let axiosServiceInstance = null;
1981
+ let defaultConfig = null;
1982
+ /**
1983
+ * Configures the singleton Axios service instance for the application.
1984
+ * This function should be called once at the application's entry point to set up
1985
+ * the base URL, headers, and other default configurations for all API requests.
1986
+ *
1987
+ * @param {AxiosServiceOptions} config - The configuration options for the Axios service.
1988
+ */
1529
1989
  const configAxios = (config) => {
1990
+ defaultConfig = config;
1530
1991
  axiosServiceInstance = new AxiosService({
1531
1992
  baseURL: config.baseURL,
1532
1993
  headers: config.headers,
1533
1994
  timeout: config.timeout,
1534
1995
  withCredentials: config.withCredentials
1535
1996
  });
1997
+ // Configure auth fetcher factory lazily to avoid circular dependency
1998
+ // The factory function is only called when getDefaultAuthFetcher() is invoked
1999
+ setDefaultAuthFetcherFactory(() => {
2000
+ return createAxiosFetcher(axiosServiceInstance.getAxiosInstance());
2001
+ });
1536
2002
  };
2003
+ /**
2004
+ * Retrieves the configured singleton Axios instance.
2005
+ * If not configured yet, creates a default instance with minimal configuration.
2006
+ * This allows lazy initialization to avoid dependency circular issues in Nuxt and other frameworks.
2007
+ *
2008
+ * @returns {AxiosInstance} The configured Axios instance.
2009
+ */
1537
2010
  const getConfiguredAxiosInstance = () => {
1538
2011
  if (!axiosServiceInstance) {
1539
- throw new Error("Axios instance not configured. Call configAxios first.");
2012
+ if (defaultConfig) {
2013
+ axiosServiceInstance = new AxiosService({
2014
+ baseURL: defaultConfig.baseURL,
2015
+ headers: defaultConfig.headers,
2016
+ timeout: defaultConfig.timeout,
2017
+ withCredentials: defaultConfig.withCredentials
2018
+ });
2019
+ }
2020
+ else {
2021
+ axiosServiceInstance = new AxiosService({
2022
+ baseURL: '',
2023
+ headers: {},
2024
+ timeout: 30000,
2025
+ withCredentials: false
2026
+ });
2027
+ }
2028
+ // Configure auth fetcher factory lazily to avoid circular dependency
2029
+ // The factory function is only called when getDefaultAuthFetcher() is invoked
2030
+ setDefaultAuthFetcherFactory(() => {
2031
+ return createAxiosFetcher(axiosServiceInstance.getAxiosInstance());
2032
+ });
1540
2033
  }
1541
2034
  return axiosServiceInstance.getAxiosInstance();
1542
2035
  };
1543
2036
 
1544
2037
  /**
1545
- * Creates and downloads a file from Blob data.
1546
- * @param {Blob} blob The Blob containing the file data.
1547
- * @param {string} fileName The name of the file to create.
2038
+ * Triggers a browser download for a file created from a `Blob` object.
2039
+ *
2040
+ * @param {Blob} blob - The `Blob` containing the file's data.
2041
+ * @param {string} fileName - The desired name for the downloaded file.
1548
2042
  */
1549
2043
  function downloadFile(blob, fileName) {
1550
2044
  const link = document.createElement('a');
@@ -1559,10 +2053,11 @@ function downloadFile(blob, fileName) {
1559
2053
  URL.revokeObjectURL(url);
1560
2054
  }
1561
2055
  /**
1562
- * Exports data to a CSV file.
1563
- * @param {string[]} headers The headers for the CSV.
1564
- * @param {any[][]} data The data to export, as an array of arrays.
1565
- * @param {string} fileName The name of the file to create.
2056
+ * Converts an array of data into a CSV format and triggers a download.
2057
+ *
2058
+ * @param {string[]} headers - An array of strings to be used as the CSV header row.
2059
+ * @param {any[][]} data - A 2D array representing the rows and cells of the data to be exported.
2060
+ * @param {string} fileName - The desired name for the downloaded CSV file.
1566
2061
  */
1567
2062
  function exportToCSV(headers, data, fileName) {
1568
2063
  const csvRows = [];
@@ -1579,10 +2074,11 @@ function exportToCSV(headers, data, fileName) {
1579
2074
  downloadFile(blob, fileName);
1580
2075
  }
1581
2076
  /**
1582
- * Exports data to an Excel file (.xls) using HTML table.
1583
- * @param {string[]} headers The headers for the Excel file.
1584
- * @param {any[][]} data The data to export, as an array of arrays.
1585
- * @param {string} fileName The name of the file to create.
2077
+ * Converts an array of data into an HTML table, then triggers a download as an Excel (.xls) file.
2078
+ *
2079
+ * @param {string[]} headers - An array of strings for the table headers.
2080
+ * @param {any[][]} data - A 2D array of the data to be exported.
2081
+ * @param {string} fileName - The desired name for the downloaded Excel file.
1586
2082
  */
1587
2083
  function exportToExcel(headers, data, fileName) {
1588
2084
  // Create a table element
@@ -1611,9 +2107,10 @@ function exportToExcel(headers, data, fileName) {
1611
2107
  downloadFile(blob, fileName);
1612
2108
  }
1613
2109
  /**
1614
- * Exports data to a JSON file.
1615
- * @param {any[]} data The data to export.
1616
- * @param {string} fileName The name of the file to create.
2110
+ * Converts an array of data into a pretty-printed JSON string and triggers a download.
2111
+ *
2112
+ * @param {any[]} data - The data to be serialized into JSON.
2113
+ * @param {string} fileName - The desired name for the downloaded JSON file.
1617
2114
  */
1618
2115
  function exportToJSON(data, fileName) {
1619
2116
  const jsonContent = JSON.stringify(data, null, 2); // Pretty print with 2 spaces
@@ -1622,10 +2119,11 @@ function exportToJSON(data, fileName) {
1622
2119
  downloadFile(blob, fileName);
1623
2120
  }
1624
2121
  /**
1625
- * Exports data to an XML file.
1626
- * @param {string[]} headers The headers for the XML.
1627
- * @param {any[][]} data The data to export, as an array of arrays.
1628
- * @param {string} fileName The name of the file to create.
2122
+ * Converts an array of data into a simple XML format and triggers a download.
2123
+ *
2124
+ * @param {string[]} headers - An array of strings to be used as column headers in the XML.
2125
+ * @param {any[][]} data - A 2D array of the data to be exported.
2126
+ * @param {string} fileName - The desired name for the downloaded XML file.
1629
2127
  */
1630
2128
  function exportToXML(headers, data, fileName) {
1631
2129
  let xmlContent = '<?xml version="1.0" encoding="UTF-8"?>\n<rows>\n';
@@ -1649,10 +2147,11 @@ function exportToXML(headers, data, fileName) {
1649
2147
  downloadFile(blob, fileName);
1650
2148
  }
1651
2149
  /**
1652
- * Exports data to a plain text file.
1653
- * @param {string[]} headers The headers for the text file.
1654
- * @param {any[][]} data The data to export, as an array of arrays.
1655
- * @param {string} fileName The name of the file to create.
2150
+ * Converts an array of data into a tab-separated text format and triggers a download.
2151
+ *
2152
+ * @param {string[]} headers - An array of strings for the header row.
2153
+ * @param {any[][]} data - A 2D array of the data to be exported.
2154
+ * @param {string} fileName - The desired name for the downloaded text file.
1656
2155
  */
1657
2156
  function exportToText(headers, data, fileName) {
1658
2157
  const textRows = [];
@@ -1670,12 +2169,13 @@ function exportToText(headers, data, fileName) {
1670
2169
  }
1671
2170
 
1672
2171
  /**
1673
- * Opens a new window with the specified URL and options.
1674
- * @param {string} url The URL to open.
1675
- * @param {Object} [opt] Options for the new window.
1676
- * @param {string} [opt.target='__blank'] The target window name.
1677
- * @param {boolean} [opt.noopener=true] Whether to add 'noopener' attribute.
1678
- * @param {boolean} [opt.noreferrer=true] Whether to add 'noreferrer' attribute.
2172
+ * Opens a new browser window or tab with a specified URL, providing options for the target and security attributes.
2173
+ *
2174
+ * @param {string} url - The URL to open in the new window.
2175
+ * @param {object} [opt] - Optional configuration for the new window.
2176
+ * @param {string} [opt.target='_blank'] - The target attribute for the link, specifying where to open the content (e.g., '_blank', '_self').
2177
+ * @param {boolean} [opt.noopener=true] - If `true`, adds `noopener` to the window features to prevent the new window from accessing the original window's object.
2178
+ * @param {boolean} [opt.noreferrer=true] - If `true`, adds `noreferrer` to prevent the browser from sending the `Referer` HTTP header.
1679
2179
  */
1680
2180
  function openWindow(url, opt) {
1681
2181
  const { target = '__blank', noopener = true, noreferrer = true } = opt || {};
@@ -1689,9 +2189,11 @@ function openWindow(url, opt) {
1689
2189
  window.open(url, target, features.join(','));
1690
2190
  }
1691
2191
  /**
1692
- * Copies text to the clipboard.
1693
- * @param {string} text The text to copy.
1694
- * @returns {Promise<void>} A promise that resolves when the text has been copied.
2192
+ * Asynchronously copies a given string to the user's clipboard. It uses the modern `navigator.clipboard` API
2193
+ * with a fallback to the deprecated `document.execCommand` for older browsers.
2194
+ *
2195
+ * @param {string} text - The string to be copied to the clipboard.
2196
+ * @returns {Promise<void>} A promise that resolves when the text has been successfully copied.
1695
2197
  */
1696
2198
  async function copyToClipboard(text) {
1697
2199
  if (navigator.clipboard) {
@@ -1708,8 +2210,10 @@ async function copyToClipboard(text) {
1708
2210
  }
1709
2211
  }
1710
2212
  /**
1711
- * Scrolls the window to the top smoothly.
1712
- * @param {number} [duration=300] Duration of the scroll animation in milliseconds.
2213
+ * Smoothly scrolls the window to the top of the page using a `requestAnimationFrame` loop
2214
+ * for a fluid animation.
2215
+ *
2216
+ * @param {number} [duration=300] - The total duration of the scroll animation in milliseconds.
1713
2217
  */
1714
2218
  function scrollToTop(duration = 300) {
1715
2219
  const start = window.scrollY;
@@ -1725,9 +2229,10 @@ function scrollToTop(duration = 300) {
1725
2229
  requestAnimationFrame(scroll);
1726
2230
  }
1727
2231
  /**
1728
- * Gets the value of a query parameter from the URL.
1729
- * @param {string} paramName The name of the query parameter.
1730
- * @returns {string | null} The value of the query parameter, or null if it does not exist.
2232
+ * Retrieves the value of a specified query parameter from the current URL's search string.
2233
+ *
2234
+ * @param {string} paramName - The name of the query parameter to retrieve.
2235
+ * @returns {string | null} The value of the query parameter, or `null` if the parameter is not present in the URL.
1731
2236
  */
1732
2237
  function getQueryParam(paramName) {
1733
2238
  const urlParams = new URLSearchParams(window.location.search);
@@ -1735,7 +2240,7 @@ function getQueryParam(paramName) {
1735
2240
  }
1736
2241
 
1737
2242
  /**
1738
- * Disables the right-click context menu on the window.
2243
+ * Disables the default right-click context menu on the entire window.
1739
2244
  */
1740
2245
  function disableRightClick() {
1741
2246
  const handler = (event) => event.preventDefault();
@@ -1745,7 +2250,7 @@ function disableRightClick() {
1745
2250
  }
1746
2251
  disableRightClick.handler = null;
1747
2252
  /**
1748
- * Enables the right-click context menu on the window.
2253
+ * Re-enables the right-click context menu if it was previously disabled by `disableRightClick`.
1749
2254
  */
1750
2255
  function enableRightClick() {
1751
2256
  if (disableRightClick.handler) {
@@ -1753,8 +2258,9 @@ function enableRightClick() {
1753
2258
  }
1754
2259
  }
1755
2260
  /**
1756
- * Disables specific mouse buttons.
1757
- * @param {Array<number>} buttons Array of mouse button codes to disable (0 for left, 1 for middle, 2 for right).
2261
+ * Prevents the default action for specific mouse buttons on the `mousedown` event.
2262
+ *
2263
+ * @param {number[]} buttons - An array of mouse button codes to disable (0 for left, 1 for middle, 2 for right).
1758
2264
  */
1759
2265
  function disableMouseButtons(buttons) {
1760
2266
  const handler = (event) => {
@@ -1769,7 +2275,7 @@ function disableMouseButtons(buttons) {
1769
2275
  }
1770
2276
  disableMouseButtons.handlers = [];
1771
2277
  /**
1772
- * Enables all previously disabled mouse buttons.
2278
+ * Re-enables all mouse buttons that were previously disabled by `disableMouseButtons`.
1773
2279
  */
1774
2280
  function enableMouseButtons() {
1775
2281
  for (const handler of disableMouseButtons.handlers) {
@@ -1779,17 +2285,19 @@ function enableMouseButtons() {
1779
2285
  disableMouseButtons.handlers = [];
1780
2286
  }
1781
2287
  /**
1782
- * Adds a double-click event listener to a specific element.
1783
- * @param {HTMLElement} element The target element.
1784
- * @param {(event: MouseEvent) => void} callback The callback function to execute on double click.
2288
+ * Attaches a `dblclick` event listener to a specified HTML element.
2289
+ *
2290
+ * @param {HTMLElement} element - The DOM element to attach the listener to.
2291
+ * @param {(event: MouseEvent) => void} callback - The function to execute when the element is double-clicked.
1785
2292
  */
1786
2293
  function addDoubleClickListener(element, callback) {
1787
2294
  element.addEventListener('dblclick', callback);
1788
2295
  }
1789
2296
  /**
1790
- * Removes a double-click event listener from a specific element.
1791
- * @param {HTMLElement} element The target element.
1792
- * @param {(event: MouseEvent) => void} callback The callback function to remove.
2297
+ * Removes a `dblclick` event listener from a specified HTML element.
2298
+ *
2299
+ * @param {HTMLElement} element - The DOM element to remove the listener from.
2300
+ * @param {(event: MouseEvent) => void} callback - The callback function that was originally added.
1793
2301
  */
1794
2302
  function removeDoubleClickListener(element, callback) {
1795
2303
  element.removeEventListener('dblclick', callback);
@@ -1797,9 +2305,10 @@ function removeDoubleClickListener(element, callback) {
1797
2305
  // Example usage:
1798
2306
  // addDoubleClickListener(document.body, () => alert('Double clicked!'));
1799
2307
  /**
1800
- * Detects a click outside a specific element and triggers a callback.
1801
- * @param {HTMLElement} element The element to detect clicks outside of.
1802
- * @param {() => void} callback The callback function to execute when a click outside is detected.
2308
+ * Sets up a global click listener to detect when a user clicks outside of a specified element.
2309
+ *
2310
+ * @param {HTMLElement} element - The element to monitor for outside clicks.
2311
+ * @param {() => void} callback - The function to execute when a click outside the element is detected.
1803
2312
  */
1804
2313
  function clickOutside(element, callback) {
1805
2314
  const handler = (event) => {
@@ -1813,8 +2322,9 @@ function clickOutside(element, callback) {
1813
2322
  }
1814
2323
  clickOutside.handlers = [];
1815
2324
  /**
1816
- * Removes the click outside listener for a specific element.
1817
- * @param {HTMLElement} element The element to stop detecting clicks outside of.
2325
+ * Removes the "click outside" event listener for a specific element that was added by `clickOutside`.
2326
+ *
2327
+ * @param {HTMLElement} element - The element for which to remove the listener.
1818
2328
  */
1819
2329
  function removeClickOutside(element) {
1820
2330
  const index = clickOutside.handlers.findIndex(h => h.element === element);
@@ -1829,7 +2339,8 @@ function removeClickOutside(element) {
1829
2339
  // clickOutside(menu, () => menu.style.display = 'none');
1830
2340
  // }
1831
2341
  /**
1832
- * Disables the F12 key and certain key combinations for developer tools.
2342
+ * Disables the F12 key and common developer tool shortcuts (Ctrl+Shift+I, Ctrl+Shift+J)
2343
+ * to prevent users from easily opening the browser's developer console.
1833
2344
  */
1834
2345
  function disableF12Key() {
1835
2346
  const handler = function (event) {
@@ -1838,8 +2349,9 @@ function disableF12Key() {
1838
2349
  document.addEventListener('keydown', handler);
1839
2350
  }
1840
2351
  /**
1841
- * Enables or disables the tab navigation (Tab key) on the page.
1842
- * @param {boolean} enable Whether to enable or disable tab navigation.
2352
+ * Enables or disables the ability to navigate through focusable elements using the Tab key.
2353
+ *
2354
+ * @param {boolean} enable - If `true`, tab navigation is enabled; if `false`, it is disabled.
1843
2355
  */
1844
2356
  function toggleTabNavigation(enable) {
1845
2357
  if (enable) {
@@ -1856,7 +2368,7 @@ function toggleTabNavigation(enable) {
1856
2368
  }
1857
2369
  }
1858
2370
  /**
1859
- * Disables the copy (Ctrl + C) functionality on the page.
2371
+ * Prevents users from copying content from the page by intercepting the `copy` event.
1860
2372
  */
1861
2373
  function disableCopy() {
1862
2374
  document.addEventListener('copy', (event) => {
@@ -1865,11 +2377,12 @@ function disableCopy() {
1865
2377
  });
1866
2378
  }
1867
2379
  /**
1868
- * Adds a custom keyboard shortcut to execute a given callback function.
1869
- * @param {string} key The key to trigger the callback.
1870
- * @param {Function} callback The function to execute on the key press.
1871
- * @param {boolean} [ctrlKey=false] Whether Ctrl key should be pressed.
1872
- * @param {boolean} [shiftKey=false] Whether Shift key should be pressed.
2380
+ * Registers a global keyboard shortcut that triggers a callback when a specific key combination is pressed.
2381
+ *
2382
+ * @param {string} key - The main key for the shortcut (e.g., 'S', 'F1').
2383
+ * @param {() => void} callback - The function to execute when the shortcut is pressed.
2384
+ * @param {boolean} [ctrlKey=false] - If `true`, the Ctrl key must be pressed.
2385
+ * @param {boolean} [shiftKey=false] - If `true`, the Shift key must be pressed.
1873
2386
  */
1874
2387
  function addCustomKeyboardShortcut(key, callback, ctrlKey = false, shiftKey = false) {
1875
2388
  document.addEventListener('keydown', (event) => {
@@ -1882,10 +2395,11 @@ function addCustomKeyboardShortcut(key, callback, ctrlKey = false, shiftKey = fa
1882
2395
  });
1883
2396
  }
1884
2397
  /**
1885
- * Removes a custom keyboard shortcut by key and modifiers.
1886
- * @param {string} key The key to trigger the callback.
1887
- * @param {boolean} [ctrlKey=false] Whether Ctrl key should be pressed.
1888
- * @param {boolean} [shiftKey=false] Whether Shift key should be pressed.
2398
+ * Removes a global keyboard shortcut that was previously added.
2399
+ *
2400
+ * @param {string} key - The main key of the shortcut to remove.
2401
+ * @param {boolean} [ctrlKey=false] - The Ctrl key modifier of the shortcut.
2402
+ * @param {boolean} [shiftKey=false] - The Shift key modifier of the shortcut.
1889
2403
  */
1890
2404
  function removeCustomKeyboardShortcut(key, ctrlKey = false, shiftKey = false) {
1891
2405
  const handler = (event) => {
@@ -1898,8 +2412,9 @@ function removeCustomKeyboardShortcut(key, ctrlKey = false, shiftKey = false) {
1898
2412
  document.removeEventListener('keydown', handler);
1899
2413
  }
1900
2414
  /**
1901
- * Disables specific keys or key combinations.
1902
- * @param {Array<string>} keys Array of key names to disable (e.g., ['F1', 'F5', 'Control+S']).
2415
+ * Disables a list of specified keys or key combinations.
2416
+ *
2417
+ * @param {string[]} keys - An array of key names or combinations (e.g., 'F1', 'Control+S') to disable.
1903
2418
  */
1904
2419
  function disableSpecificKeys(keys) {
1905
2420
  const handler = (event) => {
@@ -1914,7 +2429,7 @@ function disableSpecificKeys(keys) {
1914
2429
  }
1915
2430
  disableSpecificKeys.handlers = [];
1916
2431
  /**
1917
- * Enables keys that were previously disabled using disableSpecificKeys.
2432
+ * Re-enables all keys that were previously disabled by `disableSpecificKeys`.
1918
2433
  */
1919
2434
  function enableSpecificKeys() {
1920
2435
  for (const handler of disableSpecificKeys.handlers) {
@@ -1923,8 +2438,9 @@ function enableSpecificKeys() {
1923
2438
  disableSpecificKeys.handlers = [];
1924
2439
  }
1925
2440
  /**
1926
- * Registers multiple keyboard shortcuts with their respective callback functions.
1927
- * @param {Array<{ key: string, ctrlKey?: boolean, shiftKey?: boolean, altKey?: boolean, callback: Function }>} shortcuts Array of shortcut objects.
2441
+ * Registers multiple keyboard shortcuts from an array of shortcut configurations.
2442
+ *
2443
+ * @param {Array<{ key: string; ctrlKey?: boolean; shiftKey?: boolean; altKey?: boolean; callback: () => void }>} shortcuts - An array of shortcut objects.
1928
2444
  */
1929
2445
  function registerKeyboardShortcuts(shortcuts) {
1930
2446
  const handler = (event) => {
@@ -1944,7 +2460,7 @@ function registerKeyboardShortcuts(shortcuts) {
1944
2460
  }
1945
2461
  registerKeyboardShortcuts.handlers = [];
1946
2462
  /**
1947
- * Unregisters all keyboard shortcuts that were registered with registerKeyboardShortcuts.
2463
+ * Removes all keyboard shortcuts that were registered using `registerKeyboardShortcuts`.
1948
2464
  */
1949
2465
  function unregisterKeyboardShortcuts() {
1950
2466
  for (const handler of registerKeyboardShortcuts.handlers) {
@@ -1953,9 +2469,10 @@ function unregisterKeyboardShortcuts() {
1953
2469
  registerKeyboardShortcuts.handlers = [];
1954
2470
  }
1955
2471
  /**
1956
- * Adds a listener for a specific key to trigger a custom event.
1957
- * @param {string} key The key to listen for (e.g., 'Enter', 'Escape').
1958
- * @param {Function} callback The function to execute when the key is pressed.
2472
+ * Adds a global `keydown` listener for a specific key.
2473
+ *
2474
+ * @param {string} key - The key to listen for (e.g., 'Enter', 'Escape').
2475
+ * @param {() => void} callback - The function to execute when the key is pressed.
1959
2476
  */
1960
2477
  function addKeyListener(key, callback) {
1961
2478
  const handler = (event) => {
@@ -1970,7 +2487,7 @@ function addKeyListener(key, callback) {
1970
2487
  }
1971
2488
  addKeyListener.handlers = [];
1972
2489
  /**
1973
- * Removes all custom key listeners added by addKeyListener.
2490
+ * Removes all key listeners that were added using `addKeyListener`.
1974
2491
  */
1975
2492
  function removeKeyListeners() {
1976
2493
  for (const handler of addKeyListener.handlers) {
@@ -1979,9 +2496,10 @@ function removeKeyListeners() {
1979
2496
  addKeyListener.handlers = [];
1980
2497
  }
1981
2498
  /**
1982
- * Detects if a specific key is held down.
1983
- * @param {string} key The key to detect (e.g., 'Shift', 'Control', 'Alt', 'a').
1984
- * @param {Function} onHold Callback function to execute while the key is held down.
2499
+ * Executes a callback function repeatedly while a specific key is held down.
2500
+ *
2501
+ * @param {string} key - The key to monitor.
2502
+ * @param {() => void} onHold - The callback function to execute on each `keydown` event for the specified key.
1985
2503
  */
1986
2504
  function detectKeyHold(key, onHold) {
1987
2505
  const keyDownHandler = (event) => {
@@ -1995,7 +2513,7 @@ function detectKeyHold(key, onHold) {
1995
2513
  }
1996
2514
  detectKeyHold.handlers = [];
1997
2515
  /**
1998
- * Stops detecting if a specific key is held down.
2516
+ * Removes all key hold listeners that were added by `detectKeyHold`.
1999
2517
  */
2000
2518
  function stopDetectingKeyHold() {
2001
2519
  for (const handler of detectKeyHold.handlers) {
@@ -2004,8 +2522,9 @@ function stopDetectingKeyHold() {
2004
2522
  detectKeyHold.handlers = [];
2005
2523
  }
2006
2524
  /**
2007
- * Tracks currently pressed keys and provides a map of active keys.
2008
- * @returns {Set<string>} A set of currently pressed keys.
2525
+ * Creates and maintains a `Set` of currently pressed keys.
2526
+ *
2527
+ * @returns {Set<string>} A `Set` that dynamically updates with the keys being pressed.
2009
2528
  */
2010
2529
  function createKeyMap() {
2011
2530
  const pressedKeys = new Set();
@@ -2025,13 +2544,14 @@ function createKeyMap() {
2025
2544
  return pressedKeys;
2026
2545
  }
2027
2546
  /**
2028
- * Clears listeners for the key map tracking.
2547
+ * Clears the `keydown` and `keyup` event listeners created by `createKeyMap`.
2029
2548
  */
2030
2549
  createKeyMap.clearListeners = () => { };
2031
2550
  /**
2032
- * Sets up custom keyboard shortcuts with flexible order.
2033
- * @param {Array<string>} keys The combination of keys for the shortcut.
2034
- * @param {Function} callback The callback function to execute when the combination is detected.
2551
+ * Sets up a keyboard shortcut that triggers a callback when a specific combination of keys is held down, regardless of order.
2552
+ *
2553
+ * @param {string[]} keys - An array of keys that constitute the shortcut.
2554
+ * @param {() => void} callback - The function to execute when the key combination is active.
2035
2555
  */
2036
2556
  function customShortcut(keys, callback) {
2037
2557
  const pressedKeys = new Set();
@@ -2051,7 +2571,7 @@ function customShortcut(keys, callback) {
2051
2571
  }
2052
2572
  customShortcut.handlers = [];
2053
2573
  /**
2054
- * Removes all custom keyboard shortcuts added by customShortcut.
2574
+ * Removes all keyboard shortcut listeners that were added by `customShortcut`.
2055
2575
  */
2056
2576
  function removeCustomShortcuts() {
2057
2577
  for (const { keyDownHandler, keyUpHandler } of customShortcut.handlers) {
@@ -2061,11 +2581,12 @@ function removeCustomShortcuts() {
2061
2581
  customShortcut.handlers = [];
2062
2582
  }
2063
2583
  /**
2064
- * Simulates a key press event.
2065
- * @param {string} key The key to simulate (e.g., 'Enter', 'a').
2066
- * @param {boolean} ctrlKey If true, include Ctrl key in the event.
2067
- * @param {boolean} shiftKey If true, include Shift key in the event.
2068
- * @param {boolean} altKey If true, include Alt key in the event.
2584
+ * Programmatically dispatches a `keydown` event to simulate a key press.
2585
+ *
2586
+ * @param {string} key - The key to simulate (e.g., 'Enter', 'a').
2587
+ * @param {boolean} [ctrlKey=false] - Whether to simulate the Ctrl key being pressed.
2588
+ * @param {boolean} [shiftKey=false] - Whether to simulate the Shift key being pressed.
2589
+ * @param {boolean} [altKey=false] - Whether to simulate the Alt key being pressed.
2069
2590
  */
2070
2591
  function simulateKeyPress(key, ctrlKey = false, shiftKey = false, altKey = false) {
2071
2592
  const event = new KeyboardEvent('keydown', {
@@ -2080,9 +2601,11 @@ function simulateKeyPress(key, ctrlKey = false, shiftKey = false, altKey = false
2080
2601
  }
2081
2602
 
2082
2603
  /**
2083
- * Parses a date string into a Date object.
2084
- * @param {string} dateString The date string in 'YYYY-MM-DD' format.
2085
- * @returns {Date | null} The parsed Date object or null if the format is invalid.
2604
+ * Parses a date string in the format 'YYYY-MM-DD' and returns a `Date` object.
2605
+ * It includes validation to ensure the parsed date is a valid calendar date.
2606
+ *
2607
+ * @param {string} dateString - The date string to parse.
2608
+ * @returns {Date | null} A `Date` object if the string is a valid date, otherwise `null`.
2086
2609
  */
2087
2610
  function parseDate(dateString) {
2088
2611
  const parts = dateString.split('-');
@@ -2098,9 +2621,11 @@ function parseDate(dateString) {
2098
2621
  return null;
2099
2622
  }
2100
2623
  /**
2101
- * Formats a Date object into a string.
2102
- * @param {Date} date The date to format.
2103
- * @param {string} format The format string (e.g., 'YYYY-MM-DD').
2624
+ * Formats a `Date` object into a custom string format.
2625
+ * Supported format specifiers: YYYY, MM, DD, HH, mm, ss.
2626
+ *
2627
+ * @param {Date} date - The `Date` object to format.
2628
+ * @param {string} format - The desired string format (e.g., 'YYYY-MM-DD HH:mm:ss').
2104
2629
  * @returns {string} The formatted date string.
2105
2630
  */
2106
2631
  function formatDate(date, format) {
@@ -2115,9 +2640,10 @@ function formatDate(date, format) {
2115
2640
  return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => (map[matched] || matched).toString());
2116
2641
  }
2117
2642
  /**
2118
- * Calculates the number of days between two dates.
2119
- * @param {Date} startDate The start date.
2120
- * @param {Date} endDate The end date.
2643
+ * Calculates the total number of full days between two dates.
2644
+ *
2645
+ * @param {Date} startDate - The starting date.
2646
+ * @param {Date} endDate - The ending date.
2121
2647
  * @returns {number} The number of days between the two dates.
2122
2648
  */
2123
2649
  function daysBetween(startDate, endDate) {
@@ -2125,10 +2651,11 @@ function daysBetween(startDate, endDate) {
2125
2651
  return Math.round((endDate.getTime() - startDate.getTime()) / millisecondsPerDay);
2126
2652
  }
2127
2653
  /**
2128
- * Adds a specified number of days to a date.
2129
- * @param {Date} date The date to modify.
2130
- * @param {number} days The number of days to add.
2131
- * @returns {Date} The new date with days added.
2654
+ * Adds a specified number of days to a given date.
2655
+ *
2656
+ * @param {Date} date - The original date.
2657
+ * @param {number} days - The number of days to add (can be negative to subtract).
2658
+ * @returns {Date} A new `Date` object representing the resulting date.
2132
2659
  */
2133
2660
  function addDays(date, days) {
2134
2661
  const result = new Date(date);
@@ -2136,41 +2663,46 @@ function addDays(date, days) {
2136
2663
  return result;
2137
2664
  }
2138
2665
  /**
2139
- * Subtracts a specified number of days from a date.
2140
- * @param {Date} date The date to modify.
2141
- * @param {number} days The number of days to subtract.
2142
- * @returns {Date} The new date with days subtracted.
2666
+ * Subtracts a specified number of days from a given date.
2667
+ *
2668
+ * @param {Date} date - The original date.
2669
+ * @param {number} days - The number of days to subtract.
2670
+ * @returns {Date} A new `Date` object representing the resulting date.
2143
2671
  */
2144
2672
  function subtractDays(date, days) {
2145
2673
  return addDays(date, -days);
2146
2674
  }
2147
2675
  /**
2148
- * Determines if a year is a leap year.
2149
- * @param {number} year The year to check.
2150
- * @returns {boolean} True if the year is a leap year, false otherwise.
2676
+ * Determines whether a given year is a leap year according to the Gregorian calendar rules.
2677
+ *
2678
+ * @param {number} year - The year to check.
2679
+ * @returns {boolean} `true` if the year is a leap year, otherwise `false`.
2151
2680
  */
2152
2681
  function isLeapYear(year) {
2153
2682
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
2154
2683
  }
2155
2684
  /**
2156
- * Gets the first day of the month for a given date.
2157
- * @param {Date} date The date to use.
2158
- * @returns {Date} The first day of the month.
2685
+ * Returns a new `Date` object set to the first day of the month for a given date.
2686
+ *
2687
+ * @param {Date} date - The date from which to determine the month and year.
2688
+ * @returns {Date} A `Date` object representing the start of the month.
2159
2689
  */
2160
2690
  function getStartOfMonth(date) {
2161
2691
  return new Date(date.getFullYear(), date.getMonth(), 1);
2162
2692
  }
2163
2693
  /**
2164
- * Gets the last day of the month for a given date.
2165
- * @param {Date} date The date to use.
2166
- * @returns {Date} The last day of the month.
2694
+ * Returns a new `Date` object set to the last day of the month for a given date.
2695
+ *
2696
+ * @param {Date} date - The date from which to determine the month and year.
2697
+ * @returns {Date} A `Date` object representing the end of the month.
2167
2698
  */
2168
2699
  function getEndOfMonth(date) {
2169
2700
  return new Date(date.getFullYear(), date.getMonth() + 1, 0);
2170
2701
  }
2171
2702
  /**
2172
- * Calculates age from a given birth date.
2173
- * @param {Date} birthDate The birth date.
2703
+ * Calculates the current age in years based on a given birth date.
2704
+ *
2705
+ * @param {Date} birthDate - The date of birth.
2174
2706
  * @returns {number} The calculated age.
2175
2707
  */
2176
2708
  function calculateAge(birthDate) {
@@ -2183,8 +2715,9 @@ function calculateAge(birthDate) {
2183
2715
  return age;
2184
2716
  }
2185
2717
  /**
2186
- * Calculates the number of days until the next birthday.
2187
- * @param {Date} birthDate The birth date.
2718
+ * Calculates the number of days from the current date until the next birthday.
2719
+ *
2720
+ * @param {Date} birthDate - The date of birth.
2188
2721
  * @returns {number} The number of days until the next birthday.
2189
2722
  */
2190
2723
  function daysToNextBirthday(birthDate) {
@@ -2198,10 +2731,11 @@ function daysToNextBirthday(birthDate) {
2198
2731
  return daysBetween(today, nextBirthday);
2199
2732
  }
2200
2733
  /**
2201
- * Calculates the age at a specific date.
2202
- * @param {Date} birthDate The birth date.
2203
- * @param {Date} atDate The date to calculate the age at.
2204
- * @returns {number} The calculated age.
2734
+ * Calculates the age of a person on a specific date in the past or future.
2735
+ *
2736
+ * @param {Date} birthDate - The date of birth.
2737
+ * @param {Date} atDate - The target date for which to calculate the age.
2738
+ * @returns {number} The age on the specified date.
2205
2739
  */
2206
2740
  function ageAtDate(birthDate, atDate) {
2207
2741
  let age = atDate.getFullYear() - birthDate.getFullYear();
@@ -2213,11 +2747,12 @@ function ageAtDate(birthDate, atDate) {
2213
2747
  }
2214
2748
 
2215
2749
  /**
2216
- * Creates a debounced asynchronous validator function.
2750
+ * Creates a debounced version of an asynchronous validator function. This is useful for scenarios
2751
+ * like form input validation where you want to delay validation until the user has stopped typing.
2217
2752
  *
2218
- * @param validator - The async validator function to debounce.
2219
- * @param delay - The debounce delay in milliseconds.
2220
- * @returns A debounced version of the validator function.
2753
+ * @param validator - The asynchronous validator function to be debounced. It receives the value to validate and a `debounce` function.
2754
+ * @param {number} delay - The debounce delay in milliseconds.
2755
+ * @returns A new function that takes a value and returns a promise that resolves or rejects based on the debounced validation.
2221
2756
  */
2222
2757
  function debounceAsyncValidator(validator, delay) {
2223
2758
  let currentPromiseReject = null;
@@ -2248,10 +2783,13 @@ function debounceAsyncValidator(validator, delay) {
2248
2783
  };
2249
2784
  }
2250
2785
  /**
2251
- * Creates a debounced version of an asynchronous function.
2252
- * @param {Function} func The asynchronous function to debounce.
2253
- * @param {number} wait The number of milliseconds to wait before invoking the function.
2254
- * @returns {Function} The debounced function.
2786
+ * Creates a debounced version of an asynchronous function. The debounced function will only
2787
+ * resolve the promise of the last invocation within the `wait` period.
2788
+ *
2789
+ * @template T - The type of the asynchronous function.
2790
+ * @param {T} func - The asynchronous function to debounce.
2791
+ * @param {number} wait - The debounce delay in milliseconds.
2792
+ * @returns A new debounced asynchronous function.
2255
2793
  */
2256
2794
  function debounceAsync(func, wait) {
2257
2795
  let timeoutReject = null;
@@ -2270,10 +2808,13 @@ function debounceAsync(func, wait) {
2270
2808
  };
2271
2809
  }
2272
2810
  /**
2273
- * Creates a debounced asynchronous function that executes immediately on the first call.
2274
- * @param {Function} func The asynchronous function to debounce.
2275
- * @param {number} wait The number of milliseconds to wait before invoking the function.
2276
- * @returns {Function} The debounced function with immediate execution on the first call.
2811
+ * Creates a debounced version of an asynchronous function that executes immediately on the first call
2812
+ * and then waits for the specified delay before allowing the next execution.
2813
+ *
2814
+ * @template T - The type of the asynchronous function.
2815
+ * @param {T} func - The asynchronous function to debounce.
2816
+ * @param {number} wait - The cooldown period in milliseconds after an immediate execution.
2817
+ * @returns A new debounced asynchronous function that executes on the leading edge.
2277
2818
  */
2278
2819
  function debounceAsyncWithImmediate(func, wait) {
2279
2820
  let timeoutReject = null;
@@ -2305,10 +2846,13 @@ function debounceAsyncWithImmediate(func, wait) {
2305
2846
  };
2306
2847
  }
2307
2848
  /**
2308
- * Creates a debounced version of a function that executes on the leading edge.
2309
- * @param {Function} func The function to debounce.
2310
- * @param {number} wait The number of milliseconds to wait before invoking the function.
2311
- * @returns {Function} The debounced function.
2849
+ * Creates a debounced function that invokes `func` on the leading edge of the `wait` timeout.
2850
+ * Subsequent calls within the `wait` period are ignored.
2851
+ *
2852
+ * @template T - The type of the function.
2853
+ * @param {T} func - The function to debounce.
2854
+ * @param {number} wait - The debounce delay in milliseconds.
2855
+ * @returns A new debounced function.
2312
2856
  */
2313
2857
  function debounceLeading(func, wait) {
2314
2858
  let timeoutReject = null;
@@ -2329,10 +2873,13 @@ function debounceLeading(func, wait) {
2329
2873
  };
2330
2874
  }
2331
2875
  /**
2332
- * Creates a debounced version of a function that executes on the trailing edge.
2333
- * @param {Function} func The function to debounce.
2334
- * @param {number} wait The number of milliseconds to wait before invoking the function.
2335
- * @returns {Function} The debounced function.
2876
+ * Creates a debounced function that invokes `func` on the trailing edge of the `wait` timeout.
2877
+ * The function is called only after `wait` milliseconds of inactivity.
2878
+ *
2879
+ * @template T - The type of the function.
2880
+ * @param {T} func - The function to debounce.
2881
+ * @param {number} wait - The debounce delay in milliseconds.
2882
+ * @returns A new debounced function.
2336
2883
  */
2337
2884
  function debounceTrailing(func, wait) {
2338
2885
  let timeoutReject = null;
@@ -2350,10 +2897,13 @@ function debounceTrailing(func, wait) {
2350
2897
  };
2351
2898
  }
2352
2899
  /**
2353
- * Creates a debounced version of a function that executes on both leading and trailing edges.
2354
- * @param {Function} func The function to debounce.
2355
- * @param {number} wait The number of milliseconds to wait before invoking the function.
2356
- * @returns {Function} The debounced function.
2900
+ * Creates a debounced function that invokes `func` on both the leading and trailing edges of the `wait` timeout.
2901
+ * This is useful for UIs where an action should happen immediately on the first event, but also after a pause in events.
2902
+ *
2903
+ * @template T - The type of the function.
2904
+ * @param {T} func - The function to debounce.
2905
+ * @param {number} wait - The debounce delay in milliseconds.
2906
+ * @returns A new debounced function.
2357
2907
  */
2358
2908
  function debounceLeadingTrailing(func, wait) {
2359
2909
  let timeoutReject = null;
@@ -2379,10 +2929,13 @@ function debounceLeadingTrailing(func, wait) {
2379
2929
  };
2380
2930
  }
2381
2931
  /**
2382
- * Creates a debounced version of a function.
2383
- * @param {Function} func The function to debounce.
2384
- * @param {number} wait The number of milliseconds to wait before invoking the function.
2385
- * @returns {Function} The debounced function.
2932
+ * Creates a standard debounced function that delays invoking `func` until after `wait` milliseconds
2933
+ * have elapsed since the last time the debounced function was invoked. (This is an alias for `debounceTrailing`).
2934
+ *
2935
+ * @template T - The type of the function.
2936
+ * @param {T} func - The function to debounce.
2937
+ * @param {number} wait - The debounce delay in milliseconds.
2938
+ * @returns A new debounced function.
2386
2939
  */
2387
2940
  function debounce(func, wait) {
2388
2941
  let timeoutReject = null;
@@ -2399,10 +2952,13 @@ function debounce(func, wait) {
2399
2952
  };
2400
2953
  }
2401
2954
  /**
2402
- * Creates a throttled version of a function.
2403
- * @param {Function} func The function to throttle.
2404
- * @param {number} limit The number of milliseconds to wait between function calls.
2405
- * @returns {Function} The throttled function.
2955
+ * Creates a throttled function that only invokes `func` at most once per every `limit` milliseconds.
2956
+ * This is useful for rate-limiting events that fire frequently, such as scrolling or resizing.
2957
+ *
2958
+ * @template T - The type of the function.
2959
+ * @param {T} func - The function to throttle.
2960
+ * @param {number} limit - The throttle duration in milliseconds.
2961
+ * @returns A new throttled function.
2406
2962
  */
2407
2963
  function throttle(func, limit) {
2408
2964
  let lastCall = 0;
@@ -2416,9 +2972,11 @@ function throttle(func, limit) {
2416
2972
  }
2417
2973
 
2418
2974
  /**
2419
- * Converts a FormData object to a plain JavaScript object.
2420
- * @param {FormData} formData The FormData object to convert.
2421
- * @returns {Record<string, any>} The plain JavaScript object.
2975
+ * Converts a `FormData` object into a regular JavaScript object. It correctly handles
2976
+ * multiple values for the same key by creating an array for that key.
2977
+ *
2978
+ * @param {FormData} formData - The `FormData` object to convert.
2979
+ * @returns {Record<string, any>} A plain JavaScript object representation of the FormData.
2422
2980
  */
2423
2981
  function formDataToObject(formData) {
2424
2982
  const obj = {};
@@ -2437,9 +2995,10 @@ function formDataToObject(formData) {
2437
2995
  return obj;
2438
2996
  }
2439
2997
  /**
2440
- * Reads a file as text.
2441
- * @param {File} file The file to read.
2442
- * @returns {Promise<string>} A promise that resolves with the file content.
2998
+ * Asynchronously reads the content of a `File` object as a text string.
2999
+ *
3000
+ * @param {File} file - The `File` object to read.
3001
+ * @returns {Promise<string>} A promise that resolves with the text content of the file.
2443
3002
  */
2444
3003
  function readFileAsText(file) {
2445
3004
  return new Promise((resolve, reject) => {
@@ -2450,9 +3009,10 @@ function readFileAsText(file) {
2450
3009
  });
2451
3010
  }
2452
3011
  /**
2453
- * Reads a file as a Data URL.
2454
- * @param {File} file The file to read.
2455
- * @returns {Promise<string>} A promise that resolves with the Data URL.
3012
+ * Asynchronously reads the content of a `File` object as a Base64-encoded Data URL.
3013
+ *
3014
+ * @param {File} file - The `File` object to read.
3015
+ * @returns {Promise<string>} A promise that resolves with the Data URL representing the file's content.
2456
3016
  */
2457
3017
  function readFileAsDataURL(file) {
2458
3018
  return new Promise((resolve, reject) => {
@@ -2463,27 +3023,30 @@ function readFileAsDataURL(file) {
2463
3023
  });
2464
3024
  }
2465
3025
  /**
2466
- * Creates a Blob from a string.
2467
- * @param {string} content The string content for the Blob.
2468
- * @param {string} [type='text/plain'] The MIME type of the Blob.
2469
- * @returns {Blob} The Blob object.
3026
+ * Creates a `Blob` object from a string.
3027
+ *
3028
+ * @param {string} content - The string content to be put into the Blob.
3029
+ * @param {string} [type='text/plain'] - The MIME type of the Blob.
3030
+ * @returns {Blob} A new `Blob` object.
2470
3031
  */
2471
3032
  function stringToBlob(content, type = 'text/plain') {
2472
3033
  return new Blob([content], { type });
2473
3034
  }
2474
3035
  /**
2475
- * Creates a Blob from an ArrayBuffer.
2476
- * @param {ArrayBuffer} buffer The ArrayBuffer to convert.
2477
- * @param {string} [type='application/octet-stream'] The MIME type of the Blob.
2478
- * @returns {Blob} The Blob object.
3036
+ * Creates a `Blob` object from an `ArrayBuffer`.
3037
+ *
3038
+ * @param {ArrayBuffer} buffer - The `ArrayBuffer` to be put into the Blob.
3039
+ * @param {string} [type='application/octet-stream'] - The MIME type of the Blob.
3040
+ * @returns {Blob} A new `Blob` object.
2479
3041
  */
2480
3042
  function bufferToBlob(buffer, type = 'application/octet-stream') {
2481
3043
  return new Blob([buffer], { type });
2482
3044
  }
2483
3045
  /**
2484
- * Creates and downloads a file from Blob data.
2485
- * @param {Blob} blob The Blob containing the file data.
2486
- * @param {string} fileName The name of the file to create.
3046
+ * Triggers a browser download for a file created from a `Blob` object.
3047
+ *
3048
+ * @param {Blob} blob - The `Blob` containing the file data.
3049
+ * @param {string} fileName - The desired name for the downloaded file.
2487
3050
  */
2488
3051
  function downloadBlob(blob, fileName) {
2489
3052
  const link = document.createElement('a');
@@ -2498,11 +3061,12 @@ function downloadBlob(blob, fileName) {
2498
3061
  URL.revokeObjectURL(url);
2499
3062
  }
2500
3063
  /**
2501
- * Creates a FormData object containing a Blob.
2502
- * @param {Blob} blob The Blob to include in the FormData.
2503
- * @param {string} name The name of the form field.
2504
- * @param {string} [fileName='file'] The file name for the Blob.
2505
- * @returns {FormData} The FormData object.
3064
+ * Appends a `Blob` to a new `FormData` object.
3065
+ *
3066
+ * @param {Blob} blob - The `Blob` to append.
3067
+ * @param {string} name - The name of the field to append the blob as.
3068
+ * @param {string} [fileName='file'] - The filename to associate with the blob in the `FormData`.
3069
+ * @returns {FormData} A new `FormData` object containing the blob.
2506
3070
  */
2507
3071
  function blobToFormData(blob, name, fileName = 'file') {
2508
3072
  const formData = new FormData();
@@ -2511,9 +3075,10 @@ function blobToFormData(blob, name, fileName = 'file') {
2511
3075
  }
2512
3076
 
2513
3077
  /**
2514
- * Capitalizes the first character of a string.
2515
- * @param {string} s The string to capitalize.
2516
- * @returns {string} The capitalized string.
3078
+ * Capitalizes the first letter of a string.
3079
+ *
3080
+ * @param {string} s - The input string.
3081
+ * @returns {string} The string with the first letter capitalized.
2517
3082
  */
2518
3083
  function upperFirst(s) {
2519
3084
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -2521,9 +3086,10 @@ function upperFirst(s) {
2521
3086
  // Example usage:
2522
3087
  // console.log(upperFirst('hello')); // 'Hello'
2523
3088
  /**
2524
- * Lowercases the first character of a string.
2525
- * @param {string} s The string to lowercase.
2526
- * @returns {string} The lowercased string.
3089
+ * Converts the first letter of a string to lowercase.
3090
+ *
3091
+ * @param {string} s - The input string.
3092
+ * @returns {string} The string with the first letter in lowercase.
2527
3093
  */
2528
3094
  function lowerFirst(s) {
2529
3095
  return s.charAt(0).toLowerCase() + s.slice(1);
@@ -2531,9 +3097,11 @@ function lowerFirst(s) {
2531
3097
  // Example usage:
2532
3098
  // console.log(lowerFirst('Hello')); // 'hello'
2533
3099
  /**
2534
- * Removes accents and special characters from a string and converts it to a URL-friendly format.
2535
- * @param {string} input The string to process.
2536
- * @returns {string} The processed string.
3100
+ * Normalizes a string by converting it to lowercase, trimming whitespace, replacing spaces with hyphens,
3101
+ * and removing diacritical marks (accents).
3102
+ *
3103
+ * @param {string} input - The string to normalize.
3104
+ * @returns {string} The URL-friendly, normalized string.
2537
3105
  */
2538
3106
  function removeAccent(input) {
2539
3107
  return input
@@ -2547,8 +3115,9 @@ function removeAccent(input) {
2547
3115
  // Example usage:
2548
3116
  // console.log(removeAccent('Café du Nord')); // 'cafe-du-nord'
2549
3117
  /**
2550
- * Reverses a string.
2551
- * @param {string} str The string to reverse.
3118
+ * Reverses the characters of a string.
3119
+ *
3120
+ * @param {string} str - The input string.
2552
3121
  * @returns {string} The reversed string.
2553
3122
  */
2554
3123
  function reverseString(str) {
@@ -2557,9 +3126,10 @@ function reverseString(str) {
2557
3126
  // Example usage:
2558
3127
  // console.log(reverseString('hello')); // 'olleh'
2559
3128
  /**
2560
- * Counts the number of words in a string.
2561
- * @param {string} str The string to analyze.
2562
- * @returns {number} The word count.
3129
+ * Counts the number of words in a string, based on whitespace separation.
3130
+ *
3131
+ * @param {string} str - The input string.
3132
+ * @returns {number} The number of words in the string.
2563
3133
  */
2564
3134
  function countWords(str) {
2565
3135
  return str.trim().split(/\s+/).length;
@@ -2567,9 +3137,10 @@ function countWords(str) {
2567
3137
  // Example usage:
2568
3138
  // console.log(countWords('Hello world!')); // 2
2569
3139
  /**
2570
- * Truncates a string to the specified length and adds ellipsis if necessary.
2571
- * @param {string} str The string to truncate.
2572
- * @param {number} maxLength The maximum length of the string.
3140
+ * Truncates a string to a specified maximum length, appending '...' if the string is cut.
3141
+ *
3142
+ * @param {string} str - The input string.
3143
+ * @param {number} maxLength - The maximum desired length of the string.
2573
3144
  * @returns {string} The truncated string.
2574
3145
  */
2575
3146
  function truncateString(str, maxLength) {
@@ -2578,9 +3149,10 @@ function truncateString(str, maxLength) {
2578
3149
  // Example usage:
2579
3150
  // console.log(truncateString('This is a long string', 10)); // 'This is a...'
2580
3151
  /**
2581
- * Converts a string to camel case.
2582
- * @param {string} str The string to convert.
2583
- * @returns {string} The camel cased string.
3152
+ * Converts a string from various cases (e.g., snake_case, kebab-case, space separated) into camelCase.
3153
+ *
3154
+ * @param {string} str - The input string.
3155
+ * @returns {string} The camelCase version of the string.
2584
3156
  */
2585
3157
  function toCamelCase(str) {
2586
3158
  return str
@@ -2590,9 +3162,10 @@ function toCamelCase(str) {
2590
3162
  // Example usage:
2591
3163
  // console.log(toCamelCase('hello world example')); // 'helloWorldExample'
2592
3164
  /**
2593
- * Converts a string to kebab case.
2594
- * @param {string} str The string to convert.
2595
- * @returns {string} The kebab cased string.
3165
+ * Converts a string from various cases (e.g., camelCase, PascalCase, space separated) into kebab-case.
3166
+ *
3167
+ * @param {string} str - The input string.
3168
+ * @returns {string} The kebab-case version of the string.
2596
3169
  */
2597
3170
  function toKebabCase(str) {
2598
3171
  return str
@@ -2603,11 +3176,12 @@ function toKebabCase(str) {
2603
3176
  // Example usage:
2604
3177
  // console.log(toKebabCase('Hello World Example')); // 'hello-world-example'
2605
3178
  /**
2606
- * Replaces all instances of a substring within a string.
2607
- * @param {string} str The original string.
2608
- * @param {string} find The substring to find.
2609
- * @param {string} replace The substring to replace with.
2610
- * @returns {string} The modified string.
3179
+ * Replaces all occurrences of a substring with a new substring.
3180
+ *
3181
+ * @param {string} str - The original string.
3182
+ * @param {string} find - The substring to find and replace.
3183
+ * @param {string} replace - The substring to replace with.
3184
+ * @returns {string} A new string with all replacements made.
2611
3185
  */
2612
3186
  function replaceAll(str, find, replace) {
2613
3187
  return str.split(find).join(replace);
@@ -2615,9 +3189,10 @@ function replaceAll(str, find, replace) {
2615
3189
  // Example usage:
2616
3190
  // console.log(replaceAll('hello world', 'o', 'a')); // 'hella warld'
2617
3191
  /**
2618
- * Generates a random string of a specific length.
2619
- * @param {number} length The length of the string to generate.
2620
- * @returns {string} The random string.
3192
+ * Generates a random alphanumeric string of a specified length.
3193
+ *
3194
+ * @param {number} length - The desired length of the random string.
3195
+ * @returns {string} The generated random string.
2621
3196
  */
2622
3197
  function generateRandomString(length) {
2623
3198
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -2627,9 +3202,10 @@ function generateRandomString(length) {
2627
3202
  // console.log(generateRandomString(10)); // 'A1b2C3d4E5'
2628
3203
 
2629
3204
  /**
2630
- * Validates if the key pressed is a valid letter or special character.
2631
- * @param {KeyboardEvent} e The keyboard event.
2632
- * @returns {boolean} True if the key is valid, otherwise false.
3205
+ * An event handler that prevents a `KeyboardEvent`'s default action if the key pressed is not a letter or a specific special character.
3206
+ *
3207
+ * @param {KeyboardEvent} e - The `KeyboardEvent` object.
3208
+ * @returns {boolean} `true` if the key is valid, `false` otherwise.
2633
3209
  */
2634
3210
  function validateLetters(e) {
2635
3211
  const key = e.keyCode;
@@ -2660,9 +3236,10 @@ function validateLetters(e) {
2660
3236
  // Example usage:
2661
3237
  // document.addEventListener('keydown', validateLetters);
2662
3238
  /**
2663
- * Validates if the key pressed is a valid alphanumeric character.
2664
- * @param {KeyboardEvent} e The keyboard event.
2665
- * @returns {boolean} True if the key is valid, otherwise false.
3239
+ * An event handler that prevents a `KeyboardEvent`'s default action if the key pressed is not an alphanumeric character.
3240
+ *
3241
+ * @param {KeyboardEvent} e - The `KeyboardEvent` object.
3242
+ * @returns {boolean} `true` if the key is valid, `false` otherwise.
2666
3243
  */
2667
3244
  function validateAlphanumeric(e) {
2668
3245
  const key = e.keyCode;
@@ -2683,9 +3260,10 @@ function validateAlphanumeric(e) {
2683
3260
  // Example usage:
2684
3261
  // document.addEventListener('keydown', validateAlphanumeric);
2685
3262
  /**
2686
- * Validates if the key pressed is a number.
2687
- * @param {KeyboardEvent} e The keyboard event.
2688
- * @returns {boolean} True if the key is a number, otherwise false.
3263
+ * An event handler that prevents a `KeyboardEvent`'s default action if the key pressed is not a number.
3264
+ *
3265
+ * @param {KeyboardEvent} e - The `KeyboardEvent` object.
3266
+ * @returns {boolean} `true` if the key is a number, otherwise `false`.
2689
3267
  */
2690
3268
  function validateNumbers(e) {
2691
3269
  const key = e.keyCode;
@@ -2698,9 +3276,10 @@ function validateNumbers(e) {
2698
3276
  // Example usage:
2699
3277
  // document.addEventListener('keydown', validateNumbers);
2700
3278
  /**
2701
- * Validates if a phone number is valid.
2702
- * @param {string} phoneNumber The phone number to validate.
2703
- * @returns {boolean} True if the phone number is valid, otherwise false.
3279
+ * Validates a phone number against a regex for 10-digit numbers.
3280
+ *
3281
+ * @param {string} phoneNumber - The phone number to validate.
3282
+ * @returns {boolean} `true` if the phone number is valid, otherwise `false`.
2704
3283
  */
2705
3284
  function isValidPhoneNumber(phoneNumber) {
2706
3285
  const phonePattern = /^[0-9]{10}$/; // Example pattern for 10-digit phone numbers
@@ -2710,9 +3289,10 @@ function isValidPhoneNumber(phoneNumber) {
2710
3289
  // console.log(isValidPhoneNumber('1234567890')); // true
2711
3290
  // console.log(isValidPhoneNumber('123-456-7890')); // false
2712
3291
  /**
2713
- * Validates if a string is a valid email address.
2714
- * @param {string} email The email address to validate.
2715
- * @returns {boolean} True if the email address is valid, otherwise false.
3292
+ * Validates an email address against a standard regex pattern.
3293
+ *
3294
+ * @param {string} email - The email address to validate.
3295
+ * @returns {boolean} `true` if the email is valid, otherwise `false`.
2716
3296
  */
2717
3297
  function isValidEmail(email) {
2718
3298
  const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -2722,9 +3302,10 @@ function isValidEmail(email) {
2722
3302
  // console.log(isValidEmail('example@domain.com')); // true
2723
3303
  // console.log(isValidEmail('invalid-email')); // false
2724
3304
  /**
2725
- * Validates if a string is a valid URL.
2726
- * @param {string} url The URL to validate.
2727
- * @returns {boolean} True if the URL is valid, otherwise false.
3305
+ * Validates a string to see if it is a well-formed URL.
3306
+ *
3307
+ * @param {string} url - The URL string to validate.
3308
+ * @returns {boolean} `true` if the URL is valid, otherwise `false`.
2728
3309
  */
2729
3310
  function isValidURL(url) {
2730
3311
  try {
@@ -2739,9 +3320,10 @@ function isValidURL(url) {
2739
3320
  // console.log(isValidURL('https://www.example.com')); // true
2740
3321
  // console.log(isValidURL('invalid-url')); // false
2741
3322
  /**
2742
- * Validates if a string is a valid date in YYYY-MM-DD format.
2743
- * @param {string} date The date string to validate.
2744
- * @returns {boolean} True if the date is valid, otherwise false.
3323
+ * Validates a string to ensure it is a valid date in 'YYYY-MM-DD' format.
3324
+ *
3325
+ * @param {string} date - The date string to validate.
3326
+ * @returns {boolean} `true` if the date is valid, otherwise `false`.
2745
3327
  */
2746
3328
  function isValidDate(date) {
2747
3329
  const datePattern = /^\d{4}-\d{2}-\d{2}$/;
@@ -2755,9 +3337,10 @@ function isValidDate(date) {
2755
3337
  // console.log(isValidDate('2024-08-31')); // true
2756
3338
  // console.log(isValidDate('2024-02-30')); // false
2757
3339
  /**
2758
- * Validates if a password meets certain strength criteria.
2759
- * @param {string} password The password to validate.
2760
- * @returns {boolean} True if the password is strong, otherwise false.
3340
+ * Checks if a password meets a set of strength requirements (minimum length, uppercase, lowercase, numbers, special characters).
3341
+ *
3342
+ * @param {string} password - The password to validate.
3343
+ * @returns {boolean} `true` if the password is strong, otherwise `false`.
2761
3344
  */
2762
3345
  function isStrongPassword(password) {
2763
3346
  const minLength = 8;
@@ -2771,9 +3354,10 @@ function isStrongPassword(password) {
2771
3354
  // console.log(isStrongPassword('Strong1@password')); // true
2772
3355
  // console.log(isStrongPassword('weakpass')); // false
2773
3356
  /**
2774
- * Validates a credit card number using the Luhn algorithm.
2775
- * @param {string} cardNumber The credit card number to validate.
2776
- * @returns {boolean} True if the credit card number is valid, otherwise false.
3357
+ * Validates a credit card number using the Luhn algorithm (mod-10 check).
3358
+ *
3359
+ * @param {string} cardNumber - The credit card number to validate.
3360
+ * @returns {boolean} `true` if the credit card number is valid, otherwise `false`.
2777
3361
  */
2778
3362
  function isValidCreditCard(cardNumber) {
2779
3363
  const sanitized = cardNumber.replace(/\D/g, '');
@@ -2795,9 +3379,10 @@ function isValidCreditCard(cardNumber) {
2795
3379
  // console.log(isValidCreditCard('4111111111111111')); // true
2796
3380
  // console.log(isValidCreditCard('1234567812345670')); // false
2797
3381
  /**
2798
- * Validates if a string is a valid hex color code.
2799
- * @param {string} color The color code to validate.
2800
- * @returns {boolean} True if the color code is valid, otherwise false.
3382
+ * Validates a string to check if it's a valid 3- or 6-digit hexadecimal color code.
3383
+ *
3384
+ * @param {string} color - The hex color string to validate.
3385
+ * @returns {boolean} `true` if the color code is valid, otherwise `false`.
2801
3386
  */
2802
3387
  function isValidHexColor(color) {
2803
3388
  const hexPattern = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/;
@@ -2808,9 +3393,10 @@ function isValidHexColor(color) {
2808
3393
  // console.log(isValidHexColor('#FFF')); // true
2809
3394
  // console.log(isValidHexColor('#12345G')); // false
2810
3395
  /**
2811
- * Validates if a string is a valid time in HH:MM format.
2812
- * @param {string} time The time string to validate.
2813
- * @returns {boolean} True if the time is valid, otherwise false.
3396
+ * Validates a string to ensure it represents a valid time in 24-hour HH:MM format.
3397
+ *
3398
+ * @param {string} time - The time string to validate.
3399
+ * @returns {boolean} `true` if the time is valid, otherwise `false`.
2814
3400
  */
2815
3401
  function isValidTime(time) {
2816
3402
  const timePattern = /^([01]\d|2[0-3]):([0-5]\d)$/;
@@ -2820,9 +3406,10 @@ function isValidTime(time) {
2820
3406
  // console.log(isValidTime('14:30')); // true
2821
3407
  // console.log(isValidTime('25:00')); // false
2822
3408
  /**
2823
- * Validates if a string is a valid IPv4 address.
2824
- * @param {string} ip The IP address to validate.
2825
- * @returns {boolean} True if the IP address is valid, otherwise false.
3409
+ * Validates a string to check if it is a valid IPv4 address.
3410
+ *
3411
+ * @param {string} ip - The IP address string to validate.
3412
+ * @returns {boolean} `true` if the IP address is valid, otherwise `false`.
2826
3413
  */
2827
3414
  function isValidIP(ip) {
2828
3415
  const ipPattern = /^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9][0-9]?)$/;
@@ -2832,9 +3419,10 @@ function isValidIP(ip) {
2832
3419
  // console.log(isValidIP('192.168.1.1')); // true
2833
3420
  // console.log(isValidIP('999.999.999.999')); // false
2834
3421
  /**
2835
- * Validates if a string is a valid U.S. Social Security Number (SSN).
2836
- * @param {string} ssn The SSN to validate.
2837
- * @returns {boolean} True if the SSN is valid, otherwise false.
3422
+ * Validates a string to check if it matches the format of a U.S. Social Security Number (SSN).
3423
+ *
3424
+ * @param {string} ssn - The SSN string to validate.
3425
+ * @returns {boolean} `true` if the SSN format is valid, otherwise `false`.
2838
3426
  */
2839
3427
  function isValidSSN(ssn) {
2840
3428
  const ssnPattern = /^\d{3}-\d{2}-\d{4}$/;
@@ -2844,9 +3432,10 @@ function isValidSSN(ssn) {
2844
3432
  // console.log(isValidSSN('123-45-6789')); // true
2845
3433
  // console.log(isValidSSN('123-45-678')); // false
2846
3434
  /**
2847
- * Validates if a string is a valid U.S. ZIP code.
2848
- * @param {string} zip The ZIP code to validate.
2849
- * @returns {boolean} True if the ZIP code is valid, otherwise false.
3435
+ * Validates a string to check if it is a valid 5-digit or 9-digit (ZIP+4) U.S. ZIP code.
3436
+ *
3437
+ * @param {string} zip - The ZIP code string to validate.
3438
+ * @returns {boolean} `true` if the ZIP code is valid, otherwise `false`.
2850
3439
  */
2851
3440
  function isValidZIP(zip) {
2852
3441
  const zipPattern = /^\d{5}(-\d{4})?$/;
@@ -2857,9 +3446,10 @@ function isValidZIP(zip) {
2857
3446
  // console.log(isValidZIP('12345-6789')); // true
2858
3447
  // console.log(isValidZIP('1234')); // false
2859
3448
  /**
2860
- * Validates if a string is a valid credit card expiry date in MM/YY format.
2861
- * @param {string} expiryDate The expiry date to validate.
2862
- * @returns {boolean} True if the expiry date is valid, otherwise false.
3449
+ * Validates a credit card expiry date string (MM/YY format) to ensure it is a valid, non-expired date.
3450
+ *
3451
+ * @param {string} expiryDate - The expiry date to validate.
3452
+ * @returns {boolean} `true` if the expiry date is valid and not in the past, otherwise `false`.
2863
3453
  */
2864
3454
  function isValidExpiryDate(expiryDate) {
2865
3455
  const expiryPattern = /^(0[1-9]|1[0-2])\/\d{2}$/;
@@ -2874,9 +3464,10 @@ function isValidExpiryDate(expiryDate) {
2874
3464
  // console.log(isValidExpiryDate('08/24')); // true
2875
3465
  // console.log(isValidExpiryDate('12/22')); // false
2876
3466
  /**
2877
- * Validates if a string is a valid 8-character hexadecimal color code (including alpha).
2878
- * @param {string} color The color code to validate.
2879
- * @returns {boolean} True if the color code is valid, otherwise false.
3467
+ * Validates a string to check if it's a valid 8-digit hexadecimal color code (with alpha channel).
3468
+ *
3469
+ * @param {string} color - The hex color string to validate.
3470
+ * @returns {boolean} `true` if the color code is valid, otherwise `false`.
2880
3471
  */
2881
3472
  function isValidHexColorAlpha(color) {
2882
3473
  const hexPattern = /^#([0-9A-Fa-f]{8})$/;
@@ -2886,9 +3477,10 @@ function isValidHexColorAlpha(color) {
2886
3477
  // console.log(isValidHexColorAlpha('#RRGGBBAA')); // true
2887
3478
  // console.log(isValidHexColorAlpha('#FFFFFF')); // false
2888
3479
  /**
2889
- * Validates if a username meets specific criteria.
2890
- * @param {string} username The username to validate.
2891
- * @returns {boolean} True if the username is valid, otherwise false.
3480
+ * Validates a username to ensure it contains only alphanumeric characters and underscores, with a length between 3 and 16 characters.
3481
+ *
3482
+ * @param {string} username - The username to validate.
3483
+ * @returns {boolean} `true` if the username is valid, otherwise `false`.
2892
3484
  */
2893
3485
  function isValidUsername(username) {
2894
3486
  const usernamePattern = /^[a-zA-Z0-9_]{3,16}$/; // 3 to 16 characters, letters, numbers, and underscores only
@@ -2898,9 +3490,10 @@ function isValidUsername(username) {
2898
3490
  // console.log(isValidUsername('user_name123')); // true
2899
3491
  // console.log(isValidUsername('us')); // false
2900
3492
  /**
2901
- * Validates if a string represents a valid age between 0 and 120.
2902
- * @param {string} age The age to validate.
2903
- * @returns {boolean} True if the age is valid, otherwise false.
3493
+ * Validates a string to ensure it represents a plausible human age (0-120).
3494
+ *
3495
+ * @param {string} age - The age string to validate.
3496
+ * @returns {boolean} `true` if the age is valid, otherwise `false`.
2904
3497
  */
2905
3498
  function isValidAge(age) {
2906
3499
  const ageNumber = parseInt(age, 10);
@@ -2910,9 +3503,10 @@ function isValidAge(age) {
2910
3503
  // console.log(isValidAge('25')); // true
2911
3504
  // console.log(isValidAge('121')); // false
2912
3505
  /**
2913
- * Validates if a string is a valid hexadecimal number.
2914
- * @param {string} hex The hexadecimal number to validate.
2915
- * @returns {boolean} True if the number is valid, otherwise false.
3506
+ * Validates a string to check if it contains only valid hexadecimal characters.
3507
+ *
3508
+ * @param {string} hex - The string to validate.
3509
+ * @returns {boolean} `true` if the string is a valid hexadecimal number, otherwise `false`.
2916
3510
  */
2917
3511
  function isValidHexNumber(hex) {
2918
3512
  const hexPattern = /^[0-9A-Fa-f]+$/;
@@ -2922,73 +3516,211 @@ function isValidHexNumber(hex) {
2922
3516
  // console.log(isValidHexNumber('1A3F')); // true
2923
3517
  // console.log(isValidHexNumber('GHIJ')); // false
2924
3518
 
3519
+ const DEFAULT_RETRY_CONFIG = {
3520
+ retries: 3,
3521
+ retryDelay: 1000,
3522
+ maxRetryDelay: 10000,
3523
+ backoffMultiplier: 2,
3524
+ retryCondition: (error) => {
3525
+ if (error instanceof NetworkError || error instanceof ServerError) {
3526
+ const statusCode = error.statusCode;
3527
+ if (!statusCode)
3528
+ return true;
3529
+ if (statusCode >= 500)
3530
+ return true;
3531
+ if (statusCode === 408 || statusCode === 429)
3532
+ return true;
3533
+ return false;
3534
+ }
3535
+ if (error instanceof Error) {
3536
+ return error.message.includes('timeout') || error.message.includes('network');
3537
+ }
3538
+ return false;
3539
+ },
3540
+ };
3541
+ async function retryWithBackoff(fn, config = {}) {
3542
+ const finalConfig = { ...DEFAULT_RETRY_CONFIG, ...config };
3543
+ let lastError;
3544
+ let delay = finalConfig.retryDelay;
3545
+ for (let attempt = 0; attempt <= finalConfig.retries; attempt++) {
3546
+ try {
3547
+ return await fn();
3548
+ }
3549
+ catch (error) {
3550
+ lastError = error;
3551
+ if (attempt === finalConfig.retries) {
3552
+ break;
3553
+ }
3554
+ if (!finalConfig.retryCondition(error)) {
3555
+ throw error;
3556
+ }
3557
+ await new Promise((resolve) => setTimeout(resolve, delay));
3558
+ delay = Math.min(delay * finalConfig.backoffMultiplier, finalConfig.maxRetryDelay);
3559
+ }
3560
+ }
3561
+ throw lastError;
3562
+ }
3563
+
3564
+ /**
3565
+ * A standardized RESTful class that provides a generic interface for performing
3566
+ * CRUD (Create, Read, Update, Delete) operations on a specific API resource. It is designed
3567
+ * to be extended directly from your models. It supports both JSON and FormData requests.
3568
+ *
3569
+ * @example
3570
+ * ```typescript
3571
+ * export class Role extends RestStd {
3572
+ * static override resource = 'roles';
3573
+ * static fetchFn = createAxiosFetcher(axiosInstance);
3574
+ * }
3575
+ *
3576
+ * const roles = await Role.getAll();
3577
+ * ```
3578
+ */
2925
3579
  class RestStd {
3580
+ /**
3581
+ * The resource endpoint. MUST be overridden in subclasses.
3582
+ * @example static override resource = 'users';
3583
+ */
2926
3584
  static resource;
3585
+ /** A flag to determine if request data should be sent as FormData. Defaults to `false`. */
2927
3586
  static isFormData = false;
3587
+ /** A record of global headers to be sent with every request. */
2928
3588
  static headers = {};
3589
+ /** The function used to make the actual HTTP requests. Optional, defaults to Axios fetcher. */
2929
3590
  static fetchFn;
3591
+ /** Retry configuration for failed requests. Optional. */
3592
+ static retryConfig;
2930
3593
  /**
2931
- * Set global headers for all requests.
2932
- * @param headers Object containing headers to be set globally.
3594
+ * Validates that the resource property is defined.
3595
+ * @throws {Error} If resource is not defined
3596
+ */
3597
+ static validateResource() {
3598
+ if (!this.resource || this.resource.trim() === '') {
3599
+ throw new Error(`[${this.constructor.name}] Static property 'resource' is required. ` +
3600
+ `Please define: static override resource = 'your-resource';`);
3601
+ }
3602
+ }
3603
+ /**
3604
+ * Gets the fetcher function, using default if not provided.
3605
+ * Creates a default Axios fetcher if not configured, allowing lazy initialization.
3606
+ * @returns The fetcher function to use
3607
+ */
3608
+ static getFetchFn() {
3609
+ if (this.fetchFn) {
3610
+ return this.fetchFn;
3611
+ }
3612
+ const axiosInstance = getConfiguredAxiosInstance();
3613
+ return createAxiosFetcher(axiosInstance);
3614
+ }
3615
+ /**
3616
+ * Executes a fetch request with optional retry logic.
3617
+ * @param config - The fetcher configuration
3618
+ * @returns A promise that resolves with the response data
3619
+ */
3620
+ static async executeFetch(config) {
3621
+ const fetcher = this.getFetchFn();
3622
+ if (this.retryConfig) {
3623
+ return retryWithBackoff(() => fetcher(config), this.retryConfig);
3624
+ }
3625
+ try {
3626
+ return await fetcher(config);
3627
+ }
3628
+ catch (error) {
3629
+ if (error && typeof error === 'object' && 'response' in error) {
3630
+ throw NetworkError.fromAxiosError(error);
3631
+ }
3632
+ if (error instanceof Error && error.name === 'TypeError' && error.message?.includes('fetch')) {
3633
+ throw NetworkError.fromFetchError(error);
3634
+ }
3635
+ throw error;
3636
+ }
3637
+ }
3638
+ /**
3639
+ * Builds a URL by combining base URL and suffix.
3640
+ * @param baseUrl - The base URL
3641
+ * @param suffix - Optional suffix to append
3642
+ * @returns The combined URL
3643
+ */
3644
+ static buildUrl(baseUrl, suffix) {
3645
+ const cleanBase = baseUrl.replace(/\/$/, '');
3646
+ if (suffix) {
3647
+ const cleanSuffix = suffix.startsWith('/') ? suffix : `/${suffix}`;
3648
+ return cleanBase + cleanSuffix;
3649
+ }
3650
+ return cleanBase;
3651
+ }
3652
+ /**
3653
+ * Sets global headers that will be included in all subsequent requests made by this class.
3654
+ * @param headers - An object containing the headers to be set
2933
3655
  */
2934
3656
  static setHeaders(headers) {
2935
3657
  this.headers = { ...this.headers, ...headers };
2936
3658
  }
2937
3659
  /**
2938
- * Convert data to FormData if isFormData is true, otherwise return the data as is.
2939
- * @param data Data to be converted.
2940
- * @returns Data in FormData format or as is.
3660
+ * Conditionally transforms the request data to FormData if `isFormData` is true.
3661
+ * @param data - The data to be potentially transformed
3662
+ * @returns The transformed data as FormData, or the original data
2941
3663
  */
2942
3664
  static transformData(data) {
2943
3665
  if (this.isFormData) {
2944
- const formData = objectToFormData(data);
2945
- return formData;
3666
+ return objectToFormData(data);
2946
3667
  }
2947
3668
  return data;
2948
3669
  }
2949
3670
  /**
2950
- * Fetch a list of items from the server.
2951
- *
2952
- * @param params Query parameters for filtering the results.
2953
- * @param options Additional options for the fetch function.
2954
- * @returns The result of the fetch function (typically a promise).
3671
+ * Fetches a list of items from the resource's endpoint.
3672
+ * @template TResponse The expected response type
3673
+ * @template TParams The type of query parameters
3674
+ * @param options - Options including params, options, and optional url override
3675
+ * @returns A promise that resolves with the response data
2955
3676
  */
2956
- static getAll(params, options = {}) {
2957
- return this.fetchFn({
3677
+ static getAll(options = {}) {
3678
+ this.validateResource();
3679
+ const { params, url } = options;
3680
+ const finalUrl = url || this.resource;
3681
+ const config = {
2958
3682
  method: "GET",
2959
- url: this.resource,
3683
+ url: finalUrl,
2960
3684
  params,
2961
3685
  headers: this.headers,
2962
- }, options);
3686
+ };
3687
+ return this.executeFetch(config);
2963
3688
  }
2964
3689
  /**
2965
- * Fetch a single item by ID from the server.
2966
- *
2967
- * @param id The ID of the item to fetch.
2968
- * @param params Additional query parameters for the request.
2969
- * @param options Additional options for the fetch function.
2970
- * @returns The result of the fetch function (typically a promise).
3690
+ * Fetches a single item by its ID.
3691
+ * @template TResponse The expected response type
3692
+ * @template TParams The type of query parameters
3693
+ * @param options - Options including id, params, options, and optional url override
3694
+ * @returns A promise that resolves with the response data
2971
3695
  */
2972
- static getOne(id, params, options = {}) {
2973
- return this.fetchFn({
3696
+ static getOne(options) {
3697
+ this.validateResource();
3698
+ const { id, params, url } = options;
3699
+ const baseUrl = url || this.resource;
3700
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3701
+ const config = {
2974
3702
  method: "GET",
2975
- url: `${this.resource}/${id}`,
3703
+ url: finalUrl,
2976
3704
  params,
2977
3705
  headers: this.headers,
2978
- }, options);
3706
+ };
3707
+ return this.executeFetch(config);
2979
3708
  }
2980
3709
  /**
2981
- * Create a new item on the server.
2982
- *
2983
- * @param data The data for the new item to create.
2984
- * @param options Additional options for the fetch function.
2985
- * @returns The result of the fetch function (typically a promise).
3710
+ * Creates a new item.
3711
+ * @template TResponse The expected response type
3712
+ * @template TData The type of data to send
3713
+ * @param options - Options including data, options, and optional url override
3714
+ * @returns A promise that resolves with the response data
2986
3715
  */
2987
- static create(data, options = {}) {
3716
+ static create(options) {
3717
+ this.validateResource();
3718
+ const { data, url } = options;
3719
+ const finalUrl = url || this.resource;
2988
3720
  const transformedData = this.transformData(data);
2989
- return this.fetchFn({
3721
+ const config = {
2990
3722
  method: "POST",
2991
- url: this.resource,
3723
+ url: finalUrl,
2992
3724
  data: transformedData,
2993
3725
  headers: {
2994
3726
  ...this.headers,
@@ -2996,22 +3728,27 @@ class RestStd {
2996
3728
  ? ContentTypeEnum.FORM_DATA
2997
3729
  : ContentTypeEnum.JSON,
2998
3730
  },
2999
- }, options);
3731
+ };
3732
+ return this.executeFetch(config);
3000
3733
  }
3001
3734
  /**
3002
- * Create multiple new items on the server.
3003
- *
3004
- * @param data An array of data for the items to create.
3005
- * @param options Additional options for the fetch function.
3006
- * @returns The result of the fetch function.
3735
+ * Creates multiple new items in a single request.
3736
+ * @template TResponse The expected response type
3737
+ * @template TData The type of data items to send
3738
+ * @param options - Options including data array, options, and optional url override
3739
+ * @returns A promise that resolves with the response data
3007
3740
  */
3008
- static bulkCreate(data, options = {}) {
3741
+ static bulkCreate(options) {
3742
+ this.validateResource();
3743
+ const { data, url } = options;
3744
+ const baseUrl = url || this.resource;
3745
+ const finalUrl = this.buildUrl(baseUrl, 'bulk');
3009
3746
  const transformedData = this.isFormData
3010
3747
  ? data.map((item) => this.transformData(item))
3011
3748
  : data;
3012
- return this.fetchFn({
3749
+ const config = {
3013
3750
  method: "POST",
3014
- url: `${this.resource}/bulk`,
3751
+ url: finalUrl,
3015
3752
  data: transformedData,
3016
3753
  headers: {
3017
3754
  ...this.headers,
@@ -3019,21 +3756,25 @@ class RestStd {
3019
3756
  ? ContentTypeEnum.FORM_DATA
3020
3757
  : ContentTypeEnum.JSON,
3021
3758
  },
3022
- }, options);
3759
+ };
3760
+ return this.executeFetch(config);
3023
3761
  }
3024
3762
  /**
3025
- * Update an existing item on the server.
3026
- *
3027
- * @param id The ID of the item to update.
3028
- * @param data The updated data for the item.
3029
- * @param options Additional options for the fetch function.
3030
- * @returns The result of the fetch function (typically a promise).
3763
+ * Updates an existing item by its ID.
3764
+ * @template TResponse The expected response type
3765
+ * @template TData The type of data to send
3766
+ * @param options - Options including id, data, options, and optional url override
3767
+ * @returns A promise that resolves with the response data
3031
3768
  */
3032
- static update(id, data, options = {}) {
3769
+ static update(options) {
3770
+ this.validateResource();
3771
+ const { id, data, url } = options;
3772
+ const baseUrl = url || this.resource;
3773
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3033
3774
  const transformedData = this.transformData(data);
3034
- return this.fetchFn({
3775
+ const config = {
3035
3776
  method: "PUT",
3036
- url: `${this.resource}/${id}`,
3777
+ url: finalUrl,
3037
3778
  data: transformedData,
3038
3779
  headers: {
3039
3780
  ...this.headers,
@@ -3041,22 +3782,27 @@ class RestStd {
3041
3782
  ? ContentTypeEnum.FORM_DATA
3042
3783
  : ContentTypeEnum.JSON,
3043
3784
  },
3044
- }, options);
3785
+ };
3786
+ return this.executeFetch(config);
3045
3787
  }
3046
3788
  /**
3047
- * Update multiple existing items on the server.
3048
- *
3049
- * @param data An array of data for the items to update (each object should have an ID).
3050
- * @param options Additional options for the fetch function.
3051
- * @returns The result of the fetch function.
3789
+ * Updates multiple existing items in a single request.
3790
+ * @template TResponse The expected response type
3791
+ * @template TData The type of data items to send
3792
+ * @param options - Options including data array, options, and optional url override
3793
+ * @returns A promise that resolves with the response data
3052
3794
  */
3053
- static bulkUpdate(data, options = {}) {
3795
+ static bulkUpdate(options) {
3796
+ this.validateResource();
3797
+ const { data, url } = options;
3798
+ const baseUrl = url || this.resource;
3799
+ const finalUrl = this.buildUrl(baseUrl, 'bulk');
3054
3800
  const transformedData = this.isFormData
3055
3801
  ? data.map((item) => this.transformData(item))
3056
3802
  : data;
3057
- return this.fetchFn({
3803
+ const config = {
3058
3804
  method: "PUT",
3059
- url: `${this.resource}/bulk`,
3805
+ url: finalUrl,
3060
3806
  data: transformedData,
3061
3807
  headers: {
3062
3808
  ...this.headers,
@@ -3064,21 +3810,25 @@ class RestStd {
3064
3810
  ? ContentTypeEnum.FORM_DATA
3065
3811
  : ContentTypeEnum.JSON,
3066
3812
  },
3067
- }, options);
3813
+ };
3814
+ return this.executeFetch(config);
3068
3815
  }
3069
3816
  /**
3070
- * Partially update an existing item on the server.
3071
- *
3072
- * @param id The ID of the item to update.
3073
- * @param data The updated data for the item.
3074
- * @param options Additional options for the fetch function.
3075
- * @returns The result of the fetch function (typically a promise).
3817
+ * Partially updates an existing item by its ID.
3818
+ * @template TResponse The expected response type
3819
+ * @template TData The type of data to send (partial)
3820
+ * @param options - Options including id, data, options, and optional url override
3821
+ * @returns A promise that resolves with the response data
3076
3822
  */
3077
- static patch(id, data, options = {}) {
3823
+ static patch(options) {
3824
+ this.validateResource();
3825
+ const { id, data, url } = options;
3826
+ const baseUrl = url || this.resource;
3827
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3078
3828
  const transformedData = this.transformData(data);
3079
- return this.fetchFn({
3829
+ const config = {
3080
3830
  method: "PATCH",
3081
- url: `${this.resource}/${id}`,
3831
+ url: finalUrl,
3082
3832
  data: transformedData,
3083
3833
  headers: {
3084
3834
  ...this.headers,
@@ -3086,65 +3836,80 @@ class RestStd {
3086
3836
  ? ContentTypeEnum.FORM_DATA
3087
3837
  : ContentTypeEnum.JSON,
3088
3838
  },
3089
- }, options);
3839
+ };
3840
+ return this.executeFetch(config);
3090
3841
  }
3091
3842
  /**
3092
- * Delete an item from the server.
3093
- *
3094
- * @param id The ID of the item to delete.
3095
- * @param options Additional options for the fetch function.
3096
- * @returns The result of the fetch function (typically a promise).
3843
+ * Deletes an item by its ID.
3844
+ * @template TResponse The expected response type
3845
+ * @param options - Options including id, options, and optional url override
3846
+ * @returns A promise that resolves with the response data
3097
3847
  */
3098
- static delete(id, options = {}) {
3099
- return this.fetchFn({
3848
+ static delete(options) {
3849
+ this.validateResource();
3850
+ const { id, url } = options;
3851
+ const baseUrl = url || this.resource;
3852
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3853
+ const config = {
3100
3854
  method: "DELETE",
3101
- url: `${this.resource}/${id}`,
3855
+ url: finalUrl,
3102
3856
  headers: this.headers,
3103
- }, options);
3857
+ };
3858
+ return this.executeFetch(config);
3104
3859
  }
3105
3860
  /**
3106
- * Delete multiple items from the server by their IDs.
3107
- *
3108
- * @param ids An array of IDs of the items to delete.
3109
- * @param options Additional options for the fetch function.
3110
- * @returns The result of the fetch function.
3861
+ * Deletes multiple items by their IDs in a single request.
3862
+ * @template TResponse The expected response type
3863
+ * @param options - Options including ids array, options, and optional url override
3864
+ * @returns A promise that resolves with the response data
3111
3865
  */
3112
- static bulkDelete(ids, options = {}) {
3113
- return this.fetchFn({
3866
+ static bulkDelete(options) {
3867
+ this.validateResource();
3868
+ const { ids, url } = options;
3869
+ const baseUrl = url || this.resource;
3870
+ const finalUrl = this.buildUrl(baseUrl, 'bulk');
3871
+ const config = {
3114
3872
  method: "DELETE",
3115
- url: `${this.resource}/bulk`,
3873
+ url: finalUrl,
3116
3874
  data: { ids },
3117
3875
  headers: this.headers,
3118
- }, options);
3876
+ };
3877
+ return this.executeFetch(config);
3119
3878
  }
3120
3879
  /**
3121
- * Upsert method that decides whether to create or update based on the presence of 'id'.
3122
- *
3123
- * @param data The data for the item to create or update.
3124
- * @param options Additional options for the fetch function.
3125
- * @returns The result of the fetch function (typically a promise).
3880
+ * Creates a new item or updates an existing one, based on the presence of an `id` property in the data.
3881
+ * @template TResponse The expected response type
3882
+ * @template TData The type of data to send (must have optional id)
3883
+ * @param options - Options including data, options, and optional url override
3884
+ * @returns A promise that resolves with the response data
3126
3885
  */
3127
- static upsert(data, options = {}) {
3128
- if (data.id) {
3129
- return this.update(data.id, data, options);
3886
+ static upsert(options) {
3887
+ if (options.data.id) {
3888
+ return this.update({
3889
+ id: options.data.id,
3890
+ data: options.data,
3891
+ url: options.url,
3892
+ });
3130
3893
  }
3131
3894
  else {
3132
- return this.create(data, options);
3895
+ return this.create({
3896
+ data: options.data,
3897
+ url: options.url,
3898
+ });
3133
3899
  }
3134
3900
  }
3135
3901
  /**
3136
- * Custom request method for more flexibility.
3137
- *
3138
- * @param method HTTP method (GET, POST, etc.).
3139
- * @param url The custom URL for the request.
3140
- * @param params Query parameters.
3141
- * @param data Request body data.
3142
- * @param options Additional options for the fetch function.
3143
- * @returns The result of the fetch function (typically a promise).
3902
+ * Makes a custom HTTP request, providing full flexibility over the method, URL, and data.
3903
+ * @template TResponse The expected response type
3904
+ * @template TParams The type of query parameters
3905
+ * @template TData The type of request body data
3906
+ * @param options - Options including method, url, params, data, and options
3907
+ * @returns A promise that resolves with the response data
3144
3908
  */
3145
- static customRequest(method, url, params, data, options = {}) {
3909
+ static customRequest(options) {
3910
+ const { method, url, params, data } = options;
3146
3911
  const transformedData = this.transformData(data);
3147
- return this.fetchFn({
3912
+ const config = {
3148
3913
  method: method,
3149
3914
  url: url,
3150
3915
  params: params,
@@ -3155,17 +3920,20 @@ class RestStd {
3155
3920
  ? ContentTypeEnum.FORM_DATA
3156
3921
  : ContentTypeEnum.JSON,
3157
3922
  },
3158
- }, options);
3923
+ };
3924
+ return this.executeFetch(config);
3159
3925
  }
3160
3926
  }
3161
3927
 
3162
3928
  /**
3163
- * Custom composable function for making API requests with Axios.
3929
+ * A composable function that executes an Axios request and returns the response data.
3930
+ * It simplifies making API calls by wrapping the Axios request in a reusable function.
3164
3931
  *
3165
- * @template T The expected return type of the API request.
3166
- * @param {AxiosInstance} axios - The Axios instance for making HTTP requests.
3167
- * @param {AxiosRequestConfig} axiosRequest - Configuration for the Axios request.
3168
- * @returns {Promise<T>} A promise with the result of the API request.
3932
+ * @template T The expected type of the response data.
3933
+ * @param {AxiosInstance} axios - The Axios instance to use for making the request.
3934
+ * @param {AxiosRequestConfig} axiosRequest - The configuration for the Axios request (e.g., URL, method, headers).
3935
+ * @returns {Promise<T>} A promise that resolves with the data from the Axios response.
3936
+ * @throws {Error} Throws an error if the Axios request fails.
3169
3937
  */
3170
3938
  async function axiosFetch(axios, axiosRequest) {
3171
3939
  return axios(axiosRequest)
@@ -3176,10 +3944,19 @@ async function axiosFetch(axios, axiosRequest) {
3176
3944
  }
3177
3945
 
3178
3946
  /**
3179
- * Creates a fetchFn for Axios requests with an optional custom instance.
3180
- * @param fetchComposable - The fn to use for the request (can be any fetch function).
3181
- * @param axiosCustomInstance - An optional custom Axios instance to use for the request.
3182
- * @returns A function that handles the request using the provided fn.
3947
+ * A factory function that creates a reusable query function for making API requests.
3948
+ * It abstracts the Axios instance creation and allows for a custom instance to be provided.
3949
+ * This is particularly useful for creating typed query functions for use with libraries like Vue Query.
3950
+ *
3951
+ * @template TQueryFnData The expected data type of the query function's response.
3952
+ * @template TData The expected data type of the transformed data.
3953
+ * @param {Function} fetchFn - The underlying function that will be called to perform the fetch operation.
3954
+ * This function should accept an Axios instance, Axios request configuration, and optional query options.
3955
+ * @param {AxiosInstance} [axiosCustomInstance] - An optional custom Axios instance to use for the request.
3956
+ * If not provided, a default configured instance will be used.
3957
+ * @returns {(axiosRequestConfig: AxiosRequestConfig, options?: UseQueryOptions<TQueryFnData, Error, TData>) => any}
3958
+ * A new function that takes Axios request configuration and optional query options, and when executed,
3959
+ * performs the API request using the configured `fetchFn`.
3183
3960
  */
3184
3961
  function useFetch(fetchFn, axiosCustomInstance) {
3185
3962
  const instance = axiosCustomInstance || getConfiguredAxiosInstance();
@@ -3188,131 +3965,20 @@ function useFetch(fetchFn, axiosCustomInstance) {
3188
3965
  };
3189
3966
  }
3190
3967
 
3191
- /**
3192
- * Custom composable for integrating Axios requests with Vue Query.
3193
- *
3194
- * @template T - The type of data expected from the query.
3195
- * @param {AxiosInstance} axios - Axios instance used for making HTTP requests.
3196
- * @param {AxiosRequestConfig} axiosRequest - Initial Axios request configuration.
3197
- * @param {ExtendedQueryOptions<T>} [queryOptions] - Optional Vue Query options with server execution flag.
3198
- * @returns {object} Composable functions and query state for managing API requests.
3199
- */
3200
- function useVueQuery(axios, axiosRequest, queryOptions) {
3201
- const key = ref([
3202
- queryOptions?.queryKey || `${axiosRequest.url}-${JSON.stringify(axiosRequest)}`
3203
- ]);
3204
- const axiosRequestRef = ref(axiosRequest);
3205
- const queryOptionsRef = ref(queryOptions);
3206
- const isInitialized = ref(false);
3207
- const errorCallbacks = ref([]);
3208
- const resultCallbacks = ref([]);
3209
- /**
3210
- * Vue Query instance for managing API requests.
3211
- */
3212
- const query = useQuery({
3213
- queryKey: key.value,
3214
- queryFn: async () => {
3215
- const response = await axios(axiosRequestRef.value);
3216
- return response.data;
3217
- },
3218
- ...(queryOptionsRef.value?.options ?? {})
3219
- });
3220
- /**
3221
- * Executes the query manually with optional new key and request parameters.
3222
- *
3223
- * @param {Array<any>} [newKey] - New query key to use.
3224
- * @param {object} [newRequestParams] - New request parameters to use.
3225
- * @param {ExtendedQueryOptions<T>} [newQueryOptions] - New Vue Query options to use.
3226
- */
3227
- function execute(newKey, newRequestParams, newQueryOptions) {
3228
- if (newKey) {
3229
- key.value = newKey;
3230
- }
3231
- if (newRequestParams) {
3232
- axiosRequestRef.value.data = newRequestParams;
3233
- }
3234
- if (newQueryOptions) {
3235
- queryOptionsRef.value = newQueryOptions;
3236
- }
3237
- query.refetch();
3238
- }
3239
- /**
3240
- * Registers a callback to be executed on successful request result.
3241
- * If data is already available, the callback will be executed immediately.
3242
- *
3243
- * @param {(data: T) => void} cb - Callback function to handle the result.
3244
- */
3245
- function onResult(cb) {
3246
- resultCallbacks.value.push(cb);
3247
- if (query.data.value !== undefined && query.data.value !== null) {
3248
- cb(query.data.value);
3249
- }
3250
- }
3251
- /**
3252
- * Registers a callback to be executed when the request results in an error.
3253
- * If an error is already present, the callback will be executed immediately.
3254
- *
3255
- * @param {(e: unknown) => void} callback - Callback function to handle errors.
3256
- */
3257
- function onError(callback) {
3258
- errorCallbacks.value.push(callback);
3259
- if (query.error.value !== undefined) {
3260
- callback(query.error.value);
3261
- }
3262
- }
3263
- /**
3264
- * Watches for changes in the query result and triggers result callbacks.
3265
- */
3266
- watch(query.data, (newData) => {
3267
- if (newData !== undefined && newData !== null && isInitialized.value) {
3268
- resultCallbacks.value.forEach((cb) => cb(newData));
3269
- }
3270
- });
3271
- /**
3272
- * Watches for changes in query errors and triggers error callbacks.
3273
- */
3274
- watch(query.error, (newError) => {
3275
- if (newError !== undefined && isInitialized.value) {
3276
- errorCallbacks.value.forEach((cb) => cb(newError));
3277
- }
3278
- });
3279
- /**
3280
- * Handles server-side prefetching for SSR.
3281
- * Ensures data is fetched before rendering on the server.
3282
- */
3283
- onServerPrefetch(async () => {
3284
- if (queryOptionsRef.value?.server !== false) {
3285
- await query.suspense();
3286
- if (query.data.value != null) {
3287
- resultCallbacks.value.forEach((cb) => cb(query.data.value));
3288
- }
3289
- }
3290
- });
3291
- /**
3292
- * Ensures callbacks are executed after the component is mounted on the client-side.
3293
- */
3294
- onMounted(() => {
3295
- isInitialized.value = true;
3296
- if (query.data.value != null) {
3297
- resultCallbacks.value.forEach((cb) => cb(query.data.value));
3298
- }
3299
- if (query.error.value !== undefined) {
3300
- errorCallbacks.value.forEach((cb) => cb(query.error.value));
3301
- }
3302
- });
3303
- return {
3304
- execute,
3305
- onResult,
3306
- onError,
3307
- ...query
3308
- };
3309
- }
3310
-
3311
3968
  let notified = false;
3312
3969
  /**
3313
- * Composable to manage breakpoints using Tailwind CSS and shared window resize listener.
3970
+ * A composable that provides a reactive interface to Tailwind CSS breakpoints using `@vueuse/core`.
3971
+ * It simplifies working with responsive layouts by offering a set of reactive booleans for different
3972
+ * screen sizes and combinations. On its first invocation, it also logs the current device type (Mobile,
3973
+ * Tablet, Laptop, or Desktop) to the console for easier debugging during development.
3314
3974
  *
3315
- * @returns {Object} An object containing the breakpoints and their states.
3975
+ * @returns {object} An object containing various reactive properties for screen sizes, window dimensions, and breakpoint utilities, including:
3976
+ * - `current`: A ref to the current breakpoint name.
3977
+ * - `active`: A ref to the currently active breakpoint name.
3978
+ * - `sm_S`, `md_GE`, etc.: A series of refs indicating if the screen is smaller than, greater than or equal to, or between specific breakpoints.
3979
+ * - `mobile`, `tablet`, `laptop`, `desktop`: Refs that are true for common device width ranges.
3980
+ * - `windowWidth`, `windowHeight`: Reactive refs for the window's width and height.
3981
+ * - `breakpoints`: The original `useBreakpoints` return object from `@vueuse/core`.
3316
3982
  */
3317
3983
  function useBreakpoint() {
3318
3984
  const breakpoints = useBreakpoints(breakpointsTailwind);
@@ -3424,15 +4090,20 @@ function useBreakpoint() {
3424
4090
  }
3425
4091
 
3426
4092
  /**
3427
- * A composable function that filters objects based on a specific field and criteria.
4093
+ * A composable function that filters an array of objects based on a specified field, data type, and criteria.
4094
+ * It supports filtering by date range, string matching (case-insensitive and diacritic-insensitive), number range, and boolean values.
3428
4095
  *
3429
- * @param {Object[]} items - The list of objects to filter.
3430
- * @param {Object} filterConfig - Configuration for the filter, specifying the field, the data type to filter, and the criteria.
3431
- * @param {string} filterConfig.field - The field in the objects to filter.
3432
- * @param {string} filterConfig.type - The data type of the field ('date', 'string', 'number', 'boolean').
3433
- * @param {any} filterConfig.criteria - The criteria for filtering. Can be a date range, a string to search, a number range, or a boolean value.
3434
- *
3435
- * @returns {Object[]} - The filtered list of objects.
4096
+ * @template T A generic type that extends a record of string keys to any value, representing the objects in the array.
4097
+ * @param {T[]} items - The array of objects to be filtered.
4098
+ * @param {object} filterConfig - The configuration object for filtering.
4099
+ * @param {string} filterConfig.field - The name of the field in the objects to filter by.
4100
+ * @param {'date' | 'string' | 'number' | 'boolean'} filterConfig.type - The data type of the field to be filtered.
4101
+ * @param {any} filterConfig.criteria - The criteria for filtering, which varies based on the `type`:
4102
+ * - For 'date': An object `{ startDate: string, endDate: string }`.
4103
+ * - For 'string': A string to search for.
4104
+ * - For 'number': An object `{ min: number, max: number }`.
4105
+ * - For 'boolean': A boolean value.
4106
+ * @returns {T[]} The filtered array of objects. If the criteria are invalid or not provided, the original array is returned.
3436
4107
  */
3437
4108
  function useFilter(items, filterConfig) {
3438
4109
  // Ensure the filterConfig is correctly structured
@@ -3481,12 +4152,20 @@ function useFilter(items, filterConfig) {
3481
4152
  }
3482
4153
 
3483
4154
  /**
3484
- * Composable to handle pagination logic.
4155
+ * A composable that provides pagination logic based on reactive refs for the current page,
4156
+ * total number of items, and items per page.
3485
4157
  *
3486
- * @param page - Reactive ref for the current page number.
3487
- * @param total - Reactive ref for total number of items.
3488
- * @param pageSize - Reactive ref for number of items per page.
3489
- * @returns An object with pagination controls.
4158
+ * @param {Ref<number>} page - A reactive ref representing the current page number.
4159
+ * @param {Ref<number>} total - A reactive ref representing the total number of items to be paginated.
4160
+ * @param {Ref<number>} pageSize - A reactive ref representing the number of items per page.
4161
+ * @returns {{
4162
+ * totalPages: import('vue').ComputedRef<number>,
4163
+ * canFetchNextPage: () => boolean,
4164
+ * canFetchPreviousPage: () => boolean
4165
+ * }} An object containing:
4166
+ * - `totalPages`: A computed property that calculates the total number of pages.
4167
+ * - `canFetchNextPage`: A function that returns `true` if there is a next page.
4168
+ * - `canFetchPreviousPage`: A function that returns `true` if there is a previous page.
3490
4169
  */
3491
4170
  function usePagination(page, total, pageSize) {
3492
4171
  // Calculate the total number of pages
@@ -3503,11 +4182,16 @@ function usePagination(page, total, pageSize) {
3503
4182
  }
3504
4183
 
3505
4184
  /**
3506
- * Custom composable for sorting products based on a selected criterion.
3507
- * @param {Array} items - The array of products to sort.
3508
- * @param {Array} criteriaList - The list of available sorting criteria.
3509
- * @param {Number} selectedCriteria - The currently selected sorting criterion.
3510
- * @returns {ComputedRef<Array>} - The sorted array of products.
4185
+ * A composable that sorts an array of objects based on a selected criterion from a list of predefined sorting options.
4186
+ * It supports sorting by number, date, boolean, and string fields, in both ascending and descending order.
4187
+ *
4188
+ * @template T The type of items in the array.
4189
+ * @param {T[]} items - The array of objects to sort.
4190
+ * @param {Array<{value: number, label: string, field: string, order: string, type: string}>} criteriaList - A list of
4191
+ * sorting criteria objects. Each object defines a sorting option with a unique `value`, a `label` for display, the `field`
4192
+ * to sort by, the `order` ('asc' or 'desc'), and the data `type` ('number', 'date', 'boolean', 'string').
4193
+ * @param {number} selectedCriteria - The `value` of the currently selected sorting criterion from the `criteriaList`.
4194
+ * @returns {ComputedRef<T[]>} A computed ref containing the sorted items. If the selected criterion is not found, the original array is returned.
3511
4195
  */
3512
4196
  function useSorter(items, criteriaList, selectedCriteria) {
3513
4197
  return computed(() => {
@@ -3539,36 +4223,58 @@ function useSorter(items, criteriaList, selectedCriteria) {
3539
4223
  return criteria.order === 'asc' ? strA.localeCompare(strB) : strB.localeCompare(strA);
3540
4224
  }
3541
4225
  });
3542
- }).value;
4226
+ });
3543
4227
  }
3544
4228
 
3545
4229
  /**
3546
4230
  * Custom hook for authentication logic, including login, logout, token management, and session preference.
4231
+ * Accepts an optional fetcher function. If not provided, uses the default configured fetcher or falls back to Axios.
4232
+ *
4233
+ * @param {Fetcher} [fetcher] - Optional fetcher function to use for auth requests. If not provided, uses the default configured fetcher.
4234
+ * @returns {{
4235
+ * logout: (params?: Record<string, unknown>) => Promise<void>,
4236
+ * login: (params: Record<string, unknown>, persistence: LocationPreference, tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>
4237
+ * }} An object containing authentication functions.
3547
4238
  *
3548
- * @param {string} secretKey - The secret key used for token encryption/decryption.
3549
- * @returns {AuthHook} An object containing authentication functions.
4239
+ * @example
4240
+ * ```typescript
4241
+ * // Using default fetcher (Axios)
4242
+ * const auth = useAuth();
4243
+ *
4244
+ * // Using custom fetcher
4245
+ * const customFetcher = createOfetchFetcher();
4246
+ * const auth = useAuth(customFetcher);
4247
+ * ```
3550
4248
  */
3551
- function useAuth() {
3552
- const axiosInstance = getConfiguredAxiosInstance();
4249
+ function useAuth(fetcher) {
3553
4250
  const endpoints = getEndpointsConfig();
4251
+ const getFetcher = () => {
4252
+ return fetcher || getDefaultAuthFetcher();
4253
+ };
3554
4254
  /**
3555
4255
  * Logs out the user by making a POST request to the logout endpoint,
3556
4256
  * cleaning all stored credentials, and reloading the page.
3557
4257
  * The session persistence preference is NOT reset here; it persists across logouts.
3558
4258
  *
3559
- * @param {AuthParams} [params={}] - Optional parameters to send with the logout request.
4259
+ * @param {Record<string, unknown>} [params={}] - Optional parameters to send with the logout request.
3560
4260
  * @returns {Promise<void>}
3561
4261
  */
3562
4262
  const logout = async (params = {}) => {
3563
4263
  try {
3564
- await axiosInstance.post(endpoints.LOGOUT, params);
4264
+ await getFetcher()({
4265
+ method: 'POST',
4266
+ url: endpoints.LOGOUT,
4267
+ data: params,
4268
+ });
3565
4269
  }
3566
4270
  catch (error) {
3567
- handleError(error, false);
4271
+ handleError(error);
3568
4272
  }
3569
4273
  finally {
3570
4274
  await cleanCredentials(await getSessionPersistence());
3571
- window.location.reload();
4275
+ if (typeof window !== 'undefined') {
4276
+ window.location.reload();
4277
+ }
3572
4278
  }
3573
4279
  };
3574
4280
  /**
@@ -3583,7 +4289,11 @@ function useAuth() {
3583
4289
  */
3584
4290
  const login = async (params = {}, persistence, tokenPaths = getTokenPathsConfig()) => {
3585
4291
  try {
3586
- const { data } = await axiosInstance.post(endpoints.LOGIN, params);
4292
+ const data = await getFetcher()({
4293
+ method: 'POST',
4294
+ url: endpoints.LOGIN,
4295
+ data: params,
4296
+ });
3587
4297
  const { accessToken, refreshToken } = extractAndValidateTokens(data, tokenPaths, "LOGIN");
3588
4298
  configSession({
3589
4299
  persistencePreference: persistence,
@@ -3592,7 +4302,7 @@ function useAuth() {
3592
4302
  return data;
3593
4303
  }
3594
4304
  catch (error) {
3595
- handleError(error, false);
4305
+ handleError(error);
3596
4306
  throw error;
3597
4307
  }
3598
4308
  };
@@ -3602,17 +4312,63 @@ function useAuth() {
3602
4312
  };
3603
4313
  }
3604
4314
 
4315
+ // @ts-ignore - ofetch is an optional peer dependency
4316
+ /**
4317
+ * Creates a fetcher function using ofetch.
4318
+ *
4319
+ * @param baseURL - Optional base URL for requests
4320
+ * @param defaultOptions - Optional default options for ofetch
4321
+ * @returns A fetcher function compatible with RestStd
4322
+ *
4323
+ * @example
4324
+ * ```typescript
4325
+ * import { createOfetchFetcher, RestStd } from '@arex95/vue-core';
4326
+ *
4327
+ * export class Role extends RestStd {
4328
+ * static override resource = 'roles';
4329
+ * static fetchFn = createOfetchFetcher('https://api.example.com');
4330
+ * }
4331
+ * ```
4332
+ *
4333
+ * @example
4334
+ * ```typescript
4335
+ * import { createFetch } from 'ofetch';
4336
+ * import { createOfetchFetcher, RestStd } from '@arex95/vue-core';
4337
+ *
4338
+ * const ofetchInstance = createFetch({ baseURL: 'https://api.example.com' });
4339
+ *
4340
+ * export class Role extends RestStd {
4341
+ * static override resource = 'roles';
4342
+ * static fetchFn = createOfetchFetcher(undefined, { fetch: ofetchInstance });
4343
+ * }
4344
+ * ```
4345
+ */
4346
+ function createOfetchFetcher(baseURL, defaultOptions) {
4347
+ return async (config) => {
4348
+ const url = baseURL
4349
+ ? `${baseURL.replace(/\/$/, '')}/${config.url.replace(/^\//, '')}`
4350
+ : config.url;
4351
+ return $fetch(url, {
4352
+ method: config.method,
4353
+ query: config.params,
4354
+ body: config.data,
4355
+ headers: config.headers,
4356
+ ...defaultOptions,
4357
+ });
4358
+ };
4359
+ }
4360
+
3605
4361
  /**
3606
- * The Vue plugin for @arex95/vue-core.
3607
- * Configures the core functionalities for authentication and API communication.
4362
+ * A Vue plugin that serves as the entry point for the `@arex95/vue-core` library.
4363
+ * It initializes and configures all the core modules, such as authentication, API communication,
4364
+ * and token management, based on the provided options.
3608
4365
  */
3609
4366
  const ArexVueCore = {
3610
4367
  /**
3611
- * The `install` method is the entry point for the Vue plugin.
3612
- * It is automatically called when `app.use(ArexVueCore, options)` is executed.
4368
+ * The `install` method required by Vue's plugin system. It is called when `app.use()` is invoked.
3613
4369
  *
3614
- * @param app The Vue application instance.
3615
- * @param options The configuration options provided by the user.
4370
+ * @param {App} app - The Vue application instance.
4371
+ * @param {ArexVueCoreOptions} options - The configuration object for the library.
3616
4372
  */
3617
4373
  install: (app, options) => {
3618
4374
  if (!options) {
@@ -3648,4 +4404,4 @@ const ArexVueCore = {
3648
4404
  },
3649
4405
  };
3650
4406
 
3651
- export { AppTypes, ArchiveTypes, ArexVueCore, AudioTypes, AxiosService, ContentTypeEnum, DocumentTypes, ERROR_MESSAGES, ERROR_STYLES, ErrorEnum, ErrorMessages, ErrorStyles, ExceptionEnum, FontTypes, ImageTypes, KeyCodeEnum, OtherTypes, RestStd, ScreenBreakpoint, ScreenSize, StorageKeyEnum, StorageTypeEnum, TextTypes, VideoTypes, ab2hex, addCustomKeyboardShortcut, addDays, addDoubleClickListener, addKeyListener, ageAtDate, axiosFetch, blobToFormData, bufferToBlob, calculateAge, cleanCredentials, clickOutside, compareObject, configAppKey, configAxios, configEndpoints, configRefreshTokenPaths, configSession, configTokenKeys, configTokenPaths, copyToClipboard, countWords, createKeyMap, customShortcut, daysBetween, daysToNextBirthday, debounce, debounceAsync, debounceAsyncValidator, debounceAsyncWithImmediate, debounceLeading, debounceLeadingTrailing, debounceTrailing, decrypt, deepClone, deepEqual, deepMerge, detectKeyHold, disableCopy, disableF12Key, disableMouseButtons, disableRightClick, disableSpecificKeys, downloadBlob, enableMouseButtons, enableRightClick, enableSpecificKeys, encrypt, exportToCSV, exportToExcel, exportToJSON, exportToText, exportToXML, extractAndValidateTokens, filterObjectByKeys, flattenObject, formDataToObject, formatDate, generateRandomString, getAppKey, getAuthRefreshToken, getAuthToken, getConfiguredAxiosInstance, getDecryptedItem, getEndOfMonth, getEndpointsConfig, getObjectDifferences, getObjectKeys, getQueryParam, getRefreshTokenPathsConfig, getSessionConfig, getSessionId, getSessionPersistence, getStartOfMonth, getTokenConfig, getTokenPathsConfig, handleError, hasNestedProperties, hex2ab, importKey, isEmptyObject, isLeapYear, isStrongPassword, isValidAge, isValidCreditCard, isValidDate, isValidEmail, isValidExpiryDate, isValidHexColor, isValidHexColorAlpha, isValidHexNumber, isValidIP, isValidPhoneNumber, isValidSSN, isValidTime, isValidURL, isValidUsername, isValidZIP, lowerFirst, objectToFormData, objectToFormDataEnhanced, objectToQueryString, openWindow, parseDate, proxyToPlainObject, readFileAsDataURL, readFileAsText, refreshTokens, registerKeyboardShortcuts, removeAccent, removeClickOutside, removeCustomKeyboardShortcut, removeCustomShortcuts, removeDoubleClickListener, removeEmptyProperties, removeKeyListeners, replaceAll, reverseString, safeGet, screenMap, scrollToTop, simulateKeyPress, stopDetectingKeyHold, storeAuthRefreshToken, storeAuthToken, storeEncryptedItem, storeTokens, stringToBlob, subtractDays, throttle, toCamelCase, toKebabCase, toggleTabNavigation, truncateString, unregisterKeyboardShortcuts, upperFirst, useAuth, useBreakpoint, useFetch, useFilter, usePagination, useSorter, useVueQuery, validateAlphanumeric, validateLetters, validateNumbers, verifyAuth };
4407
+ export { AppTypes, ArchiveTypes, ArexVueCore, AudioTypes, AuthError, AxiosService, BaseError, ContentTypeEnum, DocumentTypes, ERROR_MESSAGES, ERROR_STYLES, ErrorEnum, ErrorMessages, ErrorStyles, ExceptionEnum, FontTypes, ImageTypes, KeyCodeEnum, NetworkError, OtherTypes, RestStd, ScreenBreakpoint, ScreenSize, ServerError, StorageKeyEnum, StorageTypeEnum, TextTypes, ValidationError, VideoTypes, ab2hex, addCustomKeyboardShortcut, addDays, addDoubleClickListener, addKeyListener, ageAtDate, axiosFetch, blobToFormData, bufferToBlob, calculateAge, cleanCredentials, clickOutside, compareObject, configAppKey, configAuthFetcher, configAxios, configEndpoints, configRefreshTokenPaths, configSession, configTokenKeys, configTokenPaths, copyToClipboard, countWords, createAxiosFetcher, createKeyMap, createOfetchFetcher, customShortcut, daysBetween, daysToNextBirthday, debounce, debounceAsync, debounceAsyncValidator, debounceAsyncWithImmediate, debounceLeading, debounceLeadingTrailing, debounceTrailing, decrypt, deepClone, deepEqual, deepMerge, detectKeyHold, disableCopy, disableF12Key, disableMouseButtons, disableRightClick, disableSpecificKeys, downloadBlob, enableMouseButtons, enableRightClick, enableSpecificKeys, encrypt, exportToCSV, exportToExcel, exportToJSON, exportToText, exportToXML, extractAndValidateTokens, filterObjectByKeys, flattenObject, formDataToObject, formatDate, generateRandomString, getAppKey, getAuthRefreshToken, getAuthToken, getConfiguredAxiosInstance, getCookieStorage, getDecryptedItem, getDefaultAuthFetcher, getEndOfMonth, getEndpointsConfig, getObjectDifferences, getObjectKeys, getPreferredStorage, getQueryParam, getRefreshTokenPathsConfig, getSessionConfig, getSessionId, getSessionPersistence, getSessionStorage, getStartOfMonth, getStorage, getTokenConfig, getTokenPathsConfig, handleError, hasNestedProperties, hex2ab, importKey, isClient, isEmptyObject, isLeapYear, isServer, isStrongPassword, isValidAge, isValidCreditCard, isValidDate, isValidEmail, isValidExpiryDate, isValidHexColor, isValidHexColorAlpha, isValidHexNumber, isValidIP, isValidPhoneNumber, isValidSSN, isValidTime, isValidURL, isValidUsername, isValidZIP, lowerFirst, objectToFormData, objectToFormDataEnhanced, objectToQueryString, openWindow, parseDate, proxyToPlainObject, readFileAsDataURL, readFileAsText, refreshTokens, registerKeyboardShortcuts, removeAccent, removeClickOutside, removeCustomKeyboardShortcut, removeCustomShortcuts, removeDoubleClickListener, removeEmptyProperties, removeKeyListeners, replaceAll, retryWithBackoff, reverseString, safeGet, screenMap, scrollToTop, setDefaultAuthFetcherFactory, simulateKeyPress, stopDetectingKeyHold, storeAuthRefreshToken, storeAuthToken, storeEncryptedItem, storeTokens, stringToBlob, subtractDays, throttle, toCamelCase, toKebabCase, toggleTabNavigation, truncateString, unregisterKeyboardShortcuts, upperFirst, useAuth, useBreakpoint, useFetch, useFilter, usePagination, useSorter, validateAlphanumeric, validateLetters, validateNumbers, verifyAuth };