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

@jkt48connect-id/api

v1.0.1

Published

Official JKT48Connect SDK + CLI — one function call per feature. Live members, theater schedule, news, events, replays and realtime streams.

Readme

@jkt48connect/api

Official SDK for the JKT48Connect API. One function per feature — no fetch setup, no headers, no manual parsing.

npm i @jkt48connect/api

Works in Node 18+, Next.js, TypeScript and plain JavaScript (ESM + CommonJS), with full type definitions. Ships with a CLI (jkt48 / jkt48connect) for testing every endpoint straight from your terminal.

CLI

npx @jkt48connect/api live          # no install needed
jkt48 login jc_your_key             # stored in ~/.jkt48connect/config.json (chmod 600)
jkt48 members
jkt48 member JKT48-Jesslyn
jkt48 theater --page 1
jkt48 recent-detail --limit 50 --type idn --sort gold --order desc
jkt48 shipping-cost --origin 1 --destination 2 --weight 1000
jkt48 watch live                    # realtime SSE, Ctrl+C to stop
jkt48 doctor                        # connectivity + latency per endpoint
jkt48 whoami                        # masked key only, never the full value
jkt48 --help

Global flags: --api-key, --json, --pretty, --quiet, --timeout <ms>, --retries <n>, --no-cache. Output is JSON automatically when piped, so jkt48 live --json | jq '.[].name' just works. Key resolution order: --api-keyJKT48_API_KEY → stored config. Exit codes: 0 success, 1 error, 2 bad arguments, 3 unauthorized or quota exceeded.

Quick start

import { JKT48Connect } from "@jkt48connect/api";

const jkt48 = new JKT48Connect({ apiKey: process.env.JKT48_API_KEY! });

const live = await jkt48.getLive();
const members = await jkt48.getMembers();
const news = await jkt48.getNews();

CommonJS:

const { JKT48Connect } = require("@jkt48connect/api");
const jkt48 = new JKT48Connect({ apiKey: process.env.JKT48_API_KEY });

Keep your API key on the server. In Next.js call the SDK from a Server Component, Route Handler or Server Action — never from a "use client" file.

Options

new JKT48Connect({
  apiKey: "...",      // required
  timeout: 15000,     // ms per attempt (default 15000)
  retries: 2,         // retries for transient failures (default 2)
  cache: 30000,       // in-memory GET cache in ms, or false (default 30000)
  fetch: myFetch,     // custom fetch implementation
  allowBrowser: false // silence the browser warning if you proxy the key
});

Every method also takes a final { signal, timeout, cache } argument:

const ctrl = new AbortController();
await jkt48.getLive({ signal: ctrl.signal, cache: false });

Live

await jkt48.getLive();                          // members live right now
await jkt48.getTopGifter({ roomId: 123456 });   // gift leaderboard
await jkt48.getRecent();                        // sessions that just ended
await jkt48.getRecentDetail({                   // full analytics + paging
  limit: 50, offset: 0, type: "idn",
  sort: "gold", order: "desc",
  from: "2026-01-01", to: new Date(),
});

Members

await jkt48.getMembers();                 // full roster
await jkt48.getMember("JKT48-Jesslyn");   // one profile
await jkt48.getBirthdays();               // upcoming birthdays

Theater

await jkt48.getTheater({ page: 1 });      // schedule
await jkt48.getTheaterDetail("ABC123");   // setlist, lineup, ticket pricing
await jkt48.getIdnPlus();                 // paid IDN+ shows

News, events and video

await jkt48.getNews({ page: 1 });
await jkt48.getNewsDetail("some-article-slug");
await jkt48.getEvents();
await jkt48.getReplay();
await jkt48.getYoutube();

Shipping (merch)

const districts = await jkt48.getShippingDistricts("Bandung");
const rates = await jkt48.getShippingCost({
  originDistrictId: districts[0].id,
  destinationDistrictId: 1234,
  weightGram: 1000,
});

Realtime

Server-sent events with automatic reconnect. Both return a stop() function.

const stop = jkt48.onLive((event) => {
  if (event.type === "live_start") console.log(`${event.member?.name} is live!`);
});

const stopPm = jkt48.onPm((msg) => console.log(msg.member, msg.message));

// later
stop();
stopPm();

Errors

Every failure is a JKT48Error with a stable code, never a raw network error.

import { JKT48Error } from "@jkt48connect/api";

try {
  await jkt48.getMember("nope");
} catch (err) {
  if (err instanceof JKT48Error) {
    console.error(err.code);      // NOT_FOUND
    console.error(err.status);    // 404
    console.error(err.retryable); // false
  }
}

| Code | Meaning | | --- | --- | | VALIDATION | Bad argument, caught before the request is sent | | UNAUTHORIZED | Missing or invalid API key | | FORBIDDEN | Key lacks access to this feature | | NOT_FOUND | No such member, show or article | | RATE_LIMITED | Too many requests — retried automatically | | QUOTA_EXCEEDED | Plan quota reached | | TIMEOUT | Attempt exceeded timeout | | NETWORK | Connection failed | | UPSTREAM | Service-side error — retried automatically | | ABORTED | You aborted via signal | | PARSE | Unexpected response body |

RATE_LIMITED, TIMEOUT, NETWORK and UPSTREAM are retried with exponential backoff and jitter (and honour Retry-After).

Security notes

  • Connection details are resolved internally; the SDK exposes no endpoint or host constants and error messages, stacks and logs are sanitised so URLs, keys and IPs never leak.
  • Inputs are validated before any request leaves your process.
  • Zero runtime dependencies.
  • An API key shipped to a browser is readable by anyone using that page — always call the SDK from your server.

License

MIT