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

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