@exodus/bytes 1.9.0 → 1.11.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/README.md +417 -90
- package/array.d.ts +42 -3
- package/base32.d.ts +83 -0
- package/base58.d.ts +62 -0
- package/base58check.d.ts +131 -0
- package/base58check.js +2 -1
- package/base64.d.ts +40 -19
- package/bech32.d.ts +76 -0
- package/bigint.d.ts +48 -0
- package/encoding-browser.d.ts +23 -0
- package/encoding-lite.d.ts +61 -0
- package/encoding.d.ts +93 -11
- package/encoding.js +4 -3
- package/fallback/_utils.js +14 -11
- package/fallback/encoding.js +34 -42
- package/fallback/encoding.util.js +38 -8
- package/fallback/multi-byte.encodings.json +4 -3
- package/fallback/multi-byte.js +87 -16
- package/fallback/multi-byte.table.js +3 -0
- package/fallback/percent.js +31 -0
- package/hex.d.ts +22 -8
- package/index.d.ts +1 -1
- package/multi-byte.d.ts +64 -0
- package/package.json +63 -9
- package/single-byte.d.ts +159 -0
- package/utf16.d.ts +92 -0
- package/utf16.js +1 -1
- package/utf8.d.ts +72 -18
- package/utf8.js +11 -6
- package/utf8.node.js +1 -1
- package/whatwg.d.ts +48 -0
- package/whatwg.js +76 -0
- package/wif.d.ts +76 -0
- package/wif.js +1 -2
package/utf8.js
CHANGED
|
@@ -27,16 +27,21 @@ function deLoose(str, loose, res) {
|
|
|
27
27
|
|
|
28
28
|
// Recheck if the string was encoded correctly
|
|
29
29
|
let start = 0
|
|
30
|
-
const last = res.length -
|
|
31
|
-
// Search for EFBFBD
|
|
32
|
-
while (start
|
|
30
|
+
const last = res.length - 3
|
|
31
|
+
// Search for EFBFBD (3-byte sequence)
|
|
32
|
+
while (start <= last) {
|
|
33
33
|
const pos = res.indexOf(0xef, start)
|
|
34
|
-
if (pos === -1) break
|
|
34
|
+
if (pos === -1 || pos > last) break
|
|
35
35
|
start = pos + 1
|
|
36
36
|
if (res[pos + 1] === 0xbf && res[pos + 2] === 0xbd) {
|
|
37
37
|
// Found a replacement char in output, need to recheck if we encoded the input correctly
|
|
38
|
-
if (str
|
|
39
|
-
|
|
38
|
+
if (!nativeDecoder && str.length < 1e7) {
|
|
39
|
+
// This is ~2x faster than decode in Hermes
|
|
40
|
+
try {
|
|
41
|
+
if (encodeURI(str) !== null) return res // guard against optimizing out
|
|
42
|
+
} catch {}
|
|
43
|
+
} else if (str === decode(res)) return res
|
|
44
|
+
throw new TypeError(E_STRICT_UNICODE)
|
|
40
45
|
}
|
|
41
46
|
}
|
|
42
47
|
|
package/utf8.node.js
CHANGED
|
@@ -9,7 +9,7 @@ if (Buffer.TYPED_ARRAY_SUPPORT) throw new Error('Unexpected Buffer polyfill')
|
|
|
9
9
|
let decoderFatal
|
|
10
10
|
const decoderLoose = new TextDecoder('utf-8', { ignoreBOM: true })
|
|
11
11
|
const { isWellFormed } = String.prototype
|
|
12
|
-
const isDeno =
|
|
12
|
+
const isDeno = !!globalThis.Deno
|
|
13
13
|
|
|
14
14
|
try {
|
|
15
15
|
decoderFatal = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true })
|
package/whatwg.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHATWG helpers
|
|
3
|
+
*
|
|
4
|
+
* ```js
|
|
5
|
+
* import '@exodus/bytes/encoding.js' // For full legacy multi-byte encodings support
|
|
6
|
+
* import { percentEncodeAfterEncoding } from '@exodus/bytes/whatwg.js'
|
|
7
|
+
* ```
|
|
8
|
+
*
|
|
9
|
+
* @module @exodus/bytes/whatwg.js
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Implements [percent-encode after encoding](https://url.spec.whatwg.org/#string-percent-encode-after-encoding)
|
|
14
|
+
* per WHATWG URL specification.
|
|
15
|
+
*
|
|
16
|
+
* > [!IMPORTANT]
|
|
17
|
+
* > You must import `@exodus/bytes/encoding.js` for this API to accept legacy multi-byte encodings.
|
|
18
|
+
*
|
|
19
|
+
* Encodings `utf16-le`, `utf16-be`, and `replacement` are not accepted.
|
|
20
|
+
*
|
|
21
|
+
* [C0 control percent-encode set](https://url.spec.whatwg.org/#c0-control-percent-encode-set) is
|
|
22
|
+
* always percent-encoded.
|
|
23
|
+
*
|
|
24
|
+
* `percentEncodeSet` is an addition to that, and must be a string of unique increasing codepoints
|
|
25
|
+
* in range 0x20 - 0x7e, e.g. `' "#<>'`.
|
|
26
|
+
*
|
|
27
|
+
* This method accepts [DOMStrings](https://webidl.spec.whatwg.org/#idl-DOMString) and converts them
|
|
28
|
+
* to [USVStrings](https://webidl.spec.whatwg.org/#idl-USVString).
|
|
29
|
+
* This is different from e.g. `encodeURI` and `encodeURIComponent` which throw on surrogates:
|
|
30
|
+
* ```js
|
|
31
|
+
* > percentEncodeAfterEncoding('utf8', '\ud800', ' "#$%&+,/:;<=>?@[\\]^`{|}') // component
|
|
32
|
+
* '%EF%BF%BD'
|
|
33
|
+
* > encodeURIComponent('\ud800')
|
|
34
|
+
* Uncaught URIError: URI malformed
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @param encoding - The encoding label per WHATWG Encoding spec
|
|
38
|
+
* @param input - Input scalar-value string to encode
|
|
39
|
+
* @param percentEncodeSet - A string of ASCII chars to escape in addition to C0 control percent-encode set
|
|
40
|
+
* @param spaceAsPlus - Whether to encode space as `'+'` instead of `'%20'` or `' '` (default: false)
|
|
41
|
+
* @returns The percent-encoded string
|
|
42
|
+
*/
|
|
43
|
+
export function percentEncodeAfterEncoding(
|
|
44
|
+
encoding: string,
|
|
45
|
+
input: string,
|
|
46
|
+
percentEncodeSet: string,
|
|
47
|
+
spaceAsPlus?: boolean
|
|
48
|
+
): string;
|
package/whatwg.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { utf8fromStringLoose } from '@exodus/bytes/utf8.js'
|
|
2
|
+
import { createSinglebyteEncoder } from '@exodus/bytes/single-byte.js'
|
|
3
|
+
import { isMultibyte, getMultibyteEncoder } from './fallback/encoding.js'
|
|
4
|
+
import { normalizeEncoding, E_ENCODING } from './fallback/encoding.api.js'
|
|
5
|
+
import { percentEncoder } from './fallback/percent.js'
|
|
6
|
+
import { encodeMap } from './fallback/single-byte.js'
|
|
7
|
+
import { E_STRING } from './fallback/_utils.js'
|
|
8
|
+
|
|
9
|
+
// https://url.spec.whatwg.org/#string-percent-encode-after-encoding
|
|
10
|
+
// Codepoints below 0x20, 0x7F specifically, and above 0x7F (non-ASCII) are always encoded
|
|
11
|
+
// > A C0 control is a code point in the range U+0000 NULL to U+001F INFORMATION SEPARATOR ONE, inclusive.
|
|
12
|
+
// > The C0 control percent-encode set are the C0 controls and all code points greater than U+007E (~).
|
|
13
|
+
export function percentEncodeAfterEncoding(encoding, input, percentEncodeSet, spaceAsPlus = false) {
|
|
14
|
+
const enc = normalizeEncoding(encoding)
|
|
15
|
+
// Ref: https://encoding.spec.whatwg.org/#get-an-encoder
|
|
16
|
+
if (!enc || enc === 'replacement' || enc === 'utf-16le' || enc === 'utf-16be') {
|
|
17
|
+
throw new RangeError(E_ENCODING)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const percent = percentEncoder(percentEncodeSet, spaceAsPlus)
|
|
21
|
+
if (enc === 'utf-8') return percent(utf8fromStringLoose(input))
|
|
22
|
+
|
|
23
|
+
const multi = isMultibyte(enc)
|
|
24
|
+
const encoder = multi ? getMultibyteEncoder() : createSinglebyteEncoder
|
|
25
|
+
const fatal = encoder(enc)
|
|
26
|
+
try {
|
|
27
|
+
return percent(fatal(input))
|
|
28
|
+
} catch {}
|
|
29
|
+
|
|
30
|
+
let res = ''
|
|
31
|
+
let last = 0
|
|
32
|
+
if (multi) {
|
|
33
|
+
const rep = enc === 'gb18030' ? percent(fatal('\uFFFD')) : `%26%23${0xff_fd}%3B` // only gb18030 can encode it
|
|
34
|
+
const escaping = encoder(enc, (cp, u, i) => {
|
|
35
|
+
res += percent(u, last, i)
|
|
36
|
+
res += cp >= 0xd8_00 && cp < 0xe0_00 ? rep : `%26%23${cp}%3B` // &#cp;
|
|
37
|
+
last = i
|
|
38
|
+
return 0 // no bytes emitted
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const u = escaping(input) // has side effects on res
|
|
42
|
+
res += percent(u, last)
|
|
43
|
+
} else {
|
|
44
|
+
if (typeof input !== 'string') throw new TypeError(E_STRING) // all other paths have their own validation
|
|
45
|
+
const m = encodeMap(enc)
|
|
46
|
+
const len = input.length
|
|
47
|
+
const u = new Uint8Array(len)
|
|
48
|
+
for (let i = 0; i < len; i++) {
|
|
49
|
+
const x = input.charCodeAt(i)
|
|
50
|
+
const b = m[x]
|
|
51
|
+
if (!b && x) {
|
|
52
|
+
let cp = x
|
|
53
|
+
const i0 = i
|
|
54
|
+
if (x >= 0xd8_00 && x < 0xe0_00) {
|
|
55
|
+
cp = 0xff_fd
|
|
56
|
+
if (x < 0xdc_00 && i + 1 < len) {
|
|
57
|
+
const x1 = input.charCodeAt(i + 1)
|
|
58
|
+
if (x1 >= 0xdc_00 && x1 < 0xe0_00) {
|
|
59
|
+
cp = 0x1_00_00 + ((x1 & 0x3_ff) | ((x & 0x3_ff) << 10))
|
|
60
|
+
i++
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
res += `${percent(u, last, i0)}%26%23${cp}%3B` // &#cp;
|
|
66
|
+
last = i + 1 // skip current
|
|
67
|
+
} else {
|
|
68
|
+
u[i] = b
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
res += percent(u, last)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return res
|
|
76
|
+
}
|
package/wif.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet Import Format (WIF) encoding and decoding.
|
|
3
|
+
*
|
|
4
|
+
* ```js
|
|
5
|
+
* import { fromWifString, toWifString } from '@exodus/bytes/wif.js'
|
|
6
|
+
* import { fromWifStringSync, toWifStringSync } from '@exodus/bytes/wif.js'
|
|
7
|
+
* ```
|
|
8
|
+
*
|
|
9
|
+
* On non-Node.js, requires peer dependency [@noble/hashes](https://www.npmjs.com/package/@noble/hashes) to be installed.
|
|
10
|
+
*
|
|
11
|
+
* @module @exodus/bytes/wif.js
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/// <reference types="node" />
|
|
15
|
+
|
|
16
|
+
import type { Uint8ArrayBuffer } from './array.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* WIF (Wallet Import Format) data structure
|
|
20
|
+
*/
|
|
21
|
+
export interface Wif {
|
|
22
|
+
/** Network version byte */
|
|
23
|
+
version: number;
|
|
24
|
+
/** 32-byte private key */
|
|
25
|
+
privateKey: Uint8ArrayBuffer;
|
|
26
|
+
/** Whether the key is compressed */
|
|
27
|
+
compressed: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Decode a WIF string to WIF data
|
|
32
|
+
*
|
|
33
|
+
* Returns a promise that resolves to an object with `{ version, privateKey, compressed }`.
|
|
34
|
+
*
|
|
35
|
+
* The optional `version` parameter validates the version byte.
|
|
36
|
+
*
|
|
37
|
+
* Throws if the WIF string is invalid or version doesn't match.
|
|
38
|
+
*
|
|
39
|
+
* @param string - The WIF encoded string
|
|
40
|
+
* @param version - Optional expected version byte to validate against
|
|
41
|
+
* @returns The decoded WIF data
|
|
42
|
+
* @throws Error if the WIF string is invalid or version doesn't match
|
|
43
|
+
*/
|
|
44
|
+
export function fromWifString(string: string, version?: number): Promise<Wif>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Decode a WIF string to WIF data (synchronous)
|
|
48
|
+
*
|
|
49
|
+
* Returns an object with `{ version, privateKey, compressed }`.
|
|
50
|
+
*
|
|
51
|
+
* The optional `version` parameter validates the version byte.
|
|
52
|
+
*
|
|
53
|
+
* Throws if the WIF string is invalid or version doesn't match.
|
|
54
|
+
*
|
|
55
|
+
* @param string - The WIF encoded string
|
|
56
|
+
* @param version - Optional expected version byte to validate against
|
|
57
|
+
* @returns The decoded WIF data
|
|
58
|
+
* @throws Error if the WIF string is invalid or version doesn't match
|
|
59
|
+
*/
|
|
60
|
+
export function fromWifStringSync(string: string, version?: number): Wif;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Encode WIF data to a WIF string
|
|
64
|
+
*
|
|
65
|
+
* @param wif - The WIF data to encode
|
|
66
|
+
* @returns The WIF encoded string
|
|
67
|
+
*/
|
|
68
|
+
export function toWifString(wif: Wif): Promise<string>;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Encode WIF data to a WIF string (synchronous)
|
|
72
|
+
*
|
|
73
|
+
* @param wif - The WIF data to encode
|
|
74
|
+
* @returns The WIF encoded string
|
|
75
|
+
*/
|
|
76
|
+
export function toWifStringSync(wif: Wif): string;
|
package/wif.js
CHANGED
|
@@ -6,6 +6,7 @@ import { assertUint8 } from './assert.js'
|
|
|
6
6
|
|
|
7
7
|
function from(arr, expectedVersion) {
|
|
8
8
|
assertUint8(arr)
|
|
9
|
+
if (arr.length !== 33 && arr.length !== 34) throw new Error('Invalid WIF length')
|
|
9
10
|
const version = arr[0]
|
|
10
11
|
if (expectedVersion !== undefined && version !== expectedVersion) {
|
|
11
12
|
throw new Error('Invalid network version')
|
|
@@ -14,7 +15,6 @@ function from(arr, expectedVersion) {
|
|
|
14
15
|
// Makes a copy, regardless of input being a Buffer or a Uint8Array (unlike .slice)
|
|
15
16
|
const privateKey = Uint8Array.from(arr.subarray(1, 33))
|
|
16
17
|
if (arr.length === 33) return { version, privateKey, compressed: false }
|
|
17
|
-
if (arr.length !== 34) throw new Error('Invalid WIF length')
|
|
18
18
|
if (arr[33] !== 1) throw new Error('Invalid compression flag')
|
|
19
19
|
return { version, privateKey, compressed: true }
|
|
20
20
|
}
|
|
@@ -22,7 +22,6 @@ function from(arr, expectedVersion) {
|
|
|
22
22
|
function to({ version: v, privateKey, compressed }) {
|
|
23
23
|
if (!Number.isSafeInteger(v) || v < 0 || v > 0xff) throw new Error('Missing or invalid version')
|
|
24
24
|
assertUint8(privateKey, { length: 32, name: 'privateKey' })
|
|
25
|
-
if (privateKey.length !== 32) throw new TypeError('Invalid privateKey length')
|
|
26
25
|
const out = new Uint8Array(compressed ? 34 : 33)
|
|
27
26
|
out[0] = v
|
|
28
27
|
out.set(privateKey, 1)
|