nodejs-insta-private-api-mqt 1.3.84 → 1.3.86

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.
Files changed (464) hide show
  1. package/dist/dist/constants/constants.d.ts +1 -0
  2. package/dist/dist/constants/index.d.ts +25 -0
  3. package/dist/dist/core/client.d.ts +106 -0
  4. package/dist/dist/core/nav-chain.d.ts +77 -0
  5. package/dist/dist/core/repository.d.ts +3 -0
  6. package/dist/dist/core/request.d.ts +76 -0
  7. package/dist/dist/core/state.d.ts +605 -0
  8. package/dist/dist/core/utils.d.ts +129 -0
  9. package/dist/dist/downloadMedia.d.ts +106 -0
  10. package/{dist-ts → dist}/dist/downloadMedia.js +19 -20
  11. package/dist/dist/errors/index.d.ts +18 -0
  12. package/dist/dist/extend.d.ts +20 -0
  13. package/dist/dist/fbns/fbns.client.d.ts +43 -0
  14. package/dist/dist/fbns/fbns.client.events.d.ts +0 -0
  15. package/{dist-ts → dist}/dist/fbns/fbns.client.js +4 -5
  16. package/dist/dist/fbns/fbns.device-auth.d.ts +9 -0
  17. package/{src-ts/dist/fbns/fbns.device-auth.ts → dist/dist/fbns/fbns.device-auth.js} +6 -3
  18. package/dist/dist/fbns/fbns.types.d.ts +0 -0
  19. package/dist/dist/fbns/fbns.utilities.d.ts +4 -0
  20. package/dist/dist/fbns/index.d.ts +2 -0
  21. package/dist/dist/index.d.ts +49 -0
  22. package/dist/dist/mqtt-shim.d.ts +1 -0
  23. package/dist/dist/mqttot/index.d.ts +2 -0
  24. package/dist/dist/mqttot/mqttot.client.d.ts +77 -0
  25. package/{dist-ts → dist}/dist/mqttot/mqttot.client.js +10 -10
  26. package/dist/dist/mqttot/mqttot.connect.request.packet.d.ts +1 -0
  27. package/dist/dist/mqttot/mqttot.connect.response.packet.d.ts +5 -0
  28. package/dist/dist/mqttot/mqttot.connection.d.ts +6 -0
  29. package/dist/dist/realtime/commands/commands.d.ts +19 -0
  30. package/dist/dist/realtime/commands/direct.commands.d.ts +142 -0
  31. package/dist/dist/realtime/commands/enhanced.direct.commands.d.ts +425 -0
  32. package/{dist-ts → dist}/dist/realtime/commands/enhanced.direct.commands.js +8 -10
  33. package/dist/dist/realtime/commands/index.d.ts +2 -0
  34. package/dist/dist/realtime/delta-sync.manager.d.ts +82 -0
  35. package/{dist-ts → dist}/dist/realtime/delta-sync.manager.js +7 -10
  36. package/dist/dist/realtime/features/dm-sender.d.ts +20 -0
  37. package/{src-ts/dist/realtime/features/dm-sender.ts → dist/dist/realtime/features/dm-sender.js} +6 -3
  38. package/dist/dist/realtime/features/error-handler.d.ts +33 -0
  39. package/{dist-ts → dist}/dist/realtime/features/error-handler.js +4 -4
  40. package/dist/dist/realtime/features/gap-handler.d.ts +19 -0
  41. package/dist/dist/realtime/features/persistent-logger.d.ts +28 -0
  42. package/{dist-ts → dist}/dist/realtime/features/persistent-logger.js +3 -3
  43. package/dist/dist/realtime/features/presence.manager.d.ts +24 -0
  44. package/{src-ts/dist/realtime/features/presence.manager.ts → dist/dist/realtime/features/presence.manager.js} +2 -1
  45. package/dist/dist/realtime/features/session-health-monitor.d.ts +93 -0
  46. package/{src-ts/dist/realtime/features/session-health-monitor.ts → dist/dist/realtime/features/session-health-monitor.js} +45 -65
  47. package/dist/dist/realtime/index.d.ts +9 -0
  48. package/dist/dist/realtime/messages/app-presence.event.d.ts +0 -0
  49. package/dist/dist/realtime/messages/index.d.ts +2 -0
  50. package/dist/dist/realtime/messages/message-sync.message.d.ts +1 -0
  51. package/dist/dist/realtime/messages/realtime-sub.direct.data.d.ts +0 -0
  52. package/dist/dist/realtime/messages/thread-update.message.d.ts +0 -0
  53. package/dist/dist/realtime/mixins/index.d.ts +2 -0
  54. package/dist/dist/realtime/mixins/message-sync.mixin.d.ts +38 -0
  55. package/{dist-ts → dist}/dist/realtime/mixins/message-sync.mixin.js +16 -18
  56. package/dist/dist/realtime/mixins/mixin.d.ts +4 -0
  57. package/dist/dist/realtime/mixins/presence-typing.mixin.d.ts +9 -0
  58. package/dist/dist/realtime/mixins/realtime-sub.mixin.d.ts +37 -0
  59. package/{dist-ts → dist}/dist/realtime/mixins/realtime-sub.mixin.js +4 -5
  60. package/dist/dist/realtime/parsers/graphql-parser.d.ts +18 -0
  61. package/dist/dist/realtime/parsers/graphql.parser.d.ts +10 -0
  62. package/{src-ts/dist/realtime/parsers/graphql.parser.ts → dist/dist/realtime/parsers/graphql.parser.js} +0 -1
  63. package/dist/dist/realtime/parsers/index.d.ts +2 -0
  64. package/dist/dist/realtime/parsers/iris-parser.d.ts +18 -0
  65. package/dist/dist/realtime/parsers/iris.parser.d.ts +3 -0
  66. package/dist/dist/realtime/parsers/json-parser.d.ts +18 -0
  67. package/dist/dist/realtime/parsers/json.parser.d.ts +6 -0
  68. package/dist/dist/realtime/parsers/parser.d.ts +0 -0
  69. package/dist/dist/realtime/parsers/region-hint-parser.d.ts +18 -0
  70. package/dist/dist/realtime/parsers/region-hint.parser.d.ts +4 -0
  71. package/dist/dist/realtime/parsers/skywalker-parser.d.ts +18 -0
  72. package/dist/dist/realtime/parsers/skywalker.parser.d.ts +7 -0
  73. package/dist/dist/realtime/parsers-advanced.d.ts +93 -0
  74. package/{dist-ts → dist}/dist/realtime/parsers-advanced.js +5 -8
  75. package/dist/dist/realtime/proto-parser.d.ts +27 -0
  76. package/{dist-ts → dist}/dist/realtime/proto-parser.js +1 -2
  77. package/dist/dist/realtime/protocols/iris.handshake.d.ts +41 -0
  78. package/dist/dist/realtime/protocols/proto-definitions.d.ts +0 -0
  79. package/dist/dist/realtime/protocols/skywalker.protocol.d.ts +20 -0
  80. package/{src-ts/dist/realtime/protocols/skywalker.protocol.ts → dist/dist/realtime/protocols/skywalker.protocol.js} +8 -5
  81. package/dist/dist/realtime/realtime.client.d.ts +169 -0
  82. package/dist/dist/realtime/realtime.client.events.d.ts +0 -0
  83. package/{dist-ts → dist}/dist/realtime/realtime.client.js +75 -86
  84. package/dist/dist/realtime/realtime.service.d.ts +109 -0
  85. package/dist/dist/realtime/reconnect.manager.d.ts +15 -0
  86. package/dist/dist/realtime/session.manager.d.ts +25 -0
  87. package/dist/dist/realtime/subscriptions/graphql.subscription.d.ts +4 -0
  88. package/dist/dist/realtime/subscriptions/index.d.ts +2 -0
  89. package/dist/dist/realtime/subscriptions/skywalker.subscription.d.ts +4 -0
  90. package/dist/dist/realtime/topic-map.d.ts +97 -0
  91. package/dist/dist/realtime/topic.d.ts +71 -0
  92. package/dist/dist/repositories/account.repository.d.ts +72 -0
  93. package/{dist-ts → dist}/dist/repositories/account.repository.js +4 -6
  94. package/dist/dist/repositories/bloks.repository.d.ts +6 -0
  95. package/dist/dist/repositories/captcha.repository.d.ts +6 -0
  96. package/dist/dist/repositories/challenge.repository.d.ts +12 -0
  97. package/{dist-ts → dist}/dist/repositories/challenge.repository.js +1 -2
  98. package/dist/dist/repositories/clip.repository.d.ts +10 -0
  99. package/dist/dist/repositories/close-friends.repository.d.ts +8 -0
  100. package/dist/dist/repositories/collection.repository.d.ts +8 -0
  101. package/dist/dist/repositories/direct-thread.repository.d.ts +88 -0
  102. package/{dist-ts → dist}/dist/repositories/direct-thread.repository.js +7 -9
  103. package/dist/dist/repositories/direct.repository.d.ts +22 -0
  104. package/{dist-ts → dist}/dist/repositories/direct.repository.js +4 -5
  105. package/dist/dist/repositories/explore.repository.d.ts +7 -0
  106. package/dist/dist/repositories/fbsearch.repository.d.ts +14 -0
  107. package/dist/dist/repositories/feed.repository.d.ts +19 -0
  108. package/dist/dist/repositories/friendship.repository.d.ts +26 -0
  109. package/dist/dist/repositories/fundraiser.repository.d.ts +6 -0
  110. package/dist/dist/repositories/hashtag.repository.d.ts +11 -0
  111. package/dist/dist/repositories/highlights.repository.d.ts +11 -0
  112. package/dist/dist/repositories/insights.repository.d.ts +8 -0
  113. package/dist/dist/repositories/location.repository.d.ts +9 -0
  114. package/dist/dist/repositories/media.repository.d.ts +41 -0
  115. package/{dist-ts → dist}/dist/repositories/media.repository.js +1 -2
  116. package/dist/dist/repositories/multiple-accounts.repository.d.ts +7 -0
  117. package/dist/dist/repositories/news.repository.d.ts +6 -0
  118. package/dist/dist/repositories/note.repository.d.ts +8 -0
  119. package/dist/dist/repositories/notification.repository.d.ts +33 -0
  120. package/{dist-ts → dist}/dist/repositories/notification.repository.js +1 -1
  121. package/dist/dist/repositories/share.repository.d.ts +12 -0
  122. package/dist/dist/repositories/signup.repository.d.ts +19 -0
  123. package/dist/dist/repositories/story.repository.d.ts +23 -0
  124. package/{dist-ts → dist}/dist/repositories/story.repository.js +1 -2
  125. package/dist/dist/repositories/timeline.repository.d.ts +7 -0
  126. package/dist/dist/repositories/totp.repository.d.ts +14 -0
  127. package/dist/dist/repositories/track.repository.d.ts +7 -0
  128. package/{dist-ts → dist}/dist/repositories/track.repository.js +1 -2
  129. package/dist/dist/repositories/upload.repository.d.ts +30 -0
  130. package/{dist-ts → dist}/dist/repositories/upload.repository.js +4 -5
  131. package/dist/dist/repositories/user.repository.d.ts +52 -0
  132. package/dist/dist/sendmedia/index.d.ts +12 -0
  133. package/dist/dist/sendmedia/sendFile.d.ts +8 -0
  134. package/dist/dist/sendmedia/sendPhoto.d.ts +26 -0
  135. package/dist/dist/sendmedia/sendRavenPhoto.d.ts +14 -0
  136. package/{dist-ts → dist}/dist/sendmedia/sendRavenPhoto.js +4 -5
  137. package/dist/dist/sendmedia/sendRavenVideo.d.ts +15 -0
  138. package/{dist-ts → dist}/dist/sendmedia/sendRavenVideo.js +4 -5
  139. package/dist/dist/sendmedia/uploadPhoto.d.ts +8 -0
  140. package/dist/dist/sendmedia/uploadfFile.d.ts +13 -0
  141. package/{dist-ts → dist}/dist/sendmedia/uploadfFile.js +3 -4
  142. package/dist/dist/services/live.service.d.ts +13 -0
  143. package/dist/dist/services/search.service.d.ts +11 -0
  144. package/dist/dist/shared/index.d.ts +4 -0
  145. package/{src-ts/dist/shared/index.ts → dist/dist/shared/index.js} +14 -13
  146. package/dist/dist/shared/shared.d.ts +15 -0
  147. package/dist/dist/thrift/index.d.ts +2 -0
  148. package/dist/dist/thrift/thrift.d.ts +11 -0
  149. package/dist/dist/thrift/thrift.reading.d.ts +49 -0
  150. package/{dist-ts → dist}/dist/thrift/thrift.reading.js +3 -5
  151. package/dist/dist/thrift/thrift.writing.d.ts +49 -0
  152. package/{dist-ts → dist}/dist/thrift/thrift.writing.js +2 -4
  153. package/dist/dist/types/index.d.ts +28 -0
  154. package/dist/dist/useMultiFileAuthState.d.ts +267 -0
  155. package/{dist-ts → dist}/dist/useMultiFileAuthState.js +47 -61
  156. package/dist/dist/utils/helper-1.d.ts +0 -0
  157. package/dist/dist/utils/helper-10.d.ts +0 -0
  158. package/dist/dist/utils/helper-11.d.ts +0 -0
  159. package/dist/dist/utils/helper-12.d.ts +0 -0
  160. package/dist/dist/utils/helper-13.d.ts +0 -0
  161. package/dist/dist/utils/helper-14.d.ts +0 -0
  162. package/dist/dist/utils/helper-15.d.ts +0 -0
  163. package/dist/dist/utils/helper-16.d.ts +0 -0
  164. package/dist/dist/utils/helper-17.d.ts +0 -0
  165. package/dist/dist/utils/helper-18.d.ts +0 -0
  166. package/dist/dist/utils/helper-19.d.ts +0 -0
  167. package/dist/dist/utils/helper-2.d.ts +0 -0
  168. package/dist/dist/utils/helper-20.d.ts +0 -0
  169. package/dist/dist/utils/helper-21.d.ts +0 -0
  170. package/dist/dist/utils/helper-22.d.ts +0 -0
  171. package/dist/dist/utils/helper-23.d.ts +0 -0
  172. package/dist/dist/utils/helper-24.d.ts +0 -0
  173. package/dist/dist/utils/helper-25.d.ts +0 -0
  174. package/dist/dist/utils/helper-26.d.ts +0 -0
  175. package/dist/dist/utils/helper-27.d.ts +0 -0
  176. package/dist/dist/utils/helper-28.d.ts +0 -0
  177. package/dist/dist/utils/helper-29.d.ts +0 -0
  178. package/dist/dist/utils/helper-3.d.ts +0 -0
  179. package/dist/dist/utils/helper-30.d.ts +0 -0
  180. package/dist/dist/utils/helper-4.d.ts +0 -0
  181. package/dist/dist/utils/helper-5.d.ts +0 -0
  182. package/dist/dist/utils/helper-6.d.ts +0 -0
  183. package/dist/dist/utils/helper-7.d.ts +0 -0
  184. package/dist/dist/utils/helper-8.d.ts +0 -0
  185. package/dist/dist/utils/helper-9.d.ts +0 -0
  186. package/dist/dist/utils/index.d.ts +56 -0
  187. package/{dist-ts → dist}/dist/utils/index.js +1 -2
  188. package/dist/dist/utils/insta-mqtt-helper.d.ts +30 -0
  189. package/dist/examples/listen-to-messages.d.ts +4 -0
  190. package/{dist-ts → dist}/examples/listen-to-messages.js +1 -2
  191. package/package.json +41 -38
  192. package/dist-ts/dist/fbns/fbns.device-auth.js +0 -59
  193. package/dist-ts/dist/realtime/features/dm-sender.js +0 -94
  194. package/dist-ts/dist/realtime/features/presence.manager.js +0 -68
  195. package/dist-ts/dist/realtime/features/session-health-monitor.js +0 -327
  196. package/dist-ts/dist/realtime/parsers/graphql.parser.js +0 -22
  197. package/dist-ts/dist/realtime/protocols/skywalker.protocol.js +0 -96
  198. package/dist-ts/dist/shared/index.js +0 -98
  199. package/examples/listen-to-messages.js +0 -86
  200. package/src-ts/dist/constants/constants.ts +0 -342
  201. package/src-ts/dist/constants/index.ts +0 -58
  202. package/src-ts/dist/core/client.ts +0 -419
  203. package/src-ts/dist/core/nav-chain.ts +0 -282
  204. package/src-ts/dist/core/repository.ts +0 -7
  205. package/src-ts/dist/core/request.ts +0 -395
  206. package/src-ts/dist/core/state.ts +0 -1484
  207. package/src-ts/dist/core/utils.ts +0 -786
  208. package/src-ts/dist/downloadMedia.ts +0 -381
  209. package/src-ts/dist/errors/index.ts +0 -38
  210. package/src-ts/dist/extend.ts +0 -167
  211. package/src-ts/dist/fbns/fbns.client.events.ts +0 -3
  212. package/src-ts/dist/fbns/fbns.client.ts +0 -252
  213. package/src-ts/dist/fbns/fbns.types.ts +0 -3
  214. package/src-ts/dist/fbns/fbns.utilities.ts +0 -79
  215. package/src-ts/dist/fbns/index.ts +0 -21
  216. package/src-ts/dist/index.ts +0 -139
  217. package/src-ts/dist/mqtt-shim.ts +0 -15
  218. package/src-ts/dist/mqttot/index.ts +0 -21
  219. package/src-ts/dist/mqttot/mqttot.client.ts +0 -318
  220. package/src-ts/dist/mqttot/mqttot.connect.request.packet.ts +0 -9
  221. package/src-ts/dist/mqttot/mqttot.connect.response.packet.ts +0 -24
  222. package/src-ts/dist/mqttot/mqttot.connection.ts +0 -77
  223. package/src-ts/dist/realtime/commands/commands.ts +0 -71
  224. package/src-ts/dist/realtime/commands/direct.commands.ts +0 -417
  225. package/src-ts/dist/realtime/commands/enhanced.direct.commands.ts +0 -1731
  226. package/src-ts/dist/realtime/commands/index.ts +0 -20
  227. package/src-ts/dist/realtime/delta-sync.manager.ts +0 -293
  228. package/src-ts/dist/realtime/features/error-handler.ts +0 -185
  229. package/src-ts/dist/realtime/features/gap-handler.ts +0 -61
  230. package/src-ts/dist/realtime/features/persistent-logger.ts +0 -186
  231. package/src-ts/dist/realtime/index.ts +0 -30
  232. package/src-ts/dist/realtime/messages/app-presence.event.ts +0 -3
  233. package/src-ts/dist/realtime/messages/index.ts +0 -20
  234. package/src-ts/dist/realtime/messages/message-sync.message.ts +0 -43
  235. package/src-ts/dist/realtime/messages/realtime-sub.direct.data.ts +0 -3
  236. package/src-ts/dist/realtime/messages/thread-update.message.ts +0 -3
  237. package/src-ts/dist/realtime/mixins/index.ts +0 -20
  238. package/src-ts/dist/realtime/mixins/message-sync.mixin.ts +0 -596
  239. package/src-ts/dist/realtime/mixins/mixin.ts +0 -41
  240. package/src-ts/dist/realtime/mixins/presence-typing.mixin.ts +0 -33
  241. package/src-ts/dist/realtime/mixins/realtime-sub.mixin.ts +0 -181
  242. package/src-ts/dist/realtime/parsers/graphql-parser.ts +0 -43
  243. package/src-ts/dist/realtime/parsers/index.ts +0 -23
  244. package/src-ts/dist/realtime/parsers/iris-parser.ts +0 -43
  245. package/src-ts/dist/realtime/parsers/iris.parser.ts +0 -10
  246. package/src-ts/dist/realtime/parsers/json-parser.ts +0 -43
  247. package/src-ts/dist/realtime/parsers/json.parser.ts +0 -10
  248. package/src-ts/dist/realtime/parsers/parser.ts +0 -3
  249. package/src-ts/dist/realtime/parsers/region-hint-parser.ts +0 -43
  250. package/src-ts/dist/realtime/parsers/region-hint.parser.ts +0 -15
  251. package/src-ts/dist/realtime/parsers/skywalker-parser.ts +0 -43
  252. package/src-ts/dist/realtime/parsers/skywalker.parser.ts +0 -15
  253. package/src-ts/dist/realtime/parsers-advanced.ts +0 -158
  254. package/src-ts/dist/realtime/proto-parser.ts +0 -195
  255. package/src-ts/dist/realtime/protocols/iris.handshake.ts +0 -74
  256. package/src-ts/dist/realtime/protocols/proto-definitions.ts +0 -80
  257. package/src-ts/dist/realtime/realtime.client.events.ts +0 -3
  258. package/src-ts/dist/realtime/realtime.client.ts +0 -1996
  259. package/src-ts/dist/realtime/realtime.service.ts +0 -462
  260. package/src-ts/dist/realtime/reconnect.manager.ts +0 -88
  261. package/src-ts/dist/realtime/session.manager.ts +0 -121
  262. package/src-ts/dist/realtime/subscriptions/graphql.subscription.ts +0 -99
  263. package/src-ts/dist/realtime/subscriptions/index.ts +0 -19
  264. package/src-ts/dist/realtime/subscriptions/skywalker.subscription.ts +0 -13
  265. package/src-ts/dist/realtime/topic-map.ts +0 -71
  266. package/src-ts/dist/realtime/topic.ts +0 -80
  267. package/src-ts/dist/repositories/account.repository.ts +0 -1384
  268. package/src-ts/dist/repositories/bloks.repository.ts +0 -70
  269. package/src-ts/dist/repositories/captcha.repository.ts +0 -44
  270. package/src-ts/dist/repositories/challenge.repository.ts +0 -120
  271. package/src-ts/dist/repositories/clip.repository.ts +0 -165
  272. package/src-ts/dist/repositories/close-friends.repository.ts +0 -46
  273. package/src-ts/dist/repositories/collection.repository.ts +0 -68
  274. package/src-ts/dist/repositories/direct-thread.repository.ts +0 -446
  275. package/src-ts/dist/repositories/direct.repository.ts +0 -266
  276. package/src-ts/dist/repositories/explore.repository.ts +0 -70
  277. package/src-ts/dist/repositories/fbsearch.repository.ts +0 -140
  278. package/src-ts/dist/repositories/feed.repository.ts +0 -245
  279. package/src-ts/dist/repositories/friendship.repository.ts +0 -296
  280. package/src-ts/dist/repositories/fundraiser.repository.ts +0 -49
  281. package/src-ts/dist/repositories/hashtag.repository.ts +0 -99
  282. package/src-ts/dist/repositories/highlights.repository.ts +0 -121
  283. package/src-ts/dist/repositories/insights.repository.ts +0 -82
  284. package/src-ts/dist/repositories/location.repository.ts +0 -84
  285. package/src-ts/dist/repositories/media.repository.ts +0 -395
  286. package/src-ts/dist/repositories/multiple-accounts.repository.ts +0 -41
  287. package/src-ts/dist/repositories/news.repository.ts +0 -35
  288. package/src-ts/dist/repositories/note.repository.ts +0 -57
  289. package/src-ts/dist/repositories/notification.repository.ts +0 -79
  290. package/src-ts/dist/repositories/share.repository.ts +0 -35
  291. package/src-ts/dist/repositories/signup.repository.ts +0 -218
  292. package/src-ts/dist/repositories/story.repository.ts +0 -290
  293. package/src-ts/dist/repositories/timeline.repository.ts +0 -60
  294. package/src-ts/dist/repositories/totp.repository.ts +0 -139
  295. package/src-ts/dist/repositories/track.repository.ts +0 -53
  296. package/src-ts/dist/repositories/upload.repository.ts +0 -204
  297. package/src-ts/dist/repositories/user.repository.ts +0 -360
  298. package/src-ts/dist/sendmedia/index.ts +0 -27
  299. package/src-ts/dist/sendmedia/sendFile.ts +0 -72
  300. package/src-ts/dist/sendmedia/sendPhoto.ts +0 -142
  301. package/src-ts/dist/sendmedia/sendRavenPhoto.ts +0 -153
  302. package/src-ts/dist/sendmedia/sendRavenVideo.ts +0 -158
  303. package/src-ts/dist/sendmedia/uploadPhoto.ts +0 -107
  304. package/src-ts/dist/sendmedia/uploadfFile.ts +0 -130
  305. package/src-ts/dist/services/live.service.ts +0 -139
  306. package/src-ts/dist/services/search.service.ts +0 -115
  307. package/src-ts/dist/shared/shared.ts +0 -86
  308. package/src-ts/dist/thrift/index.ts +0 -20
  309. package/src-ts/dist/thrift/thrift.reading.ts +0 -368
  310. package/src-ts/dist/thrift/thrift.ts +0 -111
  311. package/src-ts/dist/thrift/thrift.writing.ts +0 -396
  312. package/src-ts/dist/types/index.ts +0 -285
  313. package/src-ts/dist/useMultiFileAuthState.ts +0 -1800
  314. package/src-ts/dist/utils/helper-1.ts +0 -1
  315. package/src-ts/dist/utils/helper-10.ts +0 -1
  316. package/src-ts/dist/utils/helper-11.ts +0 -1
  317. package/src-ts/dist/utils/helper-12.ts +0 -1
  318. package/src-ts/dist/utils/helper-13.ts +0 -1
  319. package/src-ts/dist/utils/helper-14.ts +0 -1
  320. package/src-ts/dist/utils/helper-15.ts +0 -1
  321. package/src-ts/dist/utils/helper-16.ts +0 -1
  322. package/src-ts/dist/utils/helper-17.ts +0 -1
  323. package/src-ts/dist/utils/helper-18.ts +0 -1
  324. package/src-ts/dist/utils/helper-19.ts +0 -1
  325. package/src-ts/dist/utils/helper-2.ts +0 -1
  326. package/src-ts/dist/utils/helper-20.ts +0 -1
  327. package/src-ts/dist/utils/helper-21.ts +0 -1
  328. package/src-ts/dist/utils/helper-22.ts +0 -1
  329. package/src-ts/dist/utils/helper-23.ts +0 -1
  330. package/src-ts/dist/utils/helper-24.ts +0 -1
  331. package/src-ts/dist/utils/helper-25.ts +0 -1
  332. package/src-ts/dist/utils/helper-26.ts +0 -1
  333. package/src-ts/dist/utils/helper-27.ts +0 -1
  334. package/src-ts/dist/utils/helper-28.ts +0 -1
  335. package/src-ts/dist/utils/helper-29.ts +0 -1
  336. package/src-ts/dist/utils/helper-3.ts +0 -1
  337. package/src-ts/dist/utils/helper-30.ts +0 -1
  338. package/src-ts/dist/utils/helper-4.ts +0 -1
  339. package/src-ts/dist/utils/helper-5.ts +0 -1
  340. package/src-ts/dist/utils/helper-6.ts +0 -1
  341. package/src-ts/dist/utils/helper-7.ts +0 -1
  342. package/src-ts/dist/utils/helper-8.ts +0 -1
  343. package/src-ts/dist/utils/helper-9.ts +0 -1
  344. package/src-ts/dist/utils/index.ts +0 -280
  345. package/src-ts/dist/utils/insta-mqtt-helper.ts +0 -128
  346. package/src-ts/examples/listen-to-messages.ts +0 -86
  347. /package/{dist-ts → dist}/dist/constants/constants.js +0 -0
  348. /package/{dist-ts → dist}/dist/constants/index.js +0 -0
  349. /package/{dist-ts → dist}/dist/core/client.js +0 -0
  350. /package/{dist-ts → dist}/dist/core/nav-chain.js +0 -0
  351. /package/{dist-ts → dist}/dist/core/repository.js +0 -0
  352. /package/{dist-ts → dist}/dist/core/request.js +0 -0
  353. /package/{dist-ts → dist}/dist/core/state.js +0 -0
  354. /package/{dist-ts → dist}/dist/core/utils.js +0 -0
  355. /package/{dist-ts → dist}/dist/errors/index.js +0 -0
  356. /package/{dist-ts → dist}/dist/extend.js +0 -0
  357. /package/{dist-ts → dist}/dist/fbns/fbns.client.events.js +0 -0
  358. /package/{dist-ts → dist}/dist/fbns/fbns.types.js +0 -0
  359. /package/{dist-ts → dist}/dist/fbns/fbns.utilities.js +0 -0
  360. /package/{dist-ts → dist}/dist/fbns/index.js +0 -0
  361. /package/{dist-ts → dist}/dist/index.js +0 -0
  362. /package/{dist-ts → dist}/dist/mqtt-shim.js +0 -0
  363. /package/{dist-ts → dist}/dist/mqttot/index.js +0 -0
  364. /package/{dist-ts → dist}/dist/mqttot/mqttot.connect.request.packet.js +0 -0
  365. /package/{dist-ts → dist}/dist/mqttot/mqttot.connect.response.packet.js +0 -0
  366. /package/{dist-ts → dist}/dist/mqttot/mqttot.connection.js +0 -0
  367. /package/{dist-ts → dist}/dist/realtime/commands/commands.js +0 -0
  368. /package/{dist-ts → dist}/dist/realtime/commands/direct.commands.js +0 -0
  369. /package/{dist-ts → dist}/dist/realtime/commands/index.js +0 -0
  370. /package/{dist-ts → dist}/dist/realtime/features/gap-handler.js +0 -0
  371. /package/{dist-ts → dist}/dist/realtime/index.js +0 -0
  372. /package/{dist-ts → dist}/dist/realtime/messages/app-presence.event.js +0 -0
  373. /package/{dist-ts → dist}/dist/realtime/messages/index.js +0 -0
  374. /package/{dist-ts → dist}/dist/realtime/messages/message-sync.message.js +0 -0
  375. /package/{dist-ts → dist}/dist/realtime/messages/realtime-sub.direct.data.js +0 -0
  376. /package/{dist-ts → dist}/dist/realtime/messages/thread-update.message.js +0 -0
  377. /package/{dist-ts → dist}/dist/realtime/mixins/index.js +0 -0
  378. /package/{dist-ts → dist}/dist/realtime/mixins/mixin.js +0 -0
  379. /package/{dist-ts → dist}/dist/realtime/mixins/presence-typing.mixin.js +0 -0
  380. /package/{dist-ts → dist}/dist/realtime/parsers/graphql-parser.js +0 -0
  381. /package/{dist-ts → dist}/dist/realtime/parsers/index.js +0 -0
  382. /package/{dist-ts → dist}/dist/realtime/parsers/iris-parser.js +0 -0
  383. /package/{dist-ts → dist}/dist/realtime/parsers/iris.parser.js +0 -0
  384. /package/{dist-ts → dist}/dist/realtime/parsers/json-parser.js +0 -0
  385. /package/{dist-ts → dist}/dist/realtime/parsers/json.parser.js +0 -0
  386. /package/{dist-ts → dist}/dist/realtime/parsers/parser.js +0 -0
  387. /package/{dist-ts → dist}/dist/realtime/parsers/region-hint-parser.js +0 -0
  388. /package/{dist-ts → dist}/dist/realtime/parsers/region-hint.parser.js +0 -0
  389. /package/{dist-ts → dist}/dist/realtime/parsers/skywalker-parser.js +0 -0
  390. /package/{dist-ts → dist}/dist/realtime/parsers/skywalker.parser.js +0 -0
  391. /package/{dist-ts → dist}/dist/realtime/protocols/iris.handshake.js +0 -0
  392. /package/{dist-ts → dist}/dist/realtime/protocols/proto-definitions.js +0 -0
  393. /package/{dist-ts → dist}/dist/realtime/realtime.client.events.js +0 -0
  394. /package/{dist-ts → dist}/dist/realtime/realtime.service.js +0 -0
  395. /package/{dist-ts → dist}/dist/realtime/reconnect.manager.js +0 -0
  396. /package/{dist-ts → dist}/dist/realtime/session.manager.js +0 -0
  397. /package/{dist-ts → dist}/dist/realtime/subscriptions/graphql.subscription.js +0 -0
  398. /package/{dist-ts → dist}/dist/realtime/subscriptions/index.js +0 -0
  399. /package/{dist-ts → dist}/dist/realtime/subscriptions/skywalker.subscription.js +0 -0
  400. /package/{dist-ts → dist}/dist/realtime/topic-map.js +0 -0
  401. /package/{dist-ts → dist}/dist/realtime/topic.js +0 -0
  402. /package/{dist-ts → dist}/dist/repositories/bloks.repository.js +0 -0
  403. /package/{dist-ts → dist}/dist/repositories/captcha.repository.js +0 -0
  404. /package/{dist-ts → dist}/dist/repositories/clip.repository.js +0 -0
  405. /package/{dist-ts → dist}/dist/repositories/close-friends.repository.js +0 -0
  406. /package/{dist-ts → dist}/dist/repositories/collection.repository.js +0 -0
  407. /package/{dist-ts → dist}/dist/repositories/explore.repository.js +0 -0
  408. /package/{dist-ts → dist}/dist/repositories/fbsearch.repository.js +0 -0
  409. /package/{dist-ts → dist}/dist/repositories/feed.repository.js +0 -0
  410. /package/{dist-ts → dist}/dist/repositories/friendship.repository.js +0 -0
  411. /package/{dist-ts → dist}/dist/repositories/fundraiser.repository.js +0 -0
  412. /package/{dist-ts → dist}/dist/repositories/hashtag.repository.js +0 -0
  413. /package/{dist-ts → dist}/dist/repositories/highlights.repository.js +0 -0
  414. /package/{dist-ts → dist}/dist/repositories/insights.repository.js +0 -0
  415. /package/{dist-ts → dist}/dist/repositories/location.repository.js +0 -0
  416. /package/{dist-ts → dist}/dist/repositories/multiple-accounts.repository.js +0 -0
  417. /package/{dist-ts → dist}/dist/repositories/news.repository.js +0 -0
  418. /package/{dist-ts → dist}/dist/repositories/note.repository.js +0 -0
  419. /package/{dist-ts → dist}/dist/repositories/share.repository.js +0 -0
  420. /package/{dist-ts → dist}/dist/repositories/signup.repository.js +0 -0
  421. /package/{dist-ts → dist}/dist/repositories/timeline.repository.js +0 -0
  422. /package/{dist-ts → dist}/dist/repositories/totp.repository.js +0 -0
  423. /package/{dist-ts → dist}/dist/repositories/user.repository.js +0 -0
  424. /package/{dist-ts → dist}/dist/sendmedia/index.js +0 -0
  425. /package/{dist-ts → dist}/dist/sendmedia/sendFile.js +0 -0
  426. /package/{dist-ts → dist}/dist/sendmedia/sendPhoto.js +0 -0
  427. /package/{dist-ts → dist}/dist/sendmedia/uploadPhoto.js +0 -0
  428. /package/{dist-ts → dist}/dist/services/live.service.js +0 -0
  429. /package/{dist-ts → dist}/dist/services/search.service.js +0 -0
  430. /package/{dist-ts → dist}/dist/shared/shared.js +0 -0
  431. /package/{dist-ts → dist}/dist/thrift/index.js +0 -0
  432. /package/{dist-ts → dist}/dist/thrift/thrift.js +0 -0
  433. /package/{dist-ts → dist}/dist/types/index.js +0 -0
  434. /package/{dist-ts → dist}/dist/utils/helper-1.js +0 -0
  435. /package/{dist-ts → dist}/dist/utils/helper-10.js +0 -0
  436. /package/{dist-ts → dist}/dist/utils/helper-11.js +0 -0
  437. /package/{dist-ts → dist}/dist/utils/helper-12.js +0 -0
  438. /package/{dist-ts → dist}/dist/utils/helper-13.js +0 -0
  439. /package/{dist-ts → dist}/dist/utils/helper-14.js +0 -0
  440. /package/{dist-ts → dist}/dist/utils/helper-15.js +0 -0
  441. /package/{dist-ts → dist}/dist/utils/helper-16.js +0 -0
  442. /package/{dist-ts → dist}/dist/utils/helper-17.js +0 -0
  443. /package/{dist-ts → dist}/dist/utils/helper-18.js +0 -0
  444. /package/{dist-ts → dist}/dist/utils/helper-19.js +0 -0
  445. /package/{dist-ts → dist}/dist/utils/helper-2.js +0 -0
  446. /package/{dist-ts → dist}/dist/utils/helper-20.js +0 -0
  447. /package/{dist-ts → dist}/dist/utils/helper-21.js +0 -0
  448. /package/{dist-ts → dist}/dist/utils/helper-22.js +0 -0
  449. /package/{dist-ts → dist}/dist/utils/helper-23.js +0 -0
  450. /package/{dist-ts → dist}/dist/utils/helper-24.js +0 -0
  451. /package/{dist-ts → dist}/dist/utils/helper-25.js +0 -0
  452. /package/{dist-ts → dist}/dist/utils/helper-26.js +0 -0
  453. /package/{dist-ts → dist}/dist/utils/helper-27.js +0 -0
  454. /package/{dist-ts → dist}/dist/utils/helper-28.js +0 -0
  455. /package/{dist-ts → dist}/dist/utils/helper-29.js +0 -0
  456. /package/{dist-ts → dist}/dist/utils/helper-3.js +0 -0
  457. /package/{dist-ts → dist}/dist/utils/helper-30.js +0 -0
  458. /package/{dist-ts → dist}/dist/utils/helper-4.js +0 -0
  459. /package/{dist-ts → dist}/dist/utils/helper-5.js +0 -0
  460. /package/{dist-ts → dist}/dist/utils/helper-6.js +0 -0
  461. /package/{dist-ts → dist}/dist/utils/helper-7.js +0 -0
  462. /package/{dist-ts → dist}/dist/utils/helper-8.js +0 -0
  463. /package/{dist-ts → dist}/dist/utils/helper-9.js +0 -0
  464. /package/{dist-ts → dist}/dist/utils/insta-mqtt-helper.js +0 -0
@@ -1,1996 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * Console filter (quiet by default)
5
- * --------------------------------
6
- * Some helper functions inside the package may print noisy informational logs like:
7
- * [useMultiFileAuthState] ...
8
- * [MESSAGE_SYNC] ...
9
- * This filter suppresses ONLY those known prefixes while leaving your own logs intact.
10
- *
11
- * To disable this filter:
12
- * IG_SUPPRESS_INTERNAL_LOGS=0 node yourfile.js
13
- */
14
- (function installConsoleFilter() {
15
- const flag = process.env.IG_SUPPRESS_INTERNAL_LOGS;
16
- const enabled = (flag === undefined || flag === null || flag === '' || flag === '1' || flag.toLowerCase?.() === 'true');
17
- if (!enabled) return;
18
-
19
- const DROP_PREFIXES = [
20
- '[useMultiFileAuthState]',
21
- '[MESSAGE_SYNC]',
22
- '[RealtimeClient]', // safety in case any remain
23
- ];
24
-
25
- // Also drop any line that contains these tokens anywhere (covers variants like "[MESSAGE_SYNC MIXIN]")
26
- const DROP_TOKENS = [
27
- 'MESSAGE_SYNC',
28
- 'useMultiFileAuthState',
29
- 'RealtimeClient',
30
- ];
31
-
32
- const shouldDrop = (args) => {
33
- if (!args || !args.length) return false;
34
-
35
- const first = (typeof args[0] === 'string') ? args[0] : '';
36
-
37
- // Fast-path: known prefixes
38
- if (first && DROP_PREFIXES.some((p) => first.startsWith(p) || first.includes(p))) {
39
- return true;
40
- }
41
-
42
- // Robust-path: scan all string args for known tokens
43
- const joined = args
44
- .map((a) => (typeof a === 'string' ? a : ''))
45
- .filter(Boolean)
46
- .join(' ');
47
-
48
- if (!joined) return false;
49
-
50
- return DROP_TOKENS.some((t) => joined.includes(t));
51
- };
52
-
53
- const wrap = (methodName) => {
54
- const original = console[methodName].bind(console);
55
- console[methodName] = (...args) => {
56
- if (shouldDrop(args)) return;
57
- return original(...args);
58
- };
59
- };
60
-
61
- wrap('log');
62
- wrap('info');
63
- wrap('warn');
64
- wrap('error');
65
- })();
66
-
67
-
68
- /*
69
- RealtimeClient
70
- --------------
71
- This file implements the RealtimeClient which manages:
72
- - constructing the FBNS/MQTT connection payload (Thrift)
73
- - starting the MQTT client (MQTToTClient)
74
- - attaching lifecycle handlers (connect/close/error)
75
- - keepalives, message-sync refresh and traffic watchdogs
76
- - wiring MQTT messages into higher-level events (message, iris, receive)
77
-
78
- The implementation keeps original structure while applying compatibility tweaks:
79
- - persistent clientMqttSessionId and client_context handling
80
- - robust sessionid / mqttJwt / deviceSecret fallbacks
81
- - slightly adjusted appSpecificInfo to match mobile client fields
82
- - uses mqttot.MQTToTConnection to build a thrift connection payload
83
- - MQTT URL remains 'edge-mqtt.facebook.com' (Instagram/Meta edge host)
84
-
85
- Additional improvements added to keep bots alive across long idle periods:
86
- - persistent mqtt-session load/save on disk at startup & after connect
87
- - heartbeat improvements: MQTT-level ping (if available), numeric-topic pings and foreground keepalive
88
- - credential refresh hook (if auth helper exposes refreshMqttAuth or similar)
89
- - robust reconnect loop with exponential backoff and credential refresh attempts
90
- - enhanced logging and defensive guards so long-idle reconnections work better
91
- */
92
-
93
- // Keep module imports similar to your original code
94
- const constants_1 = require("../constants");
95
- const commands_1 = require("./commands");
96
- const shared_1 = require("../shared");
97
- const mqttot_1 = require("../mqttot");
98
- // Use mqtts for errors / IllegalStateError compatibility
99
- const mqtts_1 = require("mqtts");
100
- const errors_1 = require("../errors");
101
- const eventemitter3_1 = require("eventemitter3");
102
- const mixins_1 = require("./mixins");
103
- const iris_handshake_1 = require("./protocols/iris.handshake");
104
- const skywalker_protocol_1 = require("./protocols/skywalker.protocol");
105
- const presence_manager_1 = require("./features/presence.manager");
106
- const dm_sender_1 = require("./features/dm-sender");
107
- const error_handler_1 = require("./features/error-handler");
108
- const gap_handler_1 = require("./features/gap-handler");
109
- const enhanced_direct_commands_1 = require("./commands/enhanced.direct.commands");
110
- const presence_typing_mixin_1 = require("./mixins/presence-typing.mixin");
111
- const { SessionHealthMonitor } = require("./features/session-health-monitor");
112
- const { PersistentLogger } = require("./features/persistent-logger");
113
- const fs = require('fs');
114
- const path = require('path');
115
-
116
- // Use INSTAGRAM_VERSION exported from mqttot so it is applied automatically where available
117
- const INSTAGRAM_VERSION = mqttot_1.INSTAGRAM_VERSION;
118
-
119
- /**
120
- * RealtimeClient
121
- * - Extends EventEmitter to emit high-level events for consumers.
122
- * - Responsible for constructing the thrift payload, creating the MQTToTClient and wiring its events.
123
- */
124
- class RealtimeClient extends eventemitter3_1.EventEmitter {
125
- // getter to expose the underlying mqtt client instance
126
- get mqtt() {
127
- return this._mqtt;
128
- }
129
-
130
- /**
131
- * constructor(ig, mixins)
132
- * - ig: instance of instagram client (used for building payloads & fetching inbox)
133
- * - mixins: collection of mixins applied to this realtime client (message-sync, realtime-sub, presence/typing)
134
- */
135
- constructor(ig, mixins = [new mixins_1.MessageSyncMixin(), new mixins_1.RealtimeSubMixin(), new presence_typing_mixin_1.PresenceTypingMixin()]) {
136
- super();
137
- // --- Logging (quiet by default, Baileys-like) ---
138
- // Enable logs by setting IG_REALTIME_DEBUG=1 or IG_MQTT_DEBUG=1
139
- this._debug = Boolean(process.env.IG_REALTIME_DEBUG || process.env.IG_MQTT_DEBUG);
140
- // Optional external logger (pino-like): { debug/info/warn/error }
141
- this._logger = (ig && ig.logger) ? ig.logger : null;
142
- this._log = (level, ...args) => {
143
- const logger = this._logger;
144
- if (logger && typeof logger[level] === 'function') {
145
- try { return logger[level](...args); } catch (_) {}
146
- }
147
- if (!this._debug) return;
148
- const fn = console[level] || console.log;
149
- try { fn(...args); } catch (_) {}
150
- };
151
- // ----------------------------------------------
152
-
153
- // debug helpers
154
- this.realtimeDebug = (0, shared_1.debugChannel)('realtime');
155
- this.messageDebug = this.realtimeDebug.extend('message');
156
-
157
- // enhanced direct commands debug (exposed for compatibility with the enhanced commands)
158
- this.enhancedDebug = this.realtimeDebug.extend('enhanced-commands');
159
-
160
- // safeDisconnect flag used when user intentionally disconnects
161
- this.safeDisconnect = false;
162
-
163
- // convenience wrappers to emit events
164
- this.emitError = (e) => this.emit('error', e);
165
- this.emitWarning = (e) => this.emit('warning', e);
166
-
167
- // persistent references
168
- this.ig = ig;
169
- this.threads = new Map();
170
-
171
- // instantiate features / protocols / mixins
172
- this.irisHandshake = new iris_handshake_1.IrisHandshake(this);
173
- this.skywalkerProtocol = new skywalker_protocol_1.SkywalkerProtocol(this);
174
- this.presenceManager = new presence_manager_1.PresenceManager(this);
175
- this.dmSender = new dm_sender_1.DMSender(this);
176
- this.errorHandler = new error_handler_1.ErrorHandler(this);
177
- this.gapHandler = new gap_handler_1.GapHandler(this);
178
- this.directCommands = new enhanced_direct_commands_1.EnhancedDirectCommands(this);
179
-
180
- // Add transaction and ordering capability
181
- try {
182
- const { addTransactionCapability } = require('../utils/insta-mqtt-helper');
183
- addTransactionCapability(this);
184
- } catch (e) {
185
- this.realtimeDebug('Failed to add transaction capability:', e.message);
186
- }
187
-
188
- this.realtimeDebug(`Applying mixins: ${mixins.map(m => m.name).join(', ')}`);
189
- // apply mixins to this instance (keeps modular features separated)
190
- (0, mixins_1.applyMixins)(mixins, this, this.ig);
191
-
192
- // Default subscriptions (force-enable if saved ones are empty)
193
- this.defaultGraphQlSubs = ['ig_sub_direct', 'ig_sub_direct_v2_message_sync'];
194
- this.defaultSkywalkerSubs = ['presence_subscribe', 'typing_subscribe'];
195
-
196
- // internal flags & timers
197
- this._attachedAuthState = null;
198
- this._messageSyncAttached = false;
199
- this._reconnectInProgress = false;
200
- this._lastMessageAt = Date.now();
201
- this._foregroundTimer = null;
202
- this._syncTimer = null;
203
- this._trafficWatchdog = null;
204
- this._heartbeatTimer = null; // new: heartbeat timer
205
- this._reconnectDebounceMs = 500;
206
- this._reconnectTimeoutId = null;
207
-
208
- // MQTT session tracking & persistence
209
- this._mqttSessionId = null; // actual server-provided mqtt session id (string)
210
- this._mqttSessionPersistIntervalId = null; // periodic persist interval handler
211
-
212
- // Active keepalive/query timer (added)
213
- this._activeKeepaliveTimer = null;
214
-
215
- // Timer for credential refresh
216
- this._mqttAuthRefreshTimer = null;
217
-
218
- // Session health monitor (initialized on connect with enableHealthMonitor option)
219
- this.healthMonitor = null;
220
- // Persistent logger (initialized on connect with enablePersistentLogger option)
221
- this.persistentLogger = null;
222
-
223
- // Persisted identity items that must survive reconnects:
224
- // - clientMqttSessionId must NOT be re-generated each connect
225
- // - _clientContext for EnhancedDirectCommands (for message identity)
226
- if (!this._clientMqttSessionId) {
227
- // generate once for lifetime of this RealtimeClient instance
228
- try {
229
- this._clientMqttSessionId = (BigInt(Date.now()) & BigInt(0xffffffff));
230
- } catch (e) {
231
- this._clientMqttSessionId = BigInt(0);
232
- }
233
- }
234
- if (!this._clientContext) {
235
- // persistent client_context for message sends — single per session
236
- try {
237
- this._clientContext = require('uuid').v4();
238
- } catch (e) {
239
- this._clientContext = `cc_${Date.now()}`;
240
- }
241
- }
242
-
243
- //
244
- // AUTH/PERSISTENCE FOLDER RESOLUTION
245
- // - unify folder selection so we don't miss persisted mqtt-session.json saved under
246
- // different folder names in various versions.
247
- //
248
- try {
249
- const candidates = ['./authinfo_instagram', './auth_info_ig', './auth_info_ig'];
250
- let chosen = null;
251
- for (const c of candidates) {
252
- try {
253
- if (fs.existsSync(c)) {
254
- chosen = c;
255
- break;
256
- }
257
- } catch (e) {}
258
- }
259
- if (!chosen) chosen = './authinfo_instagram';
260
- this._authFolder = chosen;
261
- } catch (e) {
262
- this._authFolder = './authinfo_instagram';
263
- }
264
-
265
- // attempt to load persisted mqtt-session information (if available) to keep continuity across restarts
266
- try {
267
- this._loadPersistedMqttSession();
268
- } catch (e) {
269
- this.realtimeDebug('[MQTT] loadPersistedMqttSession failed:', e?.message || e);
270
- }
271
-
272
- // auto-connect block preserved (no change)
273
- const { useMultiFileAuthState } = require('../useMultiFileAuthState');
274
-
275
- /**
276
- * waitForMqttCredentials(auth, timeoutMs, pollMs)
277
- * - Poll the auth state for device / mqtt credentials before proceeding with auto-connect.
278
- * - This ensures the saved auth state contains the fields required to build the MQTT payload.
279
- */
280
- const waitForMqttCredentials = async (auth, timeoutMs = 15000, pollMs = 250) => {
281
- const start = Date.now();
282
- const hasCreds = () => {
283
- try {
284
- const d = (auth && typeof auth.getData === 'function') ? auth.getData() : (auth && auth.data ? auth.data : null);
285
- if (!d) return false;
286
- if (d.device && (d.device.deviceSecret || d.device.secret)) return true;
287
- if (d.mqttAuth && (d.mqttAuth.jwt || d.mqttAuth.deviceSecret)) return true;
288
- if (d.creds && (d.creds.sessionId || d.creds.csrfToken || d.creds.authorization)) return true;
289
- return false;
290
- } catch (e) {
291
- return false;
292
- }
293
- };
294
- while (Date.now() - start < timeoutMs) {
295
- if (hasCreds()) return true;
296
- await new Promise(r => setTimeout(r, pollMs));
297
- }
298
- return false;
299
- };
300
-
301
- // Auto-start if saved creds exist on disk (non-blocking)
302
- if (fs.existsSync(path.join(this._authFolder, 'creds.json'))) {
303
- setTimeout(async () => {
304
- try {
305
- if (this._mqttConnected || this._connectInProgress) {
306
- this._log('debug', '[REALTIME] Auto-start skipped — MQTT already connected or connect in progress.');
307
- return;
308
- }
309
- const auth = await useMultiFileAuthState(this._authFolder);
310
- this._attachedAuthState = auth;
311
- if (auth.hasSession && auth.hasSession()) {
312
- if (this._mqttConnected || this._connectInProgress) {
313
- this._log('debug', '[REALTIME] Auto-start skipped (after auth load) — MQTT already connected or connect in progress.');
314
- return;
315
- }
316
- this._log('debug', '[REALTIME] Auto-start candidate session detected — loading creds...');
317
- try {
318
- await auth.loadCreds(this.ig);
319
- } catch (e) {
320
- this._log('warn', '[REALTIME] loadCreds warning:', e?.message || e);
321
- }
322
- const ready = await waitForMqttCredentials(auth, 20000, 300);
323
- if (!ready) {
324
- this._log('warn', '[REALTIME] MQTT/device credentials not found within timeout — auto-connect aborted (will still allow manual connect).');
325
- return;
326
- }
327
- if (this._mqttConnected || this._connectInProgress) {
328
- this._log('debug', '[REALTIME] Auto-start skipped (after wait) — MQTT already connected or connect in progress.');
329
- return;
330
- }
331
- this._log('debug', '[REALTIME] Device/MQTT credentials present — attempting connectFromSavedSession...');
332
- try {
333
- await this.connectFromSavedSession(auth);
334
- } catch (e) {
335
- this._log('error', '[REALTIME] Constructor auto-connect failed:', e?.message || e);
336
- }
337
- }
338
- } catch (e) {
339
- this._log('error', '[REALTIME] Constructor auto-start exception:', e?.message || e);
340
- }
341
- }, 100);
342
- }
343
- }
344
-
345
- /**
346
- * _loadPersistedMqttSession()
347
- * - Attempt to read <authFolder>/mqtt-session.json on startup and restore
348
- * client-generated ids so the client can reuse previous session identifiers.
349
- */
350
- _loadPersistedMqttSession() {
351
- try {
352
- const folder = this._authFolder || './authinfo_instagram';
353
- const file = path.join(folder, 'mqtt-session.json');
354
- if (!fs.existsSync(file)) return false;
355
- const raw = fs.readFileSync(file, { encoding: 'utf8' });
356
- const data = JSON.parse(raw);
357
- if (data && data.mqttSessionId) {
358
- // restore clientMqttSessionId (if possible)
359
- try {
360
- // prefer to set local client id if server one is missing
361
- this._mqttSessionId = data.sessionId || null;
362
- if (!this._clientMqttSessionId && data.mqttSessionId) {
363
- // preserve numeric/persistent value as BigInt if possible
364
- try {
365
- this._clientMqttSessionId = BigInt(data.mqttSessionId);
366
- } catch (e) {
367
- // leave as-is if not parseable
368
- }
369
- }
370
- this.realtimeDebug('[MQTT] Loaded persisted mqtt session data from disk.');
371
- return true;
372
- } catch (e) {}
373
- }
374
- } catch (e) {
375
- this.realtimeDebug('[MQTT] _loadPersistedMqttSession error', e?.message || e);
376
- }
377
- return false;
378
- }
379
-
380
- /**
381
- * startRealTimeListener(options)
382
- * - Convenience method to fetch initial inbox (IRIS) and connect with those subscriptions.
383
- */
384
- async startRealTimeListener(options = {}) {
385
- this._connectInProgress = true;
386
- try {
387
- this._log('debug', '[REALTIME] Starting Real-Time Listener...');
388
- this._log('debug', '[REALTIME] Fetching inbox (IRIS data)...');
389
- const inboxData = await this.ig.direct.getInbox();
390
- this._log('debug', '[REALTIME] Connecting to MQTT with IRIS subscription...');
391
- await this.connect({
392
- graphQlSubs: [
393
- 'ig_sub_direct',
394
- 'ig_sub_direct_v2_message_create',
395
- ],
396
- skywalkerSubs: [
397
- 'presence_subscribe',
398
- 'typing_subscribe',
399
- ],
400
- irisData: inboxData
401
- });
402
- this._log('debug', '[REALTIME] MQTT Connected with IRIS');
403
- this._log('debug', '----------------------------------------');
404
- this._log('debug', '[REALTIME] Real-Time Listener ACTIVE');
405
- this._log('debug', '[REALTIME] Waiting for messages...');
406
- this._log('debug', '----------------------------------------');
407
- this._setupMessageHandlers();
408
-
409
- if (options.enableHealthMonitor !== false) {
410
- this.enableHealthMonitor(options.healthMonitorOptions || options);
411
- }
412
- if (options.enablePersistentLogger || options.logDir) {
413
- this.enablePersistentLogger(options.persistentLoggerOptions || options);
414
- }
415
-
416
- return { success: true };
417
- } catch (error) {
418
- this._log('error', '[REALTIME] Failed:', error.message);
419
- throw error;
420
- }
421
- }
422
-
423
- _setupMessageHandlers() {
424
- this.on('message', (data) => {
425
- const msg = this._parseMessage(data);
426
- if (msg) this.emit('message_live', msg);
427
- });
428
- this.on('iris', (data) => {
429
- const msg = this._parseIrisMessage(data);
430
- if (msg) this.emit('message_live', msg);
431
- });
432
- this.on('receive', (topic, messages) => {
433
- try {
434
- const topicPath = topic.path || '';
435
- for (const msg of (Array.isArray(messages) ? messages : [messages])) {
436
- const data = msg?.data || msg;
437
- if (!data) continue;
438
- switch (topicPath) {
439
- case '/ig_msg_dr':
440
- this.emit('deliveryReceipt', {
441
- threadId: data.thread_id || data.threadId,
442
- itemId: data.item_id || data.itemId,
443
- userId: data.user_id || data.userId,
444
- timestamp: data.timestamp || Date.now(),
445
- raw: data,
446
- });
447
- break;
448
- case '/ig_conn_update':
449
- this.emit('connectionUpdate', {
450
- type: data.type || data.event,
451
- reason: data.reason,
452
- raw: data,
453
- });
454
- break;
455
- case '/notify_disconnect':
456
- this.emit('notifyDisconnect', {
457
- reason: data.reason || data.message,
458
- code: data.code,
459
- raw: data,
460
- });
461
- break;
462
- case '/t_thread_typing':
463
- this.emit('threadTyping', {
464
- threadId: data.thread_id || data.threadId,
465
- userId: data.user_id || data.sender_id,
466
- isTyping: data.activity_status !== undefined ? data.activity_status === 1 : (data.is_typing !== false),
467
- timestamp: data.timestamp || Date.now(),
468
- raw: data,
469
- });
470
- break;
471
- case '/iris_server_reset':
472
- this.realtimeDebug('[IRIS] Server reset received, re-subscribing...');
473
- this.emit('irisServerReset', { raw: data });
474
- this._handleIrisReset();
475
- break;
476
- case '/t_ig_family_navigation_badge':
477
- this.emit('badgeCount', {
478
- count: data.badge_count ?? data.count ?? data.total,
479
- dmCount: data.dm_count ?? data.direct_count,
480
- activityCount: data.activity_count,
481
- raw: data,
482
- });
483
- break;
484
- case '/t_entity_presence':
485
- this.emit('entityPresence', {
486
- userId: data.user_id || data.entity_id,
487
- isActive: data.is_active ?? data.active ?? false,
488
- lastActivityAt: data.last_activity_at_ms || data.last_activity_at,
489
- raw: data,
490
- });
491
- break;
492
- case '/opened_thread':
493
- this.emit('threadOpened', {
494
- threadId: data.thread_id || data.threadId,
495
- userId: data.user_id,
496
- raw: data,
497
- });
498
- break;
499
- case '/buddy_list':
500
- this.emit('buddyList', {
501
- users: data.overlay || data.buddies || data,
502
- raw: data,
503
- });
504
- break;
505
- case '/webrtc':
506
- case '/webrtc_response':
507
- this.emit('callEvent', {
508
- type: data.event || data.type || (topicPath === '/webrtc' ? 'offer' : 'answer'),
509
- callId: data.call_id || data.video_call_id,
510
- peerId: data.peer_id || data.caller_id || data.user_id,
511
- sdp: data.sdp,
512
- raw: data,
513
- });
514
- break;
515
- case '/onevc':
516
- this.emit('callEvent', {
517
- type: data.event || data.action || 'onevc',
518
- callId: data.call_id || data.video_call_id,
519
- peerId: data.peer_id || data.caller_id,
520
- raw: data,
521
- });
522
- break;
523
- case '/graphql':
524
- this._handleGraphQLEvent(data);
525
- break;
526
- case '/pubsub':
527
- this._handlePubsubEvent(data);
528
- break;
529
- }
530
- }
531
- } catch (e) {
532
- this.realtimeDebug('[EVENT_HANDLER] Error processing topic event:', e?.message || e);
533
- }
534
- });
535
- }
536
-
537
- async _handleIrisReset() {
538
- try {
539
- this.realtimeDebug('[IRIS_RESET] Attempting to re-subscribe after server reset...');
540
- const inboxData = await this.ig.direct.getInbox();
541
- if (inboxData) {
542
- await this.irisSubscribe(inboxData);
543
- this.realtimeDebug('[IRIS_RESET] Re-subscribed successfully');
544
- }
545
- } catch (e) {
546
- this.realtimeDebug('[IRIS_RESET] Failed to re-subscribe:', e?.message || e);
547
- }
548
- }
549
-
550
- _handleGraphQLEvent(data) {
551
- try {
552
- const json = data.json || data;
553
- const event = json?.event || json?.data?.event;
554
- const payload = json?.data || json;
555
- if (!payload) return;
556
-
557
- if (payload.live_broadcast_comments) {
558
- this.emit('liveComment', {
559
- broadcastId: payload.broadcast_id,
560
- comments: payload.live_broadcast_comments,
561
- raw: payload,
562
- });
563
- }
564
- if (payload.live_broadcast_like_count !== undefined) {
565
- this.emit('liveLikeCount', {
566
- broadcastId: payload.broadcast_id,
567
- likeCount: payload.live_broadcast_like_count,
568
- raw: payload,
569
- });
570
- }
571
- if (payload.live_broadcast_wave) {
572
- this.emit('liveWave', {
573
- broadcastId: payload.broadcast_id,
574
- wave: payload.live_broadcast_wave,
575
- raw: payload,
576
- });
577
- }
578
- if (payload.live_broadcast_typing_indicator) {
579
- this.emit('liveTyping', {
580
- broadcastId: payload.broadcast_id,
581
- userId: payload.user_id,
582
- raw: payload,
583
- });
584
- }
585
- if (payload.live_viewer_count !== undefined) {
586
- this.emit('liveViewerCount', {
587
- broadcastId: payload.broadcast_id,
588
- viewerCount: payload.live_viewer_count,
589
- raw: payload,
590
- });
591
- }
592
- if (payload.media_feedback || payload.feedback_action) {
593
- this.emit('mediaFeedback', {
594
- mediaId: payload.media_id || payload.feedback_id,
595
- action: payload.feedback_action || payload.action_type,
596
- userId: payload.user_id,
597
- raw: payload,
598
- });
599
- }
600
- if (payload.direct_typing || payload.activity_indicator_id) {
601
- this.emit('directTyping', {
602
- userId: payload.user_id || payload.sender_id,
603
- threadId: payload.thread_id || payload.activity_indicator_id,
604
- timestamp: payload.timestamp,
605
- raw: payload,
606
- });
607
- }
608
- if (payload.presence_event || payload.user_presence) {
609
- this.emit('appPresence', {
610
- userId: payload.user_id,
611
- isActive: payload.is_active ?? payload.active,
612
- lastActivityAt: payload.last_activity_at_ms,
613
- raw: payload,
614
- });
615
- }
616
- if (payload.direct_status) {
617
- this.emit('directStatus', payload);
618
- }
619
- if (payload.interactivity) {
620
- this.emit('liveInteractivity', {
621
- broadcastId: payload.broadcast_id,
622
- data: payload.interactivity,
623
- raw: payload,
624
- });
625
- }
626
- if (payload.video_call_participant_state) {
627
- this.emit('callStateChange', {
628
- callId: payload.video_call_id,
629
- participants: payload.video_call_participant_state,
630
- raw: payload,
631
- });
632
- }
633
- this.emit('graphqlEvent', { event, payload, raw: data });
634
- } catch (e) {
635
- this.realtimeDebug('[GRAPHQL_EVENT] Parse error:', e?.message || e);
636
- }
637
- }
638
-
639
- _handlePubsubEvent(data) {
640
- try {
641
- const json = data.json || data;
642
- const payload = json?.data || json;
643
- if (!payload) return;
644
-
645
- if (payload.doublePublish) return;
646
-
647
- if (payload.event === 'patch' || payload.op) {
648
- this.emit('direct', {
649
- op: payload.op,
650
- path: payload.path,
651
- value: payload.value,
652
- threadId: payload.thread_id,
653
- raw: payload,
654
- });
655
- }
656
- if (payload.activity_indicator_id || (payload.event === 'typing')) {
657
- this.emit('directTyping', {
658
- userId: payload.user_id || payload.sender_id,
659
- threadId: payload.thread_id || payload.activity_indicator_id,
660
- isTyping: payload.activity_status !== 0,
661
- raw: payload,
662
- });
663
- }
664
- this.emit('pubsubEvent', { payload, raw: data });
665
- } catch (e) {
666
- this.realtimeDebug('[PUBSUB_EVENT] Parse error:', e?.message || e);
667
- }
668
- }
669
-
670
- // Parse a standard realtime message packet into a simplified message object
671
- _parseMessage(data) {
672
- try {
673
- const msg = data.message;
674
- if (!msg) return null;
675
- if (data.parsed) return data.parsed;
676
- const threadInfo = this.threads.get(msg.thread_id);
677
- return {
678
- id: msg.item_id || msg.id,
679
- userId: msg.user_id || msg.from_user_id,
680
- username: msg.username || msg.from_username || `user_${msg.user_id || 'unknown'}`,
681
- text: msg.text || msg.body || '',
682
- itemType: msg.item_type || 'text',
683
- thread: threadInfo?.title || `Thread ${msg.thread_id}`,
684
- thread_id: msg.thread_id,
685
- timestamp: msg.timestamp,
686
- isGroup: threadInfo?.isGroup,
687
- status: 'good'
688
- };
689
- } catch (e) {
690
- return null;
691
- }
692
- }
693
-
694
- // Parse IRIS message data into a simplified message object
695
- _parseIrisMessage(data) {
696
- try {
697
- if (data.event !== 'message_create' && !data.type?.includes('message')) return null;
698
- return {
699
- id: data.item_id || data.id,
700
- userId: data.user_id || data.from_user_id,
701
- username: data.username || data.from_username || `user_${data.user_id || 'unknown'}`,
702
- text: data.text || '',
703
- itemType: data.item_type || 'text',
704
- thread_id: data.thread_id,
705
- timestamp: data.timestamp,
706
- status: 'good'
707
- };
708
- } catch (e) {
709
- return null;
710
- }
711
- }
712
-
713
- /**
714
- * setInitOptions(initOptions)
715
- * - Normalizes init options for connect calls (accepts array or object)
716
- */
717
- setInitOptions(initOptions) {
718
- if (Array.isArray(initOptions))
719
- initOptions = { graphQlSubs: initOptions };
720
- this.initOptions = {
721
- graphQlSubs: [],
722
- skywalkerSubs: [],
723
- ...(initOptions || {}),
724
- socksOptions: typeof initOptions === 'object' && !Array.isArray(initOptions) ? initOptions.socksOptions : undefined,
725
- };
726
- }
727
-
728
- // Extract session ID from a JWT-like authorization header if present
729
- extractSessionIdFromJWT() {
730
- try {
731
- const authHeader = this.ig.state.authorization;
732
- if (!authHeader) return null;
733
- const raw = String(authHeader || '');
734
- const candidate = raw.replace(/^Bearer\s*/i, '').replace(/^IGT:2:/i, '');
735
- if (candidate.includes('.')) {
736
- const parts = candidate.split('.');
737
- if (parts.length >= 2) {
738
- try {
739
- const payload = Buffer.from(parts[1], 'base64').toString('utf8');
740
- const parsed = JSON.parse(payload);
741
- return parsed.sessionid || parsed.session_id || parsed.session || null;
742
- } catch (e) {}
743
- }
744
- }
745
- try {
746
- const decoded = Buffer.from(candidate, 'base64').toString('utf8');
747
- const parsed = JSON.parse(decoded);
748
- return parsed.sessionid || parsed.session_id || null;
749
- } catch (e) {}
750
- return null;
751
- } catch (e) {
752
- return null;
753
- }
754
- }
755
-
756
- /**
757
- * constructConnection()
758
- * - Build the MQTToTConnection payload (thrift object) used to connect.
759
- * - Pulls deviceId, sessionid, device secrets and app-specific headers to populate the payload.
760
- */
761
- constructConnection() {
762
- // Choose the best available user agent value from state fallbacks
763
- const userAgent =
764
- typeof this.ig.state.userAgent === 'string'
765
- ? this.ig.state.userAgent
766
- : typeof this.ig.state.appUserAgent === 'string'
767
- ? this.ig.state.appUserAgent
768
- : typeof this.ig.state.deviceString === 'string'
769
- ? this.ig.state.deviceString
770
- : 'Instagram 415.0.0.36.76 Android (34/14; 420dpi; 1080x2340; samsung; SM-S911B; e1s; exynos2400; en_US; 580610226)';
771
-
772
- // deviceId / phoneId fallback handling (string coercion)
773
- const deviceId = String(this.ig.state.phoneId || this.ig.state.deviceId || 'device_unknown');
774
-
775
- // attempt to extract sessionid from various locations: Authorization JWT, cookie helpers, state fields, or cookie jar
776
- let sessionid = null;
777
- try {
778
- sessionid = this.extractSessionIdFromJWT();
779
- } catch (e) { sessionid = null; }
780
-
781
- if (!sessionid) {
782
- try {
783
- if (typeof this.ig.state.extractCookieValue === 'function') {
784
- sessionid = this.ig.state.extractCookieValue('sessionid');
785
- }
786
- } catch (e) { sessionid = null; }
787
- }
788
-
789
- if (!sessionid) {
790
- try {
791
- sessionid = this.ig.state.sessionId || this.ig.state.sessionid || this.ig.state.cookies?.sessionid || null;
792
- } catch (e) { sessionid = null; }
793
- }
794
-
795
- if (!sessionid) {
796
- try {
797
- if (this.ig.state.cookieJar && typeof this.ig.state.cookieJar.getCookiesSync === 'function') {
798
- const cookies = this.ig.state.cookieJar.getCookiesSync('https://i.instagram.com/') || [];
799
- const found = cookies.find(c => (c.key === 'sessionid' || c.name === 'sessionid'));
800
- if (found) sessionid = found.value;
801
- }
802
- } catch (e) {}
803
- }
804
-
805
- // fallback sessionid generation — only used if nothing else found
806
- if (!sessionid) {
807
- const userId = this.ig.state.cookieUserId || this.ig.state.userId || '0';
808
- sessionid = String(userId) + '_' + Date.now();
809
- this.realtimeDebug(`SessionID generated (fallback): ${sessionid}`);
810
- }
811
-
812
- // device secret retrieval (from attached auth helper or state)
813
- let deviceSecret = null;
814
- try {
815
- if (this._attachedAuthState && typeof this._attachedAuthState.getData === 'function') {
816
- const d = this._attachedAuthState.getData();
817
- if (d && d.device && (d.device.deviceSecret || d.device.secret)) {
818
- deviceSecret = d.device.deviceSecret || d.device.secret;
819
- }
820
- if (!deviceSecret && d && d.mqttAuth && (d.mqttAuth.deviceSecret || d.mqttAuth.secret)) {
821
- deviceSecret = d.mqttAuth.deviceSecret || d.mqttAuth.secret;
822
- }
823
- }
824
- } catch (e) {}
825
- try {
826
- if (!deviceSecret && (this.ig.state.deviceSecret || this.ig.state.mqttDeviceSecret)) {
827
- deviceSecret = this.ig.state.deviceSecret || this.ig.state.mqttDeviceSecret;
828
- }
829
- } catch (e) {}
830
-
831
- // mqtt JWT token if available (preferred)
832
- let mqttJwt = null;
833
- try {
834
- if (this._attachedAuthState && typeof this._attachedAuthState.getData === 'function') {
835
- const d = this._attachedAuthState.getData();
836
- if (d && d.mqttAuth && d.mqttAuth.jwt) mqttJwt = d.mqttAuth.jwt;
837
- }
838
- if (!mqttJwt && this.ig.state.mqttJwt) mqttJwt = this.ig.state.mqttJwt;
839
- } catch (e) {}
840
-
841
- // password is either "jwt=..." or "sessionid=..."
842
- let password;
843
- if (mqttJwt) {
844
- password = `jwt=${mqttJwt}`;
845
- } else {
846
- password = `sessionid=${sessionid}`;
847
- }
848
-
849
- // client type indicates if device secret is available
850
- const clientType = deviceSecret ? 'secure_cookie_auth' : 'cookie_auth';
851
-
852
- // IMPORTANT: keep clientMqttSessionId persistent across reconnects (already set in constructor)
853
- if (!this._clientMqttSessionId) {
854
- try {
855
- this._clientMqttSessionId = (BigInt(Date.now()) & BigInt(0xffffffff));
856
- } catch (e) {
857
- this._clientMqttSessionId = BigInt(0);
858
- }
859
- }
860
- const clientMqttSessionId = this._clientMqttSessionId;
861
-
862
- const subscribeTopics = [88, 135, 149, 150, 133, 146, 165, 164, 176, 195, 141, 152, 160, 139, 0, 62, 63, 211];
863
-
864
- // Build the thrift connection object using mqttot.MQTToTConnection
865
- // NOTE: use deviceId.substring(0,20) for clientIdentifier because the mobile app often truncates it.
866
- // endpointCapabilities set to 128 for broader compatibility (some clients use 0, 128 provides better capability advertising).
867
- this.connection = new mqttot_1.MQTToTConnection({
868
- clientIdentifier: deviceId.substring(0, 20),
869
- clientInfo: {
870
- userId: BigInt(String(this.ig.state.cookieUserId || this.ig.state.userId || '0')), // keep full precision (avoid Number() > 2^53),
871
- userAgent,
872
- clientCapabilities: 439,
873
- endpointCapabilities: 128,
874
- publishFormat: 1,
875
- noAutomaticForeground: false,
876
- makeUserAvailableInForeground: true,
877
- deviceId,
878
- isInitiallyForeground: true,
879
- networkType: 1,
880
- networkSubtype: 0,
881
- clientMqttSessionId: clientMqttSessionId,
882
- subscribeTopics,
883
- clientType,
884
- appId: BigInt(567067343352427),
885
- deviceSecret: deviceSecret || '',
886
- clientStack: 3,
887
- ...(this.initOptions?.connectOverrides || {}),
888
- },
889
- password,
890
- appSpecificInfo: {
891
- // Use exported INSTAGRAM_VERSION automatically, fallback to this.ig.state.appVersion if missing
892
- app_version: INSTAGRAM_VERSION || this.ig.state.appVersion,
893
- 'X-IG-Capabilities': this.ig.state.capabilitiesHeader,
894
- everclear_subscriptions: JSON.stringify({
895
- inapp_notification_subscribe_comment: '17899377895239777',
896
- inapp_notification_subscribe_comment_mention_and_reply: '17899377895239777',
897
- video_call_participant_state_delivery: '17977239895057311',
898
- presence_subscribe: '17846944882223835',
899
- }),
900
- // Extra app-specific fields observed in the mobile APK (helps the server identify the client capabilities)
901
- 'User-Agent': userAgent,
902
- 'Accept-Language': (this.ig.state.language || 'en_US').replace('_', '-'),
903
- platform: 'android',
904
- ig_mqtt_route: 'django',
905
- pubsub_msg_type_blacklist: 'direct, typing_type',
906
- auth_cache_enabled: '0',
907
- },
908
- });
909
- }
910
-
911
- /**
912
- * connect(options)
913
- * - Creates the MQTToTClient using mqttot.MQTToTClient and the payloadProvider.
914
- * - Attaches idempotent lifecycle handlers for connect/close/error.
915
- * - Starts keepalive/watchdog timers and message listeners after successful connect.
916
- */
917
- async connect(options) {
918
- this._connectInProgress = true;
919
- try {
920
- this.setInitOptions(options);
921
- this.constructConnection();
922
- const { MQTToTClient } = require("../mqttot");
923
- const { compressDeflate } = require("../shared");
924
-
925
- if (this._mqtt) {
926
- try { this._mqtt.removeAllListeners(); } catch (_e) {}
927
- try { this._mqtt._stopKeepalive(); } catch (_e) {}
928
- try { this._mqtt.disconnect(); } catch (_e) {}
929
- this._mqtt = null;
930
- }
931
-
932
- this._mqtt = new MQTToTClient({
933
- url: 'edge-mqtt.facebook.com',
934
- payloadProvider: async () => {
935
- return await compressDeflate(this.connection.toThrift());
936
- },
937
- autoReconnect: false,
938
- requirePayload: false,
939
- });
940
-
941
- // attach lifecycle handlers idempotent (create once)
942
- try {
943
- if (typeof this._attachMqttLifecycle !== 'function') {
944
- this._attachMqttLifecycle = async () => {
945
- if (!this._mqtt) return;
946
- try {
947
- this._mqtt.on('connect', async () => {
948
- this.realtimeDebug('[MQTT] client emitted connect');
949
- try {
950
- // After normal after-connect handlers, try extract session id and persist it
951
- await this._afterConnectHandlers();
952
- } catch (e) {
953
- this.realtimeDebug('[MQTT] afterConnect error', e?.message || e);
954
- }
955
- // After everything, attempt to detect and persist MQTT session id
956
- try {
957
- await this._onMqttConnected();
958
- } catch (e) {
959
- this.realtimeDebug('[MQTT] _onMqttConnected error', e?.message || e);
960
- }
961
- });
962
- } catch (e) {}
963
- try {
964
- this._mqtt.on('close', async () => {
965
- this.realtimeDebug('[MQTT] client close event');
966
- this._lastMessageAt = Date.now();
967
- try { await this._persistMqttSession(); } catch (e) {}
968
- this._mqttConnected = false;
969
- this._connectInProgress = false;
970
- this.emit('mqtt_disconnected');
971
- if (this._reconnectInProgress) {
972
- this.realtimeDebug('[MQTT] close event ignored — reconnect already in progress');
973
- return;
974
- }
975
- if (this.safeDisconnect) {
976
- this.realtimeDebug('[MQTT] close event ignored — safe disconnect');
977
- return;
978
- }
979
- if (this._reconnectTimeoutId) clearTimeout(this._reconnectTimeoutId);
980
- this._reconnectTimeoutId = setTimeout(async () => {
981
- try { await this._attemptReconnectSafely(); } catch (e) {}
982
- }, this._reconnectDebounceMs);
983
- });
984
- } catch (e) {}
985
- try {
986
- this._mqtt.on('error', (err) => {
987
- this.realtimeDebug('[MQTT] client error:', err?.message || err);
988
- this.emit('mqtt_error', err);
989
- if (this._reconnectInProgress) {
990
- this.realtimeDebug('[MQTT] error event ignored — reconnect already in progress');
991
- return;
992
- }
993
- if (this.safeDisconnect) return;
994
- if (this._reconnectTimeoutId) clearTimeout(this._reconnectTimeoutId);
995
- const debounceMs = (this.errorHandler && this.errorHandler.isRateLimited())
996
- ? this.errorHandler.getRateLimitRemainingMs()
997
- : this._reconnectDebounceMs;
998
- this._reconnectTimeoutId = setTimeout(async () => {
999
- try { await this._attemptReconnectSafely(err); } catch (e) {}
1000
- }, debounceMs);
1001
- });
1002
- } catch (e) {}
1003
- };
1004
- }
1005
- try { await this._attachMqttLifecycle(); } catch (e) {}
1006
- } catch (e) {}
1007
-
1008
- // actually connect the mqtt client (this will emit connect when done)
1009
- await this._mqtt.connect();
1010
-
1011
- // Commands uses mqtt client; Commands.updateSubscriptions has been set to use qos 0.
1012
- this.commands = new commands_1.Commands(this._mqtt);
1013
-
1014
- // Notify higher-level code that we are connected
1015
- this._mqttConnected = true;
1016
- this._connectInProgress = false;
1017
- this.emit('connected');
1018
- this.emit('mqtt_connected');
1019
-
1020
- // WATCHDOG / KEEPALIVE / TRAFFIC MONITOR (rationalized - 2 primary timers + 1 watchdog)
1021
- try {
1022
- this._lastMessageAt = Date.now();
1023
- this._lastServerTrafficAt = Date.now();
1024
- const updateLast = () => { try { this._lastMessageAt = Date.now(); this._lastServerTrafficAt = Date.now(); } catch (e) {} };
1025
- this.on('receive', updateLast);
1026
- this.on('receiveRaw', updateLast);
1027
- this.on('message', updateLast);
1028
- this.on('iris', updateLast);
1029
-
1030
- const KEEPALIVE_FOREGROUND_MS = (this.initOptions && this.initOptions.keepaliveForegroundMs) ? this.initOptions.keepaliveForegroundMs : 45000; // 45s keepalive pulse
1031
- const MESSAGE_SYNC_REFRESH_MS = (this.initOptions && this.initOptions.messageSyncRefreshMs) ? this.initOptions.messageSyncRefreshMs : 300000;
1032
- const TRAFFIC_INACTIVITY_MS = (this.initOptions && this.initOptions.trafficInactivityMs) ? this.initOptions.trafficInactivityMs : 180000; // 3 min default for faster recovery
1033
- const HEARTBEAT_MS = (this.initOptions && this.initOptions.heartbeatMs) ? this.initOptions.heartbeatMs : 90000; // 90s mobile-like heartbeat
1034
-
1035
- try {
1036
- if (this._foregroundTimer) clearInterval(this._foregroundTimer);
1037
- this._foregroundTimer = setInterval(async () => {
1038
- try {
1039
- if (!this.commands) return;
1040
- await this.commands.updateSubscriptions({
1041
- topic: constants_1.Topics.PUBSUB,
1042
- data: { foreground: true }
1043
- });
1044
- this._lastMessageAt = Date.now();
1045
- this.realtimeDebug('[KEEPALIVE] Foreground pulse sent.');
1046
- } catch (e) {
1047
- this.realtimeDebug('[KEEPALIVE] Foreground pulse failed:', e?.message || e);
1048
- }
1049
- }, KEEPALIVE_FOREGROUND_MS + Math.floor(Math.random() * 5000));
1050
- } catch (e) {
1051
- this.realtimeDebug('[KEEPALIVE] Could not start foreground timer:', e?.message || e);
1052
- }
1053
-
1054
- try {
1055
- if (this._syncTimer) clearInterval(this._syncTimer);
1056
- this._syncTimer = setInterval(async () => {
1057
- try {
1058
- if (!this.commands) return;
1059
- const subs = (this.initOptions && this.initOptions.graphQlSubs && this.initOptions.graphQlSubs.length) ? this.initOptions.graphQlSubs : this.defaultGraphQlSubs;
1060
- await this.graphQlSubscribe(subs);
1061
- this._lastMessageAt = Date.now();
1062
- this.realtimeDebug('[KEEPALIVE] GraphQL subs refreshed.');
1063
- } catch (e) {
1064
- this.realtimeDebug('[KEEPALIVE] GraphQL refresh failed:', e?.message || e);
1065
- }
1066
- }, MESSAGE_SYNC_REFRESH_MS + Math.floor(Math.random() * 10000));
1067
- } catch (e) {
1068
- this.realtimeDebug('[KEEPALIVE] Could not start sync timer:', e?.message || e);
1069
- }
1070
-
1071
- try {
1072
- if (this._trafficWatchdog) clearInterval(this._trafficWatchdog);
1073
- this._trafficWatchdog = setInterval(async () => {
1074
- try {
1075
- const idle = Date.now() - (this._lastServerTrafficAt || 0);
1076
- if (idle > TRAFFIC_INACTIVITY_MS) {
1077
- this.realtimeDebug(`[WATCHDOG] No server traffic for ${Math.round(idle/1000)}s -> attempting reconnect`);
1078
- try {
1079
- if (this._mqtt && typeof this._mqtt.ping === 'function') {
1080
- await this._mqtt.ping();
1081
- this._lastMessageAt = Date.now();
1082
- this.realtimeDebug('[WATCHDOG] Ping succeeded, connection is alive.');
1083
- return;
1084
- }
1085
- } catch (e) {
1086
- this.realtimeDebug('[WATCHDOG] Ping failed, proceeding with reconnect:', e?.message || e);
1087
- }
1088
- await this._attemptReconnectSafely();
1089
- }
1090
- } catch (e) {
1091
- this.realtimeDebug('[WATCHDOG] trafficWatchdog fault:', e?.message || e);
1092
- }
1093
- }, 60000);
1094
- } catch (e) {
1095
- this.realtimeDebug('[WATCHDOG] Could not start traffic watchdog:', e?.message || e);
1096
- }
1097
-
1098
- try {
1099
- if (this._heartbeatTimer) clearInterval(this._heartbeatTimer);
1100
- this._heartbeatTimer = setInterval(async () => {
1101
- try {
1102
- if (this._mqtt && typeof this._mqtt.ping === 'function') {
1103
- try {
1104
- await this._mqtt.ping();
1105
- this._lastMessageAt = Date.now();
1106
- this.realtimeDebug('[HEARTBEAT] mqtt.ping() ok.');
1107
- } catch (e) {
1108
- this.realtimeDebug('[HEARTBEAT] mqtt.ping failed:', e?.message || e);
1109
- }
1110
- }
1111
- } catch (e) {
1112
- this.realtimeDebug('[HEARTBEAT] fault:', e?.message || e);
1113
- }
1114
- }, HEARTBEAT_MS + Math.floor(Math.random() * 5000));
1115
- } catch (e) {
1116
- this.realtimeDebug('[HEARTBEAT] Could not start heartbeat timer:', e?.message || e);
1117
- }
1118
-
1119
- } catch (e) {
1120
- this.realtimeDebug('[WATCHDOG] initialization error:', e?.message || e);
1121
- }
1122
-
1123
- /**
1124
- * Set up on-message handler:
1125
- * - Messages arriving from low-level MQTT are looked up in mqtt.topicMap,
1126
- * then parsed by the topic's parser if available. Otherwise payload is emitted as raw.
1127
- */
1128
- this._mqtt.on('message', async (msg) => {
1129
- const topicMap = this.mqtt?.topicMap;
1130
- const topic = topicMap?.get(msg.topic);
1131
- if (topic && topic.parser && !topic.noParse) {
1132
- try {
1133
- const unzipped = await (0, shared_1.tryUnzipAsync)(msg.payload);
1134
- const parsedMessages = topic.parser.parseMessage(topic, unzipped);
1135
- this.emit('receive', topic, Array.isArray(parsedMessages) ? parsedMessages : [parsedMessages]);
1136
- } catch(e) {}
1137
- } else {
1138
- try {
1139
- await (0, shared_1.tryUnzipAsync)(msg.payload);
1140
- this.emit('receiveRaw', msg);
1141
- } catch(e) {}
1142
- }
1143
- });
1144
- // propagate mqtt errors to RealtimeClient error handler
1145
- this._mqtt.on('error', this.emitError);
1146
-
1147
- try { await this._afterConnectHandlers(); } catch (e) { this.realtimeDebug('[MQTT] afterConnectHandlers failed', e?.message || e); }
1148
-
1149
- // Initial subscriptions / iris
1150
- await (0, shared_1.delay)(100);
1151
- if (this.initOptions.graphQlSubs && this.initOptions.graphQlSubs.length > 0) {
1152
- await this.graphQlSubscribe(this.initOptions.graphQlSubs);
1153
- } else {
1154
- // ensure defaults if none provided
1155
- await this.graphQlSubscribe(this.defaultGraphQlSubs);
1156
- }
1157
- if (this.initOptions.irisData) {
1158
- await this.irisSubscribe(this.initOptions.irisData);
1159
- } else {
1160
- try {
1161
- this._log('debug', '[REALTIME] Auto-fetching IRIS data...');
1162
- const autoIrisData = await this.ig.direct.getInbox();
1163
- if (autoIrisData) {
1164
- await this.irisSubscribe(autoIrisData);
1165
- this._log('debug', '[REALTIME] IRIS subscription successful');
1166
- }
1167
- } catch (e) {
1168
- this._log('debug', '[REALTIME] Could not auto-fetch IRIS data:', e.message);
1169
- }
1170
- }
1171
- if ((this.initOptions.skywalkerSubs ?? []).length > 0) {
1172
- await this.skywalkerSubscribe(this.initOptions.skywalkerSubs);
1173
- } else {
1174
- // ensure default skywalker subs if none provided
1175
- await this.skywalkerSubscribe(this.defaultSkywalkerSubs);
1176
- }
1177
- await (0, shared_1.delay)(100);
1178
- try {
1179
- await this.ig.direct.getInbox();
1180
- try {
1181
- await this.ig.request.send({
1182
- url: '/api/v1/direct_v2/threads/get_most_recent_message/',
1183
- method: 'POST',
1184
- });
1185
- } catch(e) {}
1186
- } catch (error) {}
1187
- this._setupMessageHandlers();
1188
-
1189
- // Active query keepalive disabled - redundant with rationalized foreground + heartbeat timers
1190
- // The foreground timer (60s) and heartbeat (90s) provide sufficient keepalive coverage
1191
- // without generating excessive traffic that could trigger Instagram rate limiting
1192
- } catch (connectError) {
1193
- this._connectInProgress = false;
1194
- throw connectError;
1195
- }
1196
- }
1197
-
1198
- /**
1199
- * Attempt to detect server-provided MQTT session id and persist it.
1200
- * This method is defensive: it tries multiple places on the mqtt client object.
1201
- *
1202
- * Also: schedule credential refresh if mqttAuth.expiresAt is present (so tokens are refreshed
1203
- * before they expire).
1204
- */
1205
- async _onMqttConnected() {
1206
- try {
1207
- let found = null;
1208
- try {
1209
- const mqtt = this._mqtt;
1210
- if (mqtt) {
1211
- // try common accessor first
1212
- if (typeof mqtt.getSessionId === 'function') {
1213
- try { found = mqtt.getSessionId(); } catch (e) {}
1214
- }
1215
- // try common property names (defensive)
1216
- if (!found && mqtt.sessionId) found = mqtt.sessionId;
1217
- if (!found && mqtt._sessionId) found = mqtt._sessionId;
1218
- // some clients keep last connack info
1219
- if (!found && mqtt.lastConnack && mqtt.lastConnack.sessionId) found = mqtt.lastConnack.sessionId;
1220
- if (!found && mqtt.connack && mqtt.connack.sessionId) found = mqtt.connack.sessionId;
1221
- // fallback to connection.clientInfo.clientMqttSessionId (local id)
1222
- if (!found && this.connection && this.connection.clientInfo && this.connection.clientInfo.clientMqttSessionId) {
1223
- try { found = String(this.connection.clientInfo.clientMqttSessionId); } catch (e) {}
1224
- }
1225
- }
1226
- } catch (e) {}
1227
- // If no server-provided id was found, fall back to the persistent client id (if present) or 'boot'
1228
- if (!found) {
1229
- if (this._clientMqttSessionId) {
1230
- try {
1231
- found = String(this._clientMqttSessionId);
1232
- this.realtimeDebug('[MQTT] No server mqttSessionId yet — falling back to clientMqttSessionId.');
1233
- } catch (e) {
1234
- // ignore and keep found null
1235
- }
1236
- } else {
1237
- // final fallback
1238
- found = 'boot';
1239
- this.realtimeDebug('[MQTT] No mqttSessionId available — using boot fallback.');
1240
- }
1241
- }
1242
- if (found) {
1243
- this._mqttSessionId = String(found);
1244
- this.realtimeDebug(`[MQTT] detected mqttSessionId: ${this._mqttSessionId}`);
1245
- // emit event for consumers
1246
- try { this.emit('mqtt_session', this._mqttSessionId); } catch (e) {}
1247
- // persist it right away
1248
- try { await this._persistMqttSession(); } catch (e) { this.realtimeDebug('[MQTT] persist after connect failed', e?.message || e); }
1249
- // start periodic persist if not already (persist every 4 hours to avoid excessive I/O and detection)
1250
- if (!this._mqttSessionPersistIntervalId) {
1251
- try {
1252
- this._mqttSessionPersistIntervalId = setInterval(() => {
1253
- try { this._persistMqttSession(); } catch (e) {}
1254
- }, 4 * 60 * 60 * 1000); // every 4 hours
1255
- } catch (e) {}
1256
- }
1257
- } else {
1258
- this.realtimeDebug('[MQTT] mqttSessionId not found on client after connect (will attempt again on subsequent connects)');
1259
- }
1260
-
1261
- //
1262
- // SCHEDULE CREDENTIAL REFRESH (if auth helper provided mqttAuth.expiresAt).
1263
- // We schedule a timer to refresh credentials some seconds before expiry and then attempt a
1264
- // graceful reconnect so the new token is used.
1265
- //
1266
- try {
1267
- // clear any previous timer
1268
- if (this._mqttAuthRefreshTimer) {
1269
- try { clearTimeout(this._mqttAuthRefreshTimer); } catch (e) {}
1270
- this._mqttAuthRefreshTimer = null;
1271
- }
1272
- if (this._attachedAuthState && typeof this._attachedAuthState.getData === 'function') {
1273
- try {
1274
- const d = this._attachedAuthState.getData();
1275
- const mqttAuth = d?.mqttAuth;
1276
- if (mqttAuth && mqttAuth.expiresAt) {
1277
- const expires = new Date(mqttAuth.expiresAt).getTime();
1278
- if (!isNaN(expires)) {
1279
- // refresh 60 seconds before expiry (buffer)
1280
- const msBefore = expires - Date.now() - (60 * 1000);
1281
- if (msBefore > 0) {
1282
- this.realtimeDebug(`[CREDENTIAL_REFRESH] scheduling mqttAuth refresh in ${msBefore}ms (expiresAt: ${mqttAuth.expiresAt})`);
1283
- this._mqttAuthRefreshTimer = setTimeout(async () => {
1284
- try {
1285
- this.realtimeDebug('[CREDENTIAL_REFRESH] timer fired - attempting refresh');
1286
- const refreshed = await this._refreshMqttCredentials();
1287
- if (refreshed) {
1288
- try {
1289
- // rebuild payload and attempt reconnect so new token is used
1290
- this.constructConnection();
1291
- } catch (e) {}
1292
- try {
1293
- await this._attemptReconnectSafely();
1294
- } catch (e) {
1295
- this.realtimeDebug('[CREDENTIAL_REFRESH] reconnect after refresh failed:', e?.message || e);
1296
- }
1297
- } else {
1298
- this.realtimeDebug('[CREDENTIAL_REFRESH] refresh attempt did not produce new mqtt credentials.');
1299
- }
1300
- } catch (e) {
1301
- this.realtimeDebug('[CREDENTIAL_REFRESH] unexpected error during scheduled refresh:', e?.message || e);
1302
- }
1303
- }, msBefore);
1304
- } else {
1305
- // expiry is imminent — attempt immediate refresh now
1306
- (async () => {
1307
- try {
1308
- this.realtimeDebug('[CREDENTIAL_REFRESH] mqttAuth near-expired or expired — attempting immediate refresh');
1309
- const refreshedNow = await this._refreshMqttCredentials();
1310
- if (refreshedNow) {
1311
- try { this.constructConnection(); } catch (e) {}
1312
- try { await this._attemptReconnectSafely(); } catch (e) {}
1313
- }
1314
- } catch (e) {}
1315
- })();
1316
- }
1317
- }
1318
- }
1319
- } catch (e) {
1320
- this.realtimeDebug('[CREDENTIAL_REFRESH] scheduling failed:', e?.message || e);
1321
- }
1322
- }
1323
- } catch (e) {
1324
- this.realtimeDebug('[CREDENTIAL_REFRESH] schedule block failed:', e?.message || e);
1325
- }
1326
- } catch (e) {
1327
- this.realtimeDebug('[MQTT] _onMqttConnected fatal', e?.message || e);
1328
- }
1329
- }
1330
-
1331
- /**
1332
- * _refreshMqttCredentials()
1333
- * - Attempt to refresh mqtt credentials using attached auth helper if possible.
1334
- * - This method is defensive: many auth helpers won't expose refresh methods, so it tries possible hooks and logs results.
1335
- */
1336
- async _refreshMqttCredentials() {
1337
- try {
1338
- if (!this._attachedAuthState) {
1339
- this.realtimeDebug('[CREDENTIAL_REFRESH] No attached auth helper to refresh credentials.');
1340
- return false;
1341
- }
1342
- const auth = this._attachedAuthState;
1343
- // Preferred hook: auth.refreshMqttAuth() or auth.refreshAuth()
1344
- if (typeof auth.refreshMqttAuth === 'function') {
1345
- try {
1346
- this.realtimeDebug('[CREDENTIAL_REFRESH] Calling auth.refreshMqttAuth()');
1347
- await auth.refreshMqttAuth();
1348
- // reload data into ig or auth helper if possible
1349
- if (typeof auth.getData === 'function') {
1350
- const d = auth.getData();
1351
- if (d && d.mqttAuth && d.mqttAuth.jwt) {
1352
- this.realtimeDebug('[CREDENTIAL_REFRESH] mqttAuth refreshed via refreshMqttAuth.');
1353
- return true;
1354
- }
1355
- }
1356
- } catch (e) {
1357
- this.realtimeDebug('[CREDENTIAL_REFRESH] refreshMqttAuth failed:', e?.message || e);
1358
- }
1359
- }
1360
- // Secondary hook: auth.refresh() or auth.loadCreds()
1361
- if (typeof auth.refresh === 'function') {
1362
- try {
1363
- this.realtimeDebug('[CREDENTIAL_REFRESH] Calling auth.refresh()');
1364
- await auth.refresh();
1365
- this.realtimeDebug('[CREDENTIAL_REFRESH] auth.refresh() completed.');
1366
- return true;
1367
- } catch (e) {
1368
- this.realtimeDebug('[CREDENTIAL_REFRESH] auth.refresh() failed:', e?.message || e);
1369
- }
1370
- }
1371
- if (typeof auth.loadCreds === 'function') {
1372
- try {
1373
- this.realtimeDebug('[CREDENTIAL_REFRESH] Calling auth.loadCreds(this.ig)');
1374
- await auth.loadCreds(this.ig);
1375
- this.realtimeDebug('[CREDENTIAL_REFRESH] auth.loadCreds() completed.');
1376
- return true;
1377
- } catch (e) {
1378
- this.realtimeDebug('[CREDENTIAL_REFRESH] auth.loadCreds() failed:', e?.message || e);
1379
- }
1380
- }
1381
- // If none of the above worked, attempt to re-run the useMultiFileAuthState load path if available (best-effort)
1382
- try {
1383
- if (auth.folder && typeof require('../useMultiFileAuthState') === 'function') {
1384
- try {
1385
- const { useMultiFileAuthState } = require('../useMultiFileAuthState');
1386
- const reloaded = await useMultiFileAuthState(auth.folder);
1387
- if (reloaded && reloaded.getData && typeof reloaded.getData === 'function') {
1388
- this._attachedAuthState = reloaded;
1389
- this.realtimeDebug('[CREDENTIAL_REFRESH] reloaded auth helper from folder.');
1390
- return true;
1391
- }
1392
- } catch (e) {
1393
- // not critical
1394
- }
1395
- }
1396
- } catch (e) {}
1397
- this.realtimeDebug('[CREDENTIAL_REFRESH] No refresh hook available or refresh did not produce new mqtt credentials.');
1398
- return false;
1399
- } catch (e) {
1400
- this.realtimeDebug('[CREDENTIAL_REFRESH] unexpected error', e?.message || e);
1401
- return false;
1402
- }
1403
- }
1404
-
1405
- /**
1406
- * Persist mqtt session details locally and via attached auth helper if available.
1407
- * Writes <authFolder>/mqtt-session.json as a local backup.
1408
- */
1409
- async _persistMqttSession() {
1410
- try {
1411
- const folder = this._authFolder || './authinfo_instagram';
1412
- try {
1413
- if (!fs.existsSync(folder)) fs.mkdirSync(folder, { recursive: true });
1414
- } catch (e) {}
1415
-
1416
- // IMPORTANT: prefer server-provided mqtt session id when available.
1417
- // Fallback order:
1418
- // 1) this._mqttSessionId (server-provided)
1419
- // 2) this._clientMqttSessionId (client-generated persistent id)
1420
- // 3) 'boot'
1421
- const obj = {
1422
- sessionId: this._mqttSessionId || null,
1423
- mqttSessionId: this._mqttSessionId ? String(this._mqttSessionId) : (this._clientMqttSessionId ? String(this._clientMqttSessionId) : 'boot'),
1424
- lastConnected: new Date().toISOString(),
1425
- userId: String(this.ig?.state?.cookieUserId || this.ig?.state?.userId || '')
1426
- };
1427
-
1428
- // If an auth helper supports saveMqttSession, call that first (so it can save to the canonical auth state)
1429
- try {
1430
- if (this._attachedAuthState && typeof this._attachedAuthState.saveMqttSession === 'function') {
1431
- try {
1432
- // Many helpers expect the realtime client instance
1433
- await this._attachedAuthState.saveMqttSession(this);
1434
- this.realtimeDebug('[MQTT] authState.saveMqttSession called');
1435
- } catch (e) {
1436
- this.realtimeDebug('[MQTT] authState.saveMqttSession failed', e?.message || e);
1437
- }
1438
- }
1439
- } catch (e) {}
1440
-
1441
- // Always write local backup file
1442
- try {
1443
- fs.writeFileSync(path.join(folder, 'mqtt-session.json'), JSON.stringify(obj, null, 2));
1444
- this.realtimeDebug('[MQTT] mqtt-session.json written locally');
1445
- } catch (e) {
1446
- this.realtimeDebug('[MQTT] failed writing mqtt-session.json', e?.message || e);
1447
- }
1448
- } catch (e) {
1449
- // swallow errors to not break main flow
1450
- this.realtimeDebug('[MQTT] _persistMqttSession error', e?.message || e);
1451
- }
1452
- }
1453
-
1454
- /**
1455
- * _attemptReconnectSafely()
1456
- * - Ensure only a single reconnect flow runs at once.
1457
- * - Disconnects existing mqtt client, waits briefly, refreshes credentials when appropriate,
1458
- * and calls connect() again with exponential backoff retries.
1459
- */
1460
- async _attemptReconnectSafely(lastError) {
1461
- if (this._reconnectInProgress) {
1462
- this.realtimeDebug('[RECONNECT] Skipped — reconnect already in progress');
1463
- return;
1464
- }
1465
- if (this._mqttConnected) {
1466
- this.realtimeDebug('[RECONNECT] Skipped — MQTT is already connected');
1467
- return;
1468
- }
1469
- if (this.safeDisconnect) {
1470
- this.realtimeDebug('[RECONNECT] Skipped — safe disconnect active');
1471
- return;
1472
- }
1473
- this._reconnectInProgress = true;
1474
- if (this._reconnectTimeoutId) {
1475
- clearTimeout(this._reconnectTimeoutId);
1476
- this._reconnectTimeoutId = null;
1477
- }
1478
-
1479
- if (this.errorHandler && this.errorHandler.isRateLimited()) {
1480
- const remaining = this.errorHandler.getRateLimitRemainingMs();
1481
- this.realtimeDebug(`[RECONNECT] Rate limited. Waiting ${Math.round(remaining/1000)}s before attempting reconnect.`);
1482
- await (0, shared_1.delay)(remaining);
1483
- }
1484
-
1485
- try {
1486
- let attempt = 0;
1487
- const maxAttempts = 20;
1488
- let lastErrorType = lastError ? (this.errorHandler ? this.errorHandler.classifyError(lastError) : 'unknown') : 'unknown';
1489
-
1490
- while (attempt < maxAttempts) {
1491
- attempt++;
1492
- try {
1493
- if (this._mqttConnected) {
1494
- this.realtimeDebug('[RECONNECT] MQTT connected during loop — stopping reconnect');
1495
- break;
1496
- }
1497
-
1498
- const shouldRefreshCreds = lastErrorType === 'auth_failure' || attempt > 3;
1499
- if (shouldRefreshCreds) {
1500
- try {
1501
- const refreshed = await this._refreshMqttCredentials();
1502
- if (refreshed) {
1503
- this.realtimeDebug('[RECONNECT] Credentials refreshed successfully.');
1504
- }
1505
- } catch (e) {
1506
- this.realtimeDebug('[RECONNECT] Credential refresh failed:', e?.message || e);
1507
- }
1508
- }
1509
-
1510
- this.realtimeDebug(`[RECONNECT] Attempt #${attempt}...`);
1511
- try {
1512
- await this.connect(this.initOptions);
1513
- this.realtimeDebug(`[RECONNECT] Reconnect succeeded on attempt #${attempt}.`);
1514
- if (this.errorHandler) this.errorHandler.resetErrorCounter();
1515
- this.emit('reconnected', { attempt });
1516
- return;
1517
- } catch (e) {
1518
- lastErrorType = this.errorHandler ? this.errorHandler.classifyError(e) : 'unknown';
1519
- this.realtimeDebug(`[RECONNECT] Attempt #${attempt} failed (${lastErrorType}):`, e?.message || e);
1520
- }
1521
- } catch (e) {
1522
- this.realtimeDebug('[RECONNECT] Loop error:', e?.message || e);
1523
- }
1524
-
1525
- let backoffMs;
1526
- if (this.errorHandler) {
1527
- backoffMs = this.errorHandler.getBackoffForType(lastErrorType, attempt);
1528
- } else {
1529
- const jitter = Math.floor(Math.random() * 3000);
1530
- backoffMs = Math.min(60000, 2000 * Math.pow(2, attempt)) + jitter;
1531
- }
1532
- this.realtimeDebug(`[RECONNECT] Waiting ${Math.round(backoffMs/1000)}s before attempt #${attempt + 1} (type: ${lastErrorType}).`);
1533
- await (0, shared_1.delay)(backoffMs);
1534
-
1535
- if (attempt >= maxAttempts) {
1536
- this.realtimeDebug(`[RECONNECT] Max attempts (${maxAttempts}) reached. Persisting state and stopping.`);
1537
- try { await this._persistMqttSession(); } catch (e) {}
1538
- this.emit('reconnect_failed', { attempts: attempt, lastErrorType });
1539
- break;
1540
- }
1541
- }
1542
- } finally {
1543
- this._reconnectInProgress = false;
1544
- }
1545
- }
1546
-
1547
- /**
1548
- * _ensureIrisSnapshotAndSubscribe()
1549
- * - Ensure IRIS snapshot is present and subscribe to it.
1550
- * - Tries a fresh fetch after connect to get the latest snapshot.
1551
- */
1552
- async _ensureIrisSnapshotAndSubscribe() {
1553
- try {
1554
- let iris = this.initOptions?.irisData || null;
1555
- let fetched = false;
1556
- try {
1557
- const fetchedInbox = await this.ig.direct.getInbox();
1558
- if (fetchedInbox) {
1559
- iris = fetchedInbox;
1560
- fetched = true;
1561
- this.realtimeDebug('[IRIS] Fetched fresh snapshot after connect.');
1562
- }
1563
- } catch (e) {
1564
- this.realtimeDebug('[IRIS] Fresh fetch failed:', e?.message || e);
1565
- }
1566
- if (iris) {
1567
- try {
1568
- await this.irisSubscribe(iris);
1569
- this.realtimeDebug('[IRIS] irisSubscribe executed.');
1570
- } catch (e) {
1571
- this.realtimeDebug('[IRIS] irisSubscribe failed:', e?.message || e);
1572
- }
1573
- } else {
1574
- this.realtimeDebug('[IRIS] No iris data available to subscribe.');
1575
- }
1576
- return fetched;
1577
- } catch (e) {
1578
- return false;
1579
- }
1580
- }
1581
-
1582
- /**
1583
- * Attach message_sync listener to mqtt if available
1584
- * - Some mqtt clients provide a listen() helper; attach to both numeric id and string names for compatibility.
1585
- */
1586
- async _ensureMessageSyncListener() {
1587
- try {
1588
- if (this._messageSyncAttached) return;
1589
- if (this._mqtt && typeof this._mqtt.listen === 'function') {
1590
- try {
1591
- const bound = (payload) => {
1592
- try { this.emit('message_sync', payload); } catch (e) {}
1593
- };
1594
- try { this._mqtt.listen(146, bound); } catch (e) {}
1595
- try { this._mqtt.listen('message_sync', bound); } catch (e) {}
1596
- this._messageSyncAttached = true;
1597
- this.realtimeDebug('[MESSAGE_SYNC] listener attached to mqtt (idempotent).');
1598
- } catch (e) {
1599
- this.realtimeDebug('[MESSAGE_SYNC] attach failed:', e?.message || e);
1600
- }
1601
- } else {
1602
- this.realtimeDebug('[MESSAGE_SYNC] mqtt.listen not available on client.');
1603
- }
1604
- } catch (e) {}
1605
- }
1606
-
1607
- async _afterConnectHandlers() {
1608
- try {
1609
- this._lastMessageAt = Date.now();
1610
- await this._ensureMessageSyncListener();
1611
- await this._ensureIrisSnapshotAndSubscribe();
1612
- } catch (e) {
1613
- this.realtimeDebug('[AFTER_CONNECT] handlers error:', e?.message || e);
1614
- }
1615
- }
1616
-
1617
- enableHealthMonitor(options = {}) {
1618
- if (this.healthMonitor) {
1619
- this.healthMonitor.stop();
1620
- }
1621
- this.healthMonitor = new SessionHealthMonitor(this, {
1622
- checkIntervalMs: options.checkIntervalMs || 30 * 60 * 1000,
1623
- jitterMs: options.jitterMs || 5 * 60 * 1000,
1624
- autoRelogin: options.autoRelogin !== undefined ? options.autoRelogin : !!options.credentials,
1625
- credentials: options.credentials || null,
1626
- maxConsecutiveFailures: options.maxConsecutiveFailures || 5,
1627
- onSessionExpired: options.onSessionExpired || null,
1628
- });
1629
-
1630
- this.healthMonitor.on('health_check', (data) => {
1631
- this.emit('health_check', data);
1632
- });
1633
- this.healthMonitor.on('session_expired', (data) => {
1634
- this.emit('session_expired', data);
1635
- });
1636
- this.healthMonitor.on('relogin_start', (data) => {
1637
- this.emit('relogin_start', data);
1638
- });
1639
- this.healthMonitor.on('relogin_success', (data) => {
1640
- this.emit('relogin_success', data);
1641
- });
1642
- this.healthMonitor.on('relogin_failed', (data) => {
1643
- this.emit('relogin_failed', data);
1644
- });
1645
- this.healthMonitor.on('relogin_challenge', (data) => {
1646
- this.emit('relogin_challenge', data);
1647
- });
1648
- this.healthMonitor.on('relogin_needed', (data) => {
1649
- this.emit('relogin_needed', data);
1650
- });
1651
-
1652
- if (this.persistentLogger) {
1653
- this.healthMonitor.on('log', (line) => {
1654
- this.persistentLogger.info(line);
1655
- });
1656
- }
1657
-
1658
- this.healthMonitor.start();
1659
- this.realtimeDebug('[HEALTH] Session health monitor enabled');
1660
- return this.healthMonitor;
1661
- }
1662
-
1663
- enablePersistentLogger(options = {}) {
1664
- if (this.persistentLogger) {
1665
- this.persistentLogger.stop();
1666
- }
1667
- this.persistentLogger = new PersistentLogger({
1668
- logDir: options.logDir || './logs',
1669
- prefix: options.logPrefix || 'instagram-mqtt',
1670
- maxFileSize: options.maxLogFileSize || 10 * 1024 * 1024,
1671
- maxFiles: options.maxLogFiles || 5,
1672
- flushIntervalMs: options.logFlushIntervalMs || 30000,
1673
- logToConsole: options.logToConsole !== false,
1674
- logLevel: options.logLevel || 'info',
1675
- });
1676
- this.persistentLogger.start();
1677
-
1678
- const originalDebug = this.realtimeDebug.bind(this);
1679
- this.realtimeDebug = (...args) => {
1680
- originalDebug(...args);
1681
- if (this.persistentLogger && this.persistentLogger._started) {
1682
- this.persistentLogger.info(...args);
1683
- }
1684
- };
1685
-
1686
- this.on('error', (err) => {
1687
- if (this.persistentLogger) this.persistentLogger.error('[MQTT_ERROR]', err?.message || err);
1688
- });
1689
- this.on('disconnect', (reason) => {
1690
- if (this.persistentLogger) this.persistentLogger.warn('[DISCONNECT]', reason || 'unknown');
1691
- });
1692
- this.on('reconnected', (data) => {
1693
- if (this.persistentLogger) this.persistentLogger.info('[RECONNECTED]', JSON.stringify(data));
1694
- });
1695
-
1696
- this.realtimeDebug('[LOGGER] Persistent file logger enabled at', options.logDir || './logs');
1697
- return this.persistentLogger;
1698
- }
1699
-
1700
- getHealthStats() {
1701
- if (!this.healthMonitor) return null;
1702
- return this.healthMonitor.getStats();
1703
- }
1704
-
1705
- getLoggerStats() {
1706
- if (!this.persistentLogger) return null;
1707
- return this.persistentLogger.getStats();
1708
- }
1709
-
1710
- /**
1711
- * connectFromSavedSession(authStateHelper, options)
1712
- * - Reconstructs connect options from saved authState and then calls connect()
1713
- * - Attempts to fetch a fresh IRIS snapshot (up to a few attempts) for safety.
1714
- */
1715
- async connectFromSavedSession(authStateHelper, options = {}) {
1716
- if (!authStateHelper) {
1717
- throw new Error('authStateHelper is required - use useMultiFileAuthState()');
1718
- }
1719
-
1720
- if (this._mqttConnected) {
1721
- this._log('debug', 'connectFromSavedSession skipped — already connected.');
1722
- return this;
1723
- }
1724
- if (this._connectInProgress) {
1725
- this._log('debug', 'connectFromSavedSession skipped — connect already in progress.');
1726
- return this;
1727
- }
1728
-
1729
- this._connectInProgress = true;
1730
- this._log('debug', 'Connecting from saved session...');
1731
- try { this._attachedAuthState = authStateHelper; } catch (e) {}
1732
-
1733
- const savedOptions = authStateHelper.getMqttConnectOptions?.() || {};
1734
- let irisData = options.irisData || savedOptions.irisData || null;
1735
-
1736
- let fetchedInbox = null;
1737
- const shouldForceFetch = true;
1738
- if (shouldForceFetch) {
1739
- const maxAttempts = 3;
1740
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1741
- try {
1742
- this._log('debug', `Attempting to fetch fresh IRIS inbox snapshot (attempt ${attempt}/${maxAttempts})...`);
1743
- fetchedInbox = await this.ig.direct.getInbox();
1744
- if (fetchedInbox) {
1745
- irisData = fetchedInbox;
1746
- this._log('debug', 'Fetched IRIS snapshot successfully.');
1747
- break;
1748
- }
1749
- } catch (e) {
1750
- const msg = (e?.message || String(e)).toLowerCase();
1751
- const isAuthIssue = msg.includes('login_required') || msg.includes('401') || msg.includes('403') || msg.includes('not authorized') || msg.includes('checkpoint');
1752
- this._log('warn', `Failed to fetch IRIS snapshot (attempt ${attempt}):`, e?.message || e);
1753
- if (isAuthIssue) {
1754
- this._log('warn', 'IRIS fetch failed due to auth issue — session may be expired.');
1755
- this.emit('warning', { type: 'auth_issue', message: 'Session may be expired - IRIS fetch returned auth error', error: e?.message });
1756
- break;
1757
- }
1758
- }
1759
- try { await (0, shared_1.delay)(1000 * attempt); } catch (e) {}
1760
- }
1761
- if (!fetchedInbox) {
1762
- if (savedOptions.irisData) {
1763
- irisData = savedOptions.irisData;
1764
- this._log('warn', 'Could not fetch fresh IRIS snapshot — falling back to saved irisData (may be stale).');
1765
- } else if (!irisData) {
1766
- this._log('warn', 'No IRIS snapshot available (neither fetched nor saved). Proceeding without irisData — server may not replay missed events.');
1767
- }
1768
- }
1769
- }
1770
-
1771
- const connectOptions = {
1772
- graphQlSubs: options.graphQlSubs || savedOptions.graphQlSubs || this.defaultGraphQlSubs,
1773
- skywalkerSubs: options.skywalkerSubs || savedOptions.skywalkerSubs || this.defaultSkywalkerSubs,
1774
- irisData,
1775
- ...options
1776
- };
1777
-
1778
- this._log('debug', 'Using saved subscriptions:', {
1779
- graphQlSubs: connectOptions.graphQlSubs,
1780
- skywalkerSubs: connectOptions.skywalkerSubs,
1781
- hasIrisData: !!connectOptions.irisData
1782
- });
1783
-
1784
- try {
1785
- const d = authStateHelper.getData?.() || authStateHelper.data || {};
1786
- const mqttAuth = d.mqttAuth || null;
1787
- if (mqttAuth && mqttAuth.expiresAt) {
1788
- const t = new Date(mqttAuth.expiresAt).getTime();
1789
- if (!isNaN(t) && Date.now() > t) {
1790
- this._log('warn', 'Warning: saved mqttAuth token appears expired.');
1791
- }
1792
- }
1793
- } catch (e) {}
1794
-
1795
- await this.connect(connectOptions);
1796
-
1797
- if (authStateHelper.saveMqttSession) {
1798
- try {
1799
- await authStateHelper.saveMqttSession(this);
1800
- this._log('debug', 'MQTT session saved after connect');
1801
- } catch (e) {
1802
- this._log('warn', 'Failed to save MQTT session:', e.message);
1803
- }
1804
- }
1805
-
1806
- return this;
1807
- }
1808
-
1809
- /**
1810
- * saveSession(authStateHelper)
1811
- * - Helper to persist current MQTT session to auth helper if available.
1812
- */
1813
- async saveSession(authStateHelper) {
1814
- if (!authStateHelper || !authStateHelper.saveMqttSession) {
1815
- this._log('warn', 'No authStateHelper provided');
1816
- return false;
1817
- }
1818
- await authStateHelper.saveMqttSession(this);
1819
- return true;
1820
- }
1821
-
1822
- /**
1823
- * disconnect()
1824
- * - Perform a graceful shutdown: clear timers and disconnect mqtt client.
1825
- */
1826
- disconnect() {
1827
- this.safeDisconnect = true;
1828
- try {
1829
- if (this._foregroundTimer) {
1830
- clearInterval(this._foregroundTimer);
1831
- this._foregroundTimer = null;
1832
- }
1833
- if (this._syncTimer) {
1834
- clearInterval(this._syncTimer);
1835
- this._syncTimer = null;
1836
- }
1837
- if (this._trafficWatchdog) {
1838
- clearInterval(this._trafficWatchdog);
1839
- this._trafficWatchdog = null;
1840
- }
1841
- if (this._heartbeatTimer) {
1842
- clearInterval(this._heartbeatTimer);
1843
- this._heartbeatTimer = null;
1844
- }
1845
- // clear periodic mqtt persist
1846
- if (this._mqttSessionPersistIntervalId) {
1847
- clearInterval(this._mqttSessionPersistIntervalId);
1848
- this._mqttSessionPersistIntervalId = null;
1849
- }
1850
-
1851
- // Clear the active keepalive/query timer if running
1852
- if (this._activeKeepaliveTimer) {
1853
- clearInterval(this._activeKeepaliveTimer);
1854
- this._activeKeepaliveTimer = null;
1855
- }
1856
-
1857
- // clear credential refresh timer
1858
- if (this._mqttAuthRefreshTimer) {
1859
- try { clearTimeout(this._mqttAuthRefreshTimer); } catch (e) {}
1860
- this._mqttAuthRefreshTimer = null;
1861
- }
1862
- } catch (e) {}
1863
- // persist final session snapshot
1864
- try { this._persistMqttSession(); } catch (e) {}
1865
- return this.mqtt?.disconnect() ?? Promise.resolve();
1866
- }
1867
-
1868
- /**
1869
- * graphQlSubscribe(sub)
1870
- * - Helper that delegates to Commands.updateSubscriptions (which uses qos 0).
1871
- */
1872
- graphQlSubscribe(sub) {
1873
- sub = typeof sub === 'string' ? [sub] : sub;
1874
- if (!this.commands) {
1875
- throw new mqtts_1.IllegalStateError('connect() must be called before graphQlSubscribe()');
1876
- }
1877
- // If the caller provided an empty array, ensure defaults are used
1878
- if (Array.isArray(sub) && sub.length === 0) sub = this.defaultGraphQlSubs;
1879
- this.realtimeDebug(`Subscribing with GraphQL to ${sub.join(', ')}`);
1880
- return this.commands.updateSubscriptions({
1881
- topic: constants_1.Topics.REALTIME_SUB,
1882
- data: {
1883
- sub,
1884
- },
1885
- });
1886
- }
1887
-
1888
- /**
1889
- * skywalkerSubscribe(sub)
1890
- * - Delegate to Commands.updateSubscriptions (pubsub topic).
1891
- */
1892
- skywalkerSubscribe(sub) {
1893
- sub = typeof sub === 'string' ? [sub] : sub;
1894
- if (!this.commands) {
1895
- throw new mqtts_1.IllegalStateError('connect() must be called before skywalkerSubscribe()');
1896
- }
1897
- // If empty, use defaults
1898
- if (Array.isArray(sub) && sub.length === 0) sub = this.defaultSkywalkerSubs;
1899
- this.realtimeDebug(`Subscribing with Skywalker to ${sub.join(', ')}`);
1900
- return this.commands.updateSubscriptions({
1901
- topic: constants_1.Topics.PUBSUB,
1902
- data: {
1903
- sub,
1904
- },
1905
- });
1906
- }
1907
-
1908
- /**
1909
- * irisSubscribe({ seq_id, snapshot_at_ms })
1910
- * - Subscribe to IRIS using the provided snapshot properties.
1911
- */
1912
- irisSubscribe({ seq_id, snapshot_at_ms, }) {
1913
- if (!this.commands) {
1914
- throw new mqtts_1.IllegalStateError('connect() must be called before irisSubscribe()');
1915
- }
1916
- this.realtimeDebug(`Iris Sub to: seqId: ${seq_id}, snapshot: ${snapshot_at_ms}`);
1917
- return this.commands.updateSubscriptions({
1918
- topic: constants_1.Topics.IRIS_SUB,
1919
- data: {
1920
- seq_id,
1921
- snapshot_at_ms,
1922
- snapshot_app_version: this.ig.state.appVersion,
1923
- },
1924
- });
1925
- }
1926
-
1927
- /**
1928
- * Start an "active query" keepalive loop
1929
- * - This sends a lightweight PUBSUB foreground pulse and a REALTIME_SUB reaffirmation
1930
- * on a periodic basis to keep the server-side connection state active.
1931
- *
1932
- * Behavior & protections:
1933
- * - Idle-aware: will skip sending if client received traffic within idleThresholdMs (to avoid unnecessary traffic).
1934
- * - Interval configurable via initOptions.activeKeepaliveMs (default 45s).
1935
- * - GraphQL subs reaffirmation uses initOptions.graphQlSubs or defaultGraphQlSubs.
1936
- */
1937
- _startActiveQueryKeepalive() {
1938
- try {
1939
- // Clear any existing timer idempotently
1940
- if (this._activeKeepaliveTimer) {
1941
- clearInterval(this._activeKeepaliveTimer);
1942
- this._activeKeepaliveTimer = null;
1943
- }
1944
-
1945
- const ms = (this.initOptions && this.initOptions.activeKeepaliveMs) ? this.initOptions.activeKeepaliveMs : 25000;
1946
- const idleThresholdMs = (this.initOptions && this.initOptions.activeKeepaliveIdleThresholdMs) ? this.initOptions.activeKeepaliveIdleThresholdMs : 15000;
1947
-
1948
- // small wrapper to avoid unhandled rejection inside setInterval
1949
- this._activeKeepaliveTimer = setInterval(async () => {
1950
- try {
1951
- if (!this.commands) return;
1952
-
1953
- // Do not send keepalive if we received traffic recently — avoids noisy pulses during active use.
1954
- const idle = Date.now() - (this._lastMessageAt || 0);
1955
- if (idle < idleThresholdMs) {
1956
- // skip sending if not idle enough
1957
- return;
1958
- }
1959
-
1960
- // 1) PUBSUB "foreground pulse" with a tiny timestamp payload (safe, no side-effects)
1961
- try {
1962
- await this.commands.updateSubscriptions({
1963
- topic: constants_1.Topics.PUBSUB,
1964
- data: { foreground: true, keepalive_ts: Date.now() }
1965
- });
1966
- // mark activity so the traffic watchdog won't be triggered
1967
- this._lastMessageAt = Date.now(); // <--- update last-activity timestamp after active keepalive
1968
- } catch (e) {
1969
- // log but continue to attempt realtime-sub reaffirmation
1970
- this.realtimeDebug('[ACTIVE_QUERY] PUBSUB foreground pulse failed:', e?.message || e);
1971
- }
1972
-
1973
- // 2) REALTIME_SUB reaffirmation of GraphQL subs (lightweight)
1974
- try {
1975
- const subs = (this.initOptions && this.initOptions.graphQlSubs && this.initOptions.graphQlSubs.length) ? this.initOptions.graphQlSubs : this.defaultGraphQlSubs;
1976
- await this.commands.updateSubscriptions({
1977
- topic: constants_1.Topics.REALTIME_SUB,
1978
- data: { sub: subs, keepalive_ts: Date.now() }
1979
- });
1980
- // mark activity after realtime-sub reaffirmation as well
1981
- this._lastMessageAt = Date.now(); // <--- update last-activity timestamp after realtime-sub reaffirmation
1982
- } catch (e) {
1983
- this.realtimeDebug('[ACTIVE_QUERY] REALTIME_SUB reaffirmation failed:', e?.message || e);
1984
- }
1985
-
1986
- this.realtimeDebug('[ACTIVE_QUERY] keepalive query sent (idle ms: ' + idle + ')');
1987
- } catch (e) {
1988
- this.realtimeDebug('[ACTIVE_QUERY] unexpected error in keepalive loop:', e?.message || e);
1989
- }
1990
- }, ms);
1991
- } catch (e) {
1992
- this.realtimeDebug('[ACTIVE_QUERY] could not start keepalive timer:', e?.message || e);
1993
- }
1994
- }
1995
- }
1996
- exports.RealtimeClient = RealtimeClient;