extractia-sdk 1.0.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "extractia-sdk",
3
- "version": "1.0.6",
4
- "description": "JavaScript SDK for the ExtractIA API",
5
- "author": "Tu Nombre o Empresa",
3
+ "version": "1.2.0",
4
+ "description": "JavaScript SDK for the ExtractIA API — document extraction, OCR tools, AI summaries, templates & more",
5
+ "type": "module",
6
+ "author": "ExtractIA Team",
6
7
  "license": "MIT",
7
8
  "keywords": [
8
9
  "sdk",
@@ -10,17 +11,27 @@
10
11
  "ocr",
11
12
  "documents",
12
13
  "api",
13
- "client"
14
+ "client",
15
+ "document-extraction",
16
+ "ai",
17
+ "gemini"
14
18
  ],
15
19
  "main": "dist/extractia-sdk.cjs.js",
16
- "module": "dist/extractia-sdk.esm.js",
17
- "browser": "dist/extractia-sdk.browser.js",
20
+ "module": "dist/extractia-sdk.esm.js",
21
+ "browser": "dist/extractia-sdk.browser.js",
18
22
  "exports": {
19
23
  "import": "./dist/extractia-sdk.esm.js",
20
24
  "require": "./dist/extractia-sdk.cjs.js",
21
25
  "default": "./dist/extractia-sdk.esm.js"
22
26
  },
23
- "types": "./dist/index.d.ts",
27
+ "types": "./dist/index.d.ts",
28
+ "typesVersions": {
29
+ "*": {
30
+ "*": [
31
+ "./src/index.d.ts"
32
+ ]
33
+ }
34
+ },
24
35
  "scripts": {
25
36
  "build": "node build.js",
26
37
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -0,0 +1,46 @@
1
+ // src/analytics.js
2
+ import api from "./apiClient.js";
3
+
4
+ /**
5
+ * Returns the current AI-credit balance for the authenticated user.
6
+ *
7
+ * @returns {Promise<{ monthlyBalance: number, addonBalance: number, totalBalance: number }>}
8
+ */
9
+ export async function getCreditsBalance() {
10
+ const res = await api.get("/me/credits");
11
+ return res.data;
12
+ }
13
+
14
+ /**
15
+ * Returns a paginated history of AI credit consumption events.
16
+ *
17
+ * @param {Object} [options]
18
+ * @param {number} [options.page=0] - Zero-based page index.
19
+ * @param {number} [options.size=20] - Page size (max 100).
20
+ * @returns {Promise<Object>} Spring Page object with `content` array and pagination info.
21
+ */
22
+ export async function getCreditsHistory({ page = 0, size = 20 } = {}) {
23
+ const res = await api.get("/me/credits/history", {
24
+ params: { page, size: Math.min(size, 100) },
25
+ });
26
+ return res.data;
27
+ }
28
+
29
+ /**
30
+ * Returns a paginated history of document processing events (uploads, OCR tool runs, etc.)
31
+ * for the authenticated user.
32
+ *
33
+ * Each entry includes: templateId, templateName, status (SUCCESS | FAILURE),
34
+ * uploadDate, processingTimeMs, pages, fields, and an optional errorMessage.
35
+ *
36
+ * @param {Object} [options]
37
+ * @param {number} [options.page=0] - Zero-based page index.
38
+ * @param {number} [options.size=20] - Page size (max 100).
39
+ * @returns {Promise<Object>} Spring Page object with `content` array and pagination info.
40
+ */
41
+ export async function getDocumentHistory({ page = 0, size = 20 } = {}) {
42
+ const res = await api.get("/me/documents/history", {
43
+ params: { page, size: Math.min(size, 100) },
44
+ });
45
+ return res.data;
46
+ }
package/src/apiClient.js CHANGED
@@ -1,22 +1,46 @@
1
- import axios from 'axios';
2
-
3
- let token = null;
4
-
5
- const api = axios.create({
6
- baseURL: 'https://www.extractia-api.cat/api/public',
7
- timeout: 10000,
8
- });
9
-
10
- api.interceptors.request.use((config) => {
11
- if (!token) {
12
- throw new Error('API token is required');
13
- }
14
- config.headers.Authorization = `Bearer ${token}`;
15
- return config;
16
- });
17
-
18
- export function setToken(newToken) {
19
- token = newToken;
20
- }
21
-
22
- export default api;
1
+ import axios from "axios";
2
+ import { mapAxiosError } from "./errors.js";
3
+
4
+ let token = null;
5
+
6
+ const DEFAULT_BASE_URL = "https://api.extractia.info/api/public";
7
+
8
+ const api = axios.create({
9
+ baseURL: DEFAULT_BASE_URL,
10
+ timeout: 60000, // 60s — AI processing can take 10–30s
11
+ });
12
+
13
+ api.interceptors.request.use((config) => {
14
+ if (!token) {
15
+ throw new Error(
16
+ "API token is required. Call setToken(yourApiToken) before making requests.",
17
+ );
18
+ }
19
+ config.headers.Authorization = `Bearer ${token}`;
20
+ return config;
21
+ });
22
+
23
+ api.interceptors.response.use(
24
+ (response) => response,
25
+ (err) => Promise.reject(mapAxiosError(err)),
26
+ );
27
+
28
+ /**
29
+ * Sets the API token used for all subsequent requests.
30
+ * Must be called before any SDK method.
31
+ * @param {string} newToken - Your Extractia API token.
32
+ */
33
+ export function setToken(newToken) {
34
+ token = newToken;
35
+ }
36
+
37
+ /**
38
+ * Configures SDK options.
39
+ * @param {object} opts
40
+ * @param {string} [opts.baseURL] - Override the default API base URL.
41
+ */
42
+ export function configure({ baseURL } = {}) {
43
+ if (baseURL) api.defaults.baseURL = baseURL;
44
+ }
45
+
46
+ export default api;
package/src/auth.js CHANGED
@@ -1,16 +1,25 @@
1
1
  // src/auth.js
2
- import api, { setToken } from './apiClient.js';
2
+ import api, { setToken, configure } from "./apiClient.js";
3
3
 
4
+ /**
5
+ * Returns the profile of the authenticated user.
6
+ * @returns {Promise<Object>} User profile object.
7
+ */
4
8
  export async function getMyProfile() {
5
- const response = await api.get('/me');
9
+ const response = await api.get("/me");
6
10
  return response.data;
7
11
  }
8
12
 
13
+ /**
14
+ * Updates the webhook URL for the authenticated user.
15
+ * @param {string} url - The new webhook URL.
16
+ * @returns {Promise<Object>} Updated user object.
17
+ */
9
18
  export async function updateWebhook(url) {
10
- const response = await api.put('/me/webhook', null, {
11
- params: { webhookUrl: url }
19
+ const response = await api.put("/me/webhook", null, {
20
+ params: { webhookUrl: url },
12
21
  });
13
22
  return response.data;
14
23
  }
15
24
 
16
- export { setToken };
25
+ export { setToken, configure };
@@ -1,11 +1,15 @@
1
- import * as auth from './auth.js';
2
- import * as templates from './templates.js';
3
- import * as documents from './documents.js';
1
+ import * as auth from "./auth.js";
2
+ import * as templates from "./templates.js";
3
+ import * as documents from "./documents.js";
4
+ import * as analytics from "./analytics.js";
5
+ import * as ocrTools from "./ocrTools.js";
4
6
 
5
7
  const extractia = {
6
8
  ...auth,
7
9
  ...templates,
8
10
  ...documents,
11
+ ...analytics,
12
+ ...ocrTools,
9
13
  };
10
14
 
11
- export default extractia;
15
+ export default extractia;
package/src/documents.js CHANGED
@@ -1,33 +1,195 @@
1
1
  // src/documents.js
2
- import api from './apiClient.js';
2
+ import api from "./apiClient.js";
3
3
 
4
+ /**
5
+ * Retrieves documents associated with a template (paginated).
6
+ *
7
+ * @param {string} templateId - The template ID to query.
8
+ * @param {Object} [options]
9
+ * @param {boolean} [options.preconformed] - Filter by preconfirmed status.
10
+ * @param {number} [options.index] - Zero-based page index.
11
+ * @param {string} [options.sort] - Sort direction: "1" = ASC, "-1" = DESC (default).
12
+ * @param {boolean} [options.includeImage] - Whether to include the base64 image in results.
13
+ * @returns {Promise<{ content: Object[], totalPages: number }>} Paginated document list.
14
+ */
4
15
  export async function getDocumentsByTemplateId(templateId, options = {}) {
5
- const params = {
6
- preconformed: options.preconformed ?? null,
7
- index: options.index ?? 0,
8
- sort: options.sort ?? -1,
9
- includeImage: options.includeImage ? 1 : 0,
10
- };
11
-
16
+ const params = {};
17
+ if (options.preconformed != null) params.preconformed = options.preconformed;
18
+ if (options.index != null) params.index = options.index;
19
+ if (options.sort != null) params.sort = options.sort;
20
+ params.includeImage = options.includeImage ? 1 : 0;
12
21
  const res = await api.get(`/templates/${templateId}/documents`, { params });
13
22
  return res.data;
14
23
  }
15
24
 
25
+ /**
26
+ * Returns a single document by its template and document ID.
27
+ *
28
+ * @param {string} templateId - Template ID.
29
+ * @param {string} docId - Document ID.
30
+ * @param {Object} [options]
31
+ * @param {boolean} [options.includeImage] - Whether to include the base64 source image.
32
+ * @returns {Promise<Object>} The document object.
33
+ */
34
+ export async function getDocumentById(templateId, docId, options = {}) {
35
+ const params = { includeImage: options.includeImage ? 1 : 0 };
36
+ const res = await api.get(`/templates/${templateId}/documents/${docId}`, {
37
+ params,
38
+ });
39
+ return res.data;
40
+ }
41
+
42
+ /**
43
+ * Returns the N most-recent documents across all templates.
44
+ *
45
+ * @param {number} [size=10] - Maximum number of documents to return (max 50).
46
+ * @returns {Promise<Object[]>} Array of document projection objects.
47
+ */
48
+ export async function getRecentDocuments(size = 10) {
49
+ const res = await api.get("/documents/recent", {
50
+ params: { size: Math.min(size, 50) },
51
+ });
52
+ return res.data;
53
+ }
54
+
55
+ /**
56
+ * Deletes a document by its ID.
57
+ *
58
+ * @param {string} documentId - The document ID to delete.
59
+ * @returns {Promise<void>}
60
+ */
16
61
  export async function deleteDocument(documentId) {
17
62
  const res = await api.delete(`/documents/${documentId}`);
18
63
  return res.data;
19
64
  }
20
65
 
66
+ /**
67
+ * Processes a single base64-encoded image against a template.
68
+ *
69
+ * @param {string} templateId - The template ID to process with.
70
+ * @param {string} base64Image - Base64-encoded image (with or without data-URL prefix).
71
+ * @returns {Promise<Object>} The created UserDocument with extracted JSON.
72
+ */
21
73
  export async function processImage(templateId, base64Image) {
22
- const res = await api.post(`/public/templates/${templateId}/process`, {
23
- image: base64Image
74
+ const res = await api.post(`/templates/${templateId}/process`, {
75
+ image: base64Image,
24
76
  });
25
77
  return res.data;
26
78
  }
27
79
 
80
+ /**
81
+ * Processes multiple base64-encoded images as a multi-page document.
82
+ * All pages are merged into a single UserDocument.
83
+ *
84
+ * @param {string} templateId - The template ID to process with.
85
+ * @param {string[]} base64ImagesArray - Array of base64-encoded images (one per page).
86
+ * @returns {Promise<Object>} The created UserDocument with merged extracted JSON.
87
+ */
28
88
  export async function processImagesMultipage(templateId, base64ImagesArray) {
29
- const res = await api.post(`/public/templates/${templateId}/process-multipage`, {
30
- images: base64ImagesArray
89
+ const res = await api.post(`/templates/${templateId}/process-multipage`, {
90
+ images: base64ImagesArray,
91
+ });
92
+ return res.data;
93
+ }
94
+
95
+ /**
96
+ * Generates an AI summary for the extracted data of a document.
97
+ *
98
+ * @param {string} docId - The document ID.
99
+ * @returns {Promise<{ summary: string }>} Object with the generated summary text.
100
+ */
101
+ export async function generateDocumentSummary(docId) {
102
+ const res = await api.post(`/documents/${docId}/summary`);
103
+ return res.data;
104
+ }
105
+
106
+ /**
107
+ * Updates the status of a document.
108
+ *
109
+ * Valid status values depend on your workflow configuration
110
+ * (e.g. "REVIEWED", "PENDING", "APPROVED").
111
+ *
112
+ * @param {string} docId - The document ID.
113
+ * @param {string} status - The new status string.
114
+ * @returns {Promise<{ id: string, status: string }>}
115
+ */
116
+ export async function updateDocumentStatus(docId, status) {
117
+ const res = await api.put(`/documents/${docId}/status`, { status });
118
+ return res.data;
119
+ }
120
+
121
+ /**
122
+ * Saves or clears reviewer notes on a document.
123
+ *
124
+ * @param {string} docId - The document ID.
125
+ * @param {string} notes - Annotation text. Pass an empty string to clear.
126
+ * @returns {Promise<{ id: string, notes: string }>}
127
+ */
128
+ export async function updateDocumentNotes(docId, notes) {
129
+ const res = await api.put(`/documents/${docId}/notes`, { notes });
130
+ return res.data;
131
+ }
132
+
133
+ /**
134
+ * Updates the extracted JSON data of a document and optionally marks it as reviewed.
135
+ *
136
+ * @param {string} docId - The document ID.
137
+ * @param {Object} data - New extracted data object (key-value pairs).
138
+ * @param {Object} [options]
139
+ * @param {boolean} [options.preconformed=false] - Whether to mark the document as reviewed/confirmed.
140
+ * @returns {Promise<Object>} The updated UserDocument.
141
+ */
142
+ export async function updateDocumentData(docId, data, options = {}) {
143
+ const res = await api.put(`/documents/${docId}/data`, {
144
+ data,
145
+ preconformed: options.preconformed ?? false,
146
+ });
147
+ return res.data;
148
+ }
149
+
150
+ /**
151
+ * Marks multiple documents as preconformed (reviewed) in a single request.
152
+ *
153
+ * @param {string[]} ids - Array of document IDs to mark as reviewed.
154
+ * @returns {Promise<{ updated: number }>} Number of documents actually updated.
155
+ */
156
+ export async function bulkPreconform(ids) {
157
+ const res = await api.post("/documents/bulk-preconform", { ids });
158
+ return res.data;
159
+ }
160
+
161
+ /**
162
+ * Exports all documents of a template as a CSV string.
163
+ *
164
+ * The returned string is UTF-8 CSV (with BOM). You can save it as a `.csv` file
165
+ * or feed it into a CSV parser.
166
+ *
167
+ * @param {string} templateId - The template ID.
168
+ * @param {Object} [options]
169
+ * @param {string[]} [options.fields] - Optional subset of column names to include.
170
+ * @returns {Promise<string>} Raw CSV text.
171
+ */
172
+ export async function exportDocumentsCsv(templateId, options = {}) {
173
+ const params = {};
174
+ if (options.fields && options.fields.length > 0)
175
+ params.fields = options.fields.join(",");
176
+ const res = await api.get(`/templates/${templateId}/documents/export/csv`, {
177
+ params,
178
+ responseType: "text",
31
179
  });
32
180
  return res.data;
33
181
  }
182
+
183
+ /**
184
+ * Exports all documents of a template as a JSON array.
185
+ *
186
+ * Each element contains the extracted field map plus three metadata keys:
187
+ * `_id`, `_preconformed`, and `_uploadedAt`.
188
+ *
189
+ * @param {string} templateId - The template ID.
190
+ * @returns {Promise<Object[]>} Array of document data objects.
191
+ */
192
+ export async function exportDocumentsJson(templateId) {
193
+ const res = await api.get(`/templates/${templateId}/documents/export/json`);
194
+ return res.data;
195
+ }
package/src/errors.js ADDED
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Base error for all Extractia SDK errors.
3
+ * Always carries the HTTP `status` code and a human-readable `message`.
4
+ */
5
+ export class ExtractiaError extends Error {
6
+ /** @param {string} message @param {number} status */
7
+ constructor(message, status) {
8
+ super(message);
9
+ this.name = "ExtractiaError";
10
+ this.status = status;
11
+ }
12
+ }
13
+
14
+ /**
15
+ * Thrown when the API token is missing or invalid (HTTP 401).
16
+ */
17
+ export class AuthError extends ExtractiaError {
18
+ constructor(message = "Unauthorized. Check your API token.") {
19
+ super(message, 401);
20
+ this.name = "AuthError";
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Thrown when the account has no permission to perform the action (HTTP 403).
26
+ * Typically means the email is unconfirmed or a sub-user lacks the required permission.
27
+ */
28
+ export class ForbiddenError extends ExtractiaError {
29
+ constructor(message = "Forbidden. Insufficient permissions.") {
30
+ super(message, 403);
31
+ this.name = "ForbiddenError";
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Thrown when the active plan does not allow the requested operation (HTTP 402 / 429 tier).
37
+ * Check `error.status` to distinguish payment-required (402) from rate-limit (429).
38
+ */
39
+ export class TierError extends ExtractiaError {
40
+ constructor(
41
+ message = "Tier limit reached. Upgrade your plan.",
42
+ status = 402,
43
+ ) {
44
+ super(message, status);
45
+ this.name = "TierError";
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Thrown when the API rate limit is exceeded (HTTP 429).
51
+ */
52
+ export class RateLimitError extends ExtractiaError {
53
+ constructor(message = "Too many requests. Please slow down.") {
54
+ super(message, 429);
55
+ this.name = "RateLimitError";
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Thrown when a requested resource was not found (HTTP 404).
61
+ */
62
+ export class NotFoundError extends ExtractiaError {
63
+ constructor(message = "Resource not found.") {
64
+ super(message, 404);
65
+ this.name = "NotFoundError";
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Maps an Axios error to the appropriate typed SDK error.
71
+ * Falls back to a generic `ExtractiaError` for unexpected status codes.
72
+ *
73
+ * @param {import('axios').AxiosError} err
74
+ * @returns {ExtractiaError}
75
+ */
76
+ export function mapAxiosError(err) {
77
+ const status = err.response?.status;
78
+ const serverMessage = err.response?.data;
79
+ const detail = typeof serverMessage === "string" ? serverMessage : undefined;
80
+
81
+ switch (status) {
82
+ case 401:
83
+ return new AuthError(detail);
84
+ case 402:
85
+ return new TierError(detail);
86
+ case 403:
87
+ return new ForbiddenError(detail);
88
+ case 404:
89
+ return new NotFoundError(detail);
90
+ case 429:
91
+ return new RateLimitError(detail);
92
+ default:
93
+ return new ExtractiaError(detail ?? err.message, status ?? 0);
94
+ }
95
+ }