@lazyneoaz/nkxchat 1.0.1 → 1.0.2

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": "@lazyneoaz/nkxchat",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "commonjs",
5
5
  "types": "src/types/index.d.ts",
6
6
  "description": "Advanced Facebook Chat API client for building Messenger bots — real-time messaging, thread management, MQTT, and session stability.",
@@ -3,6 +3,7 @@ const utils = require('../utils');
3
3
  const mqtt = require('mqtt');
4
4
  const WebSocket = require('ws');
5
5
  const duplexify = require('duplexify');
6
+ const { PassThrough, Writable } = require('stream');
6
7
  const HttpsProxyAgent = require('https-proxy-agent');
7
8
  const EventEmitter = require('events');
8
9
  const { parseDelta } = require('./mqttDeltaValue');
@@ -188,21 +189,91 @@ async function listenMqtt(defaultFuncs, api, ctx, globalCallback, scheduleReconn
188
189
  const wsOpts = {
189
190
  headers: options.wsOptions.headers,
190
191
  origin: options.wsOptions.origin,
191
- perMessageDeflate: false,
192
192
  };
193
193
  if (options.wsOptions.agent) wsOpts.agent = options.wsOptions.agent;
194
+
194
195
  const ws = new WebSocket(host, wsOpts);
195
- const d = duplexify();
196
- ws.once('open', () => {
197
- const s = WebSocket.createWebSocketStream(ws, { objectMode: false });
198
- d.setReadable(s);
199
- d.setWritable(s);
196
+
197
+ // Custom writable — sends chunks directly through the WebSocket socket.send()
198
+ // rather than using createWebSocketStream, which avoids perMessageDeflate
199
+ // negotiation conflicts and stream buffering edge cases.
200
+ let wsTarget = null;
201
+ let proxyEnded = false;
202
+ const proxy = new Writable({
203
+ autoDestroy: true,
204
+ write(chunk, _enc, cb) {
205
+ if (proxyEnded || this.destroyed) return cb();
206
+ const sock = wsTarget;
207
+ if (sock && sock.readyState === WebSocket.OPEN) {
208
+ try { sock.send(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk), cb); }
209
+ catch (e) { cb(e); }
210
+ } else { cb(); }
211
+ },
212
+ final(cb) {
213
+ proxyEnded = true;
214
+ const sock = wsTarget;
215
+ wsTarget = null;
216
+ if (sock && (sock.readyState === WebSocket.CONNECTING || sock.readyState === WebSocket.OPEN)) {
217
+ try { sock.terminate ? sock.terminate() : sock.close(); } catch (_) {}
218
+ }
219
+ cb();
220
+ }
200
221
  });
201
- ws.on('error', (err) => d.destroy(err));
222
+
223
+ const readable = new PassThrough();
224
+ const stream = new duplexify(undefined, undefined, { end: false, autoDestroy: true });
225
+
226
+ const toBuffer = (data) => {
227
+ if (Buffer.isBuffer(data)) return data;
228
+ if (data instanceof ArrayBuffer) return Buffer.from(data);
229
+ if (ArrayBuffer.isView(data)) return Buffer.from(data.buffer, data.byteOffset, data.byteLength);
230
+ return Buffer.from(String(data));
231
+ };
232
+
233
+ let closed = false;
234
+ const cleanup = () => {
235
+ if (closed) return;
236
+ closed = true;
237
+ proxyEnded = true;
238
+ wsTarget = null;
239
+ try { ws.removeAllListeners(); } catch (_) {}
240
+ try { if (ws.readyState === WebSocket.OPEN) ws.terminate ? ws.terminate() : ws.close(); } catch (_) {}
241
+ readable.end();
242
+ };
243
+
244
+ ws.on('open', () => {
245
+ if (closed) return;
246
+ wsTarget = ws;
247
+ stream.setWritable(proxy);
248
+ stream.setReadable(readable);
249
+ stream.emit('connect');
250
+ });
251
+
252
+ ws.on('message', (data) => {
253
+ if (closed) return;
254
+ readable.write(toBuffer(data));
255
+ });
256
+
257
+ ws.on('error', (err) => {
258
+ cleanup();
259
+ stream.destroy(err instanceof Error ? err : new Error(String(err)));
260
+ });
261
+
262
+ ws.on('close', () => {
263
+ cleanup();
264
+ stream.end();
265
+ if (!stream.destroyed) stream.destroy();
266
+ });
267
+
202
268
  ws.on('unexpected-response', (_req, res) => {
203
- d.destroy(new Error(`WebSocket unexpected response: ${res.statusCode}`));
269
+ cleanup();
270
+ stream.destroy(new Error(`WebSocket unexpected response: ${res.statusCode}`));
204
271
  });
205
- return d;
272
+
273
+ stream.on('finish', cleanup);
274
+ stream.on('close', cleanup);
275
+
276
+ return stream;
206
277
  }
207
278
 
208
279
  const mqttClient = new mqtt.Client(buildMqttStream, options);
@@ -102,6 +102,8 @@ class AutoReLoginManager {
102
102
  const setOptionsModel = require('../engine/models/setOptions');
103
103
  const buildAPIModel = require('../engine/models/buildAPI');
104
104
 
105
+ const fbLinkFunc = typeof fbLink === 'function' ? fbLink : () => fbLink;
106
+
105
107
  await new Promise((resolve, reject) => {
106
108
  loginHelperModel(
107
109
  this.credentials,
@@ -126,7 +128,7 @@ class AutoReLoginManager {
126
128
  setOptionsModel,
127
129
  buildAPIModel,
128
130
  api,
129
- fbLink,
131
+ fbLinkFunc,
130
132
  ERROR_RETRIEVING
131
133
  );
132
134
  });
@@ -194,7 +194,7 @@ function getFrom(str, startToken, endToken) {
194
194
  }
195
195
 
196
196
  function makeParsable(html) {
197
- const withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*/, "");
197
+ const withoutForLoop = html.replace(/^\s*for\s*\(;;\);\s*/i, "");
198
198
  const maybeMultipleObjects = withoutForLoop.split(/\}\r\n *\{/);
199
199
  if (maybeMultipleObjects.length === 1) return maybeMultipleObjects;
200
200