signal-sdk 0.0.8 → 0.1.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.
Files changed (36) hide show
  1. package/README.md +175 -59
  2. package/dist/SignalBot.d.ts +108 -0
  3. package/dist/SignalBot.js +811 -0
  4. package/dist/SignalCli.d.ts +205 -0
  5. package/dist/SignalCli.js +967 -0
  6. package/dist/__tests__/SignalBot.additional.test.d.ts +5 -0
  7. package/dist/__tests__/SignalBot.additional.test.js +333 -0
  8. package/dist/__tests__/SignalBot.test.d.ts +1 -0
  9. package/dist/__tests__/SignalBot.test.js +102 -0
  10. package/dist/__tests__/SignalCli.integration.test.d.ts +5 -0
  11. package/dist/__tests__/SignalCli.integration.test.js +218 -0
  12. package/dist/__tests__/SignalCli.methods.test.d.ts +5 -0
  13. package/dist/__tests__/SignalCli.methods.test.js +470 -0
  14. package/dist/__tests__/SignalCli.test.d.ts +1 -0
  15. package/dist/__tests__/SignalCli.test.js +479 -0
  16. package/dist/__tests__/config.test.d.ts +5 -0
  17. package/dist/__tests__/config.test.js +252 -0
  18. package/dist/__tests__/errors.test.d.ts +5 -0
  19. package/dist/__tests__/errors.test.js +276 -0
  20. package/dist/__tests__/retry.test.d.ts +4 -0
  21. package/dist/__tests__/retry.test.js +123 -0
  22. package/dist/__tests__/validators.test.d.ts +4 -0
  23. package/dist/__tests__/validators.test.js +147 -0
  24. package/dist/config.d.ts +67 -0
  25. package/dist/config.js +111 -0
  26. package/dist/errors.d.ts +32 -0
  27. package/dist/errors.js +75 -0
  28. package/dist/index.d.ts +7 -0
  29. package/dist/index.js +26 -0
  30. package/dist/interfaces.d.ts +1073 -0
  31. package/dist/interfaces.js +11 -0
  32. package/dist/retry.d.ts +56 -0
  33. package/dist/retry.js +135 -0
  34. package/dist/validators.d.ts +59 -0
  35. package/dist/validators.js +170 -0
  36. package/package.json +5 -6
@@ -0,0 +1,479 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const SignalCli_1 = require("../SignalCli");
4
+ const child_process_1 = require("child_process");
5
+ jest.mock('child_process');
6
+ describe('SignalCli', () => {
7
+ let signalCli;
8
+ let mockProcess;
9
+ beforeEach(() => {
10
+ mockProcess = {
11
+ stdout: {
12
+ on: jest.fn(),
13
+ once: jest.fn(),
14
+ },
15
+ stderr: {
16
+ on: jest.fn(),
17
+ },
18
+ stdin: {
19
+ write: jest.fn(),
20
+ },
21
+ on: jest.fn(),
22
+ once: jest.fn(),
23
+ kill: jest.fn(),
24
+ };
25
+ const spawnMock = child_process_1.spawn;
26
+ spawnMock.mockReturnValue(mockProcess);
27
+ signalCli = new SignalCli_1.SignalCli('signal-cli', '+1234567890');
28
+ });
29
+ it('should be defined', () => {
30
+ expect(SignalCli_1.SignalCli).toBeDefined();
31
+ });
32
+ it('should connect to JSON-RPC mode', async () => {
33
+ // Mock the stdout data event to resolve connect
34
+ mockProcess.stdout.once.mockImplementation((event, callback) => {
35
+ if (event === 'data') {
36
+ callback();
37
+ }
38
+ });
39
+ await signalCli.connect();
40
+ // On Windows, spawn may use cmd.exe /c, so we check the arguments more flexibly
41
+ const spawnCalls = child_process_1.spawn.mock.calls;
42
+ expect(spawnCalls).toHaveLength(1);
43
+ const [command, args] = spawnCalls[0];
44
+ if (process.platform === 'win32') {
45
+ // On Windows, expect cmd.exe with /c and the actual command
46
+ expect(command).toBe('cmd.exe');
47
+ expect(args).toEqual(['/c', 'signal-cli', '-a', '+1234567890', 'jsonRpc']);
48
+ }
49
+ else {
50
+ // On Unix-like systems, expect direct command
51
+ expect(command).toBe('signal-cli');
52
+ expect(args).toEqual(['-a', '+1234567890', 'jsonRpc']);
53
+ }
54
+ });
55
+ it('should send JSON-RPC request for sendMessage', async () => {
56
+ // Mock sendJsonRpcRequest directly
57
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
58
+ .mockResolvedValue({ results: [{ type: 'SUCCESS' }], timestamp: 123456 });
59
+ await signalCli.sendMessage('+10987654321', 'Hello, world!');
60
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('send', {
61
+ message: 'Hello, world!',
62
+ account: '+1234567890',
63
+ recipients: ['+10987654321'],
64
+ });
65
+ });
66
+ it('should disconnect properly', async () => {
67
+ // Connect first
68
+ mockProcess.stdout.once.mockImplementation((event, callback) => {
69
+ if (event === 'data') {
70
+ setTimeout(callback, 0);
71
+ }
72
+ });
73
+ await signalCli.connect();
74
+ // Now disconnect
75
+ signalCli.disconnect();
76
+ expect(mockProcess.kill).toHaveBeenCalled();
77
+ });
78
+ // Test new features
79
+ describe('New Features', () => {
80
+ beforeEach(() => {
81
+ // Mock sendJsonRpcRequest for all tests
82
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
83
+ });
84
+ it('should remove contact', async () => {
85
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
86
+ .mockResolvedValue({});
87
+ await signalCli.removeContact('+1234567890', { forget: true });
88
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('removeContact', {
89
+ account: '+1234567890',
90
+ recipient: '+1234567890',
91
+ forget: true
92
+ });
93
+ });
94
+ it('should get user status', async () => {
95
+ const mockResponse = {
96
+ recipients: [
97
+ { number: '+1234567890', isRegistered: true, uuid: 'test-uuid' }
98
+ ]
99
+ };
100
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
101
+ .mockResolvedValue(mockResponse);
102
+ const result = await signalCli.getUserStatus(['+1234567890']);
103
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getUserStatus', {
104
+ account: '+1234567890',
105
+ recipients: ['+1234567890']
106
+ });
107
+ expect(result).toEqual([
108
+ { number: '+1234567890', isRegistered: true, uuid: 'test-uuid', username: undefined }
109
+ ]);
110
+ });
111
+ it('should send payment notification', async () => {
112
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
113
+ .mockResolvedValue({ timestamp: 123456 });
114
+ await signalCli.sendPaymentNotification('+1234567890', {
115
+ receipt: 'base64-receipt',
116
+ note: 'Payment for coffee'
117
+ });
118
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPaymentNotification', {
119
+ account: '+1234567890',
120
+ recipient: '+1234567890',
121
+ receipt: 'base64-receipt',
122
+ note: 'Payment for coffee'
123
+ });
124
+ });
125
+ it('should upload sticker pack', async () => {
126
+ const mockResponse = {
127
+ packId: 'pack-id',
128
+ packKey: 'pack-key',
129
+ installUrl: 'https://signal.org/stickers/pack-id'
130
+ };
131
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
132
+ .mockResolvedValue(mockResponse);
133
+ const result = await signalCli.uploadStickerPack({
134
+ path: '/path/to/manifest.json'
135
+ });
136
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('uploadStickerPack', {
137
+ account: '+1234567890',
138
+ path: '/path/to/manifest.json'
139
+ });
140
+ expect(result).toEqual(mockResponse);
141
+ });
142
+ it('should submit rate limit challenge', async () => {
143
+ const mockResponse = {
144
+ success: true,
145
+ message: 'Challenge accepted'
146
+ };
147
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
148
+ .mockResolvedValue(mockResponse);
149
+ const result = await signalCli.submitRateLimitChallenge('challenge-token', 'captcha-token');
150
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('submitRateLimitChallenge', {
151
+ account: '+1234567890',
152
+ challenge: 'challenge-token',
153
+ captcha: 'captcha-token'
154
+ });
155
+ expect(result).toEqual(mockResponse);
156
+ });
157
+ it('should start change number', async () => {
158
+ const mockResponse = {
159
+ session: 'change-session-id',
160
+ challenge: 'challenge-token'
161
+ };
162
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
163
+ .mockResolvedValue(mockResponse);
164
+ const result = await signalCli.startChangeNumber('+1987654321');
165
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('startChangeNumber', {
166
+ account: '+1234567890',
167
+ number: '+1987654321',
168
+ voice: false
169
+ });
170
+ expect(result).toEqual({
171
+ session: 'change-session-id',
172
+ newNumber: '+1987654321',
173
+ challenge: 'challenge-token'
174
+ });
175
+ });
176
+ it('should finish change number', async () => {
177
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
178
+ .mockResolvedValue({});
179
+ await signalCli.finishChangeNumber('123456', 'pin-code');
180
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('finishChangeNumber', {
181
+ account: '+1234567890',
182
+ code: '123456',
183
+ pin: 'pin-code'
184
+ });
185
+ });
186
+ });
187
+ // Test cross-platform path detection
188
+ describe('Cross-platform compatibility', () => {
189
+ it('should use correct executable path based on platform', () => {
190
+ // Test Windows path
191
+ const originalPlatform = process.platform;
192
+ // Mock Windows
193
+ Object.defineProperty(process, 'platform', { value: 'win32' });
194
+ const windowsSignal = new SignalCli_1.SignalCli('+1234567890');
195
+ expect(windowsSignal.signalCliPath).toContain('signal-cli.bat');
196
+ // Mock Linux
197
+ Object.defineProperty(process, 'platform', { value: 'linux' });
198
+ const linuxSignal = new SignalCli_1.SignalCli('+1234567890');
199
+ expect(linuxSignal.signalCliPath).toContain('signal-cli');
200
+ expect(linuxSignal.signalCliPath).not.toContain('.bat');
201
+ // Mock macOS
202
+ Object.defineProperty(process, 'platform', { value: 'darwin' });
203
+ const macSignal = new SignalCli_1.SignalCli('+1234567890');
204
+ expect(macSignal.signalCliPath).toContain('signal-cli');
205
+ expect(macSignal.signalCliPath).not.toContain('.bat');
206
+ // Restore original platform
207
+ Object.defineProperty(process, 'platform', { value: originalPlatform });
208
+ });
209
+ it('should spawn correct command based on platform', async () => {
210
+ const originalPlatform = process.platform;
211
+ // Test Windows spawning
212
+ Object.defineProperty(process, 'platform', { value: 'win32' });
213
+ const windowsSignal = new SignalCli_1.SignalCli('test-path.bat', '+1234567890');
214
+ mockProcess.stdout.once.mockImplementation((event, callback) => {
215
+ if (event === 'data')
216
+ callback();
217
+ });
218
+ await windowsSignal.connect();
219
+ const windowsCalls = child_process_1.spawn.mock.calls;
220
+ const lastCall = windowsCalls[windowsCalls.length - 1];
221
+ expect(lastCall[0]).toBe('cmd.exe');
222
+ expect(lastCall[1]).toEqual(['/c', '"test-path.bat"', '-a', '+1234567890', 'jsonRpc']);
223
+ // Test Unix spawning
224
+ Object.defineProperty(process, 'platform', { value: 'linux' });
225
+ const linuxSignal = new SignalCli_1.SignalCli('test-path', '+1234567890');
226
+ await linuxSignal.connect();
227
+ const linuxCalls = child_process_1.spawn.mock.calls;
228
+ const lastLinuxCall = linuxCalls[linuxCalls.length - 1];
229
+ expect(lastLinuxCall[0]).toBe('test-path');
230
+ expect(lastLinuxCall[1]).toEqual(['-a', '+1234567890', 'jsonRpc']);
231
+ // Restore original platform
232
+ Object.defineProperty(process, 'platform', { value: originalPlatform });
233
+ });
234
+ });
235
+ // Test v0.1.0 features: Polls
236
+ describe('Poll Management', () => {
237
+ beforeEach(() => {
238
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
239
+ });
240
+ it('should create a poll', async () => {
241
+ const mockResponse = { timestamp: 123456789 };
242
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
243
+ .mockResolvedValue(mockResponse);
244
+ const result = await signalCli.sendPollCreate({
245
+ recipients: ['+1234567890'],
246
+ question: 'What is your favorite color?',
247
+ options: ['Red', 'Blue', 'Green']
248
+ });
249
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollCreate', {
250
+ account: '+1234567890',
251
+ recipients: ['+1234567890'],
252
+ question: 'What is your favorite color?',
253
+ options: ['Red', 'Blue', 'Green']
254
+ });
255
+ expect(result).toEqual(mockResponse);
256
+ });
257
+ it('should create a group poll', async () => {
258
+ const mockResponse = { timestamp: 123456789 };
259
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
260
+ .mockResolvedValue(mockResponse);
261
+ const result = await signalCli.sendPollCreate({
262
+ groupId: 'group-123',
263
+ question: 'Best meeting time?',
264
+ options: ['9 AM', '2 PM', '4 PM']
265
+ });
266
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollCreate', {
267
+ account: '+1234567890',
268
+ groupId: 'group-123',
269
+ question: 'Best meeting time?',
270
+ options: ['9 AM', '2 PM', '4 PM']
271
+ });
272
+ expect(result).toEqual(mockResponse);
273
+ });
274
+ it('should vote on a poll', async () => {
275
+ const mockResponse = { timestamp: 123456790 };
276
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
277
+ .mockResolvedValue(mockResponse);
278
+ const result = await signalCli.sendPollVote('+1234567890', {
279
+ pollAuthor: '+9876543210',
280
+ pollTimestamp: 123456789,
281
+ optionIndexes: [0, 1]
282
+ });
283
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollVote', {
284
+ account: '+1234567890',
285
+ recipient: '+1234567890',
286
+ pollAuthor: '+9876543210',
287
+ pollTimestamp: 123456789,
288
+ options: [0, 1]
289
+ });
290
+ expect(result).toEqual(mockResponse);
291
+ });
292
+ it('should terminate a poll', async () => {
293
+ const mockResponse = { timestamp: 123456791 };
294
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
295
+ .mockResolvedValue(mockResponse);
296
+ const result = await signalCli.sendPollTerminate('+1234567890', {
297
+ pollTimestamp: 123456789
298
+ });
299
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendPollTerminate', {
300
+ account: '+1234567890',
301
+ recipient: '+1234567890',
302
+ pollTimestamp: 123456789
303
+ });
304
+ expect(result).toEqual(mockResponse);
305
+ });
306
+ });
307
+ // Test v0.1.0 features: Attachment Retrieval
308
+ describe('Attachment Retrieval', () => {
309
+ beforeEach(() => {
310
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
311
+ });
312
+ it('should get attachment by ID', async () => {
313
+ const mockBase64 = 'base64-encoded-data';
314
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
315
+ .mockResolvedValue(mockBase64);
316
+ const result = await signalCli.getAttachment({
317
+ id: 'attachment-123'
318
+ });
319
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAttachment', {
320
+ account: '+1234567890',
321
+ id: 'attachment-123'
322
+ });
323
+ expect(result).toBe(mockBase64);
324
+ });
325
+ it('should get contact avatar', async () => {
326
+ const mockBase64 = 'base64-avatar-data';
327
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
328
+ .mockResolvedValue(mockBase64);
329
+ const result = await signalCli.getAvatar({
330
+ contact: '+9876543210'
331
+ });
332
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
333
+ account: '+1234567890',
334
+ contact: '+9876543210'
335
+ });
336
+ expect(result).toBe(mockBase64);
337
+ });
338
+ it('should get profile avatar', async () => {
339
+ const mockBase64 = 'base64-profile-avatar';
340
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
341
+ .mockResolvedValue(mockBase64);
342
+ const result = await signalCli.getAvatar({
343
+ profile: '+1234567890'
344
+ });
345
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
346
+ account: '+1234567890',
347
+ profile: '+1234567890'
348
+ });
349
+ expect(result).toBe(mockBase64);
350
+ });
351
+ it('should get group avatar', async () => {
352
+ const mockBase64 = 'base64-group-avatar';
353
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
354
+ .mockResolvedValue(mockBase64);
355
+ const result = await signalCli.getAvatar({
356
+ groupId: 'group-123'
357
+ });
358
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getAvatar', {
359
+ account: '+1234567890',
360
+ groupId: 'group-123'
361
+ });
362
+ expect(result).toBe(mockBase64);
363
+ });
364
+ it('should get sticker data', async () => {
365
+ const mockBase64 = 'base64-sticker-data';
366
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
367
+ .mockResolvedValue(mockBase64);
368
+ const result = await signalCli.getSticker({
369
+ packId: 'pack-123',
370
+ stickerId: 5
371
+ });
372
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('getSticker', {
373
+ account: '+1234567890',
374
+ packId: 'pack-123',
375
+ stickerId: 5
376
+ });
377
+ expect(result).toBe(mockBase64);
378
+ });
379
+ });
380
+ // Test v0.1.0 features: Account Management
381
+ describe('Account Management', () => {
382
+ beforeEach(() => {
383
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
384
+ });
385
+ it('should update account settings', async () => {
386
+ const mockResponse = {
387
+ username: 'myusername',
388
+ usernameLink: 'https://signal.me/#myusername'
389
+ };
390
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
391
+ .mockResolvedValue(mockResponse);
392
+ const result = await signalCli.updateAccount({
393
+ deviceName: 'My Device',
394
+ username: 'myusername'
395
+ });
396
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('updateAccount', {
397
+ account: '+1234567890',
398
+ deviceName: 'My Device',
399
+ username: 'myusername'
400
+ });
401
+ expect(result.success).toBe(true);
402
+ expect(result.username).toBe('myusername');
403
+ });
404
+ it('should list accounts with details', async () => {
405
+ const mockResponse = {
406
+ accounts: [
407
+ { number: '+1234567890', name: 'Account 1', uuid: 'uuid-1' },
408
+ { number: '+9876543210', name: 'Account 2', uuid: 'uuid-2' }
409
+ ]
410
+ };
411
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
412
+ .mockResolvedValue(mockResponse);
413
+ const result = await signalCli.listAccountsDetailed();
414
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listAccounts');
415
+ expect(result).toEqual(mockResponse.accounts);
416
+ });
417
+ });
418
+ // Test v0.1.0 features: Synchronization
419
+ describe('Synchronization', () => {
420
+ beforeEach(() => {
421
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
422
+ });
423
+ it('should send contacts to linked devices', async () => {
424
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
425
+ .mockResolvedValue({});
426
+ await signalCli.sendContacts();
427
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('sendContacts', {
428
+ account: '+1234567890'
429
+ });
430
+ });
431
+ it('should list groups with detailed information', async () => {
432
+ const mockGroups = [
433
+ {
434
+ id: 'group-1',
435
+ name: 'Test Group 1',
436
+ members: ['+1111111111', '+2222222222'],
437
+ groupType: 'GROUP_V2'
438
+ },
439
+ {
440
+ id: 'group-2',
441
+ name: 'Test Group 2',
442
+ members: ['+3333333333'],
443
+ groupType: 'GROUP_V2'
444
+ }
445
+ ];
446
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
447
+ .mockResolvedValue(mockGroups);
448
+ const result = await signalCli.listGroupsDetailed({
449
+ detailed: true
450
+ });
451
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listGroups', {
452
+ account: '+1234567890',
453
+ detailed: true
454
+ });
455
+ expect(result).toEqual(mockGroups);
456
+ });
457
+ it('should filter groups by ID', async () => {
458
+ const mockGroups = [
459
+ {
460
+ id: 'group-1',
461
+ name: 'Specific Group',
462
+ members: ['+1111111111']
463
+ }
464
+ ];
465
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
466
+ .mockResolvedValue(mockGroups);
467
+ const result = await signalCli.listGroupsDetailed({
468
+ groupIds: ['group-1'],
469
+ detailed: true
470
+ });
471
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('listGroups', {
472
+ account: '+1234567890',
473
+ detailed: true,
474
+ groupId: ['group-1']
475
+ });
476
+ expect(result).toEqual(mockGroups);
477
+ });
478
+ });
479
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Additional tests for config.ts
3
+ * Tests configuration validation and logger functionality
4
+ */
5
+ export {};