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,153 @@
1
+ const { v4: uuidv4 } = require('uuid');
2
+ const axios = require('axios');
3
+
4
+ function buildRavenPhotoRuploadParams(uploadId) {
5
+ return {
6
+ retry_context: JSON.stringify({ num_step_auto_retry: 0, num_reupload: 0, num_step_manual_retry: 0 }),
7
+ media_type: '1',
8
+ upload_id: uploadId.toString(),
9
+ image_compression: JSON.stringify({ lib_name: 'moz', lib_version: '3.1.m', quality: '95' }),
10
+ xsharing_user_ids: JSON.stringify([]),
11
+ direct_v2: '1',
12
+ is_optimistic_upload: 'false',
13
+ };
14
+ }
15
+
16
+ async function sendRavenPhoto(session, photoBuffer, options = {}) {
17
+ const {
18
+ threadId,
19
+ viewMode = 'replayable',
20
+ mimeType = 'image/jpeg',
21
+ } = options;
22
+
23
+ if (!photoBuffer || !Buffer.isBuffer(photoBuffer) || photoBuffer.length === 0) {
24
+ throw new Error('sendRavenPhoto: photoBuffer must be a non-empty Buffer.');
25
+ }
26
+ if (!threadId) {
27
+ throw new Error('sendRavenPhoto: threadId is required.');
28
+ }
29
+
30
+ const uploadId = Date.now().toString();
31
+ const randomSuffix = Math.floor(Math.random() * (9999999999 - 1000000000) + 1000000000);
32
+ const name = `${uploadId}_0_${randomSuffix}`;
33
+ const waterfallId = uuidv4();
34
+ const ruploadParams = buildRavenPhotoRuploadParams(uploadId);
35
+
36
+ const defaultHeaders = session.request.getDefaultHeaders();
37
+
38
+ const messengerUploadHeaders = {
39
+ ...defaultHeaders,
40
+ 'X_FB_PHOTO_WATERFALL_ID': waterfallId,
41
+ 'X-Entity-Type': mimeType,
42
+ 'Offset': '0',
43
+ 'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
44
+ 'X-Entity-Name': name,
45
+ 'X-Entity-Length': String(photoBuffer.length),
46
+ 'Content-Type': 'application/octet-stream',
47
+ 'Content-Length': String(photoBuffer.length),
48
+ 'ephemeral_media_view_mode': viewMode === 'replayable' ? '1' : '0',
49
+ 'ig_raven_metadata': '{}',
50
+ 'image_type': 'FILE_ATTACHMENT',
51
+ 'Host': 'rupload.facebook.com',
52
+ };
53
+
54
+ const uploadResp = await axios({
55
+ url: `https://rupload.facebook.com/messenger_image/${name}`,
56
+ method: 'POST',
57
+ headers: messengerUploadHeaders,
58
+ data: photoBuffer,
59
+ maxBodyLength: Infinity,
60
+ maxContentLength: Infinity,
61
+ transformRequest: [(d) => d],
62
+ });
63
+
64
+ const uploadParsed = uploadResp.data;
65
+ const serverUploadId = (uploadParsed.upload_id || uploadId).toString();
66
+ const attachmentFbid = uploadParsed.media_id
67
+ || (uploadParsed.media && uploadParsed.media.pk)
68
+ || (uploadParsed.media && uploadParsed.media.id)
69
+ || null;
70
+
71
+ const clientContext = BigInt(Math.floor(Math.random() * 2**62)).toString();
72
+ const compositionId = uuidv4();
73
+ const cameraSessionId = uuidv4();
74
+ const now = Math.floor(Date.now() / 1000);
75
+
76
+ const form = {
77
+ allow_multi_configures: '1',
78
+ recipient_users: '[]',
79
+ view_mode: viewMode,
80
+ is_shh_mode: '0',
81
+ camera_entry_point: '3',
82
+ thread_ids: JSON.stringify([String(threadId)]),
83
+ reshare_mode: 'allow_reshare',
84
+ original_media_type: '1',
85
+ send_attribution: 'direct_thread_camera',
86
+ client_context: clientContext,
87
+ camera_session_id: cameraSessionId,
88
+ include_e2ee_mentioned_user_list: '1',
89
+ hide_from_profile_grid: 'false',
90
+ scene_capture_type: '',
91
+ timezone_offset: String(new Date().getTimezoneOffset() * -60),
92
+ client_shared_at: String(now),
93
+ configure_mode: '2',
94
+ source_type: '4',
95
+ camera_position: 'unknown',
96
+ _uid: String(session.state.cookieUserId || session.state.igUserId),
97
+ device_id: session.state.deviceId,
98
+ composition_id: compositionId,
99
+ mutation_token: clientContext,
100
+ _uuid: session.state.uuid,
101
+ creation_tool_info: '[]',
102
+ creation_surface: 'camera',
103
+ capture_type: 'normal',
104
+ audience: 'default',
105
+ upload_id: serverUploadId,
106
+ client_timestamp: String(now),
107
+ sampled: 'true',
108
+ media_transformation_info: JSON.stringify({
109
+ width: '720', height: '1280',
110
+ x_transform: '0', y_transform: '0',
111
+ zoom: '1.0', rotation: '0.0', background_coverage: '0.0',
112
+ }),
113
+ edits: JSON.stringify({ filter_type: 0, filter_strength: 0.5, crop_original_size: [720.0, 1280.0] }),
114
+ extra: JSON.stringify({ source_width: 720, source_height: 1280 }),
115
+ device: JSON.stringify({
116
+ manufacturer: session.state.devicePayload?.manufacturer || 'samsung',
117
+ model: session.state.devicePayload?.model || 'SM-S938B',
118
+ android_version: session.state.devicePayload?.android_version || 35,
119
+ android_release: session.state.devicePayload?.android_release || '15',
120
+ }),
121
+ };
122
+
123
+ if (attachmentFbid) {
124
+ form.attachment_fbid = String(attachmentFbid);
125
+ }
126
+
127
+ const signedForm = (session.request && typeof session.request.sign === 'function')
128
+ ? session.request.sign(form)
129
+ : form;
130
+
131
+ const broadcastResponse = await session.request.send({
132
+ url: '/api/v1/direct_v2/threads/broadcast/raven_attachment/',
133
+ method: 'POST',
134
+ form: signedForm,
135
+ qs: { use_unified_inbox: true },
136
+ });
137
+
138
+ const body = broadcastResponse && (broadcastResponse.body || broadcastResponse.data || broadcastResponse);
139
+ return typeof body === 'string' ? JSON.parse(body) : body;
140
+ }
141
+
142
+ async function sendRavenPhotoOnce(session, photoBuffer, options = {}) {
143
+ return sendRavenPhoto(session, photoBuffer, { ...options, viewMode: 'once' });
144
+ }
145
+
146
+ async function sendRavenPhotoReplayable(session, photoBuffer, options = {}) {
147
+ return sendRavenPhoto(session, photoBuffer, { ...options, viewMode: 'replayable' });
148
+ }
149
+
150
+ module.exports = sendRavenPhoto;
151
+ module.exports.sendRavenPhoto = sendRavenPhoto;
152
+ module.exports.sendRavenPhotoOnce = sendRavenPhotoOnce;
153
+ module.exports.sendRavenPhotoReplayable = sendRavenPhotoReplayable;
@@ -0,0 +1,158 @@
1
+ const { v4: uuidv4 } = require('uuid');
2
+ const axios = require('axios');
3
+
4
+ function buildRavenVideoRuploadParams(uploadId, options = {}) {
5
+ return {
6
+ retry_context: JSON.stringify({ num_step_auto_retry: 0, num_reupload: 0, num_step_manual_retry: 0 }),
7
+ media_type: '2',
8
+ upload_id: uploadId.toString(),
9
+ upload_media_duration_ms: String(Math.round((options.duration || 0) * 1000)),
10
+ upload_media_width: String(options.width || 720),
11
+ upload_media_height: String(options.height || 1280),
12
+ xsharing_user_ids: JSON.stringify([]),
13
+ direct_v2: '1',
14
+ };
15
+ }
16
+
17
+ async function sendRavenVideo(session, videoBuffer, options = {}) {
18
+ const {
19
+ threadId,
20
+ viewMode = 'replayable',
21
+ duration = 0,
22
+ width = 720,
23
+ height = 1280,
24
+ } = options;
25
+
26
+ if (!videoBuffer || !Buffer.isBuffer(videoBuffer) || videoBuffer.length === 0) {
27
+ throw new Error('sendRavenVideo: videoBuffer must be a non-empty Buffer.');
28
+ }
29
+ if (!threadId) {
30
+ throw new Error('sendRavenVideo: threadId is required.');
31
+ }
32
+
33
+ const uploadId = Date.now().toString();
34
+ const randomSuffix = Math.floor(Math.random() * (9999999999 - 1000000000) + 1000000000);
35
+ const name = `${uploadId}_0_${randomSuffix}`;
36
+ const waterfallId = uuidv4();
37
+ const ruploadParams = buildRavenVideoRuploadParams(uploadId, { duration, width, height });
38
+
39
+ const defaultHeaders = session.request.getDefaultHeaders();
40
+
41
+ const messengerUploadHeaders = {
42
+ ...defaultHeaders,
43
+ 'X_FB_VIDEO_WATERFALL_ID': waterfallId,
44
+ 'X-Entity-Type': 'video/mp4',
45
+ 'Offset': '0',
46
+ 'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
47
+ 'X-Entity-Name': name,
48
+ 'X-Entity-Length': String(videoBuffer.length),
49
+ 'Content-Type': 'application/octet-stream',
50
+ 'Content-Length': String(videoBuffer.length),
51
+ 'ephemeral_media_view_mode': '1',
52
+ 'ig_raven_metadata': '{}',
53
+ 'video_type': 'FILE_ATTACHMENT',
54
+ 'x-fb-congestion-signal': '1',
55
+ 'Host': 'rupload.facebook.com',
56
+ };
57
+
58
+ const uploadResp = await axios({
59
+ url: `https://rupload.facebook.com/messenger_video/${name}`,
60
+ method: 'POST',
61
+ headers: messengerUploadHeaders,
62
+ data: videoBuffer,
63
+ maxBodyLength: Infinity,
64
+ maxContentLength: Infinity,
65
+ transformRequest: [(d) => d],
66
+ });
67
+
68
+ const uploadParsed = uploadResp.data;
69
+ const serverUploadId = (uploadParsed.upload_id || uploadId).toString();
70
+ const attachmentFbid = uploadParsed.media_id
71
+ || (uploadParsed.media && uploadParsed.media.pk)
72
+ || (uploadParsed.media && uploadParsed.media.id)
73
+ || null;
74
+
75
+ const clientContext = BigInt(Math.floor(Math.random() * 2**62)).toString();
76
+ const compositionId = uuidv4();
77
+ const cameraSessionId = uuidv4();
78
+ const now = Math.floor(Date.now() / 1000);
79
+
80
+ const form = {
81
+ allow_multi_configures: '1',
82
+ recipient_users: '[]',
83
+ view_mode: viewMode,
84
+ is_shh_mode: '0',
85
+ camera_entry_point: '3',
86
+ thread_ids: JSON.stringify([String(threadId)]),
87
+ reshare_mode: 'allow_reshare',
88
+ original_media_type: '1',
89
+ send_attribution: 'direct_thread_camera',
90
+ client_context: clientContext,
91
+ camera_session_id: cameraSessionId,
92
+ include_e2ee_mentioned_user_list: '1',
93
+ hide_from_profile_grid: 'false',
94
+ scene_capture_type: '',
95
+ timezone_offset: String(new Date().getTimezoneOffset() * -60),
96
+ client_shared_at: String(now),
97
+ configure_mode: '2',
98
+ source_type: '4',
99
+ camera_position: 'unknown',
100
+ _uid: String(session.state.cookieUserId || session.state.igUserId),
101
+ device_id: session.state.deviceId,
102
+ composition_id: compositionId,
103
+ mutation_token: clientContext,
104
+ _uuid: session.state.uuid,
105
+ creation_tool_info: '[]',
106
+ creation_surface: 'camera',
107
+ capture_type: 'normal',
108
+ audience: 'default',
109
+ upload_id: serverUploadId,
110
+ client_timestamp: String(now),
111
+ sampled: 'true',
112
+ video_result: '',
113
+ media_type: '1',
114
+ media_transformation_info: JSON.stringify({
115
+ width: String(width), height: String(height),
116
+ x_transform: '0', y_transform: '0',
117
+ zoom: '1.0', rotation: '0.0', background_coverage: '0.0',
118
+ }),
119
+ extra: JSON.stringify({ source_width: width, source_height: height }),
120
+ device: JSON.stringify({
121
+ manufacturer: session.state.devicePayload?.manufacturer || 'samsung',
122
+ model: session.state.devicePayload?.model || 'SM-S938B',
123
+ android_version: session.state.devicePayload?.android_version || 35,
124
+ android_release: session.state.devicePayload?.android_release || '15',
125
+ }),
126
+ };
127
+
128
+ if (attachmentFbid) {
129
+ form.attachment_fbid = String(attachmentFbid);
130
+ }
131
+
132
+ const signedForm = (session.request && typeof session.request.sign === 'function')
133
+ ? session.request.sign(form)
134
+ : form;
135
+
136
+ const broadcastResponse = await session.request.send({
137
+ url: '/api/v1/direct_v2/threads/broadcast/raven_attachment/',
138
+ method: 'POST',
139
+ form: signedForm,
140
+ qs: { use_unified_inbox: true },
141
+ });
142
+
143
+ const body = broadcastResponse && (broadcastResponse.body || broadcastResponse.data || broadcastResponse);
144
+ return typeof body === 'string' ? JSON.parse(body) : body;
145
+ }
146
+
147
+ async function sendRavenVideoOnce(session, videoBuffer, options = {}) {
148
+ return sendRavenVideo(session, videoBuffer, { ...options, viewMode: 'once' });
149
+ }
150
+
151
+ async function sendRavenVideoReplayable(session, videoBuffer, options = {}) {
152
+ return sendRavenVideo(session, videoBuffer, { ...options, viewMode: 'replayable' });
153
+ }
154
+
155
+ module.exports = sendRavenVideo;
156
+ module.exports.sendRavenVideo = sendRavenVideo;
157
+ module.exports.sendRavenVideoOnce = sendRavenVideoOnce;
158
+ module.exports.sendRavenVideoReplayable = sendRavenVideoReplayable;
@@ -0,0 +1,107 @@
1
+ /**
2
+ * uploadPhoto.js - FIXED version based on instagram-private-api
3
+ */
4
+
5
+ const { v4: uuidv4 } = require('uuid');
6
+
7
+ /**
8
+ * Validate buffer and mime type
9
+ */
10
+ function validateImageInput(photoBuffer, mimeType) {
11
+ if (!photoBuffer || !Buffer.isBuffer(photoBuffer) || photoBuffer.length === 0) {
12
+ throw new Error('uploadPhoto: photoBuffer must be a non-empty Buffer.');
13
+ }
14
+ const allowed = ['image/jpeg', 'image/jpg', 'image/png'];
15
+ if (!allowed.includes(mimeType)) {
16
+ throw new Error(`uploadPhoto: mimeType must be one of ${allowed.join(', ')}.`);
17
+ }
18
+ }
19
+
20
+ /**
21
+ * Build Instagram rupload params for photo - Matching instagram-private-api
22
+ */
23
+ function buildRuploadParams(uploadId, mimeType) {
24
+ const isJpeg = mimeType === 'image/jpeg' || mimeType === 'image/jpg';
25
+ const compression = isJpeg
26
+ ? JSON.stringify({ lib_name: 'moz', lib_version: '3.1.m', quality: '80' })
27
+ : JSON.stringify({ lib_name: 'png', lib_version: '1.0', quality: '100' });
28
+
29
+ return {
30
+ retry_context: JSON.stringify({ num_step_auto_retry: 0, num_reupload: 0, num_step_manual_retry: 0 }),
31
+ media_type: '1', // String '1' per instagram-private-api
32
+ upload_id: uploadId.toString(),
33
+ xsharing_user_ids: JSON.stringify([]),
34
+ image_compression: compression,
35
+ };
36
+ }
37
+
38
+ /**
39
+ * Upload a photo to Instagram's rupload endpoint.
40
+ */
41
+ async function uploadPhoto(session, photoBuffer, options = {}) {
42
+ const {
43
+ mimeType = 'image/jpeg',
44
+ fileName,
45
+ signal,
46
+ } = options;
47
+
48
+ validateImageInput(photoBuffer, mimeType);
49
+
50
+ const uploadId = Date.now().toString();
51
+ const name = `${uploadId}_0_${Math.floor(Math.random() * (9999999999 - 1000000000) + 1000000000)}`;
52
+ const contentLength = photoBuffer.byteLength;
53
+
54
+ const ruploadParams = buildRuploadParams(uploadId, mimeType);
55
+
56
+ // Headers expected by Instagram rupload (matched with instagram-private-api)
57
+ const headers = {
58
+ 'X_FB_PHOTO_WATERFALL_ID': uuidv4(),
59
+ 'X-Entity-Type': 'image/jpeg',
60
+ 'Offset': '0',
61
+ 'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
62
+ 'X-Entity-Name': name,
63
+ 'X-Entity-Length': String(contentLength),
64
+ 'Content-Type': 'application/octet-stream',
65
+ 'Content-Length': String(contentLength),
66
+ 'Accept-Encoding': 'gzip',
67
+ };
68
+
69
+ // If it's png, maybe we should adjust X-Entity-Type?
70
+ // instagram-private-api seems to hardcode 'image/jpeg' in the trace for 'photo' method.
71
+ // We'll stick to 'image/jpeg' for X-Entity-Type as per reference unless user provided PNG which might work anyway.
72
+
73
+ const url = `/rupload_igphoto/${name}`;
74
+
75
+ try {
76
+ const response = await session.request.send({
77
+ url,
78
+ method: 'POST',
79
+ headers,
80
+ body: photoBuffer,
81
+ signal,
82
+ });
83
+
84
+ if (!response) {
85
+ throw new Error('uploadPhoto: Empty response from Instagram rupload endpoint.');
86
+ }
87
+
88
+ // Try to get upload_id from response
89
+ let serverUploadId = null;
90
+ if (typeof response === 'object' && response.body) {
91
+ try {
92
+ const body = typeof response.body === 'string' ? JSON.parse(response.body) : response.body;
93
+ serverUploadId = body.upload_id;
94
+ } catch (e) {
95
+ // ignore parse error
96
+ }
97
+ }
98
+
99
+ return serverUploadId || uploadId;
100
+ } catch (err) {
101
+ // If error, try to extract message
102
+ const msg = err.message || err.toString();
103
+ throw new Error(`uploadPhoto: Upload failed — ${msg}`);
104
+ }
105
+ }
106
+
107
+ module.exports = uploadPhoto;
@@ -0,0 +1,130 @@
1
+ /**
2
+ * uploadfFile.js - FIXED version based on instagram-private-api
3
+ */
4
+
5
+ const { v4: uuidv4 } = require('uuid');
6
+
7
+ const DEFAULT_CHUNK_SIZE = 512 * 1024; // 512KB
8
+
9
+ /**
10
+ * Validate upload input
11
+ */
12
+ function validateFileInput(fileBuffer, mimeType) {
13
+ if (!fileBuffer || !Buffer.isBuffer(fileBuffer) || fileBuffer.length === 0) {
14
+ throw new Error('uploadFile: fileBuffer must be a non-empty Buffer.');
15
+ }
16
+ if (typeof mimeType !== 'string' || mimeType.length === 0) {
17
+ throw new Error('uploadFile: mimeType must be a non-empty string.');
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Build rupload params - Matching instagram-private-api
23
+ */
24
+ function buildRuploadParams(uploadId, mimeType, opts) {
25
+ const isVideo = mimeType.startsWith('video/');
26
+ const isAudio = mimeType.startsWith('audio/');
27
+
28
+ const params = {
29
+ retry_context: JSON.stringify({ num_step_auto_retry: 0, num_reupload: 0, num_step_manual_retry: 0 }),
30
+ media_type: isVideo ? '2' : '3', // 2 for video, 3 for audio/others?
31
+ upload_id: uploadId.toString(),
32
+ xsharing_user_ids: JSON.stringify([]),
33
+ };
34
+
35
+ if (isVideo) {
36
+ params.upload_media_duration_ms = opts.duration?.toString() || '0';
37
+ params.upload_media_width = opts.width?.toString() || '720';
38
+ params.upload_media_height = opts.height?.toString() || '1280';
39
+ params.direct_v2 = '1';
40
+ }
41
+
42
+ return params;
43
+ }
44
+
45
+ /**
46
+ * Upload file via rupload with chunking.
47
+ */
48
+ async function uploadFile(session, fileBuffer, options = {}) {
49
+ const {
50
+ mimeType = 'video/mp4',
51
+ fileName,
52
+ chunkSize = DEFAULT_CHUNK_SIZE,
53
+ signal,
54
+ } = options;
55
+
56
+ validateFileInput(fileBuffer, mimeType);
57
+
58
+ const uploadId = Date.now().toString();
59
+ const name = `${uploadId}_0_${Math.floor(Math.random() * 9000000000 + 1000000000)}`;
60
+ const totalLength = fileBuffer.length;
61
+ const waterfallId = uuidv4();
62
+
63
+ const ruploadParams = buildRuploadParams(uploadId, mimeType, options);
64
+
65
+ const endpoint = mimeType.startsWith('image/')
66
+ ? `/rupload_igphoto/${name}`
67
+ : `/rupload_igvideo/${name}`;
68
+
69
+ // Start upload
70
+ let offset = 0;
71
+ const size = Math.max(64 * 1024, Math.min(4 * 1024 * 1024, chunkSize));
72
+
73
+ try {
74
+ while (offset < totalLength) {
75
+ const end = Math.min(offset + size, totalLength);
76
+ const chunk = fileBuffer.subarray(offset, end);
77
+
78
+ const headers = {
79
+ 'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
80
+ 'X_FB_VIDEO_WATERFALL_ID': waterfallId,
81
+ 'X-Entity-Type': mimeType,
82
+ 'X-Entity-Name': name,
83
+ 'X-Entity-Length': String(totalLength),
84
+ 'Offset': String(offset),
85
+ 'Content-Type': 'application/octet-stream',
86
+ 'Content-Length': String(chunk.length),
87
+ 'Accept-Encoding': 'gzip',
88
+ };
89
+
90
+ const res = await session.request.send({
91
+ url: endpoint,
92
+ method: 'POST',
93
+ headers,
94
+ body: chunk,
95
+ signal,
96
+ });
97
+
98
+ if (!res) throw new Error(`uploadFile: Empty response at offset ${offset}`);
99
+ offset = end;
100
+ }
101
+
102
+ // Finalize
103
+ const confirm = await session.request.send({
104
+ url: endpoint,
105
+ method: 'POST',
106
+ headers: {
107
+ 'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
108
+ 'X_FB_VIDEO_WATERFALL_ID': waterfallId,
109
+ 'X-Entity-Type': mimeType,
110
+ 'Offset': String(totalLength),
111
+ 'Content-Length': '0',
112
+ },
113
+ signal,
114
+ });
115
+
116
+ let serverUploadId = null;
117
+ if (confirm && confirm.body) {
118
+ try {
119
+ const body = typeof confirm.body === 'string' ? JSON.parse(confirm.body) : confirm.body;
120
+ serverUploadId = body.upload_id;
121
+ } catch (e) {}
122
+ }
123
+
124
+ return serverUploadId || uploadId;
125
+ } catch (err) {
126
+ throw new Error(`uploadFile: Upload failed — ${err.message}`);
127
+ }
128
+ }
129
+
130
+ module.exports = uploadFile;
@@ -0,0 +1,139 @@
1
+ const Repository = require('../core/repository');
2
+
3
+ class LiveService extends Repository {
4
+ async create(options = {}) {
5
+ const {
6
+ previewWidth = 720,
7
+ previewHeight = 1280,
8
+ broadcastMessage = '',
9
+ } = options;
10
+
11
+ const response = await this.client.request.send({
12
+ method: 'POST',
13
+ url: '/api/v1/live/create/',
14
+ form: this.client.request.sign({
15
+ _uuid: this.client.state.uuid,
16
+ preview_width: previewWidth,
17
+ preview_height: previewHeight,
18
+ broadcast_message: broadcastMessage,
19
+ }),
20
+ });
21
+
22
+ return response.body;
23
+ }
24
+
25
+ async start(broadcastId, shouldSendNotifications = false) {
26
+ const response = await this.client.request.send({
27
+ method: 'POST',
28
+ url: `/api/v1/live/${broadcastId}/start/`,
29
+ form: this.client.request.sign({
30
+ _uuid: this.client.state.uuid,
31
+ should_send_notifications: shouldSendNotifications ? '1' : '0',
32
+ }),
33
+ });
34
+
35
+ return response.body;
36
+ }
37
+
38
+ async end(broadcastId, endAfterCopyrightWarning = false) {
39
+ const response = await this.client.request.send({
40
+ method: 'POST',
41
+ url: `/api/v1/live/${broadcastId}/end_broadcast/`,
42
+ form: this.client.request.sign({
43
+ _uuid: this.client.state.uuid,
44
+ end_after_copyright_warning: endAfterCopyrightWarning ? '1' : '0',
45
+ }),
46
+ });
47
+
48
+ return response.body;
49
+ }
50
+
51
+ async info(broadcastId) {
52
+ const response = await this.client.request.send({
53
+ method: 'GET',
54
+ url: `/api/v1/live/${broadcastId}/info/`,
55
+ });
56
+
57
+ return response.body;
58
+ }
59
+
60
+ async getViewerList(broadcastId) {
61
+ const response = await this.client.request.send({
62
+ method: 'GET',
63
+ url: `/api/v1/live/${broadcastId}/get_viewer_list/`,
64
+ });
65
+
66
+ return response.body;
67
+ }
68
+
69
+ async comment(broadcastId, message) {
70
+ const response = await this.client.request.send({
71
+ method: 'POST',
72
+ url: `/api/v1/live/${broadcastId}/comment/`,
73
+ form: this.client.request.sign({
74
+ _uuid: this.client.state.uuid,
75
+ user_breadcrumb: this.client.request.userBreadcrumb(message.length),
76
+ idempotence_token: Date.now(),
77
+ comment_text: message,
78
+ live_or_vod: '1',
79
+ offset: '0',
80
+ }),
81
+ });
82
+
83
+ return response.body;
84
+ }
85
+
86
+ async like(broadcastId, likeCount = 1) {
87
+ const response = await this.client.request.send({
88
+ method: 'POST',
89
+ url: `/api/v1/live/${broadcastId}/like/`,
90
+ form: this.client.request.sign({
91
+ _uuid: this.client.state.uuid,
92
+ user_like_count: likeCount,
93
+ }),
94
+ });
95
+
96
+ return response.body;
97
+ }
98
+
99
+ async getHeartbeatAndViewerCount(broadcastId) {
100
+ const response = await this.client.request.send({
101
+ method: 'POST',
102
+ url: `/api/v1/live/${broadcastId}/heartbeat_and_get_viewer_count/`,
103
+ form: this.client.request.sign({
104
+ _uuid: this.client.state.uuid,
105
+ offset_to_video_start: '0',
106
+ }),
107
+ });
108
+
109
+ return response.body;
110
+ }
111
+
112
+ async muteComment(broadcastId, userId) {
113
+ const response = await this.client.request.send({
114
+ method: 'POST',
115
+ url: `/api/v1/live/${broadcastId}/mute_comment/`,
116
+ form: this.client.request.sign({
117
+ _uuid: this.client.state.uuid,
118
+ user_id: userId,
119
+ }),
120
+ });
121
+
122
+ return response.body;
123
+ }
124
+
125
+ async unmuteComment(broadcastId, userId) {
126
+ const response = await this.client.request.send({
127
+ method: 'POST',
128
+ url: `/api/v1/live/${broadcastId}/unmute_comment/`,
129
+ form: this.client.request.sign({
130
+ _uuid: this.client.state.uuid,
131
+ user_id: userId,
132
+ }),
133
+ });
134
+
135
+ return response.body;
136
+ }
137
+ }
138
+
139
+ module.exports = LiveService;