first commit
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# base64
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## 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.
|
||||
Reference in New Issue
Block a user