@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, 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/core';
5
+ import { LogStatus, LogError } from '@memberjunction/global';
6
6
  import axios from 'axios';
7
7
  import { BaseAction } from '@memberjunction/actions';
8
8
 
@@ -12,328 +12,312 @@ 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';
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
+ };
20
205
  }
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
- ];
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
+ );
54
255
  }
55
256
 
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
- };
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;
216
284
  }
217
- }
285
+ }
218
286
 
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;
287
+ return demographics;
288
+ } catch (error) {
289
+ LogError(`Failed to get demographic insights: ${error}`);
290
+ return null;
269
291
  }
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
- }
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;
333
310
  }
334
311
 
335
- return processed;
312
+ // Add metadata
313
+ processed[`${insight.name}_meta`] = {
314
+ title: insight.title,
315
+ description: insight.description,
316
+ period: insight.period,
317
+ };
318
+ }
336
319
  }
337
320
 
338
-
339
- }
321
+ return processed;
322
+ }
323
+ }