nodejs-insta-private-api-mqtt 1.3.35 → 1.3.36

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.
@@ -105,6 +105,10 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
105
105
  this._reconnectDebounceMs = 500;
106
106
  this._reconnectTimeoutId = null;
107
107
 
108
+ // MQTT session tracking & persistence
109
+ this._mqttSessionId = null; // actual server-provided mqtt session id (string)
110
+ this._mqttSessionPersistIntervalId = null; // periodic persist interval handler
111
+
108
112
  // Persisted identity items that must survive reconnects:
109
113
  // - clientMqttSessionId must NOT be re-generated each connect
110
114
  // - _clientContext for EnhancedDirectCommands (for message identity)
@@ -488,6 +492,8 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
488
492
  this.constructConnection();
489
493
  const { MQTToTClient } = require("../mqttot");
490
494
  const { compressDeflate } = require("../shared");
495
+ const fs = require('fs');
496
+ const path = require('path');
491
497
 
492
498
  // Create the MQTT client used by the runtime.
493
499
  // requirePayload set to false to avoid treating empty CONNACK payload as fatal.
@@ -508,7 +514,18 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
508
514
  try {
509
515
  this._mqtt.on('connect', async () => {
510
516
  this.realtimeDebug('[MQTT] client emitted connect');
511
- try { await this._afterConnectHandlers(); } catch (e) { this.realtimeDebug('[MQTT] afterConnect error', e?.message || e); }
517
+ try {
518
+ // After normal after-connect handlers, try extract session id and persist it
519
+ await this._afterConnectHandlers();
520
+ } catch (e) {
521
+ this.realtimeDebug('[MQTT] afterConnect error', e?.message || e);
522
+ }
523
+ // After everything, attempt to detect and persist MQTT session id
524
+ try {
525
+ await this._onMqttConnected();
526
+ } catch (e) {
527
+ this.realtimeDebug('[MQTT] _onMqttConnected error', e?.message || e);
528
+ }
512
529
  });
513
530
  } catch (e) {}
514
531
  try {
@@ -516,6 +533,9 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
516
533
  this._mqtt.on('close', async () => {
517
534
  this.realtimeDebug('[MQTT] client close event');
518
535
  this._lastMessageAt = Date.now();
536
+ // persist session (last state) on close
537
+ try { await this._persistMqttSession(); } catch (e) {}
538
+ this.emit('mqtt_disconnected');
519
539
  if (this._reconnectTimeoutId) clearTimeout(this._reconnectTimeoutId);
520
540
  this._reconnectTimeoutId = setTimeout(async () => {
521
541
  try { await this._attemptReconnectSafely(); } catch (e) {}
@@ -526,6 +546,7 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
526
546
  // handle error -> schedule reconnect attempt with debounce
527
547
  this._mqtt.on('error', (err) => {
528
548
  this.realtimeDebug('[MQTT] client error:', err?.message || err);
549
+ this.emit('mqtt_error', err);
529
550
  if (this._reconnectTimeoutId) clearTimeout(this._reconnectTimeoutId);
530
551
  this._reconnectTimeoutId = setTimeout(async () => {
531
552
  try { await this._attemptReconnectSafely(); } catch (e) {}
@@ -545,6 +566,7 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
545
566
 
546
567
  // Notify higher-level code that we are connected
547
568
  this.emit('connected');
569
+ this.emit('mqtt_connected');
548
570
 
549
571
  // WATCHDOG / KEEPALIVE / TRAFFIC MONITOR
550
572
  try {
@@ -684,6 +706,121 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
684
706
  this._setupMessageHandlers();
685
707
  }
686
708
 
709
+ /**
710
+ * Attempt to detect server-provided MQTT session id and persist it.
711
+ * This method is defensive: it tries multiple places on the mqtt client object.
712
+ */
713
+ async _onMqttConnected() {
714
+ try {
715
+ let found = null;
716
+ try {
717
+ const mqtt = this._mqtt;
718
+ if (mqtt) {
719
+ // try common accessor first
720
+ if (typeof mqtt.getSessionId === 'function') {
721
+ try { found = mqtt.getSessionId(); } catch (e) {}
722
+ }
723
+ // try common property names (defensive)
724
+ if (!found && mqtt.sessionId) found = mqtt.sessionId;
725
+ if (!found && mqtt._sessionId) found = mqtt._sessionId;
726
+ // some clients keep last connack info
727
+ if (!found && mqtt.lastConnack && mqtt.lastConnack.sessionId) found = mqtt.lastConnack.sessionId;
728
+ if (!found && mqtt.connack && mqtt.connack.sessionId) found = mqtt.connack.sessionId;
729
+ // fallback to connection.clientInfo.clientMqttSessionId (local id)
730
+ if (!found && this.connection && this.connection.clientInfo && this.connection.clientInfo.clientMqttSessionId) {
731
+ try { found = String(this.connection.clientInfo.clientMqttSessionId); } catch (e) {}
732
+ }
733
+ }
734
+ } catch (e) {}
735
+ // If no server-provided id was found, fall back to the persistent client id (if present) or 'boot'
736
+ if (!found) {
737
+ if (this._clientMqttSessionId) {
738
+ try {
739
+ found = String(this._clientMqttSessionId);
740
+ this.realtimeDebug('[MQTT] No server mqttSessionId yet — falling back to clientMqttSessionId.');
741
+ } catch (e) {
742
+ // ignore and keep found null
743
+ }
744
+ } else {
745
+ // final fallback
746
+ found = 'boot';
747
+ this.realtimeDebug('[MQTT] No mqttSessionId available — using boot fallback.');
748
+ }
749
+ }
750
+ if (found) {
751
+ this._mqttSessionId = String(found);
752
+ this.realtimeDebug(`[MQTT] detected mqttSessionId: ${this._mqttSessionId}`);
753
+ // emit event for consumers
754
+ try { this.emit('mqtt_session', this._mqttSessionId); } catch (e) {}
755
+ // persist it right away
756
+ try { await this._persistMqttSession(); } catch (e) { this.realtimeDebug('[MQTT] persist after connect failed', e?.message || e); }
757
+ // start periodic persist if not already (persist every 30s)
758
+ if (!this._mqttSessionPersistIntervalId) {
759
+ try {
760
+ this._mqttSessionPersistIntervalId = setInterval(() => {
761
+ try { this._persistMqttSession(); } catch (e) {}
762
+ }, 30 * 1000); // every 30s
763
+ } catch (e) {}
764
+ }
765
+ } else {
766
+ this.realtimeDebug('[MQTT] mqttSessionId not found on client after connect (will attempt again on subsequent connects)');
767
+ }
768
+ } catch (e) {
769
+ this.realtimeDebug('[MQTT] _onMqttConnected fatal', e?.message || e);
770
+ }
771
+ }
772
+
773
+ /**
774
+ * Persist mqtt session details locally and via attached auth helper if available.
775
+ * Writes ./authinfo_instagram/mqtt-session.json as a local backup.
776
+ */
777
+ async _persistMqttSession() {
778
+ try {
779
+ const fs = require('fs');
780
+ const path = require('path');
781
+ const folder = './authinfo_instagram';
782
+ try {
783
+ if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
784
+ } catch (e) {}
785
+
786
+ // IMPORTANT: prefer server-provided mqtt session id when available.
787
+ // Fallback order:
788
+ // 1) this._mqttSessionId (server-provided)
789
+ // 2) this._clientMqttSessionId (client-generated persistent id)
790
+ // 3) 'boot'
791
+ const obj = {
792
+ sessionId: this._mqttSessionId || null,
793
+ mqttSessionId: this._mqttSessionId ? String(this._mqttSessionId) : (this._clientMqttSessionId ? String(this._clientMqttSessionId) : 'boot'),
794
+ lastConnected: new Date().toISOString(),
795
+ userId: String(this.ig?.state?.cookieUserId || this.ig?.state?.userId || '')
796
+ };
797
+
798
+ // If an auth helper supports saveMqttSession, call that first (so it can save to the canonical auth state)
799
+ try {
800
+ if (this._attachedAuthState && typeof this._attachedAuthState.saveMqttSession === 'function') {
801
+ try {
802
+ // Many helpers expect the realtime client instance
803
+ await this._attachedAuthState.saveMqttSession(this);
804
+ this.realtimeDebug('[MQTT] authState.saveMqttSession called');
805
+ } catch (e) {
806
+ this.realtimeDebug('[MQTT] authState.saveMqttSession failed', e?.message || e);
807
+ }
808
+ }
809
+ } catch (e) {}
810
+
811
+ // Always write local backup file
812
+ try {
813
+ fs.writeFileSync(path.join(folder, 'mqtt-session.json'), JSON.stringify(obj, null, 2));
814
+ this.realtimeDebug('[MQTT] mqtt-session.json written locally');
815
+ } catch (e) {
816
+ this.realtimeDebug('[MQTT] failed writing mqtt-session.json', e?.message || e);
817
+ }
818
+ } catch (e) {
819
+ // swallow errors to not break main flow
820
+ this.realtimeDebug('[MQTT] _persistMqttSession error', e?.message || e);
821
+ }
822
+ }
823
+
687
824
  /**
688
825
  * _attemptReconnectSafely()
689
826
  * - Ensure only a single reconnect flow runs at once.
@@ -892,7 +1029,14 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
892
1029
  clearInterval(this._trafficWatchdog);
893
1030
  this._trafficWatchdog = null;
894
1031
  }
1032
+ // clear periodic mqtt persist
1033
+ if (this._mqttSessionPersistIntervalId) {
1034
+ clearInterval(this._mqttSessionPersistIntervalId);
1035
+ this._mqttSessionPersistIntervalId = null;
1036
+ }
895
1037
  } catch (e) {}
1038
+ // persist final session snapshot
1039
+ try { this._persistMqttSession(); } catch (e) {}
896
1040
  return this.mqtt?.disconnect() ?? Promise.resolve();
897
1041
  }
898
1042
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-insta-private-api-mqtt",
3
- "version": "1.3.35",
3
+ "version": "1.3.36",
4
4
  "description": "Complete Instagram MQTT protocol with FULL iOS + Android support. 33 device presets (21 iOS + 12 Android). iPhone 16/15/14/13/12, iPad Pro, Samsung, Pixel, Huawei. Real-time DM messaging, view-once media extraction, sub-500ms latency.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 KunBORUTO20(INSTAGRAM MQTT )
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.