# 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 `=` padding - `fromBase64(b64)` — decode standard Base64; throws `HashError` on malformed input - `toBase64Url(bytes)` — URL-safe Base64, no padding, `-` and `_` alphabet - `fromBase64Url(b64url)` — decode URL-safe Base64; throws `HashError` on malformed input - Passes RFC 4648 test vectors - Pure TypeScript — no `Buffer`, no `btoa`/`atob`, no Node built-ins ## Usage: Basic Example ```ts 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 ```ts 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.