@arela/uploader 0.3.0 → 1.0.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/README.md +130 -5
- package/docs/API_ENDPOINTS_FOR_DETECTION.md +647 -0
- package/docs/QUICK_REFERENCE_API_DETECTION.md +264 -0
- package/docs/REFACTORING_SUMMARY_DETECT_PEDIMENTOS.md +200 -0
- package/package.json +1 -1
- package/src/commands/WatchCommand.js +47 -10
- package/src/config/config.js +157 -2
- package/src/document-types/support-document.js +4 -5
- package/src/file-detection.js +7 -0
- package/src/index.js +119 -4
- package/src/services/AutoProcessingService.js +146 -36
- package/src/services/DatabaseService.js +341 -517
- package/src/services/upload/ApiUploadService.js +426 -4
- package/src/services/upload/MultiApiUploadService.js +233 -0
- package/src/services/upload/UploadServiceFactory.js +24 -0
- package/src/utils/FileOperations.js +6 -3
- package/src/utils/WatchEventHandler.js +14 -9
- package/.envbackup +0 -37
- package/SUPABASE_UPLOAD_FIX.md +0 -157
|
@@ -9,6 +9,8 @@ export class UploadServiceFactory {
|
|
|
9
9
|
constructor() {
|
|
10
10
|
this.apiService = new ApiUploadService();
|
|
11
11
|
this.supabaseService = new SupabaseUploadService();
|
|
12
|
+
// Cache for target-specific API services
|
|
13
|
+
this._targetServices = new Map();
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -54,6 +56,28 @@ export class UploadServiceFactory {
|
|
|
54
56
|
throw new Error('No upload service is available');
|
|
55
57
|
}
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Get an API service configured for a specific target
|
|
61
|
+
* @param {string} target - API target: 'agencia', 'cliente', 'ktj931117p55', or 'default'
|
|
62
|
+
* @returns {Promise<ApiUploadService>} API service for the specified target
|
|
63
|
+
*/
|
|
64
|
+
async getApiServiceForTarget(target) {
|
|
65
|
+
// Import config dynamically to avoid circular dependency
|
|
66
|
+
const { appConfig } = await import('../../config/config.js');
|
|
67
|
+
|
|
68
|
+
const targetConfig = appConfig.getApiConfig(target);
|
|
69
|
+
if (!targetConfig.baseUrl) {
|
|
70
|
+
throw new Error(`No API URL configured for target '${target}'`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create a new service instance with specific config
|
|
74
|
+
// Use setExternalConfig to prevent automatic config refresh from overwriting
|
|
75
|
+
const service = new ApiUploadService();
|
|
76
|
+
service.setExternalConfig(targetConfig.baseUrl, targetConfig.token);
|
|
77
|
+
|
|
78
|
+
return service;
|
|
79
|
+
}
|
|
80
|
+
|
|
57
81
|
/**
|
|
58
82
|
* Check if API mode is currently active
|
|
59
83
|
* @returns {Promise<boolean>} True if API service is available
|
|
@@ -152,8 +152,11 @@ export class FileOperations {
|
|
|
152
152
|
*/
|
|
153
153
|
static listFilesInDirectory(dirPath, options = {}) {
|
|
154
154
|
try {
|
|
155
|
-
const {
|
|
156
|
-
|
|
155
|
+
const {
|
|
156
|
+
excludePattern = /(^|[\/\\])\.|node_modules|\.git/,
|
|
157
|
+
onlyPdf = false,
|
|
158
|
+
} = options;
|
|
159
|
+
|
|
157
160
|
if (!fs.existsSync(dirPath)) {
|
|
158
161
|
return [];
|
|
159
162
|
}
|
|
@@ -163,7 +166,7 @@ export class FileOperations {
|
|
|
163
166
|
|
|
164
167
|
for (const entry of entries) {
|
|
165
168
|
const fullPath = path.join(dirPath, entry.name);
|
|
166
|
-
|
|
169
|
+
|
|
167
170
|
// Skip excluded patterns
|
|
168
171
|
if (excludePattern && excludePattern.test(fullPath)) {
|
|
169
172
|
continue;
|
|
@@ -210,8 +210,9 @@ export class WatchEventHandler {
|
|
|
210
210
|
const files = [];
|
|
211
211
|
|
|
212
212
|
// Get all recent files (valid, non-deleted ones)
|
|
213
|
-
const validFiles = Array.from(this.recentFiles.entries())
|
|
214
|
-
|
|
213
|
+
const validFiles = Array.from(this.recentFiles.entries()).filter(
|
|
214
|
+
([_, metadata]) => metadata.event !== 'unlink',
|
|
215
|
+
);
|
|
215
216
|
|
|
216
217
|
if (validFiles.length === 0) {
|
|
217
218
|
logger.debug('[EventHandler] No valid files in batch');
|
|
@@ -221,11 +222,13 @@ export class WatchEventHandler {
|
|
|
221
222
|
// If sourceDir provided, get ALL files from that directory
|
|
222
223
|
// This ensures when one file is detected, all related files are processed together
|
|
223
224
|
if (sourceDir) {
|
|
224
|
-
logger.debug(
|
|
225
|
-
|
|
225
|
+
logger.debug(
|
|
226
|
+
`[EventHandler] Batch: Processing all files in ${sourceDir}`,
|
|
227
|
+
);
|
|
228
|
+
|
|
226
229
|
for (const [filePath, metadata] of validFiles) {
|
|
227
230
|
const fileDir = path.dirname(filePath);
|
|
228
|
-
|
|
231
|
+
|
|
229
232
|
// Only include files from the source directory or its subdirectories
|
|
230
233
|
if (filePath.startsWith(sourceDir)) {
|
|
231
234
|
try {
|
|
@@ -238,9 +241,11 @@ export class WatchEventHandler {
|
|
|
238
241
|
event: metadata.event,
|
|
239
242
|
type: 'batch',
|
|
240
243
|
});
|
|
241
|
-
|
|
244
|
+
|
|
242
245
|
if (files.length >= batchSize) {
|
|
243
|
-
logger.debug(
|
|
246
|
+
logger.debug(
|
|
247
|
+
`[EventHandler] Batch size limit (${batchSize}) reached`,
|
|
248
|
+
);
|
|
244
249
|
break;
|
|
245
250
|
}
|
|
246
251
|
} catch (error) {
|
|
@@ -254,7 +259,7 @@ export class WatchEventHandler {
|
|
|
254
259
|
} else {
|
|
255
260
|
// Fallback: Sort by timestamp (newest first) and take up to batchSize
|
|
256
261
|
const sortedFiles = validFiles.sort(
|
|
257
|
-
([_, a], [__, b]) => b.timestamp - a.timestamp
|
|
262
|
+
([_, a], [__, b]) => b.timestamp - a.timestamp,
|
|
258
263
|
);
|
|
259
264
|
|
|
260
265
|
for (const [filePath, metadata] of sortedFiles) {
|
|
@@ -268,7 +273,7 @@ export class WatchEventHandler {
|
|
|
268
273
|
event: metadata.event,
|
|
269
274
|
type: 'batch',
|
|
270
275
|
});
|
|
271
|
-
|
|
276
|
+
|
|
272
277
|
if (files.length >= batchSize) {
|
|
273
278
|
break;
|
|
274
279
|
}
|
package/.envbackup
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# SUPABASE_URL=https://supabase.prod.app.trader-docs.com
|
|
2
|
-
# SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic2VydmljZV9yb2xlIiwiaXNzIjoic3VwYWJhc2UiLCJpYXQiOjE3NDU3MzM2MDAsImV4cCI6MTkwMzUwMDAwMH0.eAoXvaBZzZa31txItwEkoLnplWG10ee-U5GMc265xwk
|
|
3
|
-
# SUPABASE_BUCKET=sample
|
|
4
|
-
|
|
5
|
-
# PATH_VARS=o:/ExpedienteElectronicko/expediente/archivos/:rfcPatente/:patente-:aduana/:year/:pedimento/ALSJDKHF ASD,KFHJA SDFK,ASLDKJFH
|
|
6
|
-
|
|
7
|
-
SUPABASE_URL=http://127.0.0.1:54321
|
|
8
|
-
SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU
|
|
9
|
-
SUPABASE_BUCKET=arela
|
|
10
|
-
|
|
11
|
-
# Arela API Configuration
|
|
12
|
-
ARELA_API_URL=http://localhost:3010
|
|
13
|
-
ARELA_API_TOKEN=f0608f83e5faa4c6be32c19975635c4e9012b31f7249a9f0a9270f54d74ec599
|
|
14
|
-
|
|
15
|
-
# Upload Configuration
|
|
16
|
-
UPLOAD_BASE_PATH=./sample
|
|
17
|
-
UPLOAD_SOURCES=2023|2024
|
|
18
|
-
|
|
19
|
-
# RFC Upload Configuration
|
|
20
|
-
# Pipe-separated list of RFCs to upload files for
|
|
21
|
-
# Example: MMJ0810145N1|ABC1234567XY|DEF9876543ZZ
|
|
22
|
-
UPLOAD_RFCS=AKS151005E46|IMS030409FZ0|RDG1107154L7|SHP031226BV2|CSM9301219B4|LIN960124HT8|LME971009SW4|AKM9707151B6|FEL000822AG2|FDM060802J54|MTM9807279B4|AUM9207011CA|MMJ0810145N1|ACC010328EQ6|PED781129JT6|CAD890407NK7|SME140411IK7|JME1903121C2|EIJ110429NF9|PTJ080414TM6|TME050503BM4
|
|
23
|
-
|
|
24
|
-
# AKS151005E46|IMS030409FZ0|RDG1107154L7|SHP031226BV2|CSM9301219B4|LIN960124HT8|LME971009SW4|AKM9707151B6|FEL000822AG2|PTJ080414TM6|TME050503BM4
|
|
25
|
-
# FDM060802J54|MTM9807279B4|AUM9207011CA|MMJ0810145N1|ACC010328EQ6|PED781129JT6|CAD890407NK7|SME140411IK7|JME1903121C2|EIJ110429NF9
|
|
26
|
-
|
|
27
|
-
# Logging and Verbosity
|
|
28
|
-
VERBOSE_LOGGING=true # Disable verbose path logging for better performance
|
|
29
|
-
BATCH_DELAY=50 # Reduce delay between batches (default: 100ms)
|
|
30
|
-
PROGRESS_UPDATE_INTERVAL=20 # Update progress every 20 items (default: 10)
|
|
31
|
-
|
|
32
|
-
# Log Buffering
|
|
33
|
-
LOG_BUFFER_SIZE=200 # Increase buffer size for fewer I/O ops (default: 100)
|
|
34
|
-
LOG_FLUSH_INTERVAL=3000 # Flush logs every 3 seconds (default: 5000ms)
|
|
35
|
-
|
|
36
|
-
# Example for maximum performance
|
|
37
|
-
# VERBOSE_LOGGING=false BATCH_DELAY=25 LOG_BUFFER_SIZE=500 arela --stats-only /path/to/files
|
package/SUPABASE_UPLOAD_FIX.md
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
# Supabase Upload Issue Fix
|
|
2
|
-
|
|
3
|
-
## Problem Description
|
|
4
|
-
|
|
5
|
-
When running the CLI with `upload --force-supabase`, the logs displayed that files were being uploaded successfully, but no files appeared in the Supabase bucket.
|
|
6
|
-
|
|
7
|
-
## Root Cause
|
|
8
|
-
|
|
9
|
-
The issue was in `/src/commands/UploadCommand.js` in the `#processFile` method. The code was **silently ignoring upload failures** from Supabase:
|
|
10
|
-
|
|
11
|
-
```javascript
|
|
12
|
-
// ❌ BEFORE - Upload result was ignored
|
|
13
|
-
if (uploadService.getServiceName() === 'Arela API') {
|
|
14
|
-
result = await uploadService.upload([fileObject], { ...options, uploadPath });
|
|
15
|
-
} else {
|
|
16
|
-
// Supabase direct upload
|
|
17
|
-
await uploadService.upload([fileObject], { uploadPath });
|
|
18
|
-
// Result ignored! No error checking!
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
logger.info(`SUCCESS: ${path.basename(filePath)} -> ${uploadPath}`);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Even if the Supabase upload failed and returned `{ success: false, error: "..." }`, the code would:
|
|
25
|
-
1. Ignore the error
|
|
26
|
-
2. Log "SUCCESS"
|
|
27
|
-
3. Continue processing
|
|
28
|
-
|
|
29
|
-
This created the illusion that files were being uploaded when they weren't.
|
|
30
|
-
|
|
31
|
-
## Changes Made
|
|
32
|
-
|
|
33
|
-
### 1. Fixed Error Handling in `UploadCommand.js`
|
|
34
|
-
|
|
35
|
-
**File:** `/src/commands/UploadCommand.js`
|
|
36
|
-
|
|
37
|
-
Now properly captures and validates the Supabase upload result:
|
|
38
|
-
|
|
39
|
-
```javascript
|
|
40
|
-
// ✅ AFTER - Upload result is captured and validated
|
|
41
|
-
if (uploadService.getServiceName() === 'Arela API') {
|
|
42
|
-
result = await uploadService.upload([fileObject], { ...options, uploadPath });
|
|
43
|
-
} else {
|
|
44
|
-
// Supabase direct upload
|
|
45
|
-
const uploadResult = await uploadService.upload([fileObject], { uploadPath });
|
|
46
|
-
|
|
47
|
-
// Check if upload was successful
|
|
48
|
-
if (!uploadResult.success) {
|
|
49
|
-
throw new Error(`Supabase upload failed: ${uploadResult.error}`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
result = { successCount: 1 };
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 2. Enhanced Logging in `SupabaseUploadService.js`
|
|
57
|
-
|
|
58
|
-
**File:** `/src/services/upload/SupabaseUploadService.js`
|
|
59
|
-
|
|
60
|
-
Added detailed logging to help diagnose upload issues:
|
|
61
|
-
|
|
62
|
-
#### Connection Initialization
|
|
63
|
-
```javascript
|
|
64
|
-
console.log(`🔌 Connecting to Supabase: ${appConfig.supabase.url}`);
|
|
65
|
-
console.log(`📦 Using bucket: ${this.bucket}`);
|
|
66
|
-
console.log(`🧪 Testing bucket access...`);
|
|
67
|
-
console.log(`✅ Successfully connected to Supabase bucket: ${this.bucket}`);
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
#### Upload Operations
|
|
71
|
-
```javascript
|
|
72
|
-
if (error) {
|
|
73
|
-
console.error(`❌ Supabase upload failed for ${normalizedPath}:`, error.message);
|
|
74
|
-
return { success: false, error: error.message };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
console.log(`✅ Supabase upload successful: ${normalizedPath}`);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
#### Better Error Messages
|
|
81
|
-
```javascript
|
|
82
|
-
if (!appConfig.supabase.url || !appConfig.supabase.key || !this.bucket) {
|
|
83
|
-
const missing = [];
|
|
84
|
-
if (!appConfig.supabase.url) missing.push('SUPABASE_URL');
|
|
85
|
-
if (!appConfig.supabase.key) missing.push('SUPABASE_KEY');
|
|
86
|
-
if (!this.bucket) missing.push('SUPABASE_BUCKET');
|
|
87
|
-
throw new Error(`Missing Supabase configuration: ${missing.join(', ')}`);
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Expected Behavior After Fix
|
|
92
|
-
|
|
93
|
-
### On Successful Upload
|
|
94
|
-
```
|
|
95
|
-
🔌 Connecting to Supabase: https://your-project.supabase.co
|
|
96
|
-
📦 Using bucket: your-bucket-name
|
|
97
|
-
🧪 Testing bucket access...
|
|
98
|
-
✅ Successfully connected to Supabase bucket: your-bucket-name
|
|
99
|
-
✅ Supabase upload successful: 2023/2000601/file.xml
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
### On Failed Upload
|
|
103
|
-
```
|
|
104
|
-
❌ Supabase upload failed for 2023/2000601/file.xml: [error details]
|
|
105
|
-
Error: Supabase upload failed: [error details]
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### On Configuration Error
|
|
109
|
-
```
|
|
110
|
-
Error: Missing Supabase configuration: SUPABASE_URL, SUPABASE_KEY
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
## Common Issues to Check
|
|
114
|
-
|
|
115
|
-
If uploads still fail after this fix, check:
|
|
116
|
-
|
|
117
|
-
1. **Environment Variables**
|
|
118
|
-
```bash
|
|
119
|
-
echo $SUPABASE_URL
|
|
120
|
-
echo $SUPABASE_KEY # Should be anon or service_role key
|
|
121
|
-
echo $SUPABASE_BUCKET
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
2. **Bucket Permissions**
|
|
125
|
-
- Check if the bucket exists in Supabase Storage
|
|
126
|
-
- Verify the API key has write permissions to the bucket
|
|
127
|
-
- Check bucket policies (public vs private)
|
|
128
|
-
|
|
129
|
-
3. **Network/Firewall**
|
|
130
|
-
- Ensure the server can reach Supabase (check firewall rules)
|
|
131
|
-
- Test connection: `curl https://your-project.supabase.co`
|
|
132
|
-
|
|
133
|
-
4. **File Size Limits**
|
|
134
|
-
- Check Supabase storage limits for your plan
|
|
135
|
-
- Verify file sizes are within allowed limits
|
|
136
|
-
|
|
137
|
-
5. **Path Format**
|
|
138
|
-
- Ensure paths don't contain invalid characters
|
|
139
|
-
- Paths are normalized (forward slashes only)
|
|
140
|
-
|
|
141
|
-
## Testing the Fix
|
|
142
|
-
|
|
143
|
-
Run the upload command with verbose logging:
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
arela upload --force-supabase -v
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
You should now see:
|
|
150
|
-
- Clear connection status messages
|
|
151
|
-
- Per-file upload success/failure messages
|
|
152
|
-
- Proper error messages if uploads fail
|
|
153
|
-
- Accurate success/error counts in the summary
|
|
154
|
-
|
|
155
|
-
## Migration Notes
|
|
156
|
-
|
|
157
|
-
No database migrations required. This is a code-only fix that improves error handling and logging.
|