@whanext/core 0.16.0 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.1
4
+
5
+ ### Fixed
6
+
7
+ - Compatibilidade com o novo formato criptografado de edições do WhatsApp (`secretEncryptedMessage`).
8
+ - O provider interpreta `targetMessageKey.fromMe` pela perspectiva do editor, deriva a chave com `messageSecret` e descriptografa edições com AES-256-GCM.
9
+ - Edições em conversas privadas preservam a chave local da mensagem original após a descriptografia.
10
+ - Edições consecutivas preservam o `messageSecret` no cache para que a versão anterior continue disponível.
11
+ - `messageEdited` continua com a mesma API pública da 0.17.0.
12
+
13
+ ## 0.17.0
14
+
15
+ ### Adicionado
16
+
17
+ - Novo evento público `messageEdited` em `app.on()` e `multi.on()`.
18
+ - Novo tipo `MessageEdited`, com versão anterior quando ainda estiver no cache, versão atual, identidade responsável e horário da edição.
19
+ - O provider Baileys passa a interpretar atualizações `editedMessage` recebidas em `messages.update`.
20
+ - O cache recente é atualizado após cada edição, permitindo acompanhar múltiplas alterações da mesma mensagem em sequência.
21
+
22
+ ### Compatibilidade
23
+
24
+ - A mudança é aditiva para consumidores da API pública.
25
+ - Providers customizados passam a incluir `messageEdited` em `ProviderEvents`.
26
+ - Quando a versão anterior já saiu do cache, o evento continua sendo emitido sem o campo `previous`.
27
+
3
28
 
4
29
  ## 0.16.0
5
30
 
package/README.md CHANGED
@@ -173,6 +173,20 @@ app.on('messageDeleted', async ({ message, deletedByMe }) => {
173
173
 
174
174
  O evento também informa `deletedById` quando o WhatsApp fornece a identidade responsável pela revogação.
175
175
 
176
+ ## Mensagens editadas
177
+
178
+ Edições recebidas pelo WhatsApp são expostas pelo evento `messageEdited`. A partir da 0.17.1, o provider inclui suporte ao envelope criptografado `secretEncryptedMessage` usado atualmente pelo WhatsApp para edições. Quando a versão anterior ainda estiver no cache recente, o payload inclui `previous`; `message` contém a versão atual.
179
+
180
+ ```ts
181
+ app.on('messageEdited', async ({ previous, message, editedByMe }) => {
182
+ if (!previous || editedByMe) return;
183
+
184
+ console.log(previous.text, message.text);
185
+ });
186
+ ```
187
+
188
+ Após cada edição, a nova versão substitui a anterior no cache recente. Assim, edições consecutivas da mesma mensagem sempre comparam a versão atual com a imediatamente anterior.
189
+
176
190
  ## Logging
177
191
 
178
192
  O nível padrão é `info`. Estão disponíveis `debug`, `info`, `warn`, `error` e `silent`.
package/dist/index.d.ts CHANGED
@@ -97,6 +97,14 @@ interface MessageDeleted {
97
97
  deletedById?: string;
98
98
  deletedAt: Date;
99
99
  }
100
+ interface MessageEdited {
101
+ key: MessageKey;
102
+ previous?: Message;
103
+ message: Message;
104
+ editedByMe: boolean;
105
+ editedById?: string;
106
+ editedAt: Date;
107
+ }
100
108
  interface Message {
101
109
  id: string;
102
110
  jid: string;
@@ -255,6 +263,7 @@ interface ConnectionUpdate {
255
263
  interface ProviderEvents {
256
264
  message: Message;
257
265
  messageDeleted: MessageDeleted;
266
+ messageEdited: MessageEdited;
258
267
  connection: ConnectionUpdate;
259
268
  groupChanged: {
260
269
  groupId: string;
@@ -755,6 +764,7 @@ declare class AccountService {
755
764
  interface AppEvents {
756
765
  message: Message;
757
766
  messageDeleted: MessageDeleted;
767
+ messageEdited: MessageEdited;
758
768
  connection: ConnectionUpdate;
759
769
  error: WhaNextError;
760
770
  mute: MuteEnforcement;
@@ -914,4 +924,4 @@ declare class SqliteMuteStore implements MuteStore {
914
924
  close(): void;
915
925
  }
916
926
 
917
- export { AccountService, type AddMuteOptions, type AddMuteResult, type AppEvents, type AppHealth, type AppHealthStatus, ArgsParser, type AudioContent, type BooleanOption, Browser, type ButtonsContent, type CacheOptions, type CacheStore, type CallEvent, type CallStatus, type ChangeResult, type CommandAccountContext, type CommandCatalogOptions, type CommandCatalogView, type CommandChatContext, type CommandConcurrency, type CommandContext, type CommandCooldown, type CommandDefinition, type CommandErrorHandler, type CommandGroupContext, type CommandGroupDefinition, type CommandGuard, type CommandHelpOptions, type CommandHooks, type CommandLocalization, type CommandMetadata, type CommandMiddleware, type CommandOptionDefinition, type CommandOptionSchema, type CommandOptionValue, type CommandOptionValues, type CommandRegistrar, CommandRouter, type CommandRuntimeServices, type CommandScope, type ConcurrencyStrategy, type ConnectionState, type ConnectionUpdate, type CopyCodeButton, type CreateMultiOptions, type CreateOptions, DeferredReply, type DownloadedMedia, type DurationOption, type EnumOption, type ExecutableCommandDefinition, type GroupAccess, type GroupAddressingMode, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, type GuardResult, type ImageContent, type InviteResult, type LinkButton, type LoadCommandsOptions, type LoadCommandsResult, type LoadedCommand, type LogContext, type LogEntry, type LogFormat, type LogLevel, type LogWriter, Logger, type LoggerConfig, type LoggerOptions, type LoginOptions, type MediaKind, type MediaSource, type MemberActionState, MemoryCache, type MemoryCacheStats, type MentionTarget, type Message, type MessageButton, type MessageContent, type MessageContentKind, type MessageDeleted, type MessageKey, type MessageMedia, type MultiAccountOptions, type MultiAppEvent, type MultiAppHealth, MultiCommandRouter, type MultiLoadCommandsResult, type MultiLoginOptions, type MuteChangeResult, type MuteEnforcement, type MuteOptions, type MuteRecord, MuteService, type MuteStore, type NumberOption, ParsedCommandOptions, type ParticipantUpdateResult, type PresenceState, type QuotedMessage, type ReconnectOptions, type RegisteredCommand, type RemoveMuteResult, type ReplyOptions, type RepostMessageOptions, type RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, WhaNextMultiApp, type WhatsAppProvider, create, createMulti, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
927
+ export { AccountService, type AddMuteOptions, type AddMuteResult, type AppEvents, type AppHealth, type AppHealthStatus, ArgsParser, type AudioContent, type BooleanOption, Browser, type ButtonsContent, type CacheOptions, type CacheStore, type CallEvent, type CallStatus, type ChangeResult, type CommandAccountContext, type CommandCatalogOptions, type CommandCatalogView, type CommandChatContext, type CommandConcurrency, type CommandContext, type CommandCooldown, type CommandDefinition, type CommandErrorHandler, type CommandGroupContext, type CommandGroupDefinition, type CommandGuard, type CommandHelpOptions, type CommandHooks, type CommandLocalization, type CommandMetadata, type CommandMiddleware, type CommandOptionDefinition, type CommandOptionSchema, type CommandOptionValue, type CommandOptionValues, type CommandRegistrar, CommandRouter, type CommandRuntimeServices, type CommandScope, type ConcurrencyStrategy, type ConnectionState, type ConnectionUpdate, type CopyCodeButton, type CreateMultiOptions, type CreateOptions, DeferredReply, type DownloadedMedia, type DurationOption, type EnumOption, type ExecutableCommandDefinition, type GroupAccess, type GroupAddressingMode, type GroupParticipant, type GroupParticipantAction, type GroupParticipantsChanged, type GroupRole, type GroupSnapshot, type GuardResult, type ImageContent, type InviteResult, type LinkButton, type LoadCommandsOptions, type LoadCommandsResult, type LoadedCommand, type LogContext, type LogEntry, type LogFormat, type LogLevel, type LogWriter, Logger, type LoggerConfig, type LoggerOptions, type LoginOptions, type MediaKind, type MediaSource, type MemberActionState, MemoryCache, type MemoryCacheStats, type MentionTarget, type Message, type MessageButton, type MessageContent, type MessageContentKind, type MessageDeleted, type MessageEdited, type MessageKey, type MessageMedia, type MultiAccountOptions, type MultiAppEvent, type MultiAppHealth, MultiCommandRouter, type MultiLoadCommandsResult, type MultiLoginOptions, type MuteChangeResult, type MuteEnforcement, type MuteOptions, type MuteRecord, MuteService, type MuteStore, type NumberOption, ParsedCommandOptions, type ParticipantUpdateResult, type PresenceState, type QuotedMessage, type ReconnectOptions, type RegisteredCommand, type RemoveMuteResult, type ReplyOptions, type RepostMessageOptions, type RouterOptions, type SentMessage, SqliteMuteStore, type StickerContent, type StoredMute, type StringOption, type TextContent, User, type UserData, type UserOption, type VideoContent, WhaNextApp, WhaNextError, type WhaNextErrorCode, WhaNextMultiApp, type WhatsAppProvider, create, createMulti, defineCommand, defineCommandGroup, defineCommands, defineSubcommand, guards, isCommandGroup, loadCommands, option, toWhaNextError };
package/dist/index.js CHANGED
@@ -2206,6 +2206,15 @@ var WhaNextApp = class {
2206
2206
  });
2207
2207
  await this.#events.emit("messageDeleted", deletion);
2208
2208
  });
2209
+ this.#provider.on("messageEdited", async (edit) => {
2210
+ this.logger.debug("Message edited", {
2211
+ chatId: edit.key.chatId,
2212
+ messageId: edit.key.id,
2213
+ editedByMe: edit.editedByMe,
2214
+ cached: edit.previous !== void 0
2215
+ });
2216
+ await this.#events.emit("messageEdited", edit);
2217
+ });
2209
2218
  this.#provider.on("message", async (message) => {
2210
2219
  try {
2211
2220
  const enforcement = await this.mute.enforce(message);
@@ -2296,7 +2305,7 @@ import {
2296
2305
  generateWAMessageFromContent,
2297
2306
  isJidGroup,
2298
2307
  makeWASocket,
2299
- proto,
2308
+ proto as proto2,
2300
2309
  useMultiFileAuthState
2301
2310
  } from "@whiskeysockets/baileys";
2302
2311
 
@@ -2578,6 +2587,179 @@ function toDate(value) {
2578
2587
  return new Date(seconds * 1e3);
2579
2588
  }
2580
2589
 
2590
+ // src/provider/baileys/secret-edit.ts
2591
+ import { createDecipheriv, hkdfSync } from "crypto";
2592
+ import {
2593
+ jidNormalizedUser,
2594
+ normalizeMessageContent as normalizeMessageContent2,
2595
+ proto
2596
+ } from "@whiskeysockets/baileys";
2597
+ function isSecretEncryptedEdit(message) {
2598
+ const content = normalizeMessageContent2(message.message);
2599
+ return content?.secretEncryptedMessage?.secretEncType === proto.Message.SecretEncryptedMessage.SecretEncType.MESSAGE_EDIT;
2600
+ }
2601
+ function secretEditTargetKey(message) {
2602
+ const content = normalizeMessageContent2(message.message);
2603
+ const secret = content?.secretEncryptedMessage;
2604
+ if (secret?.secretEncType !== proto.Message.SecretEncryptedMessage.SecretEncType.MESSAGE_EDIT || !secret.targetMessageKey?.id) {
2605
+ return void 0;
2606
+ }
2607
+ return secret.targetMessageKey;
2608
+ }
2609
+ function decryptSecretEncryptedEdit(envelope, original, meId, meLid) {
2610
+ const content = normalizeMessageContent2(envelope.message);
2611
+ const secret = content?.secretEncryptedMessage;
2612
+ const targetKey = secret?.targetMessageKey;
2613
+ if (secret?.secretEncType !== proto.Message.SecretEncryptedMessage.SecretEncType.MESSAGE_EDIT || !targetKey?.id || !secret.encPayload?.length || secret.encIv?.length !== 12) {
2614
+ return void 0;
2615
+ }
2616
+ const messageSecret = findMessageSecret(original.message);
2617
+ if (messageSecret?.length !== 32) {
2618
+ return void 0;
2619
+ }
2620
+ const editorCandidates = envelope.key.fromMe ? uniqueUserJids([meId, meLid]) : uniqueUserJids([
2621
+ envelope.key.participant,
2622
+ envelope.key.participantAlt,
2623
+ envelope.key.remoteJid,
2624
+ envelope.key.remoteJidAlt
2625
+ ]);
2626
+ const originalSenderCandidates = targetKey.fromMe ? editorCandidates : isUserJid(envelope.key.remoteJid) ? uniqueUserJids([
2627
+ targetKey.remoteJid,
2628
+ targetKey.remoteJidAlt,
2629
+ original.key.remoteJid,
2630
+ original.key.remoteJidAlt
2631
+ ]) : uniqueUserJids([
2632
+ targetKey.participant,
2633
+ targetKey.participantAlt,
2634
+ original.key.participant,
2635
+ original.key.participantAlt
2636
+ ]);
2637
+ const fallbackOriginalCandidates = original.key.fromMe ? uniqueUserJids([meId, meLid]) : uniqueUserJids([
2638
+ original.key.participant,
2639
+ original.key.participantAlt,
2640
+ original.key.remoteJid,
2641
+ original.key.remoteJidAlt
2642
+ ]);
2643
+ const senders = uniqueUserJids([
2644
+ ...originalSenderCandidates,
2645
+ ...fallbackOriginalCandidates
2646
+ ]);
2647
+ if (!editorCandidates.length || !senders.length) {
2648
+ return void 0;
2649
+ }
2650
+ let decoded;
2651
+ for (const originalSender of senders) {
2652
+ for (const editor of editorCandidates) {
2653
+ try {
2654
+ decoded = decryptPayload(
2655
+ targetKey.id,
2656
+ originalSender,
2657
+ editor,
2658
+ messageSecret,
2659
+ secret.encIv,
2660
+ secret.encPayload
2661
+ );
2662
+ break;
2663
+ } catch {
2664
+ continue;
2665
+ }
2666
+ }
2667
+ if (decoded) {
2668
+ break;
2669
+ }
2670
+ }
2671
+ const protocol = decoded?.protocolMessage;
2672
+ if (protocol?.type !== proto.Message.ProtocolMessage.Type.MESSAGE_EDIT || !protocol.editedMessage || protocol.key?.id && protocol.key.id !== targetKey.id) {
2673
+ return void 0;
2674
+ }
2675
+ const edited = protocol.editedMessage;
2676
+ if (!edited.messageContextInfo?.messageSecret?.length) {
2677
+ edited.messageContextInfo = {
2678
+ ...edited.messageContextInfo,
2679
+ messageSecret
2680
+ };
2681
+ }
2682
+ return {
2683
+ message: edited,
2684
+ ...protocol.timestampMs ? { timestamp: Math.floor(numberValue(protocol.timestampMs) / 1e3) } : {}
2685
+ };
2686
+ }
2687
+ function decryptPayload(messageId, originalSender, editor, messageSecret, iv, payload) {
2688
+ const info = Buffer.concat([
2689
+ Buffer.from(messageId, "utf8"),
2690
+ Buffer.from(originalSender, "utf8"),
2691
+ Buffer.from(editor, "utf8"),
2692
+ Buffer.from("Message Edit", "utf8")
2693
+ ]);
2694
+ const key = Buffer.from(hkdfSync(
2695
+ "sha256",
2696
+ Buffer.from(messageSecret),
2697
+ Buffer.alloc(32),
2698
+ info,
2699
+ 32
2700
+ ));
2701
+ const encrypted = Buffer.from(payload);
2702
+ if (encrypted.length <= 16) {
2703
+ throw new Error("INVALID_EDIT_PAYLOAD");
2704
+ }
2705
+ const decipher = createDecipheriv("aes-256-gcm", key, Buffer.from(iv));
2706
+ decipher.setAAD(Buffer.alloc(0));
2707
+ decipher.setAuthTag(encrypted.subarray(encrypted.length - 16));
2708
+ return proto.Message.decode(Buffer.concat([
2709
+ decipher.update(encrypted.subarray(0, encrypted.length - 16)),
2710
+ decipher.final()
2711
+ ]));
2712
+ }
2713
+ function findMessageSecret(message) {
2714
+ if (!message) {
2715
+ return void 0;
2716
+ }
2717
+ const direct = message.messageContextInfo?.messageSecret;
2718
+ if (direct?.length) {
2719
+ return direct;
2720
+ }
2721
+ const normalized = normalizeMessageContent2(message);
2722
+ const normalizedSecret = normalized?.messageContextInfo?.messageSecret;
2723
+ if (normalizedSecret?.length) {
2724
+ return normalizedSecret;
2725
+ }
2726
+ const deviceSecret = message.deviceSentMessage?.message?.messageContextInfo?.messageSecret;
2727
+ if (deviceSecret?.length) {
2728
+ return deviceSecret;
2729
+ }
2730
+ return void 0;
2731
+ }
2732
+ function uniqueUserJids(values) {
2733
+ return [...new Set(
2734
+ values.map(normalizeUserJid).filter((value) => value !== void 0)
2735
+ )];
2736
+ }
2737
+ function normalizeUserJid(value) {
2738
+ if (!isUserJid(value)) {
2739
+ return void 0;
2740
+ }
2741
+ return jidNormalizedUser(value);
2742
+ }
2743
+ function isUserJid(value) {
2744
+ if (!value) {
2745
+ return false;
2746
+ }
2747
+ const normalized = jidNormalizedUser(value);
2748
+ return normalized.endsWith("@s.whatsapp.net") || normalized.endsWith("@lid") || normalized.endsWith("@hosted") || normalized.endsWith("@hosted.lid");
2749
+ }
2750
+ function numberValue(value) {
2751
+ if (typeof value === "number") {
2752
+ return value;
2753
+ }
2754
+ if (typeof value === "bigint") {
2755
+ return Number(value);
2756
+ }
2757
+ if (value && typeof value === "object" && "toString" in value) {
2758
+ return Number(String(value));
2759
+ }
2760
+ return Number(value);
2761
+ }
2762
+
2581
2763
  // src/provider/baileys/baileys-provider.ts
2582
2764
  var BaileysProvider = class {
2583
2765
  #options;
@@ -2818,7 +3000,7 @@ var BaileysProvider = class {
2818
3000
  async setMessagePin(groupId, key, pinned) {
2819
3001
  await this.#requireSocket().sendMessage(groupId, {
2820
3002
  pin: this.#toWaKey(key),
2821
- type: pinned ? proto.PinInChat.Type.PIN_FOR_ALL : proto.PinInChat.Type.UNPIN_FOR_ALL,
3003
+ type: pinned ? proto2.PinInChat.Type.PIN_FOR_ALL : proto2.PinInChat.Type.UNPIN_FOR_ALL,
2822
3004
  ...pinned ? { time: 604800 } : {}
2823
3005
  });
2824
3006
  }
@@ -2850,6 +3032,7 @@ var BaileysProvider = class {
2850
3032
  socket.ev.on("messages.upsert", ({ messages, type }) => {
2851
3033
  if (type !== "notify") return;
2852
3034
  for (const raw of messages) {
3035
+ if (this.#handleSecretEncryptedEdit(raw)) continue;
2853
3036
  if (raw.key.id && raw.message) this.#remember(raw);
2854
3037
  const quoted = extractQuotedBaileysMessage(raw);
2855
3038
  if (quoted?.key.id && quoted.message) this.#remember(quoted);
@@ -2859,19 +3042,33 @@ var BaileysProvider = class {
2859
3042
  });
2860
3043
  socket.ev.on("messages.update", (updates) => {
2861
3044
  for (const { key, update } of updates) {
2862
- if (update.message !== null || !key.id || !key.remoteJid) continue;
3045
+ if (!key.id || !key.remoteJid) continue;
2863
3046
  const stored = this.#messageStore.get(this.#messageStoreKey(key));
2864
- const message = stored ? normalizeBaileysMessage(stored) : void 0;
2865
- const deletionKey = update.key;
2866
- const deletedByMe = deletionKey?.fromMe === true;
2867
- const deletedById = deletionKey?.participant ?? deletionKey?.participantAlt ?? (deletedByMe ? this.#socket?.user?.id : deletionKey?.remoteJid ?? void 0);
2868
- void this.#events.emit("messageDeleted", {
2869
- key: message?.keys ?? normalizeKey(key),
2870
- ...message ? { message } : {},
2871
- deletedByMe,
2872
- ...deletedById ? { deletedById } : {},
2873
- deletedAt: /* @__PURE__ */ new Date()
2874
- });
3047
+ if (update.message === null) {
3048
+ const message = stored ? normalizeBaileysMessage(stored) : void 0;
3049
+ const deletionKey = update.key;
3050
+ const deletedByMe = deletionKey?.fromMe === true;
3051
+ const deletedById = deletionKey?.participant ?? deletionKey?.participantAlt ?? (deletedByMe ? this.#socket?.user?.id : deletionKey?.remoteJid ?? void 0);
3052
+ void this.#events.emit("messageDeleted", {
3053
+ key: message?.keys ?? normalizeKey(key),
3054
+ ...message ? { message } : {},
3055
+ deletedByMe,
3056
+ ...deletedById ? { deletedById } : {},
3057
+ deletedAt: /* @__PURE__ */ new Date()
3058
+ });
3059
+ continue;
3060
+ }
3061
+ if (!update.message?.editedMessage?.message) continue;
3062
+ const editedRaw = {
3063
+ ...stored ?? {},
3064
+ key: {
3065
+ ...stored?.key ?? {},
3066
+ ...key
3067
+ },
3068
+ message: update.message,
3069
+ messageTimestamp: update.messageTimestamp ?? stored?.messageTimestamp ?? Math.floor(Date.now() / 1e3)
3070
+ };
3071
+ this.#emitMessageEdited(key, editedRaw, stored);
2875
3072
  }
2876
3073
  });
2877
3074
  socket.ev.on("groups.update", (groups) => {
@@ -2971,7 +3168,7 @@ var BaileysProvider = class {
2971
3168
  "WhatsApp did not expose the current account identity for the interactive message."
2972
3169
  );
2973
3170
  }
2974
- const interactiveMessage = proto.Message.InteractiveMessage.create({
3171
+ const interactiveMessage = proto2.Message.InteractiveMessage.create({
2975
3172
  ...content.title !== void 0 ? {
2976
3173
  header: {
2977
3174
  title: content.title,
@@ -3163,6 +3360,68 @@ var BaileysProvider = class {
3163
3360
  ];
3164
3361
  return known.find((value) => value === status) ?? "timeout";
3165
3362
  }
3363
+ #handleSecretEncryptedEdit(raw) {
3364
+ if (!isSecretEncryptedEdit(raw)) return false;
3365
+ const targetKey = secretEditTargetKey(raw);
3366
+ if (!targetKey?.id) return true;
3367
+ const stored = this.#findStoredMessage(targetKey);
3368
+ if (!stored) return true;
3369
+ try {
3370
+ const decrypted = decryptSecretEncryptedEdit(
3371
+ raw,
3372
+ stored,
3373
+ this.#socket?.user?.id,
3374
+ this.#socket?.user?.lid
3375
+ );
3376
+ if (!decrypted) return true;
3377
+ const key = {
3378
+ ...stored.key,
3379
+ id: targetKey.id
3380
+ };
3381
+ const editedRaw = {
3382
+ ...stored,
3383
+ key,
3384
+ message: {
3385
+ editedMessage: {
3386
+ message: decrypted.message
3387
+ }
3388
+ },
3389
+ messageTimestamp: decrypted.timestamp ?? raw.messageTimestamp ?? stored.messageTimestamp ?? Math.floor(Date.now() / 1e3)
3390
+ };
3391
+ this.#emitMessageEdited(key, editedRaw, stored);
3392
+ } catch (error) {
3393
+ this.#logger.warn("Could not decrypt the encrypted message edit.", {
3394
+ messageId: targetKey.id,
3395
+ error: error instanceof Error ? error.message : String(error)
3396
+ });
3397
+ }
3398
+ return true;
3399
+ }
3400
+ #emitMessageEdited(key, editedRaw, stored) {
3401
+ const previous = stored ? normalizeBaileysMessage(stored) : void 0;
3402
+ const message = normalizeBaileysMessage(editedRaw);
3403
+ if (!message) return;
3404
+ this.#remember(editedRaw);
3405
+ const editedByMe = key.fromMe === true;
3406
+ const editedById = key.participant ?? key.participantAlt ?? (editedByMe ? this.#socket?.user?.id : key.remoteJid ?? void 0);
3407
+ void this.#events.emit("messageEdited", {
3408
+ key: message.keys,
3409
+ ...previous ? { previous } : {},
3410
+ message,
3411
+ editedByMe,
3412
+ ...editedById ? { editedById } : {},
3413
+ editedAt: message.timestamp
3414
+ });
3415
+ }
3416
+ #findStoredMessage(key) {
3417
+ const direct = this.#messageStore.get(this.#messageStoreKey(key));
3418
+ if (direct) return direct;
3419
+ if (!key.id) return void 0;
3420
+ for (const message of this.#messageStore.values()) {
3421
+ if (message.key.id === key.id) return message;
3422
+ }
3423
+ return void 0;
3424
+ }
3166
3425
  #remember(message) {
3167
3426
  const key = this.#messageStoreKey(message.key);
3168
3427
  this.#messageStore.delete(key);