bb-fca 2.0.17 → 2.0.19

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.
@@ -0,0 +1,649 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.default = default_1;
37
+ const crypto = __importStar(require("crypto"));
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const utils = require("../../../utils");
41
+ /**
42
+ * @namespace api.createReel
43
+ * @description Upload and publish a Facebook Reel with full copyright check flow.
44
+ * Flow: Start Session → rupload binary → Receive confirm → Copyright Check → Publish
45
+ * @license Ex-it
46
+ */
47
+ /**
48
+ * Generate a UUID v4 string for composer_session_id / waterfall_id.
49
+ */
50
+ function generateUUID() {
51
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
52
+ const r = (Math.random() * 16) | 0;
53
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
54
+ return v.toString(16);
55
+ });
56
+ }
57
+ /**
58
+ * Sleep helper for polling.
59
+ */
60
+ function sleep(ms) {
61
+ return new Promise((resolve) => setTimeout(resolve, ms));
62
+ }
63
+ function default_1(defaultFuncs, api, ctx) {
64
+ /**
65
+ * Upload and publish a video as a Facebook Reel.
66
+ *
67
+ * @param {object} options - The reel options.
68
+ * @param {string} options.videoPath - File path to the video file.
69
+ * @param {string} [options.message=""] - Caption text for the reel.
70
+ * @param {string} [options.privacy="EVERYONE"] - Privacy: "EVERYONE", "FRIENDS", or "SELF".
71
+ * @param {boolean} [options.skipCopyrightCheck=false] - Skip copyright check polling (faster but riskier).
72
+ * @param {number} [options.copyrightCheckTimeout=60000] - Max time to wait for copyright check (ms).
73
+ * @param {number} [options.copyrightCheckInterval=2000] - Polling interval for copyright check (ms).
74
+ * @param {Function} [callback] - Optional callback function.
75
+ * @returns {Promise<object>} Object containing postID, storyID and metadata.
76
+ */
77
+ async function createReel(options, callback) {
78
+ let resolveFunc = function () { };
79
+ let rejectFunc = function () { };
80
+ const returnPromise = new Promise(function (resolve, reject) {
81
+ resolveFunc = resolve;
82
+ rejectFunc = reject;
83
+ });
84
+ callback =
85
+ callback ||
86
+ function (err, data) {
87
+ if (err)
88
+ return rejectFunc(err);
89
+ resolveFunc(data);
90
+ };
91
+ try {
92
+ // ===== Validate Input =====
93
+ if (!options || typeof options !== 'object') {
94
+ throw new Error('Options must be an object with at least { videoPath }.');
95
+ }
96
+ const videoPath = options.videoPath;
97
+ const message = options.message || '';
98
+ const privacy = options.privacy || 'EVERYONE';
99
+ const skipCopyrightCheck = options.skipCopyrightCheck || false;
100
+ const copyrightCheckTimeout = options.copyrightCheckTimeout || 60000;
101
+ const copyrightCheckInterval = options.copyrightCheckInterval || 2000;
102
+ if (!videoPath || typeof videoPath !== 'string') {
103
+ throw new Error('videoPath is required and must be a string.');
104
+ }
105
+ if (!fs.existsSync(videoPath)) {
106
+ throw new Error(`Video file not found: ${videoPath}`);
107
+ }
108
+ const validPrivacy = ['EVERYONE', 'FRIENDS', 'SELF', 'ALL_FRIENDS'];
109
+ if (!validPrivacy.includes(privacy)) {
110
+ throw new Error(`Invalid privacy setting. Use one of: ${validPrivacy.join(', ')}`);
111
+ }
112
+ const fileBuffer = fs.readFileSync(videoPath);
113
+ const fileSize = fileBuffer.length;
114
+ const fileExtension = path
115
+ .extname(videoPath)
116
+ .replace('.', '')
117
+ .toLowerCase();
118
+ // Validate extension
119
+ const allowedExtensions = [
120
+ 'mov',
121
+ 'mp4',
122
+ 'avi',
123
+ 'mkv',
124
+ 'webm',
125
+ 'wmv',
126
+ 'flv',
127
+ 'mpg',
128
+ 'mpeg',
129
+ '3gp',
130
+ '3g2',
131
+ 'm4v',
132
+ ];
133
+ if (!allowedExtensions.includes(fileExtension)) {
134
+ throw new Error(`Unsupported video format: .${fileExtension}. Supported: ${allowedExtensions.join(', ')}`);
135
+ }
136
+ const fileHash = crypto
137
+ .createHash('md5')
138
+ .update(fileBuffer)
139
+ .digest('hex');
140
+ const composerSessionId = generateUUID();
141
+ // CORS headers for cross-subdomain requests
142
+ const corsHeaders = {
143
+ Origin: 'https://www.facebook.com',
144
+ Referer: 'https://www.facebook.com/',
145
+ 'Sec-Fetch-Dest': 'empty',
146
+ 'Sec-Fetch-Mode': 'cors',
147
+ 'Sec-Fetch-Site': 'same-site',
148
+ };
149
+ // ====================================================================
150
+ // STEP 1: Initialize Upload Session (POST vupload-edge.facebook.com)
151
+ // Exact match with browser network capture
152
+ // ====================================================================
153
+ const startUrl = 'https://vupload-edge.facebook.com/ajax/video/upload/requests/start/?av=' +
154
+ ctx.userID +
155
+ '&__a=1';
156
+ // Resolve lsd once — browser always sends a real token here
157
+ const lsd = ctx.lsd || ctx.fb_dtsg;
158
+ const startForm = {
159
+ file_size: String(fileSize),
160
+ file_extension: fileExtension,
161
+ target_id: ctx.userID,
162
+ source: 'reel_composer',
163
+ composer_dialog_version: '',
164
+ waterfall_id: composerSessionId,
165
+ composer_session_id: composerSessionId,
166
+ composer_entry_point_ref: 'comet_pp_plus_reel_composer_feed_sprout',
167
+ composer_work_shared_draft_mode: '',
168
+ has_file_been_replaced: 'false',
169
+ supports_chunking: 'true',
170
+ supports_file_api: 'true',
171
+ partition_start_offset: '0',
172
+ partition_end_offset: String(fileSize),
173
+ creator_product: '2',
174
+ spherical: 'false',
175
+ video_publisher_action_source: '',
176
+ // Auth params — must match browser session exactly
177
+ __aaid: '0',
178
+ __user: ctx.userID,
179
+ __a: '1',
180
+ __req: '1',
181
+ __hs: ctx.hs || '20577.HYP:comet_pkg.2.1...0',
182
+ dpr: '1',
183
+ __ccg: 'EXCELLENT',
184
+ __rev: ctx.revision || '',
185
+ __s: ctx.__s || '',
186
+ __hsi: ctx.__hsi || '',
187
+ __dyn: ctx.__dyn || '',
188
+ __csr: ctx.__csr || '',
189
+ __hsdp: ctx.__hsdp || '',
190
+ __hblp: ctx.__hblp || '',
191
+ __sjsp: ctx.__sjsp || '',
192
+ __comet_req: '15',
193
+ fb_dtsg: ctx.fb_dtsg,
194
+ jazoest: ctx.jazoest,
195
+ lsd,
196
+ __spin_r: ctx.revision || '',
197
+ __spin_b: 'trunk',
198
+ __spin_t: String(Math.floor(Date.now() / 1000)),
199
+ __crn: ctx.__crn || 'comet.fbweb.CometHomeRoute',
200
+ };
201
+ // Debug: log auth params to identify missing values
202
+ utils.log('createReel', `Start session params: fb_dtsg=${ctx.fb_dtsg ? 'OK(' + ctx.fb_dtsg.substring(0, 10) + '...)' : 'MISSING'}, ` +
203
+ `jazoest=${ctx.jazoest || 'MISSING'}, __rev=${ctx.revision || 'MISSING'}, ` +
204
+ `__hs=${ctx.hs || 'MISSING'}, lsd=${ctx.lsd || 'MISSING'}, ` +
205
+ `userID=${ctx.userID || 'MISSING'}`);
206
+ const startRaw = await utils
207
+ .post(startUrl, ctx.jar, startForm, ctx.globalOptions, ctx, {
208
+ X_fb_video_waterfall_id: composerSessionId,
209
+ ...corsHeaders,
210
+ 'Content-Type': 'application/x-www-form-urlencoded',
211
+ });
212
+ // Debug: log raw response before parsing
213
+ utils.log('createReel', `Start raw response status=${startRaw?.statusCode}, body=${JSON.stringify(startRaw?.body)?.substring(0, 500)}`);
214
+ const startRes = await utils.parseAndCheckLogin(ctx, defaultFuncs)(startRaw);
215
+ const videoId = startRes?.payload?.video_id || startRes?.video_id;
216
+ const uploadSessionId = startRes?.payload?.upload_session_id || startRes?.upload_session_id;
217
+ const startOffset = startRes?.payload?.start_offset ?? startRes?.start_offset ?? 0;
218
+ const endOffset = startRes?.payload?.end_offset ?? startRes?.end_offset ?? fileSize;
219
+ if (!videoId) {
220
+ throw new Error('Failed to get video_id from upload session. Response: ' +
221
+ JSON.stringify(startRes));
222
+ }
223
+ utils.log('createReel', `Upload session started. video_id=${videoId}, session=${uploadSessionId}`);
224
+ // ====================================================================
225
+ // STEP 2: Probe rupload server (GET)
226
+ // ====================================================================
227
+ const ruploadPath = `/fb_video/${fileHash}-${startOffset}-${endOffset}`;
228
+ const ruploadAuthParams = new URLSearchParams({
229
+ __aaid: '0',
230
+ __user: ctx.userID,
231
+ __a: '1',
232
+ __req: '1',
233
+ __hs: ctx.hs || '20577.HYP:comet_pkg.2.1...0',
234
+ dpr: '1',
235
+ __ccg: 'EXCELLENT',
236
+ __rev: ctx.revision || '',
237
+ __s: ctx.__s || '',
238
+ __hsi: ctx.__hsi || '',
239
+ __dyn: ctx.__dyn || '',
240
+ __csr: ctx.__csr || '',
241
+ __hsdp: ctx.__hsdp || '',
242
+ __hblp: ctx.__hblp || '',
243
+ __sjsp: ctx.__sjsp || '',
244
+ __comet_req: '15',
245
+ fb_dtsg_ag: ctx.fb_dtsg_ag || ctx.fb_dtsg,
246
+ jazoest: ctx.jazoest,
247
+ __spin_r: ctx.revision || '',
248
+ __spin_b: 'trunk',
249
+ __spin_t: String(Math.floor(Date.now() / 1000)),
250
+ __crn: ctx.__crn || 'comet.fbweb.CometHomeRoute',
251
+ }).toString();
252
+ // Try multiple rupload hosts (Facebook may route to different DCs)
253
+ const ruploadHosts = [
254
+ 'rupload-hkg4-2.up.facebook.com',
255
+ 'rupload-hkg1-2.up.facebook.com',
256
+ 'rupload.facebook.com',
257
+ ];
258
+ let ruploadBaseUrl = '';
259
+ let probeSuccess = false;
260
+ for (const host of ruploadHosts) {
261
+ ruploadBaseUrl = `https://${host}${ruploadPath}?${ruploadAuthParams}`;
262
+ try {
263
+ await utils.get(ruploadBaseUrl, ctx.jar, undefined, ctx.globalOptions, ctx, corsHeaders);
264
+ probeSuccess = true;
265
+ break;
266
+ }
267
+ catch (e) {
268
+ // Try next host
269
+ }
270
+ }
271
+ if (!probeSuccess) {
272
+ // Fallback: use first host anyway
273
+ ruploadBaseUrl = `https://${ruploadHosts[0]}${ruploadPath}?${ruploadAuthParams}`;
274
+ }
275
+ // ====================================================================
276
+ // STEP 3: Upload Binary Data (POST rupload)
277
+ // ====================================================================
278
+ const fileName = path.basename(videoPath);
279
+ const mimeTypes = {
280
+ mov: 'video/quicktime',
281
+ mp4: 'video/mp4',
282
+ avi: 'video/x-msvideo',
283
+ mkv: 'video/x-matroska',
284
+ webm: 'video/webm',
285
+ wmv: 'video/x-ms-wmv',
286
+ flv: 'video/x-flv',
287
+ mpg: 'video/mpeg',
288
+ mpeg: 'video/mpeg',
289
+ '3gp': 'video/3gpp',
290
+ '3g2': 'video/3gpp2',
291
+ m4v: 'video/x-m4v',
292
+ };
293
+ const mimeType = mimeTypes[fileExtension] || 'video/mp4';
294
+ const uploadHeaders = {
295
+ 'Content-Type': 'application/octet-stream',
296
+ Product_media_id: String(videoId),
297
+ Id: String(uploadSessionId),
298
+ Start_offset: String(startOffset),
299
+ End_offset: String(endOffset),
300
+ Offset: String(startOffset),
301
+ 'X-Entity-Length': String(fileSize),
302
+ 'X-Total-Asset-Size': String(fileSize),
303
+ 'X-Entity-Type': mimeType,
304
+ 'X-Entity-Name': encodeURIComponent(fileName),
305
+ Composer_session_id: composerSessionId,
306
+ ...corsHeaders,
307
+ };
308
+ const uploadRes = await utils.postRaw(ruploadBaseUrl, ctx.jar, fileBuffer, ctx.globalOptions, ctx, uploadHeaders);
309
+ let fileHandle = null;
310
+ try {
311
+ const uploadBody = typeof uploadRes.body === 'string'
312
+ ? JSON.parse(uploadRes.body)
313
+ : uploadRes.body;
314
+ fileHandle = uploadBody?.h || null;
315
+ }
316
+ catch (_) {
317
+ /* parse error */
318
+ }
319
+ if (!fileHandle) {
320
+ throw new Error('Failed to get file handle from binary upload. Response: ' +
321
+ JSON.stringify(uploadRes.body));
322
+ }
323
+ utils.log('createReel', `Binary upload complete. Handle obtained.`);
324
+ // ====================================================================
325
+ // STEP 4: Confirm Upload (POST receive)
326
+ // ====================================================================
327
+ const receiveParams = new URLSearchParams({
328
+ av: ctx.userID,
329
+ composer_session_id: composerSessionId,
330
+ video_id: String(videoId),
331
+ start_offset: '0',
332
+ end_offset: String(endOffset),
333
+ source: 'reel_composer',
334
+ target_id: ctx.userID,
335
+ waterfall_id: composerSessionId,
336
+ composer_entry_point_ref: 'comet_pp_plus_reel_composer_feed_sprout',
337
+ composer_work_shared_draft_mode: '',
338
+ composer_dialog_version: '',
339
+ has_file_been_replaced: 'false',
340
+ supports_chunking: 'true',
341
+ upload_speed: '',
342
+ partition_start_offset: '0',
343
+ partition_end_offset: String(endOffset),
344
+ __aaid: '0',
345
+ __user: ctx.userID,
346
+ __a: '1',
347
+ __req: '1',
348
+ __hs: ctx.hs || '20577.HYP:comet_pkg.2.1...0',
349
+ dpr: '1',
350
+ __ccg: 'EXCELLENT',
351
+ __rev: ctx.revision || '',
352
+ __s: ctx.__s || '',
353
+ __hsi: ctx.__hsi || '',
354
+ __dyn: ctx.__dyn || '',
355
+ __csr: ctx.__csr || '',
356
+ __hsdp: ctx.__hsdp || '',
357
+ __hblp: ctx.__hblp || '',
358
+ __sjsp: ctx.__sjsp || '',
359
+ __comet_req: '15',
360
+ fb_dtsg: ctx.fb_dtsg,
361
+ jazoest: ctx.jazoest,
362
+ lsd,
363
+ __spin_r: ctx.revision || '',
364
+ __spin_b: 'trunk',
365
+ __spin_t: String(Math.floor(Date.now() / 1000)),
366
+ __crn: ctx.__crn || 'comet.fbweb.CometHomeRoute',
367
+ }).toString();
368
+ const receiveUrl = `https://vupload-edge.facebook.com/ajax/video/upload/requests/receive/?${receiveParams}`;
369
+ // Send as multipart/form-data with the file handle
370
+ const receiveRes = await defaultFuncs
371
+ .postFormData(receiveUrl, ctx.jar, {
372
+ fbuploader_video_file_chunk: fileHandle,
373
+ }, {
374
+ X_fb_video_waterfall_id: composerSessionId,
375
+ ...corsHeaders,
376
+ })
377
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
378
+ const recvStart = receiveRes?.payload?.start_offset ?? receiveRes?.start_offset;
379
+ const recvEnd = receiveRes?.payload?.end_offset ?? receiveRes?.end_offset;
380
+ if (recvStart !== undefined &&
381
+ recvEnd !== undefined &&
382
+ recvStart !== recvEnd) {
383
+ utils.warn('createReel', `Upload may be incomplete: start_offset=${recvStart}, end_offset=${recvEnd}`);
384
+ }
385
+ utils.log('createReel', `Upload confirmed. start=${recvStart}, end=${recvEnd}`);
386
+ // ====================================================================
387
+ // STEP 5: Copyright Check (Mutation + Polling)
388
+ // ====================================================================
389
+ if (!skipCopyrightCheck) {
390
+ utils.log('createReel', 'Starting copyright check...');
391
+ // 5a. Trigger copyright check mutation
392
+ const copyrightMutationForm = {
393
+ av: ctx.userID,
394
+ __user: ctx.userID,
395
+ __a: '1',
396
+ __req: '1',
397
+ __ccg: 'EXCELLENT',
398
+ __comet_req: '15',
399
+ fb_dtsg: ctx.fb_dtsg,
400
+ jazoest: ctx.jazoest,
401
+ lsd,
402
+ fb_api_caller_class: 'RelayModern',
403
+ fb_api_req_friendly_name: 'useCometVideoEditorCopyrightCheckMutation',
404
+ variables: JSON.stringify({
405
+ input: {
406
+ actor_id: ctx.userID,
407
+ client_mutation_id: '5',
408
+ from_mbs: false,
409
+ video_id: String(videoId),
410
+ },
411
+ __relay_internal__pv__CometVideoEditorCopyrightCheckDetails_shouldUseMatchlessrelayprovider: false,
412
+ }),
413
+ server_timestamps: 'true',
414
+ doc_id: '25171698979168867',
415
+ };
416
+ await defaultFuncs
417
+ .post('https://www.facebook.com/api/graphql/', ctx.jar, copyrightMutationForm, {})
418
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
419
+ // 5b. Poll for copyright check completion
420
+ const pollStartTime = Date.now();
421
+ let copyrightPassed = false;
422
+ while (Date.now() - pollStartTime < copyrightCheckTimeout) {
423
+ await sleep(copyrightCheckInterval);
424
+ const pollForm = {
425
+ av: ctx.userID,
426
+ __user: ctx.userID,
427
+ __a: '1',
428
+ __req: '1',
429
+ __ccg: 'EXCELLENT',
430
+ __comet_req: '15',
431
+ fb_dtsg: ctx.fb_dtsg,
432
+ jazoest: ctx.jazoest,
433
+ lsd,
434
+ fb_api_caller_class: 'RelayModern',
435
+ fb_api_req_friendly_name: 'CometVideoEditorCopyrightCheckDetailsLiveQueryUpdaterQuery',
436
+ variables: JSON.stringify({
437
+ videoID: String(videoId),
438
+ __relay_internal__pv__CometVideoEditorCopyrightCheckDetails_shouldUseMatchlessrelayprovider: false,
439
+ }),
440
+ server_timestamps: 'true',
441
+ doc_id: '25488331727450621',
442
+ };
443
+ const pollRes = await defaultFuncs
444
+ .post('https://www.facebook.com/api/graphql/', ctx.jar, pollForm, {})
445
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
446
+ const video = pollRes?.data?.video || pollRes?.data?.node;
447
+ const precheck = video?.copyright_precheck_progress;
448
+ const percentage = precheck?.percentage;
449
+ const finished = video?.if_copyright_precheck_is_finished;
450
+ if (percentage >= 100 || finished !== null) {
451
+ copyrightPassed = true;
452
+ const earlyResult = precheck?.early_return_result;
453
+ if (earlyResult?.found_early_violation) {
454
+ utils.warn('createReel', 'Copyright violation detected! The reel may be blocked.');
455
+ }
456
+ break;
457
+ }
458
+ utils.log('createReel', `Copyright check: ${percentage || 0}%`);
459
+ }
460
+ if (!copyrightPassed) {
461
+ utils.warn('createReel', 'Copyright check timed out. Proceeding with publish anyway.');
462
+ }
463
+ else {
464
+ utils.log('createReel', 'Copyright check passed!');
465
+ }
466
+ }
467
+ // ====================================================================
468
+ // STEP 6: Publish Reel (ComposerStoryCreateMutation)
469
+ // ====================================================================
470
+ utils.log('createReel', 'Publishing reel...');
471
+ const privacyBaseState = privacy === 'ALL_FRIENDS' ? 'FRIENDS' : privacy;
472
+ const publishVariables = {
473
+ input: {
474
+ composer_entry_point: 'comet_pp_plus_reel_composer_feed_sprout',
475
+ composer_source_surface: 'short_form_video',
476
+ idempotence_token: `${composerSessionId}_FEED`,
477
+ source: 'WWW',
478
+ attachments: [
479
+ {
480
+ video: {
481
+ audio_descriptions: null,
482
+ id: String(videoId),
483
+ additional_video_metadata: {
484
+ translatedAudioMetadata: [],
485
+ autoGenCaptionsSettings: {
486
+ autogenerate_captions_enabled: true,
487
+ should_review_all_captions: false,
488
+ },
489
+ },
490
+ notify_when_processed: true,
491
+ transcriptions: null,
492
+ was_created_via_unified_video_flow: {
493
+ was_created_via_unified_video_flow: true,
494
+ },
495
+ story_media_audio_data: {
496
+ raw_media_type: 'VIDEO',
497
+ },
498
+ video_media_metadata: {
499
+ audio: {
500
+ audio_type: 'original_audio',
501
+ start_time_s: 0,
502
+ volume_level: 1,
503
+ },
504
+ is_audio_muted: false,
505
+ length_in_sec: 0, // FB doesn't strictly require this
506
+ },
507
+ },
508
+ },
509
+ ],
510
+ fb_shorts: {
511
+ has_overridden_video_format: true,
512
+ is_fb_short: false,
513
+ remix_status: 'DISABLED',
514
+ },
515
+ post_publish_story_data: {
516
+ reshare_post_as_sticker: 'DISABLED',
517
+ },
518
+ message: {
519
+ ranges: [],
520
+ text: message,
521
+ },
522
+ audience: {
523
+ privacy: {
524
+ allow: [],
525
+ base_state: privacyBaseState,
526
+ deny: [],
527
+ tag_expansion_state: 'UNSPECIFIED',
528
+ },
529
+ },
530
+ with_tags_ids: null,
531
+ reels_remix: {
532
+ remix_status: 'DISABLED',
533
+ },
534
+ stars_receivable: {
535
+ is_receiving_stars_disabled: false,
536
+ },
537
+ logging: {
538
+ composer_session_id: composerSessionId,
539
+ },
540
+ navigation_data: {
541
+ attribution_id_v2: `CometHomeRoot.react,comet.home,logo,${Date.now()},631762,4748854339,,`,
542
+ },
543
+ tracking: [null],
544
+ event_share_metadata: {
545
+ surface: 'newsfeed',
546
+ },
547
+ actor_id: ctx.userID,
548
+ client_mutation_id: '1',
549
+ },
550
+ feedLocation: 'NEWSFEED',
551
+ feedbackSource: 1,
552
+ focusCommentID: null,
553
+ gridMediaWidth: null,
554
+ groupID: null,
555
+ scale: 1,
556
+ privacySelectorRenderLocation: 'COMET_STREAM',
557
+ checkPhotosToReelsUpsellEligibility: false,
558
+ referringStoryRenderLocation: null,
559
+ renderLocation: 'homepage_stream',
560
+ useDefaultActor: false,
561
+ inviteShortLinkKey: null,
562
+ isFeed: true,
563
+ isFundraiser: false,
564
+ isFunFactPost: false,
565
+ isGroup: false,
566
+ isEvent: false,
567
+ isTimeline: false,
568
+ isSocialLearning: false,
569
+ isPageNewsFeed: false,
570
+ isProfileReviews: false,
571
+ isWorkSharedDraft: false,
572
+ canUserManageOffers: false,
573
+ // Relay internal provider variables (required by ComposerStoryCreateMutation)
574
+ __relay_internal__pv__CometUFIShareActionMigrationrelayprovider: true,
575
+ __relay_internal__pv__GHLShouldChangeSponsoredDataFieldNamerelayprovider: true,
576
+ __relay_internal__pv__GHLShouldChangeAdIdFieldNamerelayprovider: true,
577
+ __relay_internal__pv__CometUFI_dedicated_comment_routable_dialog_gkrelayprovider: true,
578
+ __relay_internal__pv__CometUFICommentAutoTranslationTyperelayprovider: 'ORIGINAL',
579
+ __relay_internal__pv__CometUFICommentAvatarStickerAnimatedImagerelayprovider: false,
580
+ __relay_internal__pv__CometUFICommentActionLinksRewriteEnabledrelayprovider: false,
581
+ __relay_internal__pv__IsWorkUserrelayprovider: false,
582
+ __relay_internal__pv__CometUFIReactionsEnableShortNamerelayprovider: false,
583
+ __relay_internal__pv__CometUFISingleLineUFIrelayprovider: false,
584
+ __relay_internal__pv__CometFeedStory_enable_reactor_facepilerelayprovider: false,
585
+ __relay_internal__pv__CometFeedStory_enable_post_permalink_white_space_clickrelayprovider: false,
586
+ __relay_internal__pv__TestPilotShouldIncludeDemoAdUseCaserelayprovider: false,
587
+ __relay_internal__pv__FBReels_deprecate_short_form_video_context_gkrelayprovider: true,
588
+ __relay_internal__pv__FBReels_enable_view_dubbed_audio_type_gkrelayprovider: true,
589
+ __relay_internal__pv__CometImmersivePhotoCanUserDisable3DMotionrelayprovider: false,
590
+ __relay_internal__pv__WorkCometIsEmployeeGKProviderrelayprovider: false,
591
+ __relay_internal__pv__IsMergQAPollsrelayprovider: false,
592
+ __relay_internal__pv__FBReelsMediaFooter_comet_enable_reels_ads_gkrelayprovider: true,
593
+ __relay_internal__pv__FBReelsIFUTileContent_reelsIFUPlayOnHoverrelayprovider: true,
594
+ __relay_internal__pv__GroupsCometGYSJFeedItemHeightrelayprovider: 206,
595
+ __relay_internal__pv__ShouldEnableBakedInTextStoriesrelayprovider: false,
596
+ __relay_internal__pv__StoriesShouldIncludeFbNotesrelayprovider: false,
597
+ __relay_internal__pv__groups_comet_use_glvrelayprovider: false,
598
+ __relay_internal__pv__GHLShouldChangeSponsoredAuctionDistanceFieldNamerelayprovider: false,
599
+ __relay_internal__pv__GHLShouldUseSponsoredAuctionLabelFieldNameV1relayprovider: false,
600
+ __relay_internal__pv__GHLShouldUseSponsoredAuctionLabelFieldNameV2relayprovider: false,
601
+ };
602
+ const publishForm = {
603
+ av: ctx.userID,
604
+ __user: ctx.userID,
605
+ __a: '1',
606
+ __req: '1',
607
+ __hs: ctx.hs || '20577.HYP:comet_pkg.2.1...0',
608
+ __ccg: 'EXCELLENT',
609
+ __comet_req: '15',
610
+ fb_dtsg: ctx.fb_dtsg,
611
+ jazoest: ctx.jazoest,
612
+ lsd,
613
+ __spin_r: ctx.revision || '',
614
+ __spin_b: 'trunk',
615
+ __spin_t: Math.floor(Date.now() / 1000),
616
+ fb_api_caller_class: 'RelayModern',
617
+ fb_api_req_friendly_name: 'ComposerStoryCreateMutation',
618
+ variables: JSON.stringify(publishVariables),
619
+ server_timestamps: 'true',
620
+ doc_id: '26313541601679894',
621
+ };
622
+ const publishRes = await defaultFuncs
623
+ .post('https://www.facebook.com/api/graphql/', ctx.jar, publishForm, {})
624
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs));
625
+ if (publishRes.errors) {
626
+ throw new Error('Publish failed: ' + JSON.stringify(publishRes.errors));
627
+ }
628
+ const storyCreate = publishRes?.data?.story_create;
629
+ const result = {
630
+ success: true,
631
+ postID: storyCreate?.post_id || null,
632
+ storyID: storyCreate?.story_id || null,
633
+ videoID: String(videoId),
634
+ publishingFlow: storyCreate?.publishing_flow || null,
635
+ composerSessionId,
636
+ data: publishRes,
637
+ };
638
+ utils.log('createReel', `Reel published successfully! postID=${result.postID}`);
639
+ callback(null, result);
640
+ }
641
+ catch (err) {
642
+ utils.error('createReel', err);
643
+ callback(err);
644
+ }
645
+ return returnPromise;
646
+ }
647
+ return createReel;
648
+ }
649
+ //# sourceMappingURL=createReel.js.map