accessio 1.1.2 → 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 +95 -0
- package/cjs/accessio.cjs +59 -3
- 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 +15 -1
- package/cjs/core/buildURL.cjs.map +1 -1
- package/cjs/core/fetchAdapter.cjs +41 -4
- package/cjs/core/fetchAdapter.cjs.map +1 -1
- package/cjs/core/request.cjs +84 -31
- 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/helpers/memoryCache.cjs +51 -0
- package/cjs/helpers/memoryCache.cjs.map +1 -0
- package/cjs/helpers/toFormData.cjs +50 -0
- package/cjs/helpers/toFormData.cjs.map +1 -0
- package/cjs/index.cjs +4 -1
- package/cjs/index.cjs.map +1 -1
- package/package.json +3 -2
- package/src/accessio.ts +81 -3
- package/src/core/accessioError.ts +1 -0
- package/src/core/buildURL.ts +16 -1
- package/src/core/fetchAdapter.ts +47 -4
- package/src/core/request.ts +105 -44
- package/src/core/retry.ts +26 -6
- package/src/helpers/memoryCache.ts +30 -0
- package/src/helpers/toFormData.ts +25 -0
- package/src/index.ts +4 -1
- package/src/types.ts +26 -0
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 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 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\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 const flatHeaders = flattenHeaders(config.headers as HeadersConfig | undefined, config.method);\n
|
|
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":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
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 memoryCache_exports = {};
|
|
20
|
+
__export(memoryCache_exports, {
|
|
21
|
+
defaultMemoryCache: () => defaultMemoryCache
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(memoryCache_exports);
|
|
24
|
+
class MemoryCache {
|
|
25
|
+
cache = /* @__PURE__ */ new Map();
|
|
26
|
+
get(key) {
|
|
27
|
+
const item = this.cache.get(key);
|
|
28
|
+
if (!item) return null;
|
|
29
|
+
if (item.expiry && Date.now() > item.expiry) {
|
|
30
|
+
this.cache.delete(key);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return item.value;
|
|
34
|
+
}
|
|
35
|
+
set(key, value, ttl) {
|
|
36
|
+
const expiry = ttl ? Date.now() + ttl : null;
|
|
37
|
+
this.cache.set(key, { value, expiry });
|
|
38
|
+
}
|
|
39
|
+
delete(key) {
|
|
40
|
+
this.cache.delete(key);
|
|
41
|
+
}
|
|
42
|
+
clear() {
|
|
43
|
+
this.cache.clear();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const defaultMemoryCache = new MemoryCache();
|
|
47
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
48
|
+
0 && (module.exports = {
|
|
49
|
+
defaultMemoryCache
|
|
50
|
+
});
|
|
51
|
+
//# sourceMappingURL=memoryCache.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/memoryCache.ts"],"sourcesContent":["import type { CacheProvider } from '../types';\n\nclass MemoryCache implements CacheProvider {\n private cache = new Map<string, { value: any; expiry: number | null }>();\n\n get(key: string) {\n const item = this.cache.get(key);\n if (!item) return null;\n if (item.expiry && Date.now() > item.expiry) {\n this.cache.delete(key);\n return null;\n }\n return item.value;\n }\n\n set(key: string, value: any, ttl?: number) {\n const expiry = ttl ? Date.now() + ttl : null;\n this.cache.set(key, { value, expiry });\n }\n\n delete(key: string) {\n this.cache.delete(key);\n }\n\n clear() {\n this.cache.clear();\n }\n}\n\nexport const defaultMemoryCache = new MemoryCache();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,MAAM,YAAqC;AAAA,EACjC,QAAQ,oBAAI,IAAmD;AAAA,EAEvE,IAAI,KAAa;AACf,UAAM,OAAO,KAAK,MAAM,IAAI,GAAG;AAC/B,QAAI,CAAC,KAAM,QAAO;AAClB,QAAI,KAAK,UAAU,KAAK,IAAI,IAAI,KAAK,QAAQ;AAC3C,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,KAAa,OAAY,KAAc;AACzC,UAAM,SAAS,MAAM,KAAK,IAAI,IAAI,MAAM;AACxC,SAAK,MAAM,IAAI,KAAK,EAAE,OAAO,OAAO,CAAC;AAAA,EACvC;AAAA,EAEA,OAAO,KAAa;AAClB,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,QAAQ;AACN,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;AAEO,MAAM,qBAAqB,IAAI,YAAY;","names":[]}
|
|
@@ -0,0 +1,50 @@
|
|
|
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 toFormData_exports = {};
|
|
20
|
+
__export(toFormData_exports, {
|
|
21
|
+
toFormData: () => toFormData
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(toFormData_exports);
|
|
24
|
+
function toFormData(obj, form, namespace) {
|
|
25
|
+
const fd = form || new FormData();
|
|
26
|
+
let formKey;
|
|
27
|
+
if (obj === null || obj === void 0) {
|
|
28
|
+
return fd;
|
|
29
|
+
}
|
|
30
|
+
if (obj instanceof Date) {
|
|
31
|
+
fd.append(namespace || "", obj.toISOString());
|
|
32
|
+
} else if (typeof obj === "object" && !(obj instanceof File) && !(obj instanceof Blob)) {
|
|
33
|
+
Object.keys(obj).forEach((key) => {
|
|
34
|
+
if (Array.isArray(obj)) {
|
|
35
|
+
formKey = namespace ? `${namespace}[${key}]` : key;
|
|
36
|
+
} else {
|
|
37
|
+
formKey = namespace ? `${namespace}.${key}` : key;
|
|
38
|
+
}
|
|
39
|
+
toFormData(obj[key], fd, formKey);
|
|
40
|
+
});
|
|
41
|
+
} else {
|
|
42
|
+
fd.append(namespace || "", obj);
|
|
43
|
+
}
|
|
44
|
+
return fd;
|
|
45
|
+
}
|
|
46
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
47
|
+
0 && (module.exports = {
|
|
48
|
+
toFormData
|
|
49
|
+
});
|
|
50
|
+
//# sourceMappingURL=toFormData.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/helpers/toFormData.ts"],"sourcesContent":["export function toFormData(obj: any, form?: FormData, namespace?: string): FormData {\n const fd = form || new FormData();\n let formKey: string;\n\n if (obj === null || obj === undefined) {\n return fd;\n }\n\n if (obj instanceof Date) {\n fd.append(namespace || '', obj.toISOString());\n } else if (typeof obj === 'object' && !(obj instanceof File) && !(obj instanceof Blob)) {\n Object.keys(obj).forEach((key) => {\n if (Array.isArray(obj)) {\n formKey = namespace ? `${namespace}[${key}]` : key;\n } else {\n formKey = namespace ? `${namespace}.${key}` : key;\n }\n toFormData(obj[key], fd, formKey);\n });\n } else {\n fd.append(namespace || '', obj);\n }\n\n return fd;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,WAAW,KAAU,MAAiB,WAA8B;AAClF,QAAM,KAAK,QAAQ,IAAI,SAAS;AAChC,MAAI;AAEJ,MAAI,QAAQ,QAAQ,QAAQ,QAAW;AACrC,WAAO;AAAA,EACT;AAEA,MAAI,eAAe,MAAM;AACvB,OAAG,OAAO,aAAa,IAAI,IAAI,YAAY,CAAC;AAAA,EAC9C,WAAW,OAAO,QAAQ,YAAY,EAAE,eAAe,SAAS,EAAE,eAAe,OAAO;AACtF,WAAO,KAAK,GAAG,EAAE,QAAQ,CAAC,QAAQ;AAChC,UAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,kBAAU,YAAY,GAAG,SAAS,IAAI,GAAG,MAAM;AAAA,MACjD,OAAO;AACL,kBAAU,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AAAA,MAChD;AACA,iBAAW,IAAI,GAAG,GAAG,IAAI,OAAO;AAAA,IAClC,CAAC;AAAA,EACH,OAAO;AACL,OAAG,OAAO,aAAa,IAAI,GAAG;AAAA,EAChC;AAEA,SAAO;AACT;","names":[]}
|
package/cjs/index.cjs
CHANGED
package/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import Accessio from './accessio';\nimport defaults from './defaults';\nimport AccessioError from './core/accessioError';\nimport mergeConfig from './core/mergeConfig';\nimport buildURL from './core/buildURL';\nimport InterceptorManager from './interceptors/interceptorManager';\nimport { createRateLimiter } from './helpers/rateLimiter';\nimport { logRequest, logResponse, logError } from './helpers/debug';\nimport { ERR_CANCELED } from './constants/errorCodes';\nimport type { AccessioRequestConfig
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import Accessio from './accessio';\nimport defaults from './defaults';\nimport AccessioError from './core/accessioError';\nimport mergeConfig from './core/mergeConfig';\nimport buildURL from './core/buildURL';\nimport InterceptorManager from './interceptors/interceptorManager';\nimport { createRateLimiter } from './helpers/rateLimiter';\nimport { logRequest, logResponse, logError } from './helpers/debug';\nimport { ERR_CANCELED } from './constants/errorCodes';\nimport type { AccessioRequestConfig } from './types';\n\nconst PUBLIC_METHODS = [\n 'request',\n 'getUri',\n 'get',\n 'delete',\n 'head',\n 'options',\n 'post',\n 'put',\n 'patch',\n 'postForm',\n 'putForm',\n 'patchForm',\n 'stream',\n 'autoPaginate',\n 'gql',\n];\n\nfunction createInstance(defaultConfig: AccessioRequestConfig) {\n const context = new Accessio(defaultConfig);\n\n const instance: any = function accessio(\n configOrUrl: string | AccessioRequestConfig,\n config?: AccessioRequestConfig,\n ) {\n return context.request(configOrUrl, config);\n };\n\n for (const key of PUBLIC_METHODS) {\n const method: any = (context as any)[key];\n if (typeof method === 'function') {\n instance[key] = method.bind(context);\n }\n }\n\n instance.defaults = context.defaults;\n instance.interceptors = context.interceptors;\n instance.all = function all(promises: any[]): Promise<any[]> {\n return Promise.all(promises);\n };\n instance.spread = function spread<T>(callback: (...args: any[]) => T): (arr: any[]) => T {\n return function wrap(arr: any[]): T {\n return callback(...arr);\n };\n };\n instance.isCancel = function isCancel(value: any): boolean {\n return !!(value && value.isAccessioError && value.code === ERR_CANCELED);\n };\n instance.isAccessioError = function isAccessioError(value: any): boolean {\n return (\n value instanceof AccessioError ||\n !!(value && typeof value === 'object' && value.isAccessioError === true)\n );\n };\n instance.AccessioError = AccessioError;\n instance.Accessio = Accessio;\n instance.mergeConfig = mergeConfig;\n instance.buildURL = buildURL;\n instance.InterceptorManager = InterceptorManager;\n instance.createRateLimiter = createRateLimiter;\n\n return instance;\n}\n\nconst accessio = createInstance(defaults);\n\nfunction create(instanceConfig?: AccessioRequestConfig) {\n return createInstance(mergeConfig(defaults, instanceConfig));\n}\n\naccessio.create = create;\n\nexport default accessio;\n\nexport {\n Accessio,\n AccessioError,\n mergeConfig,\n buildURL,\n InterceptorManager,\n createInstance,\n createRateLimiter,\n logRequest,\n logResponse,\n logError,\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA,kCAAAA;AAAA,EAAA,0CAAAC;AAAA,EAAA,oDAAAC;AAAA,EAAA,gCAAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAAAC;AAAA;AAAA;AAAA,sBAAqB;AACrB,sBAAqB;AACrB,2BAA0B;AAC1B,yBAAwB;AACxB,sBAAqB;AACrB,gCAA+B;AAC/B,yBAAkC;AAClC,mBAAkD;AAClD,wBAA6B;AAG7B,MAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,eAAe,eAAsC;AAC5D,QAAM,UAAU,IAAI,gBAAAJ,QAAS,aAAa;AAE1C,QAAM,WAAgB,SAASK,UAC7B,aACA,QACA;AACA,WAAO,QAAQ,QAAQ,aAAa,MAAM;AAAA,EAC5C;AAEA,aAAW,OAAO,gBAAgB;AAChC,UAAM,SAAe,QAAgB,GAAG;AACxC,QAAI,OAAO,WAAW,YAAY;AAChC,eAAS,GAAG,IAAI,OAAO,KAAK,OAAO;AAAA,IACrC;AAAA,EACF;AAEA,WAAS,WAAW,QAAQ;AAC5B,WAAS,eAAe,QAAQ;AAChC,WAAS,MAAM,SAAS,IAAI,UAAiC;AAC3D,WAAO,QAAQ,IAAI,QAAQ;AAAA,EAC7B;AACA,WAAS,SAAS,SAAS,OAAU,UAAoD;AACvF,WAAO,SAAS,KAAK,KAAe;AAClC,aAAO,SAAS,GAAG,GAAG;AAAA,IACxB;AAAA,EACF;AACA,WAAS,WAAW,SAAS,SAAS,OAAqB;AACzD,WAAO,CAAC,EAAE,SAAS,MAAM,mBAAmB,MAAM,SAAS;AAAA,EAC7D;AACA,WAAS,kBAAkB,SAAS,gBAAgB,OAAqB;AACvE,WACE,iBAAiB,qBAAAJ,WACjB,CAAC,EAAE,SAAS,OAAO,UAAU,YAAY,MAAM,oBAAoB;AAAA,EAEvE;AACA,WAAS,gBAAgB,qBAAAA;AACzB,WAAS,WAAW,gBAAAD;AACpB,WAAS,cAAc,mBAAAI;AACvB,WAAS,WAAW,gBAAAD;AACpB,WAAS,qBAAqB,0BAAAD;AAC9B,WAAS,oBAAoB;AAE7B,SAAO;AACT;AAEA,MAAM,WAAW,eAAe,gBAAAI,OAAQ;AAExC,SAAS,OAAO,gBAAwC;AACtD,SAAO,mBAAe,mBAAAF,SAAY,gBAAAE,SAAU,cAAc,CAAC;AAC7D;AAEA,SAAS,SAAS;AAElB,IAAO,cAAQ;","names":["Accessio","AccessioError","InterceptorManager","buildURL","mergeConfig","accessio","defaults"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "accessio",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Fast, flexible HTTP client — simple, modular, and dependency-free",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./cjs/index.cjs",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"./core/buildURL": {
|
|
30
30
|
"types": "./index.d.ts",
|
|
31
31
|
"import": "./src/core/buildURL.ts",
|
|
32
|
-
"require": "./cjs/
|
|
32
|
+
"require": "./cjs/core/buildURL.cjs"
|
|
33
33
|
},
|
|
34
34
|
"./core/mergeConfig": {
|
|
35
35
|
"types": "./index.d.ts",
|
|
@@ -103,6 +103,7 @@
|
|
|
103
103
|
"prettier": "^3.8.3",
|
|
104
104
|
"tsup": "^8.0.0",
|
|
105
105
|
"typescript": "^5.0.0",
|
|
106
|
+
"typescript-eslint": "^8.59.3",
|
|
106
107
|
"vitest": "^3.1.0"
|
|
107
108
|
}
|
|
108
109
|
}
|
package/src/accessio.ts
CHANGED
|
@@ -6,6 +6,7 @@ import buildURL from './core/buildURL';
|
|
|
6
6
|
import retryRequest from './core/retry';
|
|
7
7
|
import { logRequest, logResponse, logError } from './helpers/debug';
|
|
8
8
|
import { rateLimitedRequest } from './helpers/rateLimiter';
|
|
9
|
+
import { toFormData } from './helpers/toFormData';
|
|
9
10
|
import type {
|
|
10
11
|
AccessioRequestConfig,
|
|
11
12
|
AccessioResponse,
|
|
@@ -201,11 +202,12 @@ export class Accessio {
|
|
|
201
202
|
data?: any,
|
|
202
203
|
config?: AccessioRequestConfig,
|
|
203
204
|
): Promise<AccessioResponse<T>> {
|
|
205
|
+
const formData = data && !(data instanceof FormData) ? toFormData(data) : data;
|
|
204
206
|
return this.request<T>(
|
|
205
207
|
mergeConfig(config || {}, {
|
|
206
208
|
method: 'post',
|
|
207
209
|
url,
|
|
208
|
-
data,
|
|
210
|
+
data: formData,
|
|
209
211
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
210
212
|
}),
|
|
211
213
|
);
|
|
@@ -216,11 +218,12 @@ export class Accessio {
|
|
|
216
218
|
data?: any,
|
|
217
219
|
config?: AccessioRequestConfig,
|
|
218
220
|
): Promise<AccessioResponse<T>> {
|
|
221
|
+
const formData = data && !(data instanceof FormData) ? toFormData(data) : data;
|
|
219
222
|
return this.request<T>(
|
|
220
223
|
mergeConfig(config || {}, {
|
|
221
224
|
method: 'put',
|
|
222
225
|
url,
|
|
223
|
-
data,
|
|
226
|
+
data: formData,
|
|
224
227
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
225
228
|
}),
|
|
226
229
|
);
|
|
@@ -231,15 +234,90 @@ export class Accessio {
|
|
|
231
234
|
data?: any,
|
|
232
235
|
config?: AccessioRequestConfig,
|
|
233
236
|
): Promise<AccessioResponse<T>> {
|
|
237
|
+
const formData = data && !(data instanceof FormData) ? toFormData(data) : data;
|
|
234
238
|
return this.request<T>(
|
|
235
239
|
mergeConfig(config || {}, {
|
|
236
240
|
method: 'patch',
|
|
237
241
|
url,
|
|
238
|
-
data,
|
|
242
|
+
data: formData,
|
|
239
243
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
240
244
|
}),
|
|
241
245
|
);
|
|
242
246
|
}
|
|
247
|
+
|
|
248
|
+
async *stream<T = any>(
|
|
249
|
+
url: string,
|
|
250
|
+
config?: AccessioRequestConfig,
|
|
251
|
+
): AsyncGenerator<T, void, unknown> {
|
|
252
|
+
const response = await this.request<ReadableStream<Uint8Array>>(
|
|
253
|
+
mergeConfig(config || {}, { method: 'get', url, responseType: 'stream' }),
|
|
254
|
+
);
|
|
255
|
+
if (!response.data) return;
|
|
256
|
+
|
|
257
|
+
const reader = response.data.getReader();
|
|
258
|
+
const decoder = new TextDecoder();
|
|
259
|
+
let buffer = '';
|
|
260
|
+
|
|
261
|
+
while (true) {
|
|
262
|
+
const { done, value } = await reader.read();
|
|
263
|
+
if (done) break;
|
|
264
|
+
|
|
265
|
+
buffer += decoder.decode(value, { stream: true });
|
|
266
|
+
const lines = buffer.split('\n');
|
|
267
|
+
buffer = lines.pop() || '';
|
|
268
|
+
|
|
269
|
+
for (const line of lines) {
|
|
270
|
+
if (line.trim().startsWith('data:')) {
|
|
271
|
+
const dataStr = line.replace(/^data:\s*/, '');
|
|
272
|
+
if (dataStr === '[DONE]') return;
|
|
273
|
+
try {
|
|
274
|
+
yield JSON.parse(dataStr);
|
|
275
|
+
} catch (e) {
|
|
276
|
+
yield dataStr as any;
|
|
277
|
+
}
|
|
278
|
+
} else if (line.trim().startsWith('{') || line.trim().startsWith('[')) {
|
|
279
|
+
try {
|
|
280
|
+
yield JSON.parse(line);
|
|
281
|
+
} catch (e) {
|
|
282
|
+
// ignore partial json
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async *autoPaginate<T = any>(
|
|
290
|
+
url: string,
|
|
291
|
+
config?: AccessioRequestConfig,
|
|
292
|
+
): AsyncGenerator<T, void, unknown> {
|
|
293
|
+
let nextUrl: string | null = url;
|
|
294
|
+
let currentConfig = config || {};
|
|
295
|
+
|
|
296
|
+
while (nextUrl) {
|
|
297
|
+
const response: AccessioResponse<any> = await this.get(nextUrl, currentConfig);
|
|
298
|
+
|
|
299
|
+
const items = Array.isArray(response.data) ? response.data : response.data.data;
|
|
300
|
+
if (Array.isArray(items)) {
|
|
301
|
+
for (const item of items) {
|
|
302
|
+
yield item;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
nextUrl = response.data.next || response.data.links?.next || null;
|
|
307
|
+
if (nextUrl) {
|
|
308
|
+
currentConfig = mergeConfig(currentConfig, { url: nextUrl, params: {} });
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
gql<T = any>(
|
|
314
|
+
url: string,
|
|
315
|
+
query: string,
|
|
316
|
+
variables?: Record<string, any>,
|
|
317
|
+
config?: AccessioRequestConfig,
|
|
318
|
+
): Promise<AccessioResponse<T>> {
|
|
319
|
+
return this.post<T>(url, { query, variables }, config);
|
|
320
|
+
}
|
|
243
321
|
}
|
|
244
322
|
|
|
245
323
|
export default Accessio;
|
package/src/core/buildURL.ts
CHANGED
|
@@ -75,7 +75,22 @@ export default function buildURL(
|
|
|
75
75
|
): string {
|
|
76
76
|
let fullURL = baseURL && !isAbsoluteURL(url) ? combineURLs(baseURL, url) : url || '';
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
let finalParams = params;
|
|
79
|
+
if (params && typeof params === 'object') {
|
|
80
|
+
const unusedParams = { ...params };
|
|
81
|
+
fullURL = fullURL.replace(/(?::([a-zA-Z0-9_]+))|(?:{([a-zA-Z0-9_]+)})/g, (match, p1, p2) => {
|
|
82
|
+
const key = p1 || p2;
|
|
83
|
+
if (key && unusedParams[key] !== undefined) {
|
|
84
|
+
const val = unusedParams[key];
|
|
85
|
+
delete unusedParams[key];
|
|
86
|
+
return encodeURIComponent(String(val));
|
|
87
|
+
}
|
|
88
|
+
return match;
|
|
89
|
+
});
|
|
90
|
+
finalParams = unusedParams;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const serialized = serializeParams(finalParams as Record<string, unknown>, paramsSerializer);
|
|
79
94
|
if (serialized) {
|
|
80
95
|
const hashIndex = fullURL.indexOf('#');
|
|
81
96
|
if (hashIndex !== -1) {
|
package/src/core/fetchAdapter.ts
CHANGED
|
@@ -2,7 +2,11 @@ import AccessioError from './accessioError';
|
|
|
2
2
|
import parseHeaders from '../helpers/parseHeaders';
|
|
3
3
|
import type { AccessioRequestConfig, AccessioResponse } from '../types';
|
|
4
4
|
|
|
5
|
-
async function readResponseData(
|
|
5
|
+
async function readResponseData(
|
|
6
|
+
fetchResponse: Response,
|
|
7
|
+
config: AccessioRequestConfig,
|
|
8
|
+
): Promise<unknown> {
|
|
9
|
+
const responseType = config.responseType || 'json';
|
|
6
10
|
switch (responseType) {
|
|
7
11
|
case 'arraybuffer':
|
|
8
12
|
return await fetchResponse.arrayBuffer();
|
|
@@ -94,10 +98,42 @@ export default async function fetchAdapter(
|
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
try {
|
|
97
|
-
const
|
|
101
|
+
const fetchImpl = config.fetch || fetch;
|
|
102
|
+
let fetchResponse = await fetchImpl(fullURL, fetchOptions);
|
|
103
|
+
|
|
104
|
+
if (config.onDownloadProgress && fetchResponse.body && config.responseType !== 'stream') {
|
|
105
|
+
const contentLength = fetchResponse.headers.get('content-length');
|
|
106
|
+
const total = contentLength ? parseInt(contentLength, 10) : 0;
|
|
107
|
+
let loaded = 0;
|
|
108
|
+
|
|
109
|
+
const reader = fetchResponse.body.getReader();
|
|
110
|
+
const stream = new ReadableStream({
|
|
111
|
+
async start(controller) {
|
|
112
|
+
try {
|
|
113
|
+
while (true) {
|
|
114
|
+
const { done, value } = await reader.read();
|
|
115
|
+
if (done) {
|
|
116
|
+
controller.close();
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
loaded += value.byteLength;
|
|
120
|
+
config.onDownloadProgress!({ loaded, total });
|
|
121
|
+
controller.enqueue(value);
|
|
122
|
+
}
|
|
123
|
+
} catch (e) {
|
|
124
|
+
controller.error(e);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
fetchResponse = new Response(stream, {
|
|
130
|
+
headers: fetchResponse.headers,
|
|
131
|
+
status: fetchResponse.status,
|
|
132
|
+
statusText: fetchResponse.statusText,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
98
135
|
|
|
99
136
|
let responseData: unknown;
|
|
100
|
-
const responseType = config.responseType || 'json';
|
|
101
137
|
|
|
102
138
|
const contentLength = fetchResponse.headers.get('content-length');
|
|
103
139
|
if (
|
|
@@ -115,7 +151,14 @@ export default async function fetchAdapter(
|
|
|
115
151
|
}
|
|
116
152
|
|
|
117
153
|
try {
|
|
118
|
-
responseData = await readResponseData(fetchResponse,
|
|
154
|
+
responseData = await readResponseData(fetchResponse, config);
|
|
155
|
+
if (config.schema) {
|
|
156
|
+
if (typeof config.schema.parseAsync === 'function') {
|
|
157
|
+
responseData = await config.schema.parseAsync(responseData);
|
|
158
|
+
} else {
|
|
159
|
+
responseData = config.schema.parse(responseData);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
119
162
|
} catch (readError) {
|
|
120
163
|
throw AccessioError.from(
|
|
121
164
|
readError as Error,
|