@mojaloop/sdk-scheme-adapter 24.14.0 → 24.15.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/CHANGELOG.md +20 -0
- package/CLAUDE.md +2 -0
- package/README.md +17 -0
- package/modules/api-svc/src/InboundServer/handlers.js +1 -1
- package/modules/api-svc/src/SdkServer.js +560 -0
- package/modules/api-svc/src/config.js +4 -0
- package/modules/api-svc/src/index.js +8 -529
- package/modules/api-svc/src/lib/model/OutboundTransfersModel.js +2 -1
- package/modules/api-svc/src/lib/utils.js +27 -3
- package/modules/api-svc/test/unit/{index.configPolling.test.js → SdkServer.configPolling.test.js} +11 -11
- package/modules/api-svc/test/unit/lib/utils.test.js +71 -1
- package/package.json +1 -1
- package/{sbom-v24.13.0.csv → sbom-v24.15.0.csv} +37 -37
package/modules/api-svc/test/unit/{index.configPolling.test.js → SdkServer.configPolling.test.js}
RENAMED
|
@@ -35,8 +35,8 @@ jest.mock('~/lib/cache');
|
|
|
35
35
|
jest.mock('~/ControlAgent');
|
|
36
36
|
|
|
37
37
|
const promClient = require('prom-client');
|
|
38
|
+
const SdkServer = require('../../src/SdkServer');
|
|
38
39
|
const ControlAgent = require('~/ControlAgent');
|
|
39
|
-
const { Server } = require('~/index');
|
|
40
40
|
const { logger } = require('~/lib/logger');
|
|
41
41
|
const testConfig = require('./data/defaultConfig.json');
|
|
42
42
|
|
|
@@ -92,7 +92,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
92
92
|
}
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
-
server = new
|
|
95
|
+
server = new SdkServer(config, logger);
|
|
96
96
|
await server.start();
|
|
97
97
|
|
|
98
98
|
await jest.advanceTimersByTimeAsync(POLL_INTERVAL_MS * 2);
|
|
@@ -105,7 +105,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
105
105
|
pm4mlEnabled: false,
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
-
server = new
|
|
108
|
+
server = new SdkServer(config, logger);
|
|
109
109
|
await server.start();
|
|
110
110
|
|
|
111
111
|
await jest.advanceTimersByTimeAsync(POLL_INTERVAL_MS * 2);
|
|
@@ -113,7 +113,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
it('should poll at configured interval', async () => {
|
|
116
|
-
server = new
|
|
116
|
+
server = new SdkServer(mockConfig, logger);
|
|
117
117
|
await server.start();
|
|
118
118
|
expect(mockControlAgent.getUpdatedConfig).toHaveBeenCalledTimes(0);
|
|
119
119
|
|
|
@@ -130,7 +130,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
130
130
|
jwsSigningKey: newJwsKey
|
|
131
131
|
});
|
|
132
132
|
|
|
133
|
-
server = new
|
|
133
|
+
server = new SdkServer(mockConfig, logger);
|
|
134
134
|
const restartSpy = jest.spyOn(server, 'restart');
|
|
135
135
|
|
|
136
136
|
await server.start();
|
|
@@ -150,7 +150,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
150
150
|
it('should handle unchanged config efficiently (no-op)', async () => {
|
|
151
151
|
mockControlAgent.getUpdatedConfig.mockResolvedValue({});
|
|
152
152
|
|
|
153
|
-
server = new
|
|
153
|
+
server = new SdkServer(mockConfig, logger);
|
|
154
154
|
const restartSpy = jest.spyOn(server, 'restart');
|
|
155
155
|
await server.start();
|
|
156
156
|
|
|
@@ -165,7 +165,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
165
165
|
it('should prevent race condition when update already in progress', async () => {
|
|
166
166
|
mockControlAgent.getUpdatedConfig.mockResolvedValue({ jwsSigningKey: 'new-key' });
|
|
167
167
|
|
|
168
|
-
server = new
|
|
168
|
+
server = new SdkServer(mockConfig, logger);
|
|
169
169
|
await server.start();
|
|
170
170
|
// Simulate restart in progress
|
|
171
171
|
server._configUpdateInProgress = true;
|
|
@@ -176,7 +176,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
it('should skip polling when WebSocket not OPEN', async () => {
|
|
179
|
-
server = new
|
|
179
|
+
server = new SdkServer(mockConfig, logger);
|
|
180
180
|
await server.start();
|
|
181
181
|
|
|
182
182
|
mockControlAgent.getUpdatedConfig.mockClear();
|
|
@@ -190,7 +190,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
190
190
|
it('should handle network errors gracefully during polling', async () => {
|
|
191
191
|
mockControlAgent.getUpdatedConfig.mockRejectedValue(new Error('Connection refused'));
|
|
192
192
|
|
|
193
|
-
server = new
|
|
193
|
+
server = new SdkServer(mockConfig, logger);
|
|
194
194
|
await server.start();
|
|
195
195
|
await jest.advanceTimersByTimeAsync(POLL_INTERVAL_MS);
|
|
196
196
|
|
|
@@ -204,7 +204,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
204
204
|
it('should handle missing config response', async () => {
|
|
205
205
|
mockControlAgent.getUpdatedConfig.mockResolvedValue(null);
|
|
206
206
|
|
|
207
|
-
server = new
|
|
207
|
+
server = new SdkServer(mockConfig, logger);
|
|
208
208
|
await server.start();
|
|
209
209
|
await jest.advanceTimersByTimeAsync(POLL_INTERVAL_MS);
|
|
210
210
|
|
|
@@ -214,7 +214,7 @@ describe('Config Polling Tests -->', () => {
|
|
|
214
214
|
});
|
|
215
215
|
|
|
216
216
|
it('should stop polling when server stops', async () => {
|
|
217
|
-
server = new
|
|
217
|
+
server = new SdkServer(mockConfig, logger);
|
|
218
218
|
await server.start();
|
|
219
219
|
|
|
220
220
|
expect(server._configPollInterval).toBeDefined();
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
--------------
|
|
26
26
|
******/
|
|
27
|
-
const { transformHeadersIsoToFspiop } = require('~/lib/utils');
|
|
27
|
+
const { transformHeadersIsoToFspiop, generateTraceparent, isValidTraceFlags } = require('~/lib/utils');
|
|
28
28
|
|
|
29
29
|
describe('utils', () => {
|
|
30
30
|
describe('transformHeadersIsoToFspiop', () => {
|
|
@@ -42,4 +42,74 @@ describe('utils', () => {
|
|
|
42
42
|
expect(transformHeadersIsoToFspiop(isoHeaders)).toEqual(fspiopHeaders);
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
|
+
|
|
46
|
+
describe('isValidTraceFlags', () => {
|
|
47
|
+
it('should validate correct hex strings', () => {
|
|
48
|
+
expect(isValidTraceFlags('00')).toBe(true);
|
|
49
|
+
expect(isValidTraceFlags('01')).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should reject invalid strings', () => {
|
|
53
|
+
expect(isValidTraceFlags('0')).toBe(false); // Too short
|
|
54
|
+
expect(isValidTraceFlags('000')).toBe(false); // Too long
|
|
55
|
+
expect(isValidTraceFlags('zz')).toBe(false); // Invalid hex
|
|
56
|
+
expect(isValidTraceFlags('')).toBe(false); // Empty string
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should reject non-string inputs', () => {
|
|
60
|
+
expect(isValidTraceFlags(null)).toBe(false);
|
|
61
|
+
expect(isValidTraceFlags(undefined)).toBe(false);
|
|
62
|
+
expect(isValidTraceFlags(1)).toBe(false);
|
|
63
|
+
expect(isValidTraceFlags({})).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('generateTraceparent', () => {
|
|
68
|
+
describe('default behavior', () => {
|
|
69
|
+
it('should generate valid traceparent with default flags (01)', () => {
|
|
70
|
+
const traceparent = generateTraceparent();
|
|
71
|
+
const parts = traceparent.split('-');
|
|
72
|
+
|
|
73
|
+
expect(parts).toHaveLength(4);
|
|
74
|
+
expect(parts[0]).toBe('00'); // version
|
|
75
|
+
expect(parts[1]).toHaveLength(32); // traceId (16 bytes = 32 hex chars)
|
|
76
|
+
expect(parts[2]).toHaveLength(16); // spanId (8 bytes = 16 hex chars)
|
|
77
|
+
expect(parts[3]).toBe('01'); // default flags
|
|
78
|
+
|
|
79
|
+
// Validate hex format
|
|
80
|
+
expect(/^[0-9a-f]{32}$/.test(parts[1])).toBe(true);
|
|
81
|
+
expect(/^[0-9a-f]{16}$/.test(parts[2])).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should use provided traceId', () => {
|
|
85
|
+
const traceId = '1234567890abcdef1234567890abcdef';
|
|
86
|
+
const traceparent = generateTraceparent(traceId);
|
|
87
|
+
const parts = traceparent.split('-');
|
|
88
|
+
|
|
89
|
+
expect(parts[1]).toBe(traceId);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('custom trace flags', () => {
|
|
94
|
+
it('should use custom trace flags when provided', () => {
|
|
95
|
+
const traceparent = generateTraceparent(undefined, '00');
|
|
96
|
+
expect(traceparent.split('-')[3]).toBe('00');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should accept uppercase hex and convert to lowercase', () => {
|
|
100
|
+
const traceparent = generateTraceparent(undefined, 'FF');
|
|
101
|
+
expect(traceparent.split('-')[3]).toBe('ff');
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('validation', () => {
|
|
106
|
+
it('should throw error for invalid trace flags', () => {
|
|
107
|
+
expect(() => generateTraceparent(undefined, '0')).toThrow();
|
|
108
|
+
expect(() => generateTraceparent(undefined, '000')).toThrow();
|
|
109
|
+
expect(() => generateTraceparent(undefined, 'zz')).toThrow();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
});
|
|
45
115
|
});
|