Skip to content

v1.15.0

Latest

Choose a tag to compare

@ChALkeR ChALkeR released this 04 Mar 07:11
· 1 commit to main since this release
Immutable release. Only release title and notes can be modified.
e20c47f
  • feat: isomorphicDecode(), isomorphicEncode() in /encoding.js (in #68)
  • doc: deprecate latin1toString() / latin1fromString() in favor of isomorphicDecode() / isomorphicEncode() (see #55)
  • feat: fromBase32crockford / toBase32crockford in /base32.js
  • feat: typedCopyBytes() in /array.js
  • feat: add 'arraybuffer' output format support in methods accepting format parameter (in #70)
  • feat: 'uint8' (default) output format now never returns pooled Uint8Array instances (see below)

This release brings support of native ArrayBuffer return format (under the name of format: 'arraybuffer').

Converting Uint8Array to ArrayBuffer downstream is non-trivial, and there is a lot of confusion in the ecosystem around those.
A simple access to .buffer is often seen and is incorrect -- code accepting Uint8Arrays that it didn't create should not assume that it did not receive for example a result of .subarray() (where .buffer size mismatches the view size), or a Node.js pooled Buffer instance (which are also Uint8Arrays).

That pattern (using .buffer and failing to check bounds) has been a source of numerous errors in ecosystem libraries.

To minimize the risks from such mistakes, this library now never returns Uint8Array instances (default format) that are not complete views of their underlying ArrayBuffer.

In other words, now the following are true for a returned Uint8Array instance u8:

  • u8.buffer.byteLength === u8.byteLength
  • u8.byteOffset === 0
  • deepStrictEqual(new Uint8Array(u8.buffer), u8)

The affected parts (which previously returned non-complete views / subarrays) are:

  1. On multiple platforms: fromBase58Check, createMultibyteEncoder, createSinglebyteEncoder
  2. On Node.js import condition only (any Node.js version): latin1fromString, utf8fromString, utf16fromString
  3. On Node.js import condition with Node.js < 25: fromHex, fromBase64

This comes at a reasonable performance cost (almost exclusively on Node.js import condition), but correctness/security comes first.

Note

This change doesn't affect TextEncoder, which is already governed by the Encoding Standard which demands non-pooled Uint8Arrays.

This also doesn't affect typedView() (from /array.js) which by definition is always a view of the same underlying ArrayBuffer data.
But now typedCopyBytes() is introduced.

Important

This change does not affect 'buffer' return format, which can still return pooled Buffer instances.
This is similar to the behavior of native Buffer.from / Buffer.alloc which are pooled.

Apart from making returned Uint8Array instances complete views, a dedicated ArrayBuffer return format is introduced to eliminate the need to use .buffer on the returned values in downstream code at all (as it's a bad pattern in general and tooling/lint will/should flag that).

Full Changelog: v1.14.1...v1.15.0