# `filename-codec` — caller key ↔ OPFS filename _(no submodules)_ ## Purpose OPFS filenames inherit filesystem-level constraints that caller keys must not (case-insensitivity on some platforms, no embedded `/` separator within a single entry name, byte-encoding ambiguity across browsers). This module wraps each key in RFC 4648 base64url over its UTF-8 byte representation, producing OPFS-safe filenames that round-trip every caller key — including unicode, mixed scripts, slashes, and any byte the caller threw at us. Storing the codec as a separate module keeps the algorithm independently testable (property-based round-trip suite) and replaceable (a future hash-addressed mode can plug in without touching `OpfsStorage`). ## Features - RFC 4648 base64url with `+`→`-`, `/`→`_`, padding stripped. - UTF-8 fatal decode rejects malformed byte sequences with a typed `OpfsError`. - Round-trip invariant proven by a `fast-check` property test (200 random inputs). - Output regex: `^[A-Za-z0-9_-]*$` — accepted by every OPFS implementation. - Pure / synchronous / zero workspace dependencies. ## Usage: Basic Example ```ts import { decodeFilename, encodeFilename, } from "@suaveplan/storage-browser-opfs/filename-codec"; const filename = encodeFilename("orders/2026/05.json"); // "b3JkZXJzLzIwMjYvMDUuanNvbg" const original = decodeFilename(filename); // "orders/2026/05.json" ``` ## Usage: Advanced Example ```ts import { decodeFilename, encodeFilename, OPFS_CODES, OpfsError, } from "@suaveplan/storage-browser-opfs"; function listKeysSafely(entries: { name: string }[]): string[] { const out: string[] = []; for (const entry of entries) { try { out.push(decodeFilename(entry.name)); } catch (err) { // Skip entries that aren't ours — a foreign tool may have written // something to the OPFS directory we share. if ( err instanceof OpfsError && err.code === OPFS_CODES.INVALID_KEY ) { continue; } throw err; } } return out; } ``` ## API Reference - `encodeFilename(key: string): string` — converts to base64url-without-padding. - `decodeFilename(filename: string): string` — throws `OpfsError(OPFS.INVALID_KEY)` for malformed base64 or invalid UTF-8. ## Implementation Notes The codec is deliberately byte-identical to the WHATWG spec for base64url to keep filenames stable across runtimes — the same OPFS directory written from Chrome must round-trip from Safari and Firefox. `btoa`/`atob` are universally available in browsers and in Node.js 20+, so no polyfill is needed at runtime. The fatal `TextDecoder` makes the codec self-healing: a foreign tool that writes non-base64 entries to the OPFS directory will be skipped by `decodeFilename`-using callers rather than corrupting their key view.