@xdevplatform/xdk
v0.4.0
Published
A modern TypeScript/JavaScript SDK for the X API
Readme
TypeScript XDK
A comprehensive TypeScript SDK for the X API (formerly Twitter API) with advanced features including smart pagination, multiple authentication methods, real-time streaming, and full type safety.
Key Features
- 🔐 Authentication: User Context (OAuth1.0a, OAuth2.0), and App-Only (Bearer token) authentication
- 🔄 Pagination: Automatic pagination with async iteration support
- 📡 Streaming: Event-driven streaming with automatic reconnection
- 📚 Type Safety: Complete TypeScript definitions for all endpoints and parameters
- 🎯 Full X API Support: Users, Posts, Lists, Bookmarks, Communities, and more
- 📱 Multi-Platform: Works in Node.js, browsers, and React Native
Install
npm
npm install @xdevplatform/xdkyarn
yarn add @xdevplatform/xdkpnpm
pnpm add @xdevplatform/xdkTypeScript Support
The SDK is written in TypeScript and includes full type definitions. No additional type packages are required.
Requirements
- Node.js 16+
- TypeScript 4.5+ (if using TypeScript)
React Native Support
The SDK fully supports React Native out of the box. No additional polyfills or packages are required - just install the SDK and start using it:
import { Client } from '@xdevplatform/xdk';
const client = new Client({ bearerToken: 'your-token' });The SDK uses pure JavaScript crypto implementations that work in all environments, and React Native's built-in fetch for HTTP requests.
Browser Support
The SDK works in modern browsers (Chrome, Firefox, Safari, Edge) out of the box using the Web Crypto API and native fetch.
Quick Start
import {
Client,
type ClientConfig,
type UsersGetByUsernameResponse
} from '@xdevplatform/xdk';
const config: ClientConfig = { bearerToken: 'your-bearer-token' };
const client: Client = new Client(config);
async function main(): Promise<void> {
const userResponse: UsersGetByUsernameResponse = await client.users.getByUsername('XDevelopers');
const username: string = userResponse.data?.username!;
console.log(username);
}
main();Authentication
The TypeScript SDK supports multiple authentication methods for different use cases.
Bearer Token (App-Only Auth)
For read-only operations and public data access:
import {
Client,
type ClientConfig,
type Users
} from '@xdevplatform/xdk';
const config: ClientConfig = { bearerToken: 'your-bearer-token' };
const client: Client = new Client(config);
async function main(): Promise<void> {
const userResponse: Users.GetByUsernameResponse = await client.users.getByUsername('XDevelopers');
const username: string = userResponse.data?.username!;
console.log(username);
}
main();OAuth 1.0a (User Context)
For legacy applications or specific use cases:
import {
Client,
OAuth1,
type OAuth1Config,
type ClientConfig,
type Users
} from '@xdevplatform/xdk';
const oauth1Config: OAuth1Config = {
apiKey: 'your-api-key',
apiSecret: 'your-api-secret',
accessToken: 'user-access-token',
accessTokenSecret: 'user-access-token-secret'
};
const oauth1: OAuth1 = new OAuth1(oauth1Config);
const config: ClientConfig = {
oauth1: oauth1,
};
const client: Client = new Client(config);
async function main(): Promise<void> {
const response: Users.GetMeResponse = await client.users.getMe();
const me = response.data;
console.log(me);
}
main();
OAuth 2.0 (User Context)
For user-specific operations:
import {
Client,
OAuth2,
generateCodeVerifier,
generateCodeChallenge,
type OAuth2Config,
type ClientConfig,
type OAuth2Token
} from '@xdevplatform/xdk';
(async (): Promise<void> => {
const oauth2Config: OAuth2Config = {
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
redirectUri: 'https://example.com',
scope: ['tweet.read', 'users.read', 'offline.access'],
};
const oauth2: OAuth2 = new OAuth2(oauth2Config);
const state: string = 'example-state';
const codeVerifier: string = generateCodeVerifier();
const codeChallenge: string = await generateCodeChallenge(codeVerifier);
oauth2.setPkceParameters(codeVerifier, codeChallenge);
const authUrl: string = await oauth2.getAuthorizationUrl(state);
const tokens: OAuth2Token = await oauth2.exchangeCode(authCode, codeVerifier);
const config: ClientConfig = {
accessToken: tokens.access_token,
};
const client: Client = new Client(config);
});
Environment Variables
Store sensitive credentials in environment variables:
# .env
X_API_BEARER_TOKEN=your-bearer-token
X_API_CLIENT_ID=your-client-id
X_API_CLIENT_SECRET=your-client-secretimport { Client } from '@xdevplatform/xdk';
const client = new Client({ bearerToken: process.env.X_API_BEARER_TOKEN });Pagination
The SDK provides generic paginator utilities you can use with any endpoint that returns paginated responses. Methods return plain responses; you wrap them with a paginator.
Basic Pagination
import { Client, UserPaginator, PaginatedResponse, Schemas } from '@xdevplatform/xdk';
const client: Client = new Client({ bearerToken: 'your-bearer-token' });
// Wrap any list endpoint with proper typing
const followers: UserPaginator = new UserPaginator(
async (token?: string): Promise<PaginatedResponse<Schemas.User>> => {
const res = await client.users.getFollowers('<userId>', {
maxResults: 100,
paginationToken: token,
userfields: ['id','name','username'],
});
return {
data: res.data ?? [],
meta: res.meta,
includes: res.includes,
errors: res.errors
};
}
);Manual paging
import { UserPaginator, Schemas } from '@xdevplatform/xdk';
await followers.fetchNext(); // first page
while (!followers.done) {
await followers.fetchNext(); // subsequent pages
}
const userCount: number = followers.users.length; // all fetched users
const firstUser: Schemas.User | undefined = followers.users[0];
const nextToken: string | undefined = followers.meta?.nextToken;Async iteration
import { Schemas } from '@xdevplatform/xdk';
for await (const user of followers) {
const typedUser: Schemas.User = user;
console.log(typedUser.username); // fully typed access
}Next page as a new instance
import { UserPaginator } from '@xdevplatform/xdk';
await followers.fetchNext();
if (!followers.done) {
const page2: UserPaginator = await followers.next(); // independent paginator starting at next page
await page2.fetchNext();
console.log(page2.users.length); // items from second page
}Error handling and rate limits
import { UserPaginator, Schemas } from '@xdevplatform/xdk';
try {
for await (const item of followers) {
const user: Schemas.User = item;
// process user...
}
} catch (err: unknown) {
if (followers.rateLimited) {
console.error('Rate limited, backoff required');
// backoff / retry later
} else {
console.error('Pagination error:', err);
throw err;
}
}Streaming
The TypeScript SDK provides real-time streaming capabilities for live data feeds.
Basic Streaming
Connect to real-time sampled posts:
import { Client } from '@xdevplatform/xdk';
const client: Client = new Client({ bearerToken: 'your-bearer-token' });
// 1% sampled public posts
const stream = await client.stream.postsSample({
tweetfields: ['id','text','created_at'],
expansions: ['author_id'],
userfields: ['id','username','name']
});
// Listen to events
stream.on('data', (event) => {
// event is the parsed JSON line (data/includes/matching_rules)
console.log('New data:', event);
});
stream.on('error', (e) => console.error('Stream error:', e));
stream.on('close', () => console.log('Stream closed'));Async Iteration
Consume the stream with async iteration:
const stream = await client.stream.postsSample();
for await (const event of stream) {
// Each event is a parsed JSON line (data/includes/matching_rules)
console.log(event);
}Stream Management
Control lifecycle from the event-driven stream:
// Close the stream
stream.close();
// Auto-reconnect (if enabled by your wrapper)
// The default EventDrivenStream exposes basic reconnect hooksError Handling
Handle streaming errors and reconnections:
stream.on('error', (event) => {
const err = event.error || event;
console.error('Stream error:', err);
});
stream.on('keepAlive', () => {
// heartbeat event
});