@mojaloop/sdk-scheme-adapter 24.13.0 → 24.14.0-snapshot.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.
Files changed (30) hide show
  1. package/.yarn/cache/{@mojaloop-central-services-shared-npm-18.34.0-98deaad7cb-660f407a57.zip → @mojaloop-central-services-shared-npm-18.34.1-fc3be8e73c-f7ad2f9394.zip} +0 -0
  2. package/.yarn/cache/{@mojaloop-inter-scheme-proxy-cache-lib-npm-2.7.0-84455815f8-7748014a4c.zip → @mojaloop-inter-scheme-proxy-cache-lib-npm-2.9.0-cb33cd6786-fd3f20e6a7.zip} +0 -0
  3. package/.yarn/cache/@typescript-eslint-eslint-plugin-npm-8.46.0-e6114965b4-415afd894a.zip +0 -0
  4. package/.yarn/cache/@typescript-eslint-parser-npm-8.46.0-c44629050a-6838fde776.zip +0 -0
  5. package/.yarn/cache/@typescript-eslint-project-service-npm-8.46.0-85a4b9bb9c-de11af23ae.zip +0 -0
  6. package/.yarn/cache/@typescript-eslint-scope-manager-npm-8.46.0-fd8edaba78-ed85abd08c.zip +0 -0
  7. package/.yarn/cache/@typescript-eslint-tsconfig-utils-npm-8.46.0-8919c1f746-e78a66a854.zip +0 -0
  8. package/.yarn/cache/@typescript-eslint-type-utils-npm-8.46.0-dbfff922bb-5405b71b91.zip +0 -0
  9. package/.yarn/cache/@typescript-eslint-types-npm-8.46.0-b013400d3e-0118b0dd59.zip +0 -0
  10. package/.yarn/cache/@typescript-eslint-typescript-estree-npm-8.46.0-0b10d4388a-61053bd0c3.zip +0 -0
  11. package/.yarn/cache/@typescript-eslint-utils-npm-8.46.0-a7d3832f43-4e0da60de3.zip +0 -0
  12. package/.yarn/cache/@typescript-eslint-visitor-keys-npm-8.46.0-7d793afea5-37e6145b6a.zip +0 -0
  13. package/.yarn/install-state.gz +0 -0
  14. package/.yarn/releases/{yarn-4.10.2.cjs → yarn-4.10.3.cjs} +126 -126
  15. package/.yarnrc.yml +1 -1
  16. package/CLAUDE.md +186 -0
  17. package/modules/api-svc/package.json +2 -2
  18. package/modules/api-svc/src/ControlAgent/index.js +42 -11
  19. package/modules/api-svc/src/OutboundServer/handlers.js +1 -1
  20. package/modules/api-svc/src/config.js +1 -0
  21. package/modules/api-svc/src/index.js +244 -188
  22. package/modules/api-svc/src/lib/cache.js +3 -1
  23. package/modules/api-svc/src/lib/logger.js +1 -2
  24. package/modules/api-svc/test/unit/index.configPolling.test.js +229 -0
  25. package/modules/api-svc/test/unit/lib/model/InboundPingModel.test.js +2 -2
  26. package/modules/outbound-command-event-handler/package.json +4 -4
  27. package/modules/outbound-domain-event-handler/package.json +3 -3
  28. package/modules/private-shared-lib/package.json +4 -4
  29. package/package.json +4 -4
  30. package/{sbom-v24.12.0.csv → sbom-v24.13.0.csv} +220 -231
package/.yarnrc.yml CHANGED
@@ -4,4 +4,4 @@ enableGlobalCache: false
4
4
 
5
5
  nodeLinker: node-modules
6
6
 
7
- yarnPath: .yarn/releases/yarn-4.10.2.cjs
7
+ yarnPath: .yarn/releases/yarn-4.10.3.cjs
package/CLAUDE.md ADDED
@@ -0,0 +1,186 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ This is the Mojaloop SDK Scheme Adapter - a monorepo that provides an adapter interface between Mojaloop API compliant switches and DFSP backend platforms.
8
+ The project consists of multiple modules organized using Nx workspace.
9
+
10
+ ## Quick Reference (Start Here)
11
+
12
+ | Task | Command | Prerequisites |
13
+ |------|---------|---------------|
14
+ | Run all tests | `yarn test` | - |
15
+ | Run integration tests | `yarn test:integration` | Docker running, `yarn wait-4-docker` |
16
+ | Run specific module test | `yarn workspace @mojaloop/sdk-scheme-adapter-api-svc run test:unit` | - |
17
+ | Build everything | `yarn build` | Node 22.15.1 (`nvm use`) |
18
+ | Start services | `yarn start` | Docker running, modules built |
19
+ | Update OpenAPI | `yarn build:openapi && yarn validate:api` | - |
20
+ | Debug main service | `yarn workspace @mojaloop/sdk-scheme-adapter-api-svc run start:debug` | Port 9229 available |
21
+
22
+
23
+ **Critical File Locations:**
24
+ - Models: `modules/api-svc/src/lib/model/`
25
+ - Handlers: `modules/api-svc/src/{Inbound,Outbound}Server/handlers.js`
26
+ - Config: `modules/*/src/config/default.json`
27
+ - OpenAPI templates: `modules/*/src/*_template.yaml` (edit these, not `api.yaml`)
28
+
29
+ ## Architecture
30
+ This service can be referenced as `Mojaloop Connector`, `ML Connector` or `Scheme Adapter`.
31
+
32
+ ### Core Modules
33
+
34
+ - **api-svc**: Main service module (JavaScript/Node.js) handling inbound/outbound HTTP APIs and core business logic
35
+ - **outbound-command-event-handler**: TypeScript module handling outbound command events using domain-driven design
36
+ - **outbound-domain-event-handler**: TypeScript module processing domain events for outbound operations
37
+ - **private-shared-lib**: Shared TypeScript library containing domain entities, events, and infrastructure code
38
+
39
+ ### Key Components
40
+
41
+ - **Event-Driven Architecture**: Uses Kafka for event streaming between modules
42
+ - **State Machines**: JavaScript State Machine library for managing transfer states
43
+ - **Cache Layer**: Redis for distributed caching and session management
44
+ - **Models**: Domain models for transfers, quotes, parties, bulk operations
45
+ - **Event Handlers**: FSPIOP and Backend event handling for Mojaloop protocol compliance
46
+ - **ControlAgent**: WebSocket client for PM4ML Management API with optional failsafe polling
47
+
48
+ ## Code Structure Patterns
49
+
50
+ ### API Service (modules/api-svc)
51
+ - **Handlers**: Route handlers in `src/InboundServer/handlers.js` and `src/OutboundServer/handlers.js`
52
+ - **Models**: Business logic in `src/lib/model/` with models like:
53
+ - `TransfersModel.js` - Transfer operations
54
+ - `QuotesModel.js` - Quote handling
55
+ - `AccountsModel.js` - Account management
56
+ - `InboundTransfersModel.js` - Inbound transfer processing
57
+ - `OutboundTransfersModel.js` - Outbound transfer processing
58
+ - `OutboundBulkQuotesModel.js` - Bulk quote operations
59
+ - `OutboundBulkTransfersModel.js` - Bulk transfer operations
60
+ - **State Machines**: Use `PersistentStateMachine` for managing complex state transitions
61
+ - **Middleware**: Validation and error handling middleware in `middlewares.js`
62
+ - **OpenAPI Templates**: API definitions in `api_template.yaml` files, compiled to `api.yaml`
63
+
64
+ ### Event Handlers (TypeScript modules)
65
+ - **Domain Layer**: Aggregates and entities in `src/domain/`
66
+ - **Application Layer**: Event handlers in `src/application/handlers/`
67
+ - **Infrastructure**: Kafka producers/consumers in shared lib
68
+ - **API Server**: Express-based APIs with OpenAPI specs
69
+ - **Build Process**: TypeScript compilation + file copying (YAML files)
70
+
71
+ ### Testing Patterns
72
+ - **Unit tests**: `test/unit/` directories using Jest
73
+ - **Integration tests**: `test/integration/` requiring Docker services
74
+ - **Functional tests**: Separate test suites in `test/func_bulk/` and `test/func_iso20022/`
75
+ - **Mocks**: Test mocks in `test/__mocks__/`
76
+ - **Setup**: Test setup files like `test/unit/setup.js`
77
+ - **Configuration**: Jest config in individual `jest.config.js` files
78
+
79
+ ## Development Commands
80
+ Check **[development-commands.md](./_cc/docs/development-commands.md)** file to get details about some useful commands to
81
+ build and setup the project, start the services, run tests, linting, deps and audit checks, etc.
82
+
83
+ ## Key Libraries & Dependencies
84
+
85
+ - **@mojaloop/sdk-standard-components**: Core Mojaloop SDK components
86
+ - **@mojaloop/central-services-***: Mojaloop platform services
87
+ - **@mojaloop/api-snippets**: API specification components
88
+ - **javascript-state-machine**: State management for transfers
89
+ - **redis**: Distributed caching (v5.x)
90
+ - **express/koa**: HTTP servers (Express for newer modules, Koa for some services)
91
+ - **ajv**: JSON schema validation
92
+ - **convict**: Configuration management in TypeScript modules
93
+ - **openapi-backend**: OpenAPI request validation and routing
94
+ - **Package Manager**: Yarn 4.10.2 (Berry)
95
+
96
+ ## Docker Environment
97
+
98
+ See [development-commands.md](./_cc/docs/development-commands.md#docker-operations) for Docker commands.
99
+
100
+ **Services:** redis (6379), kafka (9092), ml-testing-toolkit (4040/5050), mojaloop-testing-toolkit-ui (6060)
101
+ **Debug profile adds:** redisinsight (9001), kafka-debug-ui (9080)
102
+ **Main service ports:** 4000-4004, 9229 (debugger)
103
+
104
+ ## Development Patterns & Notes
105
+
106
+ ### Module Architecture
107
+ - **api-svc**: JavaScript-based, legacy module with core functionality
108
+ - **Shared lib**: Private workspace package for cross-module code
109
+
110
+ ### Event Sourcing
111
+ Commands → `outbound-command-event-handler` → Domain events → `outbound-domain-event-handler`
112
+ **Kafka topics:** `topic-sdk-outbound-command-events`, `topic-sdk-outbound-domain-events`
113
+
114
+ ### State Management
115
+ **Redis:** State machine persistence, distributed cache, cross-module communication, bulk transaction tracking
116
+ **Pattern:** `PersistentStateMachine` class for complex state transitions
117
+
118
+ ### OpenAPI Workflow
119
+ 1. Edit `*_template.yaml` files (not generated `api.yaml`)
120
+ 2. Run `yarn build:openapi` to compile templates
121
+ 3. Validate with `yarn validate:api`
122
+ 4. Uses `@redocly/openapi-cli` for bundling
123
+
124
+ ### Testing Workflow
125
+ 1. **Unit tests**: Run locally without dependencies
126
+ 2. **Integration tests**: Require Docker services (Redis, Kafka)
127
+ 3. **Functional tests**: Full end-to-end scenarios with TTK
128
+ 4. Use `yarn wait-4-docker` to ensure services are ready
129
+
130
+ ## Common Development Tasks
131
+
132
+ See [development-commands.md](./_cc/docs/development-commands.md) for all commands and [common-workflows.md](./_cc/docs/common-workflows.md) for step-by-step guides.
133
+
134
+ ## For AI Assistants (Memory Management Hints)
135
+
136
+ **Always Re-read Before:**
137
+ - Modifying OpenAPI specs → Review OpenAPI Workflow section first
138
+ - Running integration tests → Verify Docker prerequisites and Testing Workflow
139
+ - Making state machine changes → Review api-svc-06-state-management.md
140
+ - Debugging test failures → Check development-commands.md for troubleshooting
141
+
142
+ **Cache (Low Change Frequency):**
143
+ - Architecture: 3 TypeScript modules (command-handler, domain-handler, shared-lib) + api-svc (JavaScript)
144
+ - Event flow: Command events → outbound-command-event-handler → Domain events → outbound-domain-event-handler
145
+ - Redis patterns: State machines, distributed cache, pub/sub, bulk transaction tracking
146
+ - Kafka topics: `topic-sdk-outbound-command-events`, `topic-sdk-outbound-domain-events`
147
+ - Package manager: Yarn 4.10.2 (Berry)
148
+ - Node version: 22.15.1
149
+
150
+ **Key Patterns to Remember:**
151
+ - Edit `*_template.yaml` files, NEVER edit generated `api.yaml` files
152
+ - State machines use `PersistentStateMachine` class backed by Redis
153
+ - Integration tests require Docker services - use `yarn wait-4-docker`
154
+ - Use workspace syntax: `yarn workspace @mojaloop/sdk-scheme-adapter-<module> run <command>`
155
+ - Nx caching enabled for builds/tests - use `--skip-nx-cache` to bypass
156
+
157
+ **When Uncertain:**
158
+ - Ask user ANY clarifying questions
159
+ - Check Quick Reference section at top of this file
160
+ - Consult api-svc-01-overview.md for 30-minute onboarding
161
+ - Use development-commands.md for command reference
162
+ - See common-workflows.md for step-by-step task guides
163
+
164
+ ## Documentation
165
+
166
+ ### API-SVC Module Documentation
167
+
168
+ Comprehensive documentation for the `api-svc` module (core service handling inbound/outbound APIs):
169
+
170
+
171
+ | Document | Description |
172
+ |----------|-------------|
173
+ | **[api-svc-01-overview.md](./_cc/docs/api-svc/api-svc-01-overview.md)** | Overview, quick start guide, 30-minute onboarding with core concepts and transfer flows |
174
+ | **[api-svc-02-architecture.md](./_cc/docs/api-svc/api-svc-02-architecture.md)** | System architecture, component design, configuration system, startup sequence |
175
+ | **[api-svc-03-inbound-server.md](./_cc/docs/api-svc/api-svc-03-inbound-server.md)** | Inbound server handling async FSPIOP callbacks from Mojaloop switch |
176
+ | **[api-svc-04-outbound-server.md](./_cc/docs/api-svc/api-svc-04-outbound-server.md)** | Outbound server providing synchronous REST API for DFSP backends |
177
+ | **[api-svc-05-models.md](./_cc/docs/api-svc/api-svc-05-models.md)** | Business logic models orchestrating party lookups, quotes, transfers, bulk operations |
178
+ | **[api-svc-06-state-management.md](./_cc/docs/api-svc/api-svc-06-state-management.md)** | Redis-backed state machines, pub/sub patterns, key patterns, recovery behavior |
179
+ | **[api-svc-07-control-agent.md](./_cc/docs/api-svc/api-svc-07-control-agent.md)** | WebSocket client for PM4ML Management API dynamic configuration |
180
+ | **[api-svc-08-error-handling.md](./_cc/docs/api-svc/api-svc-08-error-handling.md)** | Error taxonomy, Mojaloop error codes, handling patterns, logging strategies |
181
+ | **[api-svc-09-core-dependencies.md](./_cc/docs/api-svc/api-svc-09-core-dependencies.md)** | Core dependencies including @mojaloop/sdk-standard-components, JWS, ILP, OIDC |
182
+ | **[api-svc-10-service-lifecycle.md](./_cc/docs/api-svc/api-svc-10-service-lifecycle.md)** | Service startup/shutdown sequences, component bootstrap order, configuration sources, hot reload |
183
+ | **[api-svc-11-event-handlers.md](./_cc/docs/api-svc/api-svc-11-event-handlers.md)** | Kafka event handlers for domain/command events integration with TypeScript modules |
184
+ | **[api-svc-12-testing.md](./_cc/docs/api-svc/api-svc-12-testing.md)** | Testing strategy covering unit, integration, and functional tests |
185
+ | **[api-svc-13-deployment.md](./_cc/docs/api-svc/api-svc-13-deployment.md)** | Kubernetes deployment with Helm charts, production configuration, monitoring |
186
+ | **[api-svc-14-examples.md](./_cc/docs/api-svc/api-svc-14-examples.md)** | Practical examples: outbound/inbound transfers, error handling, bulk operations, auto-accept |
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mojaloop/sdk-scheme-adapter-api-svc",
3
- "version": "21.0.0-snapshot.70",
3
+ "version": "21.0.0-snapshot.72",
4
4
  "description": "An adapter for connecting to Mojaloop API enabled switches.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -68,7 +68,7 @@
68
68
  "@mojaloop/central-services-error-handling": "13.1.3",
69
69
  "@mojaloop/central-services-logger": "11.10.1",
70
70
  "@mojaloop/central-services-metrics": "12.8.0",
71
- "@mojaloop/central-services-shared": "18.34.0",
71
+ "@mojaloop/central-services-shared": "18.34.1",
72
72
  "@mojaloop/event-sdk": "14.8.0",
73
73
  "@mojaloop/logging-bc-client-lib": "0.5.8",
74
74
  "@mojaloop/ml-schema-transformer-lib": "2.7.8",
@@ -40,12 +40,15 @@
40
40
  // the current configuration to
41
41
 
42
42
  const ws = require('ws');
43
+ const _ = require('lodash');
43
44
  const jsonPatch = require('fast-json-patch');
45
+ const safeStringify = require('fast-safe-stringify');
44
46
  const { generateSlug } = require('random-word-slugs');
45
- const _ = require('lodash');
46
47
 
47
48
  const FORCE_WS_CLOSE_TIMEOUT_MS = 5000;
48
49
 
50
+ const cloneJson = (obj) => JSON.parse(safeStringify(obj));
51
+
49
52
  /**************************************************************************
50
53
  * The message protocol messages, verbs, and errors
51
54
  *************************************************************************/
@@ -77,7 +80,7 @@ const EVENT = {
77
80
  /**************************************************************************
78
81
  * Private convenience functions
79
82
  *************************************************************************/
80
- const serialise = JSON.stringify;
83
+ const serialise = safeStringify;
81
84
  const deserialise = (msg) => {
82
85
  //reviver function
83
86
  return JSON.parse(msg.toString(), (k, v) => {
@@ -145,7 +148,7 @@ class Client extends ws {
145
148
  */
146
149
  constructor({ address = 'localhost', port, logger, appConfig }) {
147
150
  super(`ws://${address}:${port}`);
148
- this._logger = logger.push({ component: 'ControlClient' });
151
+ this._logger = logger.push({ component: 'ControlClientWs' });
149
152
  this._appConfig = appConfig;
150
153
  }
151
154
 
@@ -173,28 +176,30 @@ class Client extends ws {
173
176
  async receive() {
174
177
  return new Promise((resolve) => this.once('message', (data) => {
175
178
  const msg = deserialise(data);
176
- this._logger.isDebugEnabled && this._logger.push({ msg }).debug('Received');
179
+ this._logger.push({ msg }).debug('Received and deserialized ws message:');
177
180
  resolve(msg);
178
181
  }));
179
182
  }
180
183
 
181
184
  // Close connection
182
185
  async stop() {
183
- this._logger.isDebugEnabled && this._logger.debug('Control client shutting down...');
186
+ this._logger.verbose('Control client shutting down...');
184
187
  return new Promise((resolve) => {
185
188
  let timer = setTimeout(() => {
186
- this._logger.isInfoEnabled && this._logger.info('Control client forced to close');
189
+ this._logger.warn(`Control client forced to close after ${FORCE_WS_CLOSE_TIMEOUT_MS}ms`);
190
+ this.terminate();
187
191
  timer = null;
188
192
  resolve(false);
189
193
  }, FORCE_WS_CLOSE_TIMEOUT_MS);
190
194
 
191
195
  this.once('close', () => {
192
- this._logger.isInfoEnabled && this._logger.info('Control client is closed');
196
+ this._logger.info('Control client is closed');
193
197
  if (timer) clearTimeout(timer);
198
+ this.removeAllListeners();
194
199
  resolve(true);
195
200
  });
196
201
  this.once('error', (error) => {
197
- this._logger.isWarnEnabled && this._logger.push({ error }).warn('Control client failed to close');
202
+ this._logger.warn('Control client failed to close:', error);
198
203
  if (timer) clearTimeout(timer);
199
204
  resolve(false);
200
205
  });
@@ -203,6 +208,23 @@ class Client extends ws {
203
208
  });
204
209
  }
205
210
 
211
+ /**
212
+ * Call the Connector Manager in Management API to get the updated config
213
+ */
214
+ async getUpdatedConfig() { // clarify naming - why config is updated?
215
+ this._logger.info(`Getting updated config from Management API at ${this.url}...`);
216
+ const wsSendResponse = await this.send(build.CONFIGURATION.READ());
217
+ this._logger.debug('wsSendResponse: ', { wsSendResponse });
218
+
219
+ const wsReceivedData = (await this.receive())?.data;
220
+ this._logger.debug('wsReceivedData: ', { wsReceivedData });
221
+
222
+ if (!wsReceivedData) this._logger.warn('no updatedConfigFromMgmtAPI');
223
+ else this._logger.info('updatedConfigFromMgmtAPI keys:', { updatedConfigFromMgmtAPIKeys: Object.keys(wsReceivedData) });
224
+
225
+ return wsReceivedData;
226
+ }
227
+
206
228
  // Handle incoming message from the server.
207
229
  _handle(data) {
208
230
  // TODO: json-schema validation of received message- should be pretty straight-forward
@@ -211,7 +233,7 @@ class Client extends ws {
211
233
  try {
212
234
  msg = deserialise(data);
213
235
  } catch {
214
- this._logger.isErrorEnabled && this._logger.push({ data }).console.error();('Couldn\'t parse received message');
236
+ this._logger.warn('failed to parse received message: ', { data });
215
237
  this.send(build.ERROR.NOTIFY.JSON_PARSE_ERROR());
216
238
  }
217
239
  this._logger.isDebugEnabled && this._logger.push({ msg }).debug('Handling received message');
@@ -219,14 +241,14 @@ class Client extends ws {
219
241
  case MESSAGE.CONFIGURATION:
220
242
  switch (msg.verb) {
221
243
  case VERB.NOTIFY: {
222
- const dup = JSON.parse(JSON.stringify(this._appConfig)); // fast-json-patch explicitly mutates
244
+ const dup = cloneJson(this._appConfig); // fast-json-patch explicitly mutates
223
245
  _.merge(dup, msg.data);
224
246
  this._logger.isDebugEnabled && this._logger.push({ oldConf: this._appConfig, newConf: dup }).debug(`Emitting new agent configuration [${VERB.NOTIFY}]`);
225
247
  this.emit(EVENT.RECONFIGURE, dup);
226
248
  break;
227
249
  }
228
250
  case VERB.PATCH: {
229
- const dup = JSON.parse(JSON.stringify(this._appConfig)); // fast-json-patch explicitly mutates
251
+ const dup = cloneJson(this._appConfig); // fast-json-patch explicitly mutates
230
252
  jsonPatch.applyPatch(dup, msg.data);
231
253
  this._logger.isDebugEnabled && this._logger.push({ oldConf: this._appConfig, newConf: dup }).debug(`Emitting new agent configuration [${VERB.PATCH}]`);
232
254
  this.emit(EVENT.RECONFIGURE, dup);
@@ -255,9 +277,18 @@ class Client extends ws {
255
277
  }
256
278
  }
257
279
 
280
+ const createConnectedControlAgentWs = async (conf, log) => {
281
+ return await Client.Create({
282
+ address: conf.control.mgmtAPIWsUrl,
283
+ port: conf.control.mgmtAPIWsPort,
284
+ appConfig: conf,
285
+ logger: log,
286
+ });
287
+ };
258
288
 
259
289
 
260
290
  module.exports = {
291
+ createConnectedControlAgentWs,
261
292
  Client,
262
293
  build,
263
294
  MESSAGE,
@@ -53,7 +53,7 @@ const { ReturnCodes } = Enum.Http;
53
53
  * Error handling logic shared by outbound API handlers
54
54
  */
55
55
  const handleError = (method, err, ctx, stateField) => {
56
- ctx.state.logger.push({ err, stateField }).error(`Error handling ${method}`);
56
+ ctx.state.logger.push({ stateField }).error(`Error handling ${method}: `, err);
57
57
  ctx.response.status = err.httpStatusCode || ReturnCodes.INTERNALSERVERERRROR.CODE;
58
58
  ctx.response.body = {
59
59
  message: err.message || 'Unspecified error',
@@ -88,6 +88,7 @@ module.exports = {
88
88
  mgmtAPIWsUrl: env.get('MGMT_API_WS_URL').default('127.0.0.1').asString(),
89
89
  mgmtAPIWsPort: env.get('MGMT_API_WS_PORT').default('4005').asPortNumber(),
90
90
  mgmtAPILatencyAssumption: env.get('MGMT_API_LATENCY_ASSUMPTION').default('2000').asIntPositive(),
91
+ mgmtAPIPollIntervalMs: env.get('MANAGEMENT_API_POLL_INTERVAL_MS').asIntPositive(), // undefined if not set (feature disabled)
91
92
  },
92
93
  idGenerator: env.get('ID_GENERATOR').default('{"type":"ulid"}').asJsonObject(),
93
94
  logLevel: env.get('LOG_LEVEL').default('info').asEnum(LOG_LEVELS),