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,2 @@
1
+ export * from './commands';
2
+ export * from './direct.commands';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./commands"), exports);
18
+ __exportStar(require("./direct.commands"), exports);
19
+ __exportStar(require("./enhanced.direct.commands"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/realtime/commands/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,6CAA2B;AAC3B,oDAAkC"}
@@ -0,0 +1,293 @@
1
+ const debug = require('debug')('ig:delta');
2
+
3
+ /**
4
+ * Delta Sync Manager - Apply real Instagram delta updates to local state
5
+ * Based on MessageSync format from reverse-engineered instagram_mqtt
6
+ */
7
+ class DeltaSyncManager {
8
+ constructor() {
9
+ this.state = {
10
+ threads: {}, // thread_id → ThreadUpdate
11
+ messages: {}, // item_id → MessageSyncMessage
12
+ typing: {}, // thread_id → TypingIndicator
13
+ presence: {} // user_id → PresenceIndicator
14
+ };
15
+ this.listeners = [];
16
+ this.operations = { add: 0, update: 0, delete: 0 };
17
+ }
18
+
19
+ /**
20
+ * Apply delta operations (add/update/delete) to local state
21
+ */
22
+ applyDelta(delta) {
23
+ if (!delta || !delta.items || delta.items.length === 0) {
24
+ return { applied: 0, errors: [], stats: this.operations };
25
+ }
26
+
27
+ let applied = 0;
28
+ const errors = [];
29
+
30
+ delta.items.forEach(item => {
31
+ try {
32
+ const result = this.applyItem(item);
33
+ if (result) applied++;
34
+ } catch (e) {
35
+ errors.push({
36
+ itemId: item.id || item.item_id,
37
+ error: e.message,
38
+ operation: item.op || item.type
39
+ });
40
+ debug(`❌ Error applying item:`, e.message);
41
+ }
42
+ });
43
+
44
+ // Notify listeners
45
+ if (applied > 0) {
46
+ this.notifyListeners(delta);
47
+ }
48
+
49
+ return {
50
+ applied,
51
+ errors,
52
+ total: delta.items.length,
53
+ stats: this.operations
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Apply single item (message, thread, typing, presence)
59
+ */
60
+ applyItem(item) {
61
+ if (!item) return false;
62
+
63
+ // Get operation type from IrisItem
64
+ const operation = item.op || item.type || 'add'; // add, replace, delete
65
+
66
+ // Extract data from 'data' oneof field
67
+ if (item.data?.message) {
68
+ return this.applyMessage(operation, item.data.message);
69
+ }
70
+
71
+ if (item.data?.thread) {
72
+ return this.applyThread(operation, item.data.thread);
73
+ }
74
+
75
+ if (item.data?.typing) {
76
+ return this.applyTyping(operation, item.data.typing);
77
+ }
78
+
79
+ if (item.data?.presence) {
80
+ return this.applyPresence(operation, item.data.presence);
81
+ }
82
+
83
+ // Fallback for direct objects
84
+ if (item.message) {
85
+ return this.applyMessage(operation, item.message);
86
+ }
87
+ if (item.thread) {
88
+ return this.applyThread(operation, item.thread);
89
+ }
90
+ if (item.typing) {
91
+ return this.applyTyping(operation, item.typing);
92
+ }
93
+ if (item.presence) {
94
+ return this.applyPresence(operation, item.presence);
95
+ }
96
+
97
+ return false;
98
+ }
99
+
100
+ /**
101
+ * Apply message delta (real Instagram MessageSyncMessage format)
102
+ */
103
+ applyMessage(operation, message) {
104
+ const msgId = message.item_id;
105
+
106
+ if (operation === 'delete' || operation === 'deletion') {
107
+ delete this.state.messages[msgId];
108
+ this.operations.delete++;
109
+ debug(`🗑️ Deleted message ${msgId}`);
110
+ return true;
111
+ }
112
+
113
+ if (operation === 'replace' || operation === 'update') {
114
+ if (!this.state.messages[msgId]) {
115
+ debug(`⚠️ Message ${msgId} not found for update`);
116
+ return false;
117
+ }
118
+ Object.assign(this.state.messages[msgId], message);
119
+ this.operations.update++;
120
+ debug(`✏️ Updated message ${msgId}: "${message.text?.substring(0, 30)}"`);
121
+ return true;
122
+ }
123
+
124
+ // add/default
125
+ this.state.messages[msgId] = message;
126
+ this.operations.add++;
127
+ debug(`➕ Added message ${msgId}: "${message.text?.substring(0, 30) || 'media'}"`);
128
+ return true;
129
+ }
130
+
131
+ /**
132
+ * Apply thread delta (real Instagram ThreadUpdate format)
133
+ */
134
+ applyThread(operation, thread) {
135
+ const threadId = thread.thread_id || thread.thread_v2_id;
136
+
137
+ if (operation === 'delete') {
138
+ delete this.state.threads[threadId];
139
+ this.operations.delete++;
140
+ debug(`🗑️ Deleted thread ${threadId}`);
141
+ return true;
142
+ }
143
+
144
+ if (operation === 'replace' || operation === 'update') {
145
+ if (!this.state.threads[threadId]) {
146
+ // Create new thread on update if doesn't exist
147
+ this.state.threads[threadId] = thread;
148
+ this.operations.add++;
149
+ debug(`➕ Created thread from update: ${thread.thread_title}`);
150
+ return true;
151
+ }
152
+ Object.assign(this.state.threads[threadId], thread);
153
+ this.operations.update++;
154
+ debug(`✏️ Updated thread ${threadId}: "${thread.thread_title}"`);
155
+ return true;
156
+ }
157
+
158
+ // add/default
159
+ this.state.threads[threadId] = thread;
160
+ this.operations.add++;
161
+ debug(`➕ Added thread: "${thread.thread_title}" (${thread.user_ids?.length || 1} members)`);
162
+ return true;
163
+ }
164
+
165
+ /**
166
+ * Apply typing indicator delta
167
+ */
168
+ applyTyping(operation, typing) {
169
+ const threadId = typing.thread_id;
170
+
171
+ if (operation === 'delete' || typing.state === 'stopped') {
172
+ delete this.state.typing[threadId];
173
+ this.operations.delete++;
174
+ debug(`⌨️ User ${typing.from_user_id} stopped typing in ${threadId}`);
175
+ return true;
176
+ }
177
+
178
+ this.state.typing[threadId] = typing;
179
+ this.operations.add++;
180
+ debug(`⌨️ User ${typing.from_user_id} typing in ${threadId}`);
181
+ return true;
182
+ }
183
+
184
+ /**
185
+ * Apply presence indicator delta
186
+ */
187
+ applyPresence(operation, presence) {
188
+ const userId = presence.user_id;
189
+
190
+ if (operation === 'delete' || presence.status === 'inactive') {
191
+ delete this.state.presence[userId];
192
+ this.operations.delete++;
193
+ debug(`🔴 User ${userId} offline`);
194
+ return true;
195
+ }
196
+
197
+ this.state.presence[userId] = presence;
198
+ this.operations.add++;
199
+ debug(`🟢 User ${userId} ${presence.status}`);
200
+ return true;
201
+ }
202
+
203
+ /**
204
+ * Subscribe to state changes
205
+ */
206
+ subscribe(callback) {
207
+ this.listeners.push(callback);
208
+ return () => {
209
+ this.listeners = this.listeners.filter(l => l !== callback);
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Notify listeners of changes
215
+ */
216
+ notifyListeners(delta) {
217
+ this.listeners.forEach(callback => {
218
+ try {
219
+ callback(delta, this.getState());
220
+ } catch (e) {
221
+ debug('Listener error:', e.message);
222
+ }
223
+ });
224
+ }
225
+
226
+ /**
227
+ * Get current synchronized state
228
+ */
229
+ getState() {
230
+ return {
231
+ threads: JSON.parse(JSON.stringify(this.state.threads)),
232
+ messages: JSON.parse(JSON.stringify(this.state.messages)),
233
+ typing: JSON.parse(JSON.stringify(this.state.typing)),
234
+ presence: JSON.parse(JSON.stringify(this.state.presence))
235
+ };
236
+ }
237
+
238
+ /**
239
+ * Query methods
240
+ */
241
+ getThread(threadId) {
242
+ return this.state.threads[threadId] || null;
243
+ }
244
+
245
+ getThreadMessages(threadId) {
246
+ return Object.values(this.state.messages).filter(m => m.thread_id === threadId || m.thread_v2_id === threadId);
247
+ }
248
+
249
+ getThreads() {
250
+ return Object.values(this.state.threads);
251
+ }
252
+
253
+ getAllMessages() {
254
+ return Object.values(this.state.messages);
255
+ }
256
+
257
+ getTypingInThread(threadId) {
258
+ return this.state.typing[threadId] || null;
259
+ }
260
+
261
+ getUserPresence(userId) {
262
+ return this.state.presence[userId] || null;
263
+ }
264
+
265
+ /**
266
+ * Stats
267
+ */
268
+ getStats() {
269
+ return {
270
+ threads: Object.keys(this.state.threads).length,
271
+ messages: Object.keys(this.state.messages).length,
272
+ typing: Object.keys(this.state.typing).length,
273
+ presence: Object.keys(this.state.presence).length,
274
+ operations: this.operations
275
+ };
276
+ }
277
+
278
+ /**
279
+ * Clear all state
280
+ */
281
+ clear() {
282
+ this.state = {
283
+ threads: {},
284
+ messages: {},
285
+ typing: {},
286
+ presence: {}
287
+ };
288
+ this.operations = { add: 0, update: 0, delete: 0 };
289
+ debug('✓ State cleared');
290
+ }
291
+ }
292
+
293
+ module.exports = DeltaSyncManager;
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DMSender = void 0;
4
+ const shared_1 = require("../../shared");
5
+ const uuid_1 = require("uuid");
6
+ /**
7
+ * Direct Message Sender via MQTT
8
+ */
9
+ class DMSender {
10
+ constructor(client) {
11
+ this.dmDebug = (0, shared_1.debugChannel)('realtime', 'dm-sender');
12
+ this.client = client;
13
+ }
14
+ /**
15
+ * Send text message via MQTT
16
+ */
17
+ async sendTextMessage(threadId, text, clientContext = null) {
18
+ this.dmDebug(`Sending text message to thread ${threadId}: "${text.substring(0, 50)}..."`);
19
+ const command = {
20
+ action: 'send_item',
21
+ thread_id: threadId,
22
+ item_type: 'text',
23
+ text,
24
+ timestamp: Date.now(),
25
+ client_context: clientContext || (0, uuid_1.v4)(),
26
+ };
27
+ try {
28
+ return await this.client.directCommands?.sendCommand({
29
+ action: 'send_item',
30
+ data: command,
31
+ threadId,
32
+ });
33
+ } catch (err) {
34
+ this.dmDebug(`Failed to send message: ${err.message}`);
35
+ throw err;
36
+ }
37
+ }
38
+ /**
39
+ * Send media message via MQTT (photo/video)
40
+ */
41
+ async sendMediaMessage(threadId, mediaId, mediaType = 'photo', clientContext = null) {
42
+ this.dmDebug(`Sending ${mediaType} to thread ${threadId}`);
43
+ const command = {
44
+ action: 'send_item',
45
+ thread_id: threadId,
46
+ item_type: mediaType,
47
+ media_id: mediaId,
48
+ timestamp: Date.now(),
49
+ client_context: clientContext || (0, uuid_1.v4)(),
50
+ };
51
+ try {
52
+ return await this.client.directCommands?.sendCommand({
53
+ action: 'send_item',
54
+ data: command,
55
+ threadId,
56
+ });
57
+ } catch (err) {
58
+ this.dmDebug(`Failed to send media: ${err.message}`);
59
+ throw err;
60
+ }
61
+ }
62
+ /**
63
+ * Send link message
64
+ */
65
+ async sendLinkMessage(threadId, url, title = null, clientContext = null) {
66
+ this.dmDebug(`Sending link to thread ${threadId}: ${url}`);
67
+ const command = {
68
+ action: 'send_item',
69
+ thread_id: threadId,
70
+ item_type: 'link',
71
+ url,
72
+ title: title || url,
73
+ timestamp: Date.now(),
74
+ client_context: clientContext || (0, uuid_1.v4)(),
75
+ };
76
+ try {
77
+ return await this.client.directCommands?.sendCommand({
78
+ action: 'send_item',
79
+ data: command,
80
+ threadId,
81
+ });
82
+ } catch (err) {
83
+ this.dmDebug(`Failed to send link: ${err.message}`);
84
+ throw err;
85
+ }
86
+ }
87
+ }
88
+ exports.DMSender = DMSender;
@@ -0,0 +1,185 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorHandler = void 0;
4
+ const shared_1 = require("../../shared");
5
+
6
+ const ERROR_TYPES = {
7
+ RATE_LIMIT: 'rate_limit',
8
+ AUTH_FAILURE: 'auth_failure',
9
+ NETWORK: 'network',
10
+ PROTOCOL: 'protocol',
11
+ SERVER: 'server',
12
+ UNKNOWN: 'unknown',
13
+ };
14
+
15
+ const RATE_LIMIT_PATTERNS = [
16
+ 'rate limit', 'too many', 'throttl', 'spam', 'please wait',
17
+ 'action blocked', 'try again later', 'temporarily blocked',
18
+ '429', 'flood',
19
+ ];
20
+
21
+ const AUTH_PATTERNS = [
22
+ 'auth', 'login', 'session', 'credential', 'token', 'expired',
23
+ 'unauthorized', '401', 'forbidden', '403', 'password',
24
+ 'challenge_required', 'checkpoint', 'checkpoint_required',
25
+ 'login_required', 'consent_required', 'two_factor',
26
+ ];
27
+
28
+ const NETWORK_PATTERNS = [
29
+ 'ECONNRESET', 'ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND',
30
+ 'ENETUNREACH', 'socket hang up', 'network', 'dns',
31
+ 'getaddrinfo', 'connect EHOSTUNREACH', 'EPIPE', 'EAI_AGAIN',
32
+ ];
33
+
34
+ class ErrorHandler {
35
+ constructor(client) {
36
+ this.errorDebug = (0, shared_1.debugChannel)('realtime', 'errors');
37
+ this.errorCount = 0;
38
+ this.maxRetries = 15;
39
+ this.client = client;
40
+ this.errorHistory = [];
41
+ this.rateLimitUntil = 0;
42
+ this.consecutiveAuthFailures = 0;
43
+ }
44
+
45
+ classifyError(error) {
46
+ const msg = (error?.message || String(error)).toLowerCase();
47
+
48
+ for (const pattern of RATE_LIMIT_PATTERNS) {
49
+ if (msg.includes(pattern)) return ERROR_TYPES.RATE_LIMIT;
50
+ }
51
+ for (const pattern of AUTH_PATTERNS) {
52
+ if (msg.includes(pattern)) return ERROR_TYPES.AUTH_FAILURE;
53
+ }
54
+ for (const pattern of NETWORK_PATTERNS) {
55
+ if (msg.includes(pattern.toLowerCase())) return ERROR_TYPES.NETWORK;
56
+ }
57
+ if (msg.includes('connack') || msg.includes('protocol') || msg.includes('thrift') || msg.includes('parse')) {
58
+ return ERROR_TYPES.PROTOCOL;
59
+ }
60
+ if (msg.includes('500') || msg.includes('502') || msg.includes('503') || msg.includes('server')) {
61
+ return ERROR_TYPES.SERVER;
62
+ }
63
+ return ERROR_TYPES.UNKNOWN;
64
+ }
65
+
66
+ getBackoffForType(errorType, attemptNumber) {
67
+ const jitter = Math.floor(Math.random() * 2000);
68
+ switch (errorType) {
69
+ case ERROR_TYPES.RATE_LIMIT:
70
+ return Math.min(60000 * Math.pow(1.5, attemptNumber - 1), 600000) + jitter;
71
+ case ERROR_TYPES.AUTH_FAILURE:
72
+ return Math.min(10000 * Math.pow(2, attemptNumber - 1), 120000) + jitter;
73
+ case ERROR_TYPES.NETWORK:
74
+ return Math.min(2000 * Math.pow(2, attemptNumber - 1), 60000) + jitter;
75
+ case ERROR_TYPES.SERVER:
76
+ return Math.min(5000 * Math.pow(2, attemptNumber - 1), 120000) + jitter;
77
+ case ERROR_TYPES.PROTOCOL:
78
+ return Math.min(5000 * Math.pow(2, attemptNumber - 1), 60000) + jitter;
79
+ default:
80
+ return Math.min(3000 * Math.pow(2, attemptNumber - 1), 90000) + jitter;
81
+ }
82
+ }
83
+
84
+ handleConnectionError(error) {
85
+ this.errorCount++;
86
+ const errorType = this.classifyError(error);
87
+ const delay = this.getBackoffForType(errorType, this.errorCount);
88
+
89
+ this.errorHistory.push({
90
+ type: errorType,
91
+ message: error?.message || String(error),
92
+ timestamp: Date.now(),
93
+ attempt: this.errorCount,
94
+ });
95
+ if (this.errorHistory.length > 50) this.errorHistory.shift();
96
+
97
+ this.errorDebug(`[${errorType.toUpperCase()}] Error (${this.errorCount}/${this.maxRetries}): ${error?.message || error}`);
98
+
99
+ if (errorType === ERROR_TYPES.RATE_LIMIT) {
100
+ this.rateLimitUntil = Date.now() + delay;
101
+ this.errorDebug(`Rate limited. Waiting ${Math.round(delay/1000)}s before retry.`);
102
+ }
103
+
104
+ if (errorType === ERROR_TYPES.AUTH_FAILURE) {
105
+ this.consecutiveAuthFailures++;
106
+ if (this.consecutiveAuthFailures >= 3) {
107
+ this.errorDebug('Multiple auth failures. Credentials may need refresh.');
108
+ this.client.emit('auth_failure', {
109
+ count: this.consecutiveAuthFailures,
110
+ error: error?.message || String(error),
111
+ });
112
+ return false;
113
+ }
114
+ } else {
115
+ this.consecutiveAuthFailures = 0;
116
+ }
117
+
118
+ if (this.errorCount >= this.maxRetries) {
119
+ this.client.emit('error', new Error(`Max retries (${this.maxRetries}) exceeded. Last error type: ${errorType}`));
120
+ return false;
121
+ }
122
+
123
+ this.errorDebug(`Scheduling retry in ${Math.round(delay/1000)}s (type: ${errorType})`);
124
+
125
+ setTimeout(() => {
126
+ if (typeof this.client.reconnect === 'function') {
127
+ this.client.reconnect();
128
+ } else if (typeof this.client._attemptReconnectSafely === 'function') {
129
+ this.client._attemptReconnectSafely().catch(() => {});
130
+ }
131
+ }, delay);
132
+
133
+ return true;
134
+ }
135
+
136
+ isRateLimited() {
137
+ return Date.now() < this.rateLimitUntil;
138
+ }
139
+
140
+ getRateLimitRemainingMs() {
141
+ return Math.max(0, this.rateLimitUntil - Date.now());
142
+ }
143
+
144
+ handlePayloadError(error, topic) {
145
+ this.errorDebug(`Payload Error on topic ${topic}: ${error.message}`);
146
+ this.client.emit('warning', {
147
+ type: 'payload_error',
148
+ topic,
149
+ error: error.message,
150
+ });
151
+ }
152
+
153
+ handleProtocolError(error) {
154
+ this.errorDebug(`Protocol Error: ${error.message}`);
155
+ this.client.emit('error', new Error(`MQTT Protocol Error: ${error.message}`));
156
+ }
157
+
158
+ resetErrorCounter() {
159
+ this.errorCount = 0;
160
+ this.consecutiveAuthFailures = 0;
161
+ this.errorDebug('Error counter reset');
162
+ }
163
+
164
+ getErrorStats() {
165
+ const recentErrors = this.errorHistory.filter(e => Date.now() - e.timestamp < 3600000);
166
+ const typeBreakdown = {};
167
+ for (const e of recentErrors) {
168
+ typeBreakdown[e.type] = (typeBreakdown[e.type] || 0) + 1;
169
+ }
170
+ return {
171
+ errorCount: this.errorCount,
172
+ maxRetries: this.maxRetries,
173
+ canRetry: this.errorCount < this.maxRetries,
174
+ isRateLimited: this.isRateLimited(),
175
+ rateLimitRemainingMs: this.getRateLimitRemainingMs(),
176
+ consecutiveAuthFailures: this.consecutiveAuthFailures,
177
+ recentErrorCount: recentErrors.length,
178
+ typeBreakdown,
179
+ };
180
+ }
181
+ }
182
+
183
+ ErrorHandler.ERROR_TYPES = ERROR_TYPES;
184
+ exports.ErrorHandler = ErrorHandler;
185
+ exports.ERROR_TYPES = ERROR_TYPES;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GapHandler = void 0;
4
+ const shared_1 = require("../../shared");
5
+ /**
6
+ * Gap Handler - Handle message gaps and synchronization
7
+ */
8
+ class GapHandler {
9
+ constructor(client) {
10
+ this.gapDebug = (0, shared_1.debugChannel)('realtime', 'gap');
11
+ this.threadGaps = new Map();
12
+ this.client = client;
13
+ }
14
+ /**
15
+ * Detect message gap in thread
16
+ */
17
+ detectGap(threadId, lastMessageId, newMessageId) {
18
+ const lastId = parseInt(lastMessageId, 10);
19
+ const newId = parseInt(newMessageId, 10);
20
+ const gap = Math.abs(newId - lastId) > 1;
21
+
22
+ if (gap) {
23
+ this.gapDebug(`Gap detected in thread ${threadId}: ${lastMessageId} -> ${newMessageId}`);
24
+ this.threadGaps.set(threadId, { from: lastMessageId, to: newMessageId });
25
+ this.client.emit('gap', {
26
+ thread_id: threadId,
27
+ gap_from: lastMessageId,
28
+ gap_to: newMessageId,
29
+ });
30
+ }
31
+ return gap;
32
+ }
33
+ /**
34
+ * Handle gap by requesting missing messages
35
+ */
36
+ async handleGap(threadId, gapFrom, gapTo) {
37
+ this.gapDebug(`Handling gap in ${threadId}: fetching messages ${gapFrom}-${gapTo}`);
38
+ try {
39
+ // Request missing messages from REST API
40
+ const thread = await this.client.ig.direct.getThread(threadId);
41
+ const messages = await thread.getMessages({ limit: 50 });
42
+
43
+ this.client.emit('gap_filled', {
44
+ thread_id: threadId,
45
+ messages_count: messages.length,
46
+ });
47
+ return messages;
48
+ } catch (err) {
49
+ this.gapDebug(`Failed to handle gap: ${err.message}`);
50
+ this.client.emit('error', new Error(`Gap handling failed for thread ${threadId}`));
51
+ return [];
52
+ }
53
+ }
54
+ /**
55
+ * Clear gap tracking for thread
56
+ */
57
+ clearGap(threadId) {
58
+ this.threadGaps.delete(threadId);
59
+ }
60
+ }
61
+ exports.GapHandler = GapHandler;