nodejs-insta-private-api-mqt 1.3.70

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 (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3677 -0
  3. package/dist/constants/constants.js +342 -0
  4. package/dist/constants/index.js +58 -0
  5. package/dist/core/client.js +419 -0
  6. package/dist/core/nav-chain.js +282 -0
  7. package/dist/core/repository.js +7 -0
  8. package/dist/core/request.js +390 -0
  9. package/dist/core/state.js +1473 -0
  10. package/dist/core/utils.js +786 -0
  11. package/dist/downloadMedia.js +381 -0
  12. package/dist/errors/index.d.ts +16 -0
  13. package/dist/errors/index.js +38 -0
  14. package/dist/errors/index.js.map +1 -0
  15. package/dist/extend.js +167 -0
  16. package/dist/fbns/fbns.client.d.ts +32 -0
  17. package/dist/fbns/fbns.client.events.d.ts +41 -0
  18. package/dist/fbns/fbns.client.events.js +3 -0
  19. package/dist/fbns/fbns.client.events.js.map +1 -0
  20. package/dist/fbns/fbns.client.js +252 -0
  21. package/dist/fbns/fbns.client.js.map +1 -0
  22. package/dist/fbns/fbns.device-auth.d.ts +17 -0
  23. package/dist/fbns/fbns.device-auth.js +54 -0
  24. package/dist/fbns/fbns.device-auth.js.map +1 -0
  25. package/dist/fbns/fbns.types.d.ts +83 -0
  26. package/dist/fbns/fbns.types.js +3 -0
  27. package/dist/fbns/fbns.types.js.map +1 -0
  28. package/dist/fbns/fbns.utilities.d.ts +2 -0
  29. package/dist/fbns/fbns.utilities.js +79 -0
  30. package/dist/fbns/fbns.utilities.js.map +1 -0
  31. package/dist/fbns/index.d.ts +4 -0
  32. package/dist/fbns/index.js +21 -0
  33. package/dist/fbns/index.js.map +1 -0
  34. package/dist/index.js +139 -0
  35. package/dist/mqtt-shim.d.ts +96 -0
  36. package/dist/mqtt-shim.js +15 -0
  37. package/dist/mqttot/index.d.ts +4 -0
  38. package/dist/mqttot/index.js +21 -0
  39. package/dist/mqttot/index.js.map +1 -0
  40. package/dist/mqttot/mqttot.client.d.ts +39 -0
  41. package/dist/mqttot/mqttot.client.js +318 -0
  42. package/dist/mqttot/mqttot.client.js.map +1 -0
  43. package/dist/mqttot/mqttot.connect.request.packet.d.ts +7 -0
  44. package/dist/mqttot/mqttot.connect.request.packet.js +9 -0
  45. package/dist/mqttot/mqttot.connect.request.packet.js.map +1 -0
  46. package/dist/mqttot/mqttot.connect.response.packet.d.ts +7 -0
  47. package/dist/mqttot/mqttot.connect.response.packet.js +24 -0
  48. package/dist/mqttot/mqttot.connect.response.packet.js.map +1 -0
  49. package/dist/mqttot/mqttot.connection.d.ts +57 -0
  50. package/dist/mqttot/mqttot.connection.js +79 -0
  51. package/dist/mqttot/mqttot.connection.js.map +1 -0
  52. package/dist/package.json +59 -0
  53. package/dist/realtime/commands/commands.d.ts +15 -0
  54. package/dist/realtime/commands/commands.js +71 -0
  55. package/dist/realtime/commands/commands.js.map +1 -0
  56. package/dist/realtime/commands/direct.commands.d.ts +75 -0
  57. package/dist/realtime/commands/direct.commands.js +417 -0
  58. package/dist/realtime/commands/direct.commands.js.map +1 -0
  59. package/dist/realtime/commands/enhanced.direct.commands.js +1731 -0
  60. package/dist/realtime/commands/enhanced.direct.commands.js.bak +967 -0
  61. package/dist/realtime/commands/index.d.ts +2 -0
  62. package/dist/realtime/commands/index.js +20 -0
  63. package/dist/realtime/commands/index.js.map +1 -0
  64. package/dist/realtime/delta-sync.manager.js +293 -0
  65. package/dist/realtime/features/dm-sender.js +88 -0
  66. package/dist/realtime/features/error-handler.js +185 -0
  67. package/dist/realtime/features/gap-handler.js +61 -0
  68. package/dist/realtime/features/persistent-logger.js +186 -0
  69. package/dist/realtime/features/presence.manager.js +66 -0
  70. package/dist/realtime/features/session-health-monitor.js +345 -0
  71. package/dist/realtime/index.js +30 -0
  72. package/dist/realtime/messages/app-presence.event.d.ts +9 -0
  73. package/dist/realtime/messages/app-presence.event.js +3 -0
  74. package/dist/realtime/messages/app-presence.event.js.map +1 -0
  75. package/dist/realtime/messages/index.d.ts +3 -0
  76. package/dist/realtime/messages/index.js +20 -0
  77. package/dist/realtime/messages/index.js.map +1 -0
  78. package/dist/realtime/messages/message-sync.message.d.ts +222 -0
  79. package/dist/realtime/messages/message-sync.message.js +43 -0
  80. package/dist/realtime/messages/message-sync.message.js.map +1 -0
  81. package/dist/realtime/messages/realtime-sub.direct.data.d.ts +11 -0
  82. package/dist/realtime/messages/realtime-sub.direct.data.js +3 -0
  83. package/dist/realtime/messages/realtime-sub.direct.data.js.map +1 -0
  84. package/dist/realtime/messages/thread-update.message.d.ts +68 -0
  85. package/dist/realtime/messages/thread-update.message.js +3 -0
  86. package/dist/realtime/messages/thread-update.message.js.map +1 -0
  87. package/dist/realtime/mixins/index.d.ts +3 -0
  88. package/dist/realtime/mixins/index.js +20 -0
  89. package/dist/realtime/mixins/index.js.map +1 -0
  90. package/dist/realtime/mixins/message-sync.mixin.d.ts +8 -0
  91. package/dist/realtime/mixins/message-sync.mixin.js +596 -0
  92. package/dist/realtime/mixins/message-sync.mixin.js.map +1 -0
  93. package/dist/realtime/mixins/mixin.d.ts +19 -0
  94. package/dist/realtime/mixins/mixin.js +41 -0
  95. package/dist/realtime/mixins/mixin.js.map +1 -0
  96. package/dist/realtime/mixins/presence-typing.mixin.js +33 -0
  97. package/dist/realtime/mixins/realtime-sub.mixin.d.ts +8 -0
  98. package/dist/realtime/mixins/realtime-sub.mixin.js +181 -0
  99. package/dist/realtime/mixins/realtime-sub.mixin.js.map +1 -0
  100. package/dist/realtime/parsers/graphql-parser.js +43 -0
  101. package/dist/realtime/parsers/graphql.parser.d.ts +15 -0
  102. package/dist/realtime/parsers/graphql.parser.js +22 -0
  103. package/dist/realtime/parsers/graphql.parser.js.map +1 -0
  104. package/dist/realtime/parsers/index.d.ts +6 -0
  105. package/dist/realtime/parsers/index.js +23 -0
  106. package/dist/realtime/parsers/index.js.map +1 -0
  107. package/dist/realtime/parsers/iris-parser.js +43 -0
  108. package/dist/realtime/parsers/iris.parser.d.ts +17 -0
  109. package/dist/realtime/parsers/iris.parser.js +10 -0
  110. package/dist/realtime/parsers/iris.parser.js.map +1 -0
  111. package/dist/realtime/parsers/json-parser.js +43 -0
  112. package/dist/realtime/parsers/json.parser.d.ts +6 -0
  113. package/dist/realtime/parsers/json.parser.js +10 -0
  114. package/dist/realtime/parsers/json.parser.js.map +1 -0
  115. package/dist/realtime/parsers/parser.d.ts +9 -0
  116. package/dist/realtime/parsers/parser.js +3 -0
  117. package/dist/realtime/parsers/parser.js.map +1 -0
  118. package/dist/realtime/parsers/region-hint-parser.js +43 -0
  119. package/dist/realtime/parsers/region-hint.parser.d.ts +12 -0
  120. package/dist/realtime/parsers/region-hint.parser.js +15 -0
  121. package/dist/realtime/parsers/region-hint.parser.js.map +1 -0
  122. package/dist/realtime/parsers/skywalker-parser.js +43 -0
  123. package/dist/realtime/parsers/skywalker.parser.d.ts +12 -0
  124. package/dist/realtime/parsers/skywalker.parser.js +15 -0
  125. package/dist/realtime/parsers/skywalker.parser.js.map +1 -0
  126. package/dist/realtime/parsers-advanced.js +158 -0
  127. package/dist/realtime/proto/common.proto +38 -0
  128. package/dist/realtime/proto/direct.proto +65 -0
  129. package/dist/realtime/proto/ig-messages.proto +83 -0
  130. package/dist/realtime/proto/iris.proto +188 -0
  131. package/dist/realtime/proto-parser.js +195 -0
  132. package/dist/realtime/protocols/iris.handshake.js +74 -0
  133. package/dist/realtime/protocols/proto-definitions.js +80 -0
  134. package/dist/realtime/protocols/skywalker.protocol.js +91 -0
  135. package/dist/realtime/realtime.client.events.js +3 -0
  136. package/dist/realtime/realtime.client.js +1915 -0
  137. package/dist/realtime/realtime.service.js +462 -0
  138. package/dist/realtime/reconnect.manager.js +88 -0
  139. package/dist/realtime/session.manager.js +121 -0
  140. package/dist/realtime/subscriptions/graphql.subscription.d.ts +47 -0
  141. package/dist/realtime/subscriptions/graphql.subscription.js +99 -0
  142. package/dist/realtime/subscriptions/graphql.subscription.js.map +1 -0
  143. package/dist/realtime/subscriptions/index.d.ts +2 -0
  144. package/dist/realtime/subscriptions/index.js +19 -0
  145. package/dist/realtime/subscriptions/index.js.map +1 -0
  146. package/dist/realtime/subscriptions/skywalker.subscription.d.ts +4 -0
  147. package/dist/realtime/subscriptions/skywalker.subscription.js +13 -0
  148. package/dist/realtime/subscriptions/skywalker.subscription.js.map +1 -0
  149. package/dist/realtime/topic-map.js +71 -0
  150. package/dist/realtime/topic.js +80 -0
  151. package/dist/repositories/account.repository.js +575 -0
  152. package/dist/repositories/bloks.repository.js +70 -0
  153. package/dist/repositories/captcha.repository.js +44 -0
  154. package/dist/repositories/challenge.repository.js +120 -0
  155. package/dist/repositories/clip.repository.js +165 -0
  156. package/dist/repositories/close-friends.repository.js +46 -0
  157. package/dist/repositories/collection.repository.js +68 -0
  158. package/dist/repositories/direct-thread.repository.js +446 -0
  159. package/dist/repositories/direct.repository.js +232 -0
  160. package/dist/repositories/explore.repository.js +70 -0
  161. package/dist/repositories/fbsearch.repository.js +140 -0
  162. package/dist/repositories/feed.repository.js +245 -0
  163. package/dist/repositories/friendship.repository.js +296 -0
  164. package/dist/repositories/fundraiser.repository.js +49 -0
  165. package/dist/repositories/hashtag.repository.js +99 -0
  166. package/dist/repositories/highlights.repository.js +121 -0
  167. package/dist/repositories/insights.repository.js +82 -0
  168. package/dist/repositories/location.repository.js +84 -0
  169. package/dist/repositories/media.repository.js +395 -0
  170. package/dist/repositories/multiple-accounts.repository.js +41 -0
  171. package/dist/repositories/news.repository.js +35 -0
  172. package/dist/repositories/note.repository.js +57 -0
  173. package/dist/repositories/notification.repository.js +79 -0
  174. package/dist/repositories/share.repository.js +35 -0
  175. package/dist/repositories/signup.repository.js +218 -0
  176. package/dist/repositories/story.repository.js +290 -0
  177. package/dist/repositories/timeline.repository.js +60 -0
  178. package/dist/repositories/totp.repository.js +139 -0
  179. package/dist/repositories/track.repository.js +53 -0
  180. package/dist/repositories/upload.repository.js +204 -0
  181. package/dist/repositories/user.repository.js +360 -0
  182. package/dist/sendmedia/index.js +27 -0
  183. package/dist/sendmedia/sendFile.js +72 -0
  184. package/dist/sendmedia/sendPhoto.js +142 -0
  185. package/dist/sendmedia/sendRavenPhoto.js +153 -0
  186. package/dist/sendmedia/sendRavenVideo.js +158 -0
  187. package/dist/sendmedia/uploadPhoto.js +107 -0
  188. package/dist/sendmedia/uploadfFile.js +130 -0
  189. package/dist/services/live.service.js +139 -0
  190. package/dist/services/search.service.js +115 -0
  191. package/dist/shared/index.js +96 -0
  192. package/dist/shared/shared.js +86 -0
  193. package/dist/thrift/index.d.ts +3 -0
  194. package/dist/thrift/index.js +20 -0
  195. package/dist/thrift/index.js.map +1 -0
  196. package/dist/thrift/thrift.d.ts +59 -0
  197. package/dist/thrift/thrift.js +101 -0
  198. package/dist/thrift/thrift.js.map +1 -0
  199. package/dist/thrift/thrift.reading.d.ts +41 -0
  200. package/dist/thrift/thrift.reading.js +327 -0
  201. package/dist/thrift/thrift.reading.js.map +1 -0
  202. package/dist/thrift/thrift.writing.d.ts +44 -0
  203. package/dist/thrift/thrift.writing.js +342 -0
  204. package/dist/thrift/thrift.writing.js.map +1 -0
  205. package/dist/types/index.js +285 -0
  206. package/dist/useMultiFileAuthState.js +1768 -0
  207. package/dist/utils/helper-1.js +1 -0
  208. package/dist/utils/helper-10.js +1 -0
  209. package/dist/utils/helper-11.js +1 -0
  210. package/dist/utils/helper-12.js +1 -0
  211. package/dist/utils/helper-13.js +1 -0
  212. package/dist/utils/helper-14.js +1 -0
  213. package/dist/utils/helper-15.js +1 -0
  214. package/dist/utils/helper-16.js +1 -0
  215. package/dist/utils/helper-17.js +1 -0
  216. package/dist/utils/helper-18.js +1 -0
  217. package/dist/utils/helper-19.js +1 -0
  218. package/dist/utils/helper-2.js +1 -0
  219. package/dist/utils/helper-20.js +1 -0
  220. package/dist/utils/helper-21.js +1 -0
  221. package/dist/utils/helper-22.js +1 -0
  222. package/dist/utils/helper-23.js +1 -0
  223. package/dist/utils/helper-24.js +1 -0
  224. package/dist/utils/helper-25.js +1 -0
  225. package/dist/utils/helper-26.js +1 -0
  226. package/dist/utils/helper-27.js +1 -0
  227. package/dist/utils/helper-28.js +1 -0
  228. package/dist/utils/helper-29.js +1 -0
  229. package/dist/utils/helper-3.js +1 -0
  230. package/dist/utils/helper-30.js +1 -0
  231. package/dist/utils/helper-4.js +1 -0
  232. package/dist/utils/helper-5.js +1 -0
  233. package/dist/utils/helper-6.js +1 -0
  234. package/dist/utils/helper-7.js +1 -0
  235. package/dist/utils/helper-8.js +1 -0
  236. package/dist/utils/helper-9.js +1 -0
  237. package/dist/utils/index.js +280 -0
  238. package/dist/utils/insta-mqtt-helper.js +128 -0
  239. package/examples/listen-to-messages.js +86 -0
  240. package/package.json +82 -0
@@ -0,0 +1,419 @@
1
+ const EventEmitter = require('events');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const State = require('./state');
6
+ const Request = require('./request');
7
+ const AccountRepository = require('../repositories/account.repository');
8
+ const UserRepository = require('../repositories/user.repository');
9
+ const DirectRepository = require('../repositories/direct.repository');
10
+ const DirectThreadRepository = require('../repositories/direct-thread.repository');
11
+ const MediaRepository = require('../repositories/media.repository');
12
+ const UploadRepository = require('../repositories/upload.repository');
13
+ const StoryRepository = require('../repositories/story.repository');
14
+ const FeedRepository = require('../repositories/feed.repository');
15
+ const FriendshipRepository = require('../repositories/friendship.repository');
16
+ const LocationRepository = require('../repositories/location.repository');
17
+ const HashtagRepository = require('../repositories/hashtag.repository');
18
+ const NewsRepository = require('../repositories/news.repository');
19
+ const CollectionRepository = require('../repositories/collection.repository');
20
+ const CloseFriendsRepository = require('../repositories/close-friends.repository');
21
+ const ClipRepository = require('../repositories/clip.repository');
22
+ const TimelineRepository = require('../repositories/timeline.repository');
23
+ const InsightsRepository = require('../repositories/insights.repository');
24
+ const NoteRepository = require('../repositories/note.repository');
25
+ const NotificationRepository = require('../repositories/notification.repository');
26
+ const SignupRepository = require('../repositories/signup.repository');
27
+ const TOTPRepository = require('../repositories/totp.repository');
28
+ const BloksRepository = require('../repositories/bloks.repository');
29
+ const ChallengeRepository = require('../repositories/challenge.repository');
30
+ const ShareRepository = require('../repositories/share.repository');
31
+ const TrackRepository = require('../repositories/track.repository');
32
+ const ExploreRepository = require('../repositories/explore.repository');
33
+ const FBSearchRepository = require('../repositories/fbsearch.repository');
34
+ const FundraiserRepository = require('../repositories/fundraiser.repository');
35
+ const MultipleAccountsRepository = require('../repositories/multiple-accounts.repository');
36
+ const CaptchaRepository = require('../repositories/captcha.repository');
37
+ const HighlightsRepository = require('../repositories/highlights.repository');
38
+ const SearchService = require('../services/search.service');
39
+ const LiveService = require('../services/live.service');
40
+
41
+ /**
42
+ * IgApiClient
43
+ *
44
+ * - Păstrăm în totalitate funcționalitatea existentă (login/logout/isLoggedIn/saveSession/loadSession/isSessionValid/destroy)
45
+ * - Am eliminat complet stratul Realtime (WebSocket). Orice cod dependent de realtime trebuie migrat separat.
46
+ * - Am adăugat un helper generic `retryAsync(fn, opts)` pentru retry/backoff la operații asincrone (utile pentru request-uri).
47
+ */
48
+ class IgApiClient extends EventEmitter {
49
+ constructor() {
50
+ super();
51
+
52
+ this.state = new State();
53
+ this.request = new Request(this);
54
+ this.navChain = this.request.navChain;
55
+
56
+ // Initialize repositories
57
+ this.account = new AccountRepository(this);
58
+ this.user = new UserRepository(this);
59
+ this.direct = new DirectRepository(this);
60
+ this.directThread = new DirectThreadRepository(this);
61
+ this.media = new MediaRepository(this);
62
+ this.upload = new UploadRepository(this);
63
+ this.story = new StoryRepository(this);
64
+ this.feed = new FeedRepository(this);
65
+ this.friendship = new FriendshipRepository(this);
66
+ this.location = new LocationRepository(this);
67
+ this.hashtag = new HashtagRepository(this);
68
+ this.news = new NewsRepository(this);
69
+ this.collection = new CollectionRepository(this);
70
+ this.closeFriends = new CloseFriendsRepository(this);
71
+ this.clip = new ClipRepository(this);
72
+ this.timeline = new TimelineRepository(this);
73
+ this.insights = new InsightsRepository(this);
74
+ this.note = new NoteRepository(this);
75
+ this.notification = new NotificationRepository(this);
76
+ this.signup = new SignupRepository(this);
77
+ this.totp = new TOTPRepository(this);
78
+ this.bloks = new BloksRepository(this);
79
+ this.challenge = new ChallengeRepository(this);
80
+ this.share = new ShareRepository(this);
81
+ this.track = new TrackRepository(this);
82
+ this.explore = new ExploreRepository(this);
83
+ this.fbsearch = new FBSearchRepository(this);
84
+ this.fundraiser = new FundraiserRepository(this);
85
+ this.multipleAccounts = new MultipleAccountsRepository(this);
86
+ this.captcha = new CaptchaRepository(this);
87
+ this.highlights = new HighlightsRepository(this);
88
+
89
+ // Initialize services
90
+ this.search = new SearchService(this);
91
+ this.live = new LiveService(this);
92
+
93
+ // Create dm object for easier access (keeps backward compatibility)
94
+ this.dm = {
95
+ send: this.direct.send.bind(this.direct),
96
+ sendToGroup: this.directThread.sendToGroup.bind(this.directThread),
97
+ sendImage: this.direct.sendImage.bind(this.direct),
98
+ sendVideo: this.direct.sendVideo.bind(this.direct),
99
+ getInbox: this.direct.getInbox.bind(this.direct),
100
+ getThread: this.directThread.getThread.bind(this.directThread)
101
+ };
102
+
103
+ // Proxy debug / verbose
104
+ this.state.verbose = this.state.verbose || false;
105
+
106
+ // Default retry policy for the new helper retryAsync
107
+ this._defaultRetryPolicy = { retries: 3, delayMs: 500 };
108
+
109
+ }
110
+
111
+ /**
112
+ * Login -> uses account.login. Returns whatever account.login returns.
113
+ * NOTE: removed automatic realtime connection attempt.
114
+ */
115
+ async login(credentials) {
116
+ this.navChain.simulateAppOpen();
117
+ if (this.state.deviceId) {
118
+ try {
119
+ await this.preLoginFlow();
120
+ } catch (e) {
121
+ if (this.state.verbose) console.warn('[Pre-Login] Flow error (non-fatal):', e.message);
122
+ }
123
+ }
124
+ const result = await this.account.login(credentials);
125
+ try {
126
+ await this.postLoginFlow();
127
+ } catch (e) {
128
+ if (this.state.verbose) console.warn('[Post-Login] Flow error (non-fatal):', e.message);
129
+ }
130
+ return result;
131
+ }
132
+
133
+ /**
134
+ * Additional Android-specific behavior simulation
135
+ */
136
+ async simulateAndroidBehavior() {
137
+ if (this.state.verbose) console.log('[Anti-Bot] Simulating Android-specific background behaviors...');
138
+
139
+ // 0. Pre-login notification suppression / Trust signal
140
+ try {
141
+ await this.request.send({
142
+ url: '/api/v1/accounts/get_presence_disabled/',
143
+ method: 'GET',
144
+ });
145
+ } catch (e) {}
146
+
147
+ // 1. Fetch Contact Permission (often requested on start/login)
148
+ try {
149
+ await this.request.send({
150
+ url: '/api/v1/accounts/contact_point_pref/',
151
+ method: 'GET',
152
+ });
153
+ } catch (e) {}
154
+
155
+ // 2. Fetch Zero Rating (Mobile data settings)
156
+ try {
157
+ await this.request.send({
158
+ url: '/api/v1/zero/get_headers/',
159
+ method: 'GET',
160
+ });
161
+ } catch (e) {}
162
+
163
+ // 3. Fetch Banyan (Explore/Search context)
164
+ try {
165
+ await this.request.send({
166
+ url: '/api/v1/banyan/banyan/',
167
+ method: 'GET',
168
+ qs: {
169
+ views: '["direct_user_search","direct_search_context","direct_share_sheet"]',
170
+ },
171
+ });
172
+ } catch (e) {}
173
+ }
174
+
175
+ async logout() {
176
+ return await this.account.logout();
177
+ }
178
+
179
+ isLoggedIn() {
180
+ try {
181
+ return !!this.state.cookieUserId;
182
+ } catch {
183
+ return false;
184
+ }
185
+ }
186
+
187
+ async saveSession() {
188
+ return await this.state.serialize();
189
+ }
190
+
191
+ async loadSession(session) {
192
+ const ret = await this.state.deserialize(session);
193
+ this.navChain.simulateAppOpen();
194
+ return ret;
195
+ }
196
+
197
+ async isSessionValid() {
198
+ try {
199
+ await this.account.currentUser();
200
+ return true;
201
+ } catch {
202
+ return false;
203
+ }
204
+ }
205
+
206
+ destroy() {
207
+ // Cleanup resources - keep original behaviour for request streams if present
208
+ try { this.request.error$.complete(); } catch (_) {}
209
+ try { this.request.end$.complete(); } catch (_) {}
210
+ }
211
+
212
+ // -------------------------------
213
+ // === UTILITY HELPER METHODS
214
+ // -------------------------------
215
+
216
+ async preLoginFlow() {
217
+ if (this.state.verbose) console.log('[Pre-Login] Starting pre-login flow (sync_launcher)...');
218
+ try {
219
+ await this.request.send({
220
+ url: '/api/v1/launcher/sync/',
221
+ method: 'POST',
222
+ form: this.request.sign({
223
+ id: this.state.uuid,
224
+ server_config_retrieval: '1',
225
+ }),
226
+ });
227
+ if (this.state.verbose) console.log('[Pre-Login] Launcher Sync: OK');
228
+ } catch (e) {
229
+ if (this.state.verbose) console.warn('[Pre-Login] Launcher Sync Failed (non-fatal):', e.message);
230
+ }
231
+ await new Promise(resolve => setTimeout(resolve, Math.random() * 700 + 175));
232
+ }
233
+
234
+ async postLoginFlow() {
235
+ if (this.state.verbose) console.log('[Post-Login] Starting post-login flow...');
236
+ try {
237
+ await this.request.send({
238
+ url: '/api/v1/feed/reels_tray/',
239
+ method: 'POST',
240
+ form: this.request.sign({
241
+ supported_capabilities_new: JSON.stringify(this.state.constants.SUPPORTED_CAPABILITIES),
242
+ reason: 'cold_start',
243
+ timezone_offset: String(this.state.timezoneOffset),
244
+ tray_session_id: this.state.traySessionId,
245
+ request_id: this.state.requestId,
246
+ _uuid: this.state.uuid,
247
+ page_size: 50,
248
+ reel_tray_impressions: {},
249
+ }),
250
+ });
251
+ if (this.state.verbose) console.log('[Post-Login] Reels tray: OK');
252
+ } catch (e) {
253
+ if (this.state.verbose) console.warn('[Post-Login] Reels tray failed (non-fatal):', e.message);
254
+ }
255
+ try {
256
+ const timelineData = JSON.stringify({
257
+ has_camera_permission: '1',
258
+ feed_view_info: '[]',
259
+ phone_id: this.state.phoneId,
260
+ reason: 'cold_start_fetch',
261
+ battery_level: 100,
262
+ timezone_offset: String(this.state.timezoneOffset),
263
+ device_id: this.state.uuid,
264
+ request_id: this.state.requestId,
265
+ _uuid: this.state.uuid,
266
+ is_charging: Math.random() > 0.5 ? 1 : 0,
267
+ is_dark_mode: 1,
268
+ will_sound_on: Math.random() > 0.5 ? 1 : 0,
269
+ session_id: this.state.clientSessionId,
270
+ bloks_versioning_id: this.state.bloksVersionId,
271
+ is_pull_to_refresh: '0',
272
+ });
273
+ await this.request.send({
274
+ url: '/api/v1/feed/timeline/',
275
+ method: 'POST',
276
+ data: timelineData,
277
+ headers: {
278
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
279
+ 'X-Ads-Opt-Out': '0',
280
+ 'X-DEVICE-ID': this.state.uuid,
281
+ 'X-CM-Bandwidth-KBPS': '-1.000',
282
+ 'X-CM-Latency': String(Math.floor(Math.random() * 5) + 1),
283
+ },
284
+ });
285
+ if (this.state.verbose) console.log('[Post-Login] Timeline feed: OK');
286
+ } catch (e) {
287
+ if (this.state.verbose) console.warn('[Post-Login] Timeline feed failed (non-fatal):', e.message);
288
+ }
289
+ }
290
+
291
+ async simulateAppStart() {
292
+ return this.preLoginFlow();
293
+ }
294
+
295
+ /**
296
+ * Generic retry helper for async functions.
297
+ *
298
+ * Usage:
299
+ * await client.retryAsync(() => client.request.post(...), { retries: 5, delayMs: 1000 });
300
+ *
301
+ * Options:
302
+ * - retries: number (default from this._defaultRetryPolicy.retries)
303
+ * - delayMs: base delay in ms (default from this._defaultRetryPolicy.delayMs)
304
+ * - factor: multiplier for exponential backoff (default 1.5)
305
+ * - onRetry: optional callback (err, attempt) called before next retry
306
+ */
307
+ async retryAsync(fn, options = {}) {
308
+ const retries = typeof options.retries === 'number' ? options.retries : this._defaultRetryPolicy.retries;
309
+ const delayMs = typeof options.delayMs === 'number' ? options.delayMs : this._defaultRetryPolicy.delayMs;
310
+ const factor = typeof options.factor === 'number' ? options.factor : 1.5;
311
+ const onRetry = typeof options.onRetry === 'function' ? options.onRetry : null;
312
+
313
+ let lastErr;
314
+ for (let attempt = 0; attempt <= retries; attempt++) {
315
+ try {
316
+ if (this.state.verbose) {
317
+ console.log(`[Retry] attempt ${attempt + 1}/${retries + 1}`);
318
+ }
319
+ const res = await fn();
320
+ return res;
321
+ } catch (err) {
322
+ lastErr = err;
323
+ if (attempt === retries) break;
324
+ if (onRetry) {
325
+ try { onRetry(err, attempt + 1); } catch (_) {}
326
+ }
327
+ const backoff = Math.round(delayMs * Math.pow(factor, attempt));
328
+ if (this.state.verbose) {
329
+ console.warn(`[Retry] attempt ${attempt + 1} failed: ${err && err.message ? err.message : err}. Backoff ${backoff}ms`);
330
+ }
331
+ await new Promise(r => setTimeout(r, backoff));
332
+ }
333
+ }
334
+ throw lastErr || new Error('retryAsync failed without specific error');
335
+ }
336
+
337
+ /**
338
+ * Set default retry policy for retryAsync.
339
+ * Example: client.setDefaultRetryPolicy({ retries: 5, delayMs: 800 });
340
+ */
341
+ setDefaultRetryPolicy(policy = {}) {
342
+ if (typeof policy.retries === 'number') this._defaultRetryPolicy.retries = policy.retries;
343
+ if (typeof policy.delayMs === 'number') this._defaultRetryPolicy.delayMs = policy.delayMs;
344
+ return this._defaultRetryPolicy;
345
+ }
346
+
347
+ /**
348
+ * Save session object to a file. Path optional (defaults to ./session.json).
349
+ * Will call this.saveSession() internally.
350
+ */
351
+ async saveSessionToFile(filePath) {
352
+ const p = filePath || path.resolve(process.cwd(), 'session.json');
353
+ const data = await this.saveSession();
354
+ // Ensure JSON string
355
+ const json = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
356
+ await fs.promises.writeFile(p, json, { mode: 0o600 });
357
+ if (this.state.verbose) console.log('[Session] Saved session to', p);
358
+ return p;
359
+ }
360
+
361
+ /**
362
+ * Load session from file path (defaults to ./session.json). Returns true on success.
363
+ */
364
+ async loadSessionFromFile(filePath) {
365
+ const p = filePath || path.resolve(process.cwd(), 'session.json');
366
+ if (!fs.existsSync(p)) {
367
+ if (this.state.verbose) console.warn('[Session] loadSessionFromFile: file not found', p);
368
+ return false;
369
+ }
370
+ const raw = await fs.promises.readFile(p, 'utf8');
371
+ let sessionObj;
372
+ try {
373
+ sessionObj = JSON.parse(raw);
374
+ } catch (e) {
375
+ if (this.state.verbose) console.warn('[Session] loadSessionFromFile: invalid JSON in', p);
376
+ throw e;
377
+ }
378
+ await this.loadSession(sessionObj);
379
+ if (this.state.verbose) console.log('[Session] Loaded session from', p);
380
+ return true;
381
+ }
382
+
383
+ /**
384
+ * Attempt to load session JSON if exists and valid, else false.
385
+ * Wrapper helper for convenience.
386
+ */
387
+ async tryLoadSessionFileIfExists(filePath) {
388
+ try {
389
+ const loaded = await this.loadSessionFromFile(filePath);
390
+ if (!loaded) return false;
391
+ return await this.isSessionValid();
392
+ } catch (e) {
393
+ if (this.state.verbose) console.warn('[Session] tryLoadSessionFileIfExists failed:', e && e.message);
394
+ return false;
395
+ }
396
+ }
397
+
398
+ /**
399
+ * Set verbose mode on/off.
400
+ */
401
+ setVerbose(flag) {
402
+ this.state.verbose = !!flag;
403
+ return this.state.verbose;
404
+ }
405
+
406
+ /**
407
+ * safeDestroy: a slightly more robust destroy which attempts to stop requests, etc.
408
+ */
409
+ async safeDestroy() {
410
+ try { if (this.request && this.request.error$ && typeof this.request.error$.complete === 'function') this.request.error$.complete(); } catch (_) {}
411
+ try { if (this.request && this.request.end$ && typeof this.request.end$.complete === 'function') this.request.end$.complete(); } catch (_) {}
412
+
413
+
414
+ // keep original destroy for backward compatibility
415
+ try { this.destroy(); } catch (_) {}
416
+ }
417
+ }
418
+
419
+ module.exports = IgApiClient;
@@ -0,0 +1,282 @@
1
+ 'use strict';
2
+
3
+ const { random } = require('lodash');
4
+
5
+ const SCREEN_IDS = {
6
+ MAIN_FEED: 'MainFeedFragment',
7
+ FEED_TIMELINE: 'FeedTimelineFragment',
8
+ DIRECT_INBOX: 'DirectInboxFragment',
9
+ DIRECT_THREAD: 'DirectThreadFragment',
10
+ DIRECT_PENDING: 'DirectPendingInboxFragment',
11
+ SELF_PROFILE: 'SelfProfileFragment',
12
+ PROFILE: 'ProfileFragment',
13
+ PROFILE_MEDIA_TAB: 'ProfileMediaTabFragment',
14
+ EXPLORE: 'ExploreFragment',
15
+ REELS: 'ReelsFragment',
16
+ STORY_VIEWER: 'StoryViewerFragment',
17
+ SEARCH: 'SearchFragment',
18
+ ACTIVITY: 'ActivityFeedFragment',
19
+ SETTINGS: 'SettingsFragment',
20
+ MEDIA_VIEWER: 'MediaViewerFragment',
21
+ };
22
+
23
+ const MODULE_IDS = {
24
+ MAIN_FEED: 'feed_timeline',
25
+ DIRECT_INBOX: 'direct_inbox',
26
+ DIRECT_THREAD: 'direct_thread',
27
+ DIRECT_PENDING: 'direct_pending_inbox',
28
+ SELF_PROFILE: 'self_profile',
29
+ PROFILE: 'profile',
30
+ EXPLORE: 'explore_popular',
31
+ REELS: 'clips_viewer',
32
+ STORY_VIEWER: 'reel_feed_timeline',
33
+ SEARCH: 'search',
34
+ ACTIVITY: 'news',
35
+ SETTINGS: 'settings',
36
+ MEDIA_VIEWER: 'feed_contextual_profile',
37
+ };
38
+
39
+ const SHORT_CODES = {
40
+ feed_timeline: '9MV',
41
+ direct_inbox: 'QrA',
42
+ direct_thread: 'MpL',
43
+ direct_pending_inbox: 'QrB',
44
+ self_profile: '9Xf',
45
+ profile: '8wC',
46
+ explore_popular: '6xQ',
47
+ clips_viewer: '9Ly',
48
+ reel_feed_timeline: '5RE',
49
+ search: '7GJ',
50
+ news: '9HR',
51
+ settings: '4Dn',
52
+ feed_contextual_profile: '9z6',
53
+ };
54
+
55
+ const ALTERNATIVE_SHORT_CODES = {
56
+ feed_timeline: ['MainFeedFragment', '9MV', 'cold_start'],
57
+ direct_inbox: ['QrA', 'DirectInboxFragment', 'ig_direct'],
58
+ direct_thread: ['MpL', 'DirectThreadFragment', 'ig_direct_thread'],
59
+ self_profile: ['9Xf', 'SelfFragment', 'self_profile'],
60
+ profile: ['8wC', 'ProfileFragment', 'profile'],
61
+ explore_popular: ['6xQ', 'ExploreFragment', 'explore'],
62
+ };
63
+
64
+ class NavChainManager {
65
+ constructor() {
66
+ this._chain = [];
67
+ this._stepCounter = 0;
68
+ this._lastActionTimestamp = Date.now();
69
+ this._sessionStarted = false;
70
+ this._currentContext = null;
71
+ }
72
+
73
+ reset() {
74
+ this._chain = [];
75
+ this._stepCounter = 0;
76
+ this._lastActionTimestamp = Date.now();
77
+ this._sessionStarted = false;
78
+ this._currentContext = null;
79
+ }
80
+
81
+ _pickShortCode(moduleId) {
82
+ const alts = ALTERNATIVE_SHORT_CODES[moduleId];
83
+ if (alts && Math.random() < 0.3) {
84
+ return alts[Math.floor(Math.random() * alts.length)];
85
+ }
86
+ return SHORT_CODES[moduleId] || moduleId;
87
+ }
88
+
89
+ _addStep(screenOrShortCode, moduleId) {
90
+ this._stepCounter++;
91
+ const entry = `${screenOrShortCode}:${moduleId}:${this._stepCounter}`;
92
+ this._chain.push(entry);
93
+ if (this._chain.length > 8) {
94
+ this._chain = this._chain.slice(-6);
95
+ }
96
+ this._lastActionTimestamp = Date.now();
97
+ return entry;
98
+ }
99
+
100
+ simulateAppOpen() {
101
+ this.reset();
102
+ this._sessionStarted = true;
103
+
104
+ const openVariant = Math.random();
105
+ if (openVariant < 0.6) {
106
+ this._addStep(this._pickShortCode('feed_timeline'), 'feed_timeline');
107
+ } else if (openVariant < 0.85) {
108
+ this._addStep(this._pickShortCode('feed_timeline'), 'feed_timeline');
109
+ const delay = random(200, 800);
110
+ this._lastActionTimestamp = Date.now() - delay;
111
+ } else {
112
+ this._addStep('cold_start', 'feed_timeline');
113
+ }
114
+
115
+ this._currentContext = 'feed';
116
+ return this.getChainString();
117
+ }
118
+
119
+ navigateToInbox() {
120
+ if (!this._sessionStarted) {
121
+ this.simulateAppOpen();
122
+ }
123
+ this._addStep(this._pickShortCode('direct_inbox'), 'direct_inbox');
124
+ this._currentContext = 'direct_inbox';
125
+ return this.getChainString();
126
+ }
127
+
128
+ navigateToThread(threadId) {
129
+ if (this._currentContext !== 'direct_inbox' && this._currentContext !== 'direct_thread') {
130
+ this.navigateToInbox();
131
+ }
132
+ this._addStep(this._pickShortCode('direct_thread'), 'direct_thread');
133
+ this._currentContext = 'direct_thread';
134
+ return this.getChainString();
135
+ }
136
+
137
+ navigateToPendingInbox() {
138
+ if (this._currentContext !== 'direct_inbox') {
139
+ this.navigateToInbox();
140
+ }
141
+ this._addStep(this._pickShortCode('direct_pending_inbox'), 'direct_pending_inbox');
142
+ this._currentContext = 'direct_pending';
143
+ return this.getChainString();
144
+ }
145
+
146
+ navigateToProfile(isSelf = false) {
147
+ if (!this._sessionStarted) {
148
+ this.simulateAppOpen();
149
+ }
150
+ if (isSelf) {
151
+ this._addStep(this._pickShortCode('self_profile'), 'self_profile');
152
+ this._currentContext = 'self_profile';
153
+ } else {
154
+ this._addStep(this._pickShortCode('profile'), 'profile');
155
+ this._currentContext = 'profile';
156
+ }
157
+ return this.getChainString();
158
+ }
159
+
160
+ navigateToExplore() {
161
+ if (!this._sessionStarted) {
162
+ this.simulateAppOpen();
163
+ }
164
+ this._addStep(this._pickShortCode('explore_popular'), 'explore_popular');
165
+ this._currentContext = 'explore';
166
+ return this.getChainString();
167
+ }
168
+
169
+ navigateToFeed() {
170
+ if (!this._sessionStarted) {
171
+ this.simulateAppOpen();
172
+ } else {
173
+ this._addStep(this._pickShortCode('feed_timeline'), 'feed_timeline');
174
+ }
175
+ this._currentContext = 'feed';
176
+ return this.getChainString();
177
+ }
178
+
179
+ incrementForAction() {
180
+ if (!this._sessionStarted) {
181
+ this.simulateAppOpen();
182
+ }
183
+ const ctx = this._currentContext || 'feed_timeline';
184
+ const moduleMap = {
185
+ 'feed': 'feed_timeline',
186
+ 'direct_inbox': 'direct_inbox',
187
+ 'direct_thread': 'direct_thread',
188
+ 'direct_pending': 'direct_pending_inbox',
189
+ 'self_profile': 'self_profile',
190
+ 'profile': 'profile',
191
+ 'explore': 'explore_popular',
192
+ };
193
+ const moduleId = moduleMap[ctx] || 'feed_timeline';
194
+ this._addStep(this._pickShortCode(moduleId), moduleId);
195
+ return this.getChainString();
196
+ }
197
+
198
+ getChainForDMBroadcast(isNewThread = false) {
199
+ if (!this._sessionStarted) {
200
+ this.simulateAppOpen();
201
+ }
202
+
203
+ if (this._currentContext !== 'direct_thread') {
204
+ if (this._currentContext !== 'direct_inbox') {
205
+ this.navigateToInbox();
206
+ }
207
+ this.navigateToThread();
208
+ }
209
+
210
+ this._stepCounter++;
211
+ this._lastActionTimestamp = Date.now();
212
+ return this.getChainString();
213
+ }
214
+
215
+ getChainForDMSequence(messageIndex) {
216
+ if (messageIndex === 0 || !this._sessionStarted) {
217
+ this.simulateAppOpen();
218
+ this.navigateToInbox();
219
+ this.navigateToThread();
220
+ } else {
221
+ this._stepCounter++;
222
+ const lastEntry = this._chain[this._chain.length - 1];
223
+ if (lastEntry) {
224
+ const parts = lastEntry.split(':');
225
+ if (parts.length === 3) {
226
+ parts[2] = String(this._stepCounter);
227
+ this._chain[this._chain.length - 1] = parts.join(':');
228
+ }
229
+ }
230
+ }
231
+
232
+ this._lastActionTimestamp = Date.now();
233
+ return this.getChainString();
234
+ }
235
+
236
+ getChainForBulkDM(recipientIndex, totalRecipients) {
237
+ if (recipientIndex === 0) {
238
+ this.simulateAppOpen();
239
+ this.navigateToInbox();
240
+ }
241
+
242
+ this.navigateToThread();
243
+
244
+ this._stepCounter++;
245
+ this._lastActionTimestamp = Date.now();
246
+
247
+ if (recipientIndex > 0 && recipientIndex % random(3, 6) === 0) {
248
+ this.navigateToInbox();
249
+ this.navigateToThread();
250
+ }
251
+
252
+ return this.getChainString();
253
+ }
254
+
255
+ getChainString() {
256
+ if (this._chain.length === 0) {
257
+ this.simulateAppOpen();
258
+ }
259
+ return this._chain.join(',');
260
+ }
261
+
262
+ getCurrentContext() {
263
+ return this._currentContext;
264
+ }
265
+
266
+ getStepCounter() {
267
+ return this._stepCounter;
268
+ }
269
+
270
+ setContext(contextName) {
271
+ this._currentContext = contextName;
272
+ if (!this._sessionStarted) {
273
+ this.simulateAppOpen();
274
+ }
275
+ }
276
+ }
277
+
278
+ NavChainManager.SCREEN_IDS = SCREEN_IDS;
279
+ NavChainManager.MODULE_IDS = MODULE_IDS;
280
+ NavChainManager.SHORT_CODES = SHORT_CODES;
281
+
282
+ module.exports = NavChainManager;
@@ -0,0 +1,7 @@
1
+ class Repository {
2
+ constructor(client) {
3
+ this.client = client;
4
+ }
5
+ }
6
+
7
+ module.exports = Repository;