@onlineapps/conn-base-storage 1.0.1 → 1.0.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +137 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/conn-base-storage",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "MinIO storage connector with fingerprinting for immutable content storage",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -12,8 +12,78 @@
12
12
  const Minio = require('minio');
13
13
  const crypto = require('crypto');
14
14
  const winston = require('winston');
15
+ const dns = require('dns').promises;
15
16
  const SharedUrlAdapter = require('./sharedUrlAdapter');
16
17
 
18
+ /**
19
+ * Check if string is already an IP address
20
+ * @param {string} str - String to check
21
+ * @returns {boolean} True if string is an IP address
22
+ */
23
+ function isIP(str) {
24
+ // IPv4 pattern
25
+ const ipv4 = /^(\d{1,3}\.){3}\d{1,3}$/;
26
+ // IPv6 pattern (simplified)
27
+ const ipv6 = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
28
+ return ipv4.test(str) || ipv6.test(str);
29
+ }
30
+
31
+ /**
32
+ * Resolve hostname to IP address
33
+ * MinIO client sometimes has issues with hostnames, this ensures we use IP
34
+ * @param {string} host - Hostname or IP
35
+ * @returns {Promise<string>} Resolved IP address
36
+ */
37
+ async function resolveHostToIP(host) {
38
+ // If already IP, return as-is
39
+ if (isIP(host)) {
40
+ return host;
41
+ }
42
+
43
+ // If localhost, return as-is
44
+ if (host === 'localhost' || host === '127.0.0.1') {
45
+ return host;
46
+ }
47
+
48
+ try {
49
+ const { address } = await dns.lookup(host);
50
+ return address;
51
+ } catch (err) {
52
+ // If DNS lookup fails, return original hostname
53
+ console.warn(`[StorageConnector] DNS lookup failed for ${host}, using original: ${err.message}`);
54
+ return host;
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Parse storage reference to bucket and path
60
+ * Supports formats:
61
+ * - minio://bucket/path
62
+ * - internal://storage/bucket/path
63
+ *
64
+ * @param {string} ref - Storage reference
65
+ * @returns {{ bucket: string, path: string, fingerprint?: string }}
66
+ */
67
+ function parseStorageRef(ref) {
68
+ if (!ref || typeof ref !== 'string') {
69
+ throw new Error('Invalid storage reference: must be a string');
70
+ }
71
+
72
+ // minio://bucket/path
73
+ let match = ref.match(/^minio:\/\/([^/]+)\/(.+)$/);
74
+ if (match) {
75
+ return { bucket: match[1], path: match[2] };
76
+ }
77
+
78
+ // internal://storage/bucket/path
79
+ match = ref.match(/^internal:\/\/storage\/([^/]+)\/(.+)$/);
80
+ if (match) {
81
+ return { bucket: match[1], path: match[2] };
82
+ }
83
+
84
+ throw new Error(`Invalid storage reference format: ${ref}`);
85
+ }
86
+
17
87
  /**
18
88
  * Storage connector for MinIO with automatic fingerprinting
19
89
  *
@@ -141,6 +211,30 @@ class StorageConnector {
141
211
  */
142
212
  async initialize() {
143
213
  try {
214
+ // Resolve hostname to IP (MinIO client can have issues with Docker hostnames)
215
+ const originalEndpoint = this.config.endPoint;
216
+ const resolvedEndpoint = await resolveHostToIP(originalEndpoint);
217
+
218
+ if (resolvedEndpoint !== originalEndpoint) {
219
+ this.logger.info('StorageConnector: Resolved hostname to IP', {
220
+ original: originalEndpoint,
221
+ resolved: resolvedEndpoint
222
+ });
223
+
224
+ // Recreate MinIO client with resolved IP
225
+ const minioConfig = {
226
+ endPoint: resolvedEndpoint,
227
+ port: this.config.port,
228
+ useSSL: this.config.useSSL || false,
229
+ accessKey: this.config.accessKey,
230
+ secretKey: this.config.secretKey
231
+ };
232
+
233
+ this.client = new Minio.Client(minioConfig);
234
+ this.minioClient = this.client;
235
+ this.config.endPoint = resolvedEndpoint;
236
+ }
237
+
144
238
  // Check if default bucket exists
145
239
  const bucketExists = await this.client.bucketExists(this.defaultBucket);
146
240
 
@@ -827,6 +921,49 @@ class StorageConnector {
827
921
  * @property {string} [uploadedAt] - Upload timestamp
828
922
  */
829
923
 
924
+ /**
925
+ * Download file from storage reference
926
+ *
927
+ * @param {string} ref - Storage reference (minio://bucket/path)
928
+ * @returns {Promise<Buffer>} File content
929
+ *
930
+ * @example
931
+ * const buffer = await storage.downloadFromRef('minio://workflow/inputs/wf-123/doc.pdf');
932
+ */
933
+ StorageConnector.prototype.downloadFromRef = async function(ref) {
934
+ const { bucket, path } = parseStorageRef(ref);
935
+
936
+ // Download from MinIO
937
+ const stream = await this.client.getObject(bucket, path);
938
+
939
+ // Collect stream data
940
+ const chunks = [];
941
+ for await (const chunk of stream) {
942
+ chunks.push(chunk);
943
+ }
944
+
945
+ return Buffer.concat(chunks);
946
+ };
947
+
948
+ /**
949
+ * Check if storage reference is valid format
950
+ * @param {string} ref - Reference to check
951
+ * @returns {boolean}
952
+ */
953
+ StorageConnector.isValidRef = function(ref) {
954
+ try {
955
+ parseStorageRef(ref);
956
+ return true;
957
+ } catch {
958
+ return false;
959
+ }
960
+ };
961
+
962
+ /**
963
+ * Parse storage reference (static helper)
964
+ */
965
+ StorageConnector.parseRef = parseStorageRef;
966
+
830
967
  // Export main class
831
968
  module.exports = StorageConnector;
832
969