accessio 1.1.2 → 1.3.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.
Files changed (40) hide show
  1. package/README.md +109 -14
  2. package/cjs/accessio.cjs +59 -3
  3. package/cjs/accessio.cjs.map +1 -1
  4. package/cjs/core/accessioError.cjs +28 -3
  5. package/cjs/core/accessioError.cjs.map +1 -1
  6. package/cjs/core/buildURL.cjs +15 -1
  7. package/cjs/core/buildURL.cjs.map +1 -1
  8. package/cjs/core/fetchAdapter.cjs +54 -10
  9. package/cjs/core/fetchAdapter.cjs.map +1 -1
  10. package/cjs/core/request.cjs +107 -31
  11. package/cjs/core/request.cjs.map +1 -1
  12. package/cjs/core/retry.cjs +48 -4
  13. package/cjs/core/retry.cjs.map +1 -1
  14. package/cjs/helpers/flattenHeaders.cjs +37 -0
  15. package/cjs/helpers/flattenHeaders.cjs.map +1 -1
  16. package/cjs/helpers/memoryCache.cjs +51 -0
  17. package/cjs/helpers/memoryCache.cjs.map +1 -0
  18. package/cjs/helpers/rateLimiter.cjs +11 -22
  19. package/cjs/helpers/rateLimiter.cjs.map +1 -1
  20. package/cjs/helpers/toFormData.cjs +50 -0
  21. package/cjs/helpers/toFormData.cjs.map +1 -0
  22. package/cjs/helpers/transformData.cjs +2 -2
  23. package/cjs/helpers/transformData.cjs.map +1 -1
  24. package/cjs/index.cjs +4 -1
  25. package/cjs/index.cjs.map +1 -1
  26. package/index.d.ts +7 -0
  27. package/package.json +3 -2
  28. package/src/accessio.ts +81 -3
  29. package/src/core/accessioError.ts +26 -1
  30. package/src/core/buildURL.ts +16 -1
  31. package/src/core/fetchAdapter.ts +62 -10
  32. package/src/core/request.ts +134 -44
  33. package/src/core/retry.ts +44 -6
  34. package/src/helpers/flattenHeaders.ts +30 -0
  35. package/src/helpers/memoryCache.ts +30 -0
  36. package/src/helpers/rateLimiter.ts +11 -24
  37. package/src/helpers/toFormData.ts +25 -0
  38. package/src/helpers/transformData.ts +2 -1
  39. package/src/index.ts +4 -1
  40. package/src/types.ts +27 -0
@@ -32,16 +32,38 @@ __export(request_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(request_exports);
34
34
  var import_buildURL = __toESM(require("./buildURL"), 1);
35
+ var import_accessioError = __toESM(require("./accessioError"), 1);
36
+ var import_errorCodes = require("../constants/errorCodes");
35
37
  var import_transformData = __toESM(require("../helpers/transformData"), 1);
36
38
  var import_settle = __toESM(require("../helpers/settle"), 1);
37
39
  var import_flattenHeaders = require("../helpers/flattenHeaders");
38
40
  var import_auth = require("../helpers/auth");
39
41
  var import_fetchAdapter = __toESM(require("./fetchAdapter"), 1);
42
+ var import_memoryCache = require("../helpers/memoryCache");
40
43
  function buildTransformArray(transform) {
41
44
  if (!transform) return [];
42
45
  if (Array.isArray(transform)) return transform;
43
46
  return [transform];
44
47
  }
48
+ const DEFAULT_ALLOWED_PROTOCOLS = ["http:", "https:"];
49
+ function assertAllowedProtocol(fullURL, config) {
50
+ if (config.allowedProtocols === null) return;
51
+ const allowed = config.allowedProtocols ?? DEFAULT_ALLOWED_PROTOCOLS;
52
+ let scheme = null;
53
+ const match = /^([a-z][a-z\d+\-.]*):/i.exec(fullURL);
54
+ if (match) scheme = match[1].toLowerCase() + ":";
55
+ if (!scheme) return;
56
+ if (!allowed.includes(scheme)) {
57
+ throw new import_accessioError.default(
58
+ `URL protocol "${scheme}" is not allowed. Allowed: ${allowed.join(", ")}. Set config.allowedProtocols to extend, or null to disable the check.`,
59
+ import_errorCodes.ERR_BAD_OPTION,
60
+ config,
61
+ null,
62
+ null
63
+ );
64
+ }
65
+ }
66
+ const activeRequests = /* @__PURE__ */ new Map();
45
67
  async function dispatchRequest(config) {
46
68
  const fullURL = config._builtUrl || (0, import_buildURL.default)(
47
69
  config.url ?? "",
@@ -49,41 +71,95 @@ async function dispatchRequest(config) {
49
71
  config.params,
50
72
  config.paramsSerializer
51
73
  );
52
- const flatHeaders = (0, import_flattenHeaders.flattenHeaders)(config.headers, config.method);
53
- const requestTransforms = buildTransformArray(config.transformRequest);
54
- const requestData = await (0, import_transformData.default)(requestTransforms, config.data, flatHeaders, config);
55
- if (requestData === null || requestData === void 0 || typeof FormData !== "undefined" && requestData instanceof FormData) {
56
- (0, import_flattenHeaders.removeContentType)(flatHeaders);
74
+ assertAllowedProtocol(fullURL, config);
75
+ if (config.hooks?.onBeforeRequest) {
76
+ await config.hooks.onBeforeRequest(config);
57
77
  }
58
- (0, import_auth.setBasicAuth)(config, flatHeaders);
59
- const fetchOptions = {
60
- method: (config.method || "GET").toUpperCase(),
61
- headers: (0, import_flattenHeaders.buildFetchHeaders)(flatHeaders)
62
- };
63
- const methodsWithBody = ["POST", "PUT", "PATCH", "DELETE"];
64
- if (methodsWithBody.includes(fetchOptions.method) && requestData !== void 0 && requestData !== null) {
65
- fetchOptions.body = requestData;
78
+ const isGet = (config.method || "GET").toUpperCase() === "GET";
79
+ const cacheKey = isGet ? `GET:${fullURL}` : "";
80
+ if (isGet && config.cache) {
81
+ const cacheProvider = typeof config.cache === "object" ? config.cache : import_memoryCache.defaultMemoryCache;
82
+ const cached = await cacheProvider.get(cacheKey);
83
+ if (cached) {
84
+ if (config.hooks?.onRequestResponse) {
85
+ await config.hooks.onRequestResponse(cached);
86
+ }
87
+ return cached;
88
+ }
66
89
  }
67
- if (config.withCredentials) {
68
- fetchOptions.credentials = "include";
90
+ if (isGet && config.dedupe) {
91
+ if (activeRequests.has(cacheKey)) {
92
+ return activeRequests.get(cacheKey);
93
+ }
69
94
  }
70
- if (config.dispatcher) {
71
- fetchOptions.dispatcher = config.dispatcher;
95
+ const performRequest = async () => {
96
+ const flatHeaders = (0, import_flattenHeaders.flattenHeaders)(config.headers, config.method);
97
+ const requestTransforms = buildTransformArray(config.transformRequest);
98
+ const requestData = await (0, import_transformData.default)(requestTransforms, config.data, flatHeaders, config);
99
+ if (requestData === null || requestData === void 0 || typeof FormData !== "undefined" && requestData instanceof FormData) {
100
+ (0, import_flattenHeaders.removeContentType)(flatHeaders);
101
+ }
102
+ (0, import_auth.setBasicAuth)(config, flatHeaders);
103
+ const fetchOptions = {
104
+ method: (config.method || "GET").toUpperCase(),
105
+ headers: (0, import_flattenHeaders.buildFetchHeaders)(flatHeaders)
106
+ };
107
+ const methodsWithBody = ["POST", "PUT", "PATCH", "DELETE"];
108
+ if (methodsWithBody.includes(fetchOptions.method) && requestData !== void 0 && requestData !== null) {
109
+ fetchOptions.body = requestData;
110
+ }
111
+ if (config.withCredentials) {
112
+ fetchOptions.credentials = "include";
113
+ }
114
+ if (config.dispatcher) {
115
+ fetchOptions.dispatcher = config.dispatcher;
116
+ }
117
+ if (config.agent) {
118
+ fetchOptions.agent = config.agent;
119
+ }
120
+ const requestStartTime = Date.now();
121
+ const response = await (0, import_fetchAdapter.default)(config, fullURL, fetchOptions, requestStartTime);
122
+ response.config = (0, import_accessioError.redactConfig)(response.config);
123
+ const responseTransforms = buildTransformArray(config.transformResponse);
124
+ response.data = await (0, import_transformData.default)(
125
+ responseTransforms,
126
+ response.data,
127
+ response.headers,
128
+ config,
129
+ "response"
130
+ );
131
+ return new Promise((resolve, reject) => {
132
+ (0, import_settle.default)(
133
+ resolve,
134
+ reject,
135
+ response,
136
+ config
137
+ );
138
+ });
139
+ };
140
+ const promise = performRequest();
141
+ if (isGet && config.dedupe) {
142
+ activeRequests.set(cacheKey, promise);
143
+ const cleanup = () => {
144
+ activeRequests.delete(cacheKey);
145
+ };
146
+ promise.then(cleanup, cleanup);
72
147
  }
73
- if (config.agent) {
74
- fetchOptions.agent = config.agent;
148
+ try {
149
+ const response = await promise;
150
+ if (isGet && config.cache) {
151
+ const cacheProvider = typeof config.cache === "object" ? config.cache : import_memoryCache.defaultMemoryCache;
152
+ await cacheProvider.set(cacheKey, response, config.cacheTTL);
153
+ }
154
+ if (config.hooks?.onRequestResponse) {
155
+ await config.hooks.onRequestResponse(response);
156
+ }
157
+ return response;
158
+ } catch (error) {
159
+ if (config.hooks?.onRequestError && error instanceof import_accessioError.default) {
160
+ await config.hooks.onRequestError(error);
161
+ }
162
+ throw error;
75
163
  }
76
- const requestStartTime = Date.now();
77
- const response = await (0, import_fetchAdapter.default)(config, fullURL, fetchOptions, requestStartTime);
78
- const responseTransforms = buildTransformArray(config.transformResponse);
79
- response.data = await (0, import_transformData.default)(responseTransforms, response.data, response.headers, config);
80
- return new Promise((resolve, reject) => {
81
- (0, import_settle.default)(
82
- resolve,
83
- reject,
84
- response,
85
- config
86
- );
87
- });
88
164
  }
89
165
  //# sourceMappingURL=request.cjs.map
@@ -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, { redactConfig } from './accessioError';\nimport { ERR_BAD_OPTION } from '../constants/errorCodes';\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 DEFAULT_ALLOWED_PROTOCOLS = ['http:', 'https:'];\n\nfunction assertAllowedProtocol(fullURL: string, config: AccessioRequestConfig): void {\n if (config.allowedProtocols === null) return;\n const allowed = config.allowedProtocols ?? DEFAULT_ALLOWED_PROTOCOLS;\n\n let scheme: string | null = null;\n const match = /^([a-z][a-z\\d+\\-.]*):/i.exec(fullURL);\n if (match) scheme = match[1].toLowerCase() + ':';\n if (!scheme) return;\n\n if (!allowed.includes(scheme)) {\n throw new AccessioError(\n `URL protocol \"${scheme}\" is not allowed. Allowed: ${allowed.join(', ')}. ` +\n 'Set config.allowedProtocols to extend, or null to disable the check.',\n ERR_BAD_OPTION,\n config,\n null,\n null,\n );\n }\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 assertAllowedProtocol(fullURL, config);\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 response.config = redactConfig(response.config) as typeof response.config;\n\n const responseTransforms = buildTransformArray(config.transformResponse);\n\n response.data = await transformData(\n responseTransforms,\n response.data,\n response.headers,\n config,\n 'response',\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 const cleanup = () => {\n activeRequests.delete(cacheKey);\n };\n promise.then(cleanup, cleanup);\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":["AccessioError","buildURL","transformData","fetchAdapter","settle"]}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var retry_exports = {};
20
30
  __export(retry_exports, {
@@ -24,6 +34,12 @@ __export(retry_exports, {
24
34
  });
25
35
  module.exports = __toCommonJS(retry_exports);
26
36
  var import_errorCodes = require("../constants/errorCodes");
37
+ var import_accessioError = __toESM(require("./accessioError"), 1);
38
+ function isUnretriableBody(data) {
39
+ if (data == null) return false;
40
+ if (typeof ReadableStream !== "undefined" && data instanceof ReadableStream) return true;
41
+ return false;
42
+ }
27
43
  function defaultRetryCondition(error) {
28
44
  if (error.code === import_errorCodes.ERR_CANCELED) {
29
45
  return false;
@@ -34,6 +50,9 @@ function defaultRetryCondition(error) {
34
50
  if (error.response && error.response.status >= 500) {
35
51
  return true;
36
52
  }
53
+ if (error.config?.retryOn429 && error.response && error.response.status === 429) {
54
+ return true;
55
+ }
37
56
  return false;
38
57
  }
39
58
  function calculateDelay(attempt, baseDelay) {
@@ -65,24 +84,49 @@ function sleep(ms, options) {
65
84
  }
66
85
  async function retryRequest(dispatchFn, config) {
67
86
  const maxRetries = config.retry ?? 0;
68
- if (maxRetries <= 0) {
87
+ if (maxRetries <= 0 && !config.retryOn429) {
69
88
  return dispatchFn(config);
70
89
  }
71
90
  const retryDelay = config.retryDelay ?? 1e3;
72
91
  const retryCondition = config.retryCondition ?? defaultRetryCondition;
73
92
  let lastError;
74
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
93
+ const actualMaxRetries = Math.max(maxRetries, config.retryOn429 ? 3 : 0);
94
+ for (let attempt = 0; attempt <= actualMaxRetries; attempt++) {
75
95
  try {
76
96
  const response = await dispatchFn(config);
77
97
  return response;
78
98
  } catch (error) {
79
99
  lastError = error;
80
- const isLastAttempt = attempt >= maxRetries;
100
+ const isLastAttempt = attempt >= actualMaxRetries;
81
101
  const shouldRetry = !isLastAttempt && retryCondition(error);
82
102
  if (!shouldRetry) {
83
103
  throw error;
84
104
  }
85
- const delay = calculateDelay(attempt, retryDelay);
105
+ if (isUnretriableBody(config.data)) {
106
+ throw new import_accessioError.default(
107
+ "Request body is a ReadableStream and cannot be retried after consumption. Buffer the stream upstream or set retry: 0 for this call.",
108
+ import_errorCodes.ERR_BAD_OPTION,
109
+ config,
110
+ null,
111
+ error.response ?? null
112
+ );
113
+ }
114
+ let delay = calculateDelay(attempt, retryDelay);
115
+ if (config.retryOn429 && error.response?.status === 429) {
116
+ const headers = error.response?.headers;
117
+ const retryAfterStr = headers?.["retry-after"] || headers?.["Retry-After"];
118
+ if (retryAfterStr) {
119
+ const parsed = parseInt(retryAfterStr, 10);
120
+ if (!isNaN(parsed)) {
121
+ delay = parsed * 1e3;
122
+ } else {
123
+ const date = new Date(retryAfterStr);
124
+ if (!isNaN(date.getTime())) {
125
+ delay = Math.max(0, date.getTime() - Date.now());
126
+ }
127
+ }
128
+ }
129
+ }
86
130
  if (typeof config.onRetry === "function") {
87
131
  config.onRetry(attempt + 1, error, config);
88
132
  }
@@ -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_BAD_OPTION, ERR_CANCELED, ERR_NETWORK } from '../constants/errorCodes';\nimport AccessioErrorClass from './accessioError';\nimport type {\n AccessioRequestConfig,\n AccessioError,\n RetryConditionFunction,\n OnRetryFunction,\n} from '../types';\n\nfunction isUnretriableBody(data: unknown): boolean {\n if (data == null) return false;\n if (typeof ReadableStream !== 'undefined' && data instanceof ReadableStream) return true;\n return false;\n}\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 if (isUnretriableBody(config.data)) {\n throw new AccessioErrorClass(\n 'Request body is a ReadableStream and cannot be retried after consumption. ' +\n 'Buffer the stream upstream or set retry: 0 for this call.',\n ERR_BAD_OPTION,\n config,\n null,\n (error as AccessioError).response ?? null,\n );\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":["AccessioErrorClass"]}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var flattenHeaders_exports = {};
20
30
  __export(flattenHeaders_exports, {
@@ -23,6 +33,32 @@ __export(flattenHeaders_exports, {
23
33
  removeContentType: () => removeContentType
24
34
  });
25
35
  module.exports = __toCommonJS(flattenHeaders_exports);
36
+ var import_accessioError = __toESM(require("../core/accessioError"), 1);
37
+ var import_errorCodes = require("../constants/errorCodes");
38
+ const HEADER_FORBIDDEN_CHAR = /[\r\n\0]/;
39
+ function assertSafeHeader(name, value) {
40
+ if (typeof name !== "string" || HEADER_FORBIDDEN_CHAR.test(name)) {
41
+ throw new import_accessioError.default(
42
+ `Invalid header name "${String(name)}": CR, LF and NUL are not allowed`,
43
+ import_errorCodes.ERR_BAD_OPTION,
44
+ null,
45
+ null,
46
+ null
47
+ );
48
+ }
49
+ const values = Array.isArray(value) ? value : [value];
50
+ for (const v of values) {
51
+ if (typeof v === "string" && HEADER_FORBIDDEN_CHAR.test(v)) {
52
+ throw new import_accessioError.default(
53
+ `Invalid value for header "${name}": CR, LF and NUL are not allowed`,
54
+ import_errorCodes.ERR_BAD_OPTION,
55
+ null,
56
+ null,
57
+ null
58
+ );
59
+ }
60
+ }
61
+ }
26
62
  const METHOD_KEYS = /* @__PURE__ */ new Set([
27
63
  "common",
28
64
  "delete",
@@ -59,6 +95,7 @@ function removeContentType(headers) {
59
95
  function buildFetchHeaders(headers) {
60
96
  const fetchHeaders = new Headers();
61
97
  for (const [key, value] of Object.entries(headers)) {
98
+ assertSafeHeader(key, value);
62
99
  if (Array.isArray(value)) {
63
100
  for (const v of value) {
64
101
  fetchHeaders.append(key, v);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/helpers/flattenHeaders.ts"],"sourcesContent":["const 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 | string[]>>;\n\nexport function flattenHeaders(\n headers: HeadersConfig | undefined,\n method?: string,\n): Record<string, string | string[]> {\n if (!headers) return {};\n\n const merged: Record<string, 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 | string[];\n }\n }\n\n return merged;\n}\n\nexport function removeContentType(headers: Record<string, 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\nexport function buildFetchHeaders(headers: Record<string, string | string[]>): Headers {\n const fetchHeaders = new Headers();\n for (const [key, value] of Object.entries(headers)) {\n if (Array.isArray(value)) {\n for (const v of value) {\n fetchHeaders.append(key, v);\n }\n } else {\n fetchHeaders.set(key, value);\n }\n }\n return fetchHeaders;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAM,cAAc,oBAAI,IAAY;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAIM,SAAS,eACd,SACA,QACmC;AACnC,MAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,QAAM,SAA4C,CAAC;AACnD,QAAM,eAAe,UAAU,OAAO,YAAY;AAElD,MAAI,QAAQ,QAAQ,GAAG;AACrB,WAAO,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,EACzC;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,OAAO,QAAQ,QAAQ,WAAW,CAAC;AAAA,EAC5C;AAEA,aAAW,OAAO,SAAS;AACzB,QAAI,OAAO,UAAU,eAAe,KAAK,SAAS,GAAG,KAAK,CAAC,YAAY,IAAI,GAAG,GAAG;AAC/E,aAAO,GAAG,IAAI,QAAQ,GAAG;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,kBAAkB,SAAkD;AAClF,QAAM,OAAO,OAAO,KAAK,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,cAAc;AAClF,aAAW,OAAO,MAAM;AACtB,WAAO,QAAQ,GAAG;AAAA,EACpB;AACF;AAEO,SAAS,kBAAkB,SAAqD;AACrF,QAAM,eAAe,IAAI,QAAQ;AACjC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,KAAK,OAAO;AACrB,qBAAa,OAAO,KAAK,CAAC;AAAA,MAC5B;AAAA,IACF,OAAO;AACL,mBAAa,IAAI,KAAK,KAAK;AAAA,IAC7B;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/helpers/flattenHeaders.ts"],"sourcesContent":["import AccessioError from '../core/accessioError';\nimport { ERR_BAD_OPTION } from '../constants/errorCodes';\n\nconst HEADER_FORBIDDEN_CHAR = /[\\r\\n\\0]/;\n\nfunction assertSafeHeader(name: string, value: string | string[]): void {\n if (typeof name !== 'string' || HEADER_FORBIDDEN_CHAR.test(name)) {\n throw new AccessioError(\n `Invalid header name \"${String(name)}\": CR, LF and NUL are not allowed`,\n ERR_BAD_OPTION,\n null,\n null,\n null,\n );\n }\n const values = Array.isArray(value) ? value : [value];\n for (const v of values) {\n if (typeof v === 'string' && HEADER_FORBIDDEN_CHAR.test(v)) {\n throw new AccessioError(\n `Invalid value for header \"${name}\": CR, LF and NUL are not allowed`,\n ERR_BAD_OPTION,\n null,\n null,\n null,\n );\n }\n }\n}\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 | string[]>>;\n\nexport function flattenHeaders(\n headers: HeadersConfig | undefined,\n method?: string,\n): Record<string, string | string[]> {\n if (!headers) return {};\n\n const merged: Record<string, 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 | string[];\n }\n }\n\n return merged;\n}\n\nexport function removeContentType(headers: Record<string, 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\nexport function buildFetchHeaders(headers: Record<string, string | string[]>): Headers {\n const fetchHeaders = new Headers();\n for (const [key, value] of Object.entries(headers)) {\n assertSafeHeader(key, value);\n if (Array.isArray(value)) {\n for (const v of value) {\n fetchHeaders.append(key, v);\n }\n } else {\n fetchHeaders.set(key, value);\n }\n }\n return fetchHeaders;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAA0B;AAC1B,wBAA+B;AAE/B,MAAM,wBAAwB;AAE9B,SAAS,iBAAiB,MAAc,OAAgC;AACtE,MAAI,OAAO,SAAS,YAAY,sBAAsB,KAAK,IAAI,GAAG;AAChE,UAAM,IAAI,qBAAAA;AAAA,MACR,wBAAwB,OAAO,IAAI,CAAC;AAAA,MACpC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,aAAW,KAAK,QAAQ;AACtB,QAAI,OAAO,MAAM,YAAY,sBAAsB,KAAK,CAAC,GAAG;AAC1D,YAAM,IAAI,qBAAAA;AAAA,QACR,6BAA6B,IAAI;AAAA,QACjC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,MAAM,cAAc,oBAAI,IAAY;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAIM,SAAS,eACd,SACA,QACmC;AACnC,MAAI,CAAC,QAAS,QAAO,CAAC;AAEtB,QAAM,SAA4C,CAAC;AACnD,QAAM,eAAe,UAAU,OAAO,YAAY;AAElD,MAAI,QAAQ,QAAQ,GAAG;AACrB,WAAO,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,EACzC;AAEA,MAAI,QAAQ,WAAW,GAAG;AACxB,WAAO,OAAO,QAAQ,QAAQ,WAAW,CAAC;AAAA,EAC5C;AAEA,aAAW,OAAO,SAAS;AACzB,QAAI,OAAO,UAAU,eAAe,KAAK,SAAS,GAAG,KAAK,CAAC,YAAY,IAAI,GAAG,GAAG;AAC/E,aAAO,GAAG,IAAI,QAAQ,GAAG;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,kBAAkB,SAAkD;AAClF,QAAM,OAAO,OAAO,KAAK,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,cAAc;AAClF,aAAW,OAAO,MAAM;AACtB,WAAO,QAAQ,GAAG;AAAA,EACpB;AACF;AAEO,SAAS,kBAAkB,SAAqD;AACrF,QAAM,eAAe,IAAI,QAAQ;AACjC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,qBAAiB,KAAK,KAAK;AAC3B,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,KAAK,OAAO;AACrB,qBAAa,OAAO,KAAK,CAAC;AAAA,MAC5B;AAAA,IACF,OAAO;AACL,mBAAa,IAAI,KAAK,KAAK;AAAA,IAC7B;AAAA,EACF;AACA,SAAO;AACT;","names":["AccessioError"]}
@@ -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":[]}
@@ -36,10 +36,7 @@ function createRateLimiter(maxConcurrent = Infinity, maxQueueSize = Infinity) {
36
36
  }
37
37
  let active = 0;
38
38
  let destroyed = false;
39
- let head = 0;
40
- let tail = 0;
41
- let pendingCount = 0;
42
- const queue = {};
39
+ const queue = [];
43
40
  function acquire() {
44
41
  if (destroyed) {
45
42
  return Promise.reject(new Error("[Accessio] Rate limiter has been destroyed"));
@@ -48,38 +45,30 @@ function createRateLimiter(maxConcurrent = Infinity, maxQueueSize = Infinity) {
48
45
  active++;
49
46
  return Promise.resolve();
50
47
  }
51
- if (pendingCount >= maxQueueSize) {
48
+ if (queue.length >= maxQueueSize) {
52
49
  return Promise.reject(
53
50
  new Error(`[Accessio] Rate limiter queue size exceeded maxQueueSize (${maxQueueSize})`)
54
51
  );
55
52
  }
56
53
  return new Promise((resolve, reject) => {
57
- queue[tail++] = { resolve, reject };
58
- pendingCount++;
54
+ queue.push({ resolve, reject });
59
55
  });
60
56
  }
61
57
  function release() {
62
58
  if (destroyed) return;
63
59
  if (active <= 0) return;
64
- active--;
65
- if (pendingCount > 0 && active < maxConcurrent) {
66
- active++;
67
- const next = queue[head];
68
- delete queue[head];
69
- head++;
70
- pendingCount--;
71
- next?.resolve();
60
+ const next = queue.shift();
61
+ if (next) {
62
+ next.resolve();
63
+ return;
72
64
  }
65
+ active--;
73
66
  }
74
67
  function destroy() {
75
68
  destroyed = true;
76
69
  const reason = new Error("[Accessio] Rate limiter destroyed \u2014 pending request cancelled");
77
- while (pendingCount > 0) {
78
- const next = queue[head];
79
- delete queue[head];
80
- head++;
81
- pendingCount--;
82
- next?.reject(reason);
70
+ while (queue.length > 0) {
71
+ queue.shift().reject(reason);
83
72
  }
84
73
  }
85
74
  return {
@@ -87,7 +76,7 @@ function createRateLimiter(maxConcurrent = Infinity, maxQueueSize = Infinity) {
87
76
  release,
88
77
  destroy,
89
78
  get pending() {
90
- return pendingCount;
79
+ return queue.length;
91
80
  },
92
81
  get active() {
93
82
  return active;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/helpers/rateLimiter.ts"],"sourcesContent":["import type { RateLimiter, AccessioRequestConfig, AccessioResponse } from '../types';\n\ninterface QueueItem {\n resolve: () => void;\n reject: (reason: Error) => void;\n}\n\nexport function createRateLimiter(\n maxConcurrent: number = Infinity,\n maxQueueSize: number = Infinity,\n): RateLimiter {\n if (maxConcurrent !== Infinity && (!Number.isInteger(maxConcurrent) || maxConcurrent < 1)) {\n throw new RangeError(\n `[Accessio] maxConcurrent must be a positive integer or Infinity, got: ${maxConcurrent}`,\n );\n }\n if (maxQueueSize !== Infinity && (!Number.isInteger(maxQueueSize) || maxQueueSize < 1)) {\n throw new RangeError(\n `[Accessio] maxQueueSize must be a positive integer or Infinity, got: ${maxQueueSize}`,\n );\n }\n let active = 0;\n let destroyed = false;\n let head = 0;\n let tail = 0;\n let pendingCount = 0;\n const queue: Record<number, QueueItem> = {};\n\n function acquire(): Promise<void> {\n if (destroyed) {\n return Promise.reject(new Error('[Accessio] Rate limiter has been destroyed'));\n }\n\n if (active < maxConcurrent) {\n active++;\n return Promise.resolve();\n }\n\n if (pendingCount >= maxQueueSize) {\n return Promise.reject(\n new Error(`[Accessio] Rate limiter queue size exceeded maxQueueSize (${maxQueueSize})`),\n );\n }\n\n return new Promise((resolve, reject) => {\n queue[tail++] = { resolve, reject };\n pendingCount++;\n });\n }\n\n function release(): void {\n if (destroyed) return;\n\n if (active <= 0) return;\n\n active--;\n\n if (pendingCount > 0 && active < maxConcurrent) {\n active++;\n const next = queue[head];\n delete queue[head];\n head++;\n pendingCount--;\n next?.resolve();\n }\n }\n\n function destroy(): void {\n destroyed = true;\n const reason = new Error('[Accessio] Rate limiter destroyed — pending request cancelled');\n while (pendingCount > 0) {\n const next = queue[head];\n delete queue[head];\n head++;\n pendingCount--;\n next?.reject(reason);\n }\n }\n\n return {\n acquire,\n release,\n destroy,\n get pending() {\n return pendingCount;\n },\n get active() {\n return active;\n },\n get destroyed() {\n return destroyed;\n },\n };\n}\n\nexport async function rateLimitedRequest<T = unknown>(\n dispatchFn: (config: AccessioRequestConfig) => Promise<AccessioResponse<T>>,\n limiter: RateLimiter,\n config: AccessioRequestConfig,\n): Promise<AccessioResponse<T>> {\n await limiter.acquire();\n try {\n return await dispatchFn(config);\n } finally {\n limiter.release();\n }\n}\n\nexport default createRateLimiter;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,SAAS,kBACd,gBAAwB,UACxB,eAAuB,UACV;AACb,MAAI,kBAAkB,aAAa,CAAC,OAAO,UAAU,aAAa,KAAK,gBAAgB,IAAI;AACzF,UAAM,IAAI;AAAA,MACR,yEAAyE,aAAa;AAAA,IACxF;AAAA,EACF;AACA,MAAI,iBAAiB,aAAa,CAAC,OAAO,UAAU,YAAY,KAAK,eAAe,IAAI;AACtF,UAAM,IAAI;AAAA,MACR,wEAAwE,YAAY;AAAA,IACtF;AAAA,EACF;AACA,MAAI,SAAS;AACb,MAAI,YAAY;AAChB,MAAI,OAAO;AACX,MAAI,OAAO;AACX,MAAI,eAAe;AACnB,QAAM,QAAmC,CAAC;AAE1C,WAAS,UAAyB;AAChC,QAAI,WAAW;AACb,aAAO,QAAQ,OAAO,IAAI,MAAM,4CAA4C,CAAC;AAAA,IAC/E;AAEA,QAAI,SAAS,eAAe;AAC1B;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAEA,QAAI,gBAAgB,cAAc;AAChC,aAAO,QAAQ;AAAA,QACb,IAAI,MAAM,6DAA6D,YAAY,GAAG;AAAA,MACxF;AAAA,IACF;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,MAAM,IAAI,EAAE,SAAS,OAAO;AAClC;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,UAAgB;AACvB,QAAI,UAAW;AAEf,QAAI,UAAU,EAAG;AAEjB;AAEA,QAAI,eAAe,KAAK,SAAS,eAAe;AAC9C;AACA,YAAM,OAAO,MAAM,IAAI;AACvB,aAAO,MAAM,IAAI;AACjB;AACA;AACA,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAEA,WAAS,UAAgB;AACvB,gBAAY;AACZ,UAAM,SAAS,IAAI,MAAM,oEAA+D;AACxF,WAAO,eAAe,GAAG;AACvB,YAAM,OAAO,MAAM,IAAI;AACvB,aAAO,MAAM,IAAI;AACjB;AACA;AACA,YAAM,OAAO,MAAM;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,IAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAAA,IACA,IAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,IACA,IAAI,YAAY;AACd,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,eAAsB,mBACpB,YACA,SACA,QAC8B;AAC9B,QAAM,QAAQ,QAAQ;AACtB,MAAI;AACF,WAAO,MAAM,WAAW,MAAM;AAAA,EAChC,UAAE;AACA,YAAQ,QAAQ;AAAA,EAClB;AACF;AAEA,IAAO,sBAAQ;","names":[]}
1
+ {"version":3,"sources":["../../src/helpers/rateLimiter.ts"],"sourcesContent":["import type { RateLimiter, AccessioRequestConfig, AccessioResponse } from '../types';\n\ninterface QueueItem {\n resolve: () => void;\n reject: (reason: Error) => void;\n}\n\nexport function createRateLimiter(\n maxConcurrent: number = Infinity,\n maxQueueSize: number = Infinity,\n): RateLimiter {\n if (maxConcurrent !== Infinity && (!Number.isInteger(maxConcurrent) || maxConcurrent < 1)) {\n throw new RangeError(\n `[Accessio] maxConcurrent must be a positive integer or Infinity, got: ${maxConcurrent}`,\n );\n }\n if (maxQueueSize !== Infinity && (!Number.isInteger(maxQueueSize) || maxQueueSize < 1)) {\n throw new RangeError(\n `[Accessio] maxQueueSize must be a positive integer or Infinity, got: ${maxQueueSize}`,\n );\n }\n let active = 0;\n let destroyed = false;\n const queue: QueueItem[] = [];\n\n function acquire(): Promise<void> {\n if (destroyed) {\n return Promise.reject(new Error('[Accessio] Rate limiter has been destroyed'));\n }\n\n if (active < maxConcurrent) {\n active++;\n return Promise.resolve();\n }\n\n if (queue.length >= maxQueueSize) {\n return Promise.reject(\n new Error(`[Accessio] Rate limiter queue size exceeded maxQueueSize (${maxQueueSize})`),\n );\n }\n\n return new Promise((resolve, reject) => {\n queue.push({ resolve, reject });\n });\n }\n\n function release(): void {\n if (destroyed) return;\n if (active <= 0) return;\n\n const next = queue.shift();\n if (next) {\n next.resolve();\n return;\n }\n active--;\n }\n\n function destroy(): void {\n destroyed = true;\n const reason = new Error('[Accessio] Rate limiter destroyed — pending request cancelled');\n while (queue.length > 0) {\n queue.shift()!.reject(reason);\n }\n }\n\n return {\n acquire,\n release,\n destroy,\n get pending() {\n return queue.length;\n },\n get active() {\n return active;\n },\n get destroyed() {\n return destroyed;\n },\n };\n}\n\nexport async function rateLimitedRequest<T = unknown>(\n dispatchFn: (config: AccessioRequestConfig) => Promise<AccessioResponse<T>>,\n limiter: RateLimiter,\n config: AccessioRequestConfig,\n): Promise<AccessioResponse<T>> {\n await limiter.acquire();\n try {\n return await dispatchFn(config);\n } finally {\n limiter.release();\n }\n}\n\nexport default createRateLimiter;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOO,SAAS,kBACd,gBAAwB,UACxB,eAAuB,UACV;AACb,MAAI,kBAAkB,aAAa,CAAC,OAAO,UAAU,aAAa,KAAK,gBAAgB,IAAI;AACzF,UAAM,IAAI;AAAA,MACR,yEAAyE,aAAa;AAAA,IACxF;AAAA,EACF;AACA,MAAI,iBAAiB,aAAa,CAAC,OAAO,UAAU,YAAY,KAAK,eAAe,IAAI;AACtF,UAAM,IAAI;AAAA,MACR,wEAAwE,YAAY;AAAA,IACtF;AAAA,EACF;AACA,MAAI,SAAS;AACb,MAAI,YAAY;AAChB,QAAM,QAAqB,CAAC;AAE5B,WAAS,UAAyB;AAChC,QAAI,WAAW;AACb,aAAO,QAAQ,OAAO,IAAI,MAAM,4CAA4C,CAAC;AAAA,IAC/E;AAEA,QAAI,SAAS,eAAe;AAC1B;AACA,aAAO,QAAQ,QAAQ;AAAA,IACzB;AAEA,QAAI,MAAM,UAAU,cAAc;AAChC,aAAO,QAAQ;AAAA,QACb,IAAI,MAAM,6DAA6D,YAAY,GAAG;AAAA,MACxF;AAAA,IACF;AAEA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,KAAK,EAAE,SAAS,OAAO,CAAC;AAAA,IAChC,CAAC;AAAA,EACH;AAEA,WAAS,UAAgB;AACvB,QAAI,UAAW;AACf,QAAI,UAAU,EAAG;AAEjB,UAAM,OAAO,MAAM,MAAM;AACzB,QAAI,MAAM;AACR,WAAK,QAAQ;AACb;AAAA,IACF;AACA;AAAA,EACF;AAEA,WAAS,UAAgB;AACvB,gBAAY;AACZ,UAAM,SAAS,IAAI,MAAM,oEAA+D;AACxF,WAAO,MAAM,SAAS,GAAG;AACvB,YAAM,MAAM,EAAG,OAAO,MAAM;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,IAAI,UAAU;AACZ,aAAO,MAAM;AAAA,IACf;AAAA,IACA,IAAI,SAAS;AACX,aAAO;AAAA,IACT;AAAA,IACA,IAAI,YAAY;AACd,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,eAAsB,mBACpB,YACA,SACA,QAC8B;AAC9B,QAAM,QAAQ,QAAQ;AACtB,MAAI;AACF,WAAO,MAAM,WAAW,MAAM;AAAA,EAChC,UAAE;AACA,YAAQ,QAAQ;AAAA,EAClB;AACF;AAEA,IAAO,sBAAQ;","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":[]}
@@ -32,7 +32,7 @@ __export(transformData_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(transformData_exports);
34
34
  var import_accessioError = __toESM(require("../core/accessioError"), 1);
35
- async function transformData(transforms, data, headers, config) {
35
+ async function transformData(transforms, data, headers, config, direction = "request") {
36
36
  if (!transforms || !Array.isArray(transforms)) {
37
37
  return data;
38
38
  }
@@ -44,7 +44,7 @@ async function transformData(transforms, data, headers, config) {
44
44
  } catch (err) {
45
45
  throw import_accessioError.default.from(
46
46
  err instanceof Error ? err : new Error(String(err)),
47
- import_accessioError.default.ERR_BAD_REQUEST,
47
+ direction === "response" ? import_accessioError.default.ERR_BAD_RESPONSE : import_accessioError.default.ERR_BAD_REQUEST,
48
48
  config ?? null,
49
49
  null,
50
50
  null