@shoru/kitten 0.0.1 → 0.0.2

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.
@@ -1,11 +1,10 @@
1
- import { DisconnectReason } from "baileys";
2
- import { Boom } from "@hapi/boom";
3
- import qrcode from "qrcode-terminal";
4
- import chalk from "chalk";
5
- import { logger } from "#internals.js";
6
- import { initSession } from "#auth.js";
7
- import { pauseSpinner } from "#utils.js";
8
- import { getConnectionConfig } from "./getConnectionConfig.js";
1
+ import { DisconnectReason } from 'baileys';
2
+ import { Boom } from '@hapi/boom';
3
+ import qrcode from 'qrcode-terminal';
4
+ import chalk from 'chalk';
5
+ import { logger, pino, pluginManager } from '#internals.js';
6
+ import { initSession, listSessions } from '#auth.js';
7
+ import { getConnectionConfig } from './getConnectionConfig.js';
9
8
 
10
9
  export const ConnectionState = Object.freeze({
11
10
  DISCONNECTED: 'disconnected',
@@ -17,33 +16,83 @@ export const ConnectionState = Object.freeze({
17
16
  class ConnectionError extends Error {
18
17
  constructor(message, { statusCode, recoverable = true } = {}) {
19
18
  super(message);
20
- this.name = "ConnectionError";
19
+ this.name = 'ConnectionError';
21
20
  this.statusCode = statusCode;
22
21
  this.recoverable = recoverable;
23
22
  }
24
23
  }
25
24
 
26
25
  const DISCONNECT_HANDLERS = new Map([
27
- [DisconnectReason.connectionClosed, { message: "Connection closed", recoverable: true }],
28
- [DisconnectReason.restartRequired, { message: "QR Scanned", recoverable: true }],
29
- [DisconnectReason.timedOut, { message: "Connection timed out", recoverable: true }],
30
- [DisconnectReason.connectionLost, { message: "Connection lost", recoverable: true }],
31
- [DisconnectReason.unavailableService, { message: "Service unavailable", recoverable: true }],
32
- [DisconnectReason.loggedOut, { message: "Session logged out", recoverable: true, deleteSession: true }],
33
- [DisconnectReason.forbidden, { message: "Account banned", recoverable: false, deleteSession: true }],
34
- [405, { message: "Not logged in", recoverable: true, deleteSession: true }],
26
+ [DisconnectReason.connectionClosed, { message: 'Connection closed', recoverable: true }],
27
+ [DisconnectReason.restartRequired, { message: 'QR Scanned', recoverable: true }],
28
+ [DisconnectReason.timedOut, { message: 'Connection timed out', recoverable: true }],
29
+ [DisconnectReason.connectionLost, { message: 'Connection lost', recoverable: true }],
30
+ [DisconnectReason.unavailableService, { message: 'Service unavailable', recoverable: true }],
31
+ [DisconnectReason.loggedOut, { message: 'Session logged out', recoverable: true, deleteSession: true }],
32
+ [DisconnectReason.forbidden, { message: 'Account banned', recoverable: false, deleteSession: true }],
33
+ [405, { message: 'Not logged in', recoverable: true, deleteSession: true }],
35
34
  ]);
36
35
 
36
+ const silentLogger = Object.freeze({
37
+ trace: () => {},
38
+ debug: () => {},
39
+ info: () => {},
40
+ warn: () => {},
41
+ error: () => {},
42
+ fatal: () => {},
43
+ prompt: () => {},
44
+ child: () => silentLogger,
45
+ });
46
+
47
+ const silentPino = pino({ level: 'silent' });
48
+
37
49
  export class Client {
50
+ static #registry = new Map();
51
+
52
+ static #isSyncing = false;
53
+ static #isConfiguring = false;
54
+
55
+ // Static Registry API
56
+
57
+ static get(id) {
58
+ return Client.#registry.get(id);
59
+ }
60
+
61
+ static has(id) {
62
+ return Client.#registry.has(id);
63
+ }
64
+
65
+ static get size() {
66
+ return Client.#registry.size;
67
+ }
68
+
69
+ static keys() {
70
+ return Client.#registry.keys();
71
+ }
72
+
73
+ static values() {
74
+ return Client.#registry.values();
75
+ }
76
+
77
+ static entries() {
78
+ return Client.#registry.entries();
79
+ }
80
+
81
+ static [Symbol.iterator]() {
82
+ return Client.#registry.values();
83
+ }
84
+
85
+ // Instance Properties
86
+
38
87
  sock = null;
39
88
  session = null;
40
89
  id = null;
41
90
 
42
- #flag = "";
91
+ #flag = '';
92
+ #plugins = null;
43
93
  #qr = null;
44
94
  #state = ConnectionState.DISCONNECTED;
45
- #cancelWait
46
- #isConfiguring = false;
95
+ #cancelWait = null;
47
96
  #hasConnectedOnce = false;
48
97
 
49
98
  #socketConfig = null;
@@ -58,6 +107,12 @@ export class Client {
58
107
  #maxRetries;
59
108
  #backoff;
60
109
 
110
+ // Options
111
+ #silent;
112
+ #sync;
113
+ #logger;
114
+
115
+ // Callbacks
61
116
  #onPairing;
62
117
  #onConnect;
63
118
  #onReconnect;
@@ -68,19 +123,24 @@ export class Client {
68
123
  const {
69
124
  id,
70
125
  maxRetries = 30,
71
- backoff = (attempt) => Math.min(1000 * Math.pow(2, attempt - 1), 60_000),
126
+ backoff = (attempt) => Math.min(1000 * 2 ** (attempt - 1), 60_000),
127
+ silent = false,
128
+ sync = false,
72
129
  onPairing = null,
73
130
  onConnect = null,
74
131
  onReconnect = null,
75
132
  onDisconnect = null,
76
133
  onStateChange = null,
77
- socketConfig = {}
134
+ socketConfig = {},
78
135
  } = options;
79
136
 
80
137
  this.id = id;
81
138
  this.#socketConfig = socketConfig;
82
139
  this.#maxRetries = maxRetries;
83
140
  this.#backoff = backoff;
141
+ this.#silent = silent;
142
+ this.#sync = sync;
143
+ this.#logger = silent ? silentLogger : logger;
84
144
  this.#onPairing = onPairing;
85
145
  this.#onConnect = onConnect;
86
146
  this.#onReconnect = onReconnect;
@@ -100,6 +160,20 @@ export class Client {
100
160
  return this.#reconnectAttempts;
101
161
  }
102
162
 
163
+ // Registry Management
164
+
165
+ #register() {
166
+ if (this.id != null) {
167
+ Client.#registry.set(this.id, this);
168
+ }
169
+ }
170
+
171
+ #unregister() {
172
+ if (this.id != null) {
173
+ Client.#registry.delete(this.id);
174
+ }
175
+ }
176
+
103
177
  // State Management
104
178
 
105
179
  #setState(newState) {
@@ -125,7 +199,7 @@ export class Client {
125
199
  try {
126
200
  callback({ ...data, client: this });
127
201
  } catch (err) {
128
- logger.error(err, `[${this.#flag}] Error in ${event} callback`);
202
+ this.#logger.error(err, `[${this.#flag}] Error in ${event} callback`);
129
203
  }
130
204
  });
131
205
  }
@@ -151,7 +225,6 @@ export class Client {
151
225
  async #initConnection() {
152
226
  this.#setState(ConnectionState.CONNECTING);
153
227
  this.#reconnectAttempts = 0;
154
-
155
228
  this.#pendingConnect = this.#createDeferred();
156
229
 
157
230
  try {
@@ -189,8 +262,12 @@ export class Client {
189
262
  async #createSocket() {
190
263
  this.#cleanupSocket();
191
264
 
265
+ const socketConfig = this.#silent
266
+ ? { ...this.#socketConfig, logger: silentPino }
267
+ : this.#socketConfig;
268
+
192
269
  const { sock, session } = await initSession({
193
- socketConfig: this.#socketConfig,
270
+ socketConfig,
194
271
  id: this.id,
195
272
  });
196
273
 
@@ -199,7 +276,7 @@ export class Client {
199
276
  this.id = session.id;
200
277
  this.#flag = `CLIENT-${session.id}`;
201
278
 
202
- this.sock.ev.on("connection.update", (update) => {
279
+ this.sock.ev.on('connection.update', (update) => {
203
280
  this.#handleConnectionUpdate(update);
204
281
  });
205
282
  }
@@ -210,54 +287,131 @@ export class Client {
210
287
  try {
211
288
  if (qr) {
212
289
  await this.#handleAuth(qr);
213
- } else if (connection === "open") {
214
- this.#onConnectionOpen();
215
- } else if (connection === "close") {
290
+ } else if (connection === 'open') {
291
+ await this.#onConnectionOpen();
292
+ } else if (connection === 'close') {
216
293
  await this.#onConnectionClose(lastDisconnect);
217
294
  }
218
295
  } catch (err) {
219
- logger.error(err, `[${this.#flag}] Error in connection update handler`);
296
+ this.#logger.error(err, `[${this.#flag}] Error in connection update handler`);
220
297
  this.#resolvePending(null, err);
221
298
  }
222
299
  }
223
300
 
224
- #onConnectionOpen() {
301
+ async #onConnectionOpen() {
225
302
  const wasReconnecting = this.#state === ConnectionState.RECONNECTING;
226
303
  this.#setState(ConnectionState.CONNECTED);
227
304
 
305
+ this.#register();
306
+
307
+ if (!this.#plugins || this.#plugins.destroyed) {
308
+ try {
309
+ this.#plugins = await pluginManager(this.sock);
310
+ } catch (err) {
311
+ this.#logger.error(err, `[${this.#flag}] Failed to initialize plugins`);
312
+ }
313
+ }
314
+
228
315
  const attempts = this.#reconnectAttempts;
229
316
  this.#reconnectAttempts = 0;
230
317
 
231
318
  if (wasReconnecting) {
232
319
  this.#emit('reconnect', { attempts });
233
- logger.debug(`[${this.#flag}] Reconnected after ${attempts} attempt(s)`);
320
+ this.#logger.debug(`[${this.#flag}] Reconnected after ${attempts} attempt(s)`);
234
321
  } else {
235
322
  this.#hasConnectedOnce = true;
236
323
  this.#emit('connect');
237
- logger.debug(`[${this.#flag}] Connected successfully`);
238
- this.#resolvePending({ sock: this.sock, session: this.session });
324
+ this.#logger.debug(`[${this.#flag}] Connected successfully`);
325
+ this.#resolvePending({ sock: this.sock, session: this.session, id: this.id });
326
+
327
+ if (!this.#sync) {
328
+ this.#syncOtherSessions();
329
+ }
239
330
  }
240
331
  }
241
332
 
333
+ // Automatic Session Synchronization
334
+
335
+ async #syncOtherSessions() {
336
+ if (Client.#isSyncing) return;
337
+ Client.#isSyncing = true;
338
+
339
+ try {
340
+ const allSessionIds = listSessions();
341
+ const otherSessionIds = allSessionIds.filter((id) => id !== this.id);
342
+
343
+ if (otherSessionIds.length === 0) {
344
+ this.#logger.debug(`[${this.#flag}] No other sessions to sync`);
345
+ return;
346
+ }
347
+
348
+ this.#logger.debug(
349
+ `[${this.#flag}] Syncing ${otherSessionIds.length} other session(s) in background`
350
+ );
351
+
352
+ const results = await Promise.allSettled(
353
+ otherSessionIds.map((sessionId) => this.#restoreSession(sessionId))
354
+ );
355
+
356
+ let successCount = 0;
357
+ let skipCount = 0;
358
+ let failCount = 0;
359
+
360
+ for (const result of results) {
361
+ if (result.status === 'fulfilled') {
362
+ if (result.value === true) successCount++;
363
+ else skipCount++;
364
+ } else {
365
+ failCount++;
366
+ }
367
+ }
368
+
369
+ this.#logger.debug(
370
+ `[${this.#flag}] Session sync complete: ${successCount} restored, ${skipCount} skipped, ${failCount} failed`
371
+ );
372
+ } catch (err) {
373
+ this.#logger.error(err, `[${this.#flag}] Error during session sync`);
374
+ } finally {
375
+ Client.#isSyncing = false;
376
+ }
377
+ }
378
+
379
+ async #restoreSession(sessionId) {
380
+ if (Client.has(sessionId)) {
381
+ return false;
382
+ }
383
+
384
+ const client = new Client({
385
+ id: sessionId,
386
+ silent: true,
387
+ sync: true,
388
+ maxRetries: 3,
389
+ });
390
+
391
+ await client.connect();
392
+ return true;
393
+ }
394
+
242
395
  async #onConnectionClose(lastDisconnect) {
243
396
  const disconnectInfo = this.#parseDisconnectReason(lastDisconnect);
244
397
  const { message, statusCode, recoverable, deleteSession } = disconnectInfo;
245
398
 
246
- if (message === "QR Scanned" && !this.#onPairing) {
399
+ if (message === 'QR Scanned' && !this.#onPairing && !this.#silent) {
247
400
  console.clear();
248
401
  }
249
402
 
250
403
  const level = recoverable ? 'debug' : 'warn';
251
-
252
- logger[level](`[${this.#flag}] Disconnected: ${message} (code: ${statusCode})`);
404
+ this.#logger[level](`[${this.#flag}] Disconnected: ${message} (code: ${statusCode})`);
253
405
 
254
406
  if (this.#hasConnectedOnce) {
255
407
  this.#emit('disconnect', { message, statusCode, recoverable });
256
408
  }
409
+
410
+ this.#unregister();
257
411
 
258
412
  if (deleteSession) {
259
413
  await this.session?.delete().catch((err) => {
260
- logger.error(err, `[${this.#flag}] Failed to delete session`);
414
+ this.#logger.error(err, `[${this.#flag}] Failed to delete session`);
261
415
  });
262
416
  }
263
417
 
@@ -282,7 +436,7 @@ export class Client {
282
436
  );
283
437
  this.#setState(ConnectionState.DISCONNECTED);
284
438
  this.#resolvePending(null, err);
285
- logger.error(err, `[${this.#flag}] ${err.message}`);
439
+ this.#logger.error(err, `[${this.#flag}] ${err.message}`);
286
440
  return;
287
441
  }
288
442
 
@@ -291,20 +445,22 @@ export class Client {
291
445
  }
292
446
 
293
447
  const delay = this.#backoff(this.#reconnectAttempts);
448
+ const retriesInfo =
449
+ this.#maxRetries !== Infinity
450
+ ? `(${this.#reconnectAttempts}/${this.#maxRetries})`
451
+ : '';
294
452
 
295
- const retriesInfo = this.#maxRetries !== Infinity ? `(${this.#reconnectAttempts}/${this.#maxRetries})` : '';
296
-
297
- logger.debug(`[${this.#flag}] ${reason}. Reconnecting in ${delay} ms`);
453
+ this.#logger.debug(`[${this.#flag}] ${reason}. Reconnecting in ${delay}ms`);
298
454
 
299
455
  const cancelled = await this.#wait(delay);
300
456
  if (cancelled || this.#isShuttingDown) return;
301
457
 
302
- logger.debug(`[${this.#flag}] Executing reconnect attempt ${retriesInfo}`);
458
+ this.#logger.debug(`[${this.#flag}] Executing reconnect attempt ${retriesInfo}`);
303
459
 
304
460
  try {
305
461
  await this.#createSocket();
306
462
  } catch (err) {
307
- logger.error(err, `[${this.#flag}] Socket creation failed during reconnect`);
463
+ this.#logger.error(err, `[${this.#flag}] Socket creation failed during reconnect`);
308
464
  }
309
465
  }
310
466
 
@@ -340,7 +496,19 @@ export class Client {
340
496
 
341
497
  async #handleAuth(qr) {
342
498
  this.#qr = qr;
343
- if (this.#isConfiguring) return;
499
+
500
+ if (this.#sync) {
501
+ const err = new ConnectionError('Authentication required for sync connection', {
502
+ recoverable: false,
503
+ });
504
+ this.#logger.debug(`[${this.#flag}] Sync connection requires auth, aborting`);
505
+ this.#cleanupSocket();
506
+ this.#setState(ConnectionState.DISCONNECTED);
507
+ this.#resolvePending(null, err);
508
+ return;
509
+ }
510
+
511
+ if (Client.#isConfiguring) return;
344
512
 
345
513
  if (typeof this.#onPairing === 'function') {
346
514
  const requestPairingCode = this.sock?.requestPairingCode?.bind(this.sock);
@@ -348,32 +516,46 @@ export class Client {
348
516
  return;
349
517
  }
350
518
 
351
- this.#isConfiguring = true;
352
- this.#authConfig ??= await pauseSpinner(getConnectionConfig);
353
- this.#isConfiguring = false;
519
+ if (this.#silent) {
520
+ return;
521
+ }
522
+
523
+ Client.#isConfiguring = true;
524
+ try {
525
+ this.#authConfig ??= await getConnectionConfig();
526
+ } finally {
527
+ Client.#isConfiguring = false;
528
+ }
354
529
 
355
- if (this.#authConfig.type === "pn") {
530
+ if (this.#authConfig.type === 'pn') {
356
531
  const code = await this.sock.requestPairingCode(this.#authConfig.pn);
357
- logger.prompt(this.#formatPairingCode(code));
532
+ this.#logger.prompt(this.#formatPairingCode(code));
358
533
  } else {
359
534
  qrcode.generate(this.#qr, { small: true });
360
- process.stdout.write("\n");
535
+ process.stdout.write('\n');
361
536
  }
362
537
  }
363
538
 
364
539
  #formatPairingCode(code) {
365
- const formatted = code.match(/.{1,4}/g)?.join(" ") ?? code;
366
- return `\n${chalk.green("> Your OTP Code: ")}${chalk.bold(formatted)}`;
540
+ const formatted = code.match(/.{1,4}/g)?.join(' ') ?? code;
541
+ return `\n${chalk.green('> Your OTP Code: ')}${chalk.bold(formatted)}`;
367
542
  }
368
543
 
369
544
  // Cleanup & Shutdown
370
545
 
371
546
  #cleanupSocket() {
547
+ if (this.#plugins && !this.#plugins.destroyed) {
548
+ this.#plugins.destroy();
549
+ this.#plugins = null;
550
+ }
551
+
372
552
  if (!this.sock) return;
373
553
 
374
554
  try {
375
555
  this.sock.ev.removeAllListeners();
376
- } catch { /* noop */ };
556
+ } catch {
557
+ /* noop */
558
+ }
377
559
 
378
560
  this.sock = null;
379
561
  }
@@ -393,6 +575,9 @@ export class Client {
393
575
  this.#clearReconnectTimer();
394
576
  this.#resolvePending(null, new Error('Client disconnected'));
395
577
 
578
+ // Unregister from registry
579
+ this.#unregister();
580
+
396
581
  this.#cleanupSocket();
397
582
  this.#setState(ConnectionState.DISCONNECTED);
398
583
 
@@ -406,7 +591,7 @@ export class Client {
406
591
  await this.disconnect();
407
592
  await this.session?.delete();
408
593
  } catch (err) {
409
- logger.error(err, `[${this.#flag}] Logging out failed: ${err.message}`)
594
+ this.#logger.error(err, `[${this.#flag}] Logging out failed`);
410
595
  }
411
596
  }
412
597
  }
@@ -1,8 +1,9 @@
1
1
  import { select, input } from "@inquirer/prompts";
2
2
  import chalk from "chalk";
3
3
  import { logger } from "#internals.js";
4
+ import { pauseSpinner } from "#utils.js";
4
5
 
5
- export const getConnectionConfig = async () => {
6
+ const connectionConfig = async () => {
6
7
  try {
7
8
  process.stdout.write("\n");
8
9
  const type = await select({
@@ -45,4 +46,6 @@ export const getConnectionConfig = async () => {
45
46
  logger.prompt(chalk.red("\nOperation cancelled"));
46
47
  process.exit(0);
47
48
  }
48
- };
49
+ };
50
+
51
+ export const getConnectionConfig = () => pauseSpinner(connectionConfig);
@@ -20,7 +20,20 @@ const db = {
20
20
  noMetaSync: false,
21
21
  };
22
22
 
23
+ const plugins = {
24
+ dir: 'plugins',
25
+ prefixes: ['.', '\\', '!'],
26
+ defaultEvent: 'messages.upsert',
27
+ hmr: {
28
+ enable: false,
29
+ debounce: 200,
30
+ debug: false
31
+ }
32
+ }
33
+
23
34
  export default {
24
35
  db,
25
- socket
36
+ socket,
37
+ plugins,
38
+ timeZone: 'Africa/Casablanca'
26
39
  }
@@ -0,0 +1,144 @@
1
+ import {
2
+ isJidGroup,
3
+ areJidsSameUser,
4
+ getDevice,
5
+ downloadMediaMessage,
6
+ getContentType,
7
+ isLidUser,
8
+ jidNormalizedUser
9
+ } from 'baileys';
10
+
11
+ import {
12
+ getTimeString,
13
+ isString,
14
+ toNumber,
15
+ toBase64,
16
+ getPN
17
+ } from '#utils.js';
18
+
19
+ const extractMessage = (message) => {
20
+ let type = getContentType(message);
21
+ let data = message?.[type];
22
+
23
+ // cases like viewonce or document messages etc
24
+ if (data?.message) {
25
+ const innerType = getContentType(data.message);
26
+ if (innerType) {
27
+ type = innerType;
28
+ data = data.message[type];
29
+ }
30
+ }
31
+ return [type, data];
32
+ };
33
+
34
+ const extractContent = (message = {}) => ({
35
+ body: message.text ?? message.caption ??
36
+ (isString(message) ? message : undefined),
37
+ mentions: message.contextInfo?.mentionedJid,
38
+ groupMentions: message.contextInfo?.groupMentions,
39
+ mimetype: message.mimetype,
40
+ fileName: message.fileName,
41
+ pageCount: message.pageCount,
42
+ fileLength: toNumber(message.fileLength),
43
+ hash: toBase64(message.fileSha256),
44
+ isViewOnce: message.viewOnce,
45
+ url: message.matchedText,
46
+ description: message.description,
47
+ thumbnail: message.jpegThumbnail,
48
+ });
49
+
50
+ const load = async (x) => downloadMediaMessage(x, 'buffer', {});
51
+
52
+ export const formatMessage = (sock, raw) => {
53
+ const myId = jidNormalizedUser(sock.user.lid);
54
+ const [type, messageData] = extractMessage(raw.message);
55
+
56
+ const {
57
+ pushName: name,
58
+ messageTimestamp,
59
+ participant: p1,
60
+ broadcast,
61
+ key,
62
+ key: {
63
+ remoteJid: roomId,
64
+ id, fromMe,
65
+ participant: p2,
66
+ }
67
+ } = raw;
68
+
69
+ const jid = fromMe ? myId : p2 || p1 || roomId;
70
+
71
+ const {
72
+ quotedMessage,
73
+ participant: quotedSender,
74
+ stanzaId: quotedId,
75
+ isForwarded,
76
+ forwardingScore,
77
+ } = messageData?.contextInfo || {};
78
+ const [quotedType, quotedData] = extractMessage(quotedMessage);
79
+
80
+ const quotedKey = {
81
+ id: quotedId,
82
+ participant: quotedSender,
83
+ remoteJid: roomId,
84
+ fromMe: areJidsSameUser(quotedSender, myId)
85
+ };
86
+
87
+ return {
88
+ type,
89
+ name,
90
+ id,
91
+ broadcast,
92
+ isForwarded,
93
+ forwardingScore,
94
+ fromMe,
95
+ jid,
96
+ roomId,
97
+ timestamp: toNumber(messageTimestamp),
98
+ isLid: isLidUser(jid),
99
+ device: getDevice(id),
100
+ isGroup: isJidGroup(roomId),
101
+ timeString: getTimeString(messageTimestamp),
102
+ ...extractContent(messageData),
103
+ key, raw,
104
+ contextInfo: {
105
+ stanzaId: id,
106
+ participant: jid,
107
+ remoteJid: roomId
108
+ },
109
+ load() {
110
+ return load(this.raw)
111
+ },
112
+ senderIs(id) {
113
+ return areJidsSameUser(this.jid, id)
114
+ },
115
+ pn() {
116
+ return getPN(sock, this.jid)
117
+ },
118
+ quoted: quotedData ? {
119
+ type: quotedType,
120
+ jid: quotedSender,
121
+ id: quotedId,
122
+ ...extractContent(quotedData),
123
+ key: quotedKey,
124
+ contextInfo: {
125
+ stanzaId: quotedId,
126
+ participant: quotedSender,
127
+ remoteJid: roomId
128
+ },
129
+ raw: {
130
+ key: quotedKey,
131
+ message: quotedMessage
132
+ },
133
+ load() {
134
+ return load(this.raw)
135
+ },
136
+ senderIs(id) {
137
+ return areJidsSameUser(this.jid, id)
138
+ },
139
+ pn() {
140
+ return getPN(sock, this.jid)
141
+ }
142
+ }: undefined,
143
+ }
144
+ }
@@ -0,0 +1,14 @@
1
+ import { formatMessage } from './format-message.js';
2
+
3
+ export const formatter = (wa, event, eventName) => {
4
+ eventName ??= 'messages.upsert';
5
+
6
+ switch (eventName) {
7
+ case 'messages.upsert':
8
+ return {
9
+ ...formatMessage(wa, event),
10
+ event: eventName
11
+ };
12
+ default: return event;
13
+ }
14
+ }
package/src/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export * from "./auth/index.js";
2
- export * from "./client/index.js";
3
- export * from "./internals/index.js";
4
- export * from "./utils/index.js";
1
+ export * from "#internals.js";
2
+ export * from "#utils.js";
3
+ export * from "#auth.js";
4
+ export * from "#client.js";
5
+ export * from "#formatter.js"