upload-post 2.1.0 → 2.2.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/.github/workflows/publish.yml +5 -5
- package/README.md +16 -0
- package/index.d.ts +97 -2
- package/index.js +160 -2
- package/package.json +1 -1
|
@@ -46,10 +46,6 @@ jobs:
|
|
|
46
46
|
echo "🚀 New version detected: $REMOTE → $LOCAL"
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
|
-
- name: Update npm to latest
|
|
50
|
-
if: steps.version_check.outputs.new == 'true' || github.event_name == 'workflow_dispatch'
|
|
51
|
-
run: npm install -g npm@latest && npm --version
|
|
52
|
-
|
|
53
49
|
- name: Install dependencies
|
|
54
50
|
if: steps.version_check.outputs.new == 'true' || github.event_name == 'workflow_dispatch'
|
|
55
51
|
run: npm ci
|
|
@@ -61,7 +57,11 @@ jobs:
|
|
|
61
57
|
- name: Publish to npm (dry-run)
|
|
62
58
|
if: ${{ inputs.dry_run == true }}
|
|
63
59
|
run: npm publish --access public --dry-run
|
|
60
|
+
env:
|
|
61
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
64
62
|
|
|
65
63
|
- name: Publish to npm
|
|
66
64
|
if: (steps.version_check.outputs.new == 'true' && inputs.dry_run != true) || github.event_name == 'release'
|
|
67
|
-
run: npm publish --access public
|
|
65
|
+
run: npm publish --access public
|
|
66
|
+
env:
|
|
67
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
CHANGED
|
@@ -181,6 +181,22 @@ const analytics = await client.getAnalytics('my-profile', {
|
|
|
181
181
|
console.log(analytics);
|
|
182
182
|
```
|
|
183
183
|
|
|
184
|
+
### Get Media
|
|
185
|
+
|
|
186
|
+
Retrieve recent posts from a connected social account. Supported platforms:
|
|
187
|
+
`instagram`, `tiktok`, `youtube`, `linkedin`, `facebook`, `x`, `threads`,
|
|
188
|
+
`pinterest`, `bluesky`, `reddit`.
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
const { media } = await client.getMedia('linkedin', 'my-profile');
|
|
192
|
+
|
|
193
|
+
// Force the personal LinkedIn profile of an account connected as an org admin:
|
|
194
|
+
await client.getMedia('linkedin', 'my-profile', { pageUrn: 'me' });
|
|
195
|
+
|
|
196
|
+
// Target a specific LinkedIn organization page:
|
|
197
|
+
await client.getMedia('linkedin', 'my-profile', { pageUrn: '12345' });
|
|
198
|
+
```
|
|
199
|
+
|
|
184
200
|
### Helper Methods
|
|
185
201
|
|
|
186
202
|
```javascript
|
package/index.d.ts
CHANGED
|
@@ -136,8 +136,8 @@ declare module 'upload-post' {
|
|
|
136
136
|
instagramShareToFeed?: boolean;
|
|
137
137
|
/** Comma-separated collaborator usernames */
|
|
138
138
|
instagramCollaborators?: string;
|
|
139
|
-
/** Custom cover URL */
|
|
140
|
-
instagramCoverUrl?: string;
|
|
139
|
+
/** Custom cover: URL string, file path, Buffer, or ReadableStream */
|
|
140
|
+
instagramCoverUrl?: string | Buffer | NodeJS.ReadableStream;
|
|
141
141
|
/** Audio track name */
|
|
142
142
|
instagramAudioName?: string;
|
|
143
143
|
/** Comma-separated user tags */
|
|
@@ -192,6 +192,17 @@ declare module 'upload-post' {
|
|
|
192
192
|
youtubeHasPaidProductPlacement?: boolean;
|
|
193
193
|
/** Recording date (ISO 8601) */
|
|
194
194
|
youtubeRecordingDate?: string;
|
|
195
|
+
/** Subtitle/caption files to upload. Each entry needs a language code and either a file path or URL. */
|
|
196
|
+
youtubeSubtitles?: Array<{
|
|
197
|
+
/** BCP-47 language code (e.g. "en", "es") */
|
|
198
|
+
language: string;
|
|
199
|
+
/** Display name for the subtitle track (e.g. "English", "Español") */
|
|
200
|
+
name?: string;
|
|
201
|
+
/** Path to the subtitle file (SRT, VTT, SBV, SUB, ASS, SSA, TTML) */
|
|
202
|
+
file?: string;
|
|
203
|
+
/** URL to the subtitle file */
|
|
204
|
+
url?: string;
|
|
205
|
+
}>;
|
|
195
206
|
}
|
|
196
207
|
|
|
197
208
|
// ==================== LinkedIn Options ====================
|
|
@@ -589,6 +600,28 @@ declare module 'upload-post' {
|
|
|
589
600
|
metric_labels: Record<string, string>;
|
|
590
601
|
}>>;
|
|
591
602
|
|
|
603
|
+
/**
|
|
604
|
+
* Get recent media from a connected social account.
|
|
605
|
+
*
|
|
606
|
+
* @param options.pageUrn - LinkedIn only. Numeric org ID, full org URN, or "me" to force the personal profile.
|
|
607
|
+
*/
|
|
608
|
+
getMedia(
|
|
609
|
+
platform: 'instagram' | 'tiktok' | 'youtube' | 'linkedin' | 'facebook' | 'x' | 'threads' | 'pinterest' | 'bluesky' | 'reddit' | string,
|
|
610
|
+
user: string,
|
|
611
|
+
options?: { pageUrn?: string }
|
|
612
|
+
): Promise<{
|
|
613
|
+
success: boolean;
|
|
614
|
+
media: Array<{
|
|
615
|
+
id: string;
|
|
616
|
+
caption: string | null;
|
|
617
|
+
media_type: 'IMAGE' | 'VIDEO' | 'CAROUSEL_ALBUM' | 'TEXT' | string;
|
|
618
|
+
media_url: string | null;
|
|
619
|
+
permalink: string | null;
|
|
620
|
+
timestamp: string | null;
|
|
621
|
+
thumbnail_url: string | null;
|
|
622
|
+
}>;
|
|
623
|
+
}>;
|
|
624
|
+
|
|
592
625
|
// Scheduled Posts
|
|
593
626
|
/**
|
|
594
627
|
* List scheduled posts
|
|
@@ -648,6 +681,68 @@ declare module 'upload-post' {
|
|
|
648
681
|
*/
|
|
649
682
|
validateJwt(jwt: string): Promise<{ success: boolean; valid?: boolean }>;
|
|
650
683
|
|
|
684
|
+
/**
|
|
685
|
+
* Get user preferences (including calendar settings)
|
|
686
|
+
*/
|
|
687
|
+
getUserPreferences(): Promise<{ success: boolean; preferences?: { week_start_day?: number; [key: string]: any } }>;
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Update user preferences (including calendar settings)
|
|
691
|
+
* @param options - Preferences options
|
|
692
|
+
*/
|
|
693
|
+
updateUserPreferences(options?: { weekStartDay?: number }): Promise<{ success: boolean; preferences?: { week_start_day?: number; [key: string]: any } }>;
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Get notification configuration (including webhook settings)
|
|
697
|
+
*/
|
|
698
|
+
getNotificationConfig(): Promise<{ success: boolean; config?: { webhook_events?: string[]; webhook_url?: string; [key: string]: any } }>;
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Update notification configuration (including webhook settings)
|
|
702
|
+
* @param options - Notification config options
|
|
703
|
+
*/
|
|
704
|
+
updateNotificationConfig(options?: { webhookEvents?: string[]; webhookUrl?: string }): Promise<{ success: boolean; config?: { webhook_events?: string[]; webhook_url?: string; [key: string]: any } }>;
|
|
705
|
+
|
|
706
|
+
// Instagram Comments
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Get comments on an Instagram post
|
|
710
|
+
* @param user - Profile username
|
|
711
|
+
* @param options - Query options
|
|
712
|
+
*/
|
|
713
|
+
getPostComments(user: string, options?: { postId?: string; postUrl?: string }): Promise<{
|
|
714
|
+
success: boolean;
|
|
715
|
+
comments?: Array<{
|
|
716
|
+
id: string;
|
|
717
|
+
text: string;
|
|
718
|
+
timestamp: string;
|
|
719
|
+
user: { id: string; username: string };
|
|
720
|
+
}>;
|
|
721
|
+
}>;
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Send a private reply (DM) to the author of an Instagram comment
|
|
725
|
+
* @param options - Reply options
|
|
726
|
+
*/
|
|
727
|
+
replyToComment(options: { user: string; commentId: string; message: string }): Promise<{
|
|
728
|
+
success: boolean;
|
|
729
|
+
recipient_id?: string;
|
|
730
|
+
message_id?: string;
|
|
731
|
+
message?: string;
|
|
732
|
+
error?: string;
|
|
733
|
+
}>;
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Post a public reply to an Instagram comment (visible under the original comment)
|
|
737
|
+
* @param options - Reply options
|
|
738
|
+
*/
|
|
739
|
+
publicReplyToComment(options: { user: string; commentId: string; message: string }): Promise<{
|
|
740
|
+
success: boolean;
|
|
741
|
+
id?: string;
|
|
742
|
+
message?: string;
|
|
743
|
+
error?: string;
|
|
744
|
+
}>;
|
|
745
|
+
|
|
651
746
|
// Helper Endpoints
|
|
652
747
|
/**
|
|
653
748
|
* Get Facebook pages for a profile
|
package/index.js
CHANGED
|
@@ -160,7 +160,16 @@ export class UploadPost {
|
|
|
160
160
|
|
|
161
161
|
if (isVideo) {
|
|
162
162
|
if (options.instagramShareToFeed !== undefined) form.append('share_to_feed', String(options.instagramShareToFeed));
|
|
163
|
-
if (options.instagramCoverUrl)
|
|
163
|
+
if (options.instagramCoverUrl) {
|
|
164
|
+
const coverVal = options.instagramCoverUrl;
|
|
165
|
+
if (typeof coverVal === 'string' && (coverVal.toLowerCase().startsWith('http://') || coverVal.toLowerCase().startsWith('https://'))) {
|
|
166
|
+
form.append('cover_url', coverVal);
|
|
167
|
+
} else if (typeof coverVal === 'string') {
|
|
168
|
+
form.append('cover_image', createReadStream(coverVal));
|
|
169
|
+
} else {
|
|
170
|
+
form.append('cover_image', coverVal);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
164
173
|
if (options.instagramAudioName) form.append('audio_name', options.instagramAudioName);
|
|
165
174
|
if (options.instagramThumbOffset) form.append('thumb_offset', options.instagramThumbOffset);
|
|
166
175
|
}
|
|
@@ -189,6 +198,24 @@ export class UploadPost {
|
|
|
189
198
|
if (options.youtubeBlockedCountries) form.append('blockedCountries', options.youtubeBlockedCountries);
|
|
190
199
|
if (options.youtubeHasPaidProductPlacement !== undefined) form.append('hasPaidProductPlacement', String(options.youtubeHasPaidProductPlacement));
|
|
191
200
|
if (options.youtubeRecordingDate) form.append('recordingDate', options.youtubeRecordingDate);
|
|
201
|
+
if (options.youtubeSubtitles && Array.isArray(options.youtubeSubtitles)) {
|
|
202
|
+
options.youtubeSubtitles.forEach((sub, idx) => {
|
|
203
|
+
if (sub.language) {
|
|
204
|
+
form.append(`youtube_subtitle_language_${idx}`, sub.language);
|
|
205
|
+
if (sub.name) form.append(`youtube_subtitle_name_${idx}`, sub.name);
|
|
206
|
+
if (sub.file) {
|
|
207
|
+
// file can be a string path or a ReadableStream
|
|
208
|
+
if (typeof sub.file === 'string') {
|
|
209
|
+
form.append(`youtube_subtitle_file_${idx}`, createReadStream(sub.file));
|
|
210
|
+
} else {
|
|
211
|
+
form.append(`youtube_subtitle_file_${idx}`, sub.file);
|
|
212
|
+
}
|
|
213
|
+
} else if (sub.url) {
|
|
214
|
+
form.append(`youtube_subtitle_file_${idx}`, sub.url);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}
|
|
192
219
|
}
|
|
193
220
|
|
|
194
221
|
/**
|
|
@@ -326,7 +353,7 @@ export class UploadPost {
|
|
|
326
353
|
* @param {string} [options.instagramMediaType] - REELS or STORIES
|
|
327
354
|
* @param {boolean} [options.instagramShareToFeed] - Share to feed
|
|
328
355
|
* @param {string} [options.instagramCollaborators] - Comma-separated collaborator usernames
|
|
329
|
-
* @param {string} [options.instagramCoverUrl] - Custom cover URL
|
|
356
|
+
* @param {string|Buffer|ReadableStream} [options.instagramCoverUrl] - Custom cover: URL string, file path, Buffer, or ReadableStream
|
|
330
357
|
* @param {string} [options.instagramAudioName] - Audio track name
|
|
331
358
|
* @param {string} [options.instagramUserTags] - Comma-separated user tags
|
|
332
359
|
* @param {string} [options.instagramLocationId] - Location ID
|
|
@@ -710,6 +737,22 @@ export class UploadPost {
|
|
|
710
737
|
return this._request(`/uploadposts/post-analytics/${encodeURIComponent(requestId)}`, 'GET');
|
|
711
738
|
}
|
|
712
739
|
|
|
740
|
+
/**
|
|
741
|
+
* Get analytics for any post (including organic posts) using its native platform ID
|
|
742
|
+
*
|
|
743
|
+
* @param {string} platformPostId - The native post ID on the platform (e.g., Instagram media ID)
|
|
744
|
+
* @param {string} platform - The platform to query (instagram, youtube, tiktok, facebook, linkedin, x, threads, pinterest, reddit)
|
|
745
|
+
* @param {string} user - The profile_username that owns the social account
|
|
746
|
+
* @returns {Promise<Object>} Post analytics with live per-post metrics from the platform API
|
|
747
|
+
*/
|
|
748
|
+
async getPostAnalyticsByPlatformId(platformPostId, platform, user) {
|
|
749
|
+
return this._request('/uploadposts/post-analytics', 'GET', {
|
|
750
|
+
platform_post_id: platformPostId,
|
|
751
|
+
platform,
|
|
752
|
+
user,
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
|
|
713
756
|
/**
|
|
714
757
|
* Get available metrics configuration for all supported platforms
|
|
715
758
|
*
|
|
@@ -719,6 +762,21 @@ export class UploadPost {
|
|
|
719
762
|
return this._request('/uploadposts/platform-metrics', 'GET');
|
|
720
763
|
}
|
|
721
764
|
|
|
765
|
+
/**
|
|
766
|
+
* Get recent media from a connected social account.
|
|
767
|
+
*
|
|
768
|
+
* @param {string} platform - instagram, tiktok, youtube, linkedin, facebook, x, threads, pinterest, bluesky, reddit
|
|
769
|
+
* @param {string} user - Profile username
|
|
770
|
+
* @param {Object} [options]
|
|
771
|
+
* @param {string} [options.pageUrn] - LinkedIn only. Numeric org ID, full URN, or "me" to force the personal profile.
|
|
772
|
+
* @returns {Promise<Object>}
|
|
773
|
+
*/
|
|
774
|
+
async getMedia(platform, user, options = {}) {
|
|
775
|
+
const params = { platform, user };
|
|
776
|
+
if (options.pageUrn) params.page_urn = options.pageUrn;
|
|
777
|
+
return this._request('/uploadposts/media', 'GET', params);
|
|
778
|
+
}
|
|
779
|
+
|
|
722
780
|
// ==================== Scheduled Posts ====================
|
|
723
781
|
|
|
724
782
|
/**
|
|
@@ -826,6 +884,106 @@ export class UploadPost {
|
|
|
826
884
|
return this._request('/uploadposts/users/validate-jwt', 'POST', { jwt });
|
|
827
885
|
}
|
|
828
886
|
|
|
887
|
+
/**
|
|
888
|
+
* Get user preferences (including calendar settings)
|
|
889
|
+
*
|
|
890
|
+
* @returns {Promise<Object>} User preferences
|
|
891
|
+
*/
|
|
892
|
+
async getUserPreferences() {
|
|
893
|
+
return this._request('/uploadposts/users/preferences', 'GET');
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Update user preferences (including calendar settings)
|
|
898
|
+
*
|
|
899
|
+
* @param {Object} options - Preferences options
|
|
900
|
+
* @param {number} [options.weekStartDay] - Week start day (0=Sunday, 1=Monday)
|
|
901
|
+
* @returns {Promise<Object>} Updated preferences
|
|
902
|
+
*/
|
|
903
|
+
async updateUserPreferences(options = {}) {
|
|
904
|
+
const body = {};
|
|
905
|
+
if (options.weekStartDay !== undefined) body.week_start_day = options.weekStartDay;
|
|
906
|
+
return this._request('/uploadposts/users/preferences', 'POST', body);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Get notification configuration (including webhook settings)
|
|
911
|
+
*
|
|
912
|
+
* @returns {Promise<Object>} Notification config
|
|
913
|
+
*/
|
|
914
|
+
async getNotificationConfig() {
|
|
915
|
+
return this._request('/uploadposts/notification-config', 'GET');
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/**
|
|
919
|
+
* Update notification configuration (including webhook settings)
|
|
920
|
+
*
|
|
921
|
+
* @param {Object} options - Notification config options
|
|
922
|
+
* @param {string[]} [options.webhookEvents] - Webhook event types to subscribe to (upload_completed, social_account_connected, social_account_disconnected, social_account_reauth_required)
|
|
923
|
+
* @param {string} [options.webhookUrl] - Webhook URL for notifications
|
|
924
|
+
* @returns {Promise<Object>} Updated notification config
|
|
925
|
+
*/
|
|
926
|
+
async updateNotificationConfig(options = {}) {
|
|
927
|
+
const body = {};
|
|
928
|
+
if (options.webhookEvents) body.webhook_events = options.webhookEvents;
|
|
929
|
+
if (options.webhookUrl) body.webhook_url = options.webhookUrl;
|
|
930
|
+
return this._request('/uploadposts/notification-config', 'POST', body);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// ==================== Instagram Comments ====================
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Get comments on an Instagram post
|
|
937
|
+
*
|
|
938
|
+
* @param {string} user - Profile username
|
|
939
|
+
* @param {Object} options - Query options
|
|
940
|
+
* @param {string} [options.postId] - Numeric media ID (provide postId or postUrl)
|
|
941
|
+
* @param {string} [options.postUrl] - Full Instagram post URL (provide postId or postUrl)
|
|
942
|
+
* @returns {Promise<Object>} Comments data
|
|
943
|
+
*/
|
|
944
|
+
async getPostComments(user, options = {}) {
|
|
945
|
+
const params = { platform: 'instagram', user };
|
|
946
|
+
if (options.postId) params.post_id = options.postId;
|
|
947
|
+
if (options.postUrl) params.post_url = options.postUrl;
|
|
948
|
+
return this._request('/uploadposts/comments', 'GET', params);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* Send a private reply (DM) to the author of an Instagram comment
|
|
953
|
+
*
|
|
954
|
+
* @param {Object} options - Reply options
|
|
955
|
+
* @param {string} options.user - Profile username
|
|
956
|
+
* @param {string} options.commentId - Comment ID from getPostComments
|
|
957
|
+
* @param {string} options.message - Reply message text
|
|
958
|
+
* @returns {Promise<Object>} Reply result
|
|
959
|
+
*/
|
|
960
|
+
async replyToComment(options) {
|
|
961
|
+
return this._request('/uploadposts/comments/reply', 'POST', {
|
|
962
|
+
platform: 'instagram',
|
|
963
|
+
user: options.user,
|
|
964
|
+
comment_id: options.commentId,
|
|
965
|
+
message: options.message
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Post a public reply to an Instagram comment (visible under the original comment)
|
|
971
|
+
*
|
|
972
|
+
* @param {Object} options - Reply options
|
|
973
|
+
* @param {string} options.user - Profile username
|
|
974
|
+
* @param {string} options.commentId - Comment ID from getPostComments
|
|
975
|
+
* @param {string} options.message - Reply message text
|
|
976
|
+
* @returns {Promise<Object>} Reply result with the new comment ID
|
|
977
|
+
*/
|
|
978
|
+
async publicReplyToComment(options) {
|
|
979
|
+
return this._request('/uploadposts/comments/public-reply', 'POST', {
|
|
980
|
+
platform: 'instagram',
|
|
981
|
+
user: options.user,
|
|
982
|
+
comment_id: options.commentId,
|
|
983
|
+
message: options.message
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
|
|
829
987
|
// ==================== Helper Endpoints ====================
|
|
830
988
|
|
|
831
989
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "upload-post",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Official client library for Upload-Post API - Cross-platform social media upload for TikTok, Instagram, YouTube, LinkedIn, Facebook, Pinterest, Threads, Reddit, Bluesky, and X (Twitter)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|