@ma-dev/api-client 0.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/README.md +93 -0
- package/dist/http.d.ts +70 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +113 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/tokenStore.d.ts +25 -0
- package/dist/tokenStore.d.ts.map +1 -0
- package/dist/tokenStore.js +28 -0
- package/dist/tokenStore.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# @ma-dev/api-client
|
|
2
|
+
|
|
3
|
+
Shared HTTP client infrastructure for frontend projects.
|
|
4
|
+
|
|
5
|
+
## What's inside
|
|
6
|
+
|
|
7
|
+
| Export | Description |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `createHttpClient(config)` | Factory that returns a typed fetch wrapper with auto-auth injection |
|
|
10
|
+
| `ApiError` | Structured error class thrown on non-2xx responses |
|
|
11
|
+
| `tokenStore` | Imperative singleton for storing the current bearer token |
|
|
12
|
+
| `ApiResponse<T>` | Generic response envelope matching the NWC API contract |
|
|
13
|
+
| `HttpClient` | Inferred type of the object returned by `createHttpClient` |
|
|
14
|
+
| `HttpClientConfig` | Config interface for `createHttpClient` |
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Local reference (during development)
|
|
20
|
+
bun add ../nwc-api-client
|
|
21
|
+
|
|
22
|
+
# Once published to a private registry
|
|
23
|
+
bun add @ma-dev/api-client
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick start
|
|
27
|
+
|
|
28
|
+
### 1. Create your project's HTTP client singleton
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// src/lib/client.ts
|
|
32
|
+
import { createHttpClient, tokenStore } from "@ma-dev/api-client";
|
|
33
|
+
|
|
34
|
+
export const httpClient = createHttpClient({
|
|
35
|
+
baseUrl: import.meta.env.VITE_API_URL,
|
|
36
|
+
getToken: tokenStore.getToken,
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Sync the token store from your auth state
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// After login
|
|
44
|
+
tokenStore.setToken(authData.token);
|
|
45
|
+
|
|
46
|
+
// After logout
|
|
47
|
+
tokenStore.setToken(null);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 3. Create domain services
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// src/services/account.service.ts
|
|
54
|
+
import { httpClient } from "../lib/client";
|
|
55
|
+
import type { ApiResponse } from "@ma-dev/api-client";
|
|
56
|
+
|
|
57
|
+
interface LoginData { token: string; userId: string; roles: string[]; }
|
|
58
|
+
type LoginResponse = ApiResponse<LoginData>;
|
|
59
|
+
|
|
60
|
+
export const accountService = {
|
|
61
|
+
login: (username: string, password: string) =>
|
|
62
|
+
httpClient.post<LoginResponse>("/account/login", { username, password }),
|
|
63
|
+
};
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 4. Handle errors
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { ApiError } from "@ma-dev/api-client";
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
await accountService.login(username, password);
|
|
73
|
+
} catch (err) {
|
|
74
|
+
if (err instanceof ApiError) {
|
|
75
|
+
console.error(`HTTP ${err.status}: ${err.message}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Building the package
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
bun install
|
|
84
|
+
bun run build # outputs to dist/
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Publishing (when ready)
|
|
88
|
+
|
|
89
|
+
Update `package.json` to point at your private registry, then:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
bun publish
|
|
93
|
+
```
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thrown by `createHttpClient` when the server responds with a non-2xx status.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* import { ApiError } from "@ma-dev/api-client";
|
|
6
|
+
*
|
|
7
|
+
* try {
|
|
8
|
+
* await accountService.login(username, password);
|
|
9
|
+
* } catch (err) {
|
|
10
|
+
* if (err instanceof ApiError) {
|
|
11
|
+
* console.error(err.status, err.message, err.body);
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
export declare class ApiError extends Error {
|
|
16
|
+
/** HTTP status code (e.g. 401, 403, 500). */
|
|
17
|
+
readonly status: number;
|
|
18
|
+
/** Raw parsed response body — useful for logging / debug. */
|
|
19
|
+
readonly body?: unknown | undefined;
|
|
20
|
+
constructor(
|
|
21
|
+
/** HTTP status code (e.g. 401, 403, 500). */
|
|
22
|
+
status: number,
|
|
23
|
+
/** Human-readable description extracted from the response body. */
|
|
24
|
+
message: string,
|
|
25
|
+
/** Raw parsed response body — useful for logging / debug. */
|
|
26
|
+
body?: unknown | undefined);
|
|
27
|
+
}
|
|
28
|
+
type TokenGetter = () => string | null;
|
|
29
|
+
export interface HttpClientConfig {
|
|
30
|
+
/**
|
|
31
|
+
* Base URL prepended to every request path.
|
|
32
|
+
* No trailing slash: `"https://api.example.com/v1"`.
|
|
33
|
+
*/
|
|
34
|
+
baseUrl: string;
|
|
35
|
+
/**
|
|
36
|
+
* Optional callback that returns the current bearer token.
|
|
37
|
+
* The token is read on every request so rotation is transparent.
|
|
38
|
+
*/
|
|
39
|
+
getToken?: TokenGetter;
|
|
40
|
+
/** Static headers merged into every request (e.g. custom API keys). */
|
|
41
|
+
defaultHeaders?: Record<string, string>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates a thin, fully-typed `fetch` wrapper.
|
|
45
|
+
*
|
|
46
|
+
* Features:
|
|
47
|
+
* - Prepends `baseUrl` to every path.
|
|
48
|
+
* - Injects `Authorization: Bearer <token>` when `getToken` returns a value.
|
|
49
|
+
* - Throws `ApiError` on non-2xx responses with a structured message.
|
|
50
|
+
* - Generic return types — callers get typed response bodies with zero casting.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* import { createHttpClient, tokenStore } from "@ma-dev/api-client";
|
|
54
|
+
*
|
|
55
|
+
* export const httpClient = createHttpClient({
|
|
56
|
+
* baseUrl: import.meta.env.VITE_API_URL,
|
|
57
|
+
* getToken: tokenStore.getToken,
|
|
58
|
+
* });
|
|
59
|
+
*/
|
|
60
|
+
export declare function createHttpClient({ baseUrl, getToken, defaultHeaders, }: HttpClientConfig): {
|
|
61
|
+
get: <T>(path: string, headers?: HeadersInit) => Promise<T>;
|
|
62
|
+
post: <T>(path: string, body: unknown, headers?: HeadersInit) => Promise<T>;
|
|
63
|
+
put: <T>(path: string, body: unknown, headers?: HeadersInit) => Promise<T>;
|
|
64
|
+
patch: <T>(path: string, body: unknown, headers?: HeadersInit) => Promise<T>;
|
|
65
|
+
delete: <T>(path: string, headers?: HeadersInit) => Promise<T>;
|
|
66
|
+
};
|
|
67
|
+
/** Inferred type of the object returned by `createHttpClient`. */
|
|
68
|
+
export type HttpClient = ReturnType<typeof createHttpClient>;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AACH,qBAAa,QAAS,SAAQ,KAAK;IAE/B,6CAA6C;aAC7B,MAAM,EAAE,MAAM;IAG9B,6DAA6D;aAC7C,IAAI,CAAC,EAAE,OAAO;;IAL9B,6CAA6C;IAC7B,MAAM,EAAE,MAAM;IAC9B,mEAAmE;IACnE,OAAO,EAAE,MAAM;IACf,6DAA6D;IAC7C,IAAI,CAAC,EAAE,OAAO,YAAA;CAOjC;AAmCD,KAAK,WAAW,GAAG,MAAM,MAAM,GAAG,IAAI,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,cAAmB,GACpB,EAAE,gBAAgB;UA2CT,CAAC,QAAQ,MAAM,YAAY,WAAW;WAGrC,CAAC,QAAQ,MAAM,QAAQ,OAAO,YAAY,WAAW;UAGtD,CAAC,QAAQ,MAAM,QAAQ,OAAO,YAAY,WAAW;YAGnD,CAAC,QAAQ,MAAM,QAAQ,OAAO,YAAY,WAAW;aAGpD,CAAC,QAAQ,MAAM,YAAY,WAAW;EAGlD;AAED,kEAAkE;AAClE,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// ApiError – structured error thrown for non-2xx HTTP responses
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
/**
|
|
5
|
+
* Thrown by `createHttpClient` when the server responds with a non-2xx status.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { ApiError } from "@ma-dev/api-client";
|
|
9
|
+
*
|
|
10
|
+
* try {
|
|
11
|
+
* await accountService.login(username, password);
|
|
12
|
+
* } catch (err) {
|
|
13
|
+
* if (err instanceof ApiError) {
|
|
14
|
+
* console.error(err.status, err.message, err.body);
|
|
15
|
+
* }
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
export class ApiError extends Error {
|
|
19
|
+
status;
|
|
20
|
+
body;
|
|
21
|
+
constructor(
|
|
22
|
+
/** HTTP status code (e.g. 401, 403, 500). */
|
|
23
|
+
status,
|
|
24
|
+
/** Human-readable description extracted from the response body. */
|
|
25
|
+
message,
|
|
26
|
+
/** Raw parsed response body — useful for logging / debug. */
|
|
27
|
+
body) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.status = status;
|
|
30
|
+
this.body = body;
|
|
31
|
+
this.name = "ApiError";
|
|
32
|
+
// Ensures correct `instanceof` checks after TypeScript transpilation.
|
|
33
|
+
Object.setPrototypeOf(this, ApiError.prototype);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Internal helpers
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
async function parseBody(res) {
|
|
40
|
+
const ct = res.headers.get("Content-Type") ?? "";
|
|
41
|
+
try {
|
|
42
|
+
if (ct.includes("application/json") || ct.includes("text/plain")) {
|
|
43
|
+
return await res.json();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Body may be empty or unparseable — treat as null
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
function extractErrorMessage(body, fallback) {
|
|
52
|
+
if (body && typeof body === "object") {
|
|
53
|
+
const b = body;
|
|
54
|
+
return ((typeof b.message === "string" && b.message) ||
|
|
55
|
+
(typeof b.title === "string" && b.title) ||
|
|
56
|
+
(typeof b.detail === "string" && b.detail) ||
|
|
57
|
+
fallback);
|
|
58
|
+
}
|
|
59
|
+
return fallback;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Creates a thin, fully-typed `fetch` wrapper.
|
|
63
|
+
*
|
|
64
|
+
* Features:
|
|
65
|
+
* - Prepends `baseUrl` to every path.
|
|
66
|
+
* - Injects `Authorization: Bearer <token>` when `getToken` returns a value.
|
|
67
|
+
* - Throws `ApiError` on non-2xx responses with a structured message.
|
|
68
|
+
* - Generic return types — callers get typed response bodies with zero casting.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* import { createHttpClient, tokenStore } from "@ma-dev/api-client";
|
|
72
|
+
*
|
|
73
|
+
* export const httpClient = createHttpClient({
|
|
74
|
+
* baseUrl: import.meta.env.VITE_API_URL,
|
|
75
|
+
* getToken: tokenStore.getToken,
|
|
76
|
+
* });
|
|
77
|
+
*/
|
|
78
|
+
export function createHttpClient({ baseUrl, getToken, defaultHeaders = {}, }) {
|
|
79
|
+
function buildHeaders(extra = {}) {
|
|
80
|
+
const headers = new Headers({
|
|
81
|
+
"Content-Type": "application/json",
|
|
82
|
+
Accept: "application/json, text/plain",
|
|
83
|
+
...defaultHeaders,
|
|
84
|
+
...extra,
|
|
85
|
+
});
|
|
86
|
+
const token = getToken?.();
|
|
87
|
+
if (token) {
|
|
88
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
89
|
+
}
|
|
90
|
+
return headers;
|
|
91
|
+
}
|
|
92
|
+
async function request(method, path, body, headers) {
|
|
93
|
+
const res = await fetch(`${baseUrl}${path}`, {
|
|
94
|
+
method,
|
|
95
|
+
headers: buildHeaders(headers),
|
|
96
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
97
|
+
});
|
|
98
|
+
const parsed = await parseBody(res);
|
|
99
|
+
if (!res.ok) {
|
|
100
|
+
const message = extractErrorMessage(parsed, `Request failed with status ${res.status}`);
|
|
101
|
+
throw new ApiError(res.status, message, parsed);
|
|
102
|
+
}
|
|
103
|
+
return parsed;
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
get: (path, headers) => request("GET", path, undefined, headers),
|
|
107
|
+
post: (path, body, headers) => request("POST", path, body, headers),
|
|
108
|
+
put: (path, body, headers) => request("PUT", path, body, headers),
|
|
109
|
+
patch: (path, body, headers) => request("PATCH", path, body, headers),
|
|
110
|
+
delete: (path, headers) => request("DELETE", path, undefined, headers),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ma-dev/api-client
|
|
3
|
+
*
|
|
4
|
+
* Public API surface of the package.
|
|
5
|
+
* Import everything your project needs from this single entry point.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { createHttpClient, tokenStore, ApiError } from "@ma-dev/api-client";
|
|
9
|
+
* import type { ApiResponse, HttpClient, HttpClientConfig } from "@ma-dev/api-client";
|
|
10
|
+
*/
|
|
11
|
+
export { ApiError, createHttpClient, } from "./http";
|
|
12
|
+
export type { HttpClient, HttpClientConfig, } from "./http";
|
|
13
|
+
export { tokenStore } from "./tokenStore";
|
|
14
|
+
export type { ApiResponse } from "./types";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EACL,QAAQ,EACR,gBAAgB,GACjB,MAAM,QAAQ,CAAC;AAChB,YAAY,EACV,UAAU,EACV,gBAAgB,GACjB,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ma-dev/api-client
|
|
3
|
+
*
|
|
4
|
+
* Public API surface of the package.
|
|
5
|
+
* Import everything your project needs from this single entry point.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { createHttpClient, tokenStore, ApiError } from "@ma-dev/api-client";
|
|
9
|
+
* import type { ApiResponse, HttpClient, HttpClientConfig } from "@ma-dev/api-client";
|
|
10
|
+
*/
|
|
11
|
+
// HTTP client factory + error class
|
|
12
|
+
export { ApiError, createHttpClient, } from "./http";
|
|
13
|
+
// Token store singleton
|
|
14
|
+
export { tokenStore } from "./tokenStore";
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,oCAAoC;AACpC,OAAO,EACL,QAAQ,EACR,gBAAgB,GACjB,MAAM,QAAQ,CAAC;AAMhB,wBAAwB;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level token store.
|
|
3
|
+
*
|
|
4
|
+
* An imperative singleton that holds the current bearer token so the HTTP
|
|
5
|
+
* client can read it without React context or function-argument drilling.
|
|
6
|
+
*
|
|
7
|
+
* The consuming app's state layer (e.g. AppProvider) is responsible for
|
|
8
|
+
* calling `setToken` whenever authentication state changes.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* import { tokenStore } from "@ma-dev/api-client";
|
|
12
|
+
*
|
|
13
|
+
* // After login:
|
|
14
|
+
* tokenStore.setToken(response.data.token);
|
|
15
|
+
*
|
|
16
|
+
* // After logout:
|
|
17
|
+
* tokenStore.setToken(null);
|
|
18
|
+
*/
|
|
19
|
+
export declare const tokenStore: {
|
|
20
|
+
/** Returns the active bearer token, or `null` when unauthenticated. */
|
|
21
|
+
getToken: () => string | null;
|
|
22
|
+
/** Persist a new token. Call after login or token refresh. */
|
|
23
|
+
setToken: (token: string | null) => void;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=tokenStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenStore.d.ts","sourceRoot":"","sources":["../src/tokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,eAAO,MAAM,UAAU;IACrB,uEAAuE;oBACzD,MAAM,GAAG,IAAI;IAE3B,8DAA8D;sBAC5C,MAAM,GAAG,IAAI,KAAG,IAAI;CAGvC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module-level token store.
|
|
3
|
+
*
|
|
4
|
+
* An imperative singleton that holds the current bearer token so the HTTP
|
|
5
|
+
* client can read it without React context or function-argument drilling.
|
|
6
|
+
*
|
|
7
|
+
* The consuming app's state layer (e.g. AppProvider) is responsible for
|
|
8
|
+
* calling `setToken` whenever authentication state changes.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* import { tokenStore } from "@ma-dev/api-client";
|
|
12
|
+
*
|
|
13
|
+
* // After login:
|
|
14
|
+
* tokenStore.setToken(response.data.token);
|
|
15
|
+
*
|
|
16
|
+
* // After logout:
|
|
17
|
+
* tokenStore.setToken(null);
|
|
18
|
+
*/
|
|
19
|
+
let _token = null;
|
|
20
|
+
export const tokenStore = {
|
|
21
|
+
/** Returns the active bearer token, or `null` when unauthenticated. */
|
|
22
|
+
getToken: () => _token,
|
|
23
|
+
/** Persist a new token. Call after login or token refresh. */
|
|
24
|
+
setToken: (token) => {
|
|
25
|
+
_token = token;
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=tokenStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenStore.js","sourceRoot":"","sources":["../src/tokenStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,uEAAuE;IACvE,QAAQ,EAAE,GAAkB,EAAE,CAAC,MAAM;IAErC,8DAA8D;IAC9D,QAAQ,EAAE,CAAC,KAAoB,EAAQ,EAAE;QACvC,MAAM,GAAG,KAAK,CAAC;IACjB,CAAC;CACF,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic API envelope.
|
|
3
|
+
*
|
|
4
|
+
* Every NWC backend endpoint wraps its payload in this shape.
|
|
5
|
+
* Consuming projects extend it with their own domain-specific response types:
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import type { ApiResponse } from "@ma-dev/api-client";
|
|
9
|
+
*
|
|
10
|
+
* interface LoginData { token: string; userId: string; ... }
|
|
11
|
+
* type LoginResponse = ApiResponse<LoginData>;
|
|
12
|
+
*/
|
|
13
|
+
export interface ApiResponse<T = undefined> {
|
|
14
|
+
succeeded: boolean;
|
|
15
|
+
message: string;
|
|
16
|
+
errors?: string[] | null;
|
|
17
|
+
/** Present on validation / ProblemDetails error responses. */
|
|
18
|
+
status?: number;
|
|
19
|
+
title?: string;
|
|
20
|
+
type?: string;
|
|
21
|
+
detail?: string;
|
|
22
|
+
/** Present on successful responses that carry a payload. */
|
|
23
|
+
data?: T;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,SAAS;IACxC,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACzB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,CAAC;CACV"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ma-dev/api-client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Shared HTTP client and token store for frontend projects.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"dev": "tsc --watch"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"typescript": "^6.0.3"
|
|
23
|
+
}
|
|
24
|
+
}
|