@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 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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,gEAAgE;AAChE,8EAA8E;AAE9E;;;;;;;;;;;;;GAaG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGf;IAIA;IANlB;IACE,6CAA6C;IAC7B,MAAc;IAC9B,mEAAmE;IACnE,OAAe;IACf,6DAA6D;IAC7C,IAAc;QAE9B,KAAK,CAAC,OAAO,CAAC,CAAC;QANC,WAAM,GAAN,MAAM,CAAQ;QAId,SAAI,GAAJ,IAAI,CAAU;QAG9B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,sEAAsE;QACtE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClD,CAAC;CACF;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,KAAK,UAAU,SAAS,CAAC,GAAa;IACpC,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IACjD,IAAI,CAAC;QACH,IAAI,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACjE,OAAO,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC1B,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,mDAAmD;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,mBAAmB,CAAC,IAAa,EAAE,QAAgB;IAC1D,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAA+B,CAAC;QAC1C,OAAO,CACL,CAAC,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC;YAC5C,CAAC,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC;YACxC,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,CAAC;YAC1C,QAAQ,CACT,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAuBD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAC/B,OAAO,EACP,QAAQ,EACR,cAAc,GAAG,EAAE,GACF;IACjB,SAAS,YAAY,CAAC,QAAqB,EAAE;QAC3C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC;YAC1B,cAAc,EAAE,kBAAkB;YAClC,MAAM,EAAE,8BAA8B;YACtC,GAAG,cAAc;YACjB,GAAI,KAAgC;SACrC,CAAC,CAAC;QAEH,MAAM,KAAK,GAAG,QAAQ,EAAE,EAAE,CAAC;QAC3B,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,UAAU,OAAO,CACpB,MAAc,EACd,IAAY,EACZ,IAAc,EACd,OAAqB;QAErB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,GAAG,IAAI,EAAE,EAAE;YAC3C,MAAM;YACN,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC;YAC9B,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC5D,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,OAAO,GAAG,mBAAmB,CACjC,MAAM,EACN,8BAA8B,GAAG,CAAC,MAAM,EAAE,CAC3C,CAAC;YACF,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAClD,CAAC;QAED,OAAO,MAAmB,CAAC;IAC7B,CAAC;IAED,OAAO;QACL,GAAG,EAAE,CAAI,IAAY,EAAE,OAAqB,EAAE,EAAE,CAC9C,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC;QAE7C,IAAI,EAAE,CAAI,IAAY,EAAE,IAAa,EAAE,OAAqB,EAAE,EAAE,CAC9D,OAAO,CAAI,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC;QAEzC,GAAG,EAAE,CAAI,IAAY,EAAE,IAAa,EAAE,OAAqB,EAAE,EAAE,CAC7D,OAAO,CAAI,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC;QAExC,KAAK,EAAE,CAAI,IAAY,EAAE,IAAa,EAAE,OAAqB,EAAE,EAAE,CAC/D,OAAO,CAAI,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC;QAE1C,MAAM,EAAE,CAAI,IAAY,EAAE,OAAqB,EAAE,EAAE,CACjD,OAAO,CAAI,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC;KACjD,CAAC;AACJ,CAAC"}
@@ -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"}
@@ -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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -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
+ }