accessio 1.1.1 → 1.2.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 +98 -1
- package/cjs/accessio.cjs +102 -10
- package/cjs/accessio.cjs.map +1 -1
- package/cjs/core/accessioError.cjs +1 -0
- package/cjs/core/accessioError.cjs.map +1 -1
- package/cjs/core/buildURL.cjs +16 -2
- package/cjs/core/buildURL.cjs.map +1 -1
- package/cjs/core/fetchAdapter.cjs +224 -0
- package/cjs/core/fetchAdapter.cjs.map +1 -0
- package/cjs/core/mergeConfig.cjs +2 -2
- package/cjs/core/mergeConfig.cjs.map +1 -1
- package/cjs/core/request.cjs +74 -199
- package/cjs/core/request.cjs.map +1 -1
- package/cjs/core/retry.cjs +23 -4
- package/cjs/core/retry.cjs.map +1 -1
- package/cjs/defaults/transforms.cjs.map +1 -1
- package/cjs/helpers/auth.cjs +45 -0
- package/cjs/helpers/auth.cjs.map +1 -0
- package/cjs/helpers/flattenHeaders.cjs +78 -0
- package/cjs/helpers/flattenHeaders.cjs.map +1 -0
- package/cjs/helpers/memoryCache.cjs +51 -0
- package/cjs/helpers/memoryCache.cjs.map +1 -0
- package/cjs/helpers/parseHeaders.cjs +16 -4
- package/cjs/helpers/parseHeaders.cjs.map +1 -1
- package/cjs/helpers/rateLimiter.cjs +18 -8
- package/cjs/helpers/rateLimiter.cjs.map +1 -1
- package/cjs/helpers/toFormData.cjs +50 -0
- package/cjs/helpers/toFormData.cjs.map +1 -0
- package/cjs/helpers/transformData.cjs +2 -2
- package/cjs/helpers/transformData.cjs.map +1 -1
- package/cjs/index.cjs +4 -1
- package/cjs/index.cjs.map +1 -1
- package/package.json +4 -3
- package/src/accessio.ts +126 -10
- package/src/core/accessioError.ts +1 -0
- package/src/core/buildURL.ts +17 -2
- package/src/core/fetchAdapter.ts +227 -0
- package/src/core/mergeConfig.ts +2 -2
- package/src/core/request.ts +100 -250
- package/src/core/retry.ts +26 -6
- package/src/defaults/transforms.ts +4 -1
- package/src/helpers/auth.ts +26 -0
- package/src/helpers/flattenHeaders.ts +59 -0
- package/src/helpers/memoryCache.ts +30 -0
- package/src/helpers/parseHeaders.ts +19 -6
- package/src/helpers/rateLimiter.ts +18 -8
- package/src/helpers/toFormData.ts +25 -0
- package/src/helpers/transformData.ts +4 -4
- package/src/index.ts +4 -1
- package/src/types.ts +32 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/fetchAdapter.ts"],"sourcesContent":["import AccessioError from './accessioError';\nimport parseHeaders from '../helpers/parseHeaders';\nimport type { AccessioRequestConfig, AccessioResponse } from '../types';\n\nasync function readResponseData(\n fetchResponse: Response,\n config: AccessioRequestConfig,\n): Promise<unknown> {\n const responseType = config.responseType || 'json';\n switch (responseType) {\n case 'arraybuffer':\n return await fetchResponse.arrayBuffer();\n case 'blob':\n return await fetchResponse.blob();\n case 'stream':\n return fetchResponse.body;\n case 'json':\n default: {\n const contentType = fetchResponse.headers.get('content-type') || '';\n if (contentType.includes('application/json')) {\n if (typeof fetchResponse.clone === 'function') {\n const text = await fetchResponse.clone().text();\n return text ? await fetchResponse.json() : '';\n } else {\n const text = await fetchResponse.text();\n return text ? JSON.parse(text) : '';\n }\n }\n return await fetchResponse.text();\n }\n }\n}\n\nexport default async function fetchAdapter(\n config: AccessioRequestConfig,\n fullURL: string,\n fetchOptions: RequestInit,\n requestStartTime: number,\n): Promise<AccessioResponse> {\n let abortController: AbortController | null = null;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let isTimedOut = false;\n let onUserAbort: (() => void) | null = null;\n\n if (\n config.timeout !== undefined &&\n (typeof config.timeout !== 'number' || isNaN(config.timeout) || config.timeout < 0)\n ) {\n throw new AccessioError(\n `Invalid timeout value: ${config.timeout}`,\n AccessioError.ERR_BAD_OPTION_VALUE,\n config,\n null,\n null,\n );\n }\n\n const timeoutValue = Number(config.timeout);\n if (!isNaN(timeoutValue) && timeoutValue > 0) {\n abortController = new AbortController();\n\n timeoutId = setTimeout(() => {\n isTimedOut = true;\n abortController!.abort(\n new AccessioError(\n `timeout of ${timeoutValue}ms exceeded`,\n AccessioError.ETIMEDOUT,\n config,\n null,\n null,\n ),\n );\n }, timeoutValue);\n\n if (config.signal) {\n if (typeof AbortSignal.any === 'function') {\n fetchOptions.signal = AbortSignal.any([config.signal, abortController.signal]);\n } else {\n if (config.signal.aborted) {\n abortController.abort(config.signal.reason);\n } else {\n onUserAbort = () => {\n if (!isTimedOut && abortController) {\n abortController.abort(config.signal!.reason);\n }\n };\n config.signal.addEventListener('abort', onUserAbort, {\n once: true,\n });\n }\n fetchOptions.signal = abortController.signal;\n }\n } else {\n fetchOptions.signal = abortController.signal;\n }\n } else if (config.signal) {\n fetchOptions.signal = config.signal;\n }\n\n try {\n const fetchImpl = config.fetch || fetch;\n let fetchResponse = await fetchImpl(fullURL, fetchOptions);\n\n if (config.onDownloadProgress && fetchResponse.body && config.responseType !== 'stream') {\n const contentLength = fetchResponse.headers.get('content-length');\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n let loaded = 0;\n\n const reader = fetchResponse.body.getReader();\n const stream = new ReadableStream({\n async start(controller) {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n break;\n }\n loaded += value.byteLength;\n config.onDownloadProgress!({ loaded, total });\n controller.enqueue(value);\n }\n } catch (e) {\n controller.error(e);\n }\n },\n });\n\n fetchResponse = new Response(stream, {\n headers: fetchResponse.headers,\n status: fetchResponse.status,\n statusText: fetchResponse.statusText,\n });\n }\n\n let responseData: unknown;\n\n const contentLength = fetchResponse.headers.get('content-length');\n if (\n contentLength &&\n config.maxContentLength &&\n parseInt(contentLength, 10) > config.maxContentLength\n ) {\n throw new AccessioError(\n `maxContentLength size of ${config.maxContentLength} exceeded`,\n AccessioError.ERR_BAD_RESPONSE,\n config,\n fetchResponse,\n null,\n );\n }\n\n try {\n responseData = await readResponseData(fetchResponse, config);\n if (config.schema) {\n if (typeof config.schema.parseAsync === 'function') {\n responseData = await config.schema.parseAsync(responseData);\n } else {\n responseData = config.schema.parse(responseData);\n }\n }\n } catch (readError) {\n throw AccessioError.from(\n readError as Error,\n AccessioError.ERR_BAD_RESPONSE,\n config,\n fetchResponse,\n null,\n );\n }\n\n const responseHeaders = parseHeaders(fetchResponse.headers);\n\n return {\n data: responseData,\n status: fetchResponse.status,\n statusText: fetchResponse.statusText,\n headers: responseHeaders,\n config: config,\n request: fetchResponse,\n duration: Date.now() - requestStartTime,\n };\n } catch (error) {\n if (error instanceof AccessioError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === 'AbortError') {\n if (isTimedOut) {\n throw new AccessioError(\n `timeout of ${config.timeout}ms exceeded`,\n AccessioError.ETIMEDOUT,\n config,\n null,\n null,\n );\n }\n throw new AccessioError('Request aborted', AccessioError.ERR_CANCELED, config, null, null);\n }\n\n if (\n error instanceof TypeError &&\n (error.message.toLowerCase().includes('url') || error.message.toLowerCase().includes('fetch'))\n ) {\n throw new AccessioError(\n `Invalid URL: ${fullURL}`,\n AccessioError.ERR_INVALID_URL,\n config,\n null,\n null,\n );\n }\n\n throw AccessioError.from(\n error instanceof Error ? error : new Error(String(error)),\n AccessioError.ERR_NETWORK,\n config,\n null,\n null,\n );\n } finally {\n if (timeoutId) clearTimeout(timeoutId);\n if (config.signal && onUserAbort) {\n config.signal.removeEventListener('abort', onUserAbort);\n }\n }\n}\n"],"mappings":"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","names":["AccessioError","contentLength","parseHeaders"]}
|
package/cjs/core/mergeConfig.cjs
CHANGED
|
@@ -23,7 +23,7 @@ __export(mergeConfig_exports, {
|
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(mergeConfig_exports);
|
|
25
25
|
function deepMerge(...sources) {
|
|
26
|
-
const result =
|
|
26
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
27
27
|
for (const source of sources) {
|
|
28
28
|
if (!source || typeof source !== "object") continue;
|
|
29
29
|
for (const key of Object.keys(source)) {
|
|
@@ -47,7 +47,7 @@ function deepMerge(...sources) {
|
|
|
47
47
|
const requestOnlyKeys = /* @__PURE__ */ new Set(["url", "data", "signal"]);
|
|
48
48
|
const deepMergeKeys = /* @__PURE__ */ new Set(["headers"]);
|
|
49
49
|
function mergeConfig(config1 = {}, config2 = {}) {
|
|
50
|
-
const merged =
|
|
50
|
+
const merged = /* @__PURE__ */ Object.create(null);
|
|
51
51
|
const allKeys = /* @__PURE__ */ new Set([...Object.keys(config1), ...Object.keys(config2)]);
|
|
52
52
|
for (const key of allKeys) {
|
|
53
53
|
const val1 = config1[key];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/mergeConfig.ts"],"sourcesContent":["import type { AccessioRequestConfig } from '../types';\n\nfunction deepMerge(...sources: any[]): Record<string, any> {\n const result: Record<string, any> =
|
|
1
|
+
{"version":3,"sources":["../../src/core/mergeConfig.ts"],"sourcesContent":["import type { AccessioRequestConfig } from '../types';\n\nfunction deepMerge(...sources: any[]): Record<string, any> {\n const result: Record<string, any> = Object.create(null);\n\n for (const source of sources) {\n if (!source || typeof source !== 'object') continue;\n\n for (const key of Object.keys(source)) {\n if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;\n\n const value = source[key];\n\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n if (\n value instanceof Date ||\n value instanceof RegExp ||\n value instanceof Map ||\n value instanceof Set ||\n value instanceof Error ||\n (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) ||\n (typeof Blob !== 'undefined' && value instanceof Blob)\n ) {\n result[key] = value;\n } else if (result[key] && typeof result[key] === 'object' && !Array.isArray(result[key])) {\n result[key] = deepMerge(result[key], value);\n } else {\n result[key] = deepMerge(value);\n }\n } else if (value !== undefined) {\n result[key] = value;\n }\n }\n }\n\n return result;\n}\n\nconst requestOnlyKeys = new Set<string>(['url', 'data', 'signal']);\nconst deepMergeKeys = new Set<string>(['headers']);\n\nexport default function mergeConfig(\n config1: AccessioRequestConfig = {},\n config2: AccessioRequestConfig = {},\n): AccessioRequestConfig {\n const merged: any = Object.create(null);\n\n const allKeys = new Set<string>([...Object.keys(config1), ...Object.keys(config2)]);\n\n for (const key of allKeys) {\n const val1 = config1[key as keyof AccessioRequestConfig];\n const val2 = config2[key as keyof AccessioRequestConfig];\n\n if (requestOnlyKeys.has(key)) {\n if (val2 !== undefined) {\n merged[key] = val2;\n }\n } else if (deepMergeKeys.has(key)) {\n merged[key] = deepMerge(val1 || {}, val2 || {});\n } else {\n merged[key] = val2 !== undefined ? val2 : val1;\n }\n }\n\n return merged;\n}\n\nexport { deepMerge };\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,SAAS,aAAa,SAAqC;AACzD,QAAM,SAA8B,uBAAO,OAAO,IAAI;AAEtD,aAAW,UAAU,SAAS;AAC5B,QAAI,CAAC,UAAU,OAAO,WAAW,SAAU;AAE3C,eAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,UAAI,QAAQ,eAAe,QAAQ,iBAAiB,QAAQ,YAAa;AAEzE,YAAM,QAAQ,OAAO,GAAG;AAExB,UAAI,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC/D,YACE,iBAAiB,QACjB,iBAAiB,UACjB,iBAAiB,OACjB,iBAAiB,OACjB,iBAAiB,SAChB,OAAO,gBAAgB,eAAe,iBAAiB,eACvD,OAAO,SAAS,eAAe,iBAAiB,MACjD;AACA,iBAAO,GAAG,IAAI;AAAA,QAChB,WAAW,OAAO,GAAG,KAAK,OAAO,OAAO,GAAG,MAAM,YAAY,CAAC,MAAM,QAAQ,OAAO,GAAG,CAAC,GAAG;AACxF,iBAAO,GAAG,IAAI,UAAU,OAAO,GAAG,GAAG,KAAK;AAAA,QAC5C,OAAO;AACL,iBAAO,GAAG,IAAI,UAAU,KAAK;AAAA,QAC/B;AAAA,MACF,WAAW,UAAU,QAAW;AAC9B,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEA,MAAM,kBAAkB,oBAAI,IAAY,CAAC,OAAO,QAAQ,QAAQ,CAAC;AACjE,MAAM,gBAAgB,oBAAI,IAAY,CAAC,SAAS,CAAC;AAElC,SAAR,YACL,UAAiC,CAAC,GAClC,UAAiC,CAAC,GACX;AACvB,QAAM,SAAc,uBAAO,OAAO,IAAI;AAEtC,QAAM,UAAU,oBAAI,IAAY,CAAC,GAAG,OAAO,KAAK,OAAO,GAAG,GAAG,OAAO,KAAK,OAAO,CAAC,CAAC;AAElF,aAAW,OAAO,SAAS;AACzB,UAAM,OAAO,QAAQ,GAAkC;AACvD,UAAM,OAAO,QAAQ,GAAkC;AAEvD,QAAI,gBAAgB,IAAI,GAAG,GAAG;AAC5B,UAAI,SAAS,QAAW;AACtB,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF,WAAW,cAAc,IAAI,GAAG,GAAG;AACjC,aAAO,GAAG,IAAI,UAAU,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC;AAAA,IAChD,OAAO;AACL,aAAO,GAAG,IAAI,SAAS,SAAY,OAAO;AAAA,IAC5C;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
|
package/cjs/core/request.cjs
CHANGED
|
@@ -33,190 +33,79 @@ __export(request_exports, {
|
|
|
33
33
|
module.exports = __toCommonJS(request_exports);
|
|
34
34
|
var import_buildURL = __toESM(require("./buildURL"), 1);
|
|
35
35
|
var import_accessioError = __toESM(require("./accessioError"), 1);
|
|
36
|
-
var import_parseHeaders = __toESM(require("../helpers/parseHeaders"), 1);
|
|
37
36
|
var import_transformData = __toESM(require("../helpers/transformData"), 1);
|
|
38
37
|
var import_settle = __toESM(require("../helpers/settle"), 1);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"head",
|
|
44
|
-
"options",
|
|
45
|
-
"post",
|
|
46
|
-
"put",
|
|
47
|
-
"patch"
|
|
48
|
-
]);
|
|
49
|
-
function flattenHeaders(headers, method) {
|
|
50
|
-
if (!headers) return {};
|
|
51
|
-
const merged = {};
|
|
52
|
-
const methodLower = (method || "get").toLowerCase();
|
|
53
|
-
if (headers["common"]) {
|
|
54
|
-
Object.assign(merged, headers["common"]);
|
|
55
|
-
}
|
|
56
|
-
if (headers[methodLower]) {
|
|
57
|
-
Object.assign(merged, headers[methodLower]);
|
|
58
|
-
}
|
|
59
|
-
for (const key in headers) {
|
|
60
|
-
if (Object.prototype.hasOwnProperty.call(headers, key) && !METHOD_KEYS.has(key)) {
|
|
61
|
-
merged[key] = headers[key];
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return merged;
|
|
65
|
-
}
|
|
66
|
-
function removeContentType(headers) {
|
|
67
|
-
const keys = Object.keys(headers).filter((k) => k.toLowerCase() === "content-type");
|
|
68
|
-
for (const key of keys) {
|
|
69
|
-
delete headers[key];
|
|
70
|
-
}
|
|
71
|
-
}
|
|
38
|
+
var import_flattenHeaders = require("../helpers/flattenHeaders");
|
|
39
|
+
var import_auth = require("../helpers/auth");
|
|
40
|
+
var import_fetchAdapter = __toESM(require("./fetchAdapter"), 1);
|
|
41
|
+
var import_memoryCache = require("../helpers/memoryCache");
|
|
72
42
|
function buildTransformArray(transform) {
|
|
73
43
|
if (!transform) return [];
|
|
74
44
|
if (Array.isArray(transform)) return transform;
|
|
75
45
|
return [transform];
|
|
76
46
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const username = config.auth.username || "";
|
|
80
|
-
const password = config.auth.password || "";
|
|
81
|
-
const credentials = `${username}:${password}`;
|
|
82
|
-
let encoded;
|
|
83
|
-
if (typeof Buffer !== "undefined") {
|
|
84
|
-
encoded = Buffer.from(credentials).toString("base64");
|
|
85
|
-
} else {
|
|
86
|
-
encoded = btoa(
|
|
87
|
-
encodeURIComponent(credentials).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
|
88
|
-
return String.fromCharCode(parseInt(p1, 16));
|
|
89
|
-
})
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
headers["Authorization"] = `Basic ${encoded}`;
|
|
93
|
-
}
|
|
94
|
-
async function readResponseData(fetchResponse, responseType) {
|
|
95
|
-
switch (responseType) {
|
|
96
|
-
case "arraybuffer":
|
|
97
|
-
return await fetchResponse.arrayBuffer();
|
|
98
|
-
case "blob":
|
|
99
|
-
return await fetchResponse.blob();
|
|
100
|
-
case "text":
|
|
101
|
-
return await fetchResponse.text();
|
|
102
|
-
case "stream":
|
|
103
|
-
return fetchResponse.body;
|
|
104
|
-
case "json":
|
|
105
|
-
default:
|
|
106
|
-
return await fetchResponse.text();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function dispatchRequest(config) {
|
|
47
|
+
const activeRequests = /* @__PURE__ */ new Map();
|
|
48
|
+
async function dispatchRequest(config) {
|
|
110
49
|
const fullURL = config._builtUrl || (0, import_buildURL.default)(
|
|
111
50
|
config.url ?? "",
|
|
112
51
|
config.baseURL,
|
|
113
52
|
config.params,
|
|
114
53
|
config.paramsSerializer
|
|
115
54
|
);
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const requestData = (0, import_transformData.default)(requestTransforms, config.data, flatHeaders, config);
|
|
119
|
-
if (requestData === null || requestData === void 0 || typeof FormData !== "undefined" && requestData instanceof FormData) {
|
|
120
|
-
removeContentType(flatHeaders);
|
|
121
|
-
}
|
|
122
|
-
setBasicAuth(config, flatHeaders);
|
|
123
|
-
const fetchOptions = {
|
|
124
|
-
method: (config.method || "GET").toUpperCase(),
|
|
125
|
-
headers: flatHeaders
|
|
126
|
-
};
|
|
127
|
-
const methodsWithBody = ["POST", "PUT", "PATCH", "DELETE"];
|
|
128
|
-
if (methodsWithBody.includes(fetchOptions.method) && requestData !== void 0 && requestData !== null) {
|
|
129
|
-
fetchOptions.body = requestData;
|
|
55
|
+
if (config.hooks?.onBeforeRequest) {
|
|
56
|
+
await config.hooks.onBeforeRequest(config);
|
|
130
57
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
let abortController = null;
|
|
141
|
-
let timeoutId = null;
|
|
142
|
-
let isTimedOut = false;
|
|
143
|
-
let onUserAbort = null;
|
|
144
|
-
const timeoutValue = Number(config.timeout);
|
|
145
|
-
if (!isNaN(timeoutValue) && timeoutValue > 0) {
|
|
146
|
-
abortController = new AbortController();
|
|
147
|
-
timeoutId = setTimeout(() => {
|
|
148
|
-
isTimedOut = true;
|
|
149
|
-
abortController.abort(
|
|
150
|
-
new import_accessioError.default(
|
|
151
|
-
`timeout of ${timeoutValue}ms exceeded`,
|
|
152
|
-
import_accessioError.default.ETIMEDOUT,
|
|
153
|
-
config,
|
|
154
|
-
null,
|
|
155
|
-
null
|
|
156
|
-
)
|
|
157
|
-
);
|
|
158
|
-
}, timeoutValue);
|
|
159
|
-
if (config.signal) {
|
|
160
|
-
if (typeof AbortSignal.any === "function") {
|
|
161
|
-
fetchOptions.signal = AbortSignal.any([config.signal, abortController.signal]);
|
|
162
|
-
} else {
|
|
163
|
-
if (config.signal.aborted) {
|
|
164
|
-
abortController.abort(config.signal.reason);
|
|
165
|
-
} else {
|
|
166
|
-
onUserAbort = () => {
|
|
167
|
-
if (!isTimedOut && abortController) {
|
|
168
|
-
abortController.abort(config.signal.reason);
|
|
169
|
-
}
|
|
170
|
-
};
|
|
171
|
-
config.signal.addEventListener("abort", onUserAbort, {
|
|
172
|
-
once: true
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
fetchOptions.signal = abortController.signal;
|
|
58
|
+
const isGet = (config.method || "GET").toUpperCase() === "GET";
|
|
59
|
+
const cacheKey = isGet ? `GET:${fullURL}` : "";
|
|
60
|
+
if (isGet && config.cache) {
|
|
61
|
+
const cacheProvider = typeof config.cache === "object" ? config.cache : import_memoryCache.defaultMemoryCache;
|
|
62
|
+
const cached = await cacheProvider.get(cacheKey);
|
|
63
|
+
if (cached) {
|
|
64
|
+
if (config.hooks?.onRequestResponse) {
|
|
65
|
+
await config.hooks.onRequestResponse(cached);
|
|
176
66
|
}
|
|
177
|
-
|
|
178
|
-
fetchOptions.signal = abortController.signal;
|
|
67
|
+
return cached;
|
|
179
68
|
}
|
|
180
|
-
} else if (config.signal) {
|
|
181
|
-
fetchOptions.signal = config.signal;
|
|
182
69
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const responseType = config.responseType || "json";
|
|
187
|
-
const contentLength = fetchResponse.headers.get("content-length");
|
|
188
|
-
if (contentLength && config.maxContentLength && parseInt(contentLength, 10) > config.maxContentLength) {
|
|
189
|
-
throw new import_accessioError.default(
|
|
190
|
-
`maxContentLength size of ${config.maxContentLength} exceeded`,
|
|
191
|
-
import_accessioError.default.ERR_BAD_RESPONSE,
|
|
192
|
-
config,
|
|
193
|
-
fetchResponse,
|
|
194
|
-
null
|
|
195
|
-
);
|
|
70
|
+
if (isGet && config.dedupe) {
|
|
71
|
+
if (activeRequests.has(cacheKey)) {
|
|
72
|
+
return activeRequests.get(cacheKey);
|
|
196
73
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
fetchResponse,
|
|
205
|
-
null
|
|
206
|
-
);
|
|
74
|
+
}
|
|
75
|
+
const performRequest = async () => {
|
|
76
|
+
const flatHeaders = (0, import_flattenHeaders.flattenHeaders)(config.headers, config.method);
|
|
77
|
+
const requestTransforms = buildTransformArray(config.transformRequest);
|
|
78
|
+
const requestData = await (0, import_transformData.default)(requestTransforms, config.data, flatHeaders, config);
|
|
79
|
+
if (requestData === null || requestData === void 0 || typeof FormData !== "undefined" && requestData instanceof FormData) {
|
|
80
|
+
(0, import_flattenHeaders.removeContentType)(flatHeaders);
|
|
207
81
|
}
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
data: responseData,
|
|
213
|
-
status: fetchResponse.status,
|
|
214
|
-
statusText: fetchResponse.statusText,
|
|
215
|
-
headers: responseHeaders,
|
|
216
|
-
config,
|
|
217
|
-
request: fetchResponse,
|
|
218
|
-
duration: Date.now() - requestStartTime
|
|
82
|
+
(0, import_auth.setBasicAuth)(config, flatHeaders);
|
|
83
|
+
const fetchOptions = {
|
|
84
|
+
method: (config.method || "GET").toUpperCase(),
|
|
85
|
+
headers: (0, import_flattenHeaders.buildFetchHeaders)(flatHeaders)
|
|
219
86
|
};
|
|
87
|
+
const methodsWithBody = ["POST", "PUT", "PATCH", "DELETE"];
|
|
88
|
+
if (methodsWithBody.includes(fetchOptions.method) && requestData !== void 0 && requestData !== null) {
|
|
89
|
+
fetchOptions.body = requestData;
|
|
90
|
+
}
|
|
91
|
+
if (config.withCredentials) {
|
|
92
|
+
fetchOptions.credentials = "include";
|
|
93
|
+
}
|
|
94
|
+
if (config.dispatcher) {
|
|
95
|
+
fetchOptions.dispatcher = config.dispatcher;
|
|
96
|
+
}
|
|
97
|
+
if (config.agent) {
|
|
98
|
+
fetchOptions.agent = config.agent;
|
|
99
|
+
}
|
|
100
|
+
const requestStartTime = Date.now();
|
|
101
|
+
const response = await (0, import_fetchAdapter.default)(config, fullURL, fetchOptions, requestStartTime);
|
|
102
|
+
const responseTransforms = buildTransformArray(config.transformResponse);
|
|
103
|
+
response.data = await (0, import_transformData.default)(
|
|
104
|
+
responseTransforms,
|
|
105
|
+
response.data,
|
|
106
|
+
response.headers,
|
|
107
|
+
config
|
|
108
|
+
);
|
|
220
109
|
return new Promise((resolve, reject) => {
|
|
221
110
|
(0, import_settle.default)(
|
|
222
111
|
resolve,
|
|
@@ -225,43 +114,29 @@ function dispatchRequest(config) {
|
|
|
225
114
|
config
|
|
226
115
|
);
|
|
227
116
|
});
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
throw new import_accessioError.default("Request aborted", import_accessioError.default.ERR_CANCELED, config, null, null);
|
|
117
|
+
};
|
|
118
|
+
const promise = performRequest();
|
|
119
|
+
if (isGet && config.dedupe) {
|
|
120
|
+
activeRequests.set(cacheKey, promise);
|
|
121
|
+
promise.finally(() => {
|
|
122
|
+
activeRequests.delete(cacheKey);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
const response = await promise;
|
|
127
|
+
if (isGet && config.cache) {
|
|
128
|
+
const cacheProvider = typeof config.cache === "object" ? config.cache : import_memoryCache.defaultMemoryCache;
|
|
129
|
+
await cacheProvider.set(cacheKey, response, config.cacheTTL);
|
|
243
130
|
}
|
|
244
|
-
if (
|
|
245
|
-
|
|
246
|
-
`Invalid URL: ${fullURL}`,
|
|
247
|
-
import_accessioError.default.ERR_INVALID_URL,
|
|
248
|
-
config,
|
|
249
|
-
null,
|
|
250
|
-
null
|
|
251
|
-
);
|
|
131
|
+
if (config.hooks?.onRequestResponse) {
|
|
132
|
+
await config.hooks.onRequestResponse(response);
|
|
252
133
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
config
|
|
257
|
-
null,
|
|
258
|
-
null
|
|
259
|
-
);
|
|
260
|
-
}).finally(() => {
|
|
261
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
262
|
-
if (config.signal && onUserAbort) {
|
|
263
|
-
config.signal.removeEventListener("abort", onUserAbort);
|
|
134
|
+
return response;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
if (config.hooks?.onRequestError && error instanceof import_accessioError.default) {
|
|
137
|
+
await config.hooks.onRequestError(error);
|
|
264
138
|
}
|
|
265
|
-
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
266
141
|
}
|
|
267
142
|
//# sourceMappingURL=request.cjs.map
|
package/cjs/core/request.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/request.ts"],"sourcesContent":["import buildURL from './buildURL';\nimport AccessioError from './accessioError';\nimport parseHeaders from '../helpers/parseHeaders';\nimport transformData from '../helpers/transformData';\nimport settle from '../helpers/settle';\nimport type { AccessioRequestConfig, AccessioResponse, TransformFunction } from '../types';\n\nconst METHOD_KEYS = new Set<string>([\n 'common',\n 'delete',\n 'get',\n 'head',\n 'options',\n 'post',\n 'put',\n 'patch',\n]);\n\ntype HeadersConfig = Record<string, Record<string, string>>;\n\nfunction flattenHeaders(\n headers: HeadersConfig | undefined,\n method?: string,\n): Record<string, string> {\n if (!headers) return {};\n\n const merged: Record<string, string> = {};\n const methodLower = (method || 'get').toLowerCase();\n\n if (headers['common']) {\n Object.assign(merged, headers['common']);\n }\n\n if (headers[methodLower]) {\n Object.assign(merged, headers[methodLower]);\n }\n\n for (const key in headers) {\n if (Object.prototype.hasOwnProperty.call(headers, key) && !METHOD_KEYS.has(key)) {\n merged[key] = headers[key] as unknown as string;\n }\n }\n\n return merged;\n}\n\nfunction removeContentType(headers: Record<string, string>): void {\n const keys = Object.keys(headers).filter((k) => k.toLowerCase() === 'content-type');\n for (const key of keys) {\n delete headers[key];\n }\n}\n\nfunction buildTransformArray(\n transform: TransformFunction | TransformFunction[] | undefined,\n): TransformFunction[] {\n if (!transform) return [];\n if (Array.isArray(transform)) return transform;\n return [transform];\n}\n\nfunction setBasicAuth(config: AccessioRequestConfig, headers: Record<string, string>): void {\n if (!config.auth) return;\n const username = config.auth.username || '';\n const password = config.auth.password || '';\n const credentials = `${username}:${password}`;\n\n let encoded: string;\n if (typeof Buffer !== 'undefined') {\n encoded = Buffer.from(credentials).toString('base64');\n } else {\n encoded = btoa(\n encodeURIComponent(credentials).replace(/%([0-9A-F]{2})/g, (match, p1) => {\n return String.fromCharCode(parseInt(p1, 16));\n }),\n );\n }\n headers['Authorization'] = `Basic ${encoded}`;\n}\n\nasync function readResponseData(fetchResponse: Response, responseType: string): Promise<unknown> {\n switch (responseType) {\n case 'arraybuffer':\n return await fetchResponse.arrayBuffer();\n case 'blob':\n return await fetchResponse.blob();\n case 'text':\n return await fetchResponse.text();\n case 'stream':\n return fetchResponse.body;\n case 'json':\n default:\n return await fetchResponse.text();\n }\n}\n\nexport default function dispatchRequest(config: AccessioRequestConfig): Promise<AccessioResponse> {\n const fullURL =\n config._builtUrl ||\n buildURL(\n config.url ?? '',\n config.baseURL,\n config.params as Record<string, unknown> | undefined,\n config.paramsSerializer,\n );\n\n const flatHeaders = flattenHeaders(config.headers as HeadersConfig | undefined, config.method);\n\n const requestTransforms = buildTransformArray(config.transformRequest);\n\n const requestData = transformData(requestTransforms, config.data, flatHeaders, config);\n\n if (\n requestData === null ||\n requestData === undefined ||\n (typeof FormData !== 'undefined' && requestData instanceof FormData)\n ) {\n removeContentType(flatHeaders);\n }\n\n setBasicAuth(config, flatHeaders);\n\n const fetchOptions: RequestInit = {\n method: (config.method || 'GET').toUpperCase(),\n headers: flatHeaders,\n };\n\n const methodsWithBody = ['POST', 'PUT', 'PATCH', 'DELETE'];\n if (\n methodsWithBody.includes(fetchOptions.method!) &&\n requestData !== undefined &&\n requestData !== null\n ) {\n fetchOptions.body = requestData as BodyInit;\n }\n\n if (config.withCredentials) {\n fetchOptions.credentials = 'include';\n }\n\n if (config.dispatcher) {\n (fetchOptions as any).dispatcher = config.dispatcher;\n }\n if (config.agent) {\n (fetchOptions as any).agent = config.agent;\n }\n\n let abortController: AbortController | null = null;\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n let isTimedOut = false;\n let onUserAbort: (() => void) | null = null;\n\n const timeoutValue = Number(config.timeout);\n if (!isNaN(timeoutValue) && timeoutValue > 0) {\n abortController = new AbortController();\n\n timeoutId = setTimeout(() => {\n isTimedOut = true;\n abortController!.abort(\n new AccessioError(\n `timeout of ${timeoutValue}ms exceeded`,\n AccessioError.ETIMEDOUT,\n config,\n null,\n null,\n ),\n );\n }, timeoutValue);\n\n if (config.signal) {\n if (typeof AbortSignal.any === 'function') {\n fetchOptions.signal = AbortSignal.any([config.signal, abortController.signal]);\n } else {\n if (config.signal.aborted) {\n abortController.abort(config.signal.reason);\n } else {\n onUserAbort = () => {\n if (!isTimedOut && abortController) {\n abortController.abort(config.signal!.reason);\n }\n };\n config.signal.addEventListener('abort', onUserAbort, {\n once: true,\n });\n }\n fetchOptions.signal = abortController.signal;\n }\n } else {\n fetchOptions.signal = abortController.signal;\n }\n } else if (config.signal) {\n fetchOptions.signal = config.signal;\n }\n\n const requestStartTime = Date.now();\n\n return fetch(fullURL, fetchOptions)\n .then(async (fetchResponse) => {\n let responseData: unknown;\n const responseType = config.responseType || 'json';\n\n const contentLength = fetchResponse.headers.get('content-length');\n if (\n contentLength &&\n config.maxContentLength &&\n parseInt(contentLength, 10) > config.maxContentLength\n ) {\n throw new AccessioError(\n `maxContentLength size of ${config.maxContentLength} exceeded`,\n AccessioError.ERR_BAD_RESPONSE,\n config,\n fetchResponse,\n null,\n );\n }\n\n try {\n responseData = await readResponseData(fetchResponse, responseType);\n } catch (readError) {\n throw AccessioError.from(\n readError as Error,\n AccessioError.ERR_BAD_RESPONSE,\n config,\n fetchResponse,\n null,\n );\n }\n\n const responseHeaders = parseHeaders(fetchResponse.headers);\n\n const responseTransforms = buildTransformArray(config.transformResponse);\n\n responseData = transformData(responseTransforms, responseData, responseHeaders, config);\n\n const response: AccessioResponse = {\n data: responseData,\n status: fetchResponse.status,\n statusText: fetchResponse.statusText,\n headers: responseHeaders,\n config: config,\n request: fetchResponse,\n duration: Date.now() - requestStartTime,\n };\n\n return new Promise<AccessioResponse>((resolve, reject) => {\n settle(\n resolve as (value: AccessioResponse) => void,\n reject as (reason: AccessioError) => void,\n response,\n config,\n );\n });\n })\n .catch((error) => {\n if (error instanceof AccessioError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === 'AbortError') {\n if (isTimedOut) {\n throw new AccessioError(\n `timeout of ${config.timeout}ms exceeded`,\n AccessioError.ETIMEDOUT,\n config,\n null,\n null,\n );\n }\n throw new AccessioError('Request aborted', AccessioError.ERR_CANCELED, config, null, null);\n }\n\n if (\n error instanceof TypeError &&\n (error.message.toLowerCase().includes('url') ||\n error.message.toLowerCase().includes('fetch'))\n ) {\n throw new AccessioError(\n `Invalid URL: ${fullURL}`,\n AccessioError.ERR_INVALID_URL,\n config,\n null,\n null,\n );\n }\n\n throw AccessioError.from(\n error instanceof Error ? error : new Error(String(error)),\n AccessioError.ERR_NETWORK,\n config,\n null,\n null,\n );\n })\n .finally(() => {\n if (timeoutId) clearTimeout(timeoutId);\n if (config.signal && onUserAbort) {\n config.signal.removeEventListener('abort', onUserAbort);\n }\n });\n}\n"],"mappings":"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","names":["buildURL","transformData","AccessioError","parseHeaders","settle"]}
|
|
1
|
+
{"version":3,"sources":["../../src/core/request.ts"],"sourcesContent":["import buildURL from './buildURL';\nimport AccessioError from './accessioError';\nimport transformData from '../helpers/transformData';\nimport settle from '../helpers/settle';\nimport { flattenHeaders, removeContentType, buildFetchHeaders } from '../helpers/flattenHeaders';\nimport { setBasicAuth } from '../helpers/auth';\nimport fetchAdapter from './fetchAdapter';\nimport { defaultMemoryCache } from '../helpers/memoryCache';\nimport type { AccessioRequestConfig, AccessioResponse, TransformFunction } from '../types';\n\ntype HeadersConfig = Record<string, Record<string, string | string[]>>;\n\nfunction buildTransformArray(\n transform: TransformFunction | TransformFunction[] | undefined,\n): TransformFunction[] {\n if (!transform) return [];\n if (Array.isArray(transform)) return transform;\n return [transform];\n}\n\nconst activeRequests = new Map<string, Promise<AccessioResponse>>();\n\nexport default async function dispatchRequest(\n config: AccessioRequestConfig,\n): Promise<AccessioResponse> {\n const fullURL =\n config._builtUrl ||\n buildURL(\n config.url ?? '',\n config.baseURL,\n config.params as Record<string, unknown> | undefined,\n config.paramsSerializer,\n );\n\n if (config.hooks?.onBeforeRequest) {\n await config.hooks.onBeforeRequest(config);\n }\n\n const isGet = (config.method || 'GET').toUpperCase() === 'GET';\n const cacheKey = isGet ? `GET:${fullURL}` : '';\n\n if (isGet && config.cache) {\n const cacheProvider = typeof config.cache === 'object' ? config.cache : defaultMemoryCache;\n const cached = await cacheProvider.get(cacheKey);\n if (cached) {\n if (config.hooks?.onRequestResponse) {\n await config.hooks.onRequestResponse(cached);\n }\n return cached;\n }\n }\n\n if (isGet && config.dedupe) {\n if (activeRequests.has(cacheKey)) {\n return activeRequests.get(cacheKey)!;\n }\n }\n\n const performRequest = async () => {\n const flatHeaders = flattenHeaders(config.headers as HeadersConfig | undefined, config.method);\n const requestTransforms = buildTransformArray(config.transformRequest);\n const requestData = await transformData(requestTransforms, config.data, flatHeaders, config);\n\n if (\n requestData === null ||\n requestData === undefined ||\n (typeof FormData !== 'undefined' && requestData instanceof FormData)\n ) {\n removeContentType(flatHeaders);\n }\n\n setBasicAuth(config, flatHeaders);\n\n const fetchOptions: RequestInit = {\n method: (config.method || 'GET').toUpperCase(),\n headers: buildFetchHeaders(flatHeaders),\n };\n\n const methodsWithBody = ['POST', 'PUT', 'PATCH', 'DELETE'];\n if (\n methodsWithBody.includes(fetchOptions.method!) &&\n requestData !== undefined &&\n requestData !== null\n ) {\n fetchOptions.body = requestData as BodyInit;\n }\n\n if (config.withCredentials) {\n fetchOptions.credentials = 'include';\n }\n\n if (config.dispatcher) {\n (fetchOptions as any).dispatcher = config.dispatcher;\n }\n if (config.agent) {\n (fetchOptions as any).agent = config.agent;\n }\n\n const requestStartTime = Date.now();\n\n const response = await fetchAdapter(config, fullURL, fetchOptions, requestStartTime);\n\n const responseTransforms = buildTransformArray(config.transformResponse);\n\n response.data = await transformData(\n responseTransforms,\n response.data,\n response.headers,\n config,\n );\n\n return new Promise<AccessioResponse>((resolve, reject) => {\n settle(\n resolve as (value: AccessioResponse) => void,\n reject as (reason: AccessioError) => void,\n response,\n config,\n );\n });\n };\n\n const promise = performRequest();\n\n if (isGet && config.dedupe) {\n activeRequests.set(cacheKey, promise);\n promise.finally(() => {\n activeRequests.delete(cacheKey);\n });\n }\n\n try {\n const response = await promise;\n\n if (isGet && config.cache) {\n const cacheProvider = typeof config.cache === 'object' ? config.cache : defaultMemoryCache;\n await cacheProvider.set(cacheKey, response, config.cacheTTL);\n }\n\n if (config.hooks?.onRequestResponse) {\n await config.hooks.onRequestResponse(response);\n }\n\n return response;\n } catch (error) {\n if (config.hooks?.onRequestError && error instanceof AccessioError) {\n await config.hooks.onRequestError(error);\n }\n throw error;\n }\n}\n"],"mappings":"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","names":["buildURL","transformData","fetchAdapter","settle","AccessioError"]}
|
package/cjs/core/retry.cjs
CHANGED
|
@@ -34,6 +34,9 @@ function defaultRetryCondition(error) {
|
|
|
34
34
|
if (error.response && error.response.status >= 500) {
|
|
35
35
|
return true;
|
|
36
36
|
}
|
|
37
|
+
if (error.config?.retryOn429 && error.response && error.response.status === 429) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
37
40
|
return false;
|
|
38
41
|
}
|
|
39
42
|
function calculateDelay(attempt, baseDelay) {
|
|
@@ -65,24 +68,40 @@ function sleep(ms, options) {
|
|
|
65
68
|
}
|
|
66
69
|
async function retryRequest(dispatchFn, config) {
|
|
67
70
|
const maxRetries = config.retry ?? 0;
|
|
68
|
-
if (maxRetries <= 0) {
|
|
71
|
+
if (maxRetries <= 0 && !config.retryOn429) {
|
|
69
72
|
return dispatchFn(config);
|
|
70
73
|
}
|
|
71
74
|
const retryDelay = config.retryDelay ?? 1e3;
|
|
72
75
|
const retryCondition = config.retryCondition ?? defaultRetryCondition;
|
|
73
76
|
let lastError;
|
|
74
|
-
|
|
77
|
+
const actualMaxRetries = Math.max(maxRetries, config.retryOn429 ? 3 : 0);
|
|
78
|
+
for (let attempt = 0; attempt <= actualMaxRetries; attempt++) {
|
|
75
79
|
try {
|
|
76
80
|
const response = await dispatchFn(config);
|
|
77
81
|
return response;
|
|
78
82
|
} catch (error) {
|
|
79
83
|
lastError = error;
|
|
80
|
-
const isLastAttempt = attempt >=
|
|
84
|
+
const isLastAttempt = attempt >= actualMaxRetries;
|
|
81
85
|
const shouldRetry = !isLastAttempt && retryCondition(error);
|
|
82
86
|
if (!shouldRetry) {
|
|
83
87
|
throw error;
|
|
84
88
|
}
|
|
85
|
-
|
|
89
|
+
let delay = calculateDelay(attempt, retryDelay);
|
|
90
|
+
if (config.retryOn429 && error.response?.status === 429) {
|
|
91
|
+
const headers = error.response?.headers;
|
|
92
|
+
const retryAfterStr = headers?.["retry-after"] || headers?.["Retry-After"];
|
|
93
|
+
if (retryAfterStr) {
|
|
94
|
+
const parsed = parseInt(retryAfterStr, 10);
|
|
95
|
+
if (!isNaN(parsed)) {
|
|
96
|
+
delay = parsed * 1e3;
|
|
97
|
+
} else {
|
|
98
|
+
const date = new Date(retryAfterStr);
|
|
99
|
+
if (!isNaN(date.getTime())) {
|
|
100
|
+
delay = Math.max(0, date.getTime() - Date.now());
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
86
105
|
if (typeof config.onRetry === "function") {
|
|
87
106
|
config.onRetry(attempt + 1, error, config);
|
|
88
107
|
}
|
package/cjs/core/retry.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/retry.ts"],"sourcesContent":["import { ERR_CANCELED, ERR_NETWORK
|
|
1
|
+
{"version":3,"sources":["../../src/core/retry.ts"],"sourcesContent":["import { ERR_CANCELED, ERR_NETWORK } from '../constants/errorCodes';\nimport type {\n AccessioRequestConfig,\n AccessioError,\n RetryConditionFunction,\n OnRetryFunction,\n} from '../types';\n\nfunction defaultRetryCondition(error: any): boolean {\n if (error.code === ERR_CANCELED) {\n return false;\n }\n\n if (error.code === ERR_NETWORK) {\n return true;\n }\n\n if (error.response && error.response.status >= 500) {\n return true;\n }\n\n if (error.config?.retryOn429 && error.response && error.response.status === 429) {\n return true;\n }\n\n return false;\n}\n\nfunction calculateDelay(attempt: number, baseDelay: number): number {\n const exponentialDelay = baseDelay * Math.pow(2, attempt);\n const jitter = exponentialDelay * 0.25 * (Math.random() * 2 - 1);\n return Math.round(exponentialDelay + jitter);\n}\n\nfunction sleep(ms: number, options?: { signal?: AbortSignal }): Promise<void> {\n return new Promise((resolve, reject) => {\n let onAbort: (() => void) | undefined;\n\n const timeoutId = setTimeout(() => {\n if (options?.signal && onAbort) {\n options.signal.removeEventListener('abort', onAbort);\n }\n resolve();\n }, ms);\n\n if (options?.signal) {\n if (options.signal.aborted) {\n clearTimeout(timeoutId);\n return reject(options.signal.reason || new Error('Sleep aborted'));\n }\n\n onAbort = () => {\n clearTimeout(timeoutId);\n reject(options.signal!.reason || new Error('Sleep aborted'));\n };\n\n options.signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n}\n\nasync function retryRequest(\n dispatchFn: (config: AccessioRequestConfig) => Promise<any>,\n config: AccessioRequestConfig,\n): Promise<any> {\n const maxRetries = config.retry ?? 0;\n\n if (maxRetries <= 0 && !config.retryOn429) {\n return dispatchFn(config);\n }\n\n const retryDelay = config.retryDelay ?? 1000;\n const retryCondition: RetryConditionFunction = config.retryCondition ?? defaultRetryCondition;\n\n let lastError: any;\n const actualMaxRetries = Math.max(maxRetries, config.retryOn429 ? 3 : 0);\n\n for (let attempt = 0; attempt <= actualMaxRetries; attempt++) {\n try {\n const response = await dispatchFn(config);\n return response;\n } catch (error) {\n lastError = error;\n\n const isLastAttempt = attempt >= actualMaxRetries;\n const shouldRetry = !isLastAttempt && retryCondition(error as AccessioError);\n\n if (!shouldRetry) {\n throw error;\n }\n\n let delay = calculateDelay(attempt, retryDelay);\n\n if (config.retryOn429 && (error as any).response?.status === 429) {\n const headers = (error as any).response?.headers;\n const retryAfterStr = headers?.['retry-after'] || headers?.['Retry-After'];\n if (retryAfterStr) {\n const parsed = parseInt(retryAfterStr, 10);\n if (!isNaN(parsed)) {\n delay = parsed * 1000;\n } else {\n const date = new Date(retryAfterStr);\n if (!isNaN(date.getTime())) {\n delay = Math.max(0, date.getTime() - Date.now());\n }\n }\n }\n }\n\n if (typeof config.onRetry === 'function') {\n (config.onRetry as OnRetryFunction)(attempt + 1, error as AccessioError, config);\n }\n\n await sleep(delay, { signal: config.signal });\n }\n }\n\n throw lastError;\n}\n\nexport { defaultRetryCondition, calculateDelay };\nexport default retryRequest;\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/defaults/transforms.ts"],"sourcesContent":["export function defaultTransformRequest(data: unknown
|
|
1
|
+
{"version":3,"sources":["../../src/defaults/transforms.ts"],"sourcesContent":["export function defaultTransformRequest(\n data: unknown,\n headers: Record<string, string | string[]>,\n): unknown {\n if (data === null || data === undefined) {\n return data;\n }\n\n if (\n typeof data === 'string' ||\n data instanceof ArrayBuffer ||\n (typeof Blob !== 'undefined' && data instanceof Blob) ||\n (typeof FormData !== 'undefined' && data instanceof FormData) ||\n (typeof URLSearchParams !== 'undefined' && data instanceof URLSearchParams) ||\n (typeof ReadableStream !== 'undefined' && data instanceof ReadableStream)\n ) {\n return data;\n }\n\n if (typeof data === 'object') {\n if (headers && typeof headers === 'object') {\n const hasContentType = Object.keys(headers).some(\n (key) => key.toLowerCase() === 'content-type',\n );\n if (!hasContentType) {\n headers['Content-Type'] = 'application/json';\n }\n }\n try {\n return JSON.stringify(data);\n } catch (e: any) {\n if (e instanceof TypeError && e.message.toLowerCase().includes('circular')) {\n throw new Error('Accessio: Cannot stringify circular structure in request data');\n }\n throw e;\n }\n }\n\n return data;\n}\n\nexport function defaultTransformResponse(data: unknown): unknown {\n if (typeof data === 'string') {\n try {\n return JSON.parse(data);\n } catch {\n // Not JSON — return as-is\n }\n }\n return data;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,wBACd,MACA,SACS;AACT,MAAI,SAAS,QAAQ,SAAS,QAAW;AACvC,WAAO;AAAA,EACT;AAEA,MACE,OAAO,SAAS,YAChB,gBAAgB,eACf,OAAO,SAAS,eAAe,gBAAgB,QAC/C,OAAO,aAAa,eAAe,gBAAgB,YACnD,OAAO,oBAAoB,eAAe,gBAAgB,mBAC1D,OAAO,mBAAmB,eAAe,gBAAgB,gBAC1D;AACA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,SAAS,UAAU;AAC5B,QAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,YAAM,iBAAiB,OAAO,KAAK,OAAO,EAAE;AAAA,QAC1C,CAAC,QAAQ,IAAI,YAAY,MAAM;AAAA,MACjC;AACA,UAAI,CAAC,gBAAgB;AACnB,gBAAQ,cAAc,IAAI;AAAA,MAC5B;AAAA,IACF;AACA,QAAI;AACF,aAAO,KAAK,UAAU,IAAI;AAAA,IAC5B,SAAS,GAAQ;AACf,UAAI,aAAa,aAAa,EAAE,QAAQ,YAAY,EAAE,SAAS,UAAU,GAAG;AAC1E,cAAM,IAAI,MAAM,+DAA+D;AAAA,MACjF;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,yBAAyB,MAAwB;AAC/D,MAAI,OAAO,SAAS,UAAU;AAC5B,QAAI;AACF,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var auth_exports = {};
|
|
20
|
+
__export(auth_exports, {
|
|
21
|
+
setBasicAuth: () => setBasicAuth
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(auth_exports);
|
|
24
|
+
function setBasicAuth(config, headers) {
|
|
25
|
+
if (!config.auth) return;
|
|
26
|
+
const username = config.auth.username || "";
|
|
27
|
+
const password = config.auth.password || "";
|
|
28
|
+
const credentials = `${username}:${password}`;
|
|
29
|
+
let encoded;
|
|
30
|
+
if (typeof Buffer !== "undefined") {
|
|
31
|
+
encoded = Buffer.from(credentials).toString("base64");
|
|
32
|
+
} else {
|
|
33
|
+
encoded = btoa(
|
|
34
|
+
encodeURIComponent(credentials).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
|
35
|
+
return String.fromCharCode(parseInt(p1, 16));
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
headers["Authorization"] = `Basic ${encoded}`;
|
|
40
|
+
}
|
|
41
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
42
|
+
0 && (module.exports = {
|
|
43
|
+
setBasicAuth
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=auth.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/auth.ts"],"sourcesContent":["import type { AccessioRequestConfig } from '../types';\n\nexport function setBasicAuth(\n config: AccessioRequestConfig,\n headers: Record<string, string | string[]>,\n): void {\n if (!config.auth) return;\n const username = config.auth.username || '';\n const password = config.auth.password || '';\n const credentials = `${username}:${password}`;\n\n let encoded: string;\n if (typeof Buffer !== 'undefined') {\n encoded = Buffer.from(credentials).toString('base64');\n } else {\n // Cryptic but effective UTF-8 to Base64 conversion for browsers lacking Buffer.\n // encodeURIComponent converts non-ASCII to %XX, then we replace %XX with raw bytes\n // before applying btoa.\n encoded = btoa(\n encodeURIComponent(credentials).replace(/%([0-9A-F]{2})/g, (match, p1) => {\n return String.fromCharCode(parseInt(p1, 16));\n }),\n );\n }\n headers['Authorization'] = `Basic ${encoded}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,SAAS,aACd,QACA,SACM;AACN,MAAI,CAAC,OAAO,KAAM;AAClB,QAAM,WAAW,OAAO,KAAK,YAAY;AACzC,QAAM,WAAW,OAAO,KAAK,YAAY;AACzC,QAAM,cAAc,GAAG,QAAQ,IAAI,QAAQ;AAE3C,MAAI;AACJ,MAAI,OAAO,WAAW,aAAa;AACjC,cAAU,OAAO,KAAK,WAAW,EAAE,SAAS,QAAQ;AAAA,EACtD,OAAO;AAIL,cAAU;AAAA,MACR,mBAAmB,WAAW,EAAE,QAAQ,mBAAmB,CAAC,OAAO,OAAO;AACxE,eAAO,OAAO,aAAa,SAAS,IAAI,EAAE,CAAC;AAAA,MAC7C,CAAC;AAAA,IACH;AAAA,EACF;AACA,UAAQ,eAAe,IAAI,SAAS,OAAO;AAC7C;","names":[]}
|