@onlineapps/service-wrapper 2.0.17 → 2.0.19

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 CHANGED
@@ -239,7 +239,7 @@ describe('My Service', () => {
239
239
  If your service currently has workflow code:
240
240
 
241
241
  1. Install service-wrapper: `npm install @onlineapps/service-wrapper`
242
- 2. Remove all `@onlineapps/connector-*` from service code
242
+ 2. Remove all direct connector imports from service code (use wrapper instead)
243
243
  3. Delete workflow processing files
244
244
  4. Wrap your Express app with ServiceWrapper
245
245
  5. Test that everything still works
@@ -110,7 +110,7 @@ Transform your OpenAPI spec into Operations format:
110
110
  ```bash
111
111
  # Old structure
112
112
  services/my-service/
113
- ├── connector-config/
113
+ ├── conn-config/
114
114
  │ ├── manifest.json
115
115
  │ └── openapi.json
116
116
 
@@ -121,17 +121,14 @@ services/my-service/
121
121
  │ └── operations.json
122
122
  ```
123
123
 
124
- Move configuration:
124
+ Convert configuration:
125
125
  ```bash
126
126
  cd services/my-service
127
- mkdir -p conn-config
128
127
 
129
- # If you have existing config, merge it
130
- mv connector-config/manifest.json conn-config/config.json
128
+ # If you have existing manifest.json, merge it into config.json
129
+ # Move from manifest.json to config.json structure
131
130
 
132
131
  # Create operations.json (see conversion below)
133
- # Delete old directory
134
- rm -rf connector-config/
135
132
  ```
136
133
 
137
134
  ### Step 3: Convert OpenAPI to Operations
@@ -153,11 +150,12 @@ Use this mapping:
153
150
  #### Before:
154
151
  ```javascript
155
152
  const { ServiceWrapper } = require('@onlineapps/service-wrapper');
156
- const openApiSpec = require('./connector-config/openapi.json');
153
+ const openApiSpec = require('./conn-config/openapi.json');
157
154
 
158
155
  const wrapper = new ServiceWrapper({
159
156
  app,
160
157
  server,
158
+ serviceRoot: __dirname,
161
159
  config,
162
160
  openApiSpec // OLD
163
161
  });
@@ -171,6 +169,7 @@ const operations = require('./conn-config/operations.json');
171
169
  const wrapper = new ServiceWrapper({
172
170
  app,
173
171
  server,
172
+ serviceRoot: __dirname,
174
173
  config,
175
174
  operations // NEW
176
175
  });
@@ -181,7 +180,7 @@ const wrapper = new ServiceWrapper({
181
180
  #### Before:
182
181
  ```javascript
183
182
  app.get('/specification', (req, res) => {
184
- const openapi = require('./connector-config/openapi.json');
183
+ const openapi = require('./conn-config/openapi.json');
185
184
  res.json(openapi);
186
185
  });
187
186
  ```
@@ -197,7 +196,6 @@ app.get('/specification', (req, res) => {
197
196
  ### Step 6: Update Documentation References
198
197
 
199
198
  Update all references:
200
- - `connector-config/` → `conn-config/`
201
199
  - `openapi.json` → `operations.json`
202
200
  - "OpenAPI specification" → "Operations specification"
203
201
 
@@ -271,7 +269,7 @@ function convertSchema(schema) {
271
269
  }
272
270
 
273
271
  // Usage
274
- const openapi = require('./connector-config/openapi.json');
272
+ const openapi = require('./conn-config/openapi.json');
275
273
  const operations = convertOpenAPIToOperations(openapi);
276
274
  fs.writeFileSync('./conn-config/operations.json', JSON.stringify(operations, null, 2));
277
275
  console.log('Converted to operations.json');
@@ -365,7 +365,7 @@ servers:
365
365
  description: Configured base URL
366
366
  ```
367
367
 
368
- ## 9. Testing with conn-e2e-testing
368
+ ## 9. Testing with conn-orch-validator
369
369
 
370
370
  The connector testing framework will:
371
371
  1. Load your OpenAPI schema
@@ -386,4 +386,4 @@ Ensure your service is ready by:
386
386
  - [JSON Schema Validation](https://json-schema.org/draft/2019-09/json-schema-validation.html)
387
387
  - [swagger-cli Documentation](https://apitools.dev/swagger-cli/)
388
388
  - Service Wrapper documentation: `/shared/connector/service-wrapper/README.md`
389
- - Testing examples: `/shared/connector/conn-e2e-testing/examples/`
389
+ - Testing examples: `/shared/connector/conn-orch-validator/examples/`
package/jest.config.js CHANGED
@@ -7,7 +7,7 @@ module.exports = {
7
7
  '!src/**/index.js'
8
8
  ],
9
9
  testMatch: [
10
- '**/test/**/*.test.js'
10
+ '**/tests/**/*.test.js'
11
11
  ],
12
12
  testPathIgnorePatterns: [
13
13
  '/node_modules/'
@@ -22,13 +22,13 @@ module.exports = {
22
22
  },
23
23
  moduleNameMapper: {
24
24
  // Map connector imports to mocks in unit tests
25
- '@onlineapps/conn-infra-mq': '<rootDir>/test/mocks/connectors.js',
26
- '@onlineapps/conn-orch-registry': '<rootDir>/test/mocks/connectors.js',
27
- '@onlineapps/conn-base-logger': '<rootDir>/test/mocks/connectors.js',
28
- '@onlineapps/conn-orch-orchestrator': '<rootDir>/test/mocks/connectors.js',
29
- '@onlineapps/conn-orch-api-mapper': '<rootDir>/test/mocks/connectors.js',
30
- '@onlineapps/conn-orch-cookbook': '<rootDir>/test/mocks/connectors.js'
25
+ '@onlineapps/conn-infra-mq': '<rootDir>/tests/mocks/connectors.js',
26
+ '@onlineapps/conn-orch-registry': '<rootDir>/tests/mocks/connectors.js',
27
+ '@onlineapps/conn-base-logger': '<rootDir>/tests/mocks/connectors.js',
28
+ '@onlineapps/conn-orch-orchestrator': '<rootDir>/tests/mocks/connectors.js',
29
+ '@onlineapps/conn-orch-api-mapper': '<rootDir>/tests/mocks/connectors.js',
30
+ '@onlineapps/conn-orch-cookbook': '<rootDir>/tests/mocks/connectors.js'
31
31
  },
32
- setupFilesAfterEnv: ['<rootDir>/test/setup.js'],
32
+ setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
33
33
  verbose: true
34
34
  };
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@onlineapps/service-wrapper",
3
- "version": "2.0.17",
3
+ "version": "2.0.19",
4
4
  "description": "Thin orchestration layer for microservices - delegates all infrastructure concerns to specialized connectors",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
7
7
  "test": "jest",
8
- "test:unit": "jest test/unit",
9
- "test:component": "jest test/component",
10
- "test:integration": "jest test/integration",
8
+ "test:unit": "jest tests/unit",
9
+ "test:component": "jest tests/component",
10
+ "test:integration": "jest tests/integration",
11
11
  "test:coverage": "jest --coverage",
12
12
  "test:mocked": "node test/run-tests.js",
13
13
  "docs": "jsdoc2md --files src/**/*.js > API.md",
@@ -32,6 +32,7 @@
32
32
  "@onlineapps/conn-orch-cookbook": "^2.0.0",
33
33
  "@onlineapps/conn-orch-orchestrator": "^1.0.1",
34
34
  "@onlineapps/conn-orch-registry": "^1.1.13",
35
+ "@onlineapps/conn-orch-validator": "^2.0.0",
35
36
  "@onlineapps/monitoring-core": "^1.0.0"
36
37
  },
37
38
  "devDependencies": {
@@ -21,6 +21,7 @@ const ApiMapperConnector = require('@onlineapps/conn-orch-api-mapper');
21
21
  const CookbookConnector = require('@onlineapps/conn-orch-cookbook');
22
22
  const CacheConnector = require('@onlineapps/conn-base-cache');
23
23
  const ErrorHandlerConnector = require('@onlineapps/conn-infra-error-handler');
24
+ const { ValidationOrchestrator } = require('@onlineapps/conn-orch-validator');
24
25
 
25
26
  /**
26
27
  * ServiceWrapper class
@@ -34,6 +35,7 @@ class ServiceWrapper {
34
35
  * @param {Object} options.server - HTTP server instance
35
36
  * @param {Object} options.config - Service and wrapper configuration
36
37
  * @param {Object} options.operations - Operations schema
38
+ * @param {string} [options.serviceRoot] - Service root directory (for validation)
37
39
  * @param {Object} [options.validationProof=null] - Optional validation proof {hash, data}
38
40
  */
39
41
  constructor(options = {}) {
@@ -44,6 +46,7 @@ class ServiceWrapper {
44
46
  this.server = options.server;
45
47
  this.config = this._processConfig(options.config);
46
48
  this.operations = options.operations;
49
+ this.serviceRoot = options.serviceRoot;
47
50
  this.validationProof = options.validationProof || null;
48
51
 
49
52
  // Initialize connector placeholders
@@ -146,27 +149,34 @@ class ServiceWrapper {
146
149
  await this._initializeMonitoring();
147
150
  }
148
151
 
149
- // 2. Initialize MQ connection
152
+ // 2. Run pre-validation (Tier 1)
153
+ // Validates service structure, config, operations, cookbook tests
154
+ // Skips if valid proof exists in conn-runtime/validation-proof.json
155
+ if (this.serviceRoot && this.config.wrapper?.validation?.enabled !== false) {
156
+ await this._ensureValidationProof();
157
+ }
158
+
159
+ // 3. Initialize MQ connection
150
160
  if (this.config.wrapper?.mq?.enabled !== false) {
151
161
  await this._initializeMQ();
152
162
  }
153
163
 
154
- // 3. Initialize service registry
164
+ // 4. Initialize service registry
155
165
  if (this.config.wrapper?.registry?.enabled !== false) {
156
166
  await this._initializeRegistry();
157
167
  }
158
168
 
159
- // 4. Initialize cache if configured
169
+ // 5. Initialize cache if configured
160
170
  if (this.config.wrapper?.cache?.enabled === true) {
161
171
  await this._initializeCache();
162
172
  }
163
173
 
164
- // 5. Setup health checks
174
+ // 6. Setup health checks
165
175
  if (this.config.wrapper?.health?.enabled !== false) {
166
176
  this._setupHealthChecks();
167
177
  }
168
178
 
169
- // 6. Initialize orchestrator for workflow processing
179
+ // 7. Initialize orchestrator for workflow processing
170
180
  // NOTE: Orchestrator is prepared but workflow listeners will be started
171
181
  // ONLY after receiving certificate from Registry (see _initializeRegistry)
172
182
  if (this.mqClient) {
@@ -460,9 +470,16 @@ class ServiceWrapper {
460
470
  message = rawMessage;
461
471
  }
462
472
 
473
+ // Extract and normalize flags
474
+ const flags = Array.isArray(message.flags) ? message.flags : [];
475
+ const isTest = flags.includes('test');
476
+ const isTier2Validation = flags.includes('tier2-validation');
477
+
463
478
  console.log(`Processing message from ${queueName}:`, {
464
479
  workflow_id: message.workflow_id,
465
- step: message.step?.operation || message.operation
480
+ step: message.step?.operation || message.operation,
481
+ flags,
482
+ isTest
466
483
  });
467
484
 
468
485
  // Check if this message is for our service
@@ -473,22 +490,42 @@ class ServiceWrapper {
473
490
  }
474
491
 
475
492
  // Process based on message type
493
+ let result;
476
494
  if (message.operation && this.operations?.operations?.[message.operation]) {
477
495
  // Direct operation call
478
- const result = await this._executeOperation(message.operation, message.input || {});
479
- return result;
496
+ result = await this._executeOperation(message.operation, message.input || {});
480
497
  } else if (message.step?.operation && this.operations?.operations?.[message.step.operation]) {
481
498
  // Workflow step
482
- const result = await this._executeOperation(message.step.operation, message.input || {});
483
- return result;
499
+ result = await this._executeOperation(message.step.operation, message.input || {});
484
500
  } else if (this.orchestrator) {
485
501
  // Delegate to orchestrator for complex workflow processing
486
- const result = await this.orchestrator.processWorkflowMessage(message, serviceName);
487
- return result;
502
+ result = await this.orchestrator.processWorkflowMessage(message, serviceName);
488
503
  } else {
489
504
  throw new Error(`Unknown message format or operation: ${JSON.stringify(message)}`);
490
505
  }
491
506
 
507
+ // Send response to workflow.completed if workflow_id is present
508
+ if (message.workflow_id && this.mqClient) {
509
+ const workflowResponse = {
510
+ workflow_id: message.workflow_id,
511
+ service: serviceName,
512
+ operation: message.step?.operation || message.operation,
513
+ status: 'completed',
514
+ output: result,
515
+ flags,
516
+ timestamp: new Date().toISOString()
517
+ };
518
+
519
+ try {
520
+ await this.mqClient.publish('workflow.completed', workflowResponse);
521
+ console.log(`✓ Workflow response sent to workflow.completed: ${message.workflow_id}`);
522
+ } catch (error) {
523
+ console.error(`Failed to send workflow response:`, error);
524
+ }
525
+ }
526
+
527
+ return result;
528
+
492
529
  } catch (error) {
493
530
  console.error(`Error processing message from ${queueName}:`, error);
494
531
  throw error;
@@ -631,6 +668,49 @@ class ServiceWrapper {
631
668
  }
632
669
  }
633
670
 
671
+ /**
672
+ * Ensure validation proof exists and is valid
673
+ * Runs ValidationOrchestrator if proof missing or invalid
674
+ * @private
675
+ */
676
+ async _ensureValidationProof() {
677
+ if (!this.config.service?.name) {
678
+ throw new Error('Service name is required for validation');
679
+ }
680
+ if (!this.config.service?.version) {
681
+ throw new Error('Service version is required for validation');
682
+ }
683
+ if (!this.logger) {
684
+ throw new Error('Monitoring must be initialized before validation');
685
+ }
686
+
687
+ const { name: serviceName, version: serviceVersion } = this.config.service;
688
+
689
+ this.logger.info('[ServiceWrapper] Checking validation proof...');
690
+
691
+ const orchestrator = new ValidationOrchestrator({
692
+ serviceRoot: this.serviceRoot,
693
+ serviceName,
694
+ serviceVersion,
695
+ logger: this.logger
696
+ });
697
+
698
+ const result = await orchestrator.validate();
699
+
700
+ if (!result.success) {
701
+ throw new Error(`Validation failed: ${result.errors.join(', ')}`);
702
+ }
703
+
704
+ if (result.skipped) {
705
+ this.logger.info('[ServiceWrapper] ✓ Using existing validation proof');
706
+ } else {
707
+ this.logger.info('[ServiceWrapper] ✓ Validation completed successfully');
708
+ }
709
+
710
+ // Store proof for registration
711
+ this.validationProof = result.proof;
712
+ }
713
+
634
714
  /**
635
715
  * Get wrapper status
636
716
  */
@@ -9,7 +9,7 @@
9
9
  const ServiceWrapper = require('../../src/ServiceWrapper');
10
10
  const express = require('express');
11
11
 
12
- describe('ServiceWrapper Component Tests', () => {
12
+ describe('ServiceWrapper Component Tests @component', () => {
13
13
  let wrapper;
14
14
  let app;
15
15
  let server;
@@ -6,7 +6,7 @@
6
6
  * Run these after implementing each connector
7
7
  */
8
8
 
9
- describe('Connector Integration Tests', () => {
9
+ describe('Connector Integration Tests @component', () => {
10
10
  describe('Orchestrator Connector', () => {
11
11
  test.skip('should integrate with real Orchestrator connector', async () => {
12
12
  // Enable this test after conn-orch-orchestrator is fully implemented
@@ -10,7 +10,7 @@ const MQConnector = require('@onlineapps/conn-infra-mq');
10
10
  const express = require('express');
11
11
  const http = require('http');
12
12
 
13
- describe('ServiceWrapper E2E Tests', () => {
13
+ describe('ServiceWrapper E2E Tests @e2e', () => {
14
14
  let testService;
15
15
  let testServer;
16
16
  let serviceWrapper;
@@ -2,7 +2,7 @@
2
2
  * Test monitoring integration in service-wrapper
3
3
  */
4
4
 
5
- describe('ServiceWrapper Monitoring Integration', () => {
5
+ describe('ServiceWrapper Monitoring Integration @integration', () => {
6
6
  let ServiceWrapper;
7
7
  let express;
8
8
 
@@ -20,7 +20,7 @@ jest.mock('@onlineapps/conn-orch-orchestrator', () => MockOrchestratorConnector)
20
20
  jest.mock('@onlineapps/conn-orch-api-mapper', () => MockApiMapperConnector);
21
21
  jest.mock('@onlineapps/conn-orch-cookbook', () => MockCookbookConnector);
22
22
 
23
- describe('ServiceWrapper Unit Tests', () => {
23
+ describe('ServiceWrapper Unit Tests @unit', () => {
24
24
  let wrapper;
25
25
  let mockExpressApp;
26
26
  let mockOpenApiSpec;
File without changes
File without changes
File without changes