api-def 0.12.1 → 0.13.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 +3 -0
- package/bin/index.js +312 -313
- package/cjs/Api.d.ts +1 -1
- package/cjs/Api.js +99 -145
- package/cjs/ApiTypes.d.ts +1 -1
- package/cjs/ApiUtils.js +30 -32
- package/cjs/Endpoint.d.ts +1 -1
- package/cjs/Endpoint.js +112 -175
- package/cjs/EndpointBuilder.js +23 -32
- package/cjs/QueryHandling.js +12 -13
- package/cjs/RequestConfig.js +54 -36
- package/cjs/RequestContext.d.ts +1 -1
- package/cjs/RequestContext.js +125 -180
- package/cjs/RequestError.js +16 -19
- package/cjs/Requester.js +230 -312
- package/cjs/TextDecoding.js +31 -31
- package/cjs/Utils.js +20 -23
- package/cjs/backend/AxiosRequestBackend.d.ts +1 -1
- package/cjs/backend/AxiosRequestBackend.js +65 -172
- package/cjs/backend/FetchRequestBackend.d.ts +1 -1
- package/cjs/backend/FetchRequestBackend.js +108 -154
- package/cjs/backend/MockRequestBackend.d.ts +1 -1
- package/cjs/backend/MockRequestBackend.js +146 -208
- package/cjs/cache/ClientCaching.js +26 -74
- package/cjs/cache/LocalForageClientCacheBackend.js +15 -83
- package/cjs/cache/LocalStorageClientCacheBackend.js +14 -73
- package/cjs/index.d.ts +11 -11
- package/cjs/index.js +24 -21
- package/cjs/middleware/ClientCacheMiddleware.js +80 -103
- package/cjs/middleware/LoggingMiddleware.js +71 -42
- package/cjs/util/retry/index.js +42 -9
- package/cjs/util/retry/lib/retry.js +25 -27
- package/cjs/util/retry/lib/retryOperation.d.ts +1 -26
- package/cjs/util/retry/lib/retryOperation.js +21 -23
- package/esm/Api.d.ts +6 -6
- package/esm/Api.js +12 -25
- package/esm/ApiConstants.d.ts +1 -1
- package/esm/ApiTypes.d.ts +5 -5
- package/esm/ApiUtils.d.ts +2 -2
- package/esm/ApiUtils.js +4 -5
- package/esm/Endpoint.d.ts +6 -6
- package/esm/Endpoint.js +22 -28
- package/esm/EndpointBuilder.d.ts +4 -4
- package/esm/EndpointBuilder.js +2 -2
- package/esm/MockingTypes.d.ts +1 -1
- package/esm/QueryHandling.d.ts +1 -1
- package/esm/QueryHandling.js +2 -3
- package/esm/RequestConfig.d.ts +1 -1
- package/esm/RequestConfig.js +6 -7
- package/esm/RequestContext.d.ts +7 -7
- package/esm/RequestContext.js +15 -27
- package/esm/RequestError.d.ts +3 -3
- package/esm/RequestError.js +2 -3
- package/esm/Requester.d.ts +2 -2
- package/esm/Requester.js +44 -50
- package/esm/UtilTypes.d.ts +1 -1
- package/esm/Utils.js +2 -1
- package/esm/Validation.d.ts +1 -1
- package/esm/backend/AxiosRequestBackend.d.ts +4 -4
- package/esm/backend/AxiosRequestBackend.js +47 -84
- package/esm/backend/FetchRequestBackend.d.ts +5 -5
- package/esm/backend/FetchRequestBackend.js +49 -63
- package/esm/backend/MockRequestBackend.d.ts +4 -4
- package/esm/backend/MockRequestBackend.js +105 -136
- package/esm/backend/RequestBackend.d.ts +2 -2
- package/esm/cache/ClientCaching.d.ts +1 -1
- package/esm/cache/ClientCaching.js +8 -17
- package/esm/cache/LocalForageClientCacheBackend.d.ts +1 -1
- package/esm/cache/LocalForageClientCacheBackend.js +8 -25
- package/esm/cache/LocalStorageClientCacheBackend.d.ts +1 -1
- package/esm/cache/LocalStorageClientCacheBackend.js +9 -26
- package/esm/index.d.ts +16 -16
- package/esm/index.js +15 -15
- package/esm/middleware/ClientCacheMiddleware.d.ts +1 -1
- package/esm/middleware/ClientCacheMiddleware.js +8 -17
- package/esm/middleware/LoggingMiddleware.d.ts +1 -1
- package/esm/middleware/LoggingMiddleware.js +5 -6
- package/esm/util/retry/index.js +1 -1
- package/esm/util/retry/lib/retry.d.ts +1 -1
- package/esm/util/retry/lib/retry.js +13 -7
- package/esm/util/retry/lib/retryOperation.d.ts +1 -26
- package/esm/util/retry/lib/retryOperation.js +1 -1
- package/package.json +66 -28
package/esm/RequestContext.js
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { resolvePathParams, resolveUrl } from "./ApiUtils";
|
|
11
|
-
import * as Utils from "./Utils";
|
|
1
|
+
import { resolvePathParams, resolveUrl } from "./ApiUtils.js";
|
|
2
|
+
import * as Utils from "./Utils.js";
|
|
12
3
|
let contextIdCounter = 0;
|
|
13
4
|
export default class RequestContext {
|
|
14
5
|
constructor(backend, host, config, rawPath, mocking) {
|
|
@@ -100,15 +91,14 @@ export default class RequestContext {
|
|
|
100
91
|
return this;
|
|
101
92
|
}
|
|
102
93
|
parseRequestBody() {
|
|
103
|
-
var _a;
|
|
104
94
|
if (this.requestConfig.body && this.requestConfig.headers) {
|
|
105
95
|
const contentTypeKey = Object.keys(this.requestConfig.headers).find((key) => key.toLowerCase() === "content-type");
|
|
106
|
-
const contentType = contentTypeKey &&
|
|
96
|
+
const contentType = contentTypeKey && this.requestConfig.headers[contentTypeKey]?.toString().split(";")[0].trim();
|
|
107
97
|
if (contentType === "application/x-www-form-urlencoded") {
|
|
108
98
|
const searchParams = new URLSearchParams();
|
|
109
99
|
for (const key of Object.keys(this.requestConfig.body)) {
|
|
110
100
|
const value = this.requestConfig.body[key];
|
|
111
|
-
searchParams.append(key, value
|
|
101
|
+
searchParams.append(key, value?.toString());
|
|
112
102
|
}
|
|
113
103
|
this.parsedBody = searchParams;
|
|
114
104
|
}
|
|
@@ -128,20 +118,18 @@ export default class RequestContext {
|
|
|
128
118
|
this.computedRequestUrl = this.resolveRequestUrl();
|
|
129
119
|
return this;
|
|
130
120
|
}
|
|
131
|
-
triggerEvent(eventType) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return eventResult;
|
|
140
|
-
}
|
|
121
|
+
async triggerEvent(eventType) {
|
|
122
|
+
const eventHandlers = this.eventHandlers[eventType];
|
|
123
|
+
if (eventHandlers) {
|
|
124
|
+
for (let i = 0; i < eventHandlers.length; i++) {
|
|
125
|
+
const eventHandler = eventHandlers[i];
|
|
126
|
+
const eventResult = await eventHandler(this);
|
|
127
|
+
if (eventResult) {
|
|
128
|
+
return eventResult;
|
|
141
129
|
}
|
|
142
130
|
}
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
}
|
|
132
|
+
return undefined;
|
|
145
133
|
}
|
|
146
134
|
addCanceller(canceler) {
|
|
147
135
|
this.canceler = canceler;
|
|
@@ -170,7 +158,7 @@ export default class RequestContext {
|
|
|
170
158
|
this.computedMethod = method;
|
|
171
159
|
}
|
|
172
160
|
updateBody(body) {
|
|
173
|
-
// @ts-
|
|
161
|
+
// @ts-expect-error
|
|
174
162
|
this.requestConfig.body = body;
|
|
175
163
|
this.parseRequestBody();
|
|
176
164
|
}
|
package/esm/RequestError.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ApiResponse } from "./ApiTypes";
|
|
2
|
-
import type RequestContext from "./RequestContext";
|
|
3
|
-
import type { EnumOf } from "./Utils";
|
|
1
|
+
import type { ApiResponse } from "./ApiTypes.js";
|
|
2
|
+
import type RequestContext from "./RequestContext.js";
|
|
3
|
+
import type { EnumOf } from "./Utils.js";
|
|
4
4
|
export declare const RequestErrorCode: {
|
|
5
5
|
readonly MISC_UNKNOWN_ERROR: "misc/unknown-error";
|
|
6
6
|
readonly REQUEST_NETWORK_ERROR: "request/network-error";
|
package/esm/RequestError.js
CHANGED
|
@@ -46,7 +46,7 @@ export const convertToRequestError = (config) => {
|
|
|
46
46
|
});
|
|
47
47
|
try {
|
|
48
48
|
Object.defineProperty(resultError, "message", {
|
|
49
|
-
value: `A ${context.method.toUpperCase()} request to '${context.requestUrl.href}' failed${
|
|
49
|
+
value: `A ${context.method.toUpperCase()} request to '${context.requestUrl.href}' failed${response?.status ? ` with status code ${response.status}` : ""} [${code}]: ${resultError.message}`,
|
|
50
50
|
});
|
|
51
51
|
}
|
|
52
52
|
catch (e) {
|
|
@@ -57,9 +57,8 @@ export const convertToRequestError = (config) => {
|
|
|
57
57
|
return resultError;
|
|
58
58
|
};
|
|
59
59
|
export const getErrorResponse = (error) => {
|
|
60
|
-
var _a;
|
|
61
60
|
if (isRequestError(error)) {
|
|
62
|
-
return
|
|
61
|
+
return error.response ?? undefined;
|
|
63
62
|
}
|
|
64
63
|
return undefined;
|
|
65
64
|
};
|
package/esm/Requester.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { ApiResponse, Body, Params, Query, RequestConfig, RequestHost, State } from "./ApiTypes";
|
|
2
|
-
import type { EndpointMockingConfig } from "./MockingTypes";
|
|
1
|
+
import type { ApiResponse, Body, Params, Query, RequestConfig, RequestHost, State } from "./ApiTypes.js";
|
|
2
|
+
import type { EndpointMockingConfig } from "./MockingTypes.js";
|
|
3
3
|
export declare const submit: <TResponse, TParams extends Params | undefined, TQuery extends Query | undefined, TBody extends Body | undefined, TState extends State>(host: RequestHost, config: RequestConfig<TParams, TQuery, TBody, TState>, mocking: EndpointMockingConfig<TResponse, TParams, TQuery, TBody, TState> | null | undefined) => Promise<ApiResponse<TResponse>>;
|
package/esm/Requester.js
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { EventResultType, RequestEvent } from "./ApiConstants";
|
|
11
|
-
import { inferResponseType, isAcceptableStatus, isNetworkError } from "./ApiUtils";
|
|
12
|
-
import RequestContext from "./RequestContext";
|
|
13
|
-
import { RequestErrorCode, convertToRequestError, isRequestError } from "./RequestError";
|
|
14
|
-
import { textDecode } from "./TextDecoding";
|
|
15
|
-
import MockRequestBackend from "./backend/MockRequestBackend";
|
|
16
|
-
import retry from "./util/retry";
|
|
1
|
+
import { EventResultType, RequestEvent } from "./ApiConstants.js";
|
|
2
|
+
import { inferResponseType, isAcceptableStatus, isNetworkError } from "./ApiUtils.js";
|
|
3
|
+
import MockRequestBackend from "./backend/MockRequestBackend.js";
|
|
4
|
+
import RequestContext from "./RequestContext.js";
|
|
5
|
+
import { convertToRequestError, isRequestError, RequestErrorCode } from "./RequestError.js";
|
|
6
|
+
import { textDecode } from "./TextDecoding.js";
|
|
7
|
+
import retry from "./util/retry/index.js";
|
|
17
8
|
const locks = {};
|
|
18
9
|
const runningOperations = {};
|
|
19
10
|
const MOCK_REQUEST_BACKEND = new MockRequestBackend();
|
|
20
|
-
export const submit = (host, config, mocking) =>
|
|
11
|
+
export const submit = async (host, config, mocking) => {
|
|
21
12
|
const computedConfig = host.computeConfig(config);
|
|
22
13
|
const backend = mocking ? MOCK_REQUEST_BACKEND : host.getRequestBackend();
|
|
23
14
|
const context = new RequestContext(backend, host, computedConfig, host.path, mocking);
|
|
@@ -39,8 +30,8 @@ export const submit = (host, config, mocking) => __awaiter(void 0, void 0, void
|
|
|
39
30
|
locks[lock] = context;
|
|
40
31
|
}
|
|
41
32
|
try {
|
|
42
|
-
let response =
|
|
43
|
-
const successEventResult =
|
|
33
|
+
let response = await (runningOperations[key] = makeRequest(context));
|
|
34
|
+
const successEventResult = await context.triggerEvent(RequestEvent.SUCCESS);
|
|
44
35
|
if (successEventResult && successEventResult.type === EventResultType.RESPOND) {
|
|
45
36
|
context.response = response = successEventResult.response;
|
|
46
37
|
}
|
|
@@ -56,7 +47,7 @@ export const submit = (host, config, mocking) => __awaiter(void 0, void 0, void
|
|
|
56
47
|
delete locks[lock];
|
|
57
48
|
}
|
|
58
49
|
}
|
|
59
|
-
}
|
|
50
|
+
};
|
|
60
51
|
const parseRetryOptions = (retryConfig) => {
|
|
61
52
|
if (retryConfig && typeof retryConfig === "object") {
|
|
62
53
|
return retryConfig;
|
|
@@ -66,9 +57,8 @@ const parseRetryOptions = (retryConfig) => {
|
|
|
66
57
|
}
|
|
67
58
|
return { maxAttempts: 0 };
|
|
68
59
|
};
|
|
69
|
-
const makeRequest = (context) =>
|
|
70
|
-
|
|
71
|
-
const beforeSendEventResult = yield context.triggerEvent(RequestEvent.BEFORE_SEND);
|
|
60
|
+
const makeRequest = async (context) => {
|
|
61
|
+
const beforeSendEventResult = await context.triggerEvent(RequestEvent.BEFORE_SEND);
|
|
72
62
|
if (beforeSendEventResult && beforeSendEventResult.type === EventResultType.RESPOND) {
|
|
73
63
|
return (context.response = beforeSendEventResult.response);
|
|
74
64
|
}
|
|
@@ -98,22 +88,22 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
98
88
|
});
|
|
99
89
|
}
|
|
100
90
|
}
|
|
101
|
-
const retryOptions = parseRetryOptions(
|
|
91
|
+
const retryOptions = parseRetryOptions(context.requestConfig?.retry);
|
|
102
92
|
const internalRetryOptions = {
|
|
103
93
|
retries: retryOptions.maxAttempts,
|
|
104
94
|
// assume most users won't want to tune the delay between retries
|
|
105
|
-
minTimeout:
|
|
106
|
-
maxTimeout:
|
|
95
|
+
minTimeout: retryOptions.minDelay ?? 200,
|
|
96
|
+
maxTimeout: retryOptions.maxDelay ?? 1000,
|
|
107
97
|
randomize: true,
|
|
108
98
|
};
|
|
109
99
|
context.stats.attempt = 0;
|
|
110
|
-
const performRequest = (fnBail, attemptCount) =>
|
|
100
|
+
const performRequest = async (fnBail, attemptCount) => {
|
|
111
101
|
context.stats.attempt++;
|
|
112
102
|
try {
|
|
113
103
|
const { promise, canceler } = context.backend.makeRequest(context);
|
|
114
104
|
context.addCanceller(canceler);
|
|
115
|
-
const response =
|
|
116
|
-
const parsedResponse = (
|
|
105
|
+
const response = await promise;
|
|
106
|
+
const parsedResponse = (await parseResponse(context, response));
|
|
117
107
|
if (!isAcceptableStatus(parsedResponse.status, context.requestConfig.acceptableStatus)) {
|
|
118
108
|
throw convertToRequestError({
|
|
119
109
|
error: new Error(`[api-def] Invalid response status code '${parsedResponse.status}'`),
|
|
@@ -130,12 +120,12 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
130
120
|
if (context.cancelled) {
|
|
131
121
|
rawError.isCancelledRequest = true;
|
|
132
122
|
}
|
|
133
|
-
const error =
|
|
123
|
+
const error = await parseError(context, rawError);
|
|
134
124
|
context.error = error;
|
|
135
125
|
context.response = error.response;
|
|
136
126
|
context.stats.endTimestamp = Date.now();
|
|
137
|
-
const errorEventResult =
|
|
138
|
-
if (
|
|
127
|
+
const errorEventResult = await context.triggerEvent(RequestEvent.ERROR);
|
|
128
|
+
if (errorEventResult?.type === EventResultType.RESPOND) {
|
|
139
129
|
return errorEventResult.response;
|
|
140
130
|
}
|
|
141
131
|
// allow retry logic to handle network errors
|
|
@@ -144,7 +134,7 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
144
134
|
// throw error;
|
|
145
135
|
//}
|
|
146
136
|
// if we have an event that tells us to retry, we must do it
|
|
147
|
-
const forceRetry =
|
|
137
|
+
const forceRetry = errorEventResult?.type === EventResultType.RETRY;
|
|
148
138
|
if (forceRetry) {
|
|
149
139
|
return performRequest(fnBail, attemptCount);
|
|
150
140
|
}
|
|
@@ -153,7 +143,7 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
153
143
|
throw error;
|
|
154
144
|
}
|
|
155
145
|
// error is unrecoverable, bail
|
|
156
|
-
const unrecoverableErrorEventResult =
|
|
146
|
+
const unrecoverableErrorEventResult = await context.triggerEvent(RequestEvent.UNRECOVERABLE_ERROR);
|
|
157
147
|
if (unrecoverableErrorEventResult) {
|
|
158
148
|
if (unrecoverableErrorEventResult.type === EventResultType.RESPOND) {
|
|
159
149
|
return unrecoverableErrorEventResult.response;
|
|
@@ -161,8 +151,8 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
161
151
|
}
|
|
162
152
|
fnBail(error);
|
|
163
153
|
}
|
|
164
|
-
}
|
|
165
|
-
const response =
|
|
154
|
+
};
|
|
155
|
+
const response = await retry(performRequest, internalRetryOptions);
|
|
166
156
|
if (context.validation.response) {
|
|
167
157
|
try {
|
|
168
158
|
response.data = context.validation.response.parse(response.data);
|
|
@@ -176,11 +166,10 @@ const makeRequest = (context) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
176
166
|
}
|
|
177
167
|
}
|
|
178
168
|
return response;
|
|
179
|
-
}
|
|
180
|
-
const parseResponse = (context, response, error) =>
|
|
181
|
-
var _a;
|
|
169
|
+
};
|
|
170
|
+
const parseResponse = async (context, response, error) => {
|
|
182
171
|
if (response) {
|
|
183
|
-
const parsedResponse =
|
|
172
|
+
const parsedResponse = await context.backend.convertResponse(context, response);
|
|
184
173
|
const contentType = parsedResponse.headers.get("content-type");
|
|
185
174
|
const inferredResponseType = inferResponseType(contentType);
|
|
186
175
|
if (!error) {
|
|
@@ -197,7 +186,7 @@ const parseResponse = (context, response, error) => __awaiter(void 0, void 0, vo
|
|
|
197
186
|
if (inferredResponseType === "arraybuffer" && context.responseType === "json") {
|
|
198
187
|
if (parsedResponse.data && typeof parsedResponse.data === "object") {
|
|
199
188
|
const data = response.data;
|
|
200
|
-
if (
|
|
189
|
+
if (data.constructor?.name === "ArrayBuffer") {
|
|
201
190
|
try {
|
|
202
191
|
const decodedData = (response.data = textDecode(data));
|
|
203
192
|
response.data = JSON.parse(decodedData);
|
|
@@ -217,18 +206,17 @@ const parseResponse = (context, response, error) => __awaiter(void 0, void 0, vo
|
|
|
217
206
|
return parsedResponse;
|
|
218
207
|
}
|
|
219
208
|
return response;
|
|
220
|
-
}
|
|
221
|
-
const parseError = (context, rawError) =>
|
|
222
|
-
var _a;
|
|
209
|
+
};
|
|
210
|
+
const parseError = async (context, rawError) => {
|
|
223
211
|
let error;
|
|
224
212
|
if (isRequestError(rawError)) {
|
|
225
213
|
error = rawError;
|
|
226
214
|
}
|
|
227
215
|
else {
|
|
228
|
-
const extractedResponse =
|
|
229
|
-
let errorResponse
|
|
216
|
+
const extractedResponse = await context.backend.extractResponseFromError(rawError);
|
|
217
|
+
let errorResponse;
|
|
230
218
|
if (extractedResponse !== undefined) {
|
|
231
|
-
errorResponse =
|
|
219
|
+
errorResponse = await parseResponse(context, extractedResponse, true);
|
|
232
220
|
}
|
|
233
221
|
let code = isNetworkError(rawError)
|
|
234
222
|
? RequestErrorCode.REQUEST_NETWORK_ERROR
|
|
@@ -239,12 +227,18 @@ const parseError = (context, rawError) => __awaiter(void 0, void 0, void 0, func
|
|
|
239
227
|
}
|
|
240
228
|
}
|
|
241
229
|
else {
|
|
242
|
-
if (rawError.code === "ENOTFOUND" ||
|
|
230
|
+
if (rawError.code === "ENOTFOUND" || rawError.cause?.code === "ENOTFOUND") {
|
|
243
231
|
code = RequestErrorCode.REQUEST_HOST_NAME_NOT_FOUND;
|
|
244
232
|
}
|
|
245
233
|
}
|
|
246
234
|
const errorInfo = context.backend.getErrorInfo(rawError, errorResponse);
|
|
247
|
-
error = convertToRequestError(
|
|
235
|
+
error = convertToRequestError({
|
|
236
|
+
error: rawError,
|
|
237
|
+
response: errorResponse,
|
|
238
|
+
code: code,
|
|
239
|
+
context: context,
|
|
240
|
+
...errorInfo,
|
|
241
|
+
});
|
|
248
242
|
}
|
|
249
243
|
return error;
|
|
250
|
-
}
|
|
244
|
+
};
|
package/esm/UtilTypes.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type Endpoint from "./Endpoint";
|
|
1
|
+
import type Endpoint from "./Endpoint.js";
|
|
2
2
|
export type ResponseOf<E extends Endpoint<any, any, any, any>> = E extends Endpoint<infer R, any, any, any> ? R : never;
|
|
3
3
|
export type ParamsOf<E extends Endpoint<any, any, any, any>> = E extends Endpoint<any, infer P, any, any> ? P : never;
|
|
4
4
|
export type QueryOf<E extends Endpoint<any, any, any, any>> = E extends Endpoint<any, any, infer Q, any> ? Q : never;
|
package/esm/Utils.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
|
2
|
+
const hasOwn = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
2
3
|
export const assign = Object.assign ||
|
|
3
4
|
((target, ...varArgs) => {
|
|
4
5
|
if (target === null || target === undefined) {
|
|
@@ -10,7 +11,7 @@ export const assign = Object.assign ||
|
|
|
10
11
|
if (nextSource !== null && nextSource !== undefined) {
|
|
11
12
|
for (const nextKey in nextSource) {
|
|
12
13
|
// Avoid bugs when hasOwnProperty is shadowed
|
|
13
|
-
if (
|
|
14
|
+
if (hasOwn(nextSource, nextKey)) {
|
|
14
15
|
to[nextKey] = nextSource[nextKey];
|
|
15
16
|
}
|
|
16
17
|
}
|
package/esm/Validation.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type * as zod from "zod";
|
|
2
|
-
import type { Body, Params, Query, State } from "./ApiTypes";
|
|
2
|
+
import type { Body, Params, Query, State } from "./ApiTypes.js";
|
|
3
3
|
export interface Validation<TResponse = any, TParams extends Params | undefined = Params | undefined, TQuery extends Query | undefined = Query | undefined, TBody extends Body | undefined = Body | undefined, TState extends State = State> {
|
|
4
4
|
query?: zod.Schema<TQuery>;
|
|
5
5
|
params?: zod.Schema<TParams>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { AxiosError, AxiosResponse } from "axios";
|
|
2
|
-
import type { ApiResponse } from "../ApiTypes";
|
|
3
|
-
import type RequestContext from "../RequestContext";
|
|
4
|
-
import type
|
|
5
|
-
import type
|
|
2
|
+
import type { ApiResponse } from "../ApiTypes.js";
|
|
3
|
+
import type RequestContext from "../RequestContext.js";
|
|
4
|
+
import type RequestBackend from "./RequestBackend.js";
|
|
5
|
+
import type { ConvertedApiResponse, RequestBackendErrorInfo, RequestOperation } from "./RequestBackend.js";
|
|
6
6
|
export declare const isAxiosError: (error: Error) => error is AxiosError;
|
|
7
7
|
export default class AxiosRequestBackend implements RequestBackend<AxiosResponse> {
|
|
8
8
|
readonly id = "axios";
|
|
@@ -1,38 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
11
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
12
|
-
var m = o[Symbol.asyncIterator], i;
|
|
13
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
14
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
15
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
16
|
-
};
|
|
17
|
-
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
18
|
-
var __asyncDelegator = (this && this.__asyncDelegator) || function (o) {
|
|
19
|
-
var i, p;
|
|
20
|
-
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
|
|
21
|
-
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }
|
|
22
|
-
};
|
|
23
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
24
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
25
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
26
|
-
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
27
|
-
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
28
|
-
function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
|
|
29
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
30
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
31
|
-
function fulfill(value) { resume("next", value); }
|
|
32
|
-
function reject(value) { resume("throw", value); }
|
|
33
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
34
|
-
};
|
|
35
|
-
import { inferResponseType } from "../ApiUtils";
|
|
1
|
+
import { inferResponseType } from "../ApiUtils.js";
|
|
36
2
|
let axios;
|
|
37
3
|
export const isAxiosError = (error) => {
|
|
38
4
|
return "isAxiosError" in error;
|
|
@@ -66,56 +32,50 @@ export default class AxiosRequestBackend {
|
|
|
66
32
|
this.id = "axios";
|
|
67
33
|
axios = axiosLibrary;
|
|
68
34
|
}
|
|
69
|
-
extractResponseFromError(error) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
return undefined;
|
|
75
|
-
});
|
|
35
|
+
async extractResponseFromError(error) {
|
|
36
|
+
if (isAxiosError(error)) {
|
|
37
|
+
return error.response ? error.response : null;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
76
40
|
}
|
|
77
|
-
convertResponse(context, response) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
throw new Error("[api-def] Response data is null for streaming response");
|
|
86
|
-
}
|
|
87
|
-
data = {
|
|
88
|
-
[Symbol.asyncIterator]() {
|
|
89
|
-
return __asyncGenerator(this, arguments, function* _a() {
|
|
90
|
-
const stream = response.data;
|
|
91
|
-
if (stream[Symbol.asyncIterator]) {
|
|
92
|
-
yield __await(yield* __asyncDelegator(__asyncValues(stream)));
|
|
93
|
-
}
|
|
94
|
-
else if (stream.on) {
|
|
95
|
-
// Handle Node.js streams
|
|
96
|
-
yield __await(yield* __asyncDelegator(__asyncValues(stream)));
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
throw new Error("[api-def] Response data is not a valid stream");
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
},
|
|
103
|
-
};
|
|
41
|
+
async convertResponse(context, response) {
|
|
42
|
+
const contentType = response.headers["content-type"];
|
|
43
|
+
const responseType = context.responseType ?? inferResponseType(contentType == null ? contentType : String(contentType));
|
|
44
|
+
let data;
|
|
45
|
+
if (responseType === "stream") {
|
|
46
|
+
// For streaming responses, we create an async iterator from the response data
|
|
47
|
+
if (!response.data) {
|
|
48
|
+
throw new Error("[api-def] Response data is null for streaming response");
|
|
104
49
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
50
|
+
data = {
|
|
51
|
+
async *[Symbol.asyncIterator]() {
|
|
52
|
+
const stream = response.data;
|
|
53
|
+
if (stream[Symbol.asyncIterator]) {
|
|
54
|
+
yield* stream;
|
|
55
|
+
}
|
|
56
|
+
else if (stream.on) {
|
|
57
|
+
// Handle Node.js streams
|
|
58
|
+
yield* stream;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
throw new Error("[api-def] Response data is not a valid stream");
|
|
62
|
+
}
|
|
63
|
+
},
|
|
117
64
|
};
|
|
118
|
-
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
data = response.data;
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
method: context.method,
|
|
71
|
+
url: response.request.res?.responseUrl ?? response.request?._redirectable?._currentUrl,
|
|
72
|
+
data: data,
|
|
73
|
+
headers: response.headers,
|
|
74
|
+
status: response.status,
|
|
75
|
+
state: context.requestConfig.state,
|
|
76
|
+
__lowercaseHeaders: response._lowerCaseResponseHeaders,
|
|
77
|
+
stats: context.stats,
|
|
78
|
+
};
|
|
119
79
|
}
|
|
120
80
|
makeRequest(context) {
|
|
121
81
|
const { requestConfig } = context;
|
|
@@ -125,7 +85,10 @@ export default class AxiosRequestBackend {
|
|
|
125
85
|
method: context.method,
|
|
126
86
|
url: url.href,
|
|
127
87
|
data: context.getParsedBody(),
|
|
128
|
-
headers:
|
|
88
|
+
headers: {
|
|
89
|
+
...getCacheHeaders(requestConfig.browserCache),
|
|
90
|
+
...requestConfig.headers,
|
|
91
|
+
},
|
|
129
92
|
responseType: context.responseType,
|
|
130
93
|
withCredentials: requestConfig.credentials === "include" || requestConfig.credentials === "same-origin",
|
|
131
94
|
cancelToken: new axios.CancelToken((cancellerFunc) => {
|
|
@@ -134,7 +97,7 @@ export default class AxiosRequestBackend {
|
|
|
134
97
|
});
|
|
135
98
|
return {
|
|
136
99
|
promise: promise,
|
|
137
|
-
canceler: () => canceler
|
|
100
|
+
canceler: () => canceler?.(),
|
|
138
101
|
};
|
|
139
102
|
}
|
|
140
103
|
getErrorInfo(error, response) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ApiResponse } from "../ApiTypes";
|
|
2
|
-
import type RequestContext from "../RequestContext";
|
|
3
|
-
import { type Fetch } from "../Utils";
|
|
4
|
-
import type
|
|
5
|
-
import type
|
|
1
|
+
import type { ApiResponse } from "../ApiTypes.js";
|
|
2
|
+
import type RequestContext from "../RequestContext.js";
|
|
3
|
+
import { type Fetch } from "../Utils.js";
|
|
4
|
+
import type RequestBackend from "./RequestBackend.js";
|
|
5
|
+
import type { ConvertedApiResponse, RequestBackendErrorInfo, RequestOperation } from "./RequestBackend.js";
|
|
6
6
|
export default class FetchRequestBackend implements RequestBackend<Response> {
|
|
7
7
|
fetch: (((input: RequestInfo | URL, init?: RequestInit) => Promise<Response>) & typeof fetch) | undefined;
|
|
8
8
|
readonly id = "fetch";
|