nhb-toolbox 4.28.24 → 4.28.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,15 @@ All notable changes to the package will be documented here.
6
6
 
7
7
  ---
8
8
 
9
+ ## [4.28.40] - 2025-12-15
10
+
11
+ - **Added** *new class* `TextCodec` with only *static methods* to convert between `text`, `hex`, `binary`, and `Base64` representations using *byte-level transformations*.
12
+ - **Added** *new utility* `hexToBytes` with 2 new special *type guards:* `isHexString` and `isBinaryString`.
13
+
14
+ ## [4.28.30] - 2025-12-13
15
+
16
+ - **Updated** *tsdoc* for `Chronos` and *signature* of `Currency` class with generic `CurrencyCode`.
17
+
9
18
  ## [4.28.24] - 2025-12-11
10
19
 
11
20
  - **Updated** *type names* `VoidFunction` to `VoidFn`. `DelayedFn<T>` is used for both *debounced* and *throttled* functions.
@@ -34,7 +34,7 @@ Object.defineProperty(exports, "CSS_COLORS", { enumerable: true, get: function (
34
34
  var constants_3 = require("./number/constants");
35
35
  Object.defineProperty(exports, "CURRENCY_CODES", { enumerable: true, get: function () { return constants_3.CURRENCY_CODES; } });
36
36
  Object.defineProperty(exports, "CURRENCY_LOCALES", { enumerable: true, get: function () { return constants_3.CURRENCY_LOCALES; } });
37
- Object.defineProperty(exports, "FRANKFURTER_CURRENCIES", { enumerable: true, get: function () { return constants_3.SUPPORTED_CURRENCIES; } });
37
+ Object.defineProperty(exports, "FRANKFURTER_CURRENCIES", { enumerable: true, get: function () { return constants_3.FRANKFURTER_CURRENCIES; } });
38
38
  Object.defineProperty(exports, "GENERAL_UNITS", { enumerable: true, get: function () { return constants_3.UNITS; } });
39
39
  Object.defineProperty(exports, "LOCALE_CODES", { enumerable: true, get: function () { return constants_3.LOCALE_CODES; } });
40
40
  var constants_4 = require("./string/constants");
@@ -8,6 +8,8 @@ exports.isBrowser = isBrowser;
8
8
  exports.isNode = isNode;
9
9
  exports.isURL = isURL;
10
10
  exports.isBase64 = isBase64;
11
+ exports.isHexString = isHexString;
12
+ exports.isBinaryString = isBinaryString;
11
13
  exports.isPhoneNumber = isPhoneNumber;
12
14
  exports.isIPAddress = isIPAddress;
13
15
  exports.isEnvironment = isEnvironment;
@@ -49,6 +51,14 @@ function isBase64(value) {
49
51
  return ((0, primitives_1.isString)(value) &&
50
52
  /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value));
51
53
  }
54
+ function isHexString(value) {
55
+ return ((0, primitives_1.isString)(value) &&
56
+ /^[\da-fA-F\s]+$/.test(value) &&
57
+ value.replace(/\s+/g, '').length % 2 === 0);
58
+ }
59
+ function isBinaryString(value) {
60
+ return ((0, primitives_1.isString)(value) && /^[01\s]+$/.test(value) && value.replace(/\s+/g, '').length % 8 === 0);
61
+ }
52
62
  function isPhoneNumber(value) {
53
63
  return (0, primitives_1.isString)(value) && /^\+?[1-9]\d{1,14}$/.test(value);
54
64
  }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TextCodec = void 0;
4
+ const primitives_1 = require("../guards/primitives");
5
+ const specials_1 = require("../guards/specials");
6
+ const helpers_1 = require("./helpers");
7
+ const utils_1 = require("./utils");
8
+ class TextCodec {
9
+ constructor() { }
10
+ static isValidHex(hex) {
11
+ return (0, specials_1.isHexString)(hex);
12
+ }
13
+ static isValidBinary(binary) {
14
+ return (0, specials_1.isBinaryString)(binary);
15
+ }
16
+ static isValidBase64(b64) {
17
+ return (0, specials_1.isBase64)(b64);
18
+ }
19
+ static utf8ToHex(text, spaced = true) {
20
+ return [...(0, utils_1.utf8ToBytes)(text)]
21
+ .map((b) => (0, helpers_1._padStartWith0)(b, 'hex'))
22
+ .join(spaced ? ' ' : '');
23
+ }
24
+ static utf8ToBinary(text, spaced = true) {
25
+ return [...(0, utils_1.utf8ToBytes)(text)]
26
+ .map((b) => (0, helpers_1._padStartWith0)(b, 'binary'))
27
+ .join(spaced ? ' ' : '');
28
+ }
29
+ static hexToUtf8(hex) {
30
+ return (0, utils_1.bytesToUtf8)((0, utils_1.hexToBytes)(hex));
31
+ }
32
+ static binaryToUtf8(binary) {
33
+ if (!(0, specials_1.isBinaryString)(binary))
34
+ return '';
35
+ const bytes = (0, helpers_1._splitByCharLength)(binary, 8).map((b) => parseInt(b, 2));
36
+ return (0, utils_1.bytesToUtf8)(new Uint8Array(bytes));
37
+ }
38
+ static hexToBinary(hex, spaced = true) {
39
+ if (!(0, specials_1.isHexString)(hex))
40
+ return '';
41
+ return (0, helpers_1._splitByCharLength)(hex, 2)
42
+ .map((h) => (0, helpers_1._padStartWith0)(parseInt(h, 16), 'binary'))
43
+ .join(spaced ? ' ' : '');
44
+ }
45
+ static binaryToHex(binary, spaced = true) {
46
+ if (!(0, specials_1.isBinaryString)(binary))
47
+ return '';
48
+ return (0, helpers_1._splitByCharLength)(binary, 8)
49
+ .map((b) => (0, helpers_1._padStartWith0)(parseInt(b, 2), 'hex'))
50
+ .join(spaced ? ' ' : '');
51
+ }
52
+ static base64ToUtf8(b64) {
53
+ if (!(0, specials_1.isBase64)(b64))
54
+ return '';
55
+ return (0, utils_1.bytesToUtf8)((0, utils_1.base64ToBytes)(b64));
56
+ }
57
+ static utf8ToBase64(text) {
58
+ if (!(0, primitives_1.isNonEmptyString)(text))
59
+ return '';
60
+ return (0, utils_1.bytesToBase64)((0, utils_1.utf8ToBytes)(text));
61
+ }
62
+ static base64ToHex(b64, spaced = true) {
63
+ return this.utf8ToHex(this.base64ToUtf8(b64), spaced);
64
+ }
65
+ static base64ToBinary(b64, spaced = true) {
66
+ return this.utf8ToBinary(this.base64ToUtf8(b64), spaced);
67
+ }
68
+ static hexToBase64(hex) {
69
+ return this.utf8ToBase64(this.hexToUtf8(hex));
70
+ }
71
+ static binaryToBase64(binary) {
72
+ return this.utf8ToBase64(this.binaryToUtf8(binary));
73
+ }
74
+ }
75
+ exports.TextCodec = TextCodec;
@@ -10,6 +10,8 @@ exports._formatUUID = _formatUUID;
10
10
  exports._isOptionV3V5 = _isOptionV3V5;
11
11
  exports._checkUUIDVersion = _checkUUIDVersion;
12
12
  exports._constantTimeEquals = _constantTimeEquals;
13
+ exports._splitByCharLength = _splitByCharLength;
14
+ exports._padStartWith0 = _padStartWith0;
13
15
  const non_primitives_1 = require("../guards/non-primitives");
14
16
  const primitives_1 = require("../guards/primitives");
15
17
  const specials_1 = require("../guards/specials");
@@ -168,3 +170,16 @@ function _constantTimeEquals(a, b) {
168
170
  }
169
171
  return res === 0;
170
172
  }
173
+ function _splitByCharLength(str, splitByChars = 2) {
174
+ if (!(0, primitives_1.isNonEmptyString)(str))
175
+ return [];
176
+ const sanitized = str.replace(/\s+/g, '');
177
+ const result = [];
178
+ for (let i = 0; i < sanitized.length; i += splitByChars) {
179
+ result.push(sanitized.slice(i, i + splitByChars));
180
+ }
181
+ return result;
182
+ }
183
+ function _padStartWith0(byte, type) {
184
+ return byte.toString(type === 'hex' ? 16 : 2).padStart(type === 'hex' ? 2 : 8, '0');
185
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.uuid = exports.isUUIDv8 = exports.isUUIDv7 = exports.isUUIDv6 = exports.isUUIDv5 = exports.isUUIDv4 = exports.isUUIDv3 = exports.isUUIDv2 = exports.isUUIDv1 = exports.decodeUUID = exports.utf8ToBytes = exports.uint8To32ArrayBE = exports.sha256Bytes = exports.randomHex = exports.intTo4BytesBE = exports.hmacSha256 = exports.concatBytes = exports.bytesToUtf8 = exports.bytesToHex = exports.bytesToBase64 = exports.base64ToBytes = exports.Signet = exports.sha256 = exports.sha1 = exports.md5 = exports.Cipher = exports.randomID = exports.generateRandomID = exports.isUUID = void 0;
3
+ exports.uuid = exports.isUUIDv8 = exports.isUUIDv7 = exports.isUUIDv6 = exports.isUUIDv5 = exports.isUUIDv4 = exports.isUUIDv3 = exports.isUUIDv2 = exports.isUUIDv1 = exports.decodeUUID = exports.utf8ToBytes = exports.uint8To32ArrayBE = exports.sha256Bytes = exports.randomHex = exports.intTo4BytesBE = exports.hmacSha256 = exports.hexToBytes = exports.concatBytes = exports.bytesToUtf8 = exports.bytesToHex = exports.bytesToBase64 = exports.base64ToBytes = exports.TextCodec = exports.Signet = exports.sha256 = exports.sha1 = exports.md5 = exports.Cipher = exports.randomID = exports.generateRandomID = exports.isUUID = void 0;
4
4
  var specials_1 = require("../guards/specials");
5
5
  Object.defineProperty(exports, "isUUID", { enumerable: true, get: function () { return specials_1.isUUID; } });
6
6
  var basics_1 = require("../string/basics");
@@ -14,12 +14,15 @@ Object.defineProperty(exports, "sha1", { enumerable: true, get: function () { re
14
14
  Object.defineProperty(exports, "sha256", { enumerable: true, get: function () { return core_1.sha256; } });
15
15
  var Signet_1 = require("./Signet");
16
16
  Object.defineProperty(exports, "Signet", { enumerable: true, get: function () { return Signet_1.Signet; } });
17
+ var TextCodec_1 = require("./TextCodec");
18
+ Object.defineProperty(exports, "TextCodec", { enumerable: true, get: function () { return TextCodec_1.TextCodec; } });
17
19
  var utils_1 = require("./utils");
18
20
  Object.defineProperty(exports, "base64ToBytes", { enumerable: true, get: function () { return utils_1.base64ToBytes; } });
19
21
  Object.defineProperty(exports, "bytesToBase64", { enumerable: true, get: function () { return utils_1.bytesToBase64; } });
20
22
  Object.defineProperty(exports, "bytesToHex", { enumerable: true, get: function () { return utils_1.bytesToHex; } });
21
23
  Object.defineProperty(exports, "bytesToUtf8", { enumerable: true, get: function () { return utils_1.bytesToUtf8; } });
22
24
  Object.defineProperty(exports, "concatBytes", { enumerable: true, get: function () { return utils_1.concatBytes; } });
25
+ Object.defineProperty(exports, "hexToBytes", { enumerable: true, get: function () { return utils_1.hexToBytes; } });
23
26
  Object.defineProperty(exports, "hmacSha256", { enumerable: true, get: function () { return utils_1.hmacSha256; } });
24
27
  Object.defineProperty(exports, "intTo4BytesBE", { enumerable: true, get: function () { return utils_1.intTo4BytesBE; } });
25
28
  Object.defineProperty(exports, "randomHex", { enumerable: true, get: function () { return utils_1.randomHex; } });
@@ -11,6 +11,9 @@ exports.hmacSha256 = hmacSha256;
11
11
  exports.uint8To32ArrayBE = uint8To32ArrayBE;
12
12
  exports.intTo4BytesBE = intTo4BytesBE;
13
13
  exports.bytesToHex = bytesToHex;
14
+ exports.hexToBytes = hexToBytes;
15
+ const specials_1 = require("../guards/specials");
16
+ const helpers_1 = require("./helpers");
14
17
  function randomHex(length, uppercase = false) {
15
18
  const genHex = () => Math.floor(Math.random() * 16).toString(16);
16
19
  const hex = Array.from({ length }, genHex).join('');
@@ -250,3 +253,9 @@ function bytesToHex(bytes) {
250
253
  }
251
254
  return hex;
252
255
  }
256
+ function hexToBytes(hex) {
257
+ if (!(0, specials_1.isHexString)(hex))
258
+ return new Uint8Array();
259
+ const bytes = (0, helpers_1._splitByCharLength)(hex, 2).map((h) => parseInt(h, 16));
260
+ return new Uint8Array(bytes);
261
+ }
package/dist/cjs/index.js CHANGED
@@ -7,7 +7,7 @@ exports.formatDateTime = exports.formatDate = exports.extractTotalMinutesFromTim
7
7
  exports.convertIntoFormData = exports.splitArrayByProperty = exports.splitArray = exports.rotateArray = exports.removeDuplicatesFromArray = exports.removeDuplicates = exports.moveArrayElement = exports.groupArrayByProperty = exports.getMissingElements = exports.getDuplicatesFromArray = exports.getDuplicates = exports.findMissingElements = exports.extractMissingElements = exports.extractDuplicatesFromArray = exports.extractDuplicates = exports.createOptionsArray = exports.sortAnArray = exports.naturalSortForString = exports.naturalSort = exports.compareSorter = exports.compareNaturally = exports.Finder = exports.totalDeltaByField = exports.sumFieldDifference = exports.sumByField = exports.groupAndSumByField = exports.groupAndAvgByField = exports.groupAndAverageByField = exports.avgByField = exports.averageByField = exports.shuffleArray = exports.isValidEmptyArray = exports.isInvalidOrEmptyArray = exports.getLastArrayElement = exports.flattenArray = exports.filterArrayOfObjects = exports.minutesToUTCOffset = exports.getTotalMinutesFromUTC = exports.getTotalMinutesFromTime = exports.getTotalMinutes = exports.getTimeZoneIds = exports.getTimeZoneDetails = exports.getTimeStringFromUTC = exports.getTimeFromMinutes = exports.getNativeTimeZoneId = exports.getMinutesFromUTC = exports.getHourMinutesFromMinutes = exports.getCurrentTime = exports.getCurrentDateTime = exports.formatUTCOffset = void 0;
8
8
  exports.parseQueryStringLiteral = exports.parseQueryString = exports.literalQueryStringToObject = exports.getQueryStringAsObject = exports.getQueryParams = exports.generateQueryParams = exports.formatQueryParams = exports.createQueryParams = exports.removeObjectFields = exports.removeFields = exports.remapObjectFields = exports.remapFields = exports.pickObjectFieldsByCondition = exports.pickObjectFields = exports.pickFieldsByCondition = exports.pickFields = exports.omitObjectFields = exports.omitFields = exports.deleteObjectFields = exports.deleteFields = exports.convertObjectValues = exports.sanitizeData = exports.parseStringifiedObjectValues = exports.parseObjectValues = exports.parseJsonToObject = exports.mergeObjects = exports.mergeAndFlattenObjects = exports.flattenObjectKeyValue = exports.flattenObjectDotNotation = exports.extractUpdatedFields = exports.extractUpdatedAndNewFields = exports.extractNewFields = exports.extractObjectKeysDeep = exports.extractObjectKeys = exports.extractKeysDeep = exports.extractKeys = exports.countObjectFields = exports.cloneObject = exports.isValidFormData = exports.isOriginFileObj = exports.isFileUpload = exports.isFileOrBlob = exports.isFileList = exports.isFileArray = exports.isCustomFileArray = exports.isCustomFile = exports.serializeForm = exports.parseFormData = exports.createFormData = exports.createControlledFormData = void 0;
9
9
  exports.isArrayOfType = exports.isArray = exports.doesReturnPromise = exports.isUndefined = exports.isTruthy = exports.isSymbol = exports.isString = exports.isPrimitive = exports.isPositiveInteger = exports.isNumber = exports.isNull = exports.isNormalPrimitive = exports.isNonEmptyString = exports.isInteger = exports.isFalsy = exports.isBoolean = exports.isBigInt = exports.Paginator = exports.throttleAction = exports.stripJsonEdgeGarbage = exports.stableStringify = exports.parsePrimitivesDeep = exports.parseJsonDeep = exports.parseJSON = exports.joinArrayElements = exports.isDeepEqual = exports.getStaticMethodsCount = exports.getStaticMethodNames = exports.getStaticGetterNames = exports.getInstanceMethodsCount = exports.getInstanceMethodNames = exports.getInstanceGetterNames = exports.getClassDetails = exports.definePrototypeMethod = exports.deepParsePrimitives = exports.debounceAction = exports.countStaticMethods = exports.countInstanceMethods = exports.convertArrayToString = exports.saveToSessionStorage = exports.saveToLocalStorage = exports.removeFromSessionStorage = exports.removeFromLocalStorage = exports.getFromSessionStorage = exports.getFromLocalStorage = exports.toggleFullScreen = exports.smoothScrollTo = exports.copyToClipboard = exports.updateQueryParam = exports.queryStringToObject = void 0;
10
- exports.isValidURL = exports.isValidEmail = exports.isUUID = exports.isURL = exports.isPhoneNumber = exports.isNumericString = exports.isNodeEnvironment = exports.isNodeENV = exports.isNode = exports.isIPAddress = exports.isExpectedNodeENV = exports.isEnvironment = exports.isEmailArray = exports.isEmail = exports.isDateString = exports.isBrowser = exports.isBase64 = exports.httpStatus = exports.HttpStatus = exports.isValidSet = exports.isValidObject = exports.isValidMap = exports.isValidJSON = exports.isValidArray = exports.isSet = exports.isReturningPromise = exports.isRegularExpression = exports.isRegExp = exports.isPromise = exports.isObjectWithKeys = exports.isObjectEmpty = exports.isObject = exports.isNotEmptyObject = exports.isMethodDescriptor = exports.isMethod = exports.isMap = exports.isJSONObject = exports.isJSON = exports.isFunction = exports.isError = exports.isEmptyObjectGuard = exports.isEmptyObject = exports.isDate = exports.isArrayWithLength = void 0;
10
+ exports.isValidURL = exports.isValidEmail = exports.isUUID = exports.isURL = exports.isPhoneNumber = exports.isNumericString = exports.isNodeEnvironment = exports.isNodeENV = exports.isNode = exports.isIPAddress = exports.isHexString = exports.isExpectedNodeENV = exports.isEnvironment = exports.isEmailArray = exports.isEmail = exports.isDateString = exports.isBrowser = exports.isBinaryString = exports.isBase64 = exports.httpStatus = exports.HttpStatus = exports.isValidSet = exports.isValidObject = exports.isValidMap = exports.isValidJSON = exports.isValidArray = exports.isSet = exports.isReturningPromise = exports.isRegularExpression = exports.isRegExp = exports.isPromise = exports.isObjectWithKeys = exports.isObjectEmpty = exports.isObject = exports.isNotEmptyObject = exports.isMethodDescriptor = exports.isMethod = exports.isMap = exports.isJSONObject = exports.isJSON = exports.isFunction = exports.isError = exports.isEmptyObjectGuard = exports.isEmptyObject = exports.isDate = exports.isArrayWithLength = void 0;
11
11
  var basics_1 = require("./string/basics");
12
12
  Object.defineProperty(exports, "generateRandomID", { enumerable: true, get: function () { return basics_1.generateRandomID; } });
13
13
  Object.defineProperty(exports, "trimString", { enumerable: true, get: function () { return basics_1.trimString; } });
@@ -439,12 +439,14 @@ Object.defineProperty(exports, "HttpStatus", { enumerable: true, get: function (
439
439
  Object.defineProperty(exports, "httpStatus", { enumerable: true, get: function () { return HttpStatus_1.httpStatus; } });
440
440
  var specials_1 = require("./guards/specials");
441
441
  Object.defineProperty(exports, "isBase64", { enumerable: true, get: function () { return specials_1.isBase64; } });
442
+ Object.defineProperty(exports, "isBinaryString", { enumerable: true, get: function () { return specials_1.isBinaryString; } });
442
443
  Object.defineProperty(exports, "isBrowser", { enumerable: true, get: function () { return specials_1.isBrowser; } });
443
444
  Object.defineProperty(exports, "isDateString", { enumerable: true, get: function () { return specials_1.isDateString; } });
444
445
  Object.defineProperty(exports, "isEmail", { enumerable: true, get: function () { return specials_1.isEmail; } });
445
446
  Object.defineProperty(exports, "isEmailArray", { enumerable: true, get: function () { return specials_1.isEmailArray; } });
446
447
  Object.defineProperty(exports, "isEnvironment", { enumerable: true, get: function () { return specials_1.isEnvironment; } });
447
448
  Object.defineProperty(exports, "isExpectedNodeENV", { enumerable: true, get: function () { return specials_1.isEnvironment; } });
449
+ Object.defineProperty(exports, "isHexString", { enumerable: true, get: function () { return specials_1.isHexString; } });
448
450
  Object.defineProperty(exports, "isIPAddress", { enumerable: true, get: function () { return specials_1.isIPAddress; } });
449
451
  Object.defineProperty(exports, "isNode", { enumerable: true, get: function () { return specials_1.isNode; } });
450
452
  Object.defineProperty(exports, "isNodeENV", { enumerable: true, get: function () { return specials_1.isEnvironment; } });
@@ -11,37 +11,37 @@ class Currency {
11
11
  this.#code = code;
12
12
  this.currency = this.format('en-US');
13
13
  }
14
- static #rateCache = new Map();
14
+ static #RATE_CACHE = new Map();
15
15
  static clearRateCache() {
16
- Currency.#rateCache.clear();
16
+ Currency.#RATE_CACHE.clear();
17
17
  }
18
18
  format(locale, code) {
19
19
  return (0, utilities_1.formatCurrency)(this.#amount, code ?? this.#code, locale);
20
20
  }
21
21
  async convert(to, options) {
22
22
  const key = `${this.#code}->${to}`;
23
- if (!options?.forceRefresh && Currency.#rateCache.has(key)) {
24
- const cachedRate = Currency.#rateCache.get(key);
23
+ if (!options?.forceRefresh && Currency.#RATE_CACHE.has(key)) {
24
+ const cachedRate = Currency.#RATE_CACHE.get(key);
25
25
  return new Currency(this.#amount * cachedRate, to);
26
26
  }
27
27
  try {
28
28
  const rate = await this.#fetchFromFrankfurter(to);
29
- Currency.#rateCache.set(key, rate);
29
+ Currency.#RATE_CACHE.set(key, rate);
30
30
  return new Currency(this.#amount * rate, to);
31
31
  }
32
32
  catch (error) {
33
33
  if (options?.fallbackRate != null) {
34
- console.warn(`Currency conversion failed (${this.#code} → ${to}): ${error.message}. Using fallback rate...`);
34
+ console.warn(`Currency conversion failed (${this.#code} → ${to}): ${error?.message}. Using fallback rate...`);
35
35
  return new Currency(this.#amount * options.fallbackRate, to);
36
36
  }
37
37
  else {
38
- throw new Error(`Currency conversion failed (${this.#code} → ${to}): ${error.message}`);
38
+ throw new Error(`Currency conversion failed (${this.#code} → ${to}): ${error?.message}`);
39
39
  }
40
40
  }
41
41
  }
42
42
  convertSync(to, rate) {
43
43
  const key = `${this.#code}->${to}`;
44
- const cachedRate = Currency.#rateCache.get(key);
44
+ const cachedRate = Currency.#RATE_CACHE.get(key);
45
45
  if (cachedRate) {
46
46
  return new Currency(this.#amount * cachedRate, to);
47
47
  }
@@ -53,7 +53,7 @@ class Currency {
53
53
  }
54
54
  }
55
55
  async #fetchFromFrankfurter(to) {
56
- const url = `https://api.frankfurter.app/latest?amount=${this.#amount}&from=${this.#code}`;
56
+ const url = `https://api.frankfurter.app/latest?amount=1&from=${this.#code}`;
57
57
  try {
58
58
  const res = await fetch(url, { redirect: 'error' });
59
59
  if (!res.ok) {
@@ -61,12 +61,12 @@ class Currency {
61
61
  }
62
62
  const data = await res.json();
63
63
  if (!data.rates?.[to]) {
64
- throw new Error(`Currency "${to}" not allowed or not found in FrankFurter Database!`);
64
+ throw new Error(`Currency "${to}" is not found in FrankFurter Database!`);
65
65
  }
66
- return data.rates[to] / this.#amount;
66
+ return data.rates[to];
67
67
  }
68
68
  catch (error) {
69
- throw new Error(error.message || `Failed to fetch data from FrankFurter API`);
69
+ throw new Error(error?.message || `Failed to fetch data from FrankFurter API`);
70
70
  }
71
71
  }
72
72
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PREFIX_MULTIPLIERS = exports.UNITS = exports.SUPPORTED_CURRENCIES = exports.CURRENCY_LOCALES = exports.LOCALE_CODES = exports.CURRENCY_CODES = exports.ORDINAL_TO_CARDINAL = exports.ORDINAL_UNDER_TEEN = exports.THOUSANDS = exports.TENS = exports.TEENS = exports.ONES = void 0;
3
+ exports.PREFIX_MULTIPLIERS = exports.UNITS = exports.FRANKFURTER_CURRENCIES = exports.CURRENCY_LOCALES = exports.LOCALE_CODES = exports.CURRENCY_CODES = exports.ORDINAL_TO_CARDINAL = exports.ORDINAL_UNDER_TEEN = exports.THOUSANDS = exports.TENS = exports.TEENS = exports.ONES = void 0;
4
4
  exports.ONES = /* @__PURE__ */ Object.freeze([
5
5
  '',
6
6
  'one',
@@ -541,7 +541,7 @@ exports.CURRENCY_LOCALES = /* @__PURE__ */ Object.freeze({
541
541
  ZMW: 'en-ZM',
542
542
  ZWL: 'en-ZW',
543
543
  });
544
- exports.SUPPORTED_CURRENCIES = /* @__PURE__ */ Object.freeze([
544
+ exports.FRANKFURTER_CURRENCIES = /* @__PURE__ */ Object.freeze([
545
545
  'AUD',
546
546
  'BGN',
547
547
  'BRL',
@@ -3,7 +3,7 @@ export { IANA_TZ_IDS, NATIVE_TZ_IDS, TIME_ZONE_IDS, TIME_ZONE_LABELS, TIME_ZONES
3
3
  export { AUSTRALIA_SEASONS, BANGLADESH_SEASONS, ETHIOPIA_SEASONS, INDIA_IMD_SEASONS, INDIA_TAMIL_SEASONS, INDIA_VEDIC_SEASONS, JAPAN_SEASONS, PHILIPPINES_SEASONS, SEASON_PRESETS, US_ACADEMIC_SEASONS, DEFAULT_SEASONS as WESTERN_SEASONS, } from './date/seasons';
4
4
  export { ALPHABET_COLOR_PALETTE, NUMBER_COLOR_PALETTE } from './colors/constants';
5
5
  export { CSS_COLORS } from './colors/css-colors';
6
- export { CURRENCY_CODES, CURRENCY_LOCALES, SUPPORTED_CURRENCIES as FRANKFURTER_CURRENCIES, UNITS as GENERAL_UNITS, LOCALE_CODES, } from './number/constants';
6
+ export { CURRENCY_CODES, CURRENCY_LOCALES, FRANKFURTER_CURRENCIES, UNITS as GENERAL_UNITS, LOCALE_CODES, } from './number/constants';
7
7
  export { LOWERCASE as LOWERCASED_WORDS } from './string/constants';
8
8
  export { UNITS as CATEGORIZED_UNITS } from './converter/constants';
9
9
  export { COUNTRIES } from './object/countries';
@@ -3,16 +3,17 @@ import type { LooseLiteral, TupleOf } from '../utils/types';
3
3
  import { INTERNALS } from './constants';
4
4
  import type { $NativeTzNameOrId, $TimeZoneIdentifier, $UTCOffset, ChronosInput, ChronosInternals, ChronosMethods, ChronosObject, ChronosPlugin, ChronosWithOptions, DateRangeOptions, DateTimeFormatOptions, FormatOptions, LocalesArguments, Milliseconds, MonthName, Quarter, RangeWithDates, RelativeDateRange, RelativeRangeOptions, StrictFormat, TimeParts, TimeUnit, TimeUnitValue, TimeZone, TimeZoneId, TimeZoneIdNative, TimeZoneName, UTCOffset, WeekDay } from './types';
5
5
  /**
6
- * * Creates a new immutable local-aware `Chronos` instance.
6
+ * * Creates a new immutable `Chronos` instance.
7
7
  *
8
- * **Note**: *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC
9
- * and convert it to the **equivalent local time** using the current environment's UTC offset.*
8
+ * **Note**:
9
+ * - *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC and convert it to the **equivalent local time** using the current environment's UTC offset.*
10
10
  *
11
11
  * @param value - A date value (`number`, `string`, `Date`, or `Chronos` object).
12
- * - If a string is provided, it should be in a format that can be parsed by the `Date` constructor.
12
+ *
13
+ * @remarks
14
+ * - If a string is provided, it should be in a format that can be parsed by the {@link Date} constructor.
13
15
  * - If a number is provided, it should be a timestamp (milliseconds since the Unix epoch).
14
- * - If a `Date` object is provided, it will be used as is.
15
- * - If a `Chronos` object is provided, it will be converted to a `Date` object.
16
+ * - If a `Date` or `Chronos` object is provided, it will be handled internally to parse the date value.
16
17
  *
17
18
  * **It also accepts number values as following:**
18
19
  * - **`year, month, date, hours, minutes, seconds, milliseconds`**: Individual components of a date-time to construct a `Chronos` instance.
@@ -68,7 +69,7 @@ export declare class Chronos {
68
69
  /** Tracker to identify the instance created by {@link https://toolbox.nazmul-nhb.dev/docs/classes/Chronos/conversion#timezone timeZone} method */
69
70
  protected $tzTracker?: $TimeZoneIdentifier | TimeZone | UTCOffset;
70
71
  /**
71
- * * Creates a new immutable local-aware `Chronos` instance.
72
+ * * Creates a new immutable `Chronos` instance.
72
73
  *
73
74
  * Accepts no arguments (defaults to now).
74
75
  *
@@ -76,7 +77,7 @@ export declare class Chronos {
76
77
  */
77
78
  constructor();
78
79
  /**
79
- * * Creates a new immutable local-aware `Chronos` instance.
80
+ * * Creates a new immutable `Chronos` instance.
80
81
  *
81
82
  * @param value - A date value in `number`, it should be a timestamp (milliseconds since the Unix epoch).
82
83
  *
@@ -84,26 +85,25 @@ export declare class Chronos {
84
85
  */
85
86
  constructor(value: number);
86
87
  /**
87
- * * Creates a new immutable local-aware `Chronos` instance.
88
+ * * Creates a new immutable `Chronos` instance.
88
89
  *
89
- * **Note**: *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC
90
- * and convert it to the **equivalent local time** using the current environment's UTC offset.*
90
+ * **Note**: *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC and convert it to the **equivalent local time** using the current environment's UTC offset.*
91
91
  *
92
- * @param value - A date value in `string`, it should be in a format that can be parsed by the `Date` constructor.
92
+ * @param value - A date value in `string`, it should be in a format that can be parsed by the {@link Date} constructor.
93
93
  *
94
94
  * @returns Instance of `Chronos` with all methods and properties.
95
95
  */
96
96
  constructor(value: string);
97
97
  /**
98
- * * Creates a new immutable local-aware `Chronos` instance.
98
+ * * Creates a new immutable `Chronos` instance.
99
99
  *
100
- * @param value - A date value as `Date` object, it will be used as is.
100
+ * @param value - A date value as {@link Date} object.
101
101
  *
102
102
  * @returns Instance of `Chronos` with all methods and properties.
103
103
  */
104
104
  constructor(value: Date);
105
105
  /**
106
- * * Creates a new immutable local-aware `Chronos` instance.
106
+ * * Creates a new immutable `Chronos` instance.
107
107
  *
108
108
  * @param value - A date value as `Chronos` object.
109
109
  *
@@ -111,10 +111,9 @@ export declare class Chronos {
111
111
  */
112
112
  constructor(value: Chronos);
113
113
  /**
114
- * * Creates a new immutable local-aware `Chronos` instance.
114
+ * * Creates a new immutable `Chronos` instance.
115
115
  *
116
- * **Note**: *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC
117
- * and convert it to the **equivalent local time** using the current environment's UTC offset.*
116
+ * **Note**: *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC and convert it to the **equivalent local time** using the current environment's UTC offset.*
118
117
  *
119
118
  * @param year The full year designation is required for cross-century date accuracy. If year is between 0 and 99, year is assumed to be 1900 + year.
120
119
  * @param month The month as a `number` between 1 and 12 (January to December).
@@ -128,10 +127,9 @@ export declare class Chronos {
128
127
  */
129
128
  constructor(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number);
130
129
  /**
131
- * * Creates a new immutable local-aware `Chronos` instance.
130
+ * * Creates a new immutable `Chronos` instance.
132
131
  *
133
- * **Note**: *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC
134
- * and convert it to the **equivalent local time** using the current environment's UTC offset.*
132
+ * **Note**: *If a date is provided **without a time component**, the instance will default to `00:00:00.000` UTC and convert it to the **equivalent local time** using the current environment's UTC offset.*
135
133
  *
136
134
  * @param value - A date value (`number`, `string`, `Date`, or `Chronos` object).
137
135
  * - If a `string` is provided, it should be in a format that can be parsed by the `Date` constructor.
@@ -45,6 +45,18 @@ export declare function isURL(value: unknown): value is string;
45
45
  * @returns `true` if the value is a valid Base64 string, otherwise `false`.
46
46
  */
47
47
  export declare function isBase64(value: unknown): value is string;
48
+ /**
49
+ * * Type guard to check if a value is a valid hexadecimal byte sequence.
50
+ * @param value - The value to check, spaced between bytes or un-spaced.
51
+ * @returns `true` if the value is a valid hexadecimal byte sequence, otherwise `false`.
52
+ */
53
+ export declare function isHexString(value: unknown): value is string;
54
+ /**
55
+ * * Type guard to check if a value is a valid binary byte sequence.
56
+ * @param value - The value to check, spaced between bytes or un-spaced.
57
+ * @returns `true` if the value is a valid binary byte sequence, otherwise `false`.
58
+ */
59
+ export declare function isBinaryString(value: unknown): value is string;
48
60
  /**
49
61
  * * Type guard to check if a value is a valid phone number.
50
62
  * @param value - The value to check.
@@ -66,8 +78,9 @@ export declare function isEnvironment(env: string): boolean;
66
78
  /**
67
79
  * * Type guard to check if a value is a string representing a finite number.
68
80
  *
69
- * Accepts strings like: `"42"`, `" -5.5 "`, `"0.123"`, `"-0"`, `"1e5"`.
70
- * Rejects strings like: `"NaN"`, `"Infinity"`, `"-Infinity"`, `"abc"`, `""`, `"42abc"`.
81
+ * @remarks
82
+ * - Accepts strings like: `"42"`, `" -5.5 "`, `"0.123"`, `"-0"`, `"1e5"`.
83
+ * - Rejects strings like: `"NaN"`, `"Infinity"`, `"-Infinity"`, `"abc"`, `""`, `"42abc"`.
71
84
  *
72
85
  * @param value - The value to test.
73
86
  * @returns `true` if the value is a string that fully represents a finite number.
@@ -0,0 +1,166 @@
1
+ /**
2
+ * @class `TextCodec` provides **UTF-8–safe** conversions between `text`, `hex`, `binary`, and `Base64` representations using byte-level transformations.
3
+ *
4
+ * @example
5
+ * TextCodec.utf8ToHex('ভাষা'); // 'e0 a6 ad e0 a6 be e0 a6 b7 e0 a6 be'
6
+ * TextCodec.hexToUtf8('e0 a6 ad e0 a6 be'); // 'ভা'
7
+ */
8
+ export declare class TextCodec {
9
+ private constructor();
10
+ /**
11
+ * @static Validates whether a string represents a valid hexadecimal byte sequence.
12
+ *
13
+ * @param hex - Hex string, spaced or un-spaced (e.g. "ff 0a" or "ff0a")
14
+ * @returns `true` if the input is valid hex byte string
15
+ *
16
+ * @example
17
+ * TextCodec.isValidHex('ff 0a');
18
+ */
19
+ static isValidHex(hex: string): boolean;
20
+ /**
21
+ * @static Validates whether a string represents a valid binary byte sequence.
22
+ *
23
+ * @param binary - Binary string, spaced or un-spaced
24
+ * @returns `true` if the input is valid binary byte string
25
+ *
26
+ * @example
27
+ * TextCodec.isValidBinary('01000001');
28
+ */
29
+ static isValidBinary(binary: string): boolean;
30
+ /**
31
+ * @static Validates whether a string represents a valid Base64-encoded string.
32
+ *
33
+ * @param b64 - Base64 string to check
34
+ * @returns `true` if the input is valid Base64-encoded string
35
+ *
36
+ * @example
37
+ * TextCodec.isValidBase64('SGVsbG8=');
38
+ */
39
+ static isValidBase64(b64: string): boolean;
40
+ /**
41
+ * @static Converts UTF-8 text into hexadecimal byte representation.
42
+ *
43
+ * @param text - UTF-8 text to convert
44
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
45
+ * @returns Hexadecimal byte string
46
+ *
47
+ * @example
48
+ * TextCodec.utf8ToHex('Hi');
49
+ */
50
+ static utf8ToHex(text: string, spaced?: boolean): string;
51
+ /**
52
+ * @static Converts UTF-8 text into binary byte representation.
53
+ *
54
+ * @param text - UTF-8 text to convert
55
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
56
+ * @returns Binary byte string
57
+ *
58
+ * @example
59
+ * TextCodec.utf8ToBinary('A');
60
+ */
61
+ static utf8ToBinary(text: string, spaced?: boolean): string;
62
+ /**
63
+ * @static Converts hexadecimal byte string into UTF-8 text.
64
+ *
65
+ * @param hex - Hexadecimal byte string
66
+ * @returns Decoded UTF-8 text
67
+ *
68
+ * @example
69
+ * TextCodec.hexToUtf8('48 69');
70
+ */
71
+ static hexToUtf8(hex: string): string;
72
+ /**
73
+ * @static Converts binary byte string into UTF-8 text.
74
+ *
75
+ * @param binary - Binary byte string
76
+ * @returns Decoded UTF-8 text
77
+ *
78
+ * @example
79
+ * TextCodec.binaryToUtf8('01001000 01101001');
80
+ */
81
+ static binaryToUtf8(binary: string): string;
82
+ /**
83
+ * @static Converts hexadecimal byte string into binary byte string.
84
+ *
85
+ * @param hex - Hexadecimal byte string
86
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
87
+ * @returns Binary byte string
88
+ *
89
+ * @example
90
+ * TextCodec.hexToBinary('ff');
91
+ */
92
+ static hexToBinary(hex: string, spaced?: boolean): string;
93
+ /**
94
+ * @static Converts binary byte string into hexadecimal byte string.
95
+ *
96
+ * @param binary - Binary byte string
97
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
98
+ * @returns Hexadecimal byte string
99
+ *
100
+ * @example
101
+ * TextCodec.binaryToHex('00000001');
102
+ */
103
+ static binaryToHex(binary: string, spaced?: boolean): string;
104
+ /**
105
+ * @static Converts a Base64-encoded string into UTF-8 text.
106
+ *
107
+ * @param b64 - Base64 encoded string
108
+ * @returns Decoded UTF-8 text
109
+ *
110
+ * @example
111
+ * TextCodec.base64ToUtf8('SGVsbG8=');
112
+ */
113
+ static base64ToUtf8(b64: string): string;
114
+ /**
115
+ * @static Converts UTF-8 text into a Base64-encoded string.
116
+ *
117
+ * @param text - UTF-8 text to encode
118
+ * @returns Base64 encoded string
119
+ *
120
+ * @example
121
+ * TextCodec.utf8ToBase64('Hello');
122
+ */
123
+ static utf8ToBase64(text: string): string;
124
+ /**
125
+ * @static Converts Base64 directly into hexadecimal byte string.
126
+ *
127
+ * @param b64 - Base64 encoded string
128
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
129
+ * @returns Hexadecimal byte string
130
+ *
131
+ * @example
132
+ * TextCodec.base64ToHex('SGVsbG8=');
133
+ */
134
+ static base64ToHex(b64: string, spaced?: boolean): string;
135
+ /**
136
+ * @static Converts Base64 directly into binary byte string.
137
+ *
138
+ * @param b64 - Base64 encoded string
139
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
140
+ * @returns Binary byte string
141
+ *
142
+ * @example
143
+ * TextCodec.base64ToBinary('SGVsbG8=');
144
+ */
145
+ static base64ToBinary(b64: string, spaced?: boolean): string;
146
+ /**
147
+ * @static Converts hexadecimal byte string into a Base64 string.
148
+ *
149
+ * @param hex - Hexadecimal byte string
150
+ * @returns Base64 encoded string
151
+ *
152
+ * @example
153
+ * TextCodec.hexToBase64('48 69');
154
+ */
155
+ static hexToBase64(hex: string): string;
156
+ /**
157
+ * @static Converts binary byte string into a Base64 string.
158
+ *
159
+ * @param binary - Binary byte string
160
+ * @returns Base64 encoded string
161
+ *
162
+ * @example
163
+ * TextCodec.binaryToBase64('01001000 01101001');
164
+ */
165
+ static binaryToBase64(binary: string): string;
166
+ }
@@ -28,3 +28,7 @@ export declare function _checkUUIDVersion(value: unknown, v: `${$UUIDVersion}`):
28
28
  * Prevents timing attacks by ensuring equal-time checks regardless of data differences.
29
29
  */
30
30
  export declare function _constantTimeEquals(a: string | Uint8Array, b: string | Uint8Array): boolean;
31
+ /** Split string by substring length */
32
+ export declare function _splitByCharLength(str: string, splitByChars?: number): string[];
33
+ /** Pad start of a byte with 0 for `hex` or `binary` */
34
+ export declare function _padStartWith0(byte: number, type: 'hex' | 'binary'): string;
@@ -3,5 +3,6 @@ export { generateRandomID, generateRandomID as randomID } from '../string/basics
3
3
  export { Cipher } from './Cipher';
4
4
  export { md5, sha1, sha256 } from './core';
5
5
  export { Signet } from './Signet';
6
- export { base64ToBytes, bytesToBase64, bytesToHex, bytesToUtf8, concatBytes, hmacSha256, intTo4BytesBE, randomHex, sha256Bytes, uint8To32ArrayBE, utf8ToBytes, } from './utils';
6
+ export { TextCodec } from './TextCodec';
7
+ export { base64ToBytes, bytesToBase64, bytesToHex, bytesToUtf8, concatBytes, hexToBytes, hmacSha256, intTo4BytesBE, randomHex, sha256Bytes, uint8To32ArrayBE, utf8ToBytes, } from './utils';
7
8
  export { decodeUUID, isUUIDv1, isUUIDv2, isUUIDv3, isUUIDv4, isUUIDv5, isUUIDv6, isUUIDv7, isUUIDv8, uuid, } from './uuid';
@@ -343,6 +343,48 @@ export declare function intTo4BytesBE(n: number): Uint8Array;
343
343
  * - Converting binary data for JSON serialization
344
344
  * - Creating hex-encoded strings for APIs and protocols
345
345
  *
346
+ * @see {@link hexToBytes} for reverse process
346
347
  * @see {@link sha256Bytes} for raw byte hash results
347
348
  */
348
349
  export declare function bytesToHex(bytes: Uint8Array): string;
350
+ /**
351
+ * * Converts a hexadecimal string to a `Uint8Array`.
352
+ * - This function decodes a hexadecimal-encoded string into its raw byte representation, where every two hexadecimal characters (00–ff) are converted into one byte.
353
+ *
354
+ * @example
355
+ * ```ts
356
+ * // Convert hex to bytes
357
+ * const hex = '12abff00';
358
+ * const bytes = hexToBytes(hex);
359
+ * // Returns: Uint8Array(4) [18, 171, 255, 0]
360
+ *
361
+ * // Empty string
362
+ * const emptyBytes = hexToBytes('');
363
+ * // Returns: Uint8Array []
364
+ *
365
+ * // Decode SHA-256 hash from hex
366
+ * const hashHex =
367
+ * '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824';
368
+ * const hashBytes = hexToBytes(hashHex);
369
+ * // Returns: Uint8Array(32)
370
+ * ```
371
+ *
372
+ * @param hex - A hexadecimal string where each byte is represented by two characters (00–ff).
373
+ * @returns A `Uint8Array` containing the decoded bytes. Returns an empty array for invalid input.
374
+ *
375
+ * @remarks
376
+ * - Accepts lowercase and uppercase hexadecimal characters (0–9, a–f, A–F) with or without space between bytes
377
+ * - Ignores no prefixes (e.g., does not support "0x")
378
+ * - Requires an even number of hexadecimal characters
379
+ * - Efficient O(n) implementation with direct byte parsing
380
+ *
381
+ * **Common use cases:**
382
+ * - Decoding cryptographic hashes and signatures
383
+ * - Parsing hex-encoded binary payloads
384
+ * - Reconstructing binary data from storage or transport formats
385
+ * - Working with low-level protocols and binary APIs
386
+ *
387
+ * @see {@link bytesToHex} for the reverse process
388
+ * @see {@link isHexString} for input validation
389
+ */
390
+ export declare function hexToBytes(hex: string): Uint8Array;
@@ -65,4 +65,4 @@ export { Paginator } from './utils/Paginator';
65
65
  export { isBigInt, isBoolean, isFalsy, isInteger, isNonEmptyString, isNormalPrimitive, isNull, isNumber, isPositiveInteger, isPrimitive, isString, isSymbol, isTruthy, isUndefined, } from './guards/primitives';
66
66
  export { isReturningPromise as doesReturnPromise, isArray, isArrayOfType, isValidArray as isArrayWithLength, isDate, isEmptyObject, isEmptyObject as isEmptyObjectGuard, isError, isFunction, isJSON, isJSON as isJSONObject, isMap, isMethodDescriptor as isMethod, isMethodDescriptor, isNotEmptyObject, isObject, isEmptyObject as isObjectEmpty, isObjectWithKeys, isPromise, isRegExp, isRegExp as isRegularExpression, isReturningPromise, isSet, isValidArray, isJSON as isValidJSON, isMap as isValidMap, isNotEmptyObject as isValidObject, isSet as isValidSet, } from './guards/non-primitives';
67
67
  export { HttpStatus, httpStatus } from './http-status/HttpStatus';
68
- export { isBase64, isBrowser, isDateString, isEmail, isEmailArray, isEnvironment, isEnvironment as isExpectedNodeENV, isIPAddress, isNode, isEnvironment as isNodeENV, isEnvironment as isNodeEnvironment, isNumericString, isPhoneNumber, isURL, isUUID, isEmail as isValidEmail, isURL as isValidURL, } from './guards/specials';
68
+ export { isBase64, isBinaryString, isBrowser, isDateString, isEmail, isEmailArray, isEnvironment, isEnvironment as isExpectedNodeENV, isHexString, isIPAddress, isNode, isEnvironment as isNodeENV, isEnvironment as isNodeEnvironment, isNumericString, isPhoneNumber, isURL, isUUID, isEmail as isValidEmail, isURL as isValidURL, } from './guards/specials';
@@ -1,5 +1,5 @@
1
1
  import type { Numeric } from '../types/index';
2
- import type { ConvertOptions, CurrencyCode, LocaleCode, SupportedCurrency } from './types';
2
+ import type { ConvertOptions, CurrencyCode, FrankFurterCurrency, LocaleCode } from './types';
3
3
  /**
4
4
  * * A utility class for handling currency operations like formatting and conversion.
5
5
  *
@@ -8,7 +8,7 @@ import type { ConvertOptions, CurrencyCode, LocaleCode, SupportedCurrency } from
8
8
  * - Automatically caches conversion rates to reduce redundant API calls.
9
9
  * - Intended for use with numeric inputs (number or numeric string).
10
10
  */
11
- export declare class Currency {
11
+ export declare class Currency<Code extends CurrencyCode> {
12
12
  #private;
13
13
  /**
14
14
  * * The formatted currency string (e.g., `$1,000.00`).
@@ -24,7 +24,7 @@ export declare class Currency {
24
24
  * @param amount - The numeric amount of currency (e.g., `100`, `'99.99'`).
25
25
  * @param code - The ISO 4217 currency code representing the currency (e.g., `'USD'`, `'EUR'`).
26
26
  */
27
- constructor(amount: Numeric, code: CurrencyCode);
27
+ constructor(amount: Numeric, code: Code);
28
28
  /** * Clears cached rates that were fetched previously. */
29
29
  static clearRateCache(): void;
30
30
  /**
@@ -39,12 +39,13 @@ export declare class Currency {
39
39
  /**
40
40
  * @instance Converts the current currency amount to a target currency using real-time exchange rates.
41
41
  *
42
- * - Uses `api.frankfurter.app` to fetch live exchange rates.
42
+ * - Uses {@link https://api.frankfurter.app/latest api.frankfurter.app} to fetch live exchange rates.
43
43
  * - Supports **only the following fiat currencies**:
44
44
  * `AUD`, `BGN`, `BRL`, `CAD`, `CHF`, `CNY`, `CZK`, `DKK`, `EUR`, `GBP`, `HKD`, `HUF`, `IDR`, `ILS`, `INR`, `ISK`, `JPY`,
45
45
  * `KRW`, `MXN`, `MYR`, `NOK`, `NZD`, `PHP`, `PLN`, `RON`, `SEK`, `SGD`, `THB`, `TRY`, `USD`, `ZAR`.
46
46
  * - Uses cached rates unless `forceRefresh` is set to `true`.
47
47
  * - If API fails or currency not supported, falls back to `fallbackRate` if provided.
48
+ * - Use {@link convertSync} method to convert to other currencies using custom exchange rate.
48
49
  *
49
50
  * @param to - The target currency code (must be one of the supported ones, e.g., `'EUR'`, `'USD'`).
50
51
  * @param options - Optional settings:
@@ -56,7 +57,7 @@ export declare class Currency {
56
57
  * @example
57
58
  * await new Currency(100, 'USD').convert('EUR');
58
59
  */
59
- convert(to: SupportedCurrency | CurrencyCode, options?: ConvertOptions): Promise<Currency>;
60
+ convert<To extends FrankFurterCurrency>(to: To, options?: ConvertOptions): Promise<Currency<To>>;
60
61
  /**
61
62
  * @instance Converts the current currency amount to a target currency using either a cached rate or a manual exchange rate.
62
63
  *
@@ -75,5 +76,5 @@ export declare class Currency {
75
76
  *
76
77
  * console.log(eur.currency); // €92.00
77
78
  */
78
- convertSync(to: CurrencyCode, rate: number): Currency;
79
+ convertSync<To extends CurrencyCode>(to: To, rate: number): Currency<To>;
79
80
  }
@@ -174,7 +174,7 @@ export declare const CURRENCY_LOCALES: Readonly<{
174
174
  readonly ZWL: "en-ZW";
175
175
  }>;
176
176
  /** * Fiat currencies supported by Frankfurter API */
177
- export declare const SUPPORTED_CURRENCIES: readonly ["AUD", "BGN", "BRL", "CAD", "CHF", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "ISK", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PLN", "RON", "SEK", "SGD", "THB", "TRY", "USD", "ZAR"];
177
+ export declare const FRANKFURTER_CURRENCIES: readonly ["AUD", "BGN", "BRL", "CAD", "CHF", "CNY", "CZK", "DKK", "EUR", "GBP", "HKD", "HUF", "IDR", "ILS", "INR", "ISK", "JPY", "KRW", "MXN", "MYR", "NOK", "NZD", "PHP", "PLN", "RON", "SEK", "SGD", "THB", "TRY", "USD", "ZAR"];
178
178
  /** * Unit names and their full readable labels. */
179
179
  export declare const UNITS: Readonly<{
180
180
  readonly m: "Meter";
@@ -1,6 +1,6 @@
1
1
  import type { Maybe } from '../types/index';
2
2
  import type { LooseLiteral } from '../utils/types';
3
- import type { CURRENCY_CODES, CURRENCY_LOCALES, LOCALE_CODES, PREFIX_MULTIPLIERS, SUPPORTED_CURRENCIES, UNITS } from './constants';
3
+ import type { CURRENCY_CODES, CURRENCY_LOCALES, FRANKFURTER_CURRENCIES, LOCALE_CODES, PREFIX_MULTIPLIERS, UNITS } from './constants';
4
4
  import type { Unit } from './Unit';
5
5
  /** Enumerate & Enumerate Internal: builds a union of all numbers from 0 to N - 1 */
6
6
  type $EnumerateInternal<N extends number, Acc extends number[] = []> = Acc['length'] extends N ? Acc[number] : $EnumerateInternal<N, [...Acc, Acc['length']]>;
@@ -74,7 +74,8 @@ export type CurrencyCode = keyof typeof CURRENCY_LOCALES | (typeof CURRENCY_CODE
74
74
  /** - List of all supported BCP 47 locales */
75
75
  export type LocaleCode = (typeof CURRENCY_LOCALES)[keyof typeof CURRENCY_LOCALES] | (typeof LOCALE_CODES)[number];
76
76
  /** * Fiat currencies supported by Frankfurter API */
77
- export type SupportedCurrency = (typeof SUPPORTED_CURRENCIES)[number];
77
+ export type FrankFurterCurrency = (typeof FRANKFURTER_CURRENCIES)[number];
78
+ export type { FrankFurterCurrency as SupportedCurrency };
78
79
  /** - Options for `convert` method in `Currency` class */
79
80
  export interface ConvertOptions {
80
81
  /** A manual exchange rate to use if the API call fails. */
@@ -85,9 +86,9 @@ export interface ConvertOptions {
85
86
  /** Type Interface for API Response from `api.frankfurter.app` */
86
87
  export interface FrankFurter {
87
88
  amount: number;
88
- base: CurrencyCode;
89
+ base: FrankFurterCurrency;
89
90
  date: string;
90
- rates: Record<CurrencyCode, number>;
91
+ rates: Record<FrankFurterCurrency, number>;
91
92
  }
92
93
  /** * Options to calculate what percentage a `part` is of a `total`. */
93
94
  export interface GetPercentOptions {
@@ -212,4 +213,3 @@ export type RomanNumeral = RomanCapital | Lowercase<RomanCapital>;
212
213
  * - The {@link LooseLiteral} wrapper allows non-literal strings (e.g., variables) without losing IntelliSense for literals.
213
214
  */
214
215
  export type LooseRomanNumeral = LooseLiteral<RomanNumeral>;
215
- export {};
@@ -3,7 +3,7 @@ export { IANA_TZ_IDS, NATIVE_TZ_IDS, TIME_ZONE_IDS, TIME_ZONE_LABELS, TIME_ZONES
3
3
  export { AUSTRALIA_SEASONS, BANGLADESH_SEASONS, ETHIOPIA_SEASONS, INDIA_IMD_SEASONS, INDIA_TAMIL_SEASONS, INDIA_VEDIC_SEASONS, JAPAN_SEASONS, PHILIPPINES_SEASONS, SEASON_PRESETS, US_ACADEMIC_SEASONS, DEFAULT_SEASONS as WESTERN_SEASONS, } from './date/seasons.js';
4
4
  export { ALPHABET_COLOR_PALETTE, NUMBER_COLOR_PALETTE } from './colors/constants.js';
5
5
  export { CSS_COLORS } from './colors/css-colors.js';
6
- export { CURRENCY_CODES, CURRENCY_LOCALES, SUPPORTED_CURRENCIES as FRANKFURTER_CURRENCIES, UNITS as GENERAL_UNITS, LOCALE_CODES, } from './number/constants.js';
6
+ export { CURRENCY_CODES, CURRENCY_LOCALES, FRANKFURTER_CURRENCIES, UNITS as GENERAL_UNITS, LOCALE_CODES, } from './number/constants.js';
7
7
  export { LOWERCASE as LOWERCASED_WORDS } from './string/constants.js';
8
8
  export { UNITS as CATEGORIZED_UNITS } from './converter/constants.js';
9
9
  export { COUNTRIES } from './object/countries.js';
@@ -35,6 +35,14 @@ export function isBase64(value) {
35
35
  return (isString(value) &&
36
36
  /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value));
37
37
  }
38
+ export function isHexString(value) {
39
+ return (isString(value) &&
40
+ /^[\da-fA-F\s]+$/.test(value) &&
41
+ value.replace(/\s+/g, '').length % 2 === 0);
42
+ }
43
+ export function isBinaryString(value) {
44
+ return (isString(value) && /^[01\s]+$/.test(value) && value.replace(/\s+/g, '').length % 8 === 0);
45
+ }
38
46
  export function isPhoneNumber(value) {
39
47
  return isString(value) && /^\+?[1-9]\d{1,14}$/.test(value);
40
48
  }
@@ -0,0 +1,71 @@
1
+ import { isNonEmptyString } from '../guards/primitives.js';
2
+ import { isBase64, isBinaryString, isHexString } from '../guards/specials.js';
3
+ import { _padStartWith0, _splitByCharLength } from './helpers.js';
4
+ import { base64ToBytes, bytesToBase64, bytesToUtf8, hexToBytes, utf8ToBytes } from './utils.js';
5
+ export class TextCodec {
6
+ constructor() { }
7
+ static isValidHex(hex) {
8
+ return isHexString(hex);
9
+ }
10
+ static isValidBinary(binary) {
11
+ return isBinaryString(binary);
12
+ }
13
+ static isValidBase64(b64) {
14
+ return isBase64(b64);
15
+ }
16
+ static utf8ToHex(text, spaced = true) {
17
+ return [...utf8ToBytes(text)]
18
+ .map((b) => _padStartWith0(b, 'hex'))
19
+ .join(spaced ? ' ' : '');
20
+ }
21
+ static utf8ToBinary(text, spaced = true) {
22
+ return [...utf8ToBytes(text)]
23
+ .map((b) => _padStartWith0(b, 'binary'))
24
+ .join(spaced ? ' ' : '');
25
+ }
26
+ static hexToUtf8(hex) {
27
+ return bytesToUtf8(hexToBytes(hex));
28
+ }
29
+ static binaryToUtf8(binary) {
30
+ if (!isBinaryString(binary))
31
+ return '';
32
+ const bytes = _splitByCharLength(binary, 8).map((b) => parseInt(b, 2));
33
+ return bytesToUtf8(new Uint8Array(bytes));
34
+ }
35
+ static hexToBinary(hex, spaced = true) {
36
+ if (!isHexString(hex))
37
+ return '';
38
+ return _splitByCharLength(hex, 2)
39
+ .map((h) => _padStartWith0(parseInt(h, 16), 'binary'))
40
+ .join(spaced ? ' ' : '');
41
+ }
42
+ static binaryToHex(binary, spaced = true) {
43
+ if (!isBinaryString(binary))
44
+ return '';
45
+ return _splitByCharLength(binary, 8)
46
+ .map((b) => _padStartWith0(parseInt(b, 2), 'hex'))
47
+ .join(spaced ? ' ' : '');
48
+ }
49
+ static base64ToUtf8(b64) {
50
+ if (!isBase64(b64))
51
+ return '';
52
+ return bytesToUtf8(base64ToBytes(b64));
53
+ }
54
+ static utf8ToBase64(text) {
55
+ if (!isNonEmptyString(text))
56
+ return '';
57
+ return bytesToBase64(utf8ToBytes(text));
58
+ }
59
+ static base64ToHex(b64, spaced = true) {
60
+ return this.utf8ToHex(this.base64ToUtf8(b64), spaced);
61
+ }
62
+ static base64ToBinary(b64, spaced = true) {
63
+ return this.utf8ToBinary(this.base64ToUtf8(b64), spaced);
64
+ }
65
+ static hexToBase64(hex) {
66
+ return this.utf8ToBase64(this.hexToUtf8(hex));
67
+ }
68
+ static binaryToBase64(binary) {
69
+ return this.utf8ToBase64(this.binaryToUtf8(binary));
70
+ }
71
+ }
@@ -156,3 +156,16 @@ export function _constantTimeEquals(a, b) {
156
156
  }
157
157
  return res === 0;
158
158
  }
159
+ export function _splitByCharLength(str, splitByChars = 2) {
160
+ if (!isNonEmptyString(str))
161
+ return [];
162
+ const sanitized = str.replace(/\s+/g, '');
163
+ const result = [];
164
+ for (let i = 0; i < sanitized.length; i += splitByChars) {
165
+ result.push(sanitized.slice(i, i + splitByChars));
166
+ }
167
+ return result;
168
+ }
169
+ export function _padStartWith0(byte, type) {
170
+ return byte.toString(type === 'hex' ? 16 : 2).padStart(type === 'hex' ? 2 : 8, '0');
171
+ }
@@ -3,5 +3,6 @@ export { generateRandomID, generateRandomID as randomID } from '../string/basics
3
3
  export { Cipher } from './Cipher.js';
4
4
  export { md5, sha1, sha256 } from './core.js';
5
5
  export { Signet } from './Signet.js';
6
- export { base64ToBytes, bytesToBase64, bytesToHex, bytesToUtf8, concatBytes, hmacSha256, intTo4BytesBE, randomHex, sha256Bytes, uint8To32ArrayBE, utf8ToBytes, } from './utils.js';
6
+ export { TextCodec } from './TextCodec.js';
7
+ export { base64ToBytes, bytesToBase64, bytesToHex, bytesToUtf8, concatBytes, hexToBytes, hmacSha256, intTo4BytesBE, randomHex, sha256Bytes, uint8To32ArrayBE, utf8ToBytes, } from './utils.js';
7
8
  export { decodeUUID, isUUIDv1, isUUIDv2, isUUIDv3, isUUIDv4, isUUIDv5, isUUIDv6, isUUIDv7, isUUIDv8, uuid, } from './uuid.js';
@@ -1,3 +1,5 @@
1
+ import { isHexString } from '../guards/specials.js';
2
+ import { _splitByCharLength } from './helpers.js';
1
3
  export function randomHex(length, uppercase = false) {
2
4
  const genHex = () => Math.floor(Math.random() * 16).toString(16);
3
5
  const hex = Array.from({ length }, genHex).join('');
@@ -237,3 +239,9 @@ export function bytesToHex(bytes) {
237
239
  }
238
240
  return hex;
239
241
  }
242
+ export function hexToBytes(hex) {
243
+ if (!isHexString(hex))
244
+ return new Uint8Array();
245
+ const bytes = _splitByCharLength(hex, 2).map((h) => parseInt(h, 16));
246
+ return new Uint8Array(bytes);
247
+ }
package/dist/esm/index.js CHANGED
@@ -50,4 +50,4 @@ export { Paginator } from './utils/Paginator.js';
50
50
  export { isBigInt, isBoolean, isFalsy, isInteger, isNonEmptyString, isNormalPrimitive, isNull, isNumber, isPositiveInteger, isPrimitive, isString, isSymbol, isTruthy, isUndefined, } from './guards/primitives.js';
51
51
  export { isReturningPromise as doesReturnPromise, isArray, isArrayOfType, isValidArray as isArrayWithLength, isDate, isEmptyObject, isEmptyObject as isEmptyObjectGuard, isError, isFunction, isJSON, isJSON as isJSONObject, isMap, isMethodDescriptor as isMethod, isMethodDescriptor, isNotEmptyObject, isObject, isEmptyObject as isObjectEmpty, isObjectWithKeys, isPromise, isRegExp, isRegExp as isRegularExpression, isReturningPromise, isSet, isValidArray, isJSON as isValidJSON, isMap as isValidMap, isNotEmptyObject as isValidObject, isSet as isValidSet, } from './guards/non-primitives.js';
52
52
  export { HttpStatus, httpStatus } from './http-status/HttpStatus.js';
53
- export { isBase64, isBrowser, isDateString, isEmail, isEmailArray, isEnvironment, isEnvironment as isExpectedNodeENV, isIPAddress, isNode, isEnvironment as isNodeENV, isEnvironment as isNodeEnvironment, isNumericString, isPhoneNumber, isURL, isUUID, isEmail as isValidEmail, isURL as isValidURL, } from './guards/specials.js';
53
+ export { isBase64, isBinaryString, isBrowser, isDateString, isEmail, isEmailArray, isEnvironment, isEnvironment as isExpectedNodeENV, isHexString, isIPAddress, isNode, isEnvironment as isNodeENV, isEnvironment as isNodeEnvironment, isNumericString, isPhoneNumber, isURL, isUUID, isEmail as isValidEmail, isURL as isValidURL, } from './guards/specials.js';
@@ -8,37 +8,37 @@ export class Currency {
8
8
  this.#code = code;
9
9
  this.currency = this.format('en-US');
10
10
  }
11
- static #rateCache = new Map();
11
+ static #RATE_CACHE = new Map();
12
12
  static clearRateCache() {
13
- Currency.#rateCache.clear();
13
+ Currency.#RATE_CACHE.clear();
14
14
  }
15
15
  format(locale, code) {
16
16
  return formatCurrency(this.#amount, code ?? this.#code, locale);
17
17
  }
18
18
  async convert(to, options) {
19
19
  const key = `${this.#code}->${to}`;
20
- if (!options?.forceRefresh && Currency.#rateCache.has(key)) {
21
- const cachedRate = Currency.#rateCache.get(key);
20
+ if (!options?.forceRefresh && Currency.#RATE_CACHE.has(key)) {
21
+ const cachedRate = Currency.#RATE_CACHE.get(key);
22
22
  return new Currency(this.#amount * cachedRate, to);
23
23
  }
24
24
  try {
25
25
  const rate = await this.#fetchFromFrankfurter(to);
26
- Currency.#rateCache.set(key, rate);
26
+ Currency.#RATE_CACHE.set(key, rate);
27
27
  return new Currency(this.#amount * rate, to);
28
28
  }
29
29
  catch (error) {
30
30
  if (options?.fallbackRate != null) {
31
- console.warn(`Currency conversion failed (${this.#code} → ${to}): ${error.message}. Using fallback rate...`);
31
+ console.warn(`Currency conversion failed (${this.#code} → ${to}): ${error?.message}. Using fallback rate...`);
32
32
  return new Currency(this.#amount * options.fallbackRate, to);
33
33
  }
34
34
  else {
35
- throw new Error(`Currency conversion failed (${this.#code} → ${to}): ${error.message}`);
35
+ throw new Error(`Currency conversion failed (${this.#code} → ${to}): ${error?.message}`);
36
36
  }
37
37
  }
38
38
  }
39
39
  convertSync(to, rate) {
40
40
  const key = `${this.#code}->${to}`;
41
- const cachedRate = Currency.#rateCache.get(key);
41
+ const cachedRate = Currency.#RATE_CACHE.get(key);
42
42
  if (cachedRate) {
43
43
  return new Currency(this.#amount * cachedRate, to);
44
44
  }
@@ -50,7 +50,7 @@ export class Currency {
50
50
  }
51
51
  }
52
52
  async #fetchFromFrankfurter(to) {
53
- const url = `https://api.frankfurter.app/latest?amount=${this.#amount}&from=${this.#code}`;
53
+ const url = `https://api.frankfurter.app/latest?amount=1&from=${this.#code}`;
54
54
  try {
55
55
  const res = await fetch(url, { redirect: 'error' });
56
56
  if (!res.ok) {
@@ -58,12 +58,12 @@ export class Currency {
58
58
  }
59
59
  const data = await res.json();
60
60
  if (!data.rates?.[to]) {
61
- throw new Error(`Currency "${to}" not allowed or not found in FrankFurter Database!`);
61
+ throw new Error(`Currency "${to}" is not found in FrankFurter Database!`);
62
62
  }
63
- return data.rates[to] / this.#amount;
63
+ return data.rates[to];
64
64
  }
65
65
  catch (error) {
66
- throw new Error(error.message || `Failed to fetch data from FrankFurter API`);
66
+ throw new Error(error?.message || `Failed to fetch data from FrankFurter API`);
67
67
  }
68
68
  }
69
69
  }
@@ -538,7 +538,7 @@ export const CURRENCY_LOCALES = /* @__PURE__ */ Object.freeze({
538
538
  ZMW: 'en-ZM',
539
539
  ZWL: 'en-ZW',
540
540
  });
541
- export const SUPPORTED_CURRENCIES = /* @__PURE__ */ Object.freeze([
541
+ export const FRANKFURTER_CURRENCIES = /* @__PURE__ */ Object.freeze([
542
542
  'AUD',
543
543
  'BGN',
544
544
  'BRL',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nhb-toolbox",
3
- "version": "4.28.24",
3
+ "version": "4.28.40",
4
4
  "description": "A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -39,12 +39,12 @@
39
39
  },
40
40
  "license": "Apache-2.0",
41
41
  "devDependencies": {
42
- "@eslint/js": "^9.39.1",
42
+ "@eslint/js": "^9.39.2",
43
43
  "@types/jest": "^30.0.0",
44
- "@types/node": "^25.0.0",
44
+ "@types/node": "^25.0.1",
45
45
  "@typescript-eslint/eslint-plugin": "^8.49.0",
46
46
  "@typescript-eslint/parser": "^8.49.0",
47
- "eslint": "^9.39.1",
47
+ "eslint": "^9.39.2",
48
48
  "eslint-config-prettier": "^10.1.8",
49
49
  "eslint-plugin-prettier": "^5.5.4",
50
50
  "globals": "^16.5.0",