@theotherwillembotha/node-red-whatsapp 0.0.55

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,212 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.WhatsappService = void 0;
7
+ const node_red_plugincore_1 = require("@theotherwillembotha/node-red-plugincore");
8
+ const WhatsappClient_1 = require("./WhatsappClient");
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const qrcode_1 = __importDefault(require("qrcode"));
11
+ class WhatsappService extends node_red_plugincore_1.BaseService {
12
+ static { this.clients = {}; }
13
+ constructor() {
14
+ super("WhatsappService");
15
+ this.connections = [];
16
+ this.tempClients = {}; // temp clients are used to keep references to clients while linking accounts.
17
+ }
18
+ async init(red) {
19
+ this.red = red;
20
+ console.log("STARTING: WhatsappService");
21
+ // whatsapp client commands.
22
+ let writePermission = red.auth.needsPermission("inject.write");
23
+ red.httpAdmin.post("/whatsapp/linkaccount", writePermission, (request, response) => this.linkAccount(request, response));
24
+ red.httpAdmin.post("/whatsapp/unlinkaccount", writePermission, (request, response) => this.unlinkaccount(request, response));
25
+ red.httpAdmin.post("/whatsapp/getgroups", writePermission, (request, response) => this.getGroups(request, response));
26
+ red.httpAdmin.post("/whatsapp/creategroup", writePermission, (request, response) => this.createGroup(request, response));
27
+ red.httpAdmin.post("/whatsapp/groupadduser", writePermission, (request, response) => this.groupAddUser(request, response));
28
+ red.httpAdmin.post("/whatsapp/groupupdateuser", writePermission, (request, response) => this.groupUpdateUser(request, response));
29
+ red.httpAdmin.post("/whatsapp/groupremoveuser", writePermission, (request, response) => this.groupRemoveUser(request, response));
30
+ try {
31
+ // TODO: change the way we determine a suitable sorage location for the whatsapp data.
32
+ // if the /data folder exists, then this is probably a custom image and we can safely store the information in /data
33
+ // if it doesnt exist, then just save it to the current working folder.
34
+ if (fs_1.default.existsSync("/data")) {
35
+ console.log("Using /data as storage location");
36
+ this.configDir = "/data/whatsapp";
37
+ }
38
+ else {
39
+ this.configDir = "whatsapp";
40
+ }
41
+ this.configFile = this.configDir + "/connections.json";
42
+ // check if the directory exists.
43
+ if (!fs_1.default.existsSync(this.configDir)) {
44
+ fs_1.default.mkdirSync(this.configDir);
45
+ }
46
+ if (!fs_1.default.existsSync(this.configFile)) {
47
+ fs_1.default.writeFileSync(this.configFile, JSON.stringify([], null, 2), { flag: "w+" });
48
+ }
49
+ // read the connections file and start the clients.
50
+ this.connections = JSON.parse(fs_1.default.readFileSync(this.configFile).toString());
51
+ if (this.connections.length === 0) {
52
+ console.log("whatsapp: no connections yet");
53
+ }
54
+ await Promise.all(this.connections.map(connection => {
55
+ let client = new WhatsappClient_1.WhatsappClient({
56
+ localConnectionId: connection.key,
57
+ fileStorageRoot: this.configDir
58
+ });
59
+ WhatsappService.clients[connection.key] = client;
60
+ return client.start();
61
+ }));
62
+ }
63
+ catch (error) {
64
+ console.log(error);
65
+ }
66
+ }
67
+ deinit(red) {
68
+ console.log("STOPPING: WhatsappService");
69
+ }
70
+ static getClient(localConnectionId) {
71
+ return this.clients[localConnectionId];
72
+ }
73
+ linkAccount(request, response) {
74
+ let linkRequest = request.body;
75
+ console.log("Received request: ", linkRequest);
76
+ let red = this.red;
77
+ // create a whatsapp client.
78
+ let client = new WhatsappClient_1.WhatsappClient({
79
+ localConnectionId: linkRequest.localConnectionId,
80
+ fileStorageRoot: this.configDir
81
+ });
82
+ this.tempClients[linkRequest.localConnectionId] = client;
83
+ // start a timer that will only attempt to create a connection for 3min... after that it will close the connection.
84
+ let timeoutTimer = setTimeout(() => {
85
+ console.log("link account request timed out for " + linkRequest.localConnectionId);
86
+ client.stop().then(() => {
87
+ console.log("connection closed " + linkRequest.localConnectionId);
88
+ fs_1.default.rmSync(this.configDir + "/" + linkRequest.localConnectionId, { recursive: true });
89
+ });
90
+ delete this.tempClients[linkRequest.localConnectionId];
91
+ red.events.emit("runtime-event", {
92
+ id: "whatsapp/" + linkRequest.localConnectionId,
93
+ retain: false,
94
+ payload: {
95
+ type: "account_link_timeout"
96
+ }
97
+ });
98
+ }, 3 * 60 * 1000);
99
+ client.onQRCode((qrcode) => {
100
+ qrcode_1.default.toString(qrcode, { type: "svg" }, function (error, svgImage) {
101
+ if (error) {
102
+ console.log("Error", error);
103
+ return;
104
+ }
105
+ red.events.emit("runtime-event", {
106
+ id: "whatsapp/" + linkRequest.localConnectionId,
107
+ retain: false,
108
+ payload: {
109
+ type: "qrcode",
110
+ qrcode: svgImage
111
+ }
112
+ });
113
+ });
114
+ });
115
+ client.onConnectionSuccess(() => {
116
+ // make sure we havent got this connection already.
117
+ let knownConnection = this.connections.find(connection => connection.key === linkRequest.localConnectionId);
118
+ if (!knownConnection) {
119
+ this.connections.push({
120
+ key: linkRequest.localConnectionId
121
+ });
122
+ fs_1.default.writeFileSync(this.configFile, JSON.stringify(this.connections, null, 2), { flag: "w+" });
123
+ }
124
+ // stop the timeout timer, and move client from tempclients to clients.
125
+ clearTimeout(timeoutTimer);
126
+ delete this.tempClients[linkRequest.localConnectionId];
127
+ WhatsappService.clients[linkRequest.localConnectionId] = client;
128
+ // send a notification to the frontend.
129
+ red.events.emit("runtime-event", {
130
+ id: "whatsapp/" + linkRequest.localConnectionId,
131
+ retain: false,
132
+ payload: {
133
+ type: "account_linked"
134
+ }
135
+ });
136
+ });
137
+ client.start();
138
+ response.send({ status: "ok" });
139
+ }
140
+ unlinkaccount(request, response) {
141
+ let unlinkAccountRequest = request.body;
142
+ // get an instance of the client and stop it.
143
+ let client = WhatsappService.clients[unlinkAccountRequest.localConnectionId];
144
+ let deleteAccountData = () => {
145
+ // after stopping the client, remove it from the clients list, update the connections file, and remove its storage.
146
+ delete WhatsappService.clients[unlinkAccountRequest.localConnectionId];
147
+ this.connections = this.connections.filter(connection => connection.key !== unlinkAccountRequest.localConnectionId);
148
+ fs_1.default.writeFileSync(this.configFile, JSON.stringify(this.connections, null, 2), { flag: "w+" });
149
+ fs_1.default.rmSync(this.configDir + "/" + unlinkAccountRequest.localConnectionId, { recursive: true });
150
+ response.send({ status: "ok" });
151
+ };
152
+ if (client) {
153
+ client.stop().finally(deleteAccountData);
154
+ }
155
+ else {
156
+ deleteAccountData();
157
+ response.send({ result: "ok" });
158
+ }
159
+ }
160
+ async getGroups(request, response) {
161
+ let client = WhatsappService.clients[request.body.localConnectionId];
162
+ if (client) {
163
+ response.send(await client.groups().getAll());
164
+ }
165
+ else {
166
+ response.status(500).send({ message: "Client not linked" });
167
+ }
168
+ }
169
+ async createGroup(request, response) {
170
+ let client = WhatsappService.clients[request.body.localConnectionId];
171
+ if (client) {
172
+ response.send(await client.groups().createGroup(request.body.groupName));
173
+ }
174
+ else {
175
+ response.status(500).send({ message: "Client not linked" });
176
+ }
177
+ }
178
+ async groupAddUser(request, response) {
179
+ let client = WhatsappService.clients[request.body.localConnectionId];
180
+ if (client) {
181
+ await client.groups().addUserToGroup(request.body.userId, request.body.groupId, request.body.role);
182
+ response.send({ status: "ok" });
183
+ }
184
+ else {
185
+ response.status(500).send({ message: "Client not linked" });
186
+ }
187
+ }
188
+ async groupUpdateUser(request, response) {
189
+ let client = WhatsappService.clients[request.body.localConnectionId];
190
+ if (client) {
191
+ await client.groups().updateUserRole(request.body.userId, request.body.groupId, request.body.role);
192
+ response.send({ status: "ok" });
193
+ }
194
+ else {
195
+ response.status(500).send({ message: "Client not linked" });
196
+ }
197
+ }
198
+ async groupRemoveUser(request, response) {
199
+ let client = WhatsappService.clients[request.body.localConnectionId];
200
+ if (client) {
201
+ await client.groups().removeUserFromGroup(request.body.userId, request.body.groupId);
202
+ response.send({ status: "ok" });
203
+ }
204
+ else {
205
+ response.status(500).send({ message: "Client not linked" });
206
+ }
207
+ }
208
+ static getServiceDescriptor() {
209
+ return new node_red_plugincore_1.ServiceDescriptor("@theotherwillembotha/whatsappservice", "WhatsappService", "integration-plugin", "./whatsapp/service/WhatsappService", WhatsappService);
210
+ }
211
+ }
212
+ exports.WhatsappService = WhatsappService;
@@ -0,0 +1,408 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Message = exports.Chat = exports.Contact = exports.MessageType = exports.Role = exports.WhatsappStore = void 0;
13
+ const typeorm_1 = require("typeorm");
14
+ const WhatsappClient_1 = require("./WhatsappClient");
15
+ // ******************* WHATSAPP STORE ********************** //
16
+ class WhatsappStore {
17
+ static async createStore(id, location) {
18
+ let datasource = await new typeorm_1.DataSource({
19
+ type: "sqljs",
20
+ location: `${location}/database.sqlite`,
21
+ synchronize: true,
22
+ logging: false,
23
+ autoSave: true,
24
+ entities: [Contact, Chat, Message, Participant],
25
+ migrations: [],
26
+ subscribers: [],
27
+ }).initialize();
28
+ return new WhatsappStore(id, location, datasource);
29
+ }
30
+ constructor(id, location, datasource) {
31
+ this._id = id;
32
+ this._location = location;
33
+ this._datasource = datasource;
34
+ this._contacts = new ContactDAO(this, this._datasource.manager);
35
+ this._chats = new ChatDAO(this, this._datasource.manager);
36
+ this._messages = new MessageDAO(this, this._datasource.manager);
37
+ // print out some db stats.
38
+ this.contacts().all().then(contacts => console.log("DB CONTAINS " + contacts.length + " CONTACTS"));
39
+ this.chats().all().then(chats => console.log("DB CONTAINS " + chats.length + " CHATS"));
40
+ this.messages().all().then(messages => console.log("DB CONTAINS " + messages.length + " MESSAGES"));
41
+ }
42
+ chats() {
43
+ return this._chats;
44
+ }
45
+ contacts() {
46
+ return this._contacts;
47
+ }
48
+ messages() {
49
+ return this._messages;
50
+ }
51
+ }
52
+ exports.WhatsappStore = WhatsappStore;
53
+ class DAO {
54
+ constructor(daos, em) {
55
+ this._daos = daos;
56
+ this._em = em;
57
+ }
58
+ daos() {
59
+ return this._daos;
60
+ }
61
+ em() {
62
+ return this._em;
63
+ }
64
+ }
65
+ var ContactType;
66
+ (function (ContactType) {
67
+ ContactType["USER"] = "USER";
68
+ ContactType["GROUP"] = "GROUP";
69
+ })(ContactType || (ContactType = {}));
70
+ // ******************* CONTACTS ********************** //
71
+ let Contact = class Contact {
72
+ constructor(id) {
73
+ if (!id) {
74
+ return;
75
+ }
76
+ this.id = id;
77
+ // the ID will determine the type of the contact. if ends with "@g.us" its a group. if it ends with @s.whatsapp.net, its a user.
78
+ this.type =
79
+ id.endsWith("@s.whatsapp.net") ? ContactType.USER :
80
+ id.endsWith("@lid") ? ContactType.USER :
81
+ ContactType.GROUP;
82
+ // the phone number is the bits before the @ in the id.
83
+ this.phoneNumber = id.substring(0, id.indexOf("@"));
84
+ }
85
+ getName() {
86
+ return this.name ? this.name : this.phoneNumber;
87
+ }
88
+ };
89
+ exports.Contact = Contact;
90
+ __decorate([
91
+ (0, typeorm_1.PrimaryColumn)({ name: "id" }),
92
+ __metadata("design:type", String)
93
+ ], Contact.prototype, "id", void 0);
94
+ __decorate([
95
+ (0, typeorm_1.Column)({ name: "type", nullable: false }),
96
+ __metadata("design:type", String)
97
+ ], Contact.prototype, "type", void 0);
98
+ __decorate([
99
+ (0, typeorm_1.Column)({ name: "phoneNumber", nullable: true }),
100
+ __metadata("design:type", String)
101
+ ], Contact.prototype, "phoneNumber", void 0);
102
+ __decorate([
103
+ (0, typeorm_1.Column)({ name: "name", nullable: true }),
104
+ __metadata("design:type", String)
105
+ ], Contact.prototype, "name", void 0);
106
+ __decorate([
107
+ (0, typeorm_1.Column)({ name: "lid", nullable: true }),
108
+ __metadata("design:type", String)
109
+ ], Contact.prototype, "lid", void 0);
110
+ __decorate([
111
+ (0, typeorm_1.OneToMany)(() => Participant, (participant) => participant.chat),
112
+ __metadata("design:type", Array)
113
+ ], Contact.prototype, "participants", void 0);
114
+ exports.Contact = Contact = __decorate([
115
+ (0, typeorm_1.Entity)(),
116
+ __metadata("design:paramtypes", [String])
117
+ ], Contact);
118
+ class ContactDAO extends DAO {
119
+ constructor(daos, em) {
120
+ super(daos, em);
121
+ }
122
+ // get will always return a contact, whether it exists or not.
123
+ async get(id) {
124
+ let contact = await this.em().findOne(Contact, { where: { id: id } });
125
+ return contact ? contact : this.em().save(new Contact(id));
126
+ }
127
+ async all() {
128
+ return this.em().find(Contact);
129
+ }
130
+ async create(id) {
131
+ // first check if the client exists.
132
+ let contact = await this.em().findOne(Contact, { where: { id: id } });
133
+ if (contact) {
134
+ return contact;
135
+ }
136
+ return this.em().save(new Contact(id));
137
+ }
138
+ async save(contact) {
139
+ return this.em().save(contact);
140
+ }
141
+ async getByLid(lid) {
142
+ return this.em().findOne(Contact, { where: { lid: lid } });
143
+ }
144
+ }
145
+ var Role;
146
+ (function (Role) {
147
+ Role["Admin"] = "Admin";
148
+ Role["SuperAdmin"] = "SuperAdmin";
149
+ Role["Member"] = "Member";
150
+ })(Role || (exports.Role = Role = {}));
151
+ // ******************* CHAT ********************** //
152
+ let Chat = class Chat {
153
+ constructor(id, lid, type, owner, name, description) {
154
+ this.id = id;
155
+ this.type = type;
156
+ this.lid = lid;
157
+ this.owner = owner;
158
+ this.name = name;
159
+ this.description = description;
160
+ }
161
+ addParticipant(contact, role) {
162
+ if (!this.participants) {
163
+ this.participants = [];
164
+ }
165
+ this.participants.push(new Participant(this, contact, role));
166
+ return this;
167
+ }
168
+ };
169
+ exports.Chat = Chat;
170
+ __decorate([
171
+ (0, typeorm_1.PrimaryColumn)({ name: "id" }),
172
+ __metadata("design:type", String)
173
+ ], Chat.prototype, "id", void 0);
174
+ __decorate([
175
+ (0, typeorm_1.Column)({ name: "type", nullable: true }),
176
+ __metadata("design:type", String)
177
+ ], Chat.prototype, "type", void 0);
178
+ __decorate([
179
+ (0, typeorm_1.Column)({ name: "lid", nullable: true }),
180
+ __metadata("design:type", String)
181
+ ], Chat.prototype, "lid", void 0);
182
+ __decorate([
183
+ (0, typeorm_1.Column)({ name: "owner", nullable: true }),
184
+ __metadata("design:type", String)
185
+ ], Chat.prototype, "owner", void 0);
186
+ __decorate([
187
+ (0, typeorm_1.Column)({ name: "name", nullable: true }),
188
+ __metadata("design:type", String)
189
+ ], Chat.prototype, "name", void 0);
190
+ __decorate([
191
+ (0, typeorm_1.Column)({ name: "description", nullable: true }),
192
+ __metadata("design:type", String)
193
+ ], Chat.prototype, "description", void 0);
194
+ __decorate([
195
+ (0, typeorm_1.OneToMany)(() => Participant, (participant) => participant.chat, { cascade: ["insert", "update"], onDelete: "CASCADE", orphanedRowAction: "delete" }),
196
+ __metadata("design:type", Array)
197
+ ], Chat.prototype, "participants", void 0);
198
+ __decorate([
199
+ (0, typeorm_1.OneToMany)(() => Message, (message) => message.chat),
200
+ __metadata("design:type", Array)
201
+ ], Chat.prototype, "messages", void 0);
202
+ exports.Chat = Chat = __decorate([
203
+ (0, typeorm_1.Entity)(),
204
+ __metadata("design:paramtypes", [String, String, String, String, String, String])
205
+ ], Chat);
206
+ class ChatDAO extends DAO {
207
+ constructor(daos, em) {
208
+ super(daos, em);
209
+ }
210
+ async get(id) {
211
+ // if the id ends with @lid, then do a lookup by lid instead.
212
+ return (id.endsWith("@lid"))
213
+ ? this.em().findOne(Chat, { where: { lid: id } })
214
+ : this.em().findOne(Chat, { where: { id: id } });
215
+ }
216
+ async all() {
217
+ return this.em().find(Chat, {});
218
+ }
219
+ async create(id, lid, type, owner, name, description) {
220
+ let chat = await this.em().findOneBy(Chat, { id: id });
221
+ if (chat) {
222
+ // update the chat if some properties changed.
223
+ if (chat.name !== name) {
224
+ chat.name = name;
225
+ return this.em().save(chat);
226
+ }
227
+ else {
228
+ return chat;
229
+ }
230
+ }
231
+ return this.em().save(new Chat(id, lid, type, owner, name, description));
232
+ }
233
+ async getWithParticipants(id) {
234
+ return this.em().findOne(Chat, {
235
+ where: { id },
236
+ relations: ['participants', 'participants.contact']
237
+ });
238
+ }
239
+ async getGroups() {
240
+ return this.em().find(Chat, {
241
+ where: { type: WhatsappClient_1.ChatType.Group },
242
+ relations: ['participants', 'participants.contact']
243
+ });
244
+ }
245
+ async save(chat) {
246
+ return this.em().save(chat);
247
+ }
248
+ async delete(chatId) {
249
+ const chat = await this.em().findOne(Chat, { where: { id: chatId }, relations: ['participants'] });
250
+ if (chat) {
251
+ await this.em().remove(chat);
252
+ }
253
+ }
254
+ async removeParticipants(chatId, contactIds) {
255
+ const chat = await this.em().findOne(Chat, {
256
+ where: { id: chatId },
257
+ relations: ['participants', 'participants.contact']
258
+ });
259
+ if (!chat)
260
+ return;
261
+ chat.participants = chat.participants.filter(p => !contactIds.includes(p.contact.id));
262
+ await this.em().save(chat);
263
+ }
264
+ async updateParticipantRole(chatId, contactId, role) {
265
+ const chat = await this.em().findOne(Chat, {
266
+ where: { id: chatId },
267
+ relations: ['participants', 'participants.contact']
268
+ });
269
+ if (!chat)
270
+ return;
271
+ const participant = chat.participants.find(p => p.contact.id === contactId);
272
+ if (participant) {
273
+ participant.role = role;
274
+ await this.em().save(participant);
275
+ }
276
+ }
277
+ async updateParticipantLabel(chatId, contactId, label) {
278
+ const chat = await this.em().findOne(Chat, {
279
+ where: { id: chatId },
280
+ relations: ['participants', 'participants.contact']
281
+ });
282
+ if (!chat)
283
+ return;
284
+ const participant = chat.participants.find(p => p.contact.id === contactId);
285
+ if (participant) {
286
+ participant.label = label;
287
+ await this.em().save(participant);
288
+ }
289
+ }
290
+ }
291
+ // ******************* PARTICIPANT *************************** //
292
+ let Participant = class Participant {
293
+ constructor(chat, contact, role) {
294
+ this.chat = chat;
295
+ this.contact = contact;
296
+ this.role = role;
297
+ }
298
+ };
299
+ __decorate([
300
+ (0, typeorm_1.PrimaryGeneratedColumn)({ name: "id" }),
301
+ __metadata("design:type", String)
302
+ ], Participant.prototype, "id", void 0);
303
+ __decorate([
304
+ (0, typeorm_1.ManyToOne)(() => Chat, (chat) => chat.participants),
305
+ __metadata("design:type", Chat)
306
+ ], Participant.prototype, "chat", void 0);
307
+ __decorate([
308
+ (0, typeorm_1.ManyToOne)(() => Contact, (contact) => contact.participants),
309
+ __metadata("design:type", Contact)
310
+ ], Participant.prototype, "contact", void 0);
311
+ __decorate([
312
+ (0, typeorm_1.Column)({ nullable: true }),
313
+ __metadata("design:type", String)
314
+ ], Participant.prototype, "role", void 0);
315
+ __decorate([
316
+ (0, typeorm_1.Column)({ type: "varchar", nullable: true }),
317
+ __metadata("design:type", Object)
318
+ ], Participant.prototype, "label", void 0);
319
+ Participant = __decorate([
320
+ (0, typeorm_1.Entity)(),
321
+ __metadata("design:paramtypes", [Chat, Contact, String])
322
+ ], Participant);
323
+ // ******************* MESSAGES ********************** //
324
+ let Message = class Message {
325
+ constructor(id, chat, timestamp, type, payload) {
326
+ this.id = id;
327
+ this.chat = chat;
328
+ this.timestamp = timestamp;
329
+ this.type = type;
330
+ this.payload = payload;
331
+ }
332
+ };
333
+ exports.Message = Message;
334
+ __decorate([
335
+ (0, typeorm_1.PrimaryColumn)({ name: "id" }),
336
+ __metadata("design:type", String)
337
+ ], Message.prototype, "id", void 0);
338
+ __decorate([
339
+ (0, typeorm_1.ManyToOne)(() => Chat, (chat) => chat.messages),
340
+ __metadata("design:type", Chat)
341
+ ], Message.prototype, "chat", void 0);
342
+ __decorate([
343
+ (0, typeorm_1.Column)({ nullable: true }),
344
+ __metadata("design:type", Number)
345
+ ], Message.prototype, "timestamp", void 0);
346
+ __decorate([
347
+ (0, typeorm_1.Column)({ nullable: true }),
348
+ __metadata("design:type", String)
349
+ ], Message.prototype, "type", void 0);
350
+ __decorate([
351
+ (0, typeorm_1.Column)({ nullable: true }),
352
+ __metadata("design:type", String)
353
+ ], Message.prototype, "payload", void 0);
354
+ exports.Message = Message = __decorate([
355
+ (0, typeorm_1.Entity)(),
356
+ __metadata("design:paramtypes", [String, Chat, Number, String, String])
357
+ ], Message);
358
+ class MessageDAO extends DAO {
359
+ constructor(daos, em) {
360
+ super(daos, em);
361
+ }
362
+ async get(id) {
363
+ return this.em().findOne(Message, { where: { id: id } });
364
+ }
365
+ async all() {
366
+ return this.em().find(Message);
367
+ }
368
+ async create(chat, id, timestamp, type, payload) {
369
+ // first check if the client exists.
370
+ let message = await this.em().findOneBy(Message, { id: id, chat: chat });
371
+ if (message) {
372
+ let modified = true;
373
+ if (message.timestamp !== timestamp) {
374
+ message.timestamp = timestamp;
375
+ modified = true;
376
+ }
377
+ if (message.type !== type) {
378
+ message.type = type;
379
+ modified = true;
380
+ }
381
+ if (message.payload !== payload) {
382
+ message.payload = payload;
383
+ modified = true;
384
+ }
385
+ if (modified) {
386
+ await this.em().save(message);
387
+ }
388
+ return message;
389
+ }
390
+ return this.em().save(new Message(id, chat, timestamp, type, payload));
391
+ }
392
+ }
393
+ var MessageType;
394
+ (function (MessageType) {
395
+ MessageType["Text"] = "Text";
396
+ MessageType["Unknown"] = "Unknown";
397
+ MessageType["Image"] = "Image";
398
+ MessageType["Video"] = "Video";
399
+ MessageType["Document"] = "Document";
400
+ MessageType["Template"] = "Template";
401
+ MessageType["ExtendedText"] = "ExtendedText";
402
+ MessageType["Album"] = "Album";
403
+ MessageType["Stub"] = "Stub";
404
+ MessageType["Contact"] = "Contact";
405
+ MessageType["Interactive"] = "Interactive";
406
+ MessageType["Location"] = "Location";
407
+ MessageType["LiveLocation"] = "LiveLocation";
408
+ })(MessageType || (exports.MessageType = MessageType = {}));
Binary file
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@theotherwillembotha/node-red-whatsapp",
3
+ "version": "0.0.55",
4
+ "description": "Node-RED nodes for WhatsApp messaging via the Baileys library.",
5
+ "author": "Willem Botha (@theotherwillembotha)",
6
+ "license": "ISC",
7
+ "keywords": [
8
+ "node-red",
9
+ "whatsapp",
10
+ "baileys",
11
+ "messaging",
12
+ "chat"
13
+ ],
14
+ "main": "./build/index.js",
15
+ "exports": "./build/index.js",
16
+ "scripts": {
17
+ "test": "echo \"Error: no test specified\" && exit 1",
18
+ "build": "npm run clean && tsc && npm run generate-nodes && npm run copy-files",
19
+ "clean": "rm -rf ./build",
20
+ "typeorm": "typeorm-ts-node-commonjs",
21
+ "generate-nodes": "node build/GenerateNodes.js",
22
+ "copy-files": "cp -r ./icons ./build/"
23
+ },
24
+ "files": [
25
+ "build/",
26
+ "icons/",
27
+ "LICENSE",
28
+ "README.md"
29
+ ],
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/theotherwillembotha/nodered_whatsapp.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/theotherwillembotha/nodered_whatsapp/issues"
39
+ },
40
+ "homepage": "https://github.com/theotherwillembotha/nodered_whatsapp#readme",
41
+ "engines": {
42
+ "node": ">=18",
43
+ "nodered": ">=4.0.0"
44
+ },
45
+ "dependencies": {
46
+ "@theotherwillembotha/node-red-plugincore": "^0.0.55",
47
+ "baileys": "7.0.0-rc11",
48
+ "handlebars": "^4.7.8",
49
+ "node-cache": "^5.1.2",
50
+ "qrcode": "^1.5.4",
51
+ "sql.js": "^1.13.0",
52
+ "typeorm": "^0.3.28",
53
+ "uuid": "^13.0.0"
54
+ },
55
+ "devDependencies": {
56
+ "@theotherwillembotha/node-red-plugincore": "../nodered_plugincore",
57
+ "@types/node": "^22.15.16",
58
+ "@types/node-red": "~1.3.5",
59
+ "@types/qrcode": "^1.5.6",
60
+ "ts-node": "^10.9.2"
61
+ },
62
+ "node-red": {
63
+ "version": ">=4.0.0",
64
+ "nodes": {
65
+ "whatsapp": "./build/Nodes.js"
66
+ },
67
+ "plugins": {
68
+ "whatsapp": "./build/Plugins.js"
69
+ }
70
+ }
71
+ }