@cogitator-ai/channels 0.2.5 → 0.4.0

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 (133) hide show
  1. package/README.md +142 -40
  2. package/dist/assistant-config.d.ts +1 -0
  3. package/dist/assistant-config.d.ts.map +1 -1
  4. package/dist/assistant-config.js +1 -0
  5. package/dist/assistant-config.js.map +1 -1
  6. package/dist/channels/discord.d.ts +4 -0
  7. package/dist/channels/discord.d.ts.map +1 -1
  8. package/dist/channels/discord.js +123 -59
  9. package/dist/channels/discord.js.map +1 -1
  10. package/dist/channels/slack.d.ts +9 -0
  11. package/dist/channels/slack.d.ts.map +1 -1
  12. package/dist/channels/slack.js +153 -34
  13. package/dist/channels/slack.js.map +1 -1
  14. package/dist/channels/telegram.d.ts +13 -0
  15. package/dist/channels/telegram.d.ts.map +1 -1
  16. package/dist/channels/telegram.js +206 -111
  17. package/dist/channels/telegram.js.map +1 -1
  18. package/dist/channels/terminal.d.ts +10 -0
  19. package/dist/channels/terminal.d.ts.map +1 -1
  20. package/dist/channels/terminal.js +46 -10
  21. package/dist/channels/terminal.js.map +1 -1
  22. package/dist/channels/webchat.d.ts +7 -2
  23. package/dist/channels/webchat.d.ts.map +1 -1
  24. package/dist/channels/webchat.js +112 -50
  25. package/dist/channels/webchat.js.map +1 -1
  26. package/dist/channels/whatsapp.d.ts +19 -3
  27. package/dist/channels/whatsapp.d.ts.map +1 -1
  28. package/dist/channels/whatsapp.js +204 -66
  29. package/dist/channels/whatsapp.js.map +1 -1
  30. package/dist/cron.d.ts +2 -0
  31. package/dist/cron.d.ts.map +1 -0
  32. package/dist/cron.js +9 -0
  33. package/dist/cron.js.map +1 -0
  34. package/dist/envelope.d.ts.map +1 -1
  35. package/dist/envelope.js +7 -6
  36. package/dist/envelope.js.map +1 -1
  37. package/dist/formatters/code-protect.d.ts +2 -0
  38. package/dist/formatters/code-protect.d.ts.map +1 -0
  39. package/dist/formatters/code-protect.js +12 -0
  40. package/dist/formatters/code-protect.js.map +1 -0
  41. package/dist/formatters/markdown.d.ts +1 -1
  42. package/dist/formatters/markdown.d.ts.map +1 -1
  43. package/dist/formatters/markdown.js +79 -21
  44. package/dist/formatters/markdown.js.map +1 -1
  45. package/dist/formatters/whatsapp-markdown.d.ts.map +1 -1
  46. package/dist/formatters/whatsapp-markdown.js +7 -21
  47. package/dist/formatters/whatsapp-markdown.js.map +1 -1
  48. package/dist/gateway.d.ts +32 -3
  49. package/dist/gateway.d.ts.map +1 -1
  50. package/dist/gateway.js +275 -174
  51. package/dist/gateway.js.map +1 -1
  52. package/dist/heartbeat.d.ts +9 -2
  53. package/dist/heartbeat.d.ts.map +1 -1
  54. package/dist/heartbeat.js +121 -84
  55. package/dist/heartbeat.js.map +1 -1
  56. package/dist/inbound-debounce.js +2 -2
  57. package/dist/inbound-debounce.js.map +1 -1
  58. package/dist/index.d.ts +6 -3
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +2 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/media/audio-format.d.ts +3 -0
  63. package/dist/media/audio-format.d.ts.map +1 -0
  64. package/dist/media/audio-format.js +20 -0
  65. package/dist/media/audio-format.js.map +1 -0
  66. package/dist/media/deepgram-stt.d.ts +1 -1
  67. package/dist/media/deepgram-stt.d.ts.map +1 -1
  68. package/dist/media/deepgram-stt.js +4 -3
  69. package/dist/media/deepgram-stt.js.map +1 -1
  70. package/dist/media/media-processor.d.ts +12 -1
  71. package/dist/media/media-processor.d.ts.map +1 -1
  72. package/dist/media/media-processor.js +75 -18
  73. package/dist/media/media-processor.js.map +1 -1
  74. package/dist/media/whisper-api.d.ts.map +1 -1
  75. package/dist/media/whisper-api.js +21 -33
  76. package/dist/media/whisper-api.js.map +1 -1
  77. package/dist/media/whisper-local.d.ts +1 -0
  78. package/dist/media/whisper-local.d.ts.map +1 -1
  79. package/dist/media/whisper-local.js +106 -50
  80. package/dist/media/whisper-local.js.map +1 -1
  81. package/dist/message-queue.d.ts +1 -0
  82. package/dist/message-queue.d.ts.map +1 -1
  83. package/dist/message-queue.js +17 -10
  84. package/dist/message-queue.js.map +1 -1
  85. package/dist/middleware/auto-extract.d.ts +2 -0
  86. package/dist/middleware/auto-extract.d.ts.map +1 -1
  87. package/dist/middleware/auto-extract.js +94 -30
  88. package/dist/middleware/auto-extract.js.map +1 -1
  89. package/dist/middleware/dm-policy.d.ts +2 -1
  90. package/dist/middleware/dm-policy.d.ts.map +1 -1
  91. package/dist/middleware/dm-policy.js +26 -27
  92. package/dist/middleware/dm-policy.js.map +1 -1
  93. package/dist/middleware/owner-commands.d.ts +1 -1
  94. package/dist/middleware/owner-commands.d.ts.map +1 -1
  95. package/dist/middleware/owner-commands.js +8 -7
  96. package/dist/middleware/owner-commands.js.map +1 -1
  97. package/dist/middleware/pairing-codes.d.ts +12 -0
  98. package/dist/middleware/pairing-codes.d.ts.map +1 -0
  99. package/dist/middleware/pairing-codes.js +26 -0
  100. package/dist/middleware/pairing-codes.js.map +1 -0
  101. package/dist/middleware/pairing.d.ts +3 -3
  102. package/dist/middleware/pairing.d.ts.map +1 -1
  103. package/dist/middleware/pairing.js +18 -25
  104. package/dist/middleware/pairing.js.map +1 -1
  105. package/dist/middleware/rate-limit.d.ts +3 -1
  106. package/dist/middleware/rate-limit.d.ts.map +1 -1
  107. package/dist/middleware/rate-limit.js +21 -6
  108. package/dist/middleware/rate-limit.js.map +1 -1
  109. package/dist/runtime-builder.d.ts +11 -0
  110. package/dist/runtime-builder.d.ts.map +1 -1
  111. package/dist/runtime-builder.js +212 -62
  112. package/dist/runtime-builder.js.map +1 -1
  113. package/dist/simple-timer-store.d.ts +6 -0
  114. package/dist/simple-timer-store.d.ts.map +1 -1
  115. package/dist/simple-timer-store.js +8 -1
  116. package/dist/simple-timer-store.js.map +1 -1
  117. package/dist/stream-buffer.d.ts +14 -7
  118. package/dist/stream-buffer.d.ts.map +1 -1
  119. package/dist/stream-buffer.js +129 -84
  120. package/dist/stream-buffer.js.map +1 -1
  121. package/dist/tools/path-guard.d.ts +4 -0
  122. package/dist/tools/path-guard.d.ts.map +1 -0
  123. package/dist/tools/path-guard.js +53 -0
  124. package/dist/tools/path-guard.js.map +1 -0
  125. package/dist/tools/self-config.d.ts +12 -2
  126. package/dist/tools/self-config.d.ts.map +1 -1
  127. package/dist/tools/self-config.js +53 -16
  128. package/dist/tools/self-config.js.map +1 -1
  129. package/package.json +27 -21
  130. package/dist/media/index.d.ts +0 -7
  131. package/dist/media/index.d.ts.map +0 -1
  132. package/dist/media/index.js +0 -5
  133. package/dist/media/index.js.map +0 -1
@@ -3,19 +3,24 @@ export interface WebChatConfig {
3
3
  port: number;
4
4
  path?: string;
5
5
  auth?: (token: string) => boolean;
6
+ /** Maximum size of an incoming frame in bytes. Default: 1 MiB. */
7
+ maxPayload?: number;
6
8
  }
7
9
  export declare class WebChatChannel implements Channel {
8
10
  private readonly config;
9
11
  readonly type: ChannelType;
10
12
  private handler;
11
13
  private server;
12
- private clients;
14
+ private readonly clients;
13
15
  constructor(config: WebChatConfig);
14
16
  onMessage(handler: (msg: ChannelMessage) => Promise<void>): void;
15
17
  start(): Promise<void>;
18
+ private handleConnection;
16
19
  stop(): Promise<void>;
17
- sendText(channelId: string, text: string, _options?: SendOptions): Promise<string>;
20
+ private send;
21
+ sendText(channelId: string, text: string, options?: SendOptions): Promise<string>;
18
22
  editText(channelId: string, messageId: string, text: string): Promise<void>;
23
+ deleteMessage(channelId: string, messageId: string): Promise<void>;
19
24
  sendFile(channelId: string, file: Attachment): Promise<void>;
20
25
  sendTyping(channelId: string): Promise<void>;
21
26
  private onRawMessage;
@@ -1 +1 @@
1
- {"version":3,"file":"webchat.d.ts","sourceRoot":"","sources":["../../src/channels/webchat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,WAAW,EACX,UAAU,EACV,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAG7B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AASD,qBAAa,cAAe,YAAW,OAAO;IAMhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAa;IACvC,OAAO,CAAC,OAAO,CAAyD;IACxE,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,OAAO,CAAoC;gBAEtB,MAAM,EAAE,aAAa;IAElD,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IASlF,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAM3E,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5D,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAMpC,YAAY;CAuB3B;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAE7D"}
1
+ {"version":3,"file":"webchat.d.ts","sourceRoot":"","sources":["../../src/channels/webchat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,WAAW,EACX,UAAU,EACV,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAG7B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA4BD,qBAAa,cAAe,YAAW,OAAO;IAMhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IALnC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAa;IACvC,OAAO,CAAC,OAAO,CAAyD;IACxE,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;gBAE3B,MAAM,EAAE,aAAa;IAElD,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI1D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC5B,OAAO,CAAC,gBAAgB;IAiClB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAa3B,OAAO,CAAC,IAAI;IAON,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAYjF,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlE,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAa5D,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAIpC,YAAY;CAiB3B;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAE7D"}
@@ -1,5 +1,26 @@
1
1
  import { nanoid } from 'nanoid';
2
2
  const WS_OPEN = 1;
3
+ const DEFAULT_MAX_PAYLOAD = 1024 * 1024;
4
+ const POLICY_VIOLATION = 1008;
5
+ const GOING_AWAY = 1001;
6
+ function parsePayload(raw) {
7
+ let parsed;
8
+ try {
9
+ parsed = JSON.parse(raw);
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ if (typeof parsed !== 'object' || parsed === null)
15
+ return null;
16
+ const record = parsed;
17
+ if (typeof record.text !== 'string' || record.text.trim().length === 0)
18
+ return null;
19
+ return {
20
+ text: record.text,
21
+ ...(typeof record.id === 'string' && record.id ? { id: record.id } : {}),
22
+ };
23
+ }
3
24
  export class WebChatChannel {
4
25
  config;
5
26
  type = 'webchat';
@@ -13,89 +34,130 @@ export class WebChatChannel {
13
34
  this.handler = handler;
14
35
  }
15
36
  async start() {
16
- const { WebSocketServer } = await import('ws');
17
- const wss = new WebSocketServer({
37
+ if (this.server)
38
+ return;
39
+ let ws;
40
+ try {
41
+ ws = await import('ws');
42
+ }
43
+ catch {
44
+ throw new Error('ws is required for WebChat support. Install it: pnpm add ws');
45
+ }
46
+ const wss = new ws.WebSocketServer({
18
47
  port: this.config.port,
19
48
  path: this.config.path ?? '/ws',
49
+ maxPayload: this.config.maxPayload ?? DEFAULT_MAX_PAYLOAD,
50
+ });
51
+ await new Promise((resolve, reject) => {
52
+ const onError = (err) => {
53
+ wss.off('listening', onListening);
54
+ reject(err);
55
+ };
56
+ const onListening = () => {
57
+ wss.off('error', onError);
58
+ resolve();
59
+ };
60
+ wss.once('error', onError);
61
+ wss.once('listening', onListening);
62
+ });
63
+ wss.on('error', (err) => {
64
+ console.error('[webchat] Server error:', err.message);
20
65
  });
21
- wss.on('connection', (ws, req) => {
22
- const clientId = `webchat_${nanoid(8)}`;
23
- if (this.config.auth) {
24
- const url = new URL(req.url ?? '/', `http://localhost:${this.config.port}`);
25
- const token = url.searchParams.get('token') ?? '';
26
- if (!this.config.auth(token)) {
27
- ws.send(JSON.stringify({ type: 'error', message: 'unauthorized' }));
28
- return;
29
- }
66
+ wss.on('connection', (socket, req) => this.handleConnection(socket, req));
67
+ this.server = wss;
68
+ }
69
+ handleConnection(socket, req) {
70
+ if (this.config.auth) {
71
+ const url = new URL(req.url ?? '/', 'http://localhost');
72
+ const token = url.searchParams.get('token') ?? '';
73
+ if (!this.config.auth(token)) {
74
+ socket.send(JSON.stringify({ type: 'error', message: 'unauthorized' }));
75
+ socket.close(POLICY_VIOLATION, 'unauthorized');
76
+ return;
30
77
  }
31
- this.clients.set(clientId, ws);
32
- ws.send(JSON.stringify({ type: 'connected', clientId }));
33
- ws.on('message', (data) => {
34
- void this.onRawMessage(clientId, data.toString());
35
- });
36
- ws.on('close', () => {
37
- this.clients.delete(clientId);
78
+ }
79
+ const clientId = `webchat_${nanoid(8)}`;
80
+ this.clients.set(clientId, socket);
81
+ socket.send(JSON.stringify({ type: 'connected', clientId }));
82
+ socket.on('message', (data) => {
83
+ const raw = Array.isArray(data)
84
+ ? Buffer.concat(data).toString('utf-8')
85
+ : Buffer.from(data instanceof ArrayBuffer ? new Uint8Array(data) : data).toString('utf-8');
86
+ void this.onRawMessage(clientId, raw).catch((err) => {
87
+ console.error('[webchat] Message handler error:', err);
38
88
  });
39
89
  });
40
- this.server = wss;
90
+ socket.on('close', () => {
91
+ this.clients.delete(clientId);
92
+ });
93
+ socket.on('error', () => {
94
+ this.clients.delete(clientId);
95
+ });
41
96
  }
42
97
  async stop() {
43
- if (this.server) {
44
- this.server.close();
45
- this.server = null;
98
+ const server = this.server;
99
+ if (!server)
100
+ return;
101
+ this.server = null;
102
+ for (const socket of this.clients.values()) {
103
+ socket.close(GOING_AWAY, 'server shutting down');
46
104
  }
47
105
  this.clients.clear();
106
+ await new Promise((resolve) => server.close(() => resolve()));
48
107
  }
49
- async sendText(channelId, text, _options) {
108
+ send(channelId, payload) {
50
109
  const client = this.clients.get(channelId);
51
110
  if (client?.readyState !== WS_OPEN)
52
- return '';
111
+ return false;
112
+ client.send(JSON.stringify(payload));
113
+ return true;
114
+ }
115
+ async sendText(channelId, text, options) {
53
116
  const messageId = `msg_${nanoid(8)}`;
54
- client.send(JSON.stringify({ type: 'message', id: messageId, text }));
117
+ const delivered = this.send(channelId, {
118
+ type: 'message',
119
+ id: messageId,
120
+ text,
121
+ ...(options?.replyTo ? { replyTo: options.replyTo } : {}),
122
+ });
123
+ if (!delivered)
124
+ throw new Error(`WebChat client ${channelId} is not connected`);
55
125
  return messageId;
56
126
  }
57
127
  async editText(channelId, messageId, text) {
58
- const client = this.clients.get(channelId);
59
- if (client?.readyState !== WS_OPEN)
60
- return;
61
- client.send(JSON.stringify({ type: 'edit', id: messageId, text }));
128
+ this.send(channelId, { type: 'edit', id: messageId, text });
129
+ }
130
+ async deleteMessage(channelId, messageId) {
131
+ this.send(channelId, { type: 'delete', id: messageId });
62
132
  }
63
133
  async sendFile(channelId, file) {
64
- const client = this.clients.get(channelId);
65
- if (client?.readyState !== WS_OPEN)
66
- return;
67
- client.send(JSON.stringify({
134
+ if (!file.url && !file.buffer) {
135
+ throw new Error('Attachment must have either a buffer or a url');
136
+ }
137
+ this.send(channelId, {
68
138
  type: 'file',
69
139
  filename: file.filename,
70
140
  mimeType: file.mimeType,
71
- url: file.url,
72
- }));
141
+ ...(file.url ? { url: file.url } : {}),
142
+ ...(file.buffer ? { data: Buffer.from(file.buffer).toString('base64') } : {}),
143
+ });
73
144
  }
74
145
  async sendTyping(channelId) {
75
- const client = this.clients.get(channelId);
76
- if (client?.readyState !== WS_OPEN)
77
- return;
78
- client.send(JSON.stringify({ type: 'typing' }));
146
+ this.send(channelId, { type: 'typing' });
79
147
  }
80
148
  async onRawMessage(clientId, raw) {
81
149
  if (!this.handler)
82
150
  return;
83
- let parsed;
84
- try {
85
- parsed = JSON.parse(raw);
86
- }
87
- catch {
88
- return;
89
- }
90
- if (!parsed.text)
151
+ const payload = parsePayload(raw);
152
+ if (!payload)
91
153
  return;
92
154
  const msg = {
93
- id: parsed.id ?? `in_${nanoid(8)}`,
155
+ id: payload.id ?? `in_${nanoid(8)}`,
94
156
  channelType: 'webchat',
95
157
  channelId: clientId,
96
158
  userId: clientId,
97
- text: parsed.text,
98
- raw: parsed,
159
+ text: payload.text,
160
+ raw: payload,
99
161
  };
100
162
  await this.handler(msg);
101
163
  }
@@ -1 +1 @@
1
- {"version":3,"file":"webchat.js","sourceRoot":"","sources":["../../src/channels/webchat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webchat.js","sourceRoot":"","sources":["../../src/channels/webchat.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,11 @@
1
- import type { Attachment, Channel, ChannelMessage } from '@cogitator-ai/types';
1
+ import type { Attachment, Channel, ChannelMessage, SendOptions } from '@cogitator-ai/types';
2
2
  export interface WhatsAppChannelConfig {
3
3
  sessionPath?: string;
4
4
  qrCallback?: (qr: string) => void;
5
+ /**
6
+ * Render the pairing QR code in the terminal when no `qrCallback` is set.
7
+ * Requires the optional `qrcode-terminal` package. Default: true.
8
+ */
5
9
  printQr?: boolean;
6
10
  }
7
11
  type MessageHandler = (msg: ChannelMessage) => Promise<void>;
@@ -9,12 +13,24 @@ export declare class WhatsAppChannel implements Channel {
9
13
  readonly type = "whatsapp";
10
14
  private handler;
11
15
  private sock;
12
- private config;
16
+ private baileys;
17
+ private readonly config;
18
+ private readonly recent;
19
+ private stopped;
20
+ private reconnectAttempts;
21
+ private reconnectTimer;
13
22
  constructor(config?: WhatsAppChannelConfig);
14
23
  start(): Promise<void>;
24
+ private connect;
25
+ private handleConnectionUpdate;
26
+ private presentQr;
27
+ private extractText;
28
+ private extractAttachments;
29
+ private handleIncoming;
15
30
  stop(): Promise<void>;
16
31
  onMessage(handler: MessageHandler): void;
17
- sendText(channelId: string, text: string): Promise<string>;
32
+ private requireSocket;
33
+ sendText(channelId: string, text: string, options?: SendOptions): Promise<string>;
18
34
  editText(channelId: string, messageId: string, text: string): Promise<void>;
19
35
  sendFile(channelId: string, file: Attachment): Promise<void>;
20
36
  sendTyping(channelId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"whatsapp.d.ts","sourceRoot":"","sources":["../../src/channels/whatsapp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAG/E,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAgCD,KAAK,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7D,qBAAa,eAAgB,YAAW,OAAO;IAC7C,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,MAAM,CAAwB;gBAE1B,MAAM,GAAE,qBAA0B;IAIxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAwFtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIlC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO1D,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS3E,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAW5D,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAInD;AAED,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAEvE"}
1
+ {"version":3,"file":"whatsapp.d.ts","sourceRoot":"","sources":["../../src/channels/whatsapp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAEV,OAAO,EACP,cAAc,EACd,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAG7B,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAuED,KAAK,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAyB7D,qBAAa,eAAgB,YAAW,OAAO;IAC7C,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAA8B;IAC1C,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAwB;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqC;IAC5D,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAA8C;gBAExD,MAAM,GAAE,qBAA0B;IAIxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBd,OAAO;IA4BrB,OAAO,CAAC,sBAAsB;YA8BhB,SAAS;IAsBvB,OAAO,CAAC,WAAW;YAaL,kBAAkB;YAuBlB,cAAc;IAkCtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAIxC,OAAO,CAAC,aAAa;IAKf,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAajF,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3E,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAiC5D,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAInD;AAED,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAEvE"}
@@ -1,109 +1,247 @@
1
1
  import { markdownToWhatsApp } from '../formatters/whatsapp-markdown.js';
2
+ const MAX_RECENT_MESSAGES = 200;
3
+ const RECONNECT_BASE_MS = 1000;
4
+ const RECONNECT_MAX_MS = 60_000;
5
+ const MEDIA_KINDS = [
6
+ { key: 'imageMessage', type: 'image', fallbackMime: 'image/jpeg' },
7
+ { key: 'audioMessage', type: 'audio', fallbackMime: 'audio/ogg' },
8
+ { key: 'videoMessage', type: 'video', fallbackMime: 'video/mp4' },
9
+ { key: 'documentMessage', type: 'file', fallbackMime: 'application/octet-stream' },
10
+ ];
11
+ async function loadOptional(specifier) {
12
+ try {
13
+ return (await import(specifier));
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
2
19
  export class WhatsAppChannel {
3
20
  type = 'whatsapp';
4
21
  handler = null;
5
22
  sock = null;
23
+ baileys = null;
6
24
  config;
25
+ recent = new Map();
26
+ stopped = true;
27
+ reconnectAttempts = 0;
28
+ reconnectTimer = null;
7
29
  constructor(config = {}) {
8
30
  this.config = config;
9
31
  }
10
32
  async start() {
11
- let baileys;
12
- try {
13
- // @ts-expect-error optional peer dependency
14
- baileys = await import('@whiskeysockets/baileys');
15
- }
16
- catch {
33
+ if (this.sock)
34
+ return;
35
+ this.stopped = false;
36
+ const baileys = await loadOptional('@whiskeysockets/baileys');
37
+ if (!baileys) {
38
+ this.stopped = true;
17
39
  throw new Error('@whiskeysockets/baileys is required for WhatsApp. Install it: pnpm add @whiskeysockets/baileys');
18
40
  }
41
+ this.baileys = baileys;
42
+ await this.connect(baileys);
43
+ }
44
+ async connect(baileys) {
19
45
  const sessionPath = this.config.sessionPath ?? '.cogitator/whatsapp-session';
20
46
  const { state, saveCreds } = await baileys.useMultiFileAuthState(sessionPath);
21
- const sock = baileys.default({
22
- auth: state,
23
- printQRInTerminal: this.config.printQr ?? true,
24
- });
47
+ const sock = baileys.default({ auth: state });
25
48
  this.sock = sock;
26
- sock.ev.on('creds.update', saveCreds);
49
+ sock.ev.on('creds.update', () => {
50
+ void saveCreds().catch((err) => {
51
+ console.error('[whatsapp] Failed to persist credentials:', err);
52
+ });
53
+ });
27
54
  sock.ev.on('connection.update', (update) => {
28
- const { connection, qr } = update;
29
- if (qr && this.config.qrCallback) {
30
- this.config.qrCallback(qr);
31
- }
32
- if (connection === 'close') {
33
- const { lastDisconnect } = update;
34
- const statusCode = lastDisconnect?.error?.output?.statusCode;
35
- const loggedOut = statusCode === baileys.DisconnectReason.loggedOut;
36
- if (!loggedOut) {
37
- void this.start();
38
- }
39
- }
55
+ this.handleConnectionUpdate(sock, baileys, update);
40
56
  });
41
57
  sock.ev.on('messages.upsert', (upsert) => {
42
58
  const { messages, type } = upsert;
43
59
  if (type !== 'notify')
44
60
  return;
45
61
  for (const msg of messages) {
46
- if (msg.key.fromMe)
47
- continue;
48
- if (!msg.message)
49
- continue;
50
- const text = msg.message.conversation ?? msg.message.extendedTextMessage?.text ?? '';
51
- if (!text)
52
- continue;
53
- const jid = msg.key.remoteJid ?? '';
54
- const userId = msg.key.participant ?? jid;
55
- const isGroup = jid.endsWith('@g.us');
56
- const channelMsg = {
57
- id: msg.key.id ?? '',
58
- channelType: 'whatsapp',
59
- channelId: jid,
60
- userId: userId.split('@')[0],
61
- userName: msg.pushName ?? userId.split('@')[0],
62
- text,
63
- raw: msg,
64
- ...(isGroup ? { groupId: jid } : {}),
65
- };
66
- if (this.handler) {
67
- void this.handler(channelMsg);
68
- }
62
+ void this.handleIncoming(msg).catch((err) => {
63
+ console.error('[whatsapp] Message handler error:', err);
64
+ });
65
+ }
66
+ });
67
+ }
68
+ handleConnectionUpdate(sock, baileys, update) {
69
+ if (update.qr)
70
+ void this.presentQr(update.qr);
71
+ if (update.connection === 'open') {
72
+ this.reconnectAttempts = 0;
73
+ return;
74
+ }
75
+ if (update.connection !== 'close' || this.sock !== sock)
76
+ return;
77
+ this.sock = null;
78
+ const statusCode = update.lastDisconnect?.error?.output?.statusCode;
79
+ const loggedOut = statusCode === baileys.DisconnectReason.loggedOut;
80
+ if (this.stopped || loggedOut)
81
+ return;
82
+ const delay = Math.min(RECONNECT_BASE_MS * 2 ** this.reconnectAttempts, RECONNECT_MAX_MS);
83
+ this.reconnectAttempts++;
84
+ this.reconnectTimer = setTimeout(() => {
85
+ this.reconnectTimer = null;
86
+ if (this.stopped)
87
+ return;
88
+ void this.connect(baileys).catch((err) => {
89
+ console.error('[whatsapp] Reconnect failed:', err);
90
+ });
91
+ }, delay);
92
+ }
93
+ async presentQr(qr) {
94
+ if (this.config.qrCallback) {
95
+ this.config.qrCallback(qr);
96
+ return;
97
+ }
98
+ if (this.config.printQr === false)
99
+ return;
100
+ const qrTerminal = await loadOptional('qrcode-terminal');
101
+ const generator = qrTerminal?.default ?? qrTerminal;
102
+ if (generator?.generate) {
103
+ generator.generate(qr, { small: true });
104
+ return;
105
+ }
106
+ console.warn('[whatsapp] Scan required but qrcode-terminal is not installed (pnpm add qrcode-terminal). ' +
107
+ 'Pass qrCallback to render the QR code yourself. Raw QR payload:', qr);
108
+ }
109
+ extractText(msg) {
110
+ const m = msg.message;
111
+ if (!m)
112
+ return '';
113
+ return (m.conversation ??
114
+ m.extendedTextMessage?.text ??
115
+ m.imageMessage?.caption ??
116
+ m.videoMessage?.caption ??
117
+ m.documentMessage?.caption ??
118
+ '');
119
+ }
120
+ async extractAttachments(msg) {
121
+ const m = msg.message;
122
+ if (!m || !this.baileys)
123
+ return [];
124
+ const attachments = [];
125
+ for (const kind of MEDIA_KINDS) {
126
+ const media = m[kind.key];
127
+ if (!media)
128
+ continue;
129
+ try {
130
+ const buffer = await this.baileys.downloadMediaMessage(msg, 'buffer', {});
131
+ attachments.push({
132
+ type: kind.type,
133
+ mimeType: media.mimetype?.split(';')[0]?.trim() || kind.fallbackMime,
134
+ buffer,
135
+ ...(media.fileName ? { filename: media.fileName } : {}),
136
+ });
137
+ }
138
+ catch (err) {
139
+ console.error('[whatsapp] Failed to download media:', err);
69
140
  }
141
+ }
142
+ return attachments;
143
+ }
144
+ async handleIncoming(msg) {
145
+ if (msg.key.fromMe || !msg.message || !this.handler)
146
+ return;
147
+ const jid = msg.key.remoteJid ?? '';
148
+ const id = msg.key.id ?? '';
149
+ if (!jid || !id)
150
+ return;
151
+ const text = this.extractText(msg);
152
+ const attachments = await this.extractAttachments(msg);
153
+ if (!text && attachments.length === 0)
154
+ return;
155
+ this.recent.set(id, msg);
156
+ if (this.recent.size > MAX_RECENT_MESSAGES) {
157
+ const oldest = this.recent.keys().next().value;
158
+ if (oldest !== undefined)
159
+ this.recent.delete(oldest);
160
+ }
161
+ const sender = msg.key.participant ?? jid;
162
+ const userId = sender.split('@')[0];
163
+ const isGroup = jid.endsWith('@g.us');
164
+ await this.handler({
165
+ id,
166
+ channelType: 'whatsapp',
167
+ channelId: jid,
168
+ userId,
169
+ userName: msg.pushName ?? userId,
170
+ text,
171
+ raw: msg,
172
+ ...(isGroup ? { groupId: jid } : {}),
173
+ ...(attachments.length > 0 ? { attachments } : {}),
70
174
  });
71
175
  }
72
176
  async stop() {
177
+ this.stopped = true;
178
+ if (this.reconnectTimer) {
179
+ clearTimeout(this.reconnectTimer);
180
+ this.reconnectTimer = null;
181
+ }
73
182
  if (this.sock) {
74
- this.sock.end();
183
+ const sock = this.sock;
75
184
  this.sock = null;
185
+ sock.end();
76
186
  }
187
+ this.recent.clear();
77
188
  }
78
189
  onMessage(handler) {
79
190
  this.handler = handler;
80
191
  }
81
- async sendText(channelId, text) {
192
+ requireSocket() {
82
193
  if (!this.sock)
83
194
  throw new Error('WhatsApp not connected');
84
- const waText = markdownToWhatsApp(text);
85
- const sent = await this.sock.sendMessage(channelId, { text: waText });
86
- return sent.key.id ?? '';
195
+ return this.sock;
196
+ }
197
+ async sendText(channelId, text, options) {
198
+ const sock = this.requireSocket();
199
+ const quoted = options?.replyTo ? this.recent.get(options.replyTo) : undefined;
200
+ const sent = await sock.sendMessage(channelId, { text: markdownToWhatsApp(text) }, quoted ? { quoted } : undefined);
201
+ const id = sent?.key.id;
202
+ if (!id)
203
+ throw new Error('WhatsApp did not return a message id');
204
+ return id;
87
205
  }
88
206
  async editText(channelId, messageId, text) {
89
- if (!this.sock)
90
- return;
91
- const waText = markdownToWhatsApp(text);
92
- await this.sock.sendMessage(channelId, {
93
- text: waText,
94
- edit: { key: { remoteJid: channelId, id: messageId } },
207
+ const sock = this.requireSocket();
208
+ await sock.sendMessage(channelId, {
209
+ text: markdownToWhatsApp(text),
210
+ edit: { remoteJid: channelId, id: messageId, fromMe: true },
95
211
  });
96
212
  }
97
213
  async sendFile(channelId, file) {
98
- if (!this.sock)
99
- throw new Error('WhatsApp not connected');
100
- if (!file.buffer)
101
- return;
102
- await this.sock.sendMessage(channelId, {
103
- document: Buffer.from(file.buffer),
104
- mimetype: file.mimeType,
105
- fileName: file.filename ?? 'file',
106
- });
214
+ const sock = this.requireSocket();
215
+ let buffer;
216
+ if (file.buffer) {
217
+ buffer = Buffer.from(file.buffer);
218
+ }
219
+ else if (file.url) {
220
+ const res = await fetch(file.url);
221
+ if (!res.ok)
222
+ throw new Error(`Failed to download ${file.url}: HTTP ${res.status}`);
223
+ buffer = Buffer.from(await res.arrayBuffer());
224
+ }
225
+ else {
226
+ throw new Error('Attachment must have either a buffer or a url');
227
+ }
228
+ switch (file.type) {
229
+ case 'image':
230
+ await sock.sendMessage(channelId, { image: buffer, mimetype: file.mimeType });
231
+ return;
232
+ case 'audio':
233
+ await sock.sendMessage(channelId, { audio: buffer, mimetype: file.mimeType });
234
+ return;
235
+ case 'video':
236
+ await sock.sendMessage(channelId, { video: buffer, mimetype: file.mimeType });
237
+ return;
238
+ default:
239
+ await sock.sendMessage(channelId, {
240
+ document: buffer,
241
+ mimetype: file.mimeType,
242
+ fileName: file.filename ?? 'file',
243
+ });
244
+ }
107
245
  }
108
246
  async sendTyping(channelId) {
109
247
  if (!this.sock)