@whanext/core 0.17.0 → 0.18.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.
package/dist/index.js CHANGED
@@ -2297,96 +2297,36 @@ var Browser = /* @__PURE__ */ ((Browser2) => {
2297
2297
  return Browser2;
2298
2298
  })(Browser || {});
2299
2299
 
2300
- // src/provider/baileys/baileys-provider.ts
2300
+ // src/provider/zapo/zapo-provider.ts
2301
+ import { mkdir } from "fs/promises";
2302
+ import { join } from "path";
2303
+ import { createMediaProcessor } from "@zapo-js/media-utils";
2304
+ import { createSqliteStore } from "@zapo-js/store-sqlite";
2301
2305
  import {
2302
- Browsers,
2303
- DisconnectReason,
2304
- downloadMediaMessage,
2305
- generateWAMessageFromContent,
2306
- isJidGroup,
2307
- makeWASocket,
2308
- proto,
2309
- useMultiFileAuthState
2310
- } from "@whiskeysockets/baileys";
2306
+ WaClient,
2307
+ createStore,
2308
+ proto
2309
+ } from "zapo-js";
2311
2310
 
2312
- // src/provider/baileys/baileys-logger.ts
2313
- function createBaileysLogger(logger) {
2314
- return {
2315
- level: logger.level,
2316
- child(context) {
2317
- const name = typeof context.class === "string" ? context.class : "internal";
2318
- return createBaileysLogger(logger.child(name));
2319
- },
2320
- trace(value, message) {
2321
- logger.debug(resolveMessage(value, message, "Provider trace"), safeContext(value));
2322
- },
2323
- debug(value, message) {
2324
- logger.debug(resolveMessage(value, message, "Provider debug"), safeContext(value));
2325
- },
2326
- info(value, message) {
2327
- logger.debug(resolveMessage(value, message, "Provider info"), safeContext(value));
2328
- },
2329
- warn(value, message) {
2330
- logger.warn(resolveMessage(value, message, "Provider warning"), safeContext(value));
2331
- },
2332
- error(value, message) {
2333
- logger.error(resolveMessage(value, message, "Provider error"), safeContext(value));
2334
- }
2335
- };
2336
- }
2337
- function resolveMessage(value, message, fallback) {
2338
- if (message) {
2339
- return message;
2340
- }
2341
- return typeof value === "string" ? value : fallback;
2342
- }
2343
- function safeContext(value) {
2344
- if (value instanceof Error) {
2345
- return { error: value };
2346
- }
2347
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
2348
- return {};
2349
- }
2350
- const source = value;
2351
- const allowed = [
2352
- "location",
2353
- "reason",
2354
- "status",
2355
- "statusCode",
2356
- "type"
2357
- ];
2358
- return Object.fromEntries(
2359
- allowed.filter((key) => source[key] !== void 0).map((key) => [key, source[key]])
2360
- );
2361
- }
2362
-
2363
- // src/provider/baileys/normalize-message.ts
2364
- import {
2365
- extractMessageContent,
2366
- getContentType,
2367
- normalizeMessageContent
2368
- } from "@whiskeysockets/baileys";
2369
- function unwrapMessageContent(input) {
2311
+ // src/provider/zapo/normalize-message.ts
2312
+ function unwrapZapoMessageContent(input) {
2370
2313
  if (!input) return void 0;
2371
- const normalized = normalizeMessageContent(input);
2372
- const content = extractMessageContent(normalized);
2373
- if (!content) return void 0;
2374
- const nested = content.ephemeralMessage?.message ?? content.viewOnceMessage?.message ?? content.viewOnceMessageV2?.message ?? content.viewOnceMessageV2Extension?.message;
2375
- return nested ? unwrapMessageContent(nested) : content;
2314
+ const nested = input.ephemeralMessage?.message ?? input.viewOnceMessage?.message ?? input.viewOnceMessageV2?.message ?? input.deviceSentMessage?.message ?? input.documentWithCaptionMessage?.message;
2315
+ return nested ? unwrapZapoMessageContent(nested) : input;
2376
2316
  }
2377
- function isViewOnceContent(input) {
2317
+ function isZapoViewOnceContent(input) {
2378
2318
  if (!input) return false;
2379
- if (input.viewOnceMessage?.message || input.viewOnceMessageV2?.message || input.viewOnceMessageV2Extension?.message) {
2319
+ if (input.viewOnceMessage?.message || input.viewOnceMessageV2?.message) {
2380
2320
  return true;
2381
2321
  }
2382
- return isViewOnceContent(input.ephemeralMessage?.message);
2322
+ return isZapoViewOnceContent(input.ephemeralMessage?.message);
2383
2323
  }
2384
- function extractQuotedBaileysMessage(input) {
2385
- const chatId = input.key.remoteJid;
2386
- const content = unwrapMessageContent(input.message);
2324
+ function extractQuotedZapoMessage(input) {
2325
+ const event = input;
2326
+ const chatId = event.key.remoteJid;
2327
+ const content = unwrapZapoMessageContent(event.message);
2387
2328
  if (!chatId || !content) return void 0;
2388
- const type = getContentType(content);
2389
- const node = type ? content[type] : void 0;
2329
+ const node = contentNode(content);
2390
2330
  const context = getContextInfo(node);
2391
2331
  if (!context?.stanzaId || !context.quotedMessage) return void 0;
2392
2332
  return {
@@ -2399,26 +2339,25 @@ function extractQuotedBaileysMessage(input) {
2399
2339
  message: context.quotedMessage
2400
2340
  };
2401
2341
  }
2402
- function normalizeBaileysMessage(input) {
2403
- const chatId = input.key.remoteJid;
2404
- const id = input.key.id;
2405
- if (!chatId || !id || !input.message) {
2342
+ function normalizeZapoMessage(input) {
2343
+ const event = input;
2344
+ const chatId = event.key.remoteJid;
2345
+ const id = event.key.id;
2346
+ if (!chatId || !id || !event.message) {
2406
2347
  return void 0;
2407
2348
  }
2408
- const content = unwrapMessageContent(input.message);
2349
+ const content = unwrapZapoMessageContent(event.message);
2409
2350
  if (!content) {
2410
2351
  return void 0;
2411
2352
  }
2412
- const type = getContentType(content);
2413
- const node = type ? content[type] : void 0;
2353
+ const { type, node } = contentNode(content);
2414
2354
  const context = getContextInfo(node);
2415
- const isPrivateIncoming = !chatId.endsWith("@g.us") && input.key.fromMe !== true;
2416
- const remoteJidAlt = input.key.remoteJidAlt;
2355
+ const isPrivateIncoming = !chatId.endsWith("@g.us") && event.key.fromMe !== true;
2417
2356
  const senderIds = uniqueIdentities([
2418
- input.key.participant,
2419
- input.key.participantAlt,
2420
- input.key.participantUsername?.includes("@") ? input.key.participantUsername : void 0,
2421
- isPrivateIncoming ? remoteJidAlt : void 0,
2357
+ event.key.participant,
2358
+ event.key.participantAlt,
2359
+ event.key.senderUsername?.includes("@") ? event.key.senderUsername : void 0,
2360
+ isPrivateIncoming ? event.key.remoteJidAlt : void 0,
2422
2361
  isPrivateIncoming ? chatId : void 0
2423
2362
  ]);
2424
2363
  const senderJid = senderIds.find((identity) => identity.endsWith("@s.whatsapp.net") || identity.endsWith("@c.us"));
@@ -2427,10 +2366,11 @@ function normalizeBaileysMessage(input) {
2427
2366
  const sender = new User({
2428
2367
  id: senderId,
2429
2368
  identities: senderIds.length > 0 ? senderIds : [senderId],
2430
- ...input.pushName ? { name: input.pushName } : {}
2369
+ ...event.pushName ? { name: event.pushName } : {}
2431
2370
  });
2432
- const mentionedUsers = (context?.mentionedJid ?? []).map((identity) => User.fromIdentities([identity]));
2433
- const viewOnce = Boolean(input.key.isViewOnce) || isViewOnceContent(input.message);
2371
+ const mentionedIds = [...context?.mentionedJid ?? []];
2372
+ const mentionedUsers = mentionedIds.map((identity) => User.fromIdentities([identity]));
2373
+ const viewOnce = isZapoViewOnceContent(event.message);
2434
2374
  const media = getMedia(type, node, viewOnce);
2435
2375
  const contentKind = getContentKind(type);
2436
2376
  const text = getText(content);
@@ -2443,10 +2383,10 @@ function normalizeBaileysMessage(input) {
2443
2383
  senderId,
2444
2384
  senderIds: senderIds.length > 0 ? senderIds : [senderId],
2445
2385
  sender,
2446
- keys: normalizeKey(input.key),
2447
- mentions: [...context?.mentionedJid ?? []],
2386
+ keys: normalizeZapoKey(event.key),
2387
+ mentions: mentionedIds,
2448
2388
  mentionedUsers,
2449
- timestamp: toDate(input.messageTimestamp),
2389
+ timestamp: toDate(event.timestampSeconds),
2450
2390
  isGroup: chatId.endsWith("@g.us"),
2451
2391
  isReply: quoted !== void 0,
2452
2392
  isViewOnce: media?.viewOnce ?? false,
@@ -2464,6 +2404,45 @@ function normalizeBaileysMessage(input) {
2464
2404
  if (quoted !== void 0) message.quoted = quoted;
2465
2405
  return message;
2466
2406
  }
2407
+ function normalizeZapoKey(key) {
2408
+ const normalized = {
2409
+ id: key.id ?? "",
2410
+ chatId: key.remoteJid ?? "",
2411
+ fromMe: key.fromMe ?? false
2412
+ };
2413
+ const participantId = key.participant ?? key.participantAlt;
2414
+ if (participantId !== null && participantId !== void 0) {
2415
+ normalized.participantId = participantId;
2416
+ }
2417
+ return normalized;
2418
+ }
2419
+ function contentNode(content) {
2420
+ const order = [
2421
+ "conversation",
2422
+ "extendedTextMessage",
2423
+ "imageMessage",
2424
+ "videoMessage",
2425
+ "audioMessage",
2426
+ "documentMessage",
2427
+ "stickerMessage",
2428
+ "locationMessage",
2429
+ "liveLocationMessage",
2430
+ "contactMessage",
2431
+ "contactsArrayMessage",
2432
+ "buttonsResponseMessage",
2433
+ "listResponseMessage",
2434
+ "templateButtonReplyMessage",
2435
+ "pollCreationMessage",
2436
+ "pollCreationMessageV2",
2437
+ "pollCreationMessageV3",
2438
+ "pollCreationMessageV5",
2439
+ "productMessage",
2440
+ "orderMessage",
2441
+ "interactiveResponseMessage"
2442
+ ];
2443
+ const type = order.find((key) => content[key] !== null && content[key] !== void 0);
2444
+ return { type, node: type ? content[type] : void 0 };
2445
+ }
2467
2446
  function getContentKind(type) {
2468
2447
  switch (String(type ?? "")) {
2469
2448
  case "conversation":
@@ -2471,6 +2450,7 @@ function getContentKind(type) {
2471
2450
  case "buttonsResponseMessage":
2472
2451
  case "listResponseMessage":
2473
2452
  case "templateButtonReplyMessage":
2453
+ case "interactiveResponseMessage":
2474
2454
  return "text";
2475
2455
  case "imageMessage":
2476
2456
  return "image";
@@ -2479,7 +2459,6 @@ function getContentKind(type) {
2479
2459
  case "audioMessage":
2480
2460
  return "audio";
2481
2461
  case "documentMessage":
2482
- case "documentWithCaptionMessage":
2483
2462
  return "document";
2484
2463
  case "stickerMessage":
2485
2464
  return "sticker";
@@ -2492,6 +2471,7 @@ function getContentKind(type) {
2492
2471
  case "pollCreationMessage":
2493
2472
  case "pollCreationMessageV2":
2494
2473
  case "pollCreationMessageV3":
2474
+ case "pollCreationMessageV5":
2495
2475
  return "poll";
2496
2476
  case "productMessage":
2497
2477
  case "orderMessage":
@@ -2500,20 +2480,8 @@ function getContentKind(type) {
2500
2480
  return "unknown";
2501
2481
  }
2502
2482
  }
2503
- function normalizeKey(key) {
2504
- const normalized = {
2505
- id: key.id ?? "",
2506
- chatId: key.remoteJid ?? "",
2507
- fromMe: key.fromMe ?? false
2508
- };
2509
- const participantId = key.participant ?? key.participantAlt;
2510
- if (participantId !== null && participantId !== void 0) {
2511
- normalized.participantId = participantId;
2512
- }
2513
- return normalized;
2514
- }
2515
2483
  function getText(content) {
2516
- return content.conversation ?? content.extendedTextMessage?.text ?? content.buttonsResponseMessage?.selectedDisplayText ?? content.listResponseMessage?.title ?? void 0;
2484
+ return content.conversation ?? content.extendedTextMessage?.text ?? content.buttonsResponseMessage?.selectedDisplayText ?? content.listResponseMessage?.title ?? content.templateButtonReplyMessage?.selectedDisplayText ?? void 0;
2517
2485
  }
2518
2486
  function getCaption(content) {
2519
2487
  return content.imageMessage?.caption ?? content.videoMessage?.caption ?? content.documentMessage?.caption ?? void 0;
@@ -2522,9 +2490,9 @@ function getContextInfo(node) {
2522
2490
  if (typeof node !== "object" || node === null || !("contextInfo" in node)) {
2523
2491
  return void 0;
2524
2492
  }
2525
- return node.contextInfo;
2493
+ return node.contextInfo ?? void 0;
2526
2494
  }
2527
- function getMedia(type, node, keyViewOnce) {
2495
+ function getMedia(type, node, wrapperViewOnce) {
2528
2496
  const mapping = {
2529
2497
  imageMessage: "image",
2530
2498
  videoMessage: "video",
@@ -2539,134 +2507,112 @@ function getMedia(type, node, keyViewOnce) {
2539
2507
  const value = node;
2540
2508
  const media = {
2541
2509
  kind,
2542
- viewOnce: keyViewOnce || value.viewOnce === true
2510
+ viewOnce: wrapperViewOnce || value.viewOnce === true
2543
2511
  };
2544
2512
  if (value.mimetype) media.mimetype = value.mimetype;
2545
2513
  if (value.fileName) media.fileName = value.fileName;
2546
- if (value.seconds !== void 0 && value.seconds !== null) media.seconds = Number(value.seconds);
2514
+ const seconds = toNumber(value.seconds);
2515
+ if (seconds !== void 0) media.seconds = seconds;
2547
2516
  return media;
2548
2517
  }
2549
2518
  function getQuoted(context, chatId) {
2550
- if (!context?.stanzaId) {
2551
- return void 0;
2552
- }
2553
- const quoted = context.quotedMessage;
2554
- const quotedIsViewOnce = isViewOnceContent(quoted);
2555
- const content = unwrapMessageContent(quoted);
2556
- const type = content ? getContentType(content) : void 0;
2557
- const node = type && content ? content[type] : void 0;
2558
- const media = getMedia(type, node, quotedIsViewOnce);
2559
- const result = {
2519
+ if (!context?.stanzaId || !context.quotedMessage) return void 0;
2520
+ const content = unwrapZapoMessageContent(context.quotedMessage);
2521
+ if (!content) return void 0;
2522
+ const { type, node } = contentNode(content);
2523
+ const media = getMedia(type, node, isZapoViewOnceContent(context.quotedMessage));
2524
+ const senderId = context.participant ?? void 0;
2525
+ const quoted = {
2560
2526
  key: {
2561
2527
  id: context.stanzaId,
2562
2528
  chatId: context.remoteJid ?? chatId,
2563
- fromMe: false
2529
+ fromMe: false,
2530
+ ...senderId ? { participantId: senderId } : {}
2564
2531
  },
2565
2532
  hasMedia: media !== void 0,
2566
- isViewOnce: media?.viewOnce ?? quotedIsViewOnce
2533
+ isViewOnce: media?.viewOnce ?? false,
2534
+ contentKind: getContentKind(type)
2567
2535
  };
2568
- if (content) {
2569
- result.contentKind = getContentKind(type);
2570
- }
2571
- if (media) {
2572
- result.media = media;
2573
- }
2574
- if (context.participant) {
2575
- result.senderId = context.participant;
2576
- result.sender = User.fromIdentities([context.participant]);
2577
- result.key.participantId = context.participant;
2578
- }
2579
- if (content) {
2580
- const text = getText(content) ?? getCaption(content);
2581
- if (text !== void 0) result.text = text;
2582
- }
2583
- return result;
2536
+ const text = getText(content) ?? getCaption(content);
2537
+ if (text !== void 0) quoted.text = text;
2538
+ if (senderId !== void 0) {
2539
+ quoted.senderId = senderId;
2540
+ quoted.sender = User.fromIdentities([senderId]);
2541
+ }
2542
+ if (media !== void 0) quoted.media = media;
2543
+ return quoted;
2584
2544
  }
2585
2545
  function toDate(value) {
2586
- const seconds = value === null || value === void 0 ? Date.now() / 1e3 : Number(value);
2546
+ const seconds = toNumber(value) ?? Math.floor(Date.now() / 1e3);
2587
2547
  return new Date(seconds * 1e3);
2588
2548
  }
2549
+ function toNumber(value) {
2550
+ if (typeof value === "number") return value;
2551
+ if (value?.toNumber) return value.toNumber();
2552
+ if (typeof value?.low === "number") return value.low;
2553
+ return void 0;
2554
+ }
2589
2555
 
2590
- // src/provider/baileys/baileys-provider.ts
2591
- var BaileysProvider = class {
2556
+ // src/provider/zapo/zapo-provider.ts
2557
+ var ZapoProvider = class {
2592
2558
  #options;
2593
2559
  #events = new TypedEventEmitter();
2594
2560
  #logger;
2595
2561
  #messageStore = /* @__PURE__ */ new Map();
2596
2562
  #messageCacheSize;
2597
- #groupMetadataCache = /* @__PURE__ */ new Map();
2598
- #groupMetadataRequests = /* @__PURE__ */ new Map();
2599
- #groupMetadataGenerations = /* @__PURE__ */ new Map();
2600
- #groupMetadataCacheEnabled;
2601
- #groupMetadataCacheTtlMs;
2602
- #groupMetadataCacheSize;
2603
- #socket;
2604
- #saveCredentials;
2605
- #saveQueue = Promise.resolve();
2563
+ #client;
2564
+ #voip;
2606
2565
  #intentionalClose = false;
2607
2566
  #reconnectAttempt = 0;
2608
2567
  #reconnectTimer;
2609
- #registered = false;
2568
+ #connectPromise;
2569
+ #pairingRequired = false;
2570
+ #connected = false;
2571
+ #connectedAtSeconds = 0;
2572
+ #pairingReady = Promise.resolve();
2573
+ #resolvePairingReady;
2610
2574
  constructor(options) {
2611
2575
  this.#options = options;
2612
2576
  this.#logger = options.logger ?? new Logger("silent");
2613
2577
  this.#messageCacheSize = Math.max(1, options.messageCacheSize ?? 1e3);
2614
- this.#groupMetadataCacheEnabled = options.groupMetadataCache?.enabled !== false;
2615
- this.#groupMetadataCacheTtlMs = Math.max(1, options.groupMetadataCache?.ttlMs ?? 3e5);
2616
- this.#groupMetadataCacheSize = Math.max(1, options.groupMetadataCache?.maxEntries ?? 1e3);
2617
2578
  }
2618
2579
  on(event, listener) {
2619
2580
  return this.#events.on(event, listener);
2620
2581
  }
2621
2582
  async connect() {
2622
- if (this.#socket) {
2583
+ this.#intentionalClose = false;
2584
+ const client = await this.#ensureClient();
2585
+ if (this.#connected || this.#connectPromise) {
2623
2586
  return;
2624
2587
  }
2625
- this.#intentionalClose = false;
2588
+ this.#preparePairingGate();
2626
2589
  await this.#events.emit("connection", {
2627
2590
  state: this.#reconnectAttempt > 0 ? "reconnecting" : "connecting",
2628
2591
  attempt: this.#reconnectAttempt
2629
2592
  });
2630
- try {
2631
- const { state, saveCreds } = await useMultiFileAuthState(this.#options.auth);
2632
- this.#registered = state.creds.registered;
2633
- this.#saveCredentials = saveCreds;
2634
- const socket = makeWASocket({
2635
- auth: state,
2636
- browser: this.#browserDescription(),
2637
- logger: createBaileysLogger(this.#logger.child("baileys")),
2638
- markOnlineOnConnect: false,
2639
- enableAutoSessionRecreation: true,
2640
- enableRecentMessageCache: true,
2641
- cachedGroupMetadata: async (jid) => this.#getGroupMetadata(jid),
2642
- getMessage: async (key) => this.#messageStore.get(this.#messageStoreKey(key))?.message ?? void 0
2643
- });
2644
- this.#socket = socket;
2645
- this.#bind(socket);
2646
- } catch (error) {
2647
- this.#socket = void 0;
2648
- throw new WhaNextError("CONNECTION_FAILED", "Could not start the WhatsApp connection.", {
2649
- cause: error,
2650
- recoverable: true
2651
- });
2652
- }
2593
+ this.#startConnect(client);
2653
2594
  }
2654
2595
  async disconnect() {
2655
2596
  this.#intentionalClose = true;
2656
- if (this.#reconnectTimer) clearTimeout(this.#reconnectTimer);
2657
- const socket = this.#socket;
2658
- this.#socket = void 0;
2659
- if (socket) {
2660
- await socket.end(void 0);
2597
+ if (this.#reconnectTimer) {
2598
+ clearTimeout(this.#reconnectTimer);
2599
+ this.#reconnectTimer = void 0;
2600
+ }
2601
+ const client = this.#client;
2602
+ this.#connectPromise = void 0;
2603
+ if (client) {
2604
+ await client.disconnect();
2605
+ } else {
2606
+ await this.#events.emit("connection", { state: "closed" });
2661
2607
  }
2662
- await this.#events.emit("connection", { state: "closed" });
2608
+ this.#connected = false;
2663
2609
  }
2664
2610
  getCurrentUserIds() {
2665
- const user = this.#socket?.user;
2666
- if (!user) {
2667
- return [];
2668
- }
2669
- return [user.id, user.lid, user.phoneNumber].filter((id) => Boolean(id)).filter((id, index, ids) => ids.indexOf(id) === index);
2611
+ const credentials = this.#client?.getCredentials();
2612
+ return uniqueIdentities([
2613
+ credentials?.meJid,
2614
+ credentials?.meLid
2615
+ ]);
2670
2616
  }
2671
2617
  async requestPairingCode(phone) {
2672
2618
  const normalized = phone.replace(/\D/g, "");
@@ -2676,34 +2622,28 @@ var BaileysProvider = class {
2676
2622
  "The phone number must include its country code."
2677
2623
  );
2678
2624
  }
2679
- if (this.#registered) {
2625
+ const client = await this.#ensureClient();
2626
+ if (client.getCredentials()?.meJid) {
2680
2627
  return "";
2681
2628
  }
2682
- const socket = this.#requireSocket();
2629
+ if (!this.#connectPromise && !this.#connected) {
2630
+ await this.connect();
2631
+ }
2683
2632
  try {
2684
- await socket.waitForConnectionUpdate(async (update) => Boolean(update.qr), 6e4);
2685
- if (socket !== this.#socket) {
2686
- throw new WhaNextError(
2687
- "CONNECTION_CLOSED",
2688
- "The WhatsApp socket changed while preparing the pairing code.",
2689
- {
2690
- recoverable: true
2691
- }
2633
+ if (!this.#pairingRequired) {
2634
+ await this.#withTimeout(
2635
+ this.#pairingReady,
2636
+ 6e4,
2637
+ "The WhatsApp pairing challenge was not received in time."
2692
2638
  );
2693
2639
  }
2694
- return await socket.requestPairingCode(normalized);
2640
+ return await client.auth.requestPairingCode(normalized);
2695
2641
  } catch (error) {
2696
- if (error instanceof WhaNextError) {
2697
- throw error;
2698
- }
2642
+ if (error instanceof WhaNextError) throw error;
2699
2643
  throw new WhaNextError(
2700
2644
  "CONNECTION_FAILED",
2701
2645
  "Could not request the pairing code after the authentication challenge.",
2702
- {
2703
- cause: error,
2704
- context: { statusCode: this.#statusCode(error) },
2705
- recoverable: this.#statusCode(error) === DisconnectReason.connectionClosed
2706
- }
2646
+ { cause: error, recoverable: true }
2707
2647
  );
2708
2648
  }
2709
2649
  }
@@ -2711,18 +2651,17 @@ var BaileysProvider = class {
2711
2651
  if ("buttons" in content) {
2712
2652
  return this.#sendButtons(chatId, content, replyTo);
2713
2653
  }
2714
- const socket = this.#requireSocket();
2715
- const options = replyTo ? {
2716
- quoted: {
2717
- key: this.#toWaKey(replyTo),
2718
- message: { conversation: "" }
2719
- }
2720
- } : void 0;
2721
- const result = await socket.sendMessage(chatId, this.#toContent(content), options);
2722
- return this.#sent(result);
2654
+ const client = this.#requireClient();
2655
+ const { value, mentions, viewOnce } = await this.#toContent(content);
2656
+ const result = await client.message.send(chatId, value, {
2657
+ ...replyTo ? { quote: this.#toZapoKey(replyTo) } : {},
2658
+ ...mentions.length > 0 ? { mentions } : {},
2659
+ ...viewOnce !== void 0 ? { viewOnce } : {}
2660
+ });
2661
+ return this.#sent(result, chatId);
2723
2662
  }
2724
2663
  async repostMessage(source, chatId, options = {}) {
2725
- const original = this.#messageStore.get(this.#messageStoreKey(source));
2664
+ const original = this.#findStoredMessage(this.#toZapoKey(source));
2726
2665
  if (!original?.message) {
2727
2666
  throw new WhaNextError(
2728
2667
  "MESSAGE_NOT_FOUND",
@@ -2733,24 +2672,26 @@ var BaileysProvider = class {
2733
2672
  }
2734
2673
  );
2735
2674
  }
2736
- const content = {
2737
- forward: original,
2738
- ...options.mentions && options.mentions.length > 0 ? { mentions: this.#mentions(options.mentions) } : {}
2739
- };
2740
- const result = await this.#requireSocket().sendMessage(chatId, content);
2741
- return this.#sent(result);
2675
+ const result = await this.#requireClient().message.send(
2676
+ chatId,
2677
+ original.message,
2678
+ {
2679
+ forward: true,
2680
+ ...options.mentions && options.mentions.length > 0 ? { mentions: this.#mentions(options.mentions) } : {}
2681
+ }
2682
+ );
2683
+ return this.#sent(result, chatId);
2742
2684
  }
2743
2685
  async reactToMessage(key, emoji) {
2744
- const result = await this.#requireSocket().sendMessage(key.chatId, {
2745
- react: {
2746
- text: emoji ?? "",
2747
- key: this.#toWaKey(key)
2748
- }
2686
+ const result = await this.#requireClient().message.send(key.chatId, {
2687
+ type: "reaction",
2688
+ emoji: emoji ?? "",
2689
+ target: this.#toZapoKey(key)
2749
2690
  });
2750
- return this.#sent(result);
2691
+ return this.#sent(result, key.chatId);
2751
2692
  }
2752
2693
  async downloadMedia(key) {
2753
- const message = this.#messageStore.get(this.#messageStoreKey(key));
2694
+ const message = this.#findStoredMessage(this.#toZapoKey(key));
2754
2695
  if (!message?.message) {
2755
2696
  throw new WhaNextError(
2756
2697
  "MEDIA_NOT_AVAILABLE",
@@ -2758,54 +2699,75 @@ var BaileysProvider = class {
2758
2699
  { recoverable: true }
2759
2700
  );
2760
2701
  }
2761
- const data = await downloadMediaMessage(message, "buffer", {}, {
2762
- reuploadRequest: (current) => this.#requireSocket().updateMediaMessage(current),
2763
- logger: createBaileysLogger(this.#logger.child("media"))
2764
- });
2765
- const media = normalizeBaileysMessage(message)?.media;
2766
- if (!media) {
2767
- throw new WhaNextError("MEDIA_NOT_AVAILABLE", "The selected message does not contain media.");
2702
+ const normalized = normalizeZapoMessage(message);
2703
+ if (!normalized?.media) {
2704
+ throw new WhaNextError(
2705
+ "MEDIA_NOT_AVAILABLE",
2706
+ "The selected message does not contain media."
2707
+ );
2708
+ }
2709
+ try {
2710
+ const bytes = await this.#requireClient().message.downloadBytes(
2711
+ message
2712
+ );
2713
+ return {
2714
+ data: Buffer.from(bytes),
2715
+ kind: normalized.media.kind,
2716
+ ...normalized.media.mimetype ? { mimetype: normalized.media.mimetype } : {},
2717
+ ...normalized.media.fileName ? { fileName: normalized.media.fileName } : {}
2718
+ };
2719
+ } catch (error) {
2720
+ throw new WhaNextError(
2721
+ "MEDIA_NOT_AVAILABLE",
2722
+ "WhatsApp could not download the selected media.",
2723
+ { cause: error, recoverable: true }
2724
+ );
2768
2725
  }
2769
- return {
2770
- data,
2771
- kind: media.kind,
2772
- ...media.mimetype ? { mimetype: media.mimetype } : {},
2773
- ...media.fileName ? { fileName: media.fileName } : {}
2774
- };
2775
2726
  }
2776
2727
  async editMessage(key, content) {
2777
- const result = await this.#requireSocket().sendMessage(key.chatId, {
2778
- text: content,
2779
- edit: this.#toWaKey(key)
2780
- });
2781
- return this.#sent(result);
2728
+ const result = await this.#requireClient().message.send(
2729
+ key.chatId,
2730
+ content,
2731
+ { editKey: this.#toZapoKey(key) }
2732
+ );
2733
+ return this.#sent(result, key.chatId);
2782
2734
  }
2783
2735
  async deleteMessage(key) {
2784
- await this.#requireSocket().sendMessage(key.chatId, { delete: this.#toWaKey(key) });
2736
+ await this.#requireClient().message.send(key.chatId, {
2737
+ type: "revoke",
2738
+ target: this.#toZapoKey(key)
2739
+ });
2785
2740
  }
2786
2741
  async getGroup(groupId) {
2787
- const metadata = await this.#getGroupMetadata(groupId);
2742
+ const metadata = await this.#requireClient().group.queryGroupMetadata(groupId);
2743
+ const participants = [...metadata.participants ?? []];
2744
+ const addressingMode = metadata.addressingMode === "lid" || participants.some((participant) => (participant.jid ?? participant.id ?? "").endsWith("@lid")) ? "lid" : "pn";
2788
2745
  return {
2789
- id: metadata.id,
2790
- subject: metadata.subject,
2746
+ id: metadata.jid ?? metadata.id ?? groupId,
2747
+ subject: metadata.subject ?? "",
2791
2748
  access: metadata.announce ? "closed" : "open",
2792
- addressingMode: metadata.addressingMode === "lid" ? "lid" : "pn",
2749
+ addressingMode,
2793
2750
  fetchedAt: /* @__PURE__ */ new Date(),
2794
- participants: metadata.participants.map((participant) => ({
2795
- id: participant.id,
2796
- ...participant.lid ? { lid: participant.lid } : {},
2797
- ...participant.phoneNumber ? { phoneNumber: participant.phoneNumber } : {},
2798
- role: participant.admin === "superadmin" || participant.isSuperAdmin ? "owner" : participant.admin === "admin" || participant.isAdmin ? "admin" : "member"
2799
- }))
2751
+ participants: participants.map((participant) => {
2752
+ const id = participant.jid ?? participant.id ?? participant.lid ?? participant.phoneNumber ?? "";
2753
+ return {
2754
+ id,
2755
+ ...participant.lid ? { lid: participant.lid } : {},
2756
+ ...participant.phoneNumber ? { phoneNumber: participant.phoneNumber } : {},
2757
+ role: participant.isSuperAdmin || participant.admin === "superadmin" ? "owner" : participant.isAdmin || participant.admin === "admin" ? "admin" : "member"
2758
+ };
2759
+ })
2800
2760
  };
2801
2761
  }
2802
2762
  async setGroupAccess(groupId, access) {
2803
- const setting = access === "closed" ? "announcement" : "not_announcement";
2804
- await this.#requireSocket().groupSettingUpdate(groupId, setting);
2805
- this.#invalidateGroupMetadata(groupId);
2763
+ await this.#requireClient().group.setSetting(
2764
+ groupId,
2765
+ "announcement",
2766
+ access === "closed"
2767
+ );
2806
2768
  }
2807
2769
  async getGroupInviteCode(groupId) {
2808
- const code = await this.#requireSocket().groupInviteCode(groupId);
2770
+ const code = await this.#requireClient().group.queryInviteCode(groupId);
2809
2771
  if (!code) {
2810
2772
  throw new WhaNextError(
2811
2773
  "PROVIDER_ERROR",
@@ -2815,151 +2777,299 @@ var BaileysProvider = class {
2815
2777
  return code;
2816
2778
  }
2817
2779
  async revokeGroupInvite(groupId) {
2818
- const code = await this.#requireSocket().groupRevokeInvite(groupId);
2819
- if (!code) {
2780
+ const result = await this.#requireClient().group.revokeInvite(groupId);
2781
+ if (!result.code) {
2820
2782
  throw new WhaNextError(
2821
2783
  "PROVIDER_ERROR",
2822
2784
  "WhatsApp did not return a new group invite code."
2823
2785
  );
2824
2786
  }
2825
- return code;
2787
+ return result.code;
2826
2788
  }
2827
2789
  async setMessagePin(groupId, key, pinned) {
2828
- await this.#requireSocket().sendMessage(groupId, {
2829
- pin: this.#toWaKey(key),
2830
- type: pinned ? proto.PinInChat.Type.PIN_FOR_ALL : proto.PinInChat.Type.UNPIN_FOR_ALL,
2831
- ...pinned ? { time: 604800 } : {}
2790
+ await this.#requireClient().message.send(groupId, pinned ? {
2791
+ type: "pin",
2792
+ target: this.#toZapoKey(key),
2793
+ durationSecs: 604800
2794
+ } : {
2795
+ type: "unpin",
2796
+ target: this.#toZapoKey(key)
2832
2797
  });
2833
2798
  }
2834
2799
  async updateParticipant(groupId, memberId, action) {
2835
- const [result] = await this.#requireSocket().groupParticipantsUpdate(groupId, [memberId], action);
2836
- this.#invalidateGroupMetadata(groupId);
2837
- const status = result?.status ?? "unknown";
2800
+ const group = this.#requireClient().group;
2801
+ const results = action === "remove" ? await group.removeParticipants(groupId, [memberId]) : action === "promote" ? await group.promoteParticipants(groupId, [memberId]) : await group.demoteParticipants(groupId, [memberId]);
2802
+ const result = results[0];
2803
+ const success = result?.status === "ok";
2804
+ const status = success ? "200" : String(result?.code ?? result?.status ?? "unknown");
2838
2805
  return {
2839
- success: status === "200",
2806
+ success,
2840
2807
  status,
2841
2808
  ...result?.jid ? { memberId: result.jid } : {}
2842
2809
  };
2843
2810
  }
2844
2811
  async setPresence(chatId, state) {
2845
- const socket = this.#requireSocket();
2846
- const presence = state === "typing" ? "composing" : state === "recording" ? "recording" : "paused";
2847
- await socket.sendPresenceUpdate(presence, chatId);
2812
+ const value = state === "typing" ? "composing" : state === "recording" ? "recording" : "paused";
2813
+ const presence = this.#requireClient().presence;
2814
+ await presence.sendChatstate(chatId, { state: value });
2848
2815
  }
2849
- async rejectCall(callId, from) {
2850
- await this.#requireSocket().rejectCall(callId, from);
2851
- }
2852
- #bind(socket) {
2853
- socket.ev.on("creds.update", (update) => {
2854
- if (update.registered !== void 0) {
2855
- this.#registered = update.registered;
2816
+ async rejectCall(callId, _from) {
2817
+ this.#requireClient();
2818
+ if (!this.#voip) {
2819
+ throw new WhaNextError(
2820
+ "PROVIDER_ERROR",
2821
+ "WhatsApp call support is unavailable because the Zapo VoIP plugin could not be loaded.",
2822
+ { recoverable: true }
2823
+ );
2824
+ }
2825
+ await this.#voip.rejectCall(callId);
2826
+ }
2827
+ async #ensureClient() {
2828
+ if (this.#client) return this.#client;
2829
+ await mkdir(this.#options.auth, { recursive: true });
2830
+ const store = createStore({
2831
+ backends: {
2832
+ sqlite: createSqliteStore({
2833
+ path: join(this.#options.auth, "state.sqlite"),
2834
+ driver: "auto"
2835
+ })
2836
+ },
2837
+ providers: {
2838
+ auth: "sqlite",
2839
+ signal: "sqlite",
2840
+ preKey: "sqlite",
2841
+ session: "sqlite",
2842
+ identity: "sqlite",
2843
+ senderKey: "sqlite",
2844
+ appState: "sqlite",
2845
+ privacyToken: "sqlite",
2846
+ messages: "none",
2847
+ threads: "none",
2848
+ contacts: "none"
2849
+ },
2850
+ cacheProviders: {
2851
+ messageSecret: "sqlite"
2856
2852
  }
2857
- this.#saveQueue = this.#saveQueue.then(() => this.#saveCredentials?.()).then(() => void 0);
2858
2853
  });
2859
- socket.ev.on("messages.upsert", ({ messages, type }) => {
2860
- if (type !== "notify") return;
2861
- for (const raw of messages) {
2862
- if (raw.key.id && raw.message) this.#remember(raw);
2863
- const quoted = extractQuotedBaileysMessage(raw);
2864
- if (quoted?.key.id && quoted.message) this.#remember(quoted);
2865
- const message = normalizeBaileysMessage(raw);
2866
- if (message) void this.#events.emit("message", message);
2867
- }
2854
+ const plugins = [];
2855
+ try {
2856
+ const { voipPlugin } = await import("@zapo-js/voip");
2857
+ plugins.push(voipPlugin({ logLevel: "warn" }));
2858
+ } catch (error) {
2859
+ this.#logger.warn("Zapo VoIP support is unavailable; call events and rejection are disabled.", {
2860
+ error: error instanceof Error ? error.message : String(error)
2861
+ });
2862
+ }
2863
+ const client = new WaClient({
2864
+ store,
2865
+ sessionId: this.#options.sessionId ?? "default",
2866
+ markOnlineOnConnect: false,
2867
+ deviceBrowser: this.#deviceBrowser(),
2868
+ deviceOsDisplayName: this.#deviceOsDisplayName(),
2869
+ history: { enabled: false },
2870
+ addons: {
2871
+ autoDecrypt: true,
2872
+ persistAllSecrets: true
2873
+ },
2874
+ media: { processor: createMediaProcessor() },
2875
+ plugins
2876
+ }, new WhaNextZapoLogger(this.#logger));
2877
+ this.#client = client;
2878
+ this.#voip = client.voip;
2879
+ this.#bind(client);
2880
+ return client;
2881
+ }
2882
+ #bind(client) {
2883
+ client.on("auth_pairing_required", () => {
2884
+ this.#pairingRequired = true;
2885
+ this.#resolvePairingReady?.();
2886
+ this.#resolvePairingReady = void 0;
2868
2887
  });
2869
- socket.ev.on("messages.update", (updates) => {
2870
- for (const { key, update } of updates) {
2871
- if (!key.id || !key.remoteJid) continue;
2872
- const stored = this.#messageStore.get(this.#messageStoreKey(key));
2873
- if (update.message === null) {
2874
- const message2 = stored ? normalizeBaileysMessage(stored) : void 0;
2875
- const deletionKey = update.key;
2876
- const deletedByMe = deletionKey?.fromMe === true;
2877
- const deletedById = deletionKey?.participant ?? deletionKey?.participantAlt ?? (deletedByMe ? this.#socket?.user?.id : deletionKey?.remoteJid ?? void 0);
2878
- void this.#events.emit("messageDeleted", {
2879
- key: message2?.keys ?? normalizeKey(key),
2880
- ...message2 ? { message: message2 } : {},
2881
- deletedByMe,
2882
- ...deletedById ? { deletedById } : {},
2883
- deletedAt: /* @__PURE__ */ new Date()
2884
- });
2885
- continue;
2886
- }
2887
- if (!update.message?.editedMessage?.message) continue;
2888
- const editedRaw = {
2889
- ...stored ?? {},
2890
- key: {
2891
- ...stored?.key ?? {},
2892
- ...key
2893
- },
2894
- message: update.message,
2895
- messageTimestamp: update.messageTimestamp ?? stored?.messageTimestamp ?? Math.floor(Date.now() / 1e3)
2896
- };
2897
- const previous = stored ? normalizeBaileysMessage(stored) : void 0;
2898
- const message = normalizeBaileysMessage(editedRaw);
2899
- if (!message) continue;
2900
- this.#remember(editedRaw);
2901
- const editedByMe = key.fromMe === true;
2902
- const editedById = key.participant ?? key.participantAlt ?? (editedByMe ? this.#socket?.user?.id : key.remoteJid ?? void 0);
2903
- void this.#events.emit("messageEdited", {
2904
- key: message.keys,
2905
- ...previous ? { previous } : {},
2906
- message,
2907
- editedByMe,
2908
- ...editedById ? { editedById } : {},
2909
- editedAt: message.timestamp
2910
- });
2911
- }
2888
+ client.on("auth_paired", () => {
2889
+ this.#pairingRequired = false;
2912
2890
  });
2913
- socket.ev.on("groups.update", (groups) => {
2914
- for (const group of groups) {
2915
- if (group.id) {
2916
- this.#invalidateGroupMetadata(group.id);
2917
- void this.#events.emit("groupChanged", { groupId: group.id });
2918
- }
2919
- }
2891
+ client.on("message", (event) => {
2892
+ this.#handleMessage(event);
2920
2893
  });
2921
- socket.ev.on("group-participants.update", (update) => {
2922
- this.#invalidateGroupMetadata(update.id);
2923
- const change = this.#groupParticipantsChanged(update);
2924
- void this.#events.emit("groupParticipantsChanged", change);
2925
- const { id } = update;
2926
- void this.#events.emit("groupChanged", { groupId: id });
2894
+ client.on("message_send", (event) => {
2895
+ if (!event.id || !event.message) return;
2896
+ this.#remember({
2897
+ key: {
2898
+ id: event.id,
2899
+ remoteJid: event.to,
2900
+ fromMe: true
2901
+ },
2902
+ message: event.message,
2903
+ timestampSeconds: Math.floor(Date.now() / 1e3)
2904
+ });
2927
2905
  });
2928
- socket.ev.on("call", (calls) => {
2929
- for (const call of calls) {
2930
- void this.#events.emit("call", this.#normalizeCall(call));
2931
- }
2906
+ client.on("message_protocol", (event) => {
2907
+ this.#handleProtocolEvent(event);
2932
2908
  });
2933
- socket.ev.on("connection.update", (update) => {
2934
- void this.#handleConnectionUpdate(socket, update.connection, update.lastDisconnect?.error);
2909
+ client.on("group", (event) => {
2910
+ this.#handleGroupEvent(event);
2911
+ });
2912
+ if (this.#voip) {
2913
+ const voipClient = client;
2914
+ voipClient.on("voip_call_incoming", (event) => {
2915
+ const call = this.#normalizeVoipCall(event, "offer");
2916
+ if (call) void this.#events.emit("call", call);
2917
+ });
2918
+ voipClient.on("voip_call_state", (event) => {
2919
+ if (event.stateData?.state === "ended") return;
2920
+ const call = this.#normalizeVoipCall(event);
2921
+ if (call && call.status !== "offer") void this.#events.emit("call", call);
2922
+ });
2923
+ voipClient.on("voip_call_ended", (event) => {
2924
+ const call = this.#normalizeVoipCall(
2925
+ event,
2926
+ this.#callEndStatus(event.stateData?.endReason)
2927
+ );
2928
+ if (call) void this.#events.emit("call", call);
2929
+ });
2930
+ }
2931
+ client.on("connection", (event) => {
2932
+ void this.#handleConnectionEvent(client, event);
2935
2933
  });
2936
2934
  }
2937
- async #handleConnectionUpdate(socket, connection, error) {
2938
- if (socket !== this.#socket || !connection) return;
2939
- if (connection === "open") {
2935
+ #handleMessage(event) {
2936
+ const stored = event;
2937
+ if (this.#isOfflineMessage(stored)) {
2938
+ this.#logger.debug("Ignored message queued before the current connection.", {
2939
+ messageId: stored.key.id ?? void 0,
2940
+ chatId: stored.key.remoteJid ?? void 0,
2941
+ timestampSeconds: stored.timestampSeconds ?? void 0
2942
+ });
2943
+ return;
2944
+ }
2945
+ if (stored.key?.id && stored.message) this.#remember(stored);
2946
+ const quoted = extractQuotedZapoMessage(event);
2947
+ if (quoted) {
2948
+ const quotedStored = quoted;
2949
+ if (quotedStored.key?.id && quotedStored.message) this.#remember(quotedStored);
2950
+ }
2951
+ const message = normalizeZapoMessage(event);
2952
+ if (message) void this.#events.emit("message", message);
2953
+ }
2954
+ #handleProtocolEvent(event) {
2955
+ const protocol = event.protocolMessage ?? event.message?.protocolMessage;
2956
+ if (!protocol) return;
2957
+ const protocolKey = protocol.key;
2958
+ if (!protocolKey?.id) return;
2959
+ const remoteJid = protocolKey.remoteJid ?? event.key.remoteJid;
2960
+ const participant = protocolKey.participant ?? event.key.participant;
2961
+ const participantAlt = protocolKey.participantAlt ?? event.key.participantAlt;
2962
+ const target = {
2963
+ ...protocolKey,
2964
+ ...remoteJid !== void 0 ? { remoteJid } : {},
2965
+ ...participant !== void 0 ? { participant } : {},
2966
+ ...participantAlt !== void 0 ? { participantAlt } : {}
2967
+ };
2968
+ if (!target.remoteJid) return;
2969
+ const stored = this.#findStoredMessage(target);
2970
+ const type = protocol?.type;
2971
+ if (type === proto.Message.ProtocolMessage.Type.REVOKE) {
2972
+ const previous2 = stored ? normalizeZapoMessage(stored) : void 0;
2973
+ const deletedByMe = event.key.fromMe === true;
2974
+ const deletedById = event.key.participant ?? event.key.participantAlt ?? (deletedByMe ? this.getCurrentUserIds()[0] : event.key.remoteJid ?? void 0);
2975
+ void this.#events.emit("messageDeleted", {
2976
+ key: previous2?.keys ?? normalizeZapoKey(target),
2977
+ ...previous2 ? { message: previous2 } : {},
2978
+ deletedByMe,
2979
+ ...deletedById ? { deletedById } : {},
2980
+ deletedAt: /* @__PURE__ */ new Date()
2981
+ });
2982
+ return;
2983
+ }
2984
+ if (type !== proto.Message.ProtocolMessage.Type.MESSAGE_EDIT || !protocol.editedMessage) {
2985
+ return;
2986
+ }
2987
+ const pushName = event.pushName ?? stored?.pushName;
2988
+ const edited = {
2989
+ ...stored ?? {},
2990
+ key: {
2991
+ ...stored?.key ?? {},
2992
+ ...target
2993
+ },
2994
+ message: protocol.editedMessage,
2995
+ timestampSeconds: toSeconds(protocol.timestampMs) ?? event.timestampSeconds ?? stored?.timestampSeconds ?? Math.floor(Date.now() / 1e3),
2996
+ ...pushName !== void 0 ? { pushName } : {}
2997
+ };
2998
+ const message = normalizeZapoMessage(edited);
2999
+ if (!message) return;
3000
+ const previous = stored ? normalizeZapoMessage(stored) : void 0;
3001
+ this.#remember(edited);
3002
+ const editedByMe = event.key.fromMe === true;
3003
+ const editedById = event.key.participant ?? event.key.participantAlt ?? (editedByMe ? this.getCurrentUserIds()[0] : event.key.remoteJid ?? void 0);
3004
+ void this.#events.emit("messageEdited", {
3005
+ key: message.keys,
3006
+ ...previous ? { previous } : {},
3007
+ message,
3008
+ editedByMe,
3009
+ ...editedById ? { editedById } : {},
3010
+ editedAt: message.timestamp
3011
+ });
3012
+ }
3013
+ #handleGroupEvent(event) {
3014
+ const groupId = event.groupJid;
3015
+ if (!groupId) return;
3016
+ const action = this.#groupAction(event.action);
3017
+ const participantIds = this.#groupParticipantIds(event);
3018
+ if (action && participantIds.length > 0) {
3019
+ const authorId = event.authorJid;
3020
+ const change = {
3021
+ groupId,
3022
+ action,
3023
+ participantIds,
3024
+ ...authorId ? { authorId } : {}
3025
+ };
3026
+ void this.#events.emit("groupParticipantsChanged", change);
3027
+ }
3028
+ void this.#events.emit("groupChanged", { groupId });
3029
+ }
3030
+ async #handleConnectionEvent(client, event) {
3031
+ if (client !== this.#client) return;
3032
+ if (event.status === "open") {
3033
+ this.#connectPromise = void 0;
3034
+ this.#connected = true;
3035
+ this.#connectedAtSeconds = Math.floor(Date.now() / 1e3);
2940
3036
  this.#reconnectAttempt = 0;
2941
3037
  await this.#events.emit("connection", { state: "connected" });
2942
3038
  return;
2943
3039
  }
2944
- if (connection === "connecting") {
3040
+ this.#connectPromise = void 0;
3041
+ this.#connected = false;
3042
+ const error = event.reason instanceof Error ? event.reason : event.reason ? new Error(String(event.reason)) : void 0;
3043
+ if (this.#intentionalClose || event.isLogout) {
2945
3044
  await this.#events.emit("connection", {
2946
- state: "connecting",
2947
- attempt: this.#reconnectAttempt
3045
+ state: "closed",
3046
+ ...error ? { error } : {}
2948
3047
  });
2949
3048
  return;
2950
3049
  }
2951
- this.#socket = void 0;
2952
- if (this.#intentionalClose || this.#isTerminal(error)) {
2953
- await this.#events.emit("connection", { state: "closed", ...error ? { error } : {} });
2954
- return;
2955
- }
2956
3050
  await this.#scheduleReconnect(error);
2957
3051
  }
3052
+ #startConnect(client) {
3053
+ const promise = client.connect();
3054
+ this.#connectPromise = promise;
3055
+ void promise.catch(async (error) => {
3056
+ if (this.#connectPromise !== promise) return;
3057
+ this.#connectPromise = void 0;
3058
+ if (this.#intentionalClose) return;
3059
+ const normalized = error instanceof Error ? error : new Error(String(error));
3060
+ this.#logger.warn("WhatsApp connection attempt failed.", { error: normalized });
3061
+ await this.#scheduleReconnect(normalized);
3062
+ });
3063
+ }
2958
3064
  async #scheduleReconnect(error) {
3065
+ if (this.#reconnectTimer) return;
2959
3066
  const options = this.#options.reconnect;
2960
3067
  const maxAttempts = options?.maxAttempts ?? 10;
2961
3068
  if (options?.enabled === false || this.#reconnectAttempt >= maxAttempts) {
2962
- await this.#events.emit("connection", { state: "closed", ...error ? { error } : {} });
3069
+ await this.#events.emit("connection", {
3070
+ state: "closed",
3071
+ ...error ? { error } : {}
3072
+ });
2963
3073
  return;
2964
3074
  }
2965
3075
  this.#reconnectAttempt += 1;
@@ -2971,184 +3081,120 @@ var BaileysProvider = class {
2971
3081
  const initial = options?.initialDelayMs ?? 1e3;
2972
3082
  const maximum = options?.maxDelayMs ?? 3e4;
2973
3083
  const delay = Math.min(maximum, initial * 2 ** (this.#reconnectAttempt - 1));
2974
- this.#reconnectTimer = setTimeout(
2975
- () => void this.connect(),
2976
- delay + Math.floor(Math.random() * 250)
2977
- );
2978
- }
2979
- #browserDescription() {
2980
- if (this.#options.browser === "macos" /* MacOS */) return Browsers.macOS("Safari");
2981
- if (this.#options.browser === "ubuntu" /* Ubuntu */) return Browsers.ubuntu("Chrome");
2982
- return Browsers.windows("Brave");
2983
- }
2984
- #isTerminal(error) {
2985
- const statusCode = this.#statusCode(error);
2986
- return statusCode === DisconnectReason.loggedOut || statusCode === DisconnectReason.badSession || statusCode === DisconnectReason.connectionReplaced;
2987
- }
2988
- #statusCode(error) {
2989
- return error?.output?.statusCode;
2990
- }
2991
- #requireSocket() {
2992
- if (!this.#socket) {
2993
- throw new WhaNextError(
2994
- "CONNECTION_CLOSED",
2995
- "WhatsApp is not connected.",
2996
- { recoverable: true }
2997
- );
2998
- }
2999
- return this.#socket;
3084
+ this.#reconnectTimer = setTimeout(() => {
3085
+ this.#reconnectTimer = void 0;
3086
+ void this.connect();
3087
+ }, delay + Math.floor(Math.random() * 250));
3000
3088
  }
3001
3089
  async #sendButtons(chatId, content, replyTo) {
3002
- const socket = this.#requireSocket();
3003
- const userJid = socket.user?.id;
3004
- if (!userJid) {
3005
- throw new WhaNextError(
3006
- "PROVIDER_ERROR",
3007
- "WhatsApp did not expose the current account identity for the interactive message."
3008
- );
3009
- }
3010
- const interactiveMessage = proto.Message.InteractiveMessage.create({
3011
- ...content.title !== void 0 ? {
3012
- header: {
3013
- title: content.title,
3014
- hasMediaAttachment: false
3015
- }
3016
- } : {},
3017
- body: { text: content.text },
3018
- ...content.footer !== void 0 ? { footer: { text: content.footer } } : {},
3019
- ...content.mentions && content.mentions.length > 0 ? {
3020
- contextInfo: {
3021
- mentionedJid: this.#mentions(content.mentions)
3022
- }
3023
- } : {},
3024
- nativeFlowMessage: {
3025
- buttons: content.buttons.map((button) => {
3026
- if (button.type === "copy") {
3027
- return {
3028
- name: "cta_copy",
3029
- buttonParamsJson: JSON.stringify({
3030
- display_text: button.label,
3031
- copy_code: button.code
3032
- })
3033
- };
3090
+ const mentions = content.mentions ? this.#mentions(content.mentions) : [];
3091
+ const raw = {
3092
+ interactiveMessage: {
3093
+ ...content.title !== void 0 ? {
3094
+ header: {
3095
+ title: content.title,
3096
+ hasMediaAttachment: false
3034
3097
  }
3035
- return {
3098
+ } : {},
3099
+ body: { text: content.text },
3100
+ ...content.footer !== void 0 ? { footer: { text: content.footer } } : {},
3101
+ ...mentions.length > 0 ? { contextInfo: { mentionedJid: mentions } } : {},
3102
+ nativeFlowMessage: {
3103
+ buttons: content.buttons.map((button) => button.type === "copy" ? {
3104
+ name: "cta_copy",
3105
+ buttonParamsJson: JSON.stringify({
3106
+ display_text: button.label,
3107
+ copy_code: button.code
3108
+ })
3109
+ } : {
3036
3110
  name: "cta_url",
3037
3111
  buttonParamsJson: JSON.stringify({
3038
3112
  display_text: button.label,
3039
3113
  url: button.url,
3040
3114
  merchant_url: button.url
3041
3115
  })
3042
- };
3043
- }),
3044
- messageParamsJson: "{}",
3045
- messageVersion: 1
3046
- }
3047
- });
3048
- const quoted = replyTo ? {
3049
- key: this.#toWaKey(replyTo),
3050
- message: { conversation: "" }
3051
- } : void 0;
3052
- const generated = generateWAMessageFromContent(
3053
- chatId,
3054
- { interactiveMessage },
3055
- {
3056
- userJid,
3057
- ...quoted ? { quoted } : {}
3058
- }
3059
- );
3060
- const messageId = generated.key.id;
3061
- if (!generated.message || !messageId) {
3062
- throw new WhaNextError(
3063
- "PROVIDER_ERROR",
3064
- "WhatsApp could not generate the interactive message."
3065
- );
3066
- }
3067
- await socket.relayMessage(chatId, generated.message, {
3068
- messageId,
3069
- additionalNodes: this.#interactiveRelayNodes(chatId)
3070
- });
3071
- return this.#sent(generated);
3072
- }
3073
- #interactiveRelayNodes(chatId) {
3074
- const bizNode = {
3075
- tag: "biz",
3076
- attrs: {
3077
- actual_actors: "2",
3078
- host_storage: "2",
3079
- privacy_mode_ts: (Math.floor(Date.now() / 1e3) - 77980457).toString()
3080
- },
3081
- content: [
3082
- {
3083
- tag: "interactive",
3084
- attrs: { type: "native_flow", v: "1" },
3085
- content: [
3086
- {
3087
- tag: "native_flow",
3088
- attrs: { v: "9", name: "mixed" }
3089
- }
3090
- ]
3091
- },
3092
- {
3093
- tag: "quality_control",
3094
- attrs: { source_type: "third_party" }
3116
+ }),
3117
+ messageParamsJson: "{}",
3118
+ messageVersion: 1
3095
3119
  }
3096
- ]
3120
+ }
3097
3121
  };
3098
- if (isJidGroup(chatId)) {
3099
- return [bizNode];
3100
- }
3101
- return [
3102
- { tag: "bot", attrs: { biz_bot: "1" } },
3103
- bizNode
3104
- ];
3122
+ const result = await this.#requireClient().message.send(chatId, raw, {
3123
+ ...replyTo ? { quote: this.#toZapoKey(replyTo) } : {},
3124
+ ...mentions.length > 0 ? { mentions } : {}
3125
+ });
3126
+ return this.#sent(result, chatId);
3105
3127
  }
3106
- #toContent(content) {
3128
+ async #toContent(content) {
3107
3129
  if ("text" in content) {
3108
3130
  return {
3109
- text: content.text,
3110
- ...content.mentions ? { mentions: this.#mentions(content.mentions) } : {}
3131
+ value: { type: "text", text: content.text },
3132
+ mentions: content.mentions ? this.#mentions(content.mentions) : []
3111
3133
  };
3112
3134
  }
3113
3135
  if ("image" in content) {
3114
3136
  return {
3115
- image: this.#media(content.image),
3116
- ...content.caption !== void 0 ? { caption: content.caption } : {},
3117
- ...content.mentions ? { mentions: this.#mentions(content.mentions) } : {},
3137
+ value: {
3138
+ type: "image",
3139
+ media: await this.#media(content.image),
3140
+ ...content.caption !== void 0 ? { caption: content.caption } : {}
3141
+ },
3142
+ mentions: content.mentions ? this.#mentions(content.mentions) : [],
3118
3143
  ...content.viewOnce !== void 0 ? { viewOnce: content.viewOnce } : {}
3119
3144
  };
3120
3145
  }
3121
3146
  if ("video" in content) {
3122
3147
  return {
3123
- video: this.#media(content.video),
3124
- ...content.caption !== void 0 ? { caption: content.caption } : {},
3125
- ...content.mentions ? { mentions: this.#mentions(content.mentions) } : {},
3126
- ...content.viewOnce !== void 0 ? { viewOnce: content.viewOnce } : {},
3127
- ...content.gif !== void 0 ? { gifPlayback: content.gif } : {}
3148
+ value: {
3149
+ type: "video",
3150
+ media: await this.#media(content.video),
3151
+ ...content.caption !== void 0 ? { caption: content.caption } : {},
3152
+ ...content.gif !== void 0 ? { gifPlayback: content.gif } : {}
3153
+ },
3154
+ mentions: content.mentions ? this.#mentions(content.mentions) : [],
3155
+ ...content.viewOnce !== void 0 ? { viewOnce: content.viewOnce } : {}
3128
3156
  };
3129
3157
  }
3130
3158
  if ("sticker" in content) {
3131
- return { sticker: this.#media(content.sticker) };
3159
+ return {
3160
+ value: {
3161
+ type: "sticker",
3162
+ media: await this.#media(content.sticker),
3163
+ mimetype: "image/webp"
3164
+ },
3165
+ mentions: []
3166
+ };
3132
3167
  }
3133
3168
  return {
3134
- audio: this.#media(content.audio),
3135
- ...content.mimetype ? { mimetype: content.mimetype } : {},
3136
- ...content.voice !== void 0 ? { ptt: content.voice } : {}
3169
+ value: {
3170
+ type: "audio",
3171
+ media: await this.#media(content.audio),
3172
+ ...content.mimetype ? { mimetype: content.mimetype } : {},
3173
+ ...content.voice !== void 0 ? { ptt: content.voice } : {}
3174
+ },
3175
+ mentions: []
3137
3176
  };
3138
3177
  }
3139
- #media(source) {
3140
- if (source instanceof Uint8Array) {
3141
- return Buffer.from(source);
3142
- }
3143
- if ("url" in source) {
3144
- return { url: source.url };
3178
+ async #media(source) {
3179
+ if (source instanceof Uint8Array) return source;
3180
+ if ("path" in source) return source.path;
3181
+ const response = await fetch(source.url);
3182
+ if (!response.ok) {
3183
+ throw new WhaNextError(
3184
+ "PROVIDER_ERROR",
3185
+ "Could not download the remote media source.",
3186
+ {
3187
+ context: { status: response.status },
3188
+ recoverable: response.status >= 500
3189
+ }
3190
+ );
3145
3191
  }
3146
- return { url: source.path };
3192
+ return new Uint8Array(await response.arrayBuffer());
3147
3193
  }
3148
3194
  #mentions(mentions) {
3149
3195
  return mentions.map((mention) => typeof mention === "string" ? mention : mention.mentionId);
3150
3196
  }
3151
- #toWaKey(key) {
3197
+ #toZapoKey(key) {
3152
3198
  return {
3153
3199
  id: key.id,
3154
3200
  remoteJid: key.chatId,
@@ -3156,48 +3202,87 @@ var BaileysProvider = class {
3156
3202
  ...key.participantId ? { participant: key.participantId } : {}
3157
3203
  };
3158
3204
  }
3159
- #sent(message) {
3160
- if (!message?.key.id || !message.key.remoteJid) {
3161
- throw new WhaNextError("PROVIDER_ERROR", "WhatsApp did not confirm the sent message.");
3205
+ #sent(result, chatId) {
3206
+ if (!result.id) {
3207
+ throw new WhaNextError(
3208
+ "PROVIDER_ERROR",
3209
+ "WhatsApp did not confirm the sent message."
3210
+ );
3162
3211
  }
3163
- if (message.message) this.#remember(message);
3164
3212
  return {
3165
- id: message.key.id,
3166
- chatId: message.key.remoteJid,
3167
- keys: normalizeKey(message.key),
3213
+ id: result.id,
3214
+ chatId,
3215
+ keys: {
3216
+ id: result.id,
3217
+ chatId,
3218
+ fromMe: true
3219
+ },
3168
3220
  timestamp: /* @__PURE__ */ new Date()
3169
3221
  };
3170
3222
  }
3171
- #normalizeCall(call) {
3172
- return {
3173
- id: call.id,
3174
- chatId: call.chatId,
3175
- from: call.from,
3176
- status: this.#callStatus(call.status),
3177
- isVideo: Boolean(call.isVideo),
3178
- isGroup: Boolean(call.isGroup),
3179
- date: call.date ?? /* @__PURE__ */ new Date()
3180
- };
3181
- }
3182
- #groupParticipantsChanged(change) {
3183
- const participantIds = change.participants.map((participant) => participant.id).filter((id) => Boolean(id));
3223
+ #normalizeVoipCall(event, forcedStatus) {
3224
+ const id = event.callId;
3225
+ const from = event.callerPn ?? event.peerJid ?? event.callCreator;
3226
+ const chatId = event.groupJid ?? event.peerJid ?? from;
3227
+ if (!id || !from || !chatId) return void 0;
3184
3228
  return {
3185
- groupId: change.id,
3186
- action: change.action,
3187
- participantIds,
3188
- ...change.author ? { authorId: change.author } : {}
3229
+ id,
3230
+ chatId,
3231
+ from,
3232
+ status: forcedStatus ?? this.#callStatus(event.stateData?.state),
3233
+ isVideo: event.mediaType === "video",
3234
+ isGroup: Boolean(event.groupJid),
3235
+ date: event.createdAt ?? /* @__PURE__ */ new Date()
3189
3236
  };
3190
3237
  }
3191
3238
  #callStatus(status) {
3192
- const known = [
3193
- "offer",
3194
- "ringing",
3195
- "preaccept",
3196
- "timeout",
3197
- "reject",
3198
- "accept"
3199
- ];
3200
- return known.find((value) => value === status) ?? "timeout";
3239
+ switch (status?.toLowerCase()) {
3240
+ case "offer":
3241
+ case "initiating":
3242
+ return "offer";
3243
+ case "ringing":
3244
+ case "incoming_ringing":
3245
+ return "ringing";
3246
+ case "preaccept":
3247
+ case "connecting":
3248
+ return "preaccept";
3249
+ case "accept":
3250
+ case "accepted":
3251
+ case "active":
3252
+ return "accept";
3253
+ case "reject":
3254
+ case "rejected":
3255
+ case "terminate":
3256
+ case "terminated":
3257
+ case "ended":
3258
+ return "reject";
3259
+ default:
3260
+ return "timeout";
3261
+ }
3262
+ }
3263
+ #callEndStatus(reason) {
3264
+ return reason?.toLowerCase() === "timeout" ? "timeout" : "reject";
3265
+ }
3266
+ #groupAction(action) {
3267
+ const value = action?.toLowerCase() ?? "";
3268
+ if (value.includes("promote")) return "promote";
3269
+ if (value.includes("demote")) return "demote";
3270
+ if (value.includes("remove") || value.includes("leave")) return "remove";
3271
+ if (value.includes("add") || value.includes("join")) return "add";
3272
+ if (value.includes("participant") || value.includes("modify")) return "modify";
3273
+ return void 0;
3274
+ }
3275
+ #groupParticipantIds(event) {
3276
+ return uniqueIdentities((event.participants ?? []).map((participant) => participant.jid ?? participant.lidJid ?? participant.phoneJid));
3277
+ }
3278
+ #findStoredMessage(key) {
3279
+ const direct = this.#messageStore.get(this.#messageStoreKey(key));
3280
+ if (direct) return direct;
3281
+ if (!key.id) return void 0;
3282
+ for (const message of this.#messageStore.values()) {
3283
+ if (message.key.id === key.id) return message;
3284
+ }
3285
+ return void 0;
3201
3286
  }
3202
3287
  #remember(message) {
3203
3288
  const key = this.#messageStoreKey(message.key);
@@ -3208,70 +3293,112 @@ var BaileysProvider = class {
3208
3293
  if (oldest) this.#messageStore.delete(oldest);
3209
3294
  }
3210
3295
  }
3211
- async #getGroupMetadata(groupId) {
3212
- if (this.#groupMetadataCacheEnabled) {
3213
- const cached = this.#groupMetadataCache.get(groupId);
3214
- if (cached && cached.expiresAt > Date.now()) {
3215
- this.#groupMetadataCache.delete(groupId);
3216
- this.#groupMetadataCache.set(groupId, cached);
3217
- return cached.value;
3218
- }
3219
- if (cached) this.#groupMetadataCache.delete(groupId);
3220
- }
3221
- const generation = this.#groupMetadataGenerations.get(groupId) ?? 0;
3222
- const pending = this.#groupMetadataRequests.get(groupId);
3223
- if (pending?.generation === generation) return pending.promise;
3224
- const request = this.#requireSocket().groupMetadata(groupId);
3225
- const requestEntry = { generation, promise: request };
3226
- this.#groupMetadataRequests.set(groupId, requestEntry);
3296
+ #messageStoreKey(key) {
3297
+ return `${key.remoteJid ?? ""}:${key.id ?? ""}:${key.participant ?? key.participantAlt ?? ""}`;
3298
+ }
3299
+ #isOfflineMessage(message) {
3300
+ if (this.#options.processOfflineMessages === true) return false;
3301
+ if (message.offline === true) return true;
3302
+ if (!this.#connectedAtSeconds || message.timestampSeconds == null) return false;
3303
+ const timestamp = toSeconds(message.timestampSeconds);
3304
+ if (timestamp === void 0) return false;
3305
+ return timestamp < this.#connectedAtSeconds - 3;
3306
+ }
3307
+ #preparePairingGate() {
3308
+ this.#pairingRequired = false;
3309
+ this.#pairingReady = new Promise((resolve3) => {
3310
+ this.#resolvePairingReady = resolve3;
3311
+ });
3312
+ }
3313
+ #deviceBrowser() {
3314
+ return this.#options.browser === "macos" /* MacOS */ ? "safari" : "chrome";
3315
+ }
3316
+ #deviceOsDisplayName() {
3317
+ if (this.#options.browser === "macos" /* MacOS */) return "macOS";
3318
+ if (this.#options.browser === "ubuntu" /* Ubuntu */) return "Ubuntu";
3319
+ return "Windows";
3320
+ }
3321
+ #requireClient() {
3322
+ const client = this.#client;
3323
+ if (!client || !this.#connected) {
3324
+ throw new WhaNextError(
3325
+ "CONNECTION_CLOSED",
3326
+ "WhatsApp is not connected.",
3327
+ { recoverable: true }
3328
+ );
3329
+ }
3330
+ return client;
3331
+ }
3332
+ async #withTimeout(promise, timeoutMs, message) {
3333
+ let timer;
3227
3334
  try {
3228
- const metadata = await request;
3229
- if ((this.#groupMetadataGenerations.get(groupId) ?? 0) === generation) {
3230
- this.#rememberGroupMetadata(groupId, metadata);
3231
- }
3232
- return metadata;
3335
+ return await Promise.race([
3336
+ promise,
3337
+ new Promise((_, reject) => {
3338
+ timer = setTimeout(() => {
3339
+ reject(new WhaNextError(
3340
+ "CONNECTION_FAILED",
3341
+ message,
3342
+ { recoverable: true }
3343
+ ));
3344
+ }, timeoutMs);
3345
+ })
3346
+ ]);
3233
3347
  } finally {
3234
- if (this.#groupMetadataRequests.get(groupId) === requestEntry) {
3235
- this.#groupMetadataRequests.delete(groupId);
3236
- }
3348
+ if (timer) clearTimeout(timer);
3237
3349
  }
3238
3350
  }
3239
- #rememberGroupMetadata(groupId, metadata) {
3240
- if (!this.#groupMetadataCacheEnabled) return;
3241
- this.#groupMetadataCache.delete(groupId);
3242
- this.#groupMetadataCache.set(groupId, {
3243
- value: metadata,
3244
- expiresAt: Date.now() + this.#groupMetadataCacheTtlMs
3245
- });
3246
- while (this.#groupMetadataCache.size > this.#groupMetadataCacheSize) {
3247
- const oldest = this.#groupMetadataCache.keys().next().value;
3248
- if (oldest === void 0) return;
3249
- this.#groupMetadataCache.delete(oldest);
3250
- }
3351
+ };
3352
+ var WhaNextZapoLogger = class _WhaNextZapoLogger {
3353
+ level;
3354
+ #logger;
3355
+ #context;
3356
+ constructor(logger, context = {}) {
3357
+ this.#logger = logger;
3358
+ this.#context = context;
3359
+ this.level = logger.level === "debug" ? "debug" : logger.level === "warn" ? "warn" : logger.level === "error" || logger.level === "silent" ? "error" : "info";
3251
3360
  }
3252
- #invalidateGroupMetadata(groupId) {
3253
- this.#groupMetadataCache.delete(groupId);
3254
- const generation = this.#groupMetadataGenerations.get(groupId) ?? 0;
3255
- this.#groupMetadataGenerations.set(groupId, generation + 1);
3361
+ trace(message, context) {
3362
+ this.#logger.debug(message, this.#merge(context));
3256
3363
  }
3257
- #messageStoreKey(key) {
3258
- const chatId = "chatId" in key ? key.chatId : key.remoteJid;
3259
- return `${chatId ?? ""}:${key.id ?? ""}`;
3364
+ debug(message, context) {
3365
+ this.#logger.debug(message, this.#merge(context));
3366
+ }
3367
+ info(message, context) {
3368
+ this.#logger.info(message, this.#merge(context));
3369
+ }
3370
+ warn(message, context) {
3371
+ this.#logger.warn(message, this.#merge(context));
3372
+ }
3373
+ error(message, context) {
3374
+ this.#logger.error(message, this.#merge(context));
3375
+ }
3376
+ child(bindings) {
3377
+ return new _WhaNextZapoLogger(this.#logger, {
3378
+ ...this.#context,
3379
+ ...bindings
3380
+ });
3381
+ }
3382
+ #merge(context) {
3383
+ return context ? { ...this.#context, ...context } : this.#context;
3260
3384
  }
3261
3385
  };
3386
+ function toSeconds(value) {
3387
+ const raw = typeof value === "number" ? value : value?.toNumber ? value.toNumber() : value?.low;
3388
+ if (raw === void 0) return void 0;
3389
+ return raw > 1e10 ? Math.floor(raw / 1e3) : raw;
3390
+ }
3262
3391
 
3263
3392
  // src/app/create.ts
3264
3393
  async function create(options = {}) {
3265
3394
  const logger = new Logger(options.logger);
3266
- const provider = options.provider ?? new BaileysProvider({
3395
+ const provider = options.provider ?? new ZapoProvider({
3267
3396
  auth: options.auth ?? "./session",
3268
3397
  browser: options.browser ?? "windows" /* Windows */,
3269
3398
  logger: logger.child("provider"),
3399
+ ...options.accountId ? { sessionId: options.accountId } : {},
3270
3400
  ...options.messageCacheSize !== void 0 ? { messageCacheSize: options.messageCacheSize } : {},
3271
- groupMetadataCache: {
3272
- ...options.cache?.groupTtlMs !== void 0 ? { ttlMs: options.cache.groupTtlMs } : {},
3273
- ...options.cache?.memoryMaxEntries !== void 0 ? { maxEntries: options.cache.memoryMaxEntries } : {}
3274
- },
3401
+ ...options.processOfflineMessages !== void 0 ? { processOfflineMessages: options.processOfflineMessages } : {},
3275
3402
  ...options.reconnect ? { reconnect: options.reconnect } : {}
3276
3403
  });
3277
3404
  return new WhaNextApp(provider, {
@@ -3287,7 +3414,7 @@ async function create(options = {}) {
3287
3414
 
3288
3415
  // src/app/multi-app.ts
3289
3416
  import {
3290
- join,
3417
+ join as join2,
3291
3418
  resolve as resolve2
3292
3419
  } from "path";
3293
3420
  var MultiCommandRouter = class {
@@ -3433,7 +3560,7 @@ async function createMulti(options) {
3433
3560
  }
3434
3561
  normalizedIds.add(normalizedId);
3435
3562
  if (account.provider === void 0) {
3436
- const authPath = resolve2(account.auth ?? join(authRoot, account.id));
3563
+ const authPath = resolve2(account.auth ?? join2(authRoot, account.id));
3437
3564
  if (authPaths.has(authPath)) {
3438
3565
  throw new WhaNextError(
3439
3566
  "ARGUMENT_INVALID",
@@ -3454,13 +3581,13 @@ async function createMulti(options) {
3454
3581
  if (merged.mute?.enabled === true && merged.mute.store === void 0 && merged.mute.database === void 0) {
3455
3582
  merged.mute = {
3456
3583
  ...merged.mute,
3457
- database: join("./data", `whanext-${id}.sqlite`)
3584
+ database: join2("./data", `whanext-${id}.sqlite`)
3458
3585
  };
3459
3586
  }
3460
3587
  const app = await create({
3461
3588
  ...merged,
3462
3589
  accountId: id,
3463
- auth: overrides.auth ?? join(authRoot, id)
3590
+ auth: overrides.auth ?? join2(authRoot, id)
3464
3591
  });
3465
3592
  apps.set(id, app);
3466
3593
  }