toolbox-x 1.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 (190) hide show
  1. package/LICENSE +201 -0
  2. package/dist/Color-B3mgF9Dh.d.cts +486 -0
  3. package/dist/Color-D38Xrw65.d.mts +486 -0
  4. package/dist/Stylog-Df7eq3-j.d.cts +519 -0
  5. package/dist/Stylog-jvlLcMQq.d.mts +519 -0
  6. package/dist/array-DvW0zIu6.d.mts +130 -0
  7. package/dist/array-rUnEVisO.d.cts +130 -0
  8. package/dist/basics-D_eSv0cu.cjs +132 -0
  9. package/dist/basics-Dp_aEK81.mjs +115 -0
  10. package/dist/basics-WEYWlnRO.d.cts +95 -0
  11. package/dist/basics-uBSfkBEI.d.mts +95 -0
  12. package/dist/case-BWIt8Ash.mjs +449 -0
  13. package/dist/case-C-S-b5YP.d.cts +327 -0
  14. package/dist/case-CS8Ii3A7.cjs +526 -0
  15. package/dist/case-CybASFPD.d.mts +327 -0
  16. package/dist/change-case.cjs +32 -0
  17. package/dist/change-case.d.cts +18 -0
  18. package/dist/change-case.d.mts +18 -0
  19. package/dist/change-case.mjs +19 -0
  20. package/dist/colors.cjs +574 -0
  21. package/dist/colors.d.cts +355 -0
  22. package/dist/colors.d.mts +355 -0
  23. package/dist/colors.mjs +547 -0
  24. package/dist/constants-2gAw23_7.mjs +144 -0
  25. package/dist/constants-B34K0QPi.d.cts +21 -0
  26. package/dist/constants-BIBDKY1u.cjs +924 -0
  27. package/dist/constants-BWT-810U.cjs +158 -0
  28. package/dist/constants-BwbHnXlM.mjs +662 -0
  29. package/dist/constants-BxN9l5el.cjs +74 -0
  30. package/dist/constants-CLS_bgKD.d.mts +847 -0
  31. package/dist/constants-D73iFu8g.mjs +171 -0
  32. package/dist/constants-DAfRxaa8.mjs +62 -0
  33. package/dist/constants-DQYeCjlx.cjs +207 -0
  34. package/dist/constants-Deeie-iH.d.mts +21 -0
  35. package/dist/constants-DpTG9RP6.d.mts +29 -0
  36. package/dist/constants-DqwnkJ_d.cjs +740 -0
  37. package/dist/constants-DvRUY_FY.cjs +150 -0
  38. package/dist/constants-VcRtQu0K.d.cts +29 -0
  39. package/dist/constants-X5hm1UtB.mjs +912 -0
  40. package/dist/constants-eNd-iYsV.mjs +134 -0
  41. package/dist/constants-qm8FafmD.d.cts +847 -0
  42. package/dist/constants.cjs +415 -0
  43. package/dist/constants.d.cts +184 -0
  44. package/dist/constants.d.mts +184 -0
  45. package/dist/constants.mjs +378 -0
  46. package/dist/convert-BOCgUv2D.cjs +252 -0
  47. package/dist/convert-Bn4jFomQ.mjs +169 -0
  48. package/dist/convert-BrzlG-m_.cjs +475 -0
  49. package/dist/convert-DhaUoPVU.mjs +368 -0
  50. package/dist/converter-1P90_RcP.d.mts +402 -0
  51. package/dist/converter-CmkcAppi.d.cts +402 -0
  52. package/dist/converter.cjs +780 -0
  53. package/dist/converter.d.cts +29 -0
  54. package/dist/converter.d.mts +29 -0
  55. package/dist/converter.mjs +771 -0
  56. package/dist/countries-CIpmtEzV.cjs +1469 -0
  57. package/dist/countries-Cy0xiqS3.mjs +1463 -0
  58. package/dist/css-colors-Bx947Ng3.d.cts +179 -0
  59. package/dist/css-colors-CXCDqQbG.cjs +186 -0
  60. package/dist/css-colors-CXTp1vvy.d.mts +179 -0
  61. package/dist/css-colors-DfUW3nTR.mjs +180 -0
  62. package/dist/date.cjs +332 -0
  63. package/dist/date.d.cts +213 -0
  64. package/dist/date.d.mts +213 -0
  65. package/dist/date.mjs +298 -0
  66. package/dist/dom.cjs +461 -0
  67. package/dist/dom.d.cts +228 -0
  68. package/dist/dom.d.mts +228 -0
  69. package/dist/dom.mjs +429 -0
  70. package/dist/form-BMFVGUrN.d.mts +118 -0
  71. package/dist/form-DRFbryvK.d.cts +118 -0
  72. package/dist/guards-3kaUX66g.mjs +157 -0
  73. package/dist/guards-C8gkvIHb.cjs +240 -0
  74. package/dist/guards-DdyU4h4o.mjs +110 -0
  75. package/dist/guards-Efhp1mNy.cjs +151 -0
  76. package/dist/guards.cjs +172 -0
  77. package/dist/guards.d.cts +399 -0
  78. package/dist/guards.d.mts +399 -0
  79. package/dist/guards.mjs +75 -0
  80. package/dist/hash-B6JPEyAz.d.mts +131 -0
  81. package/dist/hash-NTpeKYB_.d.cts +131 -0
  82. package/dist/hash.cjs +2126 -0
  83. package/dist/hash.d.cts +1239 -0
  84. package/dist/hash.d.mts +1239 -0
  85. package/dist/hash.mjs +2095 -0
  86. package/dist/http-status-BAZdtr7-.d.mts +65 -0
  87. package/dist/http-status-U_3MtoGb.d.cts +65 -0
  88. package/dist/http-status.cjs +173 -0
  89. package/dist/http-status.d.cts +142 -0
  90. package/dist/http-status.d.mts +142 -0
  91. package/dist/http-status.mjs +171 -0
  92. package/dist/index.cjs +2551 -0
  93. package/dist/index.d.cts +1493 -0
  94. package/dist/index.d.mts +1493 -0
  95. package/dist/index.mjs +2357 -0
  96. package/dist/object-B0TV3eHx.d.mts +8052 -0
  97. package/dist/object-Blq0Amdv.d.cts +8052 -0
  98. package/dist/objectify-CDs0Fbr1.mjs +417 -0
  99. package/dist/objectify-DIJ-OBmo.cjs +524 -0
  100. package/dist/paginator.cjs +245 -0
  101. package/dist/paginator.d.cts +144 -0
  102. package/dist/paginator.d.mts +144 -0
  103. package/dist/paginator.mjs +243 -0
  104. package/dist/parse-2ubxXZRp.cjs +211 -0
  105. package/dist/parse-N7g942uy.mjs +164 -0
  106. package/dist/pluralizer-BjMIc6uT.d.mts +42 -0
  107. package/dist/pluralizer-Cb6ZmrDl.d.cts +42 -0
  108. package/dist/pluralizer.cjs +678 -0
  109. package/dist/pluralizer.d.cts +152 -0
  110. package/dist/pluralizer.d.mts +152 -0
  111. package/dist/pluralizer.mjs +676 -0
  112. package/dist/primitives-B26uZolQ.cjs +228 -0
  113. package/dist/primitives-KsFUp3kQ.mjs +144 -0
  114. package/dist/specials-D48_IZbd.d.mts +108 -0
  115. package/dist/specials-DzLr1ZgU.cjs +477 -0
  116. package/dist/specials-LVONlKbQ.d.cts +108 -0
  117. package/dist/specials-uhDuRg8H.mjs +292 -0
  118. package/dist/string-CBAbxaG1.d.mts +258 -0
  119. package/dist/string-CsNsm_65.d.cts +258 -0
  120. package/dist/stylog.cjs +621 -0
  121. package/dist/stylog.d.cts +49 -0
  122. package/dist/stylog.d.mts +49 -0
  123. package/dist/stylog.mjs +614 -0
  124. package/dist/timezone-B2OYK6Fh.mjs +5589 -0
  125. package/dist/timezone-Beh9IGpw.cjs +5625 -0
  126. package/dist/types/array.cjs +16 -0
  127. package/dist/types/array.d.cts +18 -0
  128. package/dist/types/array.d.mts +18 -0
  129. package/dist/types/array.mjs +17 -0
  130. package/dist/types/colors.cjs +16 -0
  131. package/dist/types/colors.d.cts +18 -0
  132. package/dist/types/colors.d.mts +18 -0
  133. package/dist/types/colors.mjs +17 -0
  134. package/dist/types/converter.cjs +16 -0
  135. package/dist/types/converter.d.cts +18 -0
  136. package/dist/types/converter.d.mts +18 -0
  137. package/dist/types/converter.mjs +17 -0
  138. package/dist/types/form.cjs +16 -0
  139. package/dist/types/form.d.cts +18 -0
  140. package/dist/types/form.d.mts +18 -0
  141. package/dist/types/form.mjs +17 -0
  142. package/dist/types/hash.cjs +16 -0
  143. package/dist/types/hash.d.cts +18 -0
  144. package/dist/types/hash.d.mts +18 -0
  145. package/dist/types/hash.mjs +17 -0
  146. package/dist/types/http-status.cjs +16 -0
  147. package/dist/types/http-status.d.cts +18 -0
  148. package/dist/types/http-status.d.mts +18 -0
  149. package/dist/types/http-status.mjs +17 -0
  150. package/dist/types/index.cjs +16 -0
  151. package/dist/types/index.d.cts +18 -0
  152. package/dist/types/index.d.mts +18 -0
  153. package/dist/types/index.mjs +17 -0
  154. package/dist/types/number.cjs +16 -0
  155. package/dist/types/number.d.cts +18 -0
  156. package/dist/types/number.d.mts +18 -0
  157. package/dist/types/number.mjs +17 -0
  158. package/dist/types/object.cjs +16 -0
  159. package/dist/types/object.d.cts +18 -0
  160. package/dist/types/object.d.mts +18 -0
  161. package/dist/types/object.mjs +17 -0
  162. package/dist/types/pluralizer.cjs +16 -0
  163. package/dist/types/pluralizer.d.cts +18 -0
  164. package/dist/types/pluralizer.d.mts +18 -0
  165. package/dist/types/pluralizer.mjs +17 -0
  166. package/dist/types/string.cjs +16 -0
  167. package/dist/types/string.d.cts +18 -0
  168. package/dist/types/string.d.mts +18 -0
  169. package/dist/types/string.mjs +17 -0
  170. package/dist/types/stylog.cjs +16 -0
  171. package/dist/types/stylog.d.cts +18 -0
  172. package/dist/types/stylog.d.mts +18 -0
  173. package/dist/types/stylog.mjs +17 -0
  174. package/dist/types/utils.cjs +16 -0
  175. package/dist/types/utils.d.cts +18 -0
  176. package/dist/types/utils.d.mts +18 -0
  177. package/dist/types/utils.mjs +17 -0
  178. package/dist/types/verbalizer.cjs +16 -0
  179. package/dist/types/verbalizer.d.cts +30 -0
  180. package/dist/types/verbalizer.d.mts +30 -0
  181. package/dist/types/verbalizer.mjs +17 -0
  182. package/dist/utilities-CLUmdQeV.cjs +140 -0
  183. package/dist/utilities-m5yFKqLd.mjs +105 -0
  184. package/dist/utils-ClW9LA6f.mjs +449 -0
  185. package/dist/utils-DLFRgXUC.cjs +568 -0
  186. package/dist/verbalizer.cjs +998 -0
  187. package/dist/verbalizer.d.cts +148 -0
  188. package/dist/verbalizer.d.mts +148 -0
  189. package/dist/verbalizer.mjs +996 -0
  190. package/package.json +249 -0
package/dist/hash.cjs ADDED
@@ -0,0 +1,2126 @@
1
+ /**
2
+ * Copyright 2026 - present Nazmul Hassan
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
18
+ const require_primitives = require('./primitives-B26uZolQ.cjs');
19
+ const require_specials = require('./specials-DzLr1ZgU.cjs');
20
+ const require_parse = require('./parse-2ubxXZRp.cjs');
21
+ const require_utils = require('./utils-DLFRgXUC.cjs');
22
+ const require_basics = require('./basics-D_eSv0cu.cjs');
23
+
24
+ //#region src/hash/utils.ts
25
+ /**
26
+ * * Generates a random hexadecimal string of the specified length.
27
+ *
28
+ * @param length - Number of hex characters to generate.
29
+ * @param uppercase - Whether to return uppercase `A–F` characters. Defaults to `false` (lowercase).
30
+ *
31
+ * @returns A randomly generated hexadecimal string.
32
+ *
33
+ * @remarks
34
+ * - This function generates a random hexadecimal string of the specified length.
35
+ * - It uses {@link crypto.getRandomValues} when available for secure randomness, and falls back to {@link Math.random} if not.
36
+ * - The output is a string of hex characters (`0–9`, `a–f` or `A–F`) with no prefixes or separators.
37
+ * - If `length` is `0` or negative, an empty string is returned.
38
+ *
39
+ * @example
40
+ * // 16-character lowercase hex
41
+ * const id = randomHex(16);
42
+ *
43
+ * @example
44
+ * // 8-character uppercase hex
45
+ * const token = randomHex(8, true);
46
+ */
47
+ function randomHex(length, uppercase = false) {
48
+ if (length <= 0) return "";
49
+ const expected = _bytesToRandomHex(new Uint8Array(Math.ceil(length / 2))).slice(0, length);
50
+ return uppercase ? expected.toUpperCase() : expected;
51
+ }
52
+ /**
53
+ * * Converts a UTF-8 string to a byte array (`Uint8Array`).
54
+ *
55
+ * This function encodes a JavaScript string into UTF-8 bytes, handling all Unicode code points including supplementary characters (surrogate pairs).
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * // Basic ASCII
60
+ * const asciiBytes = utf8ToBytes('hello');
61
+ * // Returns:
62
+ * Uint8Array(5) [104, 101, 108, 108, 111]
63
+ *
64
+ * // Unicode characters
65
+ * const unicodeBytes = utf8ToBytes('Hello পৃথিবী!');
66
+ * // Returns:
67
+ * Uint8Array(25) [
68
+ * 72, 101, 108, 108, 111, 32,
69
+ * 224, 166, 170, 224, 167, 131,
70
+ * 224, 166, 165, 224, 166, 191,
71
+ * 224, 166, 172, 224, 167, 128,
72
+ * 33
73
+ * ]
74
+ * ```
75
+ *
76
+ * @param str - The input string to encode as UTF-8 bytes.
77
+ * @returns A `Uint8Array` containing the UTF-8 encoded bytes.
78
+ *
79
+ * @remarks
80
+ * - The encoding follows the UTF-8 specification:
81
+ * - 1-byte sequence for code points U+0000 to U+007F (ASCII)
82
+ * - 2-byte sequence for code points U+0080 to U+07FF
83
+ * - 3-byte sequence for code points U+0800 to U+FFFF
84
+ * - 4-byte sequence for code points U+10000 to U+10FFFF (surrogate pairs)
85
+ *
86
+ * **Note:** Invalid surrogate pairs in the input string are silently ignored.
87
+ *
88
+ * @see {@link bytesToUtf8} for the inverse operation
89
+ */
90
+ function utf8ToBytes(str) {
91
+ const out = [];
92
+ for (let i = 0; i < str.length; i++) {
93
+ const code = str.charCodeAt(i);
94
+ if (code < 128) out.push(code);
95
+ else if (code < 2048) out.push(192 | code >> 6, 128 | code & 63);
96
+ else if (code >= 55296 && code <= 57343) {
97
+ if (code < 56320 && i + 1 < str.length) {
98
+ const hi = code;
99
+ const lo = str.charCodeAt(++i);
100
+ const codePoint = 65536 + (hi - 55296 << 10) + (lo - 56320);
101
+ out.push(240 | codePoint >> 18, 128 | codePoint >> 12 & 63, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
102
+ }
103
+ } else out.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
104
+ }
105
+ return new Uint8Array(out);
106
+ }
107
+ /**
108
+ * * Converts `UTF-8` encoded bytes back to a string.
109
+ *
110
+ * This function decodes a `Uint8Array` containing `UTF-8` bytes into a JavaScript string.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * // Decode UTF-8 bytes
115
+ * const bytes = new Uint8Array([104, 101, 108, 108, 111]);
116
+ * const str = bytesToUtf8(bytes);
117
+ * // Returns: 'hello'
118
+ *
119
+ * // Round-trip conversion
120
+ * const original = 'Hello 🌍';
121
+ * const bytes = utf8ToBytes(original);
122
+ * const decoded = bytesToUtf8(bytes);
123
+ * console.log(original === decoded); // true
124
+ * ```
125
+ *
126
+ * @param bytes - A `Uint8Array` containing `UTF-8` encoded bytes.
127
+ * @returns The decoded string.
128
+ *
129
+ * @remarks
130
+ * - The function handles all valid `UTF-8` sequences:
131
+ * - 1-byte sequences (0xxxxxxx) → ASCII characters
132
+ * - 2-byte sequences (110xxxxx 10xxxxxx)
133
+ * - 3-byte sequences (1110xxxx 10xxxxxx 10xxxxxx)
134
+ * - 4-byte sequences (11110xxx 10xxxxxx 10xxxxxx 10xxxxxx) → surrogate pairs
135
+ *
136
+ * @see {@link utf8ToBytes} for the inverse operation
137
+ */
138
+ function bytesToUtf8(bytes) {
139
+ let out = "";
140
+ let i = 0;
141
+ while (i < bytes.length) {
142
+ const b1 = bytes[i++];
143
+ if (b1 < 128) out += String.fromCharCode(b1);
144
+ else if (b1 >= 192 && b1 < 224) {
145
+ const b2 = bytes[i++];
146
+ out += String.fromCharCode((b1 & 31) << 6 | b2 & 63);
147
+ } else if (b1 >= 224 && b1 < 240) {
148
+ const b2 = bytes[i++];
149
+ const b3 = bytes[i++];
150
+ out += String.fromCharCode((b1 & 15) << 12 | (b2 & 63) << 6 | b3 & 63);
151
+ } else {
152
+ const b2 = bytes[i++];
153
+ const b3 = bytes[i++];
154
+ const b4 = bytes[i++];
155
+ let codePoint = (b1 & 7) << 18 | (b2 & 63) << 12 | (b3 & 63) << 6 | b4 & 63;
156
+ codePoint -= 65536;
157
+ out += String.fromCharCode(55296 + (codePoint >> 10 & 1023), 56320 + (codePoint & 1023));
158
+ }
159
+ }
160
+ return out;
161
+ }
162
+ /**
163
+ * * Decodes a `Base64` string to bytes.
164
+ * - This function converts a `Base64`-encoded string back to its original byte representation.
165
+ * - It handles standard `Base64` encoding with '=', '+', '/' characters.
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * // Decode Base64 string
170
+ * const bytes = base64ToBytes('aGVsbG8gd29ybGQ=');
171
+ * // Returns: Uint8Array(11) [104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
172
+ *
173
+ * // Empty string
174
+ * const empty = base64ToBytes('');
175
+ * // Returns: Uint8Array(0) []
176
+ * ```
177
+ *
178
+ * @param str - The `Base64`-encoded string to decode.
179
+ * @returns A `Uint8Array` containing the decoded bytes.
180
+ *
181
+ * @remarks
182
+ * - The function supports:
183
+ * - Standard `Base64` alphabet (A-Z, a-z, 0-9, +, /)
184
+ * - Padding with '=' characters
185
+ * - Ignores whitespace (though not explicitly trimmed in this implementation)
186
+ *
187
+ * @see {@link bytesToBase64} for the inverse operation
188
+ */
189
+ function base64ToBytes(str) {
190
+ const _b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
191
+ const out = [];
192
+ let i = 0;
193
+ while (i < str.length) {
194
+ const h1 = _b64chars.indexOf(str[i++]);
195
+ const h2 = _b64chars.indexOf(str[i++]);
196
+ const h3 = _b64chars.indexOf(str[i++]);
197
+ const h4 = _b64chars.indexOf(str[i++]);
198
+ const o1 = h1 << 2 | h2 >> 4;
199
+ const o2 = (h2 & 15) << 4 | h3 >> 2;
200
+ const o3 = (h3 & 3) << 6 | h4;
201
+ out.push(o1);
202
+ if (h3 !== 64) out.push(o2);
203
+ if (h4 !== 64) out.push(o3);
204
+ }
205
+ return new Uint8Array(out);
206
+ }
207
+ /**
208
+ * * Encodes bytes to a `Base64` string.
209
+ * - This function converts a `Uint8Array` to a `Base64`-encoded string using the standard `Base64` alphabet with padding.
210
+ *
211
+ * @example
212
+ * ```typescript
213
+ * // Encode bytes to Base64
214
+ * const bytes = new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]);
215
+ * const b64 = bytesToBase64(bytes);
216
+ * // Returns: 'aGVsbG8gd29ybGQ='
217
+ *
218
+ * // Empty array
219
+ * const empty = bytesToBase64(new Uint8Array(0));
220
+ * // Returns: ''
221
+ * ```
222
+ *
223
+ * @param bytes - The bytes to encode as `Base64`.
224
+ * @returns The `Base64`-encoded string.
225
+ *
226
+ * @remarks
227
+ * The encoding uses:
228
+ * - Standard `Base64` alphabet (A-Z, a-z, 0-9, +, /)
229
+ * - '=' padding for incomplete groups
230
+ * - No line breaks or whitespace
231
+ *
232
+ * This is a pure JavaScript implementation that doesn't rely on `btoa()`.
233
+ *
234
+ * @see {@link base64ToBytes} for the inverse operation
235
+ */
236
+ function bytesToBase64(bytes) {
237
+ const _b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
238
+ let out = "";
239
+ let i = 0;
240
+ while (i < bytes.length) {
241
+ const o1 = bytes[i++];
242
+ const o2 = bytes[i++];
243
+ const o3 = bytes[i++];
244
+ const h1 = o1 >> 2;
245
+ const h2 = (o1 & 3) << 4 | o2 >> 4;
246
+ const h3 = (o2 & 15) << 2 | o3 >> 6;
247
+ const h4 = o3 & 63;
248
+ out += _b64chars[h1] + _b64chars[h2] + _b64chars[isNaN(o2) ? 64 : h3] + _b64chars[isNaN(o3) ? 64 : h4];
249
+ }
250
+ return out;
251
+ }
252
+ /**
253
+ * * Concatenates multiple `Uint8Array`s into a single `Uint8Array`.
254
+ * - This function efficiently combines multiple byte arrays without creating intermediate strings or arrays.
255
+ *
256
+ * @example
257
+ * ```typescript
258
+ * // Concatenate multiple arrays
259
+ * const a = new Uint8Array([1, 2, 3]);
260
+ * const b = new Uint8Array([4, 5]);
261
+ * const c = new Uint8Array([6, 7, 8, 9]);
262
+ * const result = concatBytes(a, b, c);
263
+ * // Returns: Uint8Array(9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
264
+ *
265
+ * // Single array
266
+ * const single = concatBytes(new Uint8Array([1, 2, 3]));
267
+ * // Returns: Uint8Array(3) [1, 2, 3]
268
+ *
269
+ * // No arrays
270
+ * const empty = concatBytes();
271
+ * // Returns: Uint8Array(0) []
272
+ * ```
273
+ *
274
+ * @param parts - One or more `Uint8Array`s to concatenate.
275
+ * @returns A new `Uint8Array` containing all the bytes from the input arrays in the order they were provided.
276
+ *
277
+ * @remarks The function allocates a single `Uint8Array` of the total combined length and copies all bytes into it using `set()` for optimal performance.
278
+ */
279
+ function concatBytes(...parts) {
280
+ const len = parts.reduce((s, p) => s + p.length, 0);
281
+ const out = new Uint8Array(len);
282
+ let offset = 0;
283
+ for (const p of parts) {
284
+ out.set(p, offset);
285
+ offset += p.length;
286
+ }
287
+ return out;
288
+ }
289
+ /**
290
+ * * Computes the `SHA-256` hash of raw bytes.
291
+ * - This is a pure JavaScript implementation of the `SHA-256` cryptographic hash function that operates directly on byte arrays (`Uint8Array`).
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * // Hash raw bytes
296
+ * const bytes = new Uint8Array([104, 101, 108, 108, 111]); // "hello"
297
+ * const hash = sha256Bytes(bytes);
298
+ * // Returns: Uint8Array(32) with SHA-256 hash
299
+ *
300
+ * // Verify with string hash
301
+ * const strHash = sha256('hello');
302
+ * const bytesHash = bytesToHex(sha256Bytes(utf8ToBytes('hello')));
303
+ * console.log(strHash === bytesHash); // true
304
+ * ```
305
+ *
306
+ * @param message - The bytes to hash as a `Uint8Array`.
307
+ * @returns A `Uint8Array` of 32 bytes (256 bits) containing the `SHA-256` hash.
308
+ *
309
+ * @remarks
310
+ * - Implementation details:
311
+ * - Follows the `SHA-256` specification (FIPS 180-4)
312
+ * - Uses big-endian byte order throughout
313
+ * - Processes messages in 512-bit (64-byte) blocks
314
+ * - Applies proper padding with message length
315
+ * - Uses all required `SHA-256` round constants
316
+ * - Returns hash as 32-byte array
317
+ *
318
+ * @see {@link hmacSha256} for `HMAC-SHA256` computation
319
+ */
320
+ function sha256Bytes(message) {
321
+ const H = new Uint32Array([
322
+ 1779033703,
323
+ 3144134277,
324
+ 1013904242,
325
+ 2773480762,
326
+ 1359893119,
327
+ 2600822924,
328
+ 528734635,
329
+ 1541459225
330
+ ]);
331
+ const K = new Uint32Array([
332
+ 1116352408,
333
+ 1899447441,
334
+ 3049323471,
335
+ 3921009573,
336
+ 961987163,
337
+ 1508970993,
338
+ 2453635748,
339
+ 2870763221,
340
+ 3624381080,
341
+ 310598401,
342
+ 607225278,
343
+ 1426881987,
344
+ 1925078388,
345
+ 2162078206,
346
+ 2614888103,
347
+ 3248222580,
348
+ 3835390401,
349
+ 4022224774,
350
+ 264347078,
351
+ 604807628,
352
+ 770255983,
353
+ 1249150122,
354
+ 1555081692,
355
+ 1996064986,
356
+ 2554220882,
357
+ 2821834349,
358
+ 2952996808,
359
+ 3210313671,
360
+ 3336571891,
361
+ 3584528711,
362
+ 113926993,
363
+ 338241895,
364
+ 666307205,
365
+ 773529912,
366
+ 1294757372,
367
+ 1396182291,
368
+ 1695183700,
369
+ 1986661051,
370
+ 2177026350,
371
+ 2456956037,
372
+ 2730485921,
373
+ 2820302411,
374
+ 3259730800,
375
+ 3345764771,
376
+ 3516065817,
377
+ 3600352804,
378
+ 4094571909,
379
+ 275423344,
380
+ 430227734,
381
+ 506948616,
382
+ 659060556,
383
+ 883997877,
384
+ 958139571,
385
+ 1322822218,
386
+ 1537002063,
387
+ 1747873779,
388
+ 1955562222,
389
+ 2024104815,
390
+ 2227730452,
391
+ 2361852424,
392
+ 2428436474,
393
+ 2756734187,
394
+ 3204031479,
395
+ 3329325298
396
+ ]);
397
+ const ml = message.length * 8;
398
+ const padding = new Uint8Array(message.length + 8 + 64 & -64 || 64);
399
+ padding.set(message, 0);
400
+ padding[message.length] = 128;
401
+ const lenView = new DataView(padding.buffer);
402
+ lenView.setUint32(padding.length - 8, Math.floor(ml / 4294967296), false);
403
+ lenView.setUint32(padding.length - 4, ml & 4294967295, false);
404
+ const w = new Uint32Array(64);
405
+ const chunkView = new DataView(padding.buffer);
406
+ for (let offset = 0; offset < padding.length; offset += 64) {
407
+ for (let t = 0; t < 16; t++) w[t] = chunkView.getUint32(offset + t * 4, false);
408
+ for (let t = 16; t < 64; t++) {
409
+ const s0 = (w[t - 15] >>> 7 | w[t - 15] << 25) ^ (w[t - 15] >>> 18 | w[t - 15] << 14) ^ w[t - 15] >>> 3;
410
+ const s1 = (w[t - 2] >>> 17 | w[t - 2] << 15) ^ (w[t - 2] >>> 19 | w[t - 2] << 13) ^ w[t - 2] >>> 10;
411
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1 >>> 0;
412
+ }
413
+ let a = H[0];
414
+ let b = H[1];
415
+ let c = H[2];
416
+ let d = H[3];
417
+ let e = H[4];
418
+ let f = H[5];
419
+ let g = H[6];
420
+ let h = H[7];
421
+ for (let t = 0; t < 64; t++) {
422
+ const S1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);
423
+ const ch = e & f ^ ~e & g;
424
+ const temp1 = h + S1 + ch + K[t] + w[t] >>> 0;
425
+ const temp2 = ((a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10)) + (a & b ^ a & c ^ b & c) >>> 0;
426
+ h = g;
427
+ g = f;
428
+ f = e;
429
+ e = d + temp1 >>> 0;
430
+ d = c;
431
+ c = b;
432
+ b = a;
433
+ a = temp1 + temp2 >>> 0;
434
+ }
435
+ H[0] = H[0] + a >>> 0;
436
+ H[1] = H[1] + b >>> 0;
437
+ H[2] = H[2] + c >>> 0;
438
+ H[3] = H[3] + d >>> 0;
439
+ H[4] = H[4] + e >>> 0;
440
+ H[5] = H[5] + f >>> 0;
441
+ H[6] = H[6] + g >>> 0;
442
+ H[7] = H[7] + h >>> 0;
443
+ }
444
+ const out = new Uint8Array(32);
445
+ const outView = new DataView(out.buffer);
446
+ for (let i = 0; i < 8; i++) outView.setUint32(i * 4, H[i], false);
447
+ return out;
448
+ }
449
+ /**
450
+ * * Computes `HMAC-SHA256` (Hash-based Message Authentication Code using `SHA-256`).
451
+ * - This function implements the `HMAC` algorithm with `SHA-256` as the underlying hash function, providing message authentication and integrity verification.
452
+ *
453
+ * @example
454
+ * ```typescript
455
+ * // Basic HMAC calculation
456
+ * const key = new TextEncoder().encode('secret-key');
457
+ * const message = new TextEncoder().encode('Hello, world!');
458
+ * const hmac = hmacSha256(key, message);
459
+ *
460
+ * // Using with string inputs
461
+ * const keyBytes = new TextEncoder().encode('my-key');
462
+ * const msgBytes = new TextEncoder().encode('data to authenticate');
463
+ * const hmacResult = hmacSha256(keyBytes, msgBytes);
464
+ * const hexResult = bytesToHex(hmacResult);
465
+ * ```
466
+ *
467
+ * @param key - The secret key as a `Uint8Array`.
468
+ * @param message - The message to authenticate as a `Uint8Array`.
469
+ * @returns A `Uint8Array` of 32 bytes containing the `HMAC-SHA256` tag.
470
+ *
471
+ * @remarks
472
+ * - Algorithm steps:
473
+ * - 1. Keys longer than 64 bytes are hashed with `SHA-256`
474
+ * - 2. Keys shorter than 64 bytes are padded with zeros
475
+ * - 3. Inner hash: `SHA-256((key ⊕ ipad) || message)` where ipad = 0x36 repeated
476
+ * - 4. Outer hash: `SHA-256((key ⊕ opad) || inner_hash)` where opad = 0x5C repeated
477
+ *
478
+ * - The implementation follows RFC 2104 and RFC 4231 specifications.
479
+ * - Block size for `SHA-256` HMAC is 64 bytes (512 bits).
480
+ *
481
+ * **Common use cases:**
482
+ * - API authentication tokens
483
+ * - Message integrity verification
484
+ * - Key derivation (as part of `HKDF`)
485
+ *
486
+ * @see {@link sha256Bytes} for the underlying hash function
487
+ */
488
+ function hmacSha256(key, message) {
489
+ const blockSize = 64;
490
+ let k = key;
491
+ if (k.length > blockSize) k = sha256Bytes(k);
492
+ if (k.length < blockSize) {
493
+ const tmp = new Uint8Array(blockSize);
494
+ tmp.set(k, 0);
495
+ k = tmp;
496
+ }
497
+ const oKeyPad = new Uint8Array(blockSize);
498
+ const iKeyPad = new Uint8Array(blockSize);
499
+ for (let i = 0; i < blockSize; i++) {
500
+ oKeyPad[i] = k[i] ^ 92;
501
+ iKeyPad[i] = k[i] ^ 54;
502
+ }
503
+ const inner = new Uint8Array(iKeyPad.length + message.length);
504
+ inner.set(iKeyPad, 0);
505
+ inner.set(message, iKeyPad.length);
506
+ const innerHash = sha256Bytes(inner);
507
+ const outer = new Uint8Array(oKeyPad.length + innerHash.length);
508
+ outer.set(oKeyPad, 0);
509
+ outer.set(innerHash, oKeyPad.length);
510
+ return sha256Bytes(outer);
511
+ }
512
+ /**
513
+ * * Converts a `Uint8Array` to a `Uint32Array` with big-endian byte order.
514
+ * - This function groups bytes into 32-bit integers, reading them in big-endian (most significant byte first) order. Missing bytes are treated as zero.
515
+ *
516
+ * @example
517
+ * ```typescript
518
+ * // Convert bytes to 32-bit integers
519
+ * const bytes = new Uint8Array([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]);
520
+ * const words = uint8To32ArrayBE(bytes);
521
+ * // Returns: Uint32Array(2) [0x12345678, 0x9ABC0000] or equivalent: Uint32Array(2) [ 305419896, 2596012032 ]
522
+ *
523
+ * // Partial final word
524
+ * const partial = new Uint8Array([0xFF, 0xEE, 0xDD]);
525
+ * const words2 = uint8To32ArrayBE(partial);
526
+ * // Returns: Uint32Array(1) [0xFFEEDD00] or equivalent: Uint32Array(1) [ 4293844224 ]
527
+ * ```
528
+ *
529
+ * @param bytes - The bytes to convert to 32-bit words.
530
+ * @returns A `Uint32Array` containing the 32-bit big-endian words.
531
+ *
532
+ * @remarks
533
+ * - Input length doesn't need to be a multiple of 4
534
+ * - Missing bytes in the final word are padded with zeros
535
+ * - Byte order: `bytes[0]` is the most significant byte of `out[0]`
536
+ * - This is useful for cryptographic operations that work with 32-bit words
537
+ */
538
+ function uint8To32ArrayBE(bytes) {
539
+ const len = Math.ceil(bytes.length / 4);
540
+ const out = new Uint32Array(len);
541
+ for (let i = 0; i < len; i++) {
542
+ const base = i * 4;
543
+ out[i] = (bytes[base] || 0) << 24 | (bytes[base + 1] || 0) << 16 | (bytes[base + 2] || 0) << 8 | (bytes[base + 3] || 0) << 0;
544
+ }
545
+ return out;
546
+ }
547
+ /**
548
+ * * Converts a 32-bit integer into a 4-byte `Uint8Array` in big-endian (network) byte order.
549
+ * - This function takes a 32-bit integer and encodes it as 4 bytes with the most significant byte first (big-endian order), which is the standard for network protocols and many cryptographic operations.
550
+ *
551
+ * @example
552
+ * ```typescript
553
+ * // Convert integer to bytes
554
+ * const bytes = intTo4BytesBE(0x12345678);
555
+ * // Returns: Uint8Array(4) [0x12, 0x34, 0x56, 0x78] or equivalent: Uint8Array(4) [ 18, 52, 86, 120 ]
556
+ *
557
+ * // Maximum 32-bit value
558
+ * const maxBytes = intTo4BytesBE(0xFFFFFFFF);
559
+ * // Returns: Uint8Array(4) [0xFF, 0xFF, 0xFF, 0xFF]
560
+ *
561
+ * // Zero
562
+ * const zeroBytes = intTo4BytesBE(0);
563
+ * // Returns: Uint8Array(4) [0x00, 0x00, 0x00, 0x00]
564
+ * ```
565
+ *
566
+ * @param n - The 32-bit integer to convert. Values beyond 32 bits will be truncated.
567
+ * @returns A 4-byte `Uint8Array` representing the value in big-endian format.
568
+ *
569
+ * @remarks
570
+ * - The function uses unsigned 32-bit arithmetic (`>>>` operator)
571
+ * - Only the lower 32 bits of the input are used (truncation)
572
+ * - Output is always exactly 4 bytes
573
+ * - Big-endian order: byte[0] = most significant, byte[3] = least significant
574
+ *
575
+ * **Common use cases:**
576
+ * - Encoding message lengths in network protocols
577
+ * - Preparing data for cryptographic operations
578
+ * - Converting integers for storage or transmission
579
+ *
580
+ * @see {@link uint8To32ArrayBE} for bytes to 32-bit integers conversion
581
+ */
582
+ function intTo4BytesBE(n) {
583
+ const b = new Uint8Array(4);
584
+ b[0] = n >>> 24 & 255;
585
+ b[1] = n >>> 16 & 255;
586
+ b[2] = n >>> 8 & 255;
587
+ b[3] = n & 255;
588
+ return b;
589
+ }
590
+ /**
591
+ * * Converts a `Uint8Array` to a lowercase hexadecimal string.
592
+ * - This function encodes binary data (bytes) as a hexadecimal string, with each byte represented as two lowercase hexadecimal digits (0-9, a-f).
593
+ *
594
+ * @example
595
+ * ```typescript
596
+ * // Convert bytes to hex
597
+ * const bytes = new Uint8Array([0x12, 0xAB, 0xFF, 0x00]);
598
+ * const hex = bytesToHex(bytes);
599
+ * // Returns: '12abff00'
600
+ *
601
+ * // Empty array
602
+ * const emptyHex = bytesToHex(new Uint8Array(0));
603
+ * // Returns: ''
604
+ *
605
+ * // SHA-256 hash to hex
606
+ * const hashBytes = sha256Bytes(utf8ToBytes('hello'));
607
+ * const hashHex = bytesToHex(hashBytes);
608
+ * // Returns: '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
609
+ * ```
610
+ *
611
+ * @param bytes - The bytes to convert to hexadecimal representation.
612
+ * @returns A lowercase hexadecimal string where each byte is represented by two characters (00-ff).
613
+ *
614
+ * @remarks
615
+ * - Always returns lowercase letters (a-f)
616
+ * - Zero pads single-digit hex values (e.g., 0x0F → "0f", not "f")
617
+ * - Efficient O(n) implementation using string concatenation
618
+ * - No prefix (e.g., no "0x" at the beginning)
619
+ *
620
+ * **Common use cases:**
621
+ * - Displaying cryptographic hashes and signatures
622
+ * - Debugging binary data
623
+ * - Converting binary data for JSON serialization
624
+ * - Creating hex-encoded strings for APIs and protocols
625
+ *
626
+ * @see {@link hexToBytes} for reverse process
627
+ */
628
+ function bytesToHex(bytes) {
629
+ let hex = "";
630
+ for (let i = 0; i < bytes.length; i++) {
631
+ const byte = bytes[i].toString(16).padStart(2, "0");
632
+ hex += byte;
633
+ }
634
+ return hex;
635
+ }
636
+ /**
637
+ * * Converts a hexadecimal string to a `Uint8Array`.
638
+ * - This function decodes a hexadecimal-encoded string into its raw byte representation, where every two hexadecimal characters (00–ff) are converted into one byte.
639
+ *
640
+ * @example
641
+ * // Convert hex to bytes
642
+ * const hex = '12abff00';
643
+ * const bytes = hexToBytes(hex);
644
+ * // Returns: Uint8Array(4) [18, 171, 255, 0]
645
+ *
646
+ * // Empty string
647
+ * const emptyBytes = hexToBytes('');
648
+ * // Returns: Uint8Array []
649
+ *
650
+ * // Decode SHA-256 hash from hex
651
+ * const hashHex = '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824';
652
+ * const hashBytes = hexToBytes(hashHex);
653
+ * // Returns: Uint8Array(32)
654
+ *
655
+ * @param hex - A hexadecimal string where each byte is represented by two characters (00–ff).
656
+ * @returns A `Uint8Array` containing the decoded bytes. Returns an empty array for invalid input.
657
+ *
658
+ * @remarks
659
+ * - Accepts lowercase and uppercase hexadecimal characters (0–9, a–f, A–F) with or without space between bytes
660
+ * - Ignores no prefixes (e.g., does not support "0x")
661
+ * - Requires an even number of hexadecimal characters
662
+ * - Efficient O(n) implementation with direct byte parsing
663
+ *
664
+ * **Common use cases:**
665
+ * - Decoding cryptographic hashes and signatures
666
+ * - Parsing hex-encoded binary payloads
667
+ * - Reconstructing binary data from storage or transport formats
668
+ * - Working with low-level protocols and binary APIs
669
+ *
670
+ * @see {@link bytesToHex} for the reverse process
671
+ */
672
+ function hexToBytes(hex) {
673
+ if (!require_specials.isHexString(hex)) return new Uint8Array();
674
+ const bytes = _splitByCharLength(hex, 2).map((h) => parseInt(h, 16));
675
+ return new Uint8Array(bytes);
676
+ }
677
+
678
+ //#endregion
679
+ //#region src/hash/helpers.ts
680
+ /** Adds two 32-bit numbers */
681
+ function _add32(x, y) {
682
+ return x + y & 4294967295;
683
+ }
684
+ /** Converts a 32-bit number to a 4-byte hex string */
685
+ function _numToHex(n) {
686
+ return [
687
+ 0,
688
+ 8,
689
+ 16,
690
+ 24
691
+ ].map((shift) => (n >> shift & 255).toString(16).padStart(2, "0")).join("");
692
+ }
693
+ /** Converts a 64-character string block to an array of 16 numbers */
694
+ function _stringToNumbers(s) {
695
+ return Array.from({ length: 16 }, (_, i) => {
696
+ const x = i << 2;
697
+ return s.charCodeAt(x) | s.charCodeAt(x + 1) << 8 | s.charCodeAt(x + 2) << 16 | s.charCodeAt(x + 3) << 24;
698
+ });
699
+ }
700
+ /** Common MD5 transformation function */
701
+ function _transform(q, a, b, x, s, t) {
702
+ const a1 = _add32(_add32(a, q), _add32(x, t));
703
+ return _add32(a1 << s | a1 >>> 32 - s, b);
704
+ }
705
+ /** Round 1 operation */
706
+ const ff = (a, b, c, d, x, s, t) => {
707
+ return _transform(b & c | ~b & d, a, b, x, s, t);
708
+ };
709
+ /** Round 2 operation */
710
+ const gg = (a, b, c, d, x, s, t) => {
711
+ return _transform(b & d | c & ~d, a, b, x, s, t);
712
+ };
713
+ /** Round 3 operation */
714
+ const hh = (a, b, c, d, x, s, t) => {
715
+ return _transform(b ^ c ^ d, a, b, x, s, t);
716
+ };
717
+ /** Round 4 operation */
718
+ const ii = (a, b, c, d, x, s, t) => {
719
+ return _transform(c ^ (b | ~d), a, b, x, s, t);
720
+ };
721
+ /** Performs one MD5 cycle on a 4-element state with 16-word block */
722
+ function _md5cycle(x, k) {
723
+ let a = x[0];
724
+ let b = x[1];
725
+ let c = x[2];
726
+ let d = x[3];
727
+ a = ff(a, b, c, d, k[0], 7, -680876936);
728
+ d = ff(d, a, b, c, k[1], 12, -389564586);
729
+ c = ff(c, d, a, b, k[2], 17, 606105819);
730
+ b = ff(b, c, d, a, k[3], 22, -1044525330);
731
+ a = ff(a, b, c, d, k[4], 7, -176418897);
732
+ d = ff(d, a, b, c, k[5], 12, 1200080426);
733
+ c = ff(c, d, a, b, k[6], 17, -1473231341);
734
+ b = ff(b, c, d, a, k[7], 22, -45705983);
735
+ a = ff(a, b, c, d, k[8], 7, 1770035416);
736
+ d = ff(d, a, b, c, k[9], 12, -1958414417);
737
+ c = ff(c, d, a, b, k[10], 17, -42063);
738
+ b = ff(b, c, d, a, k[11], 22, -1990404162);
739
+ a = ff(a, b, c, d, k[12], 7, 1804603682);
740
+ d = ff(d, a, b, c, k[13], 12, -40341101);
741
+ c = ff(c, d, a, b, k[14], 17, -1502002290);
742
+ b = ff(b, c, d, a, k[15], 22, 1236535329);
743
+ a = gg(a, b, c, d, k[1], 5, -165796510);
744
+ d = gg(d, a, b, c, k[6], 9, -1069501632);
745
+ c = gg(c, d, a, b, k[11], 14, 643717713);
746
+ b = gg(b, c, d, a, k[0], 20, -373897302);
747
+ a = gg(a, b, c, d, k[5], 5, -701558691);
748
+ d = gg(d, a, b, c, k[10], 9, 38016083);
749
+ c = gg(c, d, a, b, k[15], 14, -660478335);
750
+ b = gg(b, c, d, a, k[4], 20, -405537848);
751
+ a = gg(a, b, c, d, k[9], 5, 568446438);
752
+ d = gg(d, a, b, c, k[14], 9, -1019803690);
753
+ c = gg(c, d, a, b, k[3], 14, -187363961);
754
+ b = gg(b, c, d, a, k[8], 20, 1163531501);
755
+ a = gg(a, b, c, d, k[13], 5, -1444681467);
756
+ d = gg(d, a, b, c, k[2], 9, -51403784);
757
+ c = gg(c, d, a, b, k[7], 14, 1735328473);
758
+ b = gg(b, c, d, a, k[12], 20, -1926607734);
759
+ a = hh(a, b, c, d, k[5], 4, -378558);
760
+ d = hh(d, a, b, c, k[8], 11, -2022574463);
761
+ c = hh(c, d, a, b, k[11], 16, 1839030562);
762
+ b = hh(b, c, d, a, k[14], 23, -35309556);
763
+ a = hh(a, b, c, d, k[1], 4, -1530992060);
764
+ d = hh(d, a, b, c, k[4], 11, 1272893353);
765
+ c = hh(c, d, a, b, k[7], 16, -155497632);
766
+ b = hh(b, c, d, a, k[10], 23, -1094730640);
767
+ a = hh(a, b, c, d, k[13], 4, 681279174);
768
+ d = hh(d, a, b, c, k[0], 11, -358537222);
769
+ c = hh(c, d, a, b, k[3], 16, -722521979);
770
+ b = hh(b, c, d, a, k[6], 23, 76029189);
771
+ a = hh(a, b, c, d, k[9], 4, -640364487);
772
+ d = hh(d, a, b, c, k[12], 11, -421815835);
773
+ c = hh(c, d, a, b, k[15], 16, 530742520);
774
+ b = hh(b, c, d, a, k[2], 23, -995338651);
775
+ a = ii(a, b, c, d, k[0], 6, -198630844);
776
+ d = ii(d, a, b, c, k[7], 10, 1126891415);
777
+ c = ii(c, d, a, b, k[14], 15, -1416354905);
778
+ b = ii(b, c, d, a, k[5], 21, -57434055);
779
+ a = ii(a, b, c, d, k[12], 6, 1700485571);
780
+ d = ii(d, a, b, c, k[3], 10, -1894986606);
781
+ c = ii(c, d, a, b, k[10], 15, -1051523);
782
+ b = ii(b, c, d, a, k[1], 21, -2054922799);
783
+ a = ii(a, b, c, d, k[8], 6, 1873313359);
784
+ d = ii(d, a, b, c, k[15], 10, -30611744);
785
+ c = ii(c, d, a, b, k[6], 15, -1560198380);
786
+ b = ii(b, c, d, a, k[13], 21, 1309151649);
787
+ a = ii(a, b, c, d, k[4], 6, -145523070);
788
+ d = ii(d, a, b, c, k[11], 10, -1120210379);
789
+ c = ii(c, d, a, b, k[2], 15, 718787259);
790
+ b = ii(b, c, d, a, k[9], 21, -343485551);
791
+ x[0] = _add32(a, x[0]);
792
+ x[1] = _add32(b, x[1]);
793
+ x[2] = _add32(c, x[2]);
794
+ x[3] = _add32(d, x[3]);
795
+ }
796
+ /**
797
+ * Computes UUID timestamp in 100-nanosecond intervals since
798
+ * 00:00:00.00 15 October 1582 (Gregorian epoch).
799
+ */
800
+ function _uuidTimestamp() {
801
+ return (BigInt(Date.now()) + 12219292800000n) * 10000n;
802
+ }
803
+ /**
804
+ * Generates a random 48-bit node ID.
805
+ * LSB of first byte must be 1 to indicate a randomly generated node.
806
+ */
807
+ function _randomNode48() {
808
+ const node = randomHex(12).split("");
809
+ return (parseInt(node.slice(0, 2).join(""), 16) | 1).toString(16).padStart(2, "0") + node.slice(2).join("");
810
+ }
811
+ /**
812
+ * Generates random hex string of given byte length using crypto API if available, otherwise falls back to Math.random.
813
+ * @param bytes Instance of {@link Uint8Array} to fill with random values.
814
+ * @returns Hex string representation of the random bytes.
815
+ */
816
+ function _bytesToRandomHex(bytes) {
817
+ if (crypto?.getRandomValues) crypto.getRandomValues(bytes);
818
+ else for (let i = 0; i < bytes.length; i++) bytes[i] = Math.floor(Math.random() * 256);
819
+ let hex = "";
820
+ for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, "0");
821
+ return hex;
822
+ }
823
+ /** * Generates a 14-bit clock sequence (2 bytes, but only 14 bits used). */
824
+ function _clockSeq14() {
825
+ return (parseInt(randomHex(4), 16) & 16383).toString(16).padStart(4, "0");
826
+ }
827
+ /** Convert a hex string to UUID format */
828
+ function _formatUUID(h, v, up) {
829
+ const part3 = String(v) + h.slice(13, 16);
830
+ const part4 = _hexVariant(h.slice(16, 18)) + h.slice(18, 20);
831
+ const formatted = [
832
+ h.slice(0, 8),
833
+ h.slice(8, 12),
834
+ part3,
835
+ part4,
836
+ h.slice(20, 32)
837
+ ].join("-");
838
+ return up ? formatted.toUpperCase() : formatted;
839
+ }
840
+ /** Ensure UUID variant is RFC4122 compliant */
841
+ function _hexVariant(hex) {
842
+ return (parseInt(hex, 16) & 63 | 128).toString(16).padStart(2, "0");
843
+ }
844
+ /** Check if the uuid `options` is compatible for `v3` and `v5` */
845
+ function _isOptionV3V5(opt) {
846
+ if (require_specials.isObjectWithKeys(opt, ["name", "namespace"])) return require_specials.isUUID(opt?.namespace) && require_primitives.isNonEmptyString(opt?.name);
847
+ return false;
848
+ }
849
+ /** Check UUID version after checking for valid UUID from `v1-v8` */
850
+ function _checkUUIDVersion(value, v) {
851
+ return require_specials.isUUID(value) && value[14] === v;
852
+ }
853
+ /**
854
+ * Compares two encrypted strings or byte arrays in constant time.
855
+ * Prevents timing attacks by ensuring equal-time checks regardless of data differences.
856
+ */
857
+ function _constantTimeEquals(a, b) {
858
+ if (a.length !== b.length) return false;
859
+ const _getRes = (x, idx) => {
860
+ return require_primitives.isString(x) ? x.charCodeAt(idx) : x[idx];
861
+ };
862
+ let res = 0;
863
+ for (let i = 0; i < a.length; i++) res |= _getRes(a, i) ^ _getRes(b, i);
864
+ return res === 0;
865
+ }
866
+ /** Split string by substring length, intended to be used internally for hex and binary converters only */
867
+ function _splitByCharLength(str, splitByChars = 2) {
868
+ if (!require_primitives.isNonEmptyString(str)) return [];
869
+ const sanitized = str.replace(/\s+/g, "");
870
+ const result = [];
871
+ for (let i = 0; i < sanitized.length; i += splitByChars) result.push(sanitized.slice(i, i + splitByChars));
872
+ return result;
873
+ }
874
+ /** Pad start of a byte with 0 for `hex` or `binary` */
875
+ function _padStartWith0(byte, type) {
876
+ return byte.toString(type === "hex" ? 16 : 2).padStart(type === "hex" ? 2 : 8, "0");
877
+ }
878
+
879
+ //#endregion
880
+ //#region src/hash/Cipher.ts
881
+ /**
882
+ * @class Lightweight stream-cipher–style encryption utility using `HMAC-SHA256` for keystream generation and authentication.
883
+ * - The class derives separate encryption and MAC keys from the provided secret.
884
+ *
885
+ * @remarks
886
+ * - **The encryption scheme is:**
887
+ * - keystream = `HMAC(encKey, iv || counter)`
888
+ * - ciphertext = `plaintext XOR keystream`
889
+ * - tag = `HMAC(macKey, iv || ciphertext)`
890
+ * - This is a custom construction and should not be used for production-grade cryptographic security.
891
+ * - `Cipher` class is a pure JS implementation. It does not rely on `crypto` or Web APIs.
892
+ */
893
+ var Cipher = class {
894
+ #secretBytes;
895
+ #encKey;
896
+ #macKey;
897
+ /**
898
+ * * Creates a new `Cipher` instance using the provided secret.
899
+ *
900
+ * @param secret - The secret string used to derive encryption and MAC keys.
901
+ * Must be a non-empty string.
902
+ */
903
+ constructor(secret) {
904
+ if (!require_primitives.isNonEmptyString(secret)) throw new Error("Secret must be non-empty string!");
905
+ this.#secretBytes = utf8ToBytes(secret);
906
+ this.#encKey = hmacSha256(this.#secretBytes, utf8ToBytes("enc"));
907
+ this.#macKey = hmacSha256(this.#secretBytes, utf8ToBytes("mac"));
908
+ }
909
+ /**
910
+ * Generates a keystream of the same length as the provided data using a `HMAC`-based counter mode.
911
+ * The keystream is deterministic from the encryption key and IV.
912
+ *
913
+ * @param target - The byte array whose length determines the keystream size.
914
+ * @param iv - The initialization vector used as input to the `HMAC`.
915
+ * @returns A byte array representing the generated keystream.
916
+ */
917
+ #genKeystream(target, iv) {
918
+ const blocks = Math.ceil(target.length / 32);
919
+ const keystreamParts = [];
920
+ for (let counter = 0; counter < blocks; counter++) keystreamParts.push(hmacSha256(this.#encKey, concatBytes(iv, intTo4BytesBE(counter))));
921
+ return concatBytes(...keystreamParts).subarray(0, target.length);
922
+ }
923
+ /**
924
+ * * Encrypts a UTF-8 string.
925
+ * - The output format is: `base64( iv || ciphertext || tag )`
926
+ *
927
+ * @param text - The plaintext string to encrypt.
928
+ * @returns A base64-encoded encrypted token.
929
+ */
930
+ encrypt(text) {
931
+ const plain = utf8ToBytes(text);
932
+ const iv = sha256Bytes(utf8ToBytes(String(Date.now()) + "-" + String(Math.random()))).subarray(0, 16);
933
+ const keystream = this.#genKeystream(plain, iv);
934
+ const ct = new Uint8Array(plain.length);
935
+ for (let i = 0; i < plain.length; i++) ct[i] = plain[i] ^ keystream[i];
936
+ return bytesToBase64(concatBytes(iv, ct, hmacSha256(this.#macKey, concatBytes(iv, ct))));
937
+ }
938
+ /**
939
+ * * Checks if a token is structurally valid and contains a matching MAC using the same secret.
940
+ *
941
+ * @param token - The base64-encoded encrypted blob to validate.
942
+ * @returns `true` if the MAC is valid, `false` otherwise.
943
+ */
944
+ isValid(token) {
945
+ if (!require_specials.isBase64(token)) return false;
946
+ const blob = base64ToBytes(token);
947
+ if (blob.length < 48) return false;
948
+ const iv = blob.subarray(0, 16);
949
+ const tag = blob.subarray(blob.length - 32);
950
+ const ct = blob.subarray(16, blob.length - 32);
951
+ return _constantTimeEquals(hmacSha256(this.#macKey, concatBytes(iv, ct)), tag);
952
+ }
953
+ /**
954
+ * * Decrypts a previously encrypted token.
955
+ * - Throws an error if the tag does not match or the token is malformed.
956
+ *
957
+ * @param token - The base64-encoded token produced by `encrypt`.
958
+ * @returns The decrypted plaintext string.
959
+ */
960
+ decrypt(token) {
961
+ if (!require_specials.isBase64(token)) throw new Error("Token must be a base64 string!");
962
+ const blob = base64ToBytes(token);
963
+ if (blob.length < 48) throw new Error("Malformed or tampered token!");
964
+ const iv = blob.subarray(0, 16);
965
+ const tag = blob.subarray(blob.length - 32);
966
+ const ct = blob.subarray(16, blob.length - 32);
967
+ if (!_constantTimeEquals(hmacSha256(this.#macKey, concatBytes(iv, ct)), tag)) throw new Error("Key in the token is tampered or invalid!)");
968
+ const keystream = this.#genKeystream(ct, iv);
969
+ const pt = new Uint8Array(ct.length);
970
+ for (let i = 0; i < ct.length; i++) pt[i] = ct[i] ^ keystream[i];
971
+ return bytesToUtf8(pt);
972
+ }
973
+ };
974
+
975
+ //#endregion
976
+ //#region src/hash/core.ts
977
+ /**
978
+ * * Computes the `MD5` digest of the given string using a pure JavaScript implementation.
979
+ *
980
+ * @remarks
981
+ * - Pure JavaScript implementation — runs on any JS engine. Does not rely on `crypto` or **Web APIs** or other external libraries.
982
+ * - Highly inspired by the algorithm used in {@link https://github.com/eustatos/pure-md5.git pure-md5} package.
983
+ *
984
+ * @param str - Input text to hash.
985
+ *
986
+ * @returns The `MD5` hash as a 32-character hex string.
987
+ *
988
+ * @example
989
+ * const hash = md5("hello");
990
+ * // → "5d41402abc4b2a76b9719d911017c592" *
991
+ *
992
+ * @example
993
+ * // Used inside UUID v3
994
+ * const digest = md5(namespace + name);
995
+ */
996
+ function md5(str) {
997
+ const state = [
998
+ 1732584193,
999
+ -271733879,
1000
+ -1732584194,
1001
+ 271733878
1002
+ ];
1003
+ const len = str.length;
1004
+ let i;
1005
+ for (i = 64; i <= len; i += 64) _md5cycle(state, _stringToNumbers(str.substring(i - 64, i)));
1006
+ const $str = str.substring(i - 64);
1007
+ const tail = [
1008
+ 0,
1009
+ 0,
1010
+ 0,
1011
+ 0,
1012
+ 0,
1013
+ 0,
1014
+ 0,
1015
+ 0,
1016
+ 0,
1017
+ 0,
1018
+ 0,
1019
+ 0,
1020
+ 0,
1021
+ 0,
1022
+ 0,
1023
+ 0
1024
+ ];
1025
+ for (i = 0; i < $str.length; i++) tail[i >> 2] |= $str.charCodeAt(i) << (i % 4 << 3);
1026
+ tail[i >> 2] |= 128 << (i % 4 << 3);
1027
+ if (i > 55) {
1028
+ _md5cycle(state, tail);
1029
+ for (let j = 0; j < 16; j++) tail[j] = 0;
1030
+ }
1031
+ tail[14] = len * 8;
1032
+ _md5cycle(state, tail);
1033
+ return state.map(_numToHex).join("");
1034
+ }
1035
+ /**
1036
+ * * Computes the `SHA-1` digest of the given string using a pure JavaScript implementation.
1037
+ *
1038
+ * @remarks Pure JavaScript implementation — runs on any JS engine. Does not rely on `crypto` or **Web APIs** or other external libraries.
1039
+ *
1040
+ * @param msg - Input text to hash.
1041
+ *
1042
+ * @returns The `SHA-1` hash as a 40-character hex string.
1043
+ *
1044
+ * @example
1045
+ * const hash = sha1("hello");
1046
+ * // → "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"
1047
+ *
1048
+ * @example
1049
+ * // Used inside UUID v5
1050
+ * const digest = sha1(namespace + name);
1051
+ */
1052
+ function sha1(msg) {
1053
+ const K = [
1054
+ 1518500249,
1055
+ 1859775393,
1056
+ 2400959708,
1057
+ 3395469782
1058
+ ];
1059
+ const utf8 = utf8ToBytes(msg);
1060
+ const rotl = (n, bits) => n << bits | n >>> 32 - bits;
1061
+ const toHex = (n) => (n >>> 0).toString(16).padStart(8, "0");
1062
+ const len = utf8.length;
1063
+ const padBytes = (len + 9) % 64 ? 64 - (len + 9) % 64 : 0;
1064
+ const total = len + 1 + padBytes + 8;
1065
+ const words = new Uint32Array(total >>> 2);
1066
+ for (let i = 0; i < utf8.length; i++) words[i >> 2] |= utf8[i] << 24 - i % 4 * 8;
1067
+ words[utf8.length >> 2] |= 128 << 24 - utf8.length % 4 * 8;
1068
+ words[words.length - 1] = utf8.length * 8;
1069
+ const h = [
1070
+ 1732584193,
1071
+ 4023233417,
1072
+ 2562383102,
1073
+ 271733878,
1074
+ 3285377520
1075
+ ];
1076
+ const W = new Uint32Array(80);
1077
+ for (let i = 0; i < words.length; i += 16) {
1078
+ for (let j = 0; j < 16; j++) W[j] = words[i + j] | 0;
1079
+ for (let j = 16; j < 80; j++) W[j] = rotl(W[j - 3] ^ W[j - 8] ^ W[j - 14] ^ W[j - 16], 1);
1080
+ let a = h[0], b = h[1], c = h[2], d = h[3], e = h[4];
1081
+ for (let j = 0; j < 80; j++) {
1082
+ let f, k;
1083
+ if (j < 20) {
1084
+ f = b & c | ~b & d;
1085
+ k = K[0];
1086
+ } else if (j < 40) {
1087
+ f = b ^ c ^ d;
1088
+ k = K[1];
1089
+ } else if (j < 60) {
1090
+ f = b & c | b & d | c & d;
1091
+ k = K[2];
1092
+ } else {
1093
+ f = b ^ c ^ d;
1094
+ k = K[3];
1095
+ }
1096
+ const temp = rotl(a, 5) + f + e + k + W[j] | 0;
1097
+ e = d;
1098
+ d = c;
1099
+ c = rotl(b, 30);
1100
+ b = a;
1101
+ a = temp;
1102
+ }
1103
+ h[0] = h[0] + a | 0;
1104
+ h[1] = h[1] + b | 0;
1105
+ h[2] = h[2] + c | 0;
1106
+ h[3] = h[3] + d | 0;
1107
+ h[4] = h[4] + e | 0;
1108
+ }
1109
+ return h.map(toHex).join("");
1110
+ }
1111
+ /**
1112
+ * * Computes the `SHA-256` hash of a `UTF-8` string and returns it as a lowercase hexadecimal string.
1113
+ *
1114
+ * @param msg - The input string to hash. Can contain any `UTF-8` characters.
1115
+ * @returns A 64-character lowercase hexadecimal string representing the `SHA-256` hash.
1116
+ *
1117
+ * @remarks Pure JavaScript implementation — runs on any JS engine. Does not rely on `crypto` or **Web APIs** or other external libraries.
1118
+ *
1119
+ * @example
1120
+ * ```typescript
1121
+ * // Basic usage
1122
+ * const hash = sha256('hello');
1123
+ * // Returns: '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824'
1124
+ *
1125
+ * // Empty string
1126
+ * const emptyHash = sha256('');
1127
+ * // Returns: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
1128
+ *
1129
+ * // Unicode string
1130
+ * const unicodeHash = sha256('Hello পৃথিবী!');
1131
+ * // Returns: '7037e204b825b83553ba336a6ec35b796d505599286ae864729ed6cb33ae9fe1'
1132
+ * ```
1133
+ *
1134
+ * @see {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/encoding#sha256bytes sha256Bytes} for hashing raw bytes
1135
+ * @see {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/encoding#utf8tobytes utf8ToBytes} for converting string to bytes
1136
+ * @see {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/encoding#bytestohex bytesToHex} for converting bytes to a hexadecimal string
1137
+ */
1138
+ function sha256(msg) {
1139
+ if (!require_primitives.isString(msg)) throw new TypeError("Input must be of type string!");
1140
+ return bytesToHex(sha256Bytes(utf8ToBytes(msg)));
1141
+ }
1142
+
1143
+ //#endregion
1144
+ //#region src/hash/Signet.ts
1145
+ /**
1146
+ * @class A lightweight, secure implementation of JWT-like tokens using `HMAC-SHA256` signatures.
1147
+ * - This class provides methods to create, verify, and decode tokens with a simple API similar to JSON Web Tokens (`JWT`)
1148
+ * but with a smaller footprint and zero dependencies.
1149
+ *
1150
+ * @remarks
1151
+ * - **Features:**
1152
+ * - `HMAC-SHA256` signatures for security
1153
+ * - Time-based claims (expiration, not-before)
1154
+ * - Standard claims (audience, issuer, subject)
1155
+ * - Constant-time signature comparison to prevent timing attacks
1156
+ * - Automatic date conversion for timestamp claims
1157
+ * - `Base64` URL-safe encoding (standard `Base64` in this implementation)
1158
+ *
1159
+ * - **Security considerations:**
1160
+ * - Keep the secret key secure and rotate periodically
1161
+ * - Use appropriate token expiration times
1162
+ * - Validate all claims relevant to your application
1163
+ * - Store tokens securely (HTTP-only cookies recommended for web)
1164
+ *
1165
+ * @example
1166
+ * ```typescript
1167
+ * // Create a token signer
1168
+ * const signet = new Signet('my-secret-key');
1169
+ *
1170
+ * // Sign a token with custom payload and options
1171
+ * const token = signet.sign(
1172
+ * { userId: 123, role: 'admin' },
1173
+ * {
1174
+ * expiresIn: '1h',
1175
+ * audience: 'my-app',
1176
+ * issuer: 'auth-service'
1177
+ * }
1178
+ * );
1179
+ *
1180
+ * // Verify a token
1181
+ * const result = signet.verify(token, {
1182
+ * audience: 'my-app',
1183
+ * issuer: 'auth-service'
1184
+ * });
1185
+ *
1186
+ * if (result.isValid) {
1187
+ * console.log('Valid token for user:', result.payload.userId);
1188
+ * } else {
1189
+ * console.log('Invalid token:', result.error);
1190
+ * }
1191
+ *
1192
+ * // Decode without verification
1193
+ * const decoded = signet.decode(token);
1194
+ * console.log('Token payload:', decoded.payload);
1195
+ * ```
1196
+ */
1197
+ var Signet = class {
1198
+ #secretBytes;
1199
+ /**
1200
+ * * Creates a new `Signet` instance with the specified secret key.
1201
+ *
1202
+ * @param secret - The secret key used for signing and verifying tokens.
1203
+ * Must be a non-empty string.
1204
+ *
1205
+ * @throws If the secret is not a non-empty string.
1206
+ *
1207
+ * @remarks
1208
+ * - The secret is converted to `UTF-8` bytes and stored internally.
1209
+ * - Choose a strong secret (at least 32 characters) and store it securely.
1210
+ * - For production, consider using key rotation strategies.
1211
+ *
1212
+ * @example
1213
+ * ```typescript
1214
+ * // Initialize with a secret key
1215
+ * const signet = new Signet('super-secret-key-123');
1216
+ *
1217
+ * // Use environment variable for the secret
1218
+ * const signet = new Signet(process.env.JWT_SECRET!);
1219
+ * ```
1220
+ */
1221
+ constructor(secret) {
1222
+ if (!require_primitives.isNonEmptyString(secret)) throw new Error("Secret must be a non-empty string!");
1223
+ this.#secretBytes = utf8ToBytes(secret);
1224
+ }
1225
+ /** Decodes a token without verifying its signature. */
1226
+ #decode(token) {
1227
+ if (!require_primitives.isNonEmptyString(token)) throw new Error("Token must be a non-empty string!");
1228
+ const parts = token.split(".");
1229
+ if (parts.length !== 3) throw new Error("Token is tampered or malformed!");
1230
+ const [hdr, pld, signature] = parts;
1231
+ const headerBytes = base64ToBytes(hdr);
1232
+ const payloadBytes = base64ToBytes(pld);
1233
+ const headerStr = require_utils.stripJsonEdgeGarbage(bytesToUtf8(headerBytes));
1234
+ const payloadStr = require_utils.stripJsonEdgeGarbage(bytesToUtf8(payloadBytes));
1235
+ let header;
1236
+ try {
1237
+ header = JSON.parse(headerStr);
1238
+ } catch {
1239
+ throw new Error("Cannot parse header!");
1240
+ }
1241
+ let payload;
1242
+ try {
1243
+ const { iat, iatDate, exp, expDate, nbf, nbfDate, aud, sub, iss, ...rest } = JSON.parse(payloadStr);
1244
+ payload = {
1245
+ iat,
1246
+ iatDate: iatDate ? new Date(iatDate) : require_parse._secToDate(iat),
1247
+ ...exp && { exp },
1248
+ ...exp && { expDate: expDate ? new Date(expDate) : require_parse._secToDate(exp) },
1249
+ ...nbf && { nbf },
1250
+ ...nbf && { nbfDate: nbfDate ? new Date(nbfDate) : require_parse._secToDate(nbf) },
1251
+ ...aud && { aud },
1252
+ ...sub && { sub },
1253
+ ...iss && { iss },
1254
+ ...rest
1255
+ };
1256
+ } catch {
1257
+ throw new Error("Cannot parse payload!");
1258
+ }
1259
+ return {
1260
+ header,
1261
+ payload,
1262
+ signature,
1263
+ signingInput: `${hdr}.${pld}`
1264
+ };
1265
+ }
1266
+ /**
1267
+ * * Creates and signs a new token with the given payload and options.
1268
+ *
1269
+ * @param payload - Custom data to include in the token payload.
1270
+ * Must be a `non-empty object`.
1271
+ * @param options - Optional configuration for token claims and expiration.
1272
+ *
1273
+ * @returns A signed token string in the format `header.payload.signature`.
1274
+ *
1275
+ * @throws If payload is not a valid object.
1276
+ *
1277
+ * @remarks
1278
+ * - **The token structure follows JWT format:**
1279
+ * - Header: Contains algorithm (`HS256`) and token type (`SIGNET+JWT`)
1280
+ * - Payload: Includes standard claims (`iat`, `exp`, `nbf`, `aud`, `sub`, `iss`) plus custom data
1281
+ * - Signature: `HMAC-SHA256(signingInput, secret)` (the result of the hash)
1282
+ * - Signing Inputs: `base64(header) + "." + base64(payload)` (the string that gets hashed)
1283
+ *
1284
+ * - **Automatic claims added:**
1285
+ * - `iat` (issued at): Current time in seconds
1286
+ * - `iatDate`: Current time as Date object
1287
+ * - If `expiresIn` is provided: `exp` and `expDate`
1288
+ * - If `notBefore` is provided: `nbf` and `nbfDate`
1289
+ *
1290
+ * @example
1291
+ * ```typescript
1292
+ * // Basic token with custom data
1293
+ * const token = signet.sign({ userId: 123, name: 'John' });
1294
+ *
1295
+ * // Token with expiration and claims
1296
+ * const token = signet.sign(
1297
+ * { userId: 123 },
1298
+ * {
1299
+ * expiresIn: '2h',
1300
+ * audience: 'api.example.com',
1301
+ * issuer: 'auth-service',
1302
+ * subject: 'user-123'
1303
+ * }
1304
+ * );
1305
+ *
1306
+ * // Token valid after 5 minutes
1307
+ * const token = signet.sign(
1308
+ * { action: 'reset-password' },
1309
+ * { notBefore: '5m' }
1310
+ * );
1311
+ * ```
1312
+ */
1313
+ sign(payload, options) {
1314
+ if (!require_specials.isNotEmptyObject(payload)) throw new Error("Payload must be a valid object!");
1315
+ const { expiresIn, notBefore, audience, issuer, subject } = options || {};
1316
+ const iat = require_parse._toSeconds(Date.now());
1317
+ const $payload = {
1318
+ iat,
1319
+ iatDate: require_parse._secToDate(iat),
1320
+ ...expiresIn && { exp: iat + require_parse._toSeconds(require_parse.parseMSec(expiresIn)) },
1321
+ ...expiresIn && { expDate: require_parse._secToDate(iat + require_parse._toSeconds(require_parse.parseMSec(expiresIn))) },
1322
+ ...notBefore && { nbf: iat + require_parse._toSeconds(require_parse.parseMSec(notBefore)) },
1323
+ ...notBefore && { nbfDate: require_parse._secToDate(iat + require_parse._toSeconds(require_parse.parseMSec(notBefore))) },
1324
+ ...audience && { aud: audience },
1325
+ ...subject && { sub: subject },
1326
+ ...issuer && { iss: issuer },
1327
+ ...payload
1328
+ };
1329
+ const headerJson = require_utils.stableStringify({
1330
+ alg: "HS256",
1331
+ typ: "SIGNET+JWT"
1332
+ });
1333
+ const payloadJson = require_utils.stableStringify($payload);
1334
+ const headerB = utf8ToBytes(headerJson);
1335
+ const payloadB = utf8ToBytes(payloadJson);
1336
+ const signingInput = `${bytesToBase64(headerB)}.${bytesToBase64(payloadB)}`;
1337
+ return `${signingInput}.${bytesToBase64(hmacSha256(this.#secretBytes, utf8ToBytes(signingInput)))}`;
1338
+ }
1339
+ /**
1340
+ * * Decodes a token without verifying its signature.
1341
+ *
1342
+ * @typeParam T - Type of custom data in the token payload.
1343
+ * @param token - The token string to decode.
1344
+ *
1345
+ * @returns The decoded token parts including header, payload, and signatures.
1346
+ *
1347
+ * @throws If the token is malformed, empty, or cannot be parsed.
1348
+ *
1349
+ * @remarks
1350
+ * - Use this method when you need to inspect token contents without verification.
1351
+ * - **Warning:** This does not validate the signature, so the data may have been tampered with.
1352
+ * - Always use {@link verify} method for security-critical operations.
1353
+ * - The payload includes both timestamp values (numbers) and {@link Date} objects for convenience.
1354
+ *
1355
+ * @example
1356
+ * ```typescript
1357
+ * // Decode token to inspect contents
1358
+ * const decoded = signet.decode(token);
1359
+ * console.log('Header:', decoded.header);
1360
+ * console.log('Payload:', decoded.payload);
1361
+ * console.log('Signature:', decoded.signature);
1362
+ *
1363
+ * // Access custom payload data with type safety
1364
+ * const decoded = signet.decode<{ userId: number }>(token);
1365
+ * const userId = decoded.payload.userId; // Type: number
1366
+ * ```
1367
+ */
1368
+ decode(token) {
1369
+ return this.#decode(token);
1370
+ }
1371
+ /**
1372
+ * * Checks if a token has expired based on its `exp` claim.
1373
+ *
1374
+ * @param token - The token to check.
1375
+ *
1376
+ * @returns `true` if the token has an `exp` claim and current time is past it,
1377
+ * `false` if token has no expiration or is still valid.
1378
+ *
1379
+ * @throws If the token is malformed or cannot be decoded.
1380
+ *
1381
+ * @remarks
1382
+ * - Tokens without `exp` claim are considered non-expiring (returns `false`)
1383
+ * - Uses current system time for comparison ({@link Date.now()})
1384
+ * - Does not verify the signature (use only with trusted tokens or after verification)
1385
+ *
1386
+ * @example
1387
+ * ```typescript
1388
+ * // Check expiration
1389
+ * if (signet.hasExpired(token)) {
1390
+ * console.log('Token has expired');
1391
+ * // Prompt user to re-authenticate
1392
+ * }
1393
+ *
1394
+ * // Use with other validation
1395
+ * const isValid = !signet.hasExpired(token) && !signet.isTooEarly(token);
1396
+ * ```
1397
+ */
1398
+ hasExpired(token) {
1399
+ const { exp } = this.#decode(token).payload;
1400
+ return exp ? require_parse._toSeconds(Date.now()) > exp : false;
1401
+ }
1402
+ /**
1403
+ * * Checks if a token's `nbf` (not-before) claim indicates it's too early to use.
1404
+ *
1405
+ * @param token - The token to check.
1406
+ *
1407
+ * @returns `true` if the token has an `nbf` claim and current time is before it,
1408
+ * `false` if token has no `nbf` claim or is already valid.
1409
+ *
1410
+ * @throws If the token is malformed or cannot be decoded.
1411
+ *
1412
+ * @remarks
1413
+ * - Useful for implementing time-based access control, like activation links that shouldn't be used until a certain time.
1414
+ * - Uses current system time for comparison ({@link Date.now()})
1415
+ * - Does not verify the signature (use only with trusted tokens or after verification)
1416
+ *
1417
+ * @example
1418
+ * ```typescript
1419
+ * // Check if token is active yet
1420
+ * if (signet.isTooEarly(token)) {
1421
+ * console.log('Token not valid yet');
1422
+ * // Wait before using
1423
+ * }
1424
+ * ```
1425
+ */
1426
+ isTooEarly(token) {
1427
+ const { nbf } = this.#decode(token).payload;
1428
+ return nbf ? require_parse._toSeconds(Date.now()) < nbf : false;
1429
+ }
1430
+ /**
1431
+ * * Validates a token's `iss` (issuer) claim against an expected value.
1432
+ *
1433
+ * @param token - The token to check.
1434
+ * @param expected - The expected issuer value. If `undefined`, always returns `false`.
1435
+ *
1436
+ * @returns `true` if the token has an `iss` claim that doesn't match the expected value,
1437
+ * `false` if issuer matches, token has no issuer claim, or expected issuer is undefined.
1438
+ *
1439
+ * @throws If the token is malformed or cannot be decoded.
1440
+ *
1441
+ * @remarks Use this to ensure tokens come from trusted sources in multi-issuer scenarios.
1442
+ *
1443
+ * @example
1444
+ * ```typescript
1445
+ * // Validate issuer
1446
+ * if (signet.isInvalidIssuer(token, 'auth-service')) {
1447
+ * console.log('Token from unexpected issuer');
1448
+ * // Reject token
1449
+ * }
1450
+ *
1451
+ * // With optional issuer check
1452
+ * const issuer = process.env.EXPECTED_ISSUER;
1453
+ * if (issuer && signet.isInvalidIssuer(token, issuer)) {
1454
+ * throw new Error('Invalid issuer');
1455
+ * }
1456
+ * ```
1457
+ */
1458
+ isInvalidIssuer(token, expected) {
1459
+ if (!expected) return false;
1460
+ const { iss } = this.#decode(token).payload;
1461
+ return iss ? iss !== expected : false;
1462
+ }
1463
+ /**
1464
+ * * Validates a token's `aud` (audience) claim against expected values.
1465
+ *
1466
+ * @param token - The token to check.
1467
+ * @param expected - The expected audience(s). Can be a string or array of strings.
1468
+ * If `undefined`, always returns `false`.
1469
+ *
1470
+ * @returns `true` if the token has an `aud` claim and none of its values match any of the expected audiences, `false` otherwise.
1471
+ *
1472
+ * @throws If the token is malformed or cannot be decoded.
1473
+ *
1474
+ * @remarks
1475
+ * - Tokens can have single audience (string) or multiple audiences (string[])
1476
+ * - Returns `false` (valid) if at least one audience matches
1477
+ * - Useful for multi-tenant or multi-service architectures
1478
+ *
1479
+ * @example
1480
+ * ```typescript
1481
+ * // Single audience check
1482
+ * if (signet.isInvalidAudience(token, 'api.example.com')) {
1483
+ * console.log('Token not intended for this audience');
1484
+ * }
1485
+ *
1486
+ * // Multiple allowed audiences
1487
+ * const validAudiences = ['web-app', 'mobile-app', 'admin-panel'];
1488
+ * if (signet.isInvalidAudience(token, validAudiences)) {
1489
+ * throw new Error('Invalid audience');
1490
+ * }
1491
+ *
1492
+ * // Token with multiple audiences
1493
+ * // Token payload: { aud: ['web-app', 'mobile-app'] }
1494
+ * // Check if at least one matches
1495
+ * const isValid = !signet.isInvalidAudience(token, ['web-app', 'admin-panel']);
1496
+ * // Returns false (valid) because 'web-app' matches
1497
+ * ```
1498
+ */
1499
+ isInvalidAudience(token, expected) {
1500
+ if (!expected) return false;
1501
+ const { aud } = this.#decode(token).payload;
1502
+ if (!aud) return false;
1503
+ const payloadAud = Array.isArray(aud) ? aud : [aud];
1504
+ const expectedAud = Array.isArray(expected) ? expected : [expected];
1505
+ return payloadAud.some((tokenAud) => expectedAud.includes(tokenAud));
1506
+ }
1507
+ /**
1508
+ * * Validates a token's `sub` (subject) claim against an expected value.
1509
+ *
1510
+ * @param token - The token to check.
1511
+ * @param expected - The expected subject value. If `undefined`, always returns `false`.
1512
+ *
1513
+ * @returns `true` if the token has a `sub` claim that doesn't match the expected value,
1514
+ * `false` if subject matches, token has no subject claim, or expected subject is undefined.
1515
+ *
1516
+ * @throws If the token is malformed or cannot be decoded.
1517
+ *
1518
+ * @remarks
1519
+ * - Use this to ensure tokens are being used by the intended user/entity.
1520
+ * - Common for authorization checks where tokens should be user-specific.
1521
+ *
1522
+ * @example
1523
+ * ```typescript
1524
+ * // Validate subject
1525
+ * const userId = 'user-123';
1526
+ * if (signet.isInvalidSubject(token, userId)) {
1527
+ * console.log('Token not for this user');
1528
+ * // Reject request
1529
+ * }
1530
+ *
1531
+ * // Optional subject validation
1532
+ * const expectedSubject = getExpectedSubjectFromRequest();
1533
+ * if (expectedSubject && signet.isInvalidSubject(token, expectedSubject)) {
1534
+ * return response.status(403).send('Invalid subject');
1535
+ * }
1536
+ * ```
1537
+ */
1538
+ isInvalidSubject(token, expected) {
1539
+ if (!expected) return false;
1540
+ const { sub } = this.#decode(token).payload;
1541
+ return sub ? sub !== expected : false;
1542
+ }
1543
+ /**
1544
+ * * Verifies a token's signature and validates all claims.
1545
+ *
1546
+ * @typeParam T - Type of custom data in the token payload.
1547
+ * @param token - The token string to verify.
1548
+ * @param options - Optional validation criteria for token claims.
1549
+ *
1550
+ * @returns A {@link VerifiedToken} object indicating success or failure.
1551
+ * - If valid: `{ isValid: true, payload: SignetPayload<T> }`
1552
+ * - If invalid: `{ isValid: false, error: string }`
1553
+ *
1554
+ * @remarks
1555
+ * - **Performs the following checks in order:**
1556
+ * - Token structure (3 parts separated by dots)
1557
+ * - Base64 decoding of header and payload
1558
+ * - JSON parsing of header and payload
1559
+ * - Signature verification (constant-time comparison)
1560
+ * - Expiration check (if `exp` claim exists)
1561
+ * - Not-before check (if `nbf` claim exists)
1562
+ * - Issuer validation (if provided in options)
1563
+ * - Audience validation (if provided in options)
1564
+ * - Subject validation (if provided in options)
1565
+ *
1566
+ * - **This is the recommended method for most token validation scenarios.**
1567
+ *
1568
+ * @example
1569
+ * ```typescript
1570
+ * // Basic verification
1571
+ * const result = signet.verify(token);
1572
+ * if (result.isValid) {
1573
+ * console.log('Valid token:', result.payload);
1574
+ * } else {
1575
+ * console.log('Invalid token:', result.error);
1576
+ * }
1577
+ *
1578
+ * // With claim validation
1579
+ * const result = signet.verify(token, {
1580
+ * audience: 'api.example.com',
1581
+ * issuer: 'auth-service',
1582
+ * subject: 'user-123'
1583
+ * });
1584
+ *
1585
+ * // Type-safe custom payload
1586
+ * interface UserToken {
1587
+ * userId: number;
1588
+ * role: string;
1589
+ * }
1590
+ * const result = signet.verify<UserToken>(token);
1591
+ * if (result.isValid) {
1592
+ * const { userId, role } = result.payload;
1593
+ * // userId and role are typed
1594
+ * }
1595
+ * ```
1596
+ */
1597
+ verify(token, options) {
1598
+ try {
1599
+ const { signature, signingInput, payload } = this.#decode(token);
1600
+ const { audience, issuer, subject } = options || {};
1601
+ if (!_constantTimeEquals(signature, bytesToBase64(hmacSha256(this.#secretBytes, utf8ToBytes(signingInput))))) throw new Error("Invalid or tampered signature!");
1602
+ if (this.hasExpired(token)) throw new Error("Token has expired!");
1603
+ if (this.isTooEarly(token)) throw new Error("Token is not active yet!");
1604
+ if (this.isInvalidIssuer(token, issuer)) throw new Error("Invalid token issuer!");
1605
+ if (this.isInvalidAudience(token, audience)) throw new Error("Invalid token audience(s!");
1606
+ if (this.isInvalidSubject(token, subject)) throw new Error("Invalid token subject!");
1607
+ return {
1608
+ isValid: true,
1609
+ payload
1610
+ };
1611
+ } catch (e) {
1612
+ return {
1613
+ isValid: false,
1614
+ error: e instanceof Error ? e.message : String(e)
1615
+ };
1616
+ }
1617
+ }
1618
+ /**
1619
+ * * Verifies a token and throws an error if invalid.
1620
+ *
1621
+ * @typeParam T - Type of custom data in the token payload.
1622
+ * @param token - The token string to verify.
1623
+ * @param options - Optional validation criteria for token claims.
1624
+ *
1625
+ * @returns A valid {@link VerifiedToken} with `isValid: true`.
1626
+ *
1627
+ * @throws If the token is invalid, with a message describing the failure.
1628
+ *
1629
+ * @remarks
1630
+ * - This method is a convenience wrapper around {@link verify} that throws instead of returning an error object.
1631
+ * - Useful for `express`-style middleware or when you want to handle authentication failures with exceptions.
1632
+ * - The thrown error message is the same as the `error` property in the invalid result from {@link verify}.
1633
+ *
1634
+ * @example
1635
+ * ```typescript
1636
+ * // Use in middleware/guard
1637
+ * function authMiddleware(req, res, next) {
1638
+ * const token = req.headers.authorization?.replace('Bearer ', '');
1639
+ *
1640
+ * try {
1641
+ * const result = signet.verifyOrThrow(token, {
1642
+ * audience: 'api.example.com'
1643
+ * });
1644
+ * req.user = result.payload;
1645
+ * next();
1646
+ * } catch (error) {
1647
+ * res.status(401).json({ error: error.message });
1648
+ * }
1649
+ * }
1650
+ *
1651
+ * // In application code
1652
+ * try {
1653
+ * const result = signet.verifyOrThrow(token);
1654
+ * // Token is guaranteed valid here
1655
+ * processUserRequest(result.payload);
1656
+ * } catch (error) {
1657
+ * handleAuthError(error);
1658
+ * }
1659
+ * ```
1660
+ */
1661
+ verifyOrThrow(token, options) {
1662
+ const res = this.verify(token, options);
1663
+ if (!res.isValid) throw new Error(res.error || "Invalid, malformed or expired token!");
1664
+ return res;
1665
+ }
1666
+ /**
1667
+ * * Extracts only the payload from a token without full verification.
1668
+ *
1669
+ * @typeParam T - Type of custom data in the token payload.
1670
+ * @param token - The token string to decode.
1671
+ *
1672
+ * @returns The token payload including standard claims and custom data.
1673
+ *
1674
+ * @throws If the token is malformed, empty, or cannot be parsed.
1675
+ *
1676
+ * @remarks
1677
+ * - This is a convenience method equivalent to `decode(token).payload`.
1678
+ *
1679
+ * - **Security Note:** This method does NOT verify the token signature.
1680
+ *
1681
+ * - **Only use it when:**
1682
+ * - You've already verified the token elsewhere
1683
+ * - The token comes from a trusted source
1684
+ * - You're debugging or logging
1685
+ * - The operation is not security-critical
1686
+ *
1687
+ * - For security-sensitive operations, always use {@link verify} or {@link verifyOrThrow} method.
1688
+ *
1689
+ * @example
1690
+ * ```typescript
1691
+ * // Quick payload extraction for non-critical operations
1692
+ * const payload = signet.decodePayload(token);
1693
+ * console.log('User ID:', payload.userId);
1694
+ * console.log('Issued at:', payload.iatDate);
1695
+ *
1696
+ * // Type-safe with custom interface
1697
+ * interface AppToken {
1698
+ * userId: number;
1699
+ * permissions: string[];
1700
+ * }
1701
+ * const payload = signet.decodePayload<AppToken>(token);
1702
+ * const canDelete = payload.permissions.includes('delete');
1703
+ * ```
1704
+ */
1705
+ decodePayload(token) {
1706
+ return this.#decode(token).payload;
1707
+ }
1708
+ };
1709
+
1710
+ //#endregion
1711
+ //#region src/hash/TextCodec.ts
1712
+ /**
1713
+ * @class `TextCodec` provides **UTF-8–safe** conversions between `text`, `hex`, `binary`, and `Base64` representations using byte-level transformations.
1714
+ *
1715
+ * @example
1716
+ * TextCodec.utf8ToHex('ভাষা'); // 'e0 a6 ad e0 a6 be e0 a6 b7 e0 a6 be'
1717
+ * TextCodec.hexToUtf8('e0 a6 ad e0 a6 be'); // 'ভা'
1718
+ */
1719
+ var TextCodec = class {
1720
+ constructor() {}
1721
+ /**
1722
+ * @static Validates whether a string represents a valid hexadecimal byte sequence.
1723
+ *
1724
+ * @param hex - Hex string, spaced or un-spaced (e.g. "ff 0a" or "ff0a")
1725
+ * @returns `true` if the input is valid hex byte string
1726
+ *
1727
+ * @example
1728
+ * TextCodec.isValidHex('ff 0a');
1729
+ */
1730
+ static isValidHex(hex) {
1731
+ return require_specials.isHexString(hex);
1732
+ }
1733
+ /**
1734
+ * @static Validates whether a string represents a valid binary byte sequence.
1735
+ *
1736
+ * @param binary - Binary string, spaced or un-spaced
1737
+ * @returns `true` if the input is valid binary byte string
1738
+ *
1739
+ * @example
1740
+ * TextCodec.isValidBinary('01000001');
1741
+ */
1742
+ static isValidBinary(binary) {
1743
+ return require_specials.isBinaryString(binary);
1744
+ }
1745
+ /**
1746
+ * @static Validates whether a string represents a valid Base64-encoded string.
1747
+ *
1748
+ * @param b64 - Base64 string to check
1749
+ * @returns `true` if the input is valid Base64-encoded string
1750
+ *
1751
+ * @example
1752
+ * TextCodec.isValidBase64('SGVsbG8=');
1753
+ */
1754
+ static isValidBase64(b64) {
1755
+ return require_specials.isBase64(b64);
1756
+ }
1757
+ /**
1758
+ * @static Converts UTF-8 text into hexadecimal byte representation.
1759
+ *
1760
+ * @param text - UTF-8 text to convert
1761
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
1762
+ * @returns Hexadecimal byte string
1763
+ *
1764
+ * @example
1765
+ * TextCodec.utf8ToHex('Hi');
1766
+ */
1767
+ static utf8ToHex(text, spaced = true) {
1768
+ return [...utf8ToBytes(text)].map((b) => _padStartWith0(b, "hex")).join(spaced ? " " : "");
1769
+ }
1770
+ /**
1771
+ * @static Converts UTF-8 text into binary byte representation.
1772
+ *
1773
+ * @param text - UTF-8 text to convert
1774
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
1775
+ * @returns Binary byte string
1776
+ *
1777
+ * @example
1778
+ * TextCodec.utf8ToBinary('A');
1779
+ */
1780
+ static utf8ToBinary(text, spaced = true) {
1781
+ return [...utf8ToBytes(text)].map((b) => _padStartWith0(b, "binary")).join(spaced ? " " : "");
1782
+ }
1783
+ /**
1784
+ * @static Converts hexadecimal byte string into UTF-8 text.
1785
+ *
1786
+ * @param hex - Hexadecimal byte string
1787
+ * @returns Decoded UTF-8 text
1788
+ *
1789
+ * @example
1790
+ * TextCodec.hexToUtf8('48 69');
1791
+ */
1792
+ static hexToUtf8(hex) {
1793
+ return bytesToUtf8(hexToBytes(hex));
1794
+ }
1795
+ /**
1796
+ * @static Converts binary byte string into UTF-8 text.
1797
+ *
1798
+ * @param binary - Binary byte string
1799
+ * @returns Decoded UTF-8 text
1800
+ *
1801
+ * @example
1802
+ * TextCodec.binaryToUtf8('01001000 01101001');
1803
+ */
1804
+ static binaryToUtf8(binary) {
1805
+ if (!require_specials.isBinaryString(binary)) return "";
1806
+ const bytes = _splitByCharLength(binary, 8).map((b) => parseInt(b, 2));
1807
+ return bytesToUtf8(new Uint8Array(bytes));
1808
+ }
1809
+ /**
1810
+ * @static Converts hexadecimal byte string into binary byte string.
1811
+ *
1812
+ * @param hex - Hexadecimal byte string
1813
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
1814
+ * @returns Binary byte string
1815
+ *
1816
+ * @example
1817
+ * TextCodec.hexToBinary('ff');
1818
+ */
1819
+ static hexToBinary(hex, spaced = true) {
1820
+ if (!require_specials.isHexString(hex)) return "";
1821
+ return _splitByCharLength(hex, 2).map((h) => _padStartWith0(parseInt(h, 16), "binary")).join(spaced ? " " : "");
1822
+ }
1823
+ /**
1824
+ * @static Converts binary byte string into hexadecimal byte string.
1825
+ *
1826
+ * @param binary - Binary byte string
1827
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
1828
+ * @returns Hexadecimal byte string
1829
+ *
1830
+ * @example
1831
+ * TextCodec.binaryToHex('00000001');
1832
+ */
1833
+ static binaryToHex(binary, spaced = true) {
1834
+ if (!require_specials.isBinaryString(binary)) return "";
1835
+ return _splitByCharLength(binary, 8).map((b) => _padStartWith0(parseInt(b, 2), "hex")).join(spaced ? " " : "");
1836
+ }
1837
+ /**
1838
+ * @static Converts a Base64-encoded string into UTF-8 text.
1839
+ *
1840
+ * @param b64 - Base64 encoded string
1841
+ * @returns Decoded UTF-8 text
1842
+ *
1843
+ * @example
1844
+ * TextCodec.base64ToUtf8('SGVsbG8=');
1845
+ */
1846
+ static base64ToUtf8(b64) {
1847
+ if (!require_specials.isBase64(b64)) return "";
1848
+ return bytesToUtf8(base64ToBytes(b64));
1849
+ }
1850
+ /**
1851
+ * @static Converts UTF-8 text into a Base64-encoded string.
1852
+ *
1853
+ * @param text - UTF-8 text to encode
1854
+ * @returns Base64 encoded string
1855
+ *
1856
+ * @example
1857
+ * TextCodec.utf8ToBase64('Hello');
1858
+ */
1859
+ static utf8ToBase64(text) {
1860
+ if (!require_primitives.isNonEmptyString(text)) return "";
1861
+ return bytesToBase64(utf8ToBytes(text));
1862
+ }
1863
+ /**
1864
+ * @static Converts Base64 directly into hexadecimal byte string.
1865
+ *
1866
+ * @param b64 - Base64 encoded string
1867
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
1868
+ * @returns Hexadecimal byte string
1869
+ *
1870
+ * @example
1871
+ * TextCodec.base64ToHex('SGVsbG8=');
1872
+ */
1873
+ static base64ToHex(b64, spaced = true) {
1874
+ return this.utf8ToHex(this.base64ToUtf8(b64), spaced);
1875
+ }
1876
+ /**
1877
+ * @static Converts Base64 directly into binary byte string.
1878
+ *
1879
+ * @param b64 - Base64 encoded string
1880
+ * @param spaced - Whether to separate bytes with spaces, defaults to `true`
1881
+ * @returns Binary byte string
1882
+ *
1883
+ * @example
1884
+ * TextCodec.base64ToBinary('SGVsbG8=');
1885
+ */
1886
+ static base64ToBinary(b64, spaced = true) {
1887
+ return this.utf8ToBinary(this.base64ToUtf8(b64), spaced);
1888
+ }
1889
+ /**
1890
+ * @static Converts hexadecimal byte string into a Base64 string.
1891
+ *
1892
+ * @param hex - Hexadecimal byte string
1893
+ * @returns Base64 encoded string
1894
+ *
1895
+ * @example
1896
+ * TextCodec.hexToBase64('48 69');
1897
+ */
1898
+ static hexToBase64(hex) {
1899
+ return this.utf8ToBase64(this.hexToUtf8(hex));
1900
+ }
1901
+ /**
1902
+ * @static Converts binary byte string into a Base64 string.
1903
+ *
1904
+ * @param binary - Binary byte string
1905
+ * @returns Base64 encoded string
1906
+ *
1907
+ * @example
1908
+ * TextCodec.binaryToBase64('01001000 01101001');
1909
+ */
1910
+ static binaryToBase64(binary) {
1911
+ return this.utf8ToBase64(this.binaryToUtf8(binary));
1912
+ }
1913
+ };
1914
+
1915
+ //#endregion
1916
+ //#region src/hash/uuid.ts
1917
+ /**
1918
+ * * Generates UUIDs across all major RFC-compliant versions (1, 3, 4, 5, 6, 7, 8), following standards from `RFC4122`. Default version is `v4`.
1919
+ *
1920
+ * - **Version behavior:**
1921
+ * - `v1` → Timestamp & node-identifier–based
1922
+ * - `v3` → MD5(namespace + name)
1923
+ * - `v4` → Pure random (correct variant + version injection)
1924
+ * - `v5` → SHA-1(namespace + name)
1925
+ * - `v6` → Re-ordered timestamp variant of `v1` (lexicographically sortable)
1926
+ * - `v7` → Unix-time–based, monotonic-friendly
1927
+ * - `v8` → Custom layout, '“Future'` variant (timestamp + randomness)
1928
+ *
1929
+ * @param options Controls version, formatting, and required fields for `v3` and `v5`.
1930
+ * @returns A 5-parts UUID string formatted with correct version/variant bits.
1931
+ *
1932
+ * @example
1933
+ * // Generate a random UUID v4
1934
+ * const id = uuid();
1935
+ *
1936
+ * @example
1937
+ * // Generate uppercase v7
1938
+ * const id = uuid({ version: 'v7', uppercase: true });
1939
+ *
1940
+ * @example
1941
+ * // Generate v5 UUID
1942
+ * const id = uuid({
1943
+ * version: 'v5',
1944
+ * namespace: '6ba7b810-9dad-11d1-80b4-00c04fd430c8',
1945
+ * name: 'example'
1946
+ * });
1947
+ *
1948
+ * @remarks
1949
+ * - This utility provides a complete, engine-agnostic UUID generator with full RFC compliance, predictable formatting, and reliable uniqueness characteristics, suitable for browsers, Node.js, and restricted JavaScript runtimes.
1950
+ * - **Notes**
1951
+ * - `v1` and `v6` use a generated pseudo-node identifier.
1952
+ * - `v4` and `v8` uses {@link Math.random} when {@link crypto.getRandomValues} is unavailable, ensuring broad compatibility.
1953
+ * - `v3` and `v5` use internal `MD5`/`SHA-1` implementations and remain fully deterministic.
1954
+ * - `v7` **do not rely on crypto APIs**, preserving engine-agnostic behavior.
1955
+ *
1956
+ * - **Limitations**
1957
+ * - `v1`/`v6`: Node identifier is pseudo-random, not derived from real MAC addresses (for privacy).
1958
+ * - `v3`/`v5`: Hash algorithms (`MD5`/`SHA-1`) follow RFC specs but are not cryptographically secure.
1959
+ * - `v7`: Millisecond precision; extremely high throughput may still cause rare collisions.
1960
+ * - `v8`: Uses a simple timestamp + randomness layout; custom layouts are not supported here.
1961
+ *
1962
+ * - Use {@link https://toolbox.nazmul-nhb.dev/docs/utilities/string/generateRandomID generateRandomID} for customized id generation or {@link https://toolbox.nazmul-nhb.dev/docs/utilities/hash/randomHex randomHex} for hex-only random string with custom length.
1963
+ */
1964
+ function uuid(options) {
1965
+ const { version = "v4", uppercase = false } = options || {};
1966
+ switch (version) {
1967
+ case "v1": {
1968
+ const timestamp = _uuidTimestamp().toString(16).padStart(15, "0");
1969
+ const vTimeHigh = (parseInt(timestamp.slice(0, -12).padStart(3, "0"), 16) | 4096).toString(16).padStart(4, "0");
1970
+ const clockSeq = _clockSeq14();
1971
+ const clockSeqHi = (parseInt(clockSeq.slice(0, 2), 16) & 63 | 128).toString(16).padStart(2, "0");
1972
+ return _formatUUID(timestamp.slice(-8) + timestamp.slice(-12, -8) + vTimeHigh + clockSeqHi + clockSeq.slice(2) + _randomNode48(), 1, uppercase);
1973
+ }
1974
+ case "v3":
1975
+ if (_isOptionV3V5(options)) return _formatUUID(md5(options.namespace + options.name), 3, uppercase);
1976
+ throw new Error("v3 requires valid namespace (uuid) and name!");
1977
+ case "v4": return _formatUUID(_bytesToRandomHex(new Uint8Array(16)), 4, uppercase);
1978
+ case "v5":
1979
+ if (_isOptionV3V5(options)) return _formatUUID(sha1(options.namespace + options.name).slice(0, 32), 5, uppercase);
1980
+ throw new Error("v5 requires valid namespace (uuid) and name!");
1981
+ case "v6": {
1982
+ const timestamp = _uuidTimestamp().toString(16).padStart(15, "0");
1983
+ const vTimeLow = (parseInt(timestamp.slice(12).padStart(3, "0"), 16) | 24576).toString(16).padStart(4, "0");
1984
+ const clockSeq = _clockSeq14();
1985
+ const clockSeqHi = (parseInt(clockSeq.slice(0, 2), 16) & 63 | 128).toString(16).padStart(2, "0");
1986
+ return _formatUUID(timestamp.slice(0, 8) + timestamp.slice(8, 12) + vTimeLow + clockSeqHi + clockSeq.slice(2) + _randomNode48(), 6, uppercase);
1987
+ }
1988
+ case "v7": return _formatUUID(Date.now().toString(16).padStart(12, "0") + randomHex(20), 7, uppercase);
1989
+ case "v8": {
1990
+ const ts = BigInt(Date.now());
1991
+ const bytes = new Uint8Array(16);
1992
+ let temp = ts;
1993
+ for (let i = 5; i >= 0; i--) {
1994
+ bytes[i] = Number(temp & 255n);
1995
+ temp >>= 8n;
1996
+ }
1997
+ return _formatUUID(_bytesToRandomHex(bytes), 8, uppercase);
1998
+ }
1999
+ default: throw new RangeError("Unsupported UUID version!");
2000
+ }
2001
+ }
2002
+ /**
2003
+ * * Decodes a UUID into its internal components, including version, variant, timestamps for time-based UUIDs and other metadata.
2004
+ * - Supports `RFC4122` UUID versions: 1-8.
2005
+ *
2006
+ * @param uuid The UUID string to decode.
2007
+ * @returns A structured `DecodedUUID` object, or `null` for invalid UUIDs.
2008
+ *
2009
+ * @example
2010
+ * const info = decodeUUID("f47ac10b-58cc-4372-a567-0e02b2c3d479");
2011
+ *
2012
+ * @example
2013
+ * const info = decodeUUID(uuid({ version: "v1" }));
2014
+ *
2015
+ * @remarks
2016
+ * - Provides a cross-runtime UUID decoder covering essential metadata and timestamp interpretation for time-ordered UUID versions.
2017
+ * - **Notes**
2018
+ * - `v1/v6` timestamps are converted from the UUID epoch (1582-10-15) to standard Unix milliseconds.
2019
+ * - `v6` timestamps are lexicographically sortable and decoded accordingly.
2020
+ * - `v7` timestamps map directly to Unix time (48-bit millisecond precision).
2021
+ * - `v8` decoding is minimal because layouts are intentionally user-defined.
2022
+ *
2023
+ * - **Limitations**
2024
+ * - `v2` decoding is not implemented specifically.
2025
+ * - `v8` decoding only returns timestamp if it matches a known layout.
2026
+ * - `v3/v5` hash UUIDs contain no timestamp information.
2027
+ */
2028
+ function decodeUUID(uuid) {
2029
+ if (!require_specials.isUUID(uuid)) return null;
2030
+ const plain = uuid.replace(/-/g, "");
2031
+ const parts = uuid.toLowerCase().split("-");
2032
+ const version = parseInt(parts[2][0], 16);
2033
+ const variantNibble = parseInt(parts[3][0], 16);
2034
+ let variant = "RFC4122";
2035
+ if ((variantNibble & 8) === 0) variant = "NCS";
2036
+ else if ((variantNibble & 12) === 8) variant = "RFC4122";
2037
+ else if ((variantNibble & 14) === 12) variant = "Microsoft";
2038
+ else variant = "Future";
2039
+ const decoded = {
2040
+ version,
2041
+ variant,
2042
+ raw: uuid,
2043
+ plain,
2044
+ singleInt: BigInt("0x" + plain)
2045
+ };
2046
+ const UUID_EPOCH_DIFF = 122192928000000000n;
2047
+ if (version === 1 || version === 6) {
2048
+ let tsHex = parts[2].slice(1) + parts[1] + parts[0];
2049
+ if (version === 6) tsHex = parts[0] + parts[1] + parts[2].slice(1);
2050
+ decoded.timestamp = Number((BigInt("0x" + tsHex) - UUID_EPOCH_DIFF) / 10000n);
2051
+ decoded.node = parts[4];
2052
+ return decoded;
2053
+ }
2054
+ if (version === 7 || version === 8) {
2055
+ const tsHex = parts.join("").slice(0, 12);
2056
+ decoded.variant = version === 7 ? "RFC4122" : "Future";
2057
+ decoded.timestamp = parseInt(tsHex, 16);
2058
+ return decoded;
2059
+ }
2060
+ return decoded;
2061
+ }
2062
+ /** Check if a value is UUID version 1 */
2063
+ function isUUIDv1(value) {
2064
+ return _checkUUIDVersion(value, "1");
2065
+ }
2066
+ /** Check if a value is UUID version 2 */
2067
+ function isUUIDv2(value) {
2068
+ return _checkUUIDVersion(value, "2");
2069
+ }
2070
+ /** Check if a value is UUID version 3 */
2071
+ function isUUIDv3(value) {
2072
+ return _checkUUIDVersion(value, "3");
2073
+ }
2074
+ /** Check if a value is UUID version 4 */
2075
+ function isUUIDv4(value) {
2076
+ return _checkUUIDVersion(value, "4");
2077
+ }
2078
+ /** Check if a value is UUID version 5 */
2079
+ function isUUIDv5(value) {
2080
+ return _checkUUIDVersion(value, "5");
2081
+ }
2082
+ /** Check if a value is UUID version 6 */
2083
+ function isUUIDv6(value) {
2084
+ return _checkUUIDVersion(value, "6");
2085
+ }
2086
+ /** Check if a value is UUID version 7 */
2087
+ function isUUIDv7(value) {
2088
+ return _checkUUIDVersion(value, "7");
2089
+ }
2090
+ /** Check if a value is UUID version 8 */
2091
+ function isUUIDv8(value) {
2092
+ return _checkUUIDVersion(value, "8");
2093
+ }
2094
+
2095
+ //#endregion
2096
+ exports.Cipher = Cipher;
2097
+ exports.Signet = Signet;
2098
+ exports.TextCodec = TextCodec;
2099
+ exports.base64ToBytes = base64ToBytes;
2100
+ exports.bytesToBase64 = bytesToBase64;
2101
+ exports.bytesToHex = bytesToHex;
2102
+ exports.bytesToUtf8 = bytesToUtf8;
2103
+ exports.concatBytes = concatBytes;
2104
+ exports.decodeUUID = decodeUUID;
2105
+ exports.generateRandomID = require_basics.generateRandomID;
2106
+ exports.hexToBytes = hexToBytes;
2107
+ exports.hmacSha256 = hmacSha256;
2108
+ exports.intTo4BytesBE = intTo4BytesBE;
2109
+ exports.isUUID = require_specials.isUUID;
2110
+ exports.isUUIDv1 = isUUIDv1;
2111
+ exports.isUUIDv2 = isUUIDv2;
2112
+ exports.isUUIDv3 = isUUIDv3;
2113
+ exports.isUUIDv4 = isUUIDv4;
2114
+ exports.isUUIDv5 = isUUIDv5;
2115
+ exports.isUUIDv6 = isUUIDv6;
2116
+ exports.isUUIDv7 = isUUIDv7;
2117
+ exports.isUUIDv8 = isUUIDv8;
2118
+ exports.md5 = md5;
2119
+ exports.randomHex = randomHex;
2120
+ exports.randomID = require_basics.generateRandomID;
2121
+ exports.sha1 = sha1;
2122
+ exports.sha256 = sha256;
2123
+ exports.sha256Bytes = sha256Bytes;
2124
+ exports.uint8To32ArrayBE = uint8To32ArrayBE;
2125
+ exports.utf8ToBytes = utf8ToBytes;
2126
+ exports.uuid = uuid;