# StormFetch

**Typed HTTP client for React, React Native, Expo, browsers, Node.js, and SSR.**

StormFetch provides one TypeScript API for web and mobile applications without adding a runtime dependency. It includes typed requests, interceptors, retries, caching, request deduplication, cancellation, uploads, downloads, React hooks, runtime-aware adapters, plugins, and normalized errors.

[![npm version](https://img.shields.io/npm/v/stormfetch?style=for-the-badge&logo=npm&color=CB3837)](https://www.npmjs.com/package/stormfetch)
[![npm downloads](https://img.shields.io/npm/dm/stormfetch?style=for-the-badge&logo=npm&color=0EA5E9)](https://www.npmjs.com/package/stormfetch)
[![license](https://img.shields.io/npm/l/stormfetch?style=for-the-badge&color=22C55E)](./LICENSE)
[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-3178C6?style=for-the-badge&logo=typescript)](https://unpkg.com/stormfetch@latest/docs/index.html#api-reference)
[![runtime dependencies](https://img.shields.io/badge/runtime_dependencies-0-7C3AED?style=for-the-badge)](https://unpkg.com/stormfetch@latest/docs/index.html#features)
[![Node](https://img.shields.io/badge/Node.js-18%2B-339933?style=for-the-badge&logo=node.js)](https://nodejs.org/)

> ┌────────────────────────────────────────────────────────────────────┐  
> **📘 LEARN HERE — FRESHER-FRIENDLY FUNCTION LESSONS**  
> Learn every public function with syntax, parameter tables, return values, examples, expected output, errors, and real use cases.  
> **[Open Attractive HTML Learning Center →](https://unpkg.com/stormfetch@latest/docs/index.html)** · **[Functions →](https://unpkg.com/stormfetch@latest/docs/index.html#functions)** · **[API Reference →](https://unpkg.com/stormfetch@latest/docs/index.html#api-reference)** · **[Support →](https://unpkg.com/stormfetch@latest/docs/index.html#support)**  
> └────────────────────────────────────────────────────────────────────┘

### 🧭 Quick navigation

[Install](#installation) · [5-minute quickstart](#quick-start-reactjs) · [Which function should I use?](#function-selection-guide) · [Complete features](#complete-feature-inventory) · [Today’s upgrade](#features-added-in-todays-advanced-upgrade) · [Security](#security-capabilities) · [React Native](#quick-start-react-native--expo) · [Errors](#errors) · [Questionnaire](#questions-freshers-ask) · [Publishing](#development-and-publishing)

| Official package identity | Details |
| --- | --- |
| Version | `1.16.3` |
| Developer | **Pradeep Kumar Sheoran (Stack Developer)** |
| Company | **BSG Technologies** |
| Contact | **+91-8595147850 (Also WhatsApp)** |
| Official website | **[🌐 Visit BSG Technologies — meet, learn, contribute, discuss new topics, or accept a coffee invitation](https://bsgtechnologies.com)** |
| Code signature | `STORMFETCH_PACKAGE_INFO.signature` |

## 📘 Learn Here on npm: your first request

### `createStormFetchClient(options?)` + `get(url, config?)`

**Description:** Create one reusable API client, then use `get` whenever the server should give you data.

**Syntax**

```ts
const api = createStormFetchClient(options);
const response = await api.get<TData>(url, config);
```

| Function parameter | Type | Required? | Easy meaning |
| --- | --- | --- | --- |
| `options` | `FastApiClientOptions` | No | Shared base URL, timeout, auth, retry, cache, and security |
| `url` | `string` | Yes | API path such as `/users` |
| `config` | `FastApiRequestConfig` | No | Params, headers, timeout, cache, retry, signal, response type |

**Return value:** `get` returns `Promise<FastApiResponse<TData>>`. Read API data from `response.data`.

```ts
import { createStormFetchClient, isStormFetchError } from 'stormfetch';

const api = createStormFetchClient({
  baseURL: 'https://api.example.com',
  timeout: 10_000,
});

try {
  const response = await api.get<{ id: number; name: string }>('/users/1');
  console.log(response.status, response.data.name);
} catch (error) {
  if (isStormFetchError(error)) console.log(error.code, error.requestId);
}
```

**Expected output**

```text
200 Asha
```

**Possible errors:** timeout, cancellation, network/DNS failure, rejected HTTP status, blocked security policy, invalid response, or body-size limit.

**Use cases:** profile pages, product lists, dashboards, application settings, search results.

Continue in the **[attractive HTML Learning Center](https://unpkg.com/stormfetch@latest/docs/index.html#functions)**, where functions are searchable and grouped by task.

## Why StormFetch?

- One client for ReactJS, React Native, Expo, Node.js, Deno, Bun, and SSR.
- Strong request body and response typing.
- No React, React Native, or UI library dependency.
- Fetch, browser XHR, Node HTTP/1.1, and Node HTTP/2 adapters.
- Dedicated `stormfetch/react-native` entry point.
- Auth, refresh-token, language, retry, cache, offline queue, and plugin support.
- Security policy layer for host allowlists, blocked hosts, HTTPS enforcement, private-network blocking, method allowlists, XSRF origin checks, request signing, and redacted debug exports.
- Tree-shakeable ESM plus CommonJS and TypeScript declarations.
- Durable offline mutations, dependency-free OpenTelemetry bridge, native background-transfer contracts, generated SDK CLI, and embeddable DevTools.
- Complete npm learning bundle: boxed Learn Here lessons, separate function directory, API reference, enterprise feature inventory, migration guide, and security documents.

## Installation

```bash
npm install stormfetch
```

## Compatibility

| Runtime | Import | Automatic adapter | Notes |
| --- | --- | --- | --- |
| ReactJS / browser | `stormfetch` | Fetch; XHR when progress is requested | Browser download and persistent web storage supported |
| React Native / Expo | `stormfetch/react-native` | Fetch | Native files, online state, and persistence use injected app adapters |
| Node.js 18+ | `stormfetch` | Node HTTP/HTTPS | Native FormData, proxy, streams, redirects, progress, and size controls supported |
| Node.js HTTP/2 | `stormfetch` | `adapter: 'http2'` | Uses Node's built-in `node:http2` client |
| Deno | `stormfetch` | Fetch | Official fetch-adapter runtime path |
| Bun | `stormfetch` | Fetch | Official fetch-adapter runtime path |
| SSR | `stormfetch` | Runtime-selected | Browser globals are guarded |

React is not bundled. `createStormFetchHooks` receives your installed React object, so the same hook factory works with React DOM and React Native.

### Focused entry points

Use the smallest public surface for each job. The root entry remains backward compatible.

| Job | Import |
| --- | --- |
| HTTP client and shared types | `stormfetch/core` |
| React hooks | `stormfetch/react` |
| Node HTTP/1.1 and HTTP/2 | `stormfetch/node` |
| DOM extraction and downloads | `stormfetch/dom` |
| Mock server and adapter | `stormfetch/mock` |
| Security plugins | `stormfetch/security` |
| OpenAPI generator | `stormfetch/openapi` |
| Metrics and tracing | `stormfetch/observability` |
| Request inspector | `stormfetch/devtools` |

## Quick Start: ReactJS

```ts
// api.ts
import { createStormFetchClient } from 'stormfetch';

export const api = createStormFetchClient({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 30_000,
  token: () => localStorage.getItem('accessToken'),
  language: () => localStorage.getItem('language') ?? 'en',
  onUnauthorized: () => {
    localStorage.removeItem('accessToken');
    window.location.assign('/login');
  },
});
```

```ts
interface User {
  id: number;
  name: string;
}

const response = await api.get<User[]>('/users', {
  params: { page: 1, active: true },
  cache: true,
  cacheTTL: 60_000,
});

console.log(response.data);
```

## Quick Start: React Native / Expo

```ts
// api.ts
import { createReactNativeStormFetchClient } from 'stormfetch/react-native';

export const api = createReactNativeStormFetchClient({
  baseURL: 'https://api.example.com',
  timeout: 30_000,
  token: async () => getAccessTokenFromSecureStorage(),
  isOnline: async () => getCurrentNetworkState(),
  onUnauthorized: () => navigateToLogin(),
  fileSaver: async (blob, fileName) => {
    await saveWithYourNativeFileSystem(blob, fileName);
  },
});
```

The native factory pins automatic requests to `fetch`. This prevents a React Native `process` shim from being mistaken for Node.js.

## React and React Native Hooks

```tsx
import * as React from 'react';
import { createStormFetchHooks } from 'stormfetch';
import { api } from './api';

const { useStormQuery, useLazyStormQuery, useStormMutation, useStormInfiniteQuery } =
  createStormFetchHooks(React, api);

export function UsersScreen() {
  const users = useStormQuery<User[]>('/users');
  const createUser = useStormMutation<User, { name: string }>('/users', 'post', {
    invalidateTags: ['users'],
  });

  if (users.loading) return null;

  return (
    <button onClick={() => createUser.mutate({ name: 'Pradeep' })}>
      Create user
    </button>
  );
}
```

Replace the JSX with `View`, `Text`, and `Pressable` in React Native; the hook setup remains the same.

## Client Methods at a Glance

| Method | What it does | Typical use |
| --- | --- | --- |
| `request(config)` | Sends any supported HTTP method | Dynamic or shared request builders |
| `fetch(url, config?)` | Fetch-like universal request | One familiar method for any API |
| `get(url, config?)` | Reads data | Lists, details, search |
| `post(url, data?, config?)` | Creates or triggers data | Forms, login, commands |
| `put(url, data?, config?)` | Fully replaces data | Full record update |
| `patch(url, data?, config?)` | Partially updates data | Edit one or more fields |
| `delete(url, config?)` | Deletes data | Record removal |
| `head(url, config?)` | Reads headers only | File/auth/CDN checks |
| `options(url, config?)` | Reads server capabilities | CORS/method discovery |
| `query(url, data?, config?)` | Sends an HTTP QUERY request | Safe/idempotent query bodies |
| `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`, `QUERY` | Uppercase aliases | HTTP-style SDKs |
| `postJson(url, data)` | Posts JSON explicitly | APIs that require JSON headers |
| `postForm(url, data)` | Posts URL encoded form data | OAuth, login, legacy APIs |
| `postMultipart(url, data)` | Posts multipart form data | Uploads |
| `graphql(query, variables?, config?)` | Sends a GraphQL operation | GraphQL APIs |
| `batch(requests)` | Runs many requests together | Dashboards, bootstrapping |
| `poll(url, options)` | Repeats a GET until stopped | Job/payment/order status |
| `getHtml`, `getXml`, `getDom`, `scrape` | Fetch and parse content | HTML/XML pages, feeds, scraping |
| `resource(basePath)` | Creates CRUD helpers | REST resources |
| `cacheManager` | Prefetch, hydrate, dehydrate, inspect keys | Smart app cache |
| `history`, `replay`, `toCurl`, `toHAR` | Debug and reproduce requests | DevTools-style workflows |
| `policy(match, config)` | Applies request defaults by route | Payments/admin/API rules |
| `streamText`, `streamJson`, `streamNdjson`, `sse` | Reads streaming APIs | AI, logs, live events |
| `contract(definition)` | Builds typed service functions | SDK-like API layer |
| `download(url, name?, config?)` | Fetches a Blob and optionally saves it | Reports, invoices, exports |
| `createFormData(data)` | Builds multipart data | Images, documents, mixed fields |
| `clearCache(key?)` | Clears all or matching cache entries | Logout, refresh, invalidation |
| `clearCacheAsync(key?)` | Clears cache and awaits async storage | AsyncStorage/MMKV wrappers |
| `invalidateTags(tags)` | Clears tagged cache entries | Mutation-driven refresh |
| `flushOfflineQueue()` | Runs queued requests | Reconnect handling |

Complete signatures and exported helpers are available in the [visual API Reference](https://unpkg.com/stormfetch@latest/docs/index.html#api-reference). Native setup and limitations are presented in the [runtime guide](https://unpkg.com/stormfetch@latest/docs/index.html#runtimes).

## Function Selection Guide

Use this table when you know the job but not the StormFetch function name.

| User goal | Use these functions/options | What to configure |
| --- | --- | --- |
| Build one shared API client | `createStormFetchClient` | `baseURL`, `timeout`, `token`, retry, cache, plugins, `security` |
| Build a mobile API client | `createReactNativeStormFetchClient` | async `token`, `isOnline`, `fileSaver`, async cache storage |
| Build an SSR/server API client | `createStormFetchServerClient` | incoming headers/cookies, server `baseURL`, Node transport options |
| Add typed routes | `createTypedStormFetchClient`, `contract` | endpoint map or contract definition with response/body types |
| Read API data | `get`, `GET`, `fetch` | `params`, `cache`, `cacheTTL`, `cacheTags`, `dedupe` |
| Write API data | `post`, `put`, `patch`, `delete` | body data, `invalidateTags`, schema validators, retry policy |
| Upload files | `createFormData`, `postMultipart`, `createReactNativeFile` | browser `File`/`Blob` or React Native `{ uri, name, type }` |
| Download files | `download`, `saveBlob`, native `fileSaver` | `responseType: 'blob'`, file name, native saver for mobile |
| Call GraphQL | `graphql` | query string, variables, endpoint override if needed |
| Load many endpoints together | `batch` | array of request configs; responses keep the same order |
| Track long-running jobs | `poll` | interval, stop condition, timeout/cancel signal |
| Generate CRUD helpers | `resource` | base path such as `/users` |
| Cache and preload screens | `cacheManager.prefetch`, `dehydrateCache`, `hydrateCache` | cache TTL, stale time, tags, SSR snapshot |
| Clear stale data after mutation | `invalidateTags`, `clearCache`, `clearCacheAsync` | tag names or cache key prefix |
| Add React state hooks | `createStormFetchHooks` | pass your React object and configured client |
| Debug a production issue | `history`, `replay`, `toCurl`, `toHAR`, `subscribe` | keep redaction enabled; attach request ID to support logs |
| Add route-specific rules | `policy` | matcher plus timeout/retry/cache/security defaults |
| Protect failing backends | `circuitBreaker` | threshold, cooldown, fallback response |
| Read streaming responses | `streamText`, `streamJson`, `streamNdjson`, `sse` | stream parser, event handlers, cancel signal |
| Parse websites or feeds | `getHtml`, `getXml`, `getDom`, `scrape` | CSS selectors or custom DOM parser |
| Mock APIs in tests | `createMockAdapter`, `createMockServer` | routes, scenarios, delays, errors, request assertions |
| Harden request safety | `security`, `hmacSigningPlugin`, `secureLoggerPlugin` | host/CIDR policy, HTTPS, credential forwarding, signing |
| Use Node HTTP/2 | `adapter: 'http2'` | Node runtime and an HTTP/2-capable server |
| Use Deno or Bun | automatic fetch adapter | import from `stormfetch`; runtime is detected automatically |

## Complete Feature Inventory

This is the full old and new capability list that npm users can scan quickly.

| Group | Features included |
| --- | --- |
| Core HTTP | `request`, `fetch`, lowercase methods, uppercase method aliases, JSON/form/multipart helpers, GraphQL, batch, polling |
| Typed SDK building | typed endpoint maps, `resource`, `contract`, OpenAPI service generator, schema validation hooks |
| Runtime support | ReactJS, React Native, Expo, browser, SSR, Node.js, Deno, Bun |
| Adapters | Fetch, XHR, Node HTTP/1.1, Node HTTP/2, mock adapter, custom adapters |
| React usage | query hook, lazy query hook, mutation hook, infinite query hook, optimistic mutation helpers |
| Mobile usage | React Native entry point, async token provider, online-state hook, native file descriptor, injected file saver |
| Cache | memory/local/custom/async cache, TTL, stale refresh, tags, prefetch, hydrate, dehydrate, cache key inspection |
| Reliability | timeout, cancellation, retries, safe retry policy, dedupe, priority queue, concurrency limits, offline queue, circuit breaker |
| Debugging | request IDs, duration, request history, replay, curl export, HAR export, structured events |
| Content tools | HTML/XML fetch, DOM parsing, scraping, metadata extraction, link/image/json-ld extraction |
| Streaming | text stream, JSON stream, NDJSON stream, Server-Sent Events |
| Upload/download | browser and Node FormData, React Native file object, multipart upload, Blob download, native save callback |
| Security | XSRF, auth helpers, host allow/block, CIDR/DNS checks, private-network blocking, metadata blocking, HTTPS guard, path traversal guard |
| Advanced security | credential forwarding policy, redirect credential stripping, no-proxy normalization, JSON/query caps, decompression guard, TLS/mTLS, certificate pinning |
| Security plugins | HMAC signing, secure logger, suspicious auth-status burst detection |
| Supply-chain process | security smoke test, threat model, release checklist, denylist, zizmor, CodeQL, Semgrep, dependency review, SBOM, OIDC provenance publish workflow |

## Features Added in Today's Advanced Upgrade

| Area | What users can do now |
| --- | --- |
| HTTP and errors | Use `query()`/`QUERY()`, conditional/one-shot interceptors, stable error constants, and preserved native network codes |
| Stream safety | Enforce upload/download limits on Fetch, XHR, Node buffers, Fetch streams, and Node streams |
| Form safety | Serialize nested forms with depth/index/dot controls, circular detection, and unsafe-key protection |
| Header/config safety | Reject control-character injection, normalize headers with a null prototype, and require an own request URL |
| Learning | Open `LEARN_HERE.md` for fresher lessons and `FUNCTIONS.md` for the complete task-based directory |
| Package identity | Read `STORMFETCH_PACKAGE_INFO` for official developer, company, contact, website, version, and signature |
| npm presentation | Professional badges, navigation, quickstart, full feature list, questionnaire, keywords, and release docs |
| Supply chain | SHA-pinned CI actions, disabled checkout credentials/caches, OIDC provenance, SBOM, CodeQL, Semgrep, zizmor, and dependency review |

This release makes StormFetch more than a normal HTTP client. These are the major advanced features now visible to npm users:

- Universal HTTP methods: `fetch`, `get`, `post`, `put`, `patch`, `delete`, `head`, `options`
- HTTP QUERY support plus uppercase aliases: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`, `QUERY`
- Data submit helpers: `postJson`, `postForm`, `postMultipart`
- GraphQL helper: `graphql(query, variables)`
- Multi-request orchestration: `batch(requests)` and `poll(url, options)`
- REST SDK generator: `resource(basePath)` and `contract(definition)`
- React and React Native hooks: query, lazy query, mutation, infinite query
- Smart cache manager: prefetch, cache tags, stale refresh, hydrate, dehydrate, key inspection
- Debug tools: request history, replay, `toCurl`, and `toHAR`
- Route policy engine: per-route retry, timeout, headers, cache, and security rules
- Reliability layer: retry policies, request dedupe, queue priority, circuit breaker fallback
- HTML/XML tools: `getHtml`, `getXml`, `getDom`, `scrape`, metadata/link/image/json-ld extraction
- Streaming tools: `streamText`, `streamJson`, `streamNdjson`, and `sse`
- Upload/download helpers for browser and React Native
- Mock testing tools: `createMockAdapter` and scenario-based `createMockServer`
- SSR helper: `createStormFetchServerClient` with cookie/header forwarding
- Security and observability: HTTPS guard, host/CIDR/DNS policy, private-network and metadata blocking, path traversal guards, no-proxy handling, redirect credential controls, request signing, redacted history/curl/HAR, structured security events

## Reliability Release: 1.13.0

StormFetch 1.13.0 adds the public hardening layer around the transport work:

- Structured `StormFetchError` objects now include `code`, `isStormFetchError`, `request`, and safe `toJSON()` output.
- Progress events include `bytes`, `rate`, `estimated`, `upload`, and `download` while keeping existing fields.
- Node `maxRate` supports practical upload/download throttling.
- `responseEncoding`, `timeoutErrorMessage`, `transport`, `env`, `fetchOptions`, and advanced Node networking options are typed.
- Invalid critical options reject with `ERR_BAD_OPTION` or `ERR_BAD_OPTION_VALUE`.
- Responses/errors expose the low-level request object where practical.

## Reliability Release: 1.12.0

StormFetch 1.12.0 closes the next legacy-client compatibility gaps found during production-readiness testing:

- Node HTTP adapter serializes native WHATWG `FormData` automatically for multipart uploads.
- Node stream uploads and `responseType: 'stream'` response bodies are supported by the HTTP/HTTPS adapter.
- gzip, deflate, brotli, and Node-supported zstd response decompression run before parsing.
- Async JSON/response parse failures reject with a StormFetch parse error instead of escaping the promise chain.
- External `AbortController` cancellation is classified as `isAbortError`, not `isNetworkError`.
- 301/302 POST and 303 redirects rewrite to GET and drop request bodies.
- HTTPS requests through HTTP/HTTPS proxies use CONNECT tunneling.
- `httpAgent` and `httpsAgent` can be supplied per client or request.
- `formSerializer` supports automatic JSON, URL-encoded, and multipart bodies plus bounded nested serialization with dot/bracket/index styles.
- Fetch, XHR, Node buffered responses, Node streams, and Fetch streams enforce `maxContentLength`; streamed uploads enforce `maxBodyLength`.
- Conditional interceptors support `runWhen`, `once`, and `prepend` without changing the existing eject-function API.
- Public `npm run reliability:test` smoke coverage and a Node 18/20/22 CI matrix are included.

## Reliability Release: 1.11.0

StormFetch 1.11.0 closed the first legacy-client compatibility gaps:

- Node HTTP adapter serializes native WHATWG `FormData` automatically for multipart uploads.
- Buffered Node uploads emit chunked progress events instead of only a final 100% callback.
- External `AbortController` cancellation is classified as `isAbortError`, not `isNetworkError`.
- Browser upload progress uses the XHR adapter even when `adapter: 'fetch'` is requested with `onUploadProgress`.

## Security Release: 1.10.0

StormFetch 1.10.0 adds deeper runtime, transport, payload, and supply-chain hardening.

```ts
import { createStormFetchClient } from 'stormfetch';

export const api = createStormFetchClient({
  baseURL: 'https://api.example.com',
  token: () => localStorage.getItem('accessToken'),
  withXSRFToken: true,
  security: {
    allowedHosts: ['api.example.com', '*.trusted.example.com'],
    blockedHosts: ['metadata.google.internal', '169.254.169.254'],
    blockedCidrs: ['169.254.169.254/32', '127.0.0.0/8', '10.0.0.0/8'],
    allowedMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
    allowAbsoluteUrls: false,
    allowPathTraversal: false,
    allowHttp: false,
    allowPrivateNetwork: false,
    blockCloudMetadata: true,
    validateDns: true,
    maxUrlLength: 4096,
    maxQueryDepth: 5,
    maxJsonDepth: 24,
    maxJsonKeys: 10_000,
    maxResponseJsonDepth: 24,
    maxResponseJsonKeys: 10_000,
    maxDecompressionRatio: 100,
    sensitiveHeaders: ['x-tenant-secret'],
    credentialPolicy: {
      authorization: ['api.example.com'],
      cookie: 'same-origin',
      'x-api-key': 'never',
    },
    signRequest: (config) => {
      config.headers['X-Client'] = 'web';
    },
  },
});
```

```ts
// Node HTTP/2
const response = await api.get('/metrics', { adapter: 'http2' });

// Enterprise proxy bypass
const enterprise = createStormFetchClient({
  proxy: {
    protocol: 'http',
    host: 'proxy.corp.local',
    port: 8080,
    noProxy: ['localhost', '.internal.example.com', '169.254.169.254'],
  },
});

// Redirect credential safety
await api.get('/download', {
  beforeRedirect: ({ from, to, requestOptions }) => {
    if (from.origin !== to.origin) {
      delete (requestOptions.headers as Record<string, string>).Authorization;
    }
  },
});

// HMAC request signing and secure logging
const signed = createStormFetchClient({
  baseURL: 'https://api.example.com',
  plugins: [
    hmacSigningPlugin({ secret: () => process.env.STORM_SIGNING_SECRET ?? '' }),
    secureLoggerPlugin(),
    securityRateLimitPlugin({ threshold: 5 }),
  ],
});

// TLS / mTLS / certificate pinning in Node
await signed.get('/secure', {
  tls: {
    ca: process.env.API_CA,
    cert: process.env.API_CERT,
    key: process.env.API_KEY,
    certificatePins: ['sha256/base64-pin-here'],
  },
});
```

### Security Capabilities

| Area | StormFetch 1.16.3 |
| --- | --- |
| Runtime dependencies | No runtime dependency |
| HTTP/2 | `adapter: 'http2'` uses Node's built-in HTTP/2 client |
| Deno and Bun | Official fetch-adapter path with runtime detection |
| Enterprise proxy bypass | `proxy.noProxy` plus `NO_PROXY`/`no_proxy` normalization |
| Redirect credentials | Cross-origin redirects strip sensitive headers by default; `beforeRedirect` can inspect/block/sign |
| DNS rebinding | Optional DNS resolution re-check with CIDR policy |
| Cloud metadata SSRF | Metadata hosts blocked by security policy |
| Path traversal | `baseURL` path traversal and absolute URL override guards |
| Payload DoS | 10MB secure default caps plus JSON, form, query, buffered-body, and stream limits |
| JSON parsing | `parseReviver`, request/response JSON depth/key caps |
| Decompression bombs | `maxDecompressionRatio` plus byte caps |
| Socket paths | Socket paths blocked unless explicitly allowlisted |
| TLS/mTLS | Node TLS options and certificate pins |
| Signing | Built-in HMAC signing plugin |
| Secure logging | Built-in secure logger plugin |
| CI scanning | zizmor, CodeQL, Semgrep, dependency review, SBOM |
| Credential binding | Per-header forwarding policies |
| HTTPS guard | Built-in through `security.allowHttp: false` |
| Host allow/block policy | Built-in exact, wildcard, RegExp, or function matching |
| Private-network/SSRF guard | Built-in `allowPrivateNetwork: false` policy |
| Debug export safety | `history()`, `toCurl()`, and `toHAR()` redact headers, URL credentials, query secrets, and body token patterns |
| XSRF handling | Optional XSRF with same-origin protection by default |
| Retry safety | Unsafe methods are not retried unless opted in |
| Schema validation | Request/response validator hooks included |
| Security process | `SECURITY.md`, `THREATMODEL.md`, release checklist, denylist, smoke tests, npm OIDC/provenance publish workflow |

For the current evidence-based comparison and capability inventory, open the [visual documentation center](https://unpkg.com/stormfetch@latest/docs/index.html#comparison).

These controls live in the client itself, so teams can make one hardened API client and reuse the same policy in React, React Native, SSR, and Node.

## Questions Freshers Ask

| Question | Answer |
| --- | --- |
| Which function should I learn first? | Start with `createStormFetchClient`, `get`, `post`, and `isStormFetchError`. |
| What was missing before the latest hardening? | Consistent streamed size limits, QUERY helpers, bounded nested forms, conditional/one-shot interceptors, and native network-code preservation. |
| Can I use StormFetch without React? | Yes. React hooks are optional and React is not bundled. |
| Can one client work in ReactJS and React Native? | Yes. Use the root entry for web/shared code and `stormfetch/react-native` for explicit mobile setup. |
| Can I work offline? | Yes. Queue mutations, persist them, retry, inspect dead letters, discard, or reconcile conflicts. |
| How do I know which function solves my task? | Open the [searchable function explorer](https://unpkg.com/stormfetch@latest/docs/index.html#functions), then filter by your task. |
| Will keywords guarantee top npm ranking? | No honest package can guarantee ranking. Accurate metadata, quality, adoption, downloads, releases, documentation, and community activity improve discovery. |
| Where can I ask, learn, contribute, or discuss? | Visit [BSG Technologies](https://bsgtechnologies.com) or WhatsApp **+91-8595147850**. |

## Complete Function Guide

### Client creation functions

| Function | Use it for | What user should do |
| --- | --- | --- |
| `createStormFetchClient(options)` | Main client for ReactJS, browser, Node.js, SSR, and shared SDKs | Create one configured API client with `baseURL`, auth token, timeout, cache, retry, plugins |
| `createReactNativeStormFetchClient(options)` | React Native and Expo apps | Use this when app runs on mobile; provide async token storage, network state, and native file saver |
| `createStormFetchServerClient(options)` | SSR/Node server requests | Forward cookies/headers from server request to API calls |
| `createTypedStormFetchClient<ApiSchema>(options)` | Compile-time typed API routes | Define endpoint map once, then get typed response/body inference |
| `fastApi` | Quick experiments and simple demos | Use pre-created default client; prefer custom client in production |

### Universal request functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `request(config)` | Sends any HTTP request using full config | Dynamic method/url, custom adapters, shared request builders |
| `fetch(url, config)` | Fetch-like API but with StormFetch retry/cache/auth/interceptors | Developers who already know browser `fetch` |
| `get(url, config)` / `GET(url, config)` | Reads data | Lists, details, search, cacheable API calls |
| `post(url, data, config)` / `POST(...)` | Sends create/action requests | Create record, login, command APIs |
| `put(url, data, config)` / `PUT(...)` | Replaces a full resource | Full update forms |
| `patch(url, data, config)` / `PATCH(...)` | Updates partial resource fields | Profile edit, status update |
| `delete(url, config)` / `DELETE(...)` | Removes data | Delete record, revoke token |
| `head(url, config)` / `HEAD(...)` | Reads only status and headers | File exists, auth check, CDN metadata |
| `options(url, config)` / `OPTIONS(...)` | Checks API capabilities | CORS/method discovery |
| `query(url, data, config)` / `QUERY(...)` | Sends the QUERY method with an optional body | Structured safe/idempotent queries |

### Body and API style helpers

| Function | What it does | Best use case |
| --- | --- | --- |
| `postJson(url, data)` | Sends JSON with explicit JSON header | Strict JSON APIs |
| `postForm(url, data)` | Sends `application/x-www-form-urlencoded` | OAuth, login forms, legacy APIs |
| `postMultipart(url, data)` | Sends `multipart/form-data` | File/image/document uploads |
| `graphql(query, variables, config)` | Sends GraphQL operation to `/graphql` or configured endpoint | GraphQL backends |
| `batch(requests)` | Runs many requests in parallel and keeps response order | Dashboard bootstrap, loading many widgets |
| `poll(url, options)` | Repeats GET until stopped or condition matches | Payment status, background job status, live order tracking |

### REST and SDK builder functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `resource(basePath)` | Creates `list`, `detail`, `create`, `replace`, `update`, `remove` helpers | Standard REST CRUD modules |
| `contract(definition)` | Creates named service functions from endpoint definitions | SDK-like API layer without writing repetitive functions |
| `generateStormFetchServicesFromOpenApi(document)` | Generates TypeScript service source from OpenAPI | Large APIs where services should be generated |

### Cache and performance functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `cacheManager.prefetch(url, config)` | Loads and stores cache before UI needs it | Faster screen transitions |
| `dehydrateCache()` | Exports current cache snapshot | SSR hydration, app state transfer |
| `hydrateCache(snapshot)` | Restores a cache snapshot | SSR/client boot, offline restore |
| `cacheKeys()` | Lists in-memory cache keys | Debugging and cache inspection |
| `clearCache(key?)` | Clears cache immediately | Logout, forced refresh |
| `clearCacheAsync(key?)` | Clears cache and awaits async storage | React Native AsyncStorage/MMKV wrappers |
| `invalidateTags(tags)` | Removes cache entries by tags | Refresh lists after create/update/delete |

### Debugging and DevTools-style functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `history()` | Returns recent request history | Debug panel, request inspection |
| `clearHistory()` | Removes stored request history | Reset debug state |
| `replay(requestId)` | Re-runs a previous request | Reproduce API bugs |
| `toCurl(requestIdOrConfig)` | Exports request as curl command | Share issue with backend team |
| `toHAR()` | Exports HAR-like request log | Browser-like network diagnostics |
| `subscribe(listener)` | Listens to request/cache events | Logging, metrics, custom DevTools |

### Reliability and policy functions

| Function / option | What it does | Best use case |
| --- | --- | --- |
| `policy(match, config)` | Applies defaults to matching routes | Different timeout/retry/cache rules for payments/admin/upload |
| `retry`, `retryPolicy`, `retryDelay` | Retries failed requests | Network instability |
| `dedupe` | Shares identical in-flight GET requests | Prevent duplicate list/detail calls |
| `priority`, `maxConcurrent`, `maxConcurrentPerHost` | Controls request scheduling | Apps with many parallel requests |
| `circuitBreaker` | Stops hitting failing hosts and optionally returns fallback | Production outage protection |
| `offlineQueue` + `flushOfflineQueue()` | Queues requests while offline, then flushes later | Mobile/offline friendly workflows |

### HTML, XML, scraping, and DOM functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `getHtml(url)` | Fetches HTML as text | Static pages, public content |
| `getXml(url)` | Fetches XML as text | RSS feeds, sitemaps, XML APIs |
| `getDom(url)` | Fetches and parses DOM | Browser scraping or custom parser flows |
| `parseDom(html, mimeType)` | Parses HTML/XML string | Reuse parsing without network call |
| `scrape(url, schema)` | Extracts values with CSS selectors | Titles, meta descriptions, links, images |
| `selectText(document, selector)` | Extracts text from first match | DOM helper |
| `selectAttr(document, selector, attr)` | Extracts attribute from first match | `href`, `src`, `content` |
| `selectAll(document, selector, attr?)` | Extracts all matches | Link/image lists |
| `extractMeta(document)` | Reads meta tags into object | SEO/content tools |
| `extractLinks(document)` | Extracts all anchor links | Crawlers |
| `extractImages(document)` | Extracts all image sources | Media extraction |
| `extractJsonLd(document)` | Parses JSON-LD scripts | SEO structured data |

### Streaming functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `streamText(url)` | Async-iterates text chunks | AI text streams, logs |
| `streamJson(url)` | Reads a streamed JSON response into object | Large JSON endpoint |
| `streamNdjson(url)` | Async-iterates newline-delimited JSON rows | Event/log feeds |
| `sse(url, options)` | Subscribes to Server-Sent Events | Live notifications and server events |

### Upload and download functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `createFormData(data)` | Converts object to multipart `FormData` | Upload with fields and files |
| `createReactNativeFile(uri, name, type)` | Creates typed RN file descriptor | Expo/ImagePicker/DocumentPicker upload |
| `isReactNativeFile(value)` | Type guard for RN file descriptor | Validation before upload |
| `download(url, fileName, config)` | Downloads Blob and optionally saves | Reports, invoices, exports |
| `saveBlob(blob, fileName)` | Browser-only Blob save helper | Manual browser save flow |

### Testing and mock functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `createMockAdapter(options)` | Creates simple mock HTTP adapter | Unit tests and demos |
| `createMockServer(options)` | Creates scenario-aware mock server with request inspection | Storybook, integration tests, empty/error/success states |
| `createStormFetchError(input)` | Creates StormFetch-compatible error | Custom adapters and test failures |
| `createInterceptorManager()` | Creates standalone interceptor manager | Advanced plugin/testing utilities |

### Runtime and utility functions

| Function | What it does | Best use case |
| --- | --- | --- |
| `getRuntimeInfo()` | Returns detected runtime and capability flags | Debug/support reports |
| `isBrowser()` | Checks browser runtime | Conditional browser behavior |
| `isReactNative()` | Checks React Native runtime | Conditional native behavior |
| `isNodeLike()` | Checks Node runtime excluding RN process shim | SSR/server behavior |
| `buildQueryString(params)` | Serializes query params | Custom URL builders |
| `replacePathParams(url, params)` | Replaces `/users/:id` placeholders | REST path building |
| `joinURL(baseURL, url)` | Safely joins base and path | Shared service code |

## CRUD Example

```ts
interface User {
  id: number;
  name: string;
  email: string;
}

interface UserInput {
  name: string;
  email: string;
}

const list = () => api.get<User[]>('/users');
const detail = (id: number) => api.get<User>('/users/:id', { pathParams: { id } });
const create = (input: UserInput) => api.post<User, UserInput>('/users', input);
const replace = (id: number, input: UserInput) =>
  api.put<User, UserInput>('/users/:id', input, { pathParams: { id } });
const update = (id: number, input: Partial<UserInput>) =>
  api.patch<User, Partial<UserInput>>('/users/:id', input, { pathParams: { id } });
const remove = (id: number) => api.delete('/users/:id', { pathParams: { id } });
```

## Typed Endpoint Map

Use `createTypedStormFetchClient` when routes should infer their response and request body types.

```ts
type ApiSchema = {
  '/users': {
    GET: { data: User[] };
    POST: { data: User; body: UserInput };
  };
};

const typedApi = createTypedStormFetchClient<ApiSchema>({
  baseURL: 'https://api.example.com',
});

const users = await typedApi.get('/users');
const created = await typedApi.post('/users', { name: 'Asha', email: 'asha@example.com' });
```

## Interceptors and Plugins

```ts
const removeInterceptor = api.interceptors.request.use((config) => ({
  ...config,
  headers: { ...config.headers, 'X-App-Version': '2.0.0' },
}));

removeInterceptor();
```

```ts
const api = createStormFetchClient({
  plugins: [
    authPlugin(() => getToken()),
    languagePlugin(() => getLanguage()),
    loggerPlugin(),
  ],
});
```

## Retry, Cache, Dedupe, and Cancellation

```ts
const controller = new AbortController();

const request = api.get<User[]>('/users', {
  retryPolicy: 'safe',
  retry: 3,
  cache: true,
  cacheTTL: 120_000,
  cacheTags: ['users'],
  staleTime: 30_000,
  staleWhileRevalidate: true,
  dedupe: true,
  signal: controller.signal,
});

controller.abort();
```

`retryUnsafe` must be explicitly enabled before POST, PATCH, or DELETE requests are retried.

## Advanced Features

### Async cache, tags, and stale refresh

```ts
const users = await api.get<User[]>('/users', {
  cache: true,
  cacheStorage: asyncStorageLikeStore,
  cacheTTL: 5 * 60_000,
  staleTime: 30_000,
  staleWhileRevalidate: true,
  cacheTags: ['users'],
});

await api.invalidateTags(['users']);
```

Use this in React Native with AsyncStorage/MMKV-style wrappers, or in web apps where you want tagged invalidation after mutations.

### Infinite queries

```tsx
const feed = useStormInfiniteQuery<Post[], string | undefined>('/feed', {
  initialPageParam: undefined,
  createConfig: (cursor) => ({ params: { cursor }, cache: true, cacheTags: ['feed'] }),
  getNextPageParam: (lastPage) => lastPage.at(-1)?.nextCursor,
});
```

### Mock adapter for tests

```ts
import { createMockAdapter, createStormFetchClient } from 'stormfetch';

const api = createStormFetchClient({
  adapter: createMockAdapter({
    routes: [
      { method: 'GET', url: '/users', data: [{ id: 1, name: 'Demo' }] },
    ],
  }),
});
```

### Universal methods, GraphQL, batch, and polling

```ts
await api.HEAD('/reports/monthly.pdf');
await api.POST('/users', { name: 'Asha' });

const profile = await api.fetch<User>('/me', { method: 'GET' });

const graph = await api.graphql<{ user: User }>(
  `query User($id: ID!) { user(id: $id) { id name } }`,
  { id: '1' }
);

const [users, stats] = await api.batch<[User[], Stats]>([
  { url: '/users', method: 'GET' },
  { url: '/stats', method: 'GET' },
]);

const poller = api.poll<Job>('/jobs/123', {
  interval: 2_000,
  stopWhen: (response) => response.data.status === 'done',
  onData: (response) => console.log(response.data.status),
});

poller.stop();
```

### HTML, XML, DOM parsing, and scraping

```ts
const page = await api.getHtml('/public-page');
const feed = await api.getXml('/feed.xml');

const scraped = await api.scrape('/blog/post', {
  title: 'h1',
  description: 'meta[name="description"]@content',
  links: ['a@href'],
});
```

In browsers, StormFetch uses native `DOMParser`. In Node.js or React Native, provide a parser adapter:

```ts
const api = createStormFetchClient({
  domParser: {
    parse(html, mimeType) {
      return yourParser(html, mimeType);
    },
  },
});
```

### REST resource builder

```ts
const users = api.resource<User, UserInput>('/users');

await users.list();
await users.detail(10);
await users.create({ name: 'Asha' });
await users.update(10, { name: 'Asha S.' });
await users.remove(10);
```

### Advanced StormFetch Features

```ts
await api.policy('/payments/**', {
  timeout: 10_000,
  retry: 0,
  headers: { 'X-Scope': 'payments' },
});

await api.cacheManager.prefetch<User[]>('/users', {
  cacheTags: ['users'],
});

const snapshot = await api.dehydrateCache();
await api.hydrateCache(snapshot);

const history = api.history();
const curl = api.toCurl(history[0].id);
const har = api.toHAR();
await api.replay(history[0].id);
```

```ts
const api = createStormFetchClient({
  circuitBreaker: {
    failureThreshold: 3,
    resetTimeout: 30_000,
    fallback: () => ({ cached: true }),
  },
});
```

```ts
for await (const line of api.streamNdjson<{ event: string }>('/events.ndjson')) {
  console.log(line.event);
}

const events = api.sse('/events', {
  onMessage: (message) => console.log(message.event, message.data),
});

events.close();
```

```ts
const sdk = api.contract({
  listUsers: { method: 'GET', url: '/users' },
  createUser: { method: 'POST', url: '/users' },
});

await sdk.listUsers<User[]>();
await sdk.createUser<User, UserInput>({ name: 'Asha' });
```

```ts
import { createMockServer } from 'stormfetch';

const mock = createMockServer({
  scenarios: {
    empty: [{ method: 'GET', url: '/users', data: [] }],
    filled: [{ method: 'GET', url: '/users', data: [{ id: 1 }] }],
  },
});

mock.setScenario('filled');
const api = createStormFetchClient({ adapter: mock.adapter });
console.log(mock.requests());
```

## Uploads

Browser:

```ts
const body = api.createFormData({ avatar: file, displayName: 'Pradeep' });
await api.post('/profile/avatar', body);
```

React Native:

```ts
import { createFormData, createReactNativeFile } from 'stormfetch/react-native';

const body = createFormData({
  avatar: createReactNativeFile(image.uri, image.fileName ?? 'avatar.jpg', image.mimeType ?? 'image/jpeg'),
  displayName: 'Pradeep',
});

await api.post('/profile/avatar', body);
```

Do not manually set the multipart `Content-Type`; StormFetch removes it so the runtime can add the boundary.

## Downloads

```ts
// Browser: automatically opens the save flow.
await api.download('/reports/monthly', 'monthly.pdf');

// Any runtime: fetch without auto-saving.
const response = await api.download('/reports/monthly', 'monthly.pdf', {
  autoSave: false,
});
```

React Native must provide `fileSaver` at client or request level because the package intentionally does not depend on a particular native filesystem library.

## Errors

```ts
try {
  await api.get('/users');
} catch (cause) {
  const error = cause as import('stormfetch').StormFetchError;
  console.log(error.status, error.code, error.fieldErrors, error.traceId);
  console.log(error.isNetworkError, error.isTimeoutError, error.isAbortError);
}
```

## Runtime Diagnostics

```ts
import { getRuntimeInfo } from 'stormfetch';

console.log(getRuntimeInfo());
// { runtime, isBrowser, isReactNative, isNode, hasFetch, hasXHR, ... }
```

## v1.14 Production Tooling

### Durable offline mutations

```ts
import {
  createJsonOfflineQueueStorage,
  createStormFetchClient,
} from 'stormfetch/core';

const api = createStormFetchClient({
  isOnline: () => networkState.online,
  offlineStorage: createJsonOfflineQueueStorage(AsyncStorage),
  offlineMaxAttempts: 5,
  offlineRetryDelay: attempt => Math.min(30_000, 1000 * 2 ** attempt),
  resolveOfflineConflict: async record =>
    record.config.url.startsWith('/drafts/') ? 'retry' : 'discard',
  onOfflineDeadLetter: entry => reportFailedMutation(entry),
});

const pending = api.post('/orders', order, { offlineQueue: true });
await api.flushOfflineQueue();
console.log(await api.offlineQueueSnapshot());
```

Unsafe queued methods receive an `Idempotency-Key` automatically. Override the header name with `offlineIdempotencyHeader`, or set it to `false`.

### Native background transfers

Inject an adapter backed by Android Download Manager, an iOS background session, or your preferred Expo/native module. `nativeUpload` and `nativeDownload` work with promise adapters; `startNativeUpload` and `startNativeDownload` expose pause, resume, and cancel when the adapter supports them.

```ts
const api = createReactNativeStormFetchClient({ nativeTransfer: platformTransfers });
const task = api.startNativeDownload({
  url: fileUrl,
  destinationUri,
  background: true,
  onProgress: event => updateProgress(event.progress),
});
await task.result;
```

### OpenTelemetry and metrics

```ts
import { createOpenTelemetryObservability, createStormFetchMetrics } from 'stormfetch/observability';

const metrics = createStormFetchMetrics();
const api = createStormFetchClient({
  observability: createOpenTelemetryObservability({
    tracer,
    onEvent: metrics.onEvent,
    traceHeaderName: 'x-trace-id',
  }),
});
```

### DevTools and generated SDK CLI

```ts
import { mountStormFetchDevTools } from 'stormfetch/devtools';

const tools = mountStormFetchDevTools(api, document.querySelector('#api-tools')!);
// tools.snapshot(), tools.clear(), tools.unmount()
```

```bash
npx stormfetch-generate --input openapi.json --output src/api.generated.ts --group-by-tags
npx stormfetch-generate --input openapi.json --output src/api.generated.ts --watch
```

## Important Platform Notes

- Browser XHR is selected when progress callbacks are requested.
- Browser XHR is also selected for `adapter: 'fetch'` when `onUploadProgress` is supplied, because Fetch does not expose portable upload progress.
- Node HTTP uploads support native FormData serialization and chunked buffered upload progress.
- React Native uses fetch; standard fetch does not provide portable upload progress events.
- Browser `localStorage` and `sessionStorage` cache are not available in React Native.
- React Native auth token providers may be asynchronous.
- React Native file saving is injected through `fileSaver`.
- Node-specific proxy, stream, redirect, and size options use the HTTP adapter.

## Development and Publishing

```bash
npm install
npm run typecheck
npm run build
npm pack --dry-run
```

Publish only after the checks pass. For a normal local PowerShell release authenticated with your npm account/token and OTP:

```bash
npm publish --access public
```

Local publishing intentionally does not force `provenance`, because npm can generate trusted provenance only inside a supported CI/OIDC provider. For the recommended supply-chain release, run the repository's GitHub Actions publish workflow; it has `id-token: write` permission and executes:

```bash
npm publish --provenance --access public
```

Do not add `"provenance": true` to `publishConfig`: that makes local publishing fail with `Automatic provenance generation not supported for provider: null`. The CI workflow explicitly enables provenance where npm can verify it.

## Release and API Policy

Open the [visual release guide](https://unpkg.com/stormfetch@latest/docs/index.html#release) for release history and policy navigation. `npm test`, packed ESM/CommonJS consumer checks, the browser matrix, runtime checks, and the benchmark budget are release gates.

## License

MIT
