@hkdigital/lib-sveltekit 0.0.59 → 0.0.61

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.
Files changed (59) hide show
  1. package/dist/classes/promise/HkPromise.d.ts +2 -2
  2. package/dist/classes/promise/HkPromise.js +2 -2
  3. package/dist/classes/stores/SubscribersCount.js +1 -1
  4. package/dist/classes/streams/LogTransformStream.js +2 -2
  5. package/dist/components/icon/HkIcon.svelte +1 -1
  6. package/dist/components/layout/HkAppLayout.state.svelte.js +1 -1
  7. package/dist/components/tab-bar/HkTabBar.state.svelte.d.ts +1 -1
  8. package/dist/components/tab-bar/HkTabBar.state.svelte.js +1 -1
  9. package/dist/constants/errors/api.d.ts +10 -0
  10. package/dist/constants/errors/api.js +9 -0
  11. package/dist/constants/errors/generic.d.ts +6 -0
  12. package/dist/constants/errors/generic.js +5 -0
  13. package/dist/constants/errors/index.d.ts +3 -0
  14. package/dist/constants/errors/index.js +3 -0
  15. package/dist/constants/errors/jwt.d.ts +8 -0
  16. package/dist/constants/errors/jwt.js +5 -0
  17. package/dist/constants/http/headers.d.ts +4 -0
  18. package/dist/constants/http/headers.js +5 -0
  19. package/dist/constants/http/index.d.ts +2 -0
  20. package/dist/constants/http/index.js +2 -0
  21. package/dist/constants/http/methods.d.ts +2 -0
  22. package/dist/constants/http/methods.js +2 -0
  23. package/dist/constants/mime/application.d.ts +2 -0
  24. package/dist/constants/mime/application.js +2 -0
  25. package/dist/constants/mime/image.d.ts +3 -0
  26. package/dist/constants/mime/image.js +3 -0
  27. package/dist/constants/mime/index.d.ts +3 -0
  28. package/dist/constants/mime/index.js +3 -0
  29. package/dist/constants/mime/text.d.ts +2 -0
  30. package/dist/constants/mime/text.js +2 -0
  31. package/dist/util/array/index.d.ts +3 -3
  32. package/dist/util/array/index.js +2 -2
  33. package/dist/util/compare/index.d.ts +14 -14
  34. package/dist/util/compare/index.js +14 -14
  35. package/dist/util/expect/index.d.ts +30 -30
  36. package/dist/util/expect/index.js +36 -29
  37. package/dist/util/http/errors.d.ts +18 -0
  38. package/dist/util/http/errors.js +97 -0
  39. package/dist/util/http/headers.d.ts +12 -0
  40. package/dist/util/http/headers.js +39 -0
  41. package/dist/util/http/http-request.d.ts +78 -0
  42. package/dist/util/http/http-request.js +259 -0
  43. package/dist/util/http/index.d.ts +4 -0
  44. package/dist/util/http/index.js +20 -0
  45. package/dist/util/http/json-request.d.ts +47 -0
  46. package/dist/util/http/json-request.js +141 -0
  47. package/dist/util/http/mocks.d.ts +12 -0
  48. package/dist/util/http/mocks.js +12 -0
  49. package/dist/util/http/response.d.ts +24 -0
  50. package/dist/util/http/response.js +105 -0
  51. package/dist/util/http/url.d.ts +8 -0
  52. package/dist/util/http/url.js +19 -0
  53. package/dist/util/is/index.d.ts +12 -12
  54. package/dist/util/is/index.js +7 -7
  55. package/dist/util/object/index.d.ts +16 -16
  56. package/dist/util/object/index.js +11 -11
  57. package/dist/util/singleton/index.d.ts +1 -1
  58. package/dist/util/singleton/index.js +1 -1
  59. package/package.json +33 -16
@@ -0,0 +1,259 @@
1
+ import { METHOD_GET, METHOD_POST } from '../../constants/http/methods.js';
2
+
3
+ import { APPLICATION_JSON } from '../../constants/mime/application.js';
4
+ import { CONTENT_TYPE } from '../../constants/http/headers.js';
5
+
6
+ import { AbortError, TimeoutError } from '../../constants/errors/api.js';
7
+
8
+ import * as expect from '../expect/index.js';
9
+
10
+ import { toURL } from './url.js';
11
+ import { setRequestHeaders } from './headers.js';
12
+ import { waitForAndCheckResponse } from './response.js';
13
+
14
+ /**
15
+ * Make GET request
16
+ *
17
+ * @param {string|URL} url - Url string or URL object
18
+ *
19
+ * @param {object} [urlSearchParams]
20
+ * Parameters that should be added to the request url
21
+ *
22
+ * @param {object} [headers]
23
+ * Object that contains custom headers. A header is a name, value pair.
24
+ *
25
+ * e.g. options.headers = { "content-type": "application/json" }
26
+ *
27
+ * @param {function} [requestHandler]
28
+ * If defined, this function will receive the abort handler function
29
+ *
30
+ * @param {number} [timeoutMs]
31
+ * If defined, this request will abort after the specified number of
32
+ * milliseconds. Values above the the built-in request timeout won't work.
33
+ *
34
+ * @returns {Promise<*>} responsePromise
35
+ */
36
+ export async function httpGet({ url, urlSearchParams, headers, requestHandler, timeoutMs }) {
37
+ const responsePromise = httpRequest({
38
+ method: METHOD_GET,
39
+ url,
40
+ urlSearchParams,
41
+ headers,
42
+ requestHandler,
43
+ timeoutMs
44
+ });
45
+
46
+ return await waitForAndCheckResponse(responsePromise, url);
47
+ }
48
+
49
+ /**
50
+ * Make POST request
51
+ *
52
+ * @param {string|URL} url - Url string or URL object
53
+ *
54
+ * @param {any} [body] - POST data
55
+ *
56
+ * @param {object} [headers]
57
+ * Object that contains custom headers. A header is a name, value pair.
58
+ *
59
+ * e.g. options.headers = { "content-type": "application/json" }
60
+ *
61
+ * @param {function} [requestHandler]
62
+ * If defined, this function will receive the abort handler function
63
+ *
64
+ * @param {number} [timeoutMs]
65
+ * If defined, this request will abort after the specified number of
66
+ * milliseconds. Values above the the built-in request timeout won't work.
67
+ *
68
+ * @returns {Promise<*>} responsePromise
69
+ */
70
+ export async function httpPost({ url, body = null, headers, requestHandler, timeoutMs }) {
71
+ const responsePromise = httpRequest({
72
+ method: METHOD_POST,
73
+ url,
74
+ body,
75
+ headers,
76
+ requestHandler,
77
+ timeoutMs
78
+ });
79
+
80
+ return await waitForAndCheckResponse(responsePromise, url);
81
+ }
82
+
83
+ // -----------------------------------------------------------------------------
84
+
85
+ /**
86
+ * Make an HTTP request
87
+ * - This is a low level function, consider using
88
+ * httpGet, httpPost, jsonGet or jsonPost instead
89
+ *
90
+ * @param {string|URL} url - Url string or URL object
91
+ *
92
+ * @param {string} method - Request method: METHOD_GET | METHOD_POST
93
+ *
94
+ * @param {object} [urlSearchParams] - URL search parameters as key-value pairs
95
+ *
96
+ * @param {any} [body] - POST data
97
+ *
98
+ * @param {object} [headers]
99
+ * Object that contains custom headers. A header is a name, value pair.
100
+ *
101
+ * e.g. options.headers = { "content-type": "application/json" }
102
+ *
103
+ * @param {function} [requestHandler]
104
+ * If defined, this function will receive the abort handler function
105
+ *
106
+ * @param {number} [timeoutMs]
107
+ * If defined, this request will abort after the specified number of
108
+ * milliseconds. Values above the the built-in request timeout won't work.
109
+ *
110
+ * @throws TypeError - If a network error occurred
111
+ *
112
+ * @note Check the `ok` property of the resolved response to check if the
113
+ * response was successfull (e.g. in case of a 404, ok is false)
114
+ *
115
+ * @returns {Promise<*>} responsePromise
116
+ */
117
+ export async function httpRequest({
118
+ method,
119
+ url,
120
+ urlSearchParams = null,
121
+ body = null,
122
+ headers,
123
+ requestHandler,
124
+ timeoutMs
125
+ }) {
126
+ url = toURL(url);
127
+
128
+ // @see https://developer.mozilla.org/en-US/docs/Web/API/Headers
129
+
130
+ const requestHeaders = new Headers();
131
+
132
+ if (headers) {
133
+ setRequestHeaders(requestHeaders, headers);
134
+
135
+ if (headers[CONTENT_TYPE] === APPLICATION_JSON && typeof body !== 'string') {
136
+ throw new Error(
137
+ `Trying to send request with [content-type:${APPLICATION_JSON}], ` +
138
+ 'but body is not a (JSON encoded) string.'
139
+ );
140
+ }
141
+ // IDEA: try to decode the body to catch errors on client side
142
+ }
143
+
144
+ const init = {
145
+ mode: 'cors',
146
+ cache: 'no-cache',
147
+ credentials: 'omit',
148
+ redirect: 'follow',
149
+ referrerPolicy: 'no-referrer',
150
+ headers: requestHeaders
151
+ };
152
+
153
+ // Allow search params also for other request types than GET
154
+
155
+ if (urlSearchParams) {
156
+ if (!(urlSearchParams instanceof URLSearchParams)) {
157
+ throw new Error(
158
+ 'Invalid parameter [urlSearchParams] ' + '(expected instanceof URLSearchParams)'
159
+ );
160
+ }
161
+
162
+ const existingParams = url.searchParams;
163
+
164
+ for (const [name, value] of urlSearchParams.entries()) {
165
+ if (existingParams.has(name)) {
166
+ throw new Error(
167
+ `Cannot set URL search parameter [${name}] ` + `in url [${url.href}] (already set)`
168
+ );
169
+ }
170
+
171
+ existingParams.set(name, value);
172
+ } // end for
173
+ }
174
+
175
+ //
176
+ // Sort search params to make the url nicer
177
+ //
178
+ url.searchParams.sort();
179
+
180
+ // console.log( "url", url );
181
+
182
+ init.method = method;
183
+
184
+ if (METHOD_POST === method) {
185
+ init.body = body || null; /* : JSON.stringify( body ) */
186
+ }
187
+
188
+ // @see https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
189
+
190
+ // console.log( "init", init );
191
+ // console.log( "headers", init.headers );
192
+
193
+ const request = new Request(url, init);
194
+
195
+ // @see https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort
196
+
197
+ const controller = new AbortController();
198
+ const signal = controller.signal;
199
+
200
+ //
201
+ // A fetch() promise will reject with a TypeError when a network error
202
+ // is encountered or CORS is misconfigured on the server-side,
203
+ // although this usually means permission issues or similar
204
+ // — a 404 does not constitute a network error, for example.
205
+ // An accurate check for a successful fetch() would include checking
206
+ // that the promise resolved, then checking that the Response.ok property
207
+ // has a value of true. The code would look something like this:
208
+ //
209
+ // fetch()
210
+ // .then( () => {
211
+ // if( !response.ok ) {
212
+ // throw new Error('Network response was not OK');
213
+ // }
214
+ // ...
215
+ // }
216
+ // .catch((error) => { .. }
217
+ //
218
+
219
+ const promise = fetch(request, { signal });
220
+
221
+ if (requestHandler || timeoutMs) {
222
+ const abort = (reason) => {
223
+ if (!reason) {
224
+ reason = new AbortError(`Request [${url.href}] aborted`);
225
+ }
226
+
227
+ controller.abort(reason);
228
+ };
229
+
230
+ /**
231
+ * Function that can be used to set a timeout on a request
232
+ *
233
+ * @param {number} delayMs
234
+ */
235
+ const timeout = (delayMs = 10000) => {
236
+ expect.positiveNumber(delayMs, 'Invalid value for [delayMs]');
237
+
238
+ const timerId = setTimeout(() => {
239
+ controller.abort(new TimeoutError(`Request [${url.href}] timed out [${delayMs}]`));
240
+ }, delayMs);
241
+
242
+ promise.finally(() => {
243
+ clearTimeout(timerId);
244
+ });
245
+ };
246
+
247
+ if (timeoutMs) {
248
+ timeout(timeoutMs);
249
+ }
250
+
251
+ if (requestHandler) {
252
+ expect.function(requestHandler, 'Invalid parameter [requestHandler]');
253
+
254
+ requestHandler({ controller, abort, timeout });
255
+ }
256
+ }
257
+
258
+ return promise;
259
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./headers.js";
2
+ export * from "./errors.js";
3
+ export * from "./url.js";
4
+ export * from "./response.js";
@@ -0,0 +1,20 @@
1
+ // import * as expect from '../expect/index.js';
2
+
3
+ // import {
4
+ // ResponseError,
5
+ // AbortError,
6
+ // TimeoutError,
7
+ // TypeOrValueError
8
+ // } from '../../constants/errors/index.js';
9
+
10
+ // import { setRequestHeaders } from './headers.js';
11
+ // import { getErrorFromResponse } from './errors.js';
12
+
13
+ export * from './headers.js';
14
+ export * from './errors.js';
15
+ export * from './url.js';
16
+ export * from './response.js';
17
+
18
+ // import { CONTENT_TYPE, METHOD_GET, METHOD_POST } from '../../constants/http/index.js';
19
+
20
+ // import { APPLICATION_JSON } from '../../constants/mime/index.js';
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Make a GET request to fetch JSON encoded data
3
+ * - Expect JSON response from server
4
+ *
5
+ * @param {string|URL} url - Url string or URL object
6
+ *
7
+ * @param {object} [urlSearchParams]
8
+ * Parameters that should be added to the request url
9
+ *
10
+ * @param {array[]} [headers]
11
+ * List of custom headers. Each header is an array that contains
12
+ * the header name and the header value.
13
+ * E.g. [ "content-type", "application/json" ]
14
+ *
15
+ * @throws ResponseError
16
+ * If a network error occurred or the response was not ok
17
+ *
18
+ * @returns {any} parsed JSON data
19
+ */
20
+ export function jsonGet({ url, urlSearchParams, headers }: string | URL): any;
21
+ /**
22
+ * Make a POST request to fetch JSON encoded data
23
+ * - Expect JSON response from server
24
+ *
25
+ * @param {string|URL} url - Url string or URL object
26
+ *
27
+ * @param {any} body
28
+ * Data that will be converted to a JSON encoded string and send to the server
29
+ *
30
+ * @param {object} [urlSearchParams]
31
+ * Parameters that should be added to the request url.
32
+ *
33
+ * @note
34
+ * Be careful when using urlSearchParams in POST requests, it can be
35
+ * confusing since the parameters usually go in the body part of the request.
36
+ *
37
+ * @param {array[]} [headers]
38
+ * List of custom headers. Each header is an array that contains
39
+ * the header name and the header value.
40
+ * E.g. [ "content-type", "application/json" ]
41
+ *
42
+ * @throws ResponseError
43
+ * If a network error occurred or the response was not ok
44
+ *
45
+ * @returns {any} parsed JSON data
46
+ */
47
+ export function jsonPost({ url, body, urlSearchParams, headers }: string | URL): any;
@@ -0,0 +1,141 @@
1
+ import { METHOD_GET, METHOD_POST } from '../../constants/http/methods.js';
2
+
3
+ import { APPLICATION_JSON } from '../../constants/mime/application.js';
4
+ import { CONTENT_TYPE } from '../../constants/http/headers.js';
5
+
6
+ import * as expect from '../expect/index.js';
7
+
8
+ import { toURL } from './url.js';
9
+ import { ResponseError } from './errors.js';
10
+ import { httpRequest } from './http-request.js';
11
+ import { waitForAndCheckResponse } from './response.js';
12
+
13
+ const ACCEPT = 'accept';
14
+
15
+ /**
16
+ * Make a GET request to fetch JSON encoded data
17
+ * - Expect JSON response from server
18
+ *
19
+ * @param {string|URL} url - Url string or URL object
20
+ *
21
+ * @param {object} [urlSearchParams]
22
+ * Parameters that should be added to the request url
23
+ *
24
+ * @param {array[]} [headers]
25
+ * List of custom headers. Each header is an array that contains
26
+ * the header name and the header value.
27
+ * E.g. [ "content-type", "application/json" ]
28
+ *
29
+ * @throws ResponseError
30
+ * If a network error occurred or the response was not ok
31
+ *
32
+ * @returns {any} parsed JSON data
33
+ */
34
+ export async function jsonGet({ url, urlSearchParams, headers }) {
35
+ url = toURL(url);
36
+
37
+ if (!headers) {
38
+ headers = {};
39
+ }
40
+
41
+ headers[ACCEPT] = APPLICATION_JSON;
42
+
43
+ const responsePromise = httpRequest({
44
+ method: METHOD_GET,
45
+ url,
46
+ urlSearchParams,
47
+ headers
48
+ });
49
+
50
+ const response = await waitForAndCheckResponse(responsePromise, url);
51
+
52
+ let parsedResponse;
53
+
54
+ try {
55
+ //
56
+ // @note when security on the client side fails, an `opaque` response
57
+ // is returned by the browser (empty body) -> parsing fails
58
+ // (use CORS to fix this)
59
+ //
60
+ parsedResponse = await response.json();
61
+ } catch (e) {
62
+ throw new ResponseError(`Failed to JSON decode server response from [${decodeURI(url.href)}]`, {
63
+ cause: e
64
+ });
65
+ }
66
+
67
+ if (parsedResponse.error) {
68
+ throw new ResponseError(`Server returned response error message [${parsedResponse.error}]`);
69
+ }
70
+
71
+ return parsedResponse;
72
+ }
73
+
74
+ /**
75
+ * Make a POST request to fetch JSON encoded data
76
+ * - Expect JSON response from server
77
+ *
78
+ * @param {string|URL} url - Url string or URL object
79
+ *
80
+ * @param {any} body
81
+ * Data that will be converted to a JSON encoded string and send to the server
82
+ *
83
+ * @param {object} [urlSearchParams]
84
+ * Parameters that should be added to the request url.
85
+ *
86
+ * @note
87
+ * Be careful when using urlSearchParams in POST requests, it can be
88
+ * confusing since the parameters usually go in the body part of the request.
89
+ *
90
+ * @param {array[]} [headers]
91
+ * List of custom headers. Each header is an array that contains
92
+ * the header name and the header value.
93
+ * E.g. [ "content-type", "application/json" ]
94
+ *
95
+ * @throws ResponseError
96
+ * If a network error occurred or the response was not ok
97
+ *
98
+ * @returns {any} parsed JSON data
99
+ */
100
+ export async function jsonPost({ url, body, urlSearchParams, headers }) {
101
+ url = toURL(url);
102
+
103
+ if (!headers) {
104
+ headers = {};
105
+ } else {
106
+ expect.object(headers);
107
+ }
108
+
109
+ expect.defined(body);
110
+
111
+ headers[ACCEPT] = APPLICATION_JSON;
112
+ headers[CONTENT_TYPE] = APPLICATION_JSON;
113
+
114
+ const responsePromise = httpRequest({ METHOD_POST, url, body, urlSearchParams, headers });
115
+
116
+ const response = await waitForAndCheckResponse(responsePromise, url);
117
+
118
+ let parsedResponse;
119
+
120
+ try {
121
+ //
122
+ // @note when security on the client side fails, an `opaque` response
123
+ // is returned by the browser (empty body) -> parsing fails
124
+ // (use CORS to fix this)
125
+ //
126
+ parsedResponse = await response.json();
127
+ } catch (e) {
128
+ // console.log( response );
129
+ throw new ResponseError(`Failed to JSON decode server response from [${decodeURI(url.href)}]`);
130
+ }
131
+
132
+ if (parsedResponse.error) {
133
+ //
134
+ // @note this is API specific, but it's quite logical
135
+ //
136
+ //
137
+ throw new ResponseError(`Server returned response error message [${parsedResponse.error}]`);
138
+ }
139
+
140
+ return parsedResponse;
141
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Create a response value that can be used by a mocked fetch function
3
+ *
4
+ * @template T
5
+ *
6
+ * @param {T} data
7
+ *
8
+ * @returns {{ json: () => Promise<T>}}
9
+ */
10
+ export function createJsonFetchResponse<T>(data: T): {
11
+ json: () => Promise<T>;
12
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Create a response value that can be used by a mocked fetch function
3
+ *
4
+ * @template T
5
+ *
6
+ * @param {T} data
7
+ *
8
+ * @returns {{ json: () => Promise<T>}}
9
+ */
10
+ export function createJsonFetchResponse(data /* , options */) {
11
+ return { json: () => new Promise((resolve) => resolve(data)) };
12
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Check if the response status is ok
3
+ *
4
+ * @param {object} response
5
+ * @param {string} url - used to produce useful error messages
6
+ *
7
+ * @throws {Error} not found
8
+ * @throws {Error} internal server error
9
+ */
10
+ export function expectResponseOk(response: object, url: string): Promise<void>;
11
+ /**
12
+ * Wait for a response and check if the response is ok
13
+ *
14
+ * @example
15
+ * const response = await waitForAndCheckResponse( responsePromise );
16
+ *
17
+ * @param {Promise<object>} responsePromise
18
+ * @param {URL} url - An url that is used for error messages
19
+ *
20
+ * @throws ResponseError - A response error if something went wrong
21
+ *
22
+ * @returns {object} response
23
+ */
24
+ export function waitForAndCheckResponse(responsePromise: Promise<object>, url: URL): object;
@@ -0,0 +1,105 @@
1
+ import { ResponseError } from '../../constants/errors/index.js';
2
+ import * as expect from '../expect/index.js';
3
+
4
+ import { WWW_AUTHENTICATE } from '../../constants/http/headers.js';
5
+
6
+ import { toURL } from './url.js';
7
+
8
+ import { getErrorFromResponse } from './errors.js';
9
+
10
+ /**
11
+ * Check if the response status is ok
12
+ *
13
+ * @param {object} response
14
+ * @param {string} url - used to produce useful error messages
15
+ *
16
+ * @throws {Error} not found
17
+ * @throws {Error} internal server error
18
+ */
19
+ export async function expectResponseOk(response, url) {
20
+ expect.object(response);
21
+
22
+ url = toURL(url);
23
+
24
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/200
25
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/201
26
+
27
+ if (200 === response.status || 201 === response.status) {
28
+ if (!response.ok) {
29
+ throw new ResponseError(
30
+ `Server returned - ${response.status} ${response.statusText} ` +
31
+ `[response.ok=false] [url=${decodeURI(url.href)}]`
32
+ );
33
+ }
34
+
35
+ // All ok
36
+ return;
37
+ }
38
+
39
+ // > Handle 401 Unauthorized
40
+
41
+ if (401 === response.status) {
42
+ let errorMessage = 'Server returned [401] Unauthorized';
43
+
44
+ const authValue = response.headers.get(WWW_AUTHENTICATE);
45
+
46
+ if (authValue) {
47
+ // Add WWW_AUTHENTICATE response to error message
48
+
49
+ errorMessage += ` (${authValue})`;
50
+ }
51
+
52
+ errorMessage += ` [url=${decodeURI(url.href)}]`;
53
+
54
+ throw new Error(errorMessage);
55
+ }
56
+
57
+ // > Handle all other error responses
58
+
59
+ const error = await getErrorFromResponse(response);
60
+
61
+ throw new ResponseError(
62
+ `Server returned - ${response.status} ${response.statusText} ` + `[url=${decodeURI(url.href)}]`,
63
+ { cause: error }
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Wait for a response and check if the response is ok
69
+ *
70
+ * @example
71
+ * const response = await waitForAndCheckResponse( responsePromise );
72
+ *
73
+ * @param {Promise<object>} responsePromise
74
+ * @param {URL} url - An url that is used for error messages
75
+ *
76
+ * @throws ResponseError - A response error if something went wrong
77
+ *
78
+ * @returns {object} response
79
+ */
80
+ export async function waitForAndCheckResponse(responsePromise, url) {
81
+ expect.promise(responsePromise);
82
+
83
+ url = toURL(url);
84
+
85
+ let response;
86
+
87
+ try {
88
+ response = await responsePromise;
89
+
90
+ if (response && false === response.ok) {
91
+ // if response.ok is false, it also indicates a network error
92
+ throw new Error(`Response failed [response.ok=false]`);
93
+ }
94
+ } catch (e) {
95
+ if (e instanceof TypeError || response?.ok === false) {
96
+ throw new ResponseError(`A network error occurred for request [${decodeURI(url.href)}]`, {
97
+ cause: e
98
+ });
99
+ } else {
100
+ throw e;
101
+ }
102
+ }
103
+
104
+ return response;
105
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Ensure to return an URL instance
3
+ *
4
+ * @param {string|URL} url
5
+ *
6
+ * @returns {URL} url instance
7
+ */
8
+ export function toURL(url: string | URL): URL;
@@ -0,0 +1,19 @@
1
+ import { TypeOrValueError } from '../../constants/errors/index.js';
2
+
3
+ /**
4
+ * Ensure to return an URL instance
5
+ *
6
+ * @param {string|URL} url
7
+ *
8
+ * @returns {URL} url instance
9
+ */
10
+ export function toURL(url) {
11
+ if (typeof url === 'string') {
12
+ return new URL(url);
13
+ } else if (!(url instanceof URL)) {
14
+ throw new TypeOrValueError('Missing or invalid parameter [url]');
15
+ }
16
+
17
+ // already an URL instance
18
+ return url;
19
+ }