@bernierllc/social-media-twitter
v1.2.0
Published
Twitter/X API v2 integration service with OAuth 2.0, content posting, scheduling, and rate limiting
Readme
@bernierllc/social-media-twitter
Twitter/X API v2 integration service with OAuth 2.0 authentication, content posting, scheduling, and rate limit management.
Installation
npm install @bernierllc/social-media-twitterFeatures
- OAuth 2.0 Authentication: Complete OAuth flow with PKCE support
- Tweet Posting: Post tweets with text, media, polls, and geo
- Thread Creation: Post multi-tweet threads automatically linked
- Media Upload: Support for images, GIFs, and videos with chunked upload
- Tweet Scheduling: Schedule tweets for future posting
- Interactions: Like, unlike, retweet, quote tweet, and reply
- Rate Limit Management: Automatic rate limit tracking and handling
- Token Management: Optional token storage with refresh support
Usage
Basic Setup
import { TwitterService } from '@bernierllc/social-media-twitter';
const twitter = new TwitterService({
clientId: process.env.TWITTER_CLIENT_ID!,
clientSecret: process.env.TWITTER_CLIENT_SECRET!,
callbackUrl: 'https://yourapp.com/auth/twitter/callback',
scopes: ['tweet.read', 'tweet.write', 'users.read', 'offline.access'],
});OAuth 2.0 Authentication
// 1. Generate authorization URL
const authUrl = await twitter.getAuthorizationUrl();
// Redirect user to authUrl
// 2. Handle callback
const result = await twitter.handleCallback(code, state);
if (result.success) {
console.log(`Authenticated as @${result.user?.username}`);
}
// 3. Refresh token when needed
const refreshed = await twitter.refreshAccessToken(credentials.refreshToken!);Posting Tweets
// Simple tweet
const result = await twitter.postTweet({
text: 'Hello from @bernierllc/social-media-twitter!',
});
console.log(`Tweet posted: ${result.url}`);
// Tweet with media
const mediaResult = await twitter.uploadMedia({
data: imageBuffer,
mimeType: 'image/jpeg',
category: 'tweet_image',
altText: 'A beautiful sunset',
});
const tweetWithMedia = await twitter.postTweet({
text: 'Check out this photo!',
media: [{ mediaId: mediaResult.mediaId! }],
});
// Tweet with poll
const pollTweet = await twitter.postTweet({
text: 'What do you prefer?',
poll: {
options: ['Option A', 'Option B', 'Option C'],
durationMinutes: 1440, // 24 hours
},
});Posting Threads
const thread = await twitter.postThread([
{ text: '1/3 This is the first tweet in a thread...' },
{ text: '2/3 This is the continuation...' },
{ text: '3/3 And this is the conclusion!' },
]);
console.log(`Thread posted with ${thread.tweets?.length} tweets`);
console.log(`Thread ID: ${thread.threadId}`);Scheduling Tweets
// Schedule for 1 hour from now
const scheduled = await twitter.scheduleTweet(
{ text: 'This is a scheduled tweet!' },
new Date(Date.now() + 60 * 60 * 1000)
);
console.log(`Tweet scheduled for ${scheduled.scheduledFor}`);
console.log(`Schedule ID: ${scheduled.scheduleId}`);
// List scheduled tweets
const pending = await twitter.listScheduledTweets();
// Cancel scheduled tweet
await twitter.cancelScheduledTweet(scheduled.scheduleId!);Interactions
// Reply to a tweet
const reply = await twitter.replyToTweet('original_tweet_id', {
text: 'Great point!',
});
// Quote tweet
const quote = await twitter.quoteTweet('original_tweet_id', {
text: 'This is an interesting take:',
});
// Retweet
await twitter.retweet('tweet_id');
// Like/Unlike
await twitter.likeTweet('tweet_id');
await twitter.unlikeTweet('tweet_id');
// Delete tweet
await twitter.deleteTweet('tweet_id');User Information
// Get current authenticated user
const me = await twitter.getCurrentUser();
console.log(`@${me.username} - ${me.followersCount} followers`);
// Get user by username
const user = await twitter.getUserInfo('elonmusk');Rate Limit Handling
// Configure rate limit strategy
const twitter = new TwitterService({
// ... other config
rateLimitConfig: {
enabled: true,
strategy: 'wait', // 'wait' | 'queue' | 'fail'
maxRetries: 3,
},
});
// Check rate limit status
const status = twitter.getRateLimitStatus('POST /2/tweets');
console.log(`${status.remaining}/${status.limit} requests remaining`);
console.log(`Resets at: ${status.reset}`);
// Manually wait for rate limit
await twitter.waitForRateLimit('POST /2/tweets');Token Storage
import { TokenStorage } from '@bernierllc/social-media-twitter';
// Implement custom token storage
const tokenStorage: TokenStorage = {
async store(key, credentials) {
await myDatabase.set(key, JSON.stringify(credentials));
},
async retrieve(key) {
const data = await myDatabase.get(key);
return data ? JSON.parse(data) : null;
},
async delete(key) {
await myDatabase.delete(key);
},
};
const twitter = new TwitterService({
// ... other config
tokenStorage,
});
// Or set later
twitter.setTokenStorage(tokenStorage);Connection Testing
// Verify credentials are valid
const isValid = await twitter.verifyCredentials();
// Full connection test
const test = await twitter.testConnection();
if (test.success) {
console.log(`Connected as @${test.user?.username}`);
console.log('Rate limits:', test.rateLimits);
}API Reference
TwitterServiceConfig
| Property | Type | Description | |----------|------|-------------| | clientId | string | Twitter API client ID | | clientSecret | string | Twitter API client secret | | callbackUrl | string | OAuth callback URL | | scopes | string[] | OAuth scopes (default: tweet.read, tweet.write, users.read, offline.access) | | rateLimitConfig | RateLimitConfig | Rate limit handling configuration | | mediaConfig | MediaConfig | Media upload configuration | | tokenStorage | TokenStorage | Token persistence adapter | | debug | boolean | Enable debug logging |
RateLimitConfig
| Property | Type | Description | |----------|------|-------------| | enabled | boolean | Enable rate limit handling | | strategy | 'wait' | 'queue' | 'fail' | Strategy when rate limit is hit | | maxRetries | number | Maximum retries before failing |
MediaConfig
| Property | Type | Description | |----------|------|-------------| | chunkSize | number | Chunk size for chunked uploads (default: 5MB) | | maxConcurrentUploads | number | Maximum concurrent uploads (default: 3) |
Media Upload Limits
| Type | Max Size | Formats | |------|----------|---------| | Image | 5MB | JPEG, PNG, GIF, WebP | | GIF | 15MB | GIF | | Video | 512MB | MP4, QuickTime |
Rate Limits (Twitter API v2)
| Endpoint | User Context | App Context | |----------|--------------|-------------| | POST /2/tweets | 200/15min | 50/15min | | DELETE /2/tweets/:id | 50/15min | 50/15min | | POST /2/users/:id/retweets | 50/15min | 50/15min | | POST /2/users/:id/likes | 50/15min | 50/15min | | GET /2/users/me | 75/15min | 75/15min |
Security
API Credentials
- Never hardcode client ID/secret - use environment variables
- Store tokens securely using encrypted storage
- Implement token refresh to avoid re-authentication
OAuth Security
- PKCE support built-in for authorization code flow
- State verification prevents CSRF attacks
- Automatic state cleanup for expired auth attempts
Integration Status
- Logger: Planned for v1.1.0
- NeverHub: Planned for v1.2.0
- Docs-Suite: Ready (TypeDoc format)
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
