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

@lessotp/sdk

v0.2.0

Published

LessOTP Inbound Phone Authentication client SDK for JavaScript, Bun, and Node. WhatsApp and Telegram channels.

Readme

LessOTP JavaScript / Bun / Node SDK

Client for the LessOTP Inbound Phone Authentication API.

Supported channels:

  • WhatsApp — inbound /START {code} phone verification.
  • Telegram — bot /start {code} plus official Share phone number contact verification.

Install

npm install @lessotp/sdk
bun add @lessotp/sdk
pnpm add @lessotp/sdk

Usage

import { LessOTPClient, parseVerifiedWebhook } from "@lessotp/sdk";

// production (default)
const client = new LessOTPClient({ apiKey: process.env.LESSOTP_API_KEY! });

// staging
const staging = new LessOTPClient({
  apiKey: process.env.LESSOTP_STAGING_API_KEY!,
  environment: "staging",
});

// WhatsApp strict (legacy-compatible)
const whatsappStrict = await client.authRequest("6281234567890");
console.log(whatsappStrict.channel, whatsappStrict.waLink);

// WhatsApp frictionless (legacy-compatible)
const whatsappFrictionless = await client.authRequest();

// Telegram strict
const telegramStrict = await client.requestAuth({
  channel: "telegram",
  phoneNumber: "6281234567890",
});
if (telegramStrict.channel === "telegram") {
  console.log(telegramStrict.telegramLink, telegramStrict.telegramText);
}

// Telegram frictionless: user shares phone number via Telegram contact button
const telegramFrictionless = await client.requestAuth({ channel: "telegram" });

// per-call environment override
const oneOff = await client.requestAuth({
  channel: "telegram",
  phoneNumber: "6281234567890",
  environment: "staging",
});

// webhook receiver
const event = await parseVerifiedWebhook(
  req.rawBody.toString("utf8"),
  req.header("x-signature"),
  process.env.LESSOTP_WEBHOOK_SECRET!,
);
if (!event) return res.status(403).end();

console.log(event.channel, event.requestId, event.phoneNumber);
if (event.channel === "telegram") {
  console.log(event.telegramUserId, event.telegramUsername);
}

void staging;
void whatsappFrictionless;
void telegramFrictionless;
void oneOff;

API

new LessOTPClient({ apiKey, environment?, baseUrl?, timeoutMs?, fetch? })

Options follow the same order as the Go SDK: apiKey → environment → baseUrl → timeout → custom transport.

| Option | Default | Description | | --- | --- | --- | | apiKey | required | App API key. | | environment | "production" | "production" or "staging". | | baseUrl | https://api.lessotp.com | API host. | | timeoutMs | 10000 | HTTP timeout. | | fetch | global fetch | Custom fetcher for testing. |

client.authRequest(phoneNumber?, options?): Promise<AuthRequestResult>

Legacy-compatible convenience method. Defaults to WhatsApp.

await client.authRequest("6281234567890"); // WhatsApp strict
await client.authRequest(); // WhatsApp frictionless
await client.authRequest("6281234567890", { environment: "staging" });

client.requestAuth(options): Promise<AuthRequestResult>

Multi-channel request method.

await client.requestAuth({ channel: "whatsapp", phoneNumber: "6281234567890" });
await client.requestAuth({ channel: "telegram", phoneNumber: "6281234567890" });
await client.requestAuth({ channel: "telegram" }); // Telegram frictionless
type AuthRequestResult =
  | {
      channel: "whatsapp";
      requestId: string;
      uniqueCode: string;
      waLink: string;
      expiresIn: number;
      mode: "strict" | "frictionless";
    }
  | {
      channel: "telegram";
      requestId: string;
      uniqueCode: string;
      telegramLink: string;
      telegramText: string;
      expiresIn: number;
      mode: "strict" | "frictionless";
    };

Telegram note: LessOTP only accepts phone numbers shared through Telegram's official contact-sharing button. The platform verifies the shared contact belongs to the Telegram sender.

verifyWebhookSignature(rawBody, signatureHeader, secret): Promise<boolean>

Constant-time HMAC-SHA256 verification. Accepts raw hex and sha256= prefixed values.

parseVerifiedWebhook(rawBody, signatureHeader, secret): Promise<VerificationSuccessEvent | null>

Returns the parsed payload if the signature is valid; null otherwise.

type VerificationSuccessEvent =
  | {
      event: "verification.success";
      channel: "whatsapp";
      requestId: string;
      phoneNumber: string;
      timestamp?: string;
    }
  | {
      event: "verification.success";
      channel: "telegram";
      requestId: string;
      phoneNumber: string;
      telegramUserId?: string;
      telegramUsername?: string | null;
      timestamp?: string;
    };

Errors

Throws LessOTPError on transport, auth, or payload problems.

Tests

bun install
bun test
bun run build