npm package: @kulkan/api-client
Description: Client used to interact with kulflow project API
Latest version: 1.1.1

# `@kulkan/api-client`

Typed HTTP client for the Truffa API. Consumed by web and mobile apps. **No baked-in base URL:** pass a preconfigured HTTP layer (typically an [Axios](https://axios-http.com/) instance with `baseURL` set). Request and response shapes come from [`@kulkan/contracts`](https://www.npmjs.com/package/@kulkan/contracts).

## Requirements

- **Node.js** ≥ 18.18
- **Peer dependency:** `@kulkan/contracts` **≥ 1.1.0** (auth types and shared envelopes)

## Installation

```bash
pnpm add @kulkan/api-client @kulkan/contracts
# or
npm install @kulkan/api-client @kulkan/contracts
```

## What ships today

| Export                                 | Description                                                                                                                                       |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createApiClient(options)`             | Factory returning `healthCheck` + **`auth`** namespace                                                                                            |
| `ApiClient` / `CreateApiClientOptions` | Typed client and `{ http: HttpClient }` options                                                                                                   |
| `HttpClient`                           | **`get`** and **`post`** (minimal surface compatible with Axios)                                                                                  |
| `HttpGet` / `HttpPost`                 | Method signatures                                                                                                                                 |
| Named auth helpers                     | `postRegister`, `postLogin`, `getGoogleOAuthStart`, `postGoogleOAuthCallback`, `postRefresh`, `postLogout`, `getMe` (see `src/endpoints/auth.ts`) |

### Endpoints implemented

| HTTP   | Path                                              | Client                                                                                     |
| ------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `GET`  | `/api/v1/health-check`                            | `client.healthCheck()`                                                                     |
| `POST` | `/api/v1/auth/register`                           | `client.auth.register(body)` or `postRegister(http, body)`                                 |
| `POST` | `/api/v1/auth/login`                              | `client.auth.login(body)` or `postLogin(http, body)`                                       |
| `GET`  | `/api/v1/auth/oauth/google/start?redirectUri=...` | `client.auth.getGoogleOAuthStart(redirectUri)` or `getGoogleOAuthStart(http, redirectUri)` |
| `POST` | `/api/v1/auth/oauth/google/callback`              | `client.auth.postGoogleOAuthCallback(body)` or `postGoogleOAuthCallback(http, body)`       |
| `POST` | `/api/v1/auth/refresh`                            | `client.auth.refresh(body)` or `postRefresh(http, body)`                                   |
| `POST` | `/api/v1/auth/logout`                             | `client.auth.logout(body)` or `postLogout(http, body)`                                     |
| `GET`  | `/api/v1/auth/me`                                 | `client.auth.me(accessToken)` or `getMe(http, accessToken)`                                |

Responses follow **`IApiResponse<T>`** from contracts (`success`, `data`, etc.). Auth session payloads are **`AuthSessionResponse`** (`TokenPair` + `user`). **`logout`** returns **204** with no JSON body.

### Usage example (Axios)

Paths are **relative to `baseURL`** (e.g. `https://api.example.com`).

```typescript
import axios from 'axios';
import { createApiClient } from '@kulkan/api-client';

const http = axios.create({
  baseURL: process.env.API_BASE_URL,
  timeout: 30_000,
  headers: { 'Content-Type': 'application/json' },
});

const api = createApiClient({ http });

const health = await api.healthCheck();
const session = await api.auth.login({ email: 'user@example.com', password: '********' });
// session.data — IApiResponse<AuthSessionResponse>; use session.data?.data for the inner payload when using Axios default response shape
```

Axios returns `{ data: body }` where `body` is the full JSON from the server. For `IApiResponse<AuthSessionResponse>`, the **envelope** is in `response.data`; the **`AuthSessionResponse`** is typically `response.data.data` (depending on your typings).

### OAuth (mobile / web)

1. Call **`getGoogleOAuthStart`** with the same **`redirectUri`** you registered in Auth0 and in the API’s `OAUTH_ALLOWED_REDIRECT_URIS`.
2. Open **`authorizationUrl`** in a browser / `ASWebAuthenticationSession`.
3. After redirect, **`POST`** the **`code`**, **`state`**, and **`redirectUri`** to **`postGoogleOAuthCallback`**.

### Why a factory?

`createApiClient({ http })` keeps env and transport out of this package, supports multiple backends in one app, and makes tests easy with a mock `http` object.

---

## Architecture

1. **`HttpClient`** — abstraction over GET/POST (`{ data: T }` shape, Axios-compatible).
2. **`src/endpoints/*.ts`** — thin functions: `(http, …args) => Promise<…>`.
3. **`createApiClient`** — wires `http` into endpoints.
4. **`@kulkan/contracts`** — DTOs (`RegisterRequest`, `AuthSessionResponse`, …).

### Extending further

If you add PATCH/PUT/DELETE, extend **`HttpClient`** in `src/http-client.ts` and add endpoint modules. For request config (query params, headers), align types with your adapter (Axios uses a second `config` argument on `get`/`post`).

---

## Testing

Inject a fake **`HttpClient`** with **`get`** and **`post`** mocks and assert URLs and payloads.

```typescript
import type { HttpClient } from '@kulkan/api-client';
import { createApiClient } from '@kulkan/api-client';

const http: HttpClient = {
  get: jest.fn().mockResolvedValue({ data: { success: true, data: {} } }),
  post: jest.fn().mockResolvedValue({ data: { success: true, data: {} } }),
};

const api = createApiClient({ http });
await api.healthCheck();
expect(http.get).toHaveBeenCalledWith('/api/v1/health-check', undefined);
```

---

## Development (this repository)

| Script                    | Purpose                              |
| ------------------------- | ------------------------------------ |
| `pnpm run build`          | `tsup` → `dist/` (CJS, ESM, `.d.ts`) |
| `pnpm run typecheck`      | `tsc --noEmit`                       |
| `pnpm run lint`           | ESLint                               |
| `pnpm run validate`       | typecheck + lint + Prettier check    |
| `pnpm run prepublishOnly` | validate + build before publish      |

---

## Changelog

See [CHANGELOG.md](./CHANGELOG.md).

## License

MIT — see [LICENSE](./LICENSE).