accessio 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +98 -1
  2. package/cjs/accessio.cjs +102 -10
  3. package/cjs/accessio.cjs.map +1 -1
  4. package/cjs/core/accessioError.cjs +1 -0
  5. package/cjs/core/accessioError.cjs.map +1 -1
  6. package/cjs/core/buildURL.cjs +16 -2
  7. package/cjs/core/buildURL.cjs.map +1 -1
  8. package/cjs/core/fetchAdapter.cjs +224 -0
  9. package/cjs/core/fetchAdapter.cjs.map +1 -0
  10. package/cjs/core/mergeConfig.cjs +2 -2
  11. package/cjs/core/mergeConfig.cjs.map +1 -1
  12. package/cjs/core/request.cjs +74 -199
  13. package/cjs/core/request.cjs.map +1 -1
  14. package/cjs/core/retry.cjs +23 -4
  15. package/cjs/core/retry.cjs.map +1 -1
  16. package/cjs/defaults/transforms.cjs.map +1 -1
  17. package/cjs/helpers/auth.cjs +45 -0
  18. package/cjs/helpers/auth.cjs.map +1 -0
  19. package/cjs/helpers/flattenHeaders.cjs +78 -0
  20. package/cjs/helpers/flattenHeaders.cjs.map +1 -0
  21. package/cjs/helpers/memoryCache.cjs +51 -0
  22. package/cjs/helpers/memoryCache.cjs.map +1 -0
  23. package/cjs/helpers/parseHeaders.cjs +16 -4
  24. package/cjs/helpers/parseHeaders.cjs.map +1 -1
  25. package/cjs/helpers/rateLimiter.cjs +18 -8
  26. package/cjs/helpers/rateLimiter.cjs.map +1 -1
  27. package/cjs/helpers/toFormData.cjs +50 -0
  28. package/cjs/helpers/toFormData.cjs.map +1 -0
  29. package/cjs/helpers/transformData.cjs +2 -2
  30. package/cjs/helpers/transformData.cjs.map +1 -1
  31. package/cjs/index.cjs +4 -1
  32. package/cjs/index.cjs.map +1 -1
  33. package/package.json +4 -3
  34. package/src/accessio.ts +126 -10
  35. package/src/core/accessioError.ts +1 -0
  36. package/src/core/buildURL.ts +17 -2
  37. package/src/core/fetchAdapter.ts +227 -0
  38. package/src/core/mergeConfig.ts +2 -2
  39. package/src/core/request.ts +100 -250
  40. package/src/core/retry.ts +26 -6
  41. package/src/defaults/transforms.ts +4 -1
  42. package/src/helpers/auth.ts +26 -0
  43. package/src/helpers/flattenHeaders.ts +59 -0
  44. package/src/helpers/memoryCache.ts +30 -0
  45. package/src/helpers/parseHeaders.ts +19 -6
  46. package/src/helpers/rateLimiter.ts +18 -8
  47. package/src/helpers/toFormData.ts +25 -0
  48. package/src/helpers/transformData.ts +4 -4
  49. package/src/index.ts +4 -1
  50. package/src/types.ts +32 -3
@@ -0,0 +1,78 @@
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 flattenHeaders_exports = {};
20
+ __export(flattenHeaders_exports, {
21
+ buildFetchHeaders: () => buildFetchHeaders,
22
+ flattenHeaders: () => flattenHeaders,
23
+ removeContentType: () => removeContentType
24
+ });
25
+ module.exports = __toCommonJS(flattenHeaders_exports);
26
+ const METHOD_KEYS = /* @__PURE__ */ new Set([
27
+ "common",
28
+ "delete",
29
+ "get",
30
+ "head",
31
+ "options",
32
+ "post",
33
+ "put",
34
+ "patch"
35
+ ]);
36
+ function flattenHeaders(headers, method) {
37
+ if (!headers) return {};
38
+ const merged = {};
39
+ const methodLower = (method || "get").toLowerCase();
40
+ if (headers["common"]) {
41
+ Object.assign(merged, headers["common"]);
42
+ }
43
+ if (headers[methodLower]) {
44
+ Object.assign(merged, headers[methodLower]);
45
+ }
46
+ for (const key in headers) {
47
+ if (Object.prototype.hasOwnProperty.call(headers, key) && !METHOD_KEYS.has(key)) {
48
+ merged[key] = headers[key];
49
+ }
50
+ }
51
+ return merged;
52
+ }
53
+ function removeContentType(headers) {
54
+ const keys = Object.keys(headers).filter((k) => k.toLowerCase() === "content-type");
55
+ for (const key of keys) {
56
+ delete headers[key];
57
+ }
58
+ }
59
+ function buildFetchHeaders(headers) {
60
+ const fetchHeaders = new Headers();
61
+ for (const [key, value] of Object.entries(headers)) {
62
+ if (Array.isArray(value)) {
63
+ for (const v of value) {
64
+ fetchHeaders.append(key, v);
65
+ }
66
+ } else {
67
+ fetchHeaders.set(key, value);
68
+ }
69
+ }
70
+ return fetchHeaders;
71
+ }
72
+ // Annotate the CommonJS export names for ESM import in node:
73
+ 0 && (module.exports = {
74
+ buildFetchHeaders,
75
+ flattenHeaders,
76
+ removeContentType
77
+ });
78
+ //# sourceMappingURL=flattenHeaders.cjs.map
@@ -0,0 +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":[]}
@@ -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":[]}
@@ -24,9 +24,21 @@ module.exports = __toCommonJS(parseHeaders_exports);
24
24
  function parseHeaders(headers) {
25
25
  const parsed = {};
26
26
  if (!headers) return parsed;
27
+ const addHeader = (key, value) => {
28
+ const k = key.toLowerCase();
29
+ if (parsed[k]) {
30
+ if (Array.isArray(parsed[k])) {
31
+ parsed[k].push(value);
32
+ } else {
33
+ parsed[k] = [parsed[k], value];
34
+ }
35
+ } else {
36
+ parsed[k] = value;
37
+ }
38
+ };
27
39
  if (typeof headers.forEach === "function") {
28
40
  headers.forEach((value, key) => {
29
- parsed[key.toLowerCase()] = value;
41
+ addHeader(key, value);
30
42
  });
31
43
  return parsed;
32
44
  }
@@ -34,16 +46,16 @@ function parseHeaders(headers) {
34
46
  headers.split("\n").forEach((line) => {
35
47
  const index = line.indexOf(":");
36
48
  if (index > 0) {
37
- const key = line.substring(0, index).trim().toLowerCase();
49
+ const key = line.substring(0, index).trim();
38
50
  const value = line.substring(index + 1).trim();
39
- parsed[key] = value;
51
+ addHeader(key, value);
40
52
  }
41
53
  });
42
54
  return parsed;
43
55
  }
44
56
  if (typeof headers === "object") {
45
57
  Object.keys(headers).forEach((key) => {
46
- parsed[key.toLowerCase()] = headers[key];
58
+ addHeader(key, headers[key]);
47
59
  });
48
60
  return parsed;
49
61
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/helpers/parseHeaders.ts"],"sourcesContent":["export default function parseHeaders(headers: any): Record<string, string> {\n const parsed: Record<string, string> = {};\n\n if (!headers) return parsed;\n\n if (typeof headers.forEach === 'function') {\n headers.forEach((value: string, key: string) => {\n parsed[key.toLowerCase()] = value;\n });\n return parsed;\n }\n\n if (typeof headers === 'string') {\n headers.split('\\n').forEach((line: string) => {\n const index = line.indexOf(':');\n if (index > 0) {\n const key = line.substring(0, index).trim().toLowerCase();\n const value = line.substring(index + 1).trim();\n parsed[key] = value;\n }\n });\n return parsed;\n }\n\n if (typeof headers === 'object') {\n Object.keys(headers).forEach((key) => {\n parsed[key.toLowerCase()] = headers[key];\n });\n return parsed;\n }\n\n return parsed;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAe,SAAR,aAA8B,SAAsC;AACzE,QAAM,SAAiC,CAAC;AAExC,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI,OAAO,QAAQ,YAAY,YAAY;AACzC,YAAQ,QAAQ,CAAC,OAAe,QAAgB;AAC9C,aAAO,IAAI,YAAY,CAAC,IAAI;AAAA,IAC9B,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,YAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,SAAiB;AAC5C,YAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,UAAI,QAAQ,GAAG;AACb,cAAM,MAAM,KAAK,UAAU,GAAG,KAAK,EAAE,KAAK,EAAE,YAAY;AACxD,cAAM,QAAQ,KAAK,UAAU,QAAQ,CAAC,EAAE,KAAK;AAC7C,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,QAAQ;AACpC,aAAO,IAAI,YAAY,CAAC,IAAI,QAAQ,GAAG;AAAA,IACzC,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/helpers/parseHeaders.ts"],"sourcesContent":["export default function parseHeaders(headers: any): Record<string, string | string[]> {\n const parsed: Record<string, string | string[]> = {};\n\n if (!headers) return parsed;\n\n const addHeader = (key: string, value: string) => {\n const k = key.toLowerCase();\n if (parsed[k]) {\n if (Array.isArray(parsed[k])) {\n (parsed[k] as string[]).push(value);\n } else {\n parsed[k] = [parsed[k] as string, value];\n }\n } else {\n parsed[k] = value;\n }\n };\n\n if (typeof headers.forEach === 'function') {\n headers.forEach((value: string, key: string) => {\n addHeader(key, value);\n });\n return parsed;\n }\n\n if (typeof headers === 'string') {\n headers.split('\\n').forEach((line: string) => {\n const index = line.indexOf(':');\n if (index > 0) {\n const key = line.substring(0, index).trim();\n const value = line.substring(index + 1).trim();\n addHeader(key, value);\n }\n });\n return parsed;\n }\n\n if (typeof headers === 'object') {\n Object.keys(headers).forEach((key) => {\n addHeader(key, headers[key]);\n });\n return parsed;\n }\n\n return parsed;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAe,SAAR,aAA8B,SAAiD;AACpF,QAAM,SAA4C,CAAC;AAEnD,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,YAAY,CAAC,KAAa,UAAkB;AAChD,UAAM,IAAI,IAAI,YAAY;AAC1B,QAAI,OAAO,CAAC,GAAG;AACb,UAAI,MAAM,QAAQ,OAAO,CAAC,CAAC,GAAG;AAC5B,QAAC,OAAO,CAAC,EAAe,KAAK,KAAK;AAAA,MACpC,OAAO;AACL,eAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAa,KAAK;AAAA,MACzC;AAAA,IACF,OAAO;AACL,aAAO,CAAC,IAAI;AAAA,IACd;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ,YAAY,YAAY;AACzC,YAAQ,QAAQ,CAAC,OAAe,QAAgB;AAC9C,gBAAU,KAAK,KAAK;AAAA,IACtB,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,YAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,SAAiB;AAC5C,YAAM,QAAQ,KAAK,QAAQ,GAAG;AAC9B,UAAI,QAAQ,GAAG;AACb,cAAM,MAAM,KAAK,UAAU,GAAG,KAAK,EAAE,KAAK;AAC1C,cAAM,QAAQ,KAAK,UAAU,QAAQ,CAAC,EAAE,KAAK;AAC7C,kBAAU,KAAK,KAAK;AAAA,MACtB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,KAAK,OAAO,EAAE,QAAQ,CAAC,QAAQ;AACpC,gBAAU,KAAK,QAAQ,GAAG,CAAC;AAAA,IAC7B,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]}
@@ -36,7 +36,10 @@ function createRateLimiter(maxConcurrent = Infinity, maxQueueSize = Infinity) {
36
36
  }
37
37
  let active = 0;
38
38
  let destroyed = false;
39
- const queue = [];
39
+ let head = 0;
40
+ let tail = 0;
41
+ let pendingCount = 0;
42
+ const queue = {};
40
43
  function acquire() {
41
44
  if (destroyed) {
42
45
  return Promise.reject(new Error("[Accessio] Rate limiter has been destroyed"));
@@ -45,30 +48,37 @@ function createRateLimiter(maxConcurrent = Infinity, maxQueueSize = Infinity) {
45
48
  active++;
46
49
  return Promise.resolve();
47
50
  }
48
- if (queue.length >= maxQueueSize) {
51
+ if (pendingCount >= maxQueueSize) {
49
52
  return Promise.reject(
50
53
  new Error(`[Accessio] Rate limiter queue size exceeded maxQueueSize (${maxQueueSize})`)
51
54
  );
52
55
  }
53
56
  return new Promise((resolve, reject) => {
54
- queue.push({ resolve, reject });
57
+ queue[tail++] = { resolve, reject };
58
+ pendingCount++;
55
59
  });
56
60
  }
57
61
  function release() {
58
62
  if (destroyed) return;
59
63
  if (active <= 0) return;
60
64
  active--;
61
- if (queue.length > 0 && active < maxConcurrent) {
65
+ if (pendingCount > 0 && active < maxConcurrent) {
62
66
  active++;
63
- const next = queue.shift();
67
+ const next = queue[head];
68
+ delete queue[head];
69
+ head++;
70
+ pendingCount--;
64
71
  next?.resolve();
65
72
  }
66
73
  }
67
74
  function destroy() {
68
75
  destroyed = true;
69
76
  const reason = new Error("[Accessio] Rate limiter destroyed \u2014 pending request cancelled");
70
- while (queue.length > 0) {
71
- const next = queue.shift();
77
+ while (pendingCount > 0) {
78
+ const next = queue[head];
79
+ delete queue[head];
80
+ head++;
81
+ pendingCount--;
72
82
  next?.reject(reason);
73
83
  }
74
84
  }
@@ -77,7 +87,7 @@ function createRateLimiter(maxConcurrent = Infinity, maxQueueSize = Infinity) {
77
87
  release,
78
88
  destroy,
79
89
  get pending() {
80
- return queue.length;
90
+ return pendingCount;
81
91
  },
82
92
  get active() {
83
93
  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 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\n if (active <= 0) return;\n\n active--;\n\n if (queue.length > 0 && active < maxConcurrent) {\n active++;\n const next = queue.shift();\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 (queue.length > 0) {\n const next = queue.shift();\n next?.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;AAEf,QAAI,UAAU,EAAG;AAEjB;AAEA,QAAI,MAAM,SAAS,KAAK,SAAS,eAAe;AAC9C;AACA,YAAM,OAAO,MAAM,MAAM;AACzB,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAEA,WAAS,UAAgB;AACvB,gBAAY;AACZ,UAAM,SAAS,IAAI,MAAM,oEAA+D;AACxF,WAAO,MAAM,SAAS,GAAG;AACvB,YAAM,OAAO,MAAM,MAAM;AACzB,YAAM,OAAO,MAAM;AAAA,IACrB;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":[]}
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":[]}
@@ -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
- function transformData(transforms, data, headers, config) {
35
+ async function transformData(transforms, data, headers, config) {
36
36
  if (!transforms || !Array.isArray(transforms)) {
37
37
  return data;
38
38
  }
@@ -40,7 +40,7 @@ function transformData(transforms, data, headers, config) {
40
40
  for (const transform of transforms) {
41
41
  if (typeof transform === "function") {
42
42
  try {
43
- result = transform(result, headers);
43
+ result = await transform(result, headers);
44
44
  } catch (err) {
45
45
  throw import_accessioError.default.from(
46
46
  err instanceof Error ? err : new Error(String(err)),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/helpers/transformData.ts"],"sourcesContent":["import AccessioError from '../core/accessioError';\nimport type { TransformFunction, AccessioRequestConfig } from '../types';\n\nexport default function transformData(\n transforms: TransformFunction | TransformFunction[] | undefined,\n data: unknown,\n headers: Record<string, string>,\n config?: AccessioRequestConfig,\n): unknown {\n if (!transforms || !Array.isArray(transforms)) {\n return data;\n }\n\n let result = data;\n\n for (const transform of transforms) {\n if (typeof transform === 'function') {\n try {\n result = transform(result, headers);\n } catch (err) {\n throw AccessioError.from(\n err instanceof Error ? err : new Error(String(err)),\n AccessioError.ERR_BAD_REQUEST,\n config ?? null,\n null,\n null,\n );\n }\n }\n }\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAA0B;AAGX,SAAR,cACL,YACA,MACA,SACA,QACS;AACT,MAAI,CAAC,cAAc,CAAC,MAAM,QAAQ,UAAU,GAAG;AAC7C,WAAO;AAAA,EACT;AAEA,MAAI,SAAS;AAEb,aAAW,aAAa,YAAY;AAClC,QAAI,OAAO,cAAc,YAAY;AACnC,UAAI;AACF,iBAAS,UAAU,QAAQ,OAAO;AAAA,MACpC,SAAS,KAAK;AACZ,cAAM,qBAAAA,QAAc;AAAA,UAClB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAAA,UAClD,qBAAAA,QAAc;AAAA,UACd,UAAU;AAAA,UACV;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":["AccessioError"]}
1
+ {"version":3,"sources":["../../src/helpers/transformData.ts"],"sourcesContent":["import AccessioError from '../core/accessioError';\nimport type { TransformFunction, AccessioRequestConfig } from '../types';\n\nexport default async function transformData(\n transforms: TransformFunction | TransformFunction[] | undefined,\n data: unknown,\n headers: Record<string, string | string[]>,\n config?: AccessioRequestConfig,\n): Promise<unknown> {\n if (!transforms || !Array.isArray(transforms)) {\n return data;\n }\n\n let result = data;\n\n for (const transform of transforms) {\n if (typeof transform === 'function') {\n try {\n result = await transform(result, headers);\n } catch (err) {\n throw AccessioError.from(\n err instanceof Error ? err : new Error(String(err)),\n AccessioError.ERR_BAD_REQUEST,\n config ?? null,\n null,\n null,\n );\n }\n }\n }\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAA0B;AAG1B,eAAO,cACL,YACA,MACA,SACA,QACkB;AAClB,MAAI,CAAC,cAAc,CAAC,MAAM,QAAQ,UAAU,GAAG;AAC7C,WAAO;AAAA,EACT;AAEA,MAAI,SAAS;AAEb,aAAW,aAAa,YAAY;AAClC,QAAI,OAAO,cAAc,YAAY;AACnC,UAAI;AACF,iBAAS,MAAM,UAAU,QAAQ,OAAO;AAAA,MAC1C,SAAS,KAAK;AACZ,cAAM,qBAAAA,QAAc;AAAA,UAClB,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAAA,UAClD,qBAAAA,QAAc;AAAA,UACd,UAAU;AAAA,UACV;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;","names":["AccessioError"]}
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.1",
3
+ "version": "1.2.0",
4
4
  "description": "Fast, flexible HTTP client — simple, modular, and dependency-free",
5
5
  "type": "module",
6
6
  "main": "./cjs/index.cjs",
@@ -29,7 +29,7 @@
29
29
  "./core/buildURL": {
30
30
  "types": "./index.d.ts",
31
31
  "import": "./src/core/buildURL.ts",
32
- "require": "./cjs/helpers/buildURL.cjs"
32
+ "require": "./cjs/core/buildURL.cjs"
33
33
  },
34
34
  "./core/mergeConfig": {
35
35
  "types": "./index.d.ts",
@@ -77,7 +77,7 @@
77
77
  "test": "vitest run",
78
78
  "test:watch": "vitest",
79
79
  "test:coverage": "vitest run --coverage",
80
- "test:browser": "vitest run --config vitest.browser.config.js",
80
+ "test:browser": "vitest run --config vitest.browser.config.ts",
81
81
  "release:npm": "gh workflow run publish-npm.yml -f publish_tag=$(git describe --tags --abbrev=0)",
82
82
  "typecheck": "tsc --noEmit"
83
83
  },
@@ -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,
@@ -52,11 +53,13 @@ export class Accessio {
52
53
 
53
54
  const requestInterceptors: any[] = [];
54
55
  const responseInterceptors: any[] = [];
56
+ let synchronousRequestInterceptors = true;
55
57
 
56
58
  this.interceptors.request.forEach((interceptor: InterceptorHandler) => {
57
59
  if (interceptor.runWhen && !interceptor.runWhen(mergedConfig)) {
58
60
  return;
59
61
  }
62
+ synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
60
63
  requestInterceptors.unshift(interceptor);
61
64
  });
62
65
 
@@ -64,15 +67,51 @@ export class Accessio {
64
67
  responseInterceptors.push(interceptor);
65
68
  });
66
69
 
67
- let promise: Promise<any> = Promise.resolve(mergedConfig);
70
+ let promise: Promise<any>;
68
71
 
69
- for (const interceptor of requestInterceptors) {
70
- promise = promise.then((value: any) => {
71
- if (interceptor.fulfilled) {
72
- return interceptor.fulfilled(value);
72
+ if (synchronousRequestInterceptors) {
73
+ let newConfig = mergedConfig;
74
+ let rejectReason: any = null;
75
+ let isRejected = false;
76
+
77
+ for (const interceptor of requestInterceptors) {
78
+ if (!isRejected) {
79
+ try {
80
+ if (interceptor.fulfilled) {
81
+ newConfig = interceptor.fulfilled(newConfig);
82
+ }
83
+ } catch (err) {
84
+ rejectReason = err;
85
+ isRejected = true;
86
+ }
87
+ } else {
88
+ if (interceptor.rejected) {
89
+ try {
90
+ newConfig = interceptor.rejected(rejectReason);
91
+ isRejected = false;
92
+ } catch (err) {
93
+ rejectReason = err;
94
+ isRejected = true;
95
+ }
96
+ }
73
97
  }
74
- return value;
75
- }, interceptor.rejected);
98
+ }
99
+
100
+ if (isRejected) {
101
+ promise = Promise.reject(rejectReason);
102
+ } else {
103
+ promise = Promise.resolve(newConfig);
104
+ }
105
+ } else {
106
+ promise = Promise.resolve(mergedConfig);
107
+ for (const interceptor of requestInterceptors) {
108
+ promise = promise.then((value: any) => {
109
+ if (interceptor.fulfilled) {
110
+ return interceptor.fulfilled(value);
111
+ }
112
+ return value;
113
+ }, interceptor.rejected);
114
+ }
76
115
  }
77
116
 
78
117
  promise = promise.then((cfg: any) => {
@@ -163,11 +202,12 @@ export class Accessio {
163
202
  data?: any,
164
203
  config?: AccessioRequestConfig,
165
204
  ): Promise<AccessioResponse<T>> {
205
+ const formData = data && !(data instanceof FormData) ? toFormData(data) : data;
166
206
  return this.request<T>(
167
207
  mergeConfig(config || {}, {
168
208
  method: 'post',
169
209
  url,
170
- data,
210
+ data: formData,
171
211
  headers: { 'Content-Type': 'multipart/form-data' },
172
212
  }),
173
213
  );
@@ -178,11 +218,12 @@ export class Accessio {
178
218
  data?: any,
179
219
  config?: AccessioRequestConfig,
180
220
  ): Promise<AccessioResponse<T>> {
221
+ const formData = data && !(data instanceof FormData) ? toFormData(data) : data;
181
222
  return this.request<T>(
182
223
  mergeConfig(config || {}, {
183
224
  method: 'put',
184
225
  url,
185
- data,
226
+ data: formData,
186
227
  headers: { 'Content-Type': 'multipart/form-data' },
187
228
  }),
188
229
  );
@@ -193,15 +234,90 @@ export class Accessio {
193
234
  data?: any,
194
235
  config?: AccessioRequestConfig,
195
236
  ): Promise<AccessioResponse<T>> {
237
+ const formData = data && !(data instanceof FormData) ? toFormData(data) : data;
196
238
  return this.request<T>(
197
239
  mergeConfig(config || {}, {
198
240
  method: 'patch',
199
241
  url,
200
- data,
242
+ data: formData,
201
243
  headers: { 'Content-Type': 'multipart/form-data' },
202
244
  }),
203
245
  );
204
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
+ }
205
321
  }
206
322
 
207
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,