first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
# `sanitizeKey`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## 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 `IndexedDbError` with `INDEXEDDB.INVALID_KEY` or `INDEXEDDB.KEY_TOO_LONG` and attach the offending key (truncated for `KEY_TOO_LONG`) to the error's `key` discriminant.
## Usage: Basic Example
```ts
import { sanitizeKey } from "@suaveplan/storage-browser-indexeddb/key-sanitizer";
const safe = sanitizeKey("user/42/profile");
console.log(safe); // "user/42/profile"
```
## Usage: Advanced Example
```ts
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` — Returns `key` unchanged when valid. Throws `IndexedDbError(INDEXEDDB.INVALID_KEY)` for non-strings, empty strings, control characters, absolute paths, and `..` segments. Throws `IndexedDbError(INDEXEDDB.KEY_TOO_LONG)` when the key exceeds 1024 characters; the error's `key` discriminant 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.