signal-sdk 0.0.8 → 0.0.9

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.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const SignalBot_1 = require("../SignalBot");
4
+ describe('SignalBot', () => {
5
+ let bot;
6
+ let mockConfig;
7
+ beforeEach(() => {
8
+ mockConfig = {
9
+ phoneNumber: '+1234567890',
10
+ admins: ['+0987654321'],
11
+ group: {
12
+ name: 'Test Bot Group',
13
+ createIfNotExists: false
14
+ }
15
+ };
16
+ });
17
+ afterEach(async () => {
18
+ if (bot) {
19
+ await bot.stop();
20
+ }
21
+ });
22
+ test('should create bot with minimal config', () => {
23
+ bot = new SignalBot_1.SignalBot({
24
+ phoneNumber: '+1234567890'
25
+ });
26
+ expect(bot).toBeDefined();
27
+ expect(bot.isAdmin('+1234567890')).toBe(false);
28
+ });
29
+ test('should create bot with full config', () => {
30
+ bot = new SignalBot_1.SignalBot(mockConfig);
31
+ expect(bot).toBeDefined();
32
+ expect(bot.isAdmin('+0987654321')).toBe(true);
33
+ expect(bot.getBotGroupId()).toBeNull();
34
+ });
35
+ test('should add and remove commands', () => {
36
+ bot = new SignalBot_1.SignalBot(mockConfig);
37
+ const testCommand = {
38
+ name: 'test',
39
+ description: 'Test command',
40
+ handler: jest.fn()
41
+ };
42
+ bot.addCommand(testCommand);
43
+ const commands = bot.getCommands();
44
+ expect(commands.some((cmd) => cmd.name === 'test')).toBe(true);
45
+ const removed = bot.removeCommand('test');
46
+ expect(removed).toBe(true);
47
+ const commandsAfter = bot.getCommands();
48
+ expect(commandsAfter.some((cmd) => cmd.name === 'test')).toBe(false);
49
+ });
50
+ test('should have default commands', () => {
51
+ bot = new SignalBot_1.SignalBot(mockConfig);
52
+ const commands = bot.getCommands();
53
+ const commandNames = commands.map((cmd) => cmd.name);
54
+ expect(commandNames).toContain('help');
55
+ expect(commandNames).toContain('stats');
56
+ expect(commandNames).toContain('ping');
57
+ expect(commandNames).toContain('info');
58
+ });
59
+ test('should emit ready event when started', (done) => {
60
+ bot = new SignalBot_1.SignalBot({
61
+ phoneNumber: '+1234567890',
62
+ group: {
63
+ name: 'Test Group',
64
+ createIfNotExists: false
65
+ }
66
+ });
67
+ // Mock SignalCli methods to avoid actual Signal operations
68
+ const mockSignalCli = bot.getSignalCli();
69
+ jest.spyOn(mockSignalCli, 'listDevices').mockResolvedValue([
70
+ { id: 1, name: 'Test Device', created: Date.now(), lastSeen: Date.now() }
71
+ ]);
72
+ jest.spyOn(mockSignalCli, 'startDaemon').mockImplementation(() => { });
73
+ jest.spyOn(mockSignalCli, 'connect').mockResolvedValue(undefined);
74
+ jest.spyOn(mockSignalCli, 'on').mockReturnValue(mockSignalCli);
75
+ bot.on('ready', () => {
76
+ expect(true).toBe(true);
77
+ done();
78
+ });
79
+ bot.start().catch(done);
80
+ });
81
+ test('should get stats', () => {
82
+ bot = new SignalBot_1.SignalBot(mockConfig);
83
+ const stats = bot.getStats();
84
+ expect(stats).toHaveProperty('messagesReceived');
85
+ expect(stats).toHaveProperty('commandsExecuted');
86
+ expect(stats).toHaveProperty('startTime');
87
+ expect(stats).toHaveProperty('lastActivity');
88
+ expect(stats).toHaveProperty('activeUsers');
89
+ expect(stats.messagesReceived).toBe(0);
90
+ expect(stats.commandsExecuted).toBe(0);
91
+ expect(stats.activeUsers).toBe(0);
92
+ });
93
+ test('should handle admin permissions', () => {
94
+ bot = new SignalBot_1.SignalBot({
95
+ phoneNumber: '+1234567890',
96
+ admins: ['+0987654321', '+1111111111']
97
+ });
98
+ expect(bot.isAdmin('+0987654321')).toBe(true);
99
+ expect(bot.isAdmin('+1111111111')).toBe(true);
100
+ expect(bot.isAdmin('+9999999999')).toBe(false);
101
+ });
102
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,235 @@
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
+ });
@@ -0,0 +1,3 @@
1
+ export { SignalCli } from './SignalCli';
2
+ export { SignalBot } from './SignalBot';
3
+ export * from './interfaces';
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.SignalBot = exports.SignalCli = void 0;
18
+ var SignalCli_1 = require("./SignalCli");
19
+ Object.defineProperty(exports, "SignalCli", { enumerable: true, get: function () { return SignalCli_1.SignalCli; } });
20
+ var SignalBot_1 = require("./SignalBot");
21
+ Object.defineProperty(exports, "SignalBot", { enumerable: true, get: function () { return SignalBot_1.SignalBot; } });
22
+ __exportStar(require("./interfaces"), exports);