nodejs-insta-private-api-mqtt 1.3.16 → 1.3.18
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/README.md +44 -26
- package/dist/fbns/fbns.client.js +1 -1
- package/dist/mqtt-shim.d.ts +96 -0
- package/dist/mqtt-shim.js +337 -0
- package/dist/mqttot/mqttot.client.d.ts +1 -1
- package/dist/mqttot/mqttot.client.js +1 -1
- package/dist/mqttot/mqttot.connect.request.packet.d.ts +1 -1
- package/dist/mqttot/mqttot.connect.response.packet.d.ts +1 -1
- package/dist/mqttot/mqttot.connect.response.packet.js +1 -1
- package/dist/package.json +1 -1
- package/dist/realtime/commands/commands.d.ts +1 -1
- package/dist/realtime/commands/direct.commands.d.ts +1 -1
- package/dist/realtime/mixins/message-sync.mixin.js +1 -1
- package/dist/realtime/mixins/realtime-sub.mixin.js +1 -1
- package/dist/realtime/realtime.client.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -292,7 +292,7 @@ There are two practical, compatible flows you can use depending on your client h
|
|
|
292
292
|
2. Call the direct broadcast / configure_photo or configure_video HTTP endpoint to create the message server-side. MQTT will then deliver the server-created message to connected clients.
|
|
293
293
|
- Use this if you prefer to avoid relying on the realtime command to create messages.
|
|
294
294
|
|
|
295
|
-
> Summary: **Always rupload via HTTP.** Then
|
|
295
|
+
> Summary: **Always rupload via HTTP.** Then **use the HTTP configure/broadcast endpoints as the primary, reliable method** to attach media to threads. Publishing an MQTT `send_item` referencing `upload_id` may work as a best-effort fallback on some servers, but it is not guaranteed. MQTT never carries the raw media bytes, only metadata/reference.
|
|
296
296
|
|
|
297
297
|
---
|
|
298
298
|
|
|
@@ -422,7 +422,7 @@ await mqtt.publish({
|
|
|
422
422
|
**A:** No — MQTT is not used for large raw bytes. The app uploads bytes via rupload HTTP.
|
|
423
423
|
|
|
424
424
|
- **Q:** *If I publish the MQTT `send_item` with `upload_id`, will the message appear in the thread?*
|
|
425
|
-
**A:**
|
|
425
|
+
**A:** Sometimes the realtime server accepts an MQTT `send_item` referencing a valid `upload_id`, but this behavior is not universally reliable across server versions, accounts, or configurations. For production reliability prefer the HTTP broadcast/configure endpoints; keep MQTT reference as a best-effort fallback.
|
|
426
426
|
|
|
427
427
|
- **Q:** *Do I need to call `/direct_v2/threads/broadcast/...` if I published MQTT?*
|
|
428
428
|
**A:** Often not — the APK pattern uses MQTT for the attach request. However, for absolute compatibility or for older server behavior, the HTTP configure/broadcast endpoints are a safe fallback.
|
|
@@ -2197,27 +2197,49 @@ async function sendVideoAsMqttReference({ ig, mqtt, videoBuffer, threadId, capti
|
|
|
2197
2197
|
|
|
2198
2198
|
const serverUploadId = (uploadResponse && uploadResponse.upload_id) ? uploadResponse.upload_id : uploadId;
|
|
2199
2199
|
|
|
2200
|
-
//
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
topic: constants.Topics.SEND_MESSAGE.id,
|
|
2216
|
-
qosLevel: 1,
|
|
2217
|
-
payload,
|
|
2200
|
+
// ATTACH VIA HTTP BROADCAST (preferred, reliable)
|
|
2201
|
+
// Attempt REST broadcast first (most reliable). This will create the direct message server-side
|
|
2202
|
+
// and let MQTT/clients receive the created message as normal sync.
|
|
2203
|
+
try {
|
|
2204
|
+
const broadcastResponse = await ig.request.send({
|
|
2205
|
+
url: '/direct_v2/threads/broadcast/upload_photo/',
|
|
2206
|
+
method: 'POST',
|
|
2207
|
+
form: {
|
|
2208
|
+
upload_id: serverUploadId,
|
|
2209
|
+
action: 'send_item',
|
|
2210
|
+
thread_ids: JSON.stringify([String(threadId)]),
|
|
2211
|
+
caption: caption || '',
|
|
2212
|
+
client_context: clientContext,
|
|
2213
|
+
},
|
|
2214
|
+
timeout: 60000,
|
|
2218
2215
|
});
|
|
2219
|
-
|
|
2220
|
-
|
|
2216
|
+
return { upload_id: serverUploadId, broadcastResponse };
|
|
2217
|
+
} catch (err) {
|
|
2218
|
+
// If REST broadcast fails for transient reasons, fall back to attempting an MQTT reference publish.
|
|
2219
|
+
// NOTE: MQTT 'reference' publish is not guaranteed to be accepted on all server versions or accounts.
|
|
2220
|
+
// Keep it as a fallback only — the HTTP broadcast above is the recommended, reliable method.
|
|
2221
|
+
try {
|
|
2222
|
+
const json = JSON.stringify({
|
|
2223
|
+
action: 'send_item',
|
|
2224
|
+
thread_id: String(threadId),
|
|
2225
|
+
item_type: 'media',
|
|
2226
|
+
upload_id: serverUploadId,
|
|
2227
|
+
text: caption || '',
|
|
2228
|
+
client_context: clientContext,
|
|
2229
|
+
timestamp: Date.now(),
|
|
2230
|
+
});
|
|
2231
|
+
const payload = await compressDeflate(json);
|
|
2232
|
+
await mqtt.publish({
|
|
2233
|
+
topic: constants.Topics.SEND_MESSAGE.id,
|
|
2234
|
+
qosLevel: 1,
|
|
2235
|
+
payload,
|
|
2236
|
+
});
|
|
2237
|
+
return { upload_id: serverUploadId, mqttFallback: true };
|
|
2238
|
+
} catch (err2) {
|
|
2239
|
+
// last-resort: return upload id and both errors for debugging
|
|
2240
|
+
return { upload_id: serverUploadId, broadcastError: err?.message || String(err), mqttError: err2?.message || String(err2) };
|
|
2241
|
+
}
|
|
2242
|
+
}
|
|
2221
2243
|
}
|
|
2222
2244
|
```
|
|
2223
2245
|
|
|
@@ -2268,10 +2290,6 @@ async function sendVideoViaRestBroadcast({ ig, videoBuffer, threadId, caption =
|
|
|
2268
2290
|
}
|
|
2269
2291
|
```
|
|
2270
2292
|
|
|
2271
|
-
### FAQ notes
|
|
2272
|
-
- **Does MQTT send the file?** No — MQTT only transports the JSON reference (`upload_id`) telling the server to attach that already-uploaded file into the thread.
|
|
2273
|
-
- **Why use MQTT for reference instead of REST broadcast?** MQTT gives near-realtime messaging semantics; the server applies the `upload_id` to the thread (same result), but the heavy binary upload must be done via HTTP `rupload`.
|
|
2274
|
-
- **Can you skip rupload and only send MQTT?** No — server needs the binary available under the `upload_id`. If you send only MQTT without previously uploading, the server won't have the file to attach.
|
|
2275
2293
|
|
|
2276
2294
|
---
|
|
2277
2295
|
|
package/dist/fbns/fbns.client.js
CHANGED
|
@@ -6,7 +6,7 @@ const fbns_device_auth_1 = require("./fbns.device-auth");
|
|
|
6
6
|
const shared_1 = require("../shared");
|
|
7
7
|
const mqttot_1 = require("../mqttot");
|
|
8
8
|
const chance_1 = require("chance");
|
|
9
|
-
const mqtts_1 = require("
|
|
9
|
+
const mqtts_1 = require("../mqtt-shim");
|
|
10
10
|
const errors_1 = require("../errors");
|
|
11
11
|
const eventemitter3_1 = require("eventemitter3");
|
|
12
12
|
const fbns_utilities_1 = require("./fbns.utilities");
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
|
|
3
|
+
export class PacketType {
|
|
4
|
+
static Connect: number;
|
|
5
|
+
static ConnAck: number;
|
|
6
|
+
static Publish: number;
|
|
7
|
+
static PubAck: number;
|
|
8
|
+
static Subscribe: number;
|
|
9
|
+
static SubAck: number;
|
|
10
|
+
static Unsubscribe: number;
|
|
11
|
+
static UnsubAck: number;
|
|
12
|
+
static PingReq: number;
|
|
13
|
+
static PingResp: number;
|
|
14
|
+
static Disconnect: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class ConnectResponsePacket {
|
|
18
|
+
ackFlags: number;
|
|
19
|
+
returnCode: number;
|
|
20
|
+
payload?: Buffer;
|
|
21
|
+
get isSuccess(): boolean;
|
|
22
|
+
get errorName(): string | null;
|
|
23
|
+
constructor(ackFlags: number, returnCode: number, payload?: Buffer);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class IllegalStateError extends Error {}
|
|
27
|
+
|
|
28
|
+
export interface MqttMessage {
|
|
29
|
+
topic: string;
|
|
30
|
+
payload: Buffer;
|
|
31
|
+
qosLevel?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface MqttMessageOutgoing {
|
|
35
|
+
topic: string;
|
|
36
|
+
payload: Buffer;
|
|
37
|
+
qosLevel?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface PacketFlowFunc {
|
|
41
|
+
(success: (packet: any) => void, error: (error: Error) => void): {
|
|
42
|
+
start: () => any;
|
|
43
|
+
accept: (packet: any) => boolean;
|
|
44
|
+
next: (packet: any) => void;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export class MqttClient extends EventEmitter {
|
|
49
|
+
constructor(options: any);
|
|
50
|
+
connect(options?: any): Promise<void>;
|
|
51
|
+
publish(message: MqttMessageOutgoing): Promise<any>;
|
|
52
|
+
subscribe(topic: string, qos?: number): Promise<void>;
|
|
53
|
+
disconnect(): void;
|
|
54
|
+
topicMap: Map<string, any>;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class TlsTransport { constructor(options: any); }
|
|
58
|
+
export class SocksTlsTransport { constructor(options: any); }
|
|
59
|
+
|
|
60
|
+
export class PacketStream {
|
|
61
|
+
constructor(buffer: Buffer);
|
|
62
|
+
readByte(): number;
|
|
63
|
+
readStringAsBuffer(): Buffer;
|
|
64
|
+
readWord(): number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const DefaultPacketReadMap: any;
|
|
68
|
+
export const DefaultPacketWriteMap: any;
|
|
69
|
+
export function isConnAck(packet: any): boolean;
|
|
70
|
+
|
|
71
|
+
export interface ConnectRequestOptions {
|
|
72
|
+
payload?: Buffer;
|
|
73
|
+
keepAlive?: number;
|
|
74
|
+
[key: string]: any;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface DefaultPacketReadResultMap {
|
|
78
|
+
[key: number]: (stream: PacketStream, length: number) => any;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface DefaultPacketWriteOptions {
|
|
82
|
+
[key: string]: any;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface PacketWriteResult {
|
|
86
|
+
[key: string]: any;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export enum ConnectReturnCode {
|
|
90
|
+
ACCEPTED = 0,
|
|
91
|
+
UNACCEPTABLE_PROTOCOL_VERSION = 1,
|
|
92
|
+
IDENTIFIER_REJECTED = 2,
|
|
93
|
+
SERVER_UNAVAILABLE = 3,
|
|
94
|
+
BAD_USERNAME_OR_PASSWORD = 4,
|
|
95
|
+
NOT_AUTHORIZED = 5,
|
|
96
|
+
}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
const EventEmitter = require('events');
|
|
2
|
+
const tls = require('tls');
|
|
3
|
+
const net = require('net');
|
|
4
|
+
let SocksClient;
|
|
5
|
+
try { SocksClient = require('socks').SocksClient; } catch (e) {}
|
|
6
|
+
|
|
7
|
+
class PacketType {
|
|
8
|
+
static Connect = 1;
|
|
9
|
+
static ConnAck = 2;
|
|
10
|
+
static Publish = 3;
|
|
11
|
+
static PubAck = 4;
|
|
12
|
+
static Subscribe = 8;
|
|
13
|
+
static SubAck = 9;
|
|
14
|
+
static Unsubscribe = 10;
|
|
15
|
+
static UnsubAck = 11;
|
|
16
|
+
static PingReq = 12;
|
|
17
|
+
static PingResp = 13;
|
|
18
|
+
static Disconnect = 14;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class ConnectResponsePacket {
|
|
22
|
+
constructor(ackFlags, returnCode, payload) {
|
|
23
|
+
this.ackFlags = ackFlags;
|
|
24
|
+
this.returnCode = returnCode;
|
|
25
|
+
this.payload = payload;
|
|
26
|
+
}
|
|
27
|
+
get isSuccess() { return this.returnCode === 0; }
|
|
28
|
+
get errorName() { return this.returnCode !== 0 ? 'Connection Refused' : null; }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class IllegalStateError extends Error {
|
|
32
|
+
constructor(msg) { super(msg); this.name = 'IllegalStateError'; }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
class PacketStream {
|
|
36
|
+
constructor(buffer) {
|
|
37
|
+
this.buffer = buffer;
|
|
38
|
+
this.offset = 0;
|
|
39
|
+
}
|
|
40
|
+
readByte() {
|
|
41
|
+
if (this.offset >= this.buffer.length) return 0;
|
|
42
|
+
return this.buffer[this.offset++];
|
|
43
|
+
}
|
|
44
|
+
readStringAsBuffer() {
|
|
45
|
+
const len = this.readWord();
|
|
46
|
+
if (this.offset + len > this.buffer.length) return Buffer.alloc(0);
|
|
47
|
+
const buf = this.buffer.slice(this.offset, this.offset + len);
|
|
48
|
+
this.offset += len;
|
|
49
|
+
return buf;
|
|
50
|
+
}
|
|
51
|
+
readWord() {
|
|
52
|
+
if (this.offset + 2 > this.buffer.length) return 0;
|
|
53
|
+
const w = this.buffer.readUInt16BE(this.offset);
|
|
54
|
+
this.offset += 2;
|
|
55
|
+
return w;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
class PacketWriter {
|
|
60
|
+
constructor() { this.chunks = []; }
|
|
61
|
+
writeByte(b) { const buf = Buffer.alloc(1); buf.writeUInt8(b); this.chunks.push(buf); return this; }
|
|
62
|
+
writeWord(w) { const buf = Buffer.alloc(2); buf.writeUInt16BE(w); this.chunks.push(buf); return this; }
|
|
63
|
+
writeString(s) { this.writeWord(s.length); this.chunks.push(Buffer.from(s)); return this; }
|
|
64
|
+
write(buf) { this.chunks.push(buf); return this; }
|
|
65
|
+
toBuffer() { return Buffer.concat(this.chunks); }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class MqttClient extends EventEmitter {
|
|
69
|
+
constructor(options) {
|
|
70
|
+
super();
|
|
71
|
+
this.options = options || {};
|
|
72
|
+
this.readMap = options.readMap || {};
|
|
73
|
+
this.writeMap = options.writeMap || {};
|
|
74
|
+
this.socket = null;
|
|
75
|
+
this.topicMap = new Map();
|
|
76
|
+
this.packetIdCounter = 1;
|
|
77
|
+
this.pendingPublishes = new Map(); // PacketID -> {resolve, reject, timer}
|
|
78
|
+
this.pingTimer = null;
|
|
79
|
+
this.keepAliveInterval = 60000;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getNextPacketId() {
|
|
83
|
+
const id = this.packetIdCounter;
|
|
84
|
+
this.packetIdCounter++;
|
|
85
|
+
if (this.packetIdCounter > 65535) this.packetIdCounter = 1;
|
|
86
|
+
return id;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async connect(opts) {
|
|
90
|
+
return new Promise(async (resolve, reject) => {
|
|
91
|
+
const port = 443;
|
|
92
|
+
const host = this.options.transport && this.options.transport.host ? this.options.transport.host : 'edge-mqtt.facebook.com';
|
|
93
|
+
const connectOpts = opts || {};
|
|
94
|
+
|
|
95
|
+
const onConnect = () => {
|
|
96
|
+
// Setup Ping Timer
|
|
97
|
+
this._setupPingTimer();
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
const writer = new PacketWriter();
|
|
101
|
+
const writeFunc = this.writeMap[PacketType.Connect];
|
|
102
|
+
if (writeFunc) {
|
|
103
|
+
writeFunc(writer, {
|
|
104
|
+
...this.options,
|
|
105
|
+
...connectOpts,
|
|
106
|
+
payload: this.connectPayload || connectOpts.payload,
|
|
107
|
+
keepAlive: 60
|
|
108
|
+
});
|
|
109
|
+
const packetData = writer.toBuffer();
|
|
110
|
+
let remLen = packetData.length;
|
|
111
|
+
const fixedHeader = [ (PacketType.Connect << 4) ];
|
|
112
|
+
do {
|
|
113
|
+
let byte = remLen % 128;
|
|
114
|
+
remLen = Math.floor(remLen / 128);
|
|
115
|
+
if (remLen > 0) byte = byte | 128;
|
|
116
|
+
fixedHeader.push(byte);
|
|
117
|
+
} while (remLen > 0);
|
|
118
|
+
|
|
119
|
+
this.socket.write(Buffer.concat([Buffer.from(fixedHeader), packetData]));
|
|
120
|
+
} else {
|
|
121
|
+
this.emit('error', new Error('No write handler for CONNECT'));
|
|
122
|
+
}
|
|
123
|
+
} catch (e) {
|
|
124
|
+
this.emit('error', e);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
if (this.options.transport instanceof SocksTlsTransport && SocksClient) {
|
|
130
|
+
// SOCKS Proxy Connection
|
|
131
|
+
const proxyOpts = this.options.transport.proxyOptions;
|
|
132
|
+
const info = {
|
|
133
|
+
proxy: {
|
|
134
|
+
host: proxyOpts.host || proxyOpts.ipaddress,
|
|
135
|
+
port: parseInt(proxyOpts.port),
|
|
136
|
+
type: 5
|
|
137
|
+
},
|
|
138
|
+
command: 'connect',
|
|
139
|
+
destination: {
|
|
140
|
+
host: host,
|
|
141
|
+
port: port
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
if (proxyOpts.username) {
|
|
146
|
+
info.proxy.userId = proxyOpts.username;
|
|
147
|
+
info.proxy.password = proxyOpts.password;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const { socket: proxySocket } = await SocksClient.createConnection(info);
|
|
151
|
+
this.socket = tls.connect({
|
|
152
|
+
socket: proxySocket,
|
|
153
|
+
rejectUnauthorized: false,
|
|
154
|
+
servername: host
|
|
155
|
+
}, onConnect);
|
|
156
|
+
} else {
|
|
157
|
+
// Direct TLS Connection
|
|
158
|
+
this.socket = tls.connect(port, host, { rejectUnauthorized: false }, onConnect);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.socket.on('data', (data) => this._handleData(data));
|
|
162
|
+
this.socket.on('error', (err) => {
|
|
163
|
+
this._clearPingTimer();
|
|
164
|
+
this.emit('error', err);
|
|
165
|
+
});
|
|
166
|
+
this.socket.on('close', () => {
|
|
167
|
+
this._clearPingTimer();
|
|
168
|
+
this.emit('disconnect');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
this.once('connect_success', resolve);
|
|
172
|
+
} catch (e) {
|
|
173
|
+
reject(e);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
_setupPingTimer() {
|
|
179
|
+
this._clearPingTimer();
|
|
180
|
+
this.pingTimer = setInterval(() => {
|
|
181
|
+
if (this.socket && !this.socket.destroyed) {
|
|
182
|
+
this.socket.write(Buffer.from([0xC0, 0x00])); // PINGREQ (12 << 4), Length 0
|
|
183
|
+
}
|
|
184
|
+
}, this.keepAliveInterval);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
_clearPingTimer() {
|
|
188
|
+
if (this.pingTimer) clearInterval(this.pingTimer);
|
|
189
|
+
this.pingTimer = null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
_handleData(data) {
|
|
193
|
+
let offset = 0;
|
|
194
|
+
while(offset < data.length) {
|
|
195
|
+
const first = data[offset++];
|
|
196
|
+
const type = first >> 4;
|
|
197
|
+
let multiplier = 1;
|
|
198
|
+
let length = 0;
|
|
199
|
+
let digit;
|
|
200
|
+
do {
|
|
201
|
+
if (offset >= data.length) break;
|
|
202
|
+
digit = data[offset++];
|
|
203
|
+
length += (digit & 127) * multiplier;
|
|
204
|
+
multiplier *= 128;
|
|
205
|
+
} while ((digit & 128) !== 0);
|
|
206
|
+
|
|
207
|
+
if (offset + length > data.length) break;
|
|
208
|
+
|
|
209
|
+
const payload = data.slice(offset, offset + length);
|
|
210
|
+
offset += length;
|
|
211
|
+
|
|
212
|
+
if (type === PacketType.ConnAck) {
|
|
213
|
+
const readFunc = this.readMap[PacketType.ConnAck];
|
|
214
|
+
if (readFunc) {
|
|
215
|
+
const stream = new PacketStream(payload);
|
|
216
|
+
const packet = readFunc(stream, length);
|
|
217
|
+
if (packet.isSuccess) this.emit('connect_success');
|
|
218
|
+
this.emit('connect', { payload: packet.payload });
|
|
219
|
+
}
|
|
220
|
+
} else if (type === PacketType.Publish) {
|
|
221
|
+
try {
|
|
222
|
+
const topicLen = payload.readUInt16BE(0);
|
|
223
|
+
const topic = payload.slice(2, 2 + topicLen).toString();
|
|
224
|
+
const qos = (first & 0x06) >> 1;
|
|
225
|
+
let msgPayload;
|
|
226
|
+
if (qos > 0) {
|
|
227
|
+
// Skip Packet ID (2 bytes)
|
|
228
|
+
msgPayload = payload.slice(2 + topicLen + 2);
|
|
229
|
+
} else {
|
|
230
|
+
msgPayload = payload.slice(2 + topicLen);
|
|
231
|
+
}
|
|
232
|
+
this.emit('message', { topic, payload: msgPayload, qosLevel: qos });
|
|
233
|
+
} catch (e) {}
|
|
234
|
+
} else if (type === PacketType.PubAck) {
|
|
235
|
+
// Handle PubAck (QoS 1)
|
|
236
|
+
if (payload.length >= 2) {
|
|
237
|
+
const packetId = payload.readUInt16BE(0);
|
|
238
|
+
const pending = this.pendingPublishes.get(packetId);
|
|
239
|
+
if (pending) {
|
|
240
|
+
pending.resolve();
|
|
241
|
+
this.pendingPublishes.delete(packetId);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
} else if (type === PacketType.PingResp) {
|
|
245
|
+
// Pong received, good
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async publish(msg) {
|
|
251
|
+
if (!this.socket) return;
|
|
252
|
+
return new Promise((resolve, reject) => {
|
|
253
|
+
const writer = new PacketWriter();
|
|
254
|
+
writer.writeString(msg.topic);
|
|
255
|
+
let packetId = 0;
|
|
256
|
+
if (msg.qosLevel > 0) {
|
|
257
|
+
packetId = this.getNextPacketId();
|
|
258
|
+
writer.writeWord(packetId);
|
|
259
|
+
}
|
|
260
|
+
writer.write(msg.payload);
|
|
261
|
+
|
|
262
|
+
const packetData = writer.toBuffer();
|
|
263
|
+
const fixedHeader = [ (PacketType.Publish << 4) | (msg.qosLevel ? 2 : 0) ];
|
|
264
|
+
let remLen = packetData.length;
|
|
265
|
+
do {
|
|
266
|
+
let byte = remLen % 128;
|
|
267
|
+
remLen = Math.floor(remLen / 128);
|
|
268
|
+
if (remLen > 0) byte = byte | 128;
|
|
269
|
+
fixedHeader.push(byte);
|
|
270
|
+
} while (remLen > 0);
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
this.socket.write(Buffer.concat([Buffer.from(fixedHeader), packetData]));
|
|
274
|
+
if (msg.qosLevel > 0) {
|
|
275
|
+
this.pendingPublishes.set(packetId, { resolve, reject });
|
|
276
|
+
// Timeout fallback for ack?
|
|
277
|
+
setTimeout(() => {
|
|
278
|
+
if (this.pendingPublishes.has(packetId)) {
|
|
279
|
+
this.pendingPublishes.delete(packetId);
|
|
280
|
+
resolve(); // Resolve anyway to not block logic
|
|
281
|
+
}
|
|
282
|
+
}, 5000);
|
|
283
|
+
} else {
|
|
284
|
+
resolve();
|
|
285
|
+
}
|
|
286
|
+
} catch (e) {
|
|
287
|
+
reject(e);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async subscribe(topic, qos = 0) {
|
|
293
|
+
if (!this.socket) return;
|
|
294
|
+
const writer = new PacketWriter();
|
|
295
|
+
writer.writeWord(this.getNextPacketId());
|
|
296
|
+
writer.writeString(topic);
|
|
297
|
+
writer.writeByte(qos);
|
|
298
|
+
|
|
299
|
+
const packetData = writer.toBuffer();
|
|
300
|
+
const fixedHeader = [ (PacketType.Subscribe << 4) | 2 ];
|
|
301
|
+
let remLen = packetData.length;
|
|
302
|
+
do {
|
|
303
|
+
let byte = remLen % 128;
|
|
304
|
+
remLen = Math.floor(remLen / 128);
|
|
305
|
+
if (remLen > 0) byte = byte | 128;
|
|
306
|
+
fixedHeader.push(byte);
|
|
307
|
+
} while (remLen > 0);
|
|
308
|
+
|
|
309
|
+
this.socket.write(Buffer.concat([Buffer.from(fixedHeader), packetData]));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
disconnect() {
|
|
313
|
+
this._clearPingTimer();
|
|
314
|
+
if (this.socket) this.socket.end();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
class TlsTransport { constructor(opts) { Object.assign(this, opts); } }
|
|
319
|
+
class SocksTlsTransport { constructor(opts) { Object.assign(this, opts); } }
|
|
320
|
+
|
|
321
|
+
function isConnAck(p) { return true; }
|
|
322
|
+
|
|
323
|
+
const DefaultPacketReadMap = {};
|
|
324
|
+
const DefaultPacketWriteMap = {};
|
|
325
|
+
|
|
326
|
+
module.exports = {
|
|
327
|
+
MqttClient,
|
|
328
|
+
PacketType,
|
|
329
|
+
ConnectResponsePacket,
|
|
330
|
+
IllegalStateError,
|
|
331
|
+
TlsTransport,
|
|
332
|
+
SocksTlsTransport,
|
|
333
|
+
DefaultPacketReadMap,
|
|
334
|
+
DefaultPacketWriteMap,
|
|
335
|
+
isConnAck,
|
|
336
|
+
PacketStream
|
|
337
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { MQTToTConnectPacketOptions } from './mqttot.connect.request.packet';
|
|
4
|
-
import
|
|
4
|
+
import * as mqtts_1 from '../mqtt-shim';
|
|
5
5
|
import { MQTToTConnectResponsePacket } from './mqttot.connect.response.packet';
|
|
6
6
|
import { SocksProxy } from 'socks';
|
|
7
7
|
import { ConnectionOptions } from 'tls';
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.mqttotConnectFlow = exports.MQTToTClient = void 0;
|
|
4
4
|
const shared_1 = require("../shared");
|
|
5
5
|
const mqttot_connect_request_packet_1 = require("./mqttot.connect.request.packet");
|
|
6
|
-
const mqtts_1 = require("
|
|
6
|
+
const mqtts_1 = require("../mqtt-shim");
|
|
7
7
|
const errors_1 = require("../errors");
|
|
8
8
|
const mqttot_connect_response_packet_1 = require("./mqttot.connect.response.packet");
|
|
9
9
|
class MQTToTClient extends mqtts_1.MqttClient {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import
|
|
2
|
+
import * as mqtts_1 from '../mqtt-shim';
|
|
3
3
|
export declare class MQTToTConnectResponsePacket extends ConnectResponsePacket {
|
|
4
4
|
readonly payload: Buffer;
|
|
5
5
|
constructor(ackFlags: number, returnCode: ConnectReturnCode, payload: Buffer);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.readConnectResponsePacket = exports.MQTToTConnectResponsePacket = void 0;
|
|
4
|
-
const mqtts_1 = require("
|
|
4
|
+
const mqtts_1 = require("../mqtt-shim");
|
|
5
5
|
class MQTToTConnectResponsePacket extends mqtts_1.ConnectResponsePacket {
|
|
6
6
|
constructor(ackFlags, returnCode, payload) {
|
|
7
7
|
super(ackFlags, returnCode);
|
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MQTToTClient } from '../../mqttot';
|
|
2
2
|
import { MessageSyncMessageTypes } from '../messages';
|
|
3
3
|
import { ThriftPacketDescriptor } from '../../thrift';
|
|
4
|
-
import
|
|
4
|
+
import * as mqtts_1 from '../../mqtt-shim';
|
|
5
5
|
interface ItemBaseType {
|
|
6
6
|
threadId: string;
|
|
7
7
|
clientContext?: string;
|
|
@@ -4,7 +4,7 @@ exports.MessageSyncMixin = void 0;
|
|
|
4
4
|
const mixin_1 = require("./mixin");
|
|
5
5
|
const constants_1 = require("../../constants");
|
|
6
6
|
const shared_1 = require("../../shared");
|
|
7
|
-
const mqtts_1 = require("
|
|
7
|
+
const mqtts_1 = require("../../mqtt-shim");
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* MessageSyncMixin - patched for 2026 (robust parsing + safe username fetch + tolerant timestamp handling)
|
|
@@ -4,7 +4,7 @@ exports.RealtimeSubMixin = void 0;
|
|
|
4
4
|
const mixin_1 = require("./mixin");
|
|
5
5
|
const constants_1 = require("../../constants");
|
|
6
6
|
const shared_1 = require("../../shared");
|
|
7
|
-
const mqtts_1 = require("
|
|
7
|
+
const mqtts_1 = require("../../mqtt-shim");
|
|
8
8
|
class RealtimeSubMixin extends mixin_1.Mixin {
|
|
9
9
|
apply(client) {
|
|
10
10
|
(0, mixin_1.hook)(client, 'connect', {
|
|
@@ -5,7 +5,7 @@ const constants_1 = require("../constants");
|
|
|
5
5
|
const commands_1 = require("./commands");
|
|
6
6
|
const shared_1 = require("../shared");
|
|
7
7
|
const mqttot_1 = require("../mqttot");
|
|
8
|
-
const mqtts_1 = require("
|
|
8
|
+
const mqtts_1 = require("../mqtt-shim");
|
|
9
9
|
const errors_1 = require("../errors");
|
|
10
10
|
const eventemitter3_1 = require("eventemitter3");
|
|
11
11
|
const mixins_1 = require("./mixins");
|
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.18",
|
|
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": {
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"eventemitter3": "^5.0.1",
|
|
53
53
|
"form-data": "^4.0.0",
|
|
54
54
|
"lodash": "^4.17.21",
|
|
55
|
-
"
|
|
55
|
+
"mqtt": "^5.10.3",
|
|
56
56
|
"node-persist": "^4.0.4",
|
|
57
57
|
"pako": "^2.1.0",
|
|
58
58
|
"protobufjs": "^7.5.4",
|