# `HttpBackend` _(no submodules)_ ## Purpose `HttpBackend` is the canonical browser-tier translation source for the `@suaveplan/i18n` family. It fetches `` per `(locale, namespace)` via an injectable `fetchFn` (defaulting to `globalThis.fetch`) and parses the response body via an injectable `parsePayload` (defaulting to a JSON-object parser that rejects arrays, null, and primitive payloads). HTTP 404 maps to `BACKEND_LOCALE_NOT_AVAILABLE` — the chained-backend fallthrough signal — while HTTP 5xx, network failures, and parse failures map to `BACKEND_READ_FAILED`, the chain-stopping signal that prevents silent degradation when the transport itself is broken. The backend is read-only by design (`canSave: false`, `canTrackModification: false`, `canWatch: false`). Consumers needing write-back wire `MultiFileFsBackend` or `StorageBackend` behind the catalog instead. Universal — runs identically in browsers, Bun, and Node.js >= 18; older Node runtimes get a clear `BACKEND_READ_FAILED` from `defaultFetch()` instructing them to inject `fetchFn`. ## Features - 5-flag capability matrix `{ canRead: true, canReadMulti: false, canSave: false, canTrackModification: false, canWatch: false }`. - URL templating via `{locale}` / `{namespace}` placeholders with `encodeURIComponent` per segment. - Pluggable `parsePayload` accepts non-JSON bodies (YAML, MessagePack, schema-validated JSON). - Pluggable `customHeaders` builder per request. - `crossDomain: true` shorthand for `credentials: "include"` + `mode: "cors"` (preserves explicit overrides in `requestOptions`). - Optional `retry?: HttpBackendRetry` (structurally compatible with `@suaveplan/retry`'s `RetryPolicy`) wraps every fetch. - Optional `signal?: AbortSignal` — pre-aborted signals throw `BACKEND_TIMEOUT` without issuing a network request; mid-flight AbortError surfaces as `BACKEND_TIMEOUT`; the signal is threaded into the underlying `RequestInit` so `fetch` can cancel mid-flight. - Zod boundary validation throws `INVALID_OPTIONS` at construction. - Per-call OTel instrumentation under `i18n.backend.http.*`. ## Usage: Basic Example ```ts import { HttpBackend } from "@suaveplan/i18n-backend-http"; const backend = new HttpBackend({ loadPath: "/i18n/{locale}/{namespace}.json", }); const record = await backend.read("en", "auth"); ``` ## Usage: Advanced Example ```ts import { HttpBackend } from "@suaveplan/i18n-backend-http"; const backend = new HttpBackend({ loadPath: "/i18n/{locale}/{namespace}.yaml", crossDomain: true, customHeaders: (locale) => ({ "x-locale": locale }), parsePayload: async (res) => parseYaml(await res.text()), retry: { run: async (op) => { for (let i = 0; i < 3; i++) { try { return await op(); } catch (err) { if (i === 2) throw err; } } throw new Error("unreachable"); }, }, }); const ctrl = new AbortController(); setTimeout(() => ctrl.abort(), 2_000); const record = await backend.read("en", "auth", ctrl.signal); ``` ## API Reference ### `class HttpBackend implements Backend` - `new HttpBackend(options: HttpBackendOptions)` — Zod-validated; throws `I18nError(I18N.INVALID_OPTIONS)` on malformed input. - `read(locale, namespace, signal?): Promise` — fetches and parses the URL. Throws `BACKEND_LOCALE_NOT_AVAILABLE` on 404; `BACKEND_READ_FAILED` on 5xx / network / parse failures; `BACKEND_TIMEOUT` on signal abort. ### Helpers - `buildUrl(loadPath, locale, namespace): string` — substitutes `{locale}` and `{namespace}` with `encodeURIComponent`-applied values. - `defaultParsePayload: ParsePayloadFn` — JSON object parser. Rejects arrays, null, and primitives as `BACKEND_READ_FAILED`. - `HttpBackendOptionsSchema: z.ZodObject` — Zod boundary schema. ## Implementation Notes The class delegates to a private `#fetchOnce` helper that classifies network failures: `AbortError` / `ABORT_ERR` codes surface as `BACKEND_TIMEOUT` (so consumers can distinguish cancellation from transport faults), and `I18nError(I18N.BACKEND_TIMEOUT)` thrown from inside `fetchFn` (e.g. an injected fake) propagates unchanged. Everything else from the network surface — `TypeError`, refused connections, DNS failures, CORS preflights — maps to `BACKEND_READ_FAILED`. Capability flags stay `false` for write paths because the HTTP transport has no canonical `PUT` semantics across CDNs; consumers needing write-back wire a different backend.