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.
@@ -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\n const requestTransforms = buildTransformArray(config.transformRequest);\n\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(responseTransforms, response.data, response.headers, config);\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAqB;AAErB,2BAA0B;AAC1B,oBAAmB;AACnB,4BAAqE;AACrE,kBAA6B;AAC7B,0BAAyB;AAKzB,SAAS,oBACP,WACqB;AACrB,MAAI,CAAC,UAAW,QAAO,CAAC;AACxB,MAAI,MAAM,QAAQ,SAAS,EAAG,QAAO;AACrC,SAAO,CAAC,SAAS;AACnB;AAEA,eAAO,gBACL,QAC2B;AAC3B,QAAM,UACJ,OAAO,iBACP,gBAAAA;AAAA,IACE,OAAO,OAAO;AAAA,IACd,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AAEF,QAAM,kBAAc,sCAAe,OAAO,SAAsC,OAAO,MAAM;AAE7F,QAAM,oBAAoB,oBAAoB,OAAO,gBAAgB;AAErE,QAAM,cAAc,UAAM,qBAAAC,SAAc,mBAAmB,OAAO,MAAM,aAAa,MAAM;AAE3F,MACE,gBAAgB,QAChB,gBAAgB,UACf,OAAO,aAAa,eAAe,uBAAuB,UAC3D;AACA,iDAAkB,WAAW;AAAA,EAC/B;AAEA,gCAAa,QAAQ,WAAW;AAEhC,QAAM,eAA4B;AAAA,IAChC,SAAS,OAAO,UAAU,OAAO,YAAY;AAAA,IAC7C,aAAS,yCAAkB,WAAW;AAAA,EACxC;AAEA,QAAM,kBAAkB,CAAC,QAAQ,OAAO,SAAS,QAAQ;AACzD,MACE,gBAAgB,SAAS,aAAa,MAAO,KAC7C,gBAAgB,UAChB,gBAAgB,MAChB;AACA,iBAAa,OAAO;AAAA,EACtB;AAEA,MAAI,OAAO,iBAAiB;AAC1B,iBAAa,cAAc;AAAA,EAC7B;AAEA,MAAI,OAAO,YAAY;AACrB,IAAC,aAAqB,aAAa,OAAO;AAAA,EAC5C;AACA,MAAI,OAAO,OAAO;AAChB,IAAC,aAAqB,QAAQ,OAAO;AAAA,EACvC;AAEA,QAAM,mBAAmB,KAAK,IAAI;AAElC,QAAM,WAAW,UAAM,oBAAAC,SAAa,QAAQ,SAAS,cAAc,gBAAgB;AAEnF,QAAM,qBAAqB,oBAAoB,OAAO,iBAAiB;AAEvE,WAAS,OAAO,UAAM,qBAAAD,SAAc,oBAAoB,SAAS,MAAM,SAAS,SAAS,MAAM;AAE/F,SAAO,IAAI,QAA0B,CAAC,SAAS,WAAW;AACxD,sBAAAE;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AACH;","names":["buildURL","transformData","fetchAdapter","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"]}
@@ -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
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
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 >= maxRetries;
84
+ const isLastAttempt = attempt >= actualMaxRetries;
81
85
  const shouldRetry = !isLastAttempt && retryCondition(error);
82
86
  if (!shouldRetry) {
83
87
  throw error;
84
88
  }
85
- const delay = calculateDelay(attempt, retryDelay);
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
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/retry.ts"],"sourcesContent":["import { ERR_CANCELED, ERR_NETWORK, ETIMEDOUT } from '../constants/errorCodes';\nimport type {\n AccessioRequestConfig,\n AccessioResponse,\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 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) {\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\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await dispatchFn(config);\n return response;\n } catch (error) {\n lastError = error;\n\n const isLastAttempt = attempt >= maxRetries;\n const shouldRetry = !isLastAttempt && retryCondition(error as AccessioError);\n\n if (!shouldRetry) {\n throw error;\n }\n\n const delay = calculateDelay(attempt, retryDelay);\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":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAqD;AASrD,SAAS,sBAAsB,OAAqB;AAClD,MAAI,MAAM,SAAS,gCAAc;AAC/B,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,SAAS,+BAAa;AAC9B,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,YAAY,MAAM,SAAS,UAAU,KAAK;AAClD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,SAAiB,WAA2B;AAClE,QAAM,mBAAmB,YAAY,KAAK,IAAI,GAAG,OAAO;AACxD,QAAM,SAAS,mBAAmB,QAAQ,KAAK,OAAO,IAAI,IAAI;AAC9D,SAAO,KAAK,MAAM,mBAAmB,MAAM;AAC7C;AAEA,SAAS,MAAM,IAAY,SAAmD;AAC5E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI;AAEJ,UAAM,YAAY,WAAW,MAAM;AACjC,UAAI,SAAS,UAAU,SAAS;AAC9B,gBAAQ,OAAO,oBAAoB,SAAS,OAAO;AAAA,MACrD;AACA,cAAQ;AAAA,IACV,GAAG,EAAE;AAEL,QAAI,SAAS,QAAQ;AACnB,UAAI,QAAQ,OAAO,SAAS;AAC1B,qBAAa,SAAS;AACtB,eAAO,OAAO,QAAQ,OAAO,UAAU,IAAI,MAAM,eAAe,CAAC;AAAA,MACnE;AAEA,gBAAU,MAAM;AACd,qBAAa,SAAS;AACtB,eAAO,QAAQ,OAAQ,UAAU,IAAI,MAAM,eAAe,CAAC;AAAA,MAC7D;AAEA,cAAQ,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IAClE;AAAA,EACF,CAAC;AACH;AAEA,eAAe,aACb,YACA,QACc;AACd,QAAM,aAAa,OAAO,SAAS;AAEnC,MAAI,cAAc,GAAG;AACnB,WAAO,WAAW,MAAM;AAAA,EAC1B;AAEA,QAAM,aAAa,OAAO,cAAc;AACxC,QAAM,iBAAyC,OAAO,kBAAkB;AAExE,MAAI;AAEJ,WAAS,UAAU,GAAG,WAAW,YAAY,WAAW;AACtD,QAAI;AACF,YAAM,WAAW,MAAM,WAAW,MAAM;AACxC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,kBAAY;AAEZ,YAAM,gBAAgB,WAAW;AACjC,YAAM,cAAc,CAAC,iBAAiB,eAAe,KAAsB;AAE3E,UAAI,CAAC,aAAa;AAChB,cAAM;AAAA,MACR;AAEA,YAAM,QAAQ,eAAe,SAAS,UAAU;AAEhD,UAAI,OAAO,OAAO,YAAY,YAAY;AACxC,QAAC,OAAO,QAA4B,UAAU,GAAG,OAAwB,MAAM;AAAA,MACjF;AAEA,YAAM,MAAM,OAAO,EAAE,QAAQ,OAAO,OAAO,CAAC;AAAA,IAC9C;AAAA,EACF;AAEA,QAAM;AACR;AAGA,IAAO,gBAAQ;","names":[]}
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
@@ -62,7 +62,10 @@ const PUBLIC_METHODS = [
62
62
  "patch",
63
63
  "postForm",
64
64
  "putForm",
65
- "patchForm"
65
+ "patchForm",
66
+ "stream",
67
+ "autoPaginate",
68
+ "gql"
66
69
  ];
67
70
  function createInstance(defaultConfig) {
68
71
  const context = new import_accessio.default(defaultConfig);
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, AccessioResponse } 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];\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;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"]}
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.1.2",
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/helpers/buildURL.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;
@@ -20,6 +20,7 @@ export class AccessioError extends Error {
20
20
  readonly response: AccessioResponse | null;
21
21
  readonly isAccessioError: true;
22
22
  cause?: Error;
23
+ override name = 'AccessioError' as const;
23
24
 
24
25
  constructor(
25
26
  message: string,
@@ -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
- const serialized = serializeParams(params as Record<string, unknown>, paramsSerializer);
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) {
@@ -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(fetchResponse: Response, responseType: string): Promise<unknown> {
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 fetchResponse = await fetch(fullURL, fetchOptions);
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, responseType);
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,