@ipetsadmin/api-client 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -19,6 +19,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
19
 
20
20
  ### Security
21
21
 
22
+ ## [1.1.0] - 2026-04-04
23
+
24
+ ### Added
25
+
26
+ - **`HttpClient.post`** and **`HttpPost`** type for JSON bodies (Axios-compatible).
27
+ - **Auth endpoints** (`src/endpoints/auth.ts`): `postRegister`, `postLogin`, `getGoogleOAuthStart`, `postGoogleOAuthCallback`, `postRefresh`, `postLogout`, `getMe`.
28
+ - **`createApiClient`** exposes **`auth`** namespace delegating to the auth endpoints.
29
+ - **Peer dependency** on `@ipetsadmin/contracts` **≥ 1.1.1** (align with service ports and Auth0 helper types on the API).
30
+ - README updated with endpoint table and OAuth flow notes.
31
+
32
+ ### Changed
33
+
34
+ - **`createApiClient`** now requires an `http` implementation that provides both **`get`** and **`post`** (breaking for consumers that only implemented `get`).
35
+
22
36
  ## [1.0.0] - 2026-04-02
23
37
 
24
38
  ### Added
package/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # `@ipetsadmin/api-client`
2
2
 
3
- Typed HTTP client for the Truffa API. This package is meant to be consumed by front-end and mobile apps. It does **not** own API URL configuration: you pass in a preconfigured HTTP implementation (typically an [Axios](https://axios-http.com/) instance with `baseURL` already set). Request and response **shapes** come from [`@ipetsadmin/contracts`](https://www.npmjs.com/package/@ipetsadmin/contracts) (or domain-specific types you align with that package).
3
+ 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 [`@ipetsadmin/contracts`](https://www.npmjs.com/package/@ipetsadmin/contracts).
4
4
 
5
5
  ## Requirements
6
6
 
7
7
  - **Node.js** ≥ 18.18
8
- - **Peer dependency:** `@ipetsadmin/contracts` (install it next to this package in your app)
8
+ - **Peer dependency:** `@ipetsadmin/contracts` **≥ 1.1.0** (auth types and shared envelopes)
9
9
 
10
10
  ## Installation
11
11
 
@@ -15,338 +15,82 @@ pnpm add @ipetsadmin/api-client @ipetsadmin/contracts
15
15
  npm install @ipetsadmin/api-client @ipetsadmin/contracts
16
16
  ```
17
17
 
18
- ## Current implementation
18
+ ## What ships today
19
19
 
20
- ### What ships today
21
-
22
- | Export | Description |
23
- | -------------------------- | ----------------------------------------------------------------------- |
24
- | `createApiClient(options)` | Factory that returns an object of API methods. |
25
- | `ApiClient` | Type of the object returned by `createApiClient`. |
26
- | `CreateApiClientOptions` | `{ http: HttpClient }`. |
27
- | `HttpClient` | Minimal interface your HTTP layer must satisfy (today: **`get` only**). |
28
- | `HttpGet` | Type of the `get` method. |
20
+ | Export | Description |
21
+ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
22
+ | `createApiClient(options)` | Factory returning `healthCheck` + **`auth`** namespace |
23
+ | `ApiClient` / `CreateApiClientOptions` | Typed client and `{ http: HttpClient }` options |
24
+ | `HttpClient` | **`get`** and **`post`** (minimal surface compatible with Axios) |
25
+ | `HttpGet` / `HttpPost` | Method signatures |
26
+ | Named auth helpers | `postRegister`, `postLogin`, `getGoogleOAuthStart`, `postGoogleOAuthCallback`, `postRefresh`, `postLogout`, `getMe` (see `src/endpoints/auth.ts`) |
29
27
 
30
28
  ### Endpoints implemented
31
29
 
32
- | Method | Path | Client method |
33
- | ------ | ---------------------- | ---------------------- |
34
- | `GET` | `/api/v1/health-check` | `client.healthCheck()` |
30
+ | HTTP | Path | Client |
31
+ | ------ | ------------------------------------------------- | ------------------------------------------------------------------------------------------ |
32
+ | `GET` | `/api/v1/health-check` | `client.healthCheck()` |
33
+ | `POST` | `/api/v1/auth/register` | `client.auth.register(body)` or `postRegister(http, body)` |
34
+ | `POST` | `/api/v1/auth/login` | `client.auth.login(body)` or `postLogin(http, body)` |
35
+ | `GET` | `/api/v1/auth/oauth/google/start?redirectUri=...` | `client.auth.getGoogleOAuthStart(redirectUri)` or `getGoogleOAuthStart(http, redirectUri)` |
36
+ | `POST` | `/api/v1/auth/oauth/google/callback` | `client.auth.postGoogleOAuthCallback(body)` or `postGoogleOAuthCallback(http, body)` |
37
+ | `POST` | `/api/v1/auth/refresh` | `client.auth.refresh(body)` or `postRefresh(http, body)` |
38
+ | `POST` | `/api/v1/auth/logout` | `client.auth.logout(body)` or `postLogout(http, body)` |
39
+ | `GET` | `/api/v1/auth/me` | `client.auth.me(accessToken)` or `getMe(http, accessToken)` |
35
40
 
36
- The health check returns `Promise<IApiResponse<unknown>>` using the shared envelope from `@ipetsadmin/contracts`. When the canonical health payload exists in contracts, replace `unknown` with that type in `src/endpoints/health-check.ts`.
41
+ Responses follow **`IApiResponse<T>`** from contracts (`success`, `data`, etc.). Auth session payloads are **`AuthSessionResponse`** (`TokenPair` + `user`). **`logout`** returns **204** with no JSON body.
37
42
 
38
43
  ### Usage example (Axios)
39
44
 
40
- Configure Axios once in your app (base URL, timeouts, auth interceptors). Paths in this library are **relative to `baseURL`** (e.g. `/api/v1/...`).
45
+ Paths are **relative to `baseURL`** (e.g. `https://api.example.com`).
41
46
 
42
47
  ```typescript
43
48
  import axios from 'axios';
44
49
  import { createApiClient } from '@ipetsadmin/api-client';
45
50
 
46
51
  const http = axios.create({
47
- baseURL: process.env.API_BASE_URL, // e.g. https://api.example.com
48
- timeout: 15_000,
52
+ baseURL: process.env.API_BASE_URL,
53
+ timeout: 30_000,
49
54
  headers: { 'Content-Type': 'application/json' },
50
55
  });
51
56
 
52
57
  const api = createApiClient({ http });
53
58
 
54
59
  const health = await api.healthCheck();
55
- // health is IApiResponse<unknown>
56
- ```
57
-
58
- Axios’s `get` signature matches what this library expects: it returns a `Promise` that resolves to an object with a `data` property.
59
-
60
- ### Why a factory?
61
-
62
- `createApiClient({ http })` keeps this package free of environment-specific configuration, supports multiple backends or tenants in one app, and makes tests trivial by injecting a mock `http` object.
63
-
64
- ---
65
-
66
- ## Architecture overview
67
-
68
- 1. **`HttpClient`** — Abstraction over “how” HTTP is performed (Axios, `fetch` wrapper, etc.).
69
- 2. **`src/endpoints/*.ts`** — One module per route (or per resource): pure async functions that take `http` and return typed data.
70
- 3. **`createApiClient`** — Wires `http` into those functions and exposes a stable, discoverable API.
71
- 4. **`@ipetsadmin/contracts`** — Source of truth for DTOs shared with the server (e.g. `IApiResponse<T>`).
72
-
73
- When the API adds a route, add an endpoint module, extend `HttpClient` if you need new verbs, and add a method on the object returned by `createApiClient`.
74
-
75
- ---
76
-
77
- ## Extending `HttpClient` for all HTTP verbs
78
-
79
- Right now `HttpClient` only declares `get`. For **POST**, **PATCH**, **PUT**, and **DELETE**, extend the interface so adapters (Axios) stay type-safe and consistent.
80
-
81
- Axios maps HTTP concepts roughly as follows:
82
-
83
- | Concern | Axios request config field |
84
- | ------------ | -------------------------------------------------------------- |
85
- | URL path | First argument `url` (often built from path + **path params**) |
86
- | Query string | `params` |
87
- | JSON body | `data` |
88
- | Headers | `headers` |
89
-
90
- Recommended shape (mirror Axios so an `AxiosInstance` is assignable with minimal wrapping):
91
-
92
- ```typescript
93
- // src/http-client.ts — extend when you add non-GET endpoints
94
-
95
- /** Optional config aligned with Axios (params, data, headers, etc.). */
96
- export type HttpRequestConfig = {
97
- params?: Record<string, unknown>;
98
- data?: unknown;
99
- headers?: Record<string, string>;
100
- };
101
-
102
- export type HttpGet = <TResponse>(
103
- url: string,
104
- config?: HttpRequestConfig,
105
- ) => Promise<{ data: TResponse }>;
106
-
107
- export type HttpPost = <TResponse>(
108
- url: string,
109
- config?: HttpRequestConfig,
110
- ) => Promise<{ data: TResponse }>;
111
-
112
- export type HttpPut = HttpPost;
113
- export type HttpPatch = HttpPost;
114
-
115
- export type HttpDelete = <TResponse>(
116
- url: string,
117
- config?: HttpRequestConfig,
118
- ) => Promise<{ data: TResponse }>;
119
-
120
- export interface HttpClient {
121
- readonly get: HttpGet;
122
- readonly post: HttpPost;
123
- readonly put: HttpPut;
124
- readonly patch: HttpPatch;
125
- readonly delete: HttpDelete;
126
- }
127
- ```
128
-
129
- **Adapter example (Axios):** if TypeScript complains about `config` width, use a typed wrapper:
130
-
131
- ```typescript
132
- import type { AxiosInstance } from 'axios';
133
- import type { HttpClient, HttpRequestConfig } from '@ipetsadmin/api-client';
134
-
135
- export function createAxiosHttpClient(instance: AxiosInstance): HttpClient {
136
- return {
137
- get: (url, config) => instance.get(url, config),
138
- post: (url, config) => instance.post(url, config?.data, config),
139
- put: (url, config) => instance.put(url, config?.data, config),
140
- patch: (url, config) => instance.patch(url, config?.data, config),
141
- delete: (url, config) => instance.delete(url, config),
142
- };
143
- }
144
- ```
145
-
146
- Note: Axios’s `post`/`put`/`patch` take `data` as the second argument and `config` as the third; the wrapper above keeps your **endpoint** code calling `http.post(url, { data, params, headers })` in one place. Adjust the wrapper to match how you prefer to thread `config`.
147
-
148
- ---
149
-
150
- ## Implementing endpoints: patterns by verb
151
-
152
- Conventions used below:
153
-
154
- - **Path** — string constant; combine with **path parameters** via a small helper or template.
155
- - **Query** — `config.params` (Axios serializes to the query string).
156
- - **Body** — `config.data` for JSON bodies.
157
- - **Headers** — `config.headers` for per-request headers (auth, idempotency keys, etc.).
158
- - **Types** — import request/response types from `@ipetsadmin/contracts` when they exist.
159
-
160
- Assume:
161
-
162
- ```typescript
163
- import type { IApiResponse } from '@ipetsadmin/contracts';
164
- import type { HttpClient } from '../http-client';
165
- ```
166
-
167
- ### Path parameters
168
-
169
- Build the URL in the endpoint (keep templates next to the constant for clarity):
170
-
171
- ```typescript
172
- const USER_BY_ID_PATH = '/api/v1/users/:userId' as const;
173
-
174
- function buildUserPath(userId: string): string {
175
- return USER_BY_ID_PATH.replace(':userId', encodeURIComponent(userId));
176
- }
177
-
178
- // GET /api/v1/users/42
179
- await http.get<IApiResponse<UserDto>>(buildUserPath('42'));
180
- ```
181
-
182
- For many segments, a tiny helper avoids mistakes:
183
-
184
- ```typescript
185
- function buildPath(template: string, params: Record<string, string | number>): string {
186
- let path = template;
187
- for (const [key, value] of Object.entries(params)) {
188
- path = path.replace(`:${key}`, encodeURIComponent(String(value)));
189
- }
190
- return path;
191
- }
192
-
193
- // '/api/v1/orgs/:orgId/projects/:projectId'
194
- buildPath('/api/v1/orgs/:orgId/projects/:projectId', {
195
- orgId: 'acme',
196
- projectId: 'proj-1',
197
- });
198
- ```
199
-
200
- ### GET — query and headers
201
-
202
- ```typescript
203
- const SEARCH_PATH = '/api/v1/items' as const;
204
-
205
- export interface ListItemsParams {
206
- readonly query?: Record<string, string | number | boolean | undefined>;
207
- readonly headers?: Record<string, string>;
208
- }
209
-
210
- export async function fetchItems(
211
- http: HttpClient,
212
- args: ListItemsParams = {},
213
- ): Promise<IApiResponse<ItemSummary[]>> {
214
- const { data } = await http.get<IApiResponse<ItemSummary[]>>(SEARCH_PATH, {
215
- params: args.query,
216
- headers: args.headers,
217
- });
218
- return data;
219
- }
220
- ```
221
-
222
- ### POST — body, query, headers
223
-
224
- ```typescript
225
- const CREATE_ITEM_PATH = '/api/v1/items' as const;
226
-
227
- export interface CreateItemInput {
228
- readonly body: CreateItemRequestDto;
229
- readonly query?: Record<string, string | number | boolean | undefined>;
230
- readonly headers?: Record<string, string>;
231
- }
232
-
233
- export async function createItem(
234
- http: HttpClient,
235
- input: CreateItemInput,
236
- ): Promise<IApiResponse<ItemDto>> {
237
- const { data } = await http.post<IApiResponse<ItemDto>>(CREATE_ITEM_PATH, {
238
- data: input.body,
239
- params: input.query,
240
- headers: input.headers,
241
- });
242
- return data;
243
- }
244
- ```
245
-
246
- ### PATCH — partial body, path id
247
-
248
- ```typescript
249
- const ITEM_PATH = '/api/v1/items/:itemId' as const;
250
-
251
- export interface UpdateItemInput {
252
- readonly itemId: string;
253
- readonly body: Partial<UpdateItemRequestDto>;
254
- readonly headers?: Record<string, string>;
255
- }
256
-
257
- export async function updateItem(
258
- http: HttpClient,
259
- input: UpdateItemInput,
260
- ): Promise<IApiResponse<ItemDto>> {
261
- const path = buildPath(ITEM_PATH, { itemId: input.itemId });
262
- const { data } = await http.patch<IApiResponse<ItemDto>>(path, {
263
- data: input.body,
264
- headers: input.headers,
265
- });
266
- return data;
267
- }
268
- ```
269
-
270
- ### PUT — full replacement body
271
-
272
- Same pattern as PATCH; use when the API semantics are “replace resource”:
273
-
274
- ```typescript
275
- export async function replaceItem(
276
- http: HttpClient,
277
- input: { itemId: string; body: ReplaceItemRequestDto; headers?: Record<string, string> },
278
- ): Promise<IApiResponse<ItemDto>> {
279
- const path = buildPath('/api/v1/items/:itemId', { itemId: input.itemId });
280
- const { data } = await http.put<IApiResponse<ItemDto>>(path, {
281
- data: input.body,
282
- headers: input.headers,
283
- });
284
- return data;
285
- }
60
+ const session = await api.auth.login({ email: 'user@example.com', password: '********' });
61
+ // session.data — IApiResponse<AuthSessionResponse>; use session.data?.data for the inner payload when using Axios default response shape
286
62
  ```
287
63
 
288
- ### DELETE path params; optional body for APIs that require one
64
+ 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).
289
65
 
290
- Many DELETE endpoints have **no body**; omit `data`:
66
+ ### OAuth (mobile / web)
291
67
 
292
- ```typescript
293
- export async function deleteItem(
294
- http: HttpClient,
295
- itemId: string,
296
- headers?: Record<string, string>,
297
- ): Promise<IApiResponse<void>> {
298
- const path = buildPath('/api/v1/items/:itemId', { itemId });
299
- const { data } = await http.delete<IApiResponse<void>>(path, { headers });
300
- return data;
301
- }
302
- ```
68
+ 1. Call **`getGoogleOAuthStart`** with the same **`redirectUri`** you registered in Auth0 and in the API’s `OAUTH_ALLOWED_REDIRECT_URIS`.
69
+ 2. Open **`authorizationUrl`** in a browser / `ASWebAuthenticationSession`.
70
+ 3. After redirect, **`POST`** the **`code`**, **`state`**, and **`redirectUri`** to **`postGoogleOAuthCallback`**.
303
71
 
304
- If your API uses a JSON body on DELETE (uncommon but possible):
72
+ ### Why a factory?
305
73
 
306
- ```typescript
307
- await http.delete<IApiResponse<void>>(path, {
308
- data: { reason: 'user_request' },
309
- headers: { 'Content-Type': 'application/json' },
310
- });
311
- ```
74
+ `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.
312
75
 
313
76
  ---
314
77
 
315
- ## Wiring new endpoints into `createApiClient`
78
+ ## Architecture
316
79
 
317
- 1. Add `src/endpoints/your-endpoint.ts` with a `fetch*` / `create*` / `update*` function that takes `http` first (and an `input` object for non-trivial inputs).
318
- 2. Extend `HttpClient` if the verb is not available yet.
319
- 3. Add a method on `ApiClient` and delegate to the endpoint function.
80
+ 1. **`HttpClient`** abstraction over GET/POST (`{ data: T }` shape, Axios-compatible).
81
+ 2. **`src/endpoints/*.ts`** thin functions: `(http, …args) => Promise<…>`.
82
+ 3. **`createApiClient`** wires `http` into endpoints.
83
+ 4. **`@ipetsadmin/contracts`** — DTOs (`RegisterRequest`, `AuthSessionResponse`, …).
320
84
 
321
- Example after adding `fetchItems` and `createItem`:
322
-
323
- ```typescript
324
- // src/create-api-client.ts
325
- import { createItem } from './endpoints/create-item';
326
- import { fetchItems } from './endpoints/list-items';
327
- import { fetchHealthCheck } from './endpoints/health-check';
328
- import type { HttpClient } from './http-client';
329
-
330
- export function createApiClient(options: { http: HttpClient }) {
331
- const { http } = options;
332
-
333
- return {
334
- healthCheck: () => fetchHealthCheck(http),
335
- listItems: (params?: ListItemsParams) => fetchItems(http, params),
336
- createItem: (input: CreateItemInput) => createItem(http, input),
337
- };
338
- }
339
- ```
85
+ ### Extending further
340
86
 
341
- Export new types (`ListItemsParams`, `CreateItemInput`, etc.) from `src/index.ts` if consumers need them.
87
+ 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`).
342
88
 
343
89
  ---
344
90
 
345
91
  ## Testing
346
92
 
347
- Inject a fake `HttpClient` and assert the right URL, method, and payload were used.
348
-
349
- **With the current `HttpClient` (only `get`):**
93
+ Inject a fake **`HttpClient`** with **`get`** and **`post`** mocks and assert URLs and payloads.
350
94
 
351
95
  ```typescript
352
96
  import type { HttpClient } from '@ipetsadmin/api-client';
@@ -354,34 +98,32 @@ import { createApiClient } from '@ipetsadmin/api-client';
354
98
 
355
99
  const http: HttpClient = {
356
100
  get: jest.fn().mockResolvedValue({ data: { success: true, data: {} } }),
101
+ post: jest.fn().mockResolvedValue({ data: { success: true, data: {} } }),
357
102
  };
358
103
 
359
104
  const api = createApiClient({ http });
360
105
  await api.healthCheck();
361
-
362
106
  expect(http.get).toHaveBeenCalledWith('/api/v1/health-check', undefined);
363
107
  ```
364
108
 
365
- **After you extend `HttpClient` with `post` / `put` / `patch` / `delete`,** add matching mocks (e.g. `post: jest.fn()`) so the object satisfies the full interface.
366
-
367
109
  ---
368
110
 
369
111
  ## Development (this repository)
370
112
 
371
- | Script | Purpose |
372
- | ------------------------- | ------------------------------------------------------------------------- |
373
- | `pnpm run build` | Produce `dist/` (CJS, ESM, `.d.ts`) via [tsup](https://tsup.egoist.dev/). |
374
- | `pnpm run typecheck` | `tsc --noEmit` |
375
- | `pnpm run lint` | ESLint |
376
- | `pnpm run validate` | typecheck + lint + Prettier check |
377
- | `pnpm run prepublishOnly` | runs validate and build before publish |
113
+ | Script | Purpose |
114
+ | ------------------------- | ------------------------------------ |
115
+ | `pnpm run build` | `tsup` `dist/` (CJS, ESM, `.d.ts`) |
116
+ | `pnpm run typecheck` | `tsc --noEmit` |
117
+ | `pnpm run lint` | ESLint |
118
+ | `pnpm run validate` | typecheck + lint + Prettier check |
119
+ | `pnpm run prepublishOnly` | validate + build before publish |
378
120
 
379
121
  ---
380
122
 
381
- ## Summary
123
+ ## Changelog
124
+
125
+ See [CHANGELOG.md](./CHANGELOG.md).
382
126
 
383
- - **Today:** `createApiClient({ http })` + `healthCheck()` + `HttpClient` with **`get` only**.
384
- - **Next:** Extend `HttpClient` with `post` / `put` / `patch` / `delete` and optional `HttpRequestConfig`, then add endpoint modules that use **path helpers**, **`params`**, **`data`**, and **`headers`** as shown above.
385
- - **Types:** Prefer `@ipetsadmin/contracts` for DTOs and `IApiResponse<T>` for envelope responses.
127
+ ## License
386
128
 
387
- For changes to this package, see [CHANGELOG.md](./CHANGELOG.md).
129
+ MIT see [LICENSE](./LICENSE).
package/dist/index.d.mts CHANGED
@@ -1,20 +1,41 @@
1
- import { IApiResponse } from '@ipetsadmin/contracts';
1
+ import { RegisterRequest, IApiResponse, AuthSessionResponse, LoginRequest, OAuthGoogleStartResponse, OAuthGoogleCallbackRequest, RefreshRequest, LogoutRequest, AuthUserResponse, HealthCheck } from '@ipetsadmin/contracts';
2
2
 
3
3
  type HttpGet = <TResponse>(url: string, config?: unknown) => Promise<{
4
4
  data: TResponse;
5
5
  }>;
6
+ type HttpPost = <TResponse, TBody = unknown>(url: string, body?: TBody, config?: unknown) => Promise<{
7
+ data: TResponse;
8
+ }>;
6
9
  interface HttpClient {
7
10
  readonly get: HttpGet;
11
+ readonly post: HttpPost;
8
12
  }
9
13
 
10
- declare function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<unknown>>;
14
+ declare function postRegister(http: HttpClient, body: RegisterRequest): Promise<IApiResponse<AuthSessionResponse>>;
15
+ declare function postLogin(http: HttpClient, body: LoginRequest): Promise<IApiResponse<AuthSessionResponse>>;
16
+ declare function getGoogleOAuthStart(http: HttpClient, redirectUri: string): Promise<IApiResponse<OAuthGoogleStartResponse>>;
17
+ declare function postGoogleOAuthCallback(http: HttpClient, body: OAuthGoogleCallbackRequest): Promise<IApiResponse<AuthSessionResponse>>;
18
+ declare function postRefresh(http: HttpClient, body: RefreshRequest): Promise<IApiResponse<AuthSessionResponse>>;
19
+ declare function postLogout(http: HttpClient, body: LogoutRequest): Promise<void>;
20
+ declare function getMe(http: HttpClient, accessToken: string): Promise<IApiResponse<AuthUserResponse>>;
21
+
22
+ declare function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<HealthCheck>>;
11
23
 
12
24
  interface CreateApiClientOptions {
13
25
  readonly http: HttpClient;
14
26
  }
15
27
  interface ApiClient {
16
28
  readonly healthCheck: () => ReturnType<typeof fetchHealthCheck>;
29
+ readonly auth: {
30
+ readonly register: (body: Parameters<typeof postRegister>[1]) => ReturnType<typeof postRegister>;
31
+ readonly login: (body: Parameters<typeof postLogin>[1]) => ReturnType<typeof postLogin>;
32
+ readonly getGoogleOAuthStart: (redirectUri: string) => ReturnType<typeof getGoogleOAuthStart>;
33
+ readonly postGoogleOAuthCallback: (body: Parameters<typeof postGoogleOAuthCallback>[1]) => ReturnType<typeof postGoogleOAuthCallback>;
34
+ readonly refresh: (body: Parameters<typeof postRefresh>[1]) => ReturnType<typeof postRefresh>;
35
+ readonly logout: (body: Parameters<typeof postLogout>[1]) => ReturnType<typeof postLogout>;
36
+ readonly me: (accessToken: string) => ReturnType<typeof getMe>;
37
+ };
17
38
  }
18
39
  declare function createApiClient(options: CreateApiClientOptions): ApiClient;
19
40
 
20
- export { type ApiClient, type CreateApiClientOptions, type HttpClient, type HttpGet, createApiClient };
41
+ export { type ApiClient, type CreateApiClientOptions, type HttpClient, type HttpGet, type HttpPost, createApiClient, getGoogleOAuthStart, getMe, postGoogleOAuthCallback, postLogin, postLogout, postRefresh, postRegister };
package/dist/index.d.ts CHANGED
@@ -1,20 +1,41 @@
1
- import { IApiResponse } from '@ipetsadmin/contracts';
1
+ import { RegisterRequest, IApiResponse, AuthSessionResponse, LoginRequest, OAuthGoogleStartResponse, OAuthGoogleCallbackRequest, RefreshRequest, LogoutRequest, AuthUserResponse, HealthCheck } from '@ipetsadmin/contracts';
2
2
 
3
3
  type HttpGet = <TResponse>(url: string, config?: unknown) => Promise<{
4
4
  data: TResponse;
5
5
  }>;
6
+ type HttpPost = <TResponse, TBody = unknown>(url: string, body?: TBody, config?: unknown) => Promise<{
7
+ data: TResponse;
8
+ }>;
6
9
  interface HttpClient {
7
10
  readonly get: HttpGet;
11
+ readonly post: HttpPost;
8
12
  }
9
13
 
10
- declare function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<unknown>>;
14
+ declare function postRegister(http: HttpClient, body: RegisterRequest): Promise<IApiResponse<AuthSessionResponse>>;
15
+ declare function postLogin(http: HttpClient, body: LoginRequest): Promise<IApiResponse<AuthSessionResponse>>;
16
+ declare function getGoogleOAuthStart(http: HttpClient, redirectUri: string): Promise<IApiResponse<OAuthGoogleStartResponse>>;
17
+ declare function postGoogleOAuthCallback(http: HttpClient, body: OAuthGoogleCallbackRequest): Promise<IApiResponse<AuthSessionResponse>>;
18
+ declare function postRefresh(http: HttpClient, body: RefreshRequest): Promise<IApiResponse<AuthSessionResponse>>;
19
+ declare function postLogout(http: HttpClient, body: LogoutRequest): Promise<void>;
20
+ declare function getMe(http: HttpClient, accessToken: string): Promise<IApiResponse<AuthUserResponse>>;
21
+
22
+ declare function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<HealthCheck>>;
11
23
 
12
24
  interface CreateApiClientOptions {
13
25
  readonly http: HttpClient;
14
26
  }
15
27
  interface ApiClient {
16
28
  readonly healthCheck: () => ReturnType<typeof fetchHealthCheck>;
29
+ readonly auth: {
30
+ readonly register: (body: Parameters<typeof postRegister>[1]) => ReturnType<typeof postRegister>;
31
+ readonly login: (body: Parameters<typeof postLogin>[1]) => ReturnType<typeof postLogin>;
32
+ readonly getGoogleOAuthStart: (redirectUri: string) => ReturnType<typeof getGoogleOAuthStart>;
33
+ readonly postGoogleOAuthCallback: (body: Parameters<typeof postGoogleOAuthCallback>[1]) => ReturnType<typeof postGoogleOAuthCallback>;
34
+ readonly refresh: (body: Parameters<typeof postRefresh>[1]) => ReturnType<typeof postRefresh>;
35
+ readonly logout: (body: Parameters<typeof postLogout>[1]) => ReturnType<typeof postLogout>;
36
+ readonly me: (accessToken: string) => ReturnType<typeof getMe>;
37
+ };
17
38
  }
18
39
  declare function createApiClient(options: CreateApiClientOptions): ApiClient;
19
40
 
20
- export { type ApiClient, type CreateApiClientOptions, type HttpClient, type HttpGet, createApiClient };
41
+ export { type ApiClient, type CreateApiClientOptions, type HttpClient, type HttpGet, type HttpPost, createApiClient, getGoogleOAuthStart, getMe, postGoogleOAuthCallback, postLogin, postLogout, postRefresh, postRegister };
package/dist/index.js CHANGED
@@ -1,20 +1,83 @@
1
1
  'use strict';
2
2
 
3
+ // src/endpoints/auth.ts
4
+ var AUTH_BASE = "/api/v1/auth";
5
+ async function postRegister(http, body) {
6
+ const { data } = await http.post(
7
+ `${AUTH_BASE}/register`,
8
+ body
9
+ );
10
+ return data;
11
+ }
12
+ async function postLogin(http, body) {
13
+ const { data } = await http.post(
14
+ `${AUTH_BASE}/login`,
15
+ body
16
+ );
17
+ return data;
18
+ }
19
+ async function getGoogleOAuthStart(http, redirectUri) {
20
+ const q = new URLSearchParams({ redirectUri });
21
+ const { data } = await http.get(
22
+ `${AUTH_BASE}/oauth/google/start?${q.toString()}`
23
+ );
24
+ return data;
25
+ }
26
+ async function postGoogleOAuthCallback(http, body) {
27
+ const { data } = await http.post(
28
+ `${AUTH_BASE}/oauth/google/callback`,
29
+ body
30
+ );
31
+ return data;
32
+ }
33
+ async function postRefresh(http, body) {
34
+ const { data } = await http.post(
35
+ `${AUTH_BASE}/refresh`,
36
+ body
37
+ );
38
+ return data;
39
+ }
40
+ async function postLogout(http, body) {
41
+ await http.post(`${AUTH_BASE}/logout`, body);
42
+ }
43
+ async function getMe(http, accessToken) {
44
+ const { data } = await http.get(`${AUTH_BASE}/me`, {
45
+ headers: { Authorization: `Bearer ${accessToken}` }
46
+ });
47
+ return data;
48
+ }
49
+
3
50
  // src/endpoints/health-check.ts
4
51
  var HEALTH_CHECK_PATH = "/api/v1/health-check";
5
52
  async function fetchHealthCheck(http) {
6
- const { data } = await http.get(HEALTH_CHECK_PATH);
7
- return data;
53
+ const { data: body } = await http.get(HEALTH_CHECK_PATH);
54
+ return body;
8
55
  }
9
56
 
10
57
  // src/create-api-client.ts
11
58
  function createApiClient(options) {
12
59
  const { http } = options;
13
60
  return {
14
- healthCheck: () => fetchHealthCheck(http)
61
+ healthCheck: () => fetchHealthCheck(http),
62
+ auth: {
63
+ register: (body) => postRegister(http, body),
64
+ login: (body) => postLogin(http, body),
65
+ getGoogleOAuthStart: (redirectUri) => getGoogleOAuthStart(http, redirectUri),
66
+ postGoogleOAuthCallback: (body) => postGoogleOAuthCallback(http, body),
67
+ refresh: (body) => postRefresh(http, body),
68
+ logout: (body) => postLogout(http, body),
69
+ me: (accessToken) => getMe(http, accessToken)
70
+ }
15
71
  };
16
72
  }
17
73
 
18
74
  exports.createApiClient = createApiClient;
75
+ exports.getGoogleOAuthStart = getGoogleOAuthStart;
76
+ exports.getMe = getMe;
77
+ exports.postGoogleOAuthCallback = postGoogleOAuthCallback;
78
+ exports.postLogin = postLogin;
79
+ exports.postLogout = postLogout;
80
+ exports.postRefresh = postRefresh;
81
+ exports.postRegister = postRegister;
19
82
  //# sourceMappingURL=index.js.map
20
83
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/endpoints/health-check.ts","../src/create-api-client.ts"],"names":[],"mappings":";;;AAGA,IAAM,iBAAA,GAAoB,sBAAA;AAO1B,eAAsB,iBAAiB,IAAA,EAAkD;AACvF,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,IAA2B,iBAAiB,CAAA;AACxE,EAAA,OAAO,IAAA;AACT;;;ACKO,SAAS,gBAAgB,OAAA,EAA4C;AAC1E,EAAA,MAAM,EAAE,MAAK,GAAI,OAAA;AAEjB,EAAA,OAAO;AAAA,IACL,WAAA,EAAa,MAAM,gBAAA,CAAiB,IAAI;AAAA,GAC1C;AACF","file":"index.js","sourcesContent":["import type { IApiResponse } from '@ipetsadmin/contracts';\nimport type { HttpClient } from '../http-client';\n\nconst HEALTH_CHECK_PATH = '/api/v1/health-check' as const;\n\n/**\n * GET /api/v1/health-check — server liveness.\n * Response shape is the standard API envelope; payload typing can be refined\n * in `@ipetsadmin/contracts` when the health payload is finalized.\n */\nexport async function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<unknown>> {\n const { data } = await http.get<IApiResponse<unknown>>(HEALTH_CHECK_PATH);\n return data;\n}\n","import { fetchHealthCheck } from './endpoints/health-check';\nimport type { HttpClient } from './http-client';\n\nexport interface CreateApiClientOptions {\n /**\n * Preconfigured HTTP client (e.g. Axios instance with `baseURL` set).\n * Paths in this library are relative to that base (e.g. `/api/v1/...`).\n */\n readonly http: HttpClient;\n}\n\nexport interface ApiClient {\n readonly healthCheck: () => ReturnType<typeof fetchHealthCheck>;\n}\n\n/**\n * Creates a typed API client backed by the provided HTTP implementation.\n */\nexport function createApiClient(options: CreateApiClientOptions): ApiClient {\n const { http } = options;\n\n return {\n healthCheck: () => fetchHealthCheck(http),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/endpoints/auth.ts","../src/endpoints/health-check.ts","../src/create-api-client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type {\n AuthSessionResponse,\n AuthUserResponse,\n IApiResponse,\n LoginRequest,\n LogoutRequest,\n OAuthGoogleCallbackRequest,\n OAuthGoogleStartResponse,\n RefreshRequest,\n RegisterRequest,\n} from '@ipetsadmin/contracts';\n\nimport type { HttpClient } from '../http-client';\n\nconst AUTH_BASE = '/api/v1/auth' as const;\n\n/**\n * POST /api/v1/auth/register\n */\nexport async function postRegister(\n http: HttpClient,\n body: RegisterRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, RegisterRequest>(\n `${AUTH_BASE}/register`,\n body,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/login\n */\nexport async function postLogin(\n http: HttpClient,\n body: LoginRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, LoginRequest>(\n `${AUTH_BASE}/login`,\n body,\n );\n return data;\n}\n\n/**\n * GET /api/v1/auth/oauth/google/start?redirectUri=...\n */\nexport async function getGoogleOAuthStart(\n http: HttpClient,\n redirectUri: string,\n): Promise<IApiResponse<OAuthGoogleStartResponse>> {\n const q = new URLSearchParams({ redirectUri });\n const { data } = await http.get<IApiResponse<OAuthGoogleStartResponse>>(\n `${AUTH_BASE}/oauth/google/start?${q.toString()}`,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/oauth/google/callback\n */\nexport async function postGoogleOAuthCallback(\n http: HttpClient,\n body: OAuthGoogleCallbackRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, OAuthGoogleCallbackRequest>(\n `${AUTH_BASE}/oauth/google/callback`,\n body,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/refresh\n */\nexport async function postRefresh(\n http: HttpClient,\n body: RefreshRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, RefreshRequest>(\n `${AUTH_BASE}/refresh`,\n body,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/logout — 204 No Content (no JSON body).\n */\nexport async function postLogout(http: HttpClient, body: LogoutRequest): Promise<void> {\n await http.post<undefined, LogoutRequest>(`${AUTH_BASE}/logout`, body);\n}\n\n/**\n * GET /api/v1/auth/me — requires `Authorization: Bearer <accessToken>`.\n */\nexport async function getMe(\n http: HttpClient,\n accessToken: string,\n): Promise<IApiResponse<AuthUserResponse>> {\n const { data } = await http.get<IApiResponse<AuthUserResponse>>(`${AUTH_BASE}/me`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n return data;\n}\n","import type { IApiResponse, HealthCheck } from '@ipetsadmin/contracts';\nimport type { HttpClient } from '../http-client';\n\n/** Same path as `/api/${v1}/health-check` on the server when `v1` is the string `'v1'`. */\nconst HEALTH_CHECK_PATH = '/api/v1/health-check' as const;\n\n/**\n * GET /api/v1/health-check — server liveness.\n *\n * Returns the full JSON the server sends (`IApiResponse<HealthCheck>`).\n *\n * **Why not `data.data` here?** Adapters like Axios wrap the HTTP body in a property also\n * called `data`. That outer `data` is the entire `res.json(...)` object. The inner\n * `IApiResponse.data` is the `HealthCheck` payload — use `.data` on the **returned** value,\n * e.g. `(await fetchHealthCheck(http)).data`.\n */\nexport async function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<HealthCheck>> {\n const { data: body } = await http.get<IApiResponse<HealthCheck>>(HEALTH_CHECK_PATH);\n\n return body;\n}\n","import {\n getGoogleOAuthStart,\n getMe,\n postGoogleOAuthCallback,\n postLogin,\n postLogout,\n postRefresh,\n postRegister,\n} from './endpoints/auth';\nimport { fetchHealthCheck } from './endpoints/health-check';\nimport type { HttpClient } from './http-client';\n\nexport interface CreateApiClientOptions {\n /**\n * Preconfigured HTTP client (e.g. Axios instance with `baseURL` set).\n * Paths in this library are relative to that base (e.g. `/api/v1/...`).\n * Both `get` and `post` are required for auth flows.\n */\n readonly http: HttpClient;\n}\n\nexport interface ApiClient {\n readonly healthCheck: () => ReturnType<typeof fetchHealthCheck>;\n readonly auth: {\n readonly register: (\n body: Parameters<typeof postRegister>[1],\n ) => ReturnType<typeof postRegister>;\n readonly login: (body: Parameters<typeof postLogin>[1]) => ReturnType<typeof postLogin>;\n readonly getGoogleOAuthStart: (redirectUri: string) => ReturnType<typeof getGoogleOAuthStart>;\n readonly postGoogleOAuthCallback: (\n body: Parameters<typeof postGoogleOAuthCallback>[1],\n ) => ReturnType<typeof postGoogleOAuthCallback>;\n readonly refresh: (body: Parameters<typeof postRefresh>[1]) => ReturnType<typeof postRefresh>;\n readonly logout: (body: Parameters<typeof postLogout>[1]) => ReturnType<typeof postLogout>;\n readonly me: (accessToken: string) => ReturnType<typeof getMe>;\n };\n}\n\n/**\n * Creates a typed API client backed by the provided HTTP implementation.\n */\nexport function createApiClient(options: CreateApiClientOptions): ApiClient {\n const { http } = options;\n\n return {\n healthCheck: () => fetchHealthCheck(http),\n auth: {\n register: (body) => postRegister(http, body),\n login: (body) => postLogin(http, body),\n getGoogleOAuthStart: (redirectUri) => getGoogleOAuthStart(http, redirectUri),\n postGoogleOAuthCallback: (body) => postGoogleOAuthCallback(http, body),\n refresh: (body) => postRefresh(http, body),\n logout: (body) => postLogout(http, body),\n me: (accessToken) => getMe(http, accessToken),\n },\n };\n}\n"]}
package/dist/index.mjs CHANGED
@@ -1,18 +1,74 @@
1
+ // src/endpoints/auth.ts
2
+ var AUTH_BASE = "/api/v1/auth";
3
+ async function postRegister(http, body) {
4
+ const { data } = await http.post(
5
+ `${AUTH_BASE}/register`,
6
+ body
7
+ );
8
+ return data;
9
+ }
10
+ async function postLogin(http, body) {
11
+ const { data } = await http.post(
12
+ `${AUTH_BASE}/login`,
13
+ body
14
+ );
15
+ return data;
16
+ }
17
+ async function getGoogleOAuthStart(http, redirectUri) {
18
+ const q = new URLSearchParams({ redirectUri });
19
+ const { data } = await http.get(
20
+ `${AUTH_BASE}/oauth/google/start?${q.toString()}`
21
+ );
22
+ return data;
23
+ }
24
+ async function postGoogleOAuthCallback(http, body) {
25
+ const { data } = await http.post(
26
+ `${AUTH_BASE}/oauth/google/callback`,
27
+ body
28
+ );
29
+ return data;
30
+ }
31
+ async function postRefresh(http, body) {
32
+ const { data } = await http.post(
33
+ `${AUTH_BASE}/refresh`,
34
+ body
35
+ );
36
+ return data;
37
+ }
38
+ async function postLogout(http, body) {
39
+ await http.post(`${AUTH_BASE}/logout`, body);
40
+ }
41
+ async function getMe(http, accessToken) {
42
+ const { data } = await http.get(`${AUTH_BASE}/me`, {
43
+ headers: { Authorization: `Bearer ${accessToken}` }
44
+ });
45
+ return data;
46
+ }
47
+
1
48
  // src/endpoints/health-check.ts
2
49
  var HEALTH_CHECK_PATH = "/api/v1/health-check";
3
50
  async function fetchHealthCheck(http) {
4
- const { data } = await http.get(HEALTH_CHECK_PATH);
5
- return data;
51
+ const { data: body } = await http.get(HEALTH_CHECK_PATH);
52
+ return body;
6
53
  }
7
54
 
8
55
  // src/create-api-client.ts
9
56
  function createApiClient(options) {
10
57
  const { http } = options;
11
58
  return {
12
- healthCheck: () => fetchHealthCheck(http)
59
+ healthCheck: () => fetchHealthCheck(http),
60
+ auth: {
61
+ register: (body) => postRegister(http, body),
62
+ login: (body) => postLogin(http, body),
63
+ getGoogleOAuthStart: (redirectUri) => getGoogleOAuthStart(http, redirectUri),
64
+ postGoogleOAuthCallback: (body) => postGoogleOAuthCallback(http, body),
65
+ refresh: (body) => postRefresh(http, body),
66
+ logout: (body) => postLogout(http, body),
67
+ me: (accessToken) => getMe(http, accessToken)
68
+ }
13
69
  };
14
70
  }
15
71
 
16
- export { createApiClient };
72
+ export { createApiClient, getGoogleOAuthStart, getMe, postGoogleOAuthCallback, postLogin, postLogout, postRefresh, postRegister };
17
73
  //# sourceMappingURL=index.mjs.map
18
74
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/endpoints/health-check.ts","../src/create-api-client.ts"],"names":[],"mappings":";AAGA,IAAM,iBAAA,GAAoB,sBAAA;AAO1B,eAAsB,iBAAiB,IAAA,EAAkD;AACvF,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,MAAM,IAAA,CAAK,IAA2B,iBAAiB,CAAA;AACxE,EAAA,OAAO,IAAA;AACT;;;ACKO,SAAS,gBAAgB,OAAA,EAA4C;AAC1E,EAAA,MAAM,EAAE,MAAK,GAAI,OAAA;AAEjB,EAAA,OAAO;AAAA,IACL,WAAA,EAAa,MAAM,gBAAA,CAAiB,IAAI;AAAA,GAC1C;AACF","file":"index.mjs","sourcesContent":["import type { IApiResponse } from '@ipetsadmin/contracts';\nimport type { HttpClient } from '../http-client';\n\nconst HEALTH_CHECK_PATH = '/api/v1/health-check' as const;\n\n/**\n * GET /api/v1/health-check — server liveness.\n * Response shape is the standard API envelope; payload typing can be refined\n * in `@ipetsadmin/contracts` when the health payload is finalized.\n */\nexport async function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<unknown>> {\n const { data } = await http.get<IApiResponse<unknown>>(HEALTH_CHECK_PATH);\n return data;\n}\n","import { fetchHealthCheck } from './endpoints/health-check';\nimport type { HttpClient } from './http-client';\n\nexport interface CreateApiClientOptions {\n /**\n * Preconfigured HTTP client (e.g. Axios instance with `baseURL` set).\n * Paths in this library are relative to that base (e.g. `/api/v1/...`).\n */\n readonly http: HttpClient;\n}\n\nexport interface ApiClient {\n readonly healthCheck: () => ReturnType<typeof fetchHealthCheck>;\n}\n\n/**\n * Creates a typed API client backed by the provided HTTP implementation.\n */\nexport function createApiClient(options: CreateApiClientOptions): ApiClient {\n const { http } = options;\n\n return {\n healthCheck: () => fetchHealthCheck(http),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/endpoints/auth.ts","../src/endpoints/health-check.ts","../src/create-api-client.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type {\n AuthSessionResponse,\n AuthUserResponse,\n IApiResponse,\n LoginRequest,\n LogoutRequest,\n OAuthGoogleCallbackRequest,\n OAuthGoogleStartResponse,\n RefreshRequest,\n RegisterRequest,\n} from '@ipetsadmin/contracts';\n\nimport type { HttpClient } from '../http-client';\n\nconst AUTH_BASE = '/api/v1/auth' as const;\n\n/**\n * POST /api/v1/auth/register\n */\nexport async function postRegister(\n http: HttpClient,\n body: RegisterRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, RegisterRequest>(\n `${AUTH_BASE}/register`,\n body,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/login\n */\nexport async function postLogin(\n http: HttpClient,\n body: LoginRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, LoginRequest>(\n `${AUTH_BASE}/login`,\n body,\n );\n return data;\n}\n\n/**\n * GET /api/v1/auth/oauth/google/start?redirectUri=...\n */\nexport async function getGoogleOAuthStart(\n http: HttpClient,\n redirectUri: string,\n): Promise<IApiResponse<OAuthGoogleStartResponse>> {\n const q = new URLSearchParams({ redirectUri });\n const { data } = await http.get<IApiResponse<OAuthGoogleStartResponse>>(\n `${AUTH_BASE}/oauth/google/start?${q.toString()}`,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/oauth/google/callback\n */\nexport async function postGoogleOAuthCallback(\n http: HttpClient,\n body: OAuthGoogleCallbackRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, OAuthGoogleCallbackRequest>(\n `${AUTH_BASE}/oauth/google/callback`,\n body,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/refresh\n */\nexport async function postRefresh(\n http: HttpClient,\n body: RefreshRequest,\n): Promise<IApiResponse<AuthSessionResponse>> {\n const { data } = await http.post<IApiResponse<AuthSessionResponse>, RefreshRequest>(\n `${AUTH_BASE}/refresh`,\n body,\n );\n return data;\n}\n\n/**\n * POST /api/v1/auth/logout — 204 No Content (no JSON body).\n */\nexport async function postLogout(http: HttpClient, body: LogoutRequest): Promise<void> {\n await http.post<undefined, LogoutRequest>(`${AUTH_BASE}/logout`, body);\n}\n\n/**\n * GET /api/v1/auth/me — requires `Authorization: Bearer <accessToken>`.\n */\nexport async function getMe(\n http: HttpClient,\n accessToken: string,\n): Promise<IApiResponse<AuthUserResponse>> {\n const { data } = await http.get<IApiResponse<AuthUserResponse>>(`${AUTH_BASE}/me`, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n return data;\n}\n","import type { IApiResponse, HealthCheck } from '@ipetsadmin/contracts';\nimport type { HttpClient } from '../http-client';\n\n/** Same path as `/api/${v1}/health-check` on the server when `v1` is the string `'v1'`. */\nconst HEALTH_CHECK_PATH = '/api/v1/health-check' as const;\n\n/**\n * GET /api/v1/health-check — server liveness.\n *\n * Returns the full JSON the server sends (`IApiResponse<HealthCheck>`).\n *\n * **Why not `data.data` here?** Adapters like Axios wrap the HTTP body in a property also\n * called `data`. That outer `data` is the entire `res.json(...)` object. The inner\n * `IApiResponse.data` is the `HealthCheck` payload — use `.data` on the **returned** value,\n * e.g. `(await fetchHealthCheck(http)).data`.\n */\nexport async function fetchHealthCheck(http: HttpClient): Promise<IApiResponse<HealthCheck>> {\n const { data: body } = await http.get<IApiResponse<HealthCheck>>(HEALTH_CHECK_PATH);\n\n return body;\n}\n","import {\n getGoogleOAuthStart,\n getMe,\n postGoogleOAuthCallback,\n postLogin,\n postLogout,\n postRefresh,\n postRegister,\n} from './endpoints/auth';\nimport { fetchHealthCheck } from './endpoints/health-check';\nimport type { HttpClient } from './http-client';\n\nexport interface CreateApiClientOptions {\n /**\n * Preconfigured HTTP client (e.g. Axios instance with `baseURL` set).\n * Paths in this library are relative to that base (e.g. `/api/v1/...`).\n * Both `get` and `post` are required for auth flows.\n */\n readonly http: HttpClient;\n}\n\nexport interface ApiClient {\n readonly healthCheck: () => ReturnType<typeof fetchHealthCheck>;\n readonly auth: {\n readonly register: (\n body: Parameters<typeof postRegister>[1],\n ) => ReturnType<typeof postRegister>;\n readonly login: (body: Parameters<typeof postLogin>[1]) => ReturnType<typeof postLogin>;\n readonly getGoogleOAuthStart: (redirectUri: string) => ReturnType<typeof getGoogleOAuthStart>;\n readonly postGoogleOAuthCallback: (\n body: Parameters<typeof postGoogleOAuthCallback>[1],\n ) => ReturnType<typeof postGoogleOAuthCallback>;\n readonly refresh: (body: Parameters<typeof postRefresh>[1]) => ReturnType<typeof postRefresh>;\n readonly logout: (body: Parameters<typeof postLogout>[1]) => ReturnType<typeof postLogout>;\n readonly me: (accessToken: string) => ReturnType<typeof getMe>;\n };\n}\n\n/**\n * Creates a typed API client backed by the provided HTTP implementation.\n */\nexport function createApiClient(options: CreateApiClientOptions): ApiClient {\n const { http } = options;\n\n return {\n healthCheck: () => fetchHealthCheck(http),\n auth: {\n register: (body) => postRegister(http, body),\n login: (body) => postLogin(http, body),\n getGoogleOAuthStart: (redirectUri) => getGoogleOAuthStart(http, redirectUri),\n postGoogleOAuthCallback: (body) => postGoogleOAuthCallback(http, body),\n refresh: (body) => postRefresh(http, body),\n logout: (body) => postLogout(http, body),\n me: (accessToken) => getMe(http, accessToken),\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ipetsadmin/api-client",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Client used to interact with Truffa project API",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -38,7 +38,7 @@
38
38
  "author": "",
39
39
  "license": "MIT",
40
40
  "devDependencies": {
41
- "@ipetsadmin/contracts": "^1.0.3",
41
+ "@ipetsadmin/contracts": "1.1.2",
42
42
  "@eslint/js": "^10.0.1",
43
43
  "@types/express": "^5.0.5",
44
44
  "@types/node": "^24.10.0",
@@ -52,7 +52,7 @@
52
52
  "typescript-eslint": "^8.58.0"
53
53
  },
54
54
  "peerDependencies": {
55
- "@ipetsadmin/contracts": "^1.0.0"
55
+ "@ipetsadmin/contracts": ">=1.1.1"
56
56
  },
57
57
  "publishConfig": {
58
58
  "access": "public"