@memberjunction/actions-bizapps-social 2.111.1 → 2.112.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +6 -6
- package/dist/base/base-social.action.d.ts.map +1 -1
- package/dist/base/base-social.action.js +18 -24
- package/dist/base/base-social.action.js.map +1 -1
- package/dist/providers/buffer/buffer-base.action.d.ts.map +1 -1
- package/dist/providers/buffer/buffer-base.action.js +35 -34
- package/dist/providers/buffer/buffer-base.action.js.map +1 -1
- package/dist/providers/facebook/actions/boost-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/boost-post.action.js +33 -33
- package/dist/providers/facebook/actions/boost-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/create-album.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/create-album.action.js +34 -36
- package/dist/providers/facebook/actions/create-album.action.js.map +1 -1
- package/dist/providers/facebook/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/create-post.action.js +20 -20
- package/dist/providers/facebook/actions/create-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-page-insights.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-page-insights.action.js +25 -27
- package/dist/providers/facebook/actions/get-page-insights.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-page-posts.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-page-posts.action.js +19 -23
- package/dist/providers/facebook/actions/get-page-posts.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-post-insights.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-post-insights.action.js +28 -32
- package/dist/providers/facebook/actions/get-post-insights.action.js.map +1 -1
- package/dist/providers/facebook/actions/respond-to-comments.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/respond-to-comments.action.js +42 -44
- package/dist/providers/facebook/actions/respond-to-comments.action.js.map +1 -1
- package/dist/providers/facebook/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/schedule-post.action.js +29 -29
- package/dist/providers/facebook/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/search-posts.action.js +37 -39
- package/dist/providers/facebook/actions/search-posts.action.js.map +1 -1
- package/dist/providers/facebook/facebook-base.action.d.ts.map +1 -1
- package/dist/providers/facebook/facebook-base.action.js +44 -59
- package/dist/providers/facebook/facebook-base.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js +33 -31
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.js +28 -32
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js +19 -19
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-analytics.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-analytics.action.js +24 -26
- package/dist/providers/hootsuite/actions/get-analytics.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js +22 -22
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-social-profiles.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-social-profiles.action.js +32 -34
- package/dist/providers/hootsuite/actions/get-social-profiles.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/search-posts.action.js +43 -52
- package/dist/providers/hootsuite/actions/search-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.js +30 -28
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/hootsuite-base.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/hootsuite-base.action.js +18 -20
- package/dist/providers/hootsuite/hootsuite-base.action.js.map +1 -1
- package/dist/providers/instagram/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/create-post.action.js +27 -26
- package/dist/providers/instagram/actions/create-post.action.js.map +1 -1
- package/dist/providers/instagram/actions/create-story.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/create-story.action.js +35 -35
- package/dist/providers/instagram/actions/create-story.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-account-insights.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-account-insights.action.js +38 -59
- package/dist/providers/instagram/actions/get-account-insights.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-business-posts.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-business-posts.action.js +29 -29
- package/dist/providers/instagram/actions/get-business-posts.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-comments.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-comments.action.js +36 -36
- package/dist/providers/instagram/actions/get-comments.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-post-insights.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-post-insights.action.js +23 -25
- package/dist/providers/instagram/actions/get-post-insights.action.js.map +1 -1
- package/dist/providers/instagram/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/schedule-post.action.js +25 -25
- package/dist/providers/instagram/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/instagram/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/search-posts.action.js +56 -60
- package/dist/providers/instagram/actions/search-posts.action.js.map +1 -1
- package/dist/providers/instagram/instagram-base.action.d.ts.map +1 -1
- package/dist/providers/instagram/instagram-base.action.js +25 -27
- package/dist/providers/instagram/instagram-base.action.js.map +1 -1
- package/dist/providers/linkedin/actions/create-article.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/create-article.action.js +55 -45
- package/dist/providers/linkedin/actions/create-article.action.js.map +1 -1
- package/dist/providers/linkedin/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/create-post.action.js +31 -29
- package/dist/providers/linkedin/actions/create-post.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-followers.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-followers.action.js +28 -28
- package/dist/providers/linkedin/actions/get-followers.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-organization-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-organization-posts.action.js +20 -20
- package/dist/providers/linkedin/actions/get-organization-posts.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-personal-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-personal-posts.action.js +19 -19
- package/dist/providers/linkedin/actions/get-personal-posts.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-post-analytics.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-post-analytics.action.js +25 -23
- package/dist/providers/linkedin/actions/get-post-analytics.action.js.map +1 -1
- package/dist/providers/linkedin/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/schedule-post.action.js +32 -30
- package/dist/providers/linkedin/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/linkedin/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/search-posts.action.js +28 -30
- package/dist/providers/linkedin/actions/search-posts.action.js.map +1 -1
- package/dist/providers/linkedin/linkedin-base.action.d.ts.map +1 -1
- package/dist/providers/linkedin/linkedin-base.action.js +33 -38
- package/dist/providers/linkedin/linkedin-base.action.js.map +1 -1
- package/dist/providers/tiktok/tiktok-base.action.d.ts.map +1 -1
- package/dist/providers/tiktok/tiktok-base.action.js +25 -26
- package/dist/providers/tiktok/tiktok-base.action.js.map +1 -1
- package/dist/providers/twitter/actions/create-thread.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/create-thread.action.js +25 -29
- package/dist/providers/twitter/actions/create-thread.action.js.map +1 -1
- package/dist/providers/twitter/actions/create-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/create-tweet.action.js +23 -23
- package/dist/providers/twitter/actions/create-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/delete-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/delete-tweet.action.js +19 -19
- package/dist/providers/twitter/actions/delete-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-analytics.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-analytics.action.js +40 -47
- package/dist/providers/twitter/actions/get-analytics.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-mentions.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-mentions.action.js +30 -31
- package/dist/providers/twitter/actions/get-mentions.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-timeline.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-timeline.action.js +29 -29
- package/dist/providers/twitter/actions/get-timeline.action.js.map +1 -1
- package/dist/providers/twitter/actions/schedule-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/schedule-tweet.action.js +26 -26
- package/dist/providers/twitter/actions/schedule-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/search-tweets.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/search-tweets.action.js +56 -58
- package/dist/providers/twitter/actions/search-tweets.action.js.map +1 -1
- package/dist/providers/twitter/twitter-base.action.d.ts.map +1 -1
- package/dist/providers/twitter/twitter-base.action.js +58 -68
- package/dist/providers/twitter/twitter-base.action.js.map +1 -1
- package/dist/providers/youtube/youtube-base.action.d.ts +1 -1
- package/dist/providers/youtube/youtube-base.action.d.ts.map +1 -1
- package/dist/providers/youtube/youtube-base.action.js +22 -25
- package/dist/providers/youtube/youtube-base.action.js.map +1 -1
- package/package.json +5 -6
- package/src/base/base-social.action.ts +217 -224
- package/src/providers/buffer/buffer-base.action.ts +435 -441
- package/src/providers/facebook/actions/boost-post.action.ts +350 -386
- package/src/providers/facebook/actions/create-album.action.ts +291 -307
- package/src/providers/facebook/actions/create-post.action.ts +224 -227
- package/src/providers/facebook/actions/get-page-insights.action.ts +383 -403
- package/src/providers/facebook/actions/get-page-posts.action.ts +214 -225
- package/src/providers/facebook/actions/get-post-insights.action.ts +300 -316
- package/src/providers/facebook/actions/respond-to-comments.action.ts +319 -336
- package/src/providers/facebook/actions/schedule-post.action.ts +289 -292
- package/src/providers/facebook/actions/search-posts.action.ts +399 -413
- package/src/providers/facebook/facebook-base.action.ts +653 -670
- package/src/providers/hootsuite/actions/bulk-schedule-posts.action.ts +257 -257
- package/src/providers/hootsuite/actions/create-scheduled-post.action.ts +184 -189
- package/src/providers/hootsuite/actions/delete-scheduled-post.action.ts +160 -161
- package/src/providers/hootsuite/actions/get-analytics.action.ts +249 -254
- package/src/providers/hootsuite/actions/get-scheduled-posts.action.ts +206 -207
- package/src/providers/hootsuite/actions/get-social-profiles.action.ts +206 -205
- package/src/providers/hootsuite/actions/search-posts.action.ts +351 -369
- package/src/providers/hootsuite/actions/update-scheduled-post.action.ts +211 -209
- package/src/providers/hootsuite/hootsuite-base.action.ts +301 -307
- package/src/providers/instagram/actions/create-post.action.ts +276 -296
- package/src/providers/instagram/actions/create-story.action.ts +378 -394
- package/src/providers/instagram/actions/get-account-insights.action.ts +384 -420
- package/src/providers/instagram/actions/get-business-posts.action.ts +233 -242
- package/src/providers/instagram/actions/get-comments.action.ts +365 -377
- package/src/providers/instagram/actions/get-post-insights.action.ts +265 -273
- package/src/providers/instagram/actions/schedule-post.action.ts +233 -235
- package/src/providers/instagram/actions/search-posts.action.ts +512 -538
- package/src/providers/instagram/instagram-base.action.ts +368 -393
- package/src/providers/linkedin/actions/create-article.action.ts +275 -266
- package/src/providers/linkedin/actions/create-post.action.ts +179 -177
- package/src/providers/linkedin/actions/get-followers.action.ts +211 -211
- package/src/providers/linkedin/actions/get-organization-posts.action.ts +146 -147
- package/src/providers/linkedin/actions/get-personal-posts.action.ts +138 -139
- package/src/providers/linkedin/actions/get-post-analytics.action.ts +190 -189
- package/src/providers/linkedin/actions/schedule-post.action.ts +191 -189
- package/src/providers/linkedin/actions/search-posts.action.ts +275 -283
- package/src/providers/linkedin/linkedin-base.action.ts +407 -421
- package/src/providers/tiktok/tiktok-base.action.ts +305 -320
- package/src/providers/twitter/actions/create-thread.action.ts +203 -207
- package/src/providers/twitter/actions/create-tweet.action.ts +187 -188
- package/src/providers/twitter/actions/delete-tweet.action.ts +128 -129
- package/src/providers/twitter/actions/get-analytics.action.ts +402 -411
- package/src/providers/twitter/actions/get-mentions.action.ts +218 -219
- package/src/providers/twitter/actions/get-timeline.action.ts +232 -233
- package/src/providers/twitter/actions/schedule-tweet.action.ts +221 -222
- package/src/providers/twitter/actions/search-tweets.action.ts +540 -543
- package/src/providers/twitter/twitter-base.action.ts +541 -560
- package/src/providers/youtube/youtube-base.action.ts +320 -333
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RegisterClass } from '@memberjunction/global';
|
|
2
2
|
import { TwitterBaseAction, CreateTweetData } from '../twitter-base.action';
|
|
3
3
|
import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
|
|
4
|
-
import { LogStatus, LogError } from '@memberjunction/
|
|
4
|
+
import { LogStatus, LogError } from '@memberjunction/global';
|
|
5
5
|
import { MediaFile } from '../../../base/base-social.action';
|
|
6
6
|
import { BaseAction } from '@memberjunction/actions';
|
|
7
7
|
|
|
@@ -12,249 +12,248 @@ import { BaseAction } from '@memberjunction/actions';
|
|
|
12
12
|
*/
|
|
13
13
|
@RegisterClass(BaseAction, 'TwitterScheduleTweetAction')
|
|
14
14
|
export class TwitterScheduleTweetAction extends TwitterBaseAction {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
// Initialize OAuth
|
|
23
|
-
const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
|
|
24
|
-
if (!await this.initializeOAuth(companyIntegrationId)) {
|
|
25
|
-
throw new Error('Failed to initialize OAuth connection');
|
|
26
|
-
}
|
|
15
|
+
/**
|
|
16
|
+
* Schedule a tweet for future posting
|
|
17
|
+
*/
|
|
18
|
+
protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
|
|
19
|
+
const { Params, ContextUser } = params;
|
|
27
20
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const pollOptions = this.getParamValue(Params, 'PollOptions');
|
|
35
|
-
const pollDurationMinutes = this.getParamValue(Params, 'PollDurationMinutes') || 1440; // Default 24 hours
|
|
21
|
+
try {
|
|
22
|
+
// Initialize OAuth
|
|
23
|
+
const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
|
|
24
|
+
if (!(await this.initializeOAuth(companyIntegrationId))) {
|
|
25
|
+
throw new Error('Failed to initialize OAuth connection');
|
|
26
|
+
}
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
// Extract parameters
|
|
29
|
+
const content = this.getParamValue(Params, 'Content');
|
|
30
|
+
const scheduledTime = this.getParamValue(Params, 'ScheduledTime');
|
|
31
|
+
const mediaFiles = this.getParamValue(Params, 'MediaFiles');
|
|
32
|
+
const replyToTweetId = this.getParamValue(Params, 'ReplyToTweetID');
|
|
33
|
+
const quoteTweetId = this.getParamValue(Params, 'QuoteTweetID');
|
|
34
|
+
const pollOptions = this.getParamValue(Params, 'PollOptions');
|
|
35
|
+
const pollDurationMinutes = this.getParamValue(Params, 'PollDurationMinutes') || 1440; // Default 24 hours
|
|
41
36
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
// Validate required parameters
|
|
38
|
+
if (!content) {
|
|
39
|
+
throw new Error('Content is required');
|
|
40
|
+
}
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (scheduleDate <= now) {
|
|
51
|
-
throw new Error('ScheduledTime must be in the future');
|
|
52
|
-
}
|
|
42
|
+
if (!scheduledTime) {
|
|
43
|
+
throw new Error('ScheduledTime is required');
|
|
44
|
+
}
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (scheduleDate > maxFutureDate) {
|
|
59
|
-
throw new Error('ScheduledTime cannot be more than 1 year in the future');
|
|
60
|
-
}
|
|
46
|
+
// Validate scheduled time is in the future
|
|
47
|
+
const scheduleDate = new Date(scheduledTime);
|
|
48
|
+
const now = new Date();
|
|
61
49
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
50
|
+
if (scheduleDate <= now) {
|
|
51
|
+
throw new Error('ScheduledTime must be in the future');
|
|
52
|
+
}
|
|
66
53
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
};
|
|
54
|
+
// Validate scheduled time is not too far in the future (e.g., 1 year)
|
|
55
|
+
const maxFutureDate = new Date();
|
|
56
|
+
maxFutureDate.setFullYear(maxFutureDate.getFullYear() + 1);
|
|
71
57
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
in_reply_to_tweet_id: replyToTweetId
|
|
76
|
-
};
|
|
77
|
-
}
|
|
58
|
+
if (scheduleDate > maxFutureDate) {
|
|
59
|
+
throw new Error('ScheduledTime cannot be more than 1 year in the future');
|
|
60
|
+
}
|
|
78
61
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
62
|
+
// Validate content length
|
|
63
|
+
if (content.length > 280) {
|
|
64
|
+
throw new Error(`Content exceeds Twitter's 280 character limit (current: ${content.length} characters)`);
|
|
65
|
+
}
|
|
83
66
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Validate poll option lengths
|
|
91
|
-
for (const option of pollOptions) {
|
|
92
|
-
if (option.length > 25) {
|
|
93
|
-
throw new Error(`Poll option "${option}" exceeds 25 character limit`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
67
|
+
// Build tweet data structure
|
|
68
|
+
const tweetData: CreateTweetData = {
|
|
69
|
+
text: content,
|
|
70
|
+
};
|
|
96
71
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
72
|
+
// Add reply if specified
|
|
73
|
+
if (replyToTweetId) {
|
|
74
|
+
tweetData.reply = {
|
|
75
|
+
in_reply_to_tweet_id: replyToTweetId,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
102
78
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
throw new Error('Twitter supports a maximum of 4 media items per tweet');
|
|
108
|
-
}
|
|
79
|
+
// Add quote tweet if specified
|
|
80
|
+
if (quoteTweetId) {
|
|
81
|
+
tweetData.quote_tweet_id = quoteTweetId;
|
|
82
|
+
}
|
|
109
83
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
// Upload now if scheduling within 24 hours
|
|
116
|
-
LogStatus(`Uploading ${mediaFiles.length} media files...`);
|
|
117
|
-
uploadedMediaIds = await this.uploadMedia(mediaFiles as MediaFile[]);
|
|
118
|
-
tweetData.media = {
|
|
119
|
-
media_ids: uploadedMediaIds
|
|
120
|
-
};
|
|
121
|
-
} else {
|
|
122
|
-
// For tweets scheduled beyond 24 hours, we'll need to store media
|
|
123
|
-
// data and upload closer to the scheduled time
|
|
124
|
-
LogStatus('Media will be uploaded closer to scheduled time due to Twitter\'s 24-hour media expiration');
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Create scheduled tweet record
|
|
129
|
-
// In a real implementation, this would save to a database or queue service
|
|
130
|
-
const scheduledTweet = {
|
|
131
|
-
id: this.generateScheduledTweetId(),
|
|
132
|
-
scheduledFor: scheduleDate.toISOString(),
|
|
133
|
-
tweetData: tweetData,
|
|
134
|
-
mediaFiles: mediaFiles, // Store for later upload if needed
|
|
135
|
-
companyIntegrationId: companyIntegrationId,
|
|
136
|
-
createdAt: new Date().toISOString(),
|
|
137
|
-
status: 'scheduled'
|
|
138
|
-
};
|
|
84
|
+
// Add poll if specified
|
|
85
|
+
if (pollOptions && Array.isArray(pollOptions) && pollOptions.length >= 2) {
|
|
86
|
+
if (pollOptions.length > 4) {
|
|
87
|
+
throw new Error('Twitter polls support a maximum of 4 options');
|
|
88
|
+
}
|
|
139
89
|
|
|
140
|
-
|
|
141
|
-
|
|
90
|
+
// Validate poll option lengths
|
|
91
|
+
for (const option of pollOptions) {
|
|
92
|
+
if (option.length > 25) {
|
|
93
|
+
throw new Error(`Poll option "${option}" exceeds 25 character limit`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
142
96
|
|
|
143
|
-
|
|
144
|
-
|
|
97
|
+
tweetData.poll = {
|
|
98
|
+
options: pollOptions,
|
|
99
|
+
duration_minutes: Math.min(Math.max(pollDurationMinutes, 5), 10080),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
145
102
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const estimatedUrlParam = outputParams.find(p => p.Name === 'EstimatedURL');
|
|
153
|
-
if (estimatedUrlParam) estimatedUrlParam.Value = `https://twitter.com/${user.username}/status/[pending]`;
|
|
103
|
+
// Handle media files
|
|
104
|
+
let uploadedMediaIds: string[] = [];
|
|
105
|
+
if (mediaFiles && Array.isArray(mediaFiles) && mediaFiles.length > 0) {
|
|
106
|
+
if (mediaFiles.length > 4) {
|
|
107
|
+
throw new Error('Twitter supports a maximum of 4 media items per tweet');
|
|
108
|
+
}
|
|
154
109
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Message: `Successfully scheduled tweet for ${scheduleDate.toLocaleString()}`,
|
|
159
|
-
Params: outputParams
|
|
160
|
-
};
|
|
110
|
+
// For scheduling, we'll upload the media now and store the IDs
|
|
111
|
+
// Note: Twitter media IDs expire after 24 hours if not used
|
|
112
|
+
const hoursUntilScheduled = (scheduleDate.getTime() - now.getTime()) / (1000 * 60 * 60);
|
|
161
113
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
114
|
+
if (hoursUntilScheduled <= 24) {
|
|
115
|
+
// Upload now if scheduling within 24 hours
|
|
116
|
+
LogStatus(`Uploading ${mediaFiles.length} media files...`);
|
|
117
|
+
uploadedMediaIds = await this.uploadMedia(mediaFiles as MediaFile[]);
|
|
118
|
+
tweetData.media = {
|
|
119
|
+
media_ids: uploadedMediaIds,
|
|
120
|
+
};
|
|
121
|
+
} else {
|
|
122
|
+
// For tweets scheduled beyond 24 hours, we'll need to store media
|
|
123
|
+
// data and upload closer to the scheduled time
|
|
124
|
+
LogStatus("Media will be uploaded closer to scheduled time due to Twitter's 24-hour media expiration");
|
|
171
125
|
}
|
|
172
|
-
|
|
126
|
+
}
|
|
173
127
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
128
|
+
// Create scheduled tweet record
|
|
129
|
+
// In a real implementation, this would save to a database or queue service
|
|
130
|
+
const scheduledTweet = {
|
|
131
|
+
id: this.generateScheduledTweetId(),
|
|
132
|
+
scheduledFor: scheduleDate.toISOString(),
|
|
133
|
+
tweetData: tweetData,
|
|
134
|
+
mediaFiles: mediaFiles, // Store for later upload if needed
|
|
135
|
+
companyIntegrationId: companyIntegrationId,
|
|
136
|
+
createdAt: new Date().toISOString(),
|
|
137
|
+
status: 'scheduled',
|
|
138
|
+
};
|
|
180
139
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
140
|
+
// Simulate saving to a scheduling service
|
|
141
|
+
LogStatus(`Tweet scheduled for ${scheduleDate.toLocaleString()}`);
|
|
142
|
+
|
|
143
|
+
// Get user info for context
|
|
144
|
+
const user = await this.getCurrentUser();
|
|
145
|
+
|
|
146
|
+
// Update output parameters
|
|
147
|
+
const outputParams = [...Params];
|
|
148
|
+
const scheduledIdParam = outputParams.find((p) => p.Name === 'ScheduledTweetID');
|
|
149
|
+
if (scheduledIdParam) scheduledIdParam.Value = scheduledTweet.id;
|
|
150
|
+
const scheduledDataParam = outputParams.find((p) => p.Name === 'ScheduledTweetData');
|
|
151
|
+
if (scheduledDataParam) scheduledDataParam.Value = scheduledTweet;
|
|
152
|
+
const estimatedUrlParam = outputParams.find((p) => p.Name === 'EstimatedURL');
|
|
153
|
+
if (estimatedUrlParam) estimatedUrlParam.Value = `https://twitter.com/${user.username}/status/[pending]`;
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
Success: true,
|
|
157
|
+
ResultCode: 'SUCCESS',
|
|
158
|
+
Message: `Successfully scheduled tweet for ${scheduleDate.toLocaleString()}`,
|
|
159
|
+
Params: outputParams,
|
|
160
|
+
};
|
|
161
|
+
} catch (error) {
|
|
162
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
|
|
194
163
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
{
|
|
202
|
-
Name: 'Content',
|
|
203
|
-
Type: 'Input',
|
|
204
|
-
Value: null
|
|
205
|
-
},
|
|
206
|
-
{
|
|
207
|
-
Name: 'ScheduledTime',
|
|
208
|
-
Type: 'Input',
|
|
209
|
-
Value: null
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
Name: 'MediaFiles',
|
|
213
|
-
Type: 'Input',
|
|
214
|
-
Value: null
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
Name: 'ReplyToTweetID',
|
|
218
|
-
Type: 'Input',
|
|
219
|
-
Value: null
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
Name: 'QuoteTweetID',
|
|
223
|
-
Type: 'Input',
|
|
224
|
-
Value: null
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
Name: 'PollOptions',
|
|
228
|
-
Type: 'Input',
|
|
229
|
-
Value: null
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
Name: 'PollDurationMinutes',
|
|
233
|
-
Type: 'Input',
|
|
234
|
-
Value: 1440 // Default 24 hours
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
Name: 'ScheduledTweetID',
|
|
238
|
-
Type: 'Output',
|
|
239
|
-
Value: null
|
|
240
|
-
},
|
|
241
|
-
{
|
|
242
|
-
Name: 'ScheduledTweetData',
|
|
243
|
-
Type: 'Output',
|
|
244
|
-
Value: null
|
|
245
|
-
},
|
|
246
|
-
{
|
|
247
|
-
Name: 'EstimatedURL',
|
|
248
|
-
Type: 'Output',
|
|
249
|
-
Value: null
|
|
250
|
-
}
|
|
251
|
-
];
|
|
164
|
+
return {
|
|
165
|
+
Success: false,
|
|
166
|
+
ResultCode: this.getErrorCode(error),
|
|
167
|
+
Message: `Failed to schedule tweet: ${errorMessage}`,
|
|
168
|
+
Params,
|
|
169
|
+
};
|
|
252
170
|
}
|
|
171
|
+
}
|
|
253
172
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Generate a unique ID for scheduled tweet
|
|
175
|
+
*/
|
|
176
|
+
private generateScheduledTweetId(): string {
|
|
177
|
+
return `scheduled_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Get error code based on error type
|
|
182
|
+
*/
|
|
183
|
+
private getErrorCode(error: any): string {
|
|
184
|
+
if (error instanceof Error) {
|
|
185
|
+
if (error.message.includes('Rate Limit')) return 'RATE_LIMIT';
|
|
186
|
+
if (error.message.includes('Unauthorized')) return 'INVALID_TOKEN';
|
|
187
|
+
if (error.message.includes('character limit')) return 'CONTENT_TOO_LONG';
|
|
188
|
+
if (error.message.includes('media')) return 'INVALID_MEDIA';
|
|
189
|
+
if (error.message.includes('future')) return 'INVALID_SCHEDULE_TIME';
|
|
259
190
|
}
|
|
260
|
-
|
|
191
|
+
return 'ERROR';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Define the parameters this action expects
|
|
196
|
+
*/
|
|
197
|
+
public get Params(): ActionParam[] {
|
|
198
|
+
return [
|
|
199
|
+
...this.commonSocialParams,
|
|
200
|
+
{
|
|
201
|
+
Name: 'Content',
|
|
202
|
+
Type: 'Input',
|
|
203
|
+
Value: null,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
Name: 'ScheduledTime',
|
|
207
|
+
Type: 'Input',
|
|
208
|
+
Value: null,
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
Name: 'MediaFiles',
|
|
212
|
+
Type: 'Input',
|
|
213
|
+
Value: null,
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
Name: 'ReplyToTweetID',
|
|
217
|
+
Type: 'Input',
|
|
218
|
+
Value: null,
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
Name: 'QuoteTweetID',
|
|
222
|
+
Type: 'Input',
|
|
223
|
+
Value: null,
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
Name: 'PollOptions',
|
|
227
|
+
Type: 'Input',
|
|
228
|
+
Value: null,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
Name: 'PollDurationMinutes',
|
|
232
|
+
Type: 'Input',
|
|
233
|
+
Value: 1440, // Default 24 hours
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
Name: 'ScheduledTweetID',
|
|
237
|
+
Type: 'Output',
|
|
238
|
+
Value: null,
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
Name: 'ScheduledTweetData',
|
|
242
|
+
Type: 'Output',
|
|
243
|
+
Value: null,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
Name: 'EstimatedURL',
|
|
247
|
+
Type: 'Output',
|
|
248
|
+
Value: null,
|
|
249
|
+
},
|
|
250
|
+
];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Get action description
|
|
255
|
+
*/
|
|
256
|
+
public get Description(): string {
|
|
257
|
+
return 'Schedules a tweet for future posting on Twitter/X with optional media attachments, polls, replies, or quote tweets';
|
|
258
|
+
}
|
|
259
|
+
}
|