@exodus/bytes 1.0.0-rc.10 → 1.0.0-rc.11

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 CHANGED
@@ -150,6 +150,9 @@ Same as `windows1252toString = createSinglebyteDecoder('windows-1252')`.
150
150
  ##### `toBase58(arr)`
151
151
  ##### `fromBase58(str, format = 'uint8')`
152
152
 
153
+ ##### `toBase58xrp(arr)`
154
+ ##### `fromBase58xrp(str, format = 'uint8')`
155
+
153
156
  ### `@exodus/bytes/base58check.js`
154
157
 
155
158
  ##### `async toBase58check(arr)`
package/base58.js CHANGED
@@ -3,10 +3,10 @@ import { assertUint8 } from './assert.js'
3
3
  import { nativeDecoder, nativeEncoder, isHermes } from './fallback/_utils.js'
4
4
  import { encodeAscii, decodeAscii } from './fallback/latin1.js'
5
5
 
6
- const alphabet = [...'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz']
7
- const codes = new Uint8Array(alphabet.map((x) => x.charCodeAt(0)))
8
- const ZERO = alphabet[0]
9
- const zeroC = codes[0]
6
+ const alphabet58 = [...'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz']
7
+ const alphabetXRP = [...'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz']
8
+ const codes58 = new Uint8Array(alphabet58.map((x) => x.charCodeAt(0)))
9
+ const codesXRP = new Uint8Array(alphabetXRP.map((x) => x.charCodeAt(0)))
10
10
 
11
11
  const _0n = BigInt(0)
12
12
  const _1n = BigInt(1)
@@ -16,17 +16,18 @@ const _58n = BigInt(58)
16
16
  const _0xffffffffn = BigInt(0xff_ff_ff_ff)
17
17
 
18
18
  let table // 15 * 82, diagonal, <1kb
19
- let fromMap
19
+ const fromMaps = new Map()
20
20
 
21
21
  const E_CHAR = 'Invalid character in base58 input'
22
22
 
23
23
  const shouldUseBigIntFrom = isHermes // faster only on Hermes, numbers path beats it on normal engines
24
24
 
25
- export function toBase58(arr) {
25
+ function toBase58core(arr, alphabet, codes) {
26
26
  assertUint8(arr)
27
27
  const length = arr.length
28
28
  if (length === 0) return ''
29
29
 
30
+ const ZERO = alphabet[0]
30
31
  let zeros = 0
31
32
  while (zeros < length && arr[zeros] === 0) zeros++
32
33
 
@@ -120,18 +121,20 @@ export function toBase58(arr) {
120
121
  return ZERO.repeat(zeros) + out
121
122
  }
122
123
 
123
- // TODO: test on 'z'.repeat(from 1 to smth)
124
- export function fromBase58(str, format = 'uint8') {
124
+ function fromBase58core(str, alphabet, codes, format = 'uint8') {
125
125
  if (typeof str !== 'string') throw new TypeError('Input is not a string')
126
126
  const length = str.length
127
127
  if (length === 0) return typedView(new Uint8Array(), format)
128
128
 
129
+ const zeroC = codes[0]
129
130
  let zeros = 0
130
131
  while (zeros < length && str.charCodeAt(zeros) === zeroC) zeros++
131
132
 
133
+ let fromMap = fromMaps.get(alphabet)
132
134
  if (!fromMap) {
133
135
  fromMap = new Int8Array(256).fill(-1)
134
136
  for (let i = 0; i < 58; i++) fromMap[alphabet[i].charCodeAt(0)] = i
137
+ fromMaps.set(alphabet, fromMap)
135
138
  }
136
139
 
137
140
  const size = zeros + (((length - zeros + 1) * 3) >> 2) // 3/4 rounded up, larger than ~0.73 coef to fit everything
@@ -210,3 +213,8 @@ export function fromBase58(str, format = 'uint8') {
210
213
 
211
214
  return typedView(res.slice(at - zeros), format) // slice is faster for small sizes than subarray
212
215
  }
216
+
217
+ export const toBase58 = (arr) => toBase58core(arr, alphabet58, codes58)
218
+ export const fromBase58 = (str, format) => fromBase58core(str, alphabet58, codes58, format)
219
+ export const toBase58xrp = (arr) => toBase58core(arr, alphabetXRP, codesXRP)
220
+ export const fromBase58xrp = (str, format) => fromBase58core(str, alphabetXRP, codesXRP, format)
@@ -1,22 +1,30 @@
1
1
  const { Buffer, TextEncoder, TextDecoder } = globalThis
2
2
  const haveNativeBuffer = Buffer && !Buffer.TYPED_ARRAY_SUPPORT
3
- let isNative = (x) => x && (haveNativeBuffer || `${x}`.includes('[native code]')) // we consider Node.js TextDecoder/TextEncoder native
3
+ export const nativeBuffer = haveNativeBuffer ? Buffer : null
4
+ export const isHermes = Boolean(globalThis.HermesInternal)
5
+ export const isDeno = Boolean(globalThis.Deno)
6
+ export const isLE = new Uint8Array(Uint16Array.of(258).buffer)[0] === 2
7
+
8
+ let isNative = (x) => {
9
+ if (!x) return false
10
+ if (haveNativeBuffer) return true // we consider Node.js TextDecoder/TextEncoder native
11
+ const s = `${x}`
12
+ // See https://github.com/facebook/hermes/pull/1855#issuecomment-3659386410
13
+ return s.includes('[native code]') || s.includes(`[bytecode]`) // Static Hermes has [bytecode] for contrib, which includes TextEncoder/TextDecoder
14
+ }
15
+
4
16
  if (!haveNativeBuffer && isNative(() => {})) isNative = () => false // e.g. XS, we don't want false positives
5
17
 
6
18
  export const nativeEncoder = isNative(TextEncoder) ? new TextEncoder() : null
7
19
  export const nativeDecoder = isNative(TextDecoder)
8
20
  ? new TextDecoder('utf-8', { ignoreBOM: true })
9
21
  : null
10
- export const nativeBuffer = haveNativeBuffer ? Buffer : null
11
- export const isHermes = Boolean(globalThis.HermesInternal)
12
- export const isDeno = Boolean(globalThis.Deno)
13
- export const isLE = new Uint8Array(Uint16Array.of(258).buffer)[0] === 2
14
22
 
15
23
  // Actually windows-1252, compatible with ascii and latin1 decoding
16
24
  // Beware that on non-latin1, i.e. on windows-1252, this is broken in ~all Node.js versions released
17
25
  // in 2025 due to a regression, so we call it Latin1 as it's usable only for that
18
26
  let nativeDecoderLatin1impl = null
19
- if (isNative(TextDecoder)) {
27
+ if (nativeDecoder) {
20
28
  // Not all barebone engines with TextDecoder support something except utf-8, detect
21
29
  try {
22
30
  nativeDecoderLatin1impl = new TextDecoder('latin1', { ignoreBOM: true })
@@ -51,10 +51,7 @@ const fromSource = (x) => {
51
51
  if (x instanceof Uint8Array) return x
52
52
  if (x instanceof ArrayBuffer) return new Uint8Array(x)
53
53
  if (ArrayBuffer.isView(x)) return new Uint8Array(x.buffer, x.byteOffset, x.byteLength)
54
- if (globalThis.SharedArrayBuffer && x instanceof globalThis.SharedArrayBuffer) {
55
- return new Uint8Array(x.buffer, x.byteOffset, x.byteLength)
56
- }
57
-
54
+ if (globalThis.SharedArrayBuffer && x instanceof SharedArrayBuffer) return new Uint8Array(x)
58
55
  throw new TypeError('Argument must be a SharedArrayBuffer, ArrayBuffer or ArrayBufferView')
59
56
  }
60
57
 
@@ -265,15 +262,28 @@ export function legacyHookDecode(input, fallbackEncoding) {
265
262
  const bomEncoding = getBOMEncoding(u8)
266
263
  if (bomEncoding) u8 = u8.subarray(bomEncoding === 'utf-8' ? 3 : 2)
267
264
  const enc = bomEncoding ?? fallbackEncoding ?? 'utf-8' // "the byte order mark is more authoritative than anything else"
265
+
268
266
  if (enc === 'utf-8') return utf8toStringLoose(u8)
269
- if (enc === 'utf-16le') return utf16toStringLoose(u8, 'uint8-le')
270
- if (enc === 'utf-16be') return utf16toStringLoose(u8, 'uint8-be')
271
- if (!Object.hasOwn(labels, enc) || enc === 'replacement') throw new RangeError(E_ENCODING)
267
+ if (enc === 'utf-16le' || enc === 'utf-16be') {
268
+ let suffix = ''
269
+ if (u8.byteLength % 2 !== 0) {
270
+ suffix = replacementChar
271
+ u8 = u8.subarray(0, -1)
272
+ }
273
+
274
+ return utf16toStringLoose(u8, enc === 'utf-16le' ? 'uint8-le' : 'uint8-be') + suffix
275
+ }
276
+
277
+ if (!Object.hasOwn(labels, enc)) throw new RangeError(E_ENCODING)
272
278
 
273
279
  if (multibyteSet.has(enc)) {
274
280
  if (!createMultibyteDecoder) throw new Error(E_MULTI)
275
281
  return createMultibyteDecoder(enc, true)(u8)
276
282
  }
277
283
 
284
+ // https://encoding.spec.whatwg.org/#replacement-decoder
285
+ // On non-streaming non-fatal case, it just replaces any non-empty input with a single replacement char
286
+ if (enc === 'replacement') return input.byteLength > 0 ? replacementChar : ''
287
+
278
288
  return createSinglebyteDecoder(enc, true)(u8)
279
289
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/bytes",
3
- "version": "1.0.0-rc.10",
3
+ "version": "1.0.0-rc.11",
4
4
  "description": "Various operations on Uint8Array data",
5
5
  "scripts": {
6
6
  "lint": "eslint .",
@@ -132,6 +132,7 @@
132
132
  "@types/node": "^22.13.0",
133
133
  "base-x": "^5.0.1",
134
134
  "base32.js": "^0.1.0",
135
+ "base58-js": "^3.0.3",
135
136
  "base64-js": "^1.5.1",
136
137
  "bech32": "^2.0.0",
137
138
  "bs58": "^6.0.0",