accessio 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -391
- package/cjs/accessio.cjs +23 -52
- package/cjs/accessio.cjs.map +1 -1
- package/cjs/core/accessioError.cjs +1 -7
- package/cjs/core/accessioError.cjs.map +1 -1
- package/cjs/core/buildURL.cjs +1 -5
- package/cjs/core/buildURL.cjs.map +1 -1
- package/cjs/core/mergeConfig.cjs +2 -4
- package/cjs/core/mergeConfig.cjs.map +1 -1
- package/cjs/core/request.cjs +44 -66
- package/cjs/core/request.cjs.map +1 -1
- package/cjs/core/retry.cjs +2 -8
- package/cjs/core/retry.cjs.map +1 -1
- package/cjs/defaults/index.cjs.map +1 -1
- package/cjs/defaults/transforms.cjs.map +1 -1
- package/cjs/helpers/debug.cjs +1 -3
- package/cjs/helpers/debug.cjs.map +1 -1
- package/cjs/helpers/parseHeaders.cjs.map +1 -1
- package/cjs/helpers/rateLimiter.cjs +22 -14
- package/cjs/helpers/rateLimiter.cjs.map +1 -1
- package/cjs/helpers/transformData.cjs.map +1 -1
- package/cjs/index.cjs.map +1 -1
- package/cjs/interceptors/interceptorManager.cjs +40 -3
- package/cjs/interceptors/interceptorManager.cjs.map +1 -1
- package/package.json +6 -14
- package/src/accessio.ts +28 -72
- package/src/core/accessioError.ts +1 -7
- package/src/core/buildURL.ts +4 -13
- package/src/core/mergeConfig.ts +6 -16
- package/src/core/request.ts +44 -74
- package/src/core/retry.ts +4 -15
- package/src/defaults/index.ts +1 -3
- package/src/defaults/transforms.ts +1 -4
- package/src/helpers/debug.ts +12 -22
- package/src/helpers/parseHeaders.ts +1 -3
- package/src/helpers/rateLimiter.ts +28 -23
- package/src/helpers/transformData.ts +1 -4
- package/src/index.ts +3 -11
- package/src/interceptors/interceptorManager.ts +50 -2
- package/src/types.ts +7 -68
package/src/core/request.ts
CHANGED
|
@@ -36,10 +36,7 @@ function flattenHeaders(
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
for (const key in headers) {
|
|
39
|
-
if (
|
|
40
|
-
Object.prototype.hasOwnProperty.call(headers, key) &&
|
|
41
|
-
!METHOD_KEYS.has(key)
|
|
42
|
-
) {
|
|
39
|
+
if (Object.prototype.hasOwnProperty.call(headers, key) && !METHOD_KEYS.has(key)) {
|
|
43
40
|
merged[key] = headers[key] as unknown as string;
|
|
44
41
|
}
|
|
45
42
|
}
|
|
@@ -48,9 +45,7 @@ function flattenHeaders(
|
|
|
48
45
|
}
|
|
49
46
|
|
|
50
47
|
function removeContentType(headers: Record<string, string>): void {
|
|
51
|
-
const key = Object.keys(headers).find(
|
|
52
|
-
(k) => k.toLowerCase() === 'content-type',
|
|
53
|
-
);
|
|
48
|
+
const key = Object.keys(headers).find((k) => k.toLowerCase() === 'content-type');
|
|
54
49
|
if (key) {
|
|
55
50
|
delete headers[key];
|
|
56
51
|
}
|
|
@@ -64,9 +59,35 @@ function buildTransformArray(
|
|
|
64
59
|
return [transform];
|
|
65
60
|
}
|
|
66
61
|
|
|
67
|
-
|
|
68
|
-
config
|
|
69
|
-
|
|
62
|
+
function setBasicAuth(config: AccessioRequestConfig, headers: Record<string, string>): void {
|
|
63
|
+
if (!config.auth) return;
|
|
64
|
+
const username = config.auth.username || '';
|
|
65
|
+
const password = config.auth.password || '';
|
|
66
|
+
const credentials = `${username}:${password}`;
|
|
67
|
+
|
|
68
|
+
let encoded: string;
|
|
69
|
+
if (typeof Buffer !== 'undefined') {
|
|
70
|
+
encoded = Buffer.from(credentials).toString('base64');
|
|
71
|
+
} else {
|
|
72
|
+
const bytes = new TextEncoder().encode(credentials);
|
|
73
|
+
const binString = Array.from(bytes, (x) => String.fromCodePoint(x)).join('');
|
|
74
|
+
encoded = btoa(binString);
|
|
75
|
+
}
|
|
76
|
+
headers['Authorization'] = `Basic ${encoded}`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function readResponseData(fetchResponse: Response, responseType: string): Promise<unknown> {
|
|
80
|
+
switch (responseType) {
|
|
81
|
+
case 'arraybuffer': return await fetchResponse.arrayBuffer();
|
|
82
|
+
case 'blob': return await fetchResponse.blob();
|
|
83
|
+
case 'text': return await fetchResponse.text();
|
|
84
|
+
case 'stream': return fetchResponse.body;
|
|
85
|
+
case 'json':
|
|
86
|
+
default: return await fetchResponse.text();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default function dispatchRequest(config: AccessioRequestConfig): Promise<AccessioResponse> {
|
|
70
91
|
const fullURL =
|
|
71
92
|
config._builtUrl ||
|
|
72
93
|
buildURL(
|
|
@@ -76,19 +97,11 @@ export default function dispatchRequest(
|
|
|
76
97
|
config.paramsSerializer,
|
|
77
98
|
);
|
|
78
99
|
|
|
79
|
-
const flatHeaders = flattenHeaders(
|
|
80
|
-
config.headers as HeadersConfig | undefined,
|
|
81
|
-
config.method,
|
|
82
|
-
);
|
|
100
|
+
const flatHeaders = flattenHeaders(config.headers as HeadersConfig | undefined, config.method);
|
|
83
101
|
|
|
84
102
|
const requestTransforms = buildTransformArray(config.transformRequest);
|
|
85
103
|
|
|
86
|
-
const requestData = transformData(
|
|
87
|
-
requestTransforms,
|
|
88
|
-
config.data,
|
|
89
|
-
flatHeaders,
|
|
90
|
-
config,
|
|
91
|
-
);
|
|
104
|
+
const requestData = transformData(requestTransforms, config.data, flatHeaders, config);
|
|
92
105
|
|
|
93
106
|
if (
|
|
94
107
|
requestData === null ||
|
|
@@ -98,24 +111,7 @@ export default function dispatchRequest(
|
|
|
98
111
|
removeContentType(flatHeaders);
|
|
99
112
|
}
|
|
100
113
|
|
|
101
|
-
|
|
102
|
-
const username = config.auth.username || '';
|
|
103
|
-
const password = config.auth.password || '';
|
|
104
|
-
const credentials = `${username}:${password}`;
|
|
105
|
-
|
|
106
|
-
let encoded: string;
|
|
107
|
-
if (typeof Buffer !== 'undefined') {
|
|
108
|
-
encoded = Buffer.from(credentials).toString('base64');
|
|
109
|
-
} else {
|
|
110
|
-
const bytes = new TextEncoder().encode(credentials);
|
|
111
|
-
const binString = Array.from(bytes, (x) =>
|
|
112
|
-
String.fromCodePoint(x),
|
|
113
|
-
).join('');
|
|
114
|
-
encoded = btoa(binString);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
flatHeaders['Authorization'] = `Basic ${encoded}`;
|
|
118
|
-
}
|
|
114
|
+
setBasicAuth(config, flatHeaders);
|
|
119
115
|
|
|
120
116
|
const fetchOptions: RequestInit = {
|
|
121
117
|
method: (config.method || 'GET').toUpperCase(),
|
|
@@ -158,10 +154,7 @@ export default function dispatchRequest(
|
|
|
158
154
|
|
|
159
155
|
if (config.signal) {
|
|
160
156
|
if (typeof AbortSignal.any === 'function') {
|
|
161
|
-
fetchOptions.signal = AbortSignal.any([
|
|
162
|
-
config.signal,
|
|
163
|
-
abortController.signal,
|
|
164
|
-
]);
|
|
157
|
+
fetchOptions.signal = AbortSignal.any([config.signal, abortController.signal]);
|
|
165
158
|
} else {
|
|
166
159
|
if (config.signal.aborted) {
|
|
167
160
|
abortController.abort(config.signal.reason);
|
|
@@ -190,24 +183,7 @@ export default function dispatchRequest(
|
|
|
190
183
|
const responseType = config.responseType || 'json';
|
|
191
184
|
|
|
192
185
|
try {
|
|
193
|
-
|
|
194
|
-
case 'arraybuffer':
|
|
195
|
-
responseData = await fetchResponse.arrayBuffer();
|
|
196
|
-
break;
|
|
197
|
-
case 'blob':
|
|
198
|
-
responseData = await fetchResponse.blob();
|
|
199
|
-
break;
|
|
200
|
-
case 'text':
|
|
201
|
-
responseData = await fetchResponse.text();
|
|
202
|
-
break;
|
|
203
|
-
case 'stream':
|
|
204
|
-
responseData = fetchResponse.body;
|
|
205
|
-
break;
|
|
206
|
-
case 'json':
|
|
207
|
-
default:
|
|
208
|
-
responseData = await fetchResponse.text();
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
186
|
+
responseData = await readResponseData(fetchResponse, responseType);
|
|
211
187
|
} catch (readError) {
|
|
212
188
|
throw AccessioError.from(
|
|
213
189
|
readError as Error,
|
|
@@ -222,12 +198,7 @@ export default function dispatchRequest(
|
|
|
222
198
|
|
|
223
199
|
const responseTransforms = buildTransformArray(config.transformResponse);
|
|
224
200
|
|
|
225
|
-
responseData = transformData(
|
|
226
|
-
responseTransforms,
|
|
227
|
-
responseData,
|
|
228
|
-
responseHeaders,
|
|
229
|
-
config,
|
|
230
|
-
);
|
|
201
|
+
responseData = transformData(responseTransforms, responseData, responseHeaders, config);
|
|
231
202
|
|
|
232
203
|
const response: AccessioResponse = {
|
|
233
204
|
data: responseData,
|
|
@@ -240,7 +211,12 @@ export default function dispatchRequest(
|
|
|
240
211
|
};
|
|
241
212
|
|
|
242
213
|
return new Promise<AccessioResponse>((resolve, reject) => {
|
|
243
|
-
settle(
|
|
214
|
+
settle(
|
|
215
|
+
resolve as (value: AccessioResponse) => void,
|
|
216
|
+
reject as (reason: AccessioError) => void,
|
|
217
|
+
response,
|
|
218
|
+
config,
|
|
219
|
+
);
|
|
244
220
|
});
|
|
245
221
|
})
|
|
246
222
|
.catch((error) => {
|
|
@@ -258,13 +234,7 @@ export default function dispatchRequest(
|
|
|
258
234
|
null,
|
|
259
235
|
);
|
|
260
236
|
}
|
|
261
|
-
throw new AccessioError(
|
|
262
|
-
'Request aborted',
|
|
263
|
-
AccessioError.ERR_CANCELED,
|
|
264
|
-
config,
|
|
265
|
-
null,
|
|
266
|
-
null,
|
|
267
|
-
);
|
|
237
|
+
throw new AccessioError('Request aborted', AccessioError.ERR_CANCELED, config, null, null);
|
|
268
238
|
}
|
|
269
239
|
|
|
270
240
|
throw AccessioError.from(
|
package/src/core/retry.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ERR_CANCELED,
|
|
3
|
-
ERR_NETWORK,
|
|
4
|
-
ETIMEDOUT,
|
|
5
|
-
} from '../constants/errorCodes';
|
|
1
|
+
import { ERR_CANCELED, ERR_NETWORK, ETIMEDOUT } from '../constants/errorCodes';
|
|
6
2
|
import type {
|
|
7
3
|
AccessioRequestConfig,
|
|
8
4
|
AccessioResponse,
|
|
@@ -51,9 +47,7 @@ function sleep(ms: number, options?: { signal?: AbortSignal }): Promise<void> {
|
|
|
51
47
|
if (options?.signal) {
|
|
52
48
|
if (options.signal.aborted) {
|
|
53
49
|
clearTimeout(timeoutId);
|
|
54
|
-
return reject(
|
|
55
|
-
options.signal.reason || new Error('Sleep aborted'),
|
|
56
|
-
);
|
|
50
|
+
return reject(options.signal.reason || new Error('Sleep aborted'));
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
onAbort = () => {
|
|
@@ -77,8 +71,7 @@ async function retryRequest(
|
|
|
77
71
|
}
|
|
78
72
|
|
|
79
73
|
const retryDelay = config.retryDelay ?? 1000;
|
|
80
|
-
const retryCondition: RetryConditionFunction =
|
|
81
|
-
config.retryCondition ?? defaultRetryCondition;
|
|
74
|
+
const retryCondition: RetryConditionFunction = config.retryCondition ?? defaultRetryCondition;
|
|
82
75
|
|
|
83
76
|
let lastError: any;
|
|
84
77
|
|
|
@@ -99,11 +92,7 @@ async function retryRequest(
|
|
|
99
92
|
const delay = calculateDelay(attempt, retryDelay);
|
|
100
93
|
|
|
101
94
|
if (typeof config.onRetry === 'function') {
|
|
102
|
-
(config.onRetry as OnRetryFunction)(
|
|
103
|
-
attempt + 1,
|
|
104
|
-
error as AccessioError,
|
|
105
|
-
config,
|
|
106
|
-
);
|
|
95
|
+
(config.onRetry as OnRetryFunction)(attempt + 1, error as AccessioError, config);
|
|
107
96
|
}
|
|
108
97
|
|
|
109
98
|
await sleep(delay, { signal: config.signal });
|
package/src/defaults/index.ts
CHANGED
|
@@ -24,9 +24,7 @@ const defaults: AccessioRequestConfig = {
|
|
|
24
24
|
},
|
|
25
25
|
transformRequest: [defaultTransformRequest],
|
|
26
26
|
transformResponse: [defaultTransformResponse],
|
|
27
|
-
validateStatus: function defaultValidateStatus(
|
|
28
|
-
status: number,
|
|
29
|
-
): boolean {
|
|
27
|
+
validateStatus: function defaultValidateStatus(status: number): boolean {
|
|
30
28
|
return status >= 200 && status < 300;
|
|
31
29
|
},
|
|
32
30
|
responseType: 'json',
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
export function defaultTransformRequest(
|
|
2
|
-
data: unknown,
|
|
3
|
-
headers: Record<string, string>,
|
|
4
|
-
): unknown {
|
|
1
|
+
export function defaultTransformRequest(data: unknown, headers: Record<string, string>): unknown {
|
|
5
2
|
if (data === null || data === undefined) {
|
|
6
3
|
return data;
|
|
7
4
|
}
|
package/src/helpers/debug.ts
CHANGED
|
@@ -8,9 +8,11 @@ function formatBytes(bytes: number): string {
|
|
|
8
8
|
return `${(bytes / Math.pow(1024, i)).toFixed(1)} ${sizes[i]}`;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
function sanitizeConfigForLog(
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
function sanitizeConfigForLog(config: AccessioRequestConfig): {
|
|
12
|
+
params: Record<string, unknown> | undefined;
|
|
13
|
+
timeout: number | undefined;
|
|
14
|
+
retry: number | undefined;
|
|
15
|
+
} {
|
|
14
16
|
return {
|
|
15
17
|
params: config.params,
|
|
16
18
|
timeout: config.timeout,
|
|
@@ -18,10 +20,7 @@ function sanitizeConfigForLog(
|
|
|
18
20
|
};
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
export function logRequest(
|
|
22
|
-
config: AccessioRequestConfig,
|
|
23
|
-
fullUrl: string,
|
|
24
|
-
): void {
|
|
23
|
+
export function logRequest(config: AccessioRequestConfig, fullUrl: string): void {
|
|
25
24
|
if (!config.debug) return;
|
|
26
25
|
|
|
27
26
|
const safe = sanitizeConfigForLog(config);
|
|
@@ -37,8 +36,7 @@ export function logRequest(
|
|
|
37
36
|
|
|
38
37
|
if (config.data && typeof config.data === 'object') {
|
|
39
38
|
const preview = JSON.stringify(config.data);
|
|
40
|
-
const truncated =
|
|
41
|
-
preview.length > 200 ? `${preview.substring(0, 200)}...` : preview;
|
|
39
|
+
const truncated = preview.length > 200 ? `${preview.substring(0, 200)}...` : preview;
|
|
42
40
|
parts.push(` Body: ${truncated}`);
|
|
43
41
|
}
|
|
44
42
|
|
|
@@ -57,19 +55,11 @@ export function logResponse(response: AccessioResponse): void {
|
|
|
57
55
|
if (!response.config || !response.config.debug) return;
|
|
58
56
|
const status = response.status;
|
|
59
57
|
const statusText = response.statusText || '';
|
|
60
|
-
const duration =
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
? '✅'
|
|
66
|
-
: status >= 400
|
|
67
|
-
? '❌'
|
|
68
|
-
: '⚠️';
|
|
69
|
-
|
|
70
|
-
const parts: string[] = [
|
|
71
|
-
`🐦⬛ [Accessio] ← ${statusIcon} ${status} ${statusText} (${duration})`,
|
|
72
|
-
];
|
|
58
|
+
const duration = response.duration != null ? `${response.duration}ms` : '??';
|
|
59
|
+
|
|
60
|
+
const statusIcon = status >= 200 && status < 300 ? '✅' : status >= 400 ? '❌' : '⚠️';
|
|
61
|
+
|
|
62
|
+
const parts: string[] = [`🐦⬛ [Accessio] ← ${statusIcon} ${status} ${statusText} (${duration})`];
|
|
73
63
|
|
|
74
64
|
if (response.data) {
|
|
75
65
|
try {
|
|
@@ -1,32 +1,33 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
RateLimiter,
|
|
3
|
-
AccessioRequestConfig,
|
|
4
|
-
AccessioResponse,
|
|
5
|
-
} from '../types';
|
|
1
|
+
import type { RateLimiter, AccessioRequestConfig, AccessioResponse } from '../types';
|
|
6
2
|
|
|
7
3
|
interface QueueItem {
|
|
8
4
|
resolve: () => void;
|
|
9
5
|
reject: (reason: Error) => void;
|
|
10
6
|
}
|
|
11
7
|
|
|
12
|
-
export function createRateLimiter(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
) {
|
|
8
|
+
export function createRateLimiter(
|
|
9
|
+
maxConcurrent: number = Infinity,
|
|
10
|
+
maxQueueSize: number = Infinity,
|
|
11
|
+
): RateLimiter {
|
|
12
|
+
if (maxConcurrent !== Infinity && (!Number.isInteger(maxConcurrent) || maxConcurrent < 1)) {
|
|
17
13
|
throw new RangeError(
|
|
18
14
|
`[Accessio] maxConcurrent must be a positive integer or Infinity, got: ${maxConcurrent}`,
|
|
19
15
|
);
|
|
20
16
|
}
|
|
17
|
+
if (maxQueueSize !== Infinity && (!Number.isInteger(maxQueueSize) || maxQueueSize < 1)) {
|
|
18
|
+
throw new RangeError(
|
|
19
|
+
`[Accessio] maxQueueSize must be a positive integer or Infinity, got: ${maxQueueSize}`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
21
22
|
let active = 0;
|
|
22
23
|
let destroyed = false;
|
|
23
|
-
|
|
24
|
+
let headIndex = 0;
|
|
25
|
+
let tailIndex = 0;
|
|
26
|
+
const queue: Record<number, QueueItem> = {};
|
|
24
27
|
|
|
25
28
|
function acquire(): Promise<void> {
|
|
26
29
|
if (destroyed) {
|
|
27
|
-
return Promise.reject(
|
|
28
|
-
new Error('[Accessio] Rate limiter has been destroyed'),
|
|
29
|
-
);
|
|
30
|
+
return Promise.reject(new Error('[Accessio] Rate limiter has been destroyed'));
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
if (active < maxConcurrent) {
|
|
@@ -34,8 +35,12 @@ export function createRateLimiter(maxConcurrent: number = Infinity): RateLimiter
|
|
|
34
35
|
return Promise.resolve();
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
if (tailIndex - headIndex >= maxQueueSize) {
|
|
39
|
+
return Promise.reject(new Error(`[Accessio] Rate limiter queue size exceeded maxQueueSize (${maxQueueSize})`));
|
|
40
|
+
}
|
|
41
|
+
|
|
37
42
|
return new Promise((resolve, reject) => {
|
|
38
|
-
queue
|
|
43
|
+
queue[tailIndex++] = { resolve, reject };
|
|
39
44
|
});
|
|
40
45
|
}
|
|
41
46
|
|
|
@@ -46,20 +51,20 @@ export function createRateLimiter(maxConcurrent: number = Infinity): RateLimiter
|
|
|
46
51
|
|
|
47
52
|
active--;
|
|
48
53
|
|
|
49
|
-
if (
|
|
54
|
+
if (tailIndex - headIndex > 0 && active < maxConcurrent) {
|
|
50
55
|
active++;
|
|
51
|
-
const next = queue
|
|
56
|
+
const next = queue[headIndex];
|
|
57
|
+
delete queue[headIndex++];
|
|
52
58
|
next?.resolve();
|
|
53
59
|
}
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
function destroy(): void {
|
|
57
63
|
destroyed = true;
|
|
58
|
-
const reason = new Error(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const next = queue.shift();
|
|
64
|
+
const reason = new Error('[Accessio] Rate limiter destroyed — pending request cancelled');
|
|
65
|
+
while (tailIndex - headIndex > 0) {
|
|
66
|
+
const next = queue[headIndex];
|
|
67
|
+
delete queue[headIndex++];
|
|
63
68
|
next?.reject(reason);
|
|
64
69
|
}
|
|
65
70
|
}
|
|
@@ -69,7 +74,7 @@ export function createRateLimiter(maxConcurrent: number = Infinity): RateLimiter
|
|
|
69
74
|
release,
|
|
70
75
|
destroy,
|
|
71
76
|
get pending() {
|
|
72
|
-
return
|
|
77
|
+
return tailIndex - headIndex;
|
|
73
78
|
},
|
|
74
79
|
get active() {
|
|
75
80
|
return active;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import AccessioError from '../core/accessioError';
|
|
2
|
-
import type {
|
|
3
|
-
TransformFunction,
|
|
4
|
-
AccessioRequestConfig,
|
|
5
|
-
} from '../types';
|
|
2
|
+
import type { TransformFunction, AccessioRequestConfig } from '../types';
|
|
6
3
|
|
|
7
4
|
export default function transformData(
|
|
8
5
|
transforms: TransformFunction | TransformFunction[] | undefined,
|
package/src/index.ts
CHANGED
|
@@ -46,23 +46,15 @@ function createInstance(defaultConfig: AccessioRequestConfig) {
|
|
|
46
46
|
instance.all = function all(promises: any[]): Promise<any[]> {
|
|
47
47
|
return Promise.all(promises);
|
|
48
48
|
};
|
|
49
|
-
instance.spread = function spread<T>(
|
|
50
|
-
callback: (...args: any[]) => T,
|
|
51
|
-
): (arr: any[]) => T {
|
|
49
|
+
instance.spread = function spread<T>(callback: (...args: any[]) => T): (arr: any[]) => T {
|
|
52
50
|
return function wrap(arr: any[]): T {
|
|
53
51
|
return callback(...arr);
|
|
54
52
|
};
|
|
55
53
|
};
|
|
56
54
|
instance.isCancel = function isCancel(value: any): boolean {
|
|
57
|
-
return !!(
|
|
58
|
-
value &&
|
|
59
|
-
value.isAccessioError &&
|
|
60
|
-
value.code === ERR_CANCELED
|
|
61
|
-
);
|
|
55
|
+
return !!(value && value.isAccessioError && value.code === ERR_CANCELED);
|
|
62
56
|
};
|
|
63
|
-
instance.isAccessioError = function isAccessioError(
|
|
64
|
-
value: any,
|
|
65
|
-
): boolean {
|
|
57
|
+
instance.isAccessioError = function isAccessioError(value: any): boolean {
|
|
66
58
|
return (
|
|
67
59
|
value instanceof AccessioError ||
|
|
68
60
|
!!(value && typeof value === 'object' && value.isAccessioError === true)
|
|
@@ -1,5 +1,53 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TransformFunction, InterceptorHandler, InterceptorOptions } from '../types';
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export class InterceptorManager {
|
|
4
|
+
handlers: Array<InterceptorHandler | null>;
|
|
5
|
+
private _activeCount: number;
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
this.handlers = [];
|
|
9
|
+
this._activeCount = 0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
use(
|
|
13
|
+
fulfilled: TransformFunction | null,
|
|
14
|
+
rejected?: ((error: unknown) => unknown) | null,
|
|
15
|
+
options: InterceptorOptions = {},
|
|
16
|
+
): number {
|
|
17
|
+
this.handlers.push({
|
|
18
|
+
fulfilled: fulfilled || null,
|
|
19
|
+
rejected: rejected || null,
|
|
20
|
+
synchronous: options.synchronous || false,
|
|
21
|
+
runWhen: options.runWhen || null,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
this._activeCount++;
|
|
25
|
+
return this.handlers.length - 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
eject(id: number): void {
|
|
29
|
+
if (this.handlers[id]) {
|
|
30
|
+
this.handlers[id] = null;
|
|
31
|
+
this._activeCount--;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
clear(): void {
|
|
36
|
+
this.handlers = [];
|
|
37
|
+
this._activeCount = 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
forEach(fn: (handler: InterceptorHandler) => void): void {
|
|
41
|
+
for (const handler of this.handlers) {
|
|
42
|
+
if (handler !== null) {
|
|
43
|
+
fn(handler);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get size(): number {
|
|
49
|
+
return this._activeCount;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
4
52
|
|
|
5
53
|
export default InterceptorManager;
|
package/src/types.ts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
| 'post'
|
|
7
|
-
| 'put'
|
|
8
|
-
| 'patch';
|
|
9
|
-
|
|
10
|
-
export type ResponseType =
|
|
11
|
-
| 'json'
|
|
12
|
-
| 'text'
|
|
13
|
-
| 'blob'
|
|
14
|
-
| 'arraybuffer'
|
|
15
|
-
| 'stream';
|
|
1
|
+
import type InterceptorManager from './interceptors/interceptorManager';
|
|
2
|
+
|
|
3
|
+
export type Method = 'get' | 'delete' | 'head' | 'options' | 'post' | 'put' | 'patch';
|
|
4
|
+
|
|
5
|
+
export type ResponseType = 'json' | 'text' | 'blob' | 'arraybuffer' | 'stream';
|
|
16
6
|
|
|
17
7
|
export interface AuthConfig {
|
|
18
8
|
username: string;
|
|
@@ -21,10 +11,7 @@ export interface AuthConfig {
|
|
|
21
11
|
|
|
22
12
|
export type ParamsSerializer = (params: Record<string, unknown>) => string;
|
|
23
13
|
|
|
24
|
-
export type TransformFunction = (
|
|
25
|
-
data: unknown,
|
|
26
|
-
headers: Record<string, string>,
|
|
27
|
-
) => unknown;
|
|
14
|
+
export type TransformFunction = (data: unknown, headers: Record<string, string>) => unknown;
|
|
28
15
|
|
|
29
16
|
export type RetryConditionFunction = (error: AccessioError) => boolean;
|
|
30
17
|
|
|
@@ -99,55 +86,7 @@ export interface AccessioError extends Error {
|
|
|
99
86
|
toJSON(): Record<string, unknown>;
|
|
100
87
|
}
|
|
101
88
|
|
|
102
|
-
|
|
103
|
-
handlers: Array<InterceptorHandler | null>;
|
|
104
|
-
private _activeCount: number;
|
|
105
|
-
|
|
106
|
-
constructor() {
|
|
107
|
-
this.handlers = [];
|
|
108
|
-
this._activeCount = 0;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
use(
|
|
112
|
-
fulfilled: TransformFunction,
|
|
113
|
-
rejected?: (error: unknown) => unknown,
|
|
114
|
-
options: InterceptorOptions = {},
|
|
115
|
-
): number {
|
|
116
|
-
this.handlers.push({
|
|
117
|
-
fulfilled: fulfilled || null,
|
|
118
|
-
rejected: rejected || null,
|
|
119
|
-
synchronous: options.synchronous || false,
|
|
120
|
-
runWhen: options.runWhen || null,
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
this._activeCount++;
|
|
124
|
-
return this.handlers.length - 1;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
eject(id: number): void {
|
|
128
|
-
if (this.handlers[id]) {
|
|
129
|
-
this.handlers[id] = null;
|
|
130
|
-
this._activeCount--;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
clear(): void {
|
|
135
|
-
this.handlers = [];
|
|
136
|
-
this._activeCount = 0;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
forEach(fn: (handler: InterceptorHandler) => void): void {
|
|
140
|
-
for (const handler of this.handlers) {
|
|
141
|
-
if (handler !== null) {
|
|
142
|
-
fn(handler);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
get size(): number {
|
|
148
|
-
return this._activeCount;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
89
|
+
|
|
151
90
|
|
|
152
91
|
export interface RateLimiter {
|
|
153
92
|
acquire: () => Promise<void>;
|