@onlineapps/conn-base-storage 1.0.2 → 1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlineapps/conn-base-storage",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "MinIO storage connector with fingerprinting for immutable content storage",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -20,6 +20,8 @@
20
20
  "connector"
21
21
  ],
22
22
  "dependencies": {
23
+ "@onlineapps/runtime-config": "1.0.2",
24
+ "@onlineapps/storage-core": "1.0.8",
23
25
  "minio": "^7.1.3",
24
26
  "crypto": "^1.0.1",
25
27
  "winston": "^3.8.2"
package/src/config.js ADDED
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Runtime configuration schema for @onlineapps/conn-base-storage.
5
+ *
6
+ * Uses @onlineapps/runtime-config for unified priority:
7
+ * 1. Explicit config (passed to constructor)
8
+ * 2. Environment variable
9
+ * 3. Owner defaults (from ./defaults.js)
10
+ *
11
+ * NOTE:
12
+ * This module resolves MinIO runtime configuration via @onlineapps/runtime-config
13
+ * to avoid inline process.env access in implementation code.
14
+ *
15
+ * @module @onlineapps/conn-base-storage/config
16
+ */
17
+
18
+ const { createRuntimeConfig } = require('@onlineapps/runtime-config');
19
+ const DEFAULTS = require('./defaults');
20
+
21
+ /**
22
+ * Runtime config schema for StorageConnector
23
+ */
24
+ const runtimeCfg = createRuntimeConfig({
25
+ defaults: DEFAULTS,
26
+ schema: {
27
+ // MinIO topology (FAIL-FAST)
28
+ // Keep key names aligned with constructor config for predictability.
29
+ endPoint: { env: 'MINIO_ENDPOINT', required: true },
30
+ port: { env: 'MINIO_PORT', required: true, type: 'number' },
31
+ useSSL: { env: 'MINIO_USE_SSL', default: false, type: 'boolean' },
32
+ accessKey: { env: 'MINIO_ACCESS_KEY', required: true },
33
+ secretKey: { env: 'MINIO_SECRET_KEY', required: true },
34
+
35
+ // Wrapper behavior (module-owned defaults)
36
+ logLevel: { env: 'STORAGE_LOG_LEVEL', defaultKey: 'logLevel' },
37
+ defaultBucket: { env: 'MINIO_DEFAULT_BUCKET', defaultKey: 'defaultBucket' },
38
+ bucketName: { defaultKey: 'bucketName' },
39
+ cacheMaxSize: { defaultKey: 'cacheMaxSize', type: 'number' },
40
+ maxCacheSize: { defaultKey: 'maxCacheSize', type: 'number' },
41
+
42
+ // InternalUrlAdapter behavior (module-owned defaults + env hints)
43
+ nodeEnv: { env: 'NODE_ENV', default: 'development' },
44
+ dockerNetwork: { env: 'DOCKER_NETWORK', default: false, type: 'boolean' },
45
+ dockerEnv: { env: 'DOCKER_ENV' },
46
+ dockerContainer: { env: 'DOCKER_CONTAINER' },
47
+ hostname: { env: 'HOSTNAME' },
48
+ internalUrlServiceMap: { defaultKey: 'internalUrlServiceMap' },
49
+ }
50
+ });
51
+
52
+ module.exports = runtimeCfg;
53
+
@@ -0,0 +1,43 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module-owned defaults for @onlineapps/conn-base-storage.
5
+ *
6
+ * Ownership rule:
7
+ * - Defaults for the StorageConnector wrapper live here (bucket naming, cache sizing, log level).
8
+ * - MinIO connection defaults belong to @onlineapps/storage-core.
9
+ */
10
+
11
+ module.exports = {
12
+ logLevel: 'info',
13
+ defaultBucket: 'api-storage',
14
+ bucketName: 'oa-drive-storage',
15
+ cacheMaxSize: 100,
16
+ maxCacheSize: 100,
17
+
18
+ // InternalUrlAdapter defaults (module-owned)
19
+ internalUrlServiceMap: {
20
+ storage: {
21
+ docker: 'api_services_storage:9000',
22
+ local: 'localhost:9000'
23
+ },
24
+ registry: {
25
+ docker: 'api_registry:8080',
26
+ local: 'localhost:8080'
27
+ },
28
+ monitoring: {
29
+ docker: 'api_monitoring:3000',
30
+ local: 'localhost:3000'
31
+ },
32
+ mq: {
33
+ docker: 'api_services_rabbit:5672',
34
+ local: 'localhost:5672'
35
+ },
36
+ cache: {
37
+ docker: 'api_node_cache:6379',
38
+ local: 'localhost:6379'
39
+ }
40
+ },
41
+ };
42
+
43
+
package/src/index.js CHANGED
@@ -9,80 +9,10 @@
9
9
  * @since 1.0.0
10
10
  */
11
11
 
12
- const Minio = require('minio');
13
- const crypto = require('crypto');
12
+ const { StorageCore } = require('@onlineapps/storage-core');
14
13
  const winston = require('winston');
15
- const dns = require('dns').promises;
16
14
  const SharedUrlAdapter = require('./sharedUrlAdapter');
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
- }
15
+ const runtimeCfg = require('./config');
86
16
 
87
17
  /**
88
18
  * Storage connector for MinIO with automatic fingerprinting
@@ -139,9 +69,12 @@ class StorageConnector {
139
69
  * });
140
70
  */
141
71
  constructor(config = {}) {
72
+ // Resolve runtime configuration for wrapper behavior
73
+ const resolved = runtimeCfg.resolve(config);
74
+
142
75
  // Logger setup
143
76
  this.logger = winston.createLogger({
144
- level: config.logLevel || 'info',
77
+ level: resolved.logLevel,
145
78
  format: winston.format.combine(
146
79
  winston.format.timestamp(),
147
80
  winston.format.json()
@@ -151,33 +84,37 @@ class StorageConnector {
151
84
  ]
152
85
  });
153
86
 
154
- // MinIO client configuration
155
- const minioConfig = {
156
- endPoint: config.endPoint || process.env.MINIO_ENDPOINT || 'localhost',
157
- port: parseInt(config.port || process.env.MINIO_PORT || 9000),
158
- useSSL: config.useSSL || process.env.MINIO_USE_SSL === 'true',
159
- accessKey: config.accessKey || process.env.MINIO_ACCESS_KEY || 'minioadmin',
160
- secretKey: config.secretKey || process.env.MINIO_SECRET_KEY || 'minioadmin'
161
- };
87
+ // Create StorageCore instance (handles MinIO client internally)
88
+ this.core = new StorageCore({
89
+ endPoint: resolved.endPoint,
90
+ port: resolved.port,
91
+ useSSL: resolved.useSSL,
92
+ accessKey: resolved.accessKey,
93
+ secretKey: resolved.secretKey
94
+ });
95
+
96
+ // Expose MinIO client for backward compatibility
97
+ this.client = this.core.client;
98
+ this.minioClient = this.core.client;
162
99
 
163
- this.client = new Minio.Client(minioConfig);
164
- this.defaultBucket = config.defaultBucket || process.env.MINIO_DEFAULT_BUCKET || 'api-storage';
100
+ this.defaultBucket = resolved.defaultBucket;
165
101
 
166
102
  // Store config for access in tests
167
103
  this.config = {
168
- ...minioConfig,
169
- bucketName: this.validateBucketName(config.bucketName || 'oa-drive-storage'),
170
- cacheMaxSize: config.cacheMaxSize || 100
104
+ endPoint: this.core.config.endPoint,
105
+ port: this.core.config.port,
106
+ useSSL: this.core.config.useSSL,
107
+ accessKey: this.core.config.accessKey,
108
+ secretKey: this.core.config.secretKey,
109
+ bucketName: this.validateBucketName(config.bucketName || resolved.bucketName),
110
+ cacheMaxSize: resolved.cacheMaxSize
171
111
  };
172
112
 
173
- // MinIO client
174
- this.minioClient = this.client;
175
-
176
113
  // Cache configuration
177
114
  this.cacheEnabled = config.cacheEnabled !== false;
178
115
  this.cache = new Map();
179
116
  this.contentCache = new Map();
180
- this.maxCacheSize = config.maxCacheSize || 100; // Max items in cache
117
+ this.maxCacheSize = resolved.maxCacheSize;
181
118
 
182
119
  // Track initialization
183
120
  this.initialized = false;
@@ -186,8 +123,8 @@ class StorageConnector {
186
123
  this.sharedUrl = new SharedUrlAdapter(this);
187
124
 
188
125
  this.logger.info('StorageConnector initialized', {
189
- endpoint: minioConfig.endPoint,
190
- port: minioConfig.port,
126
+ endpoint: this.core.config.endPoint,
127
+ port: this.core.config.port,
191
128
  defaultBucket: this.defaultBucket
192
129
  });
193
130
  }
@@ -211,39 +148,16 @@ class StorageConnector {
211
148
  */
212
149
  async initialize() {
213
150
  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
-
238
- // Check if default bucket exists
239
- const bucketExists = await this.client.bucketExists(this.defaultBucket);
151
+ // Initialize StorageCore
152
+ await this.core.initialize();
153
+
154
+ // Ensure default bucket exists (using StorageCore)
155
+ const created = await this.core.ensureBucket(this.defaultBucket);
240
156
 
241
- if (!bucketExists) {
242
- // Create bucket with versioning
243
- await this.client.makeBucket(this.defaultBucket, 'us-east-1');
157
+ if (created) {
244
158
  this.logger.info(`Bucket ${this.defaultBucket} created`);
245
159
 
246
- // Set bucket policy for read access
160
+ // Set bucket policy for read access (business-specific feature)
247
161
  const policy = {
248
162
  Version: '2012-10-17',
249
163
  Statement: [
@@ -287,25 +201,8 @@ class StorageConnector {
287
201
  * // Returns consistent hash for the object
288
202
  */
289
203
  generateFingerprint(content) {
290
- // Handle undefined and null
291
- if (content === undefined || content === null) {
292
- content = String(content);
293
- } else if (typeof content === 'symbol') {
294
- content = content.toString();
295
- } else if (typeof content !== 'string' && !Buffer.isBuffer(content)) {
296
- // Handle circular references
297
- try {
298
- content = JSON.stringify(content);
299
- } catch (err) {
300
- // If circular reference, use a deterministic string representation
301
- content = '[Circular Reference]';
302
- }
303
- }
304
-
305
- return crypto
306
- .createHash('sha256')
307
- .update(content)
308
- .digest('hex');
204
+ // Delegate to StorageCore
205
+ return this.core.calculateFingerprint(content);
309
206
  }
310
207
 
311
208
  /**
@@ -371,9 +268,9 @@ class StorageConnector {
371
268
  ? `${pathPrefix}/${fingerprint}.json`
372
269
  : `${fingerprint}.json`;
373
270
 
374
- // Check if object already exists (immutable)
375
- try {
376
- await this.client.statObject(bucket, path);
271
+ // Check if object already exists (immutable) - using StorageCore
272
+ const exists = await this.core.objectExists(bucket, path);
273
+ if (exists) {
377
274
  this.logger.debug(`Object already exists: ${bucket}/${path}`);
378
275
 
379
276
  return {
@@ -383,16 +280,13 @@ class StorageConnector {
383
280
  url: this.getPublicUrl(bucket, path),
384
281
  existed: true
385
282
  };
386
- } catch (err) {
387
- // Object doesn't exist, proceed with upload
388
283
  }
389
284
 
390
- // Upload to MinIO
391
- await this.client.putObject(
285
+ // Upload to MinIO - using StorageCore
286
+ await this.core.putObject(
392
287
  bucket,
393
288
  path,
394
289
  buffer,
395
- buffer.length,
396
290
  {
397
291
  'Content-Type': 'application/json',
398
292
  'x-amz-meta-fingerprint': fingerprint,
@@ -460,8 +354,8 @@ class StorageConnector {
460
354
  return this.contentCache.get(cacheKey);
461
355
  }
462
356
 
463
- // Download from MinIO
464
- const stream = await this.client.getObject(bucket, path);
357
+ // Download from MinIO - using StorageCore
358
+ const stream = await this.core.getObject(bucket, path);
465
359
 
466
360
  // Collect stream data
467
361
  const chunks = [];
@@ -470,16 +364,14 @@ class StorageConnector {
470
364
  }
471
365
  const buffer = Buffer.concat(chunks);
472
366
 
473
- // Verify fingerprint if provided
367
+ // Verify fingerprint if provided - using StorageCore
474
368
  if (expectedFingerprint) {
475
- const actualFingerprint = this.generateFingerprint(buffer);
476
-
369
+ const actualFingerprint = this.core.calculateFingerprint(buffer);
477
370
  if (actualFingerprint !== expectedFingerprint) {
478
371
  throw new Error(
479
372
  `Fingerprint mismatch! Expected: ${expectedFingerprint}, Got: ${actualFingerprint}`
480
373
  );
481
374
  }
482
-
483
375
  this.logger.debug(`Fingerprint verified for ${bucket}/${path}`);
484
376
  }
485
377
 
@@ -530,11 +422,8 @@ class StorageConnector {
530
422
  try {
531
423
  bucket = bucket || this.defaultBucket;
532
424
 
533
- const url = await this.client.presignedGetObject(
534
- bucket,
535
- path,
536
- expiry
537
- );
425
+ // Use StorageCore
426
+ const url = await this.core.getPresignedUrl(bucket, path, expiry);
538
427
 
539
428
  this.logger.debug(`Generated presigned URL for ${bucket}/${path}`);
540
429
  return url;
@@ -570,20 +459,25 @@ class StorageConnector {
570
459
  try {
571
460
  bucket = bucket || this.defaultBucket;
572
461
 
462
+ // Use StorageCore to list objects
463
+ const objectNames = await this.core.listByPrefix(bucket, prefix, true);
464
+
465
+ // Get metadata for each object
573
466
  const objects = [];
574
- const stream = this.client.listObjectsV2(bucket, prefix, true);
575
-
576
- for await (const obj of stream) {
577
- // Get metadata for each object
578
- const stat = await this.client.statObject(bucket, obj.name);
579
-
580
- objects.push({
581
- name: obj.name,
582
- size: obj.size,
583
- lastModified: obj.lastModified,
584
- fingerprint: stat.metaData['x-amz-meta-fingerprint'],
585
- uploadedAt: stat.metaData['x-amz-meta-uploaded-at']
586
- });
467
+ for (const name of objectNames) {
468
+ try {
469
+ const stat = await this.core.statObject(bucket, name);
470
+ objects.push({
471
+ name,
472
+ size: stat.size,
473
+ lastModified: stat.lastModified,
474
+ fingerprint: stat.metaData?.['x-amz-meta-fingerprint'],
475
+ uploadedAt: stat.metaData?.['x-amz-meta-uploaded-at']
476
+ });
477
+ } catch (err) {
478
+ // Skip objects that can't be stat'd
479
+ this.logger.warn(`Failed to stat object ${name}`, err);
480
+ }
587
481
  }
588
482
 
589
483
  return objects;
@@ -614,7 +508,8 @@ class StorageConnector {
614
508
  try {
615
509
  bucket = bucket || this.defaultBucket;
616
510
 
617
- await this.client.removeObject(bucket, path);
511
+ // Use StorageCore
512
+ await this.core.deleteObject(bucket, path);
618
513
  this.logger.warn(`Deleted object: ${bucket}/${path}`);
619
514
 
620
515
  // Clear from cache
@@ -688,10 +583,10 @@ class StorageConnector {
688
583
  */
689
584
  async ensureBucket(bucketName) {
690
585
  try {
691
- const exists = await this.client.bucketExists(bucketName);
586
+ // Use StorageCore
587
+ const created = await this.core.ensureBucket(bucketName);
692
588
 
693
- if (!exists) {
694
- await this.client.makeBucket(bucketName, 'us-east-1');
589
+ if (created) {
695
590
  this.logger.info(`Bucket ${bucketName} created`);
696
591
  }
697
592
 
@@ -921,49 +816,6 @@ class StorageConnector {
921
816
  * @property {string} [uploadedAt] - Upload timestamp
922
817
  */
923
818
 
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
-
967
819
  // Export main class
968
820
  module.exports = StorageConnector;
969
821
 
@@ -4,34 +4,16 @@
4
4
  * Skrývá implementační detaily před službami
5
5
  */
6
6
 
7
+ const fs = require('fs');
8
+ const runtimeCfg = require('./config');
9
+
7
10
  class InternalUrlAdapter {
8
11
  constructor(config = {}) {
9
- this.environment = config.environment || process.env.NODE_ENV || 'development';
10
- this.dockerNetwork = config.dockerNetwork || process.env.DOCKER_NETWORK || false;
12
+ this.environment = runtimeCfg.get('nodeEnv', config.environment);
13
+ this.dockerNetwork = runtimeCfg.get('dockerNetwork', config.dockerNetwork);
11
14
 
12
15
  // Mapování služeb na jejich interní adresy
13
- this.serviceMap = {
14
- storage: {
15
- docker: 'api_services_storage:9000',
16
- local: 'localhost:9000'
17
- },
18
- registry: {
19
- docker: 'api_registry:8080',
20
- local: 'localhost:8080'
21
- },
22
- monitoring: {
23
- docker: 'api_monitoring:3000',
24
- local: 'localhost:3000'
25
- },
26
- mq: {
27
- docker: 'api_services_rabbit:5672',
28
- local: 'localhost:5672'
29
- },
30
- cache: {
31
- docker: 'api_node_cache:6379',
32
- local: 'localhost:6379'
33
- }
34
- };
16
+ this.serviceMap = { ...runtimeCfg.get('internalUrlServiceMap') };
35
17
 
36
18
  // Rozšiřitelné přes config
37
19
  if (config.services) {
@@ -91,11 +73,14 @@ class InternalUrlAdapter {
91
73
  */
92
74
  isRunningInDocker() {
93
75
  // Několik způsobů detekce Docker kontejneru
76
+ const dockerEnv = runtimeCfg.get('dockerEnv');
77
+ const dockerContainer = runtimeCfg.get('dockerContainer');
78
+ const hostname = runtimeCfg.get('hostname');
94
79
  return !!(
95
- process.env.DOCKER_ENV ||
96
- process.env.DOCKER_CONTAINER ||
97
- (require('fs').existsSync('/.dockerenv')) ||
98
- (process.env.HOSTNAME && process.env.HOSTNAME.length === 12) // Docker container ID
80
+ dockerEnv ||
81
+ dockerContainer ||
82
+ (fs.existsSync('/.dockerenv')) ||
83
+ (hostname && hostname.length === 12) // Docker container ID
99
84
  );
100
85
  }
101
86
 
@@ -9,6 +9,8 @@ describe('InternalUrlAdapter @unit', () => {
9
9
 
10
10
  beforeEach(() => {
11
11
  adapter = new InternalUrlAdapter();
12
+ // Tests run inside a Docker container; force local-mode behavior unless explicitly enabled.
13
+ adapter.isRunningInDocker = jest.fn(() => false);
12
14
  });
13
15
 
14
16
  describe('URL Resolution', () => {
@@ -202,6 +204,8 @@ describe('InternalUrlAdapter @unit', () => {
202
204
  }
203
205
  });
204
206
 
207
+ // Tests run inside Docker; force local-mode behavior for this adapter instance.
208
+ customAdapter.isRunningInDocker = jest.fn(() => false);
205
209
  customAdapter.dockerNetwork = false;
206
210
  const resolved = customAdapter.resolve('internal://my-service/api');
207
211
 
@@ -6,6 +6,14 @@
6
6
  const StorageConnector = require('../../src/index');
7
7
  const Minio = require('minio');
8
8
 
9
+ // Minimal required MinIO config for tests (all external I/O is mocked)
10
+ const MINIO_CONFIG = {
11
+ endPoint: 'localhost',
12
+ port: 9000,
13
+ accessKey: 'test',
14
+ secretKey: 'test',
15
+ };
16
+
9
17
  // Mock MinIO client
10
18
  jest.mock('minio');
11
19
 
@@ -321,15 +329,15 @@ describe('StorageConnector Extended Unit Tests @unit', () => {
321
329
 
322
330
  describe('Internal URL Generation', () => {
323
331
  test('should generate abstract internal URL', () => {
324
- storage = new StorageConnector();
332
+ storage = new StorageConnector(MINIO_CONFIG);
325
333
 
326
334
  const url = storage.getInternalUrl('bucket', 'path/to/object');
327
335
  expect(url).toBe('internal://storage/bucket/path/to/object');
328
336
  });
329
337
 
330
338
  test('should generate consistent internal URLs', () => {
331
- const storage1 = new StorageConnector();
332
- const storage2 = new StorageConnector();
339
+ const storage1 = new StorageConnector(MINIO_CONFIG);
340
+ const storage2 = new StorageConnector(MINIO_CONFIG);
333
341
 
334
342
  const url1 = storage1.getInternalUrl('bucket', 'object');
335
343
  const url2 = storage2.getInternalUrl('bucket', 'object');
@@ -341,7 +349,7 @@ describe('StorageConnector Extended Unit Tests @unit', () => {
341
349
 
342
350
  describe('Bucket Operations', () => {
343
351
  beforeEach(() => {
344
- storage = new StorageConnector();
352
+ storage = new StorageConnector(MINIO_CONFIG);
345
353
  });
346
354
 
347
355
  test('should ensure bucket exists', async () => {
@@ -373,7 +381,7 @@ describe('StorageConnector Extended Unit Tests @unit', () => {
373
381
 
374
382
  describe('Cache Operations', () => {
375
383
  test('should clear all caches', () => {
376
- storage = new StorageConnector();
384
+ storage = new StorageConnector(MINIO_CONFIG);
377
385
 
378
386
  // Add items to caches
379
387
  storage.cache.set('key1', 'value1');
@@ -389,7 +397,7 @@ describe('StorageConnector Extended Unit Tests @unit', () => {
389
397
  });
390
398
 
391
399
  test('should handle cache size limits', () => {
392
- storage = new StorageConnector({ cacheMaxSize: 2 });
400
+ storage = new StorageConnector({ ...MINIO_CONFIG, cacheMaxSize: 2 });
393
401
 
394
402
  storage.addToCache('key1', 'value1');
395
403
  storage.addToCache('key2', 'value2');