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.
@@ -374,15 +374,15 @@ var _setImmediate = ((setImmediateSupported, postMessageSupported) => {
374
374
  if (setImmediateSupported) {
375
375
  return setImmediate;
376
376
  }
377
- return postMessageSupported ? ((token2, callbacks) => {
377
+ return postMessageSupported ? ((token, callbacks) => {
378
378
  _global.addEventListener("message", ({ source, data }) => {
379
- if (source === _global && data === token2) {
379
+ if (source === _global && data === token) {
380
380
  callbacks.length && callbacks.shift()();
381
381
  }
382
382
  }, false);
383
383
  return (cb) => {
384
384
  callbacks.push(cb);
385
- _global.postMessage(token2, "*");
385
+ _global.postMessage(token, "*");
386
386
  };
387
387
  })(`axios@${Math.random()}`, []) : (cb) => setTimeout(cb);
388
388
  })(
@@ -538,9 +538,9 @@ function removeBrackets(key) {
538
538
  }
539
539
  function renderKey(path, key, dots) {
540
540
  if (!path) return key;
541
- return path.concat(key).map(function each(token2, i) {
542
- token2 = removeBrackets(token2);
543
- return !dots && i ? "[" + token2 + "]" : token2;
541
+ return path.concat(key).map(function each(token, i) {
542
+ token = removeBrackets(token);
543
+ return !dots && i ? "[" + token + "]" : token;
544
544
  }).join(dots ? "." : "");
545
545
  }
546
546
  function isFlatArray(arr) {
@@ -1583,7 +1583,7 @@ var resolveConfig_default = (config) => {
1583
1583
  if (platform_default.hasStandardBrowserEnv || platform_default.hasStandardBrowserWebWorkerEnv) {
1584
1584
  headers.setContentType(void 0);
1585
1585
  } else if ((contentType = headers.getContentType()) !== false) {
1586
- const [type, ...tokens] = contentType ? contentType.split(";").map((token2) => token2.trim()).filter(Boolean) : [];
1586
+ const [type, ...tokens] = contentType ? contentType.split(";").map((token) => token.trim()).filter(Boolean) : [];
1587
1587
  headers.setContentType([type || "multipart/form-data", ...tokens].join("; "));
1588
1588
  }
1589
1589
  }
@@ -1603,22 +1603,22 @@ var resolveConfig_default = (config) => {
1603
1603
  var isXHRAdapterSupported = typeof XMLHttpRequest !== "undefined";
1604
1604
  var xhr_default = isXHRAdapterSupported && function(config) {
1605
1605
  return new Promise(function dispatchXhrRequest(resolve, reject) {
1606
- const _config = resolveConfig_default(config);
1607
- let requestData = _config.data;
1608
- const requestHeaders = AxiosHeaders_default.from(_config.headers).normalize();
1609
- let { responseType, onUploadProgress, onDownloadProgress } = _config;
1606
+ const _config2 = resolveConfig_default(config);
1607
+ let requestData = _config2.data;
1608
+ const requestHeaders = AxiosHeaders_default.from(_config2.headers).normalize();
1609
+ let { responseType, onUploadProgress, onDownloadProgress } = _config2;
1610
1610
  let onCanceled;
1611
1611
  let uploadThrottled, downloadThrottled;
1612
1612
  let flushUpload, flushDownload;
1613
1613
  function done() {
1614
1614
  flushUpload && flushUpload();
1615
1615
  flushDownload && flushDownload();
1616
- _config.cancelToken && _config.cancelToken.unsubscribe(onCanceled);
1617
- _config.signal && _config.signal.removeEventListener("abort", onCanceled);
1616
+ _config2.cancelToken && _config2.cancelToken.unsubscribe(onCanceled);
1617
+ _config2.signal && _config2.signal.removeEventListener("abort", onCanceled);
1618
1618
  }
1619
1619
  let request = new XMLHttpRequest();
1620
- request.open(_config.method.toUpperCase(), _config.url, true);
1621
- request.timeout = _config.timeout;
1620
+ request.open(_config2.method.toUpperCase(), _config2.url, true);
1621
+ request.timeout = _config2.timeout;
1622
1622
  function onloadend() {
1623
1623
  if (!request) {
1624
1624
  return;
@@ -1669,10 +1669,10 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1669
1669
  request = null;
1670
1670
  };
1671
1671
  request.ontimeout = function handleTimeout() {
1672
- let timeoutErrorMessage = _config.timeout ? "timeout of " + _config.timeout + "ms exceeded" : "timeout exceeded";
1673
- const transitional2 = _config.transitional || transitional_default;
1674
- if (_config.timeoutErrorMessage) {
1675
- timeoutErrorMessage = _config.timeoutErrorMessage;
1672
+ let timeoutErrorMessage = _config2.timeout ? "timeout of " + _config2.timeout + "ms exceeded" : "timeout exceeded";
1673
+ const transitional2 = _config2.transitional || transitional_default;
1674
+ if (_config2.timeoutErrorMessage) {
1675
+ timeoutErrorMessage = _config2.timeoutErrorMessage;
1676
1676
  }
1677
1677
  reject(new AxiosError_default(
1678
1678
  timeoutErrorMessage,
@@ -1688,11 +1688,11 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1688
1688
  request.setRequestHeader(key, val);
1689
1689
  });
1690
1690
  }
1691
- if (!utils_default.isUndefined(_config.withCredentials)) {
1692
- request.withCredentials = !!_config.withCredentials;
1691
+ if (!utils_default.isUndefined(_config2.withCredentials)) {
1692
+ request.withCredentials = !!_config2.withCredentials;
1693
1693
  }
1694
1694
  if (responseType && responseType !== "json") {
1695
- request.responseType = _config.responseType;
1695
+ request.responseType = _config2.responseType;
1696
1696
  }
1697
1697
  if (onDownloadProgress) {
1698
1698
  [downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true);
@@ -1703,7 +1703,7 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1703
1703
  request.upload.addEventListener("progress", uploadThrottled);
1704
1704
  request.upload.addEventListener("loadend", flushUpload);
1705
1705
  }
1706
- if (_config.cancelToken || _config.signal) {
1706
+ if (_config2.cancelToken || _config2.signal) {
1707
1707
  onCanceled = (cancel) => {
1708
1708
  if (!request) {
1709
1709
  return;
@@ -1712,12 +1712,12 @@ var xhr_default = isXHRAdapterSupported && function(config) {
1712
1712
  request.abort();
1713
1713
  request = null;
1714
1714
  };
1715
- _config.cancelToken && _config.cancelToken.subscribe(onCanceled);
1716
- if (_config.signal) {
1717
- _config.signal.aborted ? onCanceled() : _config.signal.addEventListener("abort", onCanceled);
1715
+ _config2.cancelToken && _config2.cancelToken.subscribe(onCanceled);
1716
+ if (_config2.signal) {
1717
+ _config2.signal.aborted ? onCanceled() : _config2.signal.addEventListener("abort", onCanceled);
1718
1718
  }
1719
1719
  }
1720
- const protocol = parseProtocol(_config.url);
1720
+ const protocol = parseProtocol(_config2.url);
1721
1721
  if (protocol && platform_default.protocols.indexOf(protocol) === -1) {
1722
1722
  reject(new AxiosError_default("Unsupported protocol " + protocol + ":", AxiosError_default.ERR_BAD_REQUEST, config));
1723
1723
  return;
@@ -2367,32 +2367,32 @@ var CancelToken = class _CancelToken {
2367
2367
  this.promise = new Promise(function promiseExecutor(resolve) {
2368
2368
  resolvePromise = resolve;
2369
2369
  });
2370
- const token2 = this;
2370
+ const token = this;
2371
2371
  this.promise.then((cancel) => {
2372
- if (!token2._listeners) return;
2373
- let i = token2._listeners.length;
2372
+ if (!token._listeners) return;
2373
+ let i = token._listeners.length;
2374
2374
  while (i-- > 0) {
2375
- token2._listeners[i](cancel);
2375
+ token._listeners[i](cancel);
2376
2376
  }
2377
- token2._listeners = null;
2377
+ token._listeners = null;
2378
2378
  });
2379
2379
  this.promise.then = (onfulfilled) => {
2380
2380
  let _resolve;
2381
2381
  const promise = new Promise((resolve) => {
2382
- token2.subscribe(resolve);
2382
+ token.subscribe(resolve);
2383
2383
  _resolve = resolve;
2384
2384
  }).then(onfulfilled);
2385
2385
  promise.cancel = function reject() {
2386
- token2.unsubscribe(_resolve);
2386
+ token.unsubscribe(_resolve);
2387
2387
  };
2388
2388
  return promise;
2389
2389
  };
2390
2390
  executor(function cancel(message, config, request) {
2391
- if (token2.reason) {
2391
+ if (token.reason) {
2392
2392
  return;
2393
2393
  }
2394
- token2.reason = new CanceledError_default(message, config, request);
2395
- resolvePromise(token2.reason);
2394
+ token.reason = new CanceledError_default(message, config, request);
2395
+ resolvePromise(token.reason);
2396
2396
  });
2397
2397
  }
2398
2398
  /**
@@ -2444,11 +2444,11 @@ var CancelToken = class _CancelToken {
2444
2444
  */
2445
2445
  static source() {
2446
2446
  let cancel;
2447
- const token2 = new _CancelToken(function executor(c) {
2447
+ const token = new _CancelToken(function executor(c) {
2448
2448
  cancel = c;
2449
2449
  });
2450
2450
  return {
2451
- token: token2,
2451
+ token,
2452
2452
  cancel
2453
2453
  };
2454
2454
  }
@@ -2592,93 +2592,356 @@ var {
2592
2592
  } = axios_default;
2593
2593
 
2594
2594
  // src/errors.js
2595
+ var STATUS_MESSAGES = {
2596
+ 400: "The request contains invalid data. Please check your input.",
2597
+ 401: "Your API token is invalid or has expired. Please check your credentials.",
2598
+ 402: "Your current plan does not support this feature or your document quota is exhausted.",
2599
+ 403: "You do not have permission to perform this action.",
2600
+ 404: "The requested resource could not be found.",
2601
+ 409: "A resource with this identifier already exists.",
2602
+ 429: "Too many requests. Please wait a moment and try again.",
2603
+ 500: "The server encountered an unexpected error. Please try again in a moment.",
2604
+ 502: "The server received an unexpected response. Please try again.",
2605
+ 503: "The service is temporarily unavailable. Please try again in a few minutes.",
2606
+ 504: "The server timed out while processing the request. Please try again."
2607
+ };
2595
2608
  var ExtractiaError = class extends Error {
2596
- /** @param {string} message @param {number} status */
2597
- constructor(message, status) {
2609
+ /**
2610
+ * @param {string} message Technical detail string.
2611
+ * @param {number} [status] — HTTP status code (0 = no response).
2612
+ * @param {string} [userMessage] — Human-friendly sentence shown to end users.
2613
+ * @param {string} [code] — Machine-readable error code.
2614
+ */
2615
+ constructor(message, status = 0, userMessage = null, code = "SDK_ERROR") {
2598
2616
  super(message);
2599
2617
  this.name = "ExtractiaError";
2600
2618
  this.status = status;
2619
+ this.userMessage = userMessage != null ? userMessage : message;
2620
+ this.code = code;
2621
+ this.requestId = null;
2622
+ }
2623
+ /** Returns true if automatically retrying the same request may succeed. */
2624
+ isRetryable() {
2625
+ return this.status === 429 || this.status >= 500;
2626
+ }
2627
+ toJSON() {
2628
+ return {
2629
+ name: this.name,
2630
+ code: this.code,
2631
+ status: this.status,
2632
+ message: this.message,
2633
+ userMessage: this.userMessage,
2634
+ requestId: this.requestId
2635
+ };
2601
2636
  }
2602
2637
  };
2603
2638
  var AuthError = class extends ExtractiaError {
2604
- constructor(message = "Unauthorized. Check your API token.") {
2605
- super(message, 401);
2639
+ constructor(message = STATUS_MESSAGES[401]) {
2640
+ super(message, 401, STATUS_MESSAGES[401], "AUTH_ERROR");
2606
2641
  this.name = "AuthError";
2607
2642
  }
2608
2643
  };
2609
2644
  var ForbiddenError = class extends ExtractiaError {
2610
- constructor(message = "Forbidden. Insufficient permissions.") {
2611
- super(message, 403);
2645
+ constructor(message = STATUS_MESSAGES[403]) {
2646
+ super(message, 403, STATUS_MESSAGES[403], "FORBIDDEN");
2612
2647
  this.name = "ForbiddenError";
2613
2648
  }
2614
2649
  };
2615
2650
  var TierError = class extends ExtractiaError {
2616
- constructor(message = "Tier limit reached. Upgrade your plan.", status = 402) {
2617
- super(message, status);
2651
+ constructor(message = STATUS_MESSAGES[402], status = 402) {
2652
+ super(message, status, STATUS_MESSAGES[402], "TIER_LIMIT");
2618
2653
  this.name = "TierError";
2619
2654
  }
2620
2655
  };
2656
+ var QuotaError = class extends ExtractiaError {
2657
+ constructor(message = "You have reached your document processing quota for this billing period. Please upgrade or wait for the next cycle.") {
2658
+ super(message, 402, message, "QUOTA_EXCEEDED");
2659
+ this.name = "QuotaError";
2660
+ }
2661
+ };
2621
2662
  var RateLimitError = class extends ExtractiaError {
2622
- constructor(message = "Too many requests. Please slow down.") {
2623
- super(message, 429);
2663
+ /**
2664
+ * @param {string} [message]
2665
+ * @param {number|null} [retryAfter] — Seconds to wait before retrying (from Retry-After header).
2666
+ */
2667
+ constructor(message = STATUS_MESSAGES[429], retryAfter = null) {
2668
+ super(message, 429, STATUS_MESSAGES[429], "RATE_LIMITED");
2624
2669
  this.name = "RateLimitError";
2670
+ this.retryAfter = retryAfter;
2671
+ }
2672
+ isRetryable() {
2673
+ return true;
2625
2674
  }
2626
2675
  };
2627
2676
  var NotFoundError = class extends ExtractiaError {
2628
- constructor(message = "Resource not found.") {
2629
- super(message, 404);
2677
+ constructor(message = STATUS_MESSAGES[404]) {
2678
+ super(message, 404, STATUS_MESSAGES[404], "NOT_FOUND");
2630
2679
  this.name = "NotFoundError";
2631
2680
  }
2632
2681
  };
2682
+ var ValidationError = class extends ExtractiaError {
2683
+ /**
2684
+ * @param {string} [message]
2685
+ * @param {Record<string,string>|null} [fields] — Field-level errors, if the server provides them.
2686
+ */
2687
+ constructor(message = STATUS_MESSAGES[400], fields = null) {
2688
+ super(message, 400, STATUS_MESSAGES[400], "VALIDATION_ERROR");
2689
+ this.name = "ValidationError";
2690
+ this.fields = fields;
2691
+ }
2692
+ };
2693
+ var ConflictError = class extends ExtractiaError {
2694
+ constructor(message = STATUS_MESSAGES[409]) {
2695
+ super(message, 409, STATUS_MESSAGES[409], "CONFLICT");
2696
+ this.name = "ConflictError";
2697
+ }
2698
+ };
2699
+ var ServerError = class extends ExtractiaError {
2700
+ constructor(message = STATUS_MESSAGES[500], status = 500) {
2701
+ var _a;
2702
+ super(
2703
+ message,
2704
+ status,
2705
+ (_a = STATUS_MESSAGES[status]) != null ? _a : STATUS_MESSAGES[500],
2706
+ "SERVER_ERROR"
2707
+ );
2708
+ this.name = "ServerError";
2709
+ }
2710
+ isRetryable() {
2711
+ return true;
2712
+ }
2713
+ };
2714
+ var NetworkError = class extends ExtractiaError {
2715
+ constructor(message = "Unable to reach the Extractia API. Please check your network connection and try again.") {
2716
+ super(message, 0, message, "NETWORK_ERROR");
2717
+ this.name = "NetworkError";
2718
+ }
2719
+ isRetryable() {
2720
+ return true;
2721
+ }
2722
+ };
2723
+ var TimeoutError = class extends ExtractiaError {
2724
+ constructor(message = "The request timed out. The server may be under heavy load \u2014 please try again in a moment.") {
2725
+ super(message, 0, message, "TIMEOUT");
2726
+ this.name = "TimeoutError";
2727
+ }
2728
+ isRetryable() {
2729
+ return true;
2730
+ }
2731
+ };
2732
+ function extractServerDetail(data) {
2733
+ var _a, _b, _c, _d, _e;
2734
+ if (!data) return null;
2735
+ if (typeof data === "string" && data.trim()) return data.trim();
2736
+ if (typeof data === "object") {
2737
+ const msg = (_c = (_b = (_a = data.message) != null ? _a : data.error) != null ? _b : data.detail) != null ? _c : data.title;
2738
+ if (msg && typeof msg === "string") return msg.trim();
2739
+ if (Array.isArray(data.errors) && data.errors.length > 0) {
2740
+ const first = data.errors[0];
2741
+ return typeof first === "string" ? first : (_e = (_d = first.message) != null ? _d : first.msg) != null ? _e : JSON.stringify(first);
2742
+ }
2743
+ if (Array.isArray(data.fieldErrors) && data.fieldErrors.length > 0) {
2744
+ return data.fieldErrors.map((e) => {
2745
+ var _a2, _b2;
2746
+ return `${(_a2 = e.field) != null ? _a2 : "field"}: ${(_b2 = e.message) != null ? _b2 : e.defaultMessage}`;
2747
+ }).join("; ");
2748
+ }
2749
+ }
2750
+ return null;
2751
+ }
2633
2752
  function mapAxiosError(err) {
2634
- var _a, _b;
2635
- const status = (_a = err.response) == null ? void 0 : _a.status;
2636
- const serverMessage = (_b = err.response) == null ? void 0 : _b.data;
2637
- const detail = typeof serverMessage === "string" ? serverMessage : void 0;
2753
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2754
+ if (!err.response) {
2755
+ if (err.code === "ECONNABORTED" || err.code === "ETIMEDOUT" || err.message && err.message.toLowerCase().includes("timeout")) {
2756
+ return new TimeoutError();
2757
+ }
2758
+ return new NetworkError(err.message || void 0);
2759
+ }
2760
+ const status = err.response.status;
2761
+ const detail = extractServerDetail(err.response.data);
2762
+ const userMessage = (_a = STATUS_MESSAGES[status]) != null ? _a : status >= 500 ? STATUS_MESSAGES[500] : "Something went wrong. Please try again.";
2763
+ let error;
2638
2764
  switch (status) {
2765
+ case 400: {
2766
+ const body = err.response.data;
2767
+ const fields = (_b = body == null ? void 0 : body.fields) != null ? _b : Array.isArray(body == null ? void 0 : body.fieldErrors) ? Object.fromEntries(
2768
+ body.fieldErrors.map((f) => {
2769
+ var _a2;
2770
+ return [
2771
+ f.field,
2772
+ (_a2 = f.message) != null ? _a2 : f.defaultMessage
2773
+ ];
2774
+ })
2775
+ ) : null;
2776
+ error = new ValidationError(detail != null ? detail : STATUS_MESSAGES[400], fields);
2777
+ break;
2778
+ }
2639
2779
  case 401:
2640
- return new AuthError(detail);
2780
+ error = new AuthError(detail != null ? detail : void 0);
2781
+ break;
2641
2782
  case 402:
2642
- return new TierError(detail);
2783
+ if (detail && (detail.toLowerCase().includes("quota") || detail.toLowerCase().includes("document") || detail.toLowerCase().includes("limit reached"))) {
2784
+ error = new QuotaError(detail);
2785
+ } else {
2786
+ error = new TierError(detail != null ? detail : void 0);
2787
+ }
2788
+ break;
2643
2789
  case 403:
2644
- return new ForbiddenError(detail);
2790
+ error = new ForbiddenError(detail != null ? detail : void 0);
2791
+ break;
2645
2792
  case 404:
2646
- return new NotFoundError(detail);
2647
- case 429:
2648
- return new RateLimitError(detail);
2793
+ error = new NotFoundError(detail != null ? detail : void 0);
2794
+ break;
2795
+ case 409:
2796
+ error = new ConflictError(detail != null ? detail : void 0);
2797
+ break;
2798
+ case 429: {
2799
+ const retryAfterHeader = (_c = err.response.headers) == null ? void 0 : _c["retry-after"];
2800
+ const retryAfter = retryAfterHeader != null ? parseInt(retryAfterHeader, 10) : null;
2801
+ error = new RateLimitError(
2802
+ detail != null ? detail : void 0,
2803
+ isNaN(retryAfter) ? null : retryAfter
2804
+ );
2805
+ break;
2806
+ }
2649
2807
  default:
2650
- return new ExtractiaError(detail != null ? detail : err.message, status != null ? status : 0);
2808
+ if (status >= 500) {
2809
+ error = new ServerError(
2810
+ (_d = detail != null ? detail : STATUS_MESSAGES[status]) != null ? _d : STATUS_MESSAGES[500],
2811
+ status
2812
+ );
2813
+ } else {
2814
+ error = new ExtractiaError(
2815
+ detail != null ? detail : err.message,
2816
+ status,
2817
+ userMessage,
2818
+ `HTTP_${status}`
2819
+ );
2820
+ }
2651
2821
  }
2822
+ error.userMessage = userMessage;
2823
+ 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;
2824
+ if (reqId) error.requestId = reqId;
2825
+ return error;
2652
2826
  }
2653
2827
 
2654
2828
  // src/apiClient.js
2655
- var token = null;
2656
- var DEFAULT_BASE_URL = "https://api.extractia.info/api/public";
2657
- var api = axios_default.create({
2658
- baseURL: DEFAULT_BASE_URL,
2659
- timeout: 6e4
2660
- // 60s — AI processing can take 10–30s
2829
+ var _token = null;
2830
+ var _config = {
2831
+ baseURL: "https://api.extractia.info/api/public",
2832
+ timeout: 6e4,
2833
+ retries: 1,
2834
+ retryDelay: 1e3,
2835
+ debug: false,
2836
+ defaultHeaders: {},
2837
+ onBeforeRequest: null,
2838
+ onAfterResponse: null,
2839
+ onError: null
2840
+ };
2841
+ var _api = axios_default.create({
2842
+ baseURL: _config.baseURL,
2843
+ timeout: _config.timeout
2661
2844
  });
2662
- api.interceptors.request.use((config) => {
2663
- if (!token) {
2664
- throw new Error(
2665
- "API token is required. Call setToken(yourApiToken) before making requests."
2845
+ _api.interceptors.request.use((config) => {
2846
+ var _a, _b, _c, _d, _e;
2847
+ if (!_token) {
2848
+ const err = new ExtractiaError(
2849
+ "API token not set. Call setToken(token) before making requests.",
2850
+ 0,
2851
+ "API token not set. Call setToken(token) before making requests.",
2852
+ "TOKEN_MISSING"
2853
+ );
2854
+ return Promise.reject(err);
2855
+ }
2856
+ config.headers = (_a = config.headers) != null ? _a : {};
2857
+ config.headers["Authorization"] = `Bearer ${_token}`;
2858
+ Object.assign(config.headers, _config.defaultHeaders);
2859
+ if (_config.debug) {
2860
+ console.debug(
2861
+ `[ExtractIA SDK] \u2192 ${((_b = config.method) != null ? _b : "GET").toUpperCase()} ${(_c = config.baseURL) != null ? _c : ""}${(_d = config.url) != null ? _d : ""}`,
2862
+ (_e = config.params) != null ? _e : ""
2666
2863
  );
2667
2864
  }
2668
- config.headers.Authorization = `Bearer ${token}`;
2865
+ if (typeof _config.onBeforeRequest === "function") {
2866
+ const modified = _config.onBeforeRequest(config);
2867
+ return modified != null ? modified : config;
2868
+ }
2669
2869
  return config;
2670
2870
  });
2671
- api.interceptors.response.use(
2672
- (response) => response,
2673
- (err) => Promise.reject(mapAxiosError(err))
2871
+ _api.interceptors.response.use(
2872
+ (response) => {
2873
+ var _a, _b;
2874
+ if (_config.debug) {
2875
+ console.debug(
2876
+ `[ExtractIA SDK] \u2190 ${response.status} ${(_b = (_a = response.config) == null ? void 0 : _a.url) != null ? _b : ""}`
2877
+ );
2878
+ }
2879
+ if (typeof _config.onAfterResponse === "function") {
2880
+ _config.onAfterResponse(response);
2881
+ }
2882
+ return response;
2883
+ },
2884
+ async (err) => {
2885
+ var _a, _b;
2886
+ if (err instanceof ExtractiaError) {
2887
+ if (typeof _config.onError === "function") _config.onError(err);
2888
+ return Promise.reject(err);
2889
+ }
2890
+ const mapped = mapAxiosError(err);
2891
+ const cfg = err.config;
2892
+ if (cfg && mapped.isRetryable() && ((_a = cfg._retryCount) != null ? _a : 0) < _config.retries) {
2893
+ cfg._retryCount = ((_b = cfg._retryCount) != null ? _b : 0) + 1;
2894
+ const delayMs = mapped.retryAfter != null ? mapped.retryAfter * 1e3 : _config.retryDelay * cfg._retryCount;
2895
+ if (_config.debug) {
2896
+ console.debug(
2897
+ `[ExtractIA SDK] retrying (${cfg._retryCount}/${_config.retries}) in ${delayMs}ms\u2026`
2898
+ );
2899
+ }
2900
+ await new Promise((r) => setTimeout(r, delayMs));
2901
+ return _api(cfg);
2902
+ }
2903
+ if (typeof _config.onError === "function") _config.onError(mapped);
2904
+ return Promise.reject(mapped);
2905
+ }
2674
2906
  );
2675
- function setToken(newToken) {
2676
- token = newToken;
2907
+ function setToken(token) {
2908
+ if (!token || typeof token !== "string" || !token.trim()) {
2909
+ throw new Error("setToken: token must be a non-empty string.");
2910
+ }
2911
+ _token = token.trim();
2912
+ }
2913
+ function getToken() {
2914
+ return _token;
2915
+ }
2916
+ function hasToken() {
2917
+ return Boolean(_token);
2918
+ }
2919
+ function clearToken() {
2920
+ _token = null;
2921
+ }
2922
+ function configure(opts = {}) {
2923
+ if (opts.baseURL) {
2924
+ _config.baseURL = opts.baseURL;
2925
+ _api.defaults.baseURL = opts.baseURL;
2926
+ }
2927
+ if (opts.timeout != null) {
2928
+ _config.timeout = opts.timeout;
2929
+ _api.defaults.timeout = opts.timeout;
2930
+ }
2931
+ if (opts.retries != null) _config.retries = opts.retries;
2932
+ if (opts.retryDelay != null) _config.retryDelay = opts.retryDelay;
2933
+ if (opts.debug != null) _config.debug = Boolean(opts.debug);
2934
+ if (opts.defaultHeaders) {
2935
+ _config.defaultHeaders = __spreadValues(__spreadValues({}, _config.defaultHeaders), opts.defaultHeaders);
2936
+ }
2937
+ if (opts.onBeforeRequest) _config.onBeforeRequest = opts.onBeforeRequest;
2938
+ if (opts.onAfterResponse) _config.onAfterResponse = opts.onAfterResponse;
2939
+ if (opts.onError) _config.onError = opts.onError;
2677
2940
  }
2678
- function configure({ baseURL } = {}) {
2679
- if (baseURL) api.defaults.baseURL = baseURL;
2941
+ function getConfig() {
2942
+ return __spreadValues({}, _config);
2680
2943
  }
2681
- var apiClient_default = api;
2944
+ var apiClient_default = _api;
2682
2945
 
2683
2946
  // src/auth.js
2684
2947
  async function getMyProfile() {
@@ -2865,6 +3128,7 @@ var ocrTools_exports = {};
2865
3128
  __export(ocrTools_exports, {
2866
3129
  createOcrTool: () => createOcrTool,
2867
3130
  deleteOcrTool: () => deleteOcrTool,
3131
+ getOcrToolExecutions: () => getOcrToolExecutions,
2868
3132
  getOcrTools: () => getOcrTools,
2869
3133
  runOcrTool: () => runOcrTool,
2870
3134
  updateOcrTool: () => updateOcrTool
@@ -2893,6 +3157,16 @@ async function runOcrTool(id, base64Image, options = {}) {
2893
3157
  const res = await apiClient_default.post(`/ocr-tools/${id}/run`, body);
2894
3158
  return res.data;
2895
3159
  }
3160
+ async function getOcrToolExecutions({
3161
+ toolId,
3162
+ page = 0,
3163
+ size = 20
3164
+ } = {}) {
3165
+ const params = { page, size };
3166
+ if (toolId) params.toolId = toolId;
3167
+ const res = await apiClient_default.get("/ocr-tools/executions", { params });
3168
+ return res.data;
3169
+ }
2896
3170
 
2897
3171
  // src/subusers.js
2898
3172
  var subusers_exports = {};
@@ -2907,8 +3181,17 @@ async function getSubUsers() {
2907
3181
  const res = await apiClient_default.get("/me/subusers");
2908
3182
  return res.data;
2909
3183
  }
2910
- async function createSubUser({ username, password, permissions }) {
2911
- const res = await apiClient_default.post("/me/subusers", { username, password, permissions });
3184
+ async function createSubUser({
3185
+ username,
3186
+ password,
3187
+ permissions,
3188
+ allowedFormIds
3189
+ }) {
3190
+ const res = await apiClient_default.post("/me/subusers", __spreadValues({
3191
+ username,
3192
+ password,
3193
+ permissions
3194
+ }, allowedFormIds !== void 0 ? { allowedFormIds } : {}));
2912
3195
  return res.data;
2913
3196
  }
2914
3197
  async function deleteSubUser(username) {
@@ -2916,54 +3199,205 @@ async function deleteSubUser(username) {
2916
3199
  return res.data;
2917
3200
  }
2918
3201
  async function updateSubUser(username, updates = {}) {
2919
- const res = await apiClient_default.put(`/me/subusers/${encodeURIComponent(username)}`, updates);
3202
+ const res = await apiClient_default.put(
3203
+ `/me/subusers/${encodeURIComponent(username)}`,
3204
+ updates
3205
+ );
2920
3206
  return res.data;
2921
3207
  }
2922
3208
  async function toggleSuspendSubUser(username) {
2923
- const res = await apiClient_default.put(`/me/subusers/${encodeURIComponent(username)}/suspend`);
3209
+ const res = await apiClient_default.put(
3210
+ `/me/subusers/${encodeURIComponent(username)}/suspend`
3211
+ );
2924
3212
  return res.data;
2925
3213
  }
2926
3214
 
3215
+ // src/utils.js
3216
+ var utils_exports2 = {};
3217
+ __export(utils_exports2, {
3218
+ delay: () => delay,
3219
+ ensureBase64: () => ensureBase64,
3220
+ fileToBase64: () => fileToBase64,
3221
+ getMimeType: () => getMimeType,
3222
+ isBase64: () => isBase64,
3223
+ paginate: () => paginate,
3224
+ paginateAll: () => paginateAll,
3225
+ stripDataUrlPrefix: () => stripDataUrlPrefix,
3226
+ withRetry: () => withRetry
3227
+ });
3228
+ function fileToBase64(file) {
3229
+ if (typeof FileReader === "undefined") {
3230
+ return Promise.reject(
3231
+ new Error(
3232
+ "fileToBase64: FileReader is not available in this environment. In Node.js, read the file manually and encode it with Buffer.from(data).toString('base64')."
3233
+ )
3234
+ );
3235
+ }
3236
+ return new Promise((resolve, reject) => {
3237
+ const reader = new FileReader();
3238
+ reader.onload = () => resolve(
3239
+ /** @type {string} */
3240
+ reader.result
3241
+ );
3242
+ reader.onerror = () => {
3243
+ var _a;
3244
+ return reject(
3245
+ new Error(
3246
+ `fileToBase64: failed to read file "${(_a = file.name) != null ? _a : "unknown"}".`
3247
+ )
3248
+ );
3249
+ };
3250
+ reader.readAsDataURL(file);
3251
+ });
3252
+ }
3253
+ function stripDataUrlPrefix(base64OrDataUrl) {
3254
+ if (typeof base64OrDataUrl !== "string") {
3255
+ throw new TypeError("stripDataUrlPrefix: argument must be a string.");
3256
+ }
3257
+ const idx = base64OrDataUrl.indexOf(";base64,");
3258
+ return idx !== -1 ? base64OrDataUrl.slice(idx + 8) : base64OrDataUrl;
3259
+ }
3260
+ function getMimeType(dataUrl) {
3261
+ if (typeof dataUrl !== "string") return null;
3262
+ const match = dataUrl.match(/^data:([^;]+);base64,/);
3263
+ return match ? match[1] : null;
3264
+ }
3265
+ function isBase64(str) {
3266
+ if (typeof str !== "string" || !str.trim()) return false;
3267
+ const raw = stripDataUrlPrefix(str);
3268
+ return raw.length > 0 && raw.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(raw);
3269
+ }
3270
+ async function ensureBase64(fileOrBase64) {
3271
+ if (typeof fileOrBase64 === "string") return fileOrBase64;
3272
+ if (typeof File !== "undefined" && fileOrBase64 instanceof File || typeof Blob !== "undefined" && fileOrBase64 instanceof Blob) {
3273
+ return fileToBase64(fileOrBase64);
3274
+ }
3275
+ throw new TypeError(
3276
+ "ensureBase64: argument must be a File, Blob, or a base64 string."
3277
+ );
3278
+ }
3279
+ function paginate(_0) {
3280
+ return __asyncGenerator(this, arguments, function* (fn, { size = 50, startPage = 0, maxPages = 1e3 } = {}) {
3281
+ var _a;
3282
+ let page = startPage;
3283
+ let pagesRead = 0;
3284
+ while (pagesRead < maxPages) {
3285
+ const result = yield new __await(fn({ page, size }));
3286
+ const items = Array.isArray(result == null ? void 0 : result.content) ? result.content : [];
3287
+ for (const item of items) yield item;
3288
+ const totalPages = (_a = result == null ? void 0 : result.totalPages) != null ? _a : 1;
3289
+ if (items.length === 0 || page + 1 >= totalPages) break;
3290
+ page++;
3291
+ pagesRead++;
3292
+ }
3293
+ });
3294
+ }
3295
+ async function paginateAll(fn, opts) {
3296
+ const items = [];
3297
+ try {
3298
+ for (var iter = __forAwait(paginate(fn, opts)), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
3299
+ const item = temp.value;
3300
+ items.push(item);
3301
+ }
3302
+ } catch (temp) {
3303
+ error = [temp];
3304
+ } finally {
3305
+ try {
3306
+ more && (temp = iter.return) && await temp.call(iter);
3307
+ } finally {
3308
+ if (error)
3309
+ throw error[0];
3310
+ }
3311
+ }
3312
+ return items;
3313
+ }
3314
+ function delay(ms) {
3315
+ return new Promise((resolve) => setTimeout(resolve, ms));
3316
+ }
3317
+ async function withRetry(fn, { retries = 3, initialDelay = 500, shouldRetry } = {}) {
3318
+ const isRetryable = shouldRetry != null ? shouldRetry : (err) => typeof err.isRetryable === "function" && err.isRetryable();
3319
+ let lastErr;
3320
+ for (let attempt = 0; attempt <= retries; attempt++) {
3321
+ try {
3322
+ return await fn();
3323
+ } catch (err) {
3324
+ lastErr = err;
3325
+ if (attempt < retries && isRetryable(err)) {
3326
+ const wait = err.retryAfter != null ? err.retryAfter * 1e3 : initialDelay * 2 ** attempt;
3327
+ await delay(wait);
3328
+ continue;
3329
+ }
3330
+ throw err;
3331
+ }
3332
+ }
3333
+ throw lastErr;
3334
+ }
3335
+
2927
3336
  // src/index.js
2928
- var extractia = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, auth_exports), templates_exports), documents_exports), analytics_exports), ocrTools_exports), subusers_exports);
3337
+ var extractia = __spreadProps(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({}, auth_exports), templates_exports), documents_exports), analytics_exports), ocrTools_exports), subusers_exports), utils_exports2), {
3338
+ getToken,
3339
+ hasToken,
3340
+ clearToken,
3341
+ getConfig
3342
+ });
2929
3343
  var index_default = extractia;
2930
3344
  export {
2931
3345
  AuthError,
3346
+ ConflictError,
2932
3347
  ExtractiaError,
2933
3348
  ForbiddenError,
3349
+ NetworkError,
2934
3350
  NotFoundError,
3351
+ QuotaError,
2935
3352
  RateLimitError,
3353
+ ServerError,
2936
3354
  TierError,
3355
+ TimeoutError,
3356
+ ValidationError,
2937
3357
  bulkPreconform,
3358
+ clearToken,
2938
3359
  configure,
2939
3360
  createOcrTool,
2940
3361
  createSubUser,
2941
3362
  createTemplate,
2942
3363
  index_default as default,
3364
+ delay,
2943
3365
  deleteAllTemplateDocuments,
2944
3366
  deleteDocument,
2945
3367
  deleteOcrTool,
2946
3368
  deleteSubUser,
2947
3369
  deleteTemplate,
3370
+ ensureBase64,
2948
3371
  exportDocumentsCsv,
2949
3372
  exportDocumentsJson,
3373
+ fileToBase64,
2950
3374
  generateDocumentSummary,
3375
+ getConfig,
2951
3376
  getCreditsBalance,
2952
3377
  getCreditsHistory,
2953
3378
  getDocumentById,
2954
3379
  getDocumentHistory,
2955
3380
  getDocumentsByTemplateId,
3381
+ getMimeType,
2956
3382
  getMyProfile,
3383
+ getOcrToolExecutions,
2957
3384
  getOcrTools,
2958
3385
  getRecentDocuments,
2959
3386
  getSubUsers,
2960
3387
  getTemplateById,
2961
3388
  getTemplateByName,
2962
3389
  getTemplates,
3390
+ getToken,
3391
+ hasToken,
3392
+ isBase64,
3393
+ mapAxiosError,
3394
+ paginate,
3395
+ paginateAll,
2963
3396
  processImage,
2964
3397
  processImagesMultipage,
2965
3398
  runOcrTool,
2966
3399
  setToken,
3400
+ stripDataUrlPrefix,
2967
3401
  suggestFields,
2968
3402
  toggleSuspendSubUser,
2969
3403
  updateDocumentData,
@@ -2972,6 +3406,7 @@ export {
2972
3406
  updateOcrTool,
2973
3407
  updateSubUser,
2974
3408
  updateTemplate,
2975
- updateWebhook
3409
+ updateWebhook,
3410
+ withRetry
2976
3411
  };
2977
3412
  //# sourceMappingURL=extractia-sdk.esm.js.map