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

license-exposed

v1.0.0

Published

TypeScript SDK for [License Exposed](https://license.exposed) — a platform for creating and validating software licenses.

Downloads

50

Readme

license-exposed

TypeScript SDK for License Exposed — a platform for creating and validating software licenses.

The SDK is lightweight, type-safe, and handles the full license lifecycle: machine attestation, periodic verification, and in-app access to the active license.

Installation

npm install license-exposed

Requires Node.js 18+ (uses native fetch and crypto).

Prerequisites

Before using the SDK you need two values from the License Exposed dashboard:

  • accessToken — a Personal Access Token (PAT) scoped to your product.
  • serverKey — the ECDH public key of your License Exposed server (base64-encoded), found in your product settings.

Quick Start

Wrap your application entry point with withLicense. On first run it will attest the machine (prompting the user to approve via a QR code / URL), then verify the license on every startup.

import { withLicense, License } from 'license-exposed';

async function main(license: License) {
    console.log('License valid, starting app…');
}

withLicense(main, {
    serverKey: '<YOUR_SERVER_KEY>',
    accessToken: '<YOUR_ACCESS_TOKEN>',
});

API

withLicense(app, options)

The primary entry point. Handles attestation (first run) and verification (every run), then calls app with the validated License.

withLicense(app: (license: License) => Promise<void> | void, options: Options & Partial<LicenseEvents>): Promise<void>

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | accessToken | string | required | Personal Access Token from the dashboard. | | serverKey | string \| Buffer | required | Server ECDH public key (base64 string or raw Buffer). | | path | string | ./license.key | File path where the attestation key is stored. | | interval | number | 900000 (15 min) | Milliseconds between background re-verifications. | | machineInfo | MachineInfo \| () => MachineInfo | auto-detected | Override machine metadata sent during verification. | | version | string \| () => string | from package.json | Application version reported during verification. | | interactive | boolean | true | When true, shows a QR code for manual approval. Set to false for headless/server environments. |

When interactive is false, you must also provide auth:

// Username/password auth
{ interactive: false, auth: { username: '[email protected]', password: 'secret' } }

// Token auth
{ interactive: false, auth: { token: 'pat_…' } }

Event hooks (all optional)

| Hook | Signature | Description | |------|-----------|-------------| | onAttestation | () => void | Called after a new machine attestation is written to disk. | | onVerify | (license: License) => void | Called after each successful license verification. | | onError | (error: KeyedError) => void | Called on any error instead of throwing. Useful for custom error UX. |

withLicense(main, {
    serverKey: '…',
    accessToken: '…',
    onAttestation: () => console.log('Machine registered!'),
    onVerify: (license) => console.log('License verified', license),
    onError: (err) => {
        console.error(`[${err.key}] ${err.message}`);
        process.exit(1);
    },
});

useLicense()

Access the active license from anywhere inside the withLicense call stack without passing it explicitly.

import { useLicense } from 'license-exposed';

function checkFeatureFlag() {
    const license = useLicense();
    // inspect license fields…
}

Throws a KeyedError("no_valid_license", …) if called outside a licensed context.


verifyAttestation(options)

Low-level function that sends a signed verification request to the License Exposed API. Used internally by withLicense; exposed for advanced use cases where you manage attestation yourself.

import { verifyAttestation, LicenseAttestation } from 'license-exposed';

const attestation = LicenseAttestation.fromFile('./license.key');
const license = await verifyAttestation({
    attestation,
    serverKey: '<YOUR_SERVER_KEY>',
    accessToken: '<YOUR_ACCESS_TOKEN>',
});

Attestation Strategies

When a license.key file does not yet exist, withLicense runs attestation to register the machine. Three strategies are available:

Interactive (default)

Prints a QR code and approval URL to the terminal. The end user (or an operator) opens the URL in a browser to approve the machine. Suited for desktop CLIs and developer tools.

withLicense(main, {
    serverKey: '…',
    accessToken: '…',
    // interactive: true  ← default
});

Non-interactive (username/password or token)

For server environments where no human is present. Pass credentials directly.

withLicense(main, {
    serverKey: '…',
    accessToken: '…',
    interactive: false,
    auth: { username: '[email protected]', password: 'secret' },
});

Note: Login-based attestation is not yet fully implemented and will throw a not_implemented error. Use the interactive strategy or CryptoLens migration for now.

CryptoLens migration

If you are migrating from Cryptolens, pass a cryptoLensKey alongside the standard options. The SDK will use your existing Cryptolens license key to bootstrap attestation.

withLicense(main, {
    serverKey: '…',
    accessToken: '…',
    cryptoLensKey: '<YOUR_CRYPTOLENS_KEY>',
});

Error Handling

All SDK errors are instances of KeyedError:

import { KeyedError } from 'license-exposed';

class KeyedError extends Error {
    key: string;   // machine-readable snake_case code
    message: string;
    cause?: Error;
}

Common error keys:

| Key | Meaning | |-----|---------| | invalid_configuration | A required option is missing or invalid. | | attestation_initiate_failed | Could not start the attestation flow with the server. | | attestation_timeout | User did not approve the machine within ~4 minutes. | | attestation_failed | Machine was rejected or attestation otherwise failed. | | verification_failed | The server rejected the verification request. | | no_valid_license | useLicense() was called outside a licensed context. |


Custom Machine Info

By default the SDK collects machineId, hostname, os, and arch automatically. Override any or all fields:

withLicense(main, {
    serverKey: '…',
    accessToken: '…',
    machineInfo: {
        machineId: 'my-custom-id',
        os: 'linux',
        arch: 'x64',
    },
    // or lazily:
    // machineInfo: () => fetchMachineInfoFromEnv(),
});

License Key File

The attestation key is written to ./license.key (configurable via path). This file contains the machine's private ECDH key and attestation ID. It should be:

  • Excluded from version control (add to .gitignore).
  • Kept on disk between runs — deleting it triggers a new attestation flow.
  • Not shared between machines — each machine needs its own key.