extractia-sdk 1.3.0 → 1.5.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.
@@ -85,41 +85,61 @@ var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")])
85
85
  var index_exports = {};
86
86
  __export(index_exports, {
87
87
  AuthError: () => AuthError,
88
+ ConflictError: () => ConflictError,
88
89
  ExtractiaError: () => ExtractiaError,
89
90
  ForbiddenError: () => ForbiddenError,
91
+ NetworkError: () => NetworkError,
90
92
  NotFoundError: () => NotFoundError,
93
+ QuotaError: () => QuotaError,
91
94
  RateLimitError: () => RateLimitError,
95
+ ServerError: () => ServerError,
92
96
  TierError: () => TierError,
97
+ TimeoutError: () => TimeoutError,
98
+ ValidationError: () => ValidationError,
93
99
  bulkPreconform: () => bulkPreconform,
100
+ clearToken: () => clearToken,
94
101
  configure: () => configure,
95
102
  createOcrTool: () => createOcrTool,
96
103
  createSubUser: () => createSubUser,
97
104
  createTemplate: () => createTemplate,
98
105
  default: () => index_default,
106
+ delay: () => delay,
99
107
  deleteAllTemplateDocuments: () => deleteAllTemplateDocuments,
100
108
  deleteDocument: () => deleteDocument,
101
109
  deleteOcrTool: () => deleteOcrTool,
102
110
  deleteSubUser: () => deleteSubUser,
103
111
  deleteTemplate: () => deleteTemplate,
112
+ ensureBase64: () => ensureBase64,
104
113
  exportDocumentsCsv: () => exportDocumentsCsv,
105
114
  exportDocumentsJson: () => exportDocumentsJson,
115
+ fileToBase64: () => fileToBase64,
106
116
  generateDocumentSummary: () => generateDocumentSummary,
117
+ getConfig: () => getConfig,
107
118
  getCreditsBalance: () => getCreditsBalance,
108
119
  getCreditsHistory: () => getCreditsHistory,
109
120
  getDocumentById: () => getDocumentById,
110
121
  getDocumentHistory: () => getDocumentHistory,
111
122
  getDocumentsByTemplateId: () => getDocumentsByTemplateId,
123
+ getMimeType: () => getMimeType,
112
124
  getMyProfile: () => getMyProfile,
125
+ getOcrToolExecutions: () => getOcrToolExecutions,
113
126
  getOcrTools: () => getOcrTools,
114
127
  getRecentDocuments: () => getRecentDocuments,
115
128
  getSubUsers: () => getSubUsers,
116
129
  getTemplateById: () => getTemplateById,
117
130
  getTemplateByName: () => getTemplateByName,
118
131
  getTemplates: () => getTemplates,
132
+ getToken: () => getToken,
133
+ hasToken: () => hasToken,
134
+ isBase64: () => isBase64,
135
+ mapAxiosError: () => mapAxiosError,
136
+ paginate: () => paginate,
137
+ paginateAll: () => paginateAll,
119
138
  processImage: () => processImage,
120
139
  processImagesMultipage: () => processImagesMultipage,
121
140
  runOcrTool: () => runOcrTool,
122
141
  setToken: () => setToken,
142
+ stripDataUrlPrefix: () => stripDataUrlPrefix,
123
143
  suggestFields: () => suggestFields,
124
144
  toggleSuspendSubUser: () => toggleSuspendSubUser,
125
145
  updateDocumentData: () => updateDocumentData,
@@ -128,7 +148,8 @@ __export(index_exports, {
128
148
  updateOcrTool: () => updateOcrTool,
129
149
  updateSubUser: () => updateSubUser,
130
150
  updateTemplate: () => updateTemplate,
131
- updateWebhook: () => updateWebhook
151
+ updateWebhook: () => updateWebhook,
152
+ withRetry: () => withRetry
132
153
  });
133
154
  module.exports = __toCommonJS(index_exports);
134
155
 
@@ -436,15 +457,15 @@ var _setImmediate = ((setImmediateSupported, postMessageSupported) => {
436
457
  if (setImmediateSupported) {
437
458
  return setImmediate;
438
459
  }
439
- return postMessageSupported ? ((token2, callbacks) => {
460
+ return postMessageSupported ? ((token, callbacks) => {
440
461
  _global.addEventListener("message", ({ source, data }) => {
441
- if (source === _global && data === token2) {
462
+ if (source === _global && data === token) {
442
463
  callbacks.length && callbacks.shift()();
443
464
  }
444
465
  }, false);
445
466
  return (cb) => {
446
467
  callbacks.push(cb);
447
- _global.postMessage(token2, "*");
468
+ _global.postMessage(token, "*");
448
469
  };
449
470
  })(`axios@${Math.random()}`, []) : (cb) => setTimeout(cb);
450
471
  })(
@@ -600,9 +621,9 @@ function removeBrackets(key) {
600
621
  }
601
622
  function renderKey(path, key, dots) {
602
623
  if (!path) return key;
603
- return path.concat(key).map(function each(token2, i) {
604
- token2 = removeBrackets(token2);
605
- return !dots && i ? "[" + token2 + "]" : token2;
624
+ return path.concat(key).map(function each(token, i) {
625
+ token = removeBrackets(token);
626
+ return !dots && i ? "[" + token + "]" : token;
606
627
  }).join(dots ? "." : "");
607
628
  }
608
629
  function isFlatArray(arr) {
@@ -1645,7 +1666,7 @@ var resolveConfig_default = (config) => {
1645
1666
  if (platform_default.hasStandardBrowserEnv || platform_default.hasStandardBrowserWebWorkerEnv) {
1646
1667
  headers.setContentType(void 0);
1647
1668
  } else if ((contentType = headers.getContentType()) !== false) {
1648
- const [type, ...tokens] = contentType ? contentType.split(";").map((token2) => token2.trim()).filter(Boolean) : [];
1669
+ const [type, ...tokens] = contentType ? contentType.split(";").map((token) => token.trim()).filter(Boolean) : [];
1649
1670
  headers.setContentType([type || "multipart/form-data", ...tokens].join("; "));
1650
1671
  }
1651
1672
  }
@@ -1665,22 +1686,22 @@ var resolveConfig_default = (config) => {
1665
1686
  var isXHRAdapterSupported = typeof XMLHttpRequest !== "undefined";
1666
1687
  var xhr_default = isXHRAdapterSupported && function(config) {
1667
1688
  return new Promise(function dispatchXhrRequest(resolve, reject) {
1668
- const _config = resolveConfig_default(config);
1669
- let requestData = _config.data;
1670
- const requestHeaders = AxiosHeaders_default.from(_config.headers).normalize();
1671
- let { responseType, onUploadProgress, onDownloadProgress } = _config;
1689
+ const _config2 = resolveConfig_default(config);
1690
+ let requestData = _config2.data;
1691
+ const requestHeaders = AxiosHeaders_default.from(_config2.headers).normalize();
1692
+ let { responseType, onUploadProgress, onDownloadProgress } = _config2;
1672
1693
  let onCanceled;
1673
1694
  let uploadThrottled, downloadThrottled;
1674
1695
  let flushUpload, flushDownload;
1675
1696
  function done() {
1676
1697
  flushUpload && flushUpload();
1677
1698
  flushDownload && flushDownload();
1678
- _config.cancelToken && _config.cancelToken.unsubscribe(onCanceled);
1679
- _config.signal && _config.signal.removeEventListener("abort", onCanceled);
1699
+ _config2.cancelToken && _config2.cancelToken.unsubscribe(onCanceled);
1700
+ _config2.signal && _config2.signal.removeEventListener("abort", onCanceled);
1680
1701
  }
1681
1702
  let request = new XMLHttpRequest();
1682
- request.open(_config.method.toUpperCase(), _config.url, true);
1683
- request.timeout = _config.timeout;
1703
+ request.open(_config2.method.toUpperCase(), _config2.url, true);
1704
+ request.timeout = _config2.timeout;
1684
1705
  function onloadend() {
1685
1706
  if (!request) {
1686
1707
  return;
@@ -1731,10 +1752,10 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1731
1752
  request = null;
1732
1753
  };
1733
1754
  request.ontimeout = function handleTimeout() {
1734
- let timeoutErrorMessage = _config.timeout ? "timeout of " + _config.timeout + "ms exceeded" : "timeout exceeded";
1735
- const transitional2 = _config.transitional || transitional_default;
1736
- if (_config.timeoutErrorMessage) {
1737
- timeoutErrorMessage = _config.timeoutErrorMessage;
1755
+ let timeoutErrorMessage = _config2.timeout ? "timeout of " + _config2.timeout + "ms exceeded" : "timeout exceeded";
1756
+ const transitional2 = _config2.transitional || transitional_default;
1757
+ if (_config2.timeoutErrorMessage) {
1758
+ timeoutErrorMessage = _config2.timeoutErrorMessage;
1738
1759
  }
1739
1760
  reject(new AxiosError_default(
1740
1761
  timeoutErrorMessage,
@@ -1750,11 +1771,11 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1750
1771
  request.setRequestHeader(key, val);
1751
1772
  });
1752
1773
  }
1753
- if (!utils_default.isUndefined(_config.withCredentials)) {
1754
- request.withCredentials = !!_config.withCredentials;
1774
+ if (!utils_default.isUndefined(_config2.withCredentials)) {
1775
+ request.withCredentials = !!_config2.withCredentials;
1755
1776
  }
1756
1777
  if (responseType && responseType !== "json") {
1757
- request.responseType = _config.responseType;
1778
+ request.responseType = _config2.responseType;
1758
1779
  }
1759
1780
  if (onDownloadProgress) {
1760
1781
  [downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true);
@@ -1765,7 +1786,7 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1765
1786
  request.upload.addEventListener("progress", uploadThrottled);
1766
1787
  request.upload.addEventListener("loadend", flushUpload);
1767
1788
  }
1768
- if (_config.cancelToken || _config.signal) {
1789
+ if (_config2.cancelToken || _config2.signal) {
1769
1790
  onCanceled = (cancel) => {
1770
1791
  if (!request) {
1771
1792
  return;
@@ -1774,12 +1795,12 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1774
1795
  request.abort();
1775
1796
  request = null;
1776
1797
  };
1777
- _config.cancelToken && _config.cancelToken.subscribe(onCanceled);
1778
- if (_config.signal) {
1779
- _config.signal.aborted ? onCanceled() : _config.signal.addEventListener("abort", onCanceled);
1798
+ _config2.cancelToken && _config2.cancelToken.subscribe(onCanceled);
1799
+ if (_config2.signal) {
1800
+ _config2.signal.aborted ? onCanceled() : _config2.signal.addEventListener("abort", onCanceled);
1780
1801
  }
1781
1802
  }
1782
- const protocol = parseProtocol(_config.url);
1803
+ const protocol = parseProtocol(_config2.url);
1783
1804
  if (protocol && platform_default.protocols.indexOf(protocol) === -1) {
1784
1805
  reject(new AxiosError_default("Unsupported protocol " + protocol + ":", AxiosError_default.ERR_BAD_REQUEST, config));
1785
1806
  return;
@@ -2429,32 +2450,32 @@ var CancelToken = class _CancelToken {
2429
2450
  this.promise = new Promise(function promiseExecutor(resolve) {
2430
2451
  resolvePromise = resolve;
2431
2452
  });
2432
- const token2 = this;
2453
+ const token = this;
2433
2454
  this.promise.then((cancel) => {
2434
- if (!token2._listeners) return;
2435
- let i = token2._listeners.length;
2455
+ if (!token._listeners) return;
2456
+ let i = token._listeners.length;
2436
2457
  while (i-- > 0) {
2437
- token2._listeners[i](cancel);
2458
+ token._listeners[i](cancel);
2438
2459
  }
2439
- token2._listeners = null;
2460
+ token._listeners = null;
2440
2461
  });
2441
2462
  this.promise.then = (onfulfilled) => {
2442
2463
  let _resolve;
2443
2464
  const promise = new Promise((resolve) => {
2444
- token2.subscribe(resolve);
2465
+ token.subscribe(resolve);
2445
2466
  _resolve = resolve;
2446
2467
  }).then(onfulfilled);
2447
2468
  promise.cancel = function reject() {
2448
- token2.unsubscribe(_resolve);
2469
+ token.unsubscribe(_resolve);
2449
2470
  };
2450
2471
  return promise;
2451
2472
  };
2452
2473
  executor(function cancel(message, config, request) {
2453
- if (token2.reason) {
2474
+ if (token.reason) {
2454
2475
  return;
2455
2476
  }
2456
- token2.reason = new CanceledError_default(message, config, request);
2457
- resolvePromise(token2.reason);
2477
+ token.reason = new CanceledError_default(message, config, request);
2478
+ resolvePromise(token.reason);
2458
2479
  });
2459
2480
  }
2460
2481
  /**
@@ -2506,11 +2527,11 @@ var CancelToken = class _CancelToken {
2506
2527
  */
2507
2528
  static source() {
2508
2529
  let cancel;
2509
- const token2 = new _CancelToken(function executor(c) {
2530
+ const token = new _CancelToken(function executor(c) {
2510
2531
  cancel = c;
2511
2532
  });
2512
2533
  return {
2513
- token: token2,
2534
+ token,
2514
2535
  cancel
2515
2536
  };
2516
2537
  }
@@ -2654,93 +2675,356 @@ var {
2654
2675
  } = axios_default;
2655
2676
 
2656
2677
  // src/errors.js
2678
+ var STATUS_MESSAGES = {
2679
+ 400: "The request contains invalid data. Please check your input.",
2680
+ 401: "Your API token is invalid or has expired. Please check your credentials.",
2681
+ 402: "Your current plan does not support this feature or your document quota is exhausted.",
2682
+ 403: "You do not have permission to perform this action.",
2683
+ 404: "The requested resource could not be found.",
2684
+ 409: "A resource with this identifier already exists.",
2685
+ 429: "Too many requests. Please wait a moment and try again.",
2686
+ 500: "The server encountered an unexpected error. Please try again in a moment.",
2687
+ 502: "The server received an unexpected response. Please try again.",
2688
+ 503: "The service is temporarily unavailable. Please try again in a few minutes.",
2689
+ 504: "The server timed out while processing the request. Please try again."
2690
+ };
2657
2691
  var ExtractiaError = class extends Error {
2658
- /** @param {string} message @param {number} status */
2659
- constructor(message, status) {
2692
+ /**
2693
+ * @param {string} message Technical detail string.
2694
+ * @param {number} [status] — HTTP status code (0 = no response).
2695
+ * @param {string} [userMessage] — Human-friendly sentence shown to end users.
2696
+ * @param {string} [code] — Machine-readable error code.
2697
+ */
2698
+ constructor(message, status = 0, userMessage = null, code = "SDK_ERROR") {
2660
2699
  super(message);
2661
2700
  this.name = "ExtractiaError";
2662
2701
  this.status = status;
2702
+ this.userMessage = userMessage != null ? userMessage : message;
2703
+ this.code = code;
2704
+ this.requestId = null;
2705
+ }
2706
+ /** Returns true if automatically retrying the same request may succeed. */
2707
+ isRetryable() {
2708
+ return this.status === 429 || this.status >= 500;
2709
+ }
2710
+ toJSON() {
2711
+ return {
2712
+ name: this.name,
2713
+ code: this.code,
2714
+ status: this.status,
2715
+ message: this.message,
2716
+ userMessage: this.userMessage,
2717
+ requestId: this.requestId
2718
+ };
2663
2719
  }
2664
2720
  };
2665
2721
  var AuthError = class extends ExtractiaError {
2666
- constructor(message = "Unauthorized. Check your API token.") {
2667
- super(message, 401);
2722
+ constructor(message = STATUS_MESSAGES[401]) {
2723
+ super(message, 401, STATUS_MESSAGES[401], "AUTH_ERROR");
2668
2724
  this.name = "AuthError";
2669
2725
  }
2670
2726
  };
2671
2727
  var ForbiddenError = class extends ExtractiaError {
2672
- constructor(message = "Forbidden. Insufficient permissions.") {
2673
- super(message, 403);
2728
+ constructor(message = STATUS_MESSAGES[403]) {
2729
+ super(message, 403, STATUS_MESSAGES[403], "FORBIDDEN");
2674
2730
  this.name = "ForbiddenError";
2675
2731
  }
2676
2732
  };
2677
2733
  var TierError = class extends ExtractiaError {
2678
- constructor(message = "Tier limit reached. Upgrade your plan.", status = 402) {
2679
- super(message, status);
2734
+ constructor(message = STATUS_MESSAGES[402], status = 402) {
2735
+ super(message, status, STATUS_MESSAGES[402], "TIER_LIMIT");
2680
2736
  this.name = "TierError";
2681
2737
  }
2682
2738
  };
2739
+ var QuotaError = class extends ExtractiaError {
2740
+ constructor(message = "You have reached your document processing quota for this billing period. Please upgrade or wait for the next cycle.") {
2741
+ super(message, 402, message, "QUOTA_EXCEEDED");
2742
+ this.name = "QuotaError";
2743
+ }
2744
+ };
2683
2745
  var RateLimitError = class extends ExtractiaError {
2684
- constructor(message = "Too many requests. Please slow down.") {
2685
- super(message, 429);
2746
+ /**
2747
+ * @param {string} [message]
2748
+ * @param {number|null} [retryAfter] — Seconds to wait before retrying (from Retry-After header).
2749
+ */
2750
+ constructor(message = STATUS_MESSAGES[429], retryAfter = null) {
2751
+ super(message, 429, STATUS_MESSAGES[429], "RATE_LIMITED");
2686
2752
  this.name = "RateLimitError";
2753
+ this.retryAfter = retryAfter;
2754
+ }
2755
+ isRetryable() {
2756
+ return true;
2687
2757
  }
2688
2758
  };
2689
2759
  var NotFoundError = class extends ExtractiaError {
2690
- constructor(message = "Resource not found.") {
2691
- super(message, 404);
2760
+ constructor(message = STATUS_MESSAGES[404]) {
2761
+ super(message, 404, STATUS_MESSAGES[404], "NOT_FOUND");
2692
2762
  this.name = "NotFoundError";
2693
2763
  }
2694
2764
  };
2765
+ var ValidationError = class extends ExtractiaError {
2766
+ /**
2767
+ * @param {string} [message]
2768
+ * @param {Record<string,string>|null} [fields] — Field-level errors, if the server provides them.
2769
+ */
2770
+ constructor(message = STATUS_MESSAGES[400], fields = null) {
2771
+ super(message, 400, STATUS_MESSAGES[400], "VALIDATION_ERROR");
2772
+ this.name = "ValidationError";
2773
+ this.fields = fields;
2774
+ }
2775
+ };
2776
+ var ConflictError = class extends ExtractiaError {
2777
+ constructor(message = STATUS_MESSAGES[409]) {
2778
+ super(message, 409, STATUS_MESSAGES[409], "CONFLICT");
2779
+ this.name = "ConflictError";
2780
+ }
2781
+ };
2782
+ var ServerError = class extends ExtractiaError {
2783
+ constructor(message = STATUS_MESSAGES[500], status = 500) {
2784
+ var _a;
2785
+ super(
2786
+ message,
2787
+ status,
2788
+ (_a = STATUS_MESSAGES[status]) != null ? _a : STATUS_MESSAGES[500],
2789
+ "SERVER_ERROR"
2790
+ );
2791
+ this.name = "ServerError";
2792
+ }
2793
+ isRetryable() {
2794
+ return true;
2795
+ }
2796
+ };
2797
+ var NetworkError = class extends ExtractiaError {
2798
+ constructor(message = "Unable to reach the Extractia API. Please check your network connection and try again.") {
2799
+ super(message, 0, message, "NETWORK_ERROR");
2800
+ this.name = "NetworkError";
2801
+ }
2802
+ isRetryable() {
2803
+ return true;
2804
+ }
2805
+ };
2806
+ var TimeoutError = class extends ExtractiaError {
2807
+ constructor(message = "The request timed out. The server may be under heavy load \u2014 please try again in a moment.") {
2808
+ super(message, 0, message, "TIMEOUT");
2809
+ this.name = "TimeoutError";
2810
+ }
2811
+ isRetryable() {
2812
+ return true;
2813
+ }
2814
+ };
2815
+ function extractServerDetail(data) {
2816
+ var _a, _b, _c, _d, _e;
2817
+ if (!data) return null;
2818
+ if (typeof data === "string" && data.trim()) return data.trim();
2819
+ if (typeof data === "object") {
2820
+ const msg = (_c = (_b = (_a = data.message) != null ? _a : data.error) != null ? _b : data.detail) != null ? _c : data.title;
2821
+ if (msg && typeof msg === "string") return msg.trim();
2822
+ if (Array.isArray(data.errors) && data.errors.length > 0) {
2823
+ const first = data.errors[0];
2824
+ return typeof first === "string" ? first : (_e = (_d = first.message) != null ? _d : first.msg) != null ? _e : JSON.stringify(first);
2825
+ }
2826
+ if (Array.isArray(data.fieldErrors) && data.fieldErrors.length > 0) {
2827
+ return data.fieldErrors.map((e) => {
2828
+ var _a2, _b2;
2829
+ return `${(_a2 = e.field) != null ? _a2 : "field"}: ${(_b2 = e.message) != null ? _b2 : e.defaultMessage}`;
2830
+ }).join("; ");
2831
+ }
2832
+ }
2833
+ return null;
2834
+ }
2695
2835
  function mapAxiosError(err) {
2696
- var _a, _b;
2697
- const status = (_a = err.response) == null ? void 0 : _a.status;
2698
- const serverMessage = (_b = err.response) == null ? void 0 : _b.data;
2699
- const detail = typeof serverMessage === "string" ? serverMessage : void 0;
2836
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2837
+ if (!err.response) {
2838
+ if (err.code === "ECONNABORTED" || err.code === "ETIMEDOUT" || err.message && err.message.toLowerCase().includes("timeout")) {
2839
+ return new TimeoutError();
2840
+ }
2841
+ return new NetworkError(err.message || void 0);
2842
+ }
2843
+ const status = err.response.status;
2844
+ const detail = extractServerDetail(err.response.data);
2845
+ const userMessage = (_a = STATUS_MESSAGES[status]) != null ? _a : status >= 500 ? STATUS_MESSAGES[500] : "Something went wrong. Please try again.";
2846
+ let error;
2700
2847
  switch (status) {
2848
+ case 400: {
2849
+ const body = err.response.data;
2850
+ const fields = (_b = body == null ? void 0 : body.fields) != null ? _b : Array.isArray(body == null ? void 0 : body.fieldErrors) ? Object.fromEntries(
2851
+ body.fieldErrors.map((f) => {
2852
+ var _a2;
2853
+ return [
2854
+ f.field,
2855
+ (_a2 = f.message) != null ? _a2 : f.defaultMessage
2856
+ ];
2857
+ })
2858
+ ) : null;
2859
+ error = new ValidationError(detail != null ? detail : STATUS_MESSAGES[400], fields);
2860
+ break;
2861
+ }
2701
2862
  case 401:
2702
- return new AuthError(detail);
2863
+ error = new AuthError(detail != null ? detail : void 0);
2864
+ break;
2703
2865
  case 402:
2704
- return new TierError(detail);
2866
+ if (detail && (detail.toLowerCase().includes("quota") || detail.toLowerCase().includes("document") || detail.toLowerCase().includes("limit reached"))) {
2867
+ error = new QuotaError(detail);
2868
+ } else {
2869
+ error = new TierError(detail != null ? detail : void 0);
2870
+ }
2871
+ break;
2705
2872
  case 403:
2706
- return new ForbiddenError(detail);
2873
+ error = new ForbiddenError(detail != null ? detail : void 0);
2874
+ break;
2707
2875
  case 404:
2708
- return new NotFoundError(detail);
2709
- case 429:
2710
- return new RateLimitError(detail);
2876
+ error = new NotFoundError(detail != null ? detail : void 0);
2877
+ break;
2878
+ case 409:
2879
+ error = new ConflictError(detail != null ? detail : void 0);
2880
+ break;
2881
+ case 429: {
2882
+ const retryAfterHeader = (_c = err.response.headers) == null ? void 0 : _c["retry-after"];
2883
+ const retryAfter = retryAfterHeader != null ? parseInt(retryAfterHeader, 10) : null;
2884
+ error = new RateLimitError(
2885
+ detail != null ? detail : void 0,
2886
+ isNaN(retryAfter) ? null : retryAfter
2887
+ );
2888
+ break;
2889
+ }
2711
2890
  default:
2712
- return new ExtractiaError(detail != null ? detail : err.message, status != null ? status : 0);
2891
+ if (status >= 500) {
2892
+ error = new ServerError(
2893
+ (_d = detail != null ? detail : STATUS_MESSAGES[status]) != null ? _d : STATUS_MESSAGES[500],
2894
+ status
2895
+ );
2896
+ } else {
2897
+ error = new ExtractiaError(
2898
+ detail != null ? detail : err.message,
2899
+ status,
2900
+ userMessage,
2901
+ `HTTP_${status}`
2902
+ );
2903
+ }
2713
2904
  }
2905
+ error.userMessage = userMessage;
2906
+ const reqId = (_h = (_g = (_e = err.response.headers) == null ? void 0 : _e["x-request-id"]) != null ? _g : (_f = err.response.headers) == null ? void 0 : _f["x-correlation-id"]) != null ? _h : null;
2907
+ if (reqId) error.requestId = reqId;
2908
+ return error;
2714
2909
  }
2715
2910
 
2716
2911
  // src/apiClient.js
2717
- var token = null;
2718
- var DEFAULT_BASE_URL = "https://api.extractia.info/api/public";
2719
- var api = axios_default.create({
2720
- baseURL: DEFAULT_BASE_URL,
2721
- timeout: 6e4
2722
- // 60s — AI processing can take 10–30s
2912
+ var _token = null;
2913
+ var _config = {
2914
+ baseURL: "https://api.extractia.info/api/public",
2915
+ timeout: 6e4,
2916
+ retries: 1,
2917
+ retryDelay: 1e3,
2918
+ debug: false,
2919
+ defaultHeaders: {},
2920
+ onBeforeRequest: null,
2921
+ onAfterResponse: null,
2922
+ onError: null
2923
+ };
2924
+ var _api = axios_default.create({
2925
+ baseURL: _config.baseURL,
2926
+ timeout: _config.timeout
2723
2927
  });
2724
- api.interceptors.request.use((config) => {
2725
- if (!token) {
2726
- throw new Error(
2727
- "API token is required. Call setToken(yourApiToken) before making requests."
2928
+ _api.interceptors.request.use((config) => {
2929
+ var _a, _b, _c, _d, _e;
2930
+ if (!_token) {
2931
+ const err = new ExtractiaError(
2932
+ "API token not set. Call setToken(token) before making requests.",
2933
+ 0,
2934
+ "API token not set. Call setToken(token) before making requests.",
2935
+ "TOKEN_MISSING"
2936
+ );
2937
+ return Promise.reject(err);
2938
+ }
2939
+ config.headers = (_a = config.headers) != null ? _a : {};
2940
+ config.headers["Authorization"] = `Bearer ${_token}`;
2941
+ Object.assign(config.headers, _config.defaultHeaders);
2942
+ if (_config.debug) {
2943
+ console.debug(
2944
+ `[ExtractIA SDK] \u2192 ${((_b = config.method) != null ? _b : "GET").toUpperCase()} ${(_c = config.baseURL) != null ? _c : ""}${(_d = config.url) != null ? _d : ""}`,
2945
+ (_e = config.params) != null ? _e : ""
2728
2946
  );
2729
2947
  }
2730
- config.headers.Authorization = `Bearer ${token}`;
2948
+ if (typeof _config.onBeforeRequest === "function") {
2949
+ const modified = _config.onBeforeRequest(config);
2950
+ return modified != null ? modified : config;
2951
+ }
2731
2952
  return config;
2732
2953
  });
2733
- api.interceptors.response.use(
2734
- (response) => response,
2735
- (err) => Promise.reject(mapAxiosError(err))
2954
+ _api.interceptors.response.use(
2955
+ (response) => {
2956
+ var _a, _b;
2957
+ if (_config.debug) {
2958
+ console.debug(
2959
+ `[ExtractIA SDK] \u2190 ${response.status} ${(_b = (_a = response.config) == null ? void 0 : _a.url) != null ? _b : ""}`
2960
+ );
2961
+ }
2962
+ if (typeof _config.onAfterResponse === "function") {
2963
+ _config.onAfterResponse(response);
2964
+ }
2965
+ return response;
2966
+ },
2967
+ async (err) => {
2968
+ var _a, _b;
2969
+ if (err instanceof ExtractiaError) {
2970
+ if (typeof _config.onError === "function") _config.onError(err);
2971
+ return Promise.reject(err);
2972
+ }
2973
+ const mapped = mapAxiosError(err);
2974
+ const cfg = err.config;
2975
+ if (cfg && mapped.isRetryable() && ((_a = cfg._retryCount) != null ? _a : 0) < _config.retries) {
2976
+ cfg._retryCount = ((_b = cfg._retryCount) != null ? _b : 0) + 1;
2977
+ const delayMs = mapped.retryAfter != null ? mapped.retryAfter * 1e3 : _config.retryDelay * cfg._retryCount;
2978
+ if (_config.debug) {
2979
+ console.debug(
2980
+ `[ExtractIA SDK] retrying (${cfg._retryCount}/${_config.retries}) in ${delayMs}ms\u2026`
2981
+ );
2982
+ }
2983
+ await new Promise((r) => setTimeout(r, delayMs));
2984
+ return _api(cfg);
2985
+ }
2986
+ if (typeof _config.onError === "function") _config.onError(mapped);
2987
+ return Promise.reject(mapped);
2988
+ }
2736
2989
  );
2737
- function setToken(newToken) {
2738
- token = newToken;
2990
+ function setToken(token) {
2991
+ if (!token || typeof token !== "string" || !token.trim()) {
2992
+ throw new Error("setToken: token must be a non-empty string.");
2993
+ }
2994
+ _token = token.trim();
2995
+ }
2996
+ function getToken() {
2997
+ return _token;
2998
+ }
2999
+ function hasToken() {
3000
+ return Boolean(_token);
3001
+ }
3002
+ function clearToken() {
3003
+ _token = null;
3004
+ }
3005
+ function configure(opts = {}) {
3006
+ if (opts.baseURL) {
3007
+ _config.baseURL = opts.baseURL;
3008
+ _api.defaults.baseURL = opts.baseURL;
3009
+ }
3010
+ if (opts.timeout != null) {
3011
+ _config.timeout = opts.timeout;
3012
+ _api.defaults.timeout = opts.timeout;
3013
+ }
3014
+ if (opts.retries != null) _config.retries = opts.retries;
3015
+ if (opts.retryDelay != null) _config.retryDelay = opts.retryDelay;
3016
+ if (opts.debug != null) _config.debug = Boolean(opts.debug);
3017
+ if (opts.defaultHeaders) {
3018
+ _config.defaultHeaders = __spreadValues(__spreadValues({}, _config.defaultHeaders), opts.defaultHeaders);
3019
+ }
3020
+ if (opts.onBeforeRequest) _config.onBeforeRequest = opts.onBeforeRequest;
3021
+ if (opts.onAfterResponse) _config.onAfterResponse = opts.onAfterResponse;
3022
+ if (opts.onError) _config.onError = opts.onError;
2739
3023
  }
2740
- function configure({ baseURL } = {}) {
2741
- if (baseURL) api.defaults.baseURL = baseURL;
3024
+ function getConfig() {
3025
+ return __spreadValues({}, _config);
2742
3026
  }
2743
- var apiClient_default = api;
3027
+ var apiClient_default = _api;
2744
3028
 
2745
3029
  // src/auth.js
2746
3030
  async function getMyProfile() {
@@ -2927,6 +3211,7 @@ var ocrTools_exports = {};
2927
3211
  __export(ocrTools_exports, {
2928
3212
  createOcrTool: () => createOcrTool,
2929
3213
  deleteOcrTool: () => deleteOcrTool,
3214
+ getOcrToolExecutions: () => getOcrToolExecutions,
2930
3215
  getOcrTools: () => getOcrTools,
2931
3216
  runOcrTool: () => runOcrTool,
2932
3217
  updateOcrTool: () => updateOcrTool
@@ -2955,6 +3240,16 @@ async function runOcrTool(id, base64Image, options = {}) {
2955
3240
  const res = await apiClient_default.post(`/ocr-tools/${id}/run`, body);
2956
3241
  return res.data;
2957
3242
  }
3243
+ async function getOcrToolExecutions({
3244
+ toolId,
3245
+ page = 0,
3246
+ size = 20
3247
+ } = {}) {
3248
+ const params = { page, size };
3249
+ if (toolId) params.toolId = toolId;
3250
+ const res = await apiClient_default.get("/ocr-tools/executions", { params });
3251
+ return res.data;
3252
+ }
2958
3253
 
2959
3254
  // src/subusers.js
2960
3255
  var subusers_exports = {};
@@ -2969,8 +3264,17 @@ async function getSubUsers() {
2969
3264
  const res = await apiClient_default.get("/me/subusers");
2970
3265
  return res.data;
2971
3266
  }
2972
- async function createSubUser({ username, password, permissions }) {
2973
- const res = await apiClient_default.post("/me/subusers", { username, password, permissions });
3267
+ async function createSubUser({
3268
+ username,
3269
+ password,
3270
+ permissions,
3271
+ allowedFormIds
3272
+ }) {
3273
+ const res = await apiClient_default.post("/me/subusers", __spreadValues({
3274
+ username,
3275
+ password,
3276
+ permissions
3277
+ }, allowedFormIds !== void 0 ? { allowedFormIds } : {}));
2974
3278
  return res.data;
2975
3279
  }
2976
3280
  async function deleteSubUser(username) {
@@ -2978,15 +3282,146 @@ async function deleteSubUser(username) {
2978
3282
  return res.data;
2979
3283
  }
2980
3284
  async function updateSubUser(username, updates = {}) {
2981
- const res = await apiClient_default.put(`/me/subusers/${encodeURIComponent(username)}`, updates);
3285
+ const res = await apiClient_default.put(
3286
+ `/me/subusers/${encodeURIComponent(username)}`,
3287
+ updates
3288
+ );
2982
3289
  return res.data;
2983
3290
  }
2984
3291
  async function toggleSuspendSubUser(username) {
2985
- const res = await apiClient_default.put(`/me/subusers/${encodeURIComponent(username)}/suspend`);
3292
+ const res = await apiClient_default.put(
3293
+ `/me/subusers/${encodeURIComponent(username)}/suspend`
3294
+ );
2986
3295
  return res.data;
2987
3296
  }
2988
3297
 
3298
+ // src/utils.js
3299
+ var utils_exports2 = {};
3300
+ __export(utils_exports2, {
3301
+ delay: () => delay,
3302
+ ensureBase64: () => ensureBase64,
3303
+ fileToBase64: () => fileToBase64,
3304
+ getMimeType: () => getMimeType,
3305
+ isBase64: () => isBase64,
3306
+ paginate: () => paginate,
3307
+ paginateAll: () => paginateAll,
3308
+ stripDataUrlPrefix: () => stripDataUrlPrefix,
3309
+ withRetry: () => withRetry
3310
+ });
3311
+ function fileToBase64(file) {
3312
+ if (typeof FileReader === "undefined") {
3313
+ return Promise.reject(
3314
+ new Error(
3315
+ "fileToBase64: FileReader is not available in this environment. In Node.js, read the file manually and encode it with Buffer.from(data).toString('base64')."
3316
+ )
3317
+ );
3318
+ }
3319
+ return new Promise((resolve, reject) => {
3320
+ const reader = new FileReader();
3321
+ reader.onload = () => resolve(
3322
+ /** @type {string} */
3323
+ reader.result
3324
+ );
3325
+ reader.onerror = () => {
3326
+ var _a;
3327
+ return reject(
3328
+ new Error(
3329
+ `fileToBase64: failed to read file "${(_a = file.name) != null ? _a : "unknown"}".`
3330
+ )
3331
+ );
3332
+ };
3333
+ reader.readAsDataURL(file);
3334
+ });
3335
+ }
3336
+ function stripDataUrlPrefix(base64OrDataUrl) {
3337
+ if (typeof base64OrDataUrl !== "string") {
3338
+ throw new TypeError("stripDataUrlPrefix: argument must be a string.");
3339
+ }
3340
+ const idx = base64OrDataUrl.indexOf(";base64,");
3341
+ return idx !== -1 ? base64OrDataUrl.slice(idx + 8) : base64OrDataUrl;
3342
+ }
3343
+ function getMimeType(dataUrl) {
3344
+ if (typeof dataUrl !== "string") return null;
3345
+ const match = dataUrl.match(/^data:([^;]+);base64,/);
3346
+ return match ? match[1] : null;
3347
+ }
3348
+ function isBase64(str) {
3349
+ if (typeof str !== "string" || !str.trim()) return false;
3350
+ const raw = stripDataUrlPrefix(str);
3351
+ return raw.length > 0 && raw.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(raw);
3352
+ }
3353
+ async function ensureBase64(fileOrBase64) {
3354
+ if (typeof fileOrBase64 === "string") return fileOrBase64;
3355
+ if (typeof File !== "undefined" && fileOrBase64 instanceof File || typeof Blob !== "undefined" && fileOrBase64 instanceof Blob) {
3356
+ return fileToBase64(fileOrBase64);
3357
+ }
3358
+ throw new TypeError(
3359
+ "ensureBase64: argument must be a File, Blob, or a base64 string."
3360
+ );
3361
+ }
3362
+ function paginate(_0) {
3363
+ return __asyncGenerator(this, arguments, function* (fn, { size = 50, startPage = 0, maxPages = 1e3 } = {}) {
3364
+ var _a;
3365
+ let page = startPage;
3366
+ let pagesRead = 0;
3367
+ while (pagesRead < maxPages) {
3368
+ const result = yield new __await(fn({ page, size }));
3369
+ const items = Array.isArray(result == null ? void 0 : result.content) ? result.content : [];
3370
+ for (const item of items) yield item;
3371
+ const totalPages = (_a = result == null ? void 0 : result.totalPages) != null ? _a : 1;
3372
+ if (items.length === 0 || page + 1 >= totalPages) break;
3373
+ page++;
3374
+ pagesRead++;
3375
+ }
3376
+ });
3377
+ }
3378
+ async function paginateAll(fn, opts) {
3379
+ const items = [];
3380
+ try {
3381
+ for (var iter = __forAwait(paginate(fn, opts)), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
3382
+ const item = temp.value;
3383
+ items.push(item);
3384
+ }
3385
+ } catch (temp) {
3386
+ error = [temp];
3387
+ } finally {
3388
+ try {
3389
+ more && (temp = iter.return) && await temp.call(iter);
3390
+ } finally {
3391
+ if (error)
3392
+ throw error[0];
3393
+ }
3394
+ }
3395
+ return items;
3396
+ }
3397
+ function delay(ms) {
3398
+ return new Promise((resolve) => setTimeout(resolve, ms));
3399
+ }
3400
+ async function withRetry(fn, { retries = 3, initialDelay = 500, shouldRetry } = {}) {
3401
+ const isRetryable = shouldRetry != null ? shouldRetry : (err) => typeof err.isRetryable === "function" && err.isRetryable();
3402
+ let lastErr;
3403
+ for (let attempt = 0; attempt <= retries; attempt++) {
3404
+ try {
3405
+ return await fn();
3406
+ } catch (err) {
3407
+ lastErr = err;
3408
+ if (attempt < retries && isRetryable(err)) {
3409
+ const wait = err.retryAfter != null ? err.retryAfter * 1e3 : initialDelay * 2 ** attempt;
3410
+ await delay(wait);
3411
+ continue;
3412
+ }
3413
+ throw err;
3414
+ }
3415
+ }
3416
+ throw lastErr;
3417
+ }
3418
+
2989
3419
  // src/index.js
2990
- var extractia = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, auth_exports), templates_exports), documents_exports), analytics_exports), ocrTools_exports), subusers_exports);
3420
+ var extractia = __spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, auth_exports), templates_exports), documents_exports), analytics_exports), ocrTools_exports), subusers_exports), utils_exports2), {
3421
+ getToken,
3422
+ hasToken,
3423
+ clearToken,
3424
+ getConfig
3425
+ });
2991
3426
  var index_default = extractia;
2992
3427
  //# sourceMappingURL=extractia-sdk.cjs.js.map