@whanext/core 0.19.1 → 0.19.3
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 +20 -0
- package/dist/index.js +121 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.19.3
|
|
4
|
+
### Corrigido
|
|
5
|
+
- Carregamento lazy do plugin VoIP do Zapo para evitar importar o runtime WebRTC em consumidores e testes que não inicializam o provider.
|
|
6
|
+
- Ajustes de tipagem dos testes com `exactOptionalPropertyTypes`.
|
|
7
|
+
- Provider Zapo agora usa `@zapo-js/voip` como único caminho de chamadas: eventos `voip_*` e `client.voip.rejectCall()`, sem fallback silencioso.
|
|
8
|
+
- `messageEdited` também reconhece edições criptografadas descriptografadas pelo Zapo em `message_addon`, além de `message_protocol`.
|
|
9
|
+
- `messageDeleted` e `messageEdited` ignoram protocolo de backlog durante bootstrap quando `processOfflineMessages` está desativado.
|
|
10
|
+
- Mensagens recebidas antes de `connection: open` deixam de ser publicadas como mensagens ao vivo; ainda entram no cache limitado para permitir recuperação posterior.
|
|
11
|
+
- Eventos `message` duplicados no mesmo runtime são descartados antes de chegar aos consumidores, evitando downloads repetidos de mídia/ViewOnce.
|
|
12
|
+
|
|
13
|
+
### Compatibilidade
|
|
14
|
+
- Mudança corretiva e aditiva; a API pública de `CallEvent`, `messageDeleted` e `messageEdited` permanece inalterada.
|
|
15
|
+
|
|
16
|
+
## 0.19.2
|
|
17
|
+
|
|
18
|
+
- Corrigido o download real de mídias citadas no provider Zapo: `downloadMedia()` agora entrega o `Proto.IMessage` bruto diretamente ao `downloadBytes()`, como suportado pela API do Zapo.
|
|
19
|
+
- Envelopes `viewOnceMessage`, `viewOnceMessageV2` e `viewOnceMessageV2Extension` são desembrulhados antes do download, evitando falhas ao responder imagens/vídeos de visualização única.
|
|
20
|
+
- A correção cobre replies comuns de imagem, vídeo, áudio e sticker, além de view-once.
|
|
21
|
+
|
|
22
|
+
|
|
3
23
|
## 0.19.1
|
|
4
24
|
|
|
5
25
|
- Corrige menus de lista no provider Zapo usando `interactiveMessage` Native Flow com `single_select` em vez do `listMessage` legado.
|
package/dist/index.js
CHANGED
|
@@ -2708,9 +2708,10 @@ var ZapoProvider = class {
|
|
|
2708
2708
|
#logger;
|
|
2709
2709
|
#messageStore = /* @__PURE__ */ new Map();
|
|
2710
2710
|
#messageKeyStore = /* @__PURE__ */ new WeakMap();
|
|
2711
|
+
#deliveredMessageStore = /* @__PURE__ */ new Set();
|
|
2712
|
+
#handledProtocolStore = /* @__PURE__ */ new Set();
|
|
2711
2713
|
#messageCacheSize;
|
|
2712
2714
|
#client;
|
|
2713
|
-
#voip;
|
|
2714
2715
|
#intentionalClose = false;
|
|
2715
2716
|
#reconnectAttempt = 0;
|
|
2716
2717
|
#reconnectTimer;
|
|
@@ -2859,9 +2860,8 @@ var ZapoProvider = class {
|
|
|
2859
2860
|
);
|
|
2860
2861
|
}
|
|
2861
2862
|
try {
|
|
2862
|
-
const
|
|
2863
|
-
|
|
2864
|
-
);
|
|
2863
|
+
const mediaMessage = unwrapZapoMessageContent(message.message) ?? message.message;
|
|
2864
|
+
const bytes = await this.#requireClient().message.downloadBytes(mediaMessage);
|
|
2865
2865
|
return {
|
|
2866
2866
|
data: Buffer.from(bytes),
|
|
2867
2867
|
kind: normalized.media.kind,
|
|
@@ -2966,15 +2966,8 @@ var ZapoProvider = class {
|
|
|
2966
2966
|
await presence.sendChatstate(chatId, { state: value });
|
|
2967
2967
|
}
|
|
2968
2968
|
async rejectCall(callId, _from) {
|
|
2969
|
-
this.#requireClient();
|
|
2970
|
-
|
|
2971
|
-
throw new WhaNextError(
|
|
2972
|
-
"PROVIDER_ERROR",
|
|
2973
|
-
"WhatsApp call support is unavailable because the Zapo VoIP plugin could not be loaded.",
|
|
2974
|
-
{ recoverable: true }
|
|
2975
|
-
);
|
|
2976
|
-
}
|
|
2977
|
-
await this.#voip.rejectCall(callId);
|
|
2969
|
+
const client = this.#requireClient();
|
|
2970
|
+
await client.voip.rejectCall(callId);
|
|
2978
2971
|
}
|
|
2979
2972
|
async #ensureClient() {
|
|
2980
2973
|
if (this.#client) return this.#client;
|
|
@@ -3003,15 +2996,8 @@ var ZapoProvider = class {
|
|
|
3003
2996
|
messageSecret: "sqlite"
|
|
3004
2997
|
}
|
|
3005
2998
|
});
|
|
3006
|
-
const
|
|
3007
|
-
|
|
3008
|
-
const { voipPlugin } = await import("@zapo-js/voip");
|
|
3009
|
-
plugins.push(voipPlugin({ logLevel: "warn" }));
|
|
3010
|
-
} catch (error) {
|
|
3011
|
-
this.#logger.warn("Zapo VoIP support is unavailable; call events and rejection are disabled.", {
|
|
3012
|
-
error: error instanceof Error ? error.message : String(error)
|
|
3013
|
-
});
|
|
3014
|
-
}
|
|
2999
|
+
const { voipPlugin } = await import("@zapo-js/voip");
|
|
3000
|
+
const voip = voipPlugin({ logLevel: "warn" });
|
|
3015
3001
|
const client = new WaClient({
|
|
3016
3002
|
store,
|
|
3017
3003
|
sessionId: this.#options.sessionId ?? "default",
|
|
@@ -3024,10 +3010,9 @@ var ZapoProvider = class {
|
|
|
3024
3010
|
persistAllSecrets: true
|
|
3025
3011
|
},
|
|
3026
3012
|
media: { processor: createMediaProcessor() },
|
|
3027
|
-
plugins
|
|
3013
|
+
plugins: [voip]
|
|
3028
3014
|
}, new WhaNextZapoLogger(this.#logger));
|
|
3029
3015
|
this.#client = client;
|
|
3030
|
-
this.#voip = client.voip;
|
|
3031
3016
|
this.#bind(client);
|
|
3032
3017
|
return client;
|
|
3033
3018
|
}
|
|
@@ -3059,49 +3044,60 @@ var ZapoProvider = class {
|
|
|
3059
3044
|
client.on("message_protocol", (event) => {
|
|
3060
3045
|
this.#handleProtocolEvent(event);
|
|
3061
3046
|
});
|
|
3047
|
+
client.on("message_addon", (event) => {
|
|
3048
|
+
this.#handleAddonEvent(event);
|
|
3049
|
+
});
|
|
3062
3050
|
client.on("group", (event) => {
|
|
3063
3051
|
this.#handleGroupEvent(event);
|
|
3064
3052
|
});
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
}
|
|
3053
|
+
const voipClient = client;
|
|
3054
|
+
voipClient.on("voip_call_incoming", (event) => {
|
|
3055
|
+
const call = this.#normalizeVoipCall(event, "offer");
|
|
3056
|
+
if (call) void this.#events.emit("call", call);
|
|
3057
|
+
});
|
|
3058
|
+
voipClient.on("voip_call_state", (event) => {
|
|
3059
|
+
const state = event.stateData?.state;
|
|
3060
|
+
if (state === "incoming_ringing" || state === "ended") return;
|
|
3061
|
+
const call = this.#normalizeVoipCall(event);
|
|
3062
|
+
if (call) void this.#events.emit("call", call);
|
|
3063
|
+
});
|
|
3064
|
+
voipClient.on("voip_call_ended", (event) => {
|
|
3065
|
+
const call = this.#normalizeVoipCall(
|
|
3066
|
+
event,
|
|
3067
|
+
this.#callEndStatus(event.stateData?.endReason)
|
|
3068
|
+
);
|
|
3069
|
+
if (call) void this.#events.emit("call", call);
|
|
3070
|
+
});
|
|
3084
3071
|
client.on("connection", (event) => {
|
|
3085
3072
|
void this.#handleConnectionEvent(client, event);
|
|
3086
3073
|
});
|
|
3087
3074
|
}
|
|
3088
3075
|
#handleMessage(event) {
|
|
3089
3076
|
const stored = event;
|
|
3077
|
+
if (stored.key?.id && stored.message) this.#remember(stored);
|
|
3078
|
+
const quoted = extractQuotedZapoMessage(event);
|
|
3079
|
+
if (quoted?.key.id && quoted.message) {
|
|
3080
|
+
this.#remember(quoted);
|
|
3081
|
+
}
|
|
3090
3082
|
if (this.#isOfflineMessage(stored)) {
|
|
3091
|
-
this.#logger.debug("Ignored message queued before the current connection.", {
|
|
3083
|
+
this.#logger.debug("Ignored message queued before the current live connection.", {
|
|
3092
3084
|
messageId: stored.key.id ?? void 0,
|
|
3093
3085
|
chatId: stored.key.remoteJid ?? void 0,
|
|
3094
3086
|
timestampSeconds: stored.timestampSeconds ?? void 0
|
|
3095
3087
|
});
|
|
3096
3088
|
return;
|
|
3097
3089
|
}
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3090
|
+
const deliveryKey = this.#messageDeliveryKey(stored.key);
|
|
3091
|
+
if (stored.key.id && this.#deliveredMessageStore.has(deliveryKey)) {
|
|
3092
|
+
this.#logger.debug("Ignored duplicate Zapo message event.", {
|
|
3093
|
+
messageId: stored.key.id,
|
|
3094
|
+
chatId: stored.key.remoteJid ?? void 0
|
|
3095
|
+
});
|
|
3096
|
+
return;
|
|
3102
3097
|
}
|
|
3103
3098
|
const message = normalizeZapoMessage(event);
|
|
3104
3099
|
if (!message) return;
|
|
3100
|
+
if (stored.key.id) this.#rememberDeliveredMessage(deliveryKey);
|
|
3105
3101
|
this.#messageKeyStore.set(message.keys, stored);
|
|
3106
3102
|
if (message.quoted && quoted?.message) {
|
|
3107
3103
|
this.#messageKeyStore.set(
|
|
@@ -3111,7 +3107,50 @@ var ZapoProvider = class {
|
|
|
3111
3107
|
}
|
|
3112
3108
|
void this.#events.emit("message", message);
|
|
3113
3109
|
}
|
|
3110
|
+
#handleAddonEvent(event) {
|
|
3111
|
+
if (event.kind !== "message_edit" || !event.targetMessageId) return;
|
|
3112
|
+
const editedMessage = this.#addonEditedMessage(event.decrypted);
|
|
3113
|
+
if (!editedMessage) return;
|
|
3114
|
+
const target = {
|
|
3115
|
+
id: event.targetMessageId,
|
|
3116
|
+
...event.key.remoteJid !== void 0 ? { remoteJid: event.key.remoteJid } : {},
|
|
3117
|
+
...event.key.fromMe !== void 0 ? { fromMe: event.key.fromMe } : {},
|
|
3118
|
+
...event.key.participant !== void 0 ? { participant: event.key.participant } : {},
|
|
3119
|
+
...event.key.participantAlt !== void 0 ? { participantAlt: event.key.participantAlt } : {}
|
|
3120
|
+
};
|
|
3121
|
+
this.#handleProtocolEvent({
|
|
3122
|
+
key: event.key,
|
|
3123
|
+
...event.offline !== void 0 ? { offline: event.offline } : {},
|
|
3124
|
+
protocolMessage: {
|
|
3125
|
+
type: proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
|
|
3126
|
+
key: target,
|
|
3127
|
+
editedMessage
|
|
3128
|
+
}
|
|
3129
|
+
});
|
|
3130
|
+
}
|
|
3131
|
+
#addonEditedMessage(value) {
|
|
3132
|
+
if (!value || typeof value !== "object") return void 0;
|
|
3133
|
+
const record = value;
|
|
3134
|
+
const protocol = record.protocolMessage;
|
|
3135
|
+
if (protocol && typeof protocol === "object") {
|
|
3136
|
+
const edited2 = protocol.editedMessage;
|
|
3137
|
+
if (edited2 && typeof edited2 === "object") return edited2;
|
|
3138
|
+
}
|
|
3139
|
+
const edited = record.editedMessage;
|
|
3140
|
+
if (edited && typeof edited === "object") return edited;
|
|
3141
|
+
const message = record.message;
|
|
3142
|
+
if (message && typeof message === "object") return message;
|
|
3143
|
+
return value;
|
|
3144
|
+
}
|
|
3114
3145
|
#handleProtocolEvent(event) {
|
|
3146
|
+
if (this.#isOfflineMessage(event)) {
|
|
3147
|
+
this.#logger.debug("Ignored protocol event queued before the current live connection.", {
|
|
3148
|
+
messageId: event.key.id ?? void 0,
|
|
3149
|
+
chatId: event.key.remoteJid ?? void 0,
|
|
3150
|
+
timestampSeconds: event.timestampSeconds ?? void 0
|
|
3151
|
+
});
|
|
3152
|
+
return;
|
|
3153
|
+
}
|
|
3115
3154
|
const protocol = event.protocolMessage ?? event.message?.protocolMessage;
|
|
3116
3155
|
if (!protocol) return;
|
|
3117
3156
|
const protocolKey = protocol.key;
|
|
@@ -3128,7 +3167,16 @@ var ZapoProvider = class {
|
|
|
3128
3167
|
if (!target.remoteJid) return;
|
|
3129
3168
|
const stored = this.#findStoredMessage(target);
|
|
3130
3169
|
const type = protocol?.type;
|
|
3170
|
+
const mutationKey = this.#protocolDeliveryKey(event, target, type);
|
|
3171
|
+
if (mutationKey && this.#handledProtocolStore.has(mutationKey)) {
|
|
3172
|
+
this.#logger.debug("Ignored duplicate Zapo protocol event.", {
|
|
3173
|
+
messageId: event.key.id ?? void 0,
|
|
3174
|
+
targetMessageId: target.id ?? void 0
|
|
3175
|
+
});
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3131
3178
|
if (type === proto.Message.ProtocolMessage.Type.REVOKE) {
|
|
3179
|
+
if (mutationKey) this.#rememberHandledProtocol(mutationKey);
|
|
3132
3180
|
const previous2 = stored ? normalizeZapoMessage(stored) : void 0;
|
|
3133
3181
|
const deletedByMe = event.key.fromMe === true;
|
|
3134
3182
|
const deletedById = event.key.participant ?? event.key.participantAlt ?? (deletedByMe ? this.getCurrentUserIds()[0] : event.key.remoteJid ?? void 0);
|
|
@@ -3158,6 +3206,7 @@ var ZapoProvider = class {
|
|
|
3158
3206
|
const message = normalizeZapoMessage(edited);
|
|
3159
3207
|
if (!message) return;
|
|
3160
3208
|
const previous = stored ? normalizeZapoMessage(stored) : void 0;
|
|
3209
|
+
if (mutationKey) this.#rememberHandledProtocol(mutationKey);
|
|
3161
3210
|
this.#remember(edited);
|
|
3162
3211
|
const editedByMe = event.key.fromMe === true;
|
|
3163
3212
|
const editedById = event.key.participant ?? event.key.participantAlt ?? (editedByMe ? this.getCurrentUserIds()[0] : event.key.remoteJid ?? void 0);
|
|
@@ -3608,9 +3657,33 @@ var ZapoProvider = class {
|
|
|
3608
3657
|
#messageStoreKey(key) {
|
|
3609
3658
|
return `${key.remoteJid ?? ""}:${key.id ?? ""}:${key.participant ?? key.participantAlt ?? ""}`;
|
|
3610
3659
|
}
|
|
3660
|
+
#messageDeliveryKey(key) {
|
|
3661
|
+
return `${key.remoteJid ?? ""}:${key.id ?? ""}`;
|
|
3662
|
+
}
|
|
3663
|
+
#protocolDeliveryKey(event, target, type) {
|
|
3664
|
+
if (type == null || !event.key.id || !target.id) return void 0;
|
|
3665
|
+
return `${type}:${event.key.remoteJid ?? target.remoteJid ?? ""}:${event.key.id}:${target.id}`;
|
|
3666
|
+
}
|
|
3667
|
+
#rememberHandledProtocol(key) {
|
|
3668
|
+
this.#handledProtocolStore.delete(key);
|
|
3669
|
+
this.#handledProtocolStore.add(key);
|
|
3670
|
+
while (this.#handledProtocolStore.size > this.#messageCacheSize) {
|
|
3671
|
+
const oldest = this.#handledProtocolStore.values().next().value;
|
|
3672
|
+
if (oldest) this.#handledProtocolStore.delete(oldest);
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
#rememberDeliveredMessage(key) {
|
|
3676
|
+
this.#deliveredMessageStore.delete(key);
|
|
3677
|
+
this.#deliveredMessageStore.add(key);
|
|
3678
|
+
while (this.#deliveredMessageStore.size > this.#messageCacheSize) {
|
|
3679
|
+
const oldest = this.#deliveredMessageStore.values().next().value;
|
|
3680
|
+
if (oldest) this.#deliveredMessageStore.delete(oldest);
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3611
3683
|
#isOfflineMessage(message) {
|
|
3612
3684
|
if (this.#options.processOfflineMessages === true) return false;
|
|
3613
3685
|
if (message.offline === true) return true;
|
|
3686
|
+
if (!this.#connected) return true;
|
|
3614
3687
|
if (!this.#connectedAtSeconds || message.timestampSeconds == null) return false;
|
|
3615
3688
|
const timestamp = toSeconds(message.timestampSeconds);
|
|
3616
3689
|
if (timestamp === void 0) return false;
|