@ardennguyen/zalo-agent-cli 2.5.6 → 2.5.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ardennguyen/zalo-agent-cli",
3
- "version": "2.5.6",
3
+ "version": "2.5.7",
4
4
  "description": "CLI tool for Zalo automation — multi-account, proxy, bank transfers, QR payments, Official Account API v3.0",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1259,7 +1259,18 @@ function reportRestore(res, win, ctx = {}) {
1259
1259
  return { status: "ok", reason: "phone confirmed: nothing missed in this window" };
1260
1260
  }
1261
1261
  if (res.reason === "partial" || res.reason === "socket-lost") {
1262
- const how = res.reason === "socket-lost" ? "the connection dropped" : "the run was cut short";
1262
+ const how =
1263
+ res.reason === "socket-lost"
1264
+ ? "the connection dropped"
1265
+ : res.rowErrors
1266
+ ? "some messages could not be written"
1267
+ : "the run was cut short";
1268
+ if (res.rowErrors) {
1269
+ warning(
1270
+ `${res.rowErrors} message(s) could not be written to the local cache (${res.firstRowError ?? "unknown error"}). ` +
1271
+ "Re-run with --force once the cause is gone.",
1272
+ );
1273
+ }
1263
1274
  warning(
1264
1275
  `Partial restore: ${res.messagesSaved} message(s) from ${res.conversations} conversation(s) before ${how}.`,
1265
1276
  );
@@ -384,6 +384,7 @@ export function createShardSchedule(shardCount, opts = {}) {
384
384
  * @param {number} st.total - shards requested
385
385
  * @param {number} [st.resumes=0] - reconnects used
386
386
  * @param {number} [st.waitMs] - the budget, for the timeout wording
387
+ * @param {number} [st.rowErrors] - rows that could not be written to the cache
387
388
  * @returns {{reason: string, error: string|null}}
388
389
  */
389
390
  export function describeRestoreOutcome(st) {
@@ -410,6 +411,8 @@ export function describeRestoreOutcome(st) {
410
411
  };
411
412
  }
412
413
  if (st.finished < st.total) return { reason: st.socketDied ? "socket-lost" : "partial", error: null };
414
+ // Every shard came back, but a row did not reach the cache: a hole is not complete.
415
+ if (st.rowErrors > 0) return { reason: "partial", error: null };
413
416
  return { reason: "complete", error: null };
414
417
  }
415
418
 
@@ -874,7 +877,10 @@ export class SyncV2 {
874
877
  const ik = zproto.generateKeyPair();
875
878
  let conversations = 0,
876
879
  messagesSaved = 0,
877
- attachmentsSaved = 0;
880
+ attachmentsSaved = 0,
881
+ rowErrors = 0;
882
+ /** The first reason a row could not be written, for the report. */
883
+ let firstRowError = null;
878
884
  const mappedThreads = new Set(),
879
885
  unmappedThreads = new Set();
880
886
  /** type name -> count, for the command's summary line. */
@@ -892,6 +898,8 @@ export class SyncV2 {
892
898
  confirmed,
893
899
  ...resumeInfo,
894
900
  attachmentsSaved,
901
+ rowErrors,
902
+ firstRowError,
895
903
  typeCounts: { ...typeCounts },
896
904
  // Every threadId the conversation round accounted for. Anything
897
905
  // cached outside this list is orphaned.
@@ -1253,8 +1261,12 @@ export class SyncV2 {
1253
1261
  messagesSaved++;
1254
1262
  if (info.hasAttachment) attachmentsSaved++;
1255
1263
  typeCounts[info.type] = (typeCounts[info.type] || 0) + 1;
1256
- } catch {
1257
- /* dedupe/constraint — keep going */
1264
+ } catch (e) {
1265
+ // Keep going with the rest of the chunk, but never silently: a row that cannot
1266
+ // be written (a full disk, a locked file) leaves a hole, so the run does not
1267
+ // call itself complete.
1268
+ rowErrors++;
1269
+ firstRowError ??= e?.message ?? String(e);
1258
1270
  }
1259
1271
  }
1260
1272
  }
@@ -1314,6 +1326,7 @@ export class SyncV2 {
1314
1326
  timedOut,
1315
1327
  confirmed,
1316
1328
  messagesSaved,
1329
+ rowErrors,
1317
1330
  finished,
1318
1331
  total: shards.length,
1319
1332
  resumes: schedule.resumes(),
@@ -8,7 +8,7 @@ import { basename } from "node:path";
8
8
  import { imageSizeFromFile } from "image-size/fromFile";
9
9
  import { Zalo } from "zca-js";
10
10
  import { HttpsProxyAgent } from "https-proxy-agent";
11
- import { ProxyAgent } from "undici";
11
+ import { ProxyAgent, fetch as undiciFetch } from "undici";
12
12
  import { getActive } from "./accounts.js";
13
13
  import { loadCredentials } from "./credentials.js";
14
14
  import { info } from "../utils/output.js";
@@ -100,10 +100,14 @@ export function isLoggedIn() {
100
100
  /**
101
101
  * Create a proxy-aware fetch that uses undici ProxyAgent dispatcher.
102
102
  * Native Node.js fetch ignores the `agent` option — must use `dispatcher`.
103
+ *
104
+ * The fetch is undici's own, not the global one: Node bundles its own undici and the package here is another, and a
105
+ * dispatcher from one handed to the fetch of the other fails every request with "invalid onRequestStart method". A
106
+ * proxied account could not log in at all.
103
107
  */
104
- function createProxyFetch(proxyUrl) {
108
+ export function createProxyFetch(proxyUrl) {
105
109
  const dispatcher = new ProxyAgent(proxyUrl);
106
- return (url, init = {}) => fetch(url, { ...init, dispatcher });
110
+ return (url, init = {}) => undiciFetch(url, { ...init, dispatcher });
107
111
  }
108
112
 
109
113
  /**