@whanext/core 0.19.7 → 0.19.9
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 +18 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +44 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.19.9
|
|
4
|
+
|
|
5
|
+
- Fixed live `message_addon` edits being discarded when Zapo reports the parent message timestamp instead of the mutation timestamp.
|
|
6
|
+
- Serialized decrypted edit addons through the same protocol-mutation queue used by `message_protocol`, preserving edit/revoke ordering.
|
|
7
|
+
- Offline-resume edit addons remain ignored by default unless `processOfflineMessages` is enabled.
|
|
8
|
+
|
|
9
|
+
## 0.19.8
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- The Zapo mailbox (`messages`, `threads`, and `contacts`) is now persisted in the shared SQLite store and full history sync is enabled. This lets Zapo retain parent message secrets required to decrypt `secretEncryptedMessage` edit addons after restart/offline resume.
|
|
13
|
+
- History sync now hydrates the trusted-contact/privacy-token state used by Zapo when preparing outgoing messages, including history-derived token metadata and NCT salt that can be required for `tctoken`/`cstoken` generation. Historical/bootstrap messages are still filtered by WhaNext and do not become live command events unless `processOfflineMessages` is explicitly enabled.
|
|
14
|
+
- WhatsApp negative publish ACK `463` is normalized as `MESSAGE_REACHOUT_LOCKED` with `ackCode: 463` instead of surfacing as `UNKNOWN_ERROR`, allowing consumers to avoid retry/error-reply loops while the account is reach-out time-locked.
|
|
15
|
+
|
|
16
|
+
### Compatibility
|
|
17
|
+
- Public message/edit/delete event shapes are unchanged.
|
|
18
|
+
- Existing shared multi-account stores are reused in place; the mailbox domains are created inside the same `state.sqlite` and remain isolated by `sessionId`.
|
|
19
|
+
- The first connection after this update may perform a larger history sync because mailbox persistence is now enabled deliberately.
|
|
20
|
+
|
|
3
21
|
## 0.19.7
|
|
4
22
|
|
|
5
23
|
### Fixed
|
package/dist/index.d.ts
CHANGED
|
@@ -610,7 +610,7 @@ declare class DeferredReply {
|
|
|
610
610
|
delete(): Promise<void>;
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
-
type WhaNextErrorCode = 'AUTH_INVALID_PHONE' | 'AUTH_EXPIRED' | 'AUTH_PASSKEY_REQUIRED' | 'CONNECTION_CLOSED' | 'CONNECTION_FAILED' | 'GROUP_NOT_FOUND' | 'MEMBER_NOT_FOUND' | 'BOT_NOT_ADMIN' | 'MESSAGE_NOT_FOUND' | 'MEDIA_NOT_AVAILABLE' | 'MUTE_DISABLED' | 'STORAGE_ERROR' | 'ARGUMENT_MISSING' | 'ARGUMENT_INVALID' | 'COMMAND_NOT_ALLOWED' | 'COMMAND_COOLDOWN' | 'COMMAND_BUSY' | 'COMMAND_LOAD_FAILED' | 'PROVIDER_ERROR' | 'UNKNOWN_ERROR';
|
|
613
|
+
type WhaNextErrorCode = 'AUTH_INVALID_PHONE' | 'AUTH_EXPIRED' | 'AUTH_PASSKEY_REQUIRED' | 'CONNECTION_CLOSED' | 'CONNECTION_FAILED' | 'GROUP_NOT_FOUND' | 'MEMBER_NOT_FOUND' | 'BOT_NOT_ADMIN' | 'MESSAGE_NOT_FOUND' | 'MEDIA_NOT_AVAILABLE' | 'MESSAGE_REACHOUT_LOCKED' | 'MUTE_DISABLED' | 'STORAGE_ERROR' | 'ARGUMENT_MISSING' | 'ARGUMENT_INVALID' | 'COMMAND_NOT_ALLOWED' | 'COMMAND_COOLDOWN' | 'COMMAND_BUSY' | 'COMMAND_LOAD_FAILED' | 'PROVIDER_ERROR' | 'UNKNOWN_ERROR';
|
|
614
614
|
interface WhaNextErrorOptions {
|
|
615
615
|
cause?: unknown;
|
|
616
616
|
context?: Readonly<Record<string, unknown>>;
|
package/dist/index.js
CHANGED
|
@@ -90,11 +90,40 @@ function toWhaNextError(error, context) {
|
|
|
90
90
|
return error;
|
|
91
91
|
}
|
|
92
92
|
const message = error instanceof Error ? error.message : "An unknown error occurred.";
|
|
93
|
+
if (isReachoutTimelockError(error)) {
|
|
94
|
+
return new WhaNextError(
|
|
95
|
+
"MESSAGE_REACHOUT_LOCKED",
|
|
96
|
+
"WhatsApp rejected the outgoing message (ack 463: reach-out time-lock).",
|
|
97
|
+
{
|
|
98
|
+
cause: error,
|
|
99
|
+
context: {
|
|
100
|
+
...context ?? {},
|
|
101
|
+
ackCode: 463
|
|
102
|
+
},
|
|
103
|
+
recoverable: false
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
93
107
|
return new WhaNextError("UNKNOWN_ERROR", message, {
|
|
94
108
|
cause: error,
|
|
95
109
|
...context ? { context } : {}
|
|
96
110
|
});
|
|
97
111
|
}
|
|
112
|
+
function isReachoutTimelockError(error) {
|
|
113
|
+
const seen = /* @__PURE__ */ new Set();
|
|
114
|
+
let current = error;
|
|
115
|
+
for (let depth = 0; depth < 8 && current !== void 0 && current !== null; depth += 1) {
|
|
116
|
+
if (seen.has(current)) return false;
|
|
117
|
+
seen.add(current);
|
|
118
|
+
const message = current instanceof Error ? current.message : typeof current === "string" ? current : void 0;
|
|
119
|
+
if (message && /negative publish ack:.*\berror=463\b/i.test(message)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (typeof current !== "object") return false;
|
|
123
|
+
current = Reflect.get(current, "cause");
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
98
127
|
|
|
99
128
|
// src/models/identity.ts
|
|
100
129
|
function normalizeIdentity(identity) {
|
|
@@ -3044,7 +3073,7 @@ var ZapoProvider = class {
|
|
|
3044
3073
|
markOnlineOnConnect: false,
|
|
3045
3074
|
deviceBrowser: this.#deviceBrowser(),
|
|
3046
3075
|
deviceOsDisplayName: this.#deviceOsDisplayName(),
|
|
3047
|
-
history: { enabled:
|
|
3076
|
+
history: { enabled: true, requireFullSync: true },
|
|
3048
3077
|
addons: {
|
|
3049
3078
|
autoDecrypt: true,
|
|
3050
3079
|
persistAllSecrets: true
|
|
@@ -3170,9 +3199,18 @@ var ZapoProvider = class {
|
|
|
3170
3199
|
...protocolKey?.participant !== void 0 ? { participant: protocolKey.participant } : event.key.participant !== void 0 ? { participant: event.key.participant } : {},
|
|
3171
3200
|
...protocolKey?.participantAlt !== void 0 ? { participantAlt: protocolKey.participantAlt } : event.key.participantAlt !== void 0 ? { participantAlt: event.key.participantAlt } : {}
|
|
3172
3201
|
};
|
|
3173
|
-
|
|
3202
|
+
if (event.offline === true && this.#options.processOfflineMessages !== true) {
|
|
3203
|
+
this.#logger.debug("Ignored offline Zapo edit addon from before the current live connection.", {
|
|
3204
|
+
messageId: event.key.id ?? void 0,
|
|
3205
|
+
targetMessageId,
|
|
3206
|
+
chatId: target.remoteJid ?? event.key.remoteJid ?? void 0
|
|
3207
|
+
});
|
|
3208
|
+
return;
|
|
3209
|
+
}
|
|
3210
|
+
const mutationTimestampSeconds = toSeconds(protocol?.timestampMs) ?? (event.offline === true ? toSeconds(event.timestampSeconds) : void 0) ?? Math.floor(Date.now() / 1e3);
|
|
3211
|
+
this.#enqueueProtocolEvent({
|
|
3174
3212
|
key: event.key,
|
|
3175
|
-
|
|
3213
|
+
timestampSeconds: mutationTimestampSeconds,
|
|
3176
3214
|
protocolMessage: {
|
|
3177
3215
|
type: proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
|
|
3178
3216
|
key: target,
|
|
@@ -4142,9 +4180,9 @@ function createZapoStoreEntry(storePath) {
|
|
|
4142
4180
|
senderKey: "sqlite",
|
|
4143
4181
|
appState: "sqlite",
|
|
4144
4182
|
privacyToken: "sqlite",
|
|
4145
|
-
messages: "
|
|
4146
|
-
threads: "
|
|
4147
|
-
contacts: "
|
|
4183
|
+
messages: "sqlite",
|
|
4184
|
+
threads: "sqlite",
|
|
4185
|
+
contacts: "sqlite"
|
|
4148
4186
|
},
|
|
4149
4187
|
cacheProviders: {
|
|
4150
4188
|
messageSecret: "sqlite"
|