@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.
Files changed (87) hide show
  1. package/dist/bring.js +34 -25
  2. package/dist/index.d.ts +2 -1
  3. package/dist/index.js +2 -1
  4. package/dist/response-pipe/arrayBuffer.d.ts +10 -0
  5. package/dist/response-pipe/arrayBuffer.js +17 -0
  6. package/dist/response-pipe/blob.d.ts +10 -0
  7. package/dist/response-pipe/blob.js +17 -0
  8. package/dist/response-pipe/bytes.d.ts +10 -0
  9. package/dist/response-pipe/bytes.js +17 -0
  10. package/dist/response-pipe/formData.d.ts +10 -0
  11. package/dist/response-pipe/formData.js +17 -0
  12. package/dist/response-pipe/index.d.ts +6 -0
  13. package/dist/response-pipe/index.js +6 -0
  14. package/dist/response-pipe/json.d.ts +10 -0
  15. package/dist/response-pipe/json.js +17 -0
  16. package/dist/response-pipe/text.d.ts +10 -0
  17. package/dist/response-pipe/text.js +17 -0
  18. package/dist/types/BringInit.d.ts +4 -3
  19. package/package.json +4 -3
  20. package/src/bring.ts +58 -49
  21. package/src/index.ts +2 -1
  22. package/src/response-pipe/arrayBuffer.ts +18 -0
  23. package/src/response-pipe/blob.ts +18 -0
  24. package/src/response-pipe/bytes.ts +18 -0
  25. package/src/response-pipe/formData.ts +18 -0
  26. package/src/response-pipe/index.ts +6 -0
  27. package/src/response-pipe/json.ts +20 -0
  28. package/src/response-pipe/text.ts +18 -0
  29. package/src/types/BringInit.ts +11 -3
  30. package/test/bring.spec.ts +149 -0
  31. /package/dist/{pipe-helpers → request-builder-pipe}/backoff.d.ts +0 -0
  32. /package/dist/{pipe-helpers → request-builder-pipe}/backoff.js +0 -0
  33. /package/dist/{pipe-helpers → request-builder-pipe}/body.d.ts +0 -0
  34. /package/dist/{pipe-helpers → request-builder-pipe}/body.js +0 -0
  35. /package/dist/{pipe-helpers → request-builder-pipe}/cache.d.ts +0 -0
  36. /package/dist/{pipe-helpers → request-builder-pipe}/cache.js +0 -0
  37. /package/dist/{pipe-helpers → request-builder-pipe}/cors.d.ts +0 -0
  38. /package/dist/{pipe-helpers → request-builder-pipe}/cors.js +0 -0
  39. /package/dist/{pipe-helpers → request-builder-pipe}/credentials.d.ts +0 -0
  40. /package/dist/{pipe-helpers → request-builder-pipe}/credentials.js +0 -0
  41. /package/dist/{pipe-helpers → request-builder-pipe}/header.d.ts +0 -0
  42. /package/dist/{pipe-helpers → request-builder-pipe}/header.js +0 -0
  43. /package/dist/{pipe-helpers → request-builder-pipe}/index.d.ts +0 -0
  44. /package/dist/{pipe-helpers → request-builder-pipe}/index.js +0 -0
  45. /package/dist/{pipe-helpers → request-builder-pipe}/integrity.d.ts +0 -0
  46. /package/dist/{pipe-helpers → request-builder-pipe}/integrity.js +0 -0
  47. /package/dist/{pipe-helpers → request-builder-pipe}/jitter.d.ts +0 -0
  48. /package/dist/{pipe-helpers → request-builder-pipe}/jitter.js +0 -0
  49. /package/dist/{pipe-helpers → request-builder-pipe}/jsonBody.d.ts +0 -0
  50. /package/dist/{pipe-helpers → request-builder-pipe}/jsonBody.js +0 -0
  51. /package/dist/{pipe-helpers → request-builder-pipe}/keepalive.d.ts +0 -0
  52. /package/dist/{pipe-helpers → request-builder-pipe}/keepalive.js +0 -0
  53. /package/dist/{pipe-helpers → request-builder-pipe}/method.d.ts +0 -0
  54. /package/dist/{pipe-helpers → request-builder-pipe}/method.js +0 -0
  55. /package/dist/{pipe-helpers → request-builder-pipe}/priority.d.ts +0 -0
  56. /package/dist/{pipe-helpers → request-builder-pipe}/priority.js +0 -0
  57. /package/dist/{pipe-helpers → request-builder-pipe}/redirect.d.ts +0 -0
  58. /package/dist/{pipe-helpers → request-builder-pipe}/redirect.js +0 -0
  59. /package/dist/{pipe-helpers → request-builder-pipe}/referrer.d.ts +0 -0
  60. /package/dist/{pipe-helpers → request-builder-pipe}/referrer.js +0 -0
  61. /package/dist/{pipe-helpers → request-builder-pipe}/referrerPolicy.d.ts +0 -0
  62. /package/dist/{pipe-helpers → request-builder-pipe}/referrerPolicy.js +0 -0
  63. /package/dist/{pipe-helpers → request-builder-pipe}/retry.d.ts +0 -0
  64. /package/dist/{pipe-helpers → request-builder-pipe}/retry.js +0 -0
  65. /package/dist/{pipe-helpers → request-builder-pipe}/shouldRetry.d.ts +0 -0
  66. /package/dist/{pipe-helpers → request-builder-pipe}/shouldRetry.js +0 -0
  67. /package/dist/{pipe-helpers → request-builder-pipe}/timeout.d.ts +0 -0
  68. /package/dist/{pipe-helpers → request-builder-pipe}/timeout.js +0 -0
  69. /package/src/{pipe-helpers → request-builder-pipe}/backoff.ts +0 -0
  70. /package/src/{pipe-helpers → request-builder-pipe}/body.ts +0 -0
  71. /package/src/{pipe-helpers → request-builder-pipe}/cache.ts +0 -0
  72. /package/src/{pipe-helpers → request-builder-pipe}/cors.ts +0 -0
  73. /package/src/{pipe-helpers → request-builder-pipe}/credentials.ts +0 -0
  74. /package/src/{pipe-helpers → request-builder-pipe}/header.ts +0 -0
  75. /package/src/{pipe-helpers → request-builder-pipe}/index.ts +0 -0
  76. /package/src/{pipe-helpers → request-builder-pipe}/integrity.ts +0 -0
  77. /package/src/{pipe-helpers → request-builder-pipe}/jitter.ts +0 -0
  78. /package/src/{pipe-helpers → request-builder-pipe}/jsonBody.ts +0 -0
  79. /package/src/{pipe-helpers → request-builder-pipe}/keepalive.ts +0 -0
  80. /package/src/{pipe-helpers → request-builder-pipe}/method.ts +0 -0
  81. /package/src/{pipe-helpers → request-builder-pipe}/priority.ts +0 -0
  82. /package/src/{pipe-helpers → request-builder-pipe}/redirect.ts +0 -0
  83. /package/src/{pipe-helpers → request-builder-pipe}/referrer.ts +0 -0
  84. /package/src/{pipe-helpers → request-builder-pipe}/referrerPolicy.ts +0 -0
  85. /package/src/{pipe-helpers → request-builder-pipe}/retry.ts +0 -0
  86. /package/src/{pipe-helpers → request-builder-pipe}/shouldRetry.ts +0 -0
  87. /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 error = new TimeoutError("Timeout", {
73
- context: { reason: timeoutSignal.reason, timeout },
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
- resolve(failure(error));
78
- onTimeout?.(error);
79
- onError?.(error);
80
- return;
81
+ onTimeout?.(timeoutError);
82
+ onError?.(timeoutError);
83
+ return resolve(failure(error));
81
84
  }
82
85
  if (error instanceof Error) {
83
- resolve(failure(new BringError(error.message, {
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
- return;
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
- return failure(new ClientError(response.statusText, {
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
- return failure(new ServerError(response.statusText, {
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 error = new BringError("Fetch failed", {
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
- resolve(failure(error));
137
- onError?.(error);
145
+ onError?.(unknownError);
146
+ return resolve(failure(unknownError));
138
147
  }
139
148
  }
140
149
  });
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./bring";
2
2
  export * from "./tryFetch";
3
3
  export * from "./errors";
4
- export * from "./pipe-helpers";
4
+ export * from "./request-builder-pipe";
5
+ export * from "./response-pipe";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./bring";
2
2
  export * from "./tryFetch";
3
3
  export * from "./errors";
4
- export * from "./pipe-helpers";
4
+ export * from "./request-builder-pipe";
5
+ export * from "./response-pipe";
@@ -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,6 @@
1
+ export * from "./arrayBuffer";
2
+ export * from "./blob";
3
+ export * from "./bytes";
4
+ export * from "./formData";
5
+ export * from "./json";
6
+ export * from "./text";
@@ -0,0 +1,6 @@
1
+ export * from "./arrayBuffer";
2
+ export * from "./blob";
3
+ export * from "./bytes";
4
+ export * from "./formData";
5
+ export * from "./json";
6
+ export * from "./text";
@@ -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?: (response: Response) => void;
10
- onServerError?: (response: Response) => void;
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.1",
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
- "peerDependencies": {},
13
- "devDependencies": {},
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
- resolve(failure(abortError));
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 error = new TimeoutError("Timeout", {
115
- context: { reason: timeoutSignal.reason, timeout },
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
- resolve(failure(error));
120
- onTimeout?.(error);
121
- onError?.(error);
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
- resolve(
127
- failure(
128
- new BringError(error.message, {
129
- cause: error,
130
- context: { url, method: requestInit.method ?? "GET" },
131
- url,
132
- requestInit: init,
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(failure(new BringError(error, { url, requestInit: init })));
141
- return;
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
- return failure(
156
- new ClientError(response.statusText, {
157
- context: {
158
- status: response.status,
159
- statusText: response.statusText,
160
- },
161
- response,
162
- requestInit: init,
163
- url,
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
- return failure(
169
- new ServerError(response.statusText, {
170
- response,
171
- requestInit: init,
172
- url,
173
- context: {
174
- status: response.status,
175
- statusText: response.statusText,
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 error = new BringError("Fetch failed", {
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
- resolve(failure(error));
192
- onError?.(error);
199
+
200
+ onError?.(unknownError);
201
+ return resolve(failure(unknownError));
193
202
  }
194
203
  }
195
204
  });
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./bring";
2
2
  export * from "./tryFetch";
3
3
  export * from "./errors";
4
- export * from "./pipe-helpers";
4
+ export * from "./request-builder-pipe";
5
+ export * from "./response-pipe";
@@ -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,6 @@
1
+ export * from "./arrayBuffer";
2
+ export * from "./blob";
3
+ export * from "./bytes";
4
+ export * from "./formData";
5
+ export * from "./json";
6
+ export * from "./text";
@@ -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
+ };
@@ -1,4 +1,11 @@
1
- import { AbortError, BringError, TimeoutError } from "../errors";
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?: (response: Response) => void;
23
- onServerError?: (response: Response) => void;
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
+ });