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