
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
swcombine-sdk
Advanced tools
Comprehensive TypeScript SDK for the Star Wars Combine API v2.0
Features • Installation • Quick Start • Documentation • Examples
Page<T> Pagination - Every list endpoint returns Page<T> with hasMore, getNextPage(), and for await...of auto-paginationnpm install swcombine-sdk
# or
yarn add swcombine-sdk
# or
pnpm add swcombine-sdk
import { SWCombine } from 'swcombine-sdk';
// Public mode (no auth)
const publicClient = new SWCombine();
// Token-only mode (use an existing token)
const tokenClient = new SWCombine({
token: process.env.SWC_ACCESS_TOKEN!,
});
// Full OAuth mode (required for OAuth flows and token refresh)
const fullClient = new SWCombine({
clientId: process.env.SWC_CLIENT_ID!,
clientSecret: process.env.SWC_CLIENT_SECRET!,
token: process.env.SWC_ACCESS_TOKEN, // Optional - string or OAuthToken object
redirectUri: 'http://localhost:3000/callback',
accessType: 'offline',
});
// Get public character information (no auth required)
const character = await publicClient.character.getByHandle({
handle: 'character-handle',
});
console.log(character.uid); // "1:12345"
console.log(character.name); // "Character Name"
// For authenticated endpoints, provide an access token
const authenticatedClient = new SWCombine({
token: process.env.SWC_ACCESS_TOKEN!,
});
// Get character details
const character = await authenticatedClient.character.get({
uid: '1:12345',
});
// Get character messages — list() returns Page<T>
const messages = await authenticatedClient.character.messages.list({
uid: '1:12345',
mode: 'received',
});
console.log(messages.total); // total messages across all pages
console.log(messages.data.length); // items on this page
const firstMessageId = messages.data[0]?.attributes.uid;
if (firstMessageId) {
const fullMessage = await authenticatedClient.character.messages.get({
uid: '1:12345',
messageId: firstMessageId,
});
console.log(fullMessage.communication);
}
// Send a message
// IMPORTANT: use receiver handle(s), not UID(s), for `receivers`
await authenticatedClient.character.messages.create({
uid: '1:12345',
receivers: 'recipient_handle',
communication: 'Test message',
});
// Get faction information
const faction = await authenticatedClient.faction.get({
uid: '20:123',
});
All list() methods return a Page<T> with built-in pagination support:
import { Page } from 'swcombine-sdk';
// Access page data and metadata
const ships = await client.inventory.entities.list({
entityType: 'ships',
uid: '1:12345',
assignType: 'owner',
});
ships.data; // Ship[] — items on this page
ships.total; // total ships across all pages
ships.hasMore; // boolean — are there more pages?
// Fetch the next page (preserves your filters)
if (ships.hasMore) {
const nextPage = await ships.getNextPage();
}
// Auto-paginate through everything with for-await
for await (const ship of await client.inventory.entities.list({...})) {
console.log(ship.name); // yields every ship across all pages
}
Use the included helper script to get an access token:
# 1. Add your credentials to .env
echo "SWC_CLIENT_ID=your_client_id" >> .env
echo "SWC_CLIENT_SECRET=your_client_secret" >> .env
# 2. Run the OAuth helper
npm run get-token
# 3. Visit http://localhost:3000 in your browser
# 4. Authorize the app and copy the token to .env
OAuth-only methods require full OAuth mode (clientId + clientSecret):
client.auth.getAuthorizationUrl(...)client.auth.handleCallback(...)client.auth.revokeToken(...)client.refreshToken()import { SWCombine, CharacterScopes, MessageScopes } from 'swcombine-sdk';
const client = new SWCombine({
clientId: 'your-client-id',
clientSecret: 'your-client-secret',
redirectUri: 'http://localhost:3000/callback',
accessType: 'offline', // Get refresh token
});
// 1. Generate authorization URL
const authUrl = client.auth.getAuthorizationUrl({
scopes: [
CharacterScopes.READ,
CharacterScopes.STATS,
MessageScopes.READ,
MessageScopes.SEND,
],
state: 'random-csrf-token',
});
// 2. Redirect user to authUrl...
// 3. Handle callback
const result = await client.auth.handleCallback(req.query);
if (result.success) {
const token = result.token!;
console.log('Access Token:', token.accessToken);
console.log('Refresh Token:', token.refreshToken);
}
import {
CharacterScopes,
MessageScopes,
Scopes,
getAllScopes,
getReadOnlyScopes,
} from 'swcombine-sdk';
// Use constants with autocomplete
const scopes = [
CharacterScopes.READ, // TypeScript suggests all scopes
CharacterScopes.STATS,
MessageScopes.SEND,
Scopes.PersonalInventory.SHIPS.READ,
];
// Or use helpers
const readOnly = getReadOnlyScopes();
const everything = getAllScopes();
See OAuth Scopes Guide for all 170+ available scopes.
The SDK provides access to all SW Combine API v2.0 resources through a fluent, type-safe interface:
| Resource | Access | Description |
|---|---|---|
client.api | Utilities | Hello world, permissions, rate limits, time conversion |
client.character | Characters | Profile, messages, skills, privileges, credits, credit log |
client.faction | Factions | Info, members, budgets, stockholders, credits, credit log |
client.galaxy | Galaxy | Systems, sectors, planets, stations, cities |
client.inventory | Inventory | Entity listing, management, tagging |
client.market | Market | Vendor listings |
client.news | News | GNS and Sim News feeds |
client.types | Types | Entity types, classes, and detailed type info |
client.events | Events | Personal, faction, inventory, and combat events |
client.location | Location | Entity location lookups |
client.datacard | Datacards | Datacard management and assignment |
Also includes a Timestamp utility for Combine Galactic Time (CGT) conversion and formatting.
For complete method signatures, parameters, and examples, see the API Reference Documentation.
The SW Combine API has a rate limit of 600 requests per hour. The SDK provides tools to monitor and handle rate limits:
// Check current rate limit status after any API call
const rateLimit = client.getRateLimitInfo();
if (rateLimit) {
console.log(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);
console.log(`Resets at: ${rateLimit.resetTime}`);
}
// Set up a callback to monitor rate limits in real-time
client.onRateLimitUpdate((info) => {
if (info.remaining < 100) {
console.warn(`Warning: Only ${info.remaining} API requests remaining!`);
}
});
// Or check via API endpoint for detailed per-endpoint limits
const limits = await client.api.rateLimits();
The SDK automatically handles rate limit errors with exponential backoff and respects the Retry-After header when provided.
import { SWCError } from 'swcombine-sdk';
try {
const character = await client.character.get({ uid: '1:12345' });
} catch (error) {
if (error instanceof SWCError) {
console.error('Status:', error.statusCode); // 404
console.error('Message:', error.message); // "Resource not found"
console.error('Type:', error.type); // "not_found"
console.error('Retryable:', error.retryable); // false
}
}
Full TypeScript support with intelligent type inference:
import { Page, Message, MessageListItem } from 'swcombine-sdk';
// Types are automatically inferred
const character = await client.character.get({ uid: '1:12345' });
// character: Character
// list() returns Page<T> with full type safety
const messages: Page<MessageListItem> = await client.character.messages.list({
uid: '1:12345',
mode: 'received', // TypeScript knows valid values: 'sent' | 'received'
});
const messageId = messages.data[0]?.attributes.uid;
if (messageId) {
const messageDetail: Message = await client.character.messages.get({
uid: '1:12345',
messageId,
});
console.log(messageDetail.communication);
}
// Send message: receivers must be handle(s), not UID(s)
await client.character.messages.create({
uid: '1:12345',
receivers: 'recipient_handle_1;recipient_handle_2',
communication: 'Hello there',
});
interface ClientConfig {
// Optional OAuth credentials
// If provided, both must be set together
clientId?: string;
clientSecret?: string;
// Optional authentication - string or full OAuthToken object
token?: string | OAuthToken;
// Optional OAuth settings
redirectUri?: string;
accessType?: 'online' | 'offline';
// Optional HTTP settings
baseURL?: string; // Default: https://www.swcombine.com/ws/v2.0/
timeout?: number; // Default: 30000 (30 seconds)
maxRetries?: number; // Default: 3
retryDelay?: number; // Default: 1000ms
debug?: boolean; // Default: false
}
interface OAuthToken {
accessToken: string;
refreshToken?: string;
expiresAt: number; // Timestamp in milliseconds
}
See the examples directory for complete working examples:
import { SWCombine } from 'swcombine-sdk';
const client = new SWCombine();
// Get character info
const character = await client.character.getByHandle({
handle: 'character-name',
});
console.log(`${character.name} (${character.uid})`);
Interactive OAuth flow to obtain access tokens:
npm run get-token
Quickly get a character's UID from their handle:
npm run get-character-uid YourHandle
npm run test:integration
# Install dependencies
npm install
# Build
npm run build
# Run unit tests (fast, no API calls)
npm test
# Run unit tests in watch mode
npm run test:watch
# Run all integration tests (requires .env with API credentials)
npm run test:integration
# Run integration tests for a specific resource
npm run test:integration:character
npm run test:integration:galaxy
npm run test:integration:faction
# Also: test:integration:api, test:integration:market, test:integration:news,
# test:integration:types, test:integration:misc
# Lint
npm run lint
# Format code
npm run format
MIT © Dreks Selmur aka JonMarkGo
Contributions are welcome! Please:
FAQs
Comprehensive TypeScript SDK for Star Wars Combine API v2.0
We found that swcombine-sdk demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.