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,156 @@
1
+ const Repository = require('../core/repository');
2
+ const fs = require('fs');
3
+
4
+ class StoryRepository extends Repository {
5
+ async react(options) {
6
+ const { storyId, reaction } = options;
7
+
8
+ const response = await this.client.request.send({
9
+ url: `/api/v1/media/${storyId}/story_react/`,
10
+ method: 'POST',
11
+ form: this.client.request.sign({
12
+ _csrftoken: this.client.state.cookieCsrfToken,
13
+ _uid: this.client.state.cookieUserId,
14
+ _uuid: this.client.state.uuid,
15
+ reaction_type: 'like',
16
+ emoji: reaction || '❤️',
17
+ }),
18
+ });
19
+
20
+ return response.body;
21
+ }
22
+
23
+ async getFeed() {
24
+ const response = await this.client.request.send({
25
+ method: 'GET',
26
+ url: '/api/v1/feed/reels_tray/',
27
+ });
28
+
29
+ return response.body;
30
+ }
31
+
32
+ async getUser(userId) {
33
+ const response = await this.client.request.send({
34
+ method: 'GET',
35
+ url: `/api/v1/feed/user/${userId}/reel_media/`,
36
+ });
37
+
38
+ return response.body;
39
+ }
40
+
41
+ async upload(options) {
42
+ const { imagePath, caption } = options;
43
+
44
+ // Read image file
45
+ const imageBuffer = fs.readFileSync(imagePath);
46
+
47
+ // Upload image first
48
+ const uploadResult = await this.client.upload.photo({
49
+ file: imageBuffer,
50
+ uploadId: Date.now()
51
+ });
52
+
53
+ // Configure as story
54
+ const configureResult = await this.client.upload.configure({
55
+ uploadId: uploadResult.upload_id,
56
+ source_type: '4',
57
+ configure_mode: 1, // Story mode
58
+ caption: caption || '',
59
+ });
60
+
61
+ return configureResult;
62
+ }
63
+
64
+ async uploadVideo(options) {
65
+ const { videoPath, caption } = options;
66
+
67
+ // Read video file
68
+ const videoBuffer = fs.readFileSync(videoPath);
69
+
70
+ // Upload video first
71
+ const uploadResult = await this.client.upload.video({
72
+ video: videoBuffer,
73
+ uploadId: Date.now(),
74
+ duration_ms: options.duration_ms || 15000,
75
+ width: options.width || 720,
76
+ height: options.height || 1280,
77
+ });
78
+
79
+ // Configure as story
80
+ const configureResult = await this.client.upload.configureVideo({
81
+ uploadId: uploadResult.upload_id,
82
+ source_type: '4',
83
+ configure_mode: 1, // Story mode
84
+ caption: caption || '',
85
+ length: options.duration_ms || 15000,
86
+ });
87
+
88
+ return configureResult;
89
+ }
90
+
91
+ async seen(input, sourceId = null) {
92
+ let items = [];
93
+
94
+ if (Array.isArray(input)) {
95
+ items = input;
96
+ } else {
97
+ // Flatten reels object to items array
98
+ items = Object.values(input).reduce((acc, reel) => acc.concat(reel.items), []);
99
+ }
100
+
101
+ const reels = {};
102
+ const maxSeenAt = Math.floor(Date.now() / 1000);
103
+ let seenAt = maxSeenAt - items.length;
104
+
105
+ for (const item of items) {
106
+ const itemTakenAt = item.taken_at;
107
+
108
+ if (seenAt < itemTakenAt) {
109
+ seenAt = itemTakenAt + 1;
110
+ }
111
+ if (seenAt > maxSeenAt) {
112
+ seenAt = maxSeenAt;
113
+ }
114
+
115
+ const itemSourceId = sourceId === null ? item.user.pk : sourceId;
116
+ const reelId = `${item.id}_${itemSourceId}`;
117
+ reels[reelId] = [`${itemTakenAt}_${seenAt}`];
118
+
119
+ seenAt += 1;
120
+ }
121
+
122
+ return this.client.media.seen(reels);
123
+ }
124
+
125
+ async getHighlights(userId) {
126
+ const response = await this.client.request.send({
127
+ method: 'GET',
128
+ url: `/api/v1/highlights/${userId}/highlights_tray/`,
129
+ });
130
+
131
+ return response.body;
132
+ }
133
+
134
+ async getHighlight(highlightId) {
135
+ const response = await this.client.request.send({
136
+ method: 'GET',
137
+ url: `/api/v1/feed/reels_media/`,
138
+ qs: {
139
+ reel_ids: highlightId
140
+ }
141
+ });
142
+
143
+ return response.body;
144
+ }
145
+
146
+ async viewers(storyId) {
147
+ const response = await this.client.request.send({
148
+ method: 'GET',
149
+ url: `/api/v1/media/${storyId}/list_reel_media_viewer/`,
150
+ });
151
+
152
+ return response.body;
153
+ }
154
+ }
155
+
156
+ module.exports = StoryRepository;
@@ -0,0 +1,167 @@
1
+ const Repository = require('../core/repository');
2
+ const Chance = require('chance');
3
+ const { random } = require('lodash');
4
+ const FormData = require('form-data');
5
+
6
+ class UploadRepository extends Repository {
7
+ constructor(client) {
8
+ super(client);
9
+ this.chance = new Chance();
10
+ }
11
+
12
+ async photo(options) {
13
+ const uploadId = options.uploadId || Date.now();
14
+ const name = `${uploadId}_0_${random(1000000000, 9999999999)}`;
15
+ const waterfallId = options.waterfallId || this.chance.guid();
16
+
17
+ const ruploadParams = this.createPhotoRuploadParams(options, uploadId);
18
+
19
+ const formData = new FormData();
20
+ formData.append('photo', options.file, { filename: 'photo.jpg' });
21
+
22
+ const response = await this.client.request.send({
23
+ url: `/rupload_igphoto/${name}`,
24
+ method: 'POST',
25
+ headers: {
26
+ 'X-FB-Photo-Waterfall-ID': waterfallId,
27
+ 'X-Entity-Type': 'image/jpeg',
28
+ 'Offset': '0',
29
+ 'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
30
+ 'X-Entity-Name': name,
31
+ 'X-Entity-Length': options.file.length.toString(),
32
+ 'Content-Type': 'application/octet-stream',
33
+ 'Content-Length': options.file.length.toString(),
34
+ 'Accept-Encoding': 'gzip',
35
+ ...formData.getHeaders(),
36
+ },
37
+ data: options.file,
38
+ });
39
+
40
+ return response.body;
41
+ }
42
+
43
+ async video(options) {
44
+ const uploadId = options.uploadId || Date.now();
45
+ const name = options.uploadName || `${uploadId}_0_${random(1000000000, 9999999999)}`;
46
+ const waterfallId = options.waterfallId || this.chance.guid();
47
+
48
+ const ruploadParams = this.createVideoRuploadParams(options, uploadId);
49
+
50
+ const response = await this.client.request.send({
51
+ url: `/rupload_igvideo/${name}`,
52
+ method: 'POST',
53
+ headers: {
54
+ 'X-FB-Video-Waterfall-ID': waterfallId,
55
+ 'X-Entity-Type': 'video/mp4',
56
+ 'Offset': options.offset || '0',
57
+ 'X-Instagram-Rupload-Params': JSON.stringify(ruploadParams),
58
+ 'X-Entity-Name': name,
59
+ 'X-Entity-Length': options.video.length.toString(),
60
+ 'Content-Type': 'application/octet-stream',
61
+ 'Content-Length': options.video.length.toString(),
62
+ 'Accept-Encoding': 'gzip',
63
+ },
64
+ data: options.video,
65
+ });
66
+
67
+ return response.body;
68
+ }
69
+
70
+ createPhotoRuploadParams(options, uploadId) {
71
+ return {
72
+ retry_context: JSON.stringify({
73
+ num_step_auto_retry: 0,
74
+ num_reupload: 0,
75
+ num_step_manual_retry: 0,
76
+ }),
77
+ media_type: '1',
78
+ xsharing_user_ids: JSON.stringify([]),
79
+ upload_id: uploadId.toString(),
80
+ image_compression: JSON.stringify({
81
+ lib_name: 'moz',
82
+ lib_version: '3.1.m',
83
+ quality: '95',
84
+ }),
85
+ };
86
+ }
87
+
88
+ createVideoRuploadParams(options, uploadId) {
89
+ return {
90
+ retry_context: JSON.stringify({
91
+ num_step_auto_retry: 0,
92
+ num_reupload: 0,
93
+ num_step_manual_retry: 0,
94
+ }),
95
+ media_type: '2',
96
+ xsharing_user_ids: JSON.stringify([]),
97
+ upload_id: uploadId.toString(),
98
+ upload_media_duration_ms: options.duration_ms || '0',
99
+ upload_media_width: options.width || '720',
100
+ upload_media_height: options.height || '1280',
101
+ for_album: options.for_album || false,
102
+ };
103
+ }
104
+
105
+ async configure(options) {
106
+ const basePayload = {
107
+ upload_id: options.uploadId,
108
+ source_type: options.source_type || '4',
109
+ camera_position: options.camera_position || 'back',
110
+ _csrftoken: this.client.state.cookieCsrfToken,
111
+ _uid: this.client.state.cookieUserId,
112
+ _uuid: this.client.state.uuid,
113
+ creation_logger_session_id: this.chance.guid(),
114
+ device: {
115
+ manufacturer: this.client.state.devicePayload.manufacturer,
116
+ model: this.client.state.devicePayload.model,
117
+ android_version: this.client.state.devicePayload.android_version,
118
+ android_release: this.client.state.devicePayload.android_release,
119
+ },
120
+ length: options.length || 0,
121
+ audio_muted: options.audio_muted || false,
122
+ poster_frame_index: options.poster_frame_index || 0,
123
+ filter_type: options.filter_type || '0',
124
+ video_result: options.video_result || '',
125
+ composition_id: this.chance.guid(),
126
+ clips: options.clips || [
127
+ {
128
+ length: options.length || 0,
129
+ source_type: '4',
130
+ camera_position: 'back',
131
+ },
132
+ ],
133
+ };
134
+
135
+ if (options.caption) {
136
+ basePayload.caption = options.caption;
137
+ }
138
+
139
+ if (options.location) {
140
+ basePayload.location = JSON.stringify(options.location);
141
+ }
142
+
143
+ const response = await this.client.request.send({
144
+ url: '/api/v1/media/configure/',
145
+ method: 'POST',
146
+ form: this.client.request.sign(basePayload),
147
+ });
148
+
149
+ return response.body;
150
+ }
151
+
152
+ async configureVideo(options) {
153
+ return this.configure({
154
+ ...options,
155
+ video_result: 'deprecated',
156
+ });
157
+ }
158
+
159
+ async configurePhoto(options) {
160
+ return this.configure({
161
+ ...options,
162
+ source_type: '4',
163
+ });
164
+ }
165
+ }
166
+
167
+ module.exports = UploadRepository;
@@ -0,0 +1,94 @@
1
+ const Repository = require('../core/repository');
2
+
3
+ class UserRepository extends Repository {
4
+ async infoByUsername(username) {
5
+ const response = await this.client.request.send({
6
+ method: 'GET',
7
+ url: `/api/v1/users/${username}/usernameinfo/`,
8
+ });
9
+
10
+ return response.body.user;
11
+ }
12
+
13
+ async info(userId) {
14
+ const response = await this.client.request.send({
15
+ method: 'GET',
16
+ url: `/api/v1/users/${userId}/info/`,
17
+ });
18
+
19
+ return response.body.user;
20
+ }
21
+
22
+ async search(query) {
23
+ const response = await this.client.request.send({
24
+ method: 'GET',
25
+ url: '/api/v1/users/search/',
26
+ qs: {
27
+ q: query,
28
+ count: 50
29
+ }
30
+ });
31
+
32
+ return response.body.users;
33
+ }
34
+
35
+ async follow(userId) {
36
+ const response = await this.client.request.send({
37
+ method: 'POST',
38
+ url: `/api/v1/friendships/create/${userId}/`,
39
+ form: this.client.request.sign({
40
+ _csrftoken: this.client.state.cookieCsrfToken,
41
+ _uid: this.client.state.cookieUserId,
42
+ _uuid: this.client.state.uuid,
43
+ user_id: userId,
44
+ }),
45
+ });
46
+
47
+ return response.body;
48
+ }
49
+
50
+ async unfollow(userId) {
51
+ const response = await this.client.request.send({
52
+ method: 'POST',
53
+ url: `/api/v1/friendships/destroy/${userId}/`,
54
+ form: this.client.request.sign({
55
+ _csrftoken: this.client.state.cookieCsrfToken,
56
+ _uid: this.client.state.cookieUserId,
57
+ _uuid: this.client.state.uuid,
58
+ user_id: userId,
59
+ }),
60
+ });
61
+
62
+ return response.body;
63
+ }
64
+
65
+ async getFollowers(userId, maxId = null) {
66
+ const qs = {
67
+ max_id: maxId
68
+ };
69
+
70
+ const response = await this.client.request.send({
71
+ method: 'GET',
72
+ url: `/api/v1/friendships/${userId}/followers/`,
73
+ qs
74
+ });
75
+
76
+ return response.body;
77
+ }
78
+
79
+ async getFollowing(userId, maxId = null) {
80
+ const qs = {
81
+ max_id: maxId
82
+ };
83
+
84
+ const response = await this.client.request.send({
85
+ method: 'GET',
86
+ url: `/api/v1/friendships/${userId}/following/`,
87
+ qs
88
+ });
89
+
90
+ return response.body;
91
+ }
92
+ }
93
+
94
+ module.exports = UserRepository;
@@ -0,0 +1,11 @@
1
+ const sendPhoto = require('./sendPhoto');
2
+ const sendFile = require('./sendFile');
3
+ const uploadPhoto = require('./uploadPhoto');
4
+ const uploadFile = require('./uploadfFile');
5
+
6
+ module.exports = {
7
+ sendPhoto,
8
+ sendFile,
9
+ uploadPhoto,
10
+ uploadFile
11
+ };
@@ -0,0 +1,154 @@
1
+ /**
2
+ * sendFile.js
3
+ * High-level helper to send uploaded video/audio/image files to Instagram Direct (DM or existing thread).
4
+ *
5
+ * Requires:
6
+ * - uploadFile(session, fileBuffer, options) from ./uploadFile
7
+ *
8
+ * Supports:
9
+ * - Send to a single user by userId (recipient_users)
10
+ * - Send to an existing thread (group or DM) by threadId
11
+ * - Optional caption
12
+ * - Optional mentions (array of userIds) embedded in caption
13
+ * - Custom mimeType/fileName/chunkSize/isClipsMedia forwarded to uploadFile
14
+ *
15
+ * Usage:
16
+ * const sendFile = require('./sendFile');
17
+ * await sendFile(session, {
18
+ * fileBuffer: fs.readFileSync('./clip.mp4'),
19
+ * mimeType: 'video/mp4',
20
+ * fileName: 'clip.mp4',
21
+ * userId: '123456789', // or threadId: '340282366841710300949128123456789'
22
+ * caption: 'Uite clipul!',
23
+ * });
24
+ *
25
+ * Notes:
26
+ * - Exactly one of { userId, threadId } must be provided.
27
+ * - For photos (JPEG/PNG), you can still use this with mimeType 'image/jpeg' or 'image/png',
28
+ * but uploadPhoto.js + sendPhoto.js is preferred for image-specific flows.
29
+ */
30
+
31
+ const uploadFile = require('./uploadfFile');
32
+
33
+ /**
34
+ * @typedef {Object} SendFileOptions
35
+ * @property {Buffer} fileBuffer - Required Buffer data
36
+ * @property {string} [mimeType='video/mp4'] - e.g., 'video/mp4', 'audio/mpeg', 'image/jpeg'
37
+ * @property {string} [fileName] - Optional file name; sanitized based on mime
38
+ * @property {number} [chunkSize] - Optional chunk size for uploadFile
39
+ * @property {boolean} [isClipsMedia=false] - Hint for reels-like uploads (if your flow supports it)
40
+ * @property {string} [caption] - Optional caption text
41
+ * @property {string} [userId] - Send to user (DM) — exactly one of userId or threadId
42
+ * @property {string} [threadId] - Send to existing thread (group or DM) — exactly one of userId or threadId
43
+ * @property {string[]} [mentions] - Optional array of userIds mentioned in caption
44
+ * @property {AbortSignal} [signal] - Optional AbortSignal to cancel
45
+ */
46
+
47
+ /**
48
+ * Send a file (video/audio/image) to Instagram Direct.
49
+ * Internally:
50
+ * - Uploads via rupload to get upload_id
51
+ * - Broadcasts the uploaded media to either a user (DM) or an existing thread
52
+ *
53
+ * @param {object} session - Authenticated session (with request.send)
54
+ * @param {SendFileOptions} opts - Options
55
+ * @returns {Promise<object>} Instagram response object
56
+ */
57
+ async function sendFile(session, opts = {}) {
58
+ const {
59
+ fileBuffer,
60
+ mimeType = 'video/mp4',
61
+ fileName,
62
+ chunkSize,
63
+ isClipsMedia = false,
64
+ caption = '',
65
+ userId,
66
+ threadId,
67
+ mentions = [],
68
+ signal,
69
+ } = opts;
70
+
71
+ // Validate destination
72
+ if (!userId && !threadId) {
73
+ throw new Error('sendFile: You must provide either userId (DM) or threadId (existing thread).');
74
+ }
75
+ if (userId && threadId) {
76
+ throw new Error('sendFile: Provide only one destination — userId OR threadId, not both.');
77
+ }
78
+ // Validate buffer
79
+ if (!fileBuffer || !Buffer.isBuffer(fileBuffer) || fileBuffer.length === 0) {
80
+ throw new Error('sendFile: fileBuffer must be a non-empty Buffer.');
81
+ }
82
+ if (typeof mimeType !== 'string' || mimeType.length === 0) {
83
+ throw new Error('sendFile: mimeType must be a non-empty string (e.g., "video/mp4").');
84
+ }
85
+
86
+ // 1) Upload file to get upload_id
87
+ const upload_id = await uploadFile(session, fileBuffer, {
88
+ mimeType,
89
+ fileName,
90
+ chunkSize,
91
+ isClipsMedia,
92
+ signal,
93
+ });
94
+
95
+ // 2) Build base form payload
96
+ const form = {
97
+ upload_id,
98
+ action: 'send_item',
99
+ caption,
100
+ };
101
+
102
+ // 3) Mentions (optional)
103
+ if (Array.isArray(mentions) && mentions.length > 0) {
104
+ form.entities = JSON.stringify(
105
+ mentions.map((uid) => ({
106
+ user_id: String(uid),
107
+ type: 'mention',
108
+ }))
109
+ );
110
+ }
111
+
112
+ // 4) Destination-specific fields
113
+ // For video/audio/image via this flow, IG uses the "upload_video" broadcast endpoint.
114
+ // Images can also be sent via upload_photo (recommended via sendPhoto.js).
115
+ const url = '/direct_v2/threads/broadcast/upload_video/';
116
+ if (userId) {
117
+ form.recipient_users = JSON.stringify([[String(userId)]]);
118
+ } else {
119
+ form.thread_ids = JSON.stringify([String(threadId)]);
120
+ }
121
+
122
+ // 5) Send broadcast request
123
+ try {
124
+ const response = await session.request.send({
125
+ url,
126
+ method: 'POST',
127
+ form,
128
+ signal,
129
+ });
130
+
131
+ if (!response) {
132
+ throw new Error('sendFile: Empty response from Instagram broadcast endpoint.');
133
+ }
134
+ return response;
135
+ } catch (err) {
136
+ throw new Error(`sendFile: Broadcast failed — ${normalizeError(err)}`);
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Normalize error shapes to readable text.
142
+ */
143
+ function normalizeError(err) {
144
+ if (!err) return 'Unknown error';
145
+ if (typeof err === 'string') return err;
146
+ if (err.message) return err.message;
147
+ try {
148
+ return JSON.stringify(err);
149
+ } catch {
150
+ return 'Unserializable error';
151
+ }
152
+ }
153
+
154
+ module.exports = sendFile;