All notable changes to this project are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
OpenFetch (@hamdymohamedak/openfetch) is a small, dependency-free HTTP client for any JavaScript runtime that provides the standard fetch API (Node 18+, Bun, Deno, Cloudflare Workers, browsers). It focuses on a single transport layer, no legacy browser-only globals (window, document, localStorage), so it stays SSR- and React Server Component–friendly.
Core surface: default export and createClient() / create() instances with baseURL, query params, headers, timeout, signal, body helpers, responseType, validateStatus, request/response interceptors, and async middleware wrapping the fetch adapter.
Built-in capabilities: OpenFetchError with structured shapes, createRetryMiddleware() (backoff, total/per-attempt timeouts, idempotency key helpers for retried POSTs), MemoryCacheStore and createCacheMiddleware() (TTL, optional stale-while-revalidate).
Optional entry points (tree-shaking):
@hamdymohamedak/openfetch/plugins—retry(),timeout(),hooks(),debug()(e.g. masked headers in logs),strictFetch().@hamdymohamedak/openfetch/sugar—createFluentClient(): URL + method chaining (.get(),.post(), …), terminals like.json(),.text(),.send(),.raw()(nativeResponsewithout adapter body parsing on that path), and.memo()(one HTTP round-trip; body buffered once for multiple terminals—not HTTP cache).
For a feature matrix, examples, and execution order (middleware vs retry vs interceptors), see the README.
OpenFetchError.toShape()/toJSON()— Responsedataandheadersare omitted unless you passincludeResponseData: true/includeResponseHeaders: true.createCacheMiddleware— Cache keys always foldauthorizationandcookieunlessvaryHeaderNamesis explicitly[]. ExtravaryHeaderNamesentries are merged with those two. The one-timeconsole.warnnow applies only whenvaryHeaderNames: []is explicit with auth/cookie and no customkey.
assertSafeUrlonOpenFetchConfig— When true, runsassertSafeHttpUrlon the fully resolved URL beforefetch(e.g.createClient({ assertSafeUrl: true })).
rawResponse/ fluent.raw()— Returns the nativefetchResponseasdatawithout reading the body in the adapter; skipstransformRequest/parseBody/transformResponseon that path. Client response interceptors still run (datais theResponse). Documented in types and README.createFluentClient()(@hamdymohamedak/openfetch/sugar) — Callable URL + method chaining (.get(),.post(), …); terminal methods (.json(),.text(),.send(),.raw(), …) each start a request unless.memo()is used..memo()— Request-level memoization: one HTTP round-trip; body buffered once asArrayBuffer; subsequent terminals reuse it (not HTTP caching).- Subpath exports —
package.jsonexports:"./plugins"and"./sugar"for tree-shaking. - Plugins (
@hamdymohamedak/openfetch/plugins) —retry(),timeout(),hooks(),debug(),strictFetch()wrappingcreateRetryMiddlewareand related behavior. - Retry middleware —
retry.timeoutTotalMswith monotonic timing (performance.now()when available);enforceTotalTimeoutmerges deadline intosignalper attempt;retry.timeoutPerAttemptMsoverrides per-attempttimeout; externalsignalabort stops the loop and short-circuits backoff;retry.autoIdempotencyKey/ stableIdempotency-Keyfor POST when retrying non-idempotent methods;clearTimeoutindispatchfinallyfor per-attempt timers. - Helpers —
generateIdempotencyKey,hasIdempotencyKeyHeader,ensureIdempotencyKeyHeader;maskHeaderValueswith strategiesfull,partial(e.g.Bearer ****abcd),hash(short fingerprint);cloneResponsefor multiple body reads. - Debug plugin —
maskStrategy,maskPartialTailLength(tail-only impliespartial); optional masked request headers in logs. - Example —
examples/plugins-fluent.example.ts. - Tests —
npm test: Node built-in runner; masking,cloneResponse, fluent memo, middleware order vs retry, hooks placement, abort during backoff / pre-start, retry withtimeoutPerAttemptMs. - Security tests — Expanded
security-tests/run.mjscoverage. - Documentation — README: execution model (middleware order, retry loop, terminals,
rawResponsesemantics), fluent/memo/debug/masking notes; SECURITY.md updates.
dispatch—rawResponseearly return path; timeout cleanup infinally.OpenFetchRetryOptions/ types — Extended retry andrawResponsedocumentation.
ERR_CANCELEDfrom a per-attempt timeout is not retried (same as user abort).- Published package
filesincludeCHANGELOG.mdfrom this release onward.