@beyonk/http 12.2.0 → 12.5.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 CHANGED
@@ -192,6 +192,8 @@ Handlers have a signature with two items:
192
192
  })
193
193
  ```
194
194
 
195
+ Every error carries the request that failed as `e.request` (`{ method, url }`), and HTTP failures also carry `e.status` and the parsed response as `e.body`. Errors thrown by `fetch` itself, such as network failures or aborts, have `e.request` but no `e.status`.
196
+
195
197
  ctx can be whatever you want really - it is whatever you pass in as `context(...)`.
196
198
 
197
199
  However, if the `context` object you pass in has a `fetch` function, this is used as the `fetch` for XHR requests.
@@ -240,6 +242,19 @@ Names are the same as the local handlers:
240
242
  .get()
241
243
  ```
242
244
 
245
+ A global `default` handler catches anything that no other handler does. A request-level `.default()` takes precedence over it, but global status handlers (such as `notFound`) do not check it.
246
+
247
+ ```js
248
+ Api.configure({
249
+ baseUrl: 'https://example.com/your/api/base',
250
+ handlers: {
251
+ default (e) {
252
+ throw error(500, e.message)
253
+ }
254
+ }
255
+ })
256
+ ```
257
+
243
258
  ## Retries
244
259
 
245
260
  The http client can retry if a network error is encountered. The default is `retry: false`, and requests won't be retried.
package/dist/index.cjs CHANGED
@@ -29,10 +29,13 @@ var HttpError = class extends Error {
29
29
  * Create a new HTTP error
30
30
  * @param {string} message - Error message
31
31
  * @param {any} body - Error response body
32
+ * @param {number} [status] - HTTP status code, absent when the request never got a response
32
33
  */
33
- constructor(message, body) {
34
+ constructor(message, body, status) {
34
35
  super(message);
35
36
  this.body = body;
37
+ this.status = status;
38
+ this.request = void 0;
36
39
  }
37
40
  };
38
41
  var AccessDeniedError = class extends HttpError {
@@ -141,7 +144,7 @@ var Api = class {
141
144
  handle(e, ctx) {
142
145
  const constructorName = Object.getPrototypeOf(e).constructor.name;
143
146
  const globalHandlerName = `${constructorName[0].toLowerCase()}${constructorName.slice(1, -5)}`;
144
- const handler = this.handlers[constructorName] || this.options.handlers && this.options.handlers[globalHandlerName] || this.defaultHandler || ((e2) => {
147
+ const handler = this.handlers[constructorName] || this.options.handlers && this.options.handlers[globalHandlerName] || this.defaultHandler || this.options.handlers && this.options.handlers.default || ((e2) => {
145
148
  console.error(constructorName, e2.message, e2);
146
149
  });
147
150
  return handler(e, ctx);
@@ -175,13 +178,13 @@ var Api = class {
175
178
  try {
176
179
  result = await this.#doQuery(1, client, ep, options);
177
180
  } catch (e) {
178
- console.log(e);
181
+ e.request = { method: options.method, url: ep };
179
182
  return this.handle(e, this.ctx);
180
183
  } finally {
181
184
  this.resetRequest();
182
185
  }
183
- const { json, httpStatus } = result;
184
- return fn ? fn(json, httpStatus) : json;
186
+ const { json, httpStatus, response } = result;
187
+ return fn ? fn(json, httpStatus, response) : json;
185
188
  }
186
189
  /**
187
190
  * Check if the response has content
@@ -219,7 +222,7 @@ var Api = class {
219
222
  console.error("Unable to parse response json", e.message);
220
223
  }
221
224
  }
222
- return { httpStatus: r.status, json };
225
+ return { httpStatus: r.status, json, response: r };
223
226
  }
224
227
  let content = "";
225
228
  try {
@@ -228,7 +231,7 @@ var Api = class {
228
231
  console.log("Failed to parse error body when asked.");
229
232
  }
230
233
  const ClientError = getErrorByCode(r.status);
231
- throw new ClientError(r.statusText, content);
234
+ throw new ClientError(r.statusText, content, r.status);
232
235
  } catch (e) {
233
236
  if (retry.attempts && retry.errors && attempt < retry.attempts && retry.errors.includes(e.code)) {
234
237
  console.warn(`Got ${e.code} when calling ${endpoint}. Retrying request (${attempt}/${retry.attempts})`);
package/dist/index.d.cts CHANGED
@@ -52,12 +52,14 @@ type ErrorHandlers = {
52
52
  expectationFailed?: ErrorHandler;
53
53
  badData?: ErrorHandler;
54
54
  tooManyRequests?: ErrorHandler;
55
+ /** Called when no request-level or status-specific handler matches */
56
+ default?: ErrorHandler;
55
57
  [key: string]: ErrorHandler | undefined;
56
58
  };
57
59
  /**
58
60
  * Function to transform API response
59
61
  */
60
- type ResponseTransformer<T = any> = (json: any, httpStatus: number) => T;
62
+ type ResponseTransformer<T = any> = (json: any, httpStatus: number, response: Response) => T;
61
63
  /**
62
64
  * Fetch client interface
63
65
  */
@@ -96,9 +98,16 @@ declare class HttpError extends Error {
96
98
  * Create a new HTTP error
97
99
  * @param {string} message - Error message
98
100
  * @param {any} body - Error response body
101
+ * @param {number} [status] - HTTP status code, absent when the request never got a response
99
102
  */
100
- constructor(message: string, body: any);
103
+ constructor(message: string, body: any, status?: number);
101
104
  body: any;
105
+ status: number;
106
+ /** @type {{ method: string, url: string } | undefined} The request that failed */
107
+ request: {
108
+ method: string;
109
+ url: string;
110
+ } | undefined;
102
111
  }
103
112
  declare namespace _default {
104
113
  export { create };
package/dist/index.d.ts CHANGED
@@ -52,12 +52,14 @@ type ErrorHandlers = {
52
52
  expectationFailed?: ErrorHandler;
53
53
  badData?: ErrorHandler;
54
54
  tooManyRequests?: ErrorHandler;
55
+ /** Called when no request-level or status-specific handler matches */
56
+ default?: ErrorHandler;
55
57
  [key: string]: ErrorHandler | undefined;
56
58
  };
57
59
  /**
58
60
  * Function to transform API response
59
61
  */
60
- type ResponseTransformer<T = any> = (json: any, httpStatus: number) => T;
62
+ type ResponseTransformer<T = any> = (json: any, httpStatus: number, response: Response) => T;
61
63
  /**
62
64
  * Fetch client interface
63
65
  */
@@ -96,9 +98,16 @@ declare class HttpError extends Error {
96
98
  * Create a new HTTP error
97
99
  * @param {string} message - Error message
98
100
  * @param {any} body - Error response body
101
+ * @param {number} [status] - HTTP status code, absent when the request never got a response
99
102
  */
100
- constructor(message: string, body: any);
103
+ constructor(message: string, body: any, status?: number);
101
104
  body: any;
105
+ status: number;
106
+ /** @type {{ method: string, url: string } | undefined} The request that failed */
107
+ request: {
108
+ method: string;
109
+ url: string;
110
+ } | undefined;
102
111
  }
103
112
  declare namespace _default {
104
113
  export { create };
package/dist/index.js CHANGED
@@ -4,10 +4,13 @@ var HttpError = class extends Error {
4
4
  * Create a new HTTP error
5
5
  * @param {string} message - Error message
6
6
  * @param {any} body - Error response body
7
+ * @param {number} [status] - HTTP status code, absent when the request never got a response
7
8
  */
8
- constructor(message, body) {
9
+ constructor(message, body, status) {
9
10
  super(message);
10
11
  this.body = body;
12
+ this.status = status;
13
+ this.request = void 0;
11
14
  }
12
15
  };
13
16
  var AccessDeniedError = class extends HttpError {
@@ -116,7 +119,7 @@ var Api = class {
116
119
  handle(e, ctx) {
117
120
  const constructorName = Object.getPrototypeOf(e).constructor.name;
118
121
  const globalHandlerName = `${constructorName[0].toLowerCase()}${constructorName.slice(1, -5)}`;
119
- const handler = this.handlers[constructorName] || this.options.handlers && this.options.handlers[globalHandlerName] || this.defaultHandler || ((e2) => {
122
+ const handler = this.handlers[constructorName] || this.options.handlers && this.options.handlers[globalHandlerName] || this.defaultHandler || this.options.handlers && this.options.handlers.default || ((e2) => {
120
123
  console.error(constructorName, e2.message, e2);
121
124
  });
122
125
  return handler(e, ctx);
@@ -150,13 +153,13 @@ var Api = class {
150
153
  try {
151
154
  result = await this.#doQuery(1, client, ep, options);
152
155
  } catch (e) {
153
- console.log(e);
156
+ e.request = { method: options.method, url: ep };
154
157
  return this.handle(e, this.ctx);
155
158
  } finally {
156
159
  this.resetRequest();
157
160
  }
158
- const { json, httpStatus } = result;
159
- return fn ? fn(json, httpStatus) : json;
161
+ const { json, httpStatus, response } = result;
162
+ return fn ? fn(json, httpStatus, response) : json;
160
163
  }
161
164
  /**
162
165
  * Check if the response has content
@@ -194,7 +197,7 @@ var Api = class {
194
197
  console.error("Unable to parse response json", e.message);
195
198
  }
196
199
  }
197
- return { httpStatus: r.status, json };
200
+ return { httpStatus: r.status, json, response: r };
198
201
  }
199
202
  let content = "";
200
203
  try {
@@ -203,7 +206,7 @@ var Api = class {
203
206
  console.log("Failed to parse error body when asked.");
204
207
  }
205
208
  const ClientError = getErrorByCode(r.status);
206
- throw new ClientError(r.statusText, content);
209
+ throw new ClientError(r.statusText, content, r.status);
207
210
  } catch (e) {
208
211
  if (retry.attempts && retry.errors && attempt < retry.attempts && retry.errors.includes(e.code)) {
209
212
  console.warn(`Got ${e.code} when calling ${endpoint}. Retrying request (${attempt}/${retry.attempts})`);
package/package.json CHANGED
@@ -1,12 +1,9 @@
1
1
  {
2
2
  "name": "@beyonk/http",
3
- "version": "12.2.0",
3
+ "version": "12.5.0",
4
4
  "description": "An isomorphic http client for Svelte apps",
5
5
  "type": "module",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/beyonk-adventures/http.git"
9
- },
6
+ "repository": "https://github.com/beyonk/http.git",
10
7
  "files": [
11
8
  "dist"
12
9
  ],
@@ -48,9 +45,6 @@
48
45
  ],
49
46
  "author": "Antony Jones",
50
47
  "license": "MIT",
51
- "volta": {
52
- "node": "18.15.0"
53
- },
54
48
  "scripts": {
55
49
  "test": "mocha './!(node_modules)/**/**.+(spec).js'",
56
50
  "lint": "eslint lib --ext .js",