nodejs-insta-private-api-mqtt 1.0.0

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 (210) hide show
  1. package/README.md +1650 -0
  2. package/dist/constants/constants.js +280 -0
  3. package/dist/constants/index.js +41 -0
  4. package/dist/core/client.js +243 -0
  5. package/dist/core/repository.js +7 -0
  6. package/dist/core/request.js +212 -0
  7. package/dist/core/state.js +1456 -0
  8. package/dist/core/utils.js +786 -0
  9. package/dist/downloadMedia.js +381 -0
  10. package/dist/errors/index.d.ts +16 -0
  11. package/dist/errors/index.js +30 -0
  12. package/dist/errors/index.js.map +1 -0
  13. package/dist/fbns/fbns.client.d.ts +32 -0
  14. package/dist/fbns/fbns.client.events.d.ts +41 -0
  15. package/dist/fbns/fbns.client.events.js +3 -0
  16. package/dist/fbns/fbns.client.events.js.map +1 -0
  17. package/dist/fbns/fbns.client.js +179 -0
  18. package/dist/fbns/fbns.client.js.map +1 -0
  19. package/dist/fbns/fbns.device-auth.d.ts +17 -0
  20. package/dist/fbns/fbns.device-auth.js +54 -0
  21. package/dist/fbns/fbns.device-auth.js.map +1 -0
  22. package/dist/fbns/fbns.types.d.ts +83 -0
  23. package/dist/fbns/fbns.types.js +3 -0
  24. package/dist/fbns/fbns.types.js.map +1 -0
  25. package/dist/fbns/fbns.utilities.d.ts +2 -0
  26. package/dist/fbns/fbns.utilities.js +79 -0
  27. package/dist/fbns/fbns.utilities.js.map +1 -0
  28. package/dist/fbns/index.d.ts +4 -0
  29. package/dist/fbns/index.js +21 -0
  30. package/dist/fbns/index.js.map +1 -0
  31. package/dist/index.js +39 -0
  32. package/dist/mqttot/index.d.ts +4 -0
  33. package/dist/mqttot/index.js +21 -0
  34. package/dist/mqttot/index.js.map +1 -0
  35. package/dist/mqttot/mqttot.client.d.ts +39 -0
  36. package/dist/mqttot/mqttot.client.js +120 -0
  37. package/dist/mqttot/mqttot.client.js.map +1 -0
  38. package/dist/mqttot/mqttot.connect.request.packet.d.ts +7 -0
  39. package/dist/mqttot/mqttot.connect.request.packet.js +9 -0
  40. package/dist/mqttot/mqttot.connect.request.packet.js.map +1 -0
  41. package/dist/mqttot/mqttot.connect.response.packet.d.ts +7 -0
  42. package/dist/mqttot/mqttot.connect.response.packet.js +24 -0
  43. package/dist/mqttot/mqttot.connect.response.packet.js.map +1 -0
  44. package/dist/mqttot/mqttot.connection.d.ts +57 -0
  45. package/dist/mqttot/mqttot.connection.js +56 -0
  46. package/dist/mqttot/mqttot.connection.js.map +1 -0
  47. package/dist/package.json +59 -0
  48. package/dist/realtime/commands/commands.d.ts +15 -0
  49. package/dist/realtime/commands/commands.js +21 -0
  50. package/dist/realtime/commands/commands.js.map +1 -0
  51. package/dist/realtime/commands/direct.commands.d.ts +75 -0
  52. package/dist/realtime/commands/direct.commands.js +186 -0
  53. package/dist/realtime/commands/direct.commands.js.map +1 -0
  54. package/dist/realtime/commands/enhanced.direct.commands.js +987 -0
  55. package/dist/realtime/commands/index.d.ts +2 -0
  56. package/dist/realtime/commands/index.js +19 -0
  57. package/dist/realtime/commands/index.js.map +1 -0
  58. package/dist/realtime/delta-sync.manager.js +293 -0
  59. package/dist/realtime/features/dm-sender.js +88 -0
  60. package/dist/realtime/features/error-handler.js +73 -0
  61. package/dist/realtime/features/gap-handler.js +61 -0
  62. package/dist/realtime/features/presence.manager.js +66 -0
  63. package/dist/realtime/index.js +30 -0
  64. package/dist/realtime/messages/app-presence.event.d.ts +9 -0
  65. package/dist/realtime/messages/app-presence.event.js +3 -0
  66. package/dist/realtime/messages/app-presence.event.js.map +1 -0
  67. package/dist/realtime/messages/index.d.ts +3 -0
  68. package/dist/realtime/messages/index.js +20 -0
  69. package/dist/realtime/messages/index.js.map +1 -0
  70. package/dist/realtime/messages/message-sync.message.d.ts +222 -0
  71. package/dist/realtime/messages/message-sync.message.js +43 -0
  72. package/dist/realtime/messages/message-sync.message.js.map +1 -0
  73. package/dist/realtime/messages/realtime-sub.direct.data.d.ts +11 -0
  74. package/dist/realtime/messages/realtime-sub.direct.data.js +3 -0
  75. package/dist/realtime/messages/realtime-sub.direct.data.js.map +1 -0
  76. package/dist/realtime/messages/thread-update.message.d.ts +68 -0
  77. package/dist/realtime/messages/thread-update.message.js +3 -0
  78. package/dist/realtime/messages/thread-update.message.js.map +1 -0
  79. package/dist/realtime/mixins/index.d.ts +3 -0
  80. package/dist/realtime/mixins/index.js +20 -0
  81. package/dist/realtime/mixins/index.js.map +1 -0
  82. package/dist/realtime/mixins/message-sync.mixin.d.ts +8 -0
  83. package/dist/realtime/mixins/message-sync.mixin.js +381 -0
  84. package/dist/realtime/mixins/message-sync.mixin.js.map +1 -0
  85. package/dist/realtime/mixins/mixin.d.ts +19 -0
  86. package/dist/realtime/mixins/mixin.js +41 -0
  87. package/dist/realtime/mixins/mixin.js.map +1 -0
  88. package/dist/realtime/mixins/presence-typing.mixin.js +33 -0
  89. package/dist/realtime/mixins/realtime-sub.mixin.d.ts +8 -0
  90. package/dist/realtime/mixins/realtime-sub.mixin.js +55 -0
  91. package/dist/realtime/mixins/realtime-sub.mixin.js.map +1 -0
  92. package/dist/realtime/parsers/graphql-parser.js +43 -0
  93. package/dist/realtime/parsers/graphql.parser.d.ts +15 -0
  94. package/dist/realtime/parsers/graphql.parser.js +22 -0
  95. package/dist/realtime/parsers/graphql.parser.js.map +1 -0
  96. package/dist/realtime/parsers/index.d.ts +6 -0
  97. package/dist/realtime/parsers/index.js +23 -0
  98. package/dist/realtime/parsers/index.js.map +1 -0
  99. package/dist/realtime/parsers/iris-parser.js +43 -0
  100. package/dist/realtime/parsers/iris.parser.d.ts +17 -0
  101. package/dist/realtime/parsers/iris.parser.js +10 -0
  102. package/dist/realtime/parsers/iris.parser.js.map +1 -0
  103. package/dist/realtime/parsers/json-parser.js +43 -0
  104. package/dist/realtime/parsers/json.parser.d.ts +6 -0
  105. package/dist/realtime/parsers/json.parser.js +10 -0
  106. package/dist/realtime/parsers/json.parser.js.map +1 -0
  107. package/dist/realtime/parsers/parser.d.ts +9 -0
  108. package/dist/realtime/parsers/parser.js +3 -0
  109. package/dist/realtime/parsers/parser.js.map +1 -0
  110. package/dist/realtime/parsers/region-hint-parser.js +43 -0
  111. package/dist/realtime/parsers/region-hint.parser.d.ts +12 -0
  112. package/dist/realtime/parsers/region-hint.parser.js +15 -0
  113. package/dist/realtime/parsers/region-hint.parser.js.map +1 -0
  114. package/dist/realtime/parsers/skywalker-parser.js +43 -0
  115. package/dist/realtime/parsers/skywalker.parser.d.ts +12 -0
  116. package/dist/realtime/parsers/skywalker.parser.js +15 -0
  117. package/dist/realtime/parsers/skywalker.parser.js.map +1 -0
  118. package/dist/realtime/parsers-advanced.js +158 -0
  119. package/dist/realtime/proto/common.proto +38 -0
  120. package/dist/realtime/proto/direct.proto +65 -0
  121. package/dist/realtime/proto/ig-messages.proto +83 -0
  122. package/dist/realtime/proto/iris.proto +188 -0
  123. package/dist/realtime/proto-parser.js +195 -0
  124. package/dist/realtime/protocols/iris.handshake.js +74 -0
  125. package/dist/realtime/protocols/proto-definitions.js +80 -0
  126. package/dist/realtime/protocols/skywalker.protocol.js +91 -0
  127. package/dist/realtime/realtime.client.events.js +3 -0
  128. package/dist/realtime/realtime.client.js +449 -0
  129. package/dist/realtime/realtime.service.js +462 -0
  130. package/dist/realtime/reconnect.manager.js +94 -0
  131. package/dist/realtime/session.manager.js +121 -0
  132. package/dist/realtime/subscriptions/graphql.subscription.d.ts +47 -0
  133. package/dist/realtime/subscriptions/graphql.subscription.js +99 -0
  134. package/dist/realtime/subscriptions/graphql.subscription.js.map +1 -0
  135. package/dist/realtime/subscriptions/index.d.ts +2 -0
  136. package/dist/realtime/subscriptions/index.js +19 -0
  137. package/dist/realtime/subscriptions/index.js.map +1 -0
  138. package/dist/realtime/subscriptions/skywalker.subscription.d.ts +4 -0
  139. package/dist/realtime/subscriptions/skywalker.subscription.js +13 -0
  140. package/dist/realtime/subscriptions/skywalker.subscription.js.map +1 -0
  141. package/dist/realtime/topic-map.js +71 -0
  142. package/dist/realtime/topic.js +80 -0
  143. package/dist/repositories/account.repository.js +261 -0
  144. package/dist/repositories/direct-thread.repository.js +247 -0
  145. package/dist/repositories/direct.repository.js +153 -0
  146. package/dist/repositories/feed.repository.js +233 -0
  147. package/dist/repositories/friendship.repository.js +190 -0
  148. package/dist/repositories/hashtag.repository.js +101 -0
  149. package/dist/repositories/highlights.repository.js +127 -0
  150. package/dist/repositories/location.repository.js +84 -0
  151. package/dist/repositories/media.repository.js +165 -0
  152. package/dist/repositories/story.repository.js +156 -0
  153. package/dist/repositories/upload.repository.js +167 -0
  154. package/dist/repositories/user.repository.js +94 -0
  155. package/dist/sendmedia/index.js +11 -0
  156. package/dist/sendmedia/sendFile.js +154 -0
  157. package/dist/sendmedia/sendPhoto.js +145 -0
  158. package/dist/sendmedia/uploadPhoto.js +175 -0
  159. package/dist/sendmedia/uploadfFile.js +264 -0
  160. package/dist/services/live.service.js +147 -0
  161. package/dist/services/search.service.js +116 -0
  162. package/dist/shared/index.js +35 -0
  163. package/dist/shared/shared.js +86 -0
  164. package/dist/thrift/index.d.ts +3 -0
  165. package/dist/thrift/index.js +20 -0
  166. package/dist/thrift/index.js.map +1 -0
  167. package/dist/thrift/thrift.d.ts +59 -0
  168. package/dist/thrift/thrift.js +101 -0
  169. package/dist/thrift/thrift.js.map +1 -0
  170. package/dist/thrift/thrift.reading.d.ts +41 -0
  171. package/dist/thrift/thrift.reading.js +327 -0
  172. package/dist/thrift/thrift.reading.js.map +1 -0
  173. package/dist/thrift/thrift.writing.d.ts +44 -0
  174. package/dist/thrift/thrift.writing.js +342 -0
  175. package/dist/thrift/thrift.writing.js.map +1 -0
  176. package/dist/types/index.js +285 -0
  177. package/dist/useMultiFileAuthState.js +437 -0
  178. package/dist/utils/helper-1.js +1 -0
  179. package/dist/utils/helper-10.js +1 -0
  180. package/dist/utils/helper-11.js +1 -0
  181. package/dist/utils/helper-12.js +1 -0
  182. package/dist/utils/helper-13.js +1 -0
  183. package/dist/utils/helper-14.js +1 -0
  184. package/dist/utils/helper-15.js +1 -0
  185. package/dist/utils/helper-16.js +1 -0
  186. package/dist/utils/helper-17.js +1 -0
  187. package/dist/utils/helper-18.js +1 -0
  188. package/dist/utils/helper-19.js +1 -0
  189. package/dist/utils/helper-2.js +1 -0
  190. package/dist/utils/helper-20.js +1 -0
  191. package/dist/utils/helper-21.js +1 -0
  192. package/dist/utils/helper-22.js +1 -0
  193. package/dist/utils/helper-23.js +1 -0
  194. package/dist/utils/helper-24.js +1 -0
  195. package/dist/utils/helper-25.js +1 -0
  196. package/dist/utils/helper-26.js +1 -0
  197. package/dist/utils/helper-27.js +1 -0
  198. package/dist/utils/helper-28.js +1 -0
  199. package/dist/utils/helper-29.js +1 -0
  200. package/dist/utils/helper-3.js +1 -0
  201. package/dist/utils/helper-30.js +1 -0
  202. package/dist/utils/helper-4.js +1 -0
  203. package/dist/utils/helper-5.js +1 -0
  204. package/dist/utils/helper-6.js +1 -0
  205. package/dist/utils/helper-7.js +1 -0
  206. package/dist/utils/helper-8.js +1 -0
  207. package/dist/utils/helper-9.js +1 -0
  208. package/dist/utils/index.js +280 -0
  209. package/examples/listen-to-messages.js +86 -0
  210. package/package.json +79 -0
@@ -0,0 +1,247 @@
1
+ const Repository = require('../core/repository');
2
+ const Chance = require('chance');
3
+
4
+ class DirectThreadRepository extends Repository {
5
+ constructor(client) {
6
+ super(client);
7
+ this.maxRetries = 3; // default max retries for requests
8
+ }
9
+
10
+ /**
11
+ * Generic request wrapper with retry and debug logging
12
+ * @param {Function} requestFn - async function performing request
13
+ * @param {number} retries - current retry count
14
+ */
15
+ async requestWithRetry(requestFn, retries = 0) {
16
+ try {
17
+ if (process.env.DEBUG) console.log(`[DEBUG] Attempt #${retries + 1}`);
18
+ const result = await requestFn();
19
+ return result;
20
+ } catch (error) {
21
+ const shouldRetry =
22
+ (error.data?.error_type === 'server_error' ||
23
+ error.data?.error_type === 'rate_limited') &&
24
+ retries < this.maxRetries;
25
+
26
+ if (shouldRetry) {
27
+ const delay = 1000 * (retries + 1);
28
+ if (process.env.DEBUG) console.log(`[DEBUG] Retrying after ${delay}ms due to ${error.data?.error_type}`);
29
+ await new Promise(resolve => setTimeout(resolve, delay));
30
+ return this.requestWithRetry(requestFn, retries + 1);
31
+ }
32
+
33
+ throw error;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Send a text message to a group thread
39
+ * @param {Object} options - { threadId, message }
40
+ */
41
+ async sendToGroup(options) {
42
+ const { threadId, message } = options;
43
+ if (!threadId || !message) throw new Error('threadId and message are required');
44
+
45
+ return this.broadcast({
46
+ threadIds: [threadId],
47
+ item: 'text',
48
+ form: { text: message },
49
+ });
50
+ }
51
+
52
+ /**
53
+ * Fetch a specific thread by its ID
54
+ * @param {string} threadId
55
+ */
56
+ async getThread(threadId) {
57
+ return this.requestWithRetry(async () => {
58
+ const response = await this.client.request.send({
59
+ method: 'GET',
60
+ url: `/api/v1/direct_v2/threads/${threadId}/`,
61
+ });
62
+ return response.body;
63
+ });
64
+ }
65
+
66
+ /**
67
+ * Fetch threads by participants
68
+ * @param {Array} recipientUsers
69
+ */
70
+ async getByParticipants(recipientUsers) {
71
+ return this.requestWithRetry(async () => {
72
+ const response = await this.client.request.send({
73
+ method: 'GET',
74
+ url: '/api/v1/direct_v2/threads/get_by_participants/',
75
+ qs: { recipient_users: JSON.stringify(recipientUsers) },
76
+ });
77
+ return response.body;
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Broadcast a message to multiple threads or users
83
+ */
84
+ async broadcast(options) {
85
+ const mutationToken = new Chance().guid();
86
+ const recipients = options.threadIds || options.userIds;
87
+ const recipientsType = options.threadIds ? 'thread_ids' : 'recipient_users';
88
+ const recipientsIds = Array.isArray(recipients) ? recipients : [recipients];
89
+
90
+ const form = {
91
+ action: 'send_item',
92
+ [recipientsType]: JSON.stringify(recipientsIds),
93
+ client_context: mutationToken,
94
+ _csrftoken: this.client.state.cookieCsrfToken,
95
+ device_id: this.client.state.deviceId,
96
+ mutation_token: mutationToken,
97
+ _uuid: this.client.state.uuid,
98
+ ...options.form,
99
+ };
100
+
101
+ return this.requestWithRetry(async () => {
102
+ const response = await this.client.request.send({
103
+ url: `/api/v1/direct_v2/threads/broadcast/${options.item}/`,
104
+ method: 'POST',
105
+ form: options.signed ? this.client.request.sign(form) : form,
106
+ qs: options.qs,
107
+ });
108
+ return response.body;
109
+ });
110
+ }
111
+
112
+ /**
113
+ * Mark a specific item in a thread as seen
114
+ */
115
+ async markItemSeen(threadId, threadItemId) {
116
+ return this.requestWithRetry(async () => {
117
+ const response = await this.client.request.send({
118
+ url: `/api/v1/direct_v2/threads/${threadId}/items/${threadItemId}/seen/`,
119
+ method: 'POST',
120
+ form: {
121
+ _csrftoken: this.client.state.cookieCsrfToken,
122
+ _uuid: this.client.state.uuid,
123
+ use_unified_inbox: true,
124
+ action: 'mark_seen',
125
+ thread_id: threadId,
126
+ item_id: threadItemId,
127
+ },
128
+ });
129
+ return response.body;
130
+ });
131
+ }
132
+
133
+ /**
134
+ * Delete an item from a thread
135
+ */
136
+ async deleteItem(threadId, itemId) {
137
+ return this.requestWithRetry(async () => {
138
+ const response = await this.client.request.send({
139
+ url: `/api/v1/direct_v2/threads/${threadId}/items/${itemId}/delete/`,
140
+ method: 'POST',
141
+ form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
142
+ });
143
+ return response.body;
144
+ });
145
+ }
146
+
147
+ /**
148
+ * Approve a pending thread
149
+ */
150
+ async approve(threadId) {
151
+ return this.requestWithRetry(async () => {
152
+ const response = await this.client.request.send({
153
+ url: `/api/v1/direct_v2/threads/${threadId}/approve/`,
154
+ method: 'POST',
155
+ form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
156
+ });
157
+ return response.body;
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Decline a pending thread
163
+ */
164
+ async decline(threadId) {
165
+ return this.requestWithRetry(async () => {
166
+ const response = await this.client.request.send({
167
+ url: `/api/v1/direct_v2/threads/${threadId}/decline/`,
168
+ method: 'POST',
169
+ form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
170
+ });
171
+ return response.body;
172
+ });
173
+ }
174
+
175
+ /**
176
+ * Mute a thread
177
+ */
178
+ async mute(threadId) {
179
+ return this.requestWithRetry(async () => {
180
+ const response = await this.client.request.send({
181
+ url: `/api/v1/direct_v2/threads/${threadId}/mute/`,
182
+ method: 'POST',
183
+ form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
184
+ });
185
+ return response.body;
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Unmute a thread
191
+ */
192
+ async unmute(threadId) {
193
+ return this.requestWithRetry(async () => {
194
+ const response = await this.client.request.send({
195
+ url: `/api/v1/direct_v2/threads/${threadId}/unmute/`,
196
+ method: 'POST',
197
+ form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
198
+ });
199
+ return response.body;
200
+ });
201
+ }
202
+
203
+ /**
204
+ * Add users to a thread
205
+ */
206
+ async addUser(threadId, userIds) {
207
+ if (!Array.isArray(userIds)) throw new Error('userIds must be an array');
208
+ return this.requestWithRetry(async () => {
209
+ const response = await this.client.request.send({
210
+ url: `/api/v1/direct_v2/threads/${threadId}/add_user/`,
211
+ method: 'POST',
212
+ form: { _csrftoken: this.client.state.cookieCsrfToken, user_ids: JSON.stringify(userIds), _uuid: this.client.state.uuid },
213
+ });
214
+ return response.body;
215
+ });
216
+ }
217
+
218
+ /**
219
+ * Leave a thread
220
+ */
221
+ async leave(threadId) {
222
+ return this.requestWithRetry(async () => {
223
+ const response = await this.client.request.send({
224
+ url: `/api/v1/direct_v2/threads/${threadId}/leave/`,
225
+ method: 'POST',
226
+ form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid },
227
+ });
228
+ return response.body;
229
+ });
230
+ }
231
+
232
+ /**
233
+ * Update thread title
234
+ */
235
+ async updateTitle(threadId, title) {
236
+ return this.requestWithRetry(async () => {
237
+ const response = await this.client.request.send({
238
+ url: `/api/v1/direct_v2/threads/${threadId}/update_title/`,
239
+ method: 'POST',
240
+ form: { _csrftoken: this.client.state.cookieCsrfToken, _uuid: this.client.state.uuid, title },
241
+ });
242
+ return response.body;
243
+ });
244
+ }
245
+ }
246
+
247
+ module.exports = DirectThreadRepository;
@@ -0,0 +1,153 @@
1
+ const Repository = require('../core/repository');
2
+ const fs = require('fs');
3
+
4
+ class DirectRepository extends Repository {
5
+ constructor(client) {
6
+ super(client);
7
+ this.maxRetries = 3; // maximum retries for failed requests
8
+ }
9
+
10
+ /**
11
+ * Generic request wrapper with retry and debug logging
12
+ * @param {Function} requestFn - async function performing request
13
+ * @param {number} retries - current retry count
14
+ */
15
+ async requestWithRetry(requestFn, retries = 0) {
16
+ try {
17
+ if (process.env.DEBUG) console.log(`[DEBUG] Attempt #${retries + 1}`);
18
+ const result = await requestFn();
19
+ return result;
20
+ } catch (error) {
21
+ const shouldRetry =
22
+ (error.data?.error_type === 'server_error' ||
23
+ error.data?.error_type === 'rate_limited') &&
24
+ retries < this.maxRetries;
25
+
26
+ if (shouldRetry) {
27
+ const delay = 1000 * (retries + 1);
28
+ if (process.env.DEBUG) console.log(`[DEBUG] Retrying after ${delay}ms due to ${error.data?.error_type}`);
29
+ await new Promise(resolve => setTimeout(resolve, delay));
30
+ return this.requestWithRetry(requestFn, retries + 1);
31
+ }
32
+
33
+ throw error;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Send a text message to a user
39
+ */
40
+ async send(options) {
41
+ const { to, message } = options;
42
+ if (!to || !message) throw new Error('Recipient (to) and message are required');
43
+
44
+ return this.requestWithRetry(async () => {
45
+ const user = await this.client.user.infoByUsername(to);
46
+ const thread = await this.client.directThread.getByParticipants([user.pk]);
47
+ return this.client.directThread.broadcast({
48
+ threadIds: [thread.thread_id],
49
+ item: 'text',
50
+ form: { text: message },
51
+ });
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Send an image to a user
57
+ */
58
+ async sendImage(options) {
59
+ const { to, imagePath } = options;
60
+ if (!to || !imagePath) throw new Error('Recipient (to) and imagePath are required');
61
+
62
+ return this.requestWithRetry(async () => {
63
+ const imageBuffer = fs.readFileSync(imagePath);
64
+ const uploadResult = await this.client.upload.photo({ file: imageBuffer, uploadId: Date.now() });
65
+ const user = await this.client.user.infoByUsername(to);
66
+ const thread = await this.client.directThread.getByParticipants([user.pk]);
67
+ return this.client.directThread.broadcast({
68
+ threadIds: [thread.thread_id],
69
+ item: 'configure_photo',
70
+ form: { upload_id: uploadResult.upload_id, allow_full_aspect_ratio: true },
71
+ });
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Send a video to a user
77
+ */
78
+ async sendVideo(options) {
79
+ const { to, videoPath } = options;
80
+ if (!to || !videoPath) throw new Error('Recipient (to) and videoPath are required');
81
+
82
+ return this.requestWithRetry(async () => {
83
+ const videoBuffer = fs.readFileSync(videoPath);
84
+ const uploadResult = await this.client.upload.video({ video: videoBuffer, uploadId: Date.now() });
85
+ const user = await this.client.user.infoByUsername(to);
86
+ const thread = await this.client.directThread.getByParticipants([user.pk]);
87
+ return this.client.directThread.broadcast({
88
+ threadIds: [thread.thread_id],
89
+ item: 'configure_video',
90
+ form: { upload_id: uploadResult.upload_id, video_result: 'deprecated' },
91
+ });
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Get inbox threads with optional pagination cursor
97
+ */
98
+ async getInbox(cursor = null) {
99
+ return this.requestWithRetry(async () => {
100
+ const qs = cursor ? { cursor } : {};
101
+ const response = await this.client.request.send({ method: 'GET', url: '/api/v1/direct_v2/inbox/', qs });
102
+ return response.body;
103
+ });
104
+ }
105
+
106
+ /**
107
+ * Create a group thread
108
+ */
109
+ async createGroupThread(recipientUsers, threadTitle) {
110
+ if (!Array.isArray(recipientUsers) || !threadTitle) throw new Error('recipientUsers must be array and threadTitle required');
111
+
112
+ return this.requestWithRetry(async () => {
113
+ const response = await this.client.request.send({
114
+ method: 'POST',
115
+ url: '/api/v1/direct_v2/create_group_thread/',
116
+ form: this.client.request.sign({
117
+ _csrftoken: this.client.state.cookieCsrfToken,
118
+ _uuid: this.client.state.uuid,
119
+ _uid: this.client.state.cookieUserId,
120
+ recipient_users: JSON.stringify(recipientUsers),
121
+ thread_title: threadTitle,
122
+ }),
123
+ });
124
+ return response.body;
125
+ });
126
+ }
127
+
128
+ /**
129
+ * Get ranked recipients (suggested users to send DMs)
130
+ */
131
+ async rankedRecipients(mode = 'raven', query = '') {
132
+ return this.requestWithRetry(async () => {
133
+ const response = await this.client.request.send({
134
+ method: 'GET',
135
+ url: '/api/v1/direct_v2/ranked_recipients/',
136
+ qs: { mode, query, show_threads: true },
137
+ });
138
+ return response.body;
139
+ });
140
+ }
141
+
142
+ /**
143
+ * Get online presence
144
+ */
145
+ async getPresence() {
146
+ return this.requestWithRetry(async () => {
147
+ const response = await this.client.request.send({ method: 'GET', url: '/api/v1/direct_v2/get_presence/' });
148
+ return response.body;
149
+ });
150
+ }
151
+ }
152
+
153
+ module.exports = DirectRepository;
@@ -0,0 +1,233 @@
1
+ const Repository = require('../core/repository');
2
+ const fs = require('fs');
3
+
4
+ class FeedRepository extends Repository {
5
+ async upload(options) {
6
+ const { imagePath, caption } = options;
7
+
8
+ // Read image file
9
+ const imageBuffer = fs.readFileSync(imagePath);
10
+
11
+ // Upload image first
12
+ const uploadResult = await this.client.upload.photo({
13
+ file: imageBuffer,
14
+ uploadId: Date.now()
15
+ });
16
+
17
+ // Configure as feed post
18
+ const configureResult = await this.client.upload.configurePhoto({
19
+ uploadId: uploadResult.upload_id,
20
+ caption: caption || '',
21
+ source_type: '4',
22
+ });
23
+
24
+ return configureResult;
25
+ }
26
+
27
+ async uploadVideo(options) {
28
+ const { videoPath, caption } = options;
29
+
30
+ // Read video file
31
+ const videoBuffer = fs.readFileSync(videoPath);
32
+
33
+ // Upload video first
34
+ const uploadResult = await this.client.upload.video({
35
+ video: videoBuffer,
36
+ uploadId: Date.now(),
37
+ duration_ms: options.duration_ms || 15000,
38
+ width: options.width || 720,
39
+ height: options.height || 1280,
40
+ });
41
+
42
+ // Configure as feed post
43
+ const configureResult = await this.client.upload.configureVideo({
44
+ uploadId: uploadResult.upload_id,
45
+ caption: caption || '',
46
+ source_type: '4',
47
+ length: options.duration_ms || 15000,
48
+ });
49
+
50
+ return configureResult;
51
+ }
52
+
53
+ async getFeed(maxId = null) {
54
+ const qs = {};
55
+ if (maxId) {
56
+ qs.max_id = maxId;
57
+ }
58
+
59
+ const response = await this.client.request.send({
60
+ method: 'GET',
61
+ url: '/api/v1/feed/timeline/',
62
+ qs
63
+ });
64
+
65
+ return response.body;
66
+ }
67
+
68
+ async getUserFeed(userId, maxId = null) {
69
+ const qs = {};
70
+ if (maxId) {
71
+ qs.max_id = maxId;
72
+ }
73
+
74
+ const response = await this.client.request.send({
75
+ method: 'GET',
76
+ url: `/api/v1/feed/user/${userId}/`,
77
+ qs
78
+ });
79
+
80
+ return response.body;
81
+ }
82
+
83
+ async getTag(tag, maxId = null) {
84
+ const qs = {
85
+ rank_token: this.client.state.uuid
86
+ };
87
+ if (maxId) {
88
+ qs.max_id = maxId;
89
+ }
90
+
91
+ const response = await this.client.request.send({
92
+ method: 'GET',
93
+ url: `/api/v1/feed/tag/${tag}/`,
94
+ qs
95
+ });
96
+
97
+ return response.body;
98
+ }
99
+
100
+ async getLiked(maxId = null) {
101
+ const qs = {};
102
+ if (maxId) {
103
+ qs.max_id = maxId;
104
+ }
105
+
106
+ const response = await this.client.request.send({
107
+ method: 'GET',
108
+ url: '/api/v1/feed/liked/',
109
+ qs
110
+ });
111
+
112
+ return response.body;
113
+ }
114
+
115
+ async getSaved(maxId = null) {
116
+ const qs = {};
117
+ if (maxId) {
118
+ qs.max_id = maxId;
119
+ }
120
+
121
+ const response = await this.client.request.send({
122
+ method: 'GET',
123
+ url: '/api/v1/feed/saved/',
124
+ qs
125
+ });
126
+
127
+ return response.body;
128
+ }
129
+
130
+ async getLocation(locationId, maxId = null) {
131
+ const qs = {
132
+ rank_token: this.client.state.uuid
133
+ };
134
+ if (maxId) {
135
+ qs.max_id = maxId;
136
+ }
137
+
138
+ const response = await this.client.request.send({
139
+ method: 'GET',
140
+ url: `/api/v1/feed/location/${locationId}/`,
141
+ qs
142
+ });
143
+
144
+ return response.body;
145
+ }
146
+
147
+ async getExploreFeed(maxId = null) {
148
+ const qs = {
149
+ is_prefetch: false,
150
+ is_from_promote: false,
151
+ timezone_offset: this.client.state.timezoneOffset,
152
+ session_id: this.client.state.clientSessionId,
153
+ };
154
+
155
+ if (maxId) {
156
+ qs.max_id = maxId;
157
+ }
158
+
159
+ const response = await this.client.request.send({
160
+ method: 'GET',
161
+ url: '/api/v1/discover/explore/',
162
+ qs
163
+ });
164
+
165
+ return response.body;
166
+ }
167
+
168
+ async getReelsFeed(maxId = null) {
169
+ const qs = {};
170
+ if (maxId) {
171
+ qs.max_id = maxId;
172
+ }
173
+
174
+ const response = await this.client.request.send({
175
+ method: 'GET',
176
+ url: '/api/v1/clips/browse/',
177
+ qs
178
+ });
179
+
180
+ return response.body;
181
+ }
182
+
183
+ async uploadCarousel(options) {
184
+ const { items, caption } = options;
185
+ const uploadIds = [];
186
+
187
+ // Upload all items first
188
+ for (const item of items) {
189
+ if (item.type === 'photo') {
190
+ const imageBuffer = fs.readFileSync(item.path);
191
+ const uploadResult = await this.client.upload.photo({
192
+ file: imageBuffer,
193
+ uploadId: Date.now() + Math.random() * 1000
194
+ });
195
+ uploadIds.push({
196
+ upload_id: uploadResult.upload_id,
197
+ source_type: '4'
198
+ });
199
+ } else if (item.type === 'video') {
200
+ const videoBuffer = fs.readFileSync(item.path);
201
+ const uploadResult = await this.client.upload.video({
202
+ video: videoBuffer,
203
+ uploadId: Date.now() + Math.random() * 1000,
204
+ duration_ms: item.duration_ms || 15000,
205
+ width: item.width || 720,
206
+ height: item.height || 1280,
207
+ });
208
+ uploadIds.push({
209
+ upload_id: uploadResult.upload_id,
210
+ source_type: '4'
211
+ });
212
+ }
213
+ }
214
+
215
+ // Configure carousel
216
+ const response = await this.client.request.send({
217
+ url: '/api/v1/media/configure_sidecar/',
218
+ method: 'POST',
219
+ form: this.client.request.sign({
220
+ caption: caption || '',
221
+ client_sidecar_id: Date.now(),
222
+ children_metadata: uploadIds,
223
+ _csrftoken: this.client.state.cookieCsrfToken,
224
+ _uid: this.client.state.cookieUserId,
225
+ _uuid: this.client.state.uuid,
226
+ }),
227
+ });
228
+
229
+ return response.body;
230
+ }
231
+ }
232
+
233
+ module.exports = FeedRepository;