npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@xdevplatform/xdk

v0.3.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

Install

npm

npm install @xdevplatform/xdk

yarn

yarn add @xdevplatform/xdk

pnpm

pnpm add @xdevplatform/xdk

TypeScript 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)

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-secret
import { 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?.next_token;

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 hooks

Error 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
});