@onlineapps/conn-base-hub 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.
@@ -0,0 +1,9 @@
1
+ // Separate Jest config for integration tests
2
+ module.exports = {
3
+ testEnvironment: 'node',
4
+ testMatch: ['**/test/integration/**/*.test.js'],
5
+ testTimeout: 30000, // Longer timeout for integration tests
6
+ globalSetup: './test/integration/setup.js',
7
+ coverageDirectory: 'coverage-integration',
8
+ verbose: true
9
+ };
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@onlineapps/conn-base-hub",
3
+ "version": "1.0.0",
4
+ "description": "Central hub for OA Drive connectors - bundles and integrates all essential connector libraries",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "jest",
8
+ "test:unit": "jest --testPathPattern=unit --coverage",
9
+ "test:component": "jest --testPathPattern=component --coverage",
10
+ "test:integration": "jest --config=jest.integration.config.js",
11
+ "test:integration:required": "REQUIRE_SERVICES=true jest --config=jest.integration.config.js",
12
+ "test:watch": "jest --watch",
13
+ "test:coverage": "jest --coverage --coverageReporters=text-lcov html"
14
+ },
15
+ "keywords": [
16
+ "connector",
17
+ "microservice",
18
+ "integration",
19
+ "workflow",
20
+ "mq",
21
+ "registry"
22
+ ],
23
+ "dependencies": {
24
+ "@onlineapps/conn-orch-cookbook": "^2.0.0",
25
+ "@onlineapps/conn-base-logger": "^1.0.0",
26
+ "@onlineapps/conn-infra-mq": "^1.1.0",
27
+ "@onlineapps/conn-orch-registry": "^1.1.4",
28
+ "@onlineapps/conn-base-storage": "^1.0.0",
29
+ "dotenv": "^16.0.3"
30
+ },
31
+ "devDependencies": {
32
+ "jest": "^29.7.0"
33
+ },
34
+ "author": "OA Drive Team",
35
+ "license": "ISC"
36
+ }
package/src/config.js ADDED
File without changes
package/src/index.js ADDED
@@ -0,0 +1,274 @@
1
+ /**
2
+ * @onlineapps/connector-core
3
+ *
4
+ * Core integration library that bundles all essential connectors
5
+ * for OA Drive microservices. Provides a unified interface for:
6
+ * - Message Queue operations
7
+ * - Service Registry registration and discovery
8
+ * - Workflow cookbook processing
9
+ * - Storage operations with MinIO
10
+ * - Centralized logging
11
+ */
12
+
13
+ require('dotenv').config();
14
+
15
+ // Re-export all connectors
16
+ module.exports = {
17
+ // MQ Client for RabbitMQ communication
18
+ MQClient: require('@onlineapps/conn-infra-mq'),
19
+
20
+ // Service Registry client for registration and event consumption
21
+ ...require('@onlineapps/conn-orch-registry'),
22
+
23
+ // Cookbook validation and processing
24
+ ...require('@onlineapps/conn-orch-cookbook'),
25
+
26
+ // Storage connector for MinIO with fingerprinting
27
+ StorageConnector: require('@onlineapps/conn-base-storage'),
28
+
29
+ // Logger (if available)
30
+ createLogger: (() => {
31
+ try {
32
+ return require('@onlineapps/conn-base-logger');
33
+ } catch (e) {
34
+ // Logger not available, return console as fallback
35
+ return function(config) {
36
+ return {
37
+ info: console.log,
38
+ error: console.error,
39
+ warn: console.warn,
40
+ debug: console.debug,
41
+ api: { info: console.log, error: console.error },
42
+ mq: { info: console.log, error: console.error },
43
+ workflow: { info: console.log, error: console.error },
44
+ registry: { info: console.log, error: console.error },
45
+ close: async () => {}
46
+ };
47
+ };
48
+ }
49
+ })(),
50
+
51
+ // Convenience factory for creating a fully configured microservice
52
+ createMicroservice: function(config) {
53
+ const { ServiceRegistryClient, MQClient, StorageConnector, createLogger } = module.exports;
54
+
55
+ // Create logger instance
56
+ const logger = createLogger({
57
+ serviceName: config.serviceName,
58
+ version: config.version,
59
+ ...config.logger
60
+ });
61
+
62
+ return {
63
+ logger,
64
+ // Initialize Registry Client
65
+ registry: config.registry ? new ServiceRegistryClient({
66
+ amqpUrl: config.amqpUrl || process.env.RABBITMQ_URL,
67
+ serviceName: config.serviceName,
68
+ version: config.version || '1.0.0',
69
+ ...config.registry
70
+ }) : null,
71
+
72
+ // Initialize MQ Client
73
+ mq: config.mq ? new MQClient({
74
+ type: 'rabbitmq',
75
+ host: config.amqpUrl || process.env.RABBITMQ_URL,
76
+ queue: `${config.serviceName}_queue`,
77
+ ...config.mq
78
+ }) : null,
79
+
80
+ // Initialize Storage
81
+ storage: config.storage ? new StorageConnector({
82
+ endPoint: process.env.MINIO_ENDPOINT || 'localhost',
83
+ port: parseInt(process.env.MINIO_PORT || 9000),
84
+ accessKey: process.env.MINIO_ACCESS_KEY || 'minioadmin',
85
+ secretKey: process.env.MINIO_SECRET_KEY || 'minioadmin',
86
+ ...config.storage
87
+ }) : null,
88
+
89
+ // Initialize all components
90
+ async init() {
91
+ const results = {};
92
+
93
+ // Initialize Registry
94
+ if (this.registry) {
95
+ await this.registry.initialize();
96
+
97
+ // Optionally subscribe to changes
98
+ if (config.subscribeToRegistry) {
99
+ await this.registry.subscribeToChanges();
100
+ }
101
+
102
+ // Start heartbeat
103
+ this.registry.startHeartbeat();
104
+ results.registry = true;
105
+ }
106
+
107
+ // Initialize MQ
108
+ if (this.mq) {
109
+ await this.mq.connect();
110
+ results.mq = true;
111
+ }
112
+
113
+ // Initialize Storage
114
+ if (this.storage) {
115
+ await this.storage.initialize();
116
+ results.storage = true;
117
+ }
118
+
119
+ return results;
120
+ },
121
+
122
+ // Graceful shutdown
123
+ async shutdown() {
124
+ const promises = [];
125
+
126
+ if (this.registry) {
127
+ promises.push(this.registry.dispose());
128
+ }
129
+
130
+ if (this.mq) {
131
+ promises.push(this.mq.disconnect());
132
+ }
133
+
134
+ if (this.logger && this.logger.close) {
135
+ promises.push(this.logger.close());
136
+ }
137
+
138
+ await Promise.all(promises);
139
+ }
140
+ };
141
+ },
142
+
143
+ // Helper for workflow processing
144
+ WorkflowHelper: {
145
+ /**
146
+ * Create a workflow message
147
+ */
148
+ createMessage(opts) {
149
+ return {
150
+ workflow_id: opts.workflowId,
151
+ cookbook_name: opts.cookbookName,
152
+ step_index: opts.step || 0,
153
+ data: opts.data || {},
154
+ results: [],
155
+ timestamp: new Date().toISOString()
156
+ };
157
+ },
158
+
159
+ /**
160
+ * Parse a workflow message
161
+ */
162
+ parseMessage(message) {
163
+ return {
164
+ workflowId: message.workflow_id,
165
+ cookbookName: message.cookbook_name,
166
+ step: message.step_index,
167
+ data: message.data,
168
+ results: message.results
169
+ };
170
+ },
171
+
172
+ /**
173
+ * Get next queue from cookbook step
174
+ */
175
+ getNextQueue(step) {
176
+ if (step.queue) {
177
+ return step.queue;
178
+ }
179
+ return `${step.service}.queue`;
180
+ },
181
+
182
+ /**
183
+ * Validate workflow message
184
+ */
185
+ isValidMessage(message) {
186
+ return !!(message.workflow_id && message.cookbook_name &&
187
+ typeof message.step_index === 'number' && message.data);
188
+ },
189
+
190
+ /**
191
+ * Add result to workflow message
192
+ */
193
+ addResult(message, result) {
194
+ return {
195
+ ...message,
196
+ results: [...(message.results || []), result],
197
+ last_result: result
198
+ };
199
+ },
200
+
201
+ /**
202
+ * Create error message
203
+ */
204
+ createErrorMessage(message, error, serviceName) {
205
+ return {
206
+ ...message,
207
+ status: 'error',
208
+ error: {
209
+ message: error.message,
210
+ stack: error.stack,
211
+ service: serviceName,
212
+ step: message.step_index
213
+ }
214
+ };
215
+ },
216
+
217
+ /**
218
+ * Process a workflow step
219
+ * @param {Object} message - Workflow message
220
+ * @param {Function} handler - Step handler function
221
+ * @returns {Object} - Updated workflow message
222
+ */
223
+ async processStep(message, handler) {
224
+ const { workflow_id, current_step, cookbook, context = {} } = message;
225
+
226
+ // Get current step from cookbook
227
+ const step = cookbook?.steps?.[current_step];
228
+ if (!step) {
229
+ throw new Error(`Step ${current_step} not found in cookbook`);
230
+ }
231
+
232
+ // Execute handler
233
+ const result = await handler(step, context);
234
+
235
+ // Build response message
236
+ return {
237
+ ...message,
238
+ current_step: current_step + 1,
239
+ context: {
240
+ ...context,
241
+ [`step_${current_step}_result`]: result
242
+ },
243
+ trace: [
244
+ ...(message.trace || []),
245
+ {
246
+ step: current_step,
247
+ service: step.service,
248
+ timestamp: new Date().toISOString(),
249
+ result: result
250
+ }
251
+ ]
252
+ };
253
+ },
254
+
255
+ /**
256
+ * Determine next queue based on workflow state
257
+ * @param {Object} message - Workflow message
258
+ * @returns {string} - Next queue name
259
+ */
260
+ getNextQueueFromMessage(message) {
261
+ const { current_step, cookbook } = message;
262
+
263
+ if (cookbook && current_step < cookbook.steps.length) {
264
+ const nextStep = cookbook.steps[current_step];
265
+ return `${nextStep.service}.queue`;
266
+ }
267
+
268
+ return 'workflow.completed';
269
+ }
270
+ }
271
+ };
272
+
273
+ // For backward compatibility
274
+ module.exports.ConnectorCore = module.exports;