@nakanoaas/uuid58 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.cjs +51 -29
- package/dist/index.js +51 -29
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -280,7 +280,7 @@ This project uses [Vite+](https://viteplus.dev/) (`vp`) and pnpm.
|
|
|
280
280
|
pnpm install
|
|
281
281
|
pnpm check # format, lint and type check
|
|
282
282
|
pnpm test # run tests
|
|
283
|
-
pnpm bench #
|
|
283
|
+
pnpm bench # build and benchmark (see bench/README.md)
|
|
284
284
|
pnpm build # build the npm package into dist/
|
|
285
285
|
```
|
|
286
286
|
|
package/dist/index.cjs
CHANGED
|
@@ -17,12 +17,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
const UUID58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
20
|
-
/**
|
|
21
|
-
* @internal
|
|
22
|
-
* The length of the Base58 alphabet as BigInt for encoding/decoding operations.
|
|
23
|
-
* This is exported for internal use but not part of the public API.
|
|
24
|
-
*/
|
|
25
|
-
const UUID58_LENGTH = BigInt(58);
|
|
26
20
|
// check.ts
|
|
27
21
|
const MAX_UUID58 = "YcVfxkQb6JRzqk5kF2tNLv";
|
|
28
22
|
/**
|
|
@@ -70,6 +64,35 @@ function isUuid58(uuid58) {
|
|
|
70
64
|
const MAX_PREVIEW_LENGTH = 40;
|
|
71
65
|
/**
|
|
72
66
|
* @internal
|
|
67
|
+
* 58^9, the largest power of 58 below 2^53. A 9-digit Base58 chunk therefore
|
|
68
|
+
* fits in a Number, so most digit arithmetic can avoid slow BigInt division.
|
|
69
|
+
*/
|
|
70
|
+
const BASE58_CHUNK = 7427658739644928n;
|
|
71
|
+
/** Appends `digits` Base58 digits of `value` (most significant first). */
|
|
72
|
+
function appendDigits(out, value, digits) {
|
|
73
|
+
let chunk = "";
|
|
74
|
+
for (let i = 0; i < digits; i++) {
|
|
75
|
+
const quotient = Math.floor(value / 58);
|
|
76
|
+
chunk = UUID58_ALPHABET[value - quotient * 58] + chunk;
|
|
77
|
+
value = quotient;
|
|
78
|
+
}
|
|
79
|
+
return out + chunk;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @internal
|
|
83
|
+
* Encodes an unsigned 128-bit integer as a 22-character Base58 string.
|
|
84
|
+
*
|
|
85
|
+
* The value is split into 4 + 9 + 9 digit chunks with two BigInt divisions,
|
|
86
|
+
* instead of 22 BigInt divisions (one per digit).
|
|
87
|
+
*/
|
|
88
|
+
function encodeUint128(num) {
|
|
89
|
+
const low = Number(num % BASE58_CHUNK);
|
|
90
|
+
num /= BASE58_CHUNK;
|
|
91
|
+
const mid = Number(num % BASE58_CHUNK);
|
|
92
|
+
return appendDigits(appendDigits(appendDigits("", Number(num / BASE58_CHUNK), 4), mid, 9), low, 9);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* @internal
|
|
73
96
|
* Formats untrusted input for inclusion in an error message.
|
|
74
97
|
*
|
|
75
98
|
* The input is truncated so huge strings do not bloat error messages or logs,
|
|
@@ -81,8 +104,8 @@ function previewInput(input) {
|
|
|
81
104
|
}
|
|
82
105
|
// decode.ts
|
|
83
106
|
var _Uuid58DecodeError;
|
|
84
|
-
const
|
|
85
|
-
for (let i = 0; i < 58; i++)
|
|
107
|
+
const BASE58_INDEX = (/* @__PURE__ */ new Int8Array(128)).fill(-1);
|
|
108
|
+
for (let i = 0; i < 58; i++) BASE58_INDEX[UUID58_ALPHABET.charCodeAt(i)] = i;
|
|
86
109
|
/**
|
|
87
110
|
* Error thrown when an invalid Base58 string is provided for decoding.
|
|
88
111
|
* This includes strings containing characters not in the Base58 alphabet.
|
|
@@ -109,10 +132,20 @@ _Uuid58DecodeError.prototype.name = "Uuid58DecodeError";
|
|
|
109
132
|
function uuid58DecodeSafe(uuid58) {
|
|
110
133
|
if (uuid58.length !== 22) return new Uuid58DecodeError(`Expected Base58 string of length 22, but received string of length ${uuid58.length}: ${previewInput(uuid58)}`);
|
|
111
134
|
let num = 0n;
|
|
112
|
-
for (
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
135
|
+
for (let start = 0; start < 22;) {
|
|
136
|
+
const end = start === 0 ? 4 : start + 9;
|
|
137
|
+
let chunk = 0;
|
|
138
|
+
for (let i = start; i < end; i++) {
|
|
139
|
+
const code = uuid58.charCodeAt(i);
|
|
140
|
+
const index = code < 128 ? BASE58_INDEX[code] : -1;
|
|
141
|
+
if (index < 0) {
|
|
142
|
+
const char = String.fromCodePoint(uuid58.codePointAt(i));
|
|
143
|
+
return new Uuid58DecodeError(`Invalid Base58 character ${JSON.stringify(char)} found in input: ${previewInput(uuid58)}`);
|
|
144
|
+
}
|
|
145
|
+
chunk = chunk * 58 + index;
|
|
146
|
+
}
|
|
147
|
+
num = num * BASE58_CHUNK + BigInt(chunk);
|
|
148
|
+
start = end;
|
|
116
149
|
}
|
|
117
150
|
const hex = num.toString(16).padStart(32, "0");
|
|
118
151
|
if (hex.length !== 32) return new Uuid58DecodeError(`Decoded value exceeds 128 bits of UUID: ${previewInput(uuid58)}`);
|
|
@@ -170,13 +203,7 @@ function uuid58EncodeSafe(uuid) {
|
|
|
170
203
|
const hex = uuid.replace(/-/g, "");
|
|
171
204
|
if (hex.length !== 32) return new Uuid58EncodeError(`Invalid UUID length: expected 32 characters (excluding hyphens), got ${hex.length} characters in ${previewInput(uuid)}`);
|
|
172
205
|
if (!HEX32_REGEX.test(hex)) return new Uuid58EncodeError(`Invalid UUID format: ${previewInput(uuid)} contains non-hexadecimal characters`);
|
|
173
|
-
|
|
174
|
-
let encoded = "";
|
|
175
|
-
do {
|
|
176
|
-
encoded = UUID58_ALPHABET[Number(num % UUID58_LENGTH)] + encoded;
|
|
177
|
-
num /= UUID58_LENGTH;
|
|
178
|
-
} while (num > 0n);
|
|
179
|
-
return encoded.padStart(22, UUID58_ALPHABET[0]);
|
|
206
|
+
return encodeUint128(BigInt("0x" + hex));
|
|
180
207
|
}
|
|
181
208
|
/**
|
|
182
209
|
* Converts a standard UUID string to a 22-character Base58-encoded format.
|
|
@@ -203,6 +230,7 @@ function uuid58Encode(uuid) {
|
|
|
203
230
|
return result;
|
|
204
231
|
}
|
|
205
232
|
// generate.ts
|
|
233
|
+
const random = /* @__PURE__ */ new BigUint64Array(2);
|
|
206
234
|
/**
|
|
207
235
|
* Generates a new Base58-encoded UUID (always 22 characters).
|
|
208
236
|
*
|
|
@@ -217,16 +245,10 @@ function uuid58Encode(uuid) {
|
|
|
217
245
|
* ```
|
|
218
246
|
*/
|
|
219
247
|
function uuid58() {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
let encoded = "";
|
|
225
|
-
do {
|
|
226
|
-
encoded = UUID58_ALPHABET[Number(num % UUID58_LENGTH)] + encoded;
|
|
227
|
-
num /= UUID58_LENGTH;
|
|
228
|
-
} while (num > 0n);
|
|
229
|
-
return encoded.padStart(22, UUID58_ALPHABET[0]);
|
|
248
|
+
crypto.getRandomValues(random);
|
|
249
|
+
const high = random[0] & 18446744073709490175n | 16384n;
|
|
250
|
+
const low = random[1] & 4611686018427387903n | 9223372036854775808n;
|
|
251
|
+
return encodeUint128(high << 64n | low);
|
|
230
252
|
}
|
|
231
253
|
exports.UUID58_ALPHABET = UUID58_ALPHABET;
|
|
232
254
|
exports.UUID58_REGEX = UUID58_REGEX;
|
package/dist/index.js
CHANGED
|
@@ -16,12 +16,6 @@
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
const UUID58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
19
|
-
/**
|
|
20
|
-
* @internal
|
|
21
|
-
* The length of the Base58 alphabet as BigInt for encoding/decoding operations.
|
|
22
|
-
* This is exported for internal use but not part of the public API.
|
|
23
|
-
*/
|
|
24
|
-
const UUID58_LENGTH = BigInt(58);
|
|
25
19
|
// check.ts
|
|
26
20
|
const MAX_UUID58 = "YcVfxkQb6JRzqk5kF2tNLv";
|
|
27
21
|
/**
|
|
@@ -69,6 +63,35 @@ function isUuid58(uuid58) {
|
|
|
69
63
|
const MAX_PREVIEW_LENGTH = 40;
|
|
70
64
|
/**
|
|
71
65
|
* @internal
|
|
66
|
+
* 58^9, the largest power of 58 below 2^53. A 9-digit Base58 chunk therefore
|
|
67
|
+
* fits in a Number, so most digit arithmetic can avoid slow BigInt division.
|
|
68
|
+
*/
|
|
69
|
+
const BASE58_CHUNK = 7427658739644928n;
|
|
70
|
+
/** Appends `digits` Base58 digits of `value` (most significant first). */
|
|
71
|
+
function appendDigits(out, value, digits) {
|
|
72
|
+
let chunk = "";
|
|
73
|
+
for (let i = 0; i < digits; i++) {
|
|
74
|
+
const quotient = Math.floor(value / 58);
|
|
75
|
+
chunk = UUID58_ALPHABET[value - quotient * 58] + chunk;
|
|
76
|
+
value = quotient;
|
|
77
|
+
}
|
|
78
|
+
return out + chunk;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* @internal
|
|
82
|
+
* Encodes an unsigned 128-bit integer as a 22-character Base58 string.
|
|
83
|
+
*
|
|
84
|
+
* The value is split into 4 + 9 + 9 digit chunks with two BigInt divisions,
|
|
85
|
+
* instead of 22 BigInt divisions (one per digit).
|
|
86
|
+
*/
|
|
87
|
+
function encodeUint128(num) {
|
|
88
|
+
const low = Number(num % BASE58_CHUNK);
|
|
89
|
+
num /= BASE58_CHUNK;
|
|
90
|
+
const mid = Number(num % BASE58_CHUNK);
|
|
91
|
+
return appendDigits(appendDigits(appendDigits("", Number(num / BASE58_CHUNK), 4), mid, 9), low, 9);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* @internal
|
|
72
95
|
* Formats untrusted input for inclusion in an error message.
|
|
73
96
|
*
|
|
74
97
|
* The input is truncated so huge strings do not bloat error messages or logs,
|
|
@@ -80,8 +103,8 @@ function previewInput(input) {
|
|
|
80
103
|
}
|
|
81
104
|
// decode.ts
|
|
82
105
|
var _Uuid58DecodeError;
|
|
83
|
-
const
|
|
84
|
-
for (let i = 0; i < 58; i++)
|
|
106
|
+
const BASE58_INDEX = (/* @__PURE__ */ new Int8Array(128)).fill(-1);
|
|
107
|
+
for (let i = 0; i < 58; i++) BASE58_INDEX[UUID58_ALPHABET.charCodeAt(i)] = i;
|
|
85
108
|
/**
|
|
86
109
|
* Error thrown when an invalid Base58 string is provided for decoding.
|
|
87
110
|
* This includes strings containing characters not in the Base58 alphabet.
|
|
@@ -108,10 +131,20 @@ _Uuid58DecodeError.prototype.name = "Uuid58DecodeError";
|
|
|
108
131
|
function uuid58DecodeSafe(uuid58) {
|
|
109
132
|
if (uuid58.length !== 22) return new Uuid58DecodeError(`Expected Base58 string of length 22, but received string of length ${uuid58.length}: ${previewInput(uuid58)}`);
|
|
110
133
|
let num = 0n;
|
|
111
|
-
for (
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
134
|
+
for (let start = 0; start < 22;) {
|
|
135
|
+
const end = start === 0 ? 4 : start + 9;
|
|
136
|
+
let chunk = 0;
|
|
137
|
+
for (let i = start; i < end; i++) {
|
|
138
|
+
const code = uuid58.charCodeAt(i);
|
|
139
|
+
const index = code < 128 ? BASE58_INDEX[code] : -1;
|
|
140
|
+
if (index < 0) {
|
|
141
|
+
const char = String.fromCodePoint(uuid58.codePointAt(i));
|
|
142
|
+
return new Uuid58DecodeError(`Invalid Base58 character ${JSON.stringify(char)} found in input: ${previewInput(uuid58)}`);
|
|
143
|
+
}
|
|
144
|
+
chunk = chunk * 58 + index;
|
|
145
|
+
}
|
|
146
|
+
num = num * BASE58_CHUNK + BigInt(chunk);
|
|
147
|
+
start = end;
|
|
115
148
|
}
|
|
116
149
|
const hex = num.toString(16).padStart(32, "0");
|
|
117
150
|
if (hex.length !== 32) return new Uuid58DecodeError(`Decoded value exceeds 128 bits of UUID: ${previewInput(uuid58)}`);
|
|
@@ -169,13 +202,7 @@ function uuid58EncodeSafe(uuid) {
|
|
|
169
202
|
const hex = uuid.replace(/-/g, "");
|
|
170
203
|
if (hex.length !== 32) return new Uuid58EncodeError(`Invalid UUID length: expected 32 characters (excluding hyphens), got ${hex.length} characters in ${previewInput(uuid)}`);
|
|
171
204
|
if (!HEX32_REGEX.test(hex)) return new Uuid58EncodeError(`Invalid UUID format: ${previewInput(uuid)} contains non-hexadecimal characters`);
|
|
172
|
-
|
|
173
|
-
let encoded = "";
|
|
174
|
-
do {
|
|
175
|
-
encoded = UUID58_ALPHABET[Number(num % UUID58_LENGTH)] + encoded;
|
|
176
|
-
num /= UUID58_LENGTH;
|
|
177
|
-
} while (num > 0n);
|
|
178
|
-
return encoded.padStart(22, UUID58_ALPHABET[0]);
|
|
205
|
+
return encodeUint128(BigInt("0x" + hex));
|
|
179
206
|
}
|
|
180
207
|
/**
|
|
181
208
|
* Converts a standard UUID string to a 22-character Base58-encoded format.
|
|
@@ -202,6 +229,7 @@ function uuid58Encode(uuid) {
|
|
|
202
229
|
return result;
|
|
203
230
|
}
|
|
204
231
|
// generate.ts
|
|
232
|
+
const random = /* @__PURE__ */ new BigUint64Array(2);
|
|
205
233
|
/**
|
|
206
234
|
* Generates a new Base58-encoded UUID (always 22 characters).
|
|
207
235
|
*
|
|
@@ -216,15 +244,9 @@ function uuid58Encode(uuid) {
|
|
|
216
244
|
* ```
|
|
217
245
|
*/
|
|
218
246
|
function uuid58() {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
let encoded = "";
|
|
224
|
-
do {
|
|
225
|
-
encoded = UUID58_ALPHABET[Number(num % UUID58_LENGTH)] + encoded;
|
|
226
|
-
num /= UUID58_LENGTH;
|
|
227
|
-
} while (num > 0n);
|
|
228
|
-
return encoded.padStart(22, UUID58_ALPHABET[0]);
|
|
247
|
+
crypto.getRandomValues(random);
|
|
248
|
+
const high = random[0] & 18446744073709490175n | 16384n;
|
|
249
|
+
const low = random[1] & 4611686018427387903n | 9223372036854775808n;
|
|
250
|
+
return encodeUint128(high << 64n | low);
|
|
229
251
|
}
|
|
230
252
|
export { UUID58_ALPHABET, UUID58_REGEX, Uuid58DecodeError, Uuid58EncodeError, isUuid58, uuid58, uuid58Decode, uuid58DecodeSafe, uuid58Encode, uuid58EncodeSafe };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nakanoaas/uuid58",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "A tiny, zero-dependency library for generating and converting UUIDs to Base58-encoded strings.",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/nakanoasaservice/uuid58/issues"
|
|
@@ -35,7 +35,8 @@
|
|
|
35
35
|
"build": "vp pack",
|
|
36
36
|
"check": "vp check",
|
|
37
37
|
"test": "vp test run",
|
|
38
|
-
"bench": "vp test bench --run",
|
|
38
|
+
"bench": "vp pack && vp test bench --run --reporter=default",
|
|
39
|
+
"bench:baseline": "sh bench/save-baseline.sh",
|
|
39
40
|
"jsr:dry-run": "vp pack && jsr publish --dry-run"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|