@onlineapps/content-resolver 1.1.3 → 1.1.4
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 +24 -0
- package/package.json +1 -2
- package/src/index.js +104 -0
package/README.md
CHANGED
|
@@ -110,6 +110,30 @@ Create Content Descriptor from raw content. Automatically decides inline vs file
|
|
|
110
110
|
#### `normalizeToDescriptor(value, options): Promise<Object>`
|
|
111
111
|
Normalize any value (string, reference, Buffer) to Content Descriptor.
|
|
112
112
|
|
|
113
|
+
#### `createDescriptorFromFile(tempPath, options): Promise<Object>`
|
|
114
|
+
Create Content Descriptor from a temp file. **Used by ApiMapper for file outputs.**
|
|
115
|
+
|
|
116
|
+
| Option | Type | Default | Description |
|
|
117
|
+
|--------|------|---------|-------------|
|
|
118
|
+
| `filename` | string | basename | Output filename |
|
|
119
|
+
| `content_type` | string | auto-detect | MIME type |
|
|
120
|
+
| `context` | Object | {} | `{ workflow_id, step_id }` |
|
|
121
|
+
| `deleteAfterUpload` | boolean | true | Delete temp file after upload |
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
// Handler returns temp file path
|
|
125
|
+
const handlerOutput = { temp_path: '/tmp/output.pdf', filename: 'report.pdf', content_type: 'application/pdf' };
|
|
126
|
+
|
|
127
|
+
// ApiMapper calls createDescriptorFromFile
|
|
128
|
+
const descriptor = await resolver.createDescriptorFromFile(handlerOutput.temp_path, {
|
|
129
|
+
filename: handlerOutput.filename,
|
|
130
|
+
content_type: handlerOutput.content_type,
|
|
131
|
+
context: { workflow_id: 'wf-123', step_id: 'pdf_gen' },
|
|
132
|
+
deleteAfterUpload: true // Cleanup temp file
|
|
133
|
+
});
|
|
134
|
+
// → Content Descriptor with _descriptor: true, type: 'file', storage_ref, etc.
|
|
135
|
+
```
|
|
136
|
+
|
|
113
137
|
#### `resolveInput(input, fields?): Promise<Object>`
|
|
114
138
|
Resolves all reference fields in input object (legacy method).
|
|
115
139
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/content-resolver",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Automatic conversion between text content and storage references with Content Descriptor pattern",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,4 +22,3 @@
|
|
|
22
22
|
"@onlineapps/conn-base-storage": "^1.0.0"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
|
package/src/index.js
CHANGED
|
@@ -511,6 +511,110 @@ class ContentResolver {
|
|
|
511
511
|
// Fallback
|
|
512
512
|
return await this.createDescriptor(String(value), options);
|
|
513
513
|
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Create Content Descriptor from a temp file path
|
|
517
|
+
* Reads file, uploads to MinIO, returns Descriptor, DELETES temp file
|
|
518
|
+
*
|
|
519
|
+
* @param {string} tempPath - Path to temp file
|
|
520
|
+
* @param {Object} options - Options
|
|
521
|
+
* @param {string} options.filename - Output filename
|
|
522
|
+
* @param {string} options.content_type - MIME type
|
|
523
|
+
* @param {Object} options.context - Workflow context { workflow_id, step_id }
|
|
524
|
+
* @param {boolean} options.deleteAfterUpload - Delete temp file after upload (default: true)
|
|
525
|
+
* @returns {Promise<Object>} Content Descriptor
|
|
526
|
+
*/
|
|
527
|
+
async createDescriptorFromFile(tempPath, options = {}) {
|
|
528
|
+
const fs = require('fs');
|
|
529
|
+
const path = require('path');
|
|
530
|
+
|
|
531
|
+
const {
|
|
532
|
+
filename,
|
|
533
|
+
content_type,
|
|
534
|
+
context = {},
|
|
535
|
+
deleteAfterUpload = true
|
|
536
|
+
} = options;
|
|
537
|
+
|
|
538
|
+
// Validate temp file exists
|
|
539
|
+
if (!fs.existsSync(tempPath)) {
|
|
540
|
+
throw new Error(`[ContentResolver:FAIL] Temp file not found: ${tempPath}`);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Read file into buffer
|
|
544
|
+
const buffer = fs.readFileSync(tempPath);
|
|
545
|
+
const size = buffer.length;
|
|
546
|
+
|
|
547
|
+
// Determine filename and content_type
|
|
548
|
+
const finalFilename = filename || path.basename(tempPath);
|
|
549
|
+
const finalContentType = content_type || getContentType(finalFilename, buffer);
|
|
550
|
+
|
|
551
|
+
// Log start
|
|
552
|
+
const logContext = {
|
|
553
|
+
workflow_id: context.workflow_id || 'standalone',
|
|
554
|
+
step_id: context.step_id || 'content-resolver'
|
|
555
|
+
};
|
|
556
|
+
console.log(`[${logContext.workflow_id}:${logContext.step_id}:ContentResolver:STORE_START] ${JSON.stringify({
|
|
557
|
+
temp_path: tempPath,
|
|
558
|
+
filename: finalFilename,
|
|
559
|
+
content_type: finalContentType,
|
|
560
|
+
size: size
|
|
561
|
+
})}`);
|
|
562
|
+
|
|
563
|
+
try {
|
|
564
|
+
// Upload to MinIO
|
|
565
|
+
const storage = await this.getStorage();
|
|
566
|
+
const workflowId = context.workflow_id || 'standalone';
|
|
567
|
+
const stepId = context.step_id || 'content';
|
|
568
|
+
const pathPrefix = `outputs/${workflowId}/${stepId}`;
|
|
569
|
+
const ext = finalFilename.split('.').pop() || 'bin';
|
|
570
|
+
|
|
571
|
+
const result = await storage.uploadWithFingerprint(
|
|
572
|
+
'workflow',
|
|
573
|
+
buffer,
|
|
574
|
+
pathPrefix,
|
|
575
|
+
ext
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
// Build Descriptor
|
|
579
|
+
const descriptor = {
|
|
580
|
+
_descriptor: true,
|
|
581
|
+
type: 'file',
|
|
582
|
+
storage_ref: `minio://workflow/${result.path}`,
|
|
583
|
+
filename: finalFilename,
|
|
584
|
+
content_type: finalContentType,
|
|
585
|
+
size: size,
|
|
586
|
+
fingerprint: result.fingerprint
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
// Delete temp file if requested
|
|
590
|
+
if (deleteAfterUpload) {
|
|
591
|
+
try {
|
|
592
|
+
fs.unlinkSync(tempPath);
|
|
593
|
+
} catch (unlinkErr) {
|
|
594
|
+
console.warn(`[${logContext.workflow_id}:${logContext.step_id}:ContentResolver:WARN] Failed to delete temp file: ${unlinkErr.message}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// Log success
|
|
599
|
+
console.log(`[${logContext.workflow_id}:${logContext.step_id}:ContentResolver:STORE_SUCCESS] ${JSON.stringify({
|
|
600
|
+
storage_ref: descriptor.storage_ref,
|
|
601
|
+
filename: descriptor.filename,
|
|
602
|
+
size: descriptor.size,
|
|
603
|
+
fingerprint: descriptor.fingerprint.substring(0, 16) + '...'
|
|
604
|
+
})}`);
|
|
605
|
+
|
|
606
|
+
return descriptor;
|
|
607
|
+
|
|
608
|
+
} catch (error) {
|
|
609
|
+
// Log failure
|
|
610
|
+
console.error(`[${logContext.workflow_id}:${logContext.step_id}:ContentResolver:STORE_FAIL] ${JSON.stringify({
|
|
611
|
+
error: error.message,
|
|
612
|
+
temp_path: tempPath,
|
|
613
|
+
filename: finalFilename
|
|
614
|
+
})}`);
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
514
618
|
}
|
|
515
619
|
|
|
516
620
|
// Export class and utilities
|