owpenwork 0.1.10 → 0.1.12
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.
- package/dist/bridge.js +33 -12
- package/dist/cli.js +44 -10
- package/dist/config.js +2 -0
- package/dist/logger.js +8 -1
- package/dist/whatsapp.js +76 -52
- package/package.json +1 -1
package/dist/bridge.js
CHANGED
|
@@ -19,7 +19,8 @@ const TOOL_LABELS = {
|
|
|
19
19
|
task: "agent",
|
|
20
20
|
webfetch: "webfetch",
|
|
21
21
|
};
|
|
22
|
-
export async function startBridge(config, logger) {
|
|
22
|
+
export async function startBridge(config, logger, reporter) {
|
|
23
|
+
const reportStatus = reporter?.onStatus;
|
|
23
24
|
const client = createClient(config);
|
|
24
25
|
const store = new BridgeStore(config.dbPath);
|
|
25
26
|
store.seedAllowlist("telegram", config.allowlist.telegram);
|
|
@@ -31,12 +32,14 @@ export async function startBridge(config, logger) {
|
|
|
31
32
|
}
|
|
32
33
|
else {
|
|
33
34
|
logger.info("telegram adapter disabled");
|
|
35
|
+
reportStatus?.("Telegram adapter disabled.");
|
|
34
36
|
}
|
|
35
37
|
if (config.whatsappEnabled) {
|
|
36
|
-
adapters.set("whatsapp", createWhatsAppAdapter(config, logger, handleInbound, { printQr: true }));
|
|
38
|
+
adapters.set("whatsapp", createWhatsAppAdapter(config, logger, handleInbound, { printQr: true, onStatus: reportStatus }));
|
|
37
39
|
}
|
|
38
40
|
else {
|
|
39
41
|
logger.info("whatsapp adapter disabled");
|
|
42
|
+
reportStatus?.("WhatsApp adapter disabled.");
|
|
40
43
|
}
|
|
41
44
|
const sessionQueue = new Map();
|
|
42
45
|
const activeRuns = new Map();
|
|
@@ -102,7 +105,7 @@ export async function startBridge(config, logger) {
|
|
|
102
105
|
if (output)
|
|
103
106
|
message += `\n${output}`;
|
|
104
107
|
}
|
|
105
|
-
await sendText(run.channel, run.peerId, message);
|
|
108
|
+
await sendText(run.channel, run.peerId, message, { kind: "tool" });
|
|
106
109
|
}
|
|
107
110
|
if (event.type === "permission.asked") {
|
|
108
111
|
const permission = event.properties;
|
|
@@ -117,7 +120,9 @@ export async function startBridge(config, logger) {
|
|
|
117
120
|
if (response === "reject") {
|
|
118
121
|
const run = activeRuns.get(permission.sessionID);
|
|
119
122
|
if (run) {
|
|
120
|
-
await sendText(run.channel, run.peerId, "Permission denied. Update configuration to allow tools."
|
|
123
|
+
await sendText(run.channel, run.peerId, "Permission denied. Update configuration to allow tools.", {
|
|
124
|
+
kind: "system",
|
|
125
|
+
});
|
|
121
126
|
}
|
|
122
127
|
}
|
|
123
128
|
}
|
|
@@ -125,10 +130,14 @@ export async function startBridge(config, logger) {
|
|
|
125
130
|
})().catch((error) => {
|
|
126
131
|
logger.error({ error }, "event stream closed");
|
|
127
132
|
});
|
|
128
|
-
async function sendText(channel, peerId, text) {
|
|
133
|
+
async function sendText(channel, peerId, text, options = {}) {
|
|
129
134
|
const adapter = adapters.get(channel);
|
|
130
135
|
if (!adapter)
|
|
131
136
|
return;
|
|
137
|
+
const kind = options.kind ?? "system";
|
|
138
|
+
if (options.display !== false) {
|
|
139
|
+
reporter?.onOutbound?.({ channel, peerId, text, kind });
|
|
140
|
+
}
|
|
132
141
|
const chunks = chunkText(text, adapter.maxTextLength);
|
|
133
142
|
for (const chunk of chunks) {
|
|
134
143
|
logger.info({ channel, peerId, length: chunk.length }, "sending message");
|
|
@@ -151,30 +160,36 @@ export async function startBridge(config, logger) {
|
|
|
151
160
|
const allowed = allowAll || isSelf || store.isAllowed("whatsapp", peerKey);
|
|
152
161
|
if (!allowed) {
|
|
153
162
|
if (config.whatsappDmPolicy === "allowlist") {
|
|
154
|
-
await sendText(inbound.channel, inbound.peerId, "Access denied. Ask the owner to allowlist your number.");
|
|
163
|
+
await sendText(inbound.channel, inbound.peerId, "Access denied. Ask the owner to allowlist your number.", { kind: "system" });
|
|
155
164
|
return;
|
|
156
165
|
}
|
|
157
166
|
store.prunePairingRequests();
|
|
158
167
|
const active = store.getPairingRequest("whatsapp", peerKey);
|
|
159
168
|
const pending = store.listPairingRequests("whatsapp");
|
|
160
169
|
if (!active && pending.length >= 3) {
|
|
161
|
-
await sendText(inbound.channel, inbound.peerId, "Pairing queue full. Ask the owner to approve pending requests.");
|
|
170
|
+
await sendText(inbound.channel, inbound.peerId, "Pairing queue full. Ask the owner to approve pending requests.", { kind: "system" });
|
|
162
171
|
return;
|
|
163
172
|
}
|
|
164
173
|
const code = active?.code ?? String(Math.floor(100000 + Math.random() * 900000));
|
|
165
174
|
if (!active) {
|
|
166
175
|
store.createPairingRequest("whatsapp", peerKey, code, 60 * 60_000);
|
|
167
176
|
}
|
|
168
|
-
await sendText(inbound.channel, inbound.peerId, `Pairing required. Ask the owner to approve code: ${code}
|
|
177
|
+
await sendText(inbound.channel, inbound.peerId, `Pairing required. Ask the owner to approve code: ${code}`, { kind: "system" });
|
|
169
178
|
return;
|
|
170
179
|
}
|
|
171
180
|
}
|
|
172
181
|
else if (config.allowlist[inbound.channel].size > 0) {
|
|
173
182
|
if (!store.isAllowed(inbound.channel, peerKey)) {
|
|
174
|
-
await sendText(inbound.channel, inbound.peerId, "Access denied.");
|
|
183
|
+
await sendText(inbound.channel, inbound.peerId, "Access denied.", { kind: "system" });
|
|
175
184
|
return;
|
|
176
185
|
}
|
|
177
186
|
}
|
|
187
|
+
reporter?.onInbound?.({
|
|
188
|
+
channel: inbound.channel,
|
|
189
|
+
peerId: inbound.peerId,
|
|
190
|
+
text: inbound.text,
|
|
191
|
+
fromMe: inbound.fromMe,
|
|
192
|
+
});
|
|
178
193
|
const session = store.getSession(inbound.channel, peerKey);
|
|
179
194
|
const sessionID = session?.session_id ?? (await createSession({ ...inbound, peerId: peerKey }));
|
|
180
195
|
enqueue(sessionID, async () => {
|
|
@@ -198,15 +213,19 @@ export async function startBridge(config, logger) {
|
|
|
198
213
|
.join("\n")
|
|
199
214
|
.trim();
|
|
200
215
|
if (reply) {
|
|
201
|
-
await sendText(inbound.channel, inbound.peerId, reply);
|
|
216
|
+
await sendText(inbound.channel, inbound.peerId, reply, { kind: "reply" });
|
|
202
217
|
}
|
|
203
218
|
else {
|
|
204
|
-
await sendText(inbound.channel, inbound.peerId, "No response generated. Try again."
|
|
219
|
+
await sendText(inbound.channel, inbound.peerId, "No response generated. Try again.", {
|
|
220
|
+
kind: "system",
|
|
221
|
+
});
|
|
205
222
|
}
|
|
206
223
|
}
|
|
207
224
|
catch (error) {
|
|
208
225
|
logger.error({ error }, "prompt failed");
|
|
209
|
-
await sendText(inbound.channel, inbound.peerId, "Error: failed to reach OpenCode."
|
|
226
|
+
await sendText(inbound.channel, inbound.peerId, "Error: failed to reach OpenCode.", {
|
|
227
|
+
kind: "system",
|
|
228
|
+
});
|
|
210
229
|
}
|
|
211
230
|
finally {
|
|
212
231
|
activeRuns.delete(sessionID);
|
|
@@ -242,8 +261,10 @@ export async function startBridge(config, logger) {
|
|
|
242
261
|
}
|
|
243
262
|
for (const adapter of adapters.values()) {
|
|
244
263
|
await adapter.start();
|
|
264
|
+
reportStatus?.(`${adapter.name === "whatsapp" ? "WhatsApp" : "Telegram"} adapter started.`);
|
|
245
265
|
}
|
|
246
266
|
logger.info({ channels: Array.from(adapters.keys()) }, "bridge started");
|
|
267
|
+
reportStatus?.(`Bridge running. Logs: ${config.logFile}`);
|
|
247
268
|
return {
|
|
248
269
|
async stop() {
|
|
249
270
|
eventAbort.abort();
|
package/dist/cli.js
CHANGED
|
@@ -8,8 +8,9 @@ import { loadConfig, normalizeWhatsAppId, readConfigFile, writeConfigFile, } fro
|
|
|
8
8
|
import { BridgeStore } from "./db.js";
|
|
9
9
|
import { createLogger } from "./logger.js";
|
|
10
10
|
import { createClient } from "./opencode.js";
|
|
11
|
+
import { truncateText } from "./text.js";
|
|
11
12
|
import { loginWhatsApp, unpairWhatsApp } from "./whatsapp.js";
|
|
12
|
-
const VERSION = "0.1.
|
|
13
|
+
const VERSION = "0.1.12";
|
|
13
14
|
const STEP_OPTIONS = [
|
|
14
15
|
{
|
|
15
16
|
value: "config",
|
|
@@ -62,6 +63,38 @@ function defaultSelections(configExists, whatsappLinked) {
|
|
|
62
63
|
selections.push("start");
|
|
63
64
|
return selections;
|
|
64
65
|
}
|
|
66
|
+
function createAppLogger(config) {
|
|
67
|
+
return createLogger(config.logLevel, { logFile: config.logFile });
|
|
68
|
+
}
|
|
69
|
+
function createConsoleReporter() {
|
|
70
|
+
const formatChannel = (channel) => (channel === "whatsapp" ? "WhatsApp" : "Telegram");
|
|
71
|
+
const formatPeer = (channel, peerId, fromMe) => {
|
|
72
|
+
const base = channel === "whatsapp" ? normalizeWhatsAppId(peerId) : peerId;
|
|
73
|
+
return fromMe ? `${base} (me)` : base;
|
|
74
|
+
};
|
|
75
|
+
const printBlock = (prefix, text) => {
|
|
76
|
+
const lines = text.split(/\r?\n/).map((line) => truncateText(line.trim(), 240));
|
|
77
|
+
const [first, ...rest] = lines.length ? lines : ["(empty)"];
|
|
78
|
+
console.log(`${prefix} ${first}`);
|
|
79
|
+
for (const line of rest) {
|
|
80
|
+
console.log(`${" ".repeat(prefix.length)} ${line}`);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
onStatus(message) {
|
|
85
|
+
console.log(message);
|
|
86
|
+
},
|
|
87
|
+
onInbound({ channel, peerId, text, fromMe }) {
|
|
88
|
+
const prefix = `[${formatChannel(channel)}] ${formatPeer(channel, peerId, fromMe)} >`;
|
|
89
|
+
printBlock(prefix, text);
|
|
90
|
+
},
|
|
91
|
+
onOutbound({ channel, peerId, text, kind }) {
|
|
92
|
+
const marker = kind === "reply" ? "<" : kind === "tool" ? "*" : "!";
|
|
93
|
+
const prefix = `[${formatChannel(channel)}] ${formatPeer(channel, peerId)} ${marker}`;
|
|
94
|
+
printBlock(prefix, text);
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
65
98
|
function updateConfig(configPath, updater) {
|
|
66
99
|
const { config } = readConfigFile(configPath);
|
|
67
100
|
const base = config ?? { version: 1 };
|
|
@@ -195,12 +228,13 @@ async function runStart(pathOverride) {
|
|
|
195
228
|
process.env.OPENCODE_DIRECTORY = pathOverride.trim();
|
|
196
229
|
}
|
|
197
230
|
const config = loadConfig();
|
|
198
|
-
const logger =
|
|
231
|
+
const logger = createAppLogger(config);
|
|
232
|
+
const reporter = createConsoleReporter();
|
|
199
233
|
if (!process.env.OPENCODE_DIRECTORY) {
|
|
200
234
|
process.env.OPENCODE_DIRECTORY = config.opencodeDirectory;
|
|
201
235
|
}
|
|
202
|
-
const bridge = await startBridge(config, logger);
|
|
203
|
-
|
|
236
|
+
const bridge = await startBridge(config, logger, reporter);
|
|
237
|
+
reporter.onStatus?.("Commands: owpenwork whatsapp login, owpenwork pairing list, owpenwork status");
|
|
204
238
|
const shutdown = async () => {
|
|
205
239
|
logger.info("shutting down");
|
|
206
240
|
await bridge.stop();
|
|
@@ -277,7 +311,7 @@ async function runGuidedFlow(pathArg, opts) {
|
|
|
277
311
|
if (!relink)
|
|
278
312
|
return;
|
|
279
313
|
}
|
|
280
|
-
await loginWhatsApp(config,
|
|
314
|
+
await loginWhatsApp(config, createAppLogger(config), { onStatus: console.log });
|
|
281
315
|
});
|
|
282
316
|
continue;
|
|
283
317
|
}
|
|
@@ -338,7 +372,7 @@ login
|
|
|
338
372
|
.description("Login to WhatsApp via QR code")
|
|
339
373
|
.action(async () => {
|
|
340
374
|
const config = loadConfig(process.env, { requireOpencode: false });
|
|
341
|
-
await loginWhatsApp(config,
|
|
375
|
+
await loginWhatsApp(config, createAppLogger(config), { onStatus: console.log });
|
|
342
376
|
});
|
|
343
377
|
login
|
|
344
378
|
.command("telegram")
|
|
@@ -372,28 +406,28 @@ whatsapp
|
|
|
372
406
|
.description("Login to WhatsApp via QR code")
|
|
373
407
|
.action(async () => {
|
|
374
408
|
const config = loadConfig(process.env, { requireOpencode: false });
|
|
375
|
-
await loginWhatsApp(config,
|
|
409
|
+
await loginWhatsApp(config, createAppLogger(config), { onStatus: console.log });
|
|
376
410
|
});
|
|
377
411
|
whatsapp
|
|
378
412
|
.command("logout")
|
|
379
413
|
.description("Logout of WhatsApp and clear auth state")
|
|
380
414
|
.action(() => {
|
|
381
415
|
const config = loadConfig(process.env, { requireOpencode: false });
|
|
382
|
-
unpairWhatsApp(config,
|
|
416
|
+
unpairWhatsApp(config, createAppLogger(config));
|
|
383
417
|
});
|
|
384
418
|
program
|
|
385
419
|
.command("qr")
|
|
386
420
|
.description("Print a WhatsApp QR code to pair")
|
|
387
421
|
.action(async () => {
|
|
388
422
|
const config = loadConfig(process.env, { requireOpencode: false });
|
|
389
|
-
await loginWhatsApp(config,
|
|
423
|
+
await loginWhatsApp(config, createAppLogger(config), { onStatus: console.log });
|
|
390
424
|
});
|
|
391
425
|
program
|
|
392
426
|
.command("unpair")
|
|
393
427
|
.description("Clear WhatsApp pairing data")
|
|
394
428
|
.action(() => {
|
|
395
429
|
const config = loadConfig(process.env, { requireOpencode: false });
|
|
396
|
-
unpairWhatsApp(config,
|
|
430
|
+
unpairWhatsApp(config, createAppLogger(config));
|
|
397
431
|
});
|
|
398
432
|
const pairing = program.command("pairing").description("Pairing requests");
|
|
399
433
|
pairing
|
package/dist/config.js
CHANGED
|
@@ -125,6 +125,7 @@ export function loadConfig(env = process.env, options = {}) {
|
|
|
125
125
|
const resolvedDirectory = opencodeDirectory || process.cwd();
|
|
126
126
|
const dataDir = expandHome(env.OWPENBOT_DATA_DIR ?? "~/.owpenbot");
|
|
127
127
|
const dbPath = expandHome(env.OWPENBOT_DB_PATH ?? path.join(dataDir, "owpenbot.db"));
|
|
128
|
+
const logFile = expandHome(env.OWPENBOT_LOG_FILE ?? path.join(dataDir, "logs", "owpenbot.log"));
|
|
128
129
|
const configPath = resolveConfigPath(dataDir, env);
|
|
129
130
|
const { config: configFile } = readConfigFile(configPath);
|
|
130
131
|
const whatsappFile = configFile.channels?.whatsapp ?? {};
|
|
@@ -159,6 +160,7 @@ export function loadConfig(env = process.env, options = {}) {
|
|
|
159
160
|
whatsappEnabled: parseBoolean(env.WHATSAPP_ENABLED, true),
|
|
160
161
|
dataDir,
|
|
161
162
|
dbPath,
|
|
163
|
+
logFile,
|
|
162
164
|
allowlist: envAllowlist,
|
|
163
165
|
toolUpdatesEnabled: parseBoolean(env.TOOL_UPDATES_ENABLED, false),
|
|
164
166
|
groupsEnabled: parseBoolean(env.GROUPS_ENABLED, false),
|
package/dist/logger.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
import pino from "pino";
|
|
2
|
-
export function createLogger(level) {
|
|
4
|
+
export function createLogger(level, options) {
|
|
5
|
+
if (options?.logFile) {
|
|
6
|
+
fs.mkdirSync(path.dirname(options.logFile), { recursive: true });
|
|
7
|
+
const destination = pino.destination({ dest: options.logFile, sync: false });
|
|
8
|
+
return pino({ level, base: undefined }, destination);
|
|
9
|
+
}
|
|
3
10
|
return pino({
|
|
4
11
|
level,
|
|
5
12
|
base: undefined,
|
package/dist/whatsapp.js
CHANGED
|
@@ -43,15 +43,18 @@ export function createWhatsAppAdapter(config, logger, onMessage, opts = {}) {
|
|
|
43
43
|
if (update.qr && opts.printQr) {
|
|
44
44
|
qrcode.generate(update.qr, { small: true });
|
|
45
45
|
log.info("scan the QR code to connect WhatsApp");
|
|
46
|
+
opts.onStatus?.("Scan the QR code to connect WhatsApp.");
|
|
46
47
|
}
|
|
47
48
|
if (update.connection === "open") {
|
|
48
49
|
log.info("whatsapp connected");
|
|
50
|
+
opts.onStatus?.("WhatsApp connected.");
|
|
49
51
|
}
|
|
50
52
|
if (update.connection === "close") {
|
|
51
53
|
const lastDisconnect = update.lastDisconnect;
|
|
52
54
|
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
53
55
|
if (statusCode === 515 && !stopped) {
|
|
54
56
|
log.warn("whatsapp stream error; restarting connection");
|
|
57
|
+
opts.onStatus?.("WhatsApp stream error; reconnecting.");
|
|
55
58
|
setTimeout(() => {
|
|
56
59
|
void connect();
|
|
57
60
|
}, 1000);
|
|
@@ -60,10 +63,12 @@ export function createWhatsAppAdapter(config, logger, onMessage, opts = {}) {
|
|
|
60
63
|
const shouldReconnect = statusCode !== DisconnectReason.loggedOut;
|
|
61
64
|
if (shouldReconnect && !stopped) {
|
|
62
65
|
log.warn("whatsapp connection closed, reconnecting");
|
|
66
|
+
opts.onStatus?.("WhatsApp connection closed; reconnecting.");
|
|
63
67
|
void connect();
|
|
64
68
|
}
|
|
65
69
|
else if (!shouldReconnect) {
|
|
66
70
|
log.warn("whatsapp logged out, run 'owpenbot whatsapp login'");
|
|
71
|
+
opts.onStatus?.("WhatsApp logged out. Run: owpenwork whatsapp login.");
|
|
67
72
|
}
|
|
68
73
|
}
|
|
69
74
|
});
|
|
@@ -114,67 +119,86 @@ export function createWhatsAppAdapter(config, logger, onMessage, opts = {}) {
|
|
|
114
119
|
},
|
|
115
120
|
};
|
|
116
121
|
}
|
|
117
|
-
export async function loginWhatsApp(config, logger) {
|
|
122
|
+
export async function loginWhatsApp(config, logger, options = {}) {
|
|
118
123
|
const authDir = path.resolve(config.whatsappAuthDir);
|
|
119
124
|
ensureDir(authDir);
|
|
120
125
|
const log = logger.child({ channel: "whatsapp" });
|
|
121
126
|
const { state, saveCreds } = await useMultiFileAuthState(authDir);
|
|
122
127
|
const { version } = await fetchLatestBaileysVersion();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
sock.end(undefined);
|
|
143
|
-
resolve();
|
|
144
|
-
};
|
|
145
|
-
sock.ev.on("creds.update", async () => {
|
|
146
|
-
await saveCreds();
|
|
147
|
-
if (state.creds?.registered) {
|
|
148
|
-
finish("creds.registered");
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
sock.ev.on("connection.update", (update) => {
|
|
152
|
-
if (update.qr) {
|
|
153
|
-
qrcode.generate(update.qr, { small: true });
|
|
154
|
-
log.info("scan the QR code to connect WhatsApp");
|
|
155
|
-
}
|
|
156
|
-
if (update.connection === "open") {
|
|
157
|
-
finish("connection.open");
|
|
158
|
-
}
|
|
159
|
-
if (update.connection === "close") {
|
|
160
|
-
const lastDisconnect = update.lastDisconnect;
|
|
161
|
-
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
162
|
-
if (statusCode === 515) {
|
|
163
|
-
if (state.creds?.registered) {
|
|
164
|
-
log.info("whatsapp login requires reconnect; completing login");
|
|
165
|
-
finish("connection.restart.required");
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
log.warn("whatsapp restart requested before creds registered");
|
|
169
|
-
reject(new Error("WhatsApp login restart required"));
|
|
128
|
+
const credsPath = path.join(authDir, "creds.json");
|
|
129
|
+
const maxAttempts = 2;
|
|
130
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
131
|
+
const result = await new Promise((resolve) => {
|
|
132
|
+
let finished = false;
|
|
133
|
+
const sock = makeWASocket({
|
|
134
|
+
auth: {
|
|
135
|
+
creds: state.creds,
|
|
136
|
+
keys: makeCacheableSignalKeyStore(state.keys, log),
|
|
137
|
+
},
|
|
138
|
+
version,
|
|
139
|
+
logger: log,
|
|
140
|
+
printQRInTerminal: false,
|
|
141
|
+
syncFullHistory: false,
|
|
142
|
+
markOnlineOnConnect: false,
|
|
143
|
+
browser: ["owpenbot", "cli", "0.1.0"],
|
|
144
|
+
});
|
|
145
|
+
const finish = (reason, status) => {
|
|
146
|
+
if (finished)
|
|
170
147
|
return;
|
|
171
|
-
|
|
148
|
+
finished = true;
|
|
149
|
+
log.info({ reason }, "whatsapp login finished");
|
|
150
|
+
sock.end(undefined);
|
|
151
|
+
resolve(status);
|
|
152
|
+
};
|
|
153
|
+
sock.ev.on("creds.update", async () => {
|
|
154
|
+
await saveCreds();
|
|
172
155
|
if (state.creds?.registered) {
|
|
173
|
-
finish("
|
|
156
|
+
finish("creds.registered", "linked");
|
|
174
157
|
}
|
|
175
|
-
}
|
|
158
|
+
});
|
|
159
|
+
sock.ev.on("connection.update", (update) => {
|
|
160
|
+
if (update.qr) {
|
|
161
|
+
qrcode.generate(update.qr, { small: true });
|
|
162
|
+
log.info("scan the QR code to connect WhatsApp");
|
|
163
|
+
options.onStatus?.("Scan the QR code to connect WhatsApp.");
|
|
164
|
+
}
|
|
165
|
+
if (update.connection === "open") {
|
|
166
|
+
options.onStatus?.("WhatsApp linked.");
|
|
167
|
+
finish("connection.open", "linked");
|
|
168
|
+
}
|
|
169
|
+
if (update.connection === "close") {
|
|
170
|
+
const lastDisconnect = update.lastDisconnect;
|
|
171
|
+
const statusCode = lastDisconnect?.error?.output?.statusCode;
|
|
172
|
+
if (statusCode === 515) {
|
|
173
|
+
if (state.creds?.registered || fs.existsSync(credsPath)) {
|
|
174
|
+
log.info("whatsapp login requires reconnect; completing login");
|
|
175
|
+
options.onStatus?.("WhatsApp login requires reconnect; completing login.");
|
|
176
|
+
finish("connection.restart.required", "linked");
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
log.warn("whatsapp restart requested before creds registered");
|
|
180
|
+
options.onStatus?.("WhatsApp login needs another scan.");
|
|
181
|
+
finish("connection.restart.required", "restart");
|
|
182
|
+
}
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (state.creds?.registered) {
|
|
186
|
+
options.onStatus?.("WhatsApp linked.");
|
|
187
|
+
finish("connection.close.registered", "linked");
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
});
|
|
176
191
|
});
|
|
177
|
-
|
|
192
|
+
if (result === "linked") {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (attempt < maxAttempts) {
|
|
196
|
+
log.warn("retrying whatsapp login after restart");
|
|
197
|
+
options.onStatus?.("Retrying WhatsApp login...");
|
|
198
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
throw new Error("WhatsApp login failed after restart");
|
|
178
202
|
}
|
|
179
203
|
export function unpairWhatsApp(config, logger) {
|
|
180
204
|
const authDir = path.resolve(config.whatsappAuthDir);
|