x-wrapper
v1.0.1
Published
A modular and reusable wrapper for X API v2 with rate limiting, caching, and webhooks support
Maintainers
Readme
X-Wrapper
A modular and reusable Node.js wrapper for X (Twitter) API v2 with TypeScript support.
Features
✨ Complete X API v2 Coverage
- 📝 Tweets (create, read, delete, like, retweet)
- 📸 Media uploads (images and videos with chunked upload)
- 🔔 Webhooks with built-in Express server
🚀 Advanced Features
- ⚡ Rate limiting with intelligent queue system (prioritizes writes)
- 💾 Optional in-memory caching with TTL
- 🔄 Automatic retry with exponential backoff on 5xx errors
- ✅ Strict TypeScript typing with Zod validation
- 🎯 Fluent/chainable API design
🛡️ Enterprise Ready
- Custom error handling with detailed error types
- Request timeout (3s default)
- Retry policy (3 attempts default)
- Queue management (max 3 pending requests)
Installation
npm install x-wrapperRequirements
- Node.js >= 24.0.0
- X API Bearer Token (App-only authentication)
Quick Start
import { XClient } from 'x-wrapper';
const client = new XClient({
bearerToken: 'YOUR_BEARER_TOKEN',
cache: {
enabled: true,
ttl: 5 * 60 * 1000, // 5 minutes
},
});
// Get a tweet
const tweet = await client.tweets().get('1234567890');
// Create a tweet
const newTweet = await client.tweets().create({
text: 'Hello from x-wrapper! 🚀',
});
// Upload and tweet with media
const buffer = await readFile('./image.jpg');
const mediaId = await client.media().uploadImage(buffer, 'image/jpeg');
await client.tweets().create({
text: 'Check this out!',
media: { media_ids: [mediaId] },
});
// Cleanup
await client.destroy();API Reference
Client Configuration
const client = new XClient({
bearerToken: string; // Required: X API Bearer Token
timeout?: number; // Optional: Request timeout (default: 3000ms)
maxRetries?: number; // Optional: Max retry attempts (default: 3)
cache?: {
enabled: boolean; // Enable caching (default: false)
ttl: number; // Cache TTL in ms (default: 300000 = 5min)
};
baseUrl?: string; // Optional: API base URL
uploadBaseUrl?: string; // Optional: Upload API base URL
});Tweets Resource
// Get a single tweet
const tweet = await client.tweets().get(tweetId, ['created_at', 'public_metrics']);
// Get multiple tweets
const tweets = await client.tweets().getMany(['id1', 'id2'], ['author_id']);
// Create a tweet
const tweet = await client.tweets().create({
text: 'Hello World!',
media?: { media_ids: ['123'] },
reply?: { in_reply_to_tweet_id: '456' },
quote_tweet_id?: '789',
});
// Delete a tweet
await client.tweets().delete(tweetId);
// Like a tweet
await client.tweets().like(userId, tweetId);
// Unlike a tweet
await client.tweets().unlike(userId, tweetId);
// Retweet
await client.tweets().retweet(userId, tweetId);
// Unretweet
await client.tweets().unretweet(userId, tweetId);
// Search tweets (async iterator with pagination)
for await (const tweet of client.tweets().search('javascript', { maxResults: 10 })) {
console.log(tweet.text);
}Media Resource
// Upload an image
const imageBuffer = await readFile('./image.jpg');
const mediaId = await client.media().uploadImage(imageBuffer, 'image/jpeg');
// Upload a video (automatic chunked upload)
const videoBuffer = await readFile('./video.mp4');
const mediaId = await client.media().uploadVideo(videoBuffer, 'video/mp4');Supported formats:
- Images: JPEG, PNG, WebP, GIF (max 5MB)
- Videos: MP4, QuickTime (max 512MB)
Webhooks Resource
// Register a webhook
const webhook = await client.webhooks().register('prod', 'https://example.com/webhook');
// List webhooks
const webhooks = await client.webhooks().list('prod');
// Delete a webhook
await client.webhooks().delete('prod', webhookId);
// Trigger CRC check
await client.webhooks().triggerCrc('prod', webhookId);Webhook Server
// Create webhook server
const server = client.createWebhookServer({
port: 3000,
path: '/webhook',
consumerSecret: 'YOUR_CONSUMER_SECRET',
});
// Register event handler
server.onEvent(async (event) => {
if (event.tweet_create_events) {
console.log('New tweets:', event.tweet_create_events);
}
});
// Start server
await server.start();
// Stop server
await server.stop();Error Handling
The wrapper provides custom error types:
import { XApiError, RateLimitError, AuthError, ValidationError } from 'x-wrapper';
try {
await client.tweets().create({ text: 'Hello!' });
} catch (error) {
if (error instanceof RateLimitError) {
console.log('Rate limit hit, reset at:', error.resetAt);
} else if (error instanceof AuthError) {
console.log('Authentication failed');
} else if (error instanceof ValidationError) {
console.log('Invalid data:', error.zodError);
} else if (error instanceof XApiError) {
console.log('API error:', error.statusCode, error.message);
}
}Rate Limiting
The wrapper includes an intelligent queue system:
- Max 3 requests waiting in queue
- Priority system: WRITE requests (POST, DELETE) have priority over READ requests (GET)
- Automatic blocking: Waits when rate limit is reached
- Exponential backoff: Retries on 5xx errors with backoff (1s, 2s, 4s)
// Monitor queue
console.log('Queue size:', client.getQueue().size);
// Clear queue
client.getQueue().clear();
// Check rate limits
const rateLimits = client.getRateLimits();
const info = rateLimits.get('/tweets');
console.log('Remaining requests:', info?.remaining);Caching
Optional in-memory cache with TTL:
const client = new XClient({
bearerToken: 'TOKEN',
cache: {
enabled: true,
ttl: 5 * 60 * 1000, // 5 minutes
},
});
// Cache GET requests automatically
const tweet = await client.tweets().get('123'); // Cached for 5 minutes
// Manual cache operations
client.getCache().clear();
console.log('Cache stats:', client.getCache().stats);Examples
See the /examples directory for complete examples:
basic-usage.ts- Basic tweet operationsmedia-upload.ts- Image and video uploadswebhooks.ts- Webhook server setup
License
MIT
Author
Rubz - Developer
Built with ❤️ using TypeScript, Zod, and Express
