@lazyneoaz/testfca 1.0.4 → 1.0.5

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/testfca",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "type": "commonjs",
5
5
  "description": "Advanced Facebook Chat API client for building Messenger bots — supports real-time messaging, thread management, MQTT, session stability, anti-automation protection, and real E2EE via Signal Protocol.",
6
6
  "main": "index.js",
@@ -592,130 +592,134 @@ async function listenMqtt(defaultFuncs, api, ctx, globalCallback, scheduleReconn
592
592
  }
593
593
  while (ctx._e2eePollingActive) {
594
594
  try {
595
- // Yield to event loop before blocking poll (same pattern as yumi-team)
595
+ // Yield to event loop before blocking poll
596
596
  await new Promise(resolve => setImmediate(resolve));
597
597
  if (!ctx._e2eePollingActive) break;
598
598
 
599
- // Poll with 1 s timeoutreturns a typed event object, NOT an array
600
- const ev = await api.e2ee.pollEvents(1000);
599
+ // pollEvents returns { events: [...] } iterate the array
600
+ const result = await api.e2ee.pollEvents(1000);
601
601
  if (!ctx._e2eePollingActive) break;
602
602
 
603
- // No event / empty result
604
- if (!ev) continue;
603
+ // No events returned (timeout or empty)
604
+ if (!result || !Array.isArray(result.events) || result.events.length === 0) continue;
605
605
 
606
- const evType = (ev.type || '').toLowerCase();
606
+ for (const ev of result.events) {
607
+ if (!ctx._e2eePollingActive) break;
607
608
 
608
- // ── timeout: no event arrived during the poll window ──
609
- if (evType === 'timeout') continue;
609
+ const evType = (ev.type || '').toLowerCase();
610
610
 
611
- // ── closed: Go bridge shut down ──
612
- if (evType === 'closed') {
613
- utils.warn("E2EE", "Bridge closed. Stopping DM poll loop.");
614
- ctx._e2eePollingActive = false;
615
- break;
616
- }
611
+ // ── timeout: no event arrived during the poll window ──
612
+ if (evType === 'timeout') continue;
617
613
 
618
- // ── permanent error (e.g. session invalid) ──
619
- if (evType === 'error') {
620
- const msg = ev.data && ev.data.message ? ev.data.message : JSON.stringify(ev.data);
621
- utils.warn("E2EE", "Bridge error event:", msg);
622
- if (ev.data && ev.data.code === 1) {
614
+ // ── closed: bridge shut down ──
615
+ if (evType === 'closed') {
616
+ utils.warn("E2EE", "Bridge closed. Stopping DM poll loop.");
623
617
  ctx._e2eePollingActive = false;
624
618
  break;
625
619
  }
626
- continue;
627
- }
628
620
 
629
- // ── E2EE connection confirmed by the bridge ──
630
- if (evType === 'e2eeconnected') {
631
- utils.log("E2EE", "E2EE fully connected (bridge event).");
632
- continue;
633
- }
621
+ // ── permanent error (e.g. session invalid) ──
622
+ if (evType === 'error') {
623
+ const msg = ev.data && ev.data.message ? ev.data.message : JSON.stringify(ev.data);
624
+ utils.warn("E2EE", "Bridge error event:", msg);
625
+ if (ev.data && ev.data.code === 1) {
626
+ ctx._e2eePollingActive = false;
627
+ break;
628
+ }
629
+ continue;
630
+ }
634
631
 
635
- // ── Incoming E2EE DM ─────────────────────────────────
636
- if (evType === 'e2eemessage') {
637
- const d = ev.data;
638
- if (!d) continue;
639
- // threadId may be 0 for pure-JID threads — fall back to chatJid
640
- const chatJid = d.chatJid || '';
641
- const senderJid = d.senderJid || '';
642
- const threadID = String(d.threadId || chatJid.replace(/@.*/, '') || '');
643
- const senderID = String(d.senderId || senderJid.replace(/@.*/, '') || '');
644
- if (!threadID || !senderID) {
645
- utils.log("E2EE", "e2eeMessage missing IDs — raw:", JSON.stringify(d).slice(0, 300));
632
+ // ── E2EE connection confirmed by the bridge ──
633
+ if (evType === 'e2eeconnected') {
634
+ utils.log("E2EE", "E2EE fully connected (bridge event).");
646
635
  continue;
647
636
  }
648
- if (senderID === ctx.userID.toString() && !ctx.globalOptions.selfListen) continue;
649
-
650
- utils.log("E2EE", "Incoming E2EE DM from", senderID, "→ thread", threadID, "body:", JSON.stringify(d.text || '').slice(0, 80));
651
-
652
- const fmtMsg = {
653
- type: 'message',
654
- senderID: utils.formatID(senderID),
655
- body: d.text || '',
656
- threadID: utils.formatID(threadID),
657
- messageID: d.id || '',
658
- isGroup: false,
659
- attachments: [],
660
- mentions: {},
661
- timestamp: Number(d.timestampMs || Date.now()),
662
- isUnread: true,
663
- };
664
- if (ctx.globalOptions.autoMarkDelivery) {
665
- try { api.markAsDelivered(fmtMsg.threadID, fmtMsg.messageID); } catch (_) {}
637
+
638
+ // ── Incoming E2EE DM ─────────────────────────────────
639
+ if (evType === 'e2eemessage') {
640
+ const d = ev.data;
641
+ if (!d) continue;
642
+ // threadId may be 0 for pure-JID threads — fall back to chatJid
643
+ const chatJid = d.chatJid || '';
644
+ const senderJid = d.senderJid || '';
645
+ const threadID = String(d.threadId || chatJid.replace(/@.*/, '') || '');
646
+ const senderID = String(d.senderId || senderJid.replace(/@.*/, '') || '');
647
+ if (!threadID || !senderID) {
648
+ utils.log("E2EE", "e2eeMessage missing IDs — raw:", JSON.stringify(d).slice(0, 300));
649
+ continue;
650
+ }
651
+ if (senderID === ctx.userID.toString() && !ctx.globalOptions.selfListen) continue;
652
+
653
+ utils.log("E2EE", "Incoming E2EE DM from", senderID, "→ thread", threadID, "body:", JSON.stringify(d.text || '').slice(0, 80));
654
+
655
+ const fmtMsg = {
656
+ type: 'message',
657
+ senderID: utils.formatID(senderID),
658
+ body: d.text || '',
659
+ threadID: utils.formatID(threadID),
660
+ messageID: d.id || '',
661
+ isGroup: false,
662
+ attachments: [],
663
+ mentions: {},
664
+ timestamp: Number(d.timestampMs || Date.now()),
665
+ isUnread: true,
666
+ };
667
+ if (ctx.globalOptions.autoMarkDelivery) {
668
+ try { api.markAsDelivered(fmtMsg.threadID, fmtMsg.messageID); } catch (_) {}
669
+ }
670
+ if (ctx.globalOptions.autoMarkRead) {
671
+ try { api.markAsRead(fmtMsg.threadID); } catch (_) {}
672
+ }
673
+ globalCallback(null, fmtMsg);
674
+ continue;
666
675
  }
667
- if (ctx.globalOptions.autoMarkRead) {
668
- try { api.markAsRead(fmtMsg.threadID); } catch (_) {}
676
+
677
+ // ── Incoming regular (non-E2EE) message via bridge ───
678
+ if (evType === 'message') {
679
+ const d = ev.data;
680
+ if (!d) continue;
681
+ const threadID = String(d.threadId || '');
682
+ const senderID = String(d.senderId || '');
683
+ if (!threadID || !senderID) continue;
684
+ if (senderID === ctx.userID.toString() && !ctx.globalOptions.selfListen) continue;
685
+ globalCallback(null, {
686
+ type: 'message',
687
+ senderID: utils.formatID(senderID),
688
+ body: d.text || '',
689
+ threadID: utils.formatID(threadID),
690
+ messageID: d.id || '',
691
+ isGroup: !!(d.isGroup),
692
+ attachments: [],
693
+ mentions: {},
694
+ timestamp: Number(d.timestampMs || Date.now()),
695
+ isUnread: true,
696
+ });
697
+ continue;
669
698
  }
670
- globalCallback(null, fmtMsg);
671
- continue;
672
- }
673
699
 
674
- // ── Incoming regular (non-E2EE) message via bridge ───
675
- if (evType === 'message') {
676
- const d = ev.data;
677
- if (!d) continue;
678
- const threadID = String(d.threadId || '');
679
- const senderID = String(d.senderId || '');
680
- if (!threadID || !senderID) continue;
681
- if (senderID === ctx.userID.toString() && !ctx.globalOptions.selfListen) continue;
682
- globalCallback(null, {
683
- type: 'message',
684
- senderID: utils.formatID(senderID),
685
- body: d.text || '',
686
- threadID: utils.formatID(threadID),
687
- messageID: d.id || '',
688
- isGroup: !!(d.isGroup),
689
- attachments: [],
690
- mentions: {},
691
- timestamp: Number(d.timestampMs || Date.now()),
692
- isUnread: true,
693
- });
694
- continue;
695
- }
700
+ // ── E2EE reaction ────────────────────────────────────
701
+ if (evType === 'e2eereaction') {
702
+ if (!ctx.globalOptions.listenEvents) continue;
703
+ const d = ev.data;
704
+ if (!d) continue;
705
+ const chatJid = d.chatJid || '';
706
+ const senderJid = d.senderJid || '';
707
+ globalCallback(null, {
708
+ type: 'message_reaction',
709
+ threadID: utils.formatID(chatJid.replace(/@.*/, '')),
710
+ messageID: d.messageId || '',
711
+ reaction: d.reaction || '',
712
+ senderID: utils.formatID(senderJid.replace(/@.*/, '')),
713
+ offlineThreadingId: null,
714
+ timestamp: Date.now(),
715
+ isGroup: false,
716
+ });
717
+ continue;
718
+ }
696
719
 
697
- // ── E2EE reaction ────────────────────────────────────
698
- if (evType === 'e2eereaction') {
699
- if (!ctx.globalOptions.listenEvents) continue;
700
- const d = ev.data;
701
- if (!d) continue;
702
- const chatJid = d.chatJid || '';
703
- const senderJid = d.senderJid || '';
704
- globalCallback(null, {
705
- type: 'message_reaction',
706
- threadID: utils.formatID(chatJid.replace(/@.*/, '')),
707
- messageID: d.messageId || '',
708
- reaction: d.reaction || '',
709
- senderID: utils.formatID(senderJid.replace(/@.*/, '')),
710
- offlineThreadingId: null,
711
- timestamp: Date.now(),
712
- isGroup: false,
713
- });
714
- continue;
720
+ // ready / reconnected / disconnected / deviceDataChanged / raw → ignore silently
715
721
  }
716
722
 
717
- // ready / reconnected / disconnected / deviceDataChanged / raw → ignore silently
718
-
719
723
  } catch (pollErr) {
720
724
  if (!ctx._e2eePollingActive) break;
721
725
  utils.warn("E2EE", "pollEvents error:", pollErr && pollErr.message ? pollErr.message : pollErr);
@@ -4,7 +4,10 @@
4
4
  * Lightweight E2EE bridge — delegates to the `meta-messenger.js` npm package.
5
5
  *
6
6
  * Our postinstall replaces meta-messenger.js's binary with our TLS-fixed build
7
- * so that prekey HTTPS requests succeed in sandboxed environments (Replit, Docker).
7
+ * so that prekey HTTPS requests succeed in sandboxed environments (Replit, Docker,
8
+ * Railway, etc.). We also patch at runtime (ensureTlsFixedBinary) so the fix
9
+ * applies even when postinstall was skipped (npm ci --ignore-scripts, Railway
10
+ * production installs, etc.).
8
11
  *
9
12
  * Key design decisions:
10
13
  * - enableE2EE: false → we call connectE2EE() explicitly; no auto-start race
@@ -12,12 +15,83 @@
12
15
  * - devicePath defaults to ".nkxfca_e2ee_device.json" in cwd when not provided
13
16
  */
14
17
 
18
+ const fs = require('fs');
19
+ const path = require('path');
20
+
21
+ // ── Runtime binary patcher ────────────────────────────────────────────────────
22
+ // Ensures the TLS-fixed binary is in place before meta-messenger.js is loaded.
23
+ // Runs once; safe to call multiple times.
24
+
25
+ let _patchDone = false;
26
+
27
+ function _platformKey() {
28
+ const p = process.platform;
29
+ const a = process.arch;
30
+ if (p === 'linux' && a === 'x64') return 'linux-x64-gnu';
31
+ if (p === 'linux' && a === 'arm64') return 'linux-arm64-gnu';
32
+ if (p === 'darwin' && a === 'x64') return 'darwin-x64';
33
+ if (p === 'darwin' && a === 'arm64') return 'darwin-arm64';
34
+ if (p === 'win32' && a === 'x64') return 'win32-x64-msvc';
35
+ return null;
36
+ }
37
+
38
+ function _binaryExt() {
39
+ if (process.platform === 'win32') return '.dll';
40
+ if (process.platform === 'darwin') return '.dylib';
41
+ return '.so';
42
+ }
43
+
44
+ function ensureTlsFixedBinary() {
45
+ if (_patchDone) return;
46
+ _patchDone = true;
47
+
48
+ if (process.env.NKXFCA_SKIP_POSTINSTALL === 'true') return;
49
+
50
+ const key = _platformKey();
51
+ if (!key) return;
52
+
53
+ const ext = _binaryExt();
54
+ // bridge.js lives at src/e2ee/bridge.js → prebuilt/ is two levels up
55
+ const ourBin = path.join(__dirname, '..', '..', 'prebuilt', key, 'messagix' + ext);
56
+ if (!fs.existsSync(ourBin)) return;
57
+
58
+ try {
59
+ const pkgJson = require.resolve('meta-messenger.js/package.json');
60
+ const buildDir = path.join(path.dirname(pkgJson), 'build');
61
+ const mmBin = path.join(buildDir, 'messagix' + ext);
62
+
63
+ fs.mkdirSync(buildDir, { recursive: true });
64
+
65
+ // Only copy if sizes differ (avoids unnecessary writes on every boot)
66
+ let needsCopy = true;
67
+ if (fs.existsSync(mmBin)) {
68
+ needsCopy = fs.statSync(ourBin).size !== fs.statSync(mmBin).size;
69
+ }
70
+
71
+ if (needsCopy) {
72
+ fs.copyFileSync(ourBin, mmBin);
73
+ fs.chmodSync(mmBin, 0o755);
74
+ console.log('[nkxfca] runtime patch: applied TLS-fixed binary (' + key + ')');
75
+ }
76
+ } catch (err) {
77
+ // Non-fatal — warn so the user knows why E2EE may not work
78
+ console.warn('[nkxfca] runtime patch failed (' + err.message + '). E2EE TLS errors may occur in sandboxed environments.');
79
+ }
80
+ }
81
+
82
+ // ─────────────────────────────────────────────────────────────────────────────
83
+
15
84
  let _Client = null;
16
85
  let _loadError = null;
17
86
 
18
87
  function loadClient() {
19
88
  if (_Client) return _Client;
20
89
  if (_loadError) throw _loadError;
90
+
91
+ // Patch binary BEFORE the first require('meta-messenger.js') so the
92
+ // TLS-fixed .so/.dylib/.dll is loaded by Node rather than the original.
93
+ ensureTlsFixedBinary();
94
+
21
95
  try {
22
96
  const mm = require('meta-messenger.js');
23
97
  _Client = mm.Client || mm.default?.Client;