3.6 KiB
sanitizeKey
(no submodules)
Purpose
The sanitizeKey boundary validates every caller-supplied IndexedDB primary key before it crosses the public API surface of IndexedDbStorage. Strict validation up front prevents two classes of failure: silent corruption from malformed keys (control characters that confuse later debugging tooling, empty strings that masquerade as falsy values), and security issues where attacker-controlled keys could mimic path-traversal patterns even though IndexedDB itself does not interpret slashes. The sanitiser keeps the package's key contract aligned with the sibling @suaveplan/storage-browser-opfs sanitizeKey, so a caller can swap backends behind AbstractStorage without seeing a different validation contract.
Features
- Rejects non-string input, empty strings, and keys longer than 1024 characters (
KEY_TOO_LONG). - Rejects keys with C0 control characters (0x00-0x1F) or DEL (0x7F).
- Rejects POSIX-absolute keys (
/foo) and..traversal segments — defensive guards for callers that later use keys as path-like identifiers. - Returns the validated key unchanged on success — no normalisation surprises.
- All rejections throw
IndexedDbErrorwithINDEXEDDB.INVALID_KEYorINDEXEDDB.KEY_TOO_LONGand attach the offending key (truncated forKEY_TOO_LONG) to the error'skeydiscriminant.
Usage: Basic Example
import { sanitizeKey } from "@suaveplan/storage-browser-indexeddb/key-sanitizer";
const safe = sanitizeKey("user/42/profile");
console.log(safe); // "user/42/profile"
Usage: Advanced Example
import {
INDEXEDDB_CODES,
IndexedDbError,
} from "@suaveplan/storage-browser-indexeddb/error-codes";
import { sanitizeKey } from "@suaveplan/storage-browser-indexeddb/key-sanitizer";
function validateBatch(keys: string[]): { ok: string[]; bad: { key: string; reason: string }[] } {
const ok: string[] = [];
const bad: { key: string; reason: string }[] = [];
for (const key of keys) {
try {
ok.push(sanitizeKey(key));
} catch (err) {
if (err instanceof IndexedDbError && err.code === INDEXEDDB_CODES.INVALID_KEY) {
bad.push({ key, reason: err.message });
} else if (err instanceof IndexedDbError && err.code === INDEXEDDB_CODES.KEY_TOO_LONG) {
bad.push({ key, reason: "too long" });
} else {
throw err;
}
}
}
return { ok, bad };
}
API Reference
sanitizeKey(key: string): string— Returnskeyunchanged when valid. ThrowsIndexedDbError(INDEXEDDB.INVALID_KEY)for non-strings, empty strings, control characters, absolute paths, and..segments. ThrowsIndexedDbError(INDEXEDDB.KEY_TOO_LONG)when the key exceeds 1024 characters; the error'skeydiscriminant carries the first 64 characters followed by an ellipsis so logs don't leak large payloads.
Implementation Notes
The maximum length of 1024 characters is shared with @suaveplan/storage-browser-opfs/key-sanitizer and @suaveplan/storage's own AbstractStorage.validateKey (where the limit is also 1024). Aligning the boundary across backends keeps the public contract predictable. The sanitiser does NOT normalise Windows \ separators to POSIX / (the OPFS sanitiser does) because IndexedDB primary keys are opaque strings — there is no filesystem semantic to enforce — and quiet rewriting would surprise callers that compare keys later. The runtime-level typeof guard is defensive against JavaScript callers that pass non-strings (the TypeScript signature already excludes them at compile time); we preserve the check rather than rely on type erasure alone.