Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@suaveplan/i18n-backend-storage - Universal translation backend backed by any AbstractStorage from @suaveplan/storage. Three wire layouts: single-key-per-namespace (default), single-key-per-locale, flat-keys. Pluggable codec, AbortSignal cancellation, OpenTelemetry instrumentation under i18n.backend.storage.*. Zero runtime dependencies on @suaveplan/i18n core.
Summary
Universal translation backend for the @suaveplan/i18n family,
backed by any AbstractStorage implementation from
@suaveplan/storage. Implements the full Backend contract
(read, readMulti, save, lastModified) over three wire
layouts: single-key-per-namespace (default),
single-key-per-locale, and flat-keys. Pluggable codec, optional
AbortSignal cancellation, OpenTelemetry instrumentation under the
i18n.backend.storage.* prefix. Zero runtime dependencies on
@suaveplan/i18n core.
Documentation tree
- backend — (no submodules)
- backend — (no submodules)
- factory — (no submodules)
- factory — (no submodules)
- observability — (no submodules)
- observability — (no submodules)
Why this exists
The Wave 5 modular split lifts each backend out of the
@suaveplan/i18n monolith into its own sibling so consumers can
install only the backends they need. The storage backend is the
canonical persistence layer: pair it with MemoryStorage for tests,
OpfsStorage / IndexedDBStorage for offline-first browser apps,
or S3Storage / GarageStorage / NodeFsStorage /
SqliteStorage for server-tier deployments. Splitting it out also
isolates @suaveplan/storage as a transitive dep — consumers using
only the HTTP or memory backends no longer pull it in.
Install
bun add @suaveplan/i18n-backend-storage @suaveplan/storage
Quick Start
import { storageBackend } from "@suaveplan/i18n-backend-storage";
import { MemoryStorage } from "@suaveplan/storage";
const backend = storageBackend({ storage: new MemoryStorage() });
await backend.save("en", "auth", { login: { title: "Sign in" } });
const record = await backend.read("en", "auth");
// → { login: { title: "Sign in" } }
Modules
| Subpath | Description |
|---|---|
@suaveplan/i18n-backend-storage |
Root barrel — class + factory + types + schemas + observability |
@suaveplan/i18n-backend-storage/backend |
StorageBackend class + defaultCodec |
@suaveplan/i18n-backend-storage/factory |
storageBackend factory function only |
@suaveplan/i18n-backend-storage/schemas |
Zod boundary schemas |
@suaveplan/i18n-backend-storage/observability |
OTel instruments + in-memory state ring |
Modules Documentation
- backend.md —
StorageBackendclass, layouts, codec - factory.md —
storageBackendfactory function - observability.md — OTel instruments + cardinality
Capabilities
| Flag | Value | Notes |
|---|---|---|
canRead |
true |
always |
canReadMulti |
true |
per-layout dispatch |
canSave |
true |
persists into the wrapped storage |
canTrackModification |
true |
consults getMetadata().modifiedAt |
canWatch |
false |
the storage contract has no change feed |
Layouts
single-key-per-namespace(default) — one key per(locale, ns)at<prefix>/<locale>/<namespace>.json. Best for HTTP-CDN-style storages.single-key-per-locale— one key per locale holding the whole namespace map. Best when namespaces are small and read together.flat-keys— one key per leaf string at<prefix>:<locale>:<namespace>:<dotPath>. Best for content- addressed storages with cheap per-leaf delta shipping.
Testing
The package's own tests use the shared runBackendConformance
harness from @suaveplan/i18n-shared/testing so the universal
Backend contract is exercised against a fresh storage backend
per assertion (against all three layouts):
import { runBackendConformance } from "@suaveplan/i18n-shared/testing";
import { StorageBackend } from "@suaveplan/i18n-backend-storage";
import { MemoryStorage } from "@suaveplan/storage";
runBackendConformance("StorageBackend", async () => {
const backend = new StorageBackend({ storage: new MemoryStorage() });
return {
backend,
async seed(locale, namespace, record) {
await backend.save(locale, namespace, record as never);
},
};
});
Versioning
This package is part of the i18n modular-split rollout. Stays at
0.1.0 until the slim core (Wave 6) cuts the family 1.0.0
release. The metric names under i18n.backend.storage.* are part of
the public API contract and will not change without a major bump.
Wave 5 Scope
This package is Wave 5b of the 14-package i18n modular split. It
ships pure additions only — packages/i18n/i18n/src/core/backend/storage/
retains its copy of the backend until Wave 6 deletes it. Both
copies coexist during Wave 5; downstream consumers continue to
import from the monolith and observe no behaviour change.