signal-sdk 0.1.1 → 0.1.3
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/README.md +23 -11
- package/dist/MultiAccountManager.js +11 -19
- package/dist/SignalBot.js +40 -36
- package/dist/SignalCli.d.ts +25 -301
- package/dist/SignalCli.js +226 -971
- package/dist/__tests__/DeviceManager.test.d.ts +1 -0
- package/dist/__tests__/DeviceManager.test.js +135 -0
- package/dist/__tests__/MultiAccountManager.coverage.test.d.ts +1 -0
- package/dist/__tests__/MultiAccountManager.coverage.test.js +33 -0
- package/dist/__tests__/MultiAccountManager.test.js +3 -3
- package/dist/__tests__/SignalBot.additional.test.js +40 -37
- package/dist/__tests__/SignalBot.coverage.test.d.ts +1 -0
- package/dist/__tests__/SignalBot.coverage.test.js +385 -0
- package/dist/__tests__/SignalBot.test.js +8 -8
- package/dist/__tests__/SignalCli.advanced.test.js +47 -58
- package/dist/__tests__/SignalCli.connections.test.d.ts +1 -0
- package/dist/__tests__/SignalCli.connections.test.js +110 -0
- package/dist/__tests__/SignalCli.e2e.test.js +28 -32
- package/dist/__tests__/SignalCli.events.test.d.ts +1 -0
- package/dist/__tests__/SignalCli.events.test.js +113 -0
- package/dist/__tests__/SignalCli.integration.test.js +6 -5
- package/dist/__tests__/SignalCli.methods.test.js +150 -66
- package/dist/__tests__/SignalCli.parsing.test.js +4 -13
- package/dist/__tests__/SignalCli.simple.test.d.ts +1 -0
- package/dist/__tests__/SignalCli.simple.test.js +77 -0
- package/dist/__tests__/SignalCli.test.js +133 -74
- package/dist/__tests__/config.test.js +19 -29
- package/dist/__tests__/errors.test.js +2 -2
- package/dist/__tests__/retry.test.js +10 -8
- package/dist/__tests__/robustness.test.d.ts +1 -0
- package/dist/__tests__/robustness.test.js +59 -0
- package/dist/__tests__/security.test.d.ts +1 -0
- package/dist/__tests__/security.test.js +50 -0
- package/dist/config.js +3 -3
- package/dist/interfaces.d.ts +27 -0
- package/dist/managers/AccountManager.d.ts +27 -0
- package/dist/managers/AccountManager.js +147 -0
- package/dist/managers/BaseManager.d.ts +9 -0
- package/dist/managers/BaseManager.js +17 -0
- package/dist/managers/ContactManager.d.ts +15 -0
- package/dist/managers/ContactManager.js +123 -0
- package/dist/managers/DeviceManager.d.ts +11 -0
- package/dist/managers/DeviceManager.js +139 -0
- package/dist/managers/GroupManager.d.ts +12 -0
- package/dist/managers/GroupManager.js +78 -0
- package/dist/managers/MessageManager.d.ts +18 -0
- package/dist/managers/MessageManager.js +301 -0
- package/dist/managers/StickerManager.d.ts +8 -0
- package/dist/managers/StickerManager.js +39 -0
- package/dist/retry.js +3 -3
- package/dist/validators.d.ts +9 -0
- package/dist/validators.js +20 -0
- package/package.json +11 -4
- package/scripts/install.js +1 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ContactManager = void 0;
|
|
4
|
+
const BaseManager_1 = require("./BaseManager");
|
|
5
|
+
const validators_1 = require("../validators");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
class ContactManager extends BaseManager_1.BaseManager {
|
|
8
|
+
async updateContact(number, name, options = {}) {
|
|
9
|
+
const params = { account: this.account, recipient: number };
|
|
10
|
+
if (name)
|
|
11
|
+
params.name = name;
|
|
12
|
+
if (options.givenName)
|
|
13
|
+
params.givenName = options.givenName;
|
|
14
|
+
if (options.familyName)
|
|
15
|
+
params.familyName = options.familyName;
|
|
16
|
+
if (options.nickGivenName)
|
|
17
|
+
params.nickGivenName = options.nickGivenName;
|
|
18
|
+
if (options.nickFamilyName)
|
|
19
|
+
params.nickFamilyName = options.nickFamilyName;
|
|
20
|
+
if (options.note)
|
|
21
|
+
params.note = options.note;
|
|
22
|
+
if (options.expiration !== undefined)
|
|
23
|
+
params.expiration = options.expiration;
|
|
24
|
+
if (options.color)
|
|
25
|
+
params.color = options.color;
|
|
26
|
+
if (options.block !== undefined)
|
|
27
|
+
params.block = options.block;
|
|
28
|
+
if (options.unblock !== undefined)
|
|
29
|
+
params.unblock = options.unblock;
|
|
30
|
+
if (options.archived !== undefined)
|
|
31
|
+
params.archived = options.archived;
|
|
32
|
+
if (options.muted !== undefined)
|
|
33
|
+
params.muted = options.muted;
|
|
34
|
+
if (options.mutedUntil !== undefined)
|
|
35
|
+
params.mutedUntil = options.mutedUntil;
|
|
36
|
+
if (options.hideStory !== undefined)
|
|
37
|
+
params.hideStory = options.hideStory;
|
|
38
|
+
await this.sendRequest('updateContact', params);
|
|
39
|
+
}
|
|
40
|
+
async block(recipients, groupId) {
|
|
41
|
+
await this.sendRequest('block', { account: this.account, recipient: recipients, groupId });
|
|
42
|
+
}
|
|
43
|
+
async unblock(recipients, groupId) {
|
|
44
|
+
await this.sendRequest('unblock', { account: this.account, recipient: recipients, groupId });
|
|
45
|
+
}
|
|
46
|
+
async listContacts() {
|
|
47
|
+
return this.sendRequest('listContacts', { account: this.account });
|
|
48
|
+
}
|
|
49
|
+
async removeContact(number, options = {}) {
|
|
50
|
+
const params = {
|
|
51
|
+
account: this.account,
|
|
52
|
+
recipient: number,
|
|
53
|
+
};
|
|
54
|
+
if (options.hide)
|
|
55
|
+
params.hide = true;
|
|
56
|
+
if (options.forget)
|
|
57
|
+
params.forget = true;
|
|
58
|
+
await this.sendRequest('removeContact', params);
|
|
59
|
+
}
|
|
60
|
+
async getUserStatus(numbers = [], usernames = []) {
|
|
61
|
+
const params = { account: this.account };
|
|
62
|
+
if (numbers.length > 0)
|
|
63
|
+
params.recipients = numbers;
|
|
64
|
+
if (usernames.length > 0)
|
|
65
|
+
params.usernames = usernames;
|
|
66
|
+
const result = await this.sendRequest('getUserStatus', params);
|
|
67
|
+
const statusResults = [];
|
|
68
|
+
if (result.recipients) {
|
|
69
|
+
result.recipients.forEach((recipient) => {
|
|
70
|
+
statusResults.push({
|
|
71
|
+
number: recipient.number,
|
|
72
|
+
isRegistered: recipient.isRegistered || false,
|
|
73
|
+
uuid: recipient.uuid,
|
|
74
|
+
username: recipient.username,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return statusResults;
|
|
79
|
+
}
|
|
80
|
+
async listIdentities(number) {
|
|
81
|
+
return this.sendRequest('listIdentities', { account: this.account, number });
|
|
82
|
+
}
|
|
83
|
+
async trustIdentity(number, safetyNumber, verified = true) {
|
|
84
|
+
await this.sendRequest('trust', { account: this.account, recipient: number, safetyNumber, verified });
|
|
85
|
+
}
|
|
86
|
+
async getAvatar(options) {
|
|
87
|
+
this.logger.debug('Getting avatar', options);
|
|
88
|
+
const params = { account: this.account };
|
|
89
|
+
if (options.contact) {
|
|
90
|
+
(0, validators_1.validateRecipient)(options.contact);
|
|
91
|
+
params.contact = options.contact;
|
|
92
|
+
}
|
|
93
|
+
else if (options.profile) {
|
|
94
|
+
(0, validators_1.validateRecipient)(options.profile);
|
|
95
|
+
params.profile = options.profile;
|
|
96
|
+
}
|
|
97
|
+
else if (options.groupId) {
|
|
98
|
+
params.groupId = options.groupId;
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
throw new errors_1.MessageError('Must specify contact, profile, or groupId');
|
|
102
|
+
}
|
|
103
|
+
const result = await this.sendRequest('getAvatar', params);
|
|
104
|
+
return result.data || result;
|
|
105
|
+
}
|
|
106
|
+
parseContactProfile(contact) {
|
|
107
|
+
return {
|
|
108
|
+
...contact,
|
|
109
|
+
givenName: contact.givenName || undefined,
|
|
110
|
+
familyName: contact.familyName || undefined,
|
|
111
|
+
mobileCoinAddress: contact.mobileCoinAddress || undefined,
|
|
112
|
+
profileName: contact.profileName ||
|
|
113
|
+
(contact.givenName && contact.familyName
|
|
114
|
+
? `${contact.givenName} ${contact.familyName}`
|
|
115
|
+
: contact.givenName || contact.familyName),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async getContactsWithProfiles() {
|
|
119
|
+
const contacts = await this.listContacts();
|
|
120
|
+
return contacts.map((c) => this.parseContactProfile(c));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.ContactManager = ContactManager;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseManager } from './BaseManager';
|
|
2
|
+
import { Device, LinkingOptions, LinkingResult, UpdateDeviceOptions } from '../interfaces';
|
|
3
|
+
export declare class DeviceManager extends BaseManager {
|
|
4
|
+
private readonly signalCliPath;
|
|
5
|
+
constructor(sendRequest: (method: string, params?: any) => Promise<any>, account: string | undefined, logger: any, config: any, signalCliPath: string);
|
|
6
|
+
listDevices(): Promise<Device[]>;
|
|
7
|
+
addDevice(uri: string, deviceName?: string): Promise<void>;
|
|
8
|
+
removeDevice(deviceId: number): Promise<void>;
|
|
9
|
+
updateDevice(options: UpdateDeviceOptions): Promise<void>;
|
|
10
|
+
deviceLink(options?: LinkingOptions): Promise<LinkingResult>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DeviceManager = void 0;
|
|
37
|
+
const BaseManager_1 = require("./BaseManager");
|
|
38
|
+
const validators_1 = require("../validators");
|
|
39
|
+
const qrcodeTerminal = __importStar(require("qrcode-terminal"));
|
|
40
|
+
const child_process_1 = require("child_process");
|
|
41
|
+
class DeviceManager extends BaseManager_1.BaseManager {
|
|
42
|
+
constructor(sendRequest, account, logger, config, signalCliPath) {
|
|
43
|
+
super(sendRequest, account, logger, config);
|
|
44
|
+
this.signalCliPath = signalCliPath;
|
|
45
|
+
}
|
|
46
|
+
async listDevices() {
|
|
47
|
+
return this.sendRequest('listDevices', { account: this.account });
|
|
48
|
+
}
|
|
49
|
+
async addDevice(uri, deviceName) {
|
|
50
|
+
await this.sendRequest('addDevice', { account: this.account, uri, deviceName });
|
|
51
|
+
}
|
|
52
|
+
async removeDevice(deviceId) {
|
|
53
|
+
await this.sendRequest('removeDevice', { account: this.account, deviceId });
|
|
54
|
+
}
|
|
55
|
+
async updateDevice(options) {
|
|
56
|
+
this.logger.debug('Updating device', options);
|
|
57
|
+
(0, validators_1.validateDeviceId)(options.deviceId);
|
|
58
|
+
(0, validators_1.validateMessage)(options.deviceName, 200);
|
|
59
|
+
await this.sendRequest('updateDevice', {
|
|
60
|
+
deviceId: options.deviceId,
|
|
61
|
+
deviceName: options.deviceName,
|
|
62
|
+
account: this.account,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async deviceLink(options = {}) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const deviceName = options.name || 'Signal SDK Device';
|
|
68
|
+
(0, validators_1.validateSanitizedString)(deviceName, 'deviceName');
|
|
69
|
+
let linkProcess;
|
|
70
|
+
if (process.platform === 'win32') {
|
|
71
|
+
linkProcess = (0, child_process_1.spawn)('cmd.exe', ['/c', `"${this.signalCliPath}"`, 'link', '--name', deviceName], {
|
|
72
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
linkProcess = (0, child_process_1.spawn)(this.signalCliPath, ['link', '--name', deviceName], {
|
|
77
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
let qrCodeData;
|
|
81
|
+
let linkingComplete = false;
|
|
82
|
+
let hasError = false;
|
|
83
|
+
linkProcess.stdout.on('data', (data) => {
|
|
84
|
+
const output = data.toString('utf8').trim();
|
|
85
|
+
if (output.includes('sgnl://')) {
|
|
86
|
+
const uriMatch = output.match(/sgnl:\/\/[^\s]+/);
|
|
87
|
+
if (uriMatch && !qrCodeData) {
|
|
88
|
+
const uri = uriMatch[0];
|
|
89
|
+
qrCodeData = { uri };
|
|
90
|
+
if (options.qrCodeOutput === 'console') {
|
|
91
|
+
console.log('\n- QR CODE - SCAN WITH YOUR PHONE:');
|
|
92
|
+
console.log('===================================');
|
|
93
|
+
qrcodeTerminal.generate(uri, { small: true });
|
|
94
|
+
console.log('===================================\n');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (output.includes('Device registered') || output.includes('Successfully linked')) {
|
|
99
|
+
linkingComplete = true;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
linkProcess.stderr.on('data', (data) => {
|
|
103
|
+
const error = data.toString('utf8').trim();
|
|
104
|
+
if (!error.includes('INFO') && !error.includes('DEBUG') && error.length > 0) {
|
|
105
|
+
hasError = true;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
linkProcess.on('close', (code) => {
|
|
109
|
+
if (code === 0 && linkingComplete) {
|
|
110
|
+
resolve({
|
|
111
|
+
success: true,
|
|
112
|
+
isLinked: true,
|
|
113
|
+
deviceName,
|
|
114
|
+
qrCode: qrCodeData,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else if (code === 0 && qrCodeData) {
|
|
118
|
+
resolve({
|
|
119
|
+
success: true,
|
|
120
|
+
isLinked: false,
|
|
121
|
+
deviceName,
|
|
122
|
+
qrCode: qrCodeData,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
resolve({
|
|
127
|
+
success: false,
|
|
128
|
+
error: hasError ? 'Device linking failed' : `signal-cli exited with code ${code}`,
|
|
129
|
+
qrCode: qrCodeData,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
linkProcess.on('error', (error) => {
|
|
134
|
+
reject(new Error(`Failed to start device linking: ${error.message}`));
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.DeviceManager = DeviceManager;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseManager } from './BaseManager';
|
|
2
|
+
import { GroupInfo, GroupUpdateOptions, ListGroupsOptions } from '../interfaces';
|
|
3
|
+
export declare class GroupManager extends BaseManager {
|
|
4
|
+
createGroup(name: string, members: string[]): Promise<GroupInfo>;
|
|
5
|
+
updateGroup(groupId: string, options: GroupUpdateOptions): Promise<void>;
|
|
6
|
+
listGroups(): Promise<GroupInfo[]>;
|
|
7
|
+
quitGroup(groupId: string): Promise<void>;
|
|
8
|
+
joinGroup(uri: string): Promise<void>;
|
|
9
|
+
listGroupsDetailed(options?: ListGroupsOptions): Promise<GroupInfo[]>;
|
|
10
|
+
parseGroupDetails(group: GroupInfo): GroupInfo;
|
|
11
|
+
getGroupsWithDetails(options?: ListGroupsOptions): Promise<GroupInfo[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GroupManager = void 0;
|
|
4
|
+
const BaseManager_1 = require("./BaseManager");
|
|
5
|
+
class GroupManager extends BaseManager_1.BaseManager {
|
|
6
|
+
async createGroup(name, members) {
|
|
7
|
+
return this.sendRequest('updateGroup', { account: this.account, name, members });
|
|
8
|
+
}
|
|
9
|
+
async updateGroup(groupId, options) {
|
|
10
|
+
const params = { groupId, account: this.account };
|
|
11
|
+
if (options.name)
|
|
12
|
+
params.name = options.name;
|
|
13
|
+
if (options.description)
|
|
14
|
+
params.description = options.description;
|
|
15
|
+
if (options.avatar)
|
|
16
|
+
params.avatar = options.avatar;
|
|
17
|
+
if (options.addMembers)
|
|
18
|
+
params.addMembers = options.addMembers;
|
|
19
|
+
if (options.removeMembers)
|
|
20
|
+
params.removeMembers = options.removeMembers;
|
|
21
|
+
if (options.promoteAdmins)
|
|
22
|
+
params.promoteAdmins = options.promoteAdmins;
|
|
23
|
+
if (options.demoteAdmins)
|
|
24
|
+
params.demoteAdmins = options.demoteAdmins;
|
|
25
|
+
if (options.banMembers)
|
|
26
|
+
params.banMembers = options.banMembers;
|
|
27
|
+
if (options.unbanMembers)
|
|
28
|
+
params.unbanMembers = options.unbanMembers;
|
|
29
|
+
if (options.resetInviteLink)
|
|
30
|
+
params.resetLink = true;
|
|
31
|
+
if (options.permissionAddMember)
|
|
32
|
+
params.permissionAddMember = options.permissionAddMember;
|
|
33
|
+
if (options.permissionEditDetails)
|
|
34
|
+
params.permissionEditDetails = options.permissionEditDetails;
|
|
35
|
+
if (options.permissionSendMessage)
|
|
36
|
+
params.permissionSendMessage = options.permissionSendMessage;
|
|
37
|
+
if (options.expirationTimer)
|
|
38
|
+
params.expiration = options.expirationTimer;
|
|
39
|
+
await this.sendRequest('updateGroup', params);
|
|
40
|
+
}
|
|
41
|
+
async listGroups() {
|
|
42
|
+
return this.sendRequest('listGroups', { account: this.account });
|
|
43
|
+
}
|
|
44
|
+
async quitGroup(groupId) {
|
|
45
|
+
await this.sendRequest('quitGroup', { account: this.account, groupId });
|
|
46
|
+
}
|
|
47
|
+
async joinGroup(uri) {
|
|
48
|
+
await this.sendRequest('joinGroup', { account: this.account, uri });
|
|
49
|
+
}
|
|
50
|
+
async listGroupsDetailed(options = {}) {
|
|
51
|
+
this.logger.debug('Listing groups with options', options);
|
|
52
|
+
const params = { account: this.account };
|
|
53
|
+
if (options.detailed) {
|
|
54
|
+
params.detailed = true;
|
|
55
|
+
}
|
|
56
|
+
if (options.groupIds && options.groupIds.length > 0) {
|
|
57
|
+
params.groupId = options.groupIds;
|
|
58
|
+
}
|
|
59
|
+
return this.sendRequest('listGroups', params);
|
|
60
|
+
}
|
|
61
|
+
parseGroupDetails(group) {
|
|
62
|
+
return {
|
|
63
|
+
...group,
|
|
64
|
+
inviteLink: group.groupInviteLink || group.inviteLink,
|
|
65
|
+
groupInviteLink: group.groupInviteLink || group.inviteLink,
|
|
66
|
+
pendingMembers: group.pendingMembers || [],
|
|
67
|
+
banned: group.banned || [],
|
|
68
|
+
requestingMembers: group.requestingMembers || [],
|
|
69
|
+
admins: group.admins || [],
|
|
70
|
+
members: group.members || [],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async getGroupsWithDetails(options = {}) {
|
|
74
|
+
const groups = await this.listGroupsDetailed(options);
|
|
75
|
+
return groups.map((g) => this.parseGroupDetails(g));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.GroupManager = GroupManager;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseManager } from './BaseManager';
|
|
2
|
+
import { SendMessageOptions, SendResponse, Message, ReceiveOptions, ReceiptType, PollCreateOptions, PollVoteOptions, PollTerminateOptions, GetAttachmentOptions, UploadProgress } from '../interfaces';
|
|
3
|
+
export declare class MessageManager extends BaseManager {
|
|
4
|
+
sendMessage(recipient: string, message: string, options?: Omit<SendMessageOptions, 'message'>): Promise<SendResponse>;
|
|
5
|
+
sendReaction(recipient: string, targetAuthor: string, targetTimestamp: number, emoji: string, remove?: boolean, isStory?: boolean): Promise<SendResponse>;
|
|
6
|
+
sendTyping(recipient: string, stop?: boolean): Promise<void>;
|
|
7
|
+
remoteDeleteMessage(recipient: string, targetTimestamp: number): Promise<void>;
|
|
8
|
+
sendReceipt(recipient: string, targetTimestamp: number, type?: ReceiptType): Promise<void>;
|
|
9
|
+
receive(options?: ReceiveOptions): Promise<Message[]>;
|
|
10
|
+
private parseEnvelope;
|
|
11
|
+
sendPollCreate(options: PollCreateOptions): Promise<SendResponse>;
|
|
12
|
+
sendPollVote(recipient: string, options: PollVoteOptions): Promise<SendResponse>;
|
|
13
|
+
sendPollTerminate(recipient: string, options: PollTerminateOptions): Promise<SendResponse>;
|
|
14
|
+
getAttachment(options: GetAttachmentOptions): Promise<string>;
|
|
15
|
+
sendMessageWithProgress(recipient: string, message: string, options?: SendMessageOptions & {
|
|
16
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
17
|
+
}): Promise<SendResponse>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MessageManager = void 0;
|
|
4
|
+
const BaseManager_1 = require("./BaseManager");
|
|
5
|
+
const validators_1 = require("../validators");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
class MessageManager extends BaseManager_1.BaseManager {
|
|
8
|
+
async sendMessage(recipient, message, options = {}) {
|
|
9
|
+
const params = {
|
|
10
|
+
message,
|
|
11
|
+
account: this.account,
|
|
12
|
+
};
|
|
13
|
+
if (this.isGroupId(recipient)) {
|
|
14
|
+
params.groupId = recipient;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
params.recipients = [recipient];
|
|
18
|
+
}
|
|
19
|
+
if (options.attachments && options.attachments.length > 0) {
|
|
20
|
+
params.attachments = options.attachments;
|
|
21
|
+
}
|
|
22
|
+
if (options.expiresInSeconds) {
|
|
23
|
+
params.expiresInSeconds = options.expiresInSeconds;
|
|
24
|
+
}
|
|
25
|
+
if (options.isViewOnce) {
|
|
26
|
+
params.viewOnce = options.isViewOnce;
|
|
27
|
+
}
|
|
28
|
+
if (options.mentions && options.mentions.length > 0) {
|
|
29
|
+
params.mentions = options.mentions.map((m) => ({
|
|
30
|
+
start: m.start,
|
|
31
|
+
length: m.length,
|
|
32
|
+
number: m.recipient || m.number,
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
if (options.textStyles && options.textStyles.length > 0) {
|
|
36
|
+
params.textStyles = options.textStyles.map((ts) => ({
|
|
37
|
+
start: ts.start,
|
|
38
|
+
length: ts.length,
|
|
39
|
+
style: ts.style,
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
if (options.quote) {
|
|
43
|
+
params.quoteTimestamp = options.quote.timestamp;
|
|
44
|
+
params.quoteAuthor = options.quote.author;
|
|
45
|
+
if (options.quote.text) {
|
|
46
|
+
params.quoteMessage = options.quote.text;
|
|
47
|
+
}
|
|
48
|
+
if (options.quote.mentions && options.quote.mentions.length > 0) {
|
|
49
|
+
params.quoteMentions = options.quote.mentions.map((m) => ({
|
|
50
|
+
start: m.start,
|
|
51
|
+
length: m.length,
|
|
52
|
+
number: m.recipient || m.number,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
if (options.quote.textStyles && options.quote.textStyles.length > 0) {
|
|
56
|
+
params.quoteTextStyles = options.quote.textStyles.map((ts) => ({
|
|
57
|
+
start: ts.start,
|
|
58
|
+
length: ts.length,
|
|
59
|
+
style: ts.style,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (options.previewUrl) {
|
|
64
|
+
params.previewUrl = options.previewUrl;
|
|
65
|
+
}
|
|
66
|
+
if (options.previewTitle) {
|
|
67
|
+
params.previewTitle = options.previewTitle;
|
|
68
|
+
}
|
|
69
|
+
if (options.previewDescription) {
|
|
70
|
+
params.previewDescription = options.previewDescription;
|
|
71
|
+
}
|
|
72
|
+
if (options.previewImage) {
|
|
73
|
+
params.previewImage = options.previewImage;
|
|
74
|
+
}
|
|
75
|
+
if (options.editTimestamp) {
|
|
76
|
+
params.editTimestamp = options.editTimestamp;
|
|
77
|
+
}
|
|
78
|
+
if (options.storyTimestamp && options.storyAuthor) {
|
|
79
|
+
params.storyTimestamp = options.storyTimestamp;
|
|
80
|
+
params.storyAuthor = options.storyAuthor;
|
|
81
|
+
}
|
|
82
|
+
if (options.noteToSelf) {
|
|
83
|
+
params.noteToSelf = options.noteToSelf;
|
|
84
|
+
}
|
|
85
|
+
if (options.endSession) {
|
|
86
|
+
params.endSession = options.endSession;
|
|
87
|
+
}
|
|
88
|
+
return this.sendRequest('send', params);
|
|
89
|
+
}
|
|
90
|
+
async sendReaction(recipient, targetAuthor, targetTimestamp, emoji, remove = false, isStory = false) {
|
|
91
|
+
const params = {
|
|
92
|
+
emoji,
|
|
93
|
+
targetAuthor,
|
|
94
|
+
targetTimestamp,
|
|
95
|
+
remove,
|
|
96
|
+
account: this.account,
|
|
97
|
+
};
|
|
98
|
+
if (isStory) {
|
|
99
|
+
params.story = true;
|
|
100
|
+
}
|
|
101
|
+
if (this.isGroupId(recipient)) {
|
|
102
|
+
params.groupId = recipient;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
params.recipients = [recipient];
|
|
106
|
+
}
|
|
107
|
+
return this.sendRequest('sendReaction', params);
|
|
108
|
+
}
|
|
109
|
+
async sendTyping(recipient, stop = false) {
|
|
110
|
+
const params = { when: !stop, account: this.account };
|
|
111
|
+
if (this.isGroupId(recipient)) {
|
|
112
|
+
params.groupId = recipient;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
params.recipients = [recipient];
|
|
116
|
+
}
|
|
117
|
+
await this.sendRequest('sendTyping', params);
|
|
118
|
+
}
|
|
119
|
+
async remoteDeleteMessage(recipient, targetTimestamp) {
|
|
120
|
+
const params = { targetTimestamp, account: this.account };
|
|
121
|
+
if (this.isGroupId(recipient)) {
|
|
122
|
+
params.groupId = recipient;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
params.recipients = [recipient];
|
|
126
|
+
}
|
|
127
|
+
await this.sendRequest('remoteDelete', params);
|
|
128
|
+
}
|
|
129
|
+
async sendReceipt(recipient, targetTimestamp, type = 'read') {
|
|
130
|
+
await this.sendRequest('sendReceipt', { account: this.account, recipient, targetTimestamp, type });
|
|
131
|
+
}
|
|
132
|
+
async receive(options = {}) {
|
|
133
|
+
const params = { account: this.account };
|
|
134
|
+
if (options.timeout !== undefined) {
|
|
135
|
+
params.timeout = options.timeout;
|
|
136
|
+
}
|
|
137
|
+
if (options.maxMessages !== undefined) {
|
|
138
|
+
params.maxMessages = options.maxMessages;
|
|
139
|
+
}
|
|
140
|
+
if (options.ignoreAttachments) {
|
|
141
|
+
params.ignoreAttachments = true;
|
|
142
|
+
}
|
|
143
|
+
if (options.ignoreStories) {
|
|
144
|
+
params.ignoreStories = true;
|
|
145
|
+
}
|
|
146
|
+
if (options.sendReadReceipts) {
|
|
147
|
+
params.sendReadReceipts = true;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
const result = await this.sendRequest('receive', params);
|
|
151
|
+
if (Array.isArray(result)) {
|
|
152
|
+
return result.map((envelope) => this.parseEnvelope(envelope));
|
|
153
|
+
}
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
this.logger.error('Failed to receive messages:', error);
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
parseEnvelope(envelope) {
|
|
162
|
+
const message = {
|
|
163
|
+
timestamp: envelope.timestamp || Date.now(),
|
|
164
|
+
source: envelope.source || envelope.sourceNumber,
|
|
165
|
+
sourceUuid: envelope.sourceUuid,
|
|
166
|
+
sourceDevice: envelope.sourceDevice,
|
|
167
|
+
};
|
|
168
|
+
if (envelope.dataMessage) {
|
|
169
|
+
const data = envelope.dataMessage;
|
|
170
|
+
message.text = data.message || data.body;
|
|
171
|
+
message.groupId = data.groupInfo?.groupId;
|
|
172
|
+
message.attachments = data.attachments;
|
|
173
|
+
message.mentions = data.mentions;
|
|
174
|
+
message.quote = data.quote;
|
|
175
|
+
message.reaction = data.reaction;
|
|
176
|
+
message.sticker = data.sticker;
|
|
177
|
+
message.expiresInSeconds = data.expiresInSeconds;
|
|
178
|
+
message.viewOnce = data.viewOnce;
|
|
179
|
+
}
|
|
180
|
+
if (envelope.syncMessage) {
|
|
181
|
+
message.syncMessage = envelope.syncMessage;
|
|
182
|
+
}
|
|
183
|
+
if (envelope.receiptMessage) {
|
|
184
|
+
message.receipt = envelope.receiptMessage;
|
|
185
|
+
}
|
|
186
|
+
if (envelope.typingMessage) {
|
|
187
|
+
message.typing = envelope.typingMessage;
|
|
188
|
+
}
|
|
189
|
+
return message;
|
|
190
|
+
}
|
|
191
|
+
async sendPollCreate(options) {
|
|
192
|
+
this.logger.debug('Sending poll create', options);
|
|
193
|
+
(0, validators_1.validateMessage)(options.question, 500);
|
|
194
|
+
if (!options.options || options.options.length < 2) {
|
|
195
|
+
throw new errors_1.MessageError('Poll must have at least 2 options');
|
|
196
|
+
}
|
|
197
|
+
if (options.options.length > 10) {
|
|
198
|
+
throw new errors_1.MessageError('Poll cannot have more than 10 options');
|
|
199
|
+
}
|
|
200
|
+
const params = {
|
|
201
|
+
question: options.question,
|
|
202
|
+
options: options.options,
|
|
203
|
+
account: this.account,
|
|
204
|
+
};
|
|
205
|
+
if (options.multiSelect !== undefined) {
|
|
206
|
+
params.multiSelect = options.multiSelect;
|
|
207
|
+
}
|
|
208
|
+
if (options.groupId) {
|
|
209
|
+
(0, validators_1.validateGroupId)(options.groupId);
|
|
210
|
+
params.groupId = options.groupId;
|
|
211
|
+
}
|
|
212
|
+
else if (options.recipients) {
|
|
213
|
+
params.recipients = options.recipients.map((r) => {
|
|
214
|
+
(0, validators_1.validateRecipient)(r);
|
|
215
|
+
return r;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
throw new errors_1.MessageError('Must specify either recipients or groupId');
|
|
220
|
+
}
|
|
221
|
+
return this.sendRequest('sendPollCreate', params);
|
|
222
|
+
}
|
|
223
|
+
async sendPollVote(recipient, options) {
|
|
224
|
+
this.logger.debug('Sending poll vote', { recipient, options });
|
|
225
|
+
(0, validators_1.validateRecipient)(options.pollAuthor);
|
|
226
|
+
(0, validators_1.validateTimestamp)(options.pollTimestamp);
|
|
227
|
+
if (!options.optionIndexes || options.optionIndexes.length === 0) {
|
|
228
|
+
throw new errors_1.MessageError('Must specify at least one option to vote for');
|
|
229
|
+
}
|
|
230
|
+
const params = {
|
|
231
|
+
pollAuthor: options.pollAuthor,
|
|
232
|
+
pollTimestamp: options.pollTimestamp,
|
|
233
|
+
options: options.optionIndexes,
|
|
234
|
+
account: this.account,
|
|
235
|
+
};
|
|
236
|
+
if (options.voteCount !== undefined) {
|
|
237
|
+
params.voteCount = options.voteCount;
|
|
238
|
+
}
|
|
239
|
+
if (this.isGroupId(recipient)) {
|
|
240
|
+
(0, validators_1.validateGroupId)(recipient);
|
|
241
|
+
params.groupId = recipient;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
(0, validators_1.validateRecipient)(recipient);
|
|
245
|
+
params.recipient = recipient;
|
|
246
|
+
}
|
|
247
|
+
return this.sendRequest('sendPollVote', params);
|
|
248
|
+
}
|
|
249
|
+
async sendPollTerminate(recipient, options) {
|
|
250
|
+
this.logger.debug('Sending poll terminate', { recipient, options });
|
|
251
|
+
(0, validators_1.validateTimestamp)(options.pollTimestamp);
|
|
252
|
+
const params = {
|
|
253
|
+
pollTimestamp: options.pollTimestamp,
|
|
254
|
+
account: this.account,
|
|
255
|
+
};
|
|
256
|
+
if (this.isGroupId(recipient)) {
|
|
257
|
+
(0, validators_1.validateGroupId)(recipient);
|
|
258
|
+
params.groupId = recipient;
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
(0, validators_1.validateRecipient)(recipient);
|
|
262
|
+
params.recipient = recipient;
|
|
263
|
+
}
|
|
264
|
+
return this.sendRequest('sendPollTerminate', params);
|
|
265
|
+
}
|
|
266
|
+
async getAttachment(options) {
|
|
267
|
+
this.logger.debug('Getting attachment', options);
|
|
268
|
+
if (!options.id) {
|
|
269
|
+
throw new errors_1.MessageError('Attachment ID is required');
|
|
270
|
+
}
|
|
271
|
+
const params = {
|
|
272
|
+
id: options.id,
|
|
273
|
+
account: this.account,
|
|
274
|
+
};
|
|
275
|
+
if (options.groupId) {
|
|
276
|
+
(0, validators_1.validateGroupId)(options.groupId);
|
|
277
|
+
params.groupId = options.groupId;
|
|
278
|
+
}
|
|
279
|
+
else if (options.recipient) {
|
|
280
|
+
(0, validators_1.validateRecipient)(options.recipient);
|
|
281
|
+
params.recipient = options.recipient;
|
|
282
|
+
}
|
|
283
|
+
const result = await this.sendRequest('getAttachment', params);
|
|
284
|
+
return result.data || result;
|
|
285
|
+
}
|
|
286
|
+
async sendMessageWithProgress(recipient, message, options = {}) {
|
|
287
|
+
const { onProgress, ...sendOptions } = options;
|
|
288
|
+
if (onProgress && sendOptions.attachments && sendOptions.attachments.length > 0) {
|
|
289
|
+
for (let i = 0; i <= 100; i += 10) {
|
|
290
|
+
onProgress({
|
|
291
|
+
total: 100,
|
|
292
|
+
uploaded: i,
|
|
293
|
+
percentage: i,
|
|
294
|
+
});
|
|
295
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return this.sendMessage(recipient, message, sendOptions);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
exports.MessageManager = MessageManager;
|