@torthu/jacketui-bring 0.0.1 → 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/dist/bring.js +34 -25
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/response-pipe/arrayBuffer.d.ts +10 -0
- package/dist/response-pipe/arrayBuffer.js +17 -0
- package/dist/response-pipe/blob.d.ts +10 -0
- package/dist/response-pipe/blob.js +17 -0
- package/dist/response-pipe/bytes.d.ts +10 -0
- package/dist/response-pipe/bytes.js +17 -0
- package/dist/response-pipe/formData.d.ts +10 -0
- package/dist/response-pipe/formData.js +17 -0
- package/dist/response-pipe/index.d.ts +6 -0
- package/dist/response-pipe/index.js +6 -0
- package/dist/response-pipe/json.d.ts +10 -0
- package/dist/response-pipe/json.js +17 -0
- package/dist/response-pipe/text.d.ts +10 -0
- package/dist/response-pipe/text.js +17 -0
- package/dist/types/BringInit.d.ts +4 -3
- package/package.json +4 -3
- package/src/bring.ts +58 -49
- package/src/index.ts +2 -1
- package/src/response-pipe/arrayBuffer.ts +18 -0
- package/src/response-pipe/blob.ts +18 -0
- package/src/response-pipe/bytes.ts +18 -0
- package/src/response-pipe/formData.ts +18 -0
- package/src/response-pipe/index.ts +6 -0
- package/src/response-pipe/json.ts +20 -0
- package/src/response-pipe/text.ts +18 -0
- package/src/types/BringInit.ts +11 -3
- package/test/bring.spec.ts +149 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/backoff.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/backoff.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/body.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/body.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/cache.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/cache.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/cors.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/cors.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/credentials.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/credentials.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/header.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/header.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/index.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/index.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/integrity.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/integrity.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/jitter.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/jitter.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/jsonBody.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/jsonBody.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/keepalive.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/keepalive.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/method.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/method.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/priority.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/priority.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/redirect.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/redirect.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/referrer.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/referrer.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/referrerPolicy.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/referrerPolicy.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/retry.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/retry.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/shouldRetry.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/shouldRetry.js +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/timeout.d.ts +0 -0
- /package/dist/{pipe-helpers → request-builder-pipe}/timeout.js +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/backoff.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/body.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/cache.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/cors.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/credentials.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/header.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/index.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/integrity.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/jitter.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/jsonBody.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/keepalive.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/method.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/priority.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/redirect.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/referrer.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/referrerPolicy.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/retry.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/shouldRetry.ts +0 -0
- /package/src/{pipe-helpers → request-builder-pipe}/timeout.ts +0 -0
package/dist/bring.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { success, failure, withResolvers, } from "@torthu/jacketui-core";
|
|
2
2
|
import { isClientErrorResponse } from "./types/ClientErrorResponse";
|
|
3
3
|
import { isServerErrorResponse } from "./types/ServerErrorResponse";
|
|
4
|
-
import { AbortError, ClientError, BringError, ServerError, TimeoutError, } from "./errors";
|
|
4
|
+
import { AbortError, ClientError, BringError, NetworkError, ServerError, TimeoutError, } from "./errors";
|
|
5
5
|
import { tryFetch } from "./tryFetch";
|
|
6
6
|
/** bring({url: string | URL})
|
|
7
7
|
*
|
|
@@ -40,7 +40,7 @@ import { tryFetch } from "./tryFetch";
|
|
|
40
40
|
export const bring = (init) => {
|
|
41
41
|
if (init instanceof BringError)
|
|
42
42
|
init = init.requestInit;
|
|
43
|
-
const { url, abortController = new AbortController(), timeout = 0, retry = 0, onSuccess, onError, onAbort, onRetry, onTimeout, onClientError, onServerError, ...requestInit } = init;
|
|
43
|
+
const { url, abortController = new AbortController(), timeout = 0, retry = 0, onSuccess, onError, onAbort, onRetry, onTimeout, onClientError, onServerError, onNetworkError, ...requestInit } = init;
|
|
44
44
|
// Configure promise
|
|
45
45
|
const { promise, resolve } = withResolvers();
|
|
46
46
|
const abortablePromise = promise;
|
|
@@ -60,49 +60,52 @@ export const bring = (init) => {
|
|
|
60
60
|
method: requestInit.method ?? "GET",
|
|
61
61
|
reason: abortController.signal.reason,
|
|
62
62
|
},
|
|
63
|
+
cause: error,
|
|
63
64
|
url,
|
|
64
65
|
requestInit: init,
|
|
65
66
|
});
|
|
66
|
-
resolve(failure(abortError));
|
|
67
67
|
onAbort?.(abortError);
|
|
68
68
|
onError?.(abortError);
|
|
69
|
-
return;
|
|
69
|
+
return resolve(failure(abortError));
|
|
70
70
|
}
|
|
71
71
|
if (timeoutSignal?.aborted) {
|
|
72
|
-
const
|
|
73
|
-
context: {
|
|
72
|
+
const timeoutError = new TimeoutError("Timeout", {
|
|
73
|
+
context: {
|
|
74
|
+
reason: timeoutSignal.reason,
|
|
75
|
+
timeout,
|
|
76
|
+
},
|
|
77
|
+
cause: error,
|
|
74
78
|
url,
|
|
75
79
|
requestInit: init,
|
|
76
80
|
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return;
|
|
81
|
+
onTimeout?.(timeoutError);
|
|
82
|
+
onError?.(timeoutError);
|
|
83
|
+
return resolve(failure(error));
|
|
81
84
|
}
|
|
82
85
|
if (error instanceof Error) {
|
|
83
|
-
|
|
84
|
-
cause: error,
|
|
86
|
+
const networkError = new NetworkError(error.message, {
|
|
85
87
|
context: { url, method: requestInit.method ?? "GET" },
|
|
88
|
+
cause: error,
|
|
86
89
|
url,
|
|
87
90
|
requestInit: init,
|
|
88
|
-
})
|
|
89
|
-
|
|
91
|
+
});
|
|
92
|
+
onError?.(networkError);
|
|
93
|
+
return resolve(failure(networkError));
|
|
90
94
|
}
|
|
91
95
|
if (typeof error === "string") {
|
|
92
|
-
resolve(failure(new BringError(error, { url, requestInit: init })));
|
|
93
|
-
return;
|
|
96
|
+
return resolve(failure(new BringError(error, { url, requestInit: init })));
|
|
94
97
|
}
|
|
95
|
-
resolve(failure(new BringError("Unknown error", { url, requestInit: init })));
|
|
98
|
+
return resolve(failure(new BringError("Unknown error", { url, requestInit: init })));
|
|
96
99
|
}
|
|
97
100
|
else {
|
|
98
101
|
const response = value;
|
|
99
102
|
if (response.ok) {
|
|
100
|
-
resolve(success(response));
|
|
101
103
|
onSuccess?.(response);
|
|
104
|
+
return resolve(success(response));
|
|
102
105
|
}
|
|
103
106
|
else {
|
|
104
107
|
if (isClientErrorResponse(response)) {
|
|
105
|
-
|
|
108
|
+
const clientError = new ClientError(response.statusText, {
|
|
106
109
|
context: {
|
|
107
110
|
status: response.status,
|
|
108
111
|
statusText: response.statusText,
|
|
@@ -110,10 +113,13 @@ export const bring = (init) => {
|
|
|
110
113
|
response,
|
|
111
114
|
requestInit: init,
|
|
112
115
|
url,
|
|
113
|
-
})
|
|
116
|
+
});
|
|
117
|
+
onClientError?.(clientError);
|
|
118
|
+
onError?.(clientError);
|
|
119
|
+
return resolve(failure(clientError));
|
|
114
120
|
}
|
|
115
121
|
if (isServerErrorResponse(response)) {
|
|
116
|
-
|
|
122
|
+
const serverError = new ServerError(response.statusText, {
|
|
117
123
|
response,
|
|
118
124
|
requestInit: init,
|
|
119
125
|
url,
|
|
@@ -121,9 +127,12 @@ export const bring = (init) => {
|
|
|
121
127
|
status: response.status,
|
|
122
128
|
statusText: response.statusText,
|
|
123
129
|
},
|
|
124
|
-
})
|
|
130
|
+
});
|
|
131
|
+
onServerError?.(serverError);
|
|
132
|
+
onError?.(serverError);
|
|
133
|
+
return resolve(failure(serverError));
|
|
125
134
|
}
|
|
126
|
-
const
|
|
135
|
+
const unknownError = new BringError("Fetch failed", {
|
|
127
136
|
context: {
|
|
128
137
|
url,
|
|
129
138
|
status: response.status,
|
|
@@ -133,8 +142,8 @@ export const bring = (init) => {
|
|
|
133
142
|
requestInit: init,
|
|
134
143
|
response,
|
|
135
144
|
});
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
onError?.(unknownError);
|
|
146
|
+
return resolve(failure(unknownError));
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
149
|
});
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
/** arrayBuffer(result: Result<Response, BringError>)
|
|
4
|
+
*
|
|
5
|
+
* Utility function to await Response.arrayBuffer().
|
|
6
|
+
*
|
|
7
|
+
* @param result Result<Response, BringError>
|
|
8
|
+
* @returns Promise<Result<ArrayBuffer, BringError>>
|
|
9
|
+
*/
|
|
10
|
+
export declare const arrayBuffer: (result: Result<Response, BringError>) => Promise<import("@torthu/jacketui-core").Failure<BringError> | import("@torthu/jacketui-core").Success<ArrayBuffer>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { success } from "@torthu/jacketui-core";
|
|
2
|
+
/** arrayBuffer(result: Result<Response, BringError>)
|
|
3
|
+
*
|
|
4
|
+
* Utility function to await Response.arrayBuffer().
|
|
5
|
+
*
|
|
6
|
+
* @param result Result<Response, BringError>
|
|
7
|
+
* @returns Promise<Result<ArrayBuffer, BringError>>
|
|
8
|
+
*/
|
|
9
|
+
export const arrayBuffer = async (result) => {
|
|
10
|
+
if (result.ok) {
|
|
11
|
+
const res = await result.value.arrayBuffer();
|
|
12
|
+
return success(res);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
/** blob(result: Result<Response, BringError>)
|
|
4
|
+
*
|
|
5
|
+
* Utility function to await Response.blob().
|
|
6
|
+
*
|
|
7
|
+
* @param result Result<Response, BringError>
|
|
8
|
+
* @returns Promise<Result<Blob, BringError>>
|
|
9
|
+
*/
|
|
10
|
+
export declare const blob: (result: Result<Response, BringError>) => Promise<import("@torthu/jacketui-core").Failure<BringError> | import("@torthu/jacketui-core").Success<Blob>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { success } from "@torthu/jacketui-core";
|
|
2
|
+
/** blob(result: Result<Response, BringError>)
|
|
3
|
+
*
|
|
4
|
+
* Utility function to await Response.blob().
|
|
5
|
+
*
|
|
6
|
+
* @param result Result<Response, BringError>
|
|
7
|
+
* @returns Promise<Result<Blob, BringError>>
|
|
8
|
+
*/
|
|
9
|
+
export const blob = async (result) => {
|
|
10
|
+
if (result.ok) {
|
|
11
|
+
const res = await result.value.blob();
|
|
12
|
+
return success(res);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
/** bytes(result: Result<Response, BringError>)
|
|
4
|
+
*
|
|
5
|
+
* Utility function to await Response.bytes().
|
|
6
|
+
*
|
|
7
|
+
* @param result Result<Response, BringError>
|
|
8
|
+
* @returns Promise<Result<Uint8Array, BringError>>
|
|
9
|
+
*/
|
|
10
|
+
export declare const bytes: (result: Result<Response, BringError>) => Promise<import("@torthu/jacketui-core").Failure<BringError> | import("@torthu/jacketui-core").Success<Uint8Array<ArrayBufferLike>>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { success } from "@torthu/jacketui-core";
|
|
2
|
+
/** bytes(result: Result<Response, BringError>)
|
|
3
|
+
*
|
|
4
|
+
* Utility function to await Response.bytes().
|
|
5
|
+
*
|
|
6
|
+
* @param result Result<Response, BringError>
|
|
7
|
+
* @returns Promise<Result<Uint8Array, BringError>>
|
|
8
|
+
*/
|
|
9
|
+
export const bytes = async (result) => {
|
|
10
|
+
if (result.ok) {
|
|
11
|
+
const res = await result.value.bytes();
|
|
12
|
+
return success(res);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
/** formData(result: Result<Response, BringError>)
|
|
4
|
+
*
|
|
5
|
+
* Utility function to await Response.formData().
|
|
6
|
+
*
|
|
7
|
+
* @param result Result<Response, BringError>
|
|
8
|
+
* @returns Promise<Result<FormData, BringError>>
|
|
9
|
+
*/
|
|
10
|
+
export declare const formData: (result: Result<Response, BringError>) => Promise<import("@torthu/jacketui-core").Failure<BringError> | import("@torthu/jacketui-core").Success<FormData>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { success } from "@torthu/jacketui-core";
|
|
2
|
+
/** formData(result: Result<Response, BringError>)
|
|
3
|
+
*
|
|
4
|
+
* Utility function to await Response.formData().
|
|
5
|
+
*
|
|
6
|
+
* @param result Result<Response, BringError>
|
|
7
|
+
* @returns Promise<Result<FormData, BringError>>
|
|
8
|
+
*/
|
|
9
|
+
export const formData = async (result) => {
|
|
10
|
+
if (result.ok) {
|
|
11
|
+
const res = await result.value.formData();
|
|
12
|
+
return success(res);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
/** json(result: Result<Response, BringError>)
|
|
4
|
+
*
|
|
5
|
+
* Utility function to await Response.json().
|
|
6
|
+
*
|
|
7
|
+
* @param result Result<Response, BringError>
|
|
8
|
+
* @returns Promise<Result<T, BringError>>
|
|
9
|
+
*/
|
|
10
|
+
export declare const json: <T = unknown>(result: Result<Response, BringError>) => Promise<import("@torthu/jacketui-core").Failure<BringError> | import("@torthu/jacketui-core").Success<T>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { success } from "@torthu/jacketui-core";
|
|
2
|
+
/** json(result: Result<Response, BringError>)
|
|
3
|
+
*
|
|
4
|
+
* Utility function to await Response.json().
|
|
5
|
+
*
|
|
6
|
+
* @param result Result<Response, BringError>
|
|
7
|
+
* @returns Promise<Result<T, BringError>>
|
|
8
|
+
*/
|
|
9
|
+
export const json = async (result) => {
|
|
10
|
+
if (result.ok) {
|
|
11
|
+
const json = await result.value.json();
|
|
12
|
+
return success(json);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Result } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
/** text(result: Result<Response, BringError>)
|
|
4
|
+
*
|
|
5
|
+
* Utility function to await Response.text().
|
|
6
|
+
*
|
|
7
|
+
* @param result Result<Response, BringError>
|
|
8
|
+
* @returns Promise<Result<string, BringError>>
|
|
9
|
+
*/
|
|
10
|
+
export declare const text: (result: Result<Response, BringError>) => Promise<import("@torthu/jacketui-core").Failure<BringError> | import("@torthu/jacketui-core").Success<string>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { success } from "@torthu/jacketui-core";
|
|
2
|
+
/** text(result: Result<Response, BringError>)
|
|
3
|
+
*
|
|
4
|
+
* Utility function to await Response.text().
|
|
5
|
+
*
|
|
6
|
+
* @param result Result<Response, BringError>
|
|
7
|
+
* @returns Promise<Result<string, BringError>>
|
|
8
|
+
*/
|
|
9
|
+
export const text = async (result) => {
|
|
10
|
+
if (result.ok) {
|
|
11
|
+
const res = await result.value.text();
|
|
12
|
+
return success(res);
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { AbortError, BringError, TimeoutError } from "../errors";
|
|
1
|
+
import { AbortError, BringError, ClientError, NetworkError, ServerError, TimeoutError } from "../errors";
|
|
2
2
|
type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
|
|
3
3
|
export interface BringCallbacks {
|
|
4
4
|
onAbort?: (error: AbortError) => void;
|
|
5
|
+
onNetworkError?: (error: NetworkError) => void;
|
|
5
6
|
onError?: (error: BringError) => void;
|
|
6
7
|
onRetry?: (retryNum: number) => void;
|
|
7
8
|
onSuccess?: (response: Response) => void;
|
|
8
9
|
onTimeout?: (error: TimeoutError) => void;
|
|
9
|
-
onClientError?: (
|
|
10
|
-
onServerError?: (
|
|
10
|
+
onClientError?: (error: ClientError) => void;
|
|
11
|
+
onServerError?: (error: ServerError) => void;
|
|
11
12
|
}
|
|
12
13
|
export interface RequestInit {
|
|
13
14
|
method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@torthu/jacketui-bring",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Improved fetch API with retry, timeout, and more.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
"email": "torstein@thune.io",
|
|
10
10
|
"url": "https://thune.io"
|
|
11
11
|
},
|
|
12
|
-
"
|
|
13
|
-
|
|
12
|
+
"devDependencies": {
|
|
13
|
+
"fetch-mock": "^12.5.2"
|
|
14
|
+
},
|
|
14
15
|
"dependencies": {
|
|
15
16
|
"@torthu/jacketui-core": "latest"
|
|
16
17
|
},
|
package/src/bring.ts
CHANGED
|
@@ -69,6 +69,7 @@ export const bring = (init: BringInit | BringError) => {
|
|
|
69
69
|
onTimeout,
|
|
70
70
|
onClientError,
|
|
71
71
|
onServerError,
|
|
72
|
+
onNetworkError,
|
|
72
73
|
...requestInit
|
|
73
74
|
} = init;
|
|
74
75
|
|
|
@@ -102,83 +103,90 @@ export const bring = (init: BringInit | BringError) => {
|
|
|
102
103
|
method: requestInit.method ?? "GET",
|
|
103
104
|
reason: abortController.signal.reason,
|
|
104
105
|
},
|
|
106
|
+
cause: error,
|
|
105
107
|
url,
|
|
106
108
|
requestInit: init,
|
|
107
109
|
});
|
|
108
|
-
|
|
110
|
+
|
|
109
111
|
onAbort?.(abortError);
|
|
110
112
|
onError?.(abortError);
|
|
111
|
-
return;
|
|
113
|
+
return resolve(failure(abortError));
|
|
112
114
|
}
|
|
115
|
+
|
|
113
116
|
if (timeoutSignal?.aborted) {
|
|
114
|
-
const
|
|
115
|
-
context: {
|
|
117
|
+
const timeoutError = new TimeoutError("Timeout", {
|
|
118
|
+
context: {
|
|
119
|
+
reason: timeoutSignal.reason,
|
|
120
|
+
timeout,
|
|
121
|
+
},
|
|
122
|
+
cause: error,
|
|
116
123
|
url,
|
|
117
124
|
requestInit: init,
|
|
118
125
|
});
|
|
119
|
-
|
|
120
|
-
onTimeout?.(
|
|
121
|
-
onError?.(
|
|
122
|
-
return;
|
|
126
|
+
|
|
127
|
+
onTimeout?.(timeoutError);
|
|
128
|
+
onError?.(timeoutError);
|
|
129
|
+
return resolve(failure(error));
|
|
123
130
|
}
|
|
124
131
|
|
|
125
132
|
if (error instanceof Error) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
);
|
|
136
|
-
return;
|
|
133
|
+
const networkError = new NetworkError(error.message, {
|
|
134
|
+
context: { url, method: requestInit.method ?? "GET" },
|
|
135
|
+
cause: error,
|
|
136
|
+
url,
|
|
137
|
+
requestInit: init,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
onError?.(networkError);
|
|
141
|
+
return resolve(failure(networkError));
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
if (typeof error === "string") {
|
|
140
|
-
resolve(
|
|
141
|
-
|
|
145
|
+
return resolve(
|
|
146
|
+
failure(new BringError(error, { url, requestInit: init }))
|
|
147
|
+
);
|
|
142
148
|
}
|
|
143
149
|
|
|
144
|
-
resolve(
|
|
150
|
+
return resolve(
|
|
145
151
|
failure(new BringError("Unknown error", { url, requestInit: init }))
|
|
146
152
|
);
|
|
147
153
|
} else {
|
|
148
|
-
const response = value
|
|
154
|
+
const response = value;
|
|
149
155
|
|
|
150
156
|
if (response.ok) {
|
|
151
|
-
resolve(success(response));
|
|
152
157
|
onSuccess?.(response);
|
|
158
|
+
return resolve(success(response));
|
|
153
159
|
} else {
|
|
154
160
|
if (isClientErrorResponse(response)) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
);
|
|
161
|
+
const clientError = new ClientError(response.statusText, {
|
|
162
|
+
context: {
|
|
163
|
+
status: response.status,
|
|
164
|
+
statusText: response.statusText,
|
|
165
|
+
},
|
|
166
|
+
response,
|
|
167
|
+
requestInit: init,
|
|
168
|
+
url,
|
|
169
|
+
});
|
|
170
|
+
onClientError?.(clientError);
|
|
171
|
+
onError?.(clientError);
|
|
172
|
+
return resolve(failure(clientError));
|
|
166
173
|
}
|
|
167
174
|
if (isServerErrorResponse(response)) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
);
|
|
175
|
+
const serverError = new ServerError(response.statusText, {
|
|
176
|
+
response,
|
|
177
|
+
requestInit: init,
|
|
178
|
+
url,
|
|
179
|
+
context: {
|
|
180
|
+
status: response.status,
|
|
181
|
+
statusText: response.statusText,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
onServerError?.(serverError);
|
|
185
|
+
onError?.(serverError);
|
|
186
|
+
return resolve(failure(serverError));
|
|
179
187
|
}
|
|
180
188
|
|
|
181
|
-
const
|
|
189
|
+
const unknownError = new BringError("Fetch failed", {
|
|
182
190
|
context: {
|
|
183
191
|
url,
|
|
184
192
|
status: response.status,
|
|
@@ -188,8 +196,9 @@ export const bring = (init: BringInit | BringError) => {
|
|
|
188
196
|
requestInit: init,
|
|
189
197
|
response,
|
|
190
198
|
});
|
|
191
|
-
|
|
192
|
-
onError?.(
|
|
199
|
+
|
|
200
|
+
onError?.(unknownError);
|
|
201
|
+
return resolve(failure(unknownError));
|
|
193
202
|
}
|
|
194
203
|
}
|
|
195
204
|
});
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Result, success } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
|
|
4
|
+
/** arrayBuffer(result: Result<Response, BringError>)
|
|
5
|
+
*
|
|
6
|
+
* Utility function to await Response.arrayBuffer().
|
|
7
|
+
*
|
|
8
|
+
* @param result Result<Response, BringError>
|
|
9
|
+
* @returns Promise<Result<ArrayBuffer, BringError>>
|
|
10
|
+
*/
|
|
11
|
+
export const arrayBuffer = async (result: Result<Response, BringError>) => {
|
|
12
|
+
if (result.ok) {
|
|
13
|
+
const res = await result.value.arrayBuffer();
|
|
14
|
+
return success(res);
|
|
15
|
+
} else {
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Result, success } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
|
|
4
|
+
/** blob(result: Result<Response, BringError>)
|
|
5
|
+
*
|
|
6
|
+
* Utility function to await Response.blob().
|
|
7
|
+
*
|
|
8
|
+
* @param result Result<Response, BringError>
|
|
9
|
+
* @returns Promise<Result<Blob, BringError>>
|
|
10
|
+
*/
|
|
11
|
+
export const blob = async (result: Result<Response, BringError>) => {
|
|
12
|
+
if (result.ok) {
|
|
13
|
+
const res = await result.value.blob();
|
|
14
|
+
return success(res);
|
|
15
|
+
} else {
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Result, success } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
|
|
4
|
+
/** bytes(result: Result<Response, BringError>)
|
|
5
|
+
*
|
|
6
|
+
* Utility function to await Response.bytes().
|
|
7
|
+
*
|
|
8
|
+
* @param result Result<Response, BringError>
|
|
9
|
+
* @returns Promise<Result<Uint8Array, BringError>>
|
|
10
|
+
*/
|
|
11
|
+
export const bytes = async (result: Result<Response, BringError>) => {
|
|
12
|
+
if (result.ok) {
|
|
13
|
+
const res = await result.value.bytes();
|
|
14
|
+
return success(res);
|
|
15
|
+
} else {
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Result, success } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
|
|
4
|
+
/** formData(result: Result<Response, BringError>)
|
|
5
|
+
*
|
|
6
|
+
* Utility function to await Response.formData().
|
|
7
|
+
*
|
|
8
|
+
* @param result Result<Response, BringError>
|
|
9
|
+
* @returns Promise<Result<FormData, BringError>>
|
|
10
|
+
*/
|
|
11
|
+
export const formData = async (result: Result<Response, BringError>) => {
|
|
12
|
+
if (result.ok) {
|
|
13
|
+
const res = await result.value.formData();
|
|
14
|
+
return success(res);
|
|
15
|
+
} else {
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Result, success } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
|
|
4
|
+
/** json(result: Result<Response, BringError>)
|
|
5
|
+
*
|
|
6
|
+
* Utility function to await Response.json().
|
|
7
|
+
*
|
|
8
|
+
* @param result Result<Response, BringError>
|
|
9
|
+
* @returns Promise<Result<T, BringError>>
|
|
10
|
+
*/
|
|
11
|
+
export const json = async <T = unknown>(
|
|
12
|
+
result: Result<Response, BringError>
|
|
13
|
+
) => {
|
|
14
|
+
if (result.ok) {
|
|
15
|
+
const json = await result.value.json();
|
|
16
|
+
return success(json as T);
|
|
17
|
+
} else {
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Result, success } from "@torthu/jacketui-core";
|
|
2
|
+
import { BringError } from "../errors";
|
|
3
|
+
|
|
4
|
+
/** text(result: Result<Response, BringError>)
|
|
5
|
+
*
|
|
6
|
+
* Utility function to await Response.text().
|
|
7
|
+
*
|
|
8
|
+
* @param result Result<Response, BringError>
|
|
9
|
+
* @returns Promise<Result<string, BringError>>
|
|
10
|
+
*/
|
|
11
|
+
export const text = async (result: Result<Response, BringError>) => {
|
|
12
|
+
if (result.ok) {
|
|
13
|
+
const res = await result.value.text();
|
|
14
|
+
return success(res);
|
|
15
|
+
} else {
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
};
|
package/src/types/BringInit.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AbortError,
|
|
3
|
+
BringError,
|
|
4
|
+
ClientError,
|
|
5
|
+
NetworkError,
|
|
6
|
+
ServerError,
|
|
7
|
+
TimeoutError,
|
|
8
|
+
} from "../errors";
|
|
2
9
|
|
|
3
10
|
type TypedArray =
|
|
4
11
|
| Int8Array
|
|
@@ -15,12 +22,13 @@ type TypedArray =
|
|
|
15
22
|
|
|
16
23
|
export interface BringCallbacks {
|
|
17
24
|
onAbort?: (error: AbortError) => void;
|
|
25
|
+
onNetworkError?: (error: NetworkError) => void;
|
|
18
26
|
onError?: (error: BringError) => void;
|
|
19
27
|
onRetry?: (retryNum: number) => void;
|
|
20
28
|
onSuccess?: (response: Response) => void;
|
|
21
29
|
onTimeout?: (error: TimeoutError) => void;
|
|
22
|
-
onClientError?: (
|
|
23
|
-
onServerError?: (
|
|
30
|
+
onClientError?: (error: ClientError) => void;
|
|
31
|
+
onServerError?: (error: ServerError) => void;
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
export interface RequestInit {
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
describe,
|
|
3
|
+
expect,
|
|
4
|
+
it,
|
|
5
|
+
beforeAll,
|
|
6
|
+
afterAll,
|
|
7
|
+
afterEach,
|
|
8
|
+
vi,
|
|
9
|
+
} from "vitest";
|
|
10
|
+
import fetchMock from "fetch-mock";
|
|
11
|
+
import {
|
|
12
|
+
AbortError,
|
|
13
|
+
bring,
|
|
14
|
+
ClientError,
|
|
15
|
+
ServerError,
|
|
16
|
+
TimeoutError,
|
|
17
|
+
} from "../src";
|
|
18
|
+
import { isResult } from "@torthu/jacketui-core";
|
|
19
|
+
|
|
20
|
+
describe("bring", () => {
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
fetchMock.mockGlobal();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
fetchMock.removeRoutes();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
afterAll(() => {
|
|
30
|
+
fetchMock.unmockGlobal();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should return a Response wrapped in Result", async () => {
|
|
34
|
+
fetchMock.get("http://example.com", 200);
|
|
35
|
+
|
|
36
|
+
const response = await bring({ url: "http://example.com" });
|
|
37
|
+
|
|
38
|
+
expect(isResult(response)).toBe(true);
|
|
39
|
+
expect(response.ok).toBe(true);
|
|
40
|
+
expect(response.value).toBeInstanceOf(Response);
|
|
41
|
+
|
|
42
|
+
fetchMock.removeRoute("http://example.com");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("server error should return an Error wrapped in Result", async () => {
|
|
46
|
+
fetchMock.get("http://example.com", 500);
|
|
47
|
+
|
|
48
|
+
const response = await bring({
|
|
49
|
+
url: "http://example.com",
|
|
50
|
+
retry: 1,
|
|
51
|
+
timeout: 100,
|
|
52
|
+
onError: () => console.log("error"),
|
|
53
|
+
onRetry: () => console.log("retrying"),
|
|
54
|
+
onTimeout: () => console.log("timeout"),
|
|
55
|
+
onClientError: () => console.log("client error"),
|
|
56
|
+
onServerError: () => console.log("server error"),
|
|
57
|
+
onAbort: () => console.log("aborted"),
|
|
58
|
+
onSuccess: () => console.log("success"),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
console.log(response);
|
|
62
|
+
|
|
63
|
+
expect(isResult(response)).toBe(true);
|
|
64
|
+
expect(response.ok).toBe(false);
|
|
65
|
+
expect(response.error).toBeInstanceOf(ServerError);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("client error should return an Error wrapped in Result", async () => {
|
|
69
|
+
fetchMock.get("http://example.com", 400);
|
|
70
|
+
const response = await bring({ url: "http://example.com" });
|
|
71
|
+
expect(isResult(response)).toBe(true);
|
|
72
|
+
expect(response.ok).toBe(false);
|
|
73
|
+
expect(response.error).toBeInstanceOf(ClientError);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("client error should return an Error wrapped in Result", async () => {
|
|
77
|
+
fetchMock.get("http://example.com", 400);
|
|
78
|
+
const response = await bring({ url: "http://example.com" });
|
|
79
|
+
expect(isResult(response)).toBe(true);
|
|
80
|
+
expect(response.ok).toBe(false);
|
|
81
|
+
expect(response.error).toBeInstanceOf(ClientError);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("should timeout", async () => {
|
|
85
|
+
fetchMock.get("http://foo.bar.com", 200, {
|
|
86
|
+
delay: 5000,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const retryCb = vi.fn();
|
|
90
|
+
|
|
91
|
+
const response = await bring({
|
|
92
|
+
url: "http://foo.bar.com",
|
|
93
|
+
timeout: 10,
|
|
94
|
+
onRetry: retryCb,
|
|
95
|
+
retry: 3,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(isResult(response)).toBe(true);
|
|
99
|
+
expect(response.ok).toBe(false);
|
|
100
|
+
expect(response.error).toBeInstanceOf(TimeoutError);
|
|
101
|
+
expect(retryCb).toHaveBeenCalledTimes(3);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should retry", async () => {
|
|
105
|
+
fetchMock.get("http://foo.bar.com", 200, {
|
|
106
|
+
delay: 5000,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const retryCb = vi.fn();
|
|
110
|
+
|
|
111
|
+
const response = await bring({
|
|
112
|
+
url: "http://foo.bar.com",
|
|
113
|
+
timeout: 10,
|
|
114
|
+
onRetry: retryCb,
|
|
115
|
+
retry: 3,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(isResult(response)).toBe(true);
|
|
119
|
+
expect(response.ok).toBe(false);
|
|
120
|
+
expect(response.error).toBeInstanceOf(TimeoutError);
|
|
121
|
+
expect(retryCb).toHaveBeenCalledTimes(3);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should abort", () =>
|
|
125
|
+
new Promise<void>((done) => {
|
|
126
|
+
fetchMock.get("http://foo.bar.com", 200, {
|
|
127
|
+
delay: 5000,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const abortController = new AbortController();
|
|
131
|
+
let response;
|
|
132
|
+
|
|
133
|
+
const promise = bring({
|
|
134
|
+
url: "http://foo.bar.com",
|
|
135
|
+
timeout: 10,
|
|
136
|
+
abortController,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
promise.then((res) => {
|
|
140
|
+
response = res;
|
|
141
|
+
expect(isResult(response)).toBe(true);
|
|
142
|
+
expect(response.ok).toBe(false);
|
|
143
|
+
expect(response.error).toBeInstanceOf(AbortError);
|
|
144
|
+
done();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
abortController.abort();
|
|
148
|
+
}));
|
|
149
|
+
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|