api-def 0.12.1 → 0.14.0-alpha.1
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 +3 -2
- package/cjs/ApiUtils.js +30 -32
- package/cjs/Endpoint.d.ts +1 -1
- package/cjs/Endpoint.js +112 -175
- package/cjs/EndpointBuilder.d.ts +17 -0
- package/cjs/EndpointBuilder.js +55 -36
- package/cjs/QueryHandling.js +12 -13
- package/cjs/RequestConfig.js +54 -36
- package/cjs/RequestContext.d.ts +2 -1
- package/cjs/RequestContext.js +143 -180
- package/cjs/RequestError.js +16 -19
- package/cjs/Requester.js +231 -312
- package/cjs/TextDecoding.js +31 -31
- package/cjs/Utils.d.ts +1 -0
- package/cjs/Utils.js +74 -25
- package/cjs/Validation.d.ts +8 -1
- 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 +7 -6
- 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 +21 -4
- package/esm/EndpointBuilder.js +38 -10
- 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 +8 -7
- package/esm/RequestContext.js +33 -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 +45 -50
- package/esm/UtilTypes.d.ts +1 -1
- package/esm/Utils.d.ts +1 -0
- package/esm/Utils.js +54 -2
- package/esm/Validation.d.ts +8 -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 +50 -64
- 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 +67 -28
|
@@ -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";
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 { inferResponseType } from "../ApiUtils";
|
|
11
|
-
import { RequestErrorCode, convertToRequestError } from "../RequestError";
|
|
12
|
-
import * as Utils from "../Utils";
|
|
13
|
-
import { getGlobal, getGlobalFetch } from "../Utils";
|
|
1
|
+
import { inferResponseType } from "../ApiUtils.js";
|
|
2
|
+
import { convertToRequestError, RequestErrorCode } from "../RequestError.js";
|
|
3
|
+
import * as Utils from "../Utils.js";
|
|
4
|
+
import { getGlobal, getGlobalFetch } from "../Utils.js";
|
|
14
5
|
class FetchError extends Error {
|
|
15
6
|
}
|
|
16
7
|
export default class FetchRequestBackend {
|
|
@@ -25,59 +16,54 @@ export default class FetchRequestBackend {
|
|
|
25
16
|
}
|
|
26
17
|
}
|
|
27
18
|
}
|
|
28
|
-
extractResponseFromError(error) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return undefined;
|
|
35
|
-
});
|
|
19
|
+
async extractResponseFromError(error) {
|
|
20
|
+
if ("response" in error) {
|
|
21
|
+
const fetchError = error;
|
|
22
|
+
return fetchError.response ? fetchError.response : null;
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
36
25
|
}
|
|
37
|
-
convertResponse(context, response) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (responseType === "arraybuffer") {
|
|
55
|
-
data = yield response.arrayBuffer();
|
|
56
|
-
}
|
|
57
|
-
else if (responseType === "json") {
|
|
58
|
-
text = yield response.text();
|
|
59
|
-
data = JSON.parse(text);
|
|
60
|
-
}
|
|
61
|
-
else if (responseType === "stream") {
|
|
62
|
-
data = response.body;
|
|
63
|
-
}
|
|
64
|
-
else {
|
|
65
|
-
data = yield response.text();
|
|
66
|
-
}
|
|
26
|
+
async convertResponse(context, response) {
|
|
27
|
+
const { status, headers } = response;
|
|
28
|
+
const convertedResponse = {
|
|
29
|
+
method: context.method,
|
|
30
|
+
url: response.url,
|
|
31
|
+
data: undefined,
|
|
32
|
+
status: status,
|
|
33
|
+
headers: headers,
|
|
34
|
+
state: context.requestConfig.state,
|
|
35
|
+
stats: context.stats,
|
|
36
|
+
};
|
|
37
|
+
const responseType = context.responseType ?? inferResponseType(response.headers.get("Content-Type"));
|
|
38
|
+
let text;
|
|
39
|
+
let data;
|
|
40
|
+
try {
|
|
41
|
+
if (responseType === "arraybuffer") {
|
|
42
|
+
data = await response.arrayBuffer();
|
|
67
43
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
cause: error,
|
|
72
|
-
}),
|
|
73
|
-
code: RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
|
|
74
|
-
context: context,
|
|
75
|
-
response: convertedResponse,
|
|
76
|
-
});
|
|
44
|
+
else if (responseType === "json") {
|
|
45
|
+
text = await response.text();
|
|
46
|
+
data = JSON.parse(text);
|
|
77
47
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
48
|
+
else if (responseType === "stream") {
|
|
49
|
+
data = response.body;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
data = await response.text();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw convertToRequestError({
|
|
57
|
+
error: Object.assign(new Error(`[api-def] Failed to parse response as '${responseType}'${text ? `, got: ${text}` : ""}`), {
|
|
58
|
+
cause: error,
|
|
59
|
+
}),
|
|
60
|
+
code: RequestErrorCode.REQUEST_MISMATCH_RESPONSE_TYPE,
|
|
61
|
+
context: context,
|
|
62
|
+
response: convertedResponse,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
convertedResponse.data = data;
|
|
66
|
+
return convertedResponse;
|
|
81
67
|
}
|
|
82
68
|
makeRequest(context) {
|
|
83
69
|
if (!this.fetch) {
|
|
@@ -90,7 +76,7 @@ export default class FetchRequestBackend {
|
|
|
90
76
|
let softAbort = false;
|
|
91
77
|
let responded = false;
|
|
92
78
|
const body = context.getParsedBody();
|
|
93
|
-
const bodyJsonify = body !== null && typeof body === "object" && !Utils.isFormData(body);
|
|
79
|
+
const bodyJsonify = body !== null && typeof body === "object" && !Utils.isFormData(body) && !(body instanceof URLSearchParams);
|
|
94
80
|
const headers = Utils.assign({
|
|
95
81
|
// logic from axios
|
|
96
82
|
"Content-Type": bodyJsonify ? "application/json;charset=utf-8" : undefined,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ApiResponse } from "../ApiTypes";
|
|
2
|
-
import type RequestContext from "../RequestContext";
|
|
3
|
-
import type
|
|
4
|
-
import type
|
|
1
|
+
import type { ApiResponse } from "../ApiTypes.js";
|
|
2
|
+
import type RequestContext from "../RequestContext.js";
|
|
3
|
+
import type RequestBackend from "./RequestBackend.js";
|
|
4
|
+
import type { RequestBackendErrorInfo, RequestOperation } from "./RequestBackend.js";
|
|
5
5
|
export default class MockRequestBackend implements RequestBackend<ApiResponse> {
|
|
6
6
|
readonly id = "mock";
|
|
7
7
|
convertResponse<T>(context: RequestContext, response: ApiResponse, error?: boolean): Promise<ApiResponse<T>>;
|
|
@@ -1,151 +1,120 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
|
|
11
|
-
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
|
|
12
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
13
|
-
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
14
|
-
return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
15
|
-
function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
|
|
16
|
-
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]); } }
|
|
17
|
-
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
18
|
-
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
19
|
-
function fulfill(value) { resume("next", value); }
|
|
20
|
-
function reject(value) { resume("throw", value); }
|
|
21
|
-
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
22
|
-
};
|
|
23
|
-
import { inferResponseType } from "../ApiUtils";
|
|
24
|
-
import { RequestErrorCode, convertToRequestError } from "../RequestError";
|
|
25
|
-
import * as Utils from "../Utils";
|
|
26
|
-
import { delayThenReturn, randInt } from "../Utils";
|
|
1
|
+
import { inferResponseType } from "../ApiUtils.js";
|
|
2
|
+
import { convertToRequestError, RequestErrorCode } from "../RequestError.js";
|
|
3
|
+
import * as Utils from "../Utils.js";
|
|
4
|
+
import { delayThenReturn, randInt } from "../Utils.js";
|
|
27
5
|
export default class MockRequestBackend {
|
|
28
6
|
constructor() {
|
|
29
7
|
this.id = "mock";
|
|
30
8
|
}
|
|
31
|
-
convertResponse(context, response, error) {
|
|
32
|
-
return
|
|
33
|
-
return response;
|
|
34
|
-
});
|
|
9
|
+
async convertResponse(context, response, error) {
|
|
10
|
+
return response;
|
|
35
11
|
}
|
|
36
|
-
extractResponseFromError(error) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return undefined;
|
|
43
|
-
});
|
|
12
|
+
async extractResponseFromError(error) {
|
|
13
|
+
if ("response" in error) {
|
|
14
|
+
const fetchError = error;
|
|
15
|
+
return fetchError.response ? fetchError.response : null;
|
|
16
|
+
}
|
|
17
|
+
return undefined;
|
|
44
18
|
}
|
|
45
|
-
runRequest(context) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
res.
|
|
74
|
-
if (response && typeof response === "object") {
|
|
75
|
-
res.headers["Content-Type"] = "application/json";
|
|
76
|
-
}
|
|
77
|
-
return res;
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
if ((_d = context.mocking) === null || _d === void 0 ? void 0 : _d.delay) {
|
|
81
|
-
const delay = context.mocking.delay;
|
|
82
|
-
let delayMs;
|
|
83
|
-
if (typeof delay === "number") {
|
|
84
|
-
delayMs = delay;
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
const [min, max] = delay;
|
|
88
|
-
if (min > max) {
|
|
89
|
-
throw convertToRequestError({
|
|
90
|
-
error: new Error("[api-def] Min delay cannot be greater than max delay"),
|
|
91
|
-
code: RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
92
|
-
context,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
delayMs = randInt(min, max);
|
|
19
|
+
async runRequest(context) {
|
|
20
|
+
const mockingFunc = context.mocking?.handler;
|
|
21
|
+
if (!mockingFunc) {
|
|
22
|
+
throw convertToRequestError({
|
|
23
|
+
error: new Error("[api-def] Attempted to run mocked request without mocking function"),
|
|
24
|
+
code: RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
25
|
+
context,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const req = {
|
|
29
|
+
body: context.getParsedBody(),
|
|
30
|
+
params: context.requestConfig.params ?? {},
|
|
31
|
+
query: context.requestConfig.queryObject,
|
|
32
|
+
headers: context.requestConfig.headers ?? {},
|
|
33
|
+
url: context.requestUrl.toString(),
|
|
34
|
+
state: context.requestConfig.state,
|
|
35
|
+
};
|
|
36
|
+
const res = {
|
|
37
|
+
statusCode: -1,
|
|
38
|
+
headers: {},
|
|
39
|
+
response: undefined,
|
|
40
|
+
status(statusCode) {
|
|
41
|
+
res.statusCode = statusCode;
|
|
42
|
+
return res;
|
|
43
|
+
},
|
|
44
|
+
send(response) {
|
|
45
|
+
res.response = response;
|
|
46
|
+
if (response && typeof response === "object") {
|
|
47
|
+
res.headers["Content-Type"] = "application/json";
|
|
96
48
|
}
|
|
97
|
-
|
|
49
|
+
return res;
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
if (context.mocking?.delay) {
|
|
53
|
+
const delay = context.mocking.delay;
|
|
54
|
+
let delayMs;
|
|
55
|
+
if (typeof delay === "number") {
|
|
56
|
+
delayMs = delay;
|
|
98
57
|
}
|
|
99
58
|
else {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
59
|
+
const [min, max] = delay;
|
|
60
|
+
if (min > max) {
|
|
61
|
+
throw convertToRequestError({
|
|
62
|
+
error: new Error("[api-def] Min delay cannot be greater than max delay"),
|
|
63
|
+
code: RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
64
|
+
context,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
delayMs = randInt(min, max);
|
|
108
68
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
69
|
+
await delayThenReturn(await mockingFunc(req, res), delayMs);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
await mockingFunc(req, res);
|
|
73
|
+
}
|
|
74
|
+
if (res.response === undefined) {
|
|
75
|
+
throw convertToRequestError({
|
|
76
|
+
error: new Error("[api-def] Mocked API did not respond"),
|
|
77
|
+
code: RequestErrorCode.REQUEST_INVALID_CONFIG,
|
|
78
|
+
context,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const parsedHeaders = Object.keys(res.headers).reduce((parsedHeaders, key) => {
|
|
82
|
+
parsedHeaders.set(key, res.headers[key].toString());
|
|
83
|
+
return parsedHeaders;
|
|
84
|
+
}, new Headers());
|
|
85
|
+
const responseType = context.responseType ?? inferResponseType(res.headers["content-type"]?.toString());
|
|
86
|
+
let data;
|
|
87
|
+
if (responseType === "stream") {
|
|
88
|
+
// For streaming responses, we create a mock async iterator
|
|
89
|
+
data = {
|
|
90
|
+
async *[Symbol.asyncIterator]() {
|
|
91
|
+
if (res.response) {
|
|
92
|
+
// If the response is an array, yield each item
|
|
93
|
+
if (Array.isArray(res.response)) {
|
|
94
|
+
for (const item of res.response) {
|
|
95
|
+
yield new TextEncoder().encode(`${JSON.stringify(item)}\n`);
|
|
131
96
|
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
url: context.requestUrl.href,
|
|
141
|
-
method: context.method,
|
|
142
|
-
headers: parsedHeaders,
|
|
143
|
-
data: data,
|
|
144
|
-
status: res.statusCode,
|
|
145
|
-
state: context.requestConfig.state,
|
|
146
|
-
stats: context.stats,
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
// Otherwise yield the entire response
|
|
100
|
+
yield new TextEncoder().encode(`${JSON.stringify(res.response)}\n`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
147
104
|
};
|
|
148
|
-
}
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
data = res.response;
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
url: context.requestUrl.href,
|
|
111
|
+
method: context.method,
|
|
112
|
+
headers: parsedHeaders,
|
|
113
|
+
data: data,
|
|
114
|
+
status: res.statusCode,
|
|
115
|
+
state: context.requestConfig.state,
|
|
116
|
+
stats: context.stats,
|
|
117
|
+
};
|
|
149
118
|
}
|
|
150
119
|
makeRequest(context) {
|
|
151
120
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ApiResponse } from "../ApiTypes";
|
|
2
|
-
import type RequestContext from "../RequestContext";
|
|
1
|
+
import type { ApiResponse } from "../ApiTypes.js";
|
|
2
|
+
import type RequestContext from "../RequestContext.js";
|
|
3
3
|
export interface RequestOperation<R> {
|
|
4
4
|
promise: Promise<R>;
|
|
5
5
|
canceler: () => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientCacheBackend } from "./ClientCacheBackend";
|
|
1
|
+
import type { ClientCacheBackend } from "./ClientCacheBackend.js";
|
|
2
2
|
export declare const setClientCacheBackend: (backend: ClientCacheBackend) => void;
|
|
3
3
|
export declare const DEFAULT_CLIENT_CACHE_EXPIRY: number;
|
|
4
4
|
export declare const clearClientCache: () => Promise<void>;
|
|
@@ -1,13 +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
|
-
import LocalStorageClientCacheBackend from "./LocalStorageClientCacheBackend";
|
|
1
|
+
import LocalStorageClientCacheBackend from "./LocalStorageClientCacheBackend.js";
|
|
11
2
|
let clientCacheBackend = new LocalStorageClientCacheBackend();
|
|
12
3
|
export const setClientCacheBackend = (backend) => {
|
|
13
4
|
clientCacheBackend = backend;
|
|
@@ -16,24 +7,24 @@ export const DEFAULT_CLIENT_CACHE_EXPIRY = /* 15 mins */ 60 * 1000 * 15;
|
|
|
16
7
|
export const clearClientCache = () => {
|
|
17
8
|
return clientCacheBackend.clear();
|
|
18
9
|
};
|
|
19
|
-
export const setClientCachedItem = (key, value, expiry) =>
|
|
10
|
+
export const setClientCachedItem = async (key, value, expiry) => {
|
|
20
11
|
const entry = {
|
|
21
12
|
data: value,
|
|
22
13
|
expiry: expiry === undefined || Number.isNaN(expiry) ? null : expiry,
|
|
23
14
|
};
|
|
24
|
-
|
|
15
|
+
await clientCacheBackend.setItem(key, entry);
|
|
25
16
|
return value;
|
|
26
|
-
}
|
|
27
|
-
export const getClientCachedItem = (key) =>
|
|
28
|
-
const entry =
|
|
17
|
+
};
|
|
18
|
+
export const getClientCachedItem = async (key) => {
|
|
19
|
+
const entry = await clientCacheBackend.getItem(key);
|
|
29
20
|
if (!entry) {
|
|
30
21
|
return undefined;
|
|
31
22
|
}
|
|
32
23
|
if (typeof entry.expiry === "number") {
|
|
33
24
|
if (Date.now() >= entry.expiry) {
|
|
34
|
-
|
|
25
|
+
await clientCacheBackend.removeItem(key);
|
|
35
26
|
return undefined;
|
|
36
27
|
}
|
|
37
28
|
}
|
|
38
29
|
return entry.data;
|
|
39
|
-
}
|
|
30
|
+
};
|