@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.
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 } from '../facebook-base.action';
3
3
  import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
4
4
  import { 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,402 +12,366 @@ import { BaseAction } from '@memberjunction/actions';
12
12
  */
13
13
  @RegisterClass(BaseAction, 'FacebookBoostPostAction')
14
14
  export class FacebookBoostPostAction extends FacebookBaseAction {
15
- /**
16
- * Get action description
17
- */
18
- public get Description(): string {
19
- return 'Boosts (promotes) a Facebook post to reach a wider audience through paid advertising';
20
- }
21
-
22
- /**
23
- * Define the parameters for this action
24
- */
25
- public get Params(): ActionParam[] {
26
- return [
27
- ...this.commonSocialParams,
28
- {
29
- Name: 'PostID',
30
- Type: 'Input',
31
- Value: null,
32
- },
33
- {
34
- Name: 'AdAccountID',
35
- Type: 'Input',
36
- Value: null,
37
- },
38
- {
39
- Name: 'Budget',
40
- Type: 'Input',
41
- Value: null,
42
- },
43
- {
44
- Name: 'Duration',
45
- Type: 'Input',
46
- Value: 7,
47
- },
48
- {
49
- Name: 'Objective',
50
- Type: 'Input',
51
- Value: 'POST_ENGAGEMENT',
52
- },
53
- {
54
- Name: 'AudienceType',
55
- Type: 'Input',
56
- Value: 'AUTO',
57
- },
58
- {
59
- Name: 'TargetingSpec',
60
- Type: 'Input',
61
- Value: null,
62
- },
63
- {
64
- Name: 'StartTime',
65
- Type: 'Input',
66
- Value: null,
67
- },
68
- {
69
- Name: 'CallToAction',
70
- Type: 'Input',
71
- Value: null,
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 postId = this.getParamValue(Params, 'PostID');
86
- const adAccountId = this.getParamValue(Params, 'AdAccountID');
87
- const budget = this.getParamValue(Params, 'Budget') as number;
88
-
89
- if (!companyIntegrationId) {
90
- return {
91
- Success: false,
92
- Message: 'CompanyIntegrationID is required',
93
- ResultCode: 'INVALID_TOKEN'
94
- };
95
- }
96
-
97
- if (!postId) {
98
- return {
99
- Success: false,
100
- Message: 'PostID is required',
101
- ResultCode: 'MISSING_REQUIRED_PARAM'
102
- };
103
- }
104
-
105
- if (!adAccountId) {
106
- return {
107
- Success: false,
108
- Message: 'AdAccountID is required',
109
- ResultCode: 'MISSING_REQUIRED_PARAM'
110
- };
111
- }
112
-
113
- if (!budget || budget <= 0) {
114
- return {
115
- Success: false,
116
- Message: 'Budget must be a positive number',
117
- ResultCode: 'INVALID_BUDGET'
118
- };
119
- }
120
-
121
- // Initialize OAuth
122
- if (!await this.initializeOAuth(companyIntegrationId)) {
123
- return {
124
- Success: false,
125
- Message: 'Failed to initialize Facebook OAuth connection',
126
- ResultCode: 'INVALID_TOKEN'
127
- };
128
- }
129
-
130
- // Get parameters
131
- const duration = this.getParamValue(Params, 'Duration') as number || 7;
132
- const objective = this.getParamValue(Params, 'Objective') as string || 'POST_ENGAGEMENT';
133
- const audienceType = this.getParamValue(Params, 'AudienceType') as string || 'AUTO';
134
- const targetingSpec = this.getParamValue(Params, 'TargetingSpec') as any;
135
- const startTime = this.getParamValue(Params, 'StartTime') as string;
136
- const callToAction = this.getParamValue(Params, 'CallToAction') as string;
137
-
138
- // Validate duration
139
- if (duration < 1 || duration > 30) {
140
- return {
141
- Success: false,
142
- Message: 'Duration must be between 1 and 30 days',
143
- ResultCode: 'INVALID_DURATION'
144
- };
145
- }
146
-
147
- // Extract page ID from post ID
148
- const pageId = postId.split('_')[0];
149
-
150
- // Get page access token
151
- const pageToken = await this.getPageAccessToken(pageId);
152
-
153
- LogStatus(`Creating boost campaign for post ${postId}...`);
154
-
155
- // Step 1: Create campaign
156
- const campaignName = `Boost Post ${postId} - ${new Date().toISOString()}`;
157
- const campaign = await this.createCampaign(adAccountId, campaignName, objective);
158
-
159
- // Step 2: Create ad set with targeting
160
- const adSetName = `Ad Set for ${postId}`;
161
- const targeting = this.buildTargeting(audienceType, targetingSpec, pageId);
162
- const adSet = await this.createAdSet(
163
- adAccountId,
164
- campaign.id,
165
- adSetName,
166
- budget,
167
- duration,
168
- targeting,
169
- startTime
170
- );
171
-
172
- // Step 3: Create ad creative from post
173
- const creative = await this.createCreativeFromPost(adAccountId, postId, pageToken, callToAction);
174
-
175
- // Step 4: Create the ad
176
- const adName = `Boosted Post ${postId}`;
177
- const ad = await this.createAd(adAccountId, adSet.id, creative.id, adName);
178
-
179
- // Get boost summary
180
- const boostSummary = {
181
- campaignId: campaign.id,
182
- adSetId: adSet.id,
183
- adId: ad.id,
184
- creativeId: creative.id,
185
- postId,
186
- budget,
187
- duration,
188
- objective,
189
- audienceType,
190
- startTime: adSet.start_time,
191
- endTime: adSet.end_time,
192
- status: ad.status,
193
- reviewStatus: ad.review_feedback?.global_review_status || 'PENDING',
194
- previewUrl: `https://www.facebook.com/ads/manager/account/campaigns?act=${adAccountId}&selected_campaign_ids=${campaign.id}`
195
- };
196
-
197
- LogStatus(`Successfully created boost campaign for post ${postId}`);
198
-
199
- return {
200
- Success: true,
201
- Message: 'Post boost created successfully',
202
- ResultCode: 'SUCCESS',
203
- Params
204
- };
205
-
206
- } catch (error) {
207
- LogError(`Failed to boost Facebook post: ${error instanceof Error ? error.message : 'Unknown error'}`);
208
-
209
- if (this.isAuthError(error)) {
210
- return this.handleOAuthError(error);
211
- }
212
-
213
- // Check for specific ad-related errors
214
- if (error instanceof Error) {
215
- if (error.message.includes('permissions')) {
216
- return {
217
- Success: false,
218
- Message: 'Insufficient permissions. Ensure the token has ads_management permission.',
219
- ResultCode: 'INSUFFICIENT_PERMISSIONS'
220
- };
221
- }
222
- if (error.message.includes('budget')) {
223
- return {
224
- Success: false,
225
- Message: 'Invalid budget. Check minimum budget requirements for your currency.',
226
- ResultCode: 'INVALID_BUDGET'
227
- };
228
- }
229
- }
230
-
231
- return {
232
- Success: false,
233
- Message: error instanceof Error ? error.message : 'Unknown error occurred',
234
- ResultCode: 'ERROR'
235
- };
236
- }
237
- }
238
-
239
- /**
240
- * Create a campaign
241
- */
242
- private async createCampaign(adAccountId: string, name: string, objective: string): Promise<any> {
243
- const response = await this.axiosInstance.post(
244
- `/${adAccountId}/campaigns`,
245
- {
246
- name,
247
- objective,
248
- status: 'PAUSED', // Start paused for safety
249
- special_ad_categories: [] // Required field
250
- }
251
- );
252
-
253
- return response.data;
254
- }
15
+ /**
16
+ * Get action description
17
+ */
18
+ public get Description(): string {
19
+ return 'Boosts (promotes) a Facebook post to reach a wider audience through paid advertising';
20
+ }
21
+
22
+ /**
23
+ * Define the parameters for this action
24
+ */
25
+ public get Params(): ActionParam[] {
26
+ return [
27
+ ...this.commonSocialParams,
28
+ {
29
+ Name: 'PostID',
30
+ Type: 'Input',
31
+ Value: null,
32
+ },
33
+ {
34
+ Name: 'AdAccountID',
35
+ Type: 'Input',
36
+ Value: null,
37
+ },
38
+ {
39
+ Name: 'Budget',
40
+ Type: 'Input',
41
+ Value: null,
42
+ },
43
+ {
44
+ Name: 'Duration',
45
+ Type: 'Input',
46
+ Value: 7,
47
+ },
48
+ {
49
+ Name: 'Objective',
50
+ Type: 'Input',
51
+ Value: 'POST_ENGAGEMENT',
52
+ },
53
+ {
54
+ Name: 'AudienceType',
55
+ Type: 'Input',
56
+ Value: 'AUTO',
57
+ },
58
+ {
59
+ Name: 'TargetingSpec',
60
+ Type: 'Input',
61
+ Value: null,
62
+ },
63
+ {
64
+ Name: 'StartTime',
65
+ Type: 'Input',
66
+ Value: null,
67
+ },
68
+ {
69
+ Name: 'CallToAction',
70
+ Type: 'Input',
71
+ Value: null,
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 postId = this.getParamValue(Params, 'PostID');
86
+ const adAccountId = this.getParamValue(Params, 'AdAccountID');
87
+ const budget = this.getParamValue(Params, 'Budget') as number;
88
+
89
+ if (!companyIntegrationId) {
90
+ return {
91
+ Success: false,
92
+ Message: 'CompanyIntegrationID is required',
93
+ ResultCode: 'INVALID_TOKEN',
94
+ };
95
+ }
255
96
 
256
- /**
257
- * Create an ad set
258
- */
259
- private async createAdSet(
260
- adAccountId: string,
261
- campaignId: string,
262
- name: string,
263
- budget: number,
264
- durationDays: number,
265
- targeting: any,
266
- startTime?: string
267
- ): Promise<any> {
268
- const now = new Date();
269
- const start = startTime ? new Date(startTime) : now;
270
- const end = new Date(start);
271
- end.setDate(end.getDate() + durationDays);
272
-
273
- // Calculate daily budget
274
- const dailyBudget = Math.ceil((budget * 100) / durationDays); // Convert to cents
275
-
276
- const response = await this.axiosInstance.post(
277
- `/${adAccountId}/adsets`,
278
- {
279
- name,
280
- campaign_id: campaignId,
281
- daily_budget: dailyBudget,
282
- billing_event: 'IMPRESSIONS',
283
- optimization_goal: this.getOptimizationGoal(campaignId),
284
- bid_strategy: 'LOWEST_COST_WITHOUT_CAP',
285
- targeting,
286
- start_time: start.toISOString(),
287
- end_time: end.toISOString(),
288
- status: 'PAUSED'
289
- }
290
- );
291
-
292
- return response.data;
293
- }
97
+ if (!postId) {
98
+ return {
99
+ Success: false,
100
+ Message: 'PostID is required',
101
+ ResultCode: 'MISSING_REQUIRED_PARAM',
102
+ };
103
+ }
294
104
 
295
- /**
296
- * Create creative from existing post
297
- */
298
- private async createCreativeFromPost(
299
- adAccountId: string,
300
- postId: string,
301
- pageToken: string,
302
- callToAction?: string
303
- ): Promise<any> {
304
- const creativeData: any = {
305
- name: `Creative for ${postId}`,
306
- object_story_id: postId
105
+ if (!adAccountId) {
106
+ return {
107
+ Success: false,
108
+ Message: 'AdAccountID is required',
109
+ ResultCode: 'MISSING_REQUIRED_PARAM',
307
110
  };
111
+ }
308
112
 
309
- if (callToAction) {
310
- // Get post details to add CTA
311
- const postResponse = await axios.get(
312
- `${this.apiBaseUrl}/${postId}`,
313
- {
314
- params: {
315
- access_token: pageToken,
316
- fields: 'permalink_url'
317
- }
318
- }
319
- );
320
-
321
- creativeData.call_to_action = {
322
- type: callToAction,
323
- value: {
324
- link: postResponse.data.permalink_url
325
- }
326
- };
113
+ if (!budget || budget <= 0) {
114
+ return {
115
+ Success: false,
116
+ Message: 'Budget must be a positive number',
117
+ ResultCode: 'INVALID_BUDGET',
118
+ };
119
+ }
120
+
121
+ // Initialize OAuth
122
+ if (!(await this.initializeOAuth(companyIntegrationId))) {
123
+ return {
124
+ Success: false,
125
+ Message: 'Failed to initialize Facebook OAuth connection',
126
+ ResultCode: 'INVALID_TOKEN',
127
+ };
128
+ }
129
+
130
+ // Get parameters
131
+ const duration = (this.getParamValue(Params, 'Duration') as number) || 7;
132
+ const objective = (this.getParamValue(Params, 'Objective') as string) || 'POST_ENGAGEMENT';
133
+ const audienceType = (this.getParamValue(Params, 'AudienceType') as string) || 'AUTO';
134
+ const targetingSpec = this.getParamValue(Params, 'TargetingSpec') as any;
135
+ const startTime = this.getParamValue(Params, 'StartTime') as string;
136
+ const callToAction = this.getParamValue(Params, 'CallToAction') as string;
137
+
138
+ // Validate duration
139
+ if (duration < 1 || duration > 30) {
140
+ return {
141
+ Success: false,
142
+ Message: 'Duration must be between 1 and 30 days',
143
+ ResultCode: 'INVALID_DURATION',
144
+ };
145
+ }
146
+
147
+ // Extract page ID from post ID
148
+ const pageId = postId.split('_')[0];
149
+
150
+ // Get page access token
151
+ const pageToken = await this.getPageAccessToken(pageId);
152
+
153
+ LogStatus(`Creating boost campaign for post ${postId}...`);
154
+
155
+ // Step 1: Create campaign
156
+ const campaignName = `Boost Post ${postId} - ${new Date().toISOString()}`;
157
+ const campaign = await this.createCampaign(adAccountId, campaignName, objective);
158
+
159
+ // Step 2: Create ad set with targeting
160
+ const adSetName = `Ad Set for ${postId}`;
161
+ const targeting = this.buildTargeting(audienceType, targetingSpec, pageId);
162
+ const adSet = await this.createAdSet(adAccountId, campaign.id, adSetName, budget, duration, targeting, startTime);
163
+
164
+ // Step 3: Create ad creative from post
165
+ const creative = await this.createCreativeFromPost(adAccountId, postId, pageToken, callToAction);
166
+
167
+ // Step 4: Create the ad
168
+ const adName = `Boosted Post ${postId}`;
169
+ const ad = await this.createAd(adAccountId, adSet.id, creative.id, adName);
170
+
171
+ // Get boost summary
172
+ const boostSummary = {
173
+ campaignId: campaign.id,
174
+ adSetId: adSet.id,
175
+ adId: ad.id,
176
+ creativeId: creative.id,
177
+ postId,
178
+ budget,
179
+ duration,
180
+ objective,
181
+ audienceType,
182
+ startTime: adSet.start_time,
183
+ endTime: adSet.end_time,
184
+ status: ad.status,
185
+ reviewStatus: ad.review_feedback?.global_review_status || 'PENDING',
186
+ previewUrl: `https://www.facebook.com/ads/manager/account/campaigns?act=${adAccountId}&selected_campaign_ids=${campaign.id}`,
187
+ };
188
+
189
+ LogStatus(`Successfully created boost campaign for post ${postId}`);
190
+
191
+ return {
192
+ Success: true,
193
+ Message: 'Post boost created successfully',
194
+ ResultCode: 'SUCCESS',
195
+ Params,
196
+ };
197
+ } catch (error) {
198
+ LogError(`Failed to boost Facebook post: ${error instanceof Error ? error.message : 'Unknown error'}`);
199
+
200
+ if (this.isAuthError(error)) {
201
+ return this.handleOAuthError(error);
202
+ }
203
+
204
+ // Check for specific ad-related errors
205
+ if (error instanceof Error) {
206
+ if (error.message.includes('permissions')) {
207
+ return {
208
+ Success: false,
209
+ Message: 'Insufficient permissions. Ensure the token has ads_management permission.',
210
+ ResultCode: 'INSUFFICIENT_PERMISSIONS',
211
+ };
327
212
  }
213
+ if (error.message.includes('budget')) {
214
+ return {
215
+ Success: false,
216
+ Message: 'Invalid budget. Check minimum budget requirements for your currency.',
217
+ ResultCode: 'INVALID_BUDGET',
218
+ };
219
+ }
220
+ }
328
221
 
329
- const response = await this.axiosInstance.post(
330
- `/${adAccountId}/adcreatives`,
331
- creativeData
332
- );
333
-
334
- return response.data;
222
+ return {
223
+ Success: false,
224
+ Message: error instanceof Error ? error.message : 'Unknown error occurred',
225
+ ResultCode: 'ERROR',
226
+ };
335
227
  }
336
-
337
- /**
338
- * Create the ad
339
- */
340
- private async createAd(
341
- adAccountId: string,
342
- adSetId: string,
343
- creativeId: string,
344
- name: string
345
- ): Promise<any> {
346
- const response = await this.axiosInstance.post(
347
- `/${adAccountId}/ads`,
348
- {
349
- name,
350
- adset_id: adSetId,
351
- creative: { creative_id: creativeId },
352
- status: 'PAUSED'
353
- }
354
- );
355
-
356
- return response.data;
228
+ }
229
+
230
+ /**
231
+ * Create a campaign
232
+ */
233
+ private async createCampaign(adAccountId: string, name: string, objective: string): Promise<any> {
234
+ const response = await this.axiosInstance.post(`/${adAccountId}/campaigns`, {
235
+ name,
236
+ objective,
237
+ status: 'PAUSED', // Start paused for safety
238
+ special_ad_categories: [], // Required field
239
+ });
240
+
241
+ return response.data;
242
+ }
243
+
244
+ /**
245
+ * Create an ad set
246
+ */
247
+ private async createAdSet(
248
+ adAccountId: string,
249
+ campaignId: string,
250
+ name: string,
251
+ budget: number,
252
+ durationDays: number,
253
+ targeting: any,
254
+ startTime?: string
255
+ ): Promise<any> {
256
+ const now = new Date();
257
+ const start = startTime ? new Date(startTime) : now;
258
+ const end = new Date(start);
259
+ end.setDate(end.getDate() + durationDays);
260
+
261
+ // Calculate daily budget
262
+ const dailyBudget = Math.ceil((budget * 100) / durationDays); // Convert to cents
263
+
264
+ const response = await this.axiosInstance.post(`/${adAccountId}/adsets`, {
265
+ name,
266
+ campaign_id: campaignId,
267
+ daily_budget: dailyBudget,
268
+ billing_event: 'IMPRESSIONS',
269
+ optimization_goal: this.getOptimizationGoal(campaignId),
270
+ bid_strategy: 'LOWEST_COST_WITHOUT_CAP',
271
+ targeting,
272
+ start_time: start.toISOString(),
273
+ end_time: end.toISOString(),
274
+ status: 'PAUSED',
275
+ });
276
+
277
+ return response.data;
278
+ }
279
+
280
+ /**
281
+ * Create creative from existing post
282
+ */
283
+ private async createCreativeFromPost(adAccountId: string, postId: string, pageToken: string, callToAction?: string): Promise<any> {
284
+ const creativeData: any = {
285
+ name: `Creative for ${postId}`,
286
+ object_story_id: postId,
287
+ };
288
+
289
+ if (callToAction) {
290
+ // Get post details to add CTA
291
+ const postResponse = await axios.get(`${this.apiBaseUrl}/${postId}`, {
292
+ params: {
293
+ access_token: pageToken,
294
+ fields: 'permalink_url',
295
+ },
296
+ });
297
+
298
+ creativeData.call_to_action = {
299
+ type: callToAction,
300
+ value: {
301
+ link: postResponse.data.permalink_url,
302
+ },
303
+ };
357
304
  }
358
305
 
359
- /**
360
- * Build targeting specification
361
- */
362
- private buildTargeting(audienceType: string, customTargeting: any, pageId: string): any {
363
- const baseTargeting: any = {
364
- geo_locations: {
365
- countries: ['US'] // Default to US, can be overridden
366
- }
367
- };
368
-
369
- switch (audienceType) {
370
- case 'FANS':
371
- baseTargeting.connections = [pageId];
372
- break;
373
- case 'FANS_AND_CONNECTIONS':
374
- baseTargeting.connections = [pageId];
375
- baseTargeting.friends_of_connections = [pageId];
376
- break;
377
- case 'CUSTOM':
378
- if (customTargeting) {
379
- return { ...baseTargeting, ...customTargeting };
380
- }
381
- break;
382
- case 'AUTO':
383
- default:
384
- // Facebook will automatically optimize targeting
385
- break;
306
+ const response = await this.axiosInstance.post(`/${adAccountId}/adcreatives`, creativeData);
307
+
308
+ return response.data;
309
+ }
310
+
311
+ /**
312
+ * Create the ad
313
+ */
314
+ private async createAd(adAccountId: string, adSetId: string, creativeId: string, name: string): Promise<any> {
315
+ const response = await this.axiosInstance.post(`/${adAccountId}/ads`, {
316
+ name,
317
+ adset_id: adSetId,
318
+ creative: { creative_id: creativeId },
319
+ status: 'PAUSED',
320
+ });
321
+
322
+ return response.data;
323
+ }
324
+
325
+ /**
326
+ * Build targeting specification
327
+ */
328
+ private buildTargeting(audienceType: string, customTargeting: any, pageId: string): any {
329
+ const baseTargeting: any = {
330
+ geo_locations: {
331
+ countries: ['US'], // Default to US, can be overridden
332
+ },
333
+ };
334
+
335
+ switch (audienceType) {
336
+ case 'FANS':
337
+ baseTargeting.connections = [pageId];
338
+ break;
339
+ case 'FANS_AND_CONNECTIONS':
340
+ baseTargeting.connections = [pageId];
341
+ baseTargeting.friends_of_connections = [pageId];
342
+ break;
343
+ case 'CUSTOM':
344
+ if (customTargeting) {
345
+ return { ...baseTargeting, ...customTargeting };
386
346
  }
387
-
388
- // Add any custom targeting on top
389
- if (customTargeting && audienceType !== 'CUSTOM') {
390
- Object.assign(baseTargeting, customTargeting);
391
- }
392
-
393
- return baseTargeting;
347
+ break;
348
+ case 'AUTO':
349
+ default:
350
+ // Facebook will automatically optimize targeting
351
+ break;
394
352
  }
395
353
 
396
- /**
397
- * Get optimization goal based on objective
398
- */
399
- private getOptimizationGoal(objective: string): string {
400
- const goalMap: Record<string, string> = {
401
- 'POST_ENGAGEMENT': 'POST_ENGAGEMENT',
402
- 'REACH': 'REACH',
403
- 'LINK_CLICKS': 'LINK_CLICKS',
404
- 'PAGE_LIKES': 'PAGE_LIKES',
405
- 'BRAND_AWARENESS': 'AD_RECALL_LIFT',
406
- 'VIDEO_VIEWS': 'VIDEO_VIEWS'
407
- };
408
-
409
- return goalMap[objective] || 'POST_ENGAGEMENT';
354
+ // Add any custom targeting on top
355
+ if (customTargeting && audienceType !== 'CUSTOM') {
356
+ Object.assign(baseTargeting, customTargeting);
410
357
  }
411
358
 
412
-
413
- }
359
+ return baseTargeting;
360
+ }
361
+
362
+ /**
363
+ * Get optimization goal based on objective
364
+ */
365
+ private getOptimizationGoal(objective: string): string {
366
+ const goalMap: Record<string, string> = {
367
+ POST_ENGAGEMENT: 'POST_ENGAGEMENT',
368
+ REACH: 'REACH',
369
+ LINK_CLICKS: 'LINK_CLICKS',
370
+ PAGE_LIKES: 'PAGE_LIKES',
371
+ BRAND_AWARENESS: 'AD_RECALL_LIFT',
372
+ VIDEO_VIEWS: 'VIDEO_VIEWS',
373
+ };
374
+
375
+ return goalMap[objective] || 'POST_ENGAGEMENT';
376
+ }
377
+ }