@sentimex/ts-core-sdk
v0.1.4
Published
Core TypeScript SDK for Sentimex (REST + WS, token-based auth).
Maintainers
Readme
📦 @sentimex/ts-core-sdk
Core TypeScript SDK for building Sentimex apps and integrations (including Based mini-apps).
Provides a small, dependency-light client for JWT-based auth, REST endpoints, and a browser/Node-safe WebSocket.
Features
- 🔐 Token-first auth via
TokenManager(supportsfetchToken+refreshWith) - 🌐 Tiny REST client with automatic 401 refresh retries
- 📡 Cross-env WebSocket client (browser WebSocket or Node’s
ws) - 🧰 Strong TypeScript types included
- 🧾 ESM + CJS builds
Installation
# npm
npm install @sentimex/ts-core-sdk
# yarn
yarn add @sentimex/ts-core-sdk
# pnpm
pnpm add @sentimex/ts-core-sdkNode 18+ recommended.
Importing
import { SentimexClient, TokenManager, AuthError } from "@sentimex/ts-core-sdk";const { SentimexClient, TokenManager, AuthError } = require("@sentimex/ts-core-sdk");Quick Start
1. Create a client with token sources
You provide functions to issue and refresh access tokens.
In production, your backend should hold the API key and return short-lived JWTs to the client.
import { SentimexClient } from "@sentimex/ts-core-sdk";
const userId = "some-user-id"; // your app's user identifier (preferred user address) MUST BE CONSTANT/UNIQUE for your app
const baseUrl = "https://jkbapi.app"; // SaaS base URL
const client = new SentimexClient(
userId,
{
// Initial/placeholder tokens (SDK will call fetchToken() immediately if expired)
initial: { accessToken: "", refreshToken: "", expiresIn: 0 },
// Called when we need a *new* token (e.g., first run or refresh cannot be used)
async fetchToken() {
const r = await fetch(`${baseUrl}/private/saas/auth/terminal/issue`, {
method: "POST",
headers: {
"Content-Type": "application/json",
// In production, do NOT expose your API key here; call your own backend.
"X-Api-Key": "<YOUR_API_KEY_FOR_LOCAL_DEV_ONLY>"
},
body: JSON.stringify({ user_id: userId }),
});
const j = await r.json();
return {
accessToken: j.access_token,
refreshToken: j.refresh_token ?? "",
expiresIn: j.expires_in ?? 0,
};
},
// Called to refresh an access token using a refresh token
refresh: {
async refreshWith(refreshToken: string) {
const r = await fetch(`${baseUrl}/private/saas/auth/terminal/refresh`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Api-Key": "<YOUR_API_KEY_FOR_LOCAL_DEV_ONLY>"
},
body: JSON.stringify({ refresh_token: refreshToken }),
});
const j = await r.json();
return {
accessToken: j.access_token,
refreshToken: j.refresh_token ?? refreshToken,
expiresIn: j.expires_in ?? 0,
};
},
},
skewSeconds: 30, // refresh slightly before expiry
},
{
baseUrl, // REST base
wsUrl: "wss://jkbapi.app/v1/stream/tweets", // WebSocket base
// webSocketImpl: globalThis.WebSocket, // optional override
}
);The SDK will automatically:
- Attach
Authorization: Bearer <token>for REST - Retry once on 401 by refreshing tokens
- Refresh your token a few seconds before expiry
REST: Common Calls
All REST calls live under /private/saas/v2/terminal.
// Profile for the current user (Status shows import progress state)
const me = await client.getProfile();
// Paginated list of tracked profiles (All/Followed/Unfollowed)
const page1 = await client.getTrackedProfiles(1, 25, "follow_all");
// Search tracked profiles (server-side)
const search = await client.searchTracked("elon", 1, 25, "follow_only");
// Follow / Block (unfollow) a profile by Twitter ID
await client.followTrackedProfile("44196397"); // follow @elonmusk
await client.blockTrackedProfile("44196397"); // unfollow
// Bulk delete all blocks
await client.deleteAllBlocks();
// Count of currently-following profiles
const { following_count } = await client.getFollowingCount();
// Trigger an import by username (server builds your social graph)
await client.importByUsername("elonmusk");
// Convenience helper: import + poll profile Status until complete
const doneProfile = await client.importAndAwait("elonmusk", {
intervalMs: 3000,
maxAttempts: 15,
finalizeWaitMs: 1000,
reconnectWs: true,
onProgress({ status, attempts, lastProfile }) {
// status: 0=none, 1=mapping, 2=ready, 3=finalized
console.log("progress:", { status, attempts });
},
});
// Tweets by token (server-side token concept)
const tweets = await client.getLatestTweetsByToken("SOME_TOKEN");FollowFilter values:
"follow_all"(default)"follow_only""unfollow_only"
Types for common responses are exported (see Types below).
WebSocket
The SDK exposes a browser/Node-safe WS client.
In browsers it uses globalThis.WebSocket.
In Node it will lazy-load the ws package if no global is available.
// 1) Connect and observe connection status
await client.connect(
(msg) => {
// Receive normalized message (or raw JSON if unrecognized)
console.log("WS message:", msg);
},
(status, evt) => {
// "open" | "close" | "error"
console.log("WS status:", status);
}
);
// 2) Subscribe to a feed (server understands your filter payload)
client.subscribe({ category: "trader" });
// 3) Disconnect when done
client.disconnect();- The WS client auto-reconnects with backoff and keeps a heartbeat.
- It also sends the latest access token on open (and can force refresh if empty).
Errors
AuthErroris thrown by the REST layer when a request returns 401.- The client automatically attempts to refresh once; if the refresh also fails you’ll see the error thrown.
- Network or HTTP non-200 responses are thrown as generic
Error.
try {
const me = await client.getProfile();
} catch (e) {
if (e instanceof AuthError) {
// token refresh failed or unavailable
} else {
// network/server error
}
}Types
This SDK re-exports helpful types:
import type {
ProfileResponse,
PaginatedResponse,
TrackingProfile,
TweetData,
TweetType,
User,
Media,
WebsocketData,
FullTweetNode,
} from "@sentimex/ts-core-sdk";
import type { FollowFilter } from "@sentimex/ts-core-sdk";Helpers:
import { parseTweet, toTweetNode } from "@sentimex/ts-core-sdk";Lower-level classes if you need them:
import { HttpClient, TokenManager, WSClient, AuthError } from "@sentimex/ts-core-sdk";Tree-Shaking & Builds
- ESM:
dist/index.js - CJS:
dist/index.cjs - Types:
dist/index.d.ts - Package publishes only
dist/
Usage Notes
- Server/Client split: In production, keep your API key on your server. Expose endpoints that return short-lived JWTs (what
fetchToken/refreshWithcall). The examples useX-Api-Keyonly for local dev demonstration. - Node environments: If you run WS in Node, make sure
wsis installed (the SDK will import it automatically if needed).
Minimal Example
import { SentimexClient } from "@sentimex/ts-core-sdk";
const client = new SentimexClient("demo-user", {
initial: { accessToken: "", refreshToken: "", expiresIn: 0 },
async fetchToken() { /* …return { accessToken, refreshToken, expiresIn } */ },
refresh: { async refreshWith(rt) { /* … */ } },
});
const me = await client.getProfile();
console.log("Status:", me.Status);
await client.connect(msg => console.log("WS:", msg));
client.subscribe({ category: "custom" });License
MIT © Sentimex
