@arex95/vue-core 1.1.43 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +14 -0
  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 +1633 -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,113 @@ 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 to avoid circular dependency
1998
+ const { setDefaultAuthFetcherFactory } = require("@/config/auth/authFetcher");
1999
+ const { createAxiosFetcher } = require("@/fetchers/axios");
2000
+ setDefaultAuthFetcherFactory(() => {
2001
+ return createAxiosFetcher(axiosServiceInstance.getAxiosInstance());
2002
+ });
1536
2003
  };
2004
+ /**
2005
+ * Retrieves the configured singleton Axios instance.
2006
+ * If not configured yet, creates a default instance with minimal configuration.
2007
+ * This allows lazy initialization to avoid dependency circular issues in Nuxt and other frameworks.
2008
+ *
2009
+ * @returns {AxiosInstance} The configured Axios instance.
2010
+ */
1537
2011
  const getConfiguredAxiosInstance = () => {
1538
2012
  if (!axiosServiceInstance) {
1539
- throw new Error("Axios instance not configured. Call configAxios first.");
2013
+ if (defaultConfig) {
2014
+ axiosServiceInstance = new AxiosService({
2015
+ baseURL: defaultConfig.baseURL,
2016
+ headers: defaultConfig.headers,
2017
+ timeout: defaultConfig.timeout,
2018
+ withCredentials: defaultConfig.withCredentials
2019
+ });
2020
+ }
2021
+ else {
2022
+ axiosServiceInstance = new AxiosService({
2023
+ baseURL: '',
2024
+ headers: {},
2025
+ timeout: 30000,
2026
+ withCredentials: false
2027
+ });
2028
+ }
2029
+ // Configure auth fetcher factory to avoid circular dependency
2030
+ const { setDefaultAuthFetcherFactory } = require("@/config/auth/authFetcher");
2031
+ const { createAxiosFetcher } = require("@/fetchers/axios");
2032
+ setDefaultAuthFetcherFactory(() => {
2033
+ return createAxiosFetcher(axiosServiceInstance.getAxiosInstance());
2034
+ });
1540
2035
  }
1541
2036
  return axiosServiceInstance.getAxiosInstance();
1542
2037
  };
1543
2038
 
1544
2039
  /**
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.
2040
+ * Triggers a browser download for a file created from a `Blob` object.
2041
+ *
2042
+ * @param {Blob} blob - The `Blob` containing the file's data.
2043
+ * @param {string} fileName - The desired name for the downloaded file.
1548
2044
  */
1549
2045
  function downloadFile(blob, fileName) {
1550
2046
  const link = document.createElement('a');
@@ -1559,10 +2055,11 @@ function downloadFile(blob, fileName) {
1559
2055
  URL.revokeObjectURL(url);
1560
2056
  }
1561
2057
  /**
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.
2058
+ * Converts an array of data into a CSV format and triggers a download.
2059
+ *
2060
+ * @param {string[]} headers - An array of strings to be used as the CSV header row.
2061
+ * @param {any[][]} data - A 2D array representing the rows and cells of the data to be exported.
2062
+ * @param {string} fileName - The desired name for the downloaded CSV file.
1566
2063
  */
1567
2064
  function exportToCSV(headers, data, fileName) {
1568
2065
  const csvRows = [];
@@ -1579,10 +2076,11 @@ function exportToCSV(headers, data, fileName) {
1579
2076
  downloadFile(blob, fileName);
1580
2077
  }
1581
2078
  /**
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.
2079
+ * Converts an array of data into an HTML table, then triggers a download as an Excel (.xls) file.
2080
+ *
2081
+ * @param {string[]} headers - An array of strings for the table headers.
2082
+ * @param {any[][]} data - A 2D array of the data to be exported.
2083
+ * @param {string} fileName - The desired name for the downloaded Excel file.
1586
2084
  */
1587
2085
  function exportToExcel(headers, data, fileName) {
1588
2086
  // Create a table element
@@ -1611,9 +2109,10 @@ function exportToExcel(headers, data, fileName) {
1611
2109
  downloadFile(blob, fileName);
1612
2110
  }
1613
2111
  /**
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.
2112
+ * Converts an array of data into a pretty-printed JSON string and triggers a download.
2113
+ *
2114
+ * @param {any[]} data - The data to be serialized into JSON.
2115
+ * @param {string} fileName - The desired name for the downloaded JSON file.
1617
2116
  */
1618
2117
  function exportToJSON(data, fileName) {
1619
2118
  const jsonContent = JSON.stringify(data, null, 2); // Pretty print with 2 spaces
@@ -1622,10 +2121,11 @@ function exportToJSON(data, fileName) {
1622
2121
  downloadFile(blob, fileName);
1623
2122
  }
1624
2123
  /**
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.
2124
+ * Converts an array of data into a simple XML format and triggers a download.
2125
+ *
2126
+ * @param {string[]} headers - An array of strings to be used as column headers in the XML.
2127
+ * @param {any[][]} data - A 2D array of the data to be exported.
2128
+ * @param {string} fileName - The desired name for the downloaded XML file.
1629
2129
  */
1630
2130
  function exportToXML(headers, data, fileName) {
1631
2131
  let xmlContent = '<?xml version="1.0" encoding="UTF-8"?>\n<rows>\n';
@@ -1649,10 +2149,11 @@ function exportToXML(headers, data, fileName) {
1649
2149
  downloadFile(blob, fileName);
1650
2150
  }
1651
2151
  /**
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.
2152
+ * Converts an array of data into a tab-separated text format and triggers a download.
2153
+ *
2154
+ * @param {string[]} headers - An array of strings for the header row.
2155
+ * @param {any[][]} data - A 2D array of the data to be exported.
2156
+ * @param {string} fileName - The desired name for the downloaded text file.
1656
2157
  */
1657
2158
  function exportToText(headers, data, fileName) {
1658
2159
  const textRows = [];
@@ -1670,12 +2171,13 @@ function exportToText(headers, data, fileName) {
1670
2171
  }
1671
2172
 
1672
2173
  /**
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.
2174
+ * Opens a new browser window or tab with a specified URL, providing options for the target and security attributes.
2175
+ *
2176
+ * @param {string} url - The URL to open in the new window.
2177
+ * @param {object} [opt] - Optional configuration for the new window.
2178
+ * @param {string} [opt.target='_blank'] - The target attribute for the link, specifying where to open the content (e.g., '_blank', '_self').
2179
+ * @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.
2180
+ * @param {boolean} [opt.noreferrer=true] - If `true`, adds `noreferrer` to prevent the browser from sending the `Referer` HTTP header.
1679
2181
  */
1680
2182
  function openWindow(url, opt) {
1681
2183
  const { target = '__blank', noopener = true, noreferrer = true } = opt || {};
@@ -1689,9 +2191,11 @@ function openWindow(url, opt) {
1689
2191
  window.open(url, target, features.join(','));
1690
2192
  }
1691
2193
  /**
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.
2194
+ * Asynchronously copies a given string to the user's clipboard. It uses the modern `navigator.clipboard` API
2195
+ * with a fallback to the deprecated `document.execCommand` for older browsers.
2196
+ *
2197
+ * @param {string} text - The string to be copied to the clipboard.
2198
+ * @returns {Promise<void>} A promise that resolves when the text has been successfully copied.
1695
2199
  */
1696
2200
  async function copyToClipboard(text) {
1697
2201
  if (navigator.clipboard) {
@@ -1708,8 +2212,10 @@ async function copyToClipboard(text) {
1708
2212
  }
1709
2213
  }
1710
2214
  /**
1711
- * Scrolls the window to the top smoothly.
1712
- * @param {number} [duration=300] Duration of the scroll animation in milliseconds.
2215
+ * Smoothly scrolls the window to the top of the page using a `requestAnimationFrame` loop
2216
+ * for a fluid animation.
2217
+ *
2218
+ * @param {number} [duration=300] - The total duration of the scroll animation in milliseconds.
1713
2219
  */
1714
2220
  function scrollToTop(duration = 300) {
1715
2221
  const start = window.scrollY;
@@ -1725,9 +2231,10 @@ function scrollToTop(duration = 300) {
1725
2231
  requestAnimationFrame(scroll);
1726
2232
  }
1727
2233
  /**
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.
2234
+ * Retrieves the value of a specified query parameter from the current URL's search string.
2235
+ *
2236
+ * @param {string} paramName - The name of the query parameter to retrieve.
2237
+ * @returns {string | null} The value of the query parameter, or `null` if the parameter is not present in the URL.
1731
2238
  */
1732
2239
  function getQueryParam(paramName) {
1733
2240
  const urlParams = new URLSearchParams(window.location.search);
@@ -1735,7 +2242,7 @@ function getQueryParam(paramName) {
1735
2242
  }
1736
2243
 
1737
2244
  /**
1738
- * Disables the right-click context menu on the window.
2245
+ * Disables the default right-click context menu on the entire window.
1739
2246
  */
1740
2247
  function disableRightClick() {
1741
2248
  const handler = (event) => event.preventDefault();
@@ -1745,7 +2252,7 @@ function disableRightClick() {
1745
2252
  }
1746
2253
  disableRightClick.handler = null;
1747
2254
  /**
1748
- * Enables the right-click context menu on the window.
2255
+ * Re-enables the right-click context menu if it was previously disabled by `disableRightClick`.
1749
2256
  */
1750
2257
  function enableRightClick() {
1751
2258
  if (disableRightClick.handler) {
@@ -1753,8 +2260,9 @@ function enableRightClick() {
1753
2260
  }
1754
2261
  }
1755
2262
  /**
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).
2263
+ * Prevents the default action for specific mouse buttons on the `mousedown` event.
2264
+ *
2265
+ * @param {number[]} buttons - An array of mouse button codes to disable (0 for left, 1 for middle, 2 for right).
1758
2266
  */
1759
2267
  function disableMouseButtons(buttons) {
1760
2268
  const handler = (event) => {
@@ -1769,7 +2277,7 @@ function disableMouseButtons(buttons) {
1769
2277
  }
1770
2278
  disableMouseButtons.handlers = [];
1771
2279
  /**
1772
- * Enables all previously disabled mouse buttons.
2280
+ * Re-enables all mouse buttons that were previously disabled by `disableMouseButtons`.
1773
2281
  */
1774
2282
  function enableMouseButtons() {
1775
2283
  for (const handler of disableMouseButtons.handlers) {
@@ -1779,17 +2287,19 @@ function enableMouseButtons() {
1779
2287
  disableMouseButtons.handlers = [];
1780
2288
  }
1781
2289
  /**
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.
2290
+ * Attaches a `dblclick` event listener to a specified HTML element.
2291
+ *
2292
+ * @param {HTMLElement} element - The DOM element to attach the listener to.
2293
+ * @param {(event: MouseEvent) => void} callback - The function to execute when the element is double-clicked.
1785
2294
  */
1786
2295
  function addDoubleClickListener(element, callback) {
1787
2296
  element.addEventListener('dblclick', callback);
1788
2297
  }
1789
2298
  /**
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.
2299
+ * Removes a `dblclick` event listener from a specified HTML element.
2300
+ *
2301
+ * @param {HTMLElement} element - The DOM element to remove the listener from.
2302
+ * @param {(event: MouseEvent) => void} callback - The callback function that was originally added.
1793
2303
  */
1794
2304
  function removeDoubleClickListener(element, callback) {
1795
2305
  element.removeEventListener('dblclick', callback);
@@ -1797,9 +2307,10 @@ function removeDoubleClickListener(element, callback) {
1797
2307
  // Example usage:
1798
2308
  // addDoubleClickListener(document.body, () => alert('Double clicked!'));
1799
2309
  /**
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.
2310
+ * Sets up a global click listener to detect when a user clicks outside of a specified element.
2311
+ *
2312
+ * @param {HTMLElement} element - The element to monitor for outside clicks.
2313
+ * @param {() => void} callback - The function to execute when a click outside the element is detected.
1803
2314
  */
1804
2315
  function clickOutside(element, callback) {
1805
2316
  const handler = (event) => {
@@ -1813,8 +2324,9 @@ function clickOutside(element, callback) {
1813
2324
  }
1814
2325
  clickOutside.handlers = [];
1815
2326
  /**
1816
- * Removes the click outside listener for a specific element.
1817
- * @param {HTMLElement} element The element to stop detecting clicks outside of.
2327
+ * Removes the "click outside" event listener for a specific element that was added by `clickOutside`.
2328
+ *
2329
+ * @param {HTMLElement} element - The element for which to remove the listener.
1818
2330
  */
1819
2331
  function removeClickOutside(element) {
1820
2332
  const index = clickOutside.handlers.findIndex(h => h.element === element);
@@ -1829,7 +2341,8 @@ function removeClickOutside(element) {
1829
2341
  // clickOutside(menu, () => menu.style.display = 'none');
1830
2342
  // }
1831
2343
  /**
1832
- * Disables the F12 key and certain key combinations for developer tools.
2344
+ * Disables the F12 key and common developer tool shortcuts (Ctrl+Shift+I, Ctrl+Shift+J)
2345
+ * to prevent users from easily opening the browser's developer console.
1833
2346
  */
1834
2347
  function disableF12Key() {
1835
2348
  const handler = function (event) {
@@ -1838,8 +2351,9 @@ function disableF12Key() {
1838
2351
  document.addEventListener('keydown', handler);
1839
2352
  }
1840
2353
  /**
1841
- * Enables or disables the tab navigation (Tab key) on the page.
1842
- * @param {boolean} enable Whether to enable or disable tab navigation.
2354
+ * Enables or disables the ability to navigate through focusable elements using the Tab key.
2355
+ *
2356
+ * @param {boolean} enable - If `true`, tab navigation is enabled; if `false`, it is disabled.
1843
2357
  */
1844
2358
  function toggleTabNavigation(enable) {
1845
2359
  if (enable) {
@@ -1856,7 +2370,7 @@ function toggleTabNavigation(enable) {
1856
2370
  }
1857
2371
  }
1858
2372
  /**
1859
- * Disables the copy (Ctrl + C) functionality on the page.
2373
+ * Prevents users from copying content from the page by intercepting the `copy` event.
1860
2374
  */
1861
2375
  function disableCopy() {
1862
2376
  document.addEventListener('copy', (event) => {
@@ -1865,11 +2379,12 @@ function disableCopy() {
1865
2379
  });
1866
2380
  }
1867
2381
  /**
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.
2382
+ * Registers a global keyboard shortcut that triggers a callback when a specific key combination is pressed.
2383
+ *
2384
+ * @param {string} key - The main key for the shortcut (e.g., 'S', 'F1').
2385
+ * @param {() => void} callback - The function to execute when the shortcut is pressed.
2386
+ * @param {boolean} [ctrlKey=false] - If `true`, the Ctrl key must be pressed.
2387
+ * @param {boolean} [shiftKey=false] - If `true`, the Shift key must be pressed.
1873
2388
  */
1874
2389
  function addCustomKeyboardShortcut(key, callback, ctrlKey = false, shiftKey = false) {
1875
2390
  document.addEventListener('keydown', (event) => {
@@ -1882,10 +2397,11 @@ function addCustomKeyboardShortcut(key, callback, ctrlKey = false, shiftKey = fa
1882
2397
  });
1883
2398
  }
1884
2399
  /**
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.
2400
+ * Removes a global keyboard shortcut that was previously added.
2401
+ *
2402
+ * @param {string} key - The main key of the shortcut to remove.
2403
+ * @param {boolean} [ctrlKey=false] - The Ctrl key modifier of the shortcut.
2404
+ * @param {boolean} [shiftKey=false] - The Shift key modifier of the shortcut.
1889
2405
  */
1890
2406
  function removeCustomKeyboardShortcut(key, ctrlKey = false, shiftKey = false) {
1891
2407
  const handler = (event) => {
@@ -1898,8 +2414,9 @@ function removeCustomKeyboardShortcut(key, ctrlKey = false, shiftKey = false) {
1898
2414
  document.removeEventListener('keydown', handler);
1899
2415
  }
1900
2416
  /**
1901
- * Disables specific keys or key combinations.
1902
- * @param {Array<string>} keys Array of key names to disable (e.g., ['F1', 'F5', 'Control+S']).
2417
+ * Disables a list of specified keys or key combinations.
2418
+ *
2419
+ * @param {string[]} keys - An array of key names or combinations (e.g., 'F1', 'Control+S') to disable.
1903
2420
  */
1904
2421
  function disableSpecificKeys(keys) {
1905
2422
  const handler = (event) => {
@@ -1914,7 +2431,7 @@ function disableSpecificKeys(keys) {
1914
2431
  }
1915
2432
  disableSpecificKeys.handlers = [];
1916
2433
  /**
1917
- * Enables keys that were previously disabled using disableSpecificKeys.
2434
+ * Re-enables all keys that were previously disabled by `disableSpecificKeys`.
1918
2435
  */
1919
2436
  function enableSpecificKeys() {
1920
2437
  for (const handler of disableSpecificKeys.handlers) {
@@ -1923,8 +2440,9 @@ function enableSpecificKeys() {
1923
2440
  disableSpecificKeys.handlers = [];
1924
2441
  }
1925
2442
  /**
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.
2443
+ * Registers multiple keyboard shortcuts from an array of shortcut configurations.
2444
+ *
2445
+ * @param {Array<{ key: string; ctrlKey?: boolean; shiftKey?: boolean; altKey?: boolean; callback: () => void }>} shortcuts - An array of shortcut objects.
1928
2446
  */
1929
2447
  function registerKeyboardShortcuts(shortcuts) {
1930
2448
  const handler = (event) => {
@@ -1944,7 +2462,7 @@ function registerKeyboardShortcuts(shortcuts) {
1944
2462
  }
1945
2463
  registerKeyboardShortcuts.handlers = [];
1946
2464
  /**
1947
- * Unregisters all keyboard shortcuts that were registered with registerKeyboardShortcuts.
2465
+ * Removes all keyboard shortcuts that were registered using `registerKeyboardShortcuts`.
1948
2466
  */
1949
2467
  function unregisterKeyboardShortcuts() {
1950
2468
  for (const handler of registerKeyboardShortcuts.handlers) {
@@ -1953,9 +2471,10 @@ function unregisterKeyboardShortcuts() {
1953
2471
  registerKeyboardShortcuts.handlers = [];
1954
2472
  }
1955
2473
  /**
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.
2474
+ * Adds a global `keydown` listener for a specific key.
2475
+ *
2476
+ * @param {string} key - The key to listen for (e.g., 'Enter', 'Escape').
2477
+ * @param {() => void} callback - The function to execute when the key is pressed.
1959
2478
  */
1960
2479
  function addKeyListener(key, callback) {
1961
2480
  const handler = (event) => {
@@ -1970,7 +2489,7 @@ function addKeyListener(key, callback) {
1970
2489
  }
1971
2490
  addKeyListener.handlers = [];
1972
2491
  /**
1973
- * Removes all custom key listeners added by addKeyListener.
2492
+ * Removes all key listeners that were added using `addKeyListener`.
1974
2493
  */
1975
2494
  function removeKeyListeners() {
1976
2495
  for (const handler of addKeyListener.handlers) {
@@ -1979,9 +2498,10 @@ function removeKeyListeners() {
1979
2498
  addKeyListener.handlers = [];
1980
2499
  }
1981
2500
  /**
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.
2501
+ * Executes a callback function repeatedly while a specific key is held down.
2502
+ *
2503
+ * @param {string} key - The key to monitor.
2504
+ * @param {() => void} onHold - The callback function to execute on each `keydown` event for the specified key.
1985
2505
  */
1986
2506
  function detectKeyHold(key, onHold) {
1987
2507
  const keyDownHandler = (event) => {
@@ -1995,7 +2515,7 @@ function detectKeyHold(key, onHold) {
1995
2515
  }
1996
2516
  detectKeyHold.handlers = [];
1997
2517
  /**
1998
- * Stops detecting if a specific key is held down.
2518
+ * Removes all key hold listeners that were added by `detectKeyHold`.
1999
2519
  */
2000
2520
  function stopDetectingKeyHold() {
2001
2521
  for (const handler of detectKeyHold.handlers) {
@@ -2004,8 +2524,9 @@ function stopDetectingKeyHold() {
2004
2524
  detectKeyHold.handlers = [];
2005
2525
  }
2006
2526
  /**
2007
- * Tracks currently pressed keys and provides a map of active keys.
2008
- * @returns {Set<string>} A set of currently pressed keys.
2527
+ * Creates and maintains a `Set` of currently pressed keys.
2528
+ *
2529
+ * @returns {Set<string>} A `Set` that dynamically updates with the keys being pressed.
2009
2530
  */
2010
2531
  function createKeyMap() {
2011
2532
  const pressedKeys = new Set();
@@ -2025,13 +2546,14 @@ function createKeyMap() {
2025
2546
  return pressedKeys;
2026
2547
  }
2027
2548
  /**
2028
- * Clears listeners for the key map tracking.
2549
+ * Clears the `keydown` and `keyup` event listeners created by `createKeyMap`.
2029
2550
  */
2030
2551
  createKeyMap.clearListeners = () => { };
2031
2552
  /**
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.
2553
+ * Sets up a keyboard shortcut that triggers a callback when a specific combination of keys is held down, regardless of order.
2554
+ *
2555
+ * @param {string[]} keys - An array of keys that constitute the shortcut.
2556
+ * @param {() => void} callback - The function to execute when the key combination is active.
2035
2557
  */
2036
2558
  function customShortcut(keys, callback) {
2037
2559
  const pressedKeys = new Set();
@@ -2051,7 +2573,7 @@ function customShortcut(keys, callback) {
2051
2573
  }
2052
2574
  customShortcut.handlers = [];
2053
2575
  /**
2054
- * Removes all custom keyboard shortcuts added by customShortcut.
2576
+ * Removes all keyboard shortcut listeners that were added by `customShortcut`.
2055
2577
  */
2056
2578
  function removeCustomShortcuts() {
2057
2579
  for (const { keyDownHandler, keyUpHandler } of customShortcut.handlers) {
@@ -2061,11 +2583,12 @@ function removeCustomShortcuts() {
2061
2583
  customShortcut.handlers = [];
2062
2584
  }
2063
2585
  /**
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.
2586
+ * Programmatically dispatches a `keydown` event to simulate a key press.
2587
+ *
2588
+ * @param {string} key - The key to simulate (e.g., 'Enter', 'a').
2589
+ * @param {boolean} [ctrlKey=false] - Whether to simulate the Ctrl key being pressed.
2590
+ * @param {boolean} [shiftKey=false] - Whether to simulate the Shift key being pressed.
2591
+ * @param {boolean} [altKey=false] - Whether to simulate the Alt key being pressed.
2069
2592
  */
2070
2593
  function simulateKeyPress(key, ctrlKey = false, shiftKey = false, altKey = false) {
2071
2594
  const event = new KeyboardEvent('keydown', {
@@ -2080,9 +2603,11 @@ function simulateKeyPress(key, ctrlKey = false, shiftKey = false, altKey = false
2080
2603
  }
2081
2604
 
2082
2605
  /**
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.
2606
+ * Parses a date string in the format 'YYYY-MM-DD' and returns a `Date` object.
2607
+ * It includes validation to ensure the parsed date is a valid calendar date.
2608
+ *
2609
+ * @param {string} dateString - The date string to parse.
2610
+ * @returns {Date | null} A `Date` object if the string is a valid date, otherwise `null`.
2086
2611
  */
2087
2612
  function parseDate(dateString) {
2088
2613
  const parts = dateString.split('-');
@@ -2098,9 +2623,11 @@ function parseDate(dateString) {
2098
2623
  return null;
2099
2624
  }
2100
2625
  /**
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').
2626
+ * Formats a `Date` object into a custom string format.
2627
+ * Supported format specifiers: YYYY, MM, DD, HH, mm, ss.
2628
+ *
2629
+ * @param {Date} date - The `Date` object to format.
2630
+ * @param {string} format - The desired string format (e.g., 'YYYY-MM-DD HH:mm:ss').
2104
2631
  * @returns {string} The formatted date string.
2105
2632
  */
2106
2633
  function formatDate(date, format) {
@@ -2115,9 +2642,10 @@ function formatDate(date, format) {
2115
2642
  return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (matched) => (map[matched] || matched).toString());
2116
2643
  }
2117
2644
  /**
2118
- * Calculates the number of days between two dates.
2119
- * @param {Date} startDate The start date.
2120
- * @param {Date} endDate The end date.
2645
+ * Calculates the total number of full days between two dates.
2646
+ *
2647
+ * @param {Date} startDate - The starting date.
2648
+ * @param {Date} endDate - The ending date.
2121
2649
  * @returns {number} The number of days between the two dates.
2122
2650
  */
2123
2651
  function daysBetween(startDate, endDate) {
@@ -2125,10 +2653,11 @@ function daysBetween(startDate, endDate) {
2125
2653
  return Math.round((endDate.getTime() - startDate.getTime()) / millisecondsPerDay);
2126
2654
  }
2127
2655
  /**
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.
2656
+ * Adds a specified number of days to a given date.
2657
+ *
2658
+ * @param {Date} date - The original date.
2659
+ * @param {number} days - The number of days to add (can be negative to subtract).
2660
+ * @returns {Date} A new `Date` object representing the resulting date.
2132
2661
  */
2133
2662
  function addDays(date, days) {
2134
2663
  const result = new Date(date);
@@ -2136,41 +2665,46 @@ function addDays(date, days) {
2136
2665
  return result;
2137
2666
  }
2138
2667
  /**
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.
2668
+ * Subtracts a specified number of days from a given date.
2669
+ *
2670
+ * @param {Date} date - The original date.
2671
+ * @param {number} days - The number of days to subtract.
2672
+ * @returns {Date} A new `Date` object representing the resulting date.
2143
2673
  */
2144
2674
  function subtractDays(date, days) {
2145
2675
  return addDays(date, -days);
2146
2676
  }
2147
2677
  /**
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.
2678
+ * Determines whether a given year is a leap year according to the Gregorian calendar rules.
2679
+ *
2680
+ * @param {number} year - The year to check.
2681
+ * @returns {boolean} `true` if the year is a leap year, otherwise `false`.
2151
2682
  */
2152
2683
  function isLeapYear(year) {
2153
2684
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
2154
2685
  }
2155
2686
  /**
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.
2687
+ * Returns a new `Date` object set to the first day of the month for a given date.
2688
+ *
2689
+ * @param {Date} date - The date from which to determine the month and year.
2690
+ * @returns {Date} A `Date` object representing the start of the month.
2159
2691
  */
2160
2692
  function getStartOfMonth(date) {
2161
2693
  return new Date(date.getFullYear(), date.getMonth(), 1);
2162
2694
  }
2163
2695
  /**
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.
2696
+ * Returns a new `Date` object set to the last day of the month for a given date.
2697
+ *
2698
+ * @param {Date} date - The date from which to determine the month and year.
2699
+ * @returns {Date} A `Date` object representing the end of the month.
2167
2700
  */
2168
2701
  function getEndOfMonth(date) {
2169
2702
  return new Date(date.getFullYear(), date.getMonth() + 1, 0);
2170
2703
  }
2171
2704
  /**
2172
- * Calculates age from a given birth date.
2173
- * @param {Date} birthDate The birth date.
2705
+ * Calculates the current age in years based on a given birth date.
2706
+ *
2707
+ * @param {Date} birthDate - The date of birth.
2174
2708
  * @returns {number} The calculated age.
2175
2709
  */
2176
2710
  function calculateAge(birthDate) {
@@ -2183,8 +2717,9 @@ function calculateAge(birthDate) {
2183
2717
  return age;
2184
2718
  }
2185
2719
  /**
2186
- * Calculates the number of days until the next birthday.
2187
- * @param {Date} birthDate The birth date.
2720
+ * Calculates the number of days from the current date until the next birthday.
2721
+ *
2722
+ * @param {Date} birthDate - The date of birth.
2188
2723
  * @returns {number} The number of days until the next birthday.
2189
2724
  */
2190
2725
  function daysToNextBirthday(birthDate) {
@@ -2198,10 +2733,11 @@ function daysToNextBirthday(birthDate) {
2198
2733
  return daysBetween(today, nextBirthday);
2199
2734
  }
2200
2735
  /**
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.
2736
+ * Calculates the age of a person on a specific date in the past or future.
2737
+ *
2738
+ * @param {Date} birthDate - The date of birth.
2739
+ * @param {Date} atDate - The target date for which to calculate the age.
2740
+ * @returns {number} The age on the specified date.
2205
2741
  */
2206
2742
  function ageAtDate(birthDate, atDate) {
2207
2743
  let age = atDate.getFullYear() - birthDate.getFullYear();
@@ -2213,11 +2749,12 @@ function ageAtDate(birthDate, atDate) {
2213
2749
  }
2214
2750
 
2215
2751
  /**
2216
- * Creates a debounced asynchronous validator function.
2752
+ * Creates a debounced version of an asynchronous validator function. This is useful for scenarios
2753
+ * like form input validation where you want to delay validation until the user has stopped typing.
2217
2754
  *
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.
2755
+ * @param validator - The asynchronous validator function to be debounced. It receives the value to validate and a `debounce` function.
2756
+ * @param {number} delay - The debounce delay in milliseconds.
2757
+ * @returns A new function that takes a value and returns a promise that resolves or rejects based on the debounced validation.
2221
2758
  */
2222
2759
  function debounceAsyncValidator(validator, delay) {
2223
2760
  let currentPromiseReject = null;
@@ -2248,10 +2785,13 @@ function debounceAsyncValidator(validator, delay) {
2248
2785
  };
2249
2786
  }
2250
2787
  /**
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.
2788
+ * Creates a debounced version of an asynchronous function. The debounced function will only
2789
+ * resolve the promise of the last invocation within the `wait` period.
2790
+ *
2791
+ * @template T - The type of the asynchronous function.
2792
+ * @param {T} func - The asynchronous function to debounce.
2793
+ * @param {number} wait - The debounce delay in milliseconds.
2794
+ * @returns A new debounced asynchronous function.
2255
2795
  */
2256
2796
  function debounceAsync(func, wait) {
2257
2797
  let timeoutReject = null;
@@ -2270,10 +2810,13 @@ function debounceAsync(func, wait) {
2270
2810
  };
2271
2811
  }
2272
2812
  /**
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.
2813
+ * Creates a debounced version of an asynchronous function that executes immediately on the first call
2814
+ * and then waits for the specified delay before allowing the next execution.
2815
+ *
2816
+ * @template T - The type of the asynchronous function.
2817
+ * @param {T} func - The asynchronous function to debounce.
2818
+ * @param {number} wait - The cooldown period in milliseconds after an immediate execution.
2819
+ * @returns A new debounced asynchronous function that executes on the leading edge.
2277
2820
  */
2278
2821
  function debounceAsyncWithImmediate(func, wait) {
2279
2822
  let timeoutReject = null;
@@ -2305,10 +2848,13 @@ function debounceAsyncWithImmediate(func, wait) {
2305
2848
  };
2306
2849
  }
2307
2850
  /**
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.
2851
+ * Creates a debounced function that invokes `func` on the leading edge of the `wait` timeout.
2852
+ * Subsequent calls within the `wait` period are ignored.
2853
+ *
2854
+ * @template T - The type of the function.
2855
+ * @param {T} func - The function to debounce.
2856
+ * @param {number} wait - The debounce delay in milliseconds.
2857
+ * @returns A new debounced function.
2312
2858
  */
2313
2859
  function debounceLeading(func, wait) {
2314
2860
  let timeoutReject = null;
@@ -2329,10 +2875,13 @@ function debounceLeading(func, wait) {
2329
2875
  };
2330
2876
  }
2331
2877
  /**
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.
2878
+ * Creates a debounced function that invokes `func` on the trailing edge of the `wait` timeout.
2879
+ * The function is called only after `wait` milliseconds of inactivity.
2880
+ *
2881
+ * @template T - The type of the function.
2882
+ * @param {T} func - The function to debounce.
2883
+ * @param {number} wait - The debounce delay in milliseconds.
2884
+ * @returns A new debounced function.
2336
2885
  */
2337
2886
  function debounceTrailing(func, wait) {
2338
2887
  let timeoutReject = null;
@@ -2350,10 +2899,13 @@ function debounceTrailing(func, wait) {
2350
2899
  };
2351
2900
  }
2352
2901
  /**
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.
2902
+ * Creates a debounced function that invokes `func` on both the leading and trailing edges of the `wait` timeout.
2903
+ * This is useful for UIs where an action should happen immediately on the first event, but also after a pause in events.
2904
+ *
2905
+ * @template T - The type of the function.
2906
+ * @param {T} func - The function to debounce.
2907
+ * @param {number} wait - The debounce delay in milliseconds.
2908
+ * @returns A new debounced function.
2357
2909
  */
2358
2910
  function debounceLeadingTrailing(func, wait) {
2359
2911
  let timeoutReject = null;
@@ -2379,10 +2931,13 @@ function debounceLeadingTrailing(func, wait) {
2379
2931
  };
2380
2932
  }
2381
2933
  /**
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.
2934
+ * Creates a standard debounced function that delays invoking `func` until after `wait` milliseconds
2935
+ * have elapsed since the last time the debounced function was invoked. (This is an alias for `debounceTrailing`).
2936
+ *
2937
+ * @template T - The type of the function.
2938
+ * @param {T} func - The function to debounce.
2939
+ * @param {number} wait - The debounce delay in milliseconds.
2940
+ * @returns A new debounced function.
2386
2941
  */
2387
2942
  function debounce(func, wait) {
2388
2943
  let timeoutReject = null;
@@ -2399,10 +2954,13 @@ function debounce(func, wait) {
2399
2954
  };
2400
2955
  }
2401
2956
  /**
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.
2957
+ * Creates a throttled function that only invokes `func` at most once per every `limit` milliseconds.
2958
+ * This is useful for rate-limiting events that fire frequently, such as scrolling or resizing.
2959
+ *
2960
+ * @template T - The type of the function.
2961
+ * @param {T} func - The function to throttle.
2962
+ * @param {number} limit - The throttle duration in milliseconds.
2963
+ * @returns A new throttled function.
2406
2964
  */
2407
2965
  function throttle(func, limit) {
2408
2966
  let lastCall = 0;
@@ -2416,9 +2974,11 @@ function throttle(func, limit) {
2416
2974
  }
2417
2975
 
2418
2976
  /**
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.
2977
+ * Converts a `FormData` object into a regular JavaScript object. It correctly handles
2978
+ * multiple values for the same key by creating an array for that key.
2979
+ *
2980
+ * @param {FormData} formData - The `FormData` object to convert.
2981
+ * @returns {Record<string, any>} A plain JavaScript object representation of the FormData.
2422
2982
  */
2423
2983
  function formDataToObject(formData) {
2424
2984
  const obj = {};
@@ -2437,9 +2997,10 @@ function formDataToObject(formData) {
2437
2997
  return obj;
2438
2998
  }
2439
2999
  /**
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.
3000
+ * Asynchronously reads the content of a `File` object as a text string.
3001
+ *
3002
+ * @param {File} file - The `File` object to read.
3003
+ * @returns {Promise<string>} A promise that resolves with the text content of the file.
2443
3004
  */
2444
3005
  function readFileAsText(file) {
2445
3006
  return new Promise((resolve, reject) => {
@@ -2450,9 +3011,10 @@ function readFileAsText(file) {
2450
3011
  });
2451
3012
  }
2452
3013
  /**
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.
3014
+ * Asynchronously reads the content of a `File` object as a Base64-encoded Data URL.
3015
+ *
3016
+ * @param {File} file - The `File` object to read.
3017
+ * @returns {Promise<string>} A promise that resolves with the Data URL representing the file's content.
2456
3018
  */
2457
3019
  function readFileAsDataURL(file) {
2458
3020
  return new Promise((resolve, reject) => {
@@ -2463,27 +3025,30 @@ function readFileAsDataURL(file) {
2463
3025
  });
2464
3026
  }
2465
3027
  /**
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.
3028
+ * Creates a `Blob` object from a string.
3029
+ *
3030
+ * @param {string} content - The string content to be put into the Blob.
3031
+ * @param {string} [type='text/plain'] - The MIME type of the Blob.
3032
+ * @returns {Blob} A new `Blob` object.
2470
3033
  */
2471
3034
  function stringToBlob(content, type = 'text/plain') {
2472
3035
  return new Blob([content], { type });
2473
3036
  }
2474
3037
  /**
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.
3038
+ * Creates a `Blob` object from an `ArrayBuffer`.
3039
+ *
3040
+ * @param {ArrayBuffer} buffer - The `ArrayBuffer` to be put into the Blob.
3041
+ * @param {string} [type='application/octet-stream'] - The MIME type of the Blob.
3042
+ * @returns {Blob} A new `Blob` object.
2479
3043
  */
2480
3044
  function bufferToBlob(buffer, type = 'application/octet-stream') {
2481
3045
  return new Blob([buffer], { type });
2482
3046
  }
2483
3047
  /**
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.
3048
+ * Triggers a browser download for a file created from a `Blob` object.
3049
+ *
3050
+ * @param {Blob} blob - The `Blob` containing the file data.
3051
+ * @param {string} fileName - The desired name for the downloaded file.
2487
3052
  */
2488
3053
  function downloadBlob(blob, fileName) {
2489
3054
  const link = document.createElement('a');
@@ -2498,11 +3063,12 @@ function downloadBlob(blob, fileName) {
2498
3063
  URL.revokeObjectURL(url);
2499
3064
  }
2500
3065
  /**
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.
3066
+ * Appends a `Blob` to a new `FormData` object.
3067
+ *
3068
+ * @param {Blob} blob - The `Blob` to append.
3069
+ * @param {string} name - The name of the field to append the blob as.
3070
+ * @param {string} [fileName='file'] - The filename to associate with the blob in the `FormData`.
3071
+ * @returns {FormData} A new `FormData` object containing the blob.
2506
3072
  */
2507
3073
  function blobToFormData(blob, name, fileName = 'file') {
2508
3074
  const formData = new FormData();
@@ -2511,9 +3077,10 @@ function blobToFormData(blob, name, fileName = 'file') {
2511
3077
  }
2512
3078
 
2513
3079
  /**
2514
- * Capitalizes the first character of a string.
2515
- * @param {string} s The string to capitalize.
2516
- * @returns {string} The capitalized string.
3080
+ * Capitalizes the first letter of a string.
3081
+ *
3082
+ * @param {string} s - The input string.
3083
+ * @returns {string} The string with the first letter capitalized.
2517
3084
  */
2518
3085
  function upperFirst(s) {
2519
3086
  return s.charAt(0).toUpperCase() + s.slice(1);
@@ -2521,9 +3088,10 @@ function upperFirst(s) {
2521
3088
  // Example usage:
2522
3089
  // console.log(upperFirst('hello')); // 'Hello'
2523
3090
  /**
2524
- * Lowercases the first character of a string.
2525
- * @param {string} s The string to lowercase.
2526
- * @returns {string} The lowercased string.
3091
+ * Converts the first letter of a string to lowercase.
3092
+ *
3093
+ * @param {string} s - The input string.
3094
+ * @returns {string} The string with the first letter in lowercase.
2527
3095
  */
2528
3096
  function lowerFirst(s) {
2529
3097
  return s.charAt(0).toLowerCase() + s.slice(1);
@@ -2531,9 +3099,11 @@ function lowerFirst(s) {
2531
3099
  // Example usage:
2532
3100
  // console.log(lowerFirst('Hello')); // 'hello'
2533
3101
  /**
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.
3102
+ * Normalizes a string by converting it to lowercase, trimming whitespace, replacing spaces with hyphens,
3103
+ * and removing diacritical marks (accents).
3104
+ *
3105
+ * @param {string} input - The string to normalize.
3106
+ * @returns {string} The URL-friendly, normalized string.
2537
3107
  */
2538
3108
  function removeAccent(input) {
2539
3109
  return input
@@ -2547,8 +3117,9 @@ function removeAccent(input) {
2547
3117
  // Example usage:
2548
3118
  // console.log(removeAccent('Café du Nord')); // 'cafe-du-nord'
2549
3119
  /**
2550
- * Reverses a string.
2551
- * @param {string} str The string to reverse.
3120
+ * Reverses the characters of a string.
3121
+ *
3122
+ * @param {string} str - The input string.
2552
3123
  * @returns {string} The reversed string.
2553
3124
  */
2554
3125
  function reverseString(str) {
@@ -2557,9 +3128,10 @@ function reverseString(str) {
2557
3128
  // Example usage:
2558
3129
  // console.log(reverseString('hello')); // 'olleh'
2559
3130
  /**
2560
- * Counts the number of words in a string.
2561
- * @param {string} str The string to analyze.
2562
- * @returns {number} The word count.
3131
+ * Counts the number of words in a string, based on whitespace separation.
3132
+ *
3133
+ * @param {string} str - The input string.
3134
+ * @returns {number} The number of words in the string.
2563
3135
  */
2564
3136
  function countWords(str) {
2565
3137
  return str.trim().split(/\s+/).length;
@@ -2567,9 +3139,10 @@ function countWords(str) {
2567
3139
  // Example usage:
2568
3140
  // console.log(countWords('Hello world!')); // 2
2569
3141
  /**
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.
3142
+ * Truncates a string to a specified maximum length, appending '...' if the string is cut.
3143
+ *
3144
+ * @param {string} str - The input string.
3145
+ * @param {number} maxLength - The maximum desired length of the string.
2573
3146
  * @returns {string} The truncated string.
2574
3147
  */
2575
3148
  function truncateString(str, maxLength) {
@@ -2578,9 +3151,10 @@ function truncateString(str, maxLength) {
2578
3151
  // Example usage:
2579
3152
  // console.log(truncateString('This is a long string', 10)); // 'This is a...'
2580
3153
  /**
2581
- * Converts a string to camel case.
2582
- * @param {string} str The string to convert.
2583
- * @returns {string} The camel cased string.
3154
+ * Converts a string from various cases (e.g., snake_case, kebab-case, space separated) into camelCase.
3155
+ *
3156
+ * @param {string} str - The input string.
3157
+ * @returns {string} The camelCase version of the string.
2584
3158
  */
2585
3159
  function toCamelCase(str) {
2586
3160
  return str
@@ -2590,9 +3164,10 @@ function toCamelCase(str) {
2590
3164
  // Example usage:
2591
3165
  // console.log(toCamelCase('hello world example')); // 'helloWorldExample'
2592
3166
  /**
2593
- * Converts a string to kebab case.
2594
- * @param {string} str The string to convert.
2595
- * @returns {string} The kebab cased string.
3167
+ * Converts a string from various cases (e.g., camelCase, PascalCase, space separated) into kebab-case.
3168
+ *
3169
+ * @param {string} str - The input string.
3170
+ * @returns {string} The kebab-case version of the string.
2596
3171
  */
2597
3172
  function toKebabCase(str) {
2598
3173
  return str
@@ -2603,11 +3178,12 @@ function toKebabCase(str) {
2603
3178
  // Example usage:
2604
3179
  // console.log(toKebabCase('Hello World Example')); // 'hello-world-example'
2605
3180
  /**
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.
3181
+ * Replaces all occurrences of a substring with a new substring.
3182
+ *
3183
+ * @param {string} str - The original string.
3184
+ * @param {string} find - The substring to find and replace.
3185
+ * @param {string} replace - The substring to replace with.
3186
+ * @returns {string} A new string with all replacements made.
2611
3187
  */
2612
3188
  function replaceAll(str, find, replace) {
2613
3189
  return str.split(find).join(replace);
@@ -2615,9 +3191,10 @@ function replaceAll(str, find, replace) {
2615
3191
  // Example usage:
2616
3192
  // console.log(replaceAll('hello world', 'o', 'a')); // 'hella warld'
2617
3193
  /**
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.
3194
+ * Generates a random alphanumeric string of a specified length.
3195
+ *
3196
+ * @param {number} length - The desired length of the random string.
3197
+ * @returns {string} The generated random string.
2621
3198
  */
2622
3199
  function generateRandomString(length) {
2623
3200
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -2627,9 +3204,10 @@ function generateRandomString(length) {
2627
3204
  // console.log(generateRandomString(10)); // 'A1b2C3d4E5'
2628
3205
 
2629
3206
  /**
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.
3207
+ * An event handler that prevents a `KeyboardEvent`'s default action if the key pressed is not a letter or a specific special character.
3208
+ *
3209
+ * @param {KeyboardEvent} e - The `KeyboardEvent` object.
3210
+ * @returns {boolean} `true` if the key is valid, `false` otherwise.
2633
3211
  */
2634
3212
  function validateLetters(e) {
2635
3213
  const key = e.keyCode;
@@ -2660,9 +3238,10 @@ function validateLetters(e) {
2660
3238
  // Example usage:
2661
3239
  // document.addEventListener('keydown', validateLetters);
2662
3240
  /**
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.
3241
+ * An event handler that prevents a `KeyboardEvent`'s default action if the key pressed is not an alphanumeric character.
3242
+ *
3243
+ * @param {KeyboardEvent} e - The `KeyboardEvent` object.
3244
+ * @returns {boolean} `true` if the key is valid, `false` otherwise.
2666
3245
  */
2667
3246
  function validateAlphanumeric(e) {
2668
3247
  const key = e.keyCode;
@@ -2683,9 +3262,10 @@ function validateAlphanumeric(e) {
2683
3262
  // Example usage:
2684
3263
  // document.addEventListener('keydown', validateAlphanumeric);
2685
3264
  /**
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.
3265
+ * An event handler that prevents a `KeyboardEvent`'s default action if the key pressed is not a number.
3266
+ *
3267
+ * @param {KeyboardEvent} e - The `KeyboardEvent` object.
3268
+ * @returns {boolean} `true` if the key is a number, otherwise `false`.
2689
3269
  */
2690
3270
  function validateNumbers(e) {
2691
3271
  const key = e.keyCode;
@@ -2698,9 +3278,10 @@ function validateNumbers(e) {
2698
3278
  // Example usage:
2699
3279
  // document.addEventListener('keydown', validateNumbers);
2700
3280
  /**
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.
3281
+ * Validates a phone number against a regex for 10-digit numbers.
3282
+ *
3283
+ * @param {string} phoneNumber - The phone number to validate.
3284
+ * @returns {boolean} `true` if the phone number is valid, otherwise `false`.
2704
3285
  */
2705
3286
  function isValidPhoneNumber(phoneNumber) {
2706
3287
  const phonePattern = /^[0-9]{10}$/; // Example pattern for 10-digit phone numbers
@@ -2710,9 +3291,10 @@ function isValidPhoneNumber(phoneNumber) {
2710
3291
  // console.log(isValidPhoneNumber('1234567890')); // true
2711
3292
  // console.log(isValidPhoneNumber('123-456-7890')); // false
2712
3293
  /**
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.
3294
+ * Validates an email address against a standard regex pattern.
3295
+ *
3296
+ * @param {string} email - The email address to validate.
3297
+ * @returns {boolean} `true` if the email is valid, otherwise `false`.
2716
3298
  */
2717
3299
  function isValidEmail(email) {
2718
3300
  const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
@@ -2722,9 +3304,10 @@ function isValidEmail(email) {
2722
3304
  // console.log(isValidEmail('example@domain.com')); // true
2723
3305
  // console.log(isValidEmail('invalid-email')); // false
2724
3306
  /**
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.
3307
+ * Validates a string to see if it is a well-formed URL.
3308
+ *
3309
+ * @param {string} url - The URL string to validate.
3310
+ * @returns {boolean} `true` if the URL is valid, otherwise `false`.
2728
3311
  */
2729
3312
  function isValidURL(url) {
2730
3313
  try {
@@ -2739,9 +3322,10 @@ function isValidURL(url) {
2739
3322
  // console.log(isValidURL('https://www.example.com')); // true
2740
3323
  // console.log(isValidURL('invalid-url')); // false
2741
3324
  /**
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.
3325
+ * Validates a string to ensure it is a valid date in 'YYYY-MM-DD' format.
3326
+ *
3327
+ * @param {string} date - The date string to validate.
3328
+ * @returns {boolean} `true` if the date is valid, otherwise `false`.
2745
3329
  */
2746
3330
  function isValidDate(date) {
2747
3331
  const datePattern = /^\d{4}-\d{2}-\d{2}$/;
@@ -2755,9 +3339,10 @@ function isValidDate(date) {
2755
3339
  // console.log(isValidDate('2024-08-31')); // true
2756
3340
  // console.log(isValidDate('2024-02-30')); // false
2757
3341
  /**
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.
3342
+ * Checks if a password meets a set of strength requirements (minimum length, uppercase, lowercase, numbers, special characters).
3343
+ *
3344
+ * @param {string} password - The password to validate.
3345
+ * @returns {boolean} `true` if the password is strong, otherwise `false`.
2761
3346
  */
2762
3347
  function isStrongPassword(password) {
2763
3348
  const minLength = 8;
@@ -2771,9 +3356,10 @@ function isStrongPassword(password) {
2771
3356
  // console.log(isStrongPassword('Strong1@password')); // true
2772
3357
  // console.log(isStrongPassword('weakpass')); // false
2773
3358
  /**
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.
3359
+ * Validates a credit card number using the Luhn algorithm (mod-10 check).
3360
+ *
3361
+ * @param {string} cardNumber - The credit card number to validate.
3362
+ * @returns {boolean} `true` if the credit card number is valid, otherwise `false`.
2777
3363
  */
2778
3364
  function isValidCreditCard(cardNumber) {
2779
3365
  const sanitized = cardNumber.replace(/\D/g, '');
@@ -2795,9 +3381,10 @@ function isValidCreditCard(cardNumber) {
2795
3381
  // console.log(isValidCreditCard('4111111111111111')); // true
2796
3382
  // console.log(isValidCreditCard('1234567812345670')); // false
2797
3383
  /**
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.
3384
+ * Validates a string to check if it's a valid 3- or 6-digit hexadecimal color code.
3385
+ *
3386
+ * @param {string} color - The hex color string to validate.
3387
+ * @returns {boolean} `true` if the color code is valid, otherwise `false`.
2801
3388
  */
2802
3389
  function isValidHexColor(color) {
2803
3390
  const hexPattern = /^#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/;
@@ -2808,9 +3395,10 @@ function isValidHexColor(color) {
2808
3395
  // console.log(isValidHexColor('#FFF')); // true
2809
3396
  // console.log(isValidHexColor('#12345G')); // false
2810
3397
  /**
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.
3398
+ * Validates a string to ensure it represents a valid time in 24-hour HH:MM format.
3399
+ *
3400
+ * @param {string} time - The time string to validate.
3401
+ * @returns {boolean} `true` if the time is valid, otherwise `false`.
2814
3402
  */
2815
3403
  function isValidTime(time) {
2816
3404
  const timePattern = /^([01]\d|2[0-3]):([0-5]\d)$/;
@@ -2820,9 +3408,10 @@ function isValidTime(time) {
2820
3408
  // console.log(isValidTime('14:30')); // true
2821
3409
  // console.log(isValidTime('25:00')); // false
2822
3410
  /**
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.
3411
+ * Validates a string to check if it is a valid IPv4 address.
3412
+ *
3413
+ * @param {string} ip - The IP address string to validate.
3414
+ * @returns {boolean} `true` if the IP address is valid, otherwise `false`.
2826
3415
  */
2827
3416
  function isValidIP(ip) {
2828
3417
  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 +3421,10 @@ function isValidIP(ip) {
2832
3421
  // console.log(isValidIP('192.168.1.1')); // true
2833
3422
  // console.log(isValidIP('999.999.999.999')); // false
2834
3423
  /**
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.
3424
+ * Validates a string to check if it matches the format of a U.S. Social Security Number (SSN).
3425
+ *
3426
+ * @param {string} ssn - The SSN string to validate.
3427
+ * @returns {boolean} `true` if the SSN format is valid, otherwise `false`.
2838
3428
  */
2839
3429
  function isValidSSN(ssn) {
2840
3430
  const ssnPattern = /^\d{3}-\d{2}-\d{4}$/;
@@ -2844,9 +3434,10 @@ function isValidSSN(ssn) {
2844
3434
  // console.log(isValidSSN('123-45-6789')); // true
2845
3435
  // console.log(isValidSSN('123-45-678')); // false
2846
3436
  /**
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.
3437
+ * Validates a string to check if it is a valid 5-digit or 9-digit (ZIP+4) U.S. ZIP code.
3438
+ *
3439
+ * @param {string} zip - The ZIP code string to validate.
3440
+ * @returns {boolean} `true` if the ZIP code is valid, otherwise `false`.
2850
3441
  */
2851
3442
  function isValidZIP(zip) {
2852
3443
  const zipPattern = /^\d{5}(-\d{4})?$/;
@@ -2857,9 +3448,10 @@ function isValidZIP(zip) {
2857
3448
  // console.log(isValidZIP('12345-6789')); // true
2858
3449
  // console.log(isValidZIP('1234')); // false
2859
3450
  /**
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.
3451
+ * Validates a credit card expiry date string (MM/YY format) to ensure it is a valid, non-expired date.
3452
+ *
3453
+ * @param {string} expiryDate - The expiry date to validate.
3454
+ * @returns {boolean} `true` if the expiry date is valid and not in the past, otherwise `false`.
2863
3455
  */
2864
3456
  function isValidExpiryDate(expiryDate) {
2865
3457
  const expiryPattern = /^(0[1-9]|1[0-2])\/\d{2}$/;
@@ -2874,9 +3466,10 @@ function isValidExpiryDate(expiryDate) {
2874
3466
  // console.log(isValidExpiryDate('08/24')); // true
2875
3467
  // console.log(isValidExpiryDate('12/22')); // false
2876
3468
  /**
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.
3469
+ * Validates a string to check if it's a valid 8-digit hexadecimal color code (with alpha channel).
3470
+ *
3471
+ * @param {string} color - The hex color string to validate.
3472
+ * @returns {boolean} `true` if the color code is valid, otherwise `false`.
2880
3473
  */
2881
3474
  function isValidHexColorAlpha(color) {
2882
3475
  const hexPattern = /^#([0-9A-Fa-f]{8})$/;
@@ -2886,9 +3479,10 @@ function isValidHexColorAlpha(color) {
2886
3479
  // console.log(isValidHexColorAlpha('#RRGGBBAA')); // true
2887
3480
  // console.log(isValidHexColorAlpha('#FFFFFF')); // false
2888
3481
  /**
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.
3482
+ * Validates a username to ensure it contains only alphanumeric characters and underscores, with a length between 3 and 16 characters.
3483
+ *
3484
+ * @param {string} username - The username to validate.
3485
+ * @returns {boolean} `true` if the username is valid, otherwise `false`.
2892
3486
  */
2893
3487
  function isValidUsername(username) {
2894
3488
  const usernamePattern = /^[a-zA-Z0-9_]{3,16}$/; // 3 to 16 characters, letters, numbers, and underscores only
@@ -2898,9 +3492,10 @@ function isValidUsername(username) {
2898
3492
  // console.log(isValidUsername('user_name123')); // true
2899
3493
  // console.log(isValidUsername('us')); // false
2900
3494
  /**
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.
3495
+ * Validates a string to ensure it represents a plausible human age (0-120).
3496
+ *
3497
+ * @param {string} age - The age string to validate.
3498
+ * @returns {boolean} `true` if the age is valid, otherwise `false`.
2904
3499
  */
2905
3500
  function isValidAge(age) {
2906
3501
  const ageNumber = parseInt(age, 10);
@@ -2910,9 +3505,10 @@ function isValidAge(age) {
2910
3505
  // console.log(isValidAge('25')); // true
2911
3506
  // console.log(isValidAge('121')); // false
2912
3507
  /**
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.
3508
+ * Validates a string to check if it contains only valid hexadecimal characters.
3509
+ *
3510
+ * @param {string} hex - The string to validate.
3511
+ * @returns {boolean} `true` if the string is a valid hexadecimal number, otherwise `false`.
2916
3512
  */
2917
3513
  function isValidHexNumber(hex) {
2918
3514
  const hexPattern = /^[0-9A-Fa-f]+$/;
@@ -2922,73 +3518,211 @@ function isValidHexNumber(hex) {
2922
3518
  // console.log(isValidHexNumber('1A3F')); // true
2923
3519
  // console.log(isValidHexNumber('GHIJ')); // false
2924
3520
 
3521
+ const DEFAULT_RETRY_CONFIG = {
3522
+ retries: 3,
3523
+ retryDelay: 1000,
3524
+ maxRetryDelay: 10000,
3525
+ backoffMultiplier: 2,
3526
+ retryCondition: (error) => {
3527
+ if (error instanceof NetworkError || error instanceof ServerError) {
3528
+ const statusCode = error.statusCode;
3529
+ if (!statusCode)
3530
+ return true;
3531
+ if (statusCode >= 500)
3532
+ return true;
3533
+ if (statusCode === 408 || statusCode === 429)
3534
+ return true;
3535
+ return false;
3536
+ }
3537
+ if (error instanceof Error) {
3538
+ return error.message.includes('timeout') || error.message.includes('network');
3539
+ }
3540
+ return false;
3541
+ },
3542
+ };
3543
+ async function retryWithBackoff(fn, config = {}) {
3544
+ const finalConfig = { ...DEFAULT_RETRY_CONFIG, ...config };
3545
+ let lastError;
3546
+ let delay = finalConfig.retryDelay;
3547
+ for (let attempt = 0; attempt <= finalConfig.retries; attempt++) {
3548
+ try {
3549
+ return await fn();
3550
+ }
3551
+ catch (error) {
3552
+ lastError = error;
3553
+ if (attempt === finalConfig.retries) {
3554
+ break;
3555
+ }
3556
+ if (!finalConfig.retryCondition(error)) {
3557
+ throw error;
3558
+ }
3559
+ await new Promise((resolve) => setTimeout(resolve, delay));
3560
+ delay = Math.min(delay * finalConfig.backoffMultiplier, finalConfig.maxRetryDelay);
3561
+ }
3562
+ }
3563
+ throw lastError;
3564
+ }
3565
+
3566
+ /**
3567
+ * A standardized RESTful class that provides a generic interface for performing
3568
+ * CRUD (Create, Read, Update, Delete) operations on a specific API resource. It is designed
3569
+ * to be extended directly from your models. It supports both JSON and FormData requests.
3570
+ *
3571
+ * @example
3572
+ * ```typescript
3573
+ * export class Role extends RestStd {
3574
+ * static override resource = 'roles';
3575
+ * static fetchFn = createAxiosFetcher(axiosInstance);
3576
+ * }
3577
+ *
3578
+ * const roles = await Role.getAll();
3579
+ * ```
3580
+ */
2925
3581
  class RestStd {
3582
+ /**
3583
+ * The resource endpoint. MUST be overridden in subclasses.
3584
+ * @example static override resource = 'users';
3585
+ */
2926
3586
  static resource;
3587
+ /** A flag to determine if request data should be sent as FormData. Defaults to `false`. */
2927
3588
  static isFormData = false;
3589
+ /** A record of global headers to be sent with every request. */
2928
3590
  static headers = {};
3591
+ /** The function used to make the actual HTTP requests. Optional, defaults to Axios fetcher. */
2929
3592
  static fetchFn;
3593
+ /** Retry configuration for failed requests. Optional. */
3594
+ static retryConfig;
2930
3595
  /**
2931
- * Set global headers for all requests.
2932
- * @param headers Object containing headers to be set globally.
3596
+ * Validates that the resource property is defined.
3597
+ * @throws {Error} If resource is not defined
3598
+ */
3599
+ static validateResource() {
3600
+ if (!this.resource || this.resource.trim() === '') {
3601
+ throw new Error(`[${this.constructor.name}] Static property 'resource' is required. ` +
3602
+ `Please define: static override resource = 'your-resource';`);
3603
+ }
3604
+ }
3605
+ /**
3606
+ * Gets the fetcher function, using default if not provided.
3607
+ * Creates a default Axios fetcher if not configured, allowing lazy initialization.
3608
+ * @returns The fetcher function to use
3609
+ */
3610
+ static getFetchFn() {
3611
+ if (this.fetchFn) {
3612
+ return this.fetchFn;
3613
+ }
3614
+ const axiosInstance = getConfiguredAxiosInstance();
3615
+ return createAxiosFetcher(axiosInstance);
3616
+ }
3617
+ /**
3618
+ * Executes a fetch request with optional retry logic.
3619
+ * @param config - The fetcher configuration
3620
+ * @returns A promise that resolves with the response data
3621
+ */
3622
+ static async executeFetch(config) {
3623
+ const fetcher = this.getFetchFn();
3624
+ if (this.retryConfig) {
3625
+ return retryWithBackoff(() => fetcher(config), this.retryConfig);
3626
+ }
3627
+ try {
3628
+ return await fetcher(config);
3629
+ }
3630
+ catch (error) {
3631
+ if (error && typeof error === 'object' && 'response' in error) {
3632
+ throw NetworkError.fromAxiosError(error);
3633
+ }
3634
+ if (error instanceof Error && error.name === 'TypeError' && error.message?.includes('fetch')) {
3635
+ throw NetworkError.fromFetchError(error);
3636
+ }
3637
+ throw error;
3638
+ }
3639
+ }
3640
+ /**
3641
+ * Builds a URL by combining base URL and suffix.
3642
+ * @param baseUrl - The base URL
3643
+ * @param suffix - Optional suffix to append
3644
+ * @returns The combined URL
3645
+ */
3646
+ static buildUrl(baseUrl, suffix) {
3647
+ const cleanBase = baseUrl.replace(/\/$/, '');
3648
+ if (suffix) {
3649
+ const cleanSuffix = suffix.startsWith('/') ? suffix : `/${suffix}`;
3650
+ return cleanBase + cleanSuffix;
3651
+ }
3652
+ return cleanBase;
3653
+ }
3654
+ /**
3655
+ * Sets global headers that will be included in all subsequent requests made by this class.
3656
+ * @param headers - An object containing the headers to be set
2933
3657
  */
2934
3658
  static setHeaders(headers) {
2935
3659
  this.headers = { ...this.headers, ...headers };
2936
3660
  }
2937
3661
  /**
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.
3662
+ * Conditionally transforms the request data to FormData if `isFormData` is true.
3663
+ * @param data - The data to be potentially transformed
3664
+ * @returns The transformed data as FormData, or the original data
2941
3665
  */
2942
3666
  static transformData(data) {
2943
3667
  if (this.isFormData) {
2944
- const formData = objectToFormData(data);
2945
- return formData;
3668
+ return objectToFormData(data);
2946
3669
  }
2947
3670
  return data;
2948
3671
  }
2949
3672
  /**
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).
3673
+ * Fetches a list of items from the resource's endpoint.
3674
+ * @template TResponse The expected response type
3675
+ * @template TParams The type of query parameters
3676
+ * @param options - Options including params, options, and optional url override
3677
+ * @returns A promise that resolves with the response data
2955
3678
  */
2956
- static getAll(params, options = {}) {
2957
- return this.fetchFn({
3679
+ static getAll(options = {}) {
3680
+ this.validateResource();
3681
+ const { params, url } = options;
3682
+ const finalUrl = url || this.resource;
3683
+ const config = {
2958
3684
  method: "GET",
2959
- url: this.resource,
3685
+ url: finalUrl,
2960
3686
  params,
2961
3687
  headers: this.headers,
2962
- }, options);
3688
+ };
3689
+ return this.executeFetch(config);
2963
3690
  }
2964
3691
  /**
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).
3692
+ * Fetches a single item by its ID.
3693
+ * @template TResponse The expected response type
3694
+ * @template TParams The type of query parameters
3695
+ * @param options - Options including id, params, options, and optional url override
3696
+ * @returns A promise that resolves with the response data
2971
3697
  */
2972
- static getOne(id, params, options = {}) {
2973
- return this.fetchFn({
3698
+ static getOne(options) {
3699
+ this.validateResource();
3700
+ const { id, params, url } = options;
3701
+ const baseUrl = url || this.resource;
3702
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3703
+ const config = {
2974
3704
  method: "GET",
2975
- url: `${this.resource}/${id}`,
3705
+ url: finalUrl,
2976
3706
  params,
2977
3707
  headers: this.headers,
2978
- }, options);
3708
+ };
3709
+ return this.executeFetch(config);
2979
3710
  }
2980
3711
  /**
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).
3712
+ * Creates a new item.
3713
+ * @template TResponse The expected response type
3714
+ * @template TData The type of data to send
3715
+ * @param options - Options including data, options, and optional url override
3716
+ * @returns A promise that resolves with the response data
2986
3717
  */
2987
- static create(data, options = {}) {
3718
+ static create(options) {
3719
+ this.validateResource();
3720
+ const { data, url } = options;
3721
+ const finalUrl = url || this.resource;
2988
3722
  const transformedData = this.transformData(data);
2989
- return this.fetchFn({
3723
+ const config = {
2990
3724
  method: "POST",
2991
- url: this.resource,
3725
+ url: finalUrl,
2992
3726
  data: transformedData,
2993
3727
  headers: {
2994
3728
  ...this.headers,
@@ -2996,22 +3730,27 @@ class RestStd {
2996
3730
  ? ContentTypeEnum.FORM_DATA
2997
3731
  : ContentTypeEnum.JSON,
2998
3732
  },
2999
- }, options);
3733
+ };
3734
+ return this.executeFetch(config);
3000
3735
  }
3001
3736
  /**
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.
3737
+ * Creates multiple new items in a single request.
3738
+ * @template TResponse The expected response type
3739
+ * @template TData The type of data items to send
3740
+ * @param options - Options including data array, options, and optional url override
3741
+ * @returns A promise that resolves with the response data
3007
3742
  */
3008
- static bulkCreate(data, options = {}) {
3743
+ static bulkCreate(options) {
3744
+ this.validateResource();
3745
+ const { data, url } = options;
3746
+ const baseUrl = url || this.resource;
3747
+ const finalUrl = this.buildUrl(baseUrl, 'bulk');
3009
3748
  const transformedData = this.isFormData
3010
3749
  ? data.map((item) => this.transformData(item))
3011
3750
  : data;
3012
- return this.fetchFn({
3751
+ const config = {
3013
3752
  method: "POST",
3014
- url: `${this.resource}/bulk`,
3753
+ url: finalUrl,
3015
3754
  data: transformedData,
3016
3755
  headers: {
3017
3756
  ...this.headers,
@@ -3019,21 +3758,25 @@ class RestStd {
3019
3758
  ? ContentTypeEnum.FORM_DATA
3020
3759
  : ContentTypeEnum.JSON,
3021
3760
  },
3022
- }, options);
3761
+ };
3762
+ return this.executeFetch(config);
3023
3763
  }
3024
3764
  /**
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).
3765
+ * Updates an existing item by its ID.
3766
+ * @template TResponse The expected response type
3767
+ * @template TData The type of data to send
3768
+ * @param options - Options including id, data, options, and optional url override
3769
+ * @returns A promise that resolves with the response data
3031
3770
  */
3032
- static update(id, data, options = {}) {
3771
+ static update(options) {
3772
+ this.validateResource();
3773
+ const { id, data, url } = options;
3774
+ const baseUrl = url || this.resource;
3775
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3033
3776
  const transformedData = this.transformData(data);
3034
- return this.fetchFn({
3777
+ const config = {
3035
3778
  method: "PUT",
3036
- url: `${this.resource}/${id}`,
3779
+ url: finalUrl,
3037
3780
  data: transformedData,
3038
3781
  headers: {
3039
3782
  ...this.headers,
@@ -3041,22 +3784,27 @@ class RestStd {
3041
3784
  ? ContentTypeEnum.FORM_DATA
3042
3785
  : ContentTypeEnum.JSON,
3043
3786
  },
3044
- }, options);
3787
+ };
3788
+ return this.executeFetch(config);
3045
3789
  }
3046
3790
  /**
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.
3791
+ * Updates multiple existing items in a single request.
3792
+ * @template TResponse The expected response type
3793
+ * @template TData The type of data items to send
3794
+ * @param options - Options including data array, options, and optional url override
3795
+ * @returns A promise that resolves with the response data
3052
3796
  */
3053
- static bulkUpdate(data, options = {}) {
3797
+ static bulkUpdate(options) {
3798
+ this.validateResource();
3799
+ const { data, url } = options;
3800
+ const baseUrl = url || this.resource;
3801
+ const finalUrl = this.buildUrl(baseUrl, 'bulk');
3054
3802
  const transformedData = this.isFormData
3055
3803
  ? data.map((item) => this.transformData(item))
3056
3804
  : data;
3057
- return this.fetchFn({
3805
+ const config = {
3058
3806
  method: "PUT",
3059
- url: `${this.resource}/bulk`,
3807
+ url: finalUrl,
3060
3808
  data: transformedData,
3061
3809
  headers: {
3062
3810
  ...this.headers,
@@ -3064,21 +3812,25 @@ class RestStd {
3064
3812
  ? ContentTypeEnum.FORM_DATA
3065
3813
  : ContentTypeEnum.JSON,
3066
3814
  },
3067
- }, options);
3815
+ };
3816
+ return this.executeFetch(config);
3068
3817
  }
3069
3818
  /**
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).
3819
+ * Partially updates an existing item by its ID.
3820
+ * @template TResponse The expected response type
3821
+ * @template TData The type of data to send (partial)
3822
+ * @param options - Options including id, data, options, and optional url override
3823
+ * @returns A promise that resolves with the response data
3076
3824
  */
3077
- static patch(id, data, options = {}) {
3825
+ static patch(options) {
3826
+ this.validateResource();
3827
+ const { id, data, url } = options;
3828
+ const baseUrl = url || this.resource;
3829
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3078
3830
  const transformedData = this.transformData(data);
3079
- return this.fetchFn({
3831
+ const config = {
3080
3832
  method: "PATCH",
3081
- url: `${this.resource}/${id}`,
3833
+ url: finalUrl,
3082
3834
  data: transformedData,
3083
3835
  headers: {
3084
3836
  ...this.headers,
@@ -3086,65 +3838,80 @@ class RestStd {
3086
3838
  ? ContentTypeEnum.FORM_DATA
3087
3839
  : ContentTypeEnum.JSON,
3088
3840
  },
3089
- }, options);
3841
+ };
3842
+ return this.executeFetch(config);
3090
3843
  }
3091
3844
  /**
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).
3845
+ * Deletes an item by its ID.
3846
+ * @template TResponse The expected response type
3847
+ * @param options - Options including id, options, and optional url override
3848
+ * @returns A promise that resolves with the response data
3097
3849
  */
3098
- static delete(id, options = {}) {
3099
- return this.fetchFn({
3850
+ static delete(options) {
3851
+ this.validateResource();
3852
+ const { id, url } = options;
3853
+ const baseUrl = url || this.resource;
3854
+ const finalUrl = this.buildUrl(baseUrl, String(id));
3855
+ const config = {
3100
3856
  method: "DELETE",
3101
- url: `${this.resource}/${id}`,
3857
+ url: finalUrl,
3102
3858
  headers: this.headers,
3103
- }, options);
3859
+ };
3860
+ return this.executeFetch(config);
3104
3861
  }
3105
3862
  /**
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.
3863
+ * Deletes multiple items by their IDs in a single request.
3864
+ * @template TResponse The expected response type
3865
+ * @param options - Options including ids array, options, and optional url override
3866
+ * @returns A promise that resolves with the response data
3111
3867
  */
3112
- static bulkDelete(ids, options = {}) {
3113
- return this.fetchFn({
3868
+ static bulkDelete(options) {
3869
+ this.validateResource();
3870
+ const { ids, url } = options;
3871
+ const baseUrl = url || this.resource;
3872
+ const finalUrl = this.buildUrl(baseUrl, 'bulk');
3873
+ const config = {
3114
3874
  method: "DELETE",
3115
- url: `${this.resource}/bulk`,
3875
+ url: finalUrl,
3116
3876
  data: { ids },
3117
3877
  headers: this.headers,
3118
- }, options);
3878
+ };
3879
+ return this.executeFetch(config);
3119
3880
  }
3120
3881
  /**
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).
3882
+ * Creates a new item or updates an existing one, based on the presence of an `id` property in the data.
3883
+ * @template TResponse The expected response type
3884
+ * @template TData The type of data to send (must have optional id)
3885
+ * @param options - Options including data, options, and optional url override
3886
+ * @returns A promise that resolves with the response data
3126
3887
  */
3127
- static upsert(data, options = {}) {
3128
- if (data.id) {
3129
- return this.update(data.id, data, options);
3888
+ static upsert(options) {
3889
+ if (options.data.id) {
3890
+ return this.update({
3891
+ id: options.data.id,
3892
+ data: options.data,
3893
+ url: options.url,
3894
+ });
3130
3895
  }
3131
3896
  else {
3132
- return this.create(data, options);
3897
+ return this.create({
3898
+ data: options.data,
3899
+ url: options.url,
3900
+ });
3133
3901
  }
3134
3902
  }
3135
3903
  /**
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).
3904
+ * Makes a custom HTTP request, providing full flexibility over the method, URL, and data.
3905
+ * @template TResponse The expected response type
3906
+ * @template TParams The type of query parameters
3907
+ * @template TData The type of request body data
3908
+ * @param options - Options including method, url, params, data, and options
3909
+ * @returns A promise that resolves with the response data
3144
3910
  */
3145
- static customRequest(method, url, params, data, options = {}) {
3911
+ static customRequest(options) {
3912
+ const { method, url, params, data } = options;
3146
3913
  const transformedData = this.transformData(data);
3147
- return this.fetchFn({
3914
+ const config = {
3148
3915
  method: method,
3149
3916
  url: url,
3150
3917
  params: params,
@@ -3155,17 +3922,20 @@ class RestStd {
3155
3922
  ? ContentTypeEnum.FORM_DATA
3156
3923
  : ContentTypeEnum.JSON,
3157
3924
  },
3158
- }, options);
3925
+ };
3926
+ return this.executeFetch(config);
3159
3927
  }
3160
3928
  }
3161
3929
 
3162
3930
  /**
3163
- * Custom composable function for making API requests with Axios.
3931
+ * A composable function that executes an Axios request and returns the response data.
3932
+ * It simplifies making API calls by wrapping the Axios request in a reusable function.
3164
3933
  *
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.
3934
+ * @template T The expected type of the response data.
3935
+ * @param {AxiosInstance} axios - The Axios instance to use for making the request.
3936
+ * @param {AxiosRequestConfig} axiosRequest - The configuration for the Axios request (e.g., URL, method, headers).
3937
+ * @returns {Promise<T>} A promise that resolves with the data from the Axios response.
3938
+ * @throws {Error} Throws an error if the Axios request fails.
3169
3939
  */
3170
3940
  async function axiosFetch(axios, axiosRequest) {
3171
3941
  return axios(axiosRequest)
@@ -3176,10 +3946,19 @@ async function axiosFetch(axios, axiosRequest) {
3176
3946
  }
3177
3947
 
3178
3948
  /**
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.
3949
+ * A factory function that creates a reusable query function for making API requests.
3950
+ * It abstracts the Axios instance creation and allows for a custom instance to be provided.
3951
+ * This is particularly useful for creating typed query functions for use with libraries like Vue Query.
3952
+ *
3953
+ * @template TQueryFnData The expected data type of the query function's response.
3954
+ * @template TData The expected data type of the transformed data.
3955
+ * @param {Function} fetchFn - The underlying function that will be called to perform the fetch operation.
3956
+ * This function should accept an Axios instance, Axios request configuration, and optional query options.
3957
+ * @param {AxiosInstance} [axiosCustomInstance] - An optional custom Axios instance to use for the request.
3958
+ * If not provided, a default configured instance will be used.
3959
+ * @returns {(axiosRequestConfig: AxiosRequestConfig, options?: UseQueryOptions<TQueryFnData, Error, TData>) => any}
3960
+ * A new function that takes Axios request configuration and optional query options, and when executed,
3961
+ * performs the API request using the configured `fetchFn`.
3183
3962
  */
3184
3963
  function useFetch(fetchFn, axiosCustomInstance) {
3185
3964
  const instance = axiosCustomInstance || getConfiguredAxiosInstance();
@@ -3188,131 +3967,20 @@ function useFetch(fetchFn, axiosCustomInstance) {
3188
3967
  };
3189
3968
  }
3190
3969
 
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
3970
  let notified = false;
3312
3971
  /**
3313
- * Composable to manage breakpoints using Tailwind CSS and shared window resize listener.
3972
+ * A composable that provides a reactive interface to Tailwind CSS breakpoints using `@vueuse/core`.
3973
+ * It simplifies working with responsive layouts by offering a set of reactive booleans for different
3974
+ * screen sizes and combinations. On its first invocation, it also logs the current device type (Mobile,
3975
+ * Tablet, Laptop, or Desktop) to the console for easier debugging during development.
3314
3976
  *
3315
- * @returns {Object} An object containing the breakpoints and their states.
3977
+ * @returns {object} An object containing various reactive properties for screen sizes, window dimensions, and breakpoint utilities, including:
3978
+ * - `current`: A ref to the current breakpoint name.
3979
+ * - `active`: A ref to the currently active breakpoint name.
3980
+ * - `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.
3981
+ * - `mobile`, `tablet`, `laptop`, `desktop`: Refs that are true for common device width ranges.
3982
+ * - `windowWidth`, `windowHeight`: Reactive refs for the window's width and height.
3983
+ * - `breakpoints`: The original `useBreakpoints` return object from `@vueuse/core`.
3316
3984
  */
3317
3985
  function useBreakpoint() {
3318
3986
  const breakpoints = useBreakpoints(breakpointsTailwind);
@@ -3424,15 +4092,20 @@ function useBreakpoint() {
3424
4092
  }
3425
4093
 
3426
4094
  /**
3427
- * A composable function that filters objects based on a specific field and criteria.
4095
+ * A composable function that filters an array of objects based on a specified field, data type, and criteria.
4096
+ * It supports filtering by date range, string matching (case-insensitive and diacritic-insensitive), number range, and boolean values.
3428
4097
  *
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.
4098
+ * @template T A generic type that extends a record of string keys to any value, representing the objects in the array.
4099
+ * @param {T[]} items - The array of objects to be filtered.
4100
+ * @param {object} filterConfig - The configuration object for filtering.
4101
+ * @param {string} filterConfig.field - The name of the field in the objects to filter by.
4102
+ * @param {'date' | 'string' | 'number' | 'boolean'} filterConfig.type - The data type of the field to be filtered.
4103
+ * @param {any} filterConfig.criteria - The criteria for filtering, which varies based on the `type`:
4104
+ * - For 'date': An object `{ startDate: string, endDate: string }`.
4105
+ * - For 'string': A string to search for.
4106
+ * - For 'number': An object `{ min: number, max: number }`.
4107
+ * - For 'boolean': A boolean value.
4108
+ * @returns {T[]} The filtered array of objects. If the criteria are invalid or not provided, the original array is returned.
3436
4109
  */
3437
4110
  function useFilter(items, filterConfig) {
3438
4111
  // Ensure the filterConfig is correctly structured
@@ -3481,12 +4154,20 @@ function useFilter(items, filterConfig) {
3481
4154
  }
3482
4155
 
3483
4156
  /**
3484
- * Composable to handle pagination logic.
4157
+ * A composable that provides pagination logic based on reactive refs for the current page,
4158
+ * total number of items, and items per page.
3485
4159
  *
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.
4160
+ * @param {Ref<number>} page - A reactive ref representing the current page number.
4161
+ * @param {Ref<number>} total - A reactive ref representing the total number of items to be paginated.
4162
+ * @param {Ref<number>} pageSize - A reactive ref representing the number of items per page.
4163
+ * @returns {{
4164
+ * totalPages: import('vue').ComputedRef<number>,
4165
+ * canFetchNextPage: () => boolean,
4166
+ * canFetchPreviousPage: () => boolean
4167
+ * }} An object containing:
4168
+ * - `totalPages`: A computed property that calculates the total number of pages.
4169
+ * - `canFetchNextPage`: A function that returns `true` if there is a next page.
4170
+ * - `canFetchPreviousPage`: A function that returns `true` if there is a previous page.
3490
4171
  */
3491
4172
  function usePagination(page, total, pageSize) {
3492
4173
  // Calculate the total number of pages
@@ -3503,11 +4184,16 @@ function usePagination(page, total, pageSize) {
3503
4184
  }
3504
4185
 
3505
4186
  /**
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.
4187
+ * A composable that sorts an array of objects based on a selected criterion from a list of predefined sorting options.
4188
+ * It supports sorting by number, date, boolean, and string fields, in both ascending and descending order.
4189
+ *
4190
+ * @template T The type of items in the array.
4191
+ * @param {T[]} items - The array of objects to sort.
4192
+ * @param {Array<{value: number, label: string, field: string, order: string, type: string}>} criteriaList - A list of
4193
+ * sorting criteria objects. Each object defines a sorting option with a unique `value`, a `label` for display, the `field`
4194
+ * to sort by, the `order` ('asc' or 'desc'), and the data `type` ('number', 'date', 'boolean', 'string').
4195
+ * @param {number} selectedCriteria - The `value` of the currently selected sorting criterion from the `criteriaList`.
4196
+ * @returns {ComputedRef<T[]>} A computed ref containing the sorted items. If the selected criterion is not found, the original array is returned.
3511
4197
  */
3512
4198
  function useSorter(items, criteriaList, selectedCriteria) {
3513
4199
  return computed(() => {
@@ -3539,36 +4225,58 @@ function useSorter(items, criteriaList, selectedCriteria) {
3539
4225
  return criteria.order === 'asc' ? strA.localeCompare(strB) : strB.localeCompare(strA);
3540
4226
  }
3541
4227
  });
3542
- }).value;
4228
+ });
3543
4229
  }
3544
4230
 
3545
4231
  /**
3546
4232
  * Custom hook for authentication logic, including login, logout, token management, and session preference.
4233
+ * Accepts an optional fetcher function. If not provided, uses the default configured fetcher or falls back to Axios.
4234
+ *
4235
+ * @param {Fetcher} [fetcher] - Optional fetcher function to use for auth requests. If not provided, uses the default configured fetcher.
4236
+ * @returns {{
4237
+ * logout: (params?: Record<string, unknown>) => Promise<void>,
4238
+ * login: (params: Record<string, unknown>, persistence: LocationPreference, tokenPaths?: AuthTokenPaths) => Promise<AuthResponse>
4239
+ * }} An object containing authentication functions.
3547
4240
  *
3548
- * @param {string} secretKey - The secret key used for token encryption/decryption.
3549
- * @returns {AuthHook} An object containing authentication functions.
4241
+ * @example
4242
+ * ```typescript
4243
+ * // Using default fetcher (Axios)
4244
+ * const auth = useAuth();
4245
+ *
4246
+ * // Using custom fetcher
4247
+ * const customFetcher = createOfetchFetcher();
4248
+ * const auth = useAuth(customFetcher);
4249
+ * ```
3550
4250
  */
3551
- function useAuth() {
3552
- const axiosInstance = getConfiguredAxiosInstance();
4251
+ function useAuth(fetcher) {
3553
4252
  const endpoints = getEndpointsConfig();
4253
+ const getFetcher = () => {
4254
+ return fetcher || getDefaultAuthFetcher();
4255
+ };
3554
4256
  /**
3555
4257
  * Logs out the user by making a POST request to the logout endpoint,
3556
4258
  * cleaning all stored credentials, and reloading the page.
3557
4259
  * The session persistence preference is NOT reset here; it persists across logouts.
3558
4260
  *
3559
- * @param {AuthParams} [params={}] - Optional parameters to send with the logout request.
4261
+ * @param {Record<string, unknown>} [params={}] - Optional parameters to send with the logout request.
3560
4262
  * @returns {Promise<void>}
3561
4263
  */
3562
4264
  const logout = async (params = {}) => {
3563
4265
  try {
3564
- await axiosInstance.post(endpoints.LOGOUT, params);
4266
+ await getFetcher()({
4267
+ method: 'POST',
4268
+ url: endpoints.LOGOUT,
4269
+ data: params,
4270
+ });
3565
4271
  }
3566
4272
  catch (error) {
3567
- handleError(error, false);
4273
+ handleError(error);
3568
4274
  }
3569
4275
  finally {
3570
4276
  await cleanCredentials(await getSessionPersistence());
3571
- window.location.reload();
4277
+ if (typeof window !== 'undefined') {
4278
+ window.location.reload();
4279
+ }
3572
4280
  }
3573
4281
  };
3574
4282
  /**
@@ -3583,7 +4291,11 @@ function useAuth() {
3583
4291
  */
3584
4292
  const login = async (params = {}, persistence, tokenPaths = getTokenPathsConfig()) => {
3585
4293
  try {
3586
- const { data } = await axiosInstance.post(endpoints.LOGIN, params);
4294
+ const data = await getFetcher()({
4295
+ method: 'POST',
4296
+ url: endpoints.LOGIN,
4297
+ data: params,
4298
+ });
3587
4299
  const { accessToken, refreshToken } = extractAndValidateTokens(data, tokenPaths, "LOGIN");
3588
4300
  configSession({
3589
4301
  persistencePreference: persistence,
@@ -3592,7 +4304,7 @@ function useAuth() {
3592
4304
  return data;
3593
4305
  }
3594
4306
  catch (error) {
3595
- handleError(error, false);
4307
+ handleError(error);
3596
4308
  throw error;
3597
4309
  }
3598
4310
  };
@@ -3602,17 +4314,63 @@ function useAuth() {
3602
4314
  };
3603
4315
  }
3604
4316
 
4317
+ // @ts-ignore - ofetch is an optional peer dependency
4318
+ /**
4319
+ * Creates a fetcher function using ofetch.
4320
+ *
4321
+ * @param baseURL - Optional base URL for requests
4322
+ * @param defaultOptions - Optional default options for ofetch
4323
+ * @returns A fetcher function compatible with RestStd
4324
+ *
4325
+ * @example
4326
+ * ```typescript
4327
+ * import { createOfetchFetcher, RestStd } from '@arex95/vue-core';
4328
+ *
4329
+ * export class Role extends RestStd {
4330
+ * static override resource = 'roles';
4331
+ * static fetchFn = createOfetchFetcher('https://api.example.com');
4332
+ * }
4333
+ * ```
4334
+ *
4335
+ * @example
4336
+ * ```typescript
4337
+ * import { createFetch } from 'ofetch';
4338
+ * import { createOfetchFetcher, RestStd } from '@arex95/vue-core';
4339
+ *
4340
+ * const ofetchInstance = createFetch({ baseURL: 'https://api.example.com' });
4341
+ *
4342
+ * export class Role extends RestStd {
4343
+ * static override resource = 'roles';
4344
+ * static fetchFn = createOfetchFetcher(undefined, { fetch: ofetchInstance });
4345
+ * }
4346
+ * ```
4347
+ */
4348
+ function createOfetchFetcher(baseURL, defaultOptions) {
4349
+ return async (config) => {
4350
+ const url = baseURL
4351
+ ? `${baseURL.replace(/\/$/, '')}/${config.url.replace(/^\//, '')}`
4352
+ : config.url;
4353
+ return $fetch(url, {
4354
+ method: config.method,
4355
+ query: config.params,
4356
+ body: config.data,
4357
+ headers: config.headers,
4358
+ ...defaultOptions,
4359
+ });
4360
+ };
4361
+ }
4362
+
3605
4363
  /**
3606
- * The Vue plugin for @arex95/vue-core.
3607
- * Configures the core functionalities for authentication and API communication.
4364
+ * A Vue plugin that serves as the entry point for the `@arex95/vue-core` library.
4365
+ * It initializes and configures all the core modules, such as authentication, API communication,
4366
+ * and token management, based on the provided options.
3608
4367
  */
3609
4368
  const ArexVueCore = {
3610
4369
  /**
3611
- * The `install` method is the entry point for the Vue plugin.
3612
- * It is automatically called when `app.use(ArexVueCore, options)` is executed.
4370
+ * The `install` method required by Vue's plugin system. It is called when `app.use()` is invoked.
3613
4371
  *
3614
- * @param app The Vue application instance.
3615
- * @param options The configuration options provided by the user.
4372
+ * @param {App} app - The Vue application instance.
4373
+ * @param {ArexVueCoreOptions} options - The configuration object for the library.
3616
4374
  */
3617
4375
  install: (app, options) => {
3618
4376
  if (!options) {
@@ -3648,4 +4406,4 @@ const ArexVueCore = {
3648
4406
  },
3649
4407
  };
3650
4408
 
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 };
4409
+ 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 };