@memberjunction/actions-bizapps-social 2.111.0 → 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.
Files changed (204) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +6 -6
  3. package/dist/base/base-social.action.d.ts.map +1 -1
  4. package/dist/base/base-social.action.js +18 -24
  5. package/dist/base/base-social.action.js.map +1 -1
  6. package/dist/providers/buffer/buffer-base.action.d.ts.map +1 -1
  7. package/dist/providers/buffer/buffer-base.action.js +35 -34
  8. package/dist/providers/buffer/buffer-base.action.js.map +1 -1
  9. package/dist/providers/facebook/actions/boost-post.action.d.ts.map +1 -1
  10. package/dist/providers/facebook/actions/boost-post.action.js +33 -33
  11. package/dist/providers/facebook/actions/boost-post.action.js.map +1 -1
  12. package/dist/providers/facebook/actions/create-album.action.d.ts.map +1 -1
  13. package/dist/providers/facebook/actions/create-album.action.js +34 -36
  14. package/dist/providers/facebook/actions/create-album.action.js.map +1 -1
  15. package/dist/providers/facebook/actions/create-post.action.d.ts.map +1 -1
  16. package/dist/providers/facebook/actions/create-post.action.js +20 -20
  17. package/dist/providers/facebook/actions/create-post.action.js.map +1 -1
  18. package/dist/providers/facebook/actions/get-page-insights.action.d.ts.map +1 -1
  19. package/dist/providers/facebook/actions/get-page-insights.action.js +25 -27
  20. package/dist/providers/facebook/actions/get-page-insights.action.js.map +1 -1
  21. package/dist/providers/facebook/actions/get-page-posts.action.d.ts.map +1 -1
  22. package/dist/providers/facebook/actions/get-page-posts.action.js +19 -23
  23. package/dist/providers/facebook/actions/get-page-posts.action.js.map +1 -1
  24. package/dist/providers/facebook/actions/get-post-insights.action.d.ts.map +1 -1
  25. package/dist/providers/facebook/actions/get-post-insights.action.js +28 -32
  26. package/dist/providers/facebook/actions/get-post-insights.action.js.map +1 -1
  27. package/dist/providers/facebook/actions/respond-to-comments.action.d.ts.map +1 -1
  28. package/dist/providers/facebook/actions/respond-to-comments.action.js +42 -44
  29. package/dist/providers/facebook/actions/respond-to-comments.action.js.map +1 -1
  30. package/dist/providers/facebook/actions/schedule-post.action.d.ts.map +1 -1
  31. package/dist/providers/facebook/actions/schedule-post.action.js +29 -29
  32. package/dist/providers/facebook/actions/schedule-post.action.js.map +1 -1
  33. package/dist/providers/facebook/actions/search-posts.action.d.ts.map +1 -1
  34. package/dist/providers/facebook/actions/search-posts.action.js +37 -39
  35. package/dist/providers/facebook/actions/search-posts.action.js.map +1 -1
  36. package/dist/providers/facebook/facebook-base.action.d.ts.map +1 -1
  37. package/dist/providers/facebook/facebook-base.action.js +44 -59
  38. package/dist/providers/facebook/facebook-base.action.js.map +1 -1
  39. package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.d.ts.map +1 -1
  40. package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js +33 -31
  41. package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js.map +1 -1
  42. package/dist/providers/hootsuite/actions/create-scheduled-post.action.d.ts.map +1 -1
  43. package/dist/providers/hootsuite/actions/create-scheduled-post.action.js +28 -32
  44. package/dist/providers/hootsuite/actions/create-scheduled-post.action.js.map +1 -1
  45. package/dist/providers/hootsuite/actions/delete-scheduled-post.action.d.ts.map +1 -1
  46. package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js +19 -19
  47. package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js.map +1 -1
  48. package/dist/providers/hootsuite/actions/get-analytics.action.d.ts.map +1 -1
  49. package/dist/providers/hootsuite/actions/get-analytics.action.js +24 -26
  50. package/dist/providers/hootsuite/actions/get-analytics.action.js.map +1 -1
  51. package/dist/providers/hootsuite/actions/get-scheduled-posts.action.d.ts.map +1 -1
  52. package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js +22 -22
  53. package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js.map +1 -1
  54. package/dist/providers/hootsuite/actions/get-social-profiles.action.d.ts.map +1 -1
  55. package/dist/providers/hootsuite/actions/get-social-profiles.action.js +32 -34
  56. package/dist/providers/hootsuite/actions/get-social-profiles.action.js.map +1 -1
  57. package/dist/providers/hootsuite/actions/search-posts.action.d.ts.map +1 -1
  58. package/dist/providers/hootsuite/actions/search-posts.action.js +43 -52
  59. package/dist/providers/hootsuite/actions/search-posts.action.js.map +1 -1
  60. package/dist/providers/hootsuite/actions/update-scheduled-post.action.d.ts.map +1 -1
  61. package/dist/providers/hootsuite/actions/update-scheduled-post.action.js +30 -28
  62. package/dist/providers/hootsuite/actions/update-scheduled-post.action.js.map +1 -1
  63. package/dist/providers/hootsuite/hootsuite-base.action.d.ts.map +1 -1
  64. package/dist/providers/hootsuite/hootsuite-base.action.js +18 -20
  65. package/dist/providers/hootsuite/hootsuite-base.action.js.map +1 -1
  66. package/dist/providers/instagram/actions/create-post.action.d.ts.map +1 -1
  67. package/dist/providers/instagram/actions/create-post.action.js +27 -26
  68. package/dist/providers/instagram/actions/create-post.action.js.map +1 -1
  69. package/dist/providers/instagram/actions/create-story.action.d.ts.map +1 -1
  70. package/dist/providers/instagram/actions/create-story.action.js +35 -35
  71. package/dist/providers/instagram/actions/create-story.action.js.map +1 -1
  72. package/dist/providers/instagram/actions/get-account-insights.action.d.ts.map +1 -1
  73. package/dist/providers/instagram/actions/get-account-insights.action.js +38 -59
  74. package/dist/providers/instagram/actions/get-account-insights.action.js.map +1 -1
  75. package/dist/providers/instagram/actions/get-business-posts.action.d.ts.map +1 -1
  76. package/dist/providers/instagram/actions/get-business-posts.action.js +29 -29
  77. package/dist/providers/instagram/actions/get-business-posts.action.js.map +1 -1
  78. package/dist/providers/instagram/actions/get-comments.action.d.ts.map +1 -1
  79. package/dist/providers/instagram/actions/get-comments.action.js +36 -36
  80. package/dist/providers/instagram/actions/get-comments.action.js.map +1 -1
  81. package/dist/providers/instagram/actions/get-post-insights.action.d.ts.map +1 -1
  82. package/dist/providers/instagram/actions/get-post-insights.action.js +23 -25
  83. package/dist/providers/instagram/actions/get-post-insights.action.js.map +1 -1
  84. package/dist/providers/instagram/actions/schedule-post.action.d.ts.map +1 -1
  85. package/dist/providers/instagram/actions/schedule-post.action.js +25 -25
  86. package/dist/providers/instagram/actions/schedule-post.action.js.map +1 -1
  87. package/dist/providers/instagram/actions/search-posts.action.d.ts.map +1 -1
  88. package/dist/providers/instagram/actions/search-posts.action.js +56 -60
  89. package/dist/providers/instagram/actions/search-posts.action.js.map +1 -1
  90. package/dist/providers/instagram/instagram-base.action.d.ts.map +1 -1
  91. package/dist/providers/instagram/instagram-base.action.js +25 -27
  92. package/dist/providers/instagram/instagram-base.action.js.map +1 -1
  93. package/dist/providers/linkedin/actions/create-article.action.d.ts.map +1 -1
  94. package/dist/providers/linkedin/actions/create-article.action.js +55 -45
  95. package/dist/providers/linkedin/actions/create-article.action.js.map +1 -1
  96. package/dist/providers/linkedin/actions/create-post.action.d.ts.map +1 -1
  97. package/dist/providers/linkedin/actions/create-post.action.js +31 -29
  98. package/dist/providers/linkedin/actions/create-post.action.js.map +1 -1
  99. package/dist/providers/linkedin/actions/get-followers.action.d.ts.map +1 -1
  100. package/dist/providers/linkedin/actions/get-followers.action.js +28 -28
  101. package/dist/providers/linkedin/actions/get-followers.action.js.map +1 -1
  102. package/dist/providers/linkedin/actions/get-organization-posts.action.d.ts.map +1 -1
  103. package/dist/providers/linkedin/actions/get-organization-posts.action.js +20 -20
  104. package/dist/providers/linkedin/actions/get-organization-posts.action.js.map +1 -1
  105. package/dist/providers/linkedin/actions/get-personal-posts.action.d.ts.map +1 -1
  106. package/dist/providers/linkedin/actions/get-personal-posts.action.js +19 -19
  107. package/dist/providers/linkedin/actions/get-personal-posts.action.js.map +1 -1
  108. package/dist/providers/linkedin/actions/get-post-analytics.action.d.ts.map +1 -1
  109. package/dist/providers/linkedin/actions/get-post-analytics.action.js +25 -23
  110. package/dist/providers/linkedin/actions/get-post-analytics.action.js.map +1 -1
  111. package/dist/providers/linkedin/actions/schedule-post.action.d.ts.map +1 -1
  112. package/dist/providers/linkedin/actions/schedule-post.action.js +32 -30
  113. package/dist/providers/linkedin/actions/schedule-post.action.js.map +1 -1
  114. package/dist/providers/linkedin/actions/search-posts.action.d.ts.map +1 -1
  115. package/dist/providers/linkedin/actions/search-posts.action.js +28 -30
  116. package/dist/providers/linkedin/actions/search-posts.action.js.map +1 -1
  117. package/dist/providers/linkedin/linkedin-base.action.d.ts.map +1 -1
  118. package/dist/providers/linkedin/linkedin-base.action.js +33 -38
  119. package/dist/providers/linkedin/linkedin-base.action.js.map +1 -1
  120. package/dist/providers/tiktok/tiktok-base.action.d.ts.map +1 -1
  121. package/dist/providers/tiktok/tiktok-base.action.js +25 -26
  122. package/dist/providers/tiktok/tiktok-base.action.js.map +1 -1
  123. package/dist/providers/twitter/actions/create-thread.action.d.ts.map +1 -1
  124. package/dist/providers/twitter/actions/create-thread.action.js +25 -29
  125. package/dist/providers/twitter/actions/create-thread.action.js.map +1 -1
  126. package/dist/providers/twitter/actions/create-tweet.action.d.ts.map +1 -1
  127. package/dist/providers/twitter/actions/create-tweet.action.js +23 -23
  128. package/dist/providers/twitter/actions/create-tweet.action.js.map +1 -1
  129. package/dist/providers/twitter/actions/delete-tweet.action.d.ts.map +1 -1
  130. package/dist/providers/twitter/actions/delete-tweet.action.js +19 -19
  131. package/dist/providers/twitter/actions/delete-tweet.action.js.map +1 -1
  132. package/dist/providers/twitter/actions/get-analytics.action.d.ts.map +1 -1
  133. package/dist/providers/twitter/actions/get-analytics.action.js +40 -47
  134. package/dist/providers/twitter/actions/get-analytics.action.js.map +1 -1
  135. package/dist/providers/twitter/actions/get-mentions.action.d.ts.map +1 -1
  136. package/dist/providers/twitter/actions/get-mentions.action.js +30 -31
  137. package/dist/providers/twitter/actions/get-mentions.action.js.map +1 -1
  138. package/dist/providers/twitter/actions/get-timeline.action.d.ts.map +1 -1
  139. package/dist/providers/twitter/actions/get-timeline.action.js +29 -29
  140. package/dist/providers/twitter/actions/get-timeline.action.js.map +1 -1
  141. package/dist/providers/twitter/actions/schedule-tweet.action.d.ts.map +1 -1
  142. package/dist/providers/twitter/actions/schedule-tweet.action.js +26 -26
  143. package/dist/providers/twitter/actions/schedule-tweet.action.js.map +1 -1
  144. package/dist/providers/twitter/actions/search-tweets.action.d.ts.map +1 -1
  145. package/dist/providers/twitter/actions/search-tweets.action.js +56 -58
  146. package/dist/providers/twitter/actions/search-tweets.action.js.map +1 -1
  147. package/dist/providers/twitter/twitter-base.action.d.ts.map +1 -1
  148. package/dist/providers/twitter/twitter-base.action.js +58 -68
  149. package/dist/providers/twitter/twitter-base.action.js.map +1 -1
  150. package/dist/providers/youtube/youtube-base.action.d.ts +1 -1
  151. package/dist/providers/youtube/youtube-base.action.d.ts.map +1 -1
  152. package/dist/providers/youtube/youtube-base.action.js +22 -25
  153. package/dist/providers/youtube/youtube-base.action.js.map +1 -1
  154. package/package.json +5 -6
  155. package/src/base/base-social.action.ts +217 -224
  156. package/src/providers/buffer/buffer-base.action.ts +435 -441
  157. package/src/providers/facebook/actions/boost-post.action.ts +350 -386
  158. package/src/providers/facebook/actions/create-album.action.ts +291 -307
  159. package/src/providers/facebook/actions/create-post.action.ts +224 -227
  160. package/src/providers/facebook/actions/get-page-insights.action.ts +383 -403
  161. package/src/providers/facebook/actions/get-page-posts.action.ts +214 -225
  162. package/src/providers/facebook/actions/get-post-insights.action.ts +300 -316
  163. package/src/providers/facebook/actions/respond-to-comments.action.ts +319 -336
  164. package/src/providers/facebook/actions/schedule-post.action.ts +289 -292
  165. package/src/providers/facebook/actions/search-posts.action.ts +399 -413
  166. package/src/providers/facebook/facebook-base.action.ts +653 -670
  167. package/src/providers/hootsuite/actions/bulk-schedule-posts.action.ts +257 -257
  168. package/src/providers/hootsuite/actions/create-scheduled-post.action.ts +184 -189
  169. package/src/providers/hootsuite/actions/delete-scheduled-post.action.ts +160 -161
  170. package/src/providers/hootsuite/actions/get-analytics.action.ts +249 -254
  171. package/src/providers/hootsuite/actions/get-scheduled-posts.action.ts +206 -207
  172. package/src/providers/hootsuite/actions/get-social-profiles.action.ts +206 -205
  173. package/src/providers/hootsuite/actions/search-posts.action.ts +351 -369
  174. package/src/providers/hootsuite/actions/update-scheduled-post.action.ts +211 -209
  175. package/src/providers/hootsuite/hootsuite-base.action.ts +301 -307
  176. package/src/providers/instagram/actions/create-post.action.ts +276 -296
  177. package/src/providers/instagram/actions/create-story.action.ts +378 -394
  178. package/src/providers/instagram/actions/get-account-insights.action.ts +384 -420
  179. package/src/providers/instagram/actions/get-business-posts.action.ts +233 -242
  180. package/src/providers/instagram/actions/get-comments.action.ts +365 -377
  181. package/src/providers/instagram/actions/get-post-insights.action.ts +265 -273
  182. package/src/providers/instagram/actions/schedule-post.action.ts +233 -235
  183. package/src/providers/instagram/actions/search-posts.action.ts +512 -538
  184. package/src/providers/instagram/instagram-base.action.ts +368 -393
  185. package/src/providers/linkedin/actions/create-article.action.ts +275 -266
  186. package/src/providers/linkedin/actions/create-post.action.ts +179 -177
  187. package/src/providers/linkedin/actions/get-followers.action.ts +211 -211
  188. package/src/providers/linkedin/actions/get-organization-posts.action.ts +146 -147
  189. package/src/providers/linkedin/actions/get-personal-posts.action.ts +138 -139
  190. package/src/providers/linkedin/actions/get-post-analytics.action.ts +190 -189
  191. package/src/providers/linkedin/actions/schedule-post.action.ts +191 -189
  192. package/src/providers/linkedin/actions/search-posts.action.ts +275 -283
  193. package/src/providers/linkedin/linkedin-base.action.ts +407 -421
  194. package/src/providers/tiktok/tiktok-base.action.ts +305 -320
  195. package/src/providers/twitter/actions/create-thread.action.ts +203 -207
  196. package/src/providers/twitter/actions/create-tweet.action.ts +187 -188
  197. package/src/providers/twitter/actions/delete-tweet.action.ts +128 -129
  198. package/src/providers/twitter/actions/get-analytics.action.ts +402 -411
  199. package/src/providers/twitter/actions/get-mentions.action.ts +218 -219
  200. package/src/providers/twitter/actions/get-timeline.action.ts +232 -233
  201. package/src/providers/twitter/actions/schedule-tweet.action.ts +221 -222
  202. package/src/providers/twitter/actions/search-tweets.action.ts +540 -543
  203. package/src/providers/twitter/twitter-base.action.ts +541 -560
  204. package/src/providers/youtube/youtube-base.action.ts +320 -333
@@ -2,7 +2,7 @@ import { RegisterClass } from '@memberjunction/global';
2
2
  import { FacebookBaseAction, CreatePostData } from '../facebook-base.action';
3
3
  import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
4
4
  import { MediaFile, SocialMediaErrorCode } from '../../../base/base-social.action';
5
- import { LogStatus, LogError } from '@memberjunction/core';
5
+ import { LogStatus, LogError } from '@memberjunction/global';
6
6
  import axios from 'axios';
7
7
  import { BaseAction } from '@memberjunction/actions';
8
8
 
@@ -12,300 +12,297 @@ import { BaseAction } from '@memberjunction/actions';
12
12
  */
13
13
  @RegisterClass(BaseAction, 'FacebookSchedulePostAction')
14
14
  export class FacebookSchedulePostAction extends FacebookBaseAction {
15
- /**
16
- * Get action description
17
- */
18
- public get Description(): string {
19
- return 'Schedules a post to be published on a Facebook page at a specified future time (10 minutes to 6 months in advance)';
20
- }
21
-
22
- /**
23
- * Define the parameters for this action
24
- */
25
- public get Params(): ActionParam[] {
26
- return [
27
- ...this.commonSocialParams,
28
- {
29
- Name: 'PageID',
30
- Type: 'Input',
31
- Value: null,
32
- },
33
- {
34
- Name: 'Content',
35
- Type: 'Input',
36
- Value: null,
37
- },
38
- {
39
- Name: 'ScheduledTime',
40
- Type: 'Input',
41
- Value: null,
42
- },
43
- {
44
- Name: 'Link',
45
- Type: 'Input',
46
- Value: null,
47
- },
48
- {
49
- Name: 'MediaFiles',
50
- Type: 'Input',
51
- Value: null,
52
- },
53
- {
54
- Name: 'Tags',
55
- Type: 'Input',
56
- Value: null,
57
- },
58
- {
59
- Name: 'PlaceID',
60
- Type: 'Input',
61
- Value: null,
62
- },
63
- {
64
- Name: 'TargetingRestrictions',
65
- Type: 'Input',
66
- Value: null,
67
- },
68
- {
69
- Name: 'AllowReschedule',
70
- Type: 'Input',
71
- Value: false,
72
- }
73
- ];
74
- }
75
-
76
- /**
77
- * Execute the action
78
- */
79
- protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
80
- const { Params, ContextUser } = params;
81
-
82
- try {
83
- // Validate required parameters
84
- const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
85
- const pageId = this.getParamValue(Params, 'PageID');
86
- const scheduledTime = this.getParamValue(Params, 'ScheduledTime');
87
-
88
- if (!companyIntegrationId) {
89
- return {
90
- Success: false,
91
- Message: 'CompanyIntegrationID is required',
92
- ResultCode: 'INVALID_TOKEN'
93
- };
94
- }
95
-
96
- if (!pageId) {
97
- return {
98
- Success: false,
99
- Message: 'PageID is required',
100
- ResultCode: 'MISSING_REQUIRED_PARAM'
101
- };
102
- }
103
-
104
- if (!scheduledTime) {
105
- return {
106
- Success: false,
107
- Message: 'ScheduledTime is required',
108
- ResultCode: 'MISSING_REQUIRED_PARAM'
109
- };
110
- }
111
-
112
- // Initialize OAuth
113
- if (!await this.initializeOAuth(companyIntegrationId)) {
114
- return {
115
- Success: false,
116
- Message: 'Failed to initialize Facebook OAuth connection',
117
- ResultCode: 'INVALID_TOKEN'
118
- };
119
- }
120
-
121
- // Validate scheduled time
122
- const scheduledDate = new Date(scheduledTime);
123
- const now = new Date();
124
- const minScheduleTime = new Date(now.getTime() + 10 * 60 * 1000); // 10 minutes from now
125
- const maxScheduleTime = new Date(now.getTime() + 180 * 24 * 60 * 60 * 1000); // 6 months from now
126
-
127
- if (isNaN(scheduledDate.getTime())) {
128
- return {
129
- Success: false,
130
- Message: 'Invalid scheduled time format. Use ISO 8601 format.',
131
- ResultCode: 'INVALID_SCHEDULE_TIME'
132
- };
133
- }
134
-
135
- if (scheduledDate < minScheduleTime) {
136
- return {
137
- Success: false,
138
- Message: 'Scheduled time must be at least 10 minutes in the future',
139
- ResultCode: 'INVALID_SCHEDULE_TIME'
140
- };
141
- }
142
-
143
- if (scheduledDate > maxScheduleTime) {
144
- return {
145
- Success: false,
146
- Message: 'Scheduled time cannot be more than 6 months in the future',
147
- ResultCode: 'INVALID_SCHEDULE_TIME'
148
- };
149
- }
150
-
151
- // Get parameters
152
- const content = this.getParamValue(Params, 'Content') as string;
153
- const link = this.getParamValue(Params, 'Link') as string;
154
- const mediaFiles = this.getParamValue(Params, 'MediaFiles') as MediaFile[];
155
- const tags = this.getParamValue(Params, 'Tags') as string[];
156
- const placeId = this.getParamValue(Params, 'PlaceID') as string;
157
- const targetingRestrictions = this.getParamValue(Params, 'TargetingRestrictions') as any;
158
- const allowReschedule = this.getParamValue(Params, 'AllowReschedule') as boolean;
159
-
160
- // Validate that we have some content
161
- if (!content && !link && (!mediaFiles || mediaFiles.length === 0)) {
162
- return {
163
- Success: false,
164
- Message: 'At least one of Content, Link, or MediaFiles is required',
165
- ResultCode: 'MISSING_CONTENT'
166
- };
167
- }
168
-
169
- // Check for scheduling conflicts if requested
170
- if (!allowReschedule) {
171
- const hasConflict = await this.checkSchedulingConflict(pageId, scheduledDate);
172
- if (hasConflict) {
173
- return {
174
- Success: false,
175
- Message: 'Another post is already scheduled within 5 minutes of this time',
176
- ResultCode: 'SCHEDULE_CONFLICT'
177
- };
178
- }
179
- }
180
-
181
- // Build post data
182
- const postData: CreatePostData = {
183
- scheduled_publish_time: Math.floor(scheduledDate.getTime() / 1000),
184
- published: false // Must be false for scheduled posts
185
- };
186
-
187
- if (content) {
188
- postData.message = content;
189
- }
190
-
191
- if (link) {
192
- postData.link = link;
193
- }
194
-
195
- if (placeId) {
196
- postData.place = placeId;
197
- }
198
-
199
- if (tags && tags.length > 0) {
200
- postData.tags = tags;
201
- }
202
-
203
- if (targetingRestrictions) {
204
- (postData as any).targeting = targetingRestrictions;
205
- }
206
-
207
- // Handle media uploads
208
- if (mediaFiles && mediaFiles.length > 0) {
209
- LogStatus(`Uploading ${mediaFiles.length} media files for scheduled post...`);
210
-
211
- const mediaIds: string[] = [];
212
- for (const file of mediaFiles) {
213
- try {
214
- const mediaId = await this.uploadMediaToPage(pageId, file);
215
- mediaIds.push(mediaId);
216
- LogStatus(`Uploaded media: ${file.filename}`);
217
- } catch (error) {
218
- LogError(`Failed to upload media ${file.filename}: ${error}`);
219
- return {
220
- Success: false,
221
- Message: `Failed to upload media: ${error instanceof Error ? error.message : 'Unknown error'}`,
222
- ResultCode: 'INVALID_MEDIA'
223
- };
224
- }
225
- }
226
-
227
- // Attach media to post
228
- postData.attached_media = mediaIds.map(id => ({ media_fbid: id }));
229
- }
230
-
231
- // Create the scheduled post
232
- LogStatus(`Scheduling Facebook post for ${scheduledDate.toISOString()}...`);
233
- const post = await this.createPost(pageId, postData);
234
-
235
- // Get the scheduled post details
236
- const scheduledPost = await this.getScheduledPost(pageId, post.id);
237
-
238
- LogStatus(`Facebook post scheduled successfully: ${post.id}`);
239
-
240
- return {
241
- Success: true,
242
- Message: `Post scheduled for ${scheduledDate.toISOString()}`,
243
- ResultCode: 'SUCCESS',
244
- Params
245
- };
246
-
247
- } catch (error) {
248
- LogError(`Failed to schedule Facebook post: ${error instanceof Error ? error.message : 'Unknown error'}`);
249
-
250
- if (this.isAuthError(error)) {
251
- return this.handleOAuthError(error);
252
- }
253
-
15
+ /**
16
+ * Get action description
17
+ */
18
+ public get Description(): string {
19
+ return 'Schedules a post to be published on a Facebook page at a specified future time (10 minutes to 6 months in advance)';
20
+ }
21
+
22
+ /**
23
+ * Define the parameters for this action
24
+ */
25
+ public get Params(): ActionParam[] {
26
+ return [
27
+ ...this.commonSocialParams,
28
+ {
29
+ Name: 'PageID',
30
+ Type: 'Input',
31
+ Value: null,
32
+ },
33
+ {
34
+ Name: 'Content',
35
+ Type: 'Input',
36
+ Value: null,
37
+ },
38
+ {
39
+ Name: 'ScheduledTime',
40
+ Type: 'Input',
41
+ Value: null,
42
+ },
43
+ {
44
+ Name: 'Link',
45
+ Type: 'Input',
46
+ Value: null,
47
+ },
48
+ {
49
+ Name: 'MediaFiles',
50
+ Type: 'Input',
51
+ Value: null,
52
+ },
53
+ {
54
+ Name: 'Tags',
55
+ Type: 'Input',
56
+ Value: null,
57
+ },
58
+ {
59
+ Name: 'PlaceID',
60
+ Type: 'Input',
61
+ Value: null,
62
+ },
63
+ {
64
+ Name: 'TargetingRestrictions',
65
+ Type: 'Input',
66
+ Value: null,
67
+ },
68
+ {
69
+ Name: 'AllowReschedule',
70
+ Type: 'Input',
71
+ Value: false,
72
+ },
73
+ ];
74
+ }
75
+
76
+ /**
77
+ * Execute the action
78
+ */
79
+ protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
80
+ const { Params, ContextUser } = params;
81
+
82
+ try {
83
+ // Validate required parameters
84
+ const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
85
+ const pageId = this.getParamValue(Params, 'PageID');
86
+ const scheduledTime = this.getParamValue(Params, 'ScheduledTime');
87
+
88
+ if (!companyIntegrationId) {
89
+ return {
90
+ Success: false,
91
+ Message: 'CompanyIntegrationID is required',
92
+ ResultCode: 'INVALID_TOKEN',
93
+ };
94
+ }
95
+
96
+ if (!pageId) {
97
+ return {
98
+ Success: false,
99
+ Message: 'PageID is required',
100
+ ResultCode: 'MISSING_REQUIRED_PARAM',
101
+ };
102
+ }
103
+
104
+ if (!scheduledTime) {
105
+ return {
106
+ Success: false,
107
+ Message: 'ScheduledTime is required',
108
+ ResultCode: 'MISSING_REQUIRED_PARAM',
109
+ };
110
+ }
111
+
112
+ // Initialize OAuth
113
+ if (!(await this.initializeOAuth(companyIntegrationId))) {
114
+ return {
115
+ Success: false,
116
+ Message: 'Failed to initialize Facebook OAuth connection',
117
+ ResultCode: 'INVALID_TOKEN',
118
+ };
119
+ }
120
+
121
+ // Validate scheduled time
122
+ const scheduledDate = new Date(scheduledTime);
123
+ const now = new Date();
124
+ const minScheduleTime = new Date(now.getTime() + 10 * 60 * 1000); // 10 minutes from now
125
+ const maxScheduleTime = new Date(now.getTime() + 180 * 24 * 60 * 60 * 1000); // 6 months from now
126
+
127
+ if (isNaN(scheduledDate.getTime())) {
128
+ return {
129
+ Success: false,
130
+ Message: 'Invalid scheduled time format. Use ISO 8601 format.',
131
+ ResultCode: 'INVALID_SCHEDULE_TIME',
132
+ };
133
+ }
134
+
135
+ if (scheduledDate < minScheduleTime) {
136
+ return {
137
+ Success: false,
138
+ Message: 'Scheduled time must be at least 10 minutes in the future',
139
+ ResultCode: 'INVALID_SCHEDULE_TIME',
140
+ };
141
+ }
142
+
143
+ if (scheduledDate > maxScheduleTime) {
144
+ return {
145
+ Success: false,
146
+ Message: 'Scheduled time cannot be more than 6 months in the future',
147
+ ResultCode: 'INVALID_SCHEDULE_TIME',
148
+ };
149
+ }
150
+
151
+ // Get parameters
152
+ const content = this.getParamValue(Params, 'Content') as string;
153
+ const link = this.getParamValue(Params, 'Link') as string;
154
+ const mediaFiles = this.getParamValue(Params, 'MediaFiles') as MediaFile[];
155
+ const tags = this.getParamValue(Params, 'Tags') as string[];
156
+ const placeId = this.getParamValue(Params, 'PlaceID') as string;
157
+ const targetingRestrictions = this.getParamValue(Params, 'TargetingRestrictions') as any;
158
+ const allowReschedule = this.getParamValue(Params, 'AllowReschedule') as boolean;
159
+
160
+ // Validate that we have some content
161
+ if (!content && !link && (!mediaFiles || mediaFiles.length === 0)) {
162
+ return {
163
+ Success: false,
164
+ Message: 'At least one of Content, Link, or MediaFiles is required',
165
+ ResultCode: 'MISSING_CONTENT',
166
+ };
167
+ }
168
+
169
+ // Check for scheduling conflicts if requested
170
+ if (!allowReschedule) {
171
+ const hasConflict = await this.checkSchedulingConflict(pageId, scheduledDate);
172
+ if (hasConflict) {
173
+ return {
174
+ Success: false,
175
+ Message: 'Another post is already scheduled within 5 minutes of this time',
176
+ ResultCode: 'SCHEDULE_CONFLICT',
177
+ };
178
+ }
179
+ }
180
+
181
+ // Build post data
182
+ const postData: CreatePostData = {
183
+ scheduled_publish_time: Math.floor(scheduledDate.getTime() / 1000),
184
+ published: false, // Must be false for scheduled posts
185
+ };
186
+
187
+ if (content) {
188
+ postData.message = content;
189
+ }
190
+
191
+ if (link) {
192
+ postData.link = link;
193
+ }
194
+
195
+ if (placeId) {
196
+ postData.place = placeId;
197
+ }
198
+
199
+ if (tags && tags.length > 0) {
200
+ postData.tags = tags;
201
+ }
202
+
203
+ if (targetingRestrictions) {
204
+ (postData as any).targeting = targetingRestrictions;
205
+ }
206
+
207
+ // Handle media uploads
208
+ if (mediaFiles && mediaFiles.length > 0) {
209
+ LogStatus(`Uploading ${mediaFiles.length} media files for scheduled post...`);
210
+
211
+ const mediaIds: string[] = [];
212
+ for (const file of mediaFiles) {
213
+ try {
214
+ const mediaId = await this.uploadMediaToPage(pageId, file);
215
+ mediaIds.push(mediaId);
216
+ LogStatus(`Uploaded media: ${file.filename}`);
217
+ } catch (error) {
218
+ LogError(`Failed to upload media ${file.filename}: ${error}`);
254
219
  return {
255
- Success: false,
256
- Message: error instanceof Error ? error.message : 'Unknown error occurred',
257
- ResultCode: 'ERROR'
220
+ Success: false,
221
+ Message: `Failed to upload media: ${error instanceof Error ? error.message : 'Unknown error'}`,
222
+ ResultCode: 'INVALID_MEDIA',
258
223
  };
224
+ }
259
225
  }
260
- }
261
226
 
262
- /**
263
- * Check if there's a scheduling conflict within 5 minutes
264
- */
265
- private async checkSchedulingConflict(pageId: string, scheduledTime: Date): Promise<boolean> {
266
- try {
267
- const pageToken = await this.getPageAccessToken(pageId);
268
- const fiveMinutesBefore = new Date(scheduledTime.getTime() - 5 * 60 * 1000);
269
- const fiveMinutesAfter = new Date(scheduledTime.getTime() + 5 * 60 * 1000);
270
-
271
- // Get scheduled posts in the time window
272
- const response = await axios.get(`${this.apiBaseUrl}/${pageId}/scheduled_posts`, {
273
- params: {
274
- access_token: pageToken,
275
- since: Math.floor(fiveMinutesBefore.getTime() / 1000),
276
- until: Math.floor(fiveMinutesAfter.getTime() / 1000),
277
- limit: 10
278
- }
279
- });
280
-
281
- const scheduledPosts = response.data.data || [];
282
- return scheduledPosts.length > 0;
283
- } catch (error) {
284
- LogError(`Failed to check scheduling conflicts: ${error}`);
285
- return false; // Don't block on error
286
- }
227
+ // Attach media to post
228
+ postData.attached_media = mediaIds.map((id) => ({ media_fbid: id }));
229
+ }
230
+
231
+ // Create the scheduled post
232
+ LogStatus(`Scheduling Facebook post for ${scheduledDate.toISOString()}...`);
233
+ const post = await this.createPost(pageId, postData);
234
+
235
+ // Get the scheduled post details
236
+ const scheduledPost = await this.getScheduledPost(pageId, post.id);
237
+
238
+ LogStatus(`Facebook post scheduled successfully: ${post.id}`);
239
+
240
+ return {
241
+ Success: true,
242
+ Message: `Post scheduled for ${scheduledDate.toISOString()}`,
243
+ ResultCode: 'SUCCESS',
244
+ Params,
245
+ };
246
+ } catch (error) {
247
+ LogError(`Failed to schedule Facebook post: ${error instanceof Error ? error.message : 'Unknown error'}`);
248
+
249
+ if (this.isAuthError(error)) {
250
+ return this.handleOAuthError(error);
251
+ }
252
+
253
+ return {
254
+ Success: false,
255
+ Message: error instanceof Error ? error.message : 'Unknown error occurred',
256
+ ResultCode: 'ERROR',
257
+ };
287
258
  }
288
-
289
- /**
290
- * Get details of a scheduled post
291
- */
292
- private async getScheduledPost(pageId: string, postId: string): Promise<any> {
293
- try {
294
- const pageToken = await this.getPageAccessToken(pageId);
295
-
296
- const response = await axios.get(`${this.apiBaseUrl}/${postId}`, {
297
- params: {
298
- access_token: pageToken,
299
- fields: 'id,message,scheduled_publish_time,is_published'
300
- }
301
- });
302
-
303
- return response.data;
304
- } catch (error) {
305
- LogError(`Failed to get scheduled post details: ${error}`);
306
- return null;
307
- }
259
+ }
260
+
261
+ /**
262
+ * Check if there's a scheduling conflict within 5 minutes
263
+ */
264
+ private async checkSchedulingConflict(pageId: string, scheduledTime: Date): Promise<boolean> {
265
+ try {
266
+ const pageToken = await this.getPageAccessToken(pageId);
267
+ const fiveMinutesBefore = new Date(scheduledTime.getTime() - 5 * 60 * 1000);
268
+ const fiveMinutesAfter = new Date(scheduledTime.getTime() + 5 * 60 * 1000);
269
+
270
+ // Get scheduled posts in the time window
271
+ const response = await axios.get(`${this.apiBaseUrl}/${pageId}/scheduled_posts`, {
272
+ params: {
273
+ access_token: pageToken,
274
+ since: Math.floor(fiveMinutesBefore.getTime() / 1000),
275
+ until: Math.floor(fiveMinutesAfter.getTime() / 1000),
276
+ limit: 10,
277
+ },
278
+ });
279
+
280
+ const scheduledPosts = response.data.data || [];
281
+ return scheduledPosts.length > 0;
282
+ } catch (error) {
283
+ LogError(`Failed to check scheduling conflicts: ${error}`);
284
+ return false; // Don't block on error
308
285
  }
309
-
310
-
311
- }
286
+ }
287
+
288
+ /**
289
+ * Get details of a scheduled post
290
+ */
291
+ private async getScheduledPost(pageId: string, postId: string): Promise<any> {
292
+ try {
293
+ const pageToken = await this.getPageAccessToken(pageId);
294
+
295
+ const response = await axios.get(`${this.apiBaseUrl}/${postId}`, {
296
+ params: {
297
+ access_token: pageToken,
298
+ fields: 'id,message,scheduled_publish_time,is_published',
299
+ },
300
+ });
301
+
302
+ return response.data;
303
+ } catch (error) {
304
+ LogError(`Failed to get scheduled post details: ${error}`);
305
+ return null;
306
+ }
307
+ }
308
+ }