@memberjunction/actions-bizapps-social 2.111.0 → 2.112.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +6 -6
  3. package/dist/base/base-social.action.d.ts.map +1 -1
  4. package/dist/base/base-social.action.js +18 -24
  5. package/dist/base/base-social.action.js.map +1 -1
  6. package/dist/providers/buffer/buffer-base.action.d.ts.map +1 -1
  7. package/dist/providers/buffer/buffer-base.action.js +35 -34
  8. package/dist/providers/buffer/buffer-base.action.js.map +1 -1
  9. package/dist/providers/facebook/actions/boost-post.action.d.ts.map +1 -1
  10. package/dist/providers/facebook/actions/boost-post.action.js +33 -33
  11. package/dist/providers/facebook/actions/boost-post.action.js.map +1 -1
  12. package/dist/providers/facebook/actions/create-album.action.d.ts.map +1 -1
  13. package/dist/providers/facebook/actions/create-album.action.js +34 -36
  14. package/dist/providers/facebook/actions/create-album.action.js.map +1 -1
  15. package/dist/providers/facebook/actions/create-post.action.d.ts.map +1 -1
  16. package/dist/providers/facebook/actions/create-post.action.js +20 -20
  17. package/dist/providers/facebook/actions/create-post.action.js.map +1 -1
  18. package/dist/providers/facebook/actions/get-page-insights.action.d.ts.map +1 -1
  19. package/dist/providers/facebook/actions/get-page-insights.action.js +25 -27
  20. package/dist/providers/facebook/actions/get-page-insights.action.js.map +1 -1
  21. package/dist/providers/facebook/actions/get-page-posts.action.d.ts.map +1 -1
  22. package/dist/providers/facebook/actions/get-page-posts.action.js +19 -23
  23. package/dist/providers/facebook/actions/get-page-posts.action.js.map +1 -1
  24. package/dist/providers/facebook/actions/get-post-insights.action.d.ts.map +1 -1
  25. package/dist/providers/facebook/actions/get-post-insights.action.js +28 -32
  26. package/dist/providers/facebook/actions/get-post-insights.action.js.map +1 -1
  27. package/dist/providers/facebook/actions/respond-to-comments.action.d.ts.map +1 -1
  28. package/dist/providers/facebook/actions/respond-to-comments.action.js +42 -44
  29. package/dist/providers/facebook/actions/respond-to-comments.action.js.map +1 -1
  30. package/dist/providers/facebook/actions/schedule-post.action.d.ts.map +1 -1
  31. package/dist/providers/facebook/actions/schedule-post.action.js +29 -29
  32. package/dist/providers/facebook/actions/schedule-post.action.js.map +1 -1
  33. package/dist/providers/facebook/actions/search-posts.action.d.ts.map +1 -1
  34. package/dist/providers/facebook/actions/search-posts.action.js +37 -39
  35. package/dist/providers/facebook/actions/search-posts.action.js.map +1 -1
  36. package/dist/providers/facebook/facebook-base.action.d.ts.map +1 -1
  37. package/dist/providers/facebook/facebook-base.action.js +44 -59
  38. package/dist/providers/facebook/facebook-base.action.js.map +1 -1
  39. package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.d.ts.map +1 -1
  40. package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js +33 -31
  41. package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js.map +1 -1
  42. package/dist/providers/hootsuite/actions/create-scheduled-post.action.d.ts.map +1 -1
  43. package/dist/providers/hootsuite/actions/create-scheduled-post.action.js +28 -32
  44. package/dist/providers/hootsuite/actions/create-scheduled-post.action.js.map +1 -1
  45. package/dist/providers/hootsuite/actions/delete-scheduled-post.action.d.ts.map +1 -1
  46. package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js +19 -19
  47. package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js.map +1 -1
  48. package/dist/providers/hootsuite/actions/get-analytics.action.d.ts.map +1 -1
  49. package/dist/providers/hootsuite/actions/get-analytics.action.js +24 -26
  50. package/dist/providers/hootsuite/actions/get-analytics.action.js.map +1 -1
  51. package/dist/providers/hootsuite/actions/get-scheduled-posts.action.d.ts.map +1 -1
  52. package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js +22 -22
  53. package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js.map +1 -1
  54. package/dist/providers/hootsuite/actions/get-social-profiles.action.d.ts.map +1 -1
  55. package/dist/providers/hootsuite/actions/get-social-profiles.action.js +32 -34
  56. package/dist/providers/hootsuite/actions/get-social-profiles.action.js.map +1 -1
  57. package/dist/providers/hootsuite/actions/search-posts.action.d.ts.map +1 -1
  58. package/dist/providers/hootsuite/actions/search-posts.action.js +43 -52
  59. package/dist/providers/hootsuite/actions/search-posts.action.js.map +1 -1
  60. package/dist/providers/hootsuite/actions/update-scheduled-post.action.d.ts.map +1 -1
  61. package/dist/providers/hootsuite/actions/update-scheduled-post.action.js +30 -28
  62. package/dist/providers/hootsuite/actions/update-scheduled-post.action.js.map +1 -1
  63. package/dist/providers/hootsuite/hootsuite-base.action.d.ts.map +1 -1
  64. package/dist/providers/hootsuite/hootsuite-base.action.js +18 -20
  65. package/dist/providers/hootsuite/hootsuite-base.action.js.map +1 -1
  66. package/dist/providers/instagram/actions/create-post.action.d.ts.map +1 -1
  67. package/dist/providers/instagram/actions/create-post.action.js +27 -26
  68. package/dist/providers/instagram/actions/create-post.action.js.map +1 -1
  69. package/dist/providers/instagram/actions/create-story.action.d.ts.map +1 -1
  70. package/dist/providers/instagram/actions/create-story.action.js +35 -35
  71. package/dist/providers/instagram/actions/create-story.action.js.map +1 -1
  72. package/dist/providers/instagram/actions/get-account-insights.action.d.ts.map +1 -1
  73. package/dist/providers/instagram/actions/get-account-insights.action.js +38 -59
  74. package/dist/providers/instagram/actions/get-account-insights.action.js.map +1 -1
  75. package/dist/providers/instagram/actions/get-business-posts.action.d.ts.map +1 -1
  76. package/dist/providers/instagram/actions/get-business-posts.action.js +29 -29
  77. package/dist/providers/instagram/actions/get-business-posts.action.js.map +1 -1
  78. package/dist/providers/instagram/actions/get-comments.action.d.ts.map +1 -1
  79. package/dist/providers/instagram/actions/get-comments.action.js +36 -36
  80. package/dist/providers/instagram/actions/get-comments.action.js.map +1 -1
  81. package/dist/providers/instagram/actions/get-post-insights.action.d.ts.map +1 -1
  82. package/dist/providers/instagram/actions/get-post-insights.action.js +23 -25
  83. package/dist/providers/instagram/actions/get-post-insights.action.js.map +1 -1
  84. package/dist/providers/instagram/actions/schedule-post.action.d.ts.map +1 -1
  85. package/dist/providers/instagram/actions/schedule-post.action.js +25 -25
  86. package/dist/providers/instagram/actions/schedule-post.action.js.map +1 -1
  87. package/dist/providers/instagram/actions/search-posts.action.d.ts.map +1 -1
  88. package/dist/providers/instagram/actions/search-posts.action.js +56 -60
  89. package/dist/providers/instagram/actions/search-posts.action.js.map +1 -1
  90. package/dist/providers/instagram/instagram-base.action.d.ts.map +1 -1
  91. package/dist/providers/instagram/instagram-base.action.js +25 -27
  92. package/dist/providers/instagram/instagram-base.action.js.map +1 -1
  93. package/dist/providers/linkedin/actions/create-article.action.d.ts.map +1 -1
  94. package/dist/providers/linkedin/actions/create-article.action.js +55 -45
  95. package/dist/providers/linkedin/actions/create-article.action.js.map +1 -1
  96. package/dist/providers/linkedin/actions/create-post.action.d.ts.map +1 -1
  97. package/dist/providers/linkedin/actions/create-post.action.js +31 -29
  98. package/dist/providers/linkedin/actions/create-post.action.js.map +1 -1
  99. package/dist/providers/linkedin/actions/get-followers.action.d.ts.map +1 -1
  100. package/dist/providers/linkedin/actions/get-followers.action.js +28 -28
  101. package/dist/providers/linkedin/actions/get-followers.action.js.map +1 -1
  102. package/dist/providers/linkedin/actions/get-organization-posts.action.d.ts.map +1 -1
  103. package/dist/providers/linkedin/actions/get-organization-posts.action.js +20 -20
  104. package/dist/providers/linkedin/actions/get-organization-posts.action.js.map +1 -1
  105. package/dist/providers/linkedin/actions/get-personal-posts.action.d.ts.map +1 -1
  106. package/dist/providers/linkedin/actions/get-personal-posts.action.js +19 -19
  107. package/dist/providers/linkedin/actions/get-personal-posts.action.js.map +1 -1
  108. package/dist/providers/linkedin/actions/get-post-analytics.action.d.ts.map +1 -1
  109. package/dist/providers/linkedin/actions/get-post-analytics.action.js +25 -23
  110. package/dist/providers/linkedin/actions/get-post-analytics.action.js.map +1 -1
  111. package/dist/providers/linkedin/actions/schedule-post.action.d.ts.map +1 -1
  112. package/dist/providers/linkedin/actions/schedule-post.action.js +32 -30
  113. package/dist/providers/linkedin/actions/schedule-post.action.js.map +1 -1
  114. package/dist/providers/linkedin/actions/search-posts.action.d.ts.map +1 -1
  115. package/dist/providers/linkedin/actions/search-posts.action.js +28 -30
  116. package/dist/providers/linkedin/actions/search-posts.action.js.map +1 -1
  117. package/dist/providers/linkedin/linkedin-base.action.d.ts.map +1 -1
  118. package/dist/providers/linkedin/linkedin-base.action.js +33 -38
  119. package/dist/providers/linkedin/linkedin-base.action.js.map +1 -1
  120. package/dist/providers/tiktok/tiktok-base.action.d.ts.map +1 -1
  121. package/dist/providers/tiktok/tiktok-base.action.js +25 -26
  122. package/dist/providers/tiktok/tiktok-base.action.js.map +1 -1
  123. package/dist/providers/twitter/actions/create-thread.action.d.ts.map +1 -1
  124. package/dist/providers/twitter/actions/create-thread.action.js +25 -29
  125. package/dist/providers/twitter/actions/create-thread.action.js.map +1 -1
  126. package/dist/providers/twitter/actions/create-tweet.action.d.ts.map +1 -1
  127. package/dist/providers/twitter/actions/create-tweet.action.js +23 -23
  128. package/dist/providers/twitter/actions/create-tweet.action.js.map +1 -1
  129. package/dist/providers/twitter/actions/delete-tweet.action.d.ts.map +1 -1
  130. package/dist/providers/twitter/actions/delete-tweet.action.js +19 -19
  131. package/dist/providers/twitter/actions/delete-tweet.action.js.map +1 -1
  132. package/dist/providers/twitter/actions/get-analytics.action.d.ts.map +1 -1
  133. package/dist/providers/twitter/actions/get-analytics.action.js +40 -47
  134. package/dist/providers/twitter/actions/get-analytics.action.js.map +1 -1
  135. package/dist/providers/twitter/actions/get-mentions.action.d.ts.map +1 -1
  136. package/dist/providers/twitter/actions/get-mentions.action.js +30 -31
  137. package/dist/providers/twitter/actions/get-mentions.action.js.map +1 -1
  138. package/dist/providers/twitter/actions/get-timeline.action.d.ts.map +1 -1
  139. package/dist/providers/twitter/actions/get-timeline.action.js +29 -29
  140. package/dist/providers/twitter/actions/get-timeline.action.js.map +1 -1
  141. package/dist/providers/twitter/actions/schedule-tweet.action.d.ts.map +1 -1
  142. package/dist/providers/twitter/actions/schedule-tweet.action.js +26 -26
  143. package/dist/providers/twitter/actions/schedule-tweet.action.js.map +1 -1
  144. package/dist/providers/twitter/actions/search-tweets.action.d.ts.map +1 -1
  145. package/dist/providers/twitter/actions/search-tweets.action.js +56 -58
  146. package/dist/providers/twitter/actions/search-tweets.action.js.map +1 -1
  147. package/dist/providers/twitter/twitter-base.action.d.ts.map +1 -1
  148. package/dist/providers/twitter/twitter-base.action.js +58 -68
  149. package/dist/providers/twitter/twitter-base.action.js.map +1 -1
  150. package/dist/providers/youtube/youtube-base.action.d.ts +1 -1
  151. package/dist/providers/youtube/youtube-base.action.d.ts.map +1 -1
  152. package/dist/providers/youtube/youtube-base.action.js +22 -25
  153. package/dist/providers/youtube/youtube-base.action.js.map +1 -1
  154. package/package.json +5 -6
  155. package/src/base/base-social.action.ts +217 -224
  156. package/src/providers/buffer/buffer-base.action.ts +435 -441
  157. package/src/providers/facebook/actions/boost-post.action.ts +350 -386
  158. package/src/providers/facebook/actions/create-album.action.ts +291 -307
  159. package/src/providers/facebook/actions/create-post.action.ts +224 -227
  160. package/src/providers/facebook/actions/get-page-insights.action.ts +383 -403
  161. package/src/providers/facebook/actions/get-page-posts.action.ts +214 -225
  162. package/src/providers/facebook/actions/get-post-insights.action.ts +300 -316
  163. package/src/providers/facebook/actions/respond-to-comments.action.ts +319 -336
  164. package/src/providers/facebook/actions/schedule-post.action.ts +289 -292
  165. package/src/providers/facebook/actions/search-posts.action.ts +399 -413
  166. package/src/providers/facebook/facebook-base.action.ts +653 -670
  167. package/src/providers/hootsuite/actions/bulk-schedule-posts.action.ts +257 -257
  168. package/src/providers/hootsuite/actions/create-scheduled-post.action.ts +184 -189
  169. package/src/providers/hootsuite/actions/delete-scheduled-post.action.ts +160 -161
  170. package/src/providers/hootsuite/actions/get-analytics.action.ts +249 -254
  171. package/src/providers/hootsuite/actions/get-scheduled-posts.action.ts +206 -207
  172. package/src/providers/hootsuite/actions/get-social-profiles.action.ts +206 -205
  173. package/src/providers/hootsuite/actions/search-posts.action.ts +351 -369
  174. package/src/providers/hootsuite/actions/update-scheduled-post.action.ts +211 -209
  175. package/src/providers/hootsuite/hootsuite-base.action.ts +301 -307
  176. package/src/providers/instagram/actions/create-post.action.ts +276 -296
  177. package/src/providers/instagram/actions/create-story.action.ts +378 -394
  178. package/src/providers/instagram/actions/get-account-insights.action.ts +384 -420
  179. package/src/providers/instagram/actions/get-business-posts.action.ts +233 -242
  180. package/src/providers/instagram/actions/get-comments.action.ts +365 -377
  181. package/src/providers/instagram/actions/get-post-insights.action.ts +265 -273
  182. package/src/providers/instagram/actions/schedule-post.action.ts +233 -235
  183. package/src/providers/instagram/actions/search-posts.action.ts +512 -538
  184. package/src/providers/instagram/instagram-base.action.ts +368 -393
  185. package/src/providers/linkedin/actions/create-article.action.ts +275 -266
  186. package/src/providers/linkedin/actions/create-post.action.ts +179 -177
  187. package/src/providers/linkedin/actions/get-followers.action.ts +211 -211
  188. package/src/providers/linkedin/actions/get-organization-posts.action.ts +146 -147
  189. package/src/providers/linkedin/actions/get-personal-posts.action.ts +138 -139
  190. package/src/providers/linkedin/actions/get-post-analytics.action.ts +190 -189
  191. package/src/providers/linkedin/actions/schedule-post.action.ts +191 -189
  192. package/src/providers/linkedin/actions/search-posts.action.ts +275 -283
  193. package/src/providers/linkedin/linkedin-base.action.ts +407 -421
  194. package/src/providers/tiktok/tiktok-base.action.ts +305 -320
  195. package/src/providers/twitter/actions/create-thread.action.ts +203 -207
  196. package/src/providers/twitter/actions/create-tweet.action.ts +187 -188
  197. package/src/providers/twitter/actions/delete-tweet.action.ts +128 -129
  198. package/src/providers/twitter/actions/get-analytics.action.ts +402 -411
  199. package/src/providers/twitter/actions/get-mentions.action.ts +218 -219
  200. package/src/providers/twitter/actions/get-timeline.action.ts +232 -233
  201. package/src/providers/twitter/actions/schedule-tweet.action.ts +221 -222
  202. package/src/providers/twitter/actions/search-tweets.action.ts +540 -543
  203. package/src/providers/twitter/twitter-base.action.ts +541 -560
  204. package/src/providers/youtube/youtube-base.action.ts +320 -333
@@ -1,7 +1,7 @@
1
1
  import { RegisterClass } from '@memberjunction/global';
2
2
  import { HootSuiteBaseAction, HootSuitePost } from '../hootsuite-base.action';
3
3
  import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
4
- import { LogStatus, LogError } from '@memberjunction/core';
4
+ import { LogStatus, LogError } from '@memberjunction/global';
5
5
  import { SearchParams, SocialPost } from '../../../base/base-social.action';
6
6
  import { BaseAction } from '@memberjunction/actions';
7
7
 
@@ -10,387 +10,369 @@ import { BaseAction } from '@memberjunction/actions';
10
10
  */
11
11
  @RegisterClass(BaseAction, 'HootSuiteSearchPostsAction')
12
12
  export class HootSuiteSearchPostsAction extends HootSuiteBaseAction {
13
- /**
14
- * Search for posts in HootSuite
15
- */
16
- protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
17
- const { Params, ContextUser } = params;
18
-
19
- try {
20
- // Initialize OAuth
21
- const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
22
- if (!await this.initializeOAuth(companyIntegrationId)) {
23
- throw new Error('Failed to initialize OAuth connection');
24
- }
25
-
26
- // Extract search parameters
27
- const query = this.getParamValue(Params, 'Query');
28
- const hashtags = this.getParamValue(Params, 'Hashtags');
29
- const startDate = this.getParamValue(Params, 'StartDate');
30
- const endDate = this.getParamValue(Params, 'EndDate');
31
- const profileId = this.getParamValue(Params, 'ProfileID');
32
- const postState = this.getParamValue(Params, 'PostState') || 'PUBLISHED';
33
- const limit = this.getParamValue(Params, 'Limit') || 100;
34
- const includeAnalytics = this.getParamValue(Params, 'IncludeAnalytics') || false;
35
- const sortBy = this.getParamValue(Params, 'SortBy') || 'publishedTime';
36
- const sortOrder = this.getParamValue(Params, 'SortOrder') || 'DESC';
37
-
38
- // Build search parameters
39
- const searchParams: SearchParams = {
40
- query: query,
41
- hashtags: hashtags,
42
- startDate: startDate ? new Date(startDate) : undefined,
43
- endDate: endDate ? new Date(endDate) : undefined,
44
- limit: limit
45
- };
46
-
47
- // Perform the search
48
- LogStatus('Searching for posts...');
49
- const posts = await this.searchPosts(searchParams);
50
-
51
- // Filter by profile if specified
52
- let filteredPosts = posts;
53
- if (profileId) {
54
- filteredPosts = posts.filter(p =>
55
- p.profileId.includes(profileId) ||
56
- (p.platformSpecificData?.socialProfileIds?.includes(profileId))
57
- );
58
- }
59
-
60
- // Sort results
61
- filteredPosts = this.sortPosts(filteredPosts, sortBy, sortOrder);
62
-
63
- // Limit results
64
- if (limit && filteredPosts.length > limit) {
65
- filteredPosts = filteredPosts.slice(0, limit);
66
- }
67
-
68
- // Optionally include analytics
69
- if (includeAnalytics) {
70
- LogStatus('Fetching analytics for posts...');
71
- filteredPosts = await this.enrichPostsWithAnalytics(filteredPosts);
72
- }
73
-
74
- // Analyze content patterns
75
- const contentAnalysis = this.analyzePostContent(filteredPosts);
76
-
77
- // Create summary
78
- const summary = {
79
- totalResults: filteredPosts.length,
80
- dateRange: {
81
- start: startDate || 'Not specified',
82
- end: endDate || 'Not specified',
83
- actualStart: filteredPosts.length > 0
84
- ? filteredPosts[filteredPosts.length - 1].publishedAt.toISOString()
85
- : null,
86
- actualEnd: filteredPosts.length > 0
87
- ? filteredPosts[0].publishedAt.toISOString()
88
- : null
89
- },
90
- byProfile: this.groupByProfile(filteredPosts),
91
- byMonth: this.groupByMonth(filteredPosts),
92
- contentAnalysis: contentAnalysis,
93
- topHashtags: this.extractTopHashtags(filteredPosts),
94
- performanceStats: includeAnalytics ? this.calculatePerformanceStats(filteredPosts) : null
95
- };
96
-
97
- // Update output parameters
98
- const outputParams = [...Params];
99
- const postsParam = outputParams.find(p => p.Name === 'Posts');
100
- if (postsParam) postsParam.Value = filteredPosts;
101
- const summaryParam = outputParams.find(p => p.Name === 'Summary');
102
- if (summaryParam) summaryParam.Value = summary;
103
-
104
- return {
105
- Success: true,
106
- ResultCode: 'SUCCESS',
107
- Message: `Found ${filteredPosts.length} posts matching search criteria`,
108
- Params: outputParams
109
- };
110
-
111
- } catch (error) {
112
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
113
-
114
- return {
115
- Success: false,
116
- ResultCode: 'ERROR',
117
- Message: `Failed to search posts: ${errorMessage}`,
118
- Params
119
- };
120
- }
13
+ /**
14
+ * Search for posts in HootSuite
15
+ */
16
+ protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
17
+ const { Params, ContextUser } = params;
18
+
19
+ try {
20
+ // Initialize OAuth
21
+ const companyIntegrationId = this.getParamValue(Params, 'CompanyIntegrationID');
22
+ if (!(await this.initializeOAuth(companyIntegrationId))) {
23
+ throw new Error('Failed to initialize OAuth connection');
24
+ }
25
+
26
+ // Extract search parameters
27
+ const query = this.getParamValue(Params, 'Query');
28
+ const hashtags = this.getParamValue(Params, 'Hashtags');
29
+ const startDate = this.getParamValue(Params, 'StartDate');
30
+ const endDate = this.getParamValue(Params, 'EndDate');
31
+ const profileId = this.getParamValue(Params, 'ProfileID');
32
+ const postState = this.getParamValue(Params, 'PostState') || 'PUBLISHED';
33
+ const limit = this.getParamValue(Params, 'Limit') || 100;
34
+ const includeAnalytics = this.getParamValue(Params, 'IncludeAnalytics') || false;
35
+ const sortBy = this.getParamValue(Params, 'SortBy') || 'publishedTime';
36
+ const sortOrder = this.getParamValue(Params, 'SortOrder') || 'DESC';
37
+
38
+ // Build search parameters
39
+ const searchParams: SearchParams = {
40
+ query: query,
41
+ hashtags: hashtags,
42
+ startDate: startDate ? new Date(startDate) : undefined,
43
+ endDate: endDate ? new Date(endDate) : undefined,
44
+ limit: limit,
45
+ };
46
+
47
+ // Perform the search
48
+ LogStatus('Searching for posts...');
49
+ const posts = await this.searchPosts(searchParams);
50
+
51
+ // Filter by profile if specified
52
+ let filteredPosts = posts;
53
+ if (profileId) {
54
+ filteredPosts = posts.filter(
55
+ (p) => p.profileId.includes(profileId) || p.platformSpecificData?.socialProfileIds?.includes(profileId)
56
+ );
57
+ }
58
+
59
+ // Sort results
60
+ filteredPosts = this.sortPosts(filteredPosts, sortBy, sortOrder);
61
+
62
+ // Limit results
63
+ if (limit && filteredPosts.length > limit) {
64
+ filteredPosts = filteredPosts.slice(0, limit);
65
+ }
66
+
67
+ // Optionally include analytics
68
+ if (includeAnalytics) {
69
+ LogStatus('Fetching analytics for posts...');
70
+ filteredPosts = await this.enrichPostsWithAnalytics(filteredPosts);
71
+ }
72
+
73
+ // Analyze content patterns
74
+ const contentAnalysis = this.analyzePostContent(filteredPosts);
75
+
76
+ // Create summary
77
+ const summary = {
78
+ totalResults: filteredPosts.length,
79
+ dateRange: {
80
+ start: startDate || 'Not specified',
81
+ end: endDate || 'Not specified',
82
+ actualStart: filteredPosts.length > 0 ? filteredPosts[filteredPosts.length - 1].publishedAt.toISOString() : null,
83
+ actualEnd: filteredPosts.length > 0 ? filteredPosts[0].publishedAt.toISOString() : null,
84
+ },
85
+ byProfile: this.groupByProfile(filteredPosts),
86
+ byMonth: this.groupByMonth(filteredPosts),
87
+ contentAnalysis: contentAnalysis,
88
+ topHashtags: this.extractTopHashtags(filteredPosts),
89
+ performanceStats: includeAnalytics ? this.calculatePerformanceStats(filteredPosts) : null,
90
+ };
91
+
92
+ // Update output parameters
93
+ const outputParams = [...Params];
94
+ const postsParam = outputParams.find((p) => p.Name === 'Posts');
95
+ if (postsParam) postsParam.Value = filteredPosts;
96
+ const summaryParam = outputParams.find((p) => p.Name === 'Summary');
97
+ if (summaryParam) summaryParam.Value = summary;
98
+
99
+ return {
100
+ Success: true,
101
+ ResultCode: 'SUCCESS',
102
+ Message: `Found ${filteredPosts.length} posts matching search criteria`,
103
+ Params: outputParams,
104
+ };
105
+ } catch (error) {
106
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
107
+
108
+ return {
109
+ Success: false,
110
+ ResultCode: 'ERROR',
111
+ Message: `Failed to search posts: ${errorMessage}`,
112
+ Params,
113
+ };
121
114
  }
122
-
123
- /**
124
- * Search for posts implementation
125
- */
126
- protected async searchPosts(params: SearchParams): Promise<SocialPost[]> {
127
- const queryParams: any = {
128
- limit: Math.min(params.limit || 100, 100),
129
- maxResults: params.limit
130
- };
131
-
132
- // Add state filter - default to published for historical search
133
- queryParams.state = 'PUBLISHED';
134
-
135
- // Add date filters
136
- if (params.startDate) {
137
- queryParams.publishedAfter = this.formatHootSuiteDate(params.startDate);
138
- }
139
- if (params.endDate) {
140
- queryParams.publishedBefore = this.formatHootSuiteDate(params.endDate);
141
- }
142
-
143
- // Add text search
144
- if (params.query) {
145
- queryParams.text = params.query;
146
- }
147
-
148
- // Add hashtag search
149
- if (params.hashtags && params.hashtags.length > 0) {
150
- // HootSuite API may require hashtags in the text query
151
- const hashtagQuery = params.hashtags.map(tag =>
152
- tag.startsWith('#') ? tag : `#${tag}`
153
- ).join(' ');
154
-
155
- queryParams.text = params.query
156
- ? `${params.query} ${hashtagQuery}`
157
- : hashtagQuery;
158
- }
159
-
160
- // Make paginated request
161
- const hootSuitePosts = await this.makePaginatedRequest<HootSuitePost>('/messages', queryParams);
162
-
163
- // Convert to common format
164
- return hootSuitePosts.map(post => this.normalizePost(post));
115
+ }
116
+
117
+ /**
118
+ * Search for posts implementation
119
+ */
120
+ protected async searchPosts(params: SearchParams): Promise<SocialPost[]> {
121
+ const queryParams: any = {
122
+ limit: Math.min(params.limit || 100, 100),
123
+ maxResults: params.limit,
124
+ };
125
+
126
+ // Add state filter - default to published for historical search
127
+ queryParams.state = 'PUBLISHED';
128
+
129
+ // Add date filters
130
+ if (params.startDate) {
131
+ queryParams.publishedAfter = this.formatHootSuiteDate(params.startDate);
165
132
  }
166
-
167
- /**
168
- * Enrich posts with analytics data
169
- */
170
- private async enrichPostsWithAnalytics(posts: SocialPost[]): Promise<SocialPost[]> {
171
- const enrichedPosts: SocialPost[] = [];
172
-
173
- for (const post of posts) {
174
- try {
175
- const response = await this.axiosInstance.get(`/analytics/posts/${post.id}`);
176
- const analytics = response.data;
177
-
178
- enrichedPosts.push({
179
- ...post,
180
- analytics: this.normalizeAnalytics(analytics.metrics)
181
- });
182
- } catch (error) {
183
- // If analytics fail, include post without analytics
184
- LogStatus(`Could not get analytics for post ${post.id}`);
185
- enrichedPosts.push(post);
186
- }
187
- }
188
-
189
- return enrichedPosts;
133
+ if (params.endDate) {
134
+ queryParams.publishedBefore = this.formatHootSuiteDate(params.endDate);
190
135
  }
191
136
 
192
- /**
193
- * Sort posts by specified criteria
194
- */
195
- private sortPosts(posts: SocialPost[], sortBy: string, sortOrder: string): SocialPost[] {
196
- return posts.sort((a, b) => {
197
- let compareValue = 0;
198
-
199
- switch (sortBy) {
200
- case 'publishedTime':
201
- compareValue = a.publishedAt.getTime() - b.publishedAt.getTime();
202
- break;
203
- case 'engagements':
204
- compareValue = (a.analytics?.engagements || 0) - (b.analytics?.engagements || 0);
205
- break;
206
- case 'impressions':
207
- compareValue = (a.analytics?.impressions || 0) - (b.analytics?.impressions || 0);
208
- break;
209
- default:
210
- compareValue = a.publishedAt.getTime() - b.publishedAt.getTime();
211
- }
212
-
213
- return sortOrder === 'DESC' ? -compareValue : compareValue;
214
- });
137
+ // Add text search
138
+ if (params.query) {
139
+ queryParams.text = params.query;
215
140
  }
216
141
 
217
- /**
218
- * Analyze post content patterns
219
- */
220
- private analyzePostContent(posts: SocialPost[]): any {
221
- const totalPosts = posts.length;
222
- if (totalPosts === 0) return null;
223
-
224
- const contentLengths = posts.map(p => p.content.length);
225
- const avgLength = contentLengths.reduce((a, b) => a + b, 0) / totalPosts;
226
-
227
- const withMedia = posts.filter(p => p.mediaUrls && p.mediaUrls.length > 0).length;
228
- const withHashtags = posts.filter(p => p.content.includes('#')).length;
229
- const withLinks = posts.filter(p =>
230
- p.content.includes('http://') || p.content.includes('https://')
231
- ).length;
232
-
233
- return {
234
- averageLength: Math.round(avgLength),
235
- minLength: Math.min(...contentLengths),
236
- maxLength: Math.max(...contentLengths),
237
- withMedia: withMedia,
238
- withMediaPercentage: (withMedia / totalPosts) * 100,
239
- withHashtags: withHashtags,
240
- withHashtagsPercentage: (withHashtags / totalPosts) * 100,
241
- withLinks: withLinks,
242
- withLinksPercentage: (withLinks / totalPosts) * 100
243
- };
244
- }
142
+ // Add hashtag search
143
+ if (params.hashtags && params.hashtags.length > 0) {
144
+ // HootSuite API may require hashtags in the text query
145
+ const hashtagQuery = params.hashtags.map((tag) => (tag.startsWith('#') ? tag : `#${tag}`)).join(' ');
245
146
 
246
- /**
247
- * Extract top hashtags from posts
248
- */
249
- private extractTopHashtags(posts: SocialPost[]): Array<{ hashtag: string; count: number }> {
250
- const hashtagCounts: Record<string, number> = {};
251
-
252
- posts.forEach(post => {
253
- const hashtags = post.content.match(/#\w+/g) || [];
254
- hashtags.forEach(tag => {
255
- const normalized = tag.toLowerCase();
256
- hashtagCounts[normalized] = (hashtagCounts[normalized] || 0) + 1;
257
- });
258
- });
259
-
260
- return Object.entries(hashtagCounts)
261
- .map(([hashtag, count]) => ({ hashtag, count }))
262
- .sort((a, b) => b.count - a.count)
263
- .slice(0, 10);
147
+ queryParams.text = params.query ? `${params.query} ${hashtagQuery}` : hashtagQuery;
264
148
  }
265
149
 
266
- /**
267
- * Calculate performance statistics
268
- */
269
- private calculatePerformanceStats(posts: SocialPost[]): any {
270
- const postsWithAnalytics = posts.filter(p => p.analytics);
271
- if (postsWithAnalytics.length === 0) return null;
150
+ // Make paginated request
151
+ const hootSuitePosts = await this.makePaginatedRequest<HootSuitePost>('/messages', queryParams);
272
152
 
273
- const totalEngagements = postsWithAnalytics.reduce((sum, p) =>
274
- sum + (p.analytics?.engagements || 0), 0
275
- );
276
- const totalImpressions = postsWithAnalytics.reduce((sum, p) =>
277
- sum + (p.analytics?.impressions || 0), 0
278
- );
153
+ // Convert to common format
154
+ return hootSuitePosts.map((post) => this.normalizePost(post));
155
+ }
279
156
 
280
- const avgEngagements = totalEngagements / postsWithAnalytics.length;
281
- const avgImpressions = totalImpressions / postsWithAnalytics.length;
282
- const engagementRate = totalImpressions > 0
283
- ? (totalEngagements / totalImpressions) * 100
284
- : 0;
285
-
286
- return {
287
- postsAnalyzed: postsWithAnalytics.length,
288
- averageEngagements: Math.round(avgEngagements),
289
- averageImpressions: Math.round(avgImpressions),
290
- totalEngagements: totalEngagements,
291
- totalImpressions: totalImpressions,
292
- engagementRate: engagementRate.toFixed(2)
293
- };
294
- }
295
-
296
- /**
297
- * Group posts by profile
298
- */
299
- private groupByProfile(posts: SocialPost[]): Record<string, number> {
300
- const groups: Record<string, number> = {};
301
-
302
- posts.forEach(post => {
303
- const profiles = post.platformSpecificData?.socialProfileIds || [post.profileId];
304
- profiles.forEach((profileId: string) => {
305
- groups[profileId] = (groups[profileId] || 0) + 1;
306
- });
307
- });
157
+ /**
158
+ * Enrich posts with analytics data
159
+ */
160
+ private async enrichPostsWithAnalytics(posts: SocialPost[]): Promise<SocialPost[]> {
161
+ const enrichedPosts: SocialPost[] = [];
308
162
 
309
- return groups;
310
- }
163
+ for (const post of posts) {
164
+ try {
165
+ const response = await this.axiosInstance.get(`/analytics/posts/${post.id}`);
166
+ const analytics = response.data;
311
167
 
312
- /**
313
- * Group posts by month
314
- */
315
- private groupByMonth(posts: SocialPost[]): Record<string, number> {
316
- const groups: Record<string, number> = {};
317
-
318
- posts.forEach(post => {
319
- const monthKey = post.publishedAt.toISOString().substring(0, 7);
320
- groups[monthKey] = (groups[monthKey] || 0) + 1;
168
+ enrichedPosts.push({
169
+ ...post,
170
+ analytics: this.normalizeAnalytics(analytics.metrics),
321
171
  });
322
-
323
- return groups;
324
- }
325
-
326
- /**
327
- * Define the parameters this action expects
328
- */
329
- public get Params(): ActionParam[] {
330
- return [
331
- ...this.commonSocialParams,
332
- {
333
- Name: 'Query',
334
- Type: 'Input',
335
- Value: null
336
- },
337
- {
338
- Name: 'Hashtags',
339
- Type: 'Input',
340
- Value: null
341
- },
342
- {
343
- Name: 'StartDate',
344
- Type: 'Input',
345
- Value: null
346
- },
347
- {
348
- Name: 'EndDate',
349
- Type: 'Input',
350
- Value: null
351
- },
352
- {
353
- Name: 'PostState',
354
- Type: 'Input',
355
- Value: null
356
- },
357
- {
358
- Name: 'Limit',
359
- Type: 'Input',
360
- Value: null
361
- },
362
- {
363
- Name: 'IncludeAnalytics',
364
- Type: 'Input',
365
- Value: null
366
- },
367
- {
368
- Name: 'SortBy',
369
- Type: 'Input',
370
- Value: null
371
- },
372
- {
373
- Name: 'SortOrder',
374
- Type: 'Input',
375
- Value: null
376
- },
377
- {
378
- Name: 'Posts',
379
- Type: 'Output',
380
- Value: null
381
- },
382
- {
383
- Name: 'Summary',
384
- Type: 'Output',
385
- Value: null
386
- }
387
- ];
172
+ } catch (error) {
173
+ // If analytics fail, include post without analytics
174
+ LogStatus(`Could not get analytics for post ${post.id}`);
175
+ enrichedPosts.push(post);
176
+ }
388
177
  }
389
178
 
390
- /**
391
- * Get action description
392
- */
393
- public get Description(): string {
394
- return 'Searches historical posts in HootSuite with support for text queries, hashtags, date ranges, and content analysis';
395
- }
396
- }
179
+ return enrichedPosts;
180
+ }
181
+
182
+ /**
183
+ * Sort posts by specified criteria
184
+ */
185
+ private sortPosts(posts: SocialPost[], sortBy: string, sortOrder: string): SocialPost[] {
186
+ return posts.sort((a, b) => {
187
+ let compareValue = 0;
188
+
189
+ switch (sortBy) {
190
+ case 'publishedTime':
191
+ compareValue = a.publishedAt.getTime() - b.publishedAt.getTime();
192
+ break;
193
+ case 'engagements':
194
+ compareValue = (a.analytics?.engagements || 0) - (b.analytics?.engagements || 0);
195
+ break;
196
+ case 'impressions':
197
+ compareValue = (a.analytics?.impressions || 0) - (b.analytics?.impressions || 0);
198
+ break;
199
+ default:
200
+ compareValue = a.publishedAt.getTime() - b.publishedAt.getTime();
201
+ }
202
+
203
+ return sortOrder === 'DESC' ? -compareValue : compareValue;
204
+ });
205
+ }
206
+
207
+ /**
208
+ * Analyze post content patterns
209
+ */
210
+ private analyzePostContent(posts: SocialPost[]): any {
211
+ const totalPosts = posts.length;
212
+ if (totalPosts === 0) return null;
213
+
214
+ const contentLengths = posts.map((p) => p.content.length);
215
+ const avgLength = contentLengths.reduce((a, b) => a + b, 0) / totalPosts;
216
+
217
+ const withMedia = posts.filter((p) => p.mediaUrls && p.mediaUrls.length > 0).length;
218
+ const withHashtags = posts.filter((p) => p.content.includes('#')).length;
219
+ const withLinks = posts.filter((p) => p.content.includes('http://') || p.content.includes('https://')).length;
220
+
221
+ return {
222
+ averageLength: Math.round(avgLength),
223
+ minLength: Math.min(...contentLengths),
224
+ maxLength: Math.max(...contentLengths),
225
+ withMedia: withMedia,
226
+ withMediaPercentage: (withMedia / totalPosts) * 100,
227
+ withHashtags: withHashtags,
228
+ withHashtagsPercentage: (withHashtags / totalPosts) * 100,
229
+ withLinks: withLinks,
230
+ withLinksPercentage: (withLinks / totalPosts) * 100,
231
+ };
232
+ }
233
+
234
+ /**
235
+ * Extract top hashtags from posts
236
+ */
237
+ private extractTopHashtags(posts: SocialPost[]): Array<{ hashtag: string; count: number }> {
238
+ const hashtagCounts: Record<string, number> = {};
239
+
240
+ posts.forEach((post) => {
241
+ const hashtags = post.content.match(/#\w+/g) || [];
242
+ hashtags.forEach((tag) => {
243
+ const normalized = tag.toLowerCase();
244
+ hashtagCounts[normalized] = (hashtagCounts[normalized] || 0) + 1;
245
+ });
246
+ });
247
+
248
+ return Object.entries(hashtagCounts)
249
+ .map(([hashtag, count]) => ({ hashtag, count }))
250
+ .sort((a, b) => b.count - a.count)
251
+ .slice(0, 10);
252
+ }
253
+
254
+ /**
255
+ * Calculate performance statistics
256
+ */
257
+ private calculatePerformanceStats(posts: SocialPost[]): any {
258
+ const postsWithAnalytics = posts.filter((p) => p.analytics);
259
+ if (postsWithAnalytics.length === 0) return null;
260
+
261
+ const totalEngagements = postsWithAnalytics.reduce((sum, p) => sum + (p.analytics?.engagements || 0), 0);
262
+ const totalImpressions = postsWithAnalytics.reduce((sum, p) => sum + (p.analytics?.impressions || 0), 0);
263
+
264
+ const avgEngagements = totalEngagements / postsWithAnalytics.length;
265
+ const avgImpressions = totalImpressions / postsWithAnalytics.length;
266
+ const engagementRate = totalImpressions > 0 ? (totalEngagements / totalImpressions) * 100 : 0;
267
+
268
+ return {
269
+ postsAnalyzed: postsWithAnalytics.length,
270
+ averageEngagements: Math.round(avgEngagements),
271
+ averageImpressions: Math.round(avgImpressions),
272
+ totalEngagements: totalEngagements,
273
+ totalImpressions: totalImpressions,
274
+ engagementRate: engagementRate.toFixed(2),
275
+ };
276
+ }
277
+
278
+ /**
279
+ * Group posts by profile
280
+ */
281
+ private groupByProfile(posts: SocialPost[]): Record<string, number> {
282
+ const groups: Record<string, number> = {};
283
+
284
+ posts.forEach((post) => {
285
+ const profiles = post.platformSpecificData?.socialProfileIds || [post.profileId];
286
+ profiles.forEach((profileId: string) => {
287
+ groups[profileId] = (groups[profileId] || 0) + 1;
288
+ });
289
+ });
290
+
291
+ return groups;
292
+ }
293
+
294
+ /**
295
+ * Group posts by month
296
+ */
297
+ private groupByMonth(posts: SocialPost[]): Record<string, number> {
298
+ const groups: Record<string, number> = {};
299
+
300
+ posts.forEach((post) => {
301
+ const monthKey = post.publishedAt.toISOString().substring(0, 7);
302
+ groups[monthKey] = (groups[monthKey] || 0) + 1;
303
+ });
304
+
305
+ return groups;
306
+ }
307
+
308
+ /**
309
+ * Define the parameters this action expects
310
+ */
311
+ public get Params(): ActionParam[] {
312
+ return [
313
+ ...this.commonSocialParams,
314
+ {
315
+ Name: 'Query',
316
+ Type: 'Input',
317
+ Value: null,
318
+ },
319
+ {
320
+ Name: 'Hashtags',
321
+ Type: 'Input',
322
+ Value: null,
323
+ },
324
+ {
325
+ Name: 'StartDate',
326
+ Type: 'Input',
327
+ Value: null,
328
+ },
329
+ {
330
+ Name: 'EndDate',
331
+ Type: 'Input',
332
+ Value: null,
333
+ },
334
+ {
335
+ Name: 'PostState',
336
+ Type: 'Input',
337
+ Value: null,
338
+ },
339
+ {
340
+ Name: 'Limit',
341
+ Type: 'Input',
342
+ Value: null,
343
+ },
344
+ {
345
+ Name: 'IncludeAnalytics',
346
+ Type: 'Input',
347
+ Value: null,
348
+ },
349
+ {
350
+ Name: 'SortBy',
351
+ Type: 'Input',
352
+ Value: null,
353
+ },
354
+ {
355
+ Name: 'SortOrder',
356
+ Type: 'Input',
357
+ Value: null,
358
+ },
359
+ {
360
+ Name: 'Posts',
361
+ Type: 'Output',
362
+ Value: null,
363
+ },
364
+ {
365
+ Name: 'Summary',
366
+ Type: 'Output',
367
+ Value: null,
368
+ },
369
+ ];
370
+ }
371
+
372
+ /**
373
+ * Get action description
374
+ */
375
+ public get Description(): string {
376
+ return 'Searches historical posts in HootSuite with support for text queries, hashtags, date ranges, and content analysis';
377
+ }
378
+ }