@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
@@ -1,7 +1,7 @@
1
1
  import { RegisterClass } from '@memberjunction/global';
2
2
  import { InstagramBaseAction } from '../instagram-base.action';
3
3
  import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
4
- import { LogError } from '@memberjunction/global';
4
+ import { LogError } from '@memberjunction/core';
5
5
  import { BaseAction } from '@memberjunction/actions';
6
6
 
7
7
  /**
@@ -10,375 +10,387 @@ import { BaseAction } from '@memberjunction/actions';
10
10
  */
11
11
  @RegisterClass(BaseAction, 'Instagram - Get Comments')
12
12
  export class InstagramGetCommentsAction extends InstagramBaseAction {
13
- protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
14
- try {
15
- const companyIntegrationId = this.getParamValue(params.Params, 'CompanyIntegrationID');
16
- const postId = this.getParamValue(params.Params, 'PostID');
17
- const includeReplies = this.getParamValue(params.Params, 'IncludeReplies') !== false;
18
- const includeHidden = this.getParamValue(params.Params, 'IncludeHidden') || false;
19
- const limit = this.getParamValue(params.Params, 'Limit') || 50;
20
- const afterCursor = this.getParamValue(params.Params, 'AfterCursor');
21
-
22
- // Initialize OAuth
23
- if (!(await this.initializeOAuth(companyIntegrationId))) {
24
- return {
25
- Success: false,
26
- Message: 'Failed to initialize Instagram authentication',
27
- ResultCode: 'AUTH_FAILED',
28
- };
29
- }
30
-
31
- // Validate inputs
32
- if (!postId) {
33
- return {
34
- Success: false,
35
- Message: 'PostID is required',
36
- ResultCode: 'MISSING_PARAMS',
37
- };
38
- }
39
-
40
- // Build fields for comment data
41
- const fields = 'id,text,username,timestamp,like_count,replies{id,text,username,timestamp,like_count}';
42
-
43
- // Build query parameters
44
- const queryParams: any = {
45
- fields,
46
- access_token: this.getAccessToken(),
47
- limit: Math.min(limit, 100),
48
- };
49
-
50
- if (afterCursor) {
51
- queryParams.after = afterCursor;
52
- }
53
-
54
- // Get comments
55
- const response = await this.makeInstagramRequest<{
56
- data: any[];
57
- paging?: {
58
- cursors: {
59
- before: string;
60
- after: string;
61
- };
62
- next?: string;
63
- };
64
- }>(`${postId}/comments`, 'GET', null, queryParams);
65
-
66
- const comments = response.data || [];
67
-
68
- // Process comments
69
- const processedComments = await this.processComments(comments, includeReplies);
70
-
71
- // Get hidden comments if requested
72
- let hiddenComments: any[] = [];
73
- if (includeHidden) {
74
- hiddenComments = await this.getHiddenComments(postId);
75
- }
76
-
77
- // Calculate engagement metrics
78
- const metrics = this.calculateCommentMetrics(processedComments);
79
-
80
- // Analyze sentiment patterns
81
- const sentimentAnalysis = this.analyzeSentiment(processedComments);
82
-
83
- // Store result in output params
84
- const outputParams = [...params.Params];
85
- outputParams.push({
86
- Name: 'ResultData',
87
- Type: 'Output',
88
- Value: JSON.stringify({
89
- postId,
90
- comments: processedComments,
91
- hiddenComments,
92
- metrics,
93
- sentimentAnalysis,
94
- paging: {
95
- hasNext: !!response.paging?.next,
96
- afterCursor: response.paging?.cursors?.after,
97
- },
98
- }),
99
- });
100
-
101
- return {
102
- Success: true,
103
- Message: `Retrieved ${processedComments.length} comments`,
104
- ResultCode: 'SUCCESS',
105
- Params: outputParams,
106
- };
107
- } catch (error: any) {
108
- LogError('Failed to retrieve Instagram comments', error);
109
-
110
- if (error.code === 'RATE_LIMIT') {
111
- return {
112
- Success: false,
113
- Message: 'Instagram API rate limit exceeded. Please try again later.',
114
- ResultCode: 'RATE_LIMIT',
13
+
14
+ protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
15
+ try {
16
+ const companyIntegrationId = this.getParamValue(params.Params, 'CompanyIntegrationID');
17
+ const postId = this.getParamValue(params.Params, 'PostID');
18
+ const includeReplies = this.getParamValue(params.Params, 'IncludeReplies') !== false;
19
+ const includeHidden = this.getParamValue(params.Params, 'IncludeHidden') || false;
20
+ const limit = this.getParamValue(params.Params, 'Limit') || 50;
21
+ const afterCursor = this.getParamValue(params.Params, 'AfterCursor');
22
+
23
+ // Initialize OAuth
24
+ if (!await this.initializeOAuth(companyIntegrationId)) {
25
+ return {
26
+ Success: false,
27
+ Message: 'Failed to initialize Instagram authentication',
28
+ ResultCode: 'AUTH_FAILED'
29
+ };
30
+ }
31
+
32
+ // Validate inputs
33
+ if (!postId) {
34
+ return {
35
+ Success: false,
36
+ Message: 'PostID is required',
37
+ ResultCode: 'MISSING_PARAMS'
38
+ };
39
+ }
40
+
41
+ // Build fields for comment data
42
+ const fields = 'id,text,username,timestamp,like_count,replies{id,text,username,timestamp,like_count}';
43
+
44
+ // Build query parameters
45
+ const queryParams: any = {
46
+ fields,
47
+ access_token: this.getAccessToken(),
48
+ limit: Math.min(limit, 100)
49
+ };
50
+
51
+ if (afterCursor) {
52
+ queryParams.after = afterCursor;
53
+ }
54
+
55
+ // Get comments
56
+ const response = await this.makeInstagramRequest<{
57
+ data: any[];
58
+ paging?: {
59
+ cursors: {
60
+ before: string;
61
+ after: string;
62
+ };
63
+ next?: string;
64
+ };
65
+ }>(
66
+ `${postId}/comments`,
67
+ 'GET',
68
+ null,
69
+ queryParams
70
+ );
71
+
72
+ const comments = response.data || [];
73
+
74
+ // Process comments
75
+ const processedComments = await this.processComments(comments, includeReplies);
76
+
77
+ // Get hidden comments if requested
78
+ let hiddenComments: any[] = [];
79
+ if (includeHidden) {
80
+ hiddenComments = await this.getHiddenComments(postId);
81
+ }
82
+
83
+ // Calculate engagement metrics
84
+ const metrics = this.calculateCommentMetrics(processedComments);
85
+
86
+ // Analyze sentiment patterns
87
+ const sentimentAnalysis = this.analyzeSentiment(processedComments);
88
+
89
+ // Store result in output params
90
+ const outputParams = [...params.Params];
91
+ outputParams.push({
92
+ Name: 'ResultData',
93
+ Type: 'Output',
94
+ Value: JSON.stringify({
95
+ postId,
96
+ comments: processedComments,
97
+ hiddenComments,
98
+ metrics,
99
+ sentimentAnalysis,
100
+ paging: {
101
+ hasNext: !!response.paging?.next,
102
+ afterCursor: response.paging?.cursors?.after
103
+ }
104
+ })
105
+ });
106
+
107
+ return {
108
+ Success: true,
109
+ Message: `Retrieved ${processedComments.length} comments`,
110
+ ResultCode: 'SUCCESS',
111
+ Params: outputParams
112
+ };
113
+
114
+ } catch (error: any) {
115
+ LogError('Failed to retrieve Instagram comments', error);
116
+
117
+ if (error.code === 'RATE_LIMIT') {
118
+ return {
119
+ Success: false,
120
+ Message: 'Instagram API rate limit exceeded. Please try again later.',
121
+ ResultCode: 'RATE_LIMIT'
122
+ };
123
+ }
124
+
125
+ if (error.code === 'POST_NOT_FOUND') {
126
+ return {
127
+ Success: false,
128
+ Message: 'Instagram post not found or access denied',
129
+ ResultCode: 'POST_NOT_FOUND'
130
+ };
131
+ }
132
+
133
+ return {
134
+ Success: false,
135
+ Message: `Failed to retrieve comments: ${error.message}`,
136
+ ResultCode: 'ERROR'
137
+ };
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Process comments and fetch replies if needed
143
+ */
144
+ private async processComments(comments: any[], includeReplies: boolean): Promise<any[]> {
145
+ const processed: any[] = [];
146
+
147
+ for (const comment of comments) {
148
+ const processedComment: any = {
149
+ id: comment.id,
150
+ text: comment.text,
151
+ username: comment.username,
152
+ timestamp: comment.timestamp,
153
+ likeCount: comment.like_count || 0,
154
+ replies: [],
155
+ metrics: {
156
+ wordCount: this.countWords(comment.text),
157
+ hasEmojis: this.containsEmojis(comment.text),
158
+ hasMentions: this.containsMentions(comment.text),
159
+ hasHashtags: this.containsHashtags(comment.text)
160
+ }
161
+ };
162
+
163
+ // Process replies if they exist and are requested
164
+ if (includeReplies && comment.replies?.data) {
165
+ processedComment.replies = comment.replies.data.map((reply: any) => ({
166
+ id: reply.id,
167
+ text: reply.text,
168
+ username: reply.username,
169
+ timestamp: reply.timestamp,
170
+ likeCount: reply.like_count || 0,
171
+ metrics: {
172
+ wordCount: this.countWords(reply.text),
173
+ hasEmojis: this.containsEmojis(reply.text),
174
+ hasMentions: this.containsMentions(reply.text),
175
+ hasHashtags: this.containsHashtags(reply.text)
176
+ }
177
+ }));
178
+ }
179
+
180
+ processed.push(processedComment);
181
+ }
182
+
183
+ return processed;
184
+ }
185
+
186
+ /**
187
+ * Get hidden comments (comments hidden by the account)
188
+ */
189
+ private async getHiddenComments(postId: string): Promise<any[]> {
190
+ try {
191
+ const response = await this.makeInstagramRequest<{ data: any[] }>(
192
+ `${postId}/comments`,
193
+ 'GET',
194
+ null,
195
+ {
196
+ fields: 'id,text,username,timestamp,hidden',
197
+ access_token: this.getAccessToken(),
198
+ filter: 'hidden'
199
+ }
200
+ );
201
+
202
+ return response.data || [];
203
+ } catch (error) {
204
+ LogError('Failed to get hidden comments', error);
205
+ return [];
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Calculate comment metrics
211
+ */
212
+ private calculateCommentMetrics(comments: any[]): any {
213
+ const metrics = {
214
+ totalComments: comments.length,
215
+ totalReplies: 0,
216
+ avgCommentLength: 0,
217
+ avgLikesPerComment: 0,
218
+ topCommenters: [] as any[],
219
+ engagementRate: 0,
220
+ responseRate: 0
115
221
  };
116
- }
117
222
 
118
- if (error.code === 'POST_NOT_FOUND') {
119
- return {
120
- Success: false,
121
- Message: 'Instagram post not found or access denied',
122
- ResultCode: 'POST_NOT_FOUND',
223
+ if (comments.length === 0) return metrics;
224
+
225
+ let totalLength = 0;
226
+ let totalLikes = 0;
227
+ const commenterCounts: Record<string, number> = {};
228
+
229
+ comments.forEach(comment => {
230
+ totalLength += comment.metrics.wordCount;
231
+ totalLikes += comment.likeCount;
232
+
233
+ // Count commenters
234
+ commenterCounts[comment.username] = (commenterCounts[comment.username] || 0) + 1;
235
+
236
+ // Count replies
237
+ metrics.totalReplies += comment.replies.length;
238
+
239
+ // Add reply stats
240
+ comment.replies.forEach((reply: any) => {
241
+ totalLength += reply.metrics.wordCount;
242
+ totalLikes += reply.likeCount;
243
+ commenterCounts[reply.username] = (commenterCounts[reply.username] || 0) + 1;
244
+ });
245
+ });
246
+
247
+ const totalInteractions = comments.length + metrics.totalReplies;
248
+ metrics.avgCommentLength = Math.round(totalLength / totalInteractions);
249
+ metrics.avgLikesPerComment = Math.round(totalLikes / totalInteractions);
250
+
251
+ // Get top commenters
252
+ metrics.topCommenters = Object.entries(commenterCounts)
253
+ .sort(([, a], [, b]) => b - a)
254
+ .slice(0, 10)
255
+ .map(([username, count]) => ({ username, count }));
256
+
257
+ // Calculate response rate (comments with replies)
258
+ const commentsWithReplies = comments.filter(c => c.replies.length > 0).length;
259
+ metrics.responseRate = (commentsWithReplies / comments.length) * 100;
260
+
261
+ return metrics;
262
+ }
263
+
264
+ /**
265
+ * Analyze sentiment patterns in comments
266
+ */
267
+ private analyzeSentiment(comments: any[]): any {
268
+ const analysis = {
269
+ positive: 0,
270
+ negative: 0,
271
+ neutral: 0,
272
+ questions: 0,
273
+ keywords: [] as any[],
274
+ emojis: [] as any[]
123
275
  };
124
- }
125
276
 
126
- return {
127
- Success: false,
128
- Message: `Failed to retrieve comments: ${error.message}`,
129
- ResultCode: 'ERROR',
130
- };
277
+ const keywordCounts: Record<string, number> = {};
278
+ const emojiCounts: Record<string, number> = {};
279
+
280
+ // Simple sentiment analysis based on keywords and patterns
281
+ const positiveWords = ['love', 'amazing', 'beautiful', 'great', 'awesome', 'perfect', 'excellent', 'wonderful', '❤️', '😍', '🔥', '💯'];
282
+ const negativeWords = ['hate', 'awful', 'terrible', 'bad', 'worst', 'ugly', 'disgusting', '😠', '😡', '👎'];
283
+ const questionWords = ['?', 'what', 'where', 'when', 'how', 'why', 'who'];
284
+
285
+ comments.forEach(comment => {
286
+ const text = comment.text.toLowerCase();
287
+
288
+ // Check sentiment
289
+ const hasPositive = positiveWords.some(word => text.includes(word));
290
+ const hasNegative = negativeWords.some(word => text.includes(word));
291
+ const hasQuestion = questionWords.some(word => text.includes(word));
292
+
293
+ if (hasQuestion) {
294
+ analysis.questions++;
295
+ }
296
+
297
+ if (hasPositive && !hasNegative) {
298
+ analysis.positive++;
299
+ } else if (hasNegative && !hasPositive) {
300
+ analysis.negative++;
301
+ } else {
302
+ analysis.neutral++;
303
+ }
304
+
305
+ // Extract keywords (simple word frequency)
306
+ const words = text.split(/\s+/).filter(word => word.length > 3);
307
+ words.forEach(word => {
308
+ keywordCounts[word] = (keywordCounts[word] || 0) + 1;
309
+ });
310
+
311
+ // Extract emojis
312
+ const emojis = text.match(/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]/gu) || [];
313
+ emojis.forEach(emoji => {
314
+ emojiCounts[emoji] = (emojiCounts[emoji] || 0) + 1;
315
+ });
316
+
317
+ // Analyze replies too
318
+ comment.replies.forEach((reply: any) => {
319
+ // Similar analysis for replies...
320
+ });
321
+ });
322
+
323
+ // Get top keywords and emojis
324
+ analysis.keywords = Object.entries(keywordCounts)
325
+ .sort(([, a], [, b]) => b - a)
326
+ .slice(0, 20)
327
+ .map(([keyword, count]) => ({ keyword, count }));
328
+
329
+ analysis.emojis = Object.entries(emojiCounts)
330
+ .sort(([, a], [, b]) => b - a)
331
+ .slice(0, 10)
332
+ .map(([emoji, count]) => ({ emoji, count }));
333
+
334
+ return analysis;
335
+ }
336
+
337
+ /**
338
+ * Helper methods for text analysis
339
+ */
340
+ private countWords(text: string): number {
341
+ return text.trim().split(/\s+/).length;
342
+ }
343
+
344
+ private containsEmojis(text: string): boolean {
345
+ return /[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]/u.test(text);
131
346
  }
132
- }
133
-
134
- /**
135
- * Process comments and fetch replies if needed
136
- */
137
- private async processComments(comments: any[], includeReplies: boolean): Promise<any[]> {
138
- const processed: any[] = [];
139
-
140
- for (const comment of comments) {
141
- const processedComment: any = {
142
- id: comment.id,
143
- text: comment.text,
144
- username: comment.username,
145
- timestamp: comment.timestamp,
146
- likeCount: comment.like_count || 0,
147
- replies: [],
148
- metrics: {
149
- wordCount: this.countWords(comment.text),
150
- hasEmojis: this.containsEmojis(comment.text),
151
- hasMentions: this.containsMentions(comment.text),
152
- hasHashtags: this.containsHashtags(comment.text),
153
- },
154
- };
155
-
156
- // Process replies if they exist and are requested
157
- if (includeReplies && comment.replies?.data) {
158
- processedComment.replies = comment.replies.data.map((reply: any) => ({
159
- id: reply.id,
160
- text: reply.text,
161
- username: reply.username,
162
- timestamp: reply.timestamp,
163
- likeCount: reply.like_count || 0,
164
- metrics: {
165
- wordCount: this.countWords(reply.text),
166
- hasEmojis: this.containsEmojis(reply.text),
167
- hasMentions: this.containsMentions(reply.text),
168
- hasHashtags: this.containsHashtags(reply.text),
169
- },
170
- }));
171
- }
172
-
173
- processed.push(processedComment);
347
+
348
+ private containsMentions(text: string): boolean {
349
+ return /@\w+/.test(text);
350
+ }
351
+
352
+ private containsHashtags(text: string): boolean {
353
+ return /#\w+/.test(text);
354
+ }
355
+
356
+ /**
357
+ * Define the parameters for this action
358
+ */
359
+ public get Params(): ActionParam[] {
360
+ return [
361
+ ...this.commonSocialParams,
362
+ {
363
+ Name: 'PostID',
364
+ Type: 'Input',
365
+ Value: null
366
+ },
367
+ {
368
+ Name: 'IncludeReplies',
369
+ Type: 'Input',
370
+ Value: true
371
+ },
372
+ {
373
+ Name: 'IncludeHidden',
374
+ Type: 'Input',
375
+ Value: false
376
+ },
377
+ {
378
+ Name: 'Limit',
379
+ Type: 'Input',
380
+ Value: 50
381
+ },
382
+ {
383
+ Name: 'AfterCursor',
384
+ Type: 'Input',
385
+ Value: null
386
+ }
387
+ ];
174
388
  }
175
389
 
176
- return processed;
177
- }
178
-
179
- /**
180
- * Get hidden comments (comments hidden by the account)
181
- */
182
- private async getHiddenComments(postId: string): Promise<any[]> {
183
- try {
184
- const response = await this.makeInstagramRequest<{ data: any[] }>(`${postId}/comments`, 'GET', null, {
185
- fields: 'id,text,username,timestamp,hidden',
186
- access_token: this.getAccessToken(),
187
- filter: 'hidden',
188
- });
189
-
190
- return response.data || [];
191
- } catch (error) {
192
- LogError('Failed to get hidden comments', error);
193
- return [];
390
+ /**
391
+ * Get the description for this action
392
+ */
393
+ public get Description(): string {
394
+ return 'Retrieves comments for an Instagram post including replies, metrics, and sentiment analysis.';
194
395
  }
195
- }
196
-
197
- /**
198
- * Calculate comment metrics
199
- */
200
- private calculateCommentMetrics(comments: any[]): any {
201
- const metrics = {
202
- totalComments: comments.length,
203
- totalReplies: 0,
204
- avgCommentLength: 0,
205
- avgLikesPerComment: 0,
206
- topCommenters: [] as any[],
207
- engagementRate: 0,
208
- responseRate: 0,
209
- };
210
-
211
- if (comments.length === 0) return metrics;
212
-
213
- let totalLength = 0;
214
- let totalLikes = 0;
215
- const commenterCounts: Record<string, number> = {};
216
-
217
- comments.forEach((comment) => {
218
- totalLength += comment.metrics.wordCount;
219
- totalLikes += comment.likeCount;
220
-
221
- // Count commenters
222
- commenterCounts[comment.username] = (commenterCounts[comment.username] || 0) + 1;
223
-
224
- // Count replies
225
- metrics.totalReplies += comment.replies.length;
226
-
227
- // Add reply stats
228
- comment.replies.forEach((reply: any) => {
229
- totalLength += reply.metrics.wordCount;
230
- totalLikes += reply.likeCount;
231
- commenterCounts[reply.username] = (commenterCounts[reply.username] || 0) + 1;
232
- });
233
- });
234
-
235
- const totalInteractions = comments.length + metrics.totalReplies;
236
- metrics.avgCommentLength = Math.round(totalLength / totalInteractions);
237
- metrics.avgLikesPerComment = Math.round(totalLikes / totalInteractions);
238
-
239
- // Get top commenters
240
- metrics.topCommenters = Object.entries(commenterCounts)
241
- .sort(([, a], [, b]) => b - a)
242
- .slice(0, 10)
243
- .map(([username, count]) => ({ username, count }));
244
-
245
- // Calculate response rate (comments with replies)
246
- const commentsWithReplies = comments.filter((c) => c.replies.length > 0).length;
247
- metrics.responseRate = (commentsWithReplies / comments.length) * 100;
248
-
249
- return metrics;
250
- }
251
-
252
- /**
253
- * Analyze sentiment patterns in comments
254
- */
255
- private analyzeSentiment(comments: any[]): any {
256
- const analysis = {
257
- positive: 0,
258
- negative: 0,
259
- neutral: 0,
260
- questions: 0,
261
- keywords: [] as any[],
262
- emojis: [] as any[],
263
- };
264
-
265
- const keywordCounts: Record<string, number> = {};
266
- const emojiCounts: Record<string, number> = {};
267
-
268
- // Simple sentiment analysis based on keywords and patterns
269
- const positiveWords = ['love', 'amazing', 'beautiful', 'great', 'awesome', 'perfect', 'excellent', 'wonderful', '❤️', '😍', '🔥', '💯'];
270
- const negativeWords = ['hate', 'awful', 'terrible', 'bad', 'worst', 'ugly', 'disgusting', '😠', '😡', '👎'];
271
- const questionWords = ['?', 'what', 'where', 'when', 'how', 'why', 'who'];
272
-
273
- comments.forEach((comment) => {
274
- const text = comment.text.toLowerCase();
275
-
276
- // Check sentiment
277
- const hasPositive = positiveWords.some((word) => text.includes(word));
278
- const hasNegative = negativeWords.some((word) => text.includes(word));
279
- const hasQuestion = questionWords.some((word) => text.includes(word));
280
-
281
- if (hasQuestion) {
282
- analysis.questions++;
283
- }
284
-
285
- if (hasPositive && !hasNegative) {
286
- analysis.positive++;
287
- } else if (hasNegative && !hasPositive) {
288
- analysis.negative++;
289
- } else {
290
- analysis.neutral++;
291
- }
292
-
293
- // Extract keywords (simple word frequency)
294
- const words = text.split(/\s+/).filter((word) => word.length > 3);
295
- words.forEach((word) => {
296
- keywordCounts[word] = (keywordCounts[word] || 0) + 1;
297
- });
298
-
299
- // Extract emojis
300
- const emojis = text.match(/[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]/gu) || [];
301
- emojis.forEach((emoji) => {
302
- emojiCounts[emoji] = (emojiCounts[emoji] || 0) + 1;
303
- });
304
-
305
- // Analyze replies too
306
- comment.replies.forEach((reply: any) => {
307
- // Similar analysis for replies...
308
- });
309
- });
310
-
311
- // Get top keywords and emojis
312
- analysis.keywords = Object.entries(keywordCounts)
313
- .sort(([, a], [, b]) => b - a)
314
- .slice(0, 20)
315
- .map(([keyword, count]) => ({ keyword, count }));
316
-
317
- analysis.emojis = Object.entries(emojiCounts)
318
- .sort(([, a], [, b]) => b - a)
319
- .slice(0, 10)
320
- .map(([emoji, count]) => ({ emoji, count }));
321
-
322
- return analysis;
323
- }
324
-
325
- /**
326
- * Helper methods for text analysis
327
- */
328
- private countWords(text: string): number {
329
- return text.trim().split(/\s+/).length;
330
- }
331
-
332
- private containsEmojis(text: string): boolean {
333
- return /[\u{1F300}-\u{1F9FF}]|[\u{2600}-\u{26FF}]/u.test(text);
334
- }
335
-
336
- private containsMentions(text: string): boolean {
337
- return /@\w+/.test(text);
338
- }
339
-
340
- private containsHashtags(text: string): boolean {
341
- return /#\w+/.test(text);
342
- }
343
-
344
- /**
345
- * Define the parameters for this action
346
- */
347
- public get Params(): ActionParam[] {
348
- return [
349
- ...this.commonSocialParams,
350
- {
351
- Name: 'PostID',
352
- Type: 'Input',
353
- Value: null,
354
- },
355
- {
356
- Name: 'IncludeReplies',
357
- Type: 'Input',
358
- Value: true,
359
- },
360
- {
361
- Name: 'IncludeHidden',
362
- Type: 'Input',
363
- Value: false,
364
- },
365
- {
366
- Name: 'Limit',
367
- Type: 'Input',
368
- Value: 50,
369
- },
370
- {
371
- Name: 'AfterCursor',
372
- Type: 'Input',
373
- Value: null,
374
- },
375
- ];
376
- }
377
-
378
- /**
379
- * Get the description for this action
380
- */
381
- public get Description(): string {
382
- return 'Retrieves comments for an Instagram post including replies, metrics, and sentiment analysis.';
383
- }
384
- }
396
+ }