@lumjs/encode 2.2.0 → 2.3.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.
- package/CHANGELOG.md +22 -3
- package/lib/base32.js +227 -0
- package/lib/hash.js +10 -5
- package/lib/hmac.js +15 -9
- package/lib/hotp.js +7 -2
- package/lib/index.js +2 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,7 +6,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
## [2.
|
|
9
|
+
## [2.3.0] - 2026-01-13
|
|
10
|
+
### Added
|
|
11
|
+
- New `base32` module with encoding and decoding of four variants of Base32.
|
|
12
|
+
- Tests for the `base32` module.
|
|
13
|
+
|
|
14
|
+
## [2.2.2] - 2026-01-13
|
|
15
|
+
### Fixed
|
|
16
|
+
- A few typos and bugs in the HMAC/HOTP/TOTP libraries I added last time.
|
|
17
|
+
- Added some missing timestamps in this changelog.
|
|
18
|
+
- Fixed references in this changelog.
|
|
19
|
+
### Changed
|
|
20
|
+
- While fixing the broken bits, I made a bunch of previously hard-coded values
|
|
21
|
+
into options. They'll need to be properly documented at some point.
|
|
22
|
+
- Changed how `hash.getAlgorithm()` works behind the scenes.
|
|
23
|
+
- v2.2.1 never got published for reasons, so no log or tag for it.
|
|
24
|
+
|
|
25
|
+
## [2.2.0] - 2025-11-18
|
|
10
26
|
### Added
|
|
11
27
|
- intToBytes() and hexToBytes() functions added to util.js
|
|
12
28
|
- A HMAC wrapper library, and a generic Signature class used by it.
|
|
@@ -16,7 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
32
|
module, this one has two JS classes and uses the SubtleCrypto API.
|
|
17
33
|
- A TODO file with things I want to do.
|
|
18
34
|
|
|
19
|
-
## [2.1.0]
|
|
35
|
+
## [2.1.0] - 2025-90-09
|
|
20
36
|
### Changed
|
|
21
37
|
- The `base64` library now supports the `Uint8Array.fromBase64` static method,
|
|
22
38
|
and the corresponding `toBase64()` instance method. As those are rather new
|
|
@@ -52,7 +68,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
52
68
|
### Added
|
|
53
69
|
- Initial release.
|
|
54
70
|
|
|
55
|
-
[Unreleased]: https://github.com/supernovus/lum.encode.js/compare/v2.
|
|
71
|
+
[Unreleased]: https://github.com/supernovus/lum.encode.js/compare/v2.3.0...HEAD
|
|
72
|
+
[2.3.0]: https://github.com/supernovus/lum.encode.js/compare/v2.2.2...v2.3.0
|
|
73
|
+
[2.2.2]: https://github.com/supernovus/lum.encode.js/compare/v2.2.0...v2.2.2
|
|
74
|
+
[2.2.0]: https://github.com/supernovus/lum.encode.js/compare/v2.1.0...v2.2.0
|
|
56
75
|
[2.1.0]: https://github.com/supernovus/lum.encode.js/compare/v2.0.0...v2.1.0
|
|
57
76
|
[2.0.0]: https://github.com/supernovus/lum.encode.js/compare/v1.2.0...v2.0.0
|
|
58
77
|
[1.2.0]: https://github.com/supernovus/lum.encode.js/compare/v1.1.0...v1.2.0
|
package/lib/base32.js
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base32 encoding in pure JS.
|
|
3
|
+
*
|
|
4
|
+
* Originally based on an implementation from Richard Thiessen:
|
|
5
|
+
* https://gist.github.com/RichardThiessen/5a4e32d57aafd5430c09122f23e4b757
|
|
6
|
+
*
|
|
7
|
+
* With a lot of my own tweaks and enhancements obviously.
|
|
8
|
+
*
|
|
9
|
+
* @module @lumjs/encode/base32
|
|
10
|
+
*/
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
const { isObj } = require('@lumjs/core/types');
|
|
14
|
+
const cp = Object.assign;
|
|
15
|
+
const lock = Object.freeze;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Supported Base32 variants.
|
|
19
|
+
*
|
|
20
|
+
* Unlike Base64 which typically only has two versions (which only have minor
|
|
21
|
+
* differences), Base32 has multiple variants which use vastly different
|
|
22
|
+
* encoding alphabets. We support a handful of well known variants.
|
|
23
|
+
*
|
|
24
|
+
* For every lowercase property name in this object, there is
|
|
25
|
+
* also an uppcase alias that is the exact same type definition.
|
|
26
|
+
*
|
|
27
|
+
* This namespace object is also exported as `TYPES`.
|
|
28
|
+
*
|
|
29
|
+
* @alias module:@lumjs/encode/base32.Base32Types
|
|
30
|
+
*/
|
|
31
|
+
const Base32Types = {
|
|
32
|
+
/** The RFC4648 standard format. */
|
|
33
|
+
rfc4648: lock(['ABCDEFGHIJKLMNOPQRSTUVWXYZ234567']),
|
|
34
|
+
/** The zbase32 variant. */
|
|
35
|
+
zbase32: lock(['ybndrfg8ejkmcpqxot1uwisza345h769']),
|
|
36
|
+
/** The geohash variant. */
|
|
37
|
+
geohash: lock(['0123456789bcdefghjkmnpqrstuvwxyz']),
|
|
38
|
+
/** Douglas Crockford's variant. */
|
|
39
|
+
crockford: lock(['0123456789ABCDEFGHJKMNPQRSTVWXYZ', 'O0', 'I1', 'L1']),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* An alias to RFC4648 recognizing that it is the default variant.
|
|
44
|
+
*/
|
|
45
|
+
Base32Types.default = Base32Types.rfc4648;
|
|
46
|
+
|
|
47
|
+
for (let lcid in Base32Types) {
|
|
48
|
+
let ucid = lcid.toUpperCase();
|
|
49
|
+
Base32Types[ucid] = Base32Types[lcid];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
lock(Base32Types);
|
|
53
|
+
|
|
54
|
+
const UTF8 = 'utf-8';
|
|
55
|
+
const encodeText = s => new TextEncoder(UTF8).encode(s);
|
|
56
|
+
const decodeText = b => new TextDecoder(UTF8).decode(b);
|
|
57
|
+
|
|
58
|
+
function _opts(opts, bopt) {
|
|
59
|
+
if (typeof opts === 'string' || Array.isArray(opts)) {
|
|
60
|
+
opts = { type: opts };
|
|
61
|
+
}
|
|
62
|
+
else if (typeof opts === 'boolean') {
|
|
63
|
+
return { [bopt]: opts, type: Base32Types.default };
|
|
64
|
+
}
|
|
65
|
+
else if (!isObj(opts)) {
|
|
66
|
+
return { type: Base32Types.default }
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (typeof opts.type === 'string') {
|
|
70
|
+
if (Array.isArray(Base32Types[opts.type])) {
|
|
71
|
+
opts.type = Base32Types[opts.type];
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
console.error("unknown base32 type", opts.type, opts);
|
|
75
|
+
opts.type = Base32Types.default;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (Array.isArray(opts.type)) {
|
|
79
|
+
if (typeof opts.type[0] !== 'string' || opts.type[0].length !== 32) {
|
|
80
|
+
console.error("invalid base32 type def", opts.type, opts);
|
|
81
|
+
opts.type = Base32Types.default;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
if (opts.type !== undefined) {
|
|
86
|
+
console.error("invalid base32 type option value", opts.type, opts);
|
|
87
|
+
}
|
|
88
|
+
opts.type = Base32Types.default;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return opts;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _b32_map(typedef) {
|
|
95
|
+
let alphabet = typedef[0].toUpperCase();
|
|
96
|
+
let aliases = typedef.slice(1);
|
|
97
|
+
let lookup = new Map(alphabet.split("").map((c, i) => [c, i]));
|
|
98
|
+
aliases.map(x => lookup.set(x[0], lookup.get(x[1])));
|
|
99
|
+
return lookup;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Decode a Base32-encoded string.
|
|
104
|
+
* @param {string} str - Base32 string.
|
|
105
|
+
* @param {(object|string)} [opts] Options.
|
|
106
|
+
*
|
|
107
|
+
* If this is a boolean it will be used as `opts.string`.
|
|
108
|
+
*
|
|
109
|
+
* If this is a string or one of the `Base32Types` properties,
|
|
110
|
+
* it will be used as `opts.type`.
|
|
111
|
+
*
|
|
112
|
+
* @param {(string|Array)} [opts.type] Base32 variant to use.
|
|
113
|
+
*
|
|
114
|
+
* If this is a string it must be the name (uppercase or lowercase)
|
|
115
|
+
* of one of the properties in the `Base32Types` object.
|
|
116
|
+
*
|
|
117
|
+
* If it is an Array it is expected that it is one of the properties
|
|
118
|
+
* from the Base32Types, or a compatible type def where the first
|
|
119
|
+
* item in the array is a string consisting of exactly 32 unique characters.
|
|
120
|
+
*
|
|
121
|
+
* @param {boolean} [opts.string=false] Return a UTF-8 string?
|
|
122
|
+
*
|
|
123
|
+
* If this is true then we will assume the original encoded value was a UTF-8
|
|
124
|
+
* string, and will decode it as such using a TextDecoder instance.
|
|
125
|
+
*
|
|
126
|
+
* If this is false (the default) we will return a Uint8Array.
|
|
127
|
+
*
|
|
128
|
+
* @returns {(Uint8Array|string)}
|
|
129
|
+
* @alias module:@lumjs/encode/base32.decode
|
|
130
|
+
*/
|
|
131
|
+
function base32Decode(str, opts) {
|
|
132
|
+
opts = _opts(opts, 'string');
|
|
133
|
+
let lookup = _b32_map(opts.type);
|
|
134
|
+
// remove whitespace and padding
|
|
135
|
+
str = str.replace(/\s+/g, "").replace(/=*$/g, "");
|
|
136
|
+
let vals = str.toUpperCase().split("").map(c => lookup.get(c));
|
|
137
|
+
if (vals.indexOf(undefined) != -1) {
|
|
138
|
+
throw new RangeError("Base32: string includes non-Base32 characters");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let bytes = new Uint8Array((vals.length * 5 / 8) | 0);
|
|
142
|
+
for (let i = 0; i < vals.length; i += 8) {
|
|
143
|
+
//do all, missing indices will fail silently
|
|
144
|
+
let b_o = (i / 8 * 5) | 0;
|
|
145
|
+
bytes[b_o + 0] = (vals[i + 0] << 3) | (vals[i + 1] >> 2);
|
|
146
|
+
bytes[b_o + 1] = (vals[i + 1] << 6) | (vals[i + 2] << 1) | (vals[i + 3] >> 4);
|
|
147
|
+
bytes[b_o + 2] = (vals[i + 3] << 4) | (vals[i + 4] >> 1);
|
|
148
|
+
bytes[b_o + 3] = (vals[i + 4] << 7) | (vals[i + 5] << 2) | (vals[i + 6] >> 3);
|
|
149
|
+
bytes[b_o + 4] = (vals[i + 6] << 5) | (vals[i + 7] >> 0);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return opts.string ? decodeText(bytes) : bytes;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Encode a value into a Base32 string.
|
|
157
|
+
*
|
|
158
|
+
* @param {(ArrayBuffer|TypedArray|string)} data - Data to be encoded.
|
|
159
|
+
*
|
|
160
|
+
* If this is a string it will be converted into a Uint8Array using a
|
|
161
|
+
* TextEncoder instance.
|
|
162
|
+
*
|
|
163
|
+
* @param {(object|string|boolean)} [opts] Options.
|
|
164
|
+
*
|
|
165
|
+
* If this is a boolean it will be used as `opts.pad`.
|
|
166
|
+
*
|
|
167
|
+
* If this is a string or one of the `Base32Types` properties,
|
|
168
|
+
* it will be used as `opts.type`.
|
|
169
|
+
*
|
|
170
|
+
* @param {(string|Array)} [opts.type] Base32 variant to use.
|
|
171
|
+
*
|
|
172
|
+
* If this is a string it must be the name (uppercase or lowercase)
|
|
173
|
+
* of one of the properties in the `Base32Types` object.
|
|
174
|
+
*
|
|
175
|
+
* If it is an Array it is expected that it is one of the properties
|
|
176
|
+
* from the Base32Types, or a compatible type def where the first
|
|
177
|
+
* item in the array is a string consisting of exactly 32 unique characters.
|
|
178
|
+
*
|
|
179
|
+
* @param {boolean} [opts.pad=true] Add `=` padding characters?
|
|
180
|
+
*
|
|
181
|
+
* Base32 (like Base64) uses `=` as a padding character to ensure the length
|
|
182
|
+
* of the encoded strings are divisible by 8. As that is a part of
|
|
183
|
+
* the standard specification, this option defaults to true.
|
|
184
|
+
*
|
|
185
|
+
* If you explicitly set this to false the string won't have any padding
|
|
186
|
+
* added to it, regardless of its length.
|
|
187
|
+
*
|
|
188
|
+
* @returns {string}
|
|
189
|
+
* @alias module:@lumjs/encode/base32.encode
|
|
190
|
+
*/
|
|
191
|
+
function base32Encode(buf, opts) {
|
|
192
|
+
opts = _opts(opts, 'pad');
|
|
193
|
+
let alphabet = opts.type[0];
|
|
194
|
+
if (buf.byteLength === undefined) { //not Arraybuffer?
|
|
195
|
+
buf = encodeText(buf);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
//may need extra zero at end of buf for some bits of last value
|
|
199
|
+
let bytes = new Uint8Array(buf.byteLength + 1);
|
|
200
|
+
bytes.set(buf, 0)
|
|
201
|
+
let out = new Uint8Array(((buf.byteLength * 8 + 4) / 5) | 0);
|
|
202
|
+
|
|
203
|
+
for (let i = 0; i < out.length; i += 8) {
|
|
204
|
+
//do all,missing indices will fail silently
|
|
205
|
+
let b_o = (i / 8 * 5) | 0;
|
|
206
|
+
out[i + 0] = (bytes[b_o + 0] >> 3);
|
|
207
|
+
out[i + 1] = (bytes[b_o + 0] << 2) | (bytes[b_o + 1] >> 6);
|
|
208
|
+
out[i + 2] = (bytes[b_o + 1] >> 1);
|
|
209
|
+
out[i + 3] = (bytes[b_o + 1] << 4) | (bytes[b_o + 2] >> 4);
|
|
210
|
+
out[i + 4] = (bytes[b_o + 2] << 1) | (bytes[b_o + 3] >> 7);
|
|
211
|
+
out[i + 5] = (bytes[b_o + 3] >> 2);
|
|
212
|
+
out[i + 6] = (bytes[b_o + 3] << 3) | (bytes[b_o + 4] >> 5);
|
|
213
|
+
out[i + 7] = (bytes[b_o + 4] >> 0);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
let str = Array.from(out.entries(), x => alphabet[x[1] & 31]).join("");
|
|
217
|
+
if (opts.pad ?? true) {
|
|
218
|
+
str = str.padEnd(out.length + (8 - (out.length % 8)) % 8, "=");
|
|
219
|
+
}
|
|
220
|
+
return str;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
module.exports = {
|
|
224
|
+
Base32Types, TYPES: Base32Types,
|
|
225
|
+
base32Encode, encode: base32Encode,
|
|
226
|
+
base32Decode, decode: base32Decode,
|
|
227
|
+
}
|
package/lib/hash.js
CHANGED
|
@@ -27,6 +27,11 @@ const ALGO_INFO =
|
|
|
27
27
|
'SHA-512': {length: 512, block: 1024},
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
for (let algo in ALGO_INFO) {
|
|
31
|
+
ALGO_INFO[algo].id = algo;
|
|
32
|
+
Object.freeze(ALGO_INFO[algo]);
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
const DATA_ENCODERS =
|
|
31
36
|
{
|
|
32
37
|
base64, base91,
|
|
@@ -184,7 +189,7 @@ module.exports = class
|
|
|
184
189
|
|
|
185
190
|
if (id in ALGO_INFO)
|
|
186
191
|
{
|
|
187
|
-
return
|
|
192
|
+
return ALGO_INFO[id];
|
|
188
193
|
}
|
|
189
194
|
|
|
190
195
|
// Invalid algorithm id, nothing to return.
|
|
@@ -299,8 +304,8 @@ module.exports = class
|
|
|
299
304
|
async base64(input, opts=this.defaults.base64)
|
|
300
305
|
{
|
|
301
306
|
const hash = await this.hash(input);
|
|
302
|
-
const b64str = base64.fromBytes(new Uint8Array(hash));
|
|
303
|
-
return opts.url ? base64.urlize(b64str) : b64str;
|
|
307
|
+
const b64str = base64.fromBytes(new Uint8Array(hash), opts);
|
|
308
|
+
return opts.url ? base64.urlize(b64str, opts) : b64str;
|
|
304
309
|
}
|
|
305
310
|
|
|
306
311
|
/**
|
|
@@ -332,7 +337,7 @@ module.exports = class
|
|
|
332
337
|
|
|
333
338
|
if (nba)
|
|
334
339
|
{
|
|
335
|
-
hash = util.numByteArray(hash);
|
|
340
|
+
hash = util.numByteArray(hash, nba);
|
|
336
341
|
}
|
|
337
342
|
|
|
338
343
|
return base91.encode(new Uint8Array(hash));
|
|
@@ -343,7 +348,7 @@ module.exports = class
|
|
|
343
348
|
*
|
|
344
349
|
* @param {(string|object)} input - A value to add to the hash.
|
|
345
350
|
*
|
|
346
|
-
* If it is an `object` then it will be processed with the `
|
|
351
|
+
* If it is an `object` then it will be processed with the `addUsing`
|
|
347
352
|
* handler. See the constructor for details on supported formats.
|
|
348
353
|
*
|
|
349
354
|
* String values are simply added _as-is_.
|
package/lib/hmac.js
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
const Signature = require('./signature');
|
|
4
4
|
|
|
5
|
+
const CKEY = Symbol('@lumjs/encore/hmac~key');
|
|
5
6
|
const HMAC = 'HMAC';
|
|
6
|
-
const DEF_OPTS = {
|
|
7
|
+
const DEF_OPTS = {
|
|
8
|
+
algorithm: 'SHA-256',
|
|
9
|
+
extractable: false,
|
|
10
|
+
keyFormat: 'raw',
|
|
11
|
+
usages: ['sign']
|
|
12
|
+
};
|
|
7
13
|
|
|
8
14
|
/**
|
|
9
15
|
* The main class to perform HMAC signing.
|
|
@@ -31,20 +37,20 @@ class HmacEncoder {
|
|
|
31
37
|
* @returns {Promise<CryptoKey>}
|
|
32
38
|
*/
|
|
33
39
|
async getKey() {
|
|
34
|
-
if (this
|
|
35
|
-
return this
|
|
40
|
+
if (this[CKEY]) {
|
|
41
|
+
return this[CKEY];
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
let hmac = { name: HMAC, hash: this.options.algorithm }
|
|
39
45
|
let key = await crypto.subtle.importKey(
|
|
40
|
-
|
|
41
|
-
this.keyBytes,
|
|
42
|
-
hmac,
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
this.options.keyFormat, // Key format
|
|
47
|
+
this.keyBytes, // Key data
|
|
48
|
+
hmac, // Algorithm
|
|
49
|
+
this.options.extractable, // Is key extractable
|
|
50
|
+
this.options.usages, // Allowed key usages
|
|
45
51
|
);
|
|
46
52
|
|
|
47
|
-
this
|
|
53
|
+
this[CKEY] = key;
|
|
48
54
|
return key;
|
|
49
55
|
}
|
|
50
56
|
|
package/lib/hotp.js
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
const HmacEncoder = require('./hmac');
|
|
4
4
|
const { intToBytes } = require('./util');
|
|
5
5
|
|
|
6
|
-
const DEF_OPTS = {
|
|
6
|
+
const DEF_OPTS = {
|
|
7
|
+
algorithm: 'SHA-1',
|
|
8
|
+
checkSize: 7,
|
|
9
|
+
counter: 0,
|
|
10
|
+
window: 50
|
|
11
|
+
};
|
|
7
12
|
|
|
8
13
|
const cp = Object.assign;
|
|
9
14
|
const isError = v => (typeof v === 'function' && Error.isPrototypeOf(v));
|
|
@@ -62,7 +67,7 @@ class HOTP {
|
|
|
62
67
|
(hb[offset + 3] & 0xff);
|
|
63
68
|
|
|
64
69
|
let v2 = (v1 % 1000000) + '';
|
|
65
|
-
let code = Array(
|
|
70
|
+
let code = Array(opts.checkSize - v2.length).join('0') + v2;
|
|
66
71
|
|
|
67
72
|
let res = {
|
|
68
73
|
opts,
|
package/lib/index.js
CHANGED
|
@@ -17,6 +17,7 @@ def(exports, 'util', {value: util}, E);
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @alias module:@lumjs/encode.ord
|
|
20
|
+
* @deprecated this alias to `util.ord` will be removed in 3.x.
|
|
20
21
|
* @see {@link module:@lumjs/encode/util.ord}
|
|
21
22
|
*/
|
|
22
23
|
def(exports, 'ord', util.ord, E);
|
|
@@ -24,6 +25,7 @@ def(exports, 'ord', util.ord, E);
|
|
|
24
25
|
/**
|
|
25
26
|
* @name module:@lumjs/encode.numByteArray
|
|
26
27
|
* @function
|
|
28
|
+
* @deprecated this alias to `util.numByteArray` will be removed in 3.x.
|
|
27
29
|
* @see {@link module:@lumjs/encode/util.numByteArray}
|
|
28
30
|
*/
|
|
29
31
|
def(exports, 'numByteArray', util.numByteArray, E);
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumjs/encode",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"exports":
|
|
6
6
|
{
|
|
7
7
|
".": "./lib/index.js",
|
|
8
|
+
"./base32": "./lib/base32.js",
|
|
8
9
|
"./base64": "./lib/base64.js",
|
|
9
10
|
"./base91": "./lib/base91.js",
|
|
10
11
|
"./hash": "./lib/hash.js",
|