@memberjunction/actions-bizapps-social 2.112.0 → 2.113.1

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 +13 -0
  3. package/dist/base/base-social.action.d.ts.map +1 -1
  4. package/dist/base/base-social.action.js +24 -18
  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 +34 -35
  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 +36 -34
  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 +27 -25
  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 +23 -19
  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 +32 -28
  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 +44 -42
  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 +39 -37
  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 +59 -44
  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 +31 -33
  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 +32 -28
  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 +26 -24
  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 +34 -32
  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 +52 -43
  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 +28 -30
  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 +20 -18
  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 +26 -27
  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 +59 -38
  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 +25 -23
  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 +60 -56
  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 +27 -25
  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 +45 -55
  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 +29 -31
  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 +23 -25
  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 +30 -32
  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 +30 -28
  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 +38 -33
  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 +26 -25
  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 +29 -25
  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 +47 -40
  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 +31 -30
  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 +58 -56
  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 +68 -58
  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 +25 -22
  153. package/dist/providers/youtube/youtube-base.action.js.map +1 -1
  154. package/package.json +6 -5
  155. package/src/base/base-social.action.ts +224 -217
  156. package/src/providers/buffer/buffer-base.action.ts +441 -435
  157. package/src/providers/facebook/actions/boost-post.action.ts +386 -350
  158. package/src/providers/facebook/actions/create-album.action.ts +307 -291
  159. package/src/providers/facebook/actions/create-post.action.ts +227 -224
  160. package/src/providers/facebook/actions/get-page-insights.action.ts +403 -383
  161. package/src/providers/facebook/actions/get-page-posts.action.ts +225 -214
  162. package/src/providers/facebook/actions/get-post-insights.action.ts +316 -300
  163. package/src/providers/facebook/actions/respond-to-comments.action.ts +336 -319
  164. package/src/providers/facebook/actions/schedule-post.action.ts +292 -289
  165. package/src/providers/facebook/actions/search-posts.action.ts +413 -399
  166. package/src/providers/facebook/facebook-base.action.ts +670 -653
  167. package/src/providers/hootsuite/actions/bulk-schedule-posts.action.ts +257 -257
  168. package/src/providers/hootsuite/actions/create-scheduled-post.action.ts +189 -184
  169. package/src/providers/hootsuite/actions/delete-scheduled-post.action.ts +161 -160
  170. package/src/providers/hootsuite/actions/get-analytics.action.ts +254 -249
  171. package/src/providers/hootsuite/actions/get-scheduled-posts.action.ts +207 -206
  172. package/src/providers/hootsuite/actions/get-social-profiles.action.ts +205 -206
  173. package/src/providers/hootsuite/actions/search-posts.action.ts +369 -351
  174. package/src/providers/hootsuite/actions/update-scheduled-post.action.ts +209 -211
  175. package/src/providers/hootsuite/hootsuite-base.action.ts +307 -301
  176. package/src/providers/instagram/actions/create-post.action.ts +296 -276
  177. package/src/providers/instagram/actions/create-story.action.ts +394 -378
  178. package/src/providers/instagram/actions/get-account-insights.action.ts +420 -384
  179. package/src/providers/instagram/actions/get-business-posts.action.ts +242 -233
  180. package/src/providers/instagram/actions/get-comments.action.ts +377 -365
  181. package/src/providers/instagram/actions/get-post-insights.action.ts +273 -265
  182. package/src/providers/instagram/actions/schedule-post.action.ts +235 -233
  183. package/src/providers/instagram/actions/search-posts.action.ts +538 -512
  184. package/src/providers/instagram/instagram-base.action.ts +393 -368
  185. package/src/providers/linkedin/actions/create-article.action.ts +266 -275
  186. package/src/providers/linkedin/actions/create-post.action.ts +177 -179
  187. package/src/providers/linkedin/actions/get-followers.action.ts +211 -211
  188. package/src/providers/linkedin/actions/get-organization-posts.action.ts +147 -146
  189. package/src/providers/linkedin/actions/get-personal-posts.action.ts +139 -138
  190. package/src/providers/linkedin/actions/get-post-analytics.action.ts +189 -190
  191. package/src/providers/linkedin/actions/schedule-post.action.ts +189 -191
  192. package/src/providers/linkedin/actions/search-posts.action.ts +283 -275
  193. package/src/providers/linkedin/linkedin-base.action.ts +421 -407
  194. package/src/providers/tiktok/tiktok-base.action.ts +320 -305
  195. package/src/providers/twitter/actions/create-thread.action.ts +207 -203
  196. package/src/providers/twitter/actions/create-tweet.action.ts +188 -187
  197. package/src/providers/twitter/actions/delete-tweet.action.ts +129 -128
  198. package/src/providers/twitter/actions/get-analytics.action.ts +411 -402
  199. package/src/providers/twitter/actions/get-mentions.action.ts +219 -218
  200. package/src/providers/twitter/actions/get-timeline.action.ts +233 -232
  201. package/src/providers/twitter/actions/schedule-tweet.action.ts +222 -221
  202. package/src/providers/twitter/actions/search-tweets.action.ts +543 -540
  203. package/src/providers/twitter/twitter-base.action.ts +560 -541
  204. package/src/providers/youtube/youtube-base.action.ts +333 -320
@@ -2,7 +2,7 @@ import { RegisterClass } from '@memberjunction/global';
2
2
  import { FacebookBaseAction, FacebookInsight } 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/global';
5
+ import { LogStatus, LogError } from '@memberjunction/core';
6
6
  import axios from 'axios';
7
7
  import { BaseAction } from '@memberjunction/actions';
8
8
 
@@ -12,312 +12,328 @@ import { BaseAction } from '@memberjunction/actions';
12
12
  */
13
13
  @RegisterClass(BaseAction, 'FacebookGetPostInsightsAction')
14
14
  export class FacebookGetPostInsightsAction extends FacebookBaseAction {
15
- /**
16
- * Get action description
17
- */
18
- public get Description(): string {
19
- return 'Retrieves detailed analytics and insights for a specific Facebook post including reach, impressions, and engagement metrics';
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: 'MetricTypes',
35
- Type: 'Input',
36
- Value: null,
37
- },
38
- {
39
- Name: 'Period',
40
- Type: 'Input',
41
- Value: 'lifetime',
42
- },
43
- {
44
- Name: 'IncludeVideoMetrics',
45
- Type: 'Input',
46
- Value: true,
47
- },
48
- {
49
- Name: 'IncludeDemographics',
50
- Type: 'Input',
51
- Value: true,
52
- },
53
- ];
54
- }
55
-
56
- /**
57
- * Execute the action
58
- */
59
- protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
60
- const { Params, ContextUser } = params;
61
-
62
- try {
63
- // Validate required parameters
64
- const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
65
- const postId = this.getParamValue(Params, 'PostID');
66
-
67
- if (!companyIntegrationId) {
68
- return {
69
- Success: false,
70
- Message: 'CompanyIntegrationID is required',
71
- ResultCode: 'INVALID_TOKEN',
72
- };
73
- }
74
-
75
- if (!postId) {
76
- return {
77
- Success: false,
78
- Message: 'PostID is required',
79
- ResultCode: 'MISSING_REQUIRED_PARAM',
80
- };
81
- }
82
-
83
- // Initialize OAuth
84
- if (!(await this.initializeOAuth(companyIntegrationId))) {
85
- return {
86
- Success: false,
87
- Message: 'Failed to initialize Facebook OAuth connection',
88
- ResultCode: 'INVALID_TOKEN',
89
- };
90
- }
91
-
92
- // Get parameters
93
- const metricTypes = this.getParamValue(Params, 'MetricTypes') as string[];
94
- const period = (this.getParamValue(Params, 'Period') as string) || 'lifetime';
95
- const includeVideoMetrics = this.getParamValue(Params, 'IncludeVideoMetrics') !== false;
96
- const includeDemographics = this.getParamValue(Params, 'IncludeDemographics') !== false;
97
-
98
- LogStatus(`Retrieving insights for Facebook post ${postId}...`);
99
-
100
- // Extract page ID from post ID (format: pageId_postId)
101
- const pageId = postId.split('_')[0];
102
-
103
- // Get page access token
104
- const pageToken = await this.getPageAccessToken(pageId);
105
-
106
- // Build metrics list
107
- const metrics = metricTypes && metricTypes.length > 0 ? metricTypes : this.getDefaultPostMetrics(includeVideoMetrics);
108
-
109
- // Get post insights
110
- const insightsResponse = await axios.get(`${this.apiBaseUrl}/${postId}/insights`, {
111
- params: {
112
- access_token: pageToken,
113
- metric: metrics.join(','),
114
- period: period,
115
- },
116
- });
117
-
118
- const insights: FacebookInsight[] = insightsResponse.data.data || [];
119
-
120
- // Get additional engagement data
121
- const engagementResponse = await axios.get(`${this.apiBaseUrl}/${postId}`, {
122
- params: {
123
- access_token: pageToken,
124
- fields: 'reactions.summary(true).limit(0),comments.summary(true).limit(0),shares,likes.summary(true).limit(0)',
125
- },
126
- });
127
-
128
- const engagementData = engagementResponse.data;
129
-
130
- // Get demographic insights if requested
131
- let demographics = null;
132
- if (includeDemographics) {
133
- demographics = await this.getPostDemographics(postId, pageToken);
134
- }
135
-
136
- // Get post details for context
137
- const postDetails = await this.getPost(postId);
138
-
139
- // Process and organize insights
140
- const processedInsights = this.processInsights(insights);
141
-
142
- // Build comprehensive analytics object
143
- const analytics = {
144
- postId,
145
- postDetails: {
146
- message: postDetails.message,
147
- createdTime: postDetails.created_time,
148
- type: postDetails.attachments?.data?.[0]?.type || 'status',
149
- permalinkUrl: postDetails.permalink_url,
150
- },
151
- metrics: processedInsights,
152
- engagement: {
153
- reactions: {
154
- total: engagementData.reactions?.summary?.total_count || 0,
155
- likes: engagementData.likes?.summary?.total_count || 0,
156
- },
157
- comments: engagementData.comments?.summary?.total_count || 0,
158
- shares: engagementData.shares?.count || 0,
159
- },
160
- demographics,
161
- period,
162
- retrievedAt: new Date().toISOString(),
163
- };
164
-
165
- // Calculate engagement rate if we have reach data
166
- const reach = processedInsights.post_impressions_unique || processedInsights.post_reach;
167
- if (reach && reach > 0) {
168
- const totalEngagements = analytics.engagement.reactions.total + analytics.engagement.comments + analytics.engagement.shares;
169
- (analytics as any).engagementRate = (totalEngagements / reach) * 100;
170
- }
171
-
172
- LogStatus(`Successfully retrieved insights for post ${postId}`);
173
-
174
- // Update output parameters
175
- const outputParams = [...Params];
176
- // TODO: Set output parameters based on result
177
-
178
- return {
179
- Success: true,
180
- Message: 'Post insights retrieved successfully',
181
- ResultCode: 'SUCCESS',
182
- Params: outputParams,
183
- };
184
- } catch (error) {
185
- LogError(`Failed to get Facebook post insights: ${error instanceof Error ? error.message : 'Unknown error'}`);
186
-
187
- if (this.isAuthError(error)) {
188
- return this.handleOAuthError(error);
189
- }
190
-
191
- // Check if it's a permissions error
192
- if (error instanceof Error && error.message.includes('permissions')) {
193
- return {
194
- Success: false,
195
- Message: 'Insufficient permissions to access post insights. Ensure the page token has insights permissions.',
196
- ResultCode: 'INSUFFICIENT_PERMISSIONS',
197
- };
198
- }
199
-
200
- return {
201
- Success: false,
202
- Message: error instanceof Error ? error.message : 'Unknown error occurred',
203
- ResultCode: 'ERROR',
204
- };
15
+ /**
16
+ * Get action description
17
+ */
18
+ public get Description(): string {
19
+ return 'Retrieves detailed analytics and insights for a specific Facebook post including reach, impressions, and engagement metrics';
205
20
  }
206
- }
207
-
208
- /**
209
- * Get default post metrics based on post type
210
- */
211
- private getDefaultPostMetrics(includeVideo: boolean): string[] {
212
- const metrics = [
213
- // Reach and impressions
214
- 'post_impressions',
215
- 'post_impressions_unique',
216
- 'post_impressions_paid',
217
- 'post_impressions_paid_unique',
218
- 'post_impressions_fan',
219
- 'post_impressions_fan_unique',
220
- 'post_impressions_organic',
221
- 'post_impressions_organic_unique',
222
-
223
- // Engagement
224
- 'post_engaged_users',
225
- 'post_engaged_fan',
226
- 'post_clicks',
227
- 'post_clicks_unique',
228
-
229
- // Reactions
230
- 'post_reactions_by_type_total',
231
-
232
- // Negative feedback
233
- 'post_negative_feedback',
234
- 'post_negative_feedback_unique',
235
-
236
- // Activity
237
- 'post_activity',
238
- 'post_activity_by_action_type',
239
- ];
240
-
241
- if (includeVideo) {
242
- metrics.push(
243
- 'post_video_views',
244
- 'post_video_views_unique',
245
- 'post_video_views_10s',
246
- 'post_video_views_10s_unique',
247
- 'post_video_avg_time_watched',
248
- 'post_video_complete_views_30s',
249
- 'post_video_complete_views_30s_unique',
250
- 'post_video_retention_graph',
251
- 'post_video_view_time',
252
- 'post_video_view_time_by_age_bucket_and_gender',
253
- 'post_video_view_time_by_region_id'
254
- );
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: 'MetricTypes',
35
+ Type: 'Input',
36
+ Value: null,
37
+ },
38
+ {
39
+ Name: 'Period',
40
+ Type: 'Input',
41
+ Value: 'lifetime',
42
+ },
43
+ {
44
+ Name: 'IncludeVideoMetrics',
45
+ Type: 'Input',
46
+ Value: true,
47
+ },
48
+ {
49
+ Name: 'IncludeDemographics',
50
+ Type: 'Input',
51
+ Value: true,
52
+ }
53
+ ];
255
54
  }
256
55
 
257
- return metrics;
258
- }
259
-
260
- /**
261
- * Get demographic insights for a post
262
- */
263
- private async getPostDemographics(postId: string, pageToken: string): Promise<any> {
264
- try {
265
- const demographicMetrics = [
266
- 'post_impressions_by_age_gender_unique',
267
- 'post_engaged_users_by_age_gender',
268
- 'post_clicks_by_age_gender_unique',
269
- ];
270
-
271
- const response = await axios.get(`${this.apiBaseUrl}/${postId}/insights`, {
272
- params: {
273
- access_token: pageToken,
274
- metric: demographicMetrics.join(','),
275
- },
276
- });
277
-
278
- const insights = response.data.data || [];
279
- const demographics: Record<string, any> = {};
280
-
281
- for (const insight of insights) {
282
- if (insight.values?.[0]?.value) {
283
- demographics[insight.name] = insight.values[0].value;
56
+ /**
57
+ * Execute the action
58
+ */
59
+ protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
60
+ const { Params, ContextUser } = params;
61
+
62
+ try {
63
+ // Validate required parameters
64
+ const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
65
+ const postId = this.getParamValue(Params, 'PostID');
66
+
67
+ if (!companyIntegrationId) {
68
+ return {
69
+ Success: false,
70
+ Message: 'CompanyIntegrationID is required',
71
+ ResultCode: 'INVALID_TOKEN'
72
+ };
73
+ }
74
+
75
+ if (!postId) {
76
+ return {
77
+ Success: false,
78
+ Message: 'PostID is required',
79
+ ResultCode: 'MISSING_REQUIRED_PARAM'
80
+ };
81
+ }
82
+
83
+ // Initialize OAuth
84
+ if (!await this.initializeOAuth(companyIntegrationId)) {
85
+ return {
86
+ Success: false,
87
+ Message: 'Failed to initialize Facebook OAuth connection',
88
+ ResultCode: 'INVALID_TOKEN'
89
+ };
90
+ }
91
+
92
+ // Get parameters
93
+ const metricTypes = this.getParamValue(Params, 'MetricTypes') as string[];
94
+ const period = this.getParamValue(Params, 'Period') as string || 'lifetime';
95
+ const includeVideoMetrics = this.getParamValue(Params, 'IncludeVideoMetrics') !== false;
96
+ const includeDemographics = this.getParamValue(Params, 'IncludeDemographics') !== false;
97
+
98
+ LogStatus(`Retrieving insights for Facebook post ${postId}...`);
99
+
100
+ // Extract page ID from post ID (format: pageId_postId)
101
+ const pageId = postId.split('_')[0];
102
+
103
+ // Get page access token
104
+ const pageToken = await this.getPageAccessToken(pageId);
105
+
106
+ // Build metrics list
107
+ const metrics = metricTypes && metricTypes.length > 0
108
+ ? metricTypes
109
+ : this.getDefaultPostMetrics(includeVideoMetrics);
110
+
111
+ // Get post insights
112
+ const insightsResponse = await axios.get(
113
+ `${this.apiBaseUrl}/${postId}/insights`,
114
+ {
115
+ params: {
116
+ access_token: pageToken,
117
+ metric: metrics.join(','),
118
+ period: period
119
+ }
120
+ }
121
+ );
122
+
123
+ const insights: FacebookInsight[] = insightsResponse.data.data || [];
124
+
125
+ // Get additional engagement data
126
+ const engagementResponse = await axios.get(
127
+ `${this.apiBaseUrl}/${postId}`,
128
+ {
129
+ params: {
130
+ access_token: pageToken,
131
+ fields: 'reactions.summary(true).limit(0),comments.summary(true).limit(0),shares,likes.summary(true).limit(0)'
132
+ }
133
+ }
134
+ );
135
+
136
+ const engagementData = engagementResponse.data;
137
+
138
+ // Get demographic insights if requested
139
+ let demographics = null;
140
+ if (includeDemographics) {
141
+ demographics = await this.getPostDemographics(postId, pageToken);
142
+ }
143
+
144
+ // Get post details for context
145
+ const postDetails = await this.getPost(postId);
146
+
147
+ // Process and organize insights
148
+ const processedInsights = this.processInsights(insights);
149
+
150
+ // Build comprehensive analytics object
151
+ const analytics = {
152
+ postId,
153
+ postDetails: {
154
+ message: postDetails.message,
155
+ createdTime: postDetails.created_time,
156
+ type: postDetails.attachments?.data?.[0]?.type || 'status',
157
+ permalinkUrl: postDetails.permalink_url
158
+ },
159
+ metrics: processedInsights,
160
+ engagement: {
161
+ reactions: {
162
+ total: engagementData.reactions?.summary?.total_count || 0,
163
+ likes: engagementData.likes?.summary?.total_count || 0
164
+ },
165
+ comments: engagementData.comments?.summary?.total_count || 0,
166
+ shares: engagementData.shares?.count || 0
167
+ },
168
+ demographics,
169
+ period,
170
+ retrievedAt: new Date().toISOString()
171
+ };
172
+
173
+ // Calculate engagement rate if we have reach data
174
+ const reach = processedInsights.post_impressions_unique || processedInsights.post_reach;
175
+ if (reach && reach > 0) {
176
+ const totalEngagements = analytics.engagement.reactions.total +
177
+ analytics.engagement.comments +
178
+ analytics.engagement.shares;
179
+ (analytics as any).engagementRate = (totalEngagements / reach) * 100;
180
+ }
181
+
182
+ LogStatus(`Successfully retrieved insights for post ${postId}`);
183
+
184
+ // Update output parameters
185
+ const outputParams = [...Params];
186
+ // TODO: Set output parameters based on result
187
+
188
+ return {
189
+ Success: true,
190
+ Message: 'Post insights retrieved successfully',
191
+ ResultCode: 'SUCCESS',
192
+ Params: outputParams
193
+ };
194
+
195
+ } catch (error) {
196
+ LogError(`Failed to get Facebook post insights: ${error instanceof Error ? error.message : 'Unknown error'}`);
197
+
198
+ if (this.isAuthError(error)) {
199
+ return this.handleOAuthError(error);
200
+ }
201
+
202
+ // Check if it's a permissions error
203
+ if (error instanceof Error && error.message.includes('permissions')) {
204
+ return {
205
+ Success: false,
206
+ Message: 'Insufficient permissions to access post insights. Ensure the page token has insights permissions.',
207
+ ResultCode: 'INSUFFICIENT_PERMISSIONS'
208
+ };
209
+ }
210
+
211
+ return {
212
+ Success: false,
213
+ Message: error instanceof Error ? error.message : 'Unknown error occurred',
214
+ ResultCode: 'ERROR'
215
+ };
284
216
  }
285
- }
217
+ }
286
218
 
287
- return demographics;
288
- } catch (error) {
289
- LogError(`Failed to get demographic insights: ${error}`);
290
- return null;
219
+ /**
220
+ * Get default post metrics based on post type
221
+ */
222
+ private getDefaultPostMetrics(includeVideo: boolean): string[] {
223
+ const metrics = [
224
+ // Reach and impressions
225
+ 'post_impressions',
226
+ 'post_impressions_unique',
227
+ 'post_impressions_paid',
228
+ 'post_impressions_paid_unique',
229
+ 'post_impressions_fan',
230
+ 'post_impressions_fan_unique',
231
+ 'post_impressions_organic',
232
+ 'post_impressions_organic_unique',
233
+
234
+ // Engagement
235
+ 'post_engaged_users',
236
+ 'post_engaged_fan',
237
+ 'post_clicks',
238
+ 'post_clicks_unique',
239
+
240
+ // Reactions
241
+ 'post_reactions_by_type_total',
242
+
243
+ // Negative feedback
244
+ 'post_negative_feedback',
245
+ 'post_negative_feedback_unique',
246
+
247
+ // Activity
248
+ 'post_activity',
249
+ 'post_activity_by_action_type'
250
+ ];
251
+
252
+ if (includeVideo) {
253
+ metrics.push(
254
+ 'post_video_views',
255
+ 'post_video_views_unique',
256
+ 'post_video_views_10s',
257
+ 'post_video_views_10s_unique',
258
+ 'post_video_avg_time_watched',
259
+ 'post_video_complete_views_30s',
260
+ 'post_video_complete_views_30s_unique',
261
+ 'post_video_retention_graph',
262
+ 'post_video_view_time',
263
+ 'post_video_view_time_by_age_bucket_and_gender',
264
+ 'post_video_view_time_by_region_id'
265
+ );
266
+ }
267
+
268
+ return metrics;
291
269
  }
292
- }
293
-
294
- /**
295
- * Process raw insights into a more usable format
296
- */
297
- private processInsights(insights: FacebookInsight[]): Record<string, any> {
298
- const processed: Record<string, any> = {};
299
-
300
- for (const insight of insights) {
301
- const value = insight.values?.[0]?.value;
302
-
303
- if (value !== undefined) {
304
- // Handle different value types
305
- if (typeof value === 'object' && !Array.isArray(value)) {
306
- // For metrics like reactions_by_type
307
- processed[insight.name] = value;
308
- } else {
309
- processed[insight.name] = value;
270
+
271
+ /**
272
+ * Get demographic insights for a post
273
+ */
274
+ private async getPostDemographics(postId: string, pageToken: string): Promise<any> {
275
+ try {
276
+ const demographicMetrics = [
277
+ 'post_impressions_by_age_gender_unique',
278
+ 'post_engaged_users_by_age_gender',
279
+ 'post_clicks_by_age_gender_unique'
280
+ ];
281
+
282
+ const response = await axios.get(
283
+ `${this.apiBaseUrl}/${postId}/insights`,
284
+ {
285
+ params: {
286
+ access_token: pageToken,
287
+ metric: demographicMetrics.join(',')
288
+ }
289
+ }
290
+ );
291
+
292
+ const insights = response.data.data || [];
293
+ const demographics: Record<string, any> = {};
294
+
295
+ for (const insight of insights) {
296
+ if (insight.values?.[0]?.value) {
297
+ demographics[insight.name] = insight.values[0].value;
298
+ }
299
+ }
300
+
301
+ return demographics;
302
+ } catch (error) {
303
+ LogError(`Failed to get demographic insights: ${error}`);
304
+ return null;
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Process raw insights into a more usable format
310
+ */
311
+ private processInsights(insights: FacebookInsight[]): Record<string, any> {
312
+ const processed: Record<string, any> = {};
313
+
314
+ for (const insight of insights) {
315
+ const value = insight.values?.[0]?.value;
316
+
317
+ if (value !== undefined) {
318
+ // Handle different value types
319
+ if (typeof value === 'object' && !Array.isArray(value)) {
320
+ // For metrics like reactions_by_type
321
+ processed[insight.name] = value;
322
+ } else {
323
+ processed[insight.name] = value;
324
+ }
325
+
326
+ // Add metadata
327
+ processed[`${insight.name}_meta`] = {
328
+ title: insight.title,
329
+ description: insight.description,
330
+ period: insight.period
331
+ };
332
+ }
310
333
  }
311
334
 
312
- // Add metadata
313
- processed[`${insight.name}_meta`] = {
314
- title: insight.title,
315
- description: insight.description,
316
- period: insight.period,
317
- };
318
- }
335
+ return processed;
319
336
  }
320
337
 
321
- return processed;
322
- }
323
- }
338
+
339
+ }