signal-sdk 0.0.9 → 0.1.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 (44) hide show
  1. package/README.md +184 -61
  2. package/dist/MultiAccountManager.d.ts +149 -0
  3. package/dist/MultiAccountManager.js +320 -0
  4. package/dist/SignalBot.d.ts +1 -0
  5. package/dist/SignalBot.js +20 -2
  6. package/dist/SignalCli.d.ts +315 -16
  7. package/dist/SignalCli.js +880 -26
  8. package/dist/__tests__/MultiAccountManager.test.d.ts +4 -0
  9. package/dist/__tests__/MultiAccountManager.test.js +209 -0
  10. package/dist/__tests__/SignalBot.additional.test.d.ts +5 -0
  11. package/dist/__tests__/SignalBot.additional.test.js +353 -0
  12. package/dist/__tests__/SignalBot.test.js +5 -0
  13. package/dist/__tests__/SignalCli.advanced.test.d.ts +5 -0
  14. package/dist/__tests__/SignalCli.advanced.test.js +295 -0
  15. package/dist/__tests__/SignalCli.e2e.test.d.ts +5 -0
  16. package/dist/__tests__/SignalCli.e2e.test.js +240 -0
  17. package/dist/__tests__/SignalCli.integration.test.d.ts +5 -0
  18. package/dist/__tests__/SignalCli.integration.test.js +225 -0
  19. package/dist/__tests__/SignalCli.methods.test.d.ts +5 -0
  20. package/dist/__tests__/SignalCli.methods.test.js +556 -0
  21. package/dist/__tests__/SignalCli.parsing.test.d.ts +5 -0
  22. package/dist/__tests__/SignalCli.parsing.test.js +258 -0
  23. package/dist/__tests__/SignalCli.test.js +249 -13
  24. package/dist/__tests__/config.test.d.ts +5 -0
  25. package/dist/__tests__/config.test.js +252 -0
  26. package/dist/__tests__/errors.test.d.ts +5 -0
  27. package/dist/__tests__/errors.test.js +276 -0
  28. package/dist/__tests__/retry.test.d.ts +4 -0
  29. package/dist/__tests__/retry.test.js +123 -0
  30. package/dist/__tests__/validators.test.d.ts +4 -0
  31. package/dist/__tests__/validators.test.js +147 -0
  32. package/dist/config.d.ts +82 -0
  33. package/dist/config.js +116 -0
  34. package/dist/errors.d.ts +32 -0
  35. package/dist/errors.js +75 -0
  36. package/dist/index.d.ts +5 -0
  37. package/dist/index.js +7 -1
  38. package/dist/interfaces.d.ts +200 -10
  39. package/dist/interfaces.js +1 -1
  40. package/dist/retry.d.ts +56 -0
  41. package/dist/retry.js +152 -0
  42. package/dist/validators.d.ts +59 -0
  43. package/dist/validators.js +170 -0
  44. package/package.json +1 -1
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ /**
3
+ * Integration tests for SignalCli
4
+ * Tests complex scenarios and edge cases
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const SignalCli_1 = require("../SignalCli");
8
+ const child_process_1 = require("child_process");
9
+ jest.mock('child_process');
10
+ describe('SignalCli Integration Tests', () => {
11
+ let signalCli;
12
+ let mockProcess;
13
+ beforeEach(() => {
14
+ mockProcess = {
15
+ stdout: {
16
+ on: jest.fn(),
17
+ once: jest.fn(),
18
+ },
19
+ stderr: {
20
+ on: jest.fn(),
21
+ },
22
+ stdin: {
23
+ write: jest.fn(),
24
+ },
25
+ on: jest.fn(),
26
+ once: jest.fn(),
27
+ kill: jest.fn(),
28
+ killed: false,
29
+ };
30
+ const spawnMock = child_process_1.spawn;
31
+ spawnMock.mockReturnValue(mockProcess);
32
+ signalCli = new SignalCli_1.SignalCli('signal-cli', '+1234567890');
33
+ });
34
+ afterEach(() => {
35
+ if (signalCli) {
36
+ signalCli.disconnect();
37
+ // Clean up all listeners
38
+ signalCli.removeAllListeners();
39
+ }
40
+ // Clear all timers and mocks
41
+ jest.clearAllTimers();
42
+ jest.clearAllMocks();
43
+ });
44
+ describe('Connection Lifecycle', () => {
45
+ it('should handle multiple connect/disconnect cycles', async () => {
46
+ mockProcess.stdout.once.mockImplementation((event, callback) => {
47
+ if (event === 'data')
48
+ callback();
49
+ });
50
+ await signalCli.connect();
51
+ signalCli.disconnect();
52
+ await signalCli.connect();
53
+ signalCli.disconnect();
54
+ expect(mockProcess.kill).toHaveBeenCalledTimes(2);
55
+ });
56
+ it('should handle graceful shutdown timeout', async () => {
57
+ mockProcess.stdout.once.mockImplementation((event, callback) => {
58
+ if (event === 'data')
59
+ callback();
60
+ });
61
+ await signalCli.connect();
62
+ // Don't emit close event to simulate hanging process
63
+ let closeCallback;
64
+ mockProcess.once.mockImplementation((event, callback) => {
65
+ if (event === 'close') {
66
+ closeCallback = callback;
67
+ }
68
+ });
69
+ const shutdownPromise = signalCli.gracefulShutdown();
70
+ // Simulate timeout and force kill with unref to prevent hanging
71
+ const timer = setTimeout(() => {
72
+ if (closeCallback)
73
+ closeCallback(0);
74
+ }, 100);
75
+ if (timer.unref)
76
+ timer.unref();
77
+ await expect(shutdownPromise).resolves.toBeUndefined();
78
+ }, 10000); // Increase timeout to 10 seconds
79
+ it('should handle stderr data with different log levels', async () => {
80
+ const handleStderrData = signalCli.handleStderrData.bind(signalCli);
81
+ const errorHandler = jest.fn();
82
+ const logHandler = jest.fn();
83
+ signalCli.on('error', errorHandler);
84
+ signalCli.on('log', logHandler);
85
+ handleStderrData('ERROR Component - Critical error');
86
+ expect(errorHandler).toHaveBeenCalled();
87
+ handleStderrData('WARN Component - Warning message');
88
+ expect(logHandler).toHaveBeenCalledWith(expect.objectContaining({ level: 'warn' }));
89
+ handleStderrData('INFO Component - Info message');
90
+ expect(logHandler).toHaveBeenCalledWith(expect.objectContaining({ level: 'info' }));
91
+ handleStderrData('DEBUG Component - Debug message');
92
+ expect(logHandler).toHaveBeenCalledWith(expect.objectContaining({ level: 'debug' }));
93
+ });
94
+ it('should filter out informational WARN messages', async () => {
95
+ const handleStderrData = signalCli.handleStderrData.bind(signalCli);
96
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
97
+ handleStderrData('WARN Component - Failed to get sender certificate');
98
+ handleStderrData('WARN Component - ignoring: java.lang.InterruptedException');
99
+ handleStderrData('WARN Component - Request was interrupted');
100
+ expect(consoleSpy).not.toHaveBeenCalled();
101
+ handleStderrData('WARN Component - Real warning message');
102
+ expect(consoleSpy).toHaveBeenCalled();
103
+ consoleSpy.mockRestore();
104
+ });
105
+ });
106
+ describe('JSON-RPC Response Handling', () => {
107
+ it('should handle multi-line JSON-RPC responses', () => {
108
+ const handleRpcResponse = signalCli.handleRpcResponse.bind(signalCli);
109
+ const mockPromise = {
110
+ resolve: jest.fn(),
111
+ reject: jest.fn(),
112
+ };
113
+ signalCli.requestPromises.set('test-id', mockPromise);
114
+ const multiLineData = `{"jsonrpc":"2.0","id":"test-id","result":{"success":true}}\n{"jsonrpc":"2.0","method":"receive","params":{"data":"test"}}`;
115
+ handleRpcResponse(multiLineData);
116
+ expect(mockPromise.resolve).toHaveBeenCalledWith({ success: true });
117
+ });
118
+ it('should handle malformed JSON gracefully', () => {
119
+ const handleRpcResponse = signalCli.handleRpcResponse.bind(signalCli);
120
+ const errorHandler = jest.fn();
121
+ signalCli.on('error', errorHandler);
122
+ handleRpcResponse('not valid json');
123
+ expect(errorHandler).toHaveBeenCalledWith(expect.objectContaining({
124
+ message: expect.stringContaining('Failed to parse JSON-RPC response')
125
+ }));
126
+ });
127
+ it('should emit notifications correctly', () => {
128
+ const handleRpcResponse = signalCli.handleRpcResponse.bind(signalCli);
129
+ const notificationHandler = jest.fn();
130
+ const messageHandler = jest.fn();
131
+ signalCli.on('notification', notificationHandler);
132
+ signalCli.on('message', messageHandler);
133
+ const notification = '{"jsonrpc":"2.0","method":"receive","params":{"envelope":{"dataMessage":"test"}}}';
134
+ handleRpcResponse(notification);
135
+ expect(notificationHandler).toHaveBeenCalled();
136
+ expect(messageHandler).toHaveBeenCalled();
137
+ });
138
+ });
139
+ describe('Validation Edge Cases', () => {
140
+ it('should validate recipients (phone, UUID, username)', async () => {
141
+ // Connect first
142
+ mockProcess.stdout.once.mockImplementation((event, callback) => {
143
+ if (event === 'data')
144
+ callback();
145
+ });
146
+ await signalCli.connect();
147
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
148
+ // Valid phone
149
+ await expect(signalCli.sendMessage('+1234567890', 'test')).resolves.toBeDefined();
150
+ // Valid UUID
151
+ await expect(signalCli.sendMessage('12345678-1234-1234-1234-123456789012', 'test')).resolves.toBeDefined();
152
+ // Valid username
153
+ await expect(signalCli.sendMessage('u:username.123', 'test')).resolves.toBeDefined();
154
+ });
155
+ });
156
+ describe('Group Detection', () => {
157
+ it('should correctly identify group IDs', () => {
158
+ const isGroupId = signalCli.isGroupId.bind(signalCli);
159
+ expect(isGroupId('base64groupid==')).toBe(true);
160
+ expect(isGroupId('group/with/slash')).toBe(true);
161
+ expect(isGroupId('multiple+signs+notphone')).toBe(true);
162
+ expect(isGroupId('+1234567890')).toBe(false);
163
+ });
164
+ });
165
+ describe('Deprecated Methods', () => {
166
+ it('should warn about deprecated receiveMessages', async () => {
167
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
168
+ await signalCli.receiveMessages();
169
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('deprecated'));
170
+ consoleSpy.mockRestore();
171
+ });
172
+ it('should warn about deprecated startDaemon', async () => {
173
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
174
+ mockProcess.stdout.once.mockImplementation((event, callback) => {
175
+ if (event === 'data')
176
+ callback();
177
+ });
178
+ await signalCli.startDaemon();
179
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('deprecated'));
180
+ consoleSpy.mockRestore();
181
+ });
182
+ it('should warn about deprecated stopDaemon', () => {
183
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation();
184
+ signalCli.stopDaemon();
185
+ expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('deprecated'));
186
+ consoleSpy.mockRestore();
187
+ });
188
+ });
189
+ describe('Complex Scenarios', () => {
190
+ beforeEach(() => {
191
+ jest.spyOn(signalCli, 'sendJsonRpcRequest').mockResolvedValue({});
192
+ });
193
+ it('should handle group message with options', async () => {
194
+ const sendJsonRpcRequestSpy = jest.spyOn(signalCli, 'sendJsonRpcRequest')
195
+ .mockResolvedValue({ results: [{ type: 'SUCCESS' }], timestamp: 123456 });
196
+ await signalCli.sendMessage('groupId==', 'Group message', {
197
+ mentions: [{ start: 0, length: 4, number: '+1111111111' }]
198
+ });
199
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalled();
200
+ expect(sendJsonRpcRequestSpy).toHaveBeenCalledWith('send', expect.objectContaining({
201
+ message: 'Group message',
202
+ groupId: 'groupId=='
203
+ }));
204
+ });
205
+ });
206
+ describe('Error Handling', () => {
207
+ it('should reject when not connected', async () => {
208
+ const disconnectedSignal = new SignalCli_1.SignalCli('signal-cli', '+1234567890');
209
+ await expect(disconnectedSignal.sendMessage('+0987654321', 'test')).rejects.toThrow('Not connected');
210
+ });
211
+ it('should handle JSON-RPC errors correctly', () => {
212
+ const handleRpcResponse = signalCli.handleRpcResponse.bind(signalCli);
213
+ const mockPromise = {
214
+ resolve: jest.fn(),
215
+ reject: jest.fn(),
216
+ };
217
+ signalCli.requestPromises.set('error-id', mockPromise);
218
+ const errorResponse = '{"jsonrpc":"2.0","id":"error-id","error":{"code":-32600,"message":"Invalid Request"}}';
219
+ handleRpcResponse(errorResponse);
220
+ expect(mockPromise.reject).toHaveBeenCalledWith(expect.objectContaining({
221
+ message: expect.stringContaining('Invalid Request')
222
+ }));
223
+ });
224
+ });
225
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for SignalCli methods
3
+ * Covers additional methods not tested in SignalCli.test.ts
4
+ */
5
+ export {};