totalum-api-sdk 3.0.1 → 3.0.3

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/README.MD CHANGED
@@ -1,4 +1,4 @@
1
- ## Totalum API SDK (v3.0.1)
1
+ ## Totalum API SDK (v3.0.2)
2
2
 
3
3
  Official TypeScript/JavaScript SDK for the Totalum API. This library provides a fully typed, modern interface to interact with all Totalum endpoints.
4
4
 
@@ -48,7 +48,7 @@ await totalumClient.crud.getManyToManyReferencesRecords(table, id, prop, query);
48
48
  ```javascript
49
49
  // v2.x (using axios)
50
50
  const result = await totalumClient.crud.getItems(table, {});
51
- const items = result.data.data; // Double .data because of axios wrapper
51
+ const items = result.data; // Double .data because of axios wrapper
52
52
 
53
53
  // v3.0 (using fetch)
54
54
  const result = await totalumClient.crud.getRecords(table, {});
@@ -64,7 +64,7 @@ const records = result.data; // Direct access to data
64
64
  // v2.x (axios throws errors)
65
65
  try {
66
66
  const result = await totalumClient.crud.getItems(table, {});
67
- const items = result.data.data;
67
+ const items = result.data;
68
68
  } catch (error) {
69
69
  console.error('Error:', error.message);
70
70
  }
@@ -178,7 +178,7 @@ const result = await totalumClient.crud.getRecords('your_table_name', {});
178
178
 
179
179
  ```html
180
180
  <head>
181
- <script src="https://cdn.jsdelivr.net/npm/totalum-api-sdk@3.0.1/dist/totalum-sdk.min.js"></script>
181
+ <script src="https://cdn.jsdelivr.net/npm/totalum-api-sdk@3.0.2/dist/totalum-sdk.min.js"></script>
182
182
  </head>
183
183
  <script>
184
184
  //Example of use TotalumSdk in your custom html page
@@ -414,7 +414,7 @@ const tableNameToGet = 'client';
414
414
 
415
415
  const result = await totalumClient.filter.nestedFilter(nestedFilter, tableNameToGet, filterOptions);
416
416
 
417
- const clients = result.data.data;
417
+ const clients = result.data;
418
418
 
419
419
  ```
420
420
 
@@ -461,7 +461,7 @@ const tableNameToGet = 'product';
461
461
 
462
462
  const result = await totalumClient.filter.nestedFilter(nestedFilter, tableNameToGet, filterOptions);
463
463
 
464
- const products = result.data.data;
464
+ const products = result.data;
465
465
 
466
466
  ```
467
467
 
@@ -911,7 +911,7 @@ Depending on the platform you are using, you will need to transform the file to
911
911
  'api-key': 'your api key here', // replace 'your api key here' with your api key
912
912
  }
913
913
  });
914
- const fileNameId = result.data.data;
914
+ const fileNameId = result.data;
915
915
  ```
916
916
 
917
917
 
@@ -1082,7 +1082,7 @@ if (result.errors) {
1082
1082
  return;
1083
1083
  }
1084
1084
 
1085
- const invoiceData = result.data.data;
1085
+ const invoiceData = result.data;
1086
1086
  const metadata = result.data.metadata;
1087
1087
 
1088
1088
  console.log('Invoice data:', invoiceData);
@@ -1136,7 +1136,7 @@ if (result.errors) {
1136
1136
  return;
1137
1137
  }
1138
1138
 
1139
- const documentData = result.data.data;
1139
+ const documentData = result.data;
1140
1140
  const metadata = result.data.metadata;
1141
1141
 
1142
1142
  console.log('Extracted data:', documentData);
@@ -10,6 +10,7 @@ export interface ErrorResult {
10
10
  export interface TotalumApiResponse<T> {
11
11
  data?: T;
12
12
  errors?: ErrorResult | null;
13
+ metadata?: any;
13
14
  }
14
15
  export interface StructureLevels {
15
16
  id: string;
@@ -17,12 +17,6 @@ export interface DeleteObjectResponse {
17
17
  /** The number of documents that were deleted */
18
18
  deletedCount: number;
19
19
  }
20
- export interface GetObjectsResponse<T = DataValues> {
21
- data: T[];
22
- metadata?: {
23
- count?: number;
24
- };
25
- }
26
20
  export interface FileUploadResponse {
27
21
  fileName: string;
28
22
  }
@@ -74,23 +68,6 @@ export interface ScanInvoiceData {
74
68
  [key: string]: any;
75
69
  };
76
70
  }
77
- export interface ScanInvoiceResponse {
78
- data: ScanInvoiceData;
79
- metadata: {
80
- ocrFullResult?: any;
81
- usageUnits: number;
82
- exactUsageUnits: number;
83
- };
84
- }
85
- export interface ScanDocumentResponse {
86
- data: any;
87
- metadata: {
88
- ocrFullResult?: any;
89
- ocrFullResultText?: string;
90
- usageUnits: number;
91
- exactUsageUnits: number;
92
- };
93
- }
94
71
  export interface PdfGenerationResponse {
95
72
  fileName: string;
96
73
  }
@@ -143,12 +120,6 @@ export interface LookupFilterResult {
143
120
  result: DataValues[] | number;
144
121
  count?: number;
145
122
  }
146
- export interface NestedFilterResponse {
147
- data: DataValues[];
148
- metadata?: {
149
- count?: number;
150
- };
151
- }
152
123
  export type CustomAggregationResponse = any;
153
124
  export interface NotificationVisibility {
154
125
  sendTo: "all" | "admins" | "specificUsers";
@@ -1,5 +1,5 @@
1
1
  import { TotalumApiResponse } from "../common/interfaces";
2
- import { FileDeleteResponse, OcrImageResponse, OcrPdfResponse, ScanInvoiceResponse, ScanDocumentResponse } from "../common/response-types";
2
+ import { FileDeleteResponse, OcrImageResponse, OcrPdfResponse, ScanInvoiceData } from "../common/response-types";
3
3
  import { FetchClient } from "../common/fetch-client";
4
4
  export declare class FilesService {
5
5
  private client;
@@ -45,12 +45,15 @@ export declare class FilesService {
45
45
  * @param {object} data - PDF creation data
46
46
  * @param {string} data.html - HTML content to convert
47
47
  * @param {string} data.name - Name for the generated PDF
48
- * @returns {Promise<TotalumApiResponse<string>>} - The generated PDF filename
48
+ * @returns {Promise<TotalumApiResponse<{url: string, fileName: string}>>} - The generated PDF url
49
49
  */
50
50
  createPdfFromHtml(data: {
51
51
  html: string;
52
52
  name: string;
53
- }): Promise<TotalumApiResponse<string>>;
53
+ }): Promise<TotalumApiResponse<{
54
+ url: string;
55
+ fileName: string;
56
+ }>>;
54
57
  /**
55
58
  * Performs OCR on an image file.
56
59
  * @param {string} fileName - The file name of the uploaded image
@@ -68,9 +71,9 @@ export declare class FilesService {
68
71
  * The response includes both data and metadata with OCR details and usage tracking.
69
72
  * @param {string} fileName - The file name of the uploaded invoice
70
73
  * @param {any} options - Optional scanning options
71
- * @returns {Promise<TotalumApiResponse<ScanInvoiceResponse>>}
74
+ * @returns {Promise<TotalumApiResponse<ScanInvoiceData>>}
72
75
  */
73
- scanInvoice(fileName: string, options?: any): Promise<TotalumApiResponse<ScanInvoiceResponse>>;
76
+ scanInvoice(fileName: string, options?: any): Promise<TotalumApiResponse<ScanInvoiceData>>;
74
77
  /**
75
78
  * Scans a document and extracts specified properties.
76
79
  * The response includes both data (based on provided schema) and metadata with OCR details.
@@ -79,5 +82,5 @@ export declare class FilesService {
79
82
  * @param {any} options - Optional scanning options
80
83
  * @returns {Promise<TotalumApiResponse<ScanDocumentResponse>>}
81
84
  */
82
- scanDocument(fileName: string, properties: any, options?: any): Promise<TotalumApiResponse<ScanDocumentResponse>>;
85
+ scanDocument(fileName: string, properties: any, options?: any): Promise<TotalumApiResponse<any>>;
83
86
  }
@@ -73,7 +73,7 @@ class FilesService {
73
73
  * @param {object} data - PDF creation data
74
74
  * @param {string} data.html - HTML content to convert
75
75
  * @param {string} data.name - Name for the generated PDF
76
- * @returns {Promise<TotalumApiResponse<string>>} - The generated PDF filename
76
+ * @returns {Promise<TotalumApiResponse<{url: string, fileName: string}>>} - The generated PDF url
77
77
  */
78
78
  createPdfFromHtml(data) {
79
79
  return __awaiter(this, void 0, void 0, function* () {
@@ -118,7 +118,7 @@ class FilesService {
118
118
  * The response includes both data and metadata with OCR details and usage tracking.
119
119
  * @param {string} fileName - The file name of the uploaded invoice
120
120
  * @param {any} options - Optional scanning options
121
- * @returns {Promise<TotalumApiResponse<ScanInvoiceResponse>>}
121
+ * @returns {Promise<TotalumApiResponse<ScanInvoiceData>>}
122
122
  */
123
123
  scanInvoice(fileName, options) {
124
124
  return __awaiter(this, void 0, void 0, function* () {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,686 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const index_1 = require("./index");
16
+ const axios_1 = __importDefault(require("axios"));
17
+ /**
18
+ * Comprehensive test suite for all Totalum API SDK endpoints
19
+ *
20
+ * This test is fully autonomous - it will:
21
+ * - Create a test table with properties
22
+ * - Create and test records
23
+ * - Generate PDF files for testing
24
+ * - Clean up everything at the end
25
+ *
26
+ * To run this test:
27
+ * 1. Set your API key: export TOTALUM_API_KEY=your-key-here
28
+ * 2. Run: npm run test-endpoints
29
+ */
30
+ // Configuration
31
+ const CONFIG = {
32
+ API_KEY: '',
33
+ //BASE_URL: 'https://api.sp-dev-tot-env.app/',
34
+ BASE_URL: 'http://localhost:9000/',
35
+ TEST_TABLE_NAME: `sdk_test_${Date.now()}`, // Unique table name
36
+ TEST_TABLE_ID: '', //no need to set this
37
+ TEST_RECORD_ID: '', //no need to set this
38
+ TEST_USER_EMAIL: 'contacto@totalum.app',
39
+ };
40
+ // Color codes for console output
41
+ const colors = {
42
+ reset: '\x1b[0m',
43
+ green: '\x1b[32m',
44
+ red: '\x1b[31m',
45
+ yellow: '\x1b[33m',
46
+ blue: '\x1b[36m',
47
+ gray: '\x1b[90m',
48
+ };
49
+ // Test results tracking
50
+ let totalTests = 0;
51
+ let passedTests = 0;
52
+ let failedTests = 0;
53
+ let skippedTests = 0;
54
+ // Validate API key
55
+ if (!CONFIG.API_KEY || CONFIG.API_KEY === 'your-api-key-here') {
56
+ console.error(`${colors.red}✗ ERROR: TOTALUM_API_KEY environment variable is not set${colors.reset}`);
57
+ console.log(`${colors.yellow}Please set your API key:${colors.reset}`);
58
+ console.log(` export TOTALUM_API_KEY=your-key-here`);
59
+ console.log(` npm run test-endpoints\n`);
60
+ process.exit(1);
61
+ }
62
+ // Initialize SDK
63
+ let sdk;
64
+ try {
65
+ sdk = new index_1.TotalumApiSdk({
66
+ apiKey: { 'api-key': CONFIG.API_KEY },
67
+ baseUrl: CONFIG.BASE_URL
68
+ });
69
+ console.log(`${colors.blue}✓ SDK initialized successfully${colors.reset}\n`);
70
+ }
71
+ catch (error) {
72
+ console.error(`${colors.red}✗ Failed to initialize SDK: ${error}${colors.reset}`);
73
+ process.exit(1);
74
+ }
75
+ // Axios instance for direct API calls (for table creation/deletion)
76
+ const axiosInstance = axios_1.default.create({
77
+ baseURL: CONFIG.BASE_URL,
78
+ headers: {
79
+ 'api-key': CONFIG.API_KEY,
80
+ 'Content-Type': 'application/json',
81
+ },
82
+ });
83
+ // Helper functions
84
+ function logTest(name) {
85
+ console.log(`${colors.gray}Testing: ${name}${colors.reset}`);
86
+ }
87
+ function logSuccess(name, data) {
88
+ totalTests++;
89
+ passedTests++;
90
+ console.log(`${colors.green}✓ ${name}${colors.reset}`);
91
+ if (data) {
92
+ console.log(` ${colors.gray}Response:${colors.reset}`, JSON.stringify(data, null, 2));
93
+ }
94
+ console.log('');
95
+ }
96
+ function logError(name, error) {
97
+ totalTests++;
98
+ failedTests++;
99
+ console.error(`${colors.red}✗ ${name}${colors.reset}`);
100
+ console.error(` ${colors.red}Error:${colors.reset}`, (error === null || error === void 0 ? void 0 : error.message) || error);
101
+ console.log('');
102
+ }
103
+ function logSkip(name, reason) {
104
+ totalTests++;
105
+ skippedTests++;
106
+ console.log(`${colors.yellow}⊘ ${name} (SKIPPED)${colors.reset}`);
107
+ if (reason) {
108
+ console.log(` ${colors.gray}Reason: ${reason}${colors.reset}`);
109
+ }
110
+ console.log('');
111
+ }
112
+ function logSection(name) {
113
+ console.log(`\n${colors.blue}${'='.repeat(60)}${colors.reset}`);
114
+ console.log(`${colors.blue}${name}${colors.reset}`);
115
+ console.log(`${colors.blue}${'='.repeat(60)}${colors.reset}\n`);
116
+ }
117
+ // Setup and teardown functions
118
+ function setupTestTable() {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ var _a, _b;
121
+ logSection('SETUP: Creating Test Table');
122
+ try {
123
+ logTest('Create test table structure');
124
+ const createTableResponse = yield axiosInstance.post('/api/v1/data-structure/', {
125
+ type: CONFIG.TEST_TABLE_NAME,
126
+ });
127
+ if ((_b = (_a = createTableResponse.data) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.insertedId) {
128
+ CONFIG.TEST_TABLE_ID = createTableResponse.data.data.insertedId.toString();
129
+ logSuccess('Create test table structure', { tableId: CONFIG.TEST_TABLE_ID });
130
+ }
131
+ else {
132
+ throw new Error('Failed to get table ID from response');
133
+ }
134
+ }
135
+ catch (error) {
136
+ logError('Create test table structure', error);
137
+ throw error;
138
+ }
139
+ // Create properties for the test table
140
+ const properties = [
141
+ {
142
+ id: 'name',
143
+ name: 'Name',
144
+ propertyType: 'string',
145
+ required: true,
146
+ },
147
+ {
148
+ id: 'description',
149
+ name: 'Description',
150
+ propertyType: 'long-string',
151
+ },
152
+ {
153
+ id: 'value',
154
+ name: 'Value',
155
+ propertyType: 'number',
156
+ }
157
+ ];
158
+ for (const property of properties) {
159
+ try {
160
+ logTest(`Create property: ${property.name}`);
161
+ yield axiosInstance.post(`/api/v1/data-structure/${CONFIG.TEST_TABLE_ID}/property`, property);
162
+ logSuccess(`Create property: ${property.name}`);
163
+ }
164
+ catch (error) {
165
+ logError(`Create property: ${property.name}`, error);
166
+ throw error;
167
+ }
168
+ }
169
+ console.log(`${colors.green}✓ Test table setup complete${colors.reset}\n`);
170
+ });
171
+ }
172
+ function teardownTestTable() {
173
+ return __awaiter(this, void 0, void 0, function* () {
174
+ logSection('TEARDOWN: Cleaning Up Test Table');
175
+ if (!CONFIG.TEST_TABLE_ID) {
176
+ console.log(`${colors.yellow}No test table to clean up${colors.reset}\n`);
177
+ return;
178
+ }
179
+ try {
180
+ logTest('Delete test table structure');
181
+ yield axiosInstance.delete(`/api/v1/data-structure/${CONFIG.TEST_TABLE_ID}`);
182
+ logSuccess('Delete test table structure');
183
+ }
184
+ catch (error) {
185
+ logError('Delete test table structure', error);
186
+ }
187
+ console.log(`${colors.green}✓ Test table cleanup complete${colors.reset}\n`);
188
+ });
189
+ }
190
+ // Main test function
191
+ function runTests() {
192
+ return __awaiter(this, void 0, void 0, function* () {
193
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
194
+ console.log(`${colors.blue}╔${'═'.repeat(58)}╗${colors.reset}`);
195
+ console.log(`${colors.blue}║ TOTALUM API SDK - COMPREHENSIVE ENDPOINT TEST SUITE ║${colors.reset}`);
196
+ console.log(`${colors.blue}╚${'═'.repeat(58)}╝${colors.reset}\n`);
197
+ try {
198
+ // Setup test environment
199
+ yield setupTestTable();
200
+ // ===========================================
201
+ // 1. CRUD SERVICE TESTS
202
+ // ===========================================
203
+ logSection('1. CRUD SERVICE TESTS');
204
+ // Test: Create Record
205
+ try {
206
+ logTest('crud.createRecord');
207
+ const createResult = yield sdk.crud.createRecord(CONFIG.TEST_TABLE_NAME, {
208
+ name: 'Test Record',
209
+ description: 'Created by SDK test suite',
210
+ value: 123,
211
+ isActive: true,
212
+ });
213
+ if (createResult.errors) {
214
+ logError('crud.createRecord', createResult.errors);
215
+ }
216
+ else if (createResult.data) {
217
+ CONFIG.TEST_RECORD_ID = createResult.data._id;
218
+ logSuccess('crud.createRecord', { recordId: CONFIG.TEST_RECORD_ID });
219
+ }
220
+ }
221
+ catch (error) {
222
+ logError('crud.createRecord', error);
223
+ }
224
+ // Test: Get Record by ID
225
+ if (CONFIG.TEST_RECORD_ID) {
226
+ try {
227
+ logTest('crud.getRecordById');
228
+ const getResult = yield sdk.crud.getRecordById(CONFIG.TEST_TABLE_NAME, CONFIG.TEST_RECORD_ID);
229
+ if (getResult.errors) {
230
+ logError('crud.getRecordById', getResult.errors);
231
+ }
232
+ else {
233
+ logSuccess('crud.getRecordById', { name: (_a = getResult.data) === null || _a === void 0 ? void 0 : _a.name });
234
+ }
235
+ }
236
+ catch (error) {
237
+ logError('crud.getRecordById', error);
238
+ }
239
+ }
240
+ else {
241
+ logSkip('crud.getRecordById', 'No record ID available');
242
+ }
243
+ // Test: Get Records (with query)
244
+ try {
245
+ logTest('crud.getRecords');
246
+ const getRecordsResult = yield sdk.crud.getRecords(CONFIG.TEST_TABLE_NAME, {
247
+ filter: [{ name: 'Test Record' }],
248
+ pagination: { limit: 10, page: 1 },
249
+ returnCount: true,
250
+ });
251
+ if (getRecordsResult.errors) {
252
+ logError('crud.getRecords', getRecordsResult.errors);
253
+ }
254
+ else {
255
+ logSuccess('crud.getRecords', {
256
+ recordCount: Array.isArray(getRecordsResult.data) ? getRecordsResult.data.length : 0,
257
+ });
258
+ }
259
+ }
260
+ catch (error) {
261
+ logError('crud.getRecords', error);
262
+ }
263
+ // Test: Edit Record by ID
264
+ if (CONFIG.TEST_RECORD_ID) {
265
+ try {
266
+ logTest('crud.editRecordById');
267
+ const editResult = yield sdk.crud.editRecordById(CONFIG.TEST_TABLE_NAME, CONFIG.TEST_RECORD_ID, { description: 'Updated by SDK test suite', value: 456 });
268
+ if (editResult.errors) {
269
+ logError('crud.editRecordById', editResult.errors);
270
+ }
271
+ else {
272
+ logSuccess('crud.editRecordById', { value: (_b = editResult.data) === null || _b === void 0 ? void 0 : _b.value });
273
+ }
274
+ }
275
+ catch (error) {
276
+ logError('crud.editRecordById', error);
277
+ }
278
+ }
279
+ else {
280
+ logSkip('crud.editRecordById', 'No record ID available');
281
+ }
282
+ // Test: Get Historic Record Updates
283
+ if (CONFIG.TEST_RECORD_ID) {
284
+ try {
285
+ logTest('crud.getHistoricRecordUpdatesById');
286
+ const historyResult = yield sdk.crud.getHistoricRecordUpdatesById(CONFIG.TEST_RECORD_ID);
287
+ if (historyResult.errors) {
288
+ logError('crud.getHistoricRecordUpdatesById', historyResult.errors);
289
+ }
290
+ else {
291
+ logSuccess('crud.getHistoricRecordUpdatesById', {
292
+ updateCount: Array.isArray(historyResult.data) ? historyResult.data.length : 0,
293
+ });
294
+ }
295
+ }
296
+ catch (error) {
297
+ logError('crud.getHistoricRecordUpdatesById', error);
298
+ }
299
+ }
300
+ else {
301
+ logSkip('crud.getHistoricRecordUpdatesById', 'No record ID available');
302
+ }
303
+ // Test: Get Nested Data
304
+ try {
305
+ logTest('crud.getNestedData');
306
+ const nestedResult = yield sdk.crud.getNestedData({
307
+ [CONFIG.TEST_TABLE_NAME]: {
308
+ tableFilter: { filter: [{ name: 'Test Record' }] },
309
+ },
310
+ });
311
+ if (nestedResult.errors) {
312
+ logError('crud.getNestedData', nestedResult.errors);
313
+ }
314
+ else {
315
+ logSuccess('crud.getNestedData', {
316
+ resultCount: Array.isArray(nestedResult.data) ? nestedResult.data.length : 0,
317
+ });
318
+ }
319
+ }
320
+ catch (error) {
321
+ logError('crud.getNestedData', error);
322
+ }
323
+ // Test: Add Many-to-Many Reference (skip if no reference data)
324
+ logSkip('crud.addManyToManyReferenceRecord', 'Requires specific reference configuration');
325
+ // Test: Get Many-to-Many References
326
+ logSkip('crud.getManyToManyReferencesRecords', 'Requires specific reference configuration');
327
+ // Test: Drop Many-to-Many Reference
328
+ logSkip('crud.dropManyToManyReferenceRecord', 'Requires specific reference configuration');
329
+ // Test: Delete Record by ID (run last for CRUD tests)
330
+ if (CONFIG.TEST_RECORD_ID) {
331
+ try {
332
+ logTest('crud.deleteRecordById');
333
+ const deleteResult = yield sdk.crud.deleteRecordById(CONFIG.TEST_TABLE_NAME, CONFIG.TEST_RECORD_ID);
334
+ if (deleteResult.errors) {
335
+ logError('crud.deleteRecordById', deleteResult.errors);
336
+ }
337
+ else {
338
+ logSuccess('crud.deleteRecordById', { acknowledged: (_c = deleteResult.data) === null || _c === void 0 ? void 0 : _c.acknowledged });
339
+ }
340
+ }
341
+ catch (error) {
342
+ logError('crud.deleteRecordById', error);
343
+ }
344
+ }
345
+ else {
346
+ logSkip('crud.deleteRecordById', 'No record ID available');
347
+ }
348
+ // ===========================================
349
+ // 2. FILTER SERVICE TESTS
350
+ // ===========================================
351
+ logSection('2. FILTER SERVICE TESTS');
352
+ // Test: Nested Filter
353
+ try {
354
+ logTest('filter.nestedFilter');
355
+ const nestedFilterResult = yield sdk.filter.nestedFilter({
356
+ [CONFIG.TEST_TABLE_NAME]: {
357
+ tableFilter: [],
358
+ },
359
+ }, CONFIG.TEST_TABLE_NAME, { pagination: { limit: 5, page: 1 } });
360
+ if (nestedFilterResult.errors) {
361
+ logError('filter.nestedFilter', nestedFilterResult.errors);
362
+ }
363
+ else {
364
+ logSuccess('filter.nestedFilter', {
365
+ resultCount: Array.isArray(nestedFilterResult.data) ? nestedFilterResult.data.length : 0,
366
+ });
367
+ }
368
+ }
369
+ catch (error) {
370
+ logError('filter.nestedFilter', error);
371
+ }
372
+ // Test: Lookup Filter (deprecated)
373
+ logSkip('filter.lookUpFilter', 'Deprecated - use nestedFilter instead');
374
+ // Test: Run Custom Mongo Aggregation Query
375
+ logSkip('filter.runCustomMongoAggregationQuery', 'Requires custom MongoDB query configuration');
376
+ // ===========================================
377
+ // 3. FILES SERVICE TESTS
378
+ // ===========================================
379
+ logSection('3. FILES SERVICE TESTS');
380
+ // Test: Generate PDF from HTML (do this first to use for file tests)
381
+ let generatedPdfFileName;
382
+ try {
383
+ logTest('files.createPdfFromHtml');
384
+ const pdfResult = yield sdk.files.createPdfFromHtml({
385
+ html: '<html><body><h1>Test PDF</h1><p>Generated by SDK test suite for testing file operations</p></body></html>',
386
+ name: 'test-pdf.pdf',
387
+ });
388
+ if (pdfResult.errors) {
389
+ logError('files.createPdfFromHtml', pdfResult.errors);
390
+ }
391
+ else if (pdfResult.data) {
392
+ generatedPdfFileName = pdfResult.data.fileName;
393
+ logSuccess('files.createPdfFromHtml', { fileName: pdfResult.data });
394
+ }
395
+ }
396
+ catch (error) {
397
+ logError('files.createPdfFromHtml', error);
398
+ }
399
+ // Test: Upload File
400
+ let uploadedFileName;
401
+ try {
402
+ logTest('files.uploadFile');
403
+ // Create a simple test file
404
+ const fileContent = 'This is a test file created by the SDK test suite';
405
+ const blob = new Blob([fileContent], { type: 'text/plain' });
406
+ const formData = new FormData();
407
+ formData.append('file', blob, 'test-file.txt');
408
+ const uploadResult = yield sdk.files.uploadFile(formData);
409
+ if (uploadResult.errors) {
410
+ logError('files.uploadFile', uploadResult.errors);
411
+ }
412
+ else if (uploadResult.data) {
413
+ uploadedFileName = uploadResult.data;
414
+ logSuccess('files.uploadFile', { fileName: uploadResult.data });
415
+ }
416
+ }
417
+ catch (error) {
418
+ logError('files.uploadFile', error);
419
+ }
420
+ // Test: Get Download URL (use generated PDF)
421
+ if (generatedPdfFileName) {
422
+ try {
423
+ logTest('files.getDownloadUrl');
424
+ const downloadUrlResult = yield sdk.files.getDownloadUrl(generatedPdfFileName);
425
+ if (downloadUrlResult.errors) {
426
+ logError('files.getDownloadUrl', downloadUrlResult.errors);
427
+ }
428
+ else {
429
+ logSuccess('files.getDownloadUrl', { urlExists: !!downloadUrlResult.data });
430
+ }
431
+ }
432
+ catch (error) {
433
+ logError('files.getDownloadUrl', error);
434
+ }
435
+ }
436
+ else {
437
+ logSkip('files.getDownloadUrl', 'No PDF file available');
438
+ }
439
+ // Test: Generate PDF by Template
440
+ logSkip('files.generatePdfByTemplate', 'Requires template configuration');
441
+ // Test: OCR of Image
442
+ logSkip('files.ocrOfImage', 'Requires uploaded image file');
443
+ // Test: OCR of PDF (use generated PDF)
444
+ if (generatedPdfFileName) {
445
+ try {
446
+ logTest('files.ocrOfPdf');
447
+ const ocrResult = yield sdk.files.ocrOfPdf(generatedPdfFileName);
448
+ if (ocrResult.errors) {
449
+ logError('files.ocrOfPdf', ocrResult.errors);
450
+ }
451
+ else {
452
+ logSuccess('files.ocrOfPdf', {
453
+ pageCount: Array.isArray((_d = ocrResult.data) === null || _d === void 0 ? void 0 : _d.pages)
454
+ ? ocrResult.data.pages.length
455
+ : 0,
456
+ });
457
+ }
458
+ }
459
+ catch (error) {
460
+ logError('files.ocrOfPdf', error);
461
+ }
462
+ }
463
+ else {
464
+ logSkip('files.ocrOfPdf', 'No PDF file available');
465
+ }
466
+ // Test: Scan Invoice
467
+ logSkip('files.scanInvoice', 'Requires uploaded invoice file');
468
+ // Test: Scan Document
469
+ logSkip('files.scanDocument', 'Requires uploaded document file and schema');
470
+ // Test: Delete Files (cleanup)
471
+ if (uploadedFileName) {
472
+ try {
473
+ logTest('files.deleteFile (uploaded file)');
474
+ const deleteFileResult = yield sdk.files.deleteFile(uploadedFileName);
475
+ if (deleteFileResult.errors) {
476
+ logError('files.deleteFile (uploaded file)', deleteFileResult.errors);
477
+ }
478
+ else {
479
+ logSuccess('files.deleteFile (uploaded file)', { acknowledged: (_e = deleteFileResult.data) === null || _e === void 0 ? void 0 : _e.acknowledged });
480
+ }
481
+ }
482
+ catch (error) {
483
+ logError('files.deleteFile (uploaded file)', error);
484
+ }
485
+ }
486
+ if (generatedPdfFileName) {
487
+ try {
488
+ logTest('files.deleteFile (generated PDF)');
489
+ const deleteFileResult = yield sdk.files.deleteFile(generatedPdfFileName);
490
+ if (deleteFileResult.errors) {
491
+ logError('files.deleteFile (generated PDF)', deleteFileResult.errors);
492
+ }
493
+ else {
494
+ logSuccess('files.deleteFile (generated PDF)', { acknowledged: (_f = deleteFileResult.data) === null || _f === void 0 ? void 0 : _f.acknowledged });
495
+ }
496
+ }
497
+ catch (error) {
498
+ logError('files.deleteFile (generated PDF)', error);
499
+ }
500
+ }
501
+ // ===========================================
502
+ // 4. OPENAI SERVICE TESTS
503
+ // ===========================================
504
+ logSection('4. OPENAI SERVICE TESTS');
505
+ // Test: Create Chat Completion
506
+ try {
507
+ logTest('openai.createChatCompletion');
508
+ const chatResult = yield sdk.openai.createChatCompletion({
509
+ model: 'gpt-3.5-turbo',
510
+ messages: [{ role: 'user', content: 'Say "SDK test successful" if you can read this.' }],
511
+ max_tokens: 50,
512
+ });
513
+ if (chatResult.errors) {
514
+ logError('openai.createChatCompletion', chatResult.errors);
515
+ }
516
+ else {
517
+ logSuccess('openai.createChatCompletion', {
518
+ response: (_k = (_j = (_h = (_g = chatResult.data) === null || _g === void 0 ? void 0 : _g.choices) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.message) === null || _k === void 0 ? void 0 : _k.content,
519
+ });
520
+ }
521
+ }
522
+ catch (error) {
523
+ logError('openai.createChatCompletion', error);
524
+ }
525
+ // Test: Create Completion (deprecated)
526
+ logSkip('openai.createCompletion', 'Deprecated - use createChatCompletion instead');
527
+ // Test: Generate Image
528
+ try {
529
+ logTest('openai.generateImage');
530
+ const imageResult = yield sdk.openai.generateImage({
531
+ prompt: 'A simple test image',
532
+ size: '256x256',
533
+ fileName: 'test-generated-image.png',
534
+ });
535
+ if (imageResult.errors) {
536
+ logError('openai.generateImage', imageResult.errors);
537
+ }
538
+ else {
539
+ logSuccess('openai.generateImage', { fileName: imageResult.data });
540
+ // Cleanup generated image
541
+ if (imageResult.data) {
542
+ try {
543
+ yield sdk.files.deleteFile(imageResult.data);
544
+ }
545
+ catch (e) {
546
+ // Ignore cleanup errors
547
+ }
548
+ }
549
+ }
550
+ }
551
+ catch (error) {
552
+ logError('openai.generateImage', error);
553
+ }
554
+ // ===========================================
555
+ // 5. NOTIFICATION SERVICE TESTS
556
+ // ===========================================
557
+ logSection('5. NOTIFICATION SERVICE TESTS');
558
+ // Test: Create Notification
559
+ try {
560
+ logTest('notification.createNotification');
561
+ const notificationResult = yield sdk.notification.createNotification({
562
+ name: 'Test Notification',
563
+ title: 'SDK Test',
564
+ description: 'This is a test notification from the SDK test suite',
565
+ visibility: {
566
+ sendTo: 'specificUsers',
567
+ specificUsersEmails: [CONFIG.TEST_USER_EMAIL],
568
+ },
569
+ action: {
570
+ actionType: 'none',
571
+ },
572
+ email: {
573
+ sendEmail: false,
574
+ },
575
+ });
576
+ if (notificationResult.errors) {
577
+ logError('notification.createNotification', notificationResult.errors);
578
+ }
579
+ else {
580
+ logSuccess('notification.createNotification', { acknowledged: (_l = notificationResult.data) === null || _l === void 0 ? void 0 : _l.acknowledged });
581
+ }
582
+ }
583
+ catch (error) {
584
+ logError('notification.createNotification', error);
585
+ }
586
+ // ===========================================
587
+ // 6. STATISTIC SERVICE TESTS
588
+ // ===========================================
589
+ logSection('6. STATISTIC SERVICE TESTS');
590
+ // Test: Get Statistic (Quantity)
591
+ try {
592
+ logTest('statistic.getStatistic (quantity)');
593
+ const statisticResult = yield sdk.statistic.getStatistic([], {
594
+ statisticType: 'quantity',
595
+ tableName: CONFIG.TEST_TABLE_NAME,
596
+ propertyName: '_id',
597
+ });
598
+ if (statisticResult.errors) {
599
+ logError('statistic.getStatistic (quantity)', statisticResult.errors);
600
+ }
601
+ else {
602
+ logSuccess('statistic.getStatistic (quantity)', { count: statisticResult.data });
603
+ }
604
+ }
605
+ catch (error) {
606
+ logError('statistic.getStatistic (quantity)', error);
607
+ }
608
+ // Test: Get Statistic (Add/Sum)
609
+ logSkip('statistic.getStatistic (add)', 'Requires numeric property configuration');
610
+ // ===========================================
611
+ // 7. EMAIL SERVICE TESTS
612
+ // ===========================================
613
+ logSection('7. EMAIL SERVICE TESTS');
614
+ // Test: Send Email
615
+ try {
616
+ logTest('email.sendEmail');
617
+ const emailResult = yield sdk.email.sendEmail({
618
+ to: [CONFIG.TEST_USER_EMAIL],
619
+ subject: 'SDK Test Email',
620
+ html: '<h1>Test Email</h1><p>This is a test email from the SDK test suite</p>',
621
+ fromName: 'SDK Test Suite',
622
+ });
623
+ if (emailResult.errors) {
624
+ logError('email.sendEmail', emailResult.errors);
625
+ }
626
+ else {
627
+ logSuccess('email.sendEmail', { emailId: (_m = emailResult.data) === null || _m === void 0 ? void 0 : _m.id });
628
+ }
629
+ }
630
+ catch (error) {
631
+ logError('email.sendEmail', error);
632
+ }
633
+ // Test: Send Email with Attachments
634
+ logSkip('email.sendEmail (with attachments)', 'Requires valid attachment URLs');
635
+ // ===========================================
636
+ // 8. SDK UTILITY TESTS
637
+ // ===========================================
638
+ logSection('8. SDK UTILITY TESTS');
639
+ // Test: Change Base URL
640
+ try {
641
+ logTest('sdk.changeBaseUrl');
642
+ const originalUrl = CONFIG.BASE_URL;
643
+ sdk.changeBaseUrl('https://api-test.totalum.app/');
644
+ sdk.changeBaseUrl(originalUrl); // Change back
645
+ logSuccess('sdk.changeBaseUrl', { message: 'Base URL changed successfully' });
646
+ }
647
+ catch (error) {
648
+ logError('sdk.changeBaseUrl', error);
649
+ }
650
+ }
651
+ finally {
652
+ // Cleanup test environment
653
+ yield teardownTestTable();
654
+ }
655
+ // ===========================================
656
+ // FINAL RESULTS
657
+ // ===========================================
658
+ console.log(`\n${colors.blue}╔${'═'.repeat(58)}╗${colors.reset}`);
659
+ console.log(`${colors.blue}║ TEST RESULTS ║${colors.reset}`);
660
+ console.log(`${colors.blue}╚${'═'.repeat(58)}╝${colors.reset}\n`);
661
+ console.log(`Total Tests: ${totalTests}`);
662
+ console.log(`${colors.green}Passed: ${passedTests}${colors.reset}`);
663
+ console.log(`${colors.red}Failed: ${failedTests}${colors.reset}`);
664
+ console.log(`${colors.yellow}Skipped: ${skippedTests}${colors.reset}`);
665
+ const executedTests = totalTests - skippedTests;
666
+ const successRate = executedTests > 0 ? ((passedTests / executedTests) * 100).toFixed(2) : '0';
667
+ console.log(`\nSuccess Rate: ${successRate}% (excluding skipped tests)\n`);
668
+ if (failedTests > 0) {
669
+ console.log(`${colors.red}⚠ Some tests failed. Please check the errors above.${colors.reset}\n`);
670
+ process.exit(1);
671
+ }
672
+ else if (passedTests === 0) {
673
+ console.log(`${colors.yellow}⚠ No tests passed. Check your configuration and API credentials.${colors.reset}\n`);
674
+ process.exit(1);
675
+ }
676
+ else {
677
+ console.log(`${colors.green}✓ All executed tests passed successfully!${colors.reset}\n`);
678
+ process.exit(0);
679
+ }
680
+ });
681
+ }
682
+ // Run the tests
683
+ runTests().catch((error) => {
684
+ console.error(`${colors.red}Unhandled error during test execution:${colors.reset}`, error);
685
+ process.exit(1);
686
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "totalum-api-sdk",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Totalum sdk wrapper and utils of totalum api",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -8,17 +8,21 @@
8
8
  "dist"
9
9
  ],
10
10
  "scripts": {
11
- "build": "tsc; npx webpack"
11
+ "build": "tsc; npx webpack",
12
+ "test-endpoints": "ts-node test-all-endpoints.ts"
12
13
  },
13
14
  "author": "Totalum",
14
15
  "license": "ISC",
15
16
  "devDependencies": {
17
+ "@types/node": "^24.8.1",
16
18
  "@types/qs": "^6.9.7",
19
+ "axios": "^1.12.2",
20
+ "openai": "^4.104.0",
17
21
  "ts-loader": "^9.5.0",
22
+ "ts-node": "^10.9.2",
18
23
  "typescript": "^5.9.2",
19
24
  "webpack": "^5.89.0",
20
- "webpack-cli": "^5.1.4",
21
- "openai": "^4.104.0"
25
+ "webpack-cli": "^5.1.4"
22
26
  },
23
27
  "dependencies": {
24
28
  "qs": "^6.11.2"