nodejs-insta-private-api-mqtt 1.3.29 → 1.3.30
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/dist/realtime/realtime.client.js +49 -12
- package/package.json +1 -1
|
@@ -1,24 +1,30 @@
|
|
|
1
|
-
// realtime.client.js
|
|
2
1
|
'use strict';
|
|
3
2
|
|
|
4
3
|
/*
|
|
5
4
|
RealtimeClient
|
|
6
5
|
--------------
|
|
7
6
|
This file implements the RealtimeClient which manages:
|
|
8
|
-
- constructing the FBNS/MQTT connection payload
|
|
7
|
+
- constructing the FBNS/MQTT connection payload (Thrift)
|
|
9
8
|
- starting the MQTT client (MQTToTClient)
|
|
10
9
|
- attaching lifecycle handlers (connect/close/error)
|
|
11
10
|
- keepalives, message-sync refresh and traffic watchdogs
|
|
12
11
|
- wiring MQTT messages into higher-level events (message, iris, receive)
|
|
13
|
-
|
|
12
|
+
|
|
13
|
+
The implementation keeps original structure while applying compatibility tweaks:
|
|
14
|
+
- persistent clientMqttSessionId and client_context handling
|
|
15
|
+
- robust sessionid / mqttJwt / deviceSecret fallbacks
|
|
16
|
+
- slightly adjusted appSpecificInfo to match mobile client fields
|
|
17
|
+
- uses mqttot.MQTToTConnection to build a thrift connection payload
|
|
18
|
+
- MQTT URL remains 'edge-mqtt.facebook.com' (Instagram/Meta edge host)
|
|
19
|
+
Comments are in English next to logic so you can follow what's happening.
|
|
14
20
|
*/
|
|
15
21
|
|
|
16
|
-
//
|
|
22
|
+
// Keep module imports similar to your original code
|
|
17
23
|
const constants_1 = require("../constants");
|
|
18
24
|
const commands_1 = require("./commands");
|
|
19
25
|
const shared_1 = require("../shared");
|
|
20
26
|
const mqttot_1 = require("../mqttot");
|
|
21
|
-
//
|
|
27
|
+
// Use mqtts for errors / IllegalStateError compatibility
|
|
22
28
|
const mqtts_1 = require("mqtts");
|
|
23
29
|
const errors_1 = require("../errors");
|
|
24
30
|
const eventemitter3_1 = require("eventemitter3");
|
|
@@ -32,7 +38,7 @@ const gap_handler_1 = require("./features/gap-handler");
|
|
|
32
38
|
const enhanced_direct_commands_1 = require("./commands/enhanced.direct.commands");
|
|
33
39
|
const presence_typing_mixin_1 = require("./mixins/presence-typing.mixin");
|
|
34
40
|
|
|
35
|
-
// Use INSTAGRAM_VERSION exported from mqttot so it is applied automatically
|
|
41
|
+
// Use INSTAGRAM_VERSION exported from mqttot so it is applied automatically where available
|
|
36
42
|
const INSTAGRAM_VERSION = mqttot_1.INSTAGRAM_VERSION;
|
|
37
43
|
|
|
38
44
|
/**
|
|
@@ -57,6 +63,9 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
57
63
|
this.realtimeDebug = (0, shared_1.debugChannel)('realtime');
|
|
58
64
|
this.messageDebug = this.realtimeDebug.extend('message');
|
|
59
65
|
|
|
66
|
+
// enhanced direct commands debug (exposed for compatibility with the enhanced commands)
|
|
67
|
+
this.enhancedDebug = this.realtimeDebug.extend('enhanced-commands');
|
|
68
|
+
|
|
60
69
|
// safeDisconnect flag used when user intentionally disconnects
|
|
61
70
|
this.safeDisconnect = false;
|
|
62
71
|
|
|
@@ -81,6 +90,10 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
81
90
|
// apply mixins to this instance (keeps modular features separated)
|
|
82
91
|
(0, mixins_1.applyMixins)(mixins, this, this.ig);
|
|
83
92
|
|
|
93
|
+
// Default subscriptions (force-enable if saved ones are empty)
|
|
94
|
+
this.defaultGraphQlSubs = ['ig_sub_direct', 'ig_sub_direct_v2_message_sync'];
|
|
95
|
+
this.defaultSkywalkerSubs = ['presence_subscribe', 'typing_subscribe'];
|
|
96
|
+
|
|
84
97
|
// internal flags & timers
|
|
85
98
|
this._attachedAuthState = null;
|
|
86
99
|
this._messageSyncAttached = false;
|
|
@@ -314,6 +327,7 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
314
327
|
* - Pulls deviceId, sessionid, device secrets and app-specific headers to populate the payload.
|
|
315
328
|
*/
|
|
316
329
|
constructConnection() {
|
|
330
|
+
// Choose the best available user agent value from state fallbacks
|
|
317
331
|
const userAgent =
|
|
318
332
|
typeof this.ig.state.userAgent === 'string'
|
|
319
333
|
? this.ig.state.userAgent
|
|
@@ -323,8 +337,10 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
323
337
|
? this.ig.state.deviceString
|
|
324
338
|
: 'Instagram 155.0.0.37.107 Android';
|
|
325
339
|
|
|
340
|
+
// deviceId / phoneId fallback handling (string coercion)
|
|
326
341
|
const deviceId = String(this.ig.state.phoneId || this.ig.state.deviceId || 'device_unknown');
|
|
327
342
|
|
|
343
|
+
// attempt to extract sessionid from various locations: Authorization JWT, cookie helpers, state fields, or cookie jar
|
|
328
344
|
let sessionid = null;
|
|
329
345
|
try {
|
|
330
346
|
sessionid = this.extractSessionIdFromJWT();
|
|
@@ -354,12 +370,14 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
354
370
|
} catch (e) {}
|
|
355
371
|
}
|
|
356
372
|
|
|
373
|
+
// fallback sessionid generation — only used if nothing else found
|
|
357
374
|
if (!sessionid) {
|
|
358
375
|
const userId = this.ig.state.cookieUserId || this.ig.state.userId || '0';
|
|
359
376
|
sessionid = String(userId) + '_' + Date.now();
|
|
360
377
|
this.realtimeDebug(`SessionID generated (fallback): ${sessionid}`);
|
|
361
378
|
}
|
|
362
379
|
|
|
380
|
+
// device secret retrieval (from attached auth helper or state)
|
|
363
381
|
let deviceSecret = null;
|
|
364
382
|
try {
|
|
365
383
|
if (this._attachedAuthState && typeof this._attachedAuthState.getData === 'function') {
|
|
@@ -388,6 +406,7 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
388
406
|
if (!mqttJwt && this.ig.state.mqttJwt) mqttJwt = this.ig.state.mqttJwt;
|
|
389
407
|
} catch (e) {}
|
|
390
408
|
|
|
409
|
+
// password is either "jwt=..." or "sessionid=..."
|
|
391
410
|
let password;
|
|
392
411
|
if (mqttJwt) {
|
|
393
412
|
password = `jwt=${mqttJwt}`;
|
|
@@ -395,9 +414,10 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
395
414
|
password = `sessionid=${sessionid}`;
|
|
396
415
|
}
|
|
397
416
|
|
|
417
|
+
// client type indicates if device secret is available
|
|
398
418
|
const clientType = deviceSecret ? 'secure_cookie_auth' : 'cookie_auth';
|
|
399
419
|
|
|
400
|
-
// IMPORTANT: keep clientMqttSessionId persistent across reconnects
|
|
420
|
+
// IMPORTANT: keep clientMqttSessionId persistent across reconnects (already set in constructor)
|
|
401
421
|
if (!this._clientMqttSessionId) {
|
|
402
422
|
try {
|
|
403
423
|
this._clientMqttSessionId = (BigInt(Date.now()) & BigInt(0xffffffff));
|
|
@@ -405,19 +425,21 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
405
425
|
this._clientMqttSessionId = BigInt(0);
|
|
406
426
|
}
|
|
407
427
|
}
|
|
408
|
-
|
|
409
428
|
const clientMqttSessionId = this._clientMqttSessionId;
|
|
410
429
|
|
|
430
|
+
// numeric topics Instagram uses for subscription mapping (kept consistent)
|
|
411
431
|
const subscribeTopics = [88, 135, 149, 150, 133, 146];
|
|
412
432
|
|
|
413
433
|
// Build the thrift connection object using mqttot.MQTToTConnection
|
|
434
|
+
// NOTE: use deviceId.substring(0,20) for clientIdentifier because the mobile app often truncates it.
|
|
435
|
+
// endpointCapabilities set to 128 for broader compatibility (some clients use 0, 128 provides better capability advertising).
|
|
414
436
|
this.connection = new mqttot_1.MQTToTConnection({
|
|
415
437
|
clientIdentifier: deviceId.substring(0, 20),
|
|
416
438
|
clientInfo: {
|
|
417
439
|
userId: BigInt(Number(this.ig.state.cookieUserId || this.ig.state.userId || 0)),
|
|
418
440
|
userAgent,
|
|
419
441
|
clientCapabilities: 183,
|
|
420
|
-
endpointCapabilities:
|
|
442
|
+
endpointCapabilities: 128,
|
|
421
443
|
publishFormat: 1,
|
|
422
444
|
noAutomaticForeground: false,
|
|
423
445
|
makeUserAvailableInForeground: true,
|
|
@@ -444,8 +466,13 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
444
466
|
video_call_participant_state_delivery: '17977239895057311',
|
|
445
467
|
presence_subscribe: '17846944882223835',
|
|
446
468
|
}),
|
|
469
|
+
// Extra app-specific fields observed in the mobile APK (helps the server identify the client capabilities)
|
|
447
470
|
'User-Agent': userAgent,
|
|
448
471
|
'Accept-Language': (this.ig.state.language || 'en_US').replace('_', '-'),
|
|
472
|
+
platform: 'android',
|
|
473
|
+
ig_mqtt_route: 'django',
|
|
474
|
+
pubsub_msg_type_blacklist: 'direct, typing_type',
|
|
475
|
+
auth_cache_enabled: '0',
|
|
449
476
|
},
|
|
450
477
|
});
|
|
451
478
|
}
|
|
@@ -557,7 +584,7 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
557
584
|
this._syncTimer = setInterval(async () => {
|
|
558
585
|
try {
|
|
559
586
|
if (!this.commands) return;
|
|
560
|
-
const subs = (this.initOptions && this.initOptions.graphQlSubs && this.initOptions.graphQlSubs.length) ? this.initOptions.graphQlSubs :
|
|
587
|
+
const subs = (this.initOptions && this.initOptions.graphQlSubs && this.initOptions.graphQlSubs.length) ? this.initOptions.graphQlSubs : this.defaultGraphQlSubs;
|
|
561
588
|
await this.graphQlSubscribe(subs);
|
|
562
589
|
this.realtimeDebug('[WATCHDOG] MESSAGE_SYNC refreshed.');
|
|
563
590
|
} catch (e) {
|
|
@@ -620,6 +647,9 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
620
647
|
await (0, shared_1.delay)(100);
|
|
621
648
|
if (this.initOptions.graphQlSubs && this.initOptions.graphQlSubs.length > 0) {
|
|
622
649
|
await this.graphQlSubscribe(this.initOptions.graphQlSubs);
|
|
650
|
+
} else {
|
|
651
|
+
// ensure defaults if none provided
|
|
652
|
+
await this.graphQlSubscribe(this.defaultGraphQlSubs);
|
|
623
653
|
}
|
|
624
654
|
if (this.initOptions.irisData) {
|
|
625
655
|
await this.irisSubscribe(this.initOptions.irisData);
|
|
@@ -637,6 +667,9 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
637
667
|
}
|
|
638
668
|
if ((this.initOptions.skywalkerSubs ?? []).length > 0) {
|
|
639
669
|
await this.skywalkerSubscribe(this.initOptions.skywalkerSubs);
|
|
670
|
+
} else {
|
|
671
|
+
// ensure default skywalker subs if none provided
|
|
672
|
+
await this.skywalkerSubscribe(this.defaultSkywalkerSubs);
|
|
640
673
|
}
|
|
641
674
|
await (0, shared_1.delay)(100);
|
|
642
675
|
try {
|
|
@@ -790,8 +823,8 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
790
823
|
}
|
|
791
824
|
|
|
792
825
|
const connectOptions = {
|
|
793
|
-
graphQlSubs: options.graphQlSubs || savedOptions.graphQlSubs ||
|
|
794
|
-
skywalkerSubs: options.skywalkerSubs || savedOptions.skywalkerSubs ||
|
|
826
|
+
graphQlSubs: options.graphQlSubs || savedOptions.graphQlSubs || this.defaultGraphQlSubs,
|
|
827
|
+
skywalkerSubs: options.skywalkerSubs || savedOptions.skywalkerSubs || this.defaultSkywalkerSubs,
|
|
795
828
|
irisData,
|
|
796
829
|
...options
|
|
797
830
|
};
|
|
@@ -872,6 +905,8 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
872
905
|
if (!this.commands) {
|
|
873
906
|
throw new mqtts_1.IllegalStateError('connect() must be called before graphQlSubscribe()');
|
|
874
907
|
}
|
|
908
|
+
// If the caller provided an empty array, ensure defaults are used
|
|
909
|
+
if (Array.isArray(sub) && sub.length === 0) sub = this.defaultGraphQlSubs;
|
|
875
910
|
this.realtimeDebug(`Subscribing with GraphQL to ${sub.join(', ')}`);
|
|
876
911
|
return this.commands.updateSubscriptions({
|
|
877
912
|
topic: constants_1.Topics.REALTIME_SUB,
|
|
@@ -890,6 +925,8 @@ class RealtimeClient extends eventemitter3_1.EventEmitter {
|
|
|
890
925
|
if (!this.commands) {
|
|
891
926
|
throw new mqtts_1.IllegalStateError('connect() must be called before skywalkerSubscribe()');
|
|
892
927
|
}
|
|
928
|
+
// If empty, use defaults
|
|
929
|
+
if (Array.isArray(sub) && sub.length === 0) sub = this.defaultSkywalkerSubs;
|
|
893
930
|
this.realtimeDebug(`Subscribing with Skywalker to ${sub.join(', ')}`);
|
|
894
931
|
return this.commands.updateSubscriptions({
|
|
895
932
|
topic: constants_1.Topics.PUBSUB,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodejs-insta-private-api-mqtt",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.30",
|
|
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": {
|