@nomalism-com/api 0.45.63 → 0.45.64

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/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
1
  import * as Nomalism from './main';
2
+ export { ApiError, isApiError, parseApiError } from './lib/apiError';
3
+ export type { ApiErrorKind, IApiErrorFields } from './lib/apiError';
2
4
  export default Nomalism;
package/dist/index.js CHANGED
@@ -129,9 +129,77 @@ __export(main_exports, {
129
129
  Workflow: () => workflow_exports,
130
130
  ZipCode: () => zipCode_exports
131
131
  });
132
- import axios, { AxiosHeaders } from "axios";
132
+ import axios2, { AxiosHeaders } from "axios";
133
133
  import Nomalism from "@nomalism-com/types";
134
134
 
135
+ // src/lib/apiError.ts
136
+ import axios from "axios";
137
+ var ApiError = class _ApiError extends Error {
138
+ constructor(fields, cause) {
139
+ super(fields.message);
140
+ this.name = "ApiError";
141
+ this.kind = fields.kind;
142
+ this.status = fields.status;
143
+ this.code = fields.code;
144
+ this.method = fields.method;
145
+ this.url = fields.url;
146
+ this.data = fields.data;
147
+ Object.defineProperty(this, "cause", {
148
+ value: cause,
149
+ enumerable: false,
150
+ writable: false,
151
+ configurable: true
152
+ });
153
+ const captureStackTrace = Error.captureStackTrace;
154
+ captureStackTrace?.(this, _ApiError);
155
+ }
156
+ /** Controls what `JSON.stringify(err)` and most loggers emit — kept compact. */
157
+ toJSON() {
158
+ return {
159
+ kind: this.kind,
160
+ message: this.message,
161
+ status: this.status,
162
+ code: this.code,
163
+ method: this.method,
164
+ url: this.url,
165
+ data: this.data
166
+ };
167
+ }
168
+ };
169
+ function isApiError(error) {
170
+ return error instanceof ApiError;
171
+ }
172
+ function extractServerMessage(data, fallback) {
173
+ if (typeof data === "string" && data.trim()) return data;
174
+ if (data && typeof data === "object") {
175
+ const record = data;
176
+ const candidate = record.message ?? record.error ?? record.detail ?? record.title;
177
+ if (typeof candidate === "string" && candidate.trim()) return candidate;
178
+ }
179
+ return fallback;
180
+ }
181
+ function parseApiError(error) {
182
+ if (error instanceof ApiError) return error;
183
+ if (!axios.isAxiosError(error)) {
184
+ const message = error instanceof Error ? error.message : String(error);
185
+ return new ApiError({ kind: "unknown", message }, error);
186
+ }
187
+ const axiosError = error;
188
+ const method = axiosError.config?.method?.toUpperCase();
189
+ const url = axiosError.config?.url;
190
+ const code = axiosError.code;
191
+ if (axiosError.response) {
192
+ const { status, data } = axiosError.response;
193
+ const message = extractServerMessage(data, `Request failed with status ${status}`);
194
+ return new ApiError({ kind: "response", message, status, code, method, url, data }, error);
195
+ }
196
+ if (axiosError.request) {
197
+ const message = code === "ECONNABORTED" ? `Request timed out${url ? ` (${method} ${url})` : ""}` : `No response received${url ? ` from ${method} ${url}` : ""}`;
198
+ return new ApiError({ kind: "request", message, code, method, url }, error);
199
+ }
200
+ return new ApiError({ kind: "setup", message: axiosError.message, code, method, url }, error);
201
+ }
202
+
135
203
  // src/modules/view/webSocket.ts
136
204
  var CLOSE_AUTH_REJECTED = 4401;
137
205
  var CLOSE_AUTH_UNAVAILABLE = 4503;
@@ -4453,10 +4521,14 @@ var API = class {
4453
4521
  if (tokenBearer) {
4454
4522
  this.defaultHeaders.setAuthorization(tokenBearer);
4455
4523
  }
4456
- this.client = axios.create({
4524
+ this.client = axios2.create({
4457
4525
  baseURL: gatewayUrl,
4458
4526
  headers: this.defaultHeaders
4459
4527
  });
4528
+ this.client.interceptors.response.use(
4529
+ (response) => response,
4530
+ (error) => Promise.reject(parseApiError(error))
4531
+ );
4460
4532
  const getServicePath = (service) => {
4461
4533
  const baseUrl = services[service];
4462
4534
  const servicePath = processEnvironment === "localhost" ? "/" : `${service}/`;
@@ -4749,5 +4821,8 @@ var API = class {
4749
4821
  // src/index.ts
4750
4822
  var index_default = main_exports;
4751
4823
  export {
4752
- index_default as default
4824
+ ApiError,
4825
+ index_default as default,
4826
+ isApiError,
4827
+ parseApiError
4753
4828
  };
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Where the failure happened in the axios lifecycle.
3
+ *
4
+ * - `response` — the server replied with a non-2xx status (HTTP / application layer).
5
+ * - `request` — the request was sent but no response came back (network, timeout, CORS, offline).
6
+ * - `setup` — the request was never sent (bad config, invalid URL, serialization error).
7
+ * - `unknown` — the thrown value was not an axios error at all.
8
+ */
9
+ export type ApiErrorKind = 'response' | 'request' | 'setup' | 'unknown';
10
+ export interface IApiErrorFields {
11
+ kind: ApiErrorKind;
12
+ message: string;
13
+ status?: number;
14
+ code?: string;
15
+ method?: string;
16
+ url?: string;
17
+ data?: unknown;
18
+ }
19
+ /**
20
+ * A compact, log-friendly error that replaces axios's huge error object.
21
+ *
22
+ * Only small primitives are kept as enumerable fields, so `console.log(err)`,
23
+ * `JSON.stringify(err)` and `err.stack` stay short. The original axios error is
24
+ * preserved on a NON-enumerable `cause` property — available for deep debugging,
25
+ * but never dumped when the error is logged.
26
+ */
27
+ export declare class ApiError extends Error {
28
+ readonly kind: ApiErrorKind;
29
+ /** HTTP status code, when the server responded. */
30
+ readonly status?: number;
31
+ /** Axios error code, e.g. 'ECONNABORTED', 'ERR_NETWORK', 'ERR_BAD_REQUEST'. */
32
+ readonly code?: string;
33
+ /** HTTP method of the failed request, uppercased. */
34
+ readonly method?: string;
35
+ /** Request URL (baseURL + path) of the failed request. */
36
+ readonly url?: string;
37
+ /** The server-provided error payload (response body), when present. */
38
+ readonly data?: unknown;
39
+ constructor(fields: IApiErrorFields, cause?: unknown);
40
+ /** Controls what `JSON.stringify(err)` and most loggers emit — kept compact. */
41
+ toJSON(): IApiErrorFields;
42
+ }
43
+ /** Type guard for the simplified error. */
44
+ export declare function isApiError(error: unknown): error is ApiError;
45
+ /**
46
+ * Convert ANY thrown value into a compact {@link ApiError}.
47
+ *
48
+ * This is the single, DRY place that understands axios's four failure modes,
49
+ * so individual modules never have to inspect `error.response` / `error.request`
50
+ * themselves.
51
+ */
52
+ export declare function parseApiError(error: unknown): ApiError;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nomalism-com/api",
3
3
  "description": "A nomalism API package for performing HTTP requests on API endpoints",
4
- "version": "0.45.63",
4
+ "version": "0.45.64",
5
5
  "author": "Nomalism <it.nomalism@gmail.com> (https://https://nomalism.com/)",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",