4.2 KiB
base64
(no submodules)
Purpose
Provides pure-TypeScript Base64 encoding and decoding in both standard (RFC
4648 §4) and URL-safe (RFC 4648 §5) variants. Cryptographic output such as
JWT payloads, bearer tokens, and encoded public keys is routinely transmitted
as Base64Url, while storage formats and MIME payloads use standard Base64.
This module implements both without depending on Node.js Buffer or btoa/
atob (which are absent in some edge runtimes), making it safe for all
@suaveplan/universal consumers.
Features
toBase64(bytes)— standard Base64 with=paddingfromBase64(b64)— decode standard Base64; throwsHashErroron malformed inputtoBase64Url(bytes)— URL-safe Base64, no padding,-and_alphabetfromBase64Url(b64url)— decode URL-safe Base64; throwsHashErroron malformed input- Passes RFC 4648 test vectors
- Pure TypeScript — no
Buffer, nobtoa/atob, no Node built-ins
Usage: Basic Example
import { toBase64, fromBase64 } from "@suaveplan/crypto-hash/encoding";
const encoder = new TextEncoder();
const bytes = encoder.encode("hello world");
const b64 = toBase64(bytes);
console.log(b64); // "aGVsbG8gd29ybGQ="
const decoded = fromBase64(b64);
console.log(new TextDecoder().decode(decoded)); // "hello world"
Usage: Advanced Example
import { toBase64Url, fromBase64Url } from "@suaveplan/crypto-hash/encoding";
import { sha256 } from "@suaveplan/crypto-hash/hash";
import { HashError } from "@suaveplan/crypto-hash/errors";
// Build a simple JWT-style header.payload structure
function buildToken(payload: object, sigKey: Uint8Array): string {
const encoder = new TextEncoder();
const header = toBase64Url(encoder.encode(JSON.stringify({ alg: "HS256" })));
const body = toBase64Url(encoder.encode(JSON.stringify(payload)));
return `${header}.${body}`;
}
// Parse and validate a Base64Url segment
function decodeSegment(segment: string): object {
try {
const bytes = fromBase64Url(segment);
return JSON.parse(new TextDecoder().decode(bytes)) as object;
} catch (err) {
if (err instanceof HashError) {
throw new TypeError(`Malformed Base64Url segment: ${err.code}`);
}
throw err;
}
}
const token = buildToken({ sub: "user-123", iat: 1700000000 }, new Uint8Array(32));
console.log(token);
API Reference
toBase64(bytes: Uint8Array): string
Encodes bytes as standard Base64 with = padding.
| Parameter | Type | Description |
|---|---|---|
bytes |
Uint8Array |
Byte sequence to encode |
Returns: Base64 string of length Math.ceil(bytes.length / 3) * 4.
fromBase64(b64: string): Uint8Array
Decodes a standard Base64 string. Padding (=) is optional.
| Parameter | Type | Description |
|---|---|---|
b64 |
string |
Standard Base64 string |
Returns: Decoded Uint8Array.
Throws: HashError("HASH.ENCODING.INVALID_INPUT") if any character is
outside the standard Base64 alphabet. Context: { encoding: "base64", input }.
toBase64Url(bytes: Uint8Array): string
Encodes bytes as URL-safe Base64 without padding. Uses - and _ in place
of + and /.
fromBase64Url(b64url: string): Uint8Array
Decodes a URL-safe Base64 string. + and / characters are rejected.
Throws: HashError("HASH.ENCODING.INVALID_INPUT") on invalid input.
Context: { encoding: "base64url", input }.
Implementation Notes
The encoder uses a 64-character alphabet lookup table and processes three bytes
at a time, producing four output characters per group. The decoder validates
every character code against a 128-entry lookup table before converting, so
malformed input is caught in a single pass rather than producing incorrect
output silently. The table approach avoids repeated indexOf calls and keeps
decoding O(n). Standard and URL-safe alphabets share the same encode/decode
pipeline via the chars and table parameters; buildTable is called once
at module load time and the resulting Uint8Array tables are module-level
constants. No Buffer, btoa, atob, or Node.js built-ins are used.