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

@mystars-tg/faas-sdk

v0.1.5

Published

Official TypeScript SDK for the MyStars FaaS API — buy Telegram Stars & Premium for any @username, paid in TON or USDT.

Readme

@mystars-tg/faas-sdk

npm license API contract

Official TypeScript/JavaScript SDK for the MyStars FaaS API — buy Telegram Stars & Premium for any @username, paid in TON or USDT (TON).

Works in Node ≥18, Deno, Bun, Cloudflare Workers, and the browser (the core has zero crypto dependencies). The opt-in wallet module (@mystars-tg/faas-wallet) and CLI (@mystars-tg/faas-cli) ship separately.

Compatible with FaaS API v1.10.0.

📖 Full interactive API reference: mystars.tg/docs.

Install

npm install @mystars-tg/faas-sdk

Get an API key

Keys are issued inside the MyStars Telegram bot — open @my_stars_tg_bot, tap API access, and copy your X-Api-Key. No dashboard, no signup form.

Quick start

import { MyStarsClient } from "@mystars-tg/faas-sdk";

const client = MyStarsClient.production(process.env.MYSTARS_API_KEY!);

// 1. Quote the price
const quote = await client.getPricing({ type: "stars", quantity: 100, payment_currency: "ton" });
console.log(`Pay ${quote.amount} ${quote.currency}`);

// 2. (optional) Check the recipient first
const check = await client.checkRecipient({ type: "stars", recipient: { username: "durov" } });
if (!check.eligible) throw new Error(check.telegram_message ?? "recipient ineligible");

// 3. Create the order. Pass a STABLE idempotencyKey derived from your own order id
//    so a retry (even after a crash) returns the SAME order instead of a duplicate.
//    Omit it and the SDK auto-generates a uuid that only dedupes within ONE call's retries.
const order = await client.createOrder(
  {
    type: "stars",
    recipient: { username: "durov" },
    quantity: 100,
    payment_currency: "ton",
    callback_url: "https://your-app.example.com/webhooks/mystars",
  },
  { idempotencyKey: `order-${myOrderId}` },
);

// 4. Pay it: send order.payment.amount to order.payment.pay_to_address
//    with the on-chain comment order.payment.memo (the bare order UUID).
console.log(order.payment);

// 5. Track it until it's delivered (or failed/reversed/expired)
const finished = await client.waitForOrder(order.order_id, {
  onUpdate: (o) => console.log("status:", o.status),
});
console.log("done:", finished.status, finished.purchase_tx);

Set MYSTARS_API_KEY in your environment before running, or load a .env with Node's built-in flag — node --env-file=.env app.js (no extra dependency). Snippets use illustrative placeholders (myOrderId, WEBHOOK_SECRET, rawBody, req/express, …) — substitute your own values.

Errors

Every failure is a typed subclass of MyStarsApiError (itself a MyStarsError):

import { RecipientIneligibleError, RateLimitError } from "@mystars-tg/faas-sdk";

try {
  await client.createOrder({ type: "premium", recipient: { username: "durov" }, months: 3 });
} catch (err) {
  if (err instanceof RecipientIneligibleError) {
    // err.telegramMessage: the buyer-facing reason to show your user.
    // For the structured reason ("already_subscribed" | "not_found" | "ineligible"),
    // call client.checkRecipient(...) first and read its `reason`.
  } else if (err instanceof RateLimitError) {
    // err.retryAfterMs, err.kind: "general" | "order_cap"
  }
}

The client retries transient failures (network, timeout, 502/503/504, 500, and the general 429 — honoring Retry-After, capped at maxDelayMs) automatically and idempotency-safely. Configure or disable via the retry option.

Recovering a createOrder that failed

When createOrder throws you can't always tell whether the order was created server-side. The thrown MyStarsApiError carries the idempotencyKey that was used — retry with that exact key to get the idempotent replay instead of a duplicate deliverable:

try {
  await client.createOrder(params, { idempotencyKey: `order-${myOrderId}` });
} catch (err) {
  if (err instanceof MyStarsApiError && err.idempotencyKey) {
    // Safe: same key → server returns the original order (replayed:true), never a 2nd order.
    await client.createOrder(params, { idempotencyKey: err.idempotencyKey });
  }
}

Pagination

// Auto-paginate every order:
for await (const order of client.listOrders({ status: "delivered" })) {
  console.log(order.order_id);
}

// Or page-by-page:
const pager = client.listOrders({ limit: 100 });
const first = await pager.page();
const next = first.next_cursor ? await pager.page(first.next_cursor) : null;

Reference

| Method | Endpoint | |---|---| | listCurrencies() | GET /v1/currencies | | listProducts() | GET /v1/products | | getPricing(params) | GET /v1/pricing | | checkRecipient(params) | POST /v1/recipients/check | | createOrder(params, opts?) | POST /v1/orders | | listOrders(params?) | GET /v1/orders | | getOrder(id) | GET /v1/orders/:id | | cancelOrder(id) | POST /v1/orders/:id/cancel | | waitForOrder(id, opts?) | polls GET /v1/orders/:id | | reconcile(opts) | diffs listOrders vs your store to catch webhook-missed terminal transitions |

Webhooks

import { constructEvent, expressWebhook } from "@mystars-tg/faas-sdk";

// Verify manually (verify over the RAW body, then dedup on order_id):
const event = await constructEvent(rawBody, req.headers["x-faas-signature"], WEBHOOK_SECRET);

// Or use the Express adapter (mount express.raw() on the route):
app.post("/webhooks/mystars", express.raw({ type: "*/*" }), expressWebhook({
  secret: WEBHOOK_SECRET,
  onEvent: async (event) => { /* event.order_id, event.status, event.purchase_tx */ },
}));

verifyWebhookSignature / constructEvent handle the 24h secret-rotation header ("current,previous") automatically. A fastifyWebhook adapter is also exported.

Your own retail markup

import { applyRetailMarkup } from "@mystars-tg/faas-sdk";

const quote = await client.getPricing({ type: "stars", quantity: 100, payment_currency: "usdt_ton" });
const retail = applyRetailMarkup(quote, { marginPct: 15, passThroughProcessingFee: true });
// retail.total → what to charge your customer; retail.profit → your gross margin.

Uses the exact two-stage cent-ceil the server uses, so your retail math never drifts a cent.

Pay an order (non-custodial)

import { buildPaymentRequest } from "@mystars-tg/faas-sdk";

const req = buildPaymentRequest(order.payment);
// req.tonDeeplink / req.qrPayload (TON), or req.tonConnect for tonConnectUI.sendTransaction({ messages })

Holds no keys. For wallet generation + signing/broadcasting from your own wallet, see @mystars-tg/faas-wallet.