@getlatedev/node 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -1,9 +1,21 @@
1
- # Late Node.js Library
1
+ <p align="center">
2
+ <a href="https://getlate.dev">
3
+ <img src="https://getlate.dev/images/icon_light.svg" alt="Late" width="60">
4
+ </a>
5
+ </p>
2
6
 
3
- [![npm version](https://img.shields.io/npm/v/late.svg)](https://www.npmjs.com/package/late)
4
- [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
7
+ <h1 align="center">Late Node.js SDK</h1>
5
8
 
6
- The official Node.js library for the [Late API](https://getlate.dev) - schedule social media posts across Instagram, TikTok, YouTube, LinkedIn, X/Twitter, Facebook, Pinterest, Threads, and more.
9
+ <p align="center">
10
+ <a href="https://www.npmjs.com/package/@getlatedev/node"><img src="https://img.shields.io/npm/v/@getlatedev/node.svg" alt="npm version"></a>
11
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="License"></a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <strong>One API to post everywhere. 13 platforms, zero headaches.</strong>
16
+ </p>
17
+
18
+ The official Node.js SDK for the [Late API](https://getlate.dev) — schedule and publish social media posts across Instagram, TikTok, YouTube, LinkedIn, X/Twitter, Facebook, Pinterest, Threads, Bluesky, Reddit, Snapchat, Telegram, and Google Business Profile with a single integration.
7
19
 
8
20
  ## Installation
9
21
 
@@ -11,46 +23,36 @@ The official Node.js library for the [Late API](https://getlate.dev) - schedule
11
23
  npm install @getlatedev/node
12
24
  ```
13
25
 
14
- ## Usage
26
+ ## Quick Start
15
27
 
16
28
  ```typescript
17
29
  import Late from '@getlatedev/node';
18
30
 
19
- const late = new Late({
20
- apiKey: process.env['LATE_API_KEY'], // This is the default and can be omitted
21
- });
31
+ const late = new Late(); // Uses LATE_API_KEY env var
22
32
 
23
- async function main() {
24
- // Create and publish a post
25
- const post = await late.posts.create({
26
- body: {
27
- content: 'Hello from the Late SDK! 🚀',
28
- platforms: [
29
- { platform: 'twitter', accountId: 'acc_xxx' },
30
- { platform: 'linkedin', accountId: 'acc_yyy' },
31
- ],
32
- publishNow: true,
33
- },
34
- });
35
-
36
- console.log(post.data);
37
- }
33
+ // Publish to multiple platforms with one call
34
+ const { data: post } = await late.posts.createPost({
35
+ body: {
36
+ content: 'Hello world from Late!',
37
+ platforms: [
38
+ { platform: 'twitter', accountId: 'acc_xxx' },
39
+ { platform: 'linkedin', accountId: 'acc_yyy' },
40
+ { platform: 'instagram', accountId: 'acc_zzz' },
41
+ ],
42
+ publishNow: true,
43
+ },
44
+ });
38
45
 
39
- main();
46
+ console.log(`Published to ${post.platforms.length} platforms!`);
40
47
  ```
41
48
 
42
49
  ## Configuration
43
50
 
44
- The client can be configured with the following options:
45
-
46
51
  ```typescript
47
52
  const late = new Late({
48
- apiKey: 'sk_...', // Defaults to process.env['LATE_API_KEY']
49
- baseURL: 'https://getlate.dev/api', // Default
50
- timeout: 60000, // Request timeout in ms
51
- defaultHeaders: {
52
- 'X-Custom-Header': 'value',
53
- },
53
+ apiKey: 'your-api-key', // Defaults to process.env['LATE_API_KEY']
54
+ baseURL: 'https://getlate.dev/api',
55
+ timeout: 60000,
54
56
  });
55
57
  ```
56
58
 
@@ -59,31 +61,33 @@ const late = new Late({
59
61
  ### Schedule a Post
60
62
 
61
63
  ```typescript
62
- const post = await late.posts.create({
64
+ const { data: post } = await late.posts.createPost({
63
65
  body: {
64
- content: 'Scheduled post from the SDK',
66
+ content: 'This post will go live tomorrow at 10am',
65
67
  platforms: [{ platform: 'instagram', accountId: 'acc_xxx' }],
66
- scheduledFor: new Date('2025-02-01T10:00:00Z').toISOString(),
68
+ scheduledFor: '2025-02-01T10:00:00Z',
67
69
  },
68
70
  });
69
71
  ```
70
72
 
71
- ### Multi-Platform with Platform-Specific Content
73
+ ### Platform-Specific Content
74
+
75
+ Customize content per platform while posting to all at once:
72
76
 
73
77
  ```typescript
74
- const post = await late.posts.create({
78
+ const { data: post } = await late.posts.createPost({
75
79
  body: {
76
- content: 'Default content for all platforms',
80
+ content: 'Default content',
77
81
  platforms: [
78
82
  {
79
83
  platform: 'twitter',
80
84
  accountId: 'acc_twitter',
81
- platformSpecificContent: 'Shorter content for X #hashtags',
85
+ platformSpecificContent: 'Short & punchy for X',
82
86
  },
83
87
  {
84
88
  platform: 'linkedin',
85
89
  accountId: 'acc_linkedin',
86
- platformSpecificContent: 'Professional content for LinkedIn',
90
+ platformSpecificContent: 'Professional tone for LinkedIn with more detail.',
87
91
  },
88
92
  ],
89
93
  publishNow: true,
@@ -91,45 +95,30 @@ const post = await late.posts.create({
91
95
  });
92
96
  ```
93
97
 
94
- ### List Posts
95
-
96
- ```typescript
97
- const { data } = await late.posts.list({
98
- query: {
99
- status: 'scheduled',
100
- limit: 20,
101
- },
102
- });
103
-
104
- for (const post of data.posts) {
105
- console.log(post.content, post.scheduledFor);
106
- }
107
- ```
108
-
109
98
  ### Upload Media
110
99
 
111
100
  ```typescript
112
- // 1. Get presigned URL
113
- const { data: presign } = await late.media.getPresignedUrl({
114
- body: {
115
- filename: 'image.jpg',
116
- contentType: 'image/jpeg',
117
- },
101
+ // 1. Get presigned upload URL
102
+ const { data: presign } = await late.media.getMediaPresignedUrl({
103
+ body: { filename: 'video.mp4', contentType: 'video/mp4' },
118
104
  });
119
105
 
120
- // 2. Upload file
106
+ // 2. Upload your file
121
107
  await fetch(presign.uploadUrl, {
122
108
  method: 'PUT',
123
- body: imageBuffer,
124
- headers: { 'Content-Type': 'image/jpeg' },
109
+ body: videoBuffer,
110
+ headers: { 'Content-Type': 'video/mp4' },
125
111
  });
126
112
 
127
113
  // 3. Create post with media
128
- await late.posts.create({
114
+ const { data: post } = await late.posts.createPost({
129
115
  body: {
130
- content: 'Post with image',
116
+ content: 'Check out this video!',
131
117
  mediaUrls: [presign.publicUrl],
132
- platforms: [{ platform: 'instagram', accountId: 'acc_xxx' }],
118
+ platforms: [
119
+ { platform: 'tiktok', accountId: 'acc_xxx' },
120
+ { platform: 'youtube', accountId: 'acc_yyy', youtubeTitle: 'My Video' },
121
+ ],
133
122
  publishNow: true,
134
123
  },
135
124
  });
@@ -138,94 +127,207 @@ await late.posts.create({
138
127
  ### Get Analytics
139
128
 
140
129
  ```typescript
141
- const { data: analytics } = await late.analytics.get({
130
+ const { data } = await late.analytics.getAnalytics({
142
131
  query: { postId: 'post_xxx' },
143
132
  });
144
133
 
145
- console.log('Impressions:', analytics.analytics.impressions);
146
- console.log('Engagement:', analytics.analytics.engagementRate);
134
+ console.log('Views:', data.analytics.views);
135
+ console.log('Likes:', data.analytics.likes);
136
+ console.log('Engagement Rate:', data.analytics.engagementRate);
147
137
  ```
148
138
 
149
139
  ### List Connected Accounts
150
140
 
151
141
  ```typescript
152
- const { data } = await late.accounts.list();
142
+ const { data } = await late.accounts.listAccounts();
153
143
 
154
144
  for (const account of data.accounts) {
155
145
  console.log(`${account.platform}: @${account.username}`);
156
146
  }
157
147
  ```
158
148
 
159
- ### Configure Webhooks
160
-
161
- ```typescript
162
- await late.webhooks.updateSettings({
163
- body: {
164
- url: 'https://your-app.com/webhooks/late',
165
- events: ['post.published', 'post.failed', 'account.disconnected'],
166
- secret: 'your-webhook-secret',
167
- },
168
- });
169
- ```
170
-
171
149
  ## Error Handling
172
150
 
173
151
  ```typescript
174
152
  import Late, { LateApiError, RateLimitError, ValidationError } from '@getlatedev/node';
175
153
 
176
- const late = new Late();
177
-
178
154
  try {
179
- await late.posts.create({ body: { ... } });
155
+ await late.posts.createPost({ body: { /* ... */ } });
180
156
  } catch (error) {
181
157
  if (error instanceof RateLimitError) {
182
- console.log(`Rate limited. Retry in ${error.getSecondsUntilReset()} seconds`);
158
+ console.log(`Rate limited. Retry in ${error.getSecondsUntilReset()}s`);
183
159
  } else if (error instanceof ValidationError) {
184
- console.log('Validation errors:', error.fields);
160
+ console.log('Invalid request:', error.fields);
185
161
  } else if (error instanceof LateApiError) {
186
- console.log(`API error ${error.statusCode}: ${error.message}`);
162
+ console.log(`Error ${error.statusCode}: ${error.message}`);
187
163
  }
188
164
  }
189
165
  ```
190
166
 
191
- ## API Reference
167
+ ## SDK Reference
192
168
 
193
169
  ### Posts
194
-
195
170
  | Method | Description |
196
171
  |--------|-------------|
197
- | `posts.list(params)` | List posts |
198
- | `posts.create(params)` | Create a post |
199
- | `posts.get(params)` | Get a post |
200
- | `posts.update(params)` | Update a post |
201
- | `posts.delete(params)` | Delete a post |
202
- | `posts.retry(params)` | Retry a failed post |
203
- | `posts.bulkUpload(params)` | Upload multiple posts |
172
+ | `posts.listPosts()` | List posts visible to the authenticated user |
173
+ | `posts.bulkUploadPosts()` | Validate and schedule multiple posts from CSV |
174
+ | `posts.createPost()` | Create a draft, scheduled, or immediate post |
175
+ | `posts.getPost()` | Get a single post |
176
+ | `posts.updatePost()` | Update a post |
177
+ | `posts.deletePost()` | Delete a post |
178
+ | `posts.retryPost()` | Retry publishing a failed or partial post |
204
179
 
205
180
  ### Accounts
206
-
207
181
  | Method | Description |
208
182
  |--------|-------------|
209
- | `accounts.list()` | List connected accounts |
210
- | `accounts.update(params)` | Update an account |
211
- | `accounts.delete(params)` | Disconnect an account |
212
- | `accounts.getFollowerStats()` | Get follower statistics |
213
- | `accounts.getAllHealth()` | Get health for all accounts |
183
+ | `accounts.getAllAccountsHealth()` | Check health of all connected accounts |
184
+ | `accounts.listAccounts()` | List connected social accounts |
185
+ | `accounts.getAccountHealth()` | Check health of a specific account |
186
+ | `accounts.getFollowerStats()` | Get follower stats and growth metrics |
187
+ | `accounts.getGoogleBusinessReviews()` | Get Google Business Profile reviews |
188
+ | `accounts.getLinkedInMentions()` | Resolve a LinkedIn profile or company URL to a URN for @mentions |
189
+ | `accounts.updateAccount()` | Update a social account |
190
+ | `accounts.deleteAccount()` | Disconnect a social account |
191
+
192
+ ### Profiles
193
+ | Method | Description |
194
+ |--------|-------------|
195
+ | `profiles.listProfiles()` | List profiles visible to the authenticated user |
196
+ | `profiles.createProfile()` | Create a new profile |
197
+ | `profiles.getProfile()` | Get a profile by id |
198
+ | `profiles.updateProfile()` | Update a profile |
199
+ | `profiles.deleteProfile()` | Delete a profile (must have no connected accounts) |
214
200
 
215
201
  ### Analytics
202
+ | Method | Description |
203
+ |--------|-------------|
204
+ | `analytics.getAnalytics()` | Unified analytics for posts |
205
+ | `analytics.getLinkedInAggregateAnalytics()` | Get aggregate analytics for a LinkedIn personal account |
206
+ | `analytics.getLinkedInPostAnalytics()` | Get analytics for a specific LinkedIn post by URN |
207
+ | `analytics.getYouTubeDailyViews()` | YouTube daily views breakdown |
216
208
 
209
+ ### Account Groups
210
+ | Method | Description |
211
+ |--------|-------------|
212
+ | `accountGroups.listAccountGroups()` | List account groups for the authenticated user |
213
+ | `accountGroups.createAccountGroup()` | Create a new account group |
214
+ | `accountGroups.updateAccountGroup()` | Update an account group |
215
+ | `accountGroups.deleteAccountGroup()` | Delete an account group |
216
+
217
+ ### Queue
218
+ | Method | Description |
219
+ |--------|-------------|
220
+ | `queue.listQueueSlots()` | Get queue schedules for a profile |
221
+ | `queue.createQueueSlot()` | Create a new queue for a profile |
222
+ | `queue.getNextQueueSlot()` | Get the next available queue slot for a profile |
223
+ | `queue.updateQueueSlot()` | Create or update a queue schedule |
224
+ | `queue.deleteQueueSlot()` | Delete a queue schedule |
225
+ | `queue.previewQueue()` | Preview upcoming queue slots for a profile |
226
+
227
+ ### Webhooks
228
+ | Method | Description |
229
+ |--------|-------------|
230
+ | `webhooks.createWebhookSettings()` | Create a new webhook |
231
+ | `webhooks.getWebhookLogs()` | Get webhook delivery logs |
232
+ | `webhooks.getWebhookSettings()` | List all webhooks |
233
+ | `webhooks.updateWebhookSettings()` | Update a webhook |
234
+ | `webhooks.deleteWebhookSettings()` | Delete a webhook |
235
+ | `webhooks.testWebhook()` | Send test webhook |
236
+
237
+ ### API Keys
217
238
  | Method | Description |
218
239
  |--------|-------------|
219
- | `analytics.get(params)` | Get post analytics |
220
- | `analytics.getYouTubeDailyViews(params)` | Get YouTube daily views |
221
- | `analytics.getLinkedInAggregate(params)` | Get LinkedIn org analytics |
240
+ | `apiKeys.listApiKeys()` | List API keys for the current user |
241
+ | `apiKeys.createApiKey()` | Create a new API key |
242
+ | `apiKeys.deleteApiKey()` | Delete an API key |
222
243
 
223
- See the [API documentation](https://getlate.dev/docs/api) for all available methods.
244
+ ### Media
245
+ | Method | Description |
246
+ |--------|-------------|
247
+ | `media.getMediaPresignedUrl()` | Get a presigned URL for direct file upload (up to 5GB) |
248
+
249
+ ### Tools
250
+ | Method | Description |
251
+ |--------|-------------|
252
+ | `tools.getYouTubeTranscript()` | Get YouTube video transcript |
253
+ | `tools.checkInstagramHashtags()` | Check Instagram hashtags for bans |
254
+ | `tools.downloadBlueskyMedia()` | Download Bluesky video |
255
+ | `tools.downloadFacebookVideo()` | Download Facebook video |
256
+ | `tools.downloadInstagramMedia()` | Download Instagram reel or post |
257
+ | `tools.downloadLinkedInVideo()` | Download LinkedIn video |
258
+ | `tools.downloadTikTokVideo()` | Download TikTok video |
259
+ | `tools.downloadTwitterMedia()` | Download Twitter/X video |
260
+ | `tools.downloadYouTubeVideo()` | Download YouTube video or audio |
261
+
262
+ ### Users
263
+ | Method | Description |
264
+ |--------|-------------|
265
+ | `users.listUsers()` | List team users (root + invited) |
266
+ | `users.getUser()` | Get user by id (self or invited) |
267
+
268
+ ### Usage
269
+ | Method | Description |
270
+ |--------|-------------|
271
+ | `usage.getUsageStats()` | Get plan and usage stats for current account |
272
+
273
+ ### Logs
274
+ | Method | Description |
275
+ |--------|-------------|
276
+ | `logs.listLogs()` | Get publishing logs |
277
+ | `logs.getLog()` | Get a single log entry |
278
+ | `logs.getPostLogs()` | Get logs for a specific post |
279
+
280
+ ### Connect (OAuth)
281
+ | Method | Description |
282
+ |--------|-------------|
283
+ | `connect.listFacebookPages()` | List Facebook Pages after OAuth (Headless Mode) |
284
+ | `connect.listGoogleBusinessLocations()` | List Google Business Locations after OAuth (Headless Mode) |
285
+ | `connect.listLinkedInOrganizations()` | Fetch full LinkedIn organization details (Headless Mode) |
286
+ | `connect.listPinterestBoardsForSelection()` | List Pinterest Boards after OAuth (Headless Mode) |
287
+ | `connect.listSnapchatProfiles()` | List Snapchat Public Profiles after OAuth (Headless Mode) |
288
+ | `connect.getConnectUrl()` | Start OAuth connection for a platform |
289
+ | `connect.getLinkedInOrganizations()` | Get available LinkedIn organizations for a connected account |
290
+ | `connect.getPinterestBoards()` | List Pinterest boards for a connected account |
291
+ | `connect.getRedditSubreddits()` | List Reddit subreddits for a connected account |
292
+ | `connect.getTelegramConnectStatus()` | Generate Telegram access code |
293
+ | `connect.updateFacebookPage()` | Update selected Facebook page for a connected account |
294
+ | `connect.updateLinkedInOrganization()` | Switch LinkedIn account type (personal/organization) |
295
+ | `connect.updatePinterestBoards()` | Set default Pinterest board on the connection |
296
+ | `connect.updateRedditSubreddits()` | Set default subreddit on the connection |
297
+ | `connect.completeTelegramConnect()` | Check Telegram connection status |
298
+ | `connect.connectBlueskyCredentials()` | Connect Bluesky using app password |
299
+ | `connect.handleOAuthCallback()` | Complete OAuth token exchange manually (for server-side flows) |
300
+ | `connect.initiateTelegramConnect()` | Direct Telegram connection (power users) |
301
+ | `connect.selectFacebookPage()` | Select a Facebook Page to complete the connection (Headless Mode) |
302
+ | `connect.selectGoogleBusinessLocation()` | Select a Google Business location to complete the connection (Headless Mode) |
303
+ | `connect.selectLinkedInOrganization()` | Select LinkedIn organization or personal account after OAuth |
304
+ | `connect.selectPinterestBoard()` | Select a Pinterest Board to complete the connection (Headless Mode) |
305
+ | `connect.selectSnapchatProfile()` | Select a Snapchat Public Profile to complete the connection (Headless Mode) |
306
+
307
+ ### Reddit
308
+ | Method | Description |
309
+ |--------|-------------|
310
+ | `reddit.getRedditFeed()` | Fetch subreddit feed via a connected account |
311
+ | `reddit.searchReddit()` | Search Reddit posts via a connected account |
312
+
313
+ ### Invites
314
+ | Method | Description |
315
+ |--------|-------------|
316
+ | `invites.listPlatformInvites()` | List platform connection invites |
317
+ | `invites.createInviteToken()` | Create a team member invite token |
318
+ | `invites.createPlatformInvite()` | Create a platform connection invite |
319
+ | `invites.deletePlatformInvite()` | Revoke a platform connection invite |
224
320
 
225
321
  ## Requirements
226
322
 
227
- - Node.js 18 or later
228
- - An API key from [Late](https://getlate.dev)
323
+ - Node.js 18+
324
+ - [Late API key](https://getlate.dev) (free tier available)
325
+
326
+ ## Links
327
+
328
+ - [Documentation](https://docs.getlate.dev)
329
+ - [Dashboard](https://getlate.dev/dashboard)
330
+ - [Changelog](https://docs.getlate.dev/changelog)
229
331
 
230
332
  ## License
231
333