@moxxy/plugin-channel-whatsapp 0.27.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 (81) hide show
  1. package/LICENSE +21 -0
  2. package/dist/auth-state.d.ts +66 -0
  3. package/dist/auth-state.d.ts.map +1 -0
  4. package/dist/auth-state.js +99 -0
  5. package/dist/auth-state.js.map +1 -0
  6. package/dist/baileys-socket.d.ts +10 -0
  7. package/dist/baileys-socket.d.ts.map +1 -0
  8. package/dist/baileys-socket.js +93 -0
  9. package/dist/baileys-socket.js.map +1 -0
  10. package/dist/channel/turn-runner.d.ts +58 -0
  11. package/dist/channel/turn-runner.d.ts.map +1 -0
  12. package/dist/channel/turn-runner.js +130 -0
  13. package/dist/channel/turn-runner.js.map +1 -0
  14. package/dist/channel/voice-handler.d.ts +27 -0
  15. package/dist/channel/voice-handler.d.ts.map +1 -0
  16. package/dist/channel/voice-handler.js +55 -0
  17. package/dist/channel/voice-handler.js.map +1 -0
  18. package/dist/channel.d.ts +105 -0
  19. package/dist/channel.d.ts.map +1 -0
  20. package/dist/channel.js +459 -0
  21. package/dist/channel.js.map +1 -0
  22. package/dist/consent-prompt.d.ts +9 -0
  23. package/dist/consent-prompt.d.ts.map +1 -0
  24. package/dist/consent-prompt.js +28 -0
  25. package/dist/consent-prompt.js.map +1 -0
  26. package/dist/consent.d.ts +22 -0
  27. package/dist/consent.d.ts.map +1 -0
  28. package/dist/consent.js +40 -0
  29. package/dist/consent.js.map +1 -0
  30. package/dist/index.d.ts +26 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +211 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/keys.d.ts +39 -0
  35. package/dist/keys.d.ts.map +1 -0
  36. package/dist/keys.js +86 -0
  37. package/dist/keys.js.map +1 -0
  38. package/dist/message-gate.d.ts +50 -0
  39. package/dist/message-gate.d.ts.map +1 -0
  40. package/dist/message-gate.js +150 -0
  41. package/dist/message-gate.js.map +1 -0
  42. package/dist/pair-flow.d.ts +12 -0
  43. package/dist/pair-flow.d.ts.map +1 -0
  44. package/dist/pair-flow.js +120 -0
  45. package/dist/pair-flow.js.map +1 -0
  46. package/dist/permission.d.ts +29 -0
  47. package/dist/permission.d.ts.map +1 -0
  48. package/dist/permission.js +78 -0
  49. package/dist/permission.js.map +1 -0
  50. package/dist/setup-wizard.d.ts +13 -0
  51. package/dist/setup-wizard.d.ts.map +1 -0
  52. package/dist/setup-wizard.js +127 -0
  53. package/dist/setup-wizard.js.map +1 -0
  54. package/dist/socket.d.ts +72 -0
  55. package/dist/socket.d.ts.map +1 -0
  56. package/dist/socket.js +22 -0
  57. package/dist/socket.js.map +1 -0
  58. package/package.json +99 -0
  59. package/src/auth-state.test.ts +103 -0
  60. package/src/auth-state.ts +161 -0
  61. package/src/baileys-socket.ts +154 -0
  62. package/src/channel/turn-runner.test.ts +31 -0
  63. package/src/channel/turn-runner.ts +156 -0
  64. package/src/channel/voice-handler.ts +83 -0
  65. package/src/channel.test.ts +344 -0
  66. package/src/channel.ts +571 -0
  67. package/src/consent-prompt.ts +28 -0
  68. package/src/consent.test.ts +56 -0
  69. package/src/consent.ts +48 -0
  70. package/src/index.ts +284 -0
  71. package/src/keys.test.ts +59 -0
  72. package/src/keys.ts +78 -0
  73. package/src/message-gate.test.ts +121 -0
  74. package/src/message-gate.ts +184 -0
  75. package/src/pair-flow.ts +133 -0
  76. package/src/permission.test.ts +94 -0
  77. package/src/permission.ts +114 -0
  78. package/src/setup-wizard.ts +162 -0
  79. package/src/socket.test.ts +17 -0
  80. package/src/socket.ts +89 -0
  81. package/src/subcommands.test.ts +198 -0
@@ -0,0 +1,105 @@
1
+ import type { ClientSession as Session } from '@moxxy/sdk';
2
+ import type { Channel, ChannelHandle, ChannelStartOptsBase } from '@moxxy/sdk';
3
+ import type { VaultStore } from '@moxxy/plugin-vault';
4
+ import { type WhatsAppAuthStorage } from './auth-state.js';
5
+ import { type WhatsAppPermissionController } from './permission.js';
6
+ import { type WhatsAppSocketFactory } from './socket.js';
7
+ export interface WhatsAppChannelLogger {
8
+ debug?(msg: string, meta?: Record<string, unknown>): void;
9
+ info?(msg: string, meta?: Record<string, unknown>): void;
10
+ warn?(msg: string, meta?: Record<string, unknown>): void;
11
+ }
12
+ export interface WhatsAppChannelOptions {
13
+ readonly vault: VaultStore;
14
+ readonly logger?: WhatsAppChannelLogger;
15
+ /** Debounce window for streaming edits (ms). Default 3000 — deliberately
16
+ * slower than Telegram/Slack; see the turn-runner rationale. */
17
+ readonly editFrameMs?: number;
18
+ /** Injectable transport (tests). Defaults to the real Baileys socket. */
19
+ readonly socketFactory?: WhatsAppSocketFactory;
20
+ /** Injectable auth-state backend. Defaults to `~/.moxxy/whatsapp-auth`. */
21
+ readonly authStorage?: WhatsAppAuthStorage;
22
+ /** Extra allow-listed JIDs from channel config/flags. */
23
+ readonly allowedJids?: ReadonlyArray<string>;
24
+ /** Consecutive reconnect attempts before giving up. Default 5. */
25
+ readonly maxReconnectAttempts?: number;
26
+ /** Reconnect backoff base (ms). Default 2000; tests shrink it. */
27
+ readonly reconnectBaseMs?: number;
28
+ }
29
+ export interface WhatsAppStartOpts extends ChannelStartOptsBase {
30
+ readonly session: Session;
31
+ /** Open in pairing mode: an unlinked start publishes QR payloads instead of
32
+ * refusing. Set by `moxxy channels whatsapp pair` / the setup wizard. */
33
+ readonly pair?: boolean;
34
+ /** Running GUI-supervised on a dedicated runner (desktop Channels panel) —
35
+ * equivalent to `pair` for the unlinked case, so the desktop can render the
36
+ * QR from the status file instead of a terminal. */
37
+ readonly dedicated?: boolean;
38
+ }
39
+ export declare class WhatsAppChannel implements Channel<WhatsAppStartOpts> {
40
+ readonly name = "whatsapp";
41
+ private readonly permission;
42
+ private readonly opts;
43
+ private readonly turns;
44
+ private session;
45
+ private model;
46
+ private socket;
47
+ private storage;
48
+ private handle;
49
+ private logUnsub;
50
+ private stopping;
51
+ private resolveRunning;
52
+ private rejectRunning;
53
+ private reconnectAttempts;
54
+ private reconnectTimer;
55
+ private pairMode;
56
+ private pairedAnnounced;
57
+ private qrPayload;
58
+ private socketOpen;
59
+ private ownerJid;
60
+ private readonly allowSet;
61
+ private currentJid;
62
+ private lastJid;
63
+ /** Recent OWN outbound message ids — Baileys echoes our sends back via
64
+ * `messages.upsert`; without this the bot would converse with itself. */
65
+ private readonly sentIds;
66
+ private readonly connectListeners;
67
+ private readonly pairedListeners;
68
+ constructor(opts: WhatsAppChannelOptions);
69
+ get permissionResolver(): WhatsAppPermissionController['resolver'];
70
+ /** Connect value published to control surfaces (`connect.kind: 'qr'`): the
71
+ * CURRENT Baileys QR pairing payload while unlinked (it rotates; each
72
+ * rotation re-publishes via onConnectChange), null once linked. */
73
+ get requestUrl(): string | null;
74
+ /** Linked + socket open — control surfaces swap the QR for "Connected". */
75
+ get connected(): boolean;
76
+ /** Fires once when a fresh QR link completes (the pair flow waits on this). */
77
+ onPaired(listener: (ownerJid: string) => void): () => void;
78
+ start(startOpts: WhatsAppStartOpts): Promise<ChannelHandle>;
79
+ private connect;
80
+ private handleConnectionUpdate;
81
+ private handleClose;
82
+ private scheduleReconnect;
83
+ private fail;
84
+ private teardown;
85
+ private handleInbound;
86
+ private handleText;
87
+ private handleAudio;
88
+ private resetSession;
89
+ private runUserTurn;
90
+ /** Every outbound send goes through here so its id lands in the echo set. */
91
+ private send;
92
+ private sendPermissionPrompt;
93
+ private recordSentId;
94
+ private mirrorForeignTurn;
95
+ private notifyConnectChange;
96
+ private emitPaired;
97
+ private rebuildAllowList;
98
+ /**
99
+ * Run a handler detached from the socket's event dispatch (a whole user turn
100
+ * must not block Baileys' event loop). Errors are logged here — nothing above
101
+ * awaits the promise.
102
+ */
103
+ private dispatchInBackground;
104
+ }
105
+ //# sourceMappingURL=channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,459 @@
1
+ import { newTurnId } from '@moxxy/core';
2
+ import { TurnCoordinator } from '@moxxy/channel-kit';
3
+ import { moxxyPath } from '@moxxy/sdk/server';
4
+ import { createFileAuthStorage, hasStoredCreds, } from './auth-state.js';
5
+ import { CONSENT_REQUIRED_MESSAGE, hasConsent } from './consent.js';
6
+ import { WHATSAPP_ALLOWED_JIDS_KEY, WHATSAPP_AUTH_DIR, WHATSAPP_OWNER_JID_KEY, normalizeJid, parseAllowedJids, } from './keys.js';
7
+ import { gateInboundMessage } from './message-gate.js';
8
+ import { createWhatsAppPermissionController, } from './permission.js';
9
+ import { openBaileysSocket } from './baileys-socket.js';
10
+ import { WA_DISCONNECT, disconnectStatusCode, } from './socket.js';
11
+ import { DEFAULT_EDIT_FRAME_MS, runWhatsAppTurn } from './channel/turn-runner.js';
12
+ import { transcribeVoiceMessage } from './channel/voice-handler.js';
13
+ /** Bound on remembered own-send message ids (echo/loop protection). */
14
+ const MAX_SENT_IDS = 512;
15
+ export class WhatsAppChannel {
16
+ name = 'whatsapp';
17
+ permission;
18
+ opts;
19
+ turns = new TurnCoordinator();
20
+ session = null;
21
+ model;
22
+ socket = null;
23
+ storage = null;
24
+ handle = null;
25
+ logUnsub = null;
26
+ stopping = false;
27
+ resolveRunning = null;
28
+ rejectRunning = null;
29
+ reconnectAttempts = 0;
30
+ reconnectTimer = null;
31
+ pairMode = false;
32
+ pairedAnnounced = false;
33
+ qrPayload = null;
34
+ socketOpen = false;
35
+ ownerJid = null;
36
+ allowSet = new Set();
37
+ currentJid = null;
38
+ lastJid = null;
39
+ /** Recent OWN outbound message ids — Baileys echoes our sends back via
40
+ * `messages.upsert`; without this the bot would converse with itself. */
41
+ sentIds = new Set();
42
+ connectListeners = new Set();
43
+ pairedListeners = new Set();
44
+ constructor(opts) {
45
+ this.opts = opts;
46
+ this.permission = createWhatsAppPermissionController();
47
+ }
48
+ get permissionResolver() {
49
+ return this.permission.resolver;
50
+ }
51
+ /** Connect value published to control surfaces (`connect.kind: 'qr'`): the
52
+ * CURRENT Baileys QR pairing payload while unlinked (it rotates; each
53
+ * rotation re-publishes via onConnectChange), null once linked. */
54
+ get requestUrl() {
55
+ return this.qrPayload;
56
+ }
57
+ /** Linked + socket open — control surfaces swap the QR for "Connected". */
58
+ get connected() {
59
+ return this.socketOpen && this.ownerJid != null;
60
+ }
61
+ /** Fires once when a fresh QR link completes (the pair flow waits on this). */
62
+ onPaired(listener) {
63
+ this.pairedListeners.add(listener);
64
+ return () => this.pairedListeners.delete(listener);
65
+ }
66
+ async start(startOpts) {
67
+ if (this.handle)
68
+ return this.handle;
69
+ // CONSENT GATE — defense in depth: the wizard/pair/subcommand paths check
70
+ // too, but start() is reachable headlessly (`moxxy whatsapp` with vault
71
+ // state, desktop supervisor), so the channel itself refuses un-acknowledged.
72
+ if (!(await hasConsent(this.opts.vault))) {
73
+ throw new Error(CONSENT_REQUIRED_MESSAGE);
74
+ }
75
+ this.session = startOpts.session;
76
+ this.model = startOpts.model;
77
+ this.storage =
78
+ this.opts.authStorage ?? createFileAuthStorage(moxxyPath(WHATSAPP_AUTH_DIR));
79
+ const dedicated = startOpts.dedicated === true || process.env.MOXXY_DEDICATED_RUNNER === '1';
80
+ this.pairMode = startOpts.pair === true || dedicated;
81
+ const hadCreds = await hasStoredCreds(this.storage);
82
+ if (!hadCreds && !this.pairMode) {
83
+ throw new Error('No WhatsApp account is linked yet. Run `moxxy channels whatsapp pair` to scan ' +
84
+ 'the QR, or start it from the desktop Channels panel.');
85
+ }
86
+ this.pairedAnnounced = hadCreds;
87
+ // Allow-list: the owner's own JID (Note to Self) is seeded on link; extra
88
+ // JIDs come from the vault and channel options. Persisted owner JID lets
89
+ // the gate work from the first inbound even before `open` resolves it.
90
+ this.ownerJid = normalizeJid(await this.opts.vault.get(WHATSAPP_OWNER_JID_KEY));
91
+ this.rebuildAllowList(parseAllowedJids(await this.opts.vault.get(WHATSAPP_ALLOWED_JIDS_KEY)));
92
+ this.permission.setSender((text) => this.sendPermissionPrompt(text));
93
+ // Mirror-to-chat: post assistant prose for turns this channel did NOT
94
+ // initiate (co-attached surface) into the last chat served (invariant #8:
95
+ // own turns are filtered by turnId inside TurnCoordinator.mirrorText).
96
+ this.logUnsub = this.session.log.subscribe((event) => this.mirrorForeignTurn(event));
97
+ const running = new Promise((resolve, reject) => {
98
+ this.resolveRunning = resolve;
99
+ this.rejectRunning = reject;
100
+ });
101
+ await this.connect();
102
+ this.opts.logger?.info?.('whatsapp channel starting', {
103
+ linked: hadCreds,
104
+ pairMode: this.pairMode,
105
+ });
106
+ this.handle = {
107
+ running,
108
+ onConnectChange: (listener) => {
109
+ this.connectListeners.add(listener);
110
+ return () => this.connectListeners.delete(listener);
111
+ },
112
+ stop: async (reason = 'shutdown') => {
113
+ this.teardown(reason);
114
+ this.resolveRunning?.();
115
+ this.resolveRunning = null;
116
+ this.rejectRunning = null;
117
+ },
118
+ };
119
+ return this.handle;
120
+ }
121
+ // ---- connection lifecycle -------------------------------------------------
122
+ async connect() {
123
+ if (this.stopping || !this.storage)
124
+ return;
125
+ const factory = this.opts.socketFactory ?? openBaileysSocket;
126
+ const socket = await factory({
127
+ storage: this.storage,
128
+ ...(this.opts.logger ? { logger: this.opts.logger } : {}),
129
+ });
130
+ this.socket = socket;
131
+ socket.onConnectionUpdate((update) => this.handleConnectionUpdate(update));
132
+ socket.onMessages((upsert) => {
133
+ for (const message of upsert.messages) {
134
+ this.dispatchInBackground(this.handleInbound(upsert.type, message), 'message');
135
+ }
136
+ });
137
+ }
138
+ handleConnectionUpdate(update) {
139
+ if (update.qr) {
140
+ this.qrPayload = update.qr;
141
+ this.notifyConnectChange();
142
+ }
143
+ if (update.connection === 'open') {
144
+ this.reconnectAttempts = 0;
145
+ this.socketOpen = true;
146
+ this.qrPayload = null;
147
+ const owner = normalizeJid(this.socket?.userJid() ?? null);
148
+ if (owner) {
149
+ this.ownerJid = owner;
150
+ this.allowSet.add(owner);
151
+ void this.opts.vault
152
+ .set(WHATSAPP_OWNER_JID_KEY, owner, ['whatsapp'])
153
+ .catch((err) => {
154
+ this.opts.logger?.warn?.('whatsapp: could not persist owner jid', {
155
+ err: String(err),
156
+ });
157
+ });
158
+ if (!this.pairedAnnounced) {
159
+ this.pairedAnnounced = true;
160
+ this.emitPaired(owner);
161
+ void this.send(owner, 'Linked with moxxy. Message yourself in this chat (Note to Self) to talk to ' +
162
+ 'the agent. Commands: /cancel aborts the current turn, /new resets the session.');
163
+ }
164
+ }
165
+ this.notifyConnectChange();
166
+ return;
167
+ }
168
+ if (update.connection === 'close') {
169
+ this.socketOpen = false;
170
+ this.notifyConnectChange();
171
+ if (this.stopping)
172
+ return;
173
+ this.handleClose(disconnectStatusCode(update.lastDisconnect?.error));
174
+ }
175
+ }
176
+ handleClose(code) {
177
+ if (code === WA_DISCONNECT.loggedOut) {
178
+ // The phone unlinked this device — the stored creds are dead. Clear them
179
+ // (standard Baileys practice) and either re-open a QR pairing window
180
+ // (pair/dedicated mode) or stop with re-pair guidance.
181
+ this.opts.logger?.warn?.('whatsapp: logged out by the phone — clearing local credentials');
182
+ this.pairedAnnounced = false;
183
+ void this.storage
184
+ ?.clear()
185
+ .catch(() => undefined)
186
+ .then(() => this.opts.vault.delete(WHATSAPP_OWNER_JID_KEY).catch(() => undefined))
187
+ .then(() => {
188
+ if (this.pairMode)
189
+ this.scheduleReconnect(0);
190
+ else {
191
+ this.fail('WhatsApp logged this device out. Run `moxxy channels whatsapp pair` to re-link ' +
192
+ '(check `moxxy channels whatsapp status`).');
193
+ }
194
+ });
195
+ return;
196
+ }
197
+ if (code === WA_DISCONNECT.connectionReplaced) {
198
+ this.fail('Another WhatsApp Web session replaced this one (440). Stop the other client, then restart the channel.');
199
+ return;
200
+ }
201
+ if (code === WA_DISCONNECT.forbidden) {
202
+ this.fail('WhatsApp refused the connection (403). The number may have been blocked or banned — ' +
203
+ 'this is the documented risk of the unofficial API.');
204
+ return;
205
+ }
206
+ // restartRequired (515) is the NORMAL post-QR-scan handoff: reconnect
207
+ // immediately. Everything else retries with exponential backoff.
208
+ if (code === WA_DISCONNECT.restartRequired) {
209
+ this.scheduleReconnect(0);
210
+ return;
211
+ }
212
+ this.reconnectAttempts += 1;
213
+ const max = this.opts.maxReconnectAttempts ?? 5;
214
+ if (this.reconnectAttempts > max) {
215
+ this.fail(`whatsapp: giving up after ${max} consecutive reconnect attempts (last code: ${code ?? 'unknown'})`);
216
+ return;
217
+ }
218
+ const base = this.opts.reconnectBaseMs ?? 2000;
219
+ this.scheduleReconnect(base * 2 ** (this.reconnectAttempts - 1));
220
+ }
221
+ scheduleReconnect(delayMs) {
222
+ if (this.stopping)
223
+ return;
224
+ this.socket = null;
225
+ this.reconnectTimer = setTimeout(() => {
226
+ this.reconnectTimer = null;
227
+ void this.connect().catch((err) => {
228
+ this.fail(`whatsapp: reconnect failed: ${err instanceof Error ? err.message : String(err)}`);
229
+ });
230
+ }, delayMs);
231
+ this.reconnectTimer.unref?.();
232
+ }
233
+ fail(message) {
234
+ if (this.stopping)
235
+ return;
236
+ this.opts.logger?.warn?.(message);
237
+ this.teardown(message);
238
+ this.rejectRunning?.(new Error(message));
239
+ this.resolveRunning = null;
240
+ this.rejectRunning = null;
241
+ }
242
+ teardown(reason) {
243
+ this.stopping = true;
244
+ if (this.reconnectTimer) {
245
+ clearTimeout(this.reconnectTimer);
246
+ this.reconnectTimer = null;
247
+ }
248
+ // Abort the in-flight turn FIRST so the model loop stops spending the
249
+ // moment the operator asks to shut down; then deny pending permission
250
+ // prompts so no caller hangs (the audit's TuiChannel.stop lesson).
251
+ this.turns.abort(reason);
252
+ this.permission.abortAll(reason);
253
+ this.permission.setSender(null);
254
+ this.logUnsub?.();
255
+ this.logUnsub = null;
256
+ this.qrPayload = null;
257
+ this.socketOpen = false;
258
+ this.socket?.end();
259
+ this.socket = null;
260
+ }
261
+ // ---- inbound --------------------------------------------------------------
262
+ async handleInbound(upsertType, raw) {
263
+ const verdict = gateInboundMessage({
264
+ ownJid: this.ownerJid,
265
+ allowedJids: this.allowSet,
266
+ isOwnSend: (id) => this.sentIds.has(id),
267
+ }, upsertType, raw);
268
+ if (!verdict.ok) {
269
+ // Silent drop (no reply): replying to unauthorized senders would leak
270
+ // the bot's existence and look like spam — both ban vectors.
271
+ this.opts.logger?.debug?.('whatsapp: dropped inbound', { reason: verdict.reason });
272
+ return;
273
+ }
274
+ if (verdict.kind === 'text') {
275
+ await this.handleText(verdict.jid, verdict.text);
276
+ return;
277
+ }
278
+ await this.handleAudio(verdict.jid, verdict.mimeType, raw);
279
+ }
280
+ async handleText(jid, text) {
281
+ // A pending permission prompt captures the next short reply — BEFORE the
282
+ // busy guard, because prompts happen mid-turn by construction.
283
+ if (this.permission.hasPending() && this.permission.offerReply(text))
284
+ return;
285
+ if (text === '/cancel') {
286
+ const controller = this.turns.controller;
287
+ if (controller && !controller.signal.aborted) {
288
+ controller.abort('user cancel');
289
+ await this.send(jid, 'cancelling current turn…');
290
+ }
291
+ else {
292
+ await this.send(jid, 'nothing to cancel.');
293
+ }
294
+ return;
295
+ }
296
+ if (text === '/new') {
297
+ await this.resetSession(jid);
298
+ return;
299
+ }
300
+ if (this.turns.busy) {
301
+ await this.send(jid, 'I am still working on the previous prompt. Send /cancel to abort it.');
302
+ return;
303
+ }
304
+ await this.runUserTurn(jid, text);
305
+ }
306
+ async handleAudio(jid, mimeType, raw) {
307
+ if (!this.session || !this.socket)
308
+ return;
309
+ if (this.turns.busy) {
310
+ await this.send(jid, 'I am still working on the previous prompt. Send /cancel to abort it.');
311
+ return;
312
+ }
313
+ const transcript = await transcribeVoiceMessage({
314
+ session: this.session,
315
+ socket: this.socket,
316
+ reply: (j, t) => this.send(j, t),
317
+ ...(this.opts.logger ? { logger: this.opts.logger } : {}),
318
+ }, { jid, mimeType, raw });
319
+ if (transcript)
320
+ await this.runUserTurn(jid, transcript);
321
+ }
322
+ async resetSession(jid) {
323
+ if (!this.session)
324
+ return;
325
+ const controller = this.turns.controller;
326
+ if (controller && !controller.signal.aborted)
327
+ controller.abort('user reset');
328
+ this.permission.abortAll('session reset');
329
+ // Wipe history at its source; a mirror-only clear would desync (A10).
330
+ try {
331
+ if (typeof this.session.reset === 'function')
332
+ await this.session.reset();
333
+ else
334
+ this.session.log.clear();
335
+ }
336
+ catch (err) {
337
+ await this.send(jid, `/new failed: ${err instanceof Error ? err.message : String(err)} — history NOT cleared`);
338
+ return;
339
+ }
340
+ await this.send(jid, 'new session — conversation history cleared');
341
+ }
342
+ async runUserTurn(jid, text) {
343
+ if (!this.session || !this.socket)
344
+ return;
345
+ // Atomic single-flight: `begin` claims the slot synchronously so two
346
+ // concurrently dispatched messages can't interleave per-turn state. The
347
+ // turnId is minted here so the coordinator records it as an own-turn id
348
+ // (mirrorForeignTurn filters on those, invariant #8).
349
+ const lease = this.turns.begin(newTurnId());
350
+ if (!lease) {
351
+ await this.send(jid, 'I am still working on the previous prompt. Send /cancel to abort it.');
352
+ return;
353
+ }
354
+ this.currentJid = jid;
355
+ this.lastJid = jid;
356
+ try {
357
+ await runWhatsAppTurn({
358
+ session: this.session,
359
+ socket: this.socket,
360
+ editFrameMs: this.opts.editFrameMs ?? DEFAULT_EDIT_FRAME_MS,
361
+ recordSentId: (key) => this.recordSentId(key),
362
+ ...(this.opts.logger ? { logger: this.opts.logger } : {}),
363
+ }, {
364
+ jid,
365
+ text,
366
+ model: this.model,
367
+ controller: lease.controller,
368
+ turnId: lease.turnId,
369
+ });
370
+ }
371
+ finally {
372
+ lease.end();
373
+ this.currentJid = null;
374
+ }
375
+ }
376
+ // ---- outbound -------------------------------------------------------------
377
+ /** Every outbound send goes through here so its id lands in the echo set. */
378
+ async send(jid, text) {
379
+ if (!this.socket)
380
+ return;
381
+ try {
382
+ const sent = await this.socket.sendText(jid, text);
383
+ this.recordSentId(sent?.key);
384
+ }
385
+ catch (err) {
386
+ this.opts.logger?.warn?.('whatsapp send failed', { err: String(err) });
387
+ }
388
+ }
389
+ sendPermissionPrompt(text) {
390
+ const target = this.currentJid ?? this.lastJid ?? this.ownerJid;
391
+ if (!target)
392
+ return Promise.reject(new Error('no chat to prompt in'));
393
+ return this.send(target, text);
394
+ }
395
+ recordSentId(key) {
396
+ const id = key?.id;
397
+ if (!id)
398
+ return;
399
+ this.sentIds.add(id);
400
+ if (this.sentIds.size > MAX_SENT_IDS) {
401
+ const oldest = this.sentIds.values().next().value;
402
+ if (oldest !== undefined)
403
+ this.sentIds.delete(oldest);
404
+ }
405
+ }
406
+ mirrorForeignTurn(event) {
407
+ const text = this.turns.mirrorText(event);
408
+ if (text == null)
409
+ return;
410
+ const target = this.lastJid ?? this.ownerJid;
411
+ if (!target)
412
+ return;
413
+ void this.send(target, text);
414
+ }
415
+ // ---- listeners ------------------------------------------------------------
416
+ notifyConnectChange() {
417
+ for (const listener of this.connectListeners) {
418
+ try {
419
+ listener();
420
+ }
421
+ catch (err) {
422
+ this.opts.logger?.warn?.('whatsapp connect-change listener threw', { err: String(err) });
423
+ }
424
+ }
425
+ }
426
+ emitPaired(ownerJid) {
427
+ for (const listener of this.pairedListeners) {
428
+ try {
429
+ listener(ownerJid);
430
+ }
431
+ catch (err) {
432
+ this.opts.logger?.warn?.('whatsapp paired listener threw', { err: String(err) });
433
+ }
434
+ }
435
+ }
436
+ rebuildAllowList(extra) {
437
+ this.allowSet.clear();
438
+ if (this.ownerJid)
439
+ this.allowSet.add(this.ownerJid);
440
+ for (const jid of this.opts.allowedJids ?? []) {
441
+ const normalized = normalizeJid(jid);
442
+ if (normalized)
443
+ this.allowSet.add(normalized);
444
+ }
445
+ for (const jid of extra)
446
+ this.allowSet.add(jid);
447
+ }
448
+ /**
449
+ * Run a handler detached from the socket's event dispatch (a whole user turn
450
+ * must not block Baileys' event loop). Errors are logged here — nothing above
451
+ * awaits the promise.
452
+ */
453
+ dispatchInBackground(work, kind) {
454
+ void work.catch((err) => {
455
+ this.opts.logger?.warn?.('whatsapp handler failed', { kind, err: String(err) });
456
+ });
457
+ }
458
+ }
459
+ //# sourceMappingURL=channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { type ConsentVault } from './consent.js';
2
+ /**
3
+ * The interactive consent gate — the FIRST step of every setup surface. Shows
4
+ * the unofficial-API warning and requires a literally typed "yes" before
5
+ * anything else may happen; anything less refuses. Returns true only when the
6
+ * risk is (or already was) acknowledged.
7
+ */
8
+ export declare function ensureConsentInteractive(vault: ConsentVault): Promise<boolean>;
9
+ //# sourceMappingURL=consent-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-prompt.d.ts","sourceRoot":"","sources":["../src/consent-prompt.ts"],"names":[],"mappings":"AACA,OAAO,EAA8C,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAE7F;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBpF"}
@@ -0,0 +1,28 @@
1
+ import { isCancel, log, note, text } from '@clack/prompts';
2
+ import { CONSENT_WARNING, hasConsent, recordConsent } from './consent.js';
3
+ /**
4
+ * The interactive consent gate — the FIRST step of every setup surface. Shows
5
+ * the unofficial-API warning and requires a literally typed "yes" before
6
+ * anything else may happen; anything less refuses. Returns true only when the
7
+ * risk is (or already was) acknowledged.
8
+ */
9
+ export async function ensureConsentInteractive(vault) {
10
+ if (await hasConsent(vault)) {
11
+ // Already acknowledged — keep the reminder visible but don't re-demand typing.
12
+ log.warn('Reminder: unofficial WhatsApp API — the linked number can be banned.');
13
+ return true;
14
+ }
15
+ note(CONSENT_WARNING, 'READ THIS FIRST');
16
+ const answer = await text({
17
+ message: "Type 'yes' to acknowledge the risk and continue (anything else aborts)",
18
+ placeholder: 'yes',
19
+ });
20
+ if (isCancel(answer) || String(answer).trim().toLowerCase() !== 'yes') {
21
+ log.error('Not acknowledged — leaving the WhatsApp channel disarmed.');
22
+ return false;
23
+ }
24
+ await recordConsent(vault);
25
+ log.success('Acknowledgment recorded.');
26
+ return true;
27
+ }
28
+ //# sourceMappingURL=consent-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-prompt.js","sourceRoot":"","sources":["../src/consent-prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,aAAa,EAAqB,MAAM,cAAc,CAAC;AAE7F;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,KAAmB;IAChE,IAAI,MAAM,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,+EAA+E;QAC/E,GAAG,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAC;QACjF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,eAAe,EAAE,iBAAiB,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC;QACxB,OAAO,EAAE,wEAAwE;QACjF,WAAW,EAAE,KAAK;KACnB,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,EAAE,CAAC;QACtE,GAAG,CAAC,KAAK,CAAC,2DAA2D,CAAC,CAAC;QACvE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;IAC3B,GAAG,CAAC,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACxC,OAAO,IAAI,CAAC;AACd,CAAC"}