@sasadevofc/baileys 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/.github/workflows/publish.yml +21 -0
  2. package/README.md +1 -0
  3. package/dist/auth/pairing.d.ts +7 -0
  4. package/dist/auth/pairing.d.ts.map +1 -0
  5. package/dist/auth/pairing.js +13 -0
  6. package/dist/auth/pairing.js.map +1 -0
  7. package/dist/auth/state.d.ts +14 -0
  8. package/dist/auth/state.d.ts.map +1 -0
  9. package/dist/auth/state.js +61 -0
  10. package/dist/auth/state.js.map +1 -0
  11. package/dist/auth/store.d.ts +16 -0
  12. package/dist/auth/store.d.ts.map +1 -0
  13. package/dist/auth/store.js +22 -0
  14. package/dist/auth/store.js.map +1 -0
  15. package/dist/client.d.ts +41 -0
  16. package/dist/client.d.ts.map +1 -0
  17. package/dist/client.js +92 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/config.d.ts +3 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +12 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/connection/handshake.d.ts +8 -0
  24. package/dist/connection/handshake.d.ts.map +1 -0
  25. package/dist/connection/handshake.js +12 -0
  26. package/dist/connection/handshake.js.map +1 -0
  27. package/dist/connection/socket.d.ts +19 -0
  28. package/dist/connection/socket.d.ts.map +1 -0
  29. package/dist/connection/socket.js +99 -0
  30. package/dist/connection/socket.js.map +1 -0
  31. package/dist/connection/transport.d.ts +8 -0
  32. package/dist/connection/transport.d.ts.map +1 -0
  33. package/dist/connection/transport.js +21 -0
  34. package/dist/connection/transport.js.map +1 -0
  35. package/dist/message/decoder.d.ts +7 -0
  36. package/dist/message/decoder.d.ts.map +1 -0
  37. package/dist/message/decoder.js +19 -0
  38. package/dist/message/decoder.js.map +1 -0
  39. package/dist/message/encoder.d.ts +7 -0
  40. package/dist/message/encoder.d.ts.map +1 -0
  41. package/dist/message/encoder.js +14 -0
  42. package/dist/message/encoder.js.map +1 -0
  43. package/dist/message/handler.d.ts +18 -0
  44. package/dist/message/handler.d.ts.map +1 -0
  45. package/dist/message/handler.js +87 -0
  46. package/dist/message/handler.js.map +1 -0
  47. package/dist/plugins/command.d.ts +10 -0
  48. package/dist/plugins/command.d.ts.map +1 -0
  49. package/dist/plugins/command.js +36 -0
  50. package/dist/plugins/command.js.map +1 -0
  51. package/dist/plugins/plugin-base.d.ts +11 -0
  52. package/dist/plugins/plugin-base.d.ts.map +1 -0
  53. package/dist/plugins/plugin-base.js +35 -0
  54. package/dist/plugins/plugin-base.js.map +1 -0
  55. package/dist/types/auth.d.ts +29 -0
  56. package/dist/types/auth.d.ts.map +1 -0
  57. package/dist/types/auth.js +3 -0
  58. package/dist/types/auth.js.map +1 -0
  59. package/dist/types/events.d.ts +54 -0
  60. package/dist/types/events.d.ts.map +1 -0
  61. package/dist/types/events.js +3 -0
  62. package/dist/types/events.js.map +1 -0
  63. package/dist/types/messages.d.ts +30 -0
  64. package/dist/types/messages.d.ts.map +1 -0
  65. package/dist/types/messages.js +3 -0
  66. package/dist/types/messages.js.map +1 -0
  67. package/dist/types/plugin.d.ts +16 -0
  68. package/dist/types/plugin.d.ts.map +1 -0
  69. package/dist/types/plugin.js +3 -0
  70. package/dist/types/plugin.js.map +1 -0
  71. package/dist/types/socket.d.ts +16 -0
  72. package/dist/types/socket.d.ts.map +1 -0
  73. package/dist/types/socket.js +3 -0
  74. package/dist/types/socket.js.map +1 -0
  75. package/dist/utils/logger.d.ts +11 -0
  76. package/dist/utils/logger.d.ts.map +1 -0
  77. package/dist/utils/logger.js +14 -0
  78. package/dist/utils/logger.js.map +1 -0
  79. package/dist/utils/retry.d.ts +2 -0
  80. package/dist/utils/retry.d.ts.map +1 -0
  81. package/dist/utils/retry.js +18 -0
  82. package/dist/utils/retry.js.map +1 -0
  83. package/dist/utils/throttle.d.ts +2 -0
  84. package/dist/utils/throttle.d.ts.map +1 -0
  85. package/dist/utils/throttle.js +14 -0
  86. package/dist/utils/throttle.js.map +1 -0
  87. package/examples/basic-bot.ts +29 -0
  88. package/examples/command-bot.ts +19 -0
  89. package/package.json +58 -0
  90. package/src/auth/pairing.ts +11 -0
  91. package/src/auth/state.ts +66 -0
  92. package/src/auth/store.ts +26 -0
  93. package/src/client.ts +119 -0
  94. package/src/config.ts +10 -0
  95. package/src/connection/handshake.ts +10 -0
  96. package/src/connection/socket.ts +109 -0
  97. package/src/connection/transport.ts +20 -0
  98. package/src/message/decoder.ts +13 -0
  99. package/src/message/encoder.ts +9 -0
  100. package/src/message/handler.ts +91 -0
  101. package/src/plugins/command.ts +40 -0
  102. package/src/plugins/plugin-base.ts +36 -0
  103. package/src/types/auth.ts +30 -0
  104. package/src/types/events.ts +60 -0
  105. package/src/types/messages.ts +34 -0
  106. package/src/types/plugin.ts +20 -0
  107. package/src/types/socket.ts +16 -0
  108. package/src/utils/logger.ts +10 -0
  109. package/src/utils/retry.ts +12 -0
  110. package/src/utils/throttle.ts +9 -0
  111. package/tsconfig.json +19 -0
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@sasadevofc/baileys",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "Ultra-modern WhatsApp Web automation library for bots and tools. Multi-device. Fast. Developer-first.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.mjs",
10
+ "require": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "engines": {
15
+ "node": ">=18"
16
+ },
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "dev": "ts-node src/index.ts",
20
+ "lint": "eslint src --ext .ts",
21
+ "test": "jest --coverage",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "keywords": [
25
+ "whatsapp",
26
+ "whatsapp-web",
27
+ "whatsapp-bot",
28
+ "whatsapp-api",
29
+ "baileys",
30
+ "sasadev",
31
+ "multi-device",
32
+ "automation"
33
+ ],
34
+ "author": "SASA DEV <dev@sasadev.com>",
35
+ "license": "Apache-2.0",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/sasadev/baileys.git"
39
+ },
40
+ "dependencies": {
41
+ "protobufjs": "^7.2.5",
42
+ "pino": "^8.16.0",
43
+ "ws": "^8.14.2",
44
+ "uuid": "^9.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^20.5.0",
48
+ "@types/ws": "^8.5.5",
49
+ "@types/uuid": "^9.0.2",
50
+ "@typescript-eslint/eslint-plugin": "^6.4.0",
51
+ "@typescript-eslint/parser": "^6.4.0",
52
+ "eslint": "^8.47.0",
53
+ "jest": "^29.6.2",
54
+ "ts-jest": "^29.1.1",
55
+ "ts-node": "^10.9.1",
56
+ "typescript": "^5.1.6"
57
+ }
58
+ }
@@ -0,0 +1,11 @@
1
+ import { BaileysClient } from '../client';
2
+ export class PairingHelper {
3
+ private client: BaileysClient;
4
+ constructor(client: BaileysClient) { this.client = client; }
5
+
6
+ async requestCode(phoneNumber: string): Promise<string> {
7
+ // Placeholder: would call WhatsApp pairing API
8
+ const code = '12345';
9
+ return code;
10
+ }
11
+ }
@@ -0,0 +1,66 @@
1
+ import { BaileysClient } from '../client';
2
+ import { AuthState, Credentials } from '../types/auth';
3
+ import { AuthStore } from './store';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import { PairingHelper } from './pairing';
6
+
7
+ export class AuthManager {
8
+ private client: BaileysClient;
9
+ private store: AuthStore;
10
+ private state: AuthState | null = null;
11
+
12
+ constructor(client: BaileysClient) {
13
+ this.client = client;
14
+ this.store = new AuthStore(); // can be replaced with custom store
15
+ }
16
+
17
+ async loadSession(sessionId?: string): Promise<AuthState | null> {
18
+ const id = sessionId || 'default';
19
+ const data = await this.store.load(id);
20
+ if (data) {
21
+ this.state = data;
22
+ return data;
23
+ }
24
+ return null;
25
+ }
26
+
27
+ async createSession(): Promise<AuthState> {
28
+ // Generate new keys (simplified)
29
+ const state: AuthState = {
30
+ creds: {
31
+ clientId: uuidv4(),
32
+ serverToken: '',
33
+ clientToken: '',
34
+ encKey: Buffer.alloc(32),
35
+ macKey: Buffer.alloc(32),
36
+ },
37
+ keys: {
38
+ registrationId: Math.floor(Math.random() * 16384),
39
+ identityKey: new Uint8Array(32),
40
+ signedPreKey: {
41
+ keyId: 1,
42
+ keyPair: { public: new Uint8Array(32), private: new Uint8Array(32) },
43
+ signature: new Uint8Array(64),
44
+ },
45
+ preKeys: [],
46
+ },
47
+ };
48
+ this.state = state;
49
+ await this.store.save('default', state);
50
+ return state;
51
+ }
52
+
53
+ async saveSession(sessionId?: string) {
54
+ if (!this.state) return;
55
+ await this.store.save(sessionId || 'default', this.state);
56
+ }
57
+
58
+ getCredentials(): Credentials | undefined {
59
+ return this.state?.creds;
60
+ }
61
+
62
+ // Pairing code helper
63
+ async startPairing(phoneNumber: string): Promise<string> {
64
+ return new PairingHelper(this.client).requestCode(phoneNumber);
65
+ }
66
+ }
@@ -0,0 +1,26 @@
1
+ import { AuthState } from '../types/auth';
2
+
3
+ export interface IAuthStore {
4
+ load(sessionId: string): Promise<AuthState | null>;
5
+ save(sessionId: string, state: AuthState): Promise<void>;
6
+ delete(sessionId: string): Promise<void>;
7
+ }
8
+
9
+ /**
10
+ * Default in‑memory store. For production use a persistent store (JSON file, DB, etc.)
11
+ */
12
+ export class AuthStore implements IAuthStore {
13
+ private cache = new Map<string, AuthState>();
14
+
15
+ async load(sessionId: string): Promise<AuthState | null> {
16
+ return this.cache.get(sessionId) || null;
17
+ }
18
+
19
+ async save(sessionId: string, state: AuthState): Promise<void> {
20
+ this.cache.set(sessionId, state);
21
+ }
22
+
23
+ async delete(sessionId: string): Promise<void> {
24
+ this.cache.delete(sessionId);
25
+ }
26
+ }
package/src/client.ts ADDED
@@ -0,0 +1,119 @@
1
+ import { EventEmitter } from 'events';
2
+ import { BaileysEventMap, ConnectionUpdate } from './types/events';
3
+ import { AuthState } from './types/auth';
4
+ import { SocketConfig, WALoginMethod } from './types/socket';
5
+ import { AuthManager } from './auth/state';
6
+ import { ConnectionManager } from './connection/socket';
7
+ import { MessageHandler } from './message/handler';
8
+ import { PluginManager } from './plugins/plugin-base';
9
+ import { Logger } from './utils/logger';
10
+ import { retry } from './utils/retry';
11
+ import { throttle } from './utils/throttle';
12
+ import { defaultConfig } from './config';
13
+
14
+ export class BaileysClient extends EventEmitter {
15
+ public auth: AuthManager;
16
+ public connection: ConnectionManager;
17
+ public messages: MessageHandler;
18
+ public plugins: PluginManager;
19
+ public logger: Logger;
20
+ private config: SocketConfig;
21
+
22
+ constructor(config: Partial<SocketConfig> = {}) {
23
+ super();
24
+ this.config = { ...defaultConfig, ...config };
25
+ this.logger = new Logger({ level: 'info' });
26
+ this.auth = new AuthManager(this);
27
+ this.connection = new ConnectionManager(this);
28
+ this.messages = new MessageHandler(this);
29
+ this.plugins = new PluginManager(this);
30
+
31
+ // Wire up internal events
32
+ this.connection.on('update', (update: ConnectionUpdate) => {
33
+ this.emit('connection.update', update);
34
+ });
35
+
36
+ this.messages.on('message', (msg) => {
37
+ // Run middleware pipeline then emit
38
+ this.plugins.runMiddleware(msg, () => {
39
+ this.emit('message.new', msg);
40
+ });
41
+ });
42
+
43
+ this.messages.on('update', (update) => this.emit('message.update', update));
44
+ this.messages.on('receipt', (receipt) => this.emit('message.receipt', receipt));
45
+ this.messages.on('group.participants.update', (upd) => this.emit('group.participants.update', upd));
46
+ this.messages.on('presence', (upd) => this.emit('presence.update', upd));
47
+ this.messages.on('contacts', (contacts) => this.emit('contacts.update', contacts));
48
+ this.messages.on('reaction', (reaction) => this.emit('reaction', reaction));
49
+ }
50
+
51
+ /** Start the connection process */
52
+ async connect(): Promise<void> {
53
+ try {
54
+ await this.connection.connect();
55
+ } catch (err) {
56
+ this.logger.error('Failed to connect:', err);
57
+ this.emit('error', err as Error);
58
+ }
59
+ }
60
+
61
+ /** Disconnect gracefully */
62
+ async disconnect(): Promise<void> {
63
+ await this.connection.disconnect();
64
+ }
65
+
66
+ /** Request QR code for login (if loginMethod = 'qr') */
67
+ async requestQR(): Promise<string> {
68
+ return this.connection.requestQR();
69
+ }
70
+
71
+ /** Request pairing code (if loginMethod = 'pairing_code') */
72
+ async requestPairingCode(phoneNumber: string): Promise<string> {
73
+ return this.connection.requestPairingCode(phoneNumber);
74
+ }
75
+
76
+ /** Send a text message */
77
+ async sendMessage(jid: string, content: string, options?: { mentions?: string[]; quotedId?: string }) {
78
+ const msg = await this.messages.sendText(jid, content, options);
79
+ return msg;
80
+ }
81
+
82
+ /** Send media (buffer or URL) */
83
+ async sendMedia(jid: string, type: 'image'|'video'|'audio'|'document', media: Buffer | string, options?: any) {
84
+ return this.messages.sendMedia(jid, type, media, options);
85
+ }
86
+
87
+ /** ... other convenient methods delegate to feature modules */
88
+ async deleteMessage(jid: string, messageId: string) {
89
+ return this.messages.deleteMessage(jid, messageId);
90
+ }
91
+
92
+ async editMessage(jid: string, messageId: string, newContent: string) {
93
+ return this.messages.editMessage(jid, messageId, newContent);
94
+ }
95
+
96
+ async reactToMessage(jid: string, messageId: string, reaction: string) {
97
+ return this.messages.react(jid, messageId, reaction);
98
+ }
99
+
100
+ async downloadMedia(message: any): Promise<Buffer> {
101
+ return this.messages.downloadMedia(message);
102
+ }
103
+
104
+ // Event emitter overrides with typed signatures
105
+ on<K extends keyof BaileysEventMap>(event: K, listener: BaileysEventMap[K]): this;
106
+ on(event: string, listener: (...args: any[]) => void): this {
107
+ return super.on(event, listener);
108
+ }
109
+
110
+ emit<K extends keyof BaileysEventMap>(event: K, ...args: Parameters<BaileysEventMap[K]>): boolean;
111
+ emit(event: string, ...args: any[]): boolean {
112
+ return super.emit(event, ...args);
113
+ }
114
+
115
+ once<K extends keyof BaileysEventMap>(event: K, listener: BaileysEventMap[K]): this;
116
+ once(event: string, listener: (...args: any[]) => void): this {
117
+ return super.once(event, listener);
118
+ }
119
+ }
package/src/config.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { SocketConfig } from './types/socket';
2
+
3
+ export const defaultConfig: SocketConfig = {
4
+ wsUrl: 'wss://web.whatsapp.com/ws/md',
5
+ autoReconnect: true,
6
+ maxReconnectAttempts: -1,
7
+ reconnectDelay: 3000,
8
+ keepAliveInterval: 10000,
9
+ loginMethod: 'qr',
10
+ };
@@ -0,0 +1,10 @@
1
+ import { BaileysClient } from '../client';
2
+ import WebSocket from 'ws';
3
+ export class Handshake {
4
+ private client: BaileysClient;
5
+ constructor(client: BaileysClient) { this.client = client; }
6
+ async perform(ws: WebSocket): Promise<void> {
7
+ // Noise handshake placeholder; would exchange keys, etc.
8
+ return;
9
+ }
10
+ }
@@ -0,0 +1,109 @@
1
+ import WebSocket from 'ws';
2
+ import { EventEmitter } from 'events';
3
+ import { BaileysClient } from '../client';
4
+ import { ConnectionUpdate } from '../types/events';
5
+ import { Transport } from './transport';
6
+ import { Handshake } from './handshake';
7
+
8
+ export class ConnectionManager extends EventEmitter {
9
+ private client: BaileysClient;
10
+ private ws: WebSocket | null = null;
11
+ private transport: Transport;
12
+ private handshake: Handshake;
13
+ private reconnectAttempts = 0;
14
+ private keepAliveTimer?: NodeJS.Timeout;
15
+
16
+ constructor(client: BaileysClient) {
17
+ super();
18
+ this.client = client;
19
+ this.transport = new Transport(client);
20
+ this.handshake = new Handshake(client);
21
+ }
22
+
23
+ async connect(): Promise<void> {
24
+ if (this.ws?.readyState === WebSocket.OPEN) return;
25
+ const { wsUrl, autoReconnect, reconnectDelay } = this.client['config'];
26
+
27
+ const doConnect = async () => {
28
+ this.emit('update', { status: 'connecting' });
29
+ const ws = new WebSocket(wsUrl);
30
+ this.ws = ws;
31
+ ws.binaryType = 'arraybuffer';
32
+
33
+ return new Promise<void>((resolve, reject) => {
34
+ ws.on('open', async () => {
35
+ this.emit('update', { status: 'open' });
36
+ this.reconnectAttempts = 0;
37
+ this.startKeepAlive();
38
+ // Perform noise handshake (stub)
39
+ await this.handshake.perform(ws);
40
+ resolve();
41
+ });
42
+
43
+ ws.on('message', (data: ArrayBuffer) => {
44
+ const decoded = this.transport.decode(data);
45
+ // route to MessageHandler
46
+ this.client.messages.processIncoming(decoded);
47
+ });
48
+
49
+ ws.on('close', (code) => {
50
+ this.stopKeepAlive();
51
+ this.emit('update', { status: 'close', error: new Error(`Closed with code ${code}`) });
52
+ if (autoReconnect && (!this.client['config'].maxReconnectAttempts || this.reconnectAttempts < this.client['config'].maxReconnectAttempts)) {
53
+ setTimeout(() => {
54
+ this.reconnectAttempts++;
55
+ this.connect().catch(() => {});
56
+ }, reconnectDelay * Math.min(this.reconnectAttempts, 10));
57
+ }
58
+ });
59
+
60
+ ws.on('error', (err) => {
61
+ reject(err);
62
+ this.emit('update', { status: 'error', error: err });
63
+ });
64
+ });
65
+ };
66
+
67
+ return doConnect();
68
+ }
69
+
70
+ async disconnect(): Promise<void> {
71
+ this.stopKeepAlive();
72
+ if (this.ws) {
73
+ this.ws.close();
74
+ this.ws = null;
75
+ }
76
+ }
77
+
78
+ async requestQR(): Promise<string> {
79
+ // Simulated QR generation (real implementation would ask WhatsApp servers)
80
+ const qr = 'data:image/png;base64,iVBORw0KGgo...'; // placeholder
81
+ this.emit('update', { status: 'qr', qr });
82
+ return qr;
83
+ }
84
+
85
+ async requestPairingCode(phoneNumber: string): Promise<string> {
86
+ const code = '12345'; // placeholder
87
+ this.emit('update', { status: 'pairing', pairingCode: code });
88
+ return code;
89
+ }
90
+
91
+ private startKeepAlive() {
92
+ this.keepAliveTimer = setInterval(() => {
93
+ this.ws?.ping();
94
+ }, this.client['config'].keepAliveInterval);
95
+ }
96
+
97
+ private stopKeepAlive() {
98
+ if (this.keepAliveTimer) clearInterval(this.keepAliveTimer);
99
+ }
100
+
101
+ // Outgoing message send raw
102
+ sendRaw(data: Uint8Array) {
103
+ if (this.ws?.readyState === WebSocket.OPEN) {
104
+ this.ws.send(data);
105
+ } else {
106
+ throw new Error('WebSocket not connected');
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,20 @@
1
+ import { BaileysClient } from '../client';
2
+ // Simplified protobuf encode/decode using protobufjs/minimal
3
+ // Real implementation would use fully defined .proto files.
4
+ export class Transport {
5
+ private client: BaileysClient;
6
+ constructor(client: BaileysClient) {
7
+ this.client = client;
8
+ }
9
+
10
+ decode(buffer: ArrayBuffer): any {
11
+ // Placeholder: parse binary into WAMessage format
12
+ // In a real lib this would use protobuf definitions
13
+ return JSON.parse(Buffer.from(buffer).toString('utf8'));
14
+ }
15
+
16
+ encode(message: any): Uint8Array {
17
+ // Placeholder
18
+ return Buffer.from(JSON.stringify(message));
19
+ }
20
+ }
@@ -0,0 +1,13 @@
1
+ import { BaileysClient } from '../client';
2
+
3
+ export class Decoder {
4
+ constructor(private client: BaileysClient) {}
5
+ decode(raw: any): any {
6
+ // Placeholder – real implementation would deserialize protobuf
7
+ try {
8
+ return JSON.parse(Buffer.from(raw).toString('utf8'));
9
+ } catch {
10
+ return {};
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,9 @@
1
+ import { BaileysClient } from '../client';
2
+
3
+ export class Encoder {
4
+ constructor(private client: BaileysClient) {}
5
+ encode(message: any): Uint8Array {
6
+ // Placeholder – real implementation would serialize to protobuf
7
+ return Buffer.from(JSON.stringify(message));
8
+ }
9
+ }
@@ -0,0 +1,91 @@
1
+ import { EventEmitter } from 'events';
2
+ import { BaileysClient } from '../client';
3
+ import { TextMessage, MediaMessage, WAMessage, WAMessageUpdate } from '../types/messages';
4
+ import { Encoder } from './encoder';
5
+ import { Decoder } from './decoder';
6
+
7
+ export class MessageHandler extends EventEmitter {
8
+ private client: BaileysClient;
9
+ private encoder: Encoder;
10
+ private decoder: Decoder;
11
+
12
+ constructor(client: BaileysClient) {
13
+ super();
14
+ this.client = client;
15
+ this.encoder = new Encoder(client);
16
+ this.decoder = new Decoder(client);
17
+ }
18
+
19
+ processIncoming(raw: any) {
20
+ const msg = this.decoder.decode(raw);
21
+ // Emit appropriate events based on msg type
22
+ if (msg.type === 'message') {
23
+ this.emit('message', msg.content);
24
+ } else if (msg.type === 'receipt') {
25
+ this.emit('receipt', msg.content);
26
+ } else if (msg.type === 'presence') {
27
+ this.emit('presence', msg.content);
28
+ } else if (msg.type === 'groupParticipants') {
29
+ this.emit('group.participants.update', msg.content);
30
+ } else if (msg.type === 'contacts') {
31
+ this.emit('contacts', msg.content);
32
+ } else if (msg.type === 'reaction') {
33
+ this.emit('reaction', msg.content);
34
+ } else if (msg.type === 'messageUpdate') {
35
+ this.emit('update', msg.content);
36
+ }
37
+ }
38
+
39
+ async sendText(jid: string, body: string, opts?: any): Promise<TextMessage> {
40
+ const msg: TextMessage = {
41
+ id: this.generateId(),
42
+ from: this.client.auth.getCredentials()?.clientId || 'me',
43
+ to: jid,
44
+ timestamp: Date.now(),
45
+ messageType: 'text',
46
+ body,
47
+ mentionedJids: opts?.mentions,
48
+ quotedMessage: opts?.quotedId ? { id: opts.quotedId } : undefined,
49
+ };
50
+ const encoded = this.encoder.encode(msg);
51
+ this.client.connection.sendRaw(encoded);
52
+ return msg;
53
+ }
54
+
55
+ async sendMedia(jid: string, type: string, media: Buffer | string, opts?: any): Promise<MediaMessage> {
56
+ // similar but with media upload
57
+ const msg: MediaMessage = {
58
+ id: this.generateId(),
59
+ from: 'me',
60
+ to: jid,
61
+ timestamp: Date.now(),
62
+ messageType: type as any,
63
+ mimeType: opts?.mimeType || 'application/octet-stream',
64
+ mediaUrl: typeof media === 'string' ? media : undefined,
65
+ };
66
+ const encoded = this.encoder.encode(msg);
67
+ this.client.connection.sendRaw(encoded);
68
+ return msg;
69
+ }
70
+
71
+ async deleteMessage(jid: string, messageId: string): Promise<void> {
72
+ // ... encode delete
73
+ }
74
+
75
+ async editMessage(jid: string, messageId: string, newBody: string): Promise<void> {
76
+ // ... encode edit
77
+ }
78
+
79
+ async react(jid: string, messageId: string, reaction: string): Promise<void> {
80
+ // ...
81
+ }
82
+
83
+ async downloadMedia(message: WAMessage): Promise<Buffer> {
84
+ // ...
85
+ return Buffer.alloc(0);
86
+ }
87
+
88
+ private generateId(): string {
89
+ return 'msg_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
90
+ }
91
+ }
@@ -0,0 +1,40 @@
1
+ import { BaileysClient } from '../client';
2
+ import { CommandHandler, CommandContext } from '../types/plugin';
3
+ import { TextMessage } from '../types/messages';
4
+
5
+ export class CommandFramework {
6
+ private client: BaileysClient;
7
+ private commands: Map<string, CommandHandler> = new Map();
8
+ private prefix: string;
9
+
10
+ constructor(client: BaileysClient, prefix = '/') {
11
+ this.client = client;
12
+ this.prefix = prefix;
13
+
14
+ // Register middleware to intercept text messages
15
+ client.plugins.use(async (ctx, next) => {
16
+ if (ctx.message.messageType === 'text') {
17
+ const textMsg = ctx.message as TextMessage;
18
+ if (textMsg.body.startsWith(this.prefix)) {
19
+ const [commandName, ...args] = textMsg.body.slice(this.prefix.length).trim().split(/\s+/);
20
+ const handler = this.commands.get(commandName.toLowerCase());
21
+ if (handler) {
22
+ const cmdCtx: CommandContext = {
23
+ client: this.client,
24
+ message: textMsg,
25
+ args,
26
+ commandName: commandName.toLowerCase(),
27
+ };
28
+ await handler(cmdCtx);
29
+ return; // prevent further processing
30
+ }
31
+ }
32
+ }
33
+ await next();
34
+ });
35
+ }
36
+
37
+ register(command: string, handler: CommandHandler) {
38
+ this.commands.set(command.toLowerCase(), handler);
39
+ }
40
+ }
@@ -0,0 +1,36 @@
1
+ import { BaileysClient } from '../client';
2
+ import { Middleware, NextFunction } from '../types/plugin';
3
+ import { WAMessage } from '../types/messages';
4
+
5
+ export class PluginManager {
6
+ private client: BaileysClient;
7
+ private middlewares: Middleware[] = [];
8
+
9
+ constructor(client: BaileysClient) {
10
+ this.client = client;
11
+ }
12
+
13
+ use(fn: Middleware) {
14
+ this.middlewares.push(fn);
15
+ }
16
+
17
+ async runMiddleware(msg: WAMessage, done: NextFunction) {
18
+ const ctx = { client: this.client, message: msg };
19
+ const stack = [...this.middlewares];
20
+
21
+ const next: NextFunction = async (err?: Error) => {
22
+ if (err) return done(err);
23
+ const fn = stack.shift();
24
+ if (fn) {
25
+ try {
26
+ await fn(ctx, next);
27
+ } catch (e) {
28
+ done(e as Error);
29
+ }
30
+ } else {
31
+ done();
32
+ }
33
+ };
34
+ await next();
35
+ }
36
+ }
@@ -0,0 +1,30 @@
1
+ export interface Credentials {
2
+ clientId: string;
3
+ serverToken: string;
4
+ clientToken: string;
5
+ encKey: Buffer;
6
+ macKey: Buffer;
7
+ }
8
+
9
+ export interface AuthState {
10
+ creds: Credentials;
11
+ /** Multi‑device pre‑keys */
12
+ keys: {
13
+ registrationId: number;
14
+ identityKey: Uint8Array;
15
+ signedPreKey: {
16
+ keyId: number;
17
+ keyPair: KeyPair;
18
+ signature: Uint8Array;
19
+ };
20
+ preKeys: Array<{
21
+ keyId: number;
22
+ keyPair: KeyPair;
23
+ }>;
24
+ };
25
+ }
26
+
27
+ export interface KeyPair {
28
+ public: Uint8Array;
29
+ private: Uint8Array;
30
+ }