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

keyzori

v0.4.1

Published

Typed SDK for integrating applications with a Keyzori License Server.

Readme

keyzori

Typed license activation for Bun and Node.js applications.

Project | Full SDK reference | API reference


The Keyzori SDK activates a license, manages its device-bound session, sends automatic heartbeats, records named-meter usage, and releases the session cleanly.

[!NOTE] This is not a browser SDK. Keep the license secret in a trusted desktop or server runtime. Licensed product users do not need a Keyzori account or dashboard access.

Install

bun add keyzori

Quick start

import { LicenseClient, LicenseRequestError } from "keyzori";

const client = new LicenseClient({
	licenseKey: process.env.KEYZORI_LICENSE_KEY ?? "",
	serverUrl: "https://licenses.example.com",
	deviceId: process.env.KEYZORI_DEVICE_ID,
	heartbeatIntervalMs: 30_000,
	maxRetries: 3,
	requestTimeoutMs: 10_000,
});

client.events.on("ready", ({ licenseType, metadata }) => {
	console.info("License ready", licenseType, metadata.tier);
});

client.events.on("license:revoked", (reason) => {
	console.error(reason);
	process.exit(1);
});

try {
	const activation = await client.activate();
	console.info("Activated", activation.licenseType);
} catch (error) {
	if (error instanceof LicenseRequestError) {
		console.error(error.status, error.code, error.message);
	}
	throw error;
}

process.once("SIGINT", async () => {
	await client.deactivate();
	process.exit(0);
});

Attach event listeners before activate() so the initial ready event cannot be missed.

Public methods

| Method | Behavior | | --- | --- | | activate() | Starts a session and returns { licenseType, metadata } | | repeated activate() | Returns the current activation result without starting another session | | consume({ meter, units, eventId }) | Atomically consumes a positive number of named-meter units | | deactivate() | Stops heartbeats and releases the session; repeated calls share the same result |

consume() requires an active session. eventId is a per-license idempotency key: retry the same logical action with the same ID. The server returns the original result for an identical retry and rejects conflicting reuse.

const usage = await client.consume({
	meter: "exports",
	units: 1,
	eventId: crypto.randomUUID(),
});

console.info(`${usage.remaining} export units remain`);

Activation and heartbeats do not consume meter balances. Only explicit consume() calls do.

Session and security behavior

new client -> activate -> automatic heartbeat loop -> deactivate -> released
                    |                 |
                    |                 +-> refreshed type and metadata
                    +-> consume named-meter usage

The full licenseKey is sent only to POST /v1/activate. The server-issued sessionToken and hashed deviceId are used for heartbeat, usage, and deactivation requests. Session tokens are kept inside the client.

Remote server URLs must use HTTPS. Loopback HTTP is allowed for local development. Redirects are refused, requests time out, response bodies are capped at 256 KiB, and success bodies are validated before use. Automatic heartbeats never overlap. The SDK tracks the server-issued session TTL and clamps transient-error and Retry-After retries so they are attempted before the current session expires. Repeated throttling is bounded and cannot create a tight retry loop.

If deviceId is supplied, its trimmed value is SHA-256 hashed before transmission. When omitted, the SDK derives a stable digest from host operating-system and network-adapter properties. A substantial host or network change can therefore register a new device.

License types

LicenseType is the lowercase union:

type LicenseType = "lifetime" | "subscription" | "metered" | "trial";

Heartbeat results refresh the current licenseType and client-visible metadata, so operator changes take effect without restarting the product.

Events

| Event | When it fires | | --- | --- | | ready | Initial activation succeeded; receives the activation result | | heartbeat:success | Session refreshed; receives the latest activation result | | heartbeat:failed | A retryable HTTP or network failure occurred | | heartbeat:throttled | A 429 delayed the next heartbeat without a failure strike | | license:revoked | The license was revoked | | license:expired | A subscription or trial expired | | session:expired | The server-issued session is invalid or expired | | license:rejected | Another license or meter policy rejected a request | | network:offline | Consecutive heartbeat failures reached maxRetries |

Consumer event-listener exceptions are contained so they cannot interrupt license enforcement.

Errors and types

Non-success HTTP responses throw LicenseRequestError, which exposes the safe server message, HTTP status, and optional stable code. Network failures and invalid server responses throw standard Error instances.

Runtime exports are LicenseClient and LicenseRequestError. Type exports include request and result types, wire response types, event types, LicenseType, LicenseErrorCode, LicenseClientConfig, and recursive JSON metadata types.

Build and test

bun run --cwd apps/sdk typecheck
bun run --cwd apps/sdk test
bun run --cwd apps/sdk build

The package ships compiled ESM JavaScript and TypeScript declarations from dist/.