npm package: @kawaiininja/fetch
Description: Core fetch utility for Onyx Framework
Author: Tristan
Latest version: 1.1.0

# @kawaiininja/fetch

A production-grade, hybrid-native HTTP client designed for the Onyx Framework.

**Rating: S-Tier Utility 🏆**

This package automates enterprise-grade security, CSRF handling, and platform detection (Web vs. Native Mobile), allowing you to focus on building features rather than handling HTTP boilerplate. It is optimized for high-performance React applications with built-in caching and retry logic.

## 🚀 Features

- **Hybrid Intelligence**: Automatically detects if running on Web or Native Mobile (Capacitor).
- **🛡️ Session Memory Vault**: High-performance token caching for native apps that avoids expensive SecureStorage calls on every request.
- **Pro Security**:
  - **Native**: Uses `SecureStoragePlugin` (with localStorage fallback) for secure token management.
  - **Web**: Uses `HttpOnly` cookies + Automatic CSRF token rotation.
- **⚡ Strict Reliability**:
  - **Smart Deadlines**: Global and per-request timeouts to prevent UI hangs.
  - **Auto-Retries**: Transparently retries failed network requests before surfacing an error.
- **📦 Caching & SWR**: Built-in support for Stale-While-Revalidate, custom dedupe keys, and focus-based revalidation.
- **Type-Safe & Efficient**: Optimized for both TypeScript and standard JavaScript.

---

## 🛠️ Setup Guide

### 1. Global Provider Configuration

Wrap your application with the `ApiProvider`. This sets the design system and security policy for every request.

```jsx
// src/main.jsx or App.jsx
import { ApiProvider } from "@kawaiininja/fetch";

const apiConfig = {
  baseUrl: "https://api.myapp.com", // Base URL for all requests
  version: "v1", // Automatically appends /v1 to non-absolute paths
  debug: true, // Detailed console logs for security & network
  timeout: 5000, // Global fallback timeout (default 5s)
  retries: 3, // Global retry attempt count
  disableCsrf: false, // Set true for local development or non-CSRF backends
  onError: (msg, status) => {
    showToast(`${status || "Error"}: ${msg}`);
  },
};

ReactDOM.createRoot(document.getElementById("root")).render(
  <ApiProvider config={apiConfig}>
    <App />
  </ApiProvider>,
);
```

---

## 📖 Essential Usage

### 1. The Standard Hook

`useFetch` is designed to be the primary way you interact with your API. It handles state, mounting logic, and method injection.

```jsx
import { useFetch } from "@kawaiininja/fetch";

export const UserList = () => {
  // 1. Initial configuration
  // Note: state contains { data, loading, error, status }
  const { state, isLoading, isSuccess, get } = useFetch("/users", {
    swr: true,
    revalidateOnFocus: true,
  });

  // Access data via state.data
  const users = state.data;

  if (isLoading && !users) return <Skeleton />;

  return (
    <ul>
      {users?.map((u) => (
        <li key={u.id}>{u.name}</li>
      ))}
      <button onClick={() => get()}>Manual Refresh</button>
    </ul>
  );
};
```

### 2. Performing Actions (Mutations)

Don't use `fetch()` or `axios` for buttons. Use the injected methods to keep security tokens consistent.

```jsx
const CommentBox = ({ postId }) => {
  const { post, isLoading } = useFetch("/comments");

  const save = async (text) => {
    // Methods return the final parsed data or undefined if failed
    const result = await post({ text, postId });
    if (result) alert("Saved!");
  };

  return (
    <button onClick={() => save("Hello!")} disabled={isLoading}>
      {isLoading ? "Saving..." : "Submit"}
    </button>
  );
};
```

---

## 🏗️ Advanced Guides

### 1. Custom Error Handling

While `ApiProvider` has a global `onError`, you can handle errors locally within a request to provide specific feedback (like inline form validation).

```javascript
const { post, state } = useFetch("/update-profile");

const handleSave = async () => {
  try {
    await post(formData);
  } catch (err) {
    // err.message will contain the server error or network issue
    console.log("Local error handling:", err.message);
  }
};
```

### 2. Manual Cache Manipulation

Sometimes you want to update the UI instantly (Optimistic UI) before the server responds.

```javascript
const { updateData, post } = useFetch("/settings");

const toggleOption = async (id) => {
  // 1. Update UI instantly
  updateData({ [id]: true });

  // 2. Sync with server in background
  await post({ id, value: true });
};
```

### 3. Reactive Dependencies

The hook automatically refetches if the `endpoint` or `dedupeKey` changes, making it perfect for search or filtered lists.

```javascript
const { state } = useFetch(`/products?category=${selectedCategory}`);
// This will automatically fire whenever selectedCategory updates!
```

---

## ⚙️ Configuration API Reference

### `ApiProvider` Config (`ApiConfig`)

| Property      | Type       | Default      | Description                                           |
| :------------ | :--------- | :----------- | :---------------------------------------------------- |
| `baseUrl`     | `string`   | **Required** | The root URL for all requests.                        |
| `version`     | `string`   | `"v1"`       | Appended to paths that don't start with `/`.          |
| `timeout`     | `number`   | `5000`       | Global timeout in MS.                                 |
| `retries`     | `number`   | `3`          | Attempts before giving up.                            |
| `disableCsrf` | `boolean`  | `false`      | Skips CSRF token retrieval if true.                   |
| `debug`       | `boolean`  | `false`      | Enables verbose security and network logs.            |
| `onError`     | `function` | `-`          | Call: `(msg: string, status: number \| null) => void` |

### `useFetch` Options (`SSSOptions`)

| Option              | Type      | Default    | Description                            |
| :------------------ | :-------- | :--------- | :------------------------------------- |
| `enabled`           | `boolean` | `true`     | Set false to skip initial mount fetch. |
| `swr`               | `boolean` | `false`    | Enable caching + background updates.   |
| `revalidateOnFocus` | `boolean` | `false`    | Refetch when window is focused.        |
| `refreshInterval`   | `number`  | `0`        | Polling interval in MS.                |
| `staleTime`         | `number`  | `300000`   | Cache fresh for 5 minutes.             |
| `dedupeKey`         | `string`  | `endpoint` | Custom key for caching logic.          |
| `timeout`           | `number`  | (Global)   | Per-hook timeout override.             |
| `retries`           | `number`  | (Global)   | Per-hook retry override.               |

### Returned Surface (`ApiSurface<T>`)

| Property              | Type            | Description                                              |
| :-------------------- | :-------------- | :------------------------------------------------------- |
| `state`               | `FetchState<T>` | Raw reactive state: `{ data, loading, error, status }`.  |
| `isLoading`           | `boolean`       | **[Alias]** for `state.loading`.                         |
| `isError`             | `boolean`       | **[Alias]** - `true` if `state.error` is present.        |
| `isSuccess`           | `boolean`       | **[Alias]** - `true` if request is successful with data. |
| `get(options)`        | `function`      | Performs a GET request.                                  |
| `post(data, options)` | `function`      | Performs a POST request.                                 |
| `put/patch/delete`    | `function`      | Corresponding HTTP methods.                              |
| `upload(formData)`    | `function`      | Multipart upload helper.                                 |
| `setData(data)`       | `function`      | Manually override the local `state.data`.                |
| `updateData(partial)` | `function`      | Merge partial updates into `state.data`.                 |

---

## 🛡️ Security & Architecture

1. **Context Initialization**: `ApiProvider` creates an immutable configuration bridge.
2. **Platform Awareness**: The library automatically switches between `Authorization` headers (Native) and `X-CSRF-Token` (Web).
3. **Execution Pipeline**:
   - **Step 1**: Check Cache (if SWR).
   - **Step 2**: Ensure CSRF (if Web and not disabled).
   - **Step 3**: Inject Auth Headers (Native Session Memory).
   - **Step 4**: Execute `fetch()` with recursive retry logic.
   - **Step 5**: Parse & Commit to state.

---

&copy; 2024 KawaiiNinja. Built for High-Performance Onyx Apps.