@softtynet/zca-js 2.1.17 → 2.1.19

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/README.md CHANGED
@@ -18,6 +18,7 @@
18
18
  - [Basic Usages](#basic-usages)
19
19
  - [Login](#login)
20
20
  - [Listen for new messages](#listen-for-new-messages)
21
+ - [Synchronize Messages from Mobile](#synchronize-messages-from-mobile)
21
22
  - [Send a message](#send-a-message)
22
23
  - [Get/Send a sticker](#getsend-a-sticker)
23
24
  - [Example](#example)
@@ -114,6 +115,44 @@ api.listener.start();
114
115
  > [!IMPORTANT]
115
116
  > Only one web listener can run per account at a time. If you open Zalo in the browser while the listener is active, the listener will be automatically stopped.
116
117
 
118
+ ### Synchronize Messages from Mobile
119
+
120
+ `zca-js` supports cross-device message synchronization from the official Zalo mobile app:
121
+
122
+ #### Case 1: Auto-Sync on QR Login
123
+ When logging in via `loginQR`, check the **"Sync message with your phone"** checkbox on your phone before confirming:
124
+
125
+ ```javascript
126
+ import { Zalo, LoginQRCallbackEventType } from "zca-js";
127
+
128
+ const zalo = new Zalo({ selfListen: true });
129
+ const api = await zalo.loginQR({ qrPath: "./qr.png" });
130
+
131
+ // Listen for historical messages pushed from phone
132
+ api.listener.on("old_messages", (messages, type) => {
133
+ console.log(`Received ${messages.length} historical synced messages!`);
134
+ });
135
+
136
+ api.listener.start();
137
+ ```
138
+
139
+ #### Case 2: Manual Trigger Sync (from existing session)
140
+ To request message synchronization from your phone at any time:
141
+
142
+ ```javascript
143
+ api.listener.on("connected", async () => {
144
+ // Send sync request signal to mobile phone
145
+ await api.requestSyncFromPhone();
146
+ console.log("Please tap 'Sync now' on your phone!");
147
+ });
148
+
149
+ api.listener.on("old_messages", (messages, type) => {
150
+ console.log(`Received ${messages.length} synced messages from phone!`);
151
+ });
152
+
153
+ api.listener.start();
154
+ ```
155
+
117
156
  ### Send a message
118
157
 
119
158
  ```javascript
@@ -0,0 +1,4 @@
1
+ export type DecryptGidsResponse = {
2
+ gids: Record<string, string>;
3
+ };
4
+ export declare const decryptGidsFactory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => (gids: string | string[]) => Promise<DecryptGidsResponse>;
@@ -0,0 +1,28 @@
1
+ import { ZaloApiError } from "../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../utils.js";
3
+ export const decryptGidsFactory = apiFactory()((api, ctx, utils) => {
4
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/gid/decrypt`);
5
+ /**
6
+ * Giải mã danh sách Global ID (g_...) ẩn danh thành User ID thật
7
+ *
8
+ * @param gids Danh sách Global ID (hoặc 1 GID đơn lẻ)
9
+ * @throws {ZaloApiError}
10
+ */
11
+ return async function decryptGids(gids) {
12
+ if (!gids)
13
+ throw new ZaloApiError("Missing gids");
14
+ if (!Array.isArray(gids))
15
+ gids = [gids];
16
+ const params = {
17
+ gids,
18
+ imei: ctx.imei,
19
+ };
20
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
21
+ if (!encryptedParams)
22
+ throw new ZaloApiError("Failed to encrypt params");
23
+ const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
24
+ method: "GET",
25
+ });
26
+ return utils.resolve(response);
27
+ };
28
+ });
@@ -0,0 +1,6 @@
1
+ export type DownloadTransferSyncOptions = string | {
2
+ key: string;
3
+ exp: number | string;
4
+ sig: string;
5
+ };
6
+ export declare const downloadTransferSyncFactory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => (options: DownloadTransferSyncOptions) => Promise<Buffer>;
@@ -0,0 +1,30 @@
1
+ import { ZaloApiError } from "../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../utils.js";
3
+ export const downloadTransferSyncFactory = apiFactory()((api, ctx, utils) => {
4
+ /**
5
+ * Tải khối dữ liệu snapshot đồng bộ tin nhắn từ máy chủ transfersync.zaloapp.com
6
+ *
7
+ * @param options URL đầy đủ hoặc object chứa { key, exp, sig }
8
+ * @throws {ZaloApiError}
9
+ */
10
+ return async function downloadTransferSync(options) {
11
+ let downloadUrl = "";
12
+ if (typeof options === "string") {
13
+ downloadUrl = options;
14
+ }
15
+ else {
16
+ if (!options.key || !options.exp || !options.sig) {
17
+ throw new ZaloApiError("Missing key, exp or sig in options");
18
+ }
19
+ downloadUrl = `https://transfersync.zaloapp.com/api/transfer-sync-v2/download?key=${options.key}&exp=${options.exp}&sig=${options.sig}`;
20
+ }
21
+ const response = await utils.request(downloadUrl, {
22
+ method: "GET",
23
+ });
24
+ if (!response.ok) {
25
+ throw new ZaloApiError(`Failed to download transfer snapshot: ${response.statusText} (${response.status})`);
26
+ }
27
+ const arrayBuffer = await response.arrayBuffer();
28
+ return Buffer.from(arrayBuffer);
29
+ };
30
+ });
@@ -0,0 +1,4 @@
1
+ export type RequestSyncFromPhoneResponse = {
2
+ success: boolean;
3
+ };
4
+ export declare const requestSyncFromPhoneFactory: (ctx: import("../context.js").ContextBase, api: import("../apis.js").API) => () => Promise<RequestSyncFromPhoneResponse>;
@@ -0,0 +1,27 @@
1
+ import { ZaloApiError } from "../Errors/ZaloApiError.js";
2
+ import { apiFactory } from "../utils.js";
3
+ export const requestSyncFromPhoneFactory = apiFactory()((api, ctx) => {
4
+ /**
5
+ * Gửi tín hiệu kích hoạt yêu cầu đồng bộ tin nhắn từ xa sang app điện thoại (Trường hợp 2)
6
+ *
7
+ * @throws {ZaloApiError}
8
+ */
9
+ return async function requestSyncFromPhone() {
10
+ if (!api.listener) {
11
+ throw new ZaloApiError("WebSocket listener is not initialized. Please call api.listener.start() first.");
12
+ }
13
+ // Gửi frame yêu cầu đồng bộ qua WebSocket
14
+ const syncPayload = {
15
+ version: 1,
16
+ cmd: 510,
17
+ subCmd: 0,
18
+ data: {
19
+ act: "sync_request",
20
+ imei: ctx.imei,
21
+ ts: Date.now(),
22
+ },
23
+ };
24
+ api.listener.sendWs(syncPayload, true);
25
+ return { success: true };
26
+ };
27
+ });
package/dist/apis.d.ts CHANGED
@@ -21,6 +21,7 @@ import { createNoteFactory } from "./apis/createNote.js";
21
21
  import { createPollFactory } from "./apis/createPoll.js";
22
22
  import { createProductCatalogFactory } from "./apis/createProductCatalog.js";
23
23
  import { createReminderFactory } from "./apis/createReminder.js";
24
+ import { decryptGidsFactory } from "./apis/decryptGids.js";
24
25
  import { deleteAutoReplyFactory } from "./apis/deleteAutoReply.js";
25
26
  import { deleteAvatarFactory } from "./apis/deleteAvatar.js";
26
27
  import { deleteCatalogFactory } from "./apis/deleteCatalog.js";
@@ -30,6 +31,7 @@ import { deleteMessageFactory } from "./apis/deleteMessage.js";
30
31
  import { deleteProductCatalogFactory } from "./apis/deleteProductCatalog.js";
31
32
  import { disableGroupLinkFactory } from "./apis/disableGroupLink.js";
32
33
  import { disperseGroupFactory } from "./apis/disperseGroup.js";
34
+ import { downloadTransferSyncFactory } from "./apis/downloadTransferSync.js";
33
35
  import { editNoteFactory } from "./apis/editNote.js";
34
36
  import { editReminderFactory } from "./apis/editReminder.js";
35
37
  import { enableGroupLinkFactory } from "./apis/enableGroupLink.js";
@@ -104,6 +106,7 @@ import { removeQuickMessageFactory } from "./apis/removeQuickMessage.js";
104
106
  import { removeReminderFactory } from "./apis/removeReminder.js";
105
107
  import { removeUnreadMarkFactory } from "./apis/removeUnreadMark.js";
106
108
  import { removeUserFromGroupFactory } from "./apis/removeUserFromGroup.js";
109
+ import { requestSyncFromPhoneFactory } from "./apis/requestSyncFromPhone.js";
107
110
  import { resetHiddenConversPinFactory } from "./apis/resetHiddenConversPin.js";
108
111
  import { reuseAvatarFactory } from "./apis/reuseAvatar.js";
109
112
  import { reviewPendingMemberRequestFactory } from "./apis/reviewPendingMemberRequest.js";
@@ -172,6 +175,7 @@ export declare class API {
172
175
  createPoll: ReturnType<typeof createPollFactory>;
173
176
  createProductCatalog: ReturnType<typeof createProductCatalogFactory>;
174
177
  createReminder: ReturnType<typeof createReminderFactory>;
178
+ decryptGids: ReturnType<typeof decryptGidsFactory>;
175
179
  deleteAutoReply: ReturnType<typeof deleteAutoReplyFactory>;
176
180
  deleteAvatar: ReturnType<typeof deleteAvatarFactory>;
177
181
  deleteCatalog: ReturnType<typeof deleteCatalogFactory>;
@@ -181,6 +185,7 @@ export declare class API {
181
185
  deleteProductCatalog: ReturnType<typeof deleteProductCatalogFactory>;
182
186
  disableGroupLink: ReturnType<typeof disableGroupLinkFactory>;
183
187
  disperseGroup: ReturnType<typeof disperseGroupFactory>;
188
+ downloadTransferSync: ReturnType<typeof downloadTransferSyncFactory>;
184
189
  editNote: ReturnType<typeof editNoteFactory>;
185
190
  editReminder: ReturnType<typeof editReminderFactory>;
186
191
  enableGroupLink: ReturnType<typeof enableGroupLinkFactory>;
@@ -255,6 +260,7 @@ export declare class API {
255
260
  removeReminder: ReturnType<typeof removeReminderFactory>;
256
261
  removeUnreadMark: ReturnType<typeof removeUnreadMarkFactory>;
257
262
  removeUserFromGroup: ReturnType<typeof removeUserFromGroupFactory>;
263
+ requestSyncFromPhone: ReturnType<typeof requestSyncFromPhoneFactory>;
258
264
  resetHiddenConversPin: ReturnType<typeof resetHiddenConversPinFactory>;
259
265
  reuseAvatar: ReturnType<typeof reuseAvatarFactory>;
260
266
  reviewPendingMemberRequest: ReturnType<typeof reviewPendingMemberRequestFactory>;
package/dist/apis.js CHANGED
@@ -21,6 +21,7 @@ import { createNoteFactory } from "./apis/createNote.js";
21
21
  import { createPollFactory } from "./apis/createPoll.js";
22
22
  import { createProductCatalogFactory } from "./apis/createProductCatalog.js";
23
23
  import { createReminderFactory } from "./apis/createReminder.js";
24
+ import { decryptGidsFactory } from "./apis/decryptGids.js";
24
25
  import { deleteAutoReplyFactory } from "./apis/deleteAutoReply.js";
25
26
  import { deleteAvatarFactory } from "./apis/deleteAvatar.js";
26
27
  import { deleteCatalogFactory } from "./apis/deleteCatalog.js";
@@ -30,6 +31,7 @@ import { deleteMessageFactory } from "./apis/deleteMessage.js";
30
31
  import { deleteProductCatalogFactory } from "./apis/deleteProductCatalog.js";
31
32
  import { disableGroupLinkFactory } from "./apis/disableGroupLink.js";
32
33
  import { disperseGroupFactory } from "./apis/disperseGroup.js";
34
+ import { downloadTransferSyncFactory } from "./apis/downloadTransferSync.js";
33
35
  import { editNoteFactory } from "./apis/editNote.js";
34
36
  import { editReminderFactory } from "./apis/editReminder.js";
35
37
  import { enableGroupLinkFactory } from "./apis/enableGroupLink.js";
@@ -104,6 +106,7 @@ import { removeQuickMessageFactory } from "./apis/removeQuickMessage.js";
104
106
  import { removeReminderFactory } from "./apis/removeReminder.js";
105
107
  import { removeUnreadMarkFactory } from "./apis/removeUnreadMark.js";
106
108
  import { removeUserFromGroupFactory } from "./apis/removeUserFromGroup.js";
109
+ import { requestSyncFromPhoneFactory } from "./apis/requestSyncFromPhone.js";
107
110
  import { resetHiddenConversPinFactory } from "./apis/resetHiddenConversPin.js";
108
111
  import { reuseAvatarFactory } from "./apis/reuseAvatar.js";
109
112
  import { reviewPendingMemberRequestFactory } from "./apis/reviewPendingMemberRequest.js";
@@ -172,6 +175,7 @@ export class API {
172
175
  this.createPoll = createPollFactory(ctx, this);
173
176
  this.createProductCatalog = createProductCatalogFactory(ctx, this);
174
177
  this.createReminder = createReminderFactory(ctx, this);
178
+ this.decryptGids = decryptGidsFactory(ctx, this);
175
179
  this.deleteAutoReply = deleteAutoReplyFactory(ctx, this);
176
180
  this.deleteAvatar = deleteAvatarFactory(ctx, this);
177
181
  this.deleteCatalog = deleteCatalogFactory(ctx, this);
@@ -181,6 +185,7 @@ export class API {
181
185
  this.deleteProductCatalog = deleteProductCatalogFactory(ctx, this);
182
186
  this.disableGroupLink = disableGroupLinkFactory(ctx, this);
183
187
  this.disperseGroup = disperseGroupFactory(ctx, this);
188
+ this.downloadTransferSync = downloadTransferSyncFactory(ctx, this);
184
189
  this.editNote = editNoteFactory(ctx, this);
185
190
  this.editReminder = editReminderFactory(ctx, this);
186
191
  this.enableGroupLink = enableGroupLinkFactory(ctx, this);
@@ -255,6 +260,7 @@ export class API {
255
260
  this.removeReminder = removeReminderFactory(ctx, this);
256
261
  this.removeUnreadMark = removeUnreadMarkFactory(ctx, this);
257
262
  this.removeUserFromGroup = removeUserFromGroupFactory(ctx, this);
263
+ this.requestSyncFromPhone = requestSyncFromPhoneFactory(ctx, this);
258
264
  this.resetHiddenConversPin = resetHiddenConversPinFactory(ctx, this);
259
265
  this.reuseAvatar = reuseAvatarFactory(ctx, this);
260
266
  this.reviewPendingMemberRequest = reviewPendingMemberRequestFactory(ctx, this);
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ var ZaloApiError = require('../Errors/ZaloApiError.cjs');
4
+ var utils = require('../utils.cjs');
5
+
6
+ const decryptGidsFactory = utils.apiFactory()((api, ctx, utils) => {
7
+ const serviceURL = utils.makeURL(`${api.zpwServiceMap.profile[0]}/api/gid/decrypt`);
8
+ /**
9
+ * Giải mã danh sách Global ID (g_...) ẩn danh thành User ID thật
10
+ *
11
+ * @param gids Danh sách Global ID (hoặc 1 GID đơn lẻ)
12
+ * @throws {ZaloApiError}
13
+ */
14
+ return async function decryptGids(gids) {
15
+ if (!gids)
16
+ throw new ZaloApiError.ZaloApiError("Missing gids");
17
+ if (!Array.isArray(gids))
18
+ gids = [gids];
19
+ const params = {
20
+ gids,
21
+ imei: ctx.imei,
22
+ };
23
+ const encryptedParams = utils.encodeAES(JSON.stringify(params));
24
+ if (!encryptedParams)
25
+ throw new ZaloApiError.ZaloApiError("Failed to encrypt params");
26
+ const response = await utils.request(utils.makeURL(serviceURL, { params: encryptedParams }), {
27
+ method: "GET",
28
+ });
29
+ return utils.resolve(response);
30
+ };
31
+ });
32
+
33
+ exports.decryptGidsFactory = decryptGidsFactory;
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ var ZaloApiError = require('../Errors/ZaloApiError.cjs');
4
+ var utils = require('../utils.cjs');
5
+
6
+ const downloadTransferSyncFactory = utils.apiFactory()((api, ctx, utils) => {
7
+ /**
8
+ * Tải khối dữ liệu snapshot đồng bộ tin nhắn từ máy chủ transfersync.zaloapp.com
9
+ *
10
+ * @param options URL đầy đủ hoặc object chứa { key, exp, sig }
11
+ * @throws {ZaloApiError}
12
+ */
13
+ return async function downloadTransferSync(options) {
14
+ let downloadUrl = "";
15
+ if (typeof options === "string") {
16
+ downloadUrl = options;
17
+ }
18
+ else {
19
+ if (!options.key || !options.exp || !options.sig) {
20
+ throw new ZaloApiError.ZaloApiError("Missing key, exp or sig in options");
21
+ }
22
+ downloadUrl = `https://transfersync.zaloapp.com/api/transfer-sync-v2/download?key=${options.key}&exp=${options.exp}&sig=${options.sig}`;
23
+ }
24
+ const response = await utils.request(downloadUrl, {
25
+ method: "GET",
26
+ });
27
+ if (!response.ok) {
28
+ throw new ZaloApiError.ZaloApiError(`Failed to download transfer snapshot: ${response.statusText} (${response.status})`);
29
+ }
30
+ const arrayBuffer = await response.arrayBuffer();
31
+ return Buffer.from(arrayBuffer);
32
+ };
33
+ });
34
+
35
+ exports.downloadTransferSyncFactory = downloadTransferSyncFactory;
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ var ZaloApiError = require('../Errors/ZaloApiError.cjs');
4
+ var utils = require('../utils.cjs');
5
+
6
+ const requestSyncFromPhoneFactory = utils.apiFactory()((api, ctx) => {
7
+ /**
8
+ * Gửi tín hiệu kích hoạt yêu cầu đồng bộ tin nhắn từ xa sang app điện thoại (Trường hợp 2)
9
+ *
10
+ * @throws {ZaloApiError}
11
+ */
12
+ return async function requestSyncFromPhone() {
13
+ if (!api.listener) {
14
+ throw new ZaloApiError.ZaloApiError("WebSocket listener is not initialized. Please call api.listener.start() first.");
15
+ }
16
+ // Gửi frame yêu cầu đồng bộ qua WebSocket
17
+ const syncPayload = {
18
+ version: 1,
19
+ cmd: 510,
20
+ subCmd: 0,
21
+ data: {
22
+ act: "sync_request",
23
+ imei: ctx.imei,
24
+ ts: Date.now(),
25
+ },
26
+ };
27
+ api.listener.sendWs(syncPayload, true);
28
+ return { success: true };
29
+ };
30
+ });
31
+
32
+ exports.requestSyncFromPhoneFactory = requestSyncFromPhoneFactory;
package/dist/cjs/apis.cjs CHANGED
@@ -23,6 +23,7 @@ var createNote = require('./apis/createNote.cjs');
23
23
  var createPoll = require('./apis/createPoll.cjs');
24
24
  var createProductCatalog = require('./apis/createProductCatalog.cjs');
25
25
  var createReminder = require('./apis/createReminder.cjs');
26
+ var decryptGids = require('./apis/decryptGids.cjs');
26
27
  var deleteAutoReply = require('./apis/deleteAutoReply.cjs');
27
28
  var deleteAvatar = require('./apis/deleteAvatar.cjs');
28
29
  var deleteCatalog = require('./apis/deleteCatalog.cjs');
@@ -32,6 +33,7 @@ var deleteMessage = require('./apis/deleteMessage.cjs');
32
33
  var deleteProductCatalog = require('./apis/deleteProductCatalog.cjs');
33
34
  var disableGroupLink = require('./apis/disableGroupLink.cjs');
34
35
  var disperseGroup = require('./apis/disperseGroup.cjs');
36
+ var downloadTransferSync = require('./apis/downloadTransferSync.cjs');
35
37
  var editNote = require('./apis/editNote.cjs');
36
38
  var editReminder = require('./apis/editReminder.cjs');
37
39
  var enableGroupLink = require('./apis/enableGroupLink.cjs');
@@ -106,6 +108,7 @@ var removeQuickMessage = require('./apis/removeQuickMessage.cjs');
106
108
  var removeReminder = require('./apis/removeReminder.cjs');
107
109
  var removeUnreadMark = require('./apis/removeUnreadMark.cjs');
108
110
  var removeUserFromGroup = require('./apis/removeUserFromGroup.cjs');
111
+ var requestSyncFromPhone = require('./apis/requestSyncFromPhone.cjs');
109
112
  var resetHiddenConversPin = require('./apis/resetHiddenConversPin.cjs');
110
113
  var reuseAvatar = require('./apis/reuseAvatar.cjs');
111
114
  var reviewPendingMemberRequest = require('./apis/reviewPendingMemberRequest.cjs');
@@ -175,6 +178,7 @@ class API {
175
178
  this.createPoll = createPoll.createPollFactory(ctx, this);
176
179
  this.createProductCatalog = createProductCatalog.createProductCatalogFactory(ctx, this);
177
180
  this.createReminder = createReminder.createReminderFactory(ctx, this);
181
+ this.decryptGids = decryptGids.decryptGidsFactory(ctx, this);
178
182
  this.deleteAutoReply = deleteAutoReply.deleteAutoReplyFactory(ctx, this);
179
183
  this.deleteAvatar = deleteAvatar.deleteAvatarFactory(ctx, this);
180
184
  this.deleteCatalog = deleteCatalog.deleteCatalogFactory(ctx, this);
@@ -184,6 +188,7 @@ class API {
184
188
  this.deleteProductCatalog = deleteProductCatalog.deleteProductCatalogFactory(ctx, this);
185
189
  this.disableGroupLink = disableGroupLink.disableGroupLinkFactory(ctx, this);
186
190
  this.disperseGroup = disperseGroup.disperseGroupFactory(ctx, this);
191
+ this.downloadTransferSync = downloadTransferSync.downloadTransferSyncFactory(ctx, this);
187
192
  this.editNote = editNote.editNoteFactory(ctx, this);
188
193
  this.editReminder = editReminder.editReminderFactory(ctx, this);
189
194
  this.enableGroupLink = enableGroupLink.enableGroupLinkFactory(ctx, this);
@@ -258,6 +263,7 @@ class API {
258
263
  this.removeReminder = removeReminder.removeReminderFactory(ctx, this);
259
264
  this.removeUnreadMark = removeUnreadMark.removeUnreadMarkFactory(ctx, this);
260
265
  this.removeUserFromGroup = removeUserFromGroup.removeUserFromGroupFactory(ctx, this);
266
+ this.requestSyncFromPhone = requestSyncFromPhone.requestSyncFromPhoneFactory(ctx, this);
261
267
  this.resetHiddenConversPin = resetHiddenConversPin.resetHiddenConversPinFactory(ctx, this);
262
268
  this.reuseAvatar = reuseAvatar.reuseAvatarFactory(ctx, this);
263
269
  this.reviewPendingMemberRequest = reviewPendingMemberRequest.reviewPendingMemberRequestFactory(ctx, this);
@@ -309,7 +309,7 @@ async function getDefaultHeaders(ctx, origin = "https://chat.zalo.me") {
309
309
  if (!ctx.userAgent)
310
310
  throw new ZaloApiError.ZaloApiError("User agent is not available");
311
311
  const secChUa = getSecChUaHeaders(ctx.userAgent);
312
- return Object.assign({ accept: "*/*", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": getBrowserLanguage(ctx.language), "content-type": "application/x-www-form-urlencoded", cookie: await ctx.cookie.getCookieString(origin), origin: "https://chat.zalo.me", priority: "u=1, i", referer: "https://chat.zalo.me/", "user-agent": ctx.userAgent, "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-site" }, secChUa);
312
+ return Object.assign({ accept: "*/*", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": getBrowserLanguage(ctx.language), "content-type": "application/x-www-form-urlencoded", cookie: await ctx.cookie.getCookieString(origin), origin: origin, priority: "u=1, i", referer: `${origin}/`, "user-agent": ctx.userAgent, "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": origin === "https://id.zalo.me" ? "same-origin" : "same-site" }, secChUa);
313
313
  }
314
314
  async function request(ctx, url, options, raw = false) {
315
315
  var _a, _b;
@@ -318,11 +318,23 @@ async function request(ctx, url, options, raw = false) {
318
318
  const origin = new URL(url).origin;
319
319
  const defaultHeaders = await getDefaultHeaders(ctx, origin);
320
320
  if (!raw) {
321
- if (options) {
322
- options.headers = Object.assign(defaultHeaders, options.headers || {});
321
+ if (options && options.headers) {
322
+ const mergedHeaders = Object.assign({}, defaultHeaders);
323
+ const inputHeaders = options.headers;
324
+ for (const [key, value] of Object.entries(inputHeaders)) {
325
+ const lowerKey = key.toLowerCase();
326
+ for (const existingKey of Object.keys(mergedHeaders)) {
327
+ if (existingKey.toLowerCase() === lowerKey && existingKey !== key) {
328
+ delete mergedHeaders[existingKey];
329
+ }
330
+ }
331
+ mergedHeaders[key] = value;
332
+ }
333
+ options.headers = mergedHeaders;
334
+ }
335
+ else {
336
+ options = Object.assign(Object.assign({}, (options || {})), { headers: defaultHeaders });
323
337
  }
324
- else
325
- options = { headers: defaultHeaders };
326
338
  }
327
339
  const _options = Object.assign(Object.assign({}, (options !== null && options !== void 0 ? options : {})), (isBun
328
340
  ? {
package/dist/index.d.ts CHANGED
@@ -31,6 +31,8 @@ export type { DeleteChatLastMessage, DeleteChatResponse } from "./apis/deleteCha
31
31
  export type { DeleteGroupInviteBoxResponse } from "./apis/deleteGroupInviteBox.js";
32
32
  export type { DeleteMessageDestination, DeleteMessageResponse } from "./apis/deleteMessage.js";
33
33
  export type { DeleteProductCatalogPayload, DeleteProductCatalogResponse } from "./apis/deleteProductCatalog.js";
34
+ export type { DecryptGidsResponse } from "./apis/decryptGids.js";
35
+ export type { DownloadTransferSyncOptions } from "./apis/downloadTransferSync.js";
34
36
  export type { DisableGroupLinkResponse } from "./apis/disableGroupLink.js";
35
37
  export type { DisperseGroupResponse } from "./apis/disperseGroup.js";
36
38
  export type { EditNoteOptions, EditNoteResponse } from "./apis/editNote.js";
@@ -103,6 +105,7 @@ export type { RemoveQuickMessageResponse } from "./apis/removeQuickMessage.js";
103
105
  export type { RemoveReminderResponse } from "./apis/removeReminder.js";
104
106
  export type { RemoveUnreadMarkResponse } from "./apis/removeUnreadMark.js";
105
107
  export type { RemoveUserFromGroupResponse } from "./apis/removeUserFromGroup.js";
108
+ export type { RequestSyncFromPhoneResponse } from "./apis/requestSyncFromPhone.js";
106
109
  export type { ResetHiddenConversPinResponse } from "./apis/resetHiddenConversPin.js";
107
110
  export type { ReuseAvatarResponse } from "./apis/reuseAvatar.js";
108
111
  export type { ReviewPendingMemberRequestPayload, ReviewPendingMemberRequestResponse } from "./apis/reviewPendingMemberRequest.js";
package/dist/utils.js CHANGED
@@ -305,7 +305,7 @@ export async function getDefaultHeaders(ctx, origin = "https://chat.zalo.me") {
305
305
  if (!ctx.userAgent)
306
306
  throw new ZaloApiError("User agent is not available");
307
307
  const secChUa = getSecChUaHeaders(ctx.userAgent);
308
- return Object.assign({ accept: "*/*", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": getBrowserLanguage(ctx.language), "content-type": "application/x-www-form-urlencoded", cookie: await ctx.cookie.getCookieString(origin), origin: "https://chat.zalo.me", priority: "u=1, i", referer: "https://chat.zalo.me/", "user-agent": ctx.userAgent, "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-site" }, secChUa);
308
+ return Object.assign({ accept: "*/*", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": getBrowserLanguage(ctx.language), "content-type": "application/x-www-form-urlencoded", cookie: await ctx.cookie.getCookieString(origin), origin: origin, priority: "u=1, i", referer: `${origin}/`, "user-agent": ctx.userAgent, "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": origin === "https://id.zalo.me" ? "same-origin" : "same-site" }, secChUa);
309
309
  }
310
310
  export async function request(ctx, url, options, raw = false) {
311
311
  var _a, _b;
@@ -314,11 +314,23 @@ export async function request(ctx, url, options, raw = false) {
314
314
  const origin = new URL(url).origin;
315
315
  const defaultHeaders = await getDefaultHeaders(ctx, origin);
316
316
  if (!raw) {
317
- if (options) {
318
- options.headers = Object.assign(defaultHeaders, options.headers || {});
317
+ if (options && options.headers) {
318
+ const mergedHeaders = Object.assign({}, defaultHeaders);
319
+ const inputHeaders = options.headers;
320
+ for (const [key, value] of Object.entries(inputHeaders)) {
321
+ const lowerKey = key.toLowerCase();
322
+ for (const existingKey of Object.keys(mergedHeaders)) {
323
+ if (existingKey.toLowerCase() === lowerKey && existingKey !== key) {
324
+ delete mergedHeaders[existingKey];
325
+ }
326
+ }
327
+ mergedHeaders[key] = value;
328
+ }
329
+ options.headers = mergedHeaders;
330
+ }
331
+ else {
332
+ options = Object.assign(Object.assign({}, (options || {})), { headers: defaultHeaders });
319
333
  }
320
- else
321
- options = { headers: defaultHeaders };
322
334
  }
323
335
  const _options = Object.assign(Object.assign({}, (options !== null && options !== void 0 ? options : {})), (isBun
324
336
  ? {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softtynet/zca-js",
3
- "version": "2.1.17",
3
+ "version": "2.1.19",
4
4
  "description": "Unofficial Zalo API for JavaScript",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",