@softtynet/zca-js 2.1.18 → 2.1.20

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.
@@ -142,8 +142,25 @@ export class Listener extends EventEmitter {
142
142
  logger(this.ctx).verbose(`Rotating endpoint to ${this.wsURL}`);
143
143
  }
144
144
  start({ retryOnClose = false } = {}) {
145
- if (this.ws)
146
- throw new ZaloApiError("Already started");
145
+ if (this.retryTimeout) {
146
+ clearTimeout(this.retryTimeout);
147
+ this.retryTimeout = undefined;
148
+ }
149
+ if (this.ws) {
150
+ const state = this.ws.readyState;
151
+ if (state === WebSocket.CONNECTING || state === WebSocket.OPEN) {
152
+ logger(this.ctx).warn("Listener is already active or connecting. Skipping duplicate start().");
153
+ return;
154
+ }
155
+ try {
156
+ this.ws.removeAllListeners();
157
+ this.ws.close();
158
+ }
159
+ catch (_a) {
160
+ // ignore
161
+ }
162
+ this.ws = null;
163
+ }
147
164
  this.wsURL = makeURL(this.ctx, this.urls[this.rotateCount], {
148
165
  t: Date.now(),
149
166
  });
@@ -185,7 +202,12 @@ export class Listener extends EventEmitter {
185
202
  }
186
203
  this.emit("reconnecting", event.code);
187
204
  this.retryTimeout = setTimeout(() => {
188
- this.start({ retryOnClose: true });
205
+ try {
206
+ this.start({ retryOnClose: true });
207
+ }
208
+ catch (error) {
209
+ logger(this.ctx).error("Failed to auto-restart listener on retry timeout:", error);
210
+ }
189
211
  }, retry);
190
212
  }
191
213
  else {
@@ -154,8 +154,25 @@ class Listener extends EventEmitter {
154
154
  utils.logger(this.ctx).verbose(`Rotating endpoint to ${this.wsURL}`);
155
155
  }
156
156
  start({ retryOnClose = false } = {}) {
157
- if (this.ws)
158
- throw new ZaloApiError.ZaloApiError("Already started");
157
+ if (this.retryTimeout) {
158
+ clearTimeout(this.retryTimeout);
159
+ this.retryTimeout = undefined;
160
+ }
161
+ if (this.ws) {
162
+ const state = this.ws.readyState;
163
+ if (state === WebSocket.CONNECTING || state === WebSocket.OPEN) {
164
+ utils.logger(this.ctx).warn("Listener is already active or connecting. Skipping duplicate start().");
165
+ return;
166
+ }
167
+ try {
168
+ this.ws.removeAllListeners();
169
+ this.ws.close();
170
+ }
171
+ catch (_a) {
172
+ // ignore
173
+ }
174
+ this.ws = null;
175
+ }
159
176
  this.wsURL = utils.makeURL(this.ctx, this.urls[this.rotateCount], {
160
177
  t: Date.now(),
161
178
  });
@@ -197,7 +214,12 @@ class Listener extends EventEmitter {
197
214
  }
198
215
  this.emit("reconnecting", event.code);
199
216
  this.retryTimeout = setTimeout(() => {
200
- this.start({ retryOnClose: true });
217
+ try {
218
+ this.start({ retryOnClose: true });
219
+ }
220
+ catch (error) {
221
+ utils.logger(this.ctx).error("Failed to auto-restart listener on retry timeout:", error);
222
+ }
201
223
  }, retry);
202
224
  }
203
225
  else {
@@ -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/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.18",
3
+ "version": "2.1.20",
4
4
  "description": "Unofficial Zalo API for JavaScript",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",