@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.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +6 -6
- package/dist/base/base-social.action.d.ts.map +1 -1
- package/dist/base/base-social.action.js +18 -24
- package/dist/base/base-social.action.js.map +1 -1
- package/dist/providers/buffer/buffer-base.action.d.ts.map +1 -1
- package/dist/providers/buffer/buffer-base.action.js +35 -34
- package/dist/providers/buffer/buffer-base.action.js.map +1 -1
- package/dist/providers/facebook/actions/boost-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/boost-post.action.js +33 -33
- package/dist/providers/facebook/actions/boost-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/create-album.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/create-album.action.js +34 -36
- package/dist/providers/facebook/actions/create-album.action.js.map +1 -1
- package/dist/providers/facebook/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/create-post.action.js +20 -20
- package/dist/providers/facebook/actions/create-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-page-insights.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-page-insights.action.js +25 -27
- package/dist/providers/facebook/actions/get-page-insights.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-page-posts.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-page-posts.action.js +19 -23
- package/dist/providers/facebook/actions/get-page-posts.action.js.map +1 -1
- package/dist/providers/facebook/actions/get-post-insights.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/get-post-insights.action.js +28 -32
- package/dist/providers/facebook/actions/get-post-insights.action.js.map +1 -1
- package/dist/providers/facebook/actions/respond-to-comments.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/respond-to-comments.action.js +42 -44
- package/dist/providers/facebook/actions/respond-to-comments.action.js.map +1 -1
- package/dist/providers/facebook/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/schedule-post.action.js +29 -29
- package/dist/providers/facebook/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/facebook/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/facebook/actions/search-posts.action.js +37 -39
- package/dist/providers/facebook/actions/search-posts.action.js.map +1 -1
- package/dist/providers/facebook/facebook-base.action.d.ts.map +1 -1
- package/dist/providers/facebook/facebook-base.action.js +44 -59
- package/dist/providers/facebook/facebook-base.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js +33 -31
- package/dist/providers/hootsuite/actions/bulk-schedule-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.js +28 -32
- package/dist/providers/hootsuite/actions/create-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js +19 -19
- package/dist/providers/hootsuite/actions/delete-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-analytics.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-analytics.action.js +24 -26
- package/dist/providers/hootsuite/actions/get-analytics.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js +22 -22
- package/dist/providers/hootsuite/actions/get-scheduled-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/get-social-profiles.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/get-social-profiles.action.js +32 -34
- package/dist/providers/hootsuite/actions/get-social-profiles.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/search-posts.action.js +43 -52
- package/dist/providers/hootsuite/actions/search-posts.action.js.map +1 -1
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.js +30 -28
- package/dist/providers/hootsuite/actions/update-scheduled-post.action.js.map +1 -1
- package/dist/providers/hootsuite/hootsuite-base.action.d.ts.map +1 -1
- package/dist/providers/hootsuite/hootsuite-base.action.js +18 -20
- package/dist/providers/hootsuite/hootsuite-base.action.js.map +1 -1
- package/dist/providers/instagram/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/create-post.action.js +27 -26
- package/dist/providers/instagram/actions/create-post.action.js.map +1 -1
- package/dist/providers/instagram/actions/create-story.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/create-story.action.js +35 -35
- package/dist/providers/instagram/actions/create-story.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-account-insights.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-account-insights.action.js +38 -59
- package/dist/providers/instagram/actions/get-account-insights.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-business-posts.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-business-posts.action.js +29 -29
- package/dist/providers/instagram/actions/get-business-posts.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-comments.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-comments.action.js +36 -36
- package/dist/providers/instagram/actions/get-comments.action.js.map +1 -1
- package/dist/providers/instagram/actions/get-post-insights.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/get-post-insights.action.js +23 -25
- package/dist/providers/instagram/actions/get-post-insights.action.js.map +1 -1
- package/dist/providers/instagram/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/schedule-post.action.js +25 -25
- package/dist/providers/instagram/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/instagram/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/instagram/actions/search-posts.action.js +56 -60
- package/dist/providers/instagram/actions/search-posts.action.js.map +1 -1
- package/dist/providers/instagram/instagram-base.action.d.ts.map +1 -1
- package/dist/providers/instagram/instagram-base.action.js +25 -27
- package/dist/providers/instagram/instagram-base.action.js.map +1 -1
- package/dist/providers/linkedin/actions/create-article.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/create-article.action.js +55 -45
- package/dist/providers/linkedin/actions/create-article.action.js.map +1 -1
- package/dist/providers/linkedin/actions/create-post.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/create-post.action.js +31 -29
- package/dist/providers/linkedin/actions/create-post.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-followers.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-followers.action.js +28 -28
- package/dist/providers/linkedin/actions/get-followers.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-organization-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-organization-posts.action.js +20 -20
- package/dist/providers/linkedin/actions/get-organization-posts.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-personal-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-personal-posts.action.js +19 -19
- package/dist/providers/linkedin/actions/get-personal-posts.action.js.map +1 -1
- package/dist/providers/linkedin/actions/get-post-analytics.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/get-post-analytics.action.js +25 -23
- package/dist/providers/linkedin/actions/get-post-analytics.action.js.map +1 -1
- package/dist/providers/linkedin/actions/schedule-post.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/schedule-post.action.js +32 -30
- package/dist/providers/linkedin/actions/schedule-post.action.js.map +1 -1
- package/dist/providers/linkedin/actions/search-posts.action.d.ts.map +1 -1
- package/dist/providers/linkedin/actions/search-posts.action.js +28 -30
- package/dist/providers/linkedin/actions/search-posts.action.js.map +1 -1
- package/dist/providers/linkedin/linkedin-base.action.d.ts.map +1 -1
- package/dist/providers/linkedin/linkedin-base.action.js +33 -38
- package/dist/providers/linkedin/linkedin-base.action.js.map +1 -1
- package/dist/providers/tiktok/tiktok-base.action.d.ts.map +1 -1
- package/dist/providers/tiktok/tiktok-base.action.js +25 -26
- package/dist/providers/tiktok/tiktok-base.action.js.map +1 -1
- package/dist/providers/twitter/actions/create-thread.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/create-thread.action.js +25 -29
- package/dist/providers/twitter/actions/create-thread.action.js.map +1 -1
- package/dist/providers/twitter/actions/create-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/create-tweet.action.js +23 -23
- package/dist/providers/twitter/actions/create-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/delete-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/delete-tweet.action.js +19 -19
- package/dist/providers/twitter/actions/delete-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-analytics.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-analytics.action.js +40 -47
- package/dist/providers/twitter/actions/get-analytics.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-mentions.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-mentions.action.js +30 -31
- package/dist/providers/twitter/actions/get-mentions.action.js.map +1 -1
- package/dist/providers/twitter/actions/get-timeline.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/get-timeline.action.js +29 -29
- package/dist/providers/twitter/actions/get-timeline.action.js.map +1 -1
- package/dist/providers/twitter/actions/schedule-tweet.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/schedule-tweet.action.js +26 -26
- package/dist/providers/twitter/actions/schedule-tweet.action.js.map +1 -1
- package/dist/providers/twitter/actions/search-tweets.action.d.ts.map +1 -1
- package/dist/providers/twitter/actions/search-tweets.action.js +56 -58
- package/dist/providers/twitter/actions/search-tweets.action.js.map +1 -1
- package/dist/providers/twitter/twitter-base.action.d.ts.map +1 -1
- package/dist/providers/twitter/twitter-base.action.js +58 -68
- package/dist/providers/twitter/twitter-base.action.js.map +1 -1
- package/dist/providers/youtube/youtube-base.action.d.ts +1 -1
- package/dist/providers/youtube/youtube-base.action.d.ts.map +1 -1
- package/dist/providers/youtube/youtube-base.action.js +22 -25
- package/dist/providers/youtube/youtube-base.action.js.map +1 -1
- package/package.json +5 -6
- package/src/base/base-social.action.ts +217 -224
- package/src/providers/buffer/buffer-base.action.ts +435 -441
- package/src/providers/facebook/actions/boost-post.action.ts +350 -386
- package/src/providers/facebook/actions/create-album.action.ts +291 -307
- package/src/providers/facebook/actions/create-post.action.ts +224 -227
- package/src/providers/facebook/actions/get-page-insights.action.ts +383 -403
- package/src/providers/facebook/actions/get-page-posts.action.ts +214 -225
- package/src/providers/facebook/actions/get-post-insights.action.ts +300 -316
- package/src/providers/facebook/actions/respond-to-comments.action.ts +319 -336
- package/src/providers/facebook/actions/schedule-post.action.ts +289 -292
- package/src/providers/facebook/actions/search-posts.action.ts +399 -413
- package/src/providers/facebook/facebook-base.action.ts +653 -670
- package/src/providers/hootsuite/actions/bulk-schedule-posts.action.ts +257 -257
- package/src/providers/hootsuite/actions/create-scheduled-post.action.ts +184 -189
- package/src/providers/hootsuite/actions/delete-scheduled-post.action.ts +160 -161
- package/src/providers/hootsuite/actions/get-analytics.action.ts +249 -254
- package/src/providers/hootsuite/actions/get-scheduled-posts.action.ts +206 -207
- package/src/providers/hootsuite/actions/get-social-profiles.action.ts +206 -205
- package/src/providers/hootsuite/actions/search-posts.action.ts +351 -369
- package/src/providers/hootsuite/actions/update-scheduled-post.action.ts +211 -209
- package/src/providers/hootsuite/hootsuite-base.action.ts +301 -307
- package/src/providers/instagram/actions/create-post.action.ts +276 -296
- package/src/providers/instagram/actions/create-story.action.ts +378 -394
- package/src/providers/instagram/actions/get-account-insights.action.ts +384 -420
- package/src/providers/instagram/actions/get-business-posts.action.ts +233 -242
- package/src/providers/instagram/actions/get-comments.action.ts +365 -377
- package/src/providers/instagram/actions/get-post-insights.action.ts +265 -273
- package/src/providers/instagram/actions/schedule-post.action.ts +233 -235
- package/src/providers/instagram/actions/search-posts.action.ts +512 -538
- package/src/providers/instagram/instagram-base.action.ts +368 -393
- package/src/providers/linkedin/actions/create-article.action.ts +275 -266
- package/src/providers/linkedin/actions/create-post.action.ts +179 -177
- package/src/providers/linkedin/actions/get-followers.action.ts +211 -211
- package/src/providers/linkedin/actions/get-organization-posts.action.ts +146 -147
- package/src/providers/linkedin/actions/get-personal-posts.action.ts +138 -139
- package/src/providers/linkedin/actions/get-post-analytics.action.ts +190 -189
- package/src/providers/linkedin/actions/schedule-post.action.ts +191 -189
- package/src/providers/linkedin/actions/search-posts.action.ts +275 -283
- package/src/providers/linkedin/linkedin-base.action.ts +407 -421
- package/src/providers/tiktok/tiktok-base.action.ts +305 -320
- package/src/providers/twitter/actions/create-thread.action.ts +203 -207
- package/src/providers/twitter/actions/create-tweet.action.ts +187 -188
- package/src/providers/twitter/actions/delete-tweet.action.ts +128 -129
- package/src/providers/twitter/actions/get-analytics.action.ts +402 -411
- package/src/providers/twitter/actions/get-mentions.action.ts +218 -219
- package/src/providers/twitter/actions/get-timeline.action.ts +232 -233
- package/src/providers/twitter/actions/schedule-tweet.action.ts +221 -222
- package/src/providers/twitter/actions/search-tweets.action.ts +540 -543
- package/src/providers/twitter/twitter-base.action.ts +541 -560
- package/src/providers/youtube/youtube-base.action.ts +320 -333
|
@@ -1,59 +1,59 @@
|
|
|
1
1
|
import { BaseOAuthAction } from '@memberjunction/actions';
|
|
2
2
|
import { ActionParam } from '@memberjunction/actions-base';
|
|
3
|
-
import { LogStatus, LogError } from '@memberjunction/
|
|
3
|
+
import { LogStatus, LogError } from '@memberjunction/global';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Common interfaces for social media actions
|
|
7
7
|
*/
|
|
8
8
|
export interface SocialPost {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
id: string;
|
|
10
|
+
platform: string;
|
|
11
|
+
profileId: string;
|
|
12
|
+
content: string;
|
|
13
|
+
mediaUrls: string[];
|
|
14
|
+
publishedAt: Date;
|
|
15
|
+
scheduledFor?: Date;
|
|
16
|
+
analytics?: SocialAnalytics;
|
|
17
|
+
platformSpecificData: Record<string, any>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export interface SocialAnalytics {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
impressions: number;
|
|
22
|
+
engagements: number;
|
|
23
|
+
clicks: number;
|
|
24
|
+
shares: number;
|
|
25
|
+
comments: number;
|
|
26
|
+
likes: number;
|
|
27
|
+
reach: number;
|
|
28
|
+
saves?: number;
|
|
29
|
+
videoViews?: number;
|
|
30
|
+
platformMetrics: Record<string, any>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export interface SearchParams {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
query?: string;
|
|
35
|
+
hashtags?: string[];
|
|
36
|
+
startDate?: Date;
|
|
37
|
+
endDate?: Date;
|
|
38
|
+
limit?: number;
|
|
39
|
+
offset?: number;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export interface MediaFile {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
filename: string;
|
|
44
|
+
mimeType: string;
|
|
45
|
+
data: Buffer | string; // Base64 or buffer
|
|
46
|
+
size: number;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
export enum SocialMediaErrorCode {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
RATE_LIMIT_EXCEEDED = 'RATE_LIMIT',
|
|
51
|
+
INVALID_TOKEN = 'INVALID_TOKEN',
|
|
52
|
+
TOKEN_EXPIRED = 'TOKEN_EXPIRED',
|
|
53
|
+
PLATFORM_ERROR = 'PLATFORM_ERROR',
|
|
54
|
+
INVALID_MEDIA = 'INVALID_MEDIA',
|
|
55
|
+
POST_NOT_FOUND = 'POST_NOT_FOUND',
|
|
56
|
+
INSUFFICIENT_PERMISSIONS = 'INSUFFICIENT_PERMISSIONS',
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/**
|
|
@@ -62,209 +62,202 @@ export enum SocialMediaErrorCode {
|
|
|
62
62
|
* analytics normalization, and rate limiting.
|
|
63
63
|
*/
|
|
64
64
|
export abstract class BaseSocialMediaAction extends BaseOAuthAction {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
65
|
+
/**
|
|
66
|
+
* Common parameters for all social media actions
|
|
67
|
+
*/
|
|
68
|
+
protected get commonSocialParams(): ActionParam[] {
|
|
69
|
+
return [
|
|
70
|
+
...this.oauthParams,
|
|
71
|
+
{
|
|
72
|
+
Name: 'ProfileID',
|
|
73
|
+
Type: 'Input',
|
|
74
|
+
Value: null,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
}
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Get the API base URL for the platform
|
|
87
|
-
*/
|
|
88
|
-
protected abstract get apiBaseUrl(): string;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Normalize platform-specific analytics to common format
|
|
92
|
-
*/
|
|
93
|
-
protected normalizeAnalytics(platformData: any): SocialAnalytics {
|
|
94
|
-
// Default implementation - override in platform-specific classes
|
|
95
|
-
return {
|
|
96
|
-
impressions: platformData.impressions || 0,
|
|
97
|
-
engagements: platformData.engagements || 0,
|
|
98
|
-
clicks: platformData.clicks || 0,
|
|
99
|
-
shares: platformData.shares || 0,
|
|
100
|
-
comments: platformData.comments || 0,
|
|
101
|
-
likes: platformData.likes || 0,
|
|
102
|
-
reach: platformData.reach || 0,
|
|
103
|
-
saves: platformData.saves,
|
|
104
|
-
videoViews: platformData.videoViews,
|
|
105
|
-
platformMetrics: platformData
|
|
106
|
-
};
|
|
107
|
-
}
|
|
79
|
+
/**
|
|
80
|
+
* Get the platform name (e.g., 'Twitter', 'LinkedIn')
|
|
81
|
+
*/
|
|
82
|
+
protected abstract get platformName(): string;
|
|
108
83
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const uploadedUrls: string[] = [];
|
|
114
|
-
|
|
115
|
-
for (const file of files) {
|
|
116
|
-
// Validate file
|
|
117
|
-
this.validateMediaFile(file);
|
|
118
|
-
|
|
119
|
-
// Upload file (platform-specific implementation)
|
|
120
|
-
const url = await this.uploadSingleMedia(file);
|
|
121
|
-
uploadedUrls.push(url);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return uploadedUrls;
|
|
125
|
-
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the API base URL for the platform
|
|
86
|
+
*/
|
|
87
|
+
protected abstract get apiBaseUrl(): string;
|
|
126
88
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
throw new Error(`Unsupported media type: ${file.mimeType}`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (file.size > maxSize) {
|
|
149
|
-
throw new Error(`File size exceeds limit. Max ${maxSize} bytes, got ${file.size} bytes`);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
89
|
+
/**
|
|
90
|
+
* Normalize platform-specific analytics to common format
|
|
91
|
+
*/
|
|
92
|
+
protected normalizeAnalytics(platformData: any): SocialAnalytics {
|
|
93
|
+
// Default implementation - override in platform-specific classes
|
|
94
|
+
return {
|
|
95
|
+
impressions: platformData.impressions || 0,
|
|
96
|
+
engagements: platformData.engagements || 0,
|
|
97
|
+
clicks: platformData.clicks || 0,
|
|
98
|
+
shares: platformData.shares || 0,
|
|
99
|
+
comments: platformData.comments || 0,
|
|
100
|
+
likes: platformData.likes || 0,
|
|
101
|
+
reach: platformData.reach || 0,
|
|
102
|
+
saves: platformData.saves,
|
|
103
|
+
videoViews: platformData.videoViews,
|
|
104
|
+
platformMetrics: platformData,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
152
107
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
LogStatus(`Rate limit hit. Waiting ${waitTime} seconds...`);
|
|
159
|
-
|
|
160
|
-
await new Promise(resolve => setTimeout(resolve, waitTime * 1000));
|
|
161
|
-
}
|
|
108
|
+
/**
|
|
109
|
+
* Upload media files to the platform
|
|
110
|
+
*/
|
|
111
|
+
protected async uploadMedia(files: MediaFile[]): Promise<string[]> {
|
|
112
|
+
const uploadedUrls: string[] = [];
|
|
162
113
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
protected abstract searchPosts(params: SearchParams): Promise<SocialPost[]>;
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Convert platform-specific post data to common format
|
|
170
|
-
*/
|
|
171
|
-
protected abstract normalizePost(platformPost: any): SocialPost;
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Parse rate limit headers from API response
|
|
175
|
-
*/
|
|
176
|
-
protected parseRateLimitHeaders(headers: any): {
|
|
177
|
-
remaining: number;
|
|
178
|
-
reset: Date;
|
|
179
|
-
limit: number;
|
|
180
|
-
} | null {
|
|
181
|
-
// Common header patterns across platforms
|
|
182
|
-
const remaining = headers['x-rate-limit-remaining'] ||
|
|
183
|
-
headers['x-ratelimit-remaining'] ||
|
|
184
|
-
headers['rate-limit-remaining'];
|
|
185
|
-
|
|
186
|
-
const reset = headers['x-rate-limit-reset'] ||
|
|
187
|
-
headers['x-ratelimit-reset'] ||
|
|
188
|
-
headers['rate-limit-reset'];
|
|
189
|
-
|
|
190
|
-
const limit = headers['x-rate-limit-limit'] ||
|
|
191
|
-
headers['x-ratelimit-limit'] ||
|
|
192
|
-
headers['rate-limit-limit'];
|
|
193
|
-
|
|
194
|
-
if (remaining !== undefined && reset && limit) {
|
|
195
|
-
return {
|
|
196
|
-
remaining: parseInt(remaining),
|
|
197
|
-
reset: new Date(parseInt(reset) * 1000), // Usually Unix timestamp
|
|
198
|
-
limit: parseInt(limit)
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
114
|
+
for (const file of files) {
|
|
115
|
+
// Validate file
|
|
116
|
+
this.validateMediaFile(file);
|
|
204
117
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
protected buildHeaders(additionalHeaders?: Record<string, string>): Record<string, string> {
|
|
209
|
-
const token = this.getAccessToken();
|
|
210
|
-
if (!token) {
|
|
211
|
-
throw new Error('No access token available');
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return {
|
|
215
|
-
'Authorization': `Bearer ${token}`,
|
|
216
|
-
'Content-Type': 'application/json',
|
|
217
|
-
'Accept': 'application/json',
|
|
218
|
-
...additionalHeaders
|
|
219
|
-
};
|
|
118
|
+
// Upload file (platform-specific implementation)
|
|
119
|
+
const url = await this.uploadSingleMedia(file);
|
|
120
|
+
uploadedUrls.push(url);
|
|
220
121
|
}
|
|
221
122
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
123
|
+
return uploadedUrls;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Platform-specific media upload implementation
|
|
128
|
+
*/
|
|
129
|
+
protected abstract uploadSingleMedia(file: MediaFile): Promise<string>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Validate media file meets platform requirements
|
|
133
|
+
*/
|
|
134
|
+
protected validateMediaFile(file: MediaFile): void {
|
|
135
|
+
const maxSizes: Record<string, number> = {
|
|
136
|
+
'image/jpeg': 5 * 1024 * 1024, // 5MB
|
|
137
|
+
'image/png': 5 * 1024 * 1024, // 5MB
|
|
138
|
+
'image/gif': 15 * 1024 * 1024, // 15MB
|
|
139
|
+
'video/mp4': 512 * 1024 * 1024, // 512MB
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const maxSize = maxSizes[file.mimeType];
|
|
143
|
+
if (!maxSize) {
|
|
144
|
+
throw new Error(`Unsupported media type: ${file.mimeType}`);
|
|
230
145
|
}
|
|
231
146
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
*/
|
|
235
|
-
protected parseDate(dateString: string): Date {
|
|
236
|
-
return new Date(dateString);
|
|
147
|
+
if (file.size > maxSize) {
|
|
148
|
+
throw new Error(`File size exceeds limit. Max ${maxSize} bytes, got ${file.size} bytes`);
|
|
237
149
|
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Handle rate limiting with exponential backoff
|
|
154
|
+
*/
|
|
155
|
+
protected async handleRateLimit(retryAfter?: number): Promise<void> {
|
|
156
|
+
const waitTime = retryAfter || 60; // Default to 60 seconds
|
|
157
|
+
LogStatus(`Rate limit hit. Waiting ${waitTime} seconds...`);
|
|
158
|
+
|
|
159
|
+
await new Promise((resolve) => setTimeout(resolve, waitTime * 1000));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Search for posts on the platform
|
|
164
|
+
*/
|
|
165
|
+
protected abstract searchPosts(params: SearchParams): Promise<SocialPost[]>;
|
|
238
166
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Convert platform-specific post data to common format
|
|
169
|
+
*/
|
|
170
|
+
protected abstract normalizePost(platformPost: any): SocialPost;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Parse rate limit headers from API response
|
|
174
|
+
*/
|
|
175
|
+
protected parseRateLimitHeaders(headers: any): {
|
|
176
|
+
remaining: number;
|
|
177
|
+
reset: Date;
|
|
178
|
+
limit: number;
|
|
179
|
+
} | null {
|
|
180
|
+
// Common header patterns across platforms
|
|
181
|
+
const remaining = headers['x-rate-limit-remaining'] || headers['x-ratelimit-remaining'] || headers['rate-limit-remaining'];
|
|
182
|
+
|
|
183
|
+
const reset = headers['x-rate-limit-reset'] || headers['x-ratelimit-reset'] || headers['rate-limit-reset'];
|
|
184
|
+
|
|
185
|
+
const limit = headers['x-rate-limit-limit'] || headers['x-ratelimit-limit'] || headers['rate-limit-limit'];
|
|
186
|
+
|
|
187
|
+
if (remaining !== undefined && reset && limit) {
|
|
188
|
+
return {
|
|
189
|
+
remaining: parseInt(remaining),
|
|
190
|
+
reset: new Date(parseInt(reset) * 1000), // Usually Unix timestamp
|
|
191
|
+
limit: parseInt(limit),
|
|
192
|
+
};
|
|
244
193
|
}
|
|
245
194
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Build common API headers including authentication
|
|
200
|
+
*/
|
|
201
|
+
protected buildHeaders(additionalHeaders?: Record<string, string>): Record<string, string> {
|
|
202
|
+
const token = this.getAccessToken();
|
|
203
|
+
if (!token) {
|
|
204
|
+
throw new Error('No access token available');
|
|
254
205
|
}
|
|
255
206
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
207
|
+
return {
|
|
208
|
+
Authorization: `Bearer ${token}`,
|
|
209
|
+
'Content-Type': 'application/json',
|
|
210
|
+
Accept: 'application/json',
|
|
211
|
+
...additionalHeaders,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Format date for API requests (ISO 8601)
|
|
217
|
+
*/
|
|
218
|
+
protected formatDate(date: Date | string): string {
|
|
219
|
+
if (typeof date === 'string') {
|
|
220
|
+
date = new Date(date);
|
|
261
221
|
}
|
|
222
|
+
return date.toISOString();
|
|
223
|
+
}
|
|
262
224
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
225
|
+
/**
|
|
226
|
+
* Parse date from API response
|
|
227
|
+
*/
|
|
228
|
+
protected parseDate(dateString: string): Date {
|
|
229
|
+
return new Date(dateString);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get profile ID from parameters or default from integration
|
|
234
|
+
*/
|
|
235
|
+
protected getProfileId(params: any): string {
|
|
236
|
+
return params.ProfileID || this.getCustomAttribute(1) || '';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Log API request for debugging
|
|
241
|
+
*/
|
|
242
|
+
protected logApiRequest(method: string, url: string, data?: any): void {
|
|
243
|
+
LogStatus(`${this.platformName} API Request: ${method} ${url}`);
|
|
244
|
+
if (data) {
|
|
245
|
+
LogStatus(`Request Data: ${JSON.stringify(data, null, 2)}`);
|
|
269
246
|
}
|
|
270
|
-
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Log API response for debugging
|
|
251
|
+
*/
|
|
252
|
+
protected logApiResponse(response: any): void {
|
|
253
|
+
LogStatus(`${this.platformName} API Response: ${JSON.stringify(response, null, 2)}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Helper to get parameter value from params array
|
|
258
|
+
*/
|
|
259
|
+
protected getParamValue(params: ActionParam[], paramName: string): any {
|
|
260
|
+
const param = params.find((p) => p.Name === paramName);
|
|
261
|
+
return param?.Value;
|
|
262
|
+
}
|
|
263
|
+
}
|