@byndyusoft-ui/http-client 0.1.0-alpha.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 +479 -0
- package/dist/cjs/adapters/FetchAdapter.cjs +218 -0
- package/dist/cjs/adapters/XhrAdapter.cjs +357 -0
- package/dist/cjs/asserts/assertNonBlankString.cjs +11 -0
- package/dist/cjs/asserts/assertValidAdapter.cjs +15 -0
- package/dist/cjs/asserts/assertValidBaseUrl.cjs +10 -0
- package/dist/cjs/asserts/assertValidBody.cjs +17 -0
- package/dist/cjs/asserts/assertValidFetchAdapterOptions.cjs +70 -0
- package/dist/cjs/asserts/assertValidHeader.cjs +18 -0
- package/dist/cjs/asserts/assertValidHeaders.cjs +17 -0
- package/dist/cjs/asserts/assertValidHttpClientOptions.cjs +60 -0
- package/dist/cjs/asserts/assertValidMethod.cjs +13 -0
- package/dist/cjs/asserts/assertValidParam.cjs +23 -0
- package/dist/cjs/asserts/assertValidParams.cjs +17 -0
- package/dist/cjs/asserts/assertValidRequestConfig.cjs +55 -0
- package/dist/cjs/asserts/assertValidResponseType.cjs +13 -0
- package/dist/cjs/asserts/assertValidSignal.cjs +16 -0
- package/dist/cjs/asserts/assertValidTimeout.cjs +12 -0
- package/dist/cjs/asserts/assertValidUrl.cjs +10 -0
- package/dist/cjs/asserts/assertValidValidateStatus.cjs +13 -0
- package/dist/cjs/asserts/assertValidWithCredentials.cjs +12 -0
- package/dist/cjs/asserts/assertValidXhrAdapterOptions.cjs +39 -0
- package/dist/cjs/asserts/headerValueLineBreakPattern.cjs +5 -0
- package/dist/cjs/asserts/isRecord.cjs +11 -0
- package/dist/cjs/constants/httpMethods.cjs +13 -0
- package/dist/cjs/constants/httpResponseTypes.cjs +11 -0
- package/dist/cjs/constants/httpStatusCodes.cjs +68 -0
- package/dist/cjs/constants/requestBuilderErrorCodes.cjs +26 -0
- package/dist/cjs/core/HttpClient.cjs +141 -0
- package/dist/cjs/core/HttpRequestBuilder.cjs +129 -0
- package/dist/cjs/errors/AbortError.cjs +12 -0
- package/dist/cjs/errors/HttpClientError.cjs +18 -0
- package/dist/cjs/errors/HttpResponseError.cjs +26 -0
- package/dist/cjs/errors/NetworkError.cjs +12 -0
- package/dist/cjs/errors/ParseError.cjs +20 -0
- package/dist/cjs/errors/RequestBuilderError.cjs +18 -0
- package/dist/cjs/errors/RequestPreparationError.cjs +13 -0
- package/dist/cjs/errors/TimeoutError.cjs +18 -0
- package/dist/cjs/index.cjs +45 -0
- package/dist/cjs/utilities/buildUrl.cjs +94 -0
- package/dist/cjs/utilities/getErrorMessage.cjs +8 -0
- package/dist/cjs/utilities/isStatusAccepted.cjs +8 -0
- package/dist/cjs/utilities/mergeHeaders.cjs +30 -0
- package/dist/cjs/utilities/mergeParams.cjs +37 -0
- package/dist/cjs/utilities/prepareRequestBody.cjs +43 -0
- package/dist/esm/adapters/FetchAdapter.js +216 -0
- package/dist/esm/adapters/XhrAdapter.js +355 -0
- package/dist/esm/asserts/assertNonBlankString.js +9 -0
- package/dist/esm/asserts/assertValidAdapter.js +13 -0
- package/dist/esm/asserts/assertValidBaseUrl.js +8 -0
- package/dist/esm/asserts/assertValidBody.js +15 -0
- package/dist/esm/asserts/assertValidFetchAdapterOptions.js +68 -0
- package/dist/esm/asserts/assertValidHeader.js +16 -0
- package/dist/esm/asserts/assertValidHeaders.js +15 -0
- package/dist/esm/asserts/assertValidHttpClientOptions.js +58 -0
- package/dist/esm/asserts/assertValidMethod.js +11 -0
- package/dist/esm/asserts/assertValidParam.js +21 -0
- package/dist/esm/asserts/assertValidParams.js +15 -0
- package/dist/esm/asserts/assertValidRequestConfig.js +53 -0
- package/dist/esm/asserts/assertValidResponseType.js +11 -0
- package/dist/esm/asserts/assertValidSignal.js +14 -0
- package/dist/esm/asserts/assertValidTimeout.js +10 -0
- package/dist/esm/asserts/assertValidUrl.js +8 -0
- package/dist/esm/asserts/assertValidValidateStatus.js +11 -0
- package/dist/esm/asserts/assertValidWithCredentials.js +10 -0
- package/dist/esm/asserts/assertValidXhrAdapterOptions.js +37 -0
- package/dist/esm/asserts/headerValueLineBreakPattern.js +3 -0
- package/dist/esm/asserts/isRecord.js +9 -0
- package/dist/esm/constants/httpMethods.js +11 -0
- package/dist/esm/constants/httpResponseTypes.js +9 -0
- package/dist/esm/constants/httpStatusCodes.js +66 -0
- package/dist/esm/constants/requestBuilderErrorCodes.js +24 -0
- package/dist/esm/core/HttpClient.js +139 -0
- package/dist/esm/core/HttpRequestBuilder.js +127 -0
- package/dist/esm/errors/AbortError.js +9 -0
- package/dist/esm/errors/HttpClientError.js +15 -0
- package/dist/esm/errors/HttpResponseError.js +23 -0
- package/dist/esm/errors/NetworkError.js +9 -0
- package/dist/esm/errors/ParseError.js +17 -0
- package/dist/esm/errors/RequestBuilderError.js +15 -0
- package/dist/esm/errors/RequestPreparationError.js +10 -0
- package/dist/esm/errors/TimeoutError.js +15 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/utilities/buildUrl.js +92 -0
- package/dist/esm/utilities/getErrorMessage.js +6 -0
- package/dist/esm/utilities/isStatusAccepted.js +6 -0
- package/dist/esm/utilities/mergeHeaders.js +27 -0
- package/dist/esm/utilities/mergeParams.js +35 -0
- package/dist/esm/utilities/prepareRequestBody.js +41 -0
- package/dist/index.d.ts +354 -0
- package/package.json +53 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var httpMethods = require('../constants/httpMethods.cjs');
|
|
4
|
+
var assertValidAdapter = require('../asserts/assertValidAdapter.cjs');
|
|
5
|
+
var assertValidHttpClientOptions = require('../asserts/assertValidHttpClientOptions.cjs');
|
|
6
|
+
var assertValidRequestConfig = require('../asserts/assertValidRequestConfig.cjs');
|
|
7
|
+
var FetchAdapter = require('../adapters/FetchAdapter.cjs');
|
|
8
|
+
var mergeHeaders = require('../utilities/mergeHeaders.cjs');
|
|
9
|
+
var mergeParams = require('../utilities/mergeParams.cjs');
|
|
10
|
+
var HttpRequestBuilder = require('./HttpRequestBuilder.cjs');
|
|
11
|
+
|
|
12
|
+
class HttpClient {
|
|
13
|
+
adapter;
|
|
14
|
+
defaultConfig;
|
|
15
|
+
onRequestHook;
|
|
16
|
+
onRequestErrorHook;
|
|
17
|
+
onResponseHook;
|
|
18
|
+
onResponseErrorHook;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
assertValidHttpClientOptions.assertValidHttpClientOptions(options);
|
|
21
|
+
this.adapter = options.adapter ?? new FetchAdapter.FetchAdapter();
|
|
22
|
+
this.onRequestHook = options.onRequest;
|
|
23
|
+
this.onRequestErrorHook = options.onRequestError;
|
|
24
|
+
this.onResponseHook = options.onResponse;
|
|
25
|
+
this.onResponseErrorHook = options.onResponseError;
|
|
26
|
+
this.defaultConfig = {
|
|
27
|
+
baseUrl: options.baseUrl,
|
|
28
|
+
headers: mergeHeaders.mergeHeaders(options.headers),
|
|
29
|
+
params: mergeParams.mergeParams(options.params),
|
|
30
|
+
timeout: options.timeout,
|
|
31
|
+
validateStatus: options.validateStatus,
|
|
32
|
+
withCredentials: options.withCredentials
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/** Creates an independent client with the current defaults and hooks, using the provided adapter. */
|
|
36
|
+
withAdapter(adapter) {
|
|
37
|
+
assertValidAdapter.assertValidAdapter(adapter);
|
|
38
|
+
return new HttpClient({
|
|
39
|
+
...this.defaultConfig,
|
|
40
|
+
adapter,
|
|
41
|
+
onRequest: this.onRequestHook,
|
|
42
|
+
onRequestError: this.onRequestErrorHook,
|
|
43
|
+
onResponse: this.onResponseHook,
|
|
44
|
+
onResponseError: this.onResponseErrorHook
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/** Sets the onRequest hook, replacing the hook configured through constructor options. Returns this client for chaining. */
|
|
48
|
+
onRequest(hook) {
|
|
49
|
+
this.onRequestHook = hook;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
/** Sets the onRequestError hook, replacing the hook configured through constructor options. Returns this client for chaining. */
|
|
53
|
+
onRequestError(hook) {
|
|
54
|
+
this.onRequestErrorHook = hook;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
/** Sets the onResponse hook, replacing the hook configured through constructor options. Returns this client for chaining. */
|
|
58
|
+
onResponse(hook) {
|
|
59
|
+
this.onResponseHook = hook;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
/** Sets the onResponseError hook, replacing the hook configured through constructor options. Returns this client for chaining. */
|
|
63
|
+
onResponseError(hook) {
|
|
64
|
+
this.onResponseErrorHook = hook;
|
|
65
|
+
return this;
|
|
66
|
+
}
|
|
67
|
+
request(method, url) {
|
|
68
|
+
const executor = (config) => this.executeRequest(config);
|
|
69
|
+
return new HttpRequestBuilder.HttpRequestBuilder(executor, method, url);
|
|
70
|
+
}
|
|
71
|
+
get(url) {
|
|
72
|
+
return this.request(httpMethods.HTTP_METHODS.GET, url);
|
|
73
|
+
}
|
|
74
|
+
head(url) {
|
|
75
|
+
return this.request(httpMethods.HTTP_METHODS.HEAD, url);
|
|
76
|
+
}
|
|
77
|
+
post(url) {
|
|
78
|
+
return this.request(httpMethods.HTTP_METHODS.POST, url);
|
|
79
|
+
}
|
|
80
|
+
put(url) {
|
|
81
|
+
return this.request(httpMethods.HTTP_METHODS.PUT, url);
|
|
82
|
+
}
|
|
83
|
+
delete(url) {
|
|
84
|
+
return this.request(httpMethods.HTTP_METHODS.DELETE, url);
|
|
85
|
+
}
|
|
86
|
+
options(url) {
|
|
87
|
+
return this.request(httpMethods.HTTP_METHODS.OPTIONS, url);
|
|
88
|
+
}
|
|
89
|
+
patch(url) {
|
|
90
|
+
return this.request(httpMethods.HTTP_METHODS.PATCH, url);
|
|
91
|
+
}
|
|
92
|
+
async executeRequest(config) {
|
|
93
|
+
const { onRequestHook: onRequest, onRequestErrorHook: onRequestError, onResponseHook: onResponse, onResponseErrorHook: onResponseError } = this;
|
|
94
|
+
let mergedConfig = {
|
|
95
|
+
...config,
|
|
96
|
+
baseUrl: config.baseUrl ?? this.defaultConfig.baseUrl,
|
|
97
|
+
timeout: config.timeout ?? this.defaultConfig.timeout,
|
|
98
|
+
validateStatus: config.validateStatus ?? this.defaultConfig.validateStatus,
|
|
99
|
+
withCredentials: config.withCredentials ?? this.defaultConfig.withCredentials,
|
|
100
|
+
headers: mergeHeaders.mergeHeaders(this.defaultConfig.headers, config.headers),
|
|
101
|
+
params: mergeParams.mergeParams(this.defaultConfig.params, config.params)
|
|
102
|
+
};
|
|
103
|
+
if (onRequest !== undefined) {
|
|
104
|
+
try {
|
|
105
|
+
const requestConfig = await onRequest(mergedConfig);
|
|
106
|
+
assertValidRequestConfig.assertValidRequestConfig(requestConfig);
|
|
107
|
+
mergedConfig = requestConfig;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (onRequestError === undefined) {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
const recoveredConfig = await onRequestError(error);
|
|
114
|
+
if (recoveredConfig === undefined) {
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
assertValidRequestConfig.assertValidRequestConfig(recoveredConfig);
|
|
118
|
+
mergedConfig = recoveredConfig;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
let response = await this.adapter.request(mergedConfig);
|
|
123
|
+
if (onResponse !== undefined) {
|
|
124
|
+
response = await onResponse(response);
|
|
125
|
+
}
|
|
126
|
+
return response;
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (onResponseError === undefined) {
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
const recoveredResponse = await onResponseError(error);
|
|
133
|
+
if (recoveredResponse === undefined) {
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
return recoveredResponse;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
exports.HttpClient = HttpClient;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var httpResponseTypes = require('../constants/httpResponseTypes.cjs');
|
|
4
|
+
var requestBuilderErrorCodes = require('../constants/requestBuilderErrorCodes.cjs');
|
|
5
|
+
var RequestBuilderError = require('../errors/RequestBuilderError.cjs');
|
|
6
|
+
var assertValidBody = require('../asserts/assertValidBody.cjs');
|
|
7
|
+
var assertNonBlankString = require('../asserts/assertNonBlankString.cjs');
|
|
8
|
+
var assertValidBaseUrl = require('../asserts/assertValidBaseUrl.cjs');
|
|
9
|
+
var assertValidHeader = require('../asserts/assertValidHeader.cjs');
|
|
10
|
+
var assertValidHeaders = require('../asserts/assertValidHeaders.cjs');
|
|
11
|
+
var assertValidParams = require('../asserts/assertValidParams.cjs');
|
|
12
|
+
var assertValidTimeout = require('../asserts/assertValidTimeout.cjs');
|
|
13
|
+
var assertValidWithCredentials = require('../asserts/assertValidWithCredentials.cjs');
|
|
14
|
+
var assertValidValidateStatus = require('../asserts/assertValidValidateStatus.cjs');
|
|
15
|
+
var assertValidMethod = require('../asserts/assertValidMethod.cjs');
|
|
16
|
+
var assertValidParam = require('../asserts/assertValidParam.cjs');
|
|
17
|
+
var assertValidRequestConfig = require('../asserts/assertValidRequestConfig.cjs');
|
|
18
|
+
var assertValidSignal = require('../asserts/assertValidSignal.cjs');
|
|
19
|
+
var assertValidUrl = require('../asserts/assertValidUrl.cjs');
|
|
20
|
+
var headerValueLineBreakPattern = require('../asserts/headerValueLineBreakPattern.cjs');
|
|
21
|
+
var mergeHeaders = require('../utilities/mergeHeaders.cjs');
|
|
22
|
+
var mergeParams = require('../utilities/mergeParams.cjs');
|
|
23
|
+
|
|
24
|
+
function cloneConfig(config) {
|
|
25
|
+
return {
|
|
26
|
+
...config,
|
|
27
|
+
...(config.headers === undefined ? {} : { headers: { ...config.headers } }),
|
|
28
|
+
...(config.params === undefined ? {} : { params: mergeParams.mergeParams(config.params) })
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Builds request configs immutably. Every configuration method returns a new builder instance.
|
|
33
|
+
*/
|
|
34
|
+
class HttpRequestBuilder {
|
|
35
|
+
executor;
|
|
36
|
+
config;
|
|
37
|
+
constructor(executor, method, url) {
|
|
38
|
+
if (typeof executor !== 'function') {
|
|
39
|
+
throw new RequestBuilderError.RequestBuilderError('Executor must be a function', requestBuilderErrorCodes.REQUEST_BUILDER_ERROR_CODES.INVALID_EXECUTOR);
|
|
40
|
+
}
|
|
41
|
+
assertValidMethod.assertValidMethod(method);
|
|
42
|
+
assertValidUrl.assertValidUrl(url);
|
|
43
|
+
this.executor = executor;
|
|
44
|
+
this.config = { method, url };
|
|
45
|
+
}
|
|
46
|
+
withConfig(partial) {
|
|
47
|
+
const builder = new HttpRequestBuilder(this.executor, this.config.method, this.config.url);
|
|
48
|
+
builder.config = cloneConfig({ ...this.config, ...partial });
|
|
49
|
+
return builder;
|
|
50
|
+
}
|
|
51
|
+
build() {
|
|
52
|
+
assertValidRequestConfig.assertValidRequestConfig(this.config);
|
|
53
|
+
return cloneConfig(this.config);
|
|
54
|
+
}
|
|
55
|
+
baseUrl(value) {
|
|
56
|
+
assertValidBaseUrl.assertValidBaseUrl(value);
|
|
57
|
+
return this.withConfig({ baseUrl: value });
|
|
58
|
+
}
|
|
59
|
+
header(key, value) {
|
|
60
|
+
assertValidHeader.assertValidHeader(key, value);
|
|
61
|
+
return this.withConfig({ headers: mergeHeaders.mergeHeaders(this.config.headers, { [key]: value }) });
|
|
62
|
+
}
|
|
63
|
+
headers(headers) {
|
|
64
|
+
assertValidHeaders.assertValidHeaders(headers);
|
|
65
|
+
return this.withConfig({ headers: mergeHeaders.mergeHeaders(this.config.headers, headers) });
|
|
66
|
+
}
|
|
67
|
+
param(key, value) {
|
|
68
|
+
assertValidParam.assertValidParam(key, value);
|
|
69
|
+
return this.withConfig({
|
|
70
|
+
params: mergeParams.mergeParams(this.config.params, { [key]: value })
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
params(params) {
|
|
74
|
+
assertValidParams.assertValidParams(params);
|
|
75
|
+
return this.withConfig({
|
|
76
|
+
params: mergeParams.mergeParams(this.config.params, params)
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
body(data) {
|
|
80
|
+
assertValidBody.assertValidBody(this.config.method, data);
|
|
81
|
+
return this.withConfig({ data });
|
|
82
|
+
}
|
|
83
|
+
signal(signal) {
|
|
84
|
+
assertValidSignal.assertValidSignal(signal);
|
|
85
|
+
return this.withConfig({ signal });
|
|
86
|
+
}
|
|
87
|
+
/** A zero timeout disables the request timeout, including a timeout inherited from the client config. */
|
|
88
|
+
timeout(timeout) {
|
|
89
|
+
assertValidTimeout.assertValidTimeout(timeout);
|
|
90
|
+
return this.withConfig({ timeout });
|
|
91
|
+
}
|
|
92
|
+
/** Determines whether a response status should be treated as successful. */
|
|
93
|
+
validateStatus(validateStatus) {
|
|
94
|
+
assertValidValidateStatus.assertValidValidateStatus(validateStatus);
|
|
95
|
+
return this.withConfig({ validateStatus });
|
|
96
|
+
}
|
|
97
|
+
/** Includes credentials in cross-origin requests. */
|
|
98
|
+
withCredentials(withCredentials) {
|
|
99
|
+
assertValidWithCredentials.assertValidWithCredentials(withCredentials);
|
|
100
|
+
return this.withConfig({ withCredentials });
|
|
101
|
+
}
|
|
102
|
+
bearer(token) {
|
|
103
|
+
assertNonBlankString.assertNonBlankString(token, 'Bearer token must be a non-empty string', requestBuilderErrorCodes.REQUEST_BUILDER_ERROR_CODES.INVALID_BEARER_TOKEN);
|
|
104
|
+
if (headerValueLineBreakPattern.HEADER_VALUE_LINE_BREAK_PATTERN.test(token)) {
|
|
105
|
+
throw new RequestBuilderError.RequestBuilderError('Bearer token must not contain line breaks', requestBuilderErrorCodes.REQUEST_BUILDER_ERROR_CODES.INVALID_BEARER_TOKEN);
|
|
106
|
+
}
|
|
107
|
+
return this.header('Authorization', `Bearer ${token}`);
|
|
108
|
+
}
|
|
109
|
+
asJson() {
|
|
110
|
+
return this.withConfig({ responseType: httpResponseTypes.HTTP_RESPONSE_TYPES.JSON });
|
|
111
|
+
}
|
|
112
|
+
asText() {
|
|
113
|
+
return this.withConfig({ responseType: httpResponseTypes.HTTP_RESPONSE_TYPES.TEXT });
|
|
114
|
+
}
|
|
115
|
+
asBlob() {
|
|
116
|
+
return this.withConfig({ responseType: httpResponseTypes.HTTP_RESPONSE_TYPES.BLOB });
|
|
117
|
+
}
|
|
118
|
+
asArrayBuffer() {
|
|
119
|
+
return this.withConfig({ responseType: httpResponseTypes.HTTP_RESPONSE_TYPES.ARRAY_BUFFER });
|
|
120
|
+
}
|
|
121
|
+
asStream() {
|
|
122
|
+
return this.withConfig({ responseType: httpResponseTypes.HTTP_RESPONSE_TYPES.STREAM });
|
|
123
|
+
}
|
|
124
|
+
execute() {
|
|
125
|
+
return this.executor(this.build());
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
exports.HttpRequestBuilder = HttpRequestBuilder;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var HttpClientError = require('./HttpClientError.cjs');
|
|
4
|
+
|
|
5
|
+
class AbortError extends HttpClientError.HttpClientError {
|
|
6
|
+
}
|
|
7
|
+
function isAbortError(error) {
|
|
8
|
+
return error instanceof AbortError;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
exports.AbortError = AbortError;
|
|
12
|
+
exports.isAbortError = isAbortError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Base class for all HTTP client errors. Supports catching any client error with a single instanceof check. */
|
|
4
|
+
class HttpClientError extends Error {
|
|
5
|
+
config;
|
|
6
|
+
constructor(message, options) {
|
|
7
|
+
super(message, options);
|
|
8
|
+
this.name = this.constructor.name;
|
|
9
|
+
this.config = options?.config;
|
|
10
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isHttpClientError(error) {
|
|
14
|
+
return error instanceof HttpClientError;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.HttpClientError = HttpClientError;
|
|
18
|
+
exports.isHttpClientError = isHttpClientError;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var HttpClientError = require('./HttpClientError.cjs');
|
|
4
|
+
|
|
5
|
+
/** Indicates that the server completed the request with a non-2xx status. */
|
|
6
|
+
class HttpResponseError extends HttpClientError.HttpClientError {
|
|
7
|
+
status;
|
|
8
|
+
statusText;
|
|
9
|
+
headers;
|
|
10
|
+
config;
|
|
11
|
+
data;
|
|
12
|
+
constructor(message, status, statusText, headers, config, data, options) {
|
|
13
|
+
super(message, { ...options, config });
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.statusText = statusText;
|
|
16
|
+
this.headers = headers;
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.data = data;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function isHttpResponseError(error) {
|
|
22
|
+
return error instanceof HttpResponseError;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
exports.HttpResponseError = HttpResponseError;
|
|
26
|
+
exports.isHttpResponseError = isHttpResponseError;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var HttpClientError = require('./HttpClientError.cjs');
|
|
4
|
+
|
|
5
|
+
class NetworkError extends HttpClientError.HttpClientError {
|
|
6
|
+
}
|
|
7
|
+
function isNetworkError(error) {
|
|
8
|
+
return error instanceof NetworkError;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
exports.NetworkError = NetworkError;
|
|
12
|
+
exports.isNetworkError = isNetworkError;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var HttpClientError = require('./HttpClientError.cjs');
|
|
4
|
+
|
|
5
|
+
/** Indicates that a successful response could not be parsed in the requested format. */
|
|
6
|
+
class ParseError extends HttpClientError.HttpClientError {
|
|
7
|
+
responseType;
|
|
8
|
+
raw;
|
|
9
|
+
constructor(message, options) {
|
|
10
|
+
super(message, options);
|
|
11
|
+
this.responseType = options?.responseType;
|
|
12
|
+
this.raw = options?.raw;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function isParseError(error) {
|
|
16
|
+
return error instanceof ParseError;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.ParseError = ParseError;
|
|
20
|
+
exports.isParseError = isParseError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var requestBuilderErrorCodes = require('../constants/requestBuilderErrorCodes.cjs');
|
|
4
|
+
var HttpClientError = require('./HttpClientError.cjs');
|
|
5
|
+
|
|
6
|
+
class RequestBuilderError extends HttpClientError.HttpClientError {
|
|
7
|
+
code;
|
|
8
|
+
constructor(message, code = requestBuilderErrorCodes.REQUEST_BUILDER_ERROR_CODES.INVALID_CONFIG) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = code;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isRequestBuilderError(error) {
|
|
14
|
+
return error instanceof RequestBuilderError;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.RequestBuilderError = RequestBuilderError;
|
|
18
|
+
exports.isRequestBuilderError = isRequestBuilderError;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var HttpClientError = require('./HttpClientError.cjs');
|
|
4
|
+
|
|
5
|
+
/** Indicates that an adapter could not prepare a request before sending it. */
|
|
6
|
+
class RequestPreparationError extends HttpClientError.HttpClientError {
|
|
7
|
+
}
|
|
8
|
+
function isRequestPreparationError(error) {
|
|
9
|
+
return error instanceof RequestPreparationError;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
exports.RequestPreparationError = RequestPreparationError;
|
|
13
|
+
exports.isRequestPreparationError = isRequestPreparationError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var HttpClientError = require('./HttpClientError.cjs');
|
|
4
|
+
|
|
5
|
+
/** Indicates that the request exceeded the configured timeout. */
|
|
6
|
+
class TimeoutError extends HttpClientError.HttpClientError {
|
|
7
|
+
timeout;
|
|
8
|
+
constructor(message, options) {
|
|
9
|
+
super(message, options);
|
|
10
|
+
this.timeout = options?.timeout;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isTimeoutError(error) {
|
|
14
|
+
return error instanceof TimeoutError;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
exports.TimeoutError = TimeoutError;
|
|
18
|
+
exports.isTimeoutError = isTimeoutError;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var HttpClient = require('./core/HttpClient.cjs');
|
|
4
|
+
var HttpRequestBuilder = require('./core/HttpRequestBuilder.cjs');
|
|
5
|
+
var FetchAdapter = require('./adapters/FetchAdapter.cjs');
|
|
6
|
+
var XhrAdapter = require('./adapters/XhrAdapter.cjs');
|
|
7
|
+
var httpMethods = require('./constants/httpMethods.cjs');
|
|
8
|
+
var httpStatusCodes = require('./constants/httpStatusCodes.cjs');
|
|
9
|
+
var httpResponseTypes = require('./constants/httpResponseTypes.cjs');
|
|
10
|
+
var requestBuilderErrorCodes = require('./constants/requestBuilderErrorCodes.cjs');
|
|
11
|
+
var AbortError = require('./errors/AbortError.cjs');
|
|
12
|
+
var HttpClientError = require('./errors/HttpClientError.cjs');
|
|
13
|
+
var HttpResponseError = require('./errors/HttpResponseError.cjs');
|
|
14
|
+
var NetworkError = require('./errors/NetworkError.cjs');
|
|
15
|
+
var ParseError = require('./errors/ParseError.cjs');
|
|
16
|
+
var RequestBuilderError = require('./errors/RequestBuilderError.cjs');
|
|
17
|
+
var RequestPreparationError = require('./errors/RequestPreparationError.cjs');
|
|
18
|
+
var TimeoutError = require('./errors/TimeoutError.cjs');
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
exports.HttpClient = HttpClient.HttpClient;
|
|
23
|
+
exports.HttpRequestBuilder = HttpRequestBuilder.HttpRequestBuilder;
|
|
24
|
+
exports.FetchAdapter = FetchAdapter.FetchAdapter;
|
|
25
|
+
exports.XhrAdapter = XhrAdapter.XhrAdapter;
|
|
26
|
+
exports.HTTP_METHODS = httpMethods.HTTP_METHODS;
|
|
27
|
+
exports.HTTP_STATUS_CODES = httpStatusCodes.HTTP_STATUS_CODES;
|
|
28
|
+
exports.HTTP_RESPONSE_TYPES = httpResponseTypes.HTTP_RESPONSE_TYPES;
|
|
29
|
+
exports.REQUEST_BUILDER_ERROR_CODES = requestBuilderErrorCodes.REQUEST_BUILDER_ERROR_CODES;
|
|
30
|
+
exports.AbortError = AbortError.AbortError;
|
|
31
|
+
exports.isAbortError = AbortError.isAbortError;
|
|
32
|
+
exports.HttpClientError = HttpClientError.HttpClientError;
|
|
33
|
+
exports.isHttpClientError = HttpClientError.isHttpClientError;
|
|
34
|
+
exports.HttpResponseError = HttpResponseError.HttpResponseError;
|
|
35
|
+
exports.isHttpResponseError = HttpResponseError.isHttpResponseError;
|
|
36
|
+
exports.NetworkError = NetworkError.NetworkError;
|
|
37
|
+
exports.isNetworkError = NetworkError.isNetworkError;
|
|
38
|
+
exports.ParseError = ParseError.ParseError;
|
|
39
|
+
exports.isParseError = ParseError.isParseError;
|
|
40
|
+
exports.RequestBuilderError = RequestBuilderError.RequestBuilderError;
|
|
41
|
+
exports.isRequestBuilderError = RequestBuilderError.isRequestBuilderError;
|
|
42
|
+
exports.RequestPreparationError = RequestPreparationError.RequestPreparationError;
|
|
43
|
+
exports.isRequestPreparationError = RequestPreparationError.isRequestPreparationError;
|
|
44
|
+
exports.TimeoutError = TimeoutError.TimeoutError;
|
|
45
|
+
exports.isTimeoutError = TimeoutError.isTimeoutError;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function splitUrl(value) {
|
|
4
|
+
const hashIndex = value.indexOf('#');
|
|
5
|
+
const beforeHash = hashIndex === -1 ? value : value.slice(0, hashIndex);
|
|
6
|
+
const hash = hashIndex === -1 ? '' : value.slice(hashIndex);
|
|
7
|
+
const queryIndex = beforeHash.indexOf('?');
|
|
8
|
+
return {
|
|
9
|
+
path: queryIndex === -1 ? beforeHash : beforeHash.slice(0, queryIndex),
|
|
10
|
+
query: queryIndex === -1 ? '' : beforeHash.slice(queryIndex + 1),
|
|
11
|
+
hash
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function joinPaths(basePath, path) {
|
|
15
|
+
if (!path) {
|
|
16
|
+
return basePath;
|
|
17
|
+
}
|
|
18
|
+
if (!basePath) {
|
|
19
|
+
return path;
|
|
20
|
+
}
|
|
21
|
+
return `${basePath.replace(/\/+$/, '')}/${path.replace(/^\/+/, '')}`;
|
|
22
|
+
}
|
|
23
|
+
function getAbsoluteUrl(value) {
|
|
24
|
+
try {
|
|
25
|
+
return new URL(value);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function serializeParams(params) {
|
|
32
|
+
if (params === undefined) {
|
|
33
|
+
return '';
|
|
34
|
+
}
|
|
35
|
+
const searchParams = new URLSearchParams();
|
|
36
|
+
for (const [key, value] of Object.entries(params)) {
|
|
37
|
+
if (value === null || value === undefined) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const values = Array.isArray(value) ? value : [value];
|
|
41
|
+
for (const item of values) {
|
|
42
|
+
if (item === null || item === undefined) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
searchParams.append(key, String(item));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return searchParams.toString();
|
|
49
|
+
}
|
|
50
|
+
function appendParams(url, params) {
|
|
51
|
+
const query = serializeParams(params);
|
|
52
|
+
if (!query) {
|
|
53
|
+
return url;
|
|
54
|
+
}
|
|
55
|
+
const { path, query: existingQuery, hash } = splitUrl(url);
|
|
56
|
+
const combinedQuery = [existingQuery, query].filter(Boolean).join('&');
|
|
57
|
+
return `${path}?${combinedQuery}${hash}`;
|
|
58
|
+
}
|
|
59
|
+
function resolveRelativeUrl(baseUrl, url) {
|
|
60
|
+
const base = splitUrl(baseUrl);
|
|
61
|
+
const request = splitUrl(url);
|
|
62
|
+
const query = [base.query, request.query].filter(Boolean).join('&');
|
|
63
|
+
return `${joinPaths(base.path, request.path)}${query ? `?${query}` : ''}${request.hash}`;
|
|
64
|
+
}
|
|
65
|
+
function resolveAbsoluteUrl(base, url) {
|
|
66
|
+
const request = splitUrl(url);
|
|
67
|
+
base.pathname = joinPaths(base.pathname, request.path);
|
|
68
|
+
base.hash = request.hash;
|
|
69
|
+
if (request.query) {
|
|
70
|
+
const requestParams = new URLSearchParams(request.query);
|
|
71
|
+
requestParams.forEach((value, key) => {
|
|
72
|
+
base.searchParams.append(key, value);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return base.toString();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Resolves a request URL against an optional base URL, preserves existing query values and fragments,
|
|
79
|
+
* and appends serialized params before the fragment.
|
|
80
|
+
*/
|
|
81
|
+
function buildUrl(baseUrl, url, params) {
|
|
82
|
+
const absoluteUrl = getAbsoluteUrl(url);
|
|
83
|
+
if (absoluteUrl !== undefined) {
|
|
84
|
+
return appendParams(absoluteUrl.toString(), params);
|
|
85
|
+
}
|
|
86
|
+
if (baseUrl === undefined) {
|
|
87
|
+
return appendParams(url, params);
|
|
88
|
+
}
|
|
89
|
+
const absoluteBaseUrl = getAbsoluteUrl(baseUrl);
|
|
90
|
+
const fullUrl = absoluteBaseUrl === undefined ? resolveRelativeUrl(baseUrl, url) : resolveAbsoluteUrl(absoluteBaseUrl, url);
|
|
91
|
+
return appendParams(fullUrl, params);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
exports.buildUrl = buildUrl;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Returns a non-empty Error message or the provided fallback for unknown error values. */
|
|
4
|
+
function getErrorMessage(error, fallback) {
|
|
5
|
+
return error instanceof Error && error.message ? error.message : fallback;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
exports.getErrorMessage = getErrorMessage;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Applies a custom status predicate or accepts the standard successful HTTP status range. */
|
|
4
|
+
function isStatusAccepted(status, validateStatus) {
|
|
5
|
+
return validateStatus === undefined ? status >= 200 && status < 300 : validateStatus(status);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
exports.isStatusAccepted = isStatusAccepted;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/** Merges header maps from left to right using case-insensitive names while preserving the latest name casing. */
|
|
4
|
+
function mergeHeaders(...sources) {
|
|
5
|
+
const result = {};
|
|
6
|
+
const normalizedKeys = new Map();
|
|
7
|
+
for (const source of sources) {
|
|
8
|
+
if (source === undefined) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
for (const [key, value] of Object.entries(source)) {
|
|
12
|
+
const normalizedKey = key.toLowerCase();
|
|
13
|
+
const previousKey = normalizedKeys.get(normalizedKey);
|
|
14
|
+
if (previousKey !== undefined) {
|
|
15
|
+
delete result[previousKey];
|
|
16
|
+
}
|
|
17
|
+
result[key] = value;
|
|
18
|
+
normalizedKeys.set(normalizedKey, key);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
/** Checks whether a header map contains a name using case-insensitive comparison. */
|
|
24
|
+
function hasHeader(headers, name) {
|
|
25
|
+
const normalizedName = name.toLowerCase();
|
|
26
|
+
return Object.keys(headers).some(key => key.toLowerCase() === normalizedName);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.hasHeader = hasHeader;
|
|
30
|
+
exports.mergeHeaders = mergeHeaders;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function isPresentParamPrimitive(value) {
|
|
4
|
+
return value !== null && value !== undefined;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Merges query params from left to right. `null` / `undefined` remove a key; nullish array items are dropped.
|
|
8
|
+
* Returns undefined when no params remain.
|
|
9
|
+
*/
|
|
10
|
+
function mergeParams(...sources) {
|
|
11
|
+
const result = {};
|
|
12
|
+
for (const source of sources) {
|
|
13
|
+
if (source === undefined) {
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
for (const [key, value] of Object.entries(source)) {
|
|
17
|
+
if (value === null || value === undefined) {
|
|
18
|
+
delete result[key];
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (Array.isArray(value)) {
|
|
22
|
+
const items = value.filter(isPresentParamPrimitive);
|
|
23
|
+
if (items.length === 0) {
|
|
24
|
+
delete result[key];
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
result[key] = [...items];
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
result[key] = value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return Object.keys(result).length === 0 ? undefined : result;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
exports.mergeParams = mergeParams;
|