n8n-nodes-upload-post 0.1.21 → 0.1.30

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.
@@ -6,6 +6,829 @@ const MANUAL_USER_VALUE = '__manual_user__';
6
6
  const MANUAL_FACEBOOK_VALUE = '__manual_facebook__';
7
7
  const MANUAL_LINKEDIN_VALUE = '__manual_linkedin__';
8
8
  const MANUAL_PINTEREST_VALUE = '__manual_pinterest__';
9
+ const isBinaryFormField = (value) => {
10
+ return typeof value === 'object' && value !== null && 'value' in value;
11
+ };
12
+ const normalizeFormField = (value) => {
13
+ if (value === undefined || value === null) {
14
+ return undefined;
15
+ }
16
+ if (isBinaryFormField(value)) {
17
+ return value;
18
+ }
19
+ return String(value);
20
+ };
21
+ const buildMultipartPayload = (rawFormData) => {
22
+ const payload = {};
23
+ for (const [key, rawValue] of Object.entries(rawFormData)) {
24
+ if (rawValue === undefined || rawValue === null)
25
+ continue;
26
+ if (Array.isArray(rawValue)) {
27
+ const normalizedItems = rawValue
28
+ .map(item => normalizeFormField(item))
29
+ .filter((item) => item !== undefined);
30
+ if (normalizedItems.length > 0) {
31
+ payload[key] = normalizedItems;
32
+ }
33
+ continue;
34
+ }
35
+ const normalizedValue = normalizeFormField(rawValue);
36
+ if (normalizedValue !== undefined) {
37
+ payload[key] = normalizedValue;
38
+ }
39
+ }
40
+ return payload;
41
+ };
42
+ const parseJsonIfNeeded = (data) => {
43
+ if (typeof data === 'string') {
44
+ try {
45
+ return JSON.parse(data);
46
+ }
47
+ catch {
48
+ return data;
49
+ }
50
+ }
51
+ return data;
52
+ };
53
+ const API_BASE_URL = 'https://api.upload-post.com/api';
54
+ const normalizeDateInput = (value) => {
55
+ if (!value)
56
+ return undefined;
57
+ const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(value);
58
+ return hasTimezone ? value : `${value}Z`;
59
+ };
60
+ const ensureArrayFromCommaSeparated = (value) => {
61
+ return value
62
+ .split(',')
63
+ .map(item => item.trim())
64
+ .filter(item => item.length > 0);
65
+ };
66
+ const getBinaryFieldFromItem = async (ctx, propertyName, errorLabel) => {
67
+ var _a, _b;
68
+ const { node, itemIndex, items } = ctx;
69
+ try {
70
+ const binaryBuffer = await node.helpers.getBinaryDataBuffer(itemIndex, propertyName);
71
+ const binaryDetails = (_a = items[itemIndex].binary) === null || _a === void 0 ? void 0 : _a[propertyName];
72
+ return {
73
+ value: binaryBuffer,
74
+ options: {
75
+ filename: (_b = binaryDetails === null || binaryDetails === void 0 ? void 0 : binaryDetails.fileName) !== null && _b !== void 0 ? _b : propertyName,
76
+ contentType: binaryDetails === null || binaryDetails === void 0 ? void 0 : binaryDetails.mimeType,
77
+ },
78
+ };
79
+ }
80
+ catch (error) {
81
+ const message = error instanceof Error ? error.message : '';
82
+ const details = message ? ` (${message})` : '';
83
+ throw new n8n_workflow_1.NodeOperationError(node.getNode(), `${errorLabel} '${propertyName}' was not found in item ${itemIndex}.${details}`, {
84
+ itemIndex,
85
+ });
86
+ }
87
+ };
88
+ const PLATFORM_SUPPORT = {
89
+ uploadPhotos: ['facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x'],
90
+ uploadVideo: ['facebook', 'instagram', 'linkedin', 'pinterest', 'threads', 'tiktok', 'x', 'youtube'],
91
+ uploadText: ['facebook', 'linkedin', 'reddit', 'threads', 'x'],
92
+ };
93
+ const DESCRIPTION_ENABLED_PLATFORMS = new Set(['linkedin', 'facebook', 'youtube', 'pinterest', 'tiktok']);
94
+ const TITLE_OVERRIDES = [
95
+ { platform: 'instagram', param: 'instagramTitle', field: 'instagram_title' },
96
+ { platform: 'facebook', param: 'facebookTitle', field: 'facebook_title' },
97
+ { platform: 'tiktok', param: 'tiktokTitle', field: 'tiktok_title' },
98
+ { platform: 'linkedin', param: 'linkedinTitle', field: 'linkedin_title' },
99
+ { platform: 'x', param: 'xTitle', field: 'x_title' },
100
+ { platform: 'youtube', param: 'youtubeTitle', field: 'youtube_title', operations: ['uploadVideo'] },
101
+ { platform: 'pinterest', param: 'pinterestTitle', field: 'pinterest_title' },
102
+ { platform: 'threads', param: 'threadsTitle', field: 'threads_title', operations: ['uploadText'] },
103
+ ];
104
+ const DESCRIPTION_OVERRIDES = [
105
+ { platform: 'linkedin', param: 'linkedinDescription', field: 'linkedin_description', operations: ['uploadPhotos', 'uploadVideo'] },
106
+ { platform: 'youtube', param: 'youtubeDescription', field: 'youtube_description', operations: ['uploadVideo'] },
107
+ { platform: 'facebook', param: 'facebookDescription', field: 'facebook_description', operations: ['uploadPhotos', 'uploadVideo'] },
108
+ { platform: 'tiktok', param: 'tiktokDescription', field: 'tiktok_description', operations: ['uploadPhotos'] },
109
+ { platform: 'pinterest', param: 'pinterestDescription', field: 'pinterest_description', operations: ['uploadPhotos', 'uploadVideo'] },
110
+ ];
111
+ const getFilteredPlatforms = (operation, platforms) => {
112
+ var _a;
113
+ const allowed = (_a = PLATFORM_SUPPORT[operation]) !== null && _a !== void 0 ? _a : [];
114
+ return platforms.filter(platform => allowed.includes(platform));
115
+ };
116
+ const applyTitleOverrides = (ctx, operation, platforms, formData) => {
117
+ for (const override of TITLE_OVERRIDES) {
118
+ if (!platforms.includes(override.platform))
119
+ continue;
120
+ if (override.operations && !override.operations.includes(operation))
121
+ continue;
122
+ const value = ctx.node.getNodeParameter(override.param, ctx.itemIndex, '');
123
+ if (value) {
124
+ formData[override.field] = value;
125
+ }
126
+ }
127
+ };
128
+ const applyDescriptionOverrides = (ctx, operation, platforms, formData) => {
129
+ const genericDescription = ctx.node.getNodeParameter('description', ctx.itemIndex, '');
130
+ if (genericDescription &&
131
+ (operation === 'uploadPhotos' || operation === 'uploadVideo') &&
132
+ platforms.some(platform => DESCRIPTION_ENABLED_PLATFORMS.has(platform))) {
133
+ formData.description = genericDescription;
134
+ }
135
+ for (const override of DESCRIPTION_OVERRIDES) {
136
+ if (!platforms.includes(override.platform))
137
+ continue;
138
+ if (override.operations && !override.operations.includes(operation))
139
+ continue;
140
+ const value = ctx.node.getNodeParameter(override.param, ctx.itemIndex, '');
141
+ if (value) {
142
+ formData[override.field] = value;
143
+ }
144
+ }
145
+ };
146
+ const getUserForOperation = (ctx, needsUser) => {
147
+ if (!needsUser) {
148
+ return '';
149
+ }
150
+ const selection = ctx.node.getNodeParameter('user', ctx.itemIndex);
151
+ if (selection === MANUAL_USER_VALUE) {
152
+ return ctx.node.getNodeParameter('userManual', ctx.itemIndex);
153
+ }
154
+ return selection;
155
+ };
156
+ const prepareUploadBase = (ctx, operation) => {
157
+ const formData = {};
158
+ const user = getUserForOperation(ctx, true);
159
+ const title = ctx.node.getNodeParameter('title', ctx.itemIndex);
160
+ formData.user = user;
161
+ formData.title = title;
162
+ const scheduledDate = normalizeDateInput(ctx.node.getNodeParameter('scheduledDate', ctx.itemIndex, ''));
163
+ if (scheduledDate) {
164
+ formData.scheduled_date = scheduledDate;
165
+ }
166
+ const uploadAsync = ctx.node.getNodeParameter('uploadAsync', ctx.itemIndex);
167
+ if (uploadAsync !== undefined) {
168
+ formData.async_upload = String(uploadAsync);
169
+ }
170
+ const rawPlatforms = ctx.node.getNodeParameter('platform', ctx.itemIndex);
171
+ const platforms = getFilteredPlatforms(operation, Array.isArray(rawPlatforms) ? rawPlatforms : []);
172
+ formData['platform[]'] = platforms;
173
+ applyTitleOverrides(ctx, operation, platforms, formData);
174
+ applyDescriptionOverrides(ctx, operation, platforms, formData);
175
+ const waitForCompletion = ctx.node.getNodeParameter('waitForCompletion', ctx.itemIndex, false);
176
+ const pollInterval = ctx.node.getNodeParameter('pollInterval', ctx.itemIndex, 10);
177
+ const pollTimeout = ctx.node.getNodeParameter('pollTimeout', ctx.itemIndex, 600);
178
+ return {
179
+ formData,
180
+ platforms,
181
+ waitForCompletion,
182
+ pollInterval,
183
+ pollTimeout,
184
+ };
185
+ };
186
+ const applyPinterestOptions = (ctx, operation, formData) => {
187
+ const selection = ctx.node.getNodeParameter('pinterestBoardId', ctx.itemIndex, '');
188
+ const pinterestBoardId = selection === MANUAL_PINTEREST_VALUE
189
+ ? ctx.node.getNodeParameter('pinterestBoardIdManual', ctx.itemIndex)
190
+ : selection;
191
+ if (pinterestBoardId) {
192
+ formData.pinterest_board_id = pinterestBoardId;
193
+ }
194
+ const pinterestLink = ctx.node.getNodeParameter('pinterestLink', ctx.itemIndex, '');
195
+ if (pinterestLink) {
196
+ formData.pinterest_link = pinterestLink;
197
+ }
198
+ if (operation === 'uploadVideo') {
199
+ const pinterestCoverImageUrl = ctx.node.getNodeParameter('pinterestCoverImageUrl', ctx.itemIndex, '');
200
+ const pinterestCoverImageContentType = ctx.node.getNodeParameter('pinterestCoverImageContentType', ctx.itemIndex, '');
201
+ const pinterestCoverImageData = ctx.node.getNodeParameter('pinterestCoverImageData', ctx.itemIndex, '');
202
+ const pinterestCoverImageKeyFrameTime = ctx.node.getNodeParameter('pinterestCoverImageKeyFrameTime', ctx.itemIndex, 0);
203
+ if (pinterestCoverImageUrl) {
204
+ formData.pinterest_cover_image_url = pinterestCoverImageUrl;
205
+ }
206
+ else if (pinterestCoverImageContentType && pinterestCoverImageData) {
207
+ formData.pinterest_cover_image_content_type = pinterestCoverImageContentType;
208
+ formData.pinterest_cover_image_data = pinterestCoverImageData;
209
+ }
210
+ else if (pinterestCoverImageKeyFrameTime !== undefined) {
211
+ formData.pinterest_cover_image_key_frame_time = pinterestCoverImageKeyFrameTime;
212
+ }
213
+ if (pinterestLink) {
214
+ formData.pinterest_link = pinterestLink;
215
+ }
216
+ }
217
+ };
218
+ const applyLinkedinOptions = (ctx, operation, formData) => {
219
+ const selection = ctx.node.getNodeParameter('targetLinkedinPageId', ctx.itemIndex, '');
220
+ const resolvedValue = selection === MANUAL_LINKEDIN_VALUE
221
+ ? ctx.node.getNodeParameter('targetLinkedinPageIdManual', ctx.itemIndex)
222
+ : selection;
223
+ if (resolvedValue && resolvedValue !== 'me') {
224
+ const match = resolvedValue.match(/(\d+)$/);
225
+ formData.target_linkedin_page_id = match ? match[1] : resolvedValue;
226
+ }
227
+ if (operation === 'uploadPhotos') {
228
+ const linkedinVisibility = ctx.node.getNodeParameter('linkedinVisibility', ctx.itemIndex, 'PUBLIC');
229
+ if (linkedinVisibility === 'PUBLIC') {
230
+ formData.visibility = 'PUBLIC';
231
+ }
232
+ }
233
+ else if (operation === 'uploadVideo') {
234
+ const linkedinVisibility = ctx.node.getNodeParameter('linkedinVisibility', ctx.itemIndex, 'PUBLIC');
235
+ formData.visibility = linkedinVisibility;
236
+ }
237
+ };
238
+ const applyFacebookOptions = (ctx, operation, formData) => {
239
+ const selection = ctx.node.getNodeParameter('facebookPageId', ctx.itemIndex);
240
+ const resolvedValue = selection === MANUAL_FACEBOOK_VALUE
241
+ ? ctx.node.getNodeParameter('facebookPageIdManual', ctx.itemIndex)
242
+ : selection;
243
+ formData.facebook_page_id = resolvedValue;
244
+ if (operation === 'uploadVideo') {
245
+ const facebookVideoState = ctx.node.getNodeParameter('facebookVideoState', ctx.itemIndex, '');
246
+ const facebookMediaType = ctx.node.getNodeParameter('facebookMediaType', ctx.itemIndex, '');
247
+ if (facebookVideoState) {
248
+ formData.video_state = facebookVideoState;
249
+ }
250
+ if (facebookMediaType) {
251
+ formData.facebook_media_type = facebookMediaType;
252
+ }
253
+ }
254
+ else if (operation === 'uploadText') {
255
+ const facebookLink = ctx.node.getNodeParameter('facebookLink', ctx.itemIndex, '');
256
+ if (facebookLink) {
257
+ formData.facebook_link_url = facebookLink;
258
+ }
259
+ }
260
+ };
261
+ const applyTiktokOptions = (ctx, operation, formData) => {
262
+ if (operation === 'uploadPhotos') {
263
+ const autoAddMusic = ctx.node.getNodeParameter('tiktokAutoAddMusic', ctx.itemIndex, false);
264
+ const disableComment = ctx.node.getNodeParameter('tiktokDisableComment', ctx.itemIndex, false);
265
+ const brandContentToggle = ctx.node.getNodeParameter('brand_content_toggle', ctx.itemIndex, false);
266
+ const brandOrganicToggle = ctx.node.getNodeParameter('brand_organic_toggle', ctx.itemIndex, false);
267
+ const photoCoverIndex = ctx.node.getNodeParameter('tiktokPhotoCoverIndex', ctx.itemIndex, 0);
268
+ const photoDescription = ctx.node.getNodeParameter('tiktokPhotoDescription', ctx.itemIndex, '');
269
+ formData.auto_add_music = String(autoAddMusic);
270
+ formData.disable_comment = String(disableComment);
271
+ formData.brand_content_toggle = String(brandContentToggle);
272
+ formData.brand_organic_toggle = String(brandOrganicToggle);
273
+ formData.photo_cover_index = photoCoverIndex;
274
+ if (photoDescription && formData.description === undefined) {
275
+ formData.description = photoDescription;
276
+ }
277
+ }
278
+ else if (operation === 'uploadVideo') {
279
+ const privacyLevel = ctx.node.getNodeParameter('tiktokPrivacyLevel', ctx.itemIndex, '');
280
+ const disableDuet = ctx.node.getNodeParameter('tiktokDisableDuet', ctx.itemIndex, false);
281
+ const disableComment = ctx.node.getNodeParameter('tiktokDisableComment', ctx.itemIndex, false);
282
+ const disableStitch = ctx.node.getNodeParameter('tiktokDisableStitch', ctx.itemIndex, false);
283
+ const coverTimestamp = ctx.node.getNodeParameter('tiktokCoverTimestamp', ctx.itemIndex, 1000);
284
+ const brandContentToggle = ctx.node.getNodeParameter('brand_content_toggle', ctx.itemIndex, false);
285
+ const brandOrganicToggle = ctx.node.getNodeParameter('brand_organic_toggle', ctx.itemIndex, false);
286
+ const isAigc = ctx.node.getNodeParameter('tiktokIsAigc', ctx.itemIndex, false);
287
+ const postMode = ctx.node.getNodeParameter('tiktokPostMode', ctx.itemIndex, '');
288
+ if (privacyLevel)
289
+ formData.privacy_level = privacyLevel;
290
+ formData.disable_duet = String(disableDuet);
291
+ formData.disable_comment = String(disableComment);
292
+ formData.disable_stitch = String(disableStitch);
293
+ formData.cover_timestamp = coverTimestamp;
294
+ formData.brand_content_toggle = String(brandContentToggle);
295
+ formData.brand_organic_toggle = String(brandOrganicToggle);
296
+ formData.is_aigc = String(isAigc);
297
+ if (postMode)
298
+ formData.post_mode = postMode;
299
+ }
300
+ };
301
+ const applyInstagramOptions = (ctx, operation, formData) => {
302
+ const providedMediaType = ctx.node.getNodeParameter('instagramMediaType', ctx.itemIndex, '');
303
+ let finalMediaType = providedMediaType;
304
+ if (operation === 'uploadPhotos') {
305
+ if (!['IMAGE', 'STORIES'].includes(providedMediaType)) {
306
+ finalMediaType = 'IMAGE';
307
+ }
308
+ }
309
+ else if (operation === 'uploadVideo') {
310
+ if (!['REELS', 'STORIES'].includes(providedMediaType)) {
311
+ finalMediaType = 'REELS';
312
+ }
313
+ }
314
+ if (finalMediaType) {
315
+ formData.media_type = finalMediaType;
316
+ }
317
+ if (operation === 'uploadVideo') {
318
+ const shareToFeed = ctx.node.getNodeParameter('instagramShareToFeed', ctx.itemIndex, true);
319
+ const collaborators = ctx.node.getNodeParameter('instagramCollaborators', ctx.itemIndex, '');
320
+ const coverUrl = ctx.node.getNodeParameter('instagramCoverUrl', ctx.itemIndex, '');
321
+ const audioName = ctx.node.getNodeParameter('instagramAudioName', ctx.itemIndex, '');
322
+ const userTags = ctx.node.getNodeParameter('instagramUserTags', ctx.itemIndex, '');
323
+ const locationId = ctx.node.getNodeParameter('instagramLocationId', ctx.itemIndex, '');
324
+ const thumbOffset = ctx.node.getNodeParameter('instagramThumbOffset', ctx.itemIndex, '');
325
+ formData.share_to_feed = String(shareToFeed);
326
+ if (collaborators)
327
+ formData.collaborators = collaborators;
328
+ if (coverUrl)
329
+ formData.cover_url = coverUrl;
330
+ if (audioName)
331
+ formData.audio_name = audioName;
332
+ if (userTags)
333
+ formData.user_tags = userTags;
334
+ if (locationId)
335
+ formData.location_id = locationId;
336
+ if (thumbOffset)
337
+ formData.thumb_offset = thumbOffset;
338
+ }
339
+ };
340
+ const applyYoutubeOptions = async (ctx, formData) => {
341
+ const tagsRaw = ctx.node.getNodeParameter('youtubeTags', ctx.itemIndex, '');
342
+ const categoryId = ctx.node.getNodeParameter('youtubeCategoryId', ctx.itemIndex, '');
343
+ const privacyStatus = ctx.node.getNodeParameter('youtubePrivacyStatus', ctx.itemIndex, '');
344
+ const embeddable = ctx.node.getNodeParameter('youtubeEmbeddable', ctx.itemIndex, true);
345
+ const license = ctx.node.getNodeParameter('youtubeLicense', ctx.itemIndex, '');
346
+ const publicStatsViewable = ctx.node.getNodeParameter('youtubePublicStatsViewable', ctx.itemIndex, true);
347
+ const madeForKids = ctx.node.getNodeParameter('youtubeMadeForKids', ctx.itemIndex, false);
348
+ const thumbnailInput = ctx.node.getNodeParameter('youtubeThumbnail', ctx.itemIndex, '');
349
+ if (tagsRaw)
350
+ formData['tags[]'] = ensureArrayFromCommaSeparated(tagsRaw);
351
+ if (categoryId)
352
+ formData.categoryId = categoryId;
353
+ if (privacyStatus)
354
+ formData.privacyStatus = privacyStatus;
355
+ formData.embeddable = String(embeddable);
356
+ if (license)
357
+ formData.license = license;
358
+ formData.publicStatsViewable = String(publicStatsViewable);
359
+ formData.madeForKids = String(madeForKids);
360
+ if (thumbnailInput) {
361
+ if (thumbnailInput.toLowerCase().startsWith('http://') || thumbnailInput.toLowerCase().startsWith('https://')) {
362
+ formData.thumbnail_url = thumbnailInput;
363
+ }
364
+ else {
365
+ const thumbnailBinary = await getBinaryFieldFromItem(ctx, thumbnailInput, 'Binary data for YouTube thumbnail property');
366
+ formData.thumbnail = thumbnailBinary;
367
+ }
368
+ }
369
+ const selfDeclaredMadeForKids = ctx.node.getNodeParameter('youtubeSelfDeclaredMadeForKids', ctx.itemIndex, false);
370
+ const containsSyntheticMedia = ctx.node.getNodeParameter('youtubeContainsSyntheticMedia', ctx.itemIndex, false);
371
+ const defaultLanguage = ctx.node.getNodeParameter('youtubeDefaultLanguage', ctx.itemIndex, '');
372
+ const defaultAudioLanguage = ctx.node.getNodeParameter('youtubeDefaultAudioLanguage', ctx.itemIndex, '');
373
+ const allowedCountries = ctx.node.getNodeParameter('youtubeAllowedCountries', ctx.itemIndex, '');
374
+ const blockedCountries = ctx.node.getNodeParameter('youtubeBlockedCountries', ctx.itemIndex, '');
375
+ const hasPaidProductPlacement = ctx.node.getNodeParameter('youtubeHasPaidProductPlacement', ctx.itemIndex, false);
376
+ const recordingDate = ctx.node.getNodeParameter('youtubeRecordingDate', ctx.itemIndex, '');
377
+ formData.selfDeclaredMadeForKids = String(selfDeclaredMadeForKids);
378
+ formData.containsSyntheticMedia = String(containsSyntheticMedia);
379
+ if (defaultLanguage)
380
+ formData.defaultLanguage = defaultLanguage;
381
+ if (defaultAudioLanguage)
382
+ formData.defaultAudioLanguage = defaultAudioLanguage;
383
+ if (allowedCountries)
384
+ formData.allowedCountries = allowedCountries;
385
+ if (blockedCountries)
386
+ formData.blockedCountries = blockedCountries;
387
+ formData.hasPaidProductPlacement = String(hasPaidProductPlacement);
388
+ if (recordingDate)
389
+ formData.recordingDate = recordingDate;
390
+ };
391
+ const validateXPollConfiguration = (ctx, operation, formData) => {
392
+ if (operation !== 'uploadText') {
393
+ return;
394
+ }
395
+ const pollOptionsRaw = ctx.node.getNodeParameter('xPollOptions', ctx.itemIndex, '');
396
+ const hasPollOptions = pollOptionsRaw.trim().length > 0;
397
+ if (!hasPollOptions) {
398
+ return;
399
+ }
400
+ const conflictingFields = [];
401
+ const cardUri = ctx.node.getNodeParameter('xCardUri', ctx.itemIndex, '');
402
+ const quoteTweetId = ctx.node.getNodeParameter('xQuoteTweetId', ctx.itemIndex, '');
403
+ const directMessageDeepLink = ctx.node.getNodeParameter('xDirectMessageDeepLink', ctx.itemIndex, '');
404
+ if (cardUri.trim().length > 0)
405
+ conflictingFields.push('X Card URI');
406
+ if (quoteTweetId.trim().length > 0)
407
+ conflictingFields.push('X Quote Tweet ID');
408
+ if (directMessageDeepLink.trim().length > 0)
409
+ conflictingFields.push('X Direct Message Deep Link');
410
+ if (conflictingFields.length > 0) {
411
+ throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options cannot be used with: ${conflictingFields.join(', ')}. These fields are mutually exclusive.`);
412
+ }
413
+ const pollOptions = ensureArrayFromCommaSeparated(pollOptionsRaw);
414
+ if (pollOptions.length < 2 || pollOptions.length > 4) {
415
+ throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options must contain between 2 and 4 non-empty options. Found: ${pollOptions.length}`);
416
+ }
417
+ const invalidOptions = pollOptions.filter(option => option.length > 25);
418
+ if (invalidOptions.length > 0) {
419
+ throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Options cannot exceed 25 characters each. Invalid options: ${invalidOptions.join(', ')}`);
420
+ }
421
+ const pollDuration = ctx.node.getNodeParameter('xPollDuration', ctx.itemIndex, 1440);
422
+ if (pollDuration < 5 || pollDuration > 10080) {
423
+ throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `X Poll Duration must be between 5 and 10080 minutes (5 minutes to 7 days). Provided: ${pollDuration}`);
424
+ }
425
+ formData['poll_options[]'] = pollOptions;
426
+ formData.poll_duration = pollDuration;
427
+ const pollReplySettings = ctx.node.getNodeParameter('xPollReplySettings', ctx.itemIndex, 'following');
428
+ formData.poll_reply_settings = pollReplySettings;
429
+ };
430
+ const applyXOptions = (ctx, operation, formData) => {
431
+ const quoteTweetId = ctx.node.getNodeParameter('xQuoteTweetId', ctx.itemIndex, '');
432
+ const geoPlaceId = ctx.node.getNodeParameter('xGeoPlaceId', ctx.itemIndex, '');
433
+ const forSuperFollowersOnly = ctx.node.getNodeParameter('xForSuperFollowersOnly', ctx.itemIndex, false);
434
+ const communityId = ctx.node.getNodeParameter('xCommunityId', ctx.itemIndex, '');
435
+ const shareWithFollowers = ctx.node.getNodeParameter('xShareWithFollowers', ctx.itemIndex, false);
436
+ const directMessageDeepLink = ctx.node.getNodeParameter('xDirectMessageDeepLink', ctx.itemIndex, '');
437
+ const cardUri = ctx.node.getNodeParameter('xCardUri', ctx.itemIndex, '');
438
+ if (quoteTweetId)
439
+ formData.quote_tweet_id = quoteTweetId;
440
+ if (geoPlaceId)
441
+ formData.geo_place_id = geoPlaceId;
442
+ if (forSuperFollowersOnly)
443
+ formData.for_super_followers_only = String(forSuperFollowersOnly);
444
+ if (communityId)
445
+ formData.community_id = communityId;
446
+ if (shareWithFollowers)
447
+ formData.share_with_followers = String(shareWithFollowers);
448
+ if (directMessageDeepLink)
449
+ formData.direct_message_deep_link = directMessageDeepLink;
450
+ if (cardUri)
451
+ formData.card_uri = cardUri;
452
+ if (operation === 'uploadText') {
453
+ const postUrl = ctx.node.getNodeParameter('xPostUrlText', ctx.itemIndex, '');
454
+ const replySettings = ctx.node.getNodeParameter('xReplySettings', ctx.itemIndex, 'everyone');
455
+ if (postUrl)
456
+ formData.post_url = postUrl;
457
+ if (replySettings && replySettings !== 'everyone')
458
+ formData.reply_settings = replySettings;
459
+ validateXPollConfiguration(ctx, operation, formData);
460
+ const xLongTextAsPost = ctx.node.getNodeParameter('xLongTextAsPost', ctx.itemIndex, false);
461
+ if (xLongTextAsPost) {
462
+ formData.x_long_text_as_post = String(xLongTextAsPost);
463
+ }
464
+ delete formData.nullcast;
465
+ delete formData.place_id;
466
+ }
467
+ else {
468
+ const taggedUserIds = ctx.node.getNodeParameter('xTaggedUserIds', ctx.itemIndex, '');
469
+ const replySettings = ctx.node.getNodeParameter('xReplySettings', ctx.itemIndex, 'everyone');
470
+ const nullcast = ctx.node.getNodeParameter('xNullcastVideo', ctx.itemIndex, false);
471
+ if (taggedUserIds) {
472
+ formData['tagged_user_ids[]'] = ensureArrayFromCommaSeparated(taggedUserIds);
473
+ }
474
+ if (replySettings && replySettings !== 'everyone')
475
+ formData.reply_settings = replySettings;
476
+ formData.nullcast = String(nullcast);
477
+ if (operation === 'uploadVideo') {
478
+ const xLongTextAsPost = ctx.node.getNodeParameter('xLongTextAsPost', ctx.itemIndex, false);
479
+ if (xLongTextAsPost) {
480
+ formData.x_long_text_as_post = String(xLongTextAsPost);
481
+ }
482
+ }
483
+ const xPlaceIdVideo = ctx.node.getNodeParameter('xPlaceIdVideo', ctx.itemIndex, '');
484
+ if (operation === 'uploadVideo' && xPlaceIdVideo) {
485
+ formData.place_id = xPlaceIdVideo;
486
+ }
487
+ }
488
+ };
489
+ const applyThreadsOptions = (ctx, formData) => {
490
+ const threadsLongTextAsPost = ctx.node.getNodeParameter('threadsLongTextAsPost', ctx.itemIndex, false);
491
+ if (threadsLongTextAsPost) {
492
+ formData.threads_long_text_as_post = String(threadsLongTextAsPost);
493
+ }
494
+ };
495
+ const applyRedditOptions = (ctx, formData) => {
496
+ const subreddit = ctx.node.getNodeParameter('redditSubreddit', ctx.itemIndex);
497
+ const flairId = ctx.node.getNodeParameter('redditFlairId', ctx.itemIndex, '');
498
+ formData.subreddit = subreddit;
499
+ if (flairId) {
500
+ formData.flair_id = flairId;
501
+ }
502
+ };
503
+ const applyUploadPlatformOptions = async (ctx, operation, prep) => {
504
+ const { formData, platforms } = prep;
505
+ if (platforms.includes('pinterest')) {
506
+ applyPinterestOptions(ctx, operation, formData);
507
+ }
508
+ if (platforms.includes('linkedin')) {
509
+ applyLinkedinOptions(ctx, operation, formData);
510
+ }
511
+ if (platforms.includes('facebook')) {
512
+ applyFacebookOptions(ctx, operation, formData);
513
+ }
514
+ if (platforms.includes('tiktok')) {
515
+ applyTiktokOptions(ctx, operation, formData);
516
+ }
517
+ if (platforms.includes('instagram')) {
518
+ applyInstagramOptions(ctx, operation, formData);
519
+ }
520
+ if (platforms.includes('youtube') && operation === 'uploadVideo') {
521
+ await applyYoutubeOptions(ctx, formData);
522
+ }
523
+ if (platforms.includes('x')) {
524
+ applyXOptions(ctx, operation, formData);
525
+ }
526
+ if (operation === 'uploadText' && platforms.includes('threads')) {
527
+ applyThreadsOptions(ctx, formData);
528
+ }
529
+ if (operation === 'uploadText' && platforms.includes('reddit')) {
530
+ applyRedditOptions(ctx, formData);
531
+ }
532
+ };
533
+ const buildUploadPhotosRequest = async (ctx) => {
534
+ const prep = prepareUploadBase(ctx, 'uploadPhotos');
535
+ const photosInput = ctx.node.getNodeParameter('photos', ctx.itemIndex, '');
536
+ let photosToProcess = [];
537
+ if (Array.isArray(photosInput)) {
538
+ photosToProcess = photosInput.filter(item => typeof item === 'string' && item.trim().length > 0).map(item => item.trim());
539
+ }
540
+ else if (typeof photosInput === 'string') {
541
+ photosToProcess = ensureArrayFromCommaSeparated(photosInput);
542
+ }
543
+ const photoArray = [];
544
+ for (const photoItem of photosToProcess) {
545
+ if (photoItem.toLowerCase().startsWith('http://') || photoItem.toLowerCase().startsWith('https://')) {
546
+ photoArray.push(photoItem);
547
+ continue;
548
+ }
549
+ const binaryField = await getBinaryFieldFromItem(ctx, photoItem, 'Binary data for property');
550
+ photoArray.push(binaryField);
551
+ }
552
+ if (photoArray.length > 0) {
553
+ prep.formData['photos[]'] = photoArray;
554
+ }
555
+ await applyUploadPlatformOptions(ctx, 'uploadPhotos', prep);
556
+ return {
557
+ endpoint: '/upload_photos',
558
+ method: 'POST',
559
+ formData: prep.formData,
560
+ isUploadOperation: true,
561
+ waitForCompletion: prep.waitForCompletion,
562
+ pollInterval: prep.pollInterval,
563
+ pollTimeout: prep.pollTimeout,
564
+ };
565
+ };
566
+ const buildUploadVideoRequest = async (ctx) => {
567
+ const prep = prepareUploadBase(ctx, 'uploadVideo');
568
+ const videoInput = ctx.node.getNodeParameter('video', ctx.itemIndex, '');
569
+ if (videoInput) {
570
+ if (videoInput.toLowerCase().startsWith('http://') || videoInput.toLowerCase().startsWith('https://')) {
571
+ prep.formData.video = videoInput;
572
+ }
573
+ else {
574
+ const binaryField = await getBinaryFieldFromItem(ctx, videoInput, 'Binary data for video property');
575
+ prep.formData.video = binaryField;
576
+ }
577
+ }
578
+ await applyUploadPlatformOptions(ctx, 'uploadVideo', prep);
579
+ return {
580
+ endpoint: '/upload',
581
+ method: 'POST',
582
+ formData: prep.formData,
583
+ isUploadOperation: true,
584
+ waitForCompletion: prep.waitForCompletion,
585
+ pollInterval: prep.pollInterval,
586
+ pollTimeout: prep.pollTimeout,
587
+ };
588
+ };
589
+ const buildUploadTextRequest = async (ctx) => {
590
+ const prep = prepareUploadBase(ctx, 'uploadText');
591
+ await applyUploadPlatformOptions(ctx, 'uploadText', prep);
592
+ return {
593
+ endpoint: '/upload_text',
594
+ method: 'POST',
595
+ formData: prep.formData,
596
+ isUploadOperation: true,
597
+ waitForCompletion: prep.waitForCompletion,
598
+ pollInterval: prep.pollInterval,
599
+ pollTimeout: prep.pollTimeout,
600
+ };
601
+ };
602
+ const buildMonitoringRequest = (ctx) => {
603
+ switch (ctx.operation) {
604
+ case 'getStatus': {
605
+ const requestId = ctx.node.getNodeParameter('requestId', ctx.itemIndex);
606
+ return {
607
+ endpoint: '/uploadposts/status',
608
+ method: 'GET',
609
+ qs: { request_id: requestId },
610
+ isUploadOperation: false,
611
+ waitForCompletion: false,
612
+ };
613
+ }
614
+ case 'getHistory': {
615
+ const page = ctx.node.getNodeParameter('historyPage', ctx.itemIndex, 1);
616
+ const limit = ctx.node.getNodeParameter('historyLimit', ctx.itemIndex, 20);
617
+ return {
618
+ endpoint: '/uploadposts/history',
619
+ method: 'GET',
620
+ qs: { page, limit },
621
+ isUploadOperation: false,
622
+ waitForCompletion: false,
623
+ };
624
+ }
625
+ case 'getAnalytics': {
626
+ const profileUsername = ctx.node.getNodeParameter('analyticsProfileUsername', ctx.itemIndex);
627
+ const analyticsPlatforms = ctx.node.getNodeParameter('analyticsPlatforms', ctx.itemIndex, []);
628
+ const qs = {};
629
+ if (Array.isArray(analyticsPlatforms) && analyticsPlatforms.length > 0) {
630
+ qs.platforms = analyticsPlatforms.join(',');
631
+ }
632
+ return {
633
+ endpoint: `/analytics/${encodeURIComponent(profileUsername)}`,
634
+ method: 'GET',
635
+ qs,
636
+ isUploadOperation: false,
637
+ waitForCompletion: false,
638
+ };
639
+ }
640
+ case 'listScheduled': {
641
+ return {
642
+ endpoint: '/uploadposts/schedule',
643
+ method: 'GET',
644
+ isUploadOperation: false,
645
+ waitForCompletion: false,
646
+ };
647
+ }
648
+ case 'cancelScheduled': {
649
+ const jobId = ctx.node.getNodeParameter('scheduleJobId', ctx.itemIndex);
650
+ return {
651
+ endpoint: `/uploadposts/schedule/${jobId}`,
652
+ method: 'DELETE',
653
+ isUploadOperation: false,
654
+ waitForCompletion: false,
655
+ };
656
+ }
657
+ case 'editScheduled': {
658
+ const jobId = ctx.node.getNodeParameter('scheduleJobId', ctx.itemIndex);
659
+ const newScheduledDateRaw = ctx.node.getNodeParameter('newScheduledDate', ctx.itemIndex, '');
660
+ const normalizedDate = normalizeDateInput(newScheduledDateRaw);
661
+ const body = {};
662
+ if (normalizedDate) {
663
+ body.scheduled_date = normalizedDate;
664
+ }
665
+ return {
666
+ endpoint: `/uploadposts/schedule/${jobId}`,
667
+ method: 'POST',
668
+ body,
669
+ isUploadOperation: false,
670
+ waitForCompletion: false,
671
+ };
672
+ }
673
+ default:
674
+ throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported monitoring operation: ${ctx.operation}`, {
675
+ itemIndex: ctx.itemIndex,
676
+ });
677
+ }
678
+ };
679
+ const buildUserRequest = (ctx) => {
680
+ switch (ctx.operation) {
681
+ case 'listUsers':
682
+ return {
683
+ endpoint: '/uploadposts/users',
684
+ method: 'GET',
685
+ isUploadOperation: false,
686
+ waitForCompletion: false,
687
+ };
688
+ case 'createUser': {
689
+ const username = ctx.node.getNodeParameter('newUser', ctx.itemIndex);
690
+ return {
691
+ endpoint: '/uploadposts/users',
692
+ method: 'POST',
693
+ body: { username },
694
+ isUploadOperation: false,
695
+ waitForCompletion: false,
696
+ };
697
+ }
698
+ case 'deleteUser': {
699
+ const username = ctx.node.getNodeParameter('deleteUserId', ctx.itemIndex);
700
+ return {
701
+ endpoint: '/uploadposts/users',
702
+ method: 'DELETE',
703
+ body: { username },
704
+ isUploadOperation: false,
705
+ waitForCompletion: false,
706
+ };
707
+ }
708
+ case 'generateJwt': {
709
+ const username = getUserForOperation(ctx, true);
710
+ const redirectUrl = ctx.node.getNodeParameter('redirectUrl', ctx.itemIndex, '');
711
+ const logoImage = ctx.node.getNodeParameter('logoImage', ctx.itemIndex, '');
712
+ const redirectButtonText = ctx.node.getNodeParameter('redirectButtonText', ctx.itemIndex, '');
713
+ const platforms = ctx.node.getNodeParameter('jwtPlatforms', ctx.itemIndex, []);
714
+ const body = { username };
715
+ if (redirectUrl)
716
+ body.redirect_url = redirectUrl;
717
+ if (logoImage)
718
+ body.logo_image = logoImage;
719
+ if (redirectButtonText)
720
+ body.redirect_button_text = redirectButtonText;
721
+ if (Array.isArray(platforms) && platforms.length > 0)
722
+ body.platforms = platforms;
723
+ return {
724
+ endpoint: '/uploadposts/users/generate-jwt',
725
+ method: 'POST',
726
+ body,
727
+ isUploadOperation: false,
728
+ waitForCompletion: false,
729
+ };
730
+ }
731
+ case 'validateJwt': {
732
+ const jwt = ctx.node.getNodeParameter('jwtToken', ctx.itemIndex);
733
+ return {
734
+ endpoint: '/uploadposts/users/validate-jwt',
735
+ method: 'POST',
736
+ body: { jwt },
737
+ headers: { Authorization: `Bearer ${jwt}` },
738
+ isUploadOperation: false,
739
+ waitForCompletion: false,
740
+ };
741
+ }
742
+ default:
743
+ throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported user operation: ${ctx.operation}`, {
744
+ itemIndex: ctx.itemIndex,
745
+ });
746
+ }
747
+ };
748
+ const buildRequestConfig = async (ctx) => {
749
+ if (ctx.operation === 'uploadPhotos') {
750
+ return buildUploadPhotosRequest(ctx);
751
+ }
752
+ if (ctx.operation === 'uploadVideo') {
753
+ return buildUploadVideoRequest(ctx);
754
+ }
755
+ if (ctx.operation === 'uploadText') {
756
+ return buildUploadTextRequest(ctx);
757
+ }
758
+ const resource = ctx.node.getNodeParameter('resource', ctx.itemIndex);
759
+ if (resource === 'monitoring') {
760
+ return buildMonitoringRequest(ctx);
761
+ }
762
+ if (resource === 'users') {
763
+ return buildUserRequest(ctx);
764
+ }
765
+ throw new n8n_workflow_1.NodeOperationError(ctx.node.getNode(), `Unsupported operation: ${ctx.operation}`, {
766
+ itemIndex: ctx.itemIndex,
767
+ });
768
+ };
769
+ const buildNativeFormData = (payload, node) => {
770
+ if (typeof FormData === 'undefined') {
771
+ throw new n8n_workflow_1.NodeOperationError(node.getNode(), 'FormData is not supported in this runtime environment');
772
+ }
773
+ const form = new FormData();
774
+ for (const [key, value] of Object.entries(payload)) {
775
+ if (Array.isArray(value)) {
776
+ value.forEach(item => appendValue(form, key, item));
777
+ }
778
+ else {
779
+ appendValue(form, key, value);
780
+ }
781
+ }
782
+ return form;
783
+ };
784
+ const appendValue = (form, key, value) => {
785
+ if (isBinaryFormField(value)) {
786
+ appendBinaryValue(form, key, value);
787
+ }
788
+ else {
789
+ form.append(key, value);
790
+ }
791
+ };
792
+ const appendBinaryValue = (form, key, field) => {
793
+ var _a, _b;
794
+ const { value, options } = field;
795
+ if (typeof value === 'string') {
796
+ form.append(key, value);
797
+ return;
798
+ }
799
+ const filename = (_a = options === null || options === void 0 ? void 0 : options.filename) !== null && _a !== void 0 ? _a : 'upload.bin';
800
+ const contentType = (_b = options === null || options === void 0 ? void 0 : options.contentType) !== null && _b !== void 0 ? _b : 'application/octet-stream';
801
+ if (typeof Blob !== 'undefined') {
802
+ const blob = new Blob([value], { type: contentType });
803
+ form.append(key, blob, filename);
804
+ return;
805
+ }
806
+ form.append(key, value, { filename, contentType });
807
+ };
808
+ const pollUploadStatus = async (node, requestId, pollInterval, pollTimeout) => {
809
+ const start = Date.now();
810
+ let finalData = { success: false, message: 'Polling timed out', request_id: requestId };
811
+ while (true) {
812
+ await (0, n8n_workflow_1.sleep)(Math.max(1, pollInterval) * 1000);
813
+ if (Date.now() - start > Math.max(5, pollTimeout) * 1000) {
814
+ break;
815
+ }
816
+ const statusOptions = {
817
+ url: `${API_BASE_URL}/uploadposts/status`,
818
+ method: 'GET',
819
+ qs: { request_id: requestId },
820
+ json: true,
821
+ };
822
+ const statusData = await node.helpers.httpRequestWithAuthentication.call(node, 'uploadPostApi', statusOptions);
823
+ finalData = statusData;
824
+ const statusValue = (statusData && statusData.status);
825
+ if ((statusData && statusData.success === true) ||
826
+ (statusValue && ['success', 'completed', 'failed', 'error'].includes(statusValue.toLowerCase()))) {
827
+ break;
828
+ }
829
+ }
830
+ return finalData;
831
+ };
9
832
  class UploadPost {
10
833
  constructor() {
11
834
  this.description = {
@@ -1532,20 +2355,17 @@ class UploadPost {
1532
2355
  },
1533
2356
  async getFacebookPages() {
1534
2357
  try {
1535
- const credentials = await this.getCredentials('uploadPostApi');
1536
- const apiKey = credentials.apiKey;
1537
2358
  const profile = this.getCurrentNodeParameter('user') || '';
1538
2359
  const qs = {};
1539
2360
  if (profile)
1540
2361
  qs.profile = profile;
1541
2362
  const options = {
1542
- uri: 'https://api.upload-post.com/api/uploadposts/facebook/pages',
2363
+ url: 'https://api.upload-post.com/api/uploadposts/facebook/pages',
1543
2364
  method: 'GET',
1544
- headers: { Authorization: `ApiKey ${apiKey}` },
1545
2365
  qs,
1546
2366
  json: true,
1547
2367
  };
1548
- const resp = await this.helpers.request(options);
2368
+ const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
1549
2369
  const pages = (resp && (resp.pages || resp.data || []));
1550
2370
  const pageOptions = (pages || []).map(p => ({ name: p.name ? `${p.name} (${p.id})` : p.id, value: p.id }));
1551
2371
  return [
@@ -1561,20 +2381,17 @@ class UploadPost {
1561
2381
  },
1562
2382
  async getLinkedinPages() {
1563
2383
  try {
1564
- const credentials = await this.getCredentials('uploadPostApi');
1565
- const apiKey = credentials.apiKey;
1566
2384
  const profile = this.getCurrentNodeParameter('user') || '';
1567
2385
  const qs = {};
1568
2386
  if (profile)
1569
2387
  qs.profile = profile;
1570
2388
  const options = {
1571
- uri: 'https://api.upload-post.com/api/uploadposts/linkedin/pages',
2389
+ url: 'https://api.upload-post.com/api/uploadposts/linkedin/pages',
1572
2390
  method: 'GET',
1573
- headers: { Authorization: `ApiKey ${apiKey}` },
1574
2391
  qs,
1575
2392
  json: true,
1576
2393
  };
1577
- const resp = await this.helpers.request(options);
2394
+ const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
1578
2395
  const pages = (resp && (resp.pages || resp.data || []));
1579
2396
  const pageOptions = (pages || []).map(p => ({ name: p.name ? `${p.name} (${p.id})` : p.id, value: p.id }));
1580
2397
  return [
@@ -1592,20 +2409,17 @@ class UploadPost {
1592
2409
  },
1593
2410
  async getPinterestBoards() {
1594
2411
  try {
1595
- const credentials = await this.getCredentials('uploadPostApi');
1596
- const apiKey = credentials.apiKey;
1597
2412
  const profile = this.getCurrentNodeParameter('user') || '';
1598
2413
  const qs = {};
1599
2414
  if (profile)
1600
2415
  qs.profile = profile;
1601
2416
  const options = {
1602
- uri: 'https://api.upload-post.com/api/uploadposts/pinterest/boards',
2417
+ url: 'https://api.upload-post.com/api/uploadposts/pinterest/boards',
1603
2418
  method: 'GET',
1604
- headers: { Authorization: `ApiKey ${apiKey}` },
1605
2419
  qs,
1606
2420
  json: true,
1607
2421
  };
1608
- const resp = await this.helpers.request(options);
2422
+ const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
1609
2423
  const boards = (resp && (resp.boards || resp.data || []));
1610
2424
  const boardOptions = (boards || []).map(b => ({ name: b.name ? `${b.name} (${b.id})` : b.id, value: b.id }));
1611
2425
  return [
@@ -1621,15 +2435,12 @@ class UploadPost {
1621
2435
  },
1622
2436
  async getUserProfiles() {
1623
2437
  try {
1624
- const credentials = await this.getCredentials('uploadPostApi');
1625
- const apiKey = credentials.apiKey;
1626
2438
  const options = {
1627
- uri: 'https://api.upload-post.com/api/uploadposts/users',
2439
+ url: 'https://api.upload-post.com/api/uploadposts/users',
1628
2440
  method: 'GET',
1629
- headers: { Authorization: `ApiKey ${apiKey}` },
1630
2441
  json: true,
1631
2442
  };
1632
- const resp = await this.helpers.request(options);
2443
+ const resp = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', options);
1633
2444
  const profiles = (resp && resp.profiles);
1634
2445
  const profileOptions = (profiles || []).map(profile => {
1635
2446
  const connectedPlatforms = Object.keys(profile.social_accounts || {})
@@ -1658,742 +2469,55 @@ class UploadPost {
1658
2469
  };
1659
2470
  }
1660
2471
  async execute() {
1661
- var _a, _b, _c;
2472
+ var _a, _b;
1662
2473
  const items = this.getInputData();
1663
2474
  const returnData = [];
1664
- for (let i = 0; i < items.length; i++) {
1665
- const operation = this.getNodeParameter('operation', i);
1666
- const isUploadOperation = ['uploadPhotos', 'uploadVideo', 'uploadText'].includes(operation);
1667
- const needsUser = isUploadOperation || operation === 'generateJwt';
1668
- const userSelection = needsUser ? this.getNodeParameter('user', i) : '';
1669
- const userManualValue = needsUser && userSelection === MANUAL_USER_VALUE
1670
- ? this.getNodeParameter('userManual', i)
1671
- : '';
1672
- const user = needsUser
1673
- ? (userSelection === MANUAL_USER_VALUE ? userManualValue : userSelection)
1674
- : '';
1675
- let platforms = isUploadOperation ? this.getNodeParameter('platform', i) : [];
1676
- const title = isUploadOperation ? this.getNodeParameter('title', i) : '';
1677
- let endpoint = '';
1678
- let method = 'POST';
1679
- const formData = {};
1680
- const qs = {};
1681
- const body = {};
1682
- if (isUploadOperation) {
1683
- formData.user = user;
1684
- formData.title = title;
1685
- const scheduledDate = this.getNodeParameter('scheduledDate', i);
1686
- if (scheduledDate) {
1687
- let normalizedDate = scheduledDate;
1688
- const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
1689
- if (!hasTimezone) {
1690
- normalizedDate = `${normalizedDate}Z`;
1691
- }
1692
- formData.scheduled_date = normalizedDate;
1693
- }
1694
- const uploadAsync = this.getNodeParameter('uploadAsync', i);
1695
- if (uploadAsync !== undefined) {
1696
- formData.async_upload = String(uploadAsync);
1697
- }
1698
- }
1699
- if (isUploadOperation) {
1700
- try {
1701
- if (platforms.includes('instagram')) {
1702
- const instagramTitle = this.getNodeParameter('instagramTitle', i, '');
1703
- if (instagramTitle)
1704
- formData.instagram_title = instagramTitle;
1705
- }
1706
- }
1707
- catch { }
1708
- try {
1709
- if (platforms.includes('facebook')) {
1710
- const facebookTitle = this.getNodeParameter('facebookTitle', i, '');
1711
- if (facebookTitle)
1712
- formData.facebook_title = facebookTitle;
1713
- }
1714
- }
1715
- catch { }
1716
- try {
1717
- if (platforms.includes('tiktok')) {
1718
- const tiktokTitle = this.getNodeParameter('tiktokTitle', i, '');
1719
- if (tiktokTitle)
1720
- formData.tiktok_title = tiktokTitle;
1721
- }
1722
- }
1723
- catch { }
1724
- try {
1725
- if (platforms.includes('linkedin')) {
1726
- const linkedinTitle = this.getNodeParameter('linkedinTitle', i, '');
1727
- if (linkedinTitle)
1728
- formData.linkedin_title = linkedinTitle;
1729
- }
1730
- }
1731
- catch { }
1732
- try {
1733
- if (platforms.includes('x')) {
1734
- const xTitle = this.getNodeParameter('xTitle', i, '');
1735
- if (xTitle)
1736
- formData.x_title = xTitle;
1737
- }
1738
- }
1739
- catch { }
1740
- try {
1741
- if (platforms.includes('youtube')) {
1742
- const youtubeTitle = this.getNodeParameter('youtubeTitle', i, '');
1743
- if (youtubeTitle)
1744
- formData.youtube_title = youtubeTitle;
1745
- }
1746
- }
1747
- catch { }
1748
- try {
1749
- if (platforms.includes('pinterest')) {
1750
- const pinterestTitle = this.getNodeParameter('pinterestTitle', i, '');
1751
- if (pinterestTitle)
1752
- formData.pinterest_title = pinterestTitle;
1753
- }
1754
- }
1755
- catch { }
1756
- }
1757
- if (isUploadOperation) {
1758
- const genericDescription = this.getNodeParameter('description', i, '');
1759
- const descriptionPlatforms = new Set(['linkedin', 'facebook', 'youtube', 'pinterest', 'tiktok']);
1760
- if (genericDescription && platforms.some(p => descriptionPlatforms.has(p))) {
1761
- formData.description = genericDescription;
1762
- }
1763
- try {
1764
- if (platforms.includes('linkedin')) {
1765
- const linkedinDescription = this.getNodeParameter('linkedinDescription', i, '');
1766
- if (linkedinDescription)
1767
- formData.linkedin_description = linkedinDescription;
1768
- }
1769
- }
1770
- catch { }
1771
- try {
1772
- if (platforms.includes('youtube')) {
1773
- const youtubeDescription = this.getNodeParameter('youtubeDescription', i, '');
1774
- if (youtubeDescription)
1775
- formData.youtube_description = youtubeDescription;
1776
- }
1777
- }
1778
- catch { }
1779
- try {
1780
- if (platforms.includes('facebook')) {
1781
- const facebookDescription = this.getNodeParameter('facebookDescription', i, '');
1782
- if (facebookDescription)
1783
- formData.facebook_description = facebookDescription;
1784
- }
1785
- }
1786
- catch { }
1787
- try {
1788
- if (platforms.includes('tiktok')) {
1789
- const tiktokDescription = this.getNodeParameter('tiktokDescription', i, '');
1790
- if (tiktokDescription)
1791
- formData.tiktok_description = tiktokDescription;
1792
- }
1793
- }
1794
- catch { }
1795
- try {
1796
- if (platforms.includes('pinterest')) {
1797
- const pinterestDescription = this.getNodeParameter('pinterestDescription', i, '');
1798
- if (pinterestDescription)
1799
- formData.pinterest_description = pinterestDescription;
1800
- }
1801
- }
1802
- catch { }
1803
- }
1804
- switch (operation) {
1805
- case 'uploadPhotos':
1806
- endpoint = '/upload_photos';
1807
- let photosInput = this.getNodeParameter('photos', i, []);
1808
- let photosToProcess;
1809
- if (typeof photosInput === 'string') {
1810
- photosToProcess = photosInput.split(',').map(item => item.trim()).filter(item => item !== '');
1811
- }
1812
- else {
1813
- photosToProcess = photosInput.filter(item => typeof item === 'string' && item.trim() !== '');
1814
- }
1815
- const allowedPhotoPlatforms = ['tiktok', 'instagram', 'linkedin', 'facebook', 'x', 'threads', 'pinterest'];
1816
- platforms = platforms.filter(p => allowedPhotoPlatforms.includes(p));
1817
- formData['platform[]'] = platforms;
1818
- if (photosToProcess.length > 0) {
1819
- const photoArray = [];
1820
- for (const photoItem of photosToProcess) {
1821
- if (typeof photoItem === 'string' && photoItem) {
1822
- if (photoItem.toLowerCase().startsWith('http://') || photoItem.toLowerCase().startsWith('https://')) {
1823
- photoArray.push(photoItem);
1824
- }
1825
- else {
1826
- const binaryPropertyName = photoItem;
1827
- try {
1828
- const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
1829
- const binaryFileDetails = items[i].binary[binaryPropertyName];
1830
- photoArray.push({
1831
- value: binaryBuffer,
1832
- options: {
1833
- filename: (_a = binaryFileDetails.fileName) !== null && _a !== void 0 ? _a : binaryPropertyName,
1834
- contentType: binaryFileDetails.mimeType,
1835
- },
1836
- });
1837
- }
1838
- catch (error) {
1839
- this.logger.warn(`[UploadPost Node] Could not find binary data for property '${binaryPropertyName}' in item ${i}. Error: ${error.message}`);
1840
- }
1841
- }
1842
- }
1843
- }
1844
- if (photoArray.length > 0) {
1845
- formData['photos[]'] = photoArray;
1846
- }
1847
- }
1848
- break;
1849
- case 'uploadVideo':
1850
- endpoint = '/upload';
1851
- const videoInput = this.getNodeParameter('video', i);
1852
- const allowedVideoPlatforms = ['tiktok', 'instagram', 'linkedin', 'youtube', 'facebook', 'x', 'threads', 'pinterest'];
1853
- platforms = platforms.filter(p => allowedVideoPlatforms.includes(p));
1854
- formData['platform[]'] = platforms;
1855
- if (videoInput) {
1856
- if (videoInput.toLowerCase().startsWith('http://') || videoInput.toLowerCase().startsWith('https://')) {
1857
- formData.video = videoInput;
1858
- }
1859
- else {
1860
- const binaryPropertyName = videoInput;
1861
- try {
1862
- const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
1863
- const binaryFileDetails = items[i].binary[binaryPropertyName];
1864
- formData.video = {
1865
- value: binaryBuffer,
1866
- options: {
1867
- filename: (_b = binaryFileDetails.fileName) !== null && _b !== void 0 ? _b : binaryPropertyName,
1868
- contentType: binaryFileDetails.mimeType,
1869
- },
1870
- };
1871
- }
1872
- catch (error) {
1873
- this.logger.warn(`[UploadPost Node] Could not find binary data for video property '${binaryPropertyName}' in item ${i}. Error: ${error.message}`);
1874
- }
1875
- }
1876
- }
1877
- break;
1878
- case 'uploadText':
1879
- endpoint = '/upload_text';
1880
- const allowedTextPlatforms = ['x', 'linkedin', 'facebook', 'threads', 'reddit'];
1881
- platforms = platforms.filter(p => allowedTextPlatforms.includes(p));
1882
- formData['platform[]'] = platforms;
1883
- break;
1884
- case 'getStatus':
1885
- method = 'GET';
1886
- endpoint = '/uploadposts/status';
1887
- qs.request_id = this.getNodeParameter('requestId', i);
1888
- break;
1889
- case 'getHistory':
1890
- method = 'GET';
1891
- endpoint = '/uploadposts/history';
1892
- const historyPage = this.getNodeParameter('historyPage', i);
1893
- qs.page = historyPage !== null && historyPage !== void 0 ? historyPage : 1;
1894
- const historyLimit = this.getNodeParameter('historyLimit', i);
1895
- qs.limit = historyLimit !== null && historyLimit !== void 0 ? historyLimit : 20;
1896
- break;
1897
- case 'getAnalytics':
1898
- method = 'GET';
1899
- {
1900
- const analyticsPlatforms = this.getNodeParameter('analyticsPlatforms', i, []);
1901
- const profileUsername = this.getNodeParameter('analyticsProfileUsername', i);
1902
- endpoint = `/analytics/${encodeURIComponent(profileUsername)}`;
1903
- if (Array.isArray(analyticsPlatforms) && analyticsPlatforms.length > 0) {
1904
- qs.platforms = analyticsPlatforms.join(',');
1905
- }
1906
- }
1907
- break;
1908
- case 'listScheduled':
1909
- method = 'GET';
1910
- endpoint = '/uploadposts/schedule';
1911
- break;
1912
- case 'cancelScheduled':
1913
- method = 'DELETE';
1914
- {
1915
- const jobId = this.getNodeParameter('scheduleJobId', i);
1916
- endpoint = `/uploadposts/schedule/${jobId}`;
1917
- }
1918
- break;
1919
- case 'editScheduled':
1920
- method = 'POST';
1921
- {
1922
- const jobId = this.getNodeParameter('scheduleJobId', i);
1923
- endpoint = `/uploadposts/schedule/${jobId}`;
1924
- const newScheduledDate = this.getNodeParameter('newScheduledDate', i, '');
1925
- if (newScheduledDate) {
1926
- let normalizedDate = newScheduledDate;
1927
- const hasTimezone = /[zZ]$|[+-]\d{2}:?\d{2}$/.test(normalizedDate);
1928
- if (!hasTimezone)
1929
- normalizedDate = `${normalizedDate}Z`;
1930
- body.scheduled_date = normalizedDate;
1931
- }
1932
- }
1933
- break;
1934
- case 'listUsers':
1935
- method = 'GET';
1936
- endpoint = '/uploadposts/users';
1937
- break;
1938
- case 'createUser':
1939
- method = 'POST';
1940
- endpoint = '/uploadposts/users';
1941
- body.username = this.getNodeParameter('newUser', i);
1942
- break;
1943
- case 'deleteUser':
1944
- method = 'DELETE';
1945
- endpoint = '/uploadposts/users';
1946
- body.username = this.getNodeParameter('deleteUserId', i);
1947
- break;
1948
- case 'generateJwt':
1949
- method = 'POST';
1950
- endpoint = '/uploadposts/users/generate-jwt';
1951
- body.username = user;
1952
- const redirectUrl = this.getNodeParameter('redirectUrl', i, '');
1953
- const logoImage = this.getNodeParameter('logoImage', i, '');
1954
- const redirectButtonText = this.getNodeParameter('redirectButtonText', i, '');
1955
- const jwtPlatforms = this.getNodeParameter('jwtPlatforms', i, []);
1956
- if (redirectUrl)
1957
- body.redirect_url = redirectUrl;
1958
- if (logoImage)
1959
- body.logo_image = logoImage;
1960
- if (redirectButtonText)
1961
- body.redirect_button_text = redirectButtonText;
1962
- if (Array.isArray(jwtPlatforms) && jwtPlatforms.length > 0)
1963
- body.platforms = jwtPlatforms;
1964
- break;
1965
- case 'validateJwt':
1966
- method = 'POST';
1967
- endpoint = '/uploadposts/users/validate-jwt';
1968
- body.jwt = this.getNodeParameter('jwtToken', i);
1969
- break;
1970
- }
1971
- if (isUploadOperation && platforms.includes('pinterest')) {
1972
- const pinterestSelection = this.getNodeParameter('pinterestBoardId', i);
1973
- const pinterestManual = pinterestSelection === MANUAL_PINTEREST_VALUE
1974
- ? this.getNodeParameter('pinterestBoardIdManual', i)
1975
- : '';
1976
- const pinterestBoardId = pinterestSelection === MANUAL_PINTEREST_VALUE ? pinterestManual : pinterestSelection;
1977
- if (pinterestBoardId)
1978
- formData.pinterest_board_id = pinterestBoardId;
1979
- const pinterestLink = this.getNodeParameter('pinterestLink', i);
1980
- if (pinterestLink)
1981
- formData.pinterest_link = pinterestLink;
1982
- if (operation === 'uploadVideo') {
1983
- const pinterestCoverImageUrl = this.getNodeParameter('pinterestCoverImageUrl', i);
1984
- const pinterestCoverImageContentType = this.getNodeParameter('pinterestCoverImageContentType', i);
1985
- const pinterestCoverImageData = this.getNodeParameter('pinterestCoverImageData', i);
1986
- const pinterestCoverImageKeyFrameTime = this.getNodeParameter('pinterestCoverImageKeyFrameTime', i);
1987
- const pinterestLink = this.getNodeParameter('pinterestLink', i);
1988
- if (pinterestCoverImageUrl) {
1989
- formData.pinterest_cover_image_url = pinterestCoverImageUrl;
1990
- }
1991
- else {
1992
- if (pinterestCoverImageContentType && pinterestCoverImageData) {
1993
- formData.pinterest_cover_image_content_type = pinterestCoverImageContentType;
1994
- formData.pinterest_cover_image_data = pinterestCoverImageData;
1995
- }
1996
- else if (pinterestCoverImageKeyFrameTime !== undefined) {
1997
- formData.pinterest_cover_image_key_frame_time = pinterestCoverImageKeyFrameTime;
1998
- }
1999
- }
2000
- if (pinterestLink)
2001
- formData.pinterest_link = pinterestLink;
2002
- }
2003
- }
2004
- if (isUploadOperation && platforms.includes('linkedin')) {
2005
- const targetLinkedinSelection = this.getNodeParameter('targetLinkedinPageId', i);
2006
- const targetLinkedinManual = targetLinkedinSelection === MANUAL_LINKEDIN_VALUE
2007
- ? this.getNodeParameter('targetLinkedinPageIdManual', i)
2008
- : '';
2009
- const targetLinkedinPageId = targetLinkedinSelection === MANUAL_LINKEDIN_VALUE ? targetLinkedinManual : targetLinkedinSelection;
2010
- if (targetLinkedinPageId && targetLinkedinPageId !== 'me') {
2011
- const match = targetLinkedinPageId.match(/(\d+)$/);
2012
- if (match) {
2013
- formData.target_linkedin_page_id = match[1];
2014
- }
2015
- else {
2016
- formData.target_linkedin_page_id = targetLinkedinPageId;
2017
- }
2018
- }
2019
- if (operation === 'uploadPhotos') {
2020
- const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
2021
- if (linkedinVisibility === 'PUBLIC') {
2022
- formData.visibility = 'PUBLIC';
2023
- }
2024
- }
2025
- else if (operation === 'uploadVideo') {
2026
- const linkedinVisibility = this.getNodeParameter('linkedinVisibility', i);
2027
- formData.visibility = linkedinVisibility;
2028
- }
2029
- }
2030
- if (isUploadOperation && platforms.includes('facebook')) {
2031
- const facebookPageSelection = this.getNodeParameter('facebookPageId', i);
2032
- const facebookPageManual = facebookPageSelection === MANUAL_FACEBOOK_VALUE
2033
- ? this.getNodeParameter('facebookPageIdManual', i)
2034
- : '';
2035
- const facebookPageId = facebookPageSelection === MANUAL_FACEBOOK_VALUE ? facebookPageManual : facebookPageSelection;
2036
- formData.facebook_page_id = facebookPageId;
2037
- if (operation === 'uploadVideo') {
2038
- const facebookVideoState = this.getNodeParameter('facebookVideoState', i);
2039
- if (facebookVideoState)
2040
- formData.video_state = facebookVideoState;
2041
- try {
2042
- const facebookMediaType = this.getNodeParameter('facebookMediaType', i);
2043
- if (facebookMediaType)
2044
- formData.facebook_media_type = facebookMediaType;
2045
- }
2046
- catch { }
2047
- }
2048
- else if (operation === 'uploadText') {
2049
- const facebookLink = this.getNodeParameter('facebookLink', i);
2050
- if (facebookLink)
2051
- formData.facebook_link_url = facebookLink;
2052
- }
2053
- }
2054
- if (isUploadOperation && platforms.includes('tiktok')) {
2055
- if (operation === 'uploadPhotos') {
2056
- const tiktokAutoAddMusic = this.getNodeParameter('tiktokAutoAddMusic', i);
2057
- const tiktokDisableComment = this.getNodeParameter('tiktokDisableComment', i);
2058
- const brandContentToggle = this.getNodeParameter('brand_content_toggle', i);
2059
- const brandOrganicToggle = this.getNodeParameter('brand_organic_toggle', i);
2060
- const tiktokPhotoCoverIndex = this.getNodeParameter('tiktokPhotoCoverIndex', i);
2061
- const tiktokPhotoDescription = this.getNodeParameter('tiktokPhotoDescription', i);
2062
- if (tiktokAutoAddMusic !== undefined)
2063
- formData.auto_add_music = String(tiktokAutoAddMusic);
2064
- if (tiktokDisableComment !== undefined)
2065
- formData.disable_comment = String(tiktokDisableComment);
2066
- if (brandContentToggle !== undefined)
2067
- formData.brand_content_toggle = String(brandContentToggle);
2068
- if (brandOrganicToggle !== undefined)
2069
- formData.brand_organic_toggle = String(brandOrganicToggle);
2070
- if (tiktokPhotoCoverIndex !== undefined)
2071
- formData.photo_cover_index = tiktokPhotoCoverIndex;
2072
- if (tiktokPhotoDescription && formData.description === undefined)
2073
- formData.description = tiktokPhotoDescription;
2074
- }
2075
- else if (operation === 'uploadVideo') {
2076
- const tiktokPrivacyLevel = this.getNodeParameter('tiktokPrivacyLevel', i);
2077
- const tiktokDisableDuet = this.getNodeParameter('tiktokDisableDuet', i);
2078
- const tiktokDisableComment = this.getNodeParameter('tiktokDisableComment', i);
2079
- const tiktokDisableStitch = this.getNodeParameter('tiktokDisableStitch', i);
2080
- const tiktokCoverTimestamp = this.getNodeParameter('tiktokCoverTimestamp', i);
2081
- const brandContentToggle = this.getNodeParameter('brand_content_toggle', i);
2082
- const brandOrganicToggle = this.getNodeParameter('brand_organic_toggle', i);
2083
- const tiktokIsAigc = this.getNodeParameter('tiktokIsAigc', i);
2084
- const tiktokPostMode = this.getNodeParameter('tiktokPostMode', i);
2085
- if (tiktokPrivacyLevel)
2086
- formData.privacy_level = tiktokPrivacyLevel;
2087
- if (tiktokDisableDuet !== undefined)
2088
- formData.disable_duet = String(tiktokDisableDuet);
2089
- if (tiktokDisableComment !== undefined)
2090
- formData.disable_comment = String(tiktokDisableComment);
2091
- if (tiktokDisableStitch !== undefined)
2092
- formData.disable_stitch = String(tiktokDisableStitch);
2093
- if (tiktokCoverTimestamp !== undefined)
2094
- formData.cover_timestamp = tiktokCoverTimestamp;
2095
- if (brandContentToggle !== undefined)
2096
- formData.brand_content_toggle = String(brandContentToggle);
2097
- if (brandOrganicToggle !== undefined)
2098
- formData.brand_organic_toggle = String(brandOrganicToggle);
2099
- if (tiktokIsAigc !== undefined)
2100
- formData.is_aigc = String(tiktokIsAigc);
2101
- if (tiktokPostMode)
2102
- formData.post_mode = tiktokPostMode;
2103
- }
2104
- }
2105
- if (isUploadOperation && platforms.includes('instagram')) {
2106
- const instagramMediaTypeInput = this.getNodeParameter('instagramMediaType', i);
2107
- let finalInstagramMediaType = instagramMediaTypeInput;
2108
- if (operation === 'uploadPhotos') {
2109
- if (!instagramMediaTypeInput || !['IMAGE', 'STORIES'].includes(instagramMediaTypeInput)) {
2110
- finalInstagramMediaType = 'IMAGE';
2111
- }
2112
- }
2113
- else if (operation === 'uploadVideo') {
2114
- if (!instagramMediaTypeInput || !['REELS', 'STORIES'].includes(instagramMediaTypeInput)) {
2115
- finalInstagramMediaType = 'REELS';
2116
- }
2117
- }
2118
- if (finalInstagramMediaType)
2119
- formData.media_type = finalInstagramMediaType;
2120
- if (operation === 'uploadVideo') {
2121
- const instagramShareToFeed = this.getNodeParameter('instagramShareToFeed', i);
2122
- const instagramCollaborators = this.getNodeParameter('instagramCollaborators', i);
2123
- const instagramCoverUrl = this.getNodeParameter('instagramCoverUrl', i);
2124
- const instagramAudioName = this.getNodeParameter('instagramAudioName', i);
2125
- const instagramUserTags = this.getNodeParameter('instagramUserTags', i);
2126
- const instagramLocationId = this.getNodeParameter('instagramLocationId', i);
2127
- const instagramThumbOffset = this.getNodeParameter('instagramThumbOffset', i);
2128
- if (instagramShareToFeed !== undefined)
2129
- formData.share_to_feed = String(instagramShareToFeed);
2130
- if (instagramCollaborators)
2131
- formData.collaborators = instagramCollaborators;
2132
- if (instagramCoverUrl)
2133
- formData.cover_url = instagramCoverUrl;
2134
- if (instagramAudioName)
2135
- formData.audio_name = instagramAudioName;
2136
- if (instagramUserTags)
2137
- formData.user_tags = instagramUserTags;
2138
- if (instagramLocationId)
2139
- formData.location_id = instagramLocationId;
2140
- if (instagramThumbOffset)
2141
- formData.thumb_offset = instagramThumbOffset;
2142
- }
2143
- }
2144
- if (isUploadOperation && platforms.includes('youtube') && operation === 'uploadVideo') {
2145
- const youtubeTagsRaw = this.getNodeParameter('youtubeTags', i);
2146
- const youtubeCategoryId = this.getNodeParameter('youtubeCategoryId', i);
2147
- const youtubePrivacyStatus = this.getNodeParameter('youtubePrivacyStatus', i);
2148
- const youtubeEmbeddable = this.getNodeParameter('youtubeEmbeddable', i);
2149
- const youtubeLicense = this.getNodeParameter('youtubeLicense', i);
2150
- const youtubePublicStatsViewable = this.getNodeParameter('youtubePublicStatsViewable', i);
2151
- const youtubeMadeForKids = this.getNodeParameter('youtubeMadeForKids', i);
2152
- const youtubeThumbnail = this.getNodeParameter('youtubeThumbnail', i);
2153
- if (youtubeTagsRaw)
2154
- formData['tags[]'] = youtubeTagsRaw.split(',').map(tag => tag.trim());
2155
- if (youtubeCategoryId)
2156
- formData.categoryId = youtubeCategoryId;
2157
- if (youtubePrivacyStatus)
2158
- formData.privacyStatus = youtubePrivacyStatus;
2159
- if (youtubeEmbeddable !== undefined)
2160
- formData.embeddable = String(youtubeEmbeddable);
2161
- if (youtubeLicense)
2162
- formData.license = youtubeLicense;
2163
- if (youtubePublicStatsViewable !== undefined)
2164
- formData.publicStatsViewable = String(youtubePublicStatsViewable);
2165
- if (youtubeMadeForKids !== undefined)
2166
- formData.madeForKids = String(youtubeMadeForKids);
2167
- if (youtubeThumbnail) {
2168
- if (youtubeThumbnail.toLowerCase().startsWith('http://') || youtubeThumbnail.toLowerCase().startsWith('https://')) {
2169
- formData.thumbnail_url = youtubeThumbnail;
2170
- }
2171
- else {
2172
- const binaryPropertyName = youtubeThumbnail;
2173
- try {
2174
- const binaryBuffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
2175
- const binaryFileDetails = items[i].binary[binaryPropertyName];
2176
- formData.thumbnail = {
2177
- value: binaryBuffer,
2178
- options: {
2179
- filename: (_c = binaryFileDetails.fileName) !== null && _c !== void 0 ? _c : binaryPropertyName,
2180
- contentType: binaryFileDetails.mimeType,
2181
- },
2182
- };
2183
- }
2184
- catch (error) {
2185
- this.logger.warn(`[UploadPost Node] Could not find binary data for YouTube thumbnail property '${binaryPropertyName}' in item ${i}. Error: ${error.message}`);
2186
- }
2187
- }
2188
- }
2189
- const youtubeSelfDeclaredMadeForKids = this.getNodeParameter('youtubeSelfDeclaredMadeForKids', i);
2190
- const youtubeContainsSyntheticMedia = this.getNodeParameter('youtubeContainsSyntheticMedia', i);
2191
- const youtubeDefaultLanguage = this.getNodeParameter('youtubeDefaultLanguage', i);
2192
- const youtubeDefaultAudioLanguage = this.getNodeParameter('youtubeDefaultAudioLanguage', i);
2193
- const youtubeAllowedCountries = this.getNodeParameter('youtubeAllowedCountries', i);
2194
- const youtubeBlockedCountries = this.getNodeParameter('youtubeBlockedCountries', i);
2195
- const youtubeHasPaidProductPlacement = this.getNodeParameter('youtubeHasPaidProductPlacement', i);
2196
- const youtubeRecordingDate = this.getNodeParameter('youtubeRecordingDate', i);
2197
- if (youtubeSelfDeclaredMadeForKids !== undefined)
2198
- formData.selfDeclaredMadeForKids = String(youtubeSelfDeclaredMadeForKids);
2199
- if (youtubeContainsSyntheticMedia !== undefined)
2200
- formData.containsSyntheticMedia = String(youtubeContainsSyntheticMedia);
2201
- if (youtubeDefaultLanguage)
2202
- formData.defaultLanguage = youtubeDefaultLanguage;
2203
- if (youtubeDefaultAudioLanguage)
2204
- formData.defaultAudioLanguage = youtubeDefaultAudioLanguage;
2205
- if (youtubeAllowedCountries)
2206
- formData.allowedCountries = youtubeAllowedCountries;
2207
- if (youtubeBlockedCountries)
2208
- formData.blockedCountries = youtubeBlockedCountries;
2209
- if (youtubeHasPaidProductPlacement !== undefined)
2210
- formData.hasPaidProductPlacement = String(youtubeHasPaidProductPlacement);
2211
- if (youtubeRecordingDate)
2212
- formData.recordingDate = youtubeRecordingDate;
2213
- }
2214
- if (isUploadOperation && platforms.includes('x')) {
2215
- const xQuoteTweetId = this.getNodeParameter('xQuoteTweetId', i, '');
2216
- const xGeoPlaceId = this.getNodeParameter('xGeoPlaceId', i, '');
2217
- const xForSuperFollowersOnly = this.getNodeParameter('xForSuperFollowersOnly', i, false);
2218
- const xCommunityId = this.getNodeParameter('xCommunityId', i, '');
2219
- const xShareWithFollowers = this.getNodeParameter('xShareWithFollowers', i, false);
2220
- const xDirectMessageDeepLink = this.getNodeParameter('xDirectMessageDeepLink', i, '');
2221
- const xCardUri = this.getNodeParameter('xCardUri', i, '');
2222
- if (xQuoteTweetId)
2223
- formData.quote_tweet_id = xQuoteTweetId;
2224
- if (xGeoPlaceId)
2225
- formData.geo_place_id = xGeoPlaceId;
2226
- if (xForSuperFollowersOnly)
2227
- formData.for_super_followers_only = String(xForSuperFollowersOnly);
2228
- if (xCommunityId)
2229
- formData.community_id = xCommunityId;
2230
- if (xShareWithFollowers)
2231
- formData.share_with_followers = String(xShareWithFollowers);
2232
- if (xDirectMessageDeepLink)
2233
- formData.direct_message_deep_link = xDirectMessageDeepLink;
2234
- if (xCardUri)
2235
- formData.card_uri = xCardUri;
2236
- if (operation === 'uploadText') {
2237
- const xPostUrlText = this.getNodeParameter('xPostUrlText', i);
2238
- if (xPostUrlText)
2239
- formData.post_url = xPostUrlText;
2240
- const xReplySettingsText = this.getNodeParameter('xReplySettings', i);
2241
- if (xReplySettingsText && xReplySettingsText !== 'everyone')
2242
- formData.reply_settings = xReplySettingsText;
2243
- const xPollDuration = this.getNodeParameter('xPollDuration', i, 1440);
2244
- const xPollOptionsRaw = this.getNodeParameter('xPollOptions', i, '');
2245
- const xPollReplySettings = this.getNodeParameter('xPollReplySettings', i, 'following');
2246
- const xCardUri = this.getNodeParameter('xCardUri', i, '');
2247
- const xQuoteTweetId = this.getNodeParameter('xQuoteTweetId', i, '');
2248
- const xDirectMessageDeepLink = this.getNodeParameter('xDirectMessageDeepLink', i, '');
2249
- const hasPollOptions = xPollOptionsRaw && xPollOptionsRaw.trim();
2250
- const hasCardUri = xCardUri && xCardUri.trim();
2251
- const hasQuoteTweetId = xQuoteTweetId && xQuoteTweetId.trim();
2252
- const hasDirectMessageDeepLink = xDirectMessageDeepLink && xDirectMessageDeepLink.trim();
2253
- if (hasPollOptions && (hasCardUri || hasQuoteTweetId || hasDirectMessageDeepLink)) {
2254
- const conflictingFields = [];
2255
- if (hasCardUri)
2256
- conflictingFields.push('X Card URI');
2257
- if (hasQuoteTweetId)
2258
- conflictingFields.push('X Quote Tweet ID');
2259
- if (hasDirectMessageDeepLink)
2260
- conflictingFields.push('X Direct Message Deep Link');
2261
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options cannot be used with: ${conflictingFields.join(', ')}. These fields are mutually exclusive.`);
2262
- }
2263
- if (hasPollOptions) {
2264
- const pollOptions = xPollOptionsRaw.split(',').map(opt => opt.trim()).filter(opt => opt.length > 0);
2265
- if (pollOptions.length < 2 || pollOptions.length > 4) {
2266
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options must contain between 2 and 4 non-empty options. Found: ${pollOptions.length}`);
2267
- }
2268
- const invalidOptions = pollOptions.filter(opt => opt.length > 25);
2269
- if (invalidOptions.length > 0) {
2270
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Options cannot exceed 25 characters each. Invalid options: ${invalidOptions.join(', ')}`);
2271
- }
2272
- if (xPollDuration < 5 || xPollDuration > 10080) {
2273
- throw new n8n_workflow_1.NodeOperationError(this.getNode(), `X Poll Duration must be between 5 and 10080 minutes (5 minutes to 7 days). Provided: ${xPollDuration}`);
2274
- }
2275
- formData['poll_options[]'] = pollOptions;
2276
- formData.poll_duration = xPollDuration;
2277
- formData.poll_reply_settings = xPollReplySettings;
2278
- }
2279
- try {
2280
- const xLongTextAsPostText = this.getNodeParameter('xLongTextAsPost', i, false);
2281
- if (xLongTextAsPostText)
2282
- formData.x_long_text_as_post = String(xLongTextAsPostText);
2283
- }
2284
- catch { }
2285
- delete formData.nullcast;
2286
- delete formData.place_id;
2287
- }
2288
- else if (operation === 'uploadVideo' || operation === 'uploadPhotos') {
2289
- const xTaggedUserIds = this.getNodeParameter('xTaggedUserIds', i);
2290
- const xReplySettings = this.getNodeParameter('xReplySettings', i);
2291
- const xNullcastVideo = this.getNodeParameter('xNullcastVideo', i);
2292
- if (xTaggedUserIds)
2293
- formData['tagged_user_ids[]'] = xTaggedUserIds.split(',').map(id => id.trim());
2294
- if (xReplySettings && xReplySettings !== 'everyone')
2295
- formData.reply_settings = xReplySettings;
2296
- if (xNullcastVideo !== undefined)
2297
- formData.nullcast = String(xNullcastVideo);
2298
- if (operation === 'uploadVideo') {
2299
- try {
2300
- const xLongTextAsPost = this.getNodeParameter('xLongTextAsPost', i, false);
2301
- if (xLongTextAsPost)
2302
- formData.x_long_text_as_post = String(xLongTextAsPost);
2303
- }
2304
- catch { }
2305
- }
2306
- }
2475
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
2476
+ const operation = this.getNodeParameter('operation', itemIndex);
2477
+ const ctx = {
2478
+ node: this,
2479
+ items,
2480
+ itemIndex,
2481
+ operation,
2482
+ };
2483
+ const config = await buildRequestConfig(ctx);
2484
+ const requestOptions = {
2485
+ url: `${API_BASE_URL}${config.endpoint}`,
2486
+ method: config.method,
2487
+ };
2488
+ if (config.headers) {
2489
+ requestOptions.headers = config.headers;
2307
2490
  }
2308
- if (isUploadOperation && platforms.includes('threads')) {
2309
- if (operation === 'uploadText') {
2310
- const threadsTitle = this.getNodeParameter('threadsTitle', i, '');
2311
- if (threadsTitle)
2312
- formData.threads_title = threadsTitle;
2313
- const threadsLongTextAsPost = this.getNodeParameter('threadsLongTextAsPost', i, false);
2314
- if (threadsLongTextAsPost)
2315
- formData.threads_long_text_as_post = String(threadsLongTextAsPost);
2316
- }
2491
+ if (config.qs) {
2492
+ requestOptions.qs = config.qs;
2317
2493
  }
2318
- if (isUploadOperation && platforms.includes('reddit')) {
2319
- if (operation === 'uploadText') {
2320
- const redditSubreddit = this.getNodeParameter('redditSubreddit', i);
2321
- formData.subreddit = redditSubreddit;
2322
- const redditFlairId = this.getNodeParameter('redditFlairId', i, '');
2323
- if (redditFlairId)
2324
- formData.flair_id = redditFlairId;
2325
- }
2494
+ if (config.formData) {
2495
+ const multipartPayload = buildMultipartPayload(config.formData);
2496
+ const nativeFormData = buildNativeFormData(multipartPayload, this);
2497
+ requestOptions.body = nativeFormData;
2498
+ requestOptions.json = false;
2326
2499
  }
2327
- const credentials = await this.getCredentials('uploadPostApi');
2328
- const apiKey = credentials.apiKey;
2329
- const options = {
2330
- uri: `https://api.upload-post.com/api${endpoint}`,
2331
- method,
2332
- headers: {},
2333
- json: true,
2334
- };
2335
- if (operation === 'validateJwt') {
2336
- const jwt = this.getNodeParameter('jwtToken', i);
2337
- options.headers['Authorization'] = `Bearer ${jwt}`;
2500
+ else if (config.body) {
2501
+ requestOptions.body = config.body;
2502
+ requestOptions.json = true;
2338
2503
  }
2339
2504
  else {
2340
- options.headers['Authorization'] = `ApiKey ${apiKey}`;
2341
- }
2342
- if (method === 'POST') {
2343
- if (operation === 'uploadPhotos' || operation === 'uploadVideo' || operation === 'uploadText') {
2344
- options.formData = formData;
2345
- }
2346
- else {
2347
- options.body = body;
2348
- }
2349
- }
2350
- else if (method === 'GET' || method === 'DELETE') {
2351
- if (operation === 'deleteUser') {
2352
- options.body = body;
2353
- }
2354
- else {
2355
- options.qs = qs;
2356
- }
2505
+ requestOptions.json = true;
2357
2506
  }
2358
- this.logger.info(`Operation: ${operation}, Is Upload Operation: ${isUploadOperation}`);
2359
- const responseData = await this.helpers.request(options);
2360
- const shouldConsiderPolling = operation === 'uploadPhotos' || operation === 'uploadVideo' || operation === 'uploadText';
2361
- const waitForCompletion = shouldConsiderPolling ? this.getNodeParameter('waitForCompletion', i, false) : false;
2507
+ const rawResponse = await this.helpers.httpRequestWithAuthentication.call(this, 'uploadPostApi', requestOptions);
2508
+ const responseData = parseJsonIfNeeded(rawResponse);
2362
2509
  let finalData = responseData;
2363
- if (shouldConsiderPolling && waitForCompletion) {
2364
- const maybeRequestId = (responseData && responseData.request_id) ? responseData.request_id : undefined;
2365
- if (maybeRequestId) {
2366
- const requestId = maybeRequestId;
2367
- const pollIntervalSec = this.getNodeParameter('pollInterval', i, 10);
2368
- const pollTimeoutSec = this.getNodeParameter('pollTimeout', i, 600);
2369
- const start = Date.now();
2370
- while (true) {
2371
- await (0, n8n_workflow_1.sleep)(Math.max(1, pollIntervalSec) * 1000);
2372
- if (Date.now() - start > Math.max(5, pollTimeoutSec) * 1000) {
2373
- finalData = { success: false, message: 'Polling timed out', request_id: requestId };
2374
- break;
2375
- }
2376
- const statusOptions = {
2377
- uri: `https://api.upload-post.com/api/uploadposts/status`,
2378
- method: 'GET',
2379
- headers: { 'Authorization': `ApiKey ${apiKey}` },
2380
- qs: { request_id: requestId },
2381
- json: true,
2382
- };
2383
- const statusData = await this.helpers.request(statusOptions);
2384
- finalData = statusData;
2385
- const statusValue = (statusData && statusData.status);
2386
- if (statusData.success === true || (statusValue && ['success', 'completed', 'failed', 'error'].includes(statusValue.toLowerCase()))) {
2387
- break;
2388
- }
2389
- }
2510
+ if (config.isUploadOperation && config.waitForCompletion) {
2511
+ const requestId = responseData && responseData.request_id
2512
+ ? responseData.request_id
2513
+ : undefined;
2514
+ if (requestId) {
2515
+ finalData = await pollUploadStatus(this, requestId, (_a = config.pollInterval) !== null && _a !== void 0 ? _a : 10, (_b = config.pollTimeout) !== null && _b !== void 0 ? _b : 600);
2390
2516
  }
2391
2517
  }
2392
2518
  returnData.push({
2393
2519
  json: finalData,
2394
- pairedItem: {
2395
- item: i,
2396
- },
2520
+ pairedItem: { item: itemIndex },
2397
2521
  });
2398
2522
  }
2399
2523
  return [returnData];