upload-post 2.6.0 → 2.8.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 (3) hide show
  1. package/index.d.ts +88 -2
  2. package/index.js +112 -11
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -145,6 +145,10 @@ declare module 'upload-post' {
145
145
  tiktokDisableComment?: boolean;
146
146
  /** Index of photo for cover (0-based) */
147
147
  tiktokPhotoCoverIndex?: number;
148
+ /** Privacy level, e.g. PUBLIC_TO_EVERYONE, SELF_ONLY, MUTUAL_FOLLOW_FRIENDS */
149
+ tiktokPrivacyLevel?: string;
150
+ /** Post mode, e.g. DIRECT_POST or MEDIA_UPLOAD (inbox) */
151
+ tiktokPostMode?: string;
148
152
  /** Branded content toggle */
149
153
  brandContentToggle?: boolean;
150
154
  /** Brand organic toggle */
@@ -782,7 +786,27 @@ declare module 'upload-post' {
782
786
  // Instagram Comments
783
787
 
784
788
  /**
785
- * Get comments on an Instagram post
789
+ * Get comments on a post
790
+ * @param options - Query options
791
+ */
792
+ getPostComments(options: {
793
+ user: string;
794
+ platform?: 'instagram' | 'facebook' | 'youtube' | 'linkedin';
795
+ postId?: string;
796
+ postUrl?: string;
797
+ limit?: number;
798
+ after?: string;
799
+ }): Promise<{
800
+ success: boolean;
801
+ comments?: Array<{
802
+ id: string;
803
+ text: string;
804
+ timestamp: string;
805
+ user: { id: string; username: string };
806
+ }>;
807
+ }>;
808
+ /**
809
+ * Get comments on an Instagram post (legacy positional signature)
786
810
  * @param user - Profile username
787
811
  * @param options - Query options
788
812
  */
@@ -800,7 +824,7 @@ declare module 'upload-post' {
800
824
  * Send a private reply (DM) to the author of an Instagram comment
801
825
  * @param options - Reply options
802
826
  */
803
- replyToComment(options: { user: string; commentId: string; message: string }): Promise<{
827
+ replyToComment(options: { user: string; commentId: string; message: string; buttons?: Array<{ title: string; url: string }> }): Promise<{
804
828
  success: boolean;
805
829
  recipient_id?: string;
806
830
  message_id?: string;
@@ -819,6 +843,68 @@ declare module 'upload-post' {
819
843
  error?: string;
820
844
  }>;
821
845
 
846
+ /**
847
+ * Create a comment on a post, or reply to an existing comment.
848
+ * One of postId, postUrl, or commentId is required.
849
+ * @param options - Comment options
850
+ */
851
+ createComment(options: {
852
+ user: string;
853
+ platform: 'instagram' | 'facebook' | 'youtube' | 'linkedin';
854
+ message: string;
855
+ postId?: string;
856
+ postUrl?: string;
857
+ commentId?: string;
858
+ }): Promise<{
859
+ success: boolean;
860
+ id?: string;
861
+ message?: string;
862
+ error?: string;
863
+ }>;
864
+
865
+ /**
866
+ * Delete a comment on a post
867
+ * @param options - Delete options
868
+ */
869
+ deleteComment(options: {
870
+ user: string;
871
+ platform: 'instagram' | 'facebook' | 'youtube' | 'linkedin';
872
+ commentId: string;
873
+ /** Post identifier (the post URN for LinkedIn) */
874
+ postId?: string;
875
+ }): Promise<{
876
+ success: boolean;
877
+ message?: string;
878
+ error?: string;
879
+ }>;
880
+
881
+ // Post Management
882
+ /**
883
+ * Retry a failed post. Provide requestId or jobId.
884
+ * @param options - Retry options
885
+ */
886
+ retryPost(options: { requestId?: string; jobId?: string }): Promise<{
887
+ success: boolean;
888
+ request_id?: string;
889
+ job_id?: string;
890
+ message?: string;
891
+ error?: string;
892
+ }>;
893
+
894
+ /**
895
+ * Unpublish (delete) a post from the platform
896
+ * @param options - Unpublish options
897
+ */
898
+ unpublishPost(options: {
899
+ user: string;
900
+ platform: 'facebook' | 'youtube' | 'x' | 'linkedin' | 'threads';
901
+ postId: string;
902
+ }): Promise<{
903
+ success: boolean;
904
+ message?: string;
905
+ error?: string;
906
+ }>;
907
+
822
908
  // Helper Endpoints
823
909
  /**
824
910
  * Get Facebook pages for a profile
package/index.js CHANGED
@@ -160,13 +160,17 @@ export class UploadPost {
160
160
  if (options.brandContentToggle !== undefined) form.append('brand_content_toggle', String(options.brandContentToggle));
161
161
  if (options.brandOrganicToggle !== undefined) form.append('brand_organic_toggle', String(options.brandOrganicToggle));
162
162
 
163
+ // Shared by TikTok video AND photo uploads: the backend reads privacy_level and
164
+ // post_mode for both /upload and /upload_photos. Gating them behind isVideo made
165
+ // photo carousels always publish as PUBLIC_TO_EVERYONE / DIRECT_POST.
166
+ if (options.tiktokPrivacyLevel) form.append('privacy_level', options.tiktokPrivacyLevel);
167
+ if (options.tiktokPostMode) form.append('post_mode', options.tiktokPostMode);
168
+
163
169
  if (isVideo) {
164
- if (options.tiktokPrivacyLevel) form.append('privacy_level', options.tiktokPrivacyLevel);
165
170
  if (options.tiktokDisableDuet !== undefined) form.append('disable_duet', String(options.tiktokDisableDuet));
166
171
  if (options.tiktokDisableStitch !== undefined) form.append('disable_stitch', String(options.tiktokDisableStitch));
167
172
  if (options.tiktokCoverTimestamp !== undefined) form.append('cover_timestamp', options.tiktokCoverTimestamp);
168
173
  if (options.tiktokIsAigc !== undefined) form.append('is_aigc', String(options.tiktokIsAigc));
169
- if (options.tiktokPostMode) form.append('post_mode', options.tiktokPostMode);
170
174
  } else {
171
175
  // Photo-specific
172
176
  if (options.tiktokAutoAddMusic !== undefined) form.append('auto_add_music', String(options.tiktokAutoAddMusic));
@@ -749,7 +753,7 @@ export class UploadPost {
749
753
  * @param {Object} [options] - Query options
750
754
  * @param {string[]} [options.platforms] - Filter by platforms (instagram, linkedin, facebook, x, youtube, tiktok, threads, pinterest, reddit)
751
755
  * @param {string} [options.pageId] - Facebook Page ID (required for Facebook analytics)
752
- * @param {string} [options.pageUrn] - LinkedIn page URN (defaults to "me" for personal profile)
756
+ * @param {string} [options.pageUrn] - LinkedIn organization/company page URN or numeric ID. LinkedIn analytics are only available for pages you administer; personal profiles are not supported (LinkedIn exposes no member-level analytics). Defaults to the first administered organization page.
753
757
  * @returns {Promise<Object>} Analytics data per platform
754
758
  */
755
759
  async getAnalytics(profileUsername, options = {}) {
@@ -1023,18 +1027,27 @@ export class UploadPost {
1023
1027
  // ==================== Instagram Comments ====================
1024
1028
 
1025
1029
  /**
1026
- * Get comments on an Instagram post
1030
+ * Get comments on a post
1027
1031
  *
1028
- * @param {string} user - Profile username
1029
1032
  * @param {Object} options - Query options
1030
- * @param {string} [options.postId] - Numeric media ID (provide postId or postUrl)
1031
- * @param {string} [options.postUrl] - Full Instagram post URL (provide postId or postUrl)
1033
+ * @param {string} options.user - Profile username
1034
+ * @param {string} [options.platform='instagram'] - Platform (instagram, facebook, youtube, linkedin)
1035
+ * @param {string} [options.postId] - Native post/media ID (provide postId or postUrl)
1036
+ * @param {string} [options.postUrl] - Full post URL (provide postId or postUrl)
1037
+ * @param {number} [options.limit] - Max number of comments to return
1038
+ * @param {string} [options.after] - Pagination cursor for the next page
1032
1039
  * @returns {Promise<Object>} Comments data
1033
1040
  */
1034
- async getPostComments(user, options = {}) {
1035
- const params = { platform: 'instagram', user };
1041
+ async getPostComments(options = {}) {
1042
+ // Backwards compatibility: getPostComments(user, { postId, postUrl })
1043
+ if (typeof options === 'string') {
1044
+ options = { user: options, ...(arguments[1] || {}) };
1045
+ }
1046
+ const params = { platform: options.platform || 'instagram', user: options.user };
1036
1047
  if (options.postId) params.post_id = options.postId;
1037
1048
  if (options.postUrl) params.post_url = options.postUrl;
1049
+ if (options.limit !== undefined) params.limit = options.limit;
1050
+ if (options.after) params.after = options.after;
1038
1051
  return this._request('/uploadposts/comments', 'GET', params);
1039
1052
  }
1040
1053
 
@@ -1045,15 +1058,19 @@ export class UploadPost {
1045
1058
  * @param {string} options.user - Profile username
1046
1059
  * @param {string} options.commentId - Comment ID from getPostComments
1047
1060
  * @param {string} options.message - Reply message text
1061
+ * @param {Array<{title: string, url: string}>} [options.buttons] - Optional web_url
1062
+ * buttons (max 3) rendered in the Instagram DM. Each item is `{ title, url }`.
1048
1063
  * @returns {Promise<Object>} Reply result
1049
1064
  */
1050
1065
  async replyToComment(options) {
1051
- return this._request('/uploadposts/comments/reply', 'POST', {
1066
+ const body = {
1052
1067
  platform: 'instagram',
1053
1068
  user: options.user,
1054
1069
  comment_id: options.commentId,
1055
1070
  message: options.message
1056
- });
1071
+ };
1072
+ if (options.buttons) body.buttons = options.buttons;
1073
+ return this._request('/uploadposts/comments/reply', 'POST', body);
1057
1074
  }
1058
1075
 
1059
1076
  /**
@@ -1074,6 +1091,90 @@ export class UploadPost {
1074
1091
  });
1075
1092
  }
1076
1093
 
1094
+ /**
1095
+ * Create a comment on a post, or reply to an existing comment
1096
+ *
1097
+ * One of postId, postUrl, or commentId is required. Pass commentId to reply
1098
+ * to an existing comment; pass postId/postUrl to comment on the post itself.
1099
+ *
1100
+ * @param {Object} options - Comment options
1101
+ * @param {string} options.user - Profile username
1102
+ * @param {string} options.platform - Platform (instagram, facebook, youtube, linkedin)
1103
+ * @param {string} options.message - Comment text
1104
+ * @param {string} [options.postId] - Native post/media ID to comment on
1105
+ * @param {string} [options.postUrl] - Full post URL to comment on
1106
+ * @param {string} [options.commentId] - Existing comment ID to reply to
1107
+ * @returns {Promise<Object>} Created comment result
1108
+ */
1109
+ async createComment(options) {
1110
+ const body = {
1111
+ platform: options.platform,
1112
+ user: options.user,
1113
+ message: options.message
1114
+ };
1115
+ if (options.commentId) body.comment_id = options.commentId;
1116
+ if (options.postId) body.post_id = options.postId;
1117
+ if (options.postUrl) body.post_url = options.postUrl;
1118
+ return this._request('/uploadposts/comments/create', 'POST', body);
1119
+ }
1120
+
1121
+ /**
1122
+ * Delete a comment on a post
1123
+ *
1124
+ * @param {Object} options - Delete options
1125
+ * @param {string} options.user - Profile username
1126
+ * @param {string} options.platform - Platform (instagram, facebook, youtube, linkedin)
1127
+ * @param {string} options.commentId - Comment ID to delete
1128
+ * @param {string} [options.postId] - Post identifier (the post URN for LinkedIn)
1129
+ * @returns {Promise<Object>} Deletion result
1130
+ */
1131
+ async deleteComment(options) {
1132
+ const body = {
1133
+ platform: options.platform,
1134
+ user: options.user,
1135
+ comment_id: options.commentId
1136
+ };
1137
+ if (options.postId) body.post_id = options.postId;
1138
+ return this._request('/uploadposts/comments/delete', 'DELETE', body);
1139
+ }
1140
+
1141
+ // ==================== Post Management ====================
1142
+
1143
+ /**
1144
+ * Retry a failed post
1145
+ *
1146
+ * Provide the request_id (from an async upload) or the job_id (from a
1147
+ * scheduled/queued upload).
1148
+ *
1149
+ * @param {Object} options - Retry options
1150
+ * @param {string} [options.requestId] - The request_id of the post to retry
1151
+ * @param {string} [options.jobId] - The job_id of the post to retry
1152
+ * @returns {Promise<Object>} Retry result
1153
+ */
1154
+ async retryPost(options = {}) {
1155
+ const body = {};
1156
+ if (options.requestId) body.request_id = options.requestId;
1157
+ if (options.jobId) body.job_id = options.jobId;
1158
+ return this._request('/uploadposts/posts/retry', 'POST', body);
1159
+ }
1160
+
1161
+ /**
1162
+ * Unpublish (delete) a post from the platform
1163
+ *
1164
+ * @param {Object} options - Unpublish options
1165
+ * @param {string} options.user - Profile username
1166
+ * @param {string} options.platform - Platform (facebook, youtube, x, linkedin, threads)
1167
+ * @param {string} options.postId - Native post ID to unpublish
1168
+ * @returns {Promise<Object>} Unpublish result
1169
+ */
1170
+ async unpublishPost(options) {
1171
+ return this._request('/uploadposts/posts/unpublish', 'POST', {
1172
+ platform: options.platform,
1173
+ user: options.user,
1174
+ post_id: options.postId
1175
+ });
1176
+ }
1177
+
1077
1178
  // ==================== Helper Endpoints ====================
1078
1179
 
1079
1180
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upload-post",
3
- "version": "2.6.0",
3
+ "version": "2.8.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",