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

@licenseseat/tauri-plugin

v0.6.0

Published

Tauri plugin for LicenseSeat software licensing

Readme

LicenseSeat for Tauri 2

Native Tauri 2 plugin and typed JavaScript bindings for the LicenseSeat Rust SDK.

The Rust plugin owns durable state, network/crypto work, restoration, and background tasks. The JavaScript package exposes commands, normalized errors, stable state snapshots, and serialized subscriptions for the renderer.

Requirements

  • Rust 1.88+
  • Tauri 2
  • Node 18+ for building the JavaScript package
  • @tauri-apps/api >=2 <3
  • a publishable LicenseSeat pk_* key

An sk_* secret key is rejected during plugin setup. Secret keys must remain on a server.

Install and register

cargo add tauri-plugin-licenseseat
npm add @licenseseat/tauri-plugin
fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_licenseseat::init())
        .run(tauri::generate_context!())
        .expect("failed to run Tauri application");
}

Production configuration

{
  "plugins": {
    "licenseseat": {
      "apiKey": "pk_live_your_publishable_key",
      "productSlug": "your-product",
      "signingPublicKey": "BASE64_ED25519_PUBLIC_KEY",
      "signingKeyId": "production-key-v1",
      "offlineFallbackMode": "networkOnly",
      "telemetryEnabled": true,
      "sendFingerprintComponents": false,
      "emitFrontendEvents": true
    }
  }
}

The default storage directory is app_data_dir()/licenseseat, which gives each Tauri application an app-scoped location. The core SDK applies an additional product-scoped prefix.

Release builds reject "$VARIABLE" runtime placeholders for trust configuration. Client keys and signing keys are public material and should be compiled into the signed application/config generated by the release pipeline. Runtime environment expansion remains available in debug builds for local development.

Configuration reference

All durations are seconds.

| JSON field | Default | Notes | | --- | --- | --- | | apiKey | required | Publishable key; sk_* rejected | | productSlug | required | Product identity | | apiBaseUrl | LicenseSeat production API | Remote URLs require HTTPS | | storagePrefix | product-scoped default | Filename-normalized | | storagePath | app data licenseseat/ | Preflighted before plugin startup completes | | deviceIdentifier | durable random UUID | Explicit installation override | | sendFingerprintComponents | false | Opt-in raw hostname/hardware component collection | | signingPublicKey / signingKeyId | none | Pin both for offline startup | | autoValidateInterval | 3600 | Zero disables | | heartbeatInterval | 300 | Zero disables | | networkRecheckInterval | 30 | Zero disables | | timeoutSeconds | 30 | Must be greater than zero | | maxRetries | 3 | Retryable availability failures only | | retryDelaySeconds | 1 | Exponential delay is capped | | verifySsl | true | May be false only for loopback development | | offlineFallbackMode | networkOnly | Canonical values: networkOnly, always; documented legacy aliases remain accepted | | maxOfflineDays | 0 | No extra host-age cap; signed expiry still applies | | maxClockSkewSeconds | 300 | Signed artifact time checks | | offlineTokenRefreshInterval | 259200 | Zero disables all periodic artifact refresh | | enableLegacyOfflineTokens | false | Machine files remain preferred | | telemetryEnabled | true | OS/SDK/app/coarse-capacity/locale fields | | debug | false | Sensitive fields stay redacted | | emitFrontendEvents | true | Set false for a native-facade integration; native Rust subscribers are unaffected | | appVersion | Tauri package version | Telemetry | | appBuild | none | Telemetry |

Unknown fallback spellings fail setup rather than silently changing policy. networkOnly permits signed fallback only after transport/timeout/408/5xx availability failure. always additionally permits it after 429. Neither overrides authentication, configuration, ordinary client/business, malformed-response, identity-binding, or local race errors.

Capabilities and least privilege

No renderer command is usable until its Tauri capability grants permission.

Default application surface

{
  "identifier": "main",
  "windows": ["main"],
  "permissions": ["licenseseat:default"]
}

licenseseat:default grants ordinary activation, validation, deactivation, heartbeat, restoration, health, status/state, fingerprint, license, and entitlement commands. It does not grant raw offline artifacts, explicit arbitrary key/fingerprint operations, destructive reset, detailed diagnostics, or release/download commands.

Optional permission sets

| Set | Commands and exposure | | --- | --- | | licenseseat:diagnostics | health, detailed admin snapshot; may reveal cached license/artifact data and local paths, but not raw API/signing keys | | licenseseat:advanced-lifecycle | explicit validateKey, deactivateKey, heartbeatKey, and destructive reset | | licenseseat:offline-management | raw machine-file/token checkout, verification, signing-key lookup, and refresh | | licenseseat:releases | release listing/latest lookup and license-bound download-token generation |

Grant sets only to the windows/webviews that require them. Do not combine LicenseSeat capabilities with untrusted remote web content.

The generic frontend surface necessarily sees a user-entered license key and can retrieve license state. For a higher-assurance product, register the plugin/core SDK natively with emitFrontendEvents: false, grant no generic LicenseSeat permissions to the renderer, and expose a small app-specific Rust command facade that returns redacted state and performs entitlement checks again around native value-producing operations. Disabling the bridge prevents raw generic lifecycle payloads from being broadcast to renderers; native LicenseSeat::subscribe() consumers still receive the full event stream.

Typed compile-time configuration is also available when release trust material is injected by the build pipeline:

let config = tauri_plugin_licenseseat::PluginConfig {
    api_key: env!("LICENSESEAT_API_KEY").into(),
    product_slug: "your-product".into(),
    signing_public_key: Some(env!("LICENSESEAT_SIGNING_PUBLIC_KEY").into()),
    signing_key_id: Some(env!("LICENSESEAT_SIGNING_KEY_ID").into()),
    emit_frontend_events: Some(false),
    ..Default::default()
};

tauri::Builder::default()
    .plugin(tauri_plugin_licenseseat::init_with_config(config));

init_with_config replaces the optional JSON plugin configuration rather than merging two sources of truth. These values are public client configuration embedded in the application, not secrets.

Startup and state

Plugin setup:

  1. validates configuration and durable storage;
  2. constructs the core SDK with LicenseSeat::try_new;
  3. starts a resilient native-to-Tauri event bridge;
  4. manages the SDK in Tauri state;
  5. asynchronously calls the idempotent restore_license.

Persisted unsigned online state is pending after restart and grants no entitlements until current online or pinned-key signed-offline verification establishes trust.

import {
  bootstrapState,
  stateHasEntitlement,
  subscribeState,
  type LicenseSeatState,
} from '@licenseseat/tauri-plugin';

let state: LicenseSeatState = await bootstrapState();

const unsubscribe = await subscribeState(
  ({ eventName, state: nextState }) => {
    state = nextState;
    updateUi({
      status: state.clientStatus,
      paid: stateHasEntitlement(state, 'pro-features'),
      source: eventName,
    });
  },
  {
    emitCurrent: true,
    onError: (error) => reportError(error),
  },
);

bootstrapState() calls the idempotent native restore and returns the latest observable state. It defaults validateIfActivated to false, avoiding duplicate validation with plugin setup. Pass true only when an explicit extra online validation is desired.

subscribeState serializes refresh and handler delivery so slow async handlers cannot overlap or observe snapshots out of order. The native getState() response is itself derived from one coherent core SDK state observation, and heartbeat grant changes are included in the default refresh events. Handler/get-state failures are normalized and sent to onError; one failure does not kill future deliveries. Unsubscribe stops new delivery, removes every native listener, and drains the already queued work.

Because the underlying event bus may interleave network and background events, always treat getState() as the snapshot source of truth.

Activation and entitlement gating

import {
  activateAndGetState,
  checkEntitlement,
  hasEntitlement,
} from '@licenseseat/tauri-plugin';

const state = await activateAndGetState(customerLicenseKey, {
  deviceName: 'Jane’s Mac',
});

if (await hasEntitlement('cloud-sync')) {
  enableCloudSyncUi();
}

const detail = await checkEntitlement('cloud-sync');
// reason: 'nolicense' | 'invalidlicense' | 'notfound' | 'expired' | undefined

Activation immediately establishes a trusted online grant. activateAndGetState performs no additional validation request — the activation response already contains the validated grant — and simply returns one getState() snapshot read after the activation succeeds.

Use hasEntitlement, checkEntitlement, getEntitlements, or the entitlement fields in getState. Do not gate from getLicense or raw validation.license.activeEntitlements; diagnostic data can exist while the process is pending/untrusted.

Paid native operations should repeat the entitlement check inside Rust. Hiding a button in JavaScript is not a security boundary.

API groups

State and lifecycle

  • activate, activateAndGetState
  • validate, deactivate, heartbeat
  • restoreLicense, restoreAndGetState, bootstrapState
  • getState, getStatus, getClientStatus, getLicense
  • isOnline, health, getFingerprint
  • checkEntitlement, hasEntitlement, getEntitlements
  • state-only helpers stateHasEntitlement, stateHasAnyEntitlement, stateHasAllEntitlements

Advanced lifecycle

  • validateKey
  • deactivateKey
  • heartbeatKey
  • reset

Fingerprint aliases (fingerprint, deviceId, deviceFingerprint) must agree if more than one is provided. Ambiguous input fails locally.

Offline management

  • checkoutMachineFile
  • verifyMachineFile
  • syncOfflineAssets
  • fetchSigningKey
  • legacy generateOfflineToken / verifyOfflineToken

Machine files are fetched and verified before cache commit. They are bound to license, product, activation, and installation and constrained by signed/host time policies. A fetched signing key works for the current online process but is not a cross-process trust anchor; pin the key pair in production.

Raw hardware components are omitted by default. fingerprintComponents opts in for one checkout; sendFingerprintComponents opts in for automatic checkouts.

Releases

  • getLatestRelease
  • listReleases
  • generateDownloadToken

These validate returned product/channel/platform metadata and expiry. They do not package, sign, download, hash-verify, install, restart, roll back, or stage updates.

Events

LICENSESEAT_EVENTS contains the typed event-name constants, and listenEvent registers a raw listener. LICENSESEAT_STATE_EVENTS is the curated set that triggers subscribeState refreshes.

Event names use licenseseat:// and include lifecycle, offline artifact, offline validation, auto-validation, network, revocation, reset, and SDK error events. Event payloads are structured license/validation/error/message/timestamp data where available.

The bridge handles Tokio broadcast lag by warning and continuing rather than terminating permanently. Consumers should resynchronize through getState after any suspected gap.

Events are not gated by the plugin permission system. The bridge emits through Tauri's global event system, and listening requires only core:event:allow-listen (part of core:default) — no licenseseat:* permission. Any window holding core defaults can therefore observe every bridged payload, including activation-success/license-loaded payloads that carry the license key. If any window renders remote or third-party content, set emitFrontendEvents: false and have trusted windows poll getState, or withhold core:event:allow-listen from that window's capability. The native-facade pattern above avoids the exposure entirely.

Error handling

Every command rejects with a normalized LicenseSeatPluginError:

import {
  activate,
  normalizeError,
  type LicenseSeatPluginError,
} from '@licenseseat/tauri-plugin';

try {
  await activate(customerLicenseKey);
} catch (cause) {
  const error: LicenseSeatPluginError = normalizeError(cause);
  console.error(error.code, error.message, error.status, error.cause);
}

Normalization handles Error objects, strings, structured objects, nested Tauri payloads, and nested JSON strings with a bounded recursion depth. API messages and transport errors are already sanitized/bounded by the Rust layer, and request URLs containing license keys are removed.

Admin diagnostics

getAdminSnapshot is diagnostic and non-authoritative. It includes redacted configuration, runtime scheduling/connectivity information, cached state/artifacts, signing-key metadata, trusted-license source, and cache paths. It never returns the configured API key or signing private material; nevertheless, restrict licenseseat:diagnostics because the snapshot can contain customer license/artifact data and filesystem paths.

Build and verify

# Rust side, from the workspace root
cargo test -p tauri-plugin-licenseseat --all-features
cargo clippy --workspace --all-targets --all-features -- -D warnings

# JavaScript side
cd crates/tauri-plugin-licenseseat
npm ci
npm test
npm run pack:check

npm test compiles TypeScript and runs tests for error normalization, bounded nested payload handling, serialized state delivery, handler-error recovery, and unsubscribe behavior. pack:check verifies the publishable npm contents without publishing.

See the workspace production hardening audit for the complete threat model and release evidence.