upload-post 2.0.3 → 2.0.4

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.
@@ -3,6 +3,9 @@ name: Publish to npm
3
3
  on:
4
4
  release:
5
5
  types: [published]
6
+ push:
7
+ branches: [main]
8
+ paths: ['package.json']
6
9
  workflow_dispatch:
7
10
  inputs:
8
11
  dry_run:
@@ -16,7 +19,7 @@ jobs:
16
19
  runs-on: ubuntu-latest
17
20
  permissions:
18
21
  contents: read
19
- id-token: write # Required for OIDC trusted publishing
22
+ id-token: write
20
23
  steps:
21
24
  - name: Checkout
22
25
  uses: actions/checkout@v4
@@ -27,13 +30,32 @@ jobs:
27
30
  node-version: '22'
28
31
  registry-url: 'https://registry.npmjs.org'
29
32
 
33
+ - name: Check if version is new
34
+ id: version_check
35
+ run: |
36
+ LOCAL=$(node -p "require('./package.json').version")
37
+ PKG_NAME=$(node -p "require('./package.json').name")
38
+ REMOTE=$(npm view "$PKG_NAME" version 2>/dev/null || echo "0.0.0")
39
+ echo "local=$LOCAL" >> $GITHUB_OUTPUT
40
+ echo "remote=$REMOTE" >> $GITHUB_OUTPUT
41
+ if [ "$LOCAL" = "$REMOTE" ]; then
42
+ echo "new=false" >> $GITHUB_OUTPUT
43
+ echo "⏭️ Version $LOCAL already published, skipping."
44
+ else
45
+ echo "new=true" >> $GITHUB_OUTPUT
46
+ echo "🚀 New version detected: $REMOTE → $LOCAL"
47
+ fi
48
+
30
49
  - name: Update npm to latest
50
+ if: steps.version_check.outputs.new == 'true' || github.event_name == 'workflow_dispatch'
31
51
  run: npm install -g npm@latest && npm --version
32
52
 
33
53
  - name: Install dependencies
54
+ if: steps.version_check.outputs.new == 'true' || github.event_name == 'workflow_dispatch'
34
55
  run: npm ci
35
56
 
36
57
  - name: Build (if needed)
58
+ if: steps.version_check.outputs.new == 'true' || github.event_name == 'workflow_dispatch'
37
59
  run: npm run build --if-present
38
60
 
39
61
  - name: Publish to npm (dry-run)
@@ -41,5 +63,5 @@ jobs:
41
63
  run: npm publish --access public --dry-run
42
64
 
43
65
  - name: Publish to npm
44
- if: ${{ inputs.dry_run != true }}
66
+ if: (steps.version_check.outputs.new == 'true' && inputs.dry_run != true) || github.event_name == 'release'
45
67
  run: npm publish --access public --provenance
package/README.md CHANGED
@@ -238,7 +238,8 @@ const boards = await client.getPinterestBoards('my-profile');
238
238
  ### Facebook
239
239
  - `facebookPageId` - Facebook Page ID (required)
240
240
  - `facebookVideoState` - PUBLISHED, DRAFT
241
- - `facebookMediaType` - REELS, STORIES
241
+ - `facebookMediaType` - REELS, STORIES, VIDEO (VIDEO for normal page videos with no 9:16 restriction)
242
+ - `thumbnailUrl` - URL for custom video thumbnail (only when facebookMediaType is VIDEO)
242
243
  - `facebookLinkUrl` - URL for text posts
243
244
 
244
245
  ### Pinterest
@@ -261,9 +262,11 @@ const boards = await client.getPinterestBoards('my-profile');
261
262
  - `xShareWithFollowers` - Share community post with followers
262
263
  - `xCardUri` - Card URI for Twitter Cards
263
264
  - `xLongTextAsPost` - Post long text as single post
265
+ - `xThreadImageLayout` - Comma-separated image layout for thread (e.g. "4,4" or "2,3,1")
264
266
 
265
267
  ### Threads
266
268
  - `threadsLongTextAsPost` - Post long text as single post (vs thread)
269
+ - `threadsThreadMediaLayout` - Comma-separated list of how many media items to include in each Threads post. Each value must be 1-10, and the total must equal the number of files. Example: '5,5' splits 10 items into 2 posts with 5 each. If omitted and more than 10 items are provided, auto-chunks into groups of 10.
267
270
 
268
271
  ### Reddit
269
272
  - `redditSubreddit` - Subreddit name (without r/)
package/index.d.ts CHANGED
@@ -35,7 +35,7 @@ declare module 'upload-post' {
35
35
  export type FacebookVideoState = 'PUBLISHED' | 'DRAFT';
36
36
 
37
37
  /** Facebook media type */
38
- export type FacebookMediaType = 'REELS' | 'STORIES';
38
+ export type FacebookMediaType = 'REELS' | 'STORIES' | 'VIDEO';
39
39
 
40
40
  /** X (Twitter) reply settings */
41
41
  export type XReplySettings = 'everyone' | 'following' | 'mentionedUsers' | 'subscribers' | 'verified';
@@ -210,6 +210,8 @@ declare module 'upload-post' {
210
210
  facebookVideoState?: FacebookVideoState;
211
211
  /** Media type */
212
212
  facebookMediaType?: FacebookMediaType;
213
+ /** Thumbnail URL for normal page videos (only when facebookMediaType is 'VIDEO') */
214
+ thumbnailUrl?: string;
213
215
  }
214
216
 
215
217
  export interface FacebookPhotoOptions {
@@ -276,6 +278,8 @@ declare module 'upload-post' {
276
278
  xTaggedUserIds?: string | string[];
277
279
  /** Location place ID */
278
280
  xPlaceId?: string;
281
+ /** Comma-separated image layout for thread (e.g. "4,4" or "2,3,1"). Each value 1-4, total must equal image count. */
282
+ xThreadImageLayout?: string;
279
283
  }
280
284
 
281
285
  export interface XTextOptions extends XBaseOptions {
@@ -298,6 +302,8 @@ declare module 'upload-post' {
298
302
  export interface ThreadsOptions {
299
303
  /** Post long text as single post (vs thread) */
300
304
  threadsLongTextAsPost?: boolean;
305
+ /** Comma-separated list of how many media items per Threads post (e.g. "5,5"). Each value 1-10, total must equal file count. */
306
+ threadsThreadMediaLayout?: string;
301
307
  }
302
308
 
303
309
  // ==================== Reddit Options ====================
@@ -555,6 +561,10 @@ declare module 'upload-post' {
555
561
  logoImage?: string;
556
562
  redirectButtonText?: string;
557
563
  platforms?: string[];
564
+ showCalendar?: boolean;
565
+ readonlyCalendar?: boolean;
566
+ connectTitle?: string;
567
+ connectDescription?: string;
558
568
  }): Promise<JwtResponse>;
559
569
 
560
570
  /**
package/index.js CHANGED
@@ -190,6 +190,7 @@ export class UploadPost {
190
190
  if (isVideo) {
191
191
  if (options.facebookVideoState) form.append('video_state', options.facebookVideoState);
192
192
  if (options.facebookMediaType) form.append('facebook_media_type', options.facebookMediaType);
193
+ if (options.thumbnailUrl) form.append('thumbnail_url', options.thumbnailUrl);
193
194
  }
194
195
 
195
196
  if (isText && options.facebookLinkUrl) {
@@ -235,6 +236,7 @@ export class UploadPost {
235
236
  ids.forEach(id => form.append('tagged_user_ids[]', id));
236
237
  }
237
238
  if (options.xPlaceId) form.append('place_id', options.xPlaceId);
239
+ if (options.xThreadImageLayout) form.append('x_thread_image_layout', options.xThreadImageLayout);
238
240
  } else {
239
241
  if (options.xPostUrl) form.append('post_url', options.xPostUrl);
240
242
  if (options.xCardUri) form.append('card_uri', options.xCardUri);
@@ -255,6 +257,7 @@ export class UploadPost {
255
257
  */
256
258
  _addThreadsParams(form, options) {
257
259
  if (options.threadsLongTextAsPost !== undefined) form.append('threads_long_text_as_post', String(options.threadsLongTextAsPost));
260
+ if (options.threadsThreadMediaLayout) form.append('threads_thread_media_layout', options.threadsThreadMediaLayout);
258
261
  }
259
262
 
260
263
  /**
@@ -326,8 +329,9 @@ export class UploadPost {
326
329
  * Facebook options:
327
330
  * @param {string} [options.facebookPageId] - Facebook Page ID
328
331
  * @param {string} [options.facebookVideoState] - PUBLISHED or DRAFT
329
- * @param {string} [options.facebookMediaType] - REELS or STORIES
330
- *
332
+ * @param {string} [options.facebookMediaType] - REELS, STORIES, or VIDEO
333
+ * @param {string} [options.thumbnailUrl] - Thumbnail URL for normal page videos (VIDEO type only)
334
+ *
331
335
  * Pinterest options:
332
336
  * @param {string} [options.pinterestBoardId] - Board ID
333
337
  * @param {string} [options.pinterestLink] - Destination link
@@ -347,7 +351,8 @@ export class UploadPost {
347
351
  *
348
352
  * Threads options:
349
353
  * @param {boolean} [options.threadsLongTextAsPost] - Post long text as single post (vs thread)
350
- *
354
+ * @param {string} [options.threadsThreadMediaLayout] - Comma-separated list of how many media items per Threads post (e.g. "5,5")
355
+ *
351
356
  * @returns {Promise<Object>} API response with request_id for async uploads
352
357
  */
353
358
  async upload(videoPathOrUrl, options) {
@@ -424,14 +429,15 @@ export class UploadPost {
424
429
  * @param {boolean} [options.xNullcast] - Promoted-only post
425
430
  * @param {string|string[]} [options.xTaggedUserIds] - User IDs to tag
426
431
  * @param {boolean} [options.xLongTextAsPost] - Post long text as single post
427
- *
432
+ *
428
433
  * Threads options:
429
434
  * @param {boolean} [options.threadsLongTextAsPost] - Post long text as single post
430
- *
435
+ * @param {string} [options.threadsThreadMediaLayout] - Comma-separated list of how many media items per Threads post (e.g. "5,5")
436
+ *
431
437
  * Reddit options:
432
438
  * @param {string} [options.redditSubreddit] - Subreddit name (without r/)
433
439
  * @param {string} [options.redditFlairId] - Flair template ID
434
- *
440
+ *
435
441
  * @returns {Promise<Object>} API response
436
442
  */
437
443
  async uploadPhotos(photosPathsOrUrls, options) {
@@ -493,14 +499,15 @@ export class UploadPost {
493
499
  * @param {string} [options.xPollReplySettings] - Who can reply to poll
494
500
  * @param {string} [options.xCardUri] - Card URI for Twitter Cards
495
501
  * @param {boolean} [options.xLongTextAsPost] - Post long text as single post
496
- *
502
+ *
497
503
  * Threads options:
498
504
  * @param {boolean} [options.threadsLongTextAsPost] - Post long text as single post
499
- *
505
+ * @param {string} [options.threadsThreadMediaLayout] - Comma-separated list of how many media items per Threads post (e.g. "5,5")
506
+ *
500
507
  * Reddit options:
501
508
  * @param {string} [options.redditSubreddit] - Subreddit name (without r/)
502
509
  * @param {string} [options.redditFlairId] - Flair template ID
503
- *
510
+ *
504
511
  * @returns {Promise<Object>} API response
505
512
  */
506
513
  async uploadText(options) {
@@ -685,6 +692,10 @@ export class UploadPost {
685
692
  * @param {string} [options.logoImage] - Logo image URL for the linking page
686
693
  * @param {string} [options.redirectButtonText] - Text for redirect button
687
694
  * @param {string[]} [options.platforms] - Platforms to show for connection
695
+ * @param {boolean} [options.showCalendar] - Whether to show the calendar view
696
+ * @param {boolean} [options.readonlyCalendar] - Show only a read-only calendar (no editing, no account connection)
697
+ * @param {string} [options.connectTitle] - Custom title for the connection page
698
+ * @param {string} [options.connectDescription] - Custom description for the connection page
688
699
  * @returns {Promise<Object>} JWT and connection URL
689
700
  */
690
701
  async generateJwt(username, options = {}) {
@@ -693,6 +704,10 @@ export class UploadPost {
693
704
  if (options.logoImage) body.logo_image = options.logoImage;
694
705
  if (options.redirectButtonText) body.redirect_button_text = options.redirectButtonText;
695
706
  if (options.platforms && options.platforms.length > 0) body.platforms = options.platforms;
707
+ if (options.showCalendar !== undefined) body.show_calendar = options.showCalendar;
708
+ if (options.readonlyCalendar !== undefined) body.readonly_calendar = options.readonlyCalendar;
709
+ if (options.connectTitle) body.connect_title = options.connectTitle;
710
+ if (options.connectDescription) body.connect_description = options.connectDescription;
696
711
  return this._request('/uploadposts/users/generate-jwt', 'POST', body);
697
712
  }
698
713
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "upload-post",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
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",