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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@crosspost/sdk

v0.3.1

Published

SDK for interacting with the Crosspost API

Downloads

144

Readme

@crosspost/sdk

SDK for interacting with the Crosspost Proxy Service.

This package is designed to be used with near-sign-verify for authenticating requests via a wallet or keypair.

Installation

bun install @crosspost/sdk

Usage

import * as near from "fastintear"; // or near-api-js for creating key pairs
import { sign } from "near-sign-verify";
import {
  CrosspostClient,
  // error handling helpers
  CrosspostError,
  isAuthError,
  isPlatformError,
  isRateLimitError,
  isValidationError
} from '@crosspost/sdk';
import type {
  ConnectedAccount,
  CreatePostRequest,
} from "@crosspost/sdk";

// Initialize the client
const client = new CrosspostClient({
  baseUrl: 'https://your-self-hosted-crosspost-api.com', // Optional: Defaults to official API
});

const authToken = await sign({ signer: near, recipient: "crosspost.near", message: "createPost" });

client.setAuthentication(authToken);
client.setAccountHeader("signer.near")

const connectedAccounts: ApiResponse<ConnectedAccountsResponse> = await client.auth.getConnectedAccounts():

try {
  const response = await await client.post.createPost({
    targets: [
      {
        userId: connectedAccounts[0].userId,
        platform: connectedAccounts[0].platform
      }
    ],
    content: [{
      text: "hello world",
      media: {
        data: imageBlob,
        mimeType: 'image/jpeg',
        altText: 'a beautiful sunset',
      }
    }]
  } as CreatePostRequest);

  console.log('Post created successfully');
  console.log('Post ID:', response.id);
  console.log('Platform:', response.platform);
  console.log('URL:', response.url);
  console.log('Created at:', response.createdAt);

} catch (error) {
  // Check if it's an authentication error
  if (isAuthError(error)) {
    console.error('Authentication required. Attempting to authorize...');
    // The account must be authorized with the backend
    const authorized = await client.auth.authorizeNearAccount();
    if (authorized) {
      // Retry the operation
      return createPost();
    }
  } else {
    // Handle other error types
    console.error('Error creating post:', error);
    if (error instanceof CrosspostError) {
      // Use error utility functions to handle specific cases
      if (isPlatformError(error)) {
        console.error('Platform:', error.platform);
        console.error('Error code:', error.code);
        console.error('Details:', error.details);
      } else if (isRateLimitError(error)) {
        console.error('Rate limited until:', error.details?.rateLimit?.reset);
      } else if (isValidationError(error)) {
        console.error('Validation errors:', error.details?.validationErrors);
      }
      // Check if error is recoverable
      if (error.recoverable) {
        console.log('This error is recoverable - retry may succeed');
      }
    } else if (error instanceof Error) {
      // Handle non-API errors (network issues, etc)
      console.error('Unexpected error:', error.message);
    }
  } 
}

Methods

  • client.setAuthentication(authToken: string): Promise<void> - Sets authentication data, necessary for non-GET requests
  • client.isAuthenticated(): boolean - Checks if client is authenticated
  • client.setAccountHeader(accountId: string): Promise<void> - Sets X-Near-Account Header, necessary for GET requests
  • client.clear(): boolean - Clears authentication and account header

Auth API (client.auth)

  • client.auth.authorizeNearAccount(): Promise<ApiResponse<NearAuthorizationResponse>> - Authorizes NEAR account
  • client.auth.unauthorizeNearAccount(): Promise<ApiResponse<NearAuthorizationResponse>> - Unauthorizes NEAR account
  • client.auth.getNearAuthorizationStatus(): Promise<ApiResponse<NearAuthorizationResponse>> - Checks authorization status for authenticated account
  • client.auth.loginToPlatform(platform, options?): Promise<AuthCallbackResponse | ApiResponse<AuthUrlResponse>> - Opens popup to initiate OAuth flow with platform
  • client.auth.refreshToken(platform): Promise<ApiResponse<AuthCallbackResponse>> - Refreshes platform token
  • client.auth.refreshProfile(platform): Promise<ApiResponse<ConnectedAccount>> - Refreshes user profile
  • client.auth.getAuthStatus(platform): Promise<ApiResponse<AuthStatusResponse>> - Gets authentication status
  • client.auth.revokeAuth(platform): Promise<ApiResponse<AuthRevokeResponse>> - Revokes platform access
  • client.auth.getConnectedAccounts(): Promise<ApiResponse<ConnectedAccountsResponse>> - Lists connected accounts

Post API (client.post)

Each post operation accepts a request object that includes:

  • targets: Array of { platform: string, userId: string } specifying where to perform the action
  • Additional parameters specific to each operation

Available methods:

  • client.post.createPost(request: CreatePostRequest): Promise<CreatePostResponse> - Creates posts on specified platforms
  • client.post.repost(request: RepostRequest): Promise<RepostResponse> - Reposts an existing post
  • client.post.quotePost(request: QuotePostRequest): Promise<QuotePostResponse> - Quotes an existing post
  • client.post.replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse> - Replies to a post
  • client.post.likePost(request: LikePostRequest): Promise<LikePostResponse> - Likes a post
  • client.post.unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse> - Unlikes a post
  • client.post.deletePost(request: DeletePostRequest): Promise<DeletePostResponse> - Deletes posts

Activity API (client.activity)

  • client.activity.getLeaderboard(options): Promise<LeaderboardResponse> - Gets activity leaderboard
  • client.activity.getAccountActivity(signerId, options): Promise<AccountActivityResponse> - Gets account activity
  • client.activity.getAccountPosts(signerId, options): Promise<AccountPostsResponse> - Gets account posts

System API (client.system)

  • client.system.getRateLimits(): Promise<RateLimitsResponse> - Gets all rate limits
  • client.system.getEndpointRateLimit(endpoint): Promise<EndpointRateLimitResponse> - Gets endpoint rate limit
  • client.system.getHealthStatus(): Promise<HealthStatusResponse> - Gets API health status

API Reference

Pagination

The SDK supports offset-based pagination for endpoints that return large collections:

// Get paginated results with specific limit and offset
const response = await client.activity.getLeaderboard({
  limit: 10, // Number of items per page
  offset: 20, // Skip the first 20 items
});

// Access pagination metadata
console.log(`Total items: ${response.meta.pagination?.total}`);
console.log(`Current page size: ${response.meta.pagination?.limit}`);
console.log(`Current offset: ${response.meta.pagination?.offset}`);

Multi-Status Responses

Post operations always return multi-status responses:

// Operation targeting multiple platforms
const response = await client.post.createPost({
  targets: [
    { platform: 'twitter', userId: 'user1' },
    { platform: 'facebook', userId: 'user2' },
  ],
  content: [{ text: 'hello world' }],
});

// Check multi-status summary
console.log(`Total operations: ${response.data.summary.total}`);
console.log(`Successful: ${response.data.summary.succeeded}`);
console.log(`Failed: ${response.data.summary.failed}`);

// Access successful results
response.data.results.forEach((result) => {
  console.log(`Success on ${result.platform}: ${result.details.id}`);
});

// Access errors (if any)
if (response.data.errors && response.data.errors.length > 0) {
  // Error structure is identical to error.details.errors when all operations fail
  response.data.errors.forEach((error) => {
    console.log(`Error on ${error.details.platform}: ${error.message}`);
    console.log(`Error code: ${error.code}`);
    console.log(`Recoverable: ${error.recoverable}`);
  });
}

If all operations fail, the SDK throws a CrosspostError with the same error structure in details.errors:

try {
  await client.post.createPost({...});
} catch (error) {
  if (error instanceof CrosspostError) {
    // Error structure is identical to response.data.errors in partial success case
    error.details.errors.forEach(err => {
      console.log(`Error on ${err.details.platform}: ${err.message}`);
      console.log(`Error code: ${err.code}`);
      console.log(`Recoverable: ${err.recoverable}`);
    });
  }
}

This consistent error structure allows you to use the same error handling logic regardless of whether you're dealing with partial failures in a multi-status response or complete failure.

Validation Error Handling

The SDK provides detailed validation error information:

try {
  await client.post.createPost({
    // Invalid or missing required fields
  });
} catch (error) {
  if (isValidationError(error)) {
    console.error('Validation failed:');

    // Access validation error details
    if (error.details?.validationErrors) {
      Object.entries(error.details.validationErrors).forEach(([field, issues]) => {
        console.error(`Field '${field}': ${issues.join(', ')}`);
      });
    }
  }
}

Error Handling Utilities

import {
  getErrorDetails,
  getErrorMessage,
  isAuthError,
  isContentError,
  isMediaError,
  isNetworkError,
  isPlatformError,
  isPostError,
  isRateLimitError,
  isRecoverableError,
  isValidationError,
} from '@crosspost/sdk';

// Check error types
if (isAuthError(error)) {
  // Handle authentication errors
}

// Get user-friendly error message
const message = getErrorMessage(error, 'Default message');

// Get error details
const details = getErrorDetails(error);

Usage Examples

Creating a Post

// Create a text post on Twitter
const textPostResponse = await client.post.createPost({
  targets: [{
    platform: 'twitter',
    userId: 'your-twitter-id',
  }],
  content: [{
    text: 'Hello from Crosspost SDK!',
  }],
});

// Create a post with media on multiple platforms
const mediaPostResponse = await client.post.createPost({
  targets: [
    { platform: 'twitter', userId: 'your-twitter-id' },
    { platform: 'facebook', userId: 'your-facebook-id' },
  ],
  content: [{
    text: 'Check out this image!',
    media: [{
      data: imageBlob,
      mimeType: 'image/jpeg',
      altText: 'A beautiful sunset',
    }],
  }],
});

Post Interactions

// Like a post on Twitter
await client.post.likePost({
  targets: [{
    platform: 'twitter',
    userId: 'your-twitter-id',
  }],
  platform: 'twitter',
  postId: '1234567890',
});

// Repost on multiple platforms
await client.post.repost({
  targets: [
    { platform: 'twitter', userId: 'your-twitter-id' },
    { platform: 'facebook', userId: 'your-facebook-id' },
  ],
  platform: 'twitter',
  postId: '1234567890',
});

// Reply to a post
await client.post.replyToPost({
  targets: [{
    platform: 'twitter',
    userId: 'your-twitter-id',
  }],
  platform: 'twitter',
  postId: '1234567890',
  content: [{
    text: 'This is a reply',
  }],
});

// Delete posts
await client.post.deletePost({
  targets: [{
    platform: 'twitter',
    userId: 'your-twitter-id',
  }],
  posts: [{
    platform: 'twitter',
    userId: 'your-twitter-id',
    postId: '1234567890',
  }],
});

Getting Activity Data

// Get leaderboard
const leaderboard = await client.activity.getLeaderboard({
  timeframe: 'week',
  limit: 10,
});

// Get account activity
const activity = await client.activity.getAccountActivity('user.near', {
  timeframe: 'month',
});

// Get account posts
const posts = await client.activity.getAccountPosts('user.near', {
  limit: 20,
  offset: 0,
});

Checking Rate Limits

// Get all rate limits
const rateLimits = await client.system.getRateLimits();

// Get rate limit for a specific endpoint
const postRateLimit = await client.system.getEndpointRateLimit('post');