@onlineapps/service-wrapper 3.1.0 → 3.2.1
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 +7 -6
- package/src/ContextBuilder.js +7 -1
- package/src/ServiceWrapper.js +49 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/service-wrapper",
|
|
3
|
-
"version": "3.1
|
|
3
|
+
"version": "3.2.1",
|
|
4
4
|
"description": "Thin orchestration layer for microservices - delegates all infrastructure concerns to specialized connectors",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -25,17 +25,18 @@
|
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@onlineapps/conn-base-cache": "1.0.9",
|
|
28
|
-
"@onlineapps/conn-base-monitoring": "1.0.
|
|
28
|
+
"@onlineapps/conn-base-monitoring": "1.0.13",
|
|
29
29
|
"@onlineapps/conn-base-state": "1.0.1",
|
|
30
|
-
"@onlineapps/conn-infra-error-handler": "1.0.
|
|
30
|
+
"@onlineapps/conn-infra-error-handler": "1.0.12",
|
|
31
31
|
"@onlineapps/conn-infra-mq": "1.1.70",
|
|
32
|
+
"@onlineapps/conn-infra-secrets": "1.0.0",
|
|
32
33
|
"@onlineapps/conn-orch-cookbook": "2.1.3",
|
|
33
|
-
"@onlineapps/conn-orch-orchestrator": "2.1.
|
|
34
|
+
"@onlineapps/conn-orch-orchestrator": "2.1.1",
|
|
34
35
|
"@onlineapps/conn-orch-registry": "1.2.1",
|
|
35
36
|
"@onlineapps/conn-orch-validator": "3.1.2",
|
|
36
|
-
"@onlineapps/monitoring-core": "1.0.
|
|
37
|
+
"@onlineapps/monitoring-core": "1.0.24",
|
|
37
38
|
"@onlineapps/runtime-config": "1.0.2",
|
|
38
|
-
"@onlineapps/service-common": "1.1.
|
|
39
|
+
"@onlineapps/service-common": "1.1.3",
|
|
39
40
|
"ajv": "8.17.1",
|
|
40
41
|
"ajv-formats": "3.0.1"
|
|
41
42
|
},
|
package/src/ContextBuilder.js
CHANGED
|
@@ -92,6 +92,9 @@ class ContextBuilder {
|
|
|
92
92
|
const httpClient = this._connectors.http;
|
|
93
93
|
const secretsAdapter = this._connectors.secrets;
|
|
94
94
|
const secrets = {
|
|
95
|
+
// Handlers call ctx.secrets.get(ref); the facade injects the invocation
|
|
96
|
+
// scope so the connector can resolve the tenant/workspace projection
|
|
97
|
+
// (see api/docs/architecture/secretbox.md §6).
|
|
95
98
|
get: (name) => {
|
|
96
99
|
if (!secretsAdapter || typeof secretsAdapter.get !== 'function') {
|
|
97
100
|
throw new Error(
|
|
@@ -99,7 +102,10 @@ class ContextBuilder {
|
|
|
99
102
|
'wire a secrets connector before using ctx.secrets'
|
|
100
103
|
);
|
|
101
104
|
}
|
|
102
|
-
return secretsAdapter.get(name
|
|
105
|
+
return secretsAdapter.get(name, {
|
|
106
|
+
tenant_id: envelope.tenant_id ?? null,
|
|
107
|
+
workspace_id: envelope.workspace_id ?? null
|
|
108
|
+
});
|
|
103
109
|
}
|
|
104
110
|
};
|
|
105
111
|
|
package/src/ServiceWrapper.js
CHANGED
|
@@ -20,6 +20,7 @@ const OrchestratorConnector = require('@onlineapps/conn-orch-orchestrator');
|
|
|
20
20
|
const CookbookConnector = require('@onlineapps/conn-orch-cookbook');
|
|
21
21
|
const CacheConnector = require('@onlineapps/conn-base-cache');
|
|
22
22
|
const StateConnector = require('@onlineapps/conn-base-state');
|
|
23
|
+
const SecretsConnector = require('@onlineapps/conn-infra-secrets');
|
|
23
24
|
const ErrorHandlerConnector = require('@onlineapps/conn-infra-error-handler');
|
|
24
25
|
const { ValidationOrchestrator } = require('@onlineapps/conn-orch-validator');
|
|
25
26
|
const runtimeCfg = require('./config');
|
|
@@ -146,6 +147,7 @@ class ServiceWrapper {
|
|
|
146
147
|
this.registryClient = null;
|
|
147
148
|
this.orchestrator = null;
|
|
148
149
|
this.cacheConnector = null;
|
|
150
|
+
this.secretsConnector = null;
|
|
149
151
|
this.monitoring = null;
|
|
150
152
|
this.logger = null;
|
|
151
153
|
|
|
@@ -734,6 +736,15 @@ class ServiceWrapper {
|
|
|
734
736
|
}
|
|
735
737
|
}
|
|
736
738
|
|
|
739
|
+
if (this.secretsConnector) {
|
|
740
|
+
try {
|
|
741
|
+
await this.secretsConnector.disconnect();
|
|
742
|
+
console.log(`[CLEANUP] ✓ Closed Redis secrets connection`);
|
|
743
|
+
} catch (err) {
|
|
744
|
+
console.warn(`[CLEANUP] Failed to close Redis secrets connection:`, err.message);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
737
748
|
// 5. Clear state variables
|
|
738
749
|
this.workflowInitConsumerTag = null;
|
|
739
750
|
this.workflowControlConsumerTag = null;
|
|
@@ -897,6 +908,12 @@ class ServiceWrapper {
|
|
|
897
908
|
await this._initializeState();
|
|
898
909
|
}
|
|
899
910
|
|
|
911
|
+
// Initialize secrets connector if configured (SecretBox resolution for
|
|
912
|
+
// ctx.secrets.get(ref)). Critical when enabled — let it throw.
|
|
913
|
+
if (this.config.wrapper?.secrets?.enabled === true) {
|
|
914
|
+
await this._initializeSecrets();
|
|
915
|
+
}
|
|
916
|
+
|
|
900
917
|
// v3 handler-registry pipeline (RFC §5.9). Replaces the v2 HTTP-loopback
|
|
901
918
|
// invocation path. Must run AFTER connectors are instantiated (storage,
|
|
902
919
|
// cache, monitoring, mq) and BEFORE MQ messages are dispatched.
|
|
@@ -1463,6 +1480,32 @@ class ServiceWrapper {
|
|
|
1463
1480
|
this.logger?.info('State connector initialized');
|
|
1464
1481
|
}
|
|
1465
1482
|
|
|
1483
|
+
/**
|
|
1484
|
+
* Initialize secrets connector (SecretBox). Resolves ctx.secrets.get(ref) by
|
|
1485
|
+
* reading the encrypted Redis projection written by biz-meta and decrypting
|
|
1486
|
+
* in-process. Redis reuses wrapper.cache.url (shared api_node_cache); the AES
|
|
1487
|
+
* master key is required from env (no fallback).
|
|
1488
|
+
* @private
|
|
1489
|
+
*/
|
|
1490
|
+
async _initializeSecrets() {
|
|
1491
|
+
const { requireEnv } = require('@onlineapps/service-common');
|
|
1492
|
+
const secretsConfig = this.config.wrapper?.secrets || {};
|
|
1493
|
+
const redisUrl = secretsConfig.url || this.config.wrapper?.cache?.url
|
|
1494
|
+
|| requireEnv('REDIS_URL', 'Redis connection URL for secrets projection');
|
|
1495
|
+
const masterKeyBase64 = secretsConfig.masterKey
|
|
1496
|
+
|| requireEnv('SECRETS_MASTER_KEY', 'base64-encoded 32-byte AES-256-GCM master key for secret resolution');
|
|
1497
|
+
|
|
1498
|
+
this.secretsConnector = new SecretsConnector({
|
|
1499
|
+
redisUrl,
|
|
1500
|
+
masterKeyBase64,
|
|
1501
|
+
password: secretsConfig.password,
|
|
1502
|
+
db: secretsConfig.db
|
|
1503
|
+
});
|
|
1504
|
+
|
|
1505
|
+
await this.secretsConnector.connect();
|
|
1506
|
+
this.logger?.info('Secrets connector initialized');
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1466
1509
|
/**
|
|
1467
1510
|
* Setup health check endpoint
|
|
1468
1511
|
* @private
|
|
@@ -2287,7 +2330,7 @@ class ServiceWrapper {
|
|
|
2287
2330
|
storage: null,
|
|
2288
2331
|
cache: this.cacheConnector || null,
|
|
2289
2332
|
http: null,
|
|
2290
|
-
secrets: null,
|
|
2333
|
+
secrets: this.secretsConnector || null,
|
|
2291
2334
|
monitoring: this.monitoring || null,
|
|
2292
2335
|
mq: this.mqClient || null,
|
|
2293
2336
|
state: this.stateConnector || null
|
|
@@ -2765,6 +2808,11 @@ class ServiceWrapper {
|
|
|
2765
2808
|
await this.stateConnector.disconnect();
|
|
2766
2809
|
}
|
|
2767
2810
|
|
|
2811
|
+
// Disconnect from secrets
|
|
2812
|
+
if (this.secretsConnector) {
|
|
2813
|
+
await this.secretsConnector.disconnect();
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2768
2816
|
// Disconnect from MQ
|
|
2769
2817
|
if (this.mqClient) {
|
|
2770
2818
|
await this.mqClient.disconnect();
|