@splendidlabz/third-party 1.3.9 → 1.3.10

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @splendidlabz/third-party
2
2
 
3
+ ## 1.3.10
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies
8
+ - @splendidlabz/utils@1.10.4
9
+
3
10
  ## 1.3.9
4
11
 
5
12
  ### Patch Changes
package/lib/logger.js CHANGED
@@ -3,7 +3,10 @@ import pino from 'pino'
3
3
  // Potentially can put into logtail for production
4
4
  // Potentially can use pino-http for logging requests
5
5
 
6
- const isDev = import.meta.env.DEV
6
+ const isDev =
7
+ process.env.NODE_ENV === 'development' ||
8
+ import.meta.env?.DEV === true ||
9
+ import.meta.env?.MODE === 'development'
7
10
 
8
11
  export function createLogger({ verbose = false, level = 'info' } = {}) {
9
12
  return pino({
@@ -0,0 +1,107 @@
1
+ # Social Media Content Automation
2
+
3
+ Automate posting content across Twitter, Threads, and Instagram with platform-specific formatting.
4
+
5
+ ## Features
6
+
7
+ - **Content formatting**: Automatically formats content for each platform's requirements
8
+ - **Thread support**: Splits long content into Twitter/Threads threads
9
+ - **Cross-platform**: Post to multiple platforms from one content object
10
+ - **Dry run mode**: Preview content before posting
11
+
12
+ ## Usage
13
+
14
+ ### Basic Example
15
+
16
+ ```js
17
+ import { formatContent, postToPlatforms, createTwitter, createInstagram } from '@splendidlabz/third-party/social'
18
+
19
+ // Define your content once
20
+ const content = {
21
+ title: 'CSS trick that saved me 2 hours',
22
+ points: [
23
+ 'Use `:has()` selector for conditional styling',
24
+ 'No JavaScript needed',
25
+ 'Works in all modern browsers',
26
+ ],
27
+ hashtags: ['webdev', 'css', 'frontend'],
28
+ link: 'https://example.com/tutorial',
29
+ videoUrl: 'https://example.com/video.mp4', // For Instagram
30
+ }
31
+
32
+ // Format for all platforms
33
+ const formatted = formatContent(content)
34
+ console.log(formatted.twitter) // Thread format
35
+ console.log(formatted.instagram) // Caption + first comment
36
+ ```
37
+
38
+ ### Posting to Platforms
39
+
40
+ ```js
41
+ // Set up clients
42
+ const twitter = createTwitter({
43
+ bearerToken: process.env.TWITTER_BEARER_TOKEN,
44
+ })
45
+
46
+ const instagram = createInstagram({
47
+ accessToken: process.env.INSTAGRAM_ACCESS_TOKEN,
48
+ instagramAccountId: process.env.INSTAGRAM_ACCOUNT_ID,
49
+ })
50
+
51
+ // Post to all platforms
52
+ const results = await postToPlatforms(
53
+ content,
54
+ { twitter, instagram },
55
+ { dryRun: true } // Preview first
56
+ )
57
+ ```
58
+
59
+ ### Platform-Specific Formatting
60
+
61
+ **Twitter/Threads:**
62
+ - Auto-splits into threads if content is too long
63
+ - Adds hashtags at the end
64
+ - Includes link if provided
65
+
66
+ **Instagram:**
67
+ - Formats as caption with numbered points
68
+ - Adds hashtags (10-20 recommended)
69
+ - Generates first comment for engagement
70
+ - Requires video URL for Reels
71
+
72
+ ## API Setup
73
+
74
+ ### Twitter/X API
75
+
76
+ 1. Create a Twitter Developer account
77
+ 2. Create an app and get Bearer Token
78
+ 3. For OAuth 1.0a, get API Key, Secret, Access Token, and Access Token Secret
79
+
80
+ ### Instagram Graph API
81
+
82
+ 1. Create a Facebook App
83
+ 2. Get Instagram Business Account ID
84
+ 3. Generate Access Token with `instagram_basic`, `instagram_content_publish`, `pages_read_engagement` permissions
85
+ 4. Note: Video URLs must be publicly accessible
86
+
87
+ ## Content Object Structure
88
+
89
+ ```js
90
+ {
91
+ title: string, // Main hook/title (required)
92
+ points: string[], // Key points (optional)
93
+ hashtags: string[], // Hashtags without # (optional)
94
+ link: string, // Link to full content (optional)
95
+ videoUrl: string, // Video URL for Instagram (optional)
96
+ }
97
+ ```
98
+
99
+ ## Notes
100
+
101
+ - Twitter API v2 requires authentication
102
+ - Instagram Reels require video to be publicly accessible
103
+ - Threads can use the same client as Twitter (Meta API)
104
+ - Use `dryRun: true` to preview before posting
105
+ - Rate limits apply - the system includes delays for threads
106
+
107
+
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Formats content for different social media platforms
3
+ * @param {Object} content - Base content object
4
+ * @param {string} content.title - Main title/hook
5
+ * @param {string[]} content.points - Array of key points
6
+ * @param {string} [content.videoUrl] - Video URL for Instagram
7
+ * @param {string[]} [content.hashtags] - Hashtags to include
8
+ * @param {string} [content.link] - Link to full content
9
+ * @param {Object} [options] - Formatting options
10
+ * @return {Object} Platform-specific formatted content
11
+ */
12
+ export function formatContent(content, options = {}) {
13
+ const { title, points = [], videoUrl, hashtags = [], link } = content
14
+ const { maxThreadLength = 280, maxInstagramLength = 2200 } = options
15
+
16
+ return {
17
+ twitter: formatTwitter({
18
+ title,
19
+ points,
20
+ hashtags,
21
+ link,
22
+ maxLength: maxThreadLength,
23
+ }),
24
+ threads: formatThreads({
25
+ title,
26
+ points,
27
+ hashtags,
28
+ link,
29
+ maxLength: maxThreadLength,
30
+ }),
31
+ instagram: formatInstagram({
32
+ title,
33
+ points,
34
+ videoUrl,
35
+ hashtags,
36
+ link,
37
+ maxLength: maxInstagramLength,
38
+ }),
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Formats content for Twitter/X
44
+ * @param {Object} params
45
+ * @return {Object} Formatted Twitter content
46
+ */
47
+ function formatTwitter({ title, points, hashtags, link, maxLength }) {
48
+ const hashtagStr =
49
+ hashtags.length > 0 ? '\n\n' + hashtags.map(h => `#${h}`).join(' ') : ''
50
+ const linkStr = link ? `\n\n${link}` : ''
51
+
52
+ // Single tweet if short enough
53
+ const singleTweet = title + hashtagStr + linkStr
54
+ if (singleTweet.length <= maxLength) {
55
+ return {
56
+ type: 'single',
57
+ content: [singleTweet],
58
+ }
59
+ }
60
+
61
+ // Thread format
62
+ const thread = [title]
63
+
64
+ points.forEach((point, i) => {
65
+ const num = `${i + 1}/${points.length}`
66
+ const tweet = `${num} ${point}`
67
+ thread.push(tweet)
68
+ })
69
+
70
+ if (link) thread.push(`🔗 Full post: ${link}`)
71
+ if (hashtags.length > 0) {
72
+ const hashtagTweet = hashtags.map(h => `#${h}`).join(' ')
73
+ thread.push(hashtagTweet)
74
+ }
75
+
76
+ return {
77
+ type: 'thread',
78
+ content: thread,
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Formats content for Threads (similar to Twitter but slightly different)
84
+ * @param {Object} params
85
+ * @return {Object} Formatted Threads content
86
+ */
87
+ function formatThreads({ title, points, hashtags, link, maxLength }) {
88
+ // Threads allows longer posts, but similar format
89
+ return formatTwitter({
90
+ title,
91
+ points,
92
+ hashtags,
93
+ link,
94
+ maxLength: maxLength * 2,
95
+ })
96
+ }
97
+
98
+ /**
99
+ * Formats content for Instagram
100
+ * @param {Object} params
101
+ * @return {Object} Formatted Instagram content
102
+ */
103
+ function formatInstagram({
104
+ title,
105
+ points,
106
+ videoUrl,
107
+ hashtags,
108
+ link,
109
+ maxLength,
110
+ }) {
111
+ let caption = title + '\n\n'
112
+
113
+ if (points.length > 0) {
114
+ caption += points.map((p, i) => `${i + 1}. ${p}`).join('\n\n') + '\n\n'
115
+ }
116
+
117
+ if (link) caption += `🔗 Link in bio: ${link}\n\n`
118
+
119
+ // Instagram hashtags (10-20 recommended)
120
+ const instagramHashtags = hashtags.slice(0, 20)
121
+ if (instagramHashtags.length > 0) {
122
+ caption += instagramHashtags.map(h => `#${h}`).join(' ')
123
+ }
124
+
125
+ // Instagram comment (first comment strategy)
126
+ const firstComment = link
127
+ ? `Full tutorial: ${link}\n\nWhat would you like to see next? 👇`
128
+ : `What would you like to see next? 👇`
129
+
130
+ return {
131
+ caption: caption.trim(),
132
+ firstComment,
133
+ videoUrl,
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Splits long text into thread chunks
139
+ * @param {string} text - Text to split
140
+ * @param {number} maxLength - Maximum length per chunk
141
+ * @return {string[]} Array of text chunks
142
+ */
143
+ export function splitIntoThread(text, maxLength = 280) {
144
+ const sentences = text.split(/[.!?]\s+/)
145
+ const chunks = []
146
+ let currentChunk = ''
147
+
148
+ sentences.forEach(sentence => {
149
+ const testChunk = currentChunk ? `${currentChunk}. ${sentence}` : sentence
150
+
151
+ if (testChunk.length <= maxLength) {
152
+ currentChunk = testChunk
153
+ } else {
154
+ if (currentChunk) chunks.push(currentChunk)
155
+ currentChunk = sentence
156
+ }
157
+ })
158
+
159
+ if (currentChunk) chunks.push(currentChunk)
160
+ return chunks
161
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Example usage of social media automation
3
+ *
4
+ * This shows how to format and post content across platforms
5
+ */
6
+
7
+ import { formatContent, postToPlatforms, createTwitter, createInstagram } from './index.js'
8
+
9
+ // Example: Create your content once
10
+ const content = {
11
+ title: 'CSS trick that saved me 2 hours yesterday',
12
+ points: [
13
+ 'Use `:has()` selector to style parent based on child',
14
+ 'No JavaScript needed for conditional styling',
15
+ 'Works in all modern browsers now',
16
+ ],
17
+ hashtags: ['webdev', 'css', 'frontend', 'coding'],
18
+ link: 'https://example.com/full-tutorial',
19
+ videoUrl: 'https://example.com/video.mp4', // For Instagram
20
+ }
21
+
22
+ // Format for all platforms
23
+ const formatted = formatContent(content)
24
+ console.log('Twitter:', formatted.twitter)
25
+ console.log('Instagram:', formatted.instagram)
26
+
27
+ // Example: Set up clients
28
+ const twitter = createTwitter({
29
+ bearerToken: process.env.TWITTER_BEARER_TOKEN,
30
+ })
31
+
32
+ const instagram = createInstagram({
33
+ accessToken: process.env.INSTAGRAM_ACCESS_TOKEN,
34
+ instagramAccountId: process.env.INSTAGRAM_ACCOUNT_ID,
35
+ })
36
+
37
+ // Post to all platforms (dry run first)
38
+ const results = await postToPlatforms(
39
+ content,
40
+ { twitter, instagram },
41
+ { dryRun: true }
42
+ )
43
+
44
+ console.log('Preview results:', results)
45
+
46
+ // When ready, post for real
47
+ // const realResults = await postToPlatforms(content, { twitter, instagram })
48
+
49
+
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Social media content automation
3
+ * Formats and posts content across multiple platforms
4
+ */
5
+
6
+ export { formatContent, splitIntoThread } from './content-formatter.js'
7
+ export { createTwitter } from './twitter.js'
8
+ export { createThreads } from './threads.js'
9
+ export { createInstagram } from './instagram.js'
10
+
11
+ /**
12
+ * Orchestrates posting to multiple platforms
13
+ * @param {Object} content - Base content (see content-formatter.js)
14
+ * @param {Object} clients - Platform clients
15
+ * @param {Object} [clients.twitter] - Twitter client instance
16
+ * @param {Object} [clients.threads] - Threads client (can use Twitter client)
17
+ * @param {Object} [clients.instagram] - Instagram client instance
18
+ * @param {Object} [options] - Posting options
19
+ * @param {boolean} [options.dryRun] - Preview without posting
20
+ * @return {Promise<Object>} Results from each platform
21
+ */
22
+ export async function postToPlatforms(content, clients, options = {}) {
23
+ const { dryRun = false } = options
24
+ const formatted = formatContent(content)
25
+ const results = {}
26
+
27
+ // Post to Twitter
28
+ if (clients.twitter && formatted.twitter) {
29
+ if (dryRun) {
30
+ results.twitter = { preview: formatted.twitter }
31
+ } else {
32
+ // Twitter client handles both single tweets and arrays
33
+ results.twitter = await clients.twitter.post(formatted.twitter.content)
34
+ }
35
+ }
36
+
37
+ // Post to Threads
38
+ if (clients.threads && formatted.threads) {
39
+ if (dryRun) {
40
+ results.threads = { preview: formatted.threads }
41
+ } else {
42
+ const threadsClient = clients.threads
43
+ // Threads content is same format as Twitter
44
+ // For single post, join content; for thread, use array
45
+ const threadsContent = formatted.threads.type === 'single'
46
+ ? formatted.threads.content[0]
47
+ : formatted.threads.content
48
+ results.threads = await threadsClient.post(threadsContent)
49
+ }
50
+ }
51
+
52
+ // Post to Instagram
53
+ if (clients.instagram && formatted.instagram) {
54
+ if (dryRun) {
55
+ results.instagram = { preview: formatted.instagram }
56
+ } else {
57
+ const { caption, videoUrl, firstComment } = formatted.instagram
58
+
59
+ // Post the reel
60
+ const reel = await clients.instagram.postReel(videoUrl, caption)
61
+
62
+ // Add first comment if provided
63
+ if (firstComment && reel.id) {
64
+ await clients.instagram.addComment(reel.id, firstComment)
65
+ }
66
+
67
+ results.instagram = reel
68
+ }
69
+ }
70
+
71
+ return results
72
+ }
73
+
@@ -0,0 +1,105 @@
1
+ import { createZlFetch } from 'zl-fetch'
2
+
3
+ /**
4
+ * Creates an Instagram Graph API client
5
+ * Note: Instagram API requires Facebook App setup and access tokens
6
+ * @param {Object} config - Configuration
7
+ * @param {string} config.accessToken - Instagram Graph API Access Token
8
+ * @param {string} config.instagramAccountId - Instagram Business Account ID
9
+ * @return {Object} Instagram client
10
+ */
11
+ export function createInstagram({ accessToken, instagramAccountId }) {
12
+ const BASE_URL = 'https://graph.facebook.com/v19.0'
13
+
14
+ const instagram = createZlFetch(BASE_URL, {
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ },
18
+ returnError: true,
19
+ })
20
+
21
+ return {
22
+ /**
23
+ * Create a media container (step 1 of posting)
24
+ * @param {string} videoUrl - URL to video file
25
+ * @param {string} caption - Post caption
26
+ * @return {Promise<Object>} Container creation response
27
+ */
28
+ async createVideoContainer(videoUrl, caption) {
29
+ const { response, error } = await instagram.post(
30
+ `/${instagramAccountId}/media`,
31
+ {
32
+ query: {
33
+ access_token: accessToken,
34
+ media_type: 'REELS',
35
+ video_url: videoUrl,
36
+ caption,
37
+ },
38
+ }
39
+ )
40
+
41
+ if (response) return response.body
42
+ if (error) throw error
43
+ },
44
+
45
+ /**
46
+ * Publish a media container (step 2 of posting)
47
+ * @param {string} creationId - Container creation ID from step 1
48
+ * @return {Promise<Object>} Publishing response
49
+ */
50
+ async publishContainer(creationId) {
51
+ const { response, error } = await instagram.post(
52
+ `/${instagramAccountId}/media_publish`,
53
+ {
54
+ query: {
55
+ access_token: accessToken,
56
+ creation_id: creationId,
57
+ },
58
+ }
59
+ )
60
+
61
+ if (response) return response.body
62
+ if (error) throw error
63
+ },
64
+
65
+ /**
66
+ * Post a Reel (two-step process)
67
+ * @param {string} videoUrl - URL to video file (must be publicly accessible)
68
+ * @param {string} caption - Post caption
69
+ * @return {Promise<Object>} Post response
70
+ */
71
+ async postReel(videoUrl, caption) {
72
+ // Step 1: Create container
73
+ const container = await this.createVideoContainer(videoUrl, caption)
74
+
75
+ // Step 2: Publish (may need to wait for processing)
76
+ // In production, you'd want to poll status or use webhooks
77
+ const published = await this.publishContainer(container.id)
78
+
79
+ return published
80
+ },
81
+
82
+ /**
83
+ * Add a comment to a post
84
+ * @param {string} mediaId - Instagram media ID
85
+ * @param {string} text - Comment text
86
+ * @return {Promise<Object>} Comment response
87
+ */
88
+ async addComment(mediaId, text) {
89
+ const { response, error } = await instagram.post(
90
+ `/${mediaId}/comments`,
91
+ {
92
+ query: {
93
+ access_token: accessToken,
94
+ message: text,
95
+ },
96
+ }
97
+ )
98
+
99
+ if (response) return response.body
100
+ if (error) throw error
101
+ },
102
+ }
103
+ }
104
+
105
+
@@ -0,0 +1,110 @@
1
+ import { createZlFetch } from 'zl-fetch'
2
+
3
+ /**
4
+ * Creates a Threads API client
5
+ * Note: Threads API is part of Meta's Graph API
6
+ * @param {Object} config - Configuration
7
+ * @param {string} config.accessToken - Meta Access Token
8
+ * @param {string} config.threadsUserId - Threads User ID (your account ID)
9
+ * @return {Object} Threads client
10
+ */
11
+ export function createThreads({ accessToken, threadsUserId }) {
12
+ const BASE_URL = 'https://graph.threads.net/v1.0'
13
+
14
+ const threads = createZlFetch(BASE_URL, {
15
+ headers: {
16
+ 'Content-Type': 'application/json',
17
+ },
18
+ returnError: true,
19
+ })
20
+
21
+ return {
22
+ /**
23
+ * Create a media container (step 1 of posting)
24
+ * @param {string} text - Thread text
25
+ * @param {string} [mediaType] - 'TEXT' or 'IMAGE' (default: 'TEXT')
26
+ * @return {Promise<Object>} Container creation response
27
+ */
28
+ async createContainer(text, mediaType = 'TEXT') {
29
+ const { response, error } = await threads.post(
30
+ `/${threadsUserId}/threads`,
31
+ {
32
+ query: {
33
+ access_token: accessToken,
34
+ media_type: mediaType,
35
+ text,
36
+ },
37
+ }
38
+ )
39
+
40
+ if (response) return response.body
41
+ if (error) throw error
42
+ },
43
+
44
+ /**
45
+ * Publish a media container (step 2 of posting)
46
+ * @param {string} creationId - Container creation ID from step 1
47
+ * @return {Promise<Object>} Publishing response
48
+ */
49
+ async publishContainer(creationId) {
50
+ const { response, error } = await threads.post(
51
+ `/${threadsUserId}/threads_publish`,
52
+ {
53
+ query: {
54
+ access_token: accessToken,
55
+ creation_id: creationId,
56
+ },
57
+ }
58
+ )
59
+
60
+ if (response) return response.body
61
+ if (error) throw error
62
+ },
63
+
64
+ /**
65
+ * Post a thread (two-step process)
66
+ * @param {string} text - Thread text
67
+ * @return {Promise<Object>} Post response
68
+ */
69
+ async postThread(text) {
70
+ // Step 1: Create container
71
+ const container = await this.createContainer(text)
72
+
73
+ // Step 2: Publish
74
+ const published = await this.publishContainer(container.id)
75
+
76
+ return published
77
+ },
78
+
79
+ /**
80
+ * Post content (can be string or array for thread replies)
81
+ * @param {string|string[]} content - Single post or array for replies
82
+ * @return {Promise<Object|Object[]>} Post response(s)
83
+ */
84
+ async post(content) {
85
+ if (Array.isArray(content)) {
86
+ // For threads, you'd need to reply to previous post
87
+ // This is a simplified version - full implementation would track reply IDs
88
+ const results = []
89
+ let parentId = null
90
+
91
+ for (const text of content) {
92
+ // Note: Threads API reply structure may differ
93
+ // This is a placeholder for the actual implementation
94
+ const result = await this.postThread(text)
95
+ results.push(result)
96
+ // Add delay between posts
97
+ if (content.length > 1) {
98
+ await new Promise(resolve => setTimeout(resolve, 1000))
99
+ }
100
+ }
101
+
102
+ return results
103
+ }
104
+
105
+ return this.postThread(content)
106
+ },
107
+ }
108
+ }
109
+
110
+
@@ -0,0 +1,90 @@
1
+ import { createZlFetch } from 'zl-fetch'
2
+
3
+ /**
4
+ * Creates a Twitter/X API client
5
+ * @param {Object} config - Configuration
6
+ * @param {string} config.bearerToken - Twitter Bearer Token
7
+ * @param {string} [config.apiKey] - API Key (for OAuth 1.0a)
8
+ * @param {string} [config.apiSecret] - API Secret (for OAuth 1.0a)
9
+ * @param {string} [config.accessToken] - Access Token (for OAuth 1.0a)
10
+ * @param {string} [config.accessTokenSecret] - Access Token Secret (for OAuth 1.0a)
11
+ * @return {Object} Twitter client
12
+ */
13
+ export function createTwitter({
14
+ bearerToken,
15
+ apiKey,
16
+ apiSecret,
17
+ accessToken,
18
+ accessTokenSecret,
19
+ }) {
20
+ const BASE_URL = 'https://api.twitter.com/2'
21
+
22
+ // Use OAuth 1.0a if credentials provided, otherwise Bearer token
23
+ const useOAuth = apiKey && apiSecret && accessToken && accessTokenSecret
24
+
25
+ const twitter = createZlFetch(BASE_URL, {
26
+ headers: {
27
+ 'Content-Type': 'application/json',
28
+ ...(bearerToken && !useOAuth
29
+ ? { Authorization: `Bearer ${bearerToken}` }
30
+ : {}),
31
+ },
32
+ returnError: true,
33
+ })
34
+
35
+ return {
36
+ /**
37
+ * Post a single tweet
38
+ * @param {string} text - Tweet text
39
+ * @param {Object} [options] - Additional options
40
+ * @return {Promise<Object>} Tweet response
41
+ */
42
+ async postTweet(text, options = {}) {
43
+ const { response, error } = await twitter.post('/tweets', {
44
+ body: {
45
+ text,
46
+ ...options,
47
+ },
48
+ })
49
+
50
+ if (response) return response.body
51
+ if (error) throw error
52
+ },
53
+
54
+ /**
55
+ * Post a thread (reply chain)
56
+ * @param {string[]} tweets - Array of tweet texts
57
+ * @return {Promise<Object[]>} Array of tweet responses
58
+ */
59
+ async postThread(tweets) {
60
+ const results = []
61
+ let replyToId = null
62
+
63
+ for (const tweet of tweets) {
64
+ const options = replyToId
65
+ ? { reply: { in_reply_to_tweet_id: replyToId } }
66
+ : {}
67
+ const result = await this.postTweet(tweet, options)
68
+ replyToId = result.data?.id
69
+ results.push(result)
70
+
71
+ // Small delay between tweets to avoid rate limits
72
+ if (tweets.length > 1) {
73
+ await new Promise(resolve => setTimeout(resolve, 1000))
74
+ }
75
+ }
76
+
77
+ return results
78
+ },
79
+
80
+ /**
81
+ * Post content (auto-detects single vs thread)
82
+ * @param {string|string[]} content - Single tweet or array for thread
83
+ * @return {Promise<Object|Object[]>} Tweet response(s)
84
+ */
85
+ async post(content) {
86
+ if (Array.isArray(content)) return this.postThread(content)
87
+ return this.postTweet(content)
88
+ },
89
+ }
90
+ }
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@splendidlabz/third-party",
3
3
  "prettier": "@splendidlabz/prettier-config",
4
- "version": "1.3.9",
4
+ "version": "1.3.10",
5
5
  "description": "",
6
6
  "type": "module",
7
7
  "main": "index.js",
8
8
  "sideEffects": false,
9
9
  "exports": {
10
- "./*": "./lib/*.js"
10
+ "./*": "./lib/*.js",
11
+ "./social": "./lib/social/index.js"
11
12
  },
12
13
  "scripts": {
13
14
  "lint": "eslint . --fix",
@@ -16,7 +17,7 @@
16
17
  },
17
18
  "author": "Zell Liew <zellwk@gmail.com>",
18
19
  "dependencies": {
19
- "@splendidlabz/utils": "1.10.3",
20
+ "@splendidlabz/utils": "1.10.4",
20
21
  "googleapis": "^148.0.0",
21
22
  "http-errors": "^2.0.0",
22
23
  "pino": "^9.7.0",