@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.
Files changed (3) hide show
  1. package/README.md +24 -0
  2. package/package.json +1 -2
  3. 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",
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