nhb-toolbox 4.30.0 → 4.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  All notable changes to the package will be documented here.
6
6
 
7
+ ## [4.30.1] - 2026-04-27
8
+
9
+ - **Updated** *random hex generation* logic in `randomHex` and `uuid` utilities to use `crypto.getRandomValues` for better performance and security when available, with a fallback to `Math.random` for environments where `crypto` is not available.
10
+
7
11
  ## [4.30.0] - 2026-04-27
8
12
 
9
13
  - **Added** new utility `getCountryByPhone` to get country details (country name, country code, ISO short code, and ISO code) by matching the country code in the given phone number.
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  <img src="https://img.shields.io/npm/v/nhb-toolbox.svg?label=NPM&style=flat&color=teal&logo=npm" alt="Latest Version" />
12
12
  </a>
13
13
  <a href="https://bundlejs.com/?q=nhb-toolbox" aria-label="Bundle Size">
14
- <img src="https://deno.bundlejs.com/badge?q=nhb-toolbox" alt="Bundle Size" />
14
+ <img src="https://img.shields.io/bundlejs/size/nhb-toolbox?label=Bundle%20Size&style=flat&color=blue&logo=npm" alt="Bundle Size" />
15
15
  </a>
16
16
 
17
17
  <!-- Project Metadata -->
@@ -5,6 +5,7 @@ exports._stringToNumbers = _stringToNumbers;
5
5
  exports._md5cycle = _md5cycle;
6
6
  exports._uuidTimestamp = _uuidTimestamp;
7
7
  exports._randomNode48 = _randomNode48;
8
+ exports._bytesToRandomHex = _bytesToRandomHex;
8
9
  exports._clockSeq14 = _clockSeq14;
9
10
  exports._formatUUID = _formatUUID;
10
11
  exports._isOptionV3V5 = _isOptionV3V5;
@@ -135,6 +136,21 @@ function _randomNode48() {
135
136
  const modified = (firstByte | 0b00000001).toString(16).padStart(2, '0');
136
137
  return modified + node.slice(2).join('');
137
138
  }
139
+ function _bytesToRandomHex(bytes) {
140
+ if (crypto?.getRandomValues) {
141
+ crypto.getRandomValues(bytes);
142
+ }
143
+ else {
144
+ for (let i = 0; i < bytes.length; i++) {
145
+ bytes[i] = Math.floor(Math.random() * 256);
146
+ }
147
+ }
148
+ let hex = '';
149
+ for (let i = 0; i < bytes.length; i++) {
150
+ hex += bytes[i].toString(16).padStart(2, '0');
151
+ }
152
+ return hex;
153
+ }
138
154
  function _clockSeq14() {
139
155
  const seq = parseInt((0, utils_1.randomHex)(4), 16) & 0x3fff;
140
156
  return seq.toString(16).padStart(4, '0');
@@ -15,9 +15,11 @@ exports.hexToBytes = hexToBytes;
15
15
  const specials_1 = require("../guards/specials");
16
16
  const helpers_1 = require("./helpers");
17
17
  function randomHex(length, uppercase = false) {
18
- const genHex = () => Math.floor(Math.random() * 16).toString(16);
19
- const hex = Array.from({ length }, genHex).join('');
20
- return uppercase ? hex.toUpperCase() : hex;
18
+ if (length <= 0)
19
+ return '';
20
+ const bytes = new Uint8Array(Math.ceil(length / 2));
21
+ const expected = (0, helpers_1._bytesToRandomHex)(bytes).slice(0, length);
22
+ return uppercase ? expected.toUpperCase() : expected;
21
23
  }
22
24
  function utf8ToBytes(str) {
23
25
  const out = [];
@@ -42,19 +42,7 @@ function uuid(options) {
42
42
  throw new Error('v3 requires valid namespace (uuid) and name!');
43
43
  }
44
44
  case 'v4': {
45
- const bytes = new Uint8Array(16);
46
- if (crypto.getRandomValues) {
47
- crypto.getRandomValues(bytes);
48
- }
49
- else {
50
- for (let i = 0; i < 16; i++) {
51
- bytes[i] = Math.floor(Math.random() * 256);
52
- }
53
- }
54
- let hex = '';
55
- for (let i = 0; i < 16; i++) {
56
- hex += bytes[i].toString(16).padStart(2, '0');
57
- }
45
+ const hex = (0, helpers_1._bytesToRandomHex)(new Uint8Array(16));
58
46
  return (0, helpers_1._formatUUID)(hex, 4, uppercase);
59
47
  }
60
48
  case 'v5': {
@@ -93,18 +81,7 @@ function uuid(options) {
93
81
  bytes[i] = Number(temp & 0xffn);
94
82
  temp >>= 8n;
95
83
  }
96
- if (crypto.getRandomValues) {
97
- crypto.getRandomValues(bytes);
98
- }
99
- else {
100
- for (let i = 6; i < 16; i++) {
101
- bytes[i] = Math.floor(Math.random() * 256);
102
- }
103
- }
104
- let hex = '';
105
- for (let i = 0; i < 16; i++) {
106
- hex += bytes[i].toString(16).padStart(2, '0');
107
- }
84
+ const hex = (0, helpers_1._bytesToRandomHex)(bytes);
108
85
  return (0, helpers_1._formatUUID)(hex, 8, uppercase);
109
86
  }
110
87
  default:
@@ -15,6 +15,12 @@ export declare function _uuidTimestamp(): bigint;
15
15
  * LSB of first byte must be 1 to indicate a randomly generated node.
16
16
  */
17
17
  export declare function _randomNode48(): string;
18
+ /**
19
+ * Generates random hex string of given byte length using crypto API if available, otherwise falls back to Math.random.
20
+ * @param bytes Instance of {@link Uint8Array} to fill with random values.
21
+ * @returns Hex string representation of the random bytes.
22
+ */
23
+ export declare function _bytesToRandomHex(bytes: Uint8Array<ArrayBuffer>): string;
18
24
  /** * Generates a 14-bit clock sequence (2 bytes, but only 14 bits used). */
19
25
  export declare function _clockSeq14(): string;
20
26
  /** Convert a hex string to UUID format */
@@ -2,10 +2,16 @@
2
2
  * * Generates a random hexadecimal string of the specified length.
3
3
  *
4
4
  * @param length - Number of hex characters to generate.
5
- * @param uppercase - Whether to return uppercase `A–F` characters.
5
+ * @param uppercase - Whether to return uppercase `A–F` characters. Defaults to `false` (lowercase).
6
6
  *
7
7
  * @returns A randomly generated hexadecimal string.
8
8
  *
9
+ * @remarks
10
+ * - This function generates a random hexadecimal string of the specified length.
11
+ * - It uses {@link crypto.getRandomValues} when available for secure randomness, and falls back to {@link Math.random} if not.
12
+ * - The output is a string of hex characters (`0–9`, `a–f` or `A–F`) with no prefixes or separators.
13
+ * - If `length` is `0` or negative, an empty string is returned.
14
+ *
9
15
  * @example
10
16
  * // 16-character lowercase hex
11
17
  * const id = randomHex(16);
@@ -121,6 +121,21 @@ export function _randomNode48() {
121
121
  const modified = (firstByte | 0b00000001).toString(16).padStart(2, '0');
122
122
  return modified + node.slice(2).join('');
123
123
  }
124
+ export function _bytesToRandomHex(bytes) {
125
+ if (crypto?.getRandomValues) {
126
+ crypto.getRandomValues(bytes);
127
+ }
128
+ else {
129
+ for (let i = 0; i < bytes.length; i++) {
130
+ bytes[i] = Math.floor(Math.random() * 256);
131
+ }
132
+ }
133
+ let hex = '';
134
+ for (let i = 0; i < bytes.length; i++) {
135
+ hex += bytes[i].toString(16).padStart(2, '0');
136
+ }
137
+ return hex;
138
+ }
124
139
  export function _clockSeq14() {
125
140
  const seq = parseInt(randomHex(4), 16) & 0x3fff;
126
141
  return seq.toString(16).padStart(4, '0');
@@ -1,9 +1,11 @@
1
1
  import { isHexString } from '../guards/specials.js';
2
- import { _splitByCharLength } from './helpers.js';
2
+ import { _bytesToRandomHex, _splitByCharLength } from './helpers.js';
3
3
  export function randomHex(length, uppercase = false) {
4
- const genHex = () => Math.floor(Math.random() * 16).toString(16);
5
- const hex = Array.from({ length }, genHex).join('');
6
- return uppercase ? hex.toUpperCase() : hex;
4
+ if (length <= 0)
5
+ return '';
6
+ const bytes = new Uint8Array(Math.ceil(length / 2));
7
+ const expected = _bytesToRandomHex(bytes).slice(0, length);
8
+ return uppercase ? expected.toUpperCase() : expected;
7
9
  }
8
10
  export function utf8ToBytes(str) {
9
11
  const out = [];
@@ -1,6 +1,6 @@
1
1
  import { isUUID } from '../guards/specials.js';
2
2
  import { md5, sha1 } from './core.js';
3
- import { _checkUUIDVersion, _clockSeq14, _formatUUID, _isOptionV3V5, _randomNode48, _uuidTimestamp, } from './helpers.js';
3
+ import { _bytesToRandomHex, _checkUUIDVersion, _clockSeq14, _formatUUID, _isOptionV3V5, _randomNode48, _uuidTimestamp, } from './helpers.js';
4
4
  import { randomHex } from './utils.js';
5
5
  export function uuid(options) {
6
6
  const { version = 'v4', uppercase = false } = options || {};
@@ -30,19 +30,7 @@ export function uuid(options) {
30
30
  throw new Error('v3 requires valid namespace (uuid) and name!');
31
31
  }
32
32
  case 'v4': {
33
- const bytes = new Uint8Array(16);
34
- if (crypto.getRandomValues) {
35
- crypto.getRandomValues(bytes);
36
- }
37
- else {
38
- for (let i = 0; i < 16; i++) {
39
- bytes[i] = Math.floor(Math.random() * 256);
40
- }
41
- }
42
- let hex = '';
43
- for (let i = 0; i < 16; i++) {
44
- hex += bytes[i].toString(16).padStart(2, '0');
45
- }
33
+ const hex = _bytesToRandomHex(new Uint8Array(16));
46
34
  return _formatUUID(hex, 4, uppercase);
47
35
  }
48
36
  case 'v5': {
@@ -81,18 +69,7 @@ export function uuid(options) {
81
69
  bytes[i] = Number(temp & 0xffn);
82
70
  temp >>= 8n;
83
71
  }
84
- if (crypto.getRandomValues) {
85
- crypto.getRandomValues(bytes);
86
- }
87
- else {
88
- for (let i = 6; i < 16; i++) {
89
- bytes[i] = Math.floor(Math.random() * 256);
90
- }
91
- }
92
- let hex = '';
93
- for (let i = 0; i < 16; i++) {
94
- hex += bytes[i].toString(16).padStart(2, '0');
95
- }
72
+ const hex = _bytesToRandomHex(bytes);
96
73
  return _formatUUID(hex, 8, uppercase);
97
74
  }
98
75
  default:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nhb-toolbox",
3
- "version": "4.30.0",
3
+ "version": "4.30.1",
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",