Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ Base64 utilities provide a simple interface to encode and decode data in base64

### Encoding

Encode data in base64 format. Input can be a string, `ArrayBuffer`, or `TypedArray`.
Encode data in base64 format. Input can be a string, `ArrayBuffer`, or number-based `TypedArray`. BigInt typed arrays are not supported.

```ts
import { base64 } from "@better-auth/utils/base64";
Expand Down Expand Up @@ -343,7 +343,7 @@ Hex utilities provide a simple interface to encode and decode data in hexadecima

### Encoding

Encode data in hexadecimal format. Input can be a string, `ArrayBuffer`, or `TypedArray`.
Encode data in hexadecimal format. Input can be a string, `ArrayBuffer`, or number-based `TypedArray`. BigInt typed arrays are not supported.

```ts
import { hex } from "@better-auth/utils/hex";
Expand Down
10 changes: 5 additions & 5 deletions src/base32.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//inspired by oslo implementation by pilcrowonpaper: https://github.com/pilcrowonpaper/oslo/blob/main/src/encoding/base32.ts

import type { TypedArray, Uint8Array_ } from "./type";
import type { NumberTypedArray, TypedArray, Uint8Array_ } from "./type";
import { toUint8Array } from "./bytes";

/**
Expand Down Expand Up @@ -100,12 +100,12 @@ function base32Decode(data: string, alphabet: string): Uint8Array_ {
export const base32 = {
/**
* Encodes data into a Base32 string.
* @param data - The data to encode (ArrayBuffer, TypedArray, or string).
* @param data - The data to encode (ArrayBuffer, number-based TypedArray, or string).
* @param options - Encoding options.
* @returns The Base32 encoded string.
*/
encode(
data: ArrayBuffer | TypedArray | string,
data: ArrayBuffer | NumberTypedArray | string,
options: { padding?: boolean } = {},
): string {
const alphabet = getAlphabet(false);
Expand Down Expand Up @@ -133,12 +133,12 @@ export const base32 = {
export const base32hex = {
/**
* Encodes data into a Base32hex string.
* @param data - The data to encode (ArrayBuffer, TypedArray, or string).
* @param data - The data to encode (ArrayBuffer, number-based TypedArray, or string).
* @param options - Encoding options.
* @returns The Base32hex encoded string.
*/
encode(
data: ArrayBuffer | TypedArray | string,
data: ArrayBuffer | NumberTypedArray | string,
options: { padding?: boolean } = {},
): string {
const alphabet = getAlphabet(true);
Expand Down
6 changes: 3 additions & 3 deletions src/base64.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//inspired by oslo implementation by pilcrowonpaper: https://github.com/pilcrowonpaper/oslo/blob/main/src/encoding/base64.ts

import type { TypedArray, Uint8Array_ } from "./type";
import type { NumberTypedArray, TypedArray, Uint8Array_ } from "./type";
import { toUint8Array } from "./bytes";

function getAlphabet(urlSafe: boolean): string {
Expand Down Expand Up @@ -68,7 +68,7 @@ function base64Decode(data: string, alphabet: string): Uint8Array_ {

export const base64 = {
encode(
data: ArrayBuffer | TypedArray | string,
data: ArrayBuffer | NumberTypedArray | string,
options: { padding?: boolean } = {},
) {
const alphabet = getAlphabet(false);
Expand All @@ -87,7 +87,7 @@ export const base64 = {

export const base64Url = {
encode(
data: ArrayBuffer | TypedArray | string,
data: ArrayBuffer | NumberTypedArray | string,
options: { padding?: boolean } = {},
) {
const alphabet = getAlphabet(true);
Expand Down
15 changes: 14 additions & 1 deletion src/bytes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ describe("bytes", () => {
expect(toBufferSource(input)).toBe(input);
});

it("reuses ArrayBuffer-backed BigInt views", () => {
const input = new BigUint64Array([1n]);

expect(toBufferSource(input)).toBe(input);
});

it("copies SharedArrayBuffer-backed views", () => {
const buffer = new SharedArrayBuffer(4);
const input = new Uint8Array(buffer, 1, 2);
Expand Down Expand Up @@ -42,13 +48,20 @@ describe("bytes", () => {
});

describe("toUint8Array", () => {
it("accepts clamped typed arrays", () => {
const input = new Uint8ClampedArray([0, 255]);

expect(Array.from(toUint8Array(input))).toEqual([0, 255]);
});

it("preserves element conversion for multi-byte typed arrays", () => {
const input = new Uint16Array([256, 1]);

expect(Array.from(toUint8Array(input))).toEqual([0, 1]);
});

it("preserves errors for BigInt typed arrays", () => {
it("rejects BigInt typed arrays", () => {
// @ts-expect-error BigInt typed arrays do not contain number elements.
expect(() => toUint8Array(new BigUint64Array([1n]))).toThrow(TypeError);
});
});
Expand Down
8 changes: 4 additions & 4 deletions src/bytes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { TypedArray, Uint8Array_ } from "./type";
import type { NumberTypedArray, Uint8Array_ } from "./type";

export function toBufferSource(
data: string | ArrayBuffer | ArrayBufferView,
Expand All @@ -18,14 +18,14 @@ export function toBufferSource(
/**
* Converts strings and binary data into a `Uint8Array`.
*
* `ArrayBuffer` inputs share memory with the returned view, while `TypedArray`
* inputs are copied according to native constructor semantics.
* `ArrayBuffer` inputs share memory with the returned view, while number-based
* `TypedArray` inputs are copied according to native constructor semantics.
*
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#buffer | ArrayBuffer constructor behavior}
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#typedarray | TypedArray constructor behavior}
*/
export function toUint8Array(
data: string | ArrayBuffer | TypedArray,
data: string | ArrayBuffer | NumberTypedArray,
): Uint8Array_ {
if (typeof data === "string") {
return new TextEncoder().encode(data);
Expand Down
4 changes: 2 additions & 2 deletions src/hex.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { hexToBytes } from "@noble/hashes/utils.js";
import type { TypedArray, Uint8Array_ } from "./type";
import { toUint8Array } from "./bytes";
import type { NumberTypedArray, TypedArray, Uint8Array_ } from "./type";

const toBytes = (data: string): Uint8Array_ => hexToBytes(data) as Uint8Array_;

export const hex = {
encode: (data: string | ArrayBuffer | TypedArray) => {
encode: (data: string | ArrayBuffer | NumberTypedArray) => {
const buffer = toUint8Array(data);
if (buffer.byteLength === 0) {
return "";
Expand Down
9 changes: 5 additions & 4 deletions src/type.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
export type TypedArray =
export type NumberTypedArray =
| Uint8Array
| Uint8ClampedArray
| Int8Array
| Uint16Array
| Int16Array
| Uint32Array
| Int32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array;
| Float64Array;

export type TypedArray = NumberTypedArray | BigInt64Array | BigUint64Array;

/**
* Equivalent to `Uint8Array` before TypeScript 5.7, and `Uint8Array<ArrayBuffer>` in TypeScript 5.7
Expand Down