upload-post 2.14.1 → 2.16.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 (4) hide show
  1. package/README.md +11 -1
  2. package/index.d.ts +52 -13
  3. package/index.js +31 -1
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -191,6 +191,14 @@ await client.editScheduled('job-id', {
191
191
  },
192
192
  });
193
193
 
194
+ // Change any other option by its API form name (null removes it), schedule the
195
+ // video natively on YouTube, or replace the Reels cover
196
+ await client.editScheduled('job-id', {
197
+ fields: { privacyStatus: 'unlisted', disable_comment: true, instagram_first_comment: 'Link in bio' },
198
+ youtubePublishAt: '2026-11-01T09:00:00Z',
199
+ coverImageBase64: 'data:image/jpeg;base64,...', // or removeCover: true
200
+ });
201
+
194
202
  // Cancel a scheduled post
195
203
  await client.cancelScheduled('job-id');
196
204
  ```
@@ -656,7 +664,7 @@ for those options.
656
664
  - `facebookPageId` - Facebook Page ID (required)
657
665
  - `facebookVideoState` - PUBLISHED, DRAFT
658
666
  - `facebookMediaType` - REELS, STORIES, VIDEO (VIDEO for normal page videos with no 9:16 restriction)
659
- - `thumbnailUrl` - URL for custom video thumbnail (only when facebookMediaType is VIDEO)
667
+ - `thumbnailUrl` - URL for custom video cover (generic field, also read by X, YouTube and LinkedIn; on Facebook only when facebookMediaType is VIDEO)
660
668
  - `facebookLinkUrl` - URL for text posts
661
669
  - `facebookAltText` - Alt text per photo
662
670
  - `facebookPlaceId` - Place ID
@@ -694,6 +702,8 @@ for those options.
694
702
  - `xAltText` - Alt text (≤1000 chars)
695
703
  - `xSubtitles` / `xSubtitlesUrl` / `xSubtitlesLanguage` / `xSubtitlesName` - Video captions
696
704
  - `xPaidPartnership` - Paid partnership label
705
+ - `madeWithAi` - Disclose AI-generated media on X (`made_with_ai`; alias `isAiGenerated`)
706
+ - `thumbnailUrl` - Custom video cover (generic field; applied by X as the post's preview image)
697
707
  - `xArticleTitle` / `xArticleBody` / `xArticleContentState` / `xArticleDraft` / `xArticleCoverMedia` - X Articles (Premium)
698
708
 
699
709
  ### Threads
package/index.d.ts CHANGED
@@ -389,7 +389,7 @@ declare module 'upload-post' {
389
389
  facebookVideoState?: FacebookVideoState;
390
390
  /** Media type */
391
391
  facebookMediaType?: FacebookMediaType;
392
- /** Thumbnail URL for normal page videos (only when facebookMediaType is 'VIDEO') */
392
+ /** Custom video cover URL. Generic API field: X, YouTube, LinkedIn and Facebook (only when facebookMediaType is 'VIDEO') read it */
393
393
  thumbnailUrl?: string;
394
394
  /** Facebook Place ID */
395
395
  facebookPlaceId?: string;
@@ -517,6 +517,12 @@ declare module 'upload-post' {
517
517
  xThreadImageLayout?: string;
518
518
  /** Alt text (≤1000 chars). String for video; string, list or `x_alt_text[]` for photos */
519
519
  xAltText?: string | string[];
520
+ /** Disclose that the post contains AI-generated media (X `made_with_ai`). Alias: isAiGenerated */
521
+ madeWithAi?: boolean;
522
+ /** Same as madeWithAi */
523
+ xMadeWithAi?: boolean;
524
+ /** Cross-platform alias of madeWithAi (API `is_ai_generated`) */
525
+ isAiGenerated?: boolean;
520
526
  /** Public URL of a .srt file (≤1 MB) */
521
527
  xSubtitlesUrl?: string;
522
528
  /** Inline SRT text, or a URL if the value starts with http(s) */
@@ -962,6 +968,50 @@ declare module 'upload-post' {
962
968
  [key: string]: any;
963
969
  }
964
970
 
971
+ /** Body of PATCH /api/uploadposts/schedule/<job_id>. Every key is optional. */
972
+ export interface EditScheduledOptions {
973
+ /** New publish date (ISO 8601); must be in the future and within 1 year */
974
+ scheduledDate?: string;
975
+ /** IANA timezone `scheduledDate` is read in (default UTC) */
976
+ timezone?: string;
977
+ /** New title for every platform */
978
+ title?: string;
979
+ /** New caption/description for every platform */
980
+ caption?: string;
981
+ /** Alias of caption */
982
+ description?: string;
983
+ /** Per-platform text; only the platforms listed are touched */
984
+ platformContent?: Record<string, { title?: string; caption?: string }>;
985
+ /**
986
+ * Any other editable upload option, keyed by its API form name
987
+ * (e.g. `privacyStatus`, `tags`, `disable_comment`, `instagram_first_comment`,
988
+ * `gbp_cta_url`). `null` removes the option; unknown or internal keys are ignored.
989
+ */
990
+ fields?: Record<string, string | number | boolean | string[] | null>;
991
+ /** Native YouTube scheduling (RFC3339), sent as `fields.youtube_publish_at`; `null` removes it */
992
+ youtubePublishAt?: string | null;
993
+ /** New cover image (Instagram / Facebook Reels) as base64 or a data URL */
994
+ coverImageBase64?: string;
995
+ /** File name of the new cover (default `cover.jpg`) */
996
+ coverFilename?: string;
997
+ /** MIME type of the new cover (default `image/jpeg`) */
998
+ coverContentType?: string;
999
+ /** Remove the custom cover */
1000
+ removeCover?: boolean;
1001
+ }
1002
+
1003
+ export interface EditScheduledResponse {
1004
+ success: boolean;
1005
+ job_id?: string;
1006
+ scheduled_date?: string;
1007
+ title?: string;
1008
+ caption?: string;
1009
+ platform_content?: Record<string, { title: string; caption: string }>;
1010
+ error?: string;
1011
+ error_code?: string;
1012
+ [key: string]: any;
1013
+ }
1014
+
965
1015
  export interface UserProfile {
966
1016
  username: string;
967
1017
  social_accounts?: Record<string, any>;
@@ -1406,18 +1456,7 @@ declare module 'upload-post' {
1406
1456
  * @param jobId - Scheduled job ID
1407
1457
  * @param options - Edit options
1408
1458
  */
1409
- editScheduled(jobId: string, options: {
1410
- scheduledDate?: string;
1411
- timezone?: string;
1412
- /** New title for every platform */
1413
- title?: string;
1414
- /** New caption/description for every platform */
1415
- caption?: string;
1416
- /** Alias of caption */
1417
- description?: string;
1418
- /** Per-platform text; only the platforms listed are touched */
1419
- platformContent?: Record<string, { title?: string; caption?: string }>;
1420
- }): Promise<{ success: boolean }>;
1459
+ editScheduled(jobId: string, options?: EditScheduledOptions): Promise<EditScheduledResponse>;
1421
1460
 
1422
1461
  // User Management
1423
1462
  /**
package/index.js CHANGED
@@ -492,6 +492,8 @@ export class UploadPost {
492
492
  this._appendField(form, 'x_subtitles', this._pick(options, 'xSubtitles', 'x_subtitles'));
493
493
  this._appendField(form, 'x_subtitles_language', this._pick(options, 'xSubtitlesLanguage', 'x_subtitles_language'));
494
494
  this._appendField(form, 'x_subtitles_name', this._pick(options, 'xSubtitlesName', 'x_subtitles_name'));
495
+ // AI-media disclosure (X "made_with_ai"); is_ai_generated is the cross-platform alias.
496
+ this._appendField(form, 'made_with_ai', this._pick(options, 'xMadeWithAi', 'madeWithAi', 'made_with_ai', 'isAiGenerated', 'is_ai_generated'));
495
497
  } else {
496
498
  if (options.xPostUrl) form.append('post_url', options.xPostUrl);
497
499
  if (options.xCardUri) form.append('card_uri', options.xCardUri);
@@ -902,6 +904,14 @@ export class UploadPost {
902
904
  if (platforms.includes('google_business')) this._addGoogleBusinessParams(form, options);
903
905
  this._addCredentialPlatformParams(form, options);
904
906
 
907
+ // thumbnail_url is one generic API field, read by X, YouTube, LinkedIn and Facebook.
908
+ // The Facebook and YouTube helpers already send it for their platform; send it once
909
+ // here for the rest (X since 2.15.0) without duplicating the field.
910
+ const cover = this._pick(options, 'thumbnailUrl', 'thumbnail_url');
911
+ const coverAlreadySent = (platforms.includes('facebook') && cover)
912
+ || (platforms.includes('youtube') && options.youtubeThumbnailUrl);
913
+ if (cover && !coverAlreadySent) form.append('thumbnail_url', cover);
914
+
905
915
  return this._request('/upload', 'POST', form, true, this._idempotencyHeaders(options));
906
916
  }
907
917
 
@@ -1415,9 +1425,20 @@ export class UploadPost {
1415
1425
  * @param {Object} [options.platformContent] - Per-platform text, e.g.
1416
1426
  * { instagram: { caption: '...' }, tiktok: { caption: '...' }, youtube: { title: '...' } }.
1417
1427
  * Only the platforms listed are touched.
1428
+ * @param {Object} [options.fields] - Any other editable upload option, keyed by the
1429
+ * API form name (e.g. { privacyStatus: 'unlisted', tags: '["a","b"]', disable_comment: true,
1430
+ * instagram_first_comment: '...' }). `null` removes an option. Unknown or internal keys
1431
+ * are ignored by the API.
1432
+ * @param {string|null} [options.youtubePublishAt] - Native YouTube scheduling (RFC3339),
1433
+ * sent as fields.youtube_publish_at; `null` removes it. Wins over the same key in `fields`.
1434
+ * @param {string} [options.coverImageBase64] - New cover image (Instagram / Facebook Reels),
1435
+ * base64 or a data URL
1436
+ * @param {string} [options.coverFilename] - File name of the new cover (default cover.jpg)
1437
+ * @param {string} [options.coverContentType] - MIME type of the new cover (default image/jpeg)
1438
+ * @param {boolean} [options.removeCover] - Remove the custom cover
1418
1439
  * @returns {Promise<Object>} Edit result
1419
1440
  */
1420
- async editScheduled(jobId, options) {
1441
+ async editScheduled(jobId, options = {}) {
1421
1442
  const body = {};
1422
1443
  if (options.scheduledDate) body.scheduled_date = options.scheduledDate;
1423
1444
  if (options.timezone) body.timezone = options.timezone;
@@ -1425,6 +1446,15 @@ export class UploadPost {
1425
1446
  if (options.caption !== undefined) body.caption = options.caption;
1426
1447
  else if (options.description !== undefined) body.description = options.description;
1427
1448
  if (options.platformContent) body.platform_content = options.platformContent;
1449
+ const fields = { ...(options.fields || {}) };
1450
+ if (options.youtubePublishAt !== undefined) fields.youtube_publish_at = options.youtubePublishAt;
1451
+ if (Object.keys(fields).length) body.fields = fields;
1452
+ if (options.removeCover === true) body.remove_cover = true;
1453
+ else if (options.coverImageBase64) {
1454
+ body.cover_image_base64 = options.coverImageBase64;
1455
+ if (options.coverFilename) body.cover_filename = options.coverFilename;
1456
+ if (options.coverContentType) body.cover_content_type = options.coverContentType;
1457
+ }
1428
1458
  return this._request(`/uploadposts/schedule/${jobId}`, 'PATCH', body);
1429
1459
  }
1430
1460
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upload-post",
3
- "version": "2.14.1",
3
+ "version": "2.16.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",