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

@heossihq/qnsi

v0.6.0

Published

Official Node.js / TypeScript SDK for QNSI. Typed clients for mounted vault, KMS, audit, auth, tenant, access-control, billing, crypto-inventory, storage, search, and AI routes, plus local PQC utilities and webhook verification.

Readme

@heossihq/qnsi — Node.js / TypeScript SDK for the Quantum-Native Security Infrastructure

npm version License

The official single-package Node.js / TypeScript SDK for QNSI. It exposes typed clients for the mounted vault, KMS, audit, auth, tenant, access-control, billing, crypto-inventory, storage, search, and AI routes, plus local PQC utilities and webhook verification. Cross-language SDKs are independently versioned and may expose different contracts.

Platform: https://qnsi.heossi.com · Free tier: free-forever account at https://cloud.qnsi.heossi.com/auth — 60-second signup, no credit card. Includes 10 GB PQC storage, 50 000 API calls/month, 20 KMS keys, 25 vault secrets.

Why one package?

Previous TypeScript consumers had to install up to 11 separate @heossihq/qnsi-*-sdk packages and keep their versions in sync. @heossihq/qnsi collapses that into a single dependency with sub-namespaces:

import { QnsiClient } from "@heossihq/qnsi";

const qnsi = new QnsiClient({ apiKey: process.env.QNSI_API_KEY! });

await qnsi.vault.createSecret({ ... });   // was @heossihq/qnsi-vault-sdk
await qnsi.kms.sign(keyId, data);          // was @heossihq/qnsi-kms-client
await qnsi.audit.logEvent({ ... });        // was @heossihq/qnsi-audit-sdk
await qnsi.tenant.getTenant(tenantId);     // was @heossihq/qnsi-tenant-sdk
// ...

One activation handshake on first use, shared across all 11 sub-clients. One version bump per QNSI release. One CHANGELOG. One source of truth.

Install

pnpm add @heossihq/qnsi

Requires Node.js ≥ 22.0.0. ESM-first; CommonJS consumers can await import("@heossihq/qnsi").

Quick start

import { QnsiClient } from "@heossihq/qnsi";

const qnsi = new QnsiClient({ apiKey: process.env.QNSI_API_KEY! });

// Vault — PQC-encrypted secret storage
const secret = await qnsi.vault.createSecret({
  name: "openai-api-key",
  payloadB64: Buffer.from("sk-...").toString("base64"),
  algorithm: "ml-kem-768",
});

// KMS — server-side PQC keys
const key = await qnsi.kms.createKey({ algorithm: "ml-dsa-65", purpose: "signing" });
const sig = await qnsi.kms.sign(key.keyId as string, new TextEncoder().encode("hello"));
const ok  = await qnsi.kms.verify(key.keyId as string, new TextEncoder().encode("hello"), sig);

// Audit — immutable, hash-chained event log
await qnsi.audit.logEvent({
  eventType: "model.inference",
  payload: { modelId: "gpt-4o", latencyMs: 412 },
});

// Tenant, access, billing, crypto-inventory, storage, search, ai, auth — all on one client
await qnsi.tenant.getTenant(await qnsi.tenantId());
await qnsi.access.checkPermission({ subjectId: "user-1", permission: "vault.read" });
await qnsi.billing.getEntitlements();

Modules

Each sub-namespace wraps one QNSI backend service:

| Sub-client | Wraps | Key methods | |---|---|---| | qnsi.vault | apps/vault-service (/vault/v1) | createSecret, getSecret, getSecretVersion, rotateSecret, deleteSecret, listSecretVersions | | qnsi.kms | apps/kms-service (/kms/v1) | createKey, listKeys, getKey, rotateKey, deleteKey, sign, verify, wrap, unwrap | | qnsi.audit | apps/audit-service (/audit/v1) | logEvent, ingestEvents, listEvents | | qnsi.auth | apps/auth-service (/auth) | login, refreshToken, revoke, passkey lifecycle including deletePasskey(credentialId, userId), mfaChallenge / mfaVerify, federateSAML / federateOIDC, evaluateRisk | | qnsi.tenant | apps/tenant-service (/tenant/v1) | createTenant, getTenant, updateTenant, listTenants, getCryptoPolicy, upsertCryptoPolicy, getCurrentHealth, getCurrentQuotas | | qnsi.access | apps/access-control-service (/access/v1) | createRole, getRole, listRoles, deleteRole, assignRole, revokeRoleAssignment, checkPermission | | qnsi.billing | apps/billing-service (/billing/v1) | getEntitlements, ingestMeter, ingestMeters, listInvoices, getInvoice, getCreditBalance | | qnsi.cryptoInventory | apps/crypto-inventory-service (/crypto/v1) | listAssets, getAsset, getAssetStats, discoverAssets, getReadinessScore | | qnsi.storage | apps/storage-service (/storage/v1) | putObject, getObject (returns [bytes, descriptor]), deleteObject, listObjects, listBuckets | | qnsi.search | apps/search-service (/search/v1) | createIndex, listIndexes, deleteIndex, upsertVectors, query | | qnsi.ai | apps/ai-orchestrator (/ai/v1) | model registry, deployments, workloads, inference, artifacts |

Strict write contracts

AI model registration requires modelType; deployment requires modelId and environment; workload submission requires scheduling, image, command, environment, resources, artifacts, and a signed manifest; inference uses modelDeploymentId; artifact registration uses documentId and version. Billing meters require source, meter type, quantity, unit, timestamp, and the complete security envelope; the SDK wraps both single and batch requests in { meters: [...] } and binds each meter to the activated tenant. Tenant creation requires name, slug, and a complete security envelope and uses plan; tenant updates also require the security envelope.

Verifying inbound webhooks

QNSI signs every webhook with HMAC-SHA-256. Verify the raw body before parsing JSON:

import { parseQnsiWebhook, QnsiWebhookError } from "@heossihq/qnsi";

app.post("/webhooks/qnsi", express.raw({ type: "application/json" }), (req, res) => {
  try {
    const event = parseQnsiWebhook({
      body: req.body, // raw Buffer
      signatureHeader: req.header("x-qnsp-signature") ?? "",
      timestampHeader: req.header("x-qnsp-timestamp"),
      secret: process.env.QNSI_WEBHOOK_SECRET!,
    });
    if (event.eventType === "key.rotated") {
      // ...
    }
    res.sendStatus(200);
  } catch (err) {
    if (err instanceof QnsiWebhookError) {
      res.status(400).send(err.reason);
    } else {
      throw err;
    }
  }
});

Constant-time HMAC comparison, 5-minute replay window by default (MAX_WEBHOOK_SKEW_MS), refuses payloads missing required fields.

Error handling

All errors descend from QnsiError:

| Class | When | |---|---| | QnsiNetworkError | DNS, TLS, timeout, or connection failure | | QnsiAuthError | API key rejected at activation | | QnsiApiError | A service returned 4xx/5xx with a structured body | | QnsiWebhookError | HMAC mismatch, expired timestamp, malformed body, etc. |

import { QnsiApiError, QnsiNetworkError } from "@heossihq/qnsi";

try {
  await qnsi.vault.getSecret("missing");
} catch (err) {
  if (err instanceof QnsiApiError) console.log("HTTP", err.statusCode, err.code);
  else if (err instanceof QnsiNetworkError) console.log("could not reach QNSI:", err.message);
  else throw err;
}

Activation + tier introspection

QnsiClient performs a one-shot handshake against /billing/v1/sdk/activate on first use. The result is cached in memory; subsequent calls reuse it until ~60 s before expiry. You can inspect the current activation:

await qnsi.tenantId();      // resolved tenant
await qnsi.tier();          // plan tier
await qnsi.limits();        // full limits dict
await qnsi.hasFeature("sseEnabled");  // convenience boolean

// Force the handshake at startup so you fail fast on a bad key:
await qnsi.ensureActivated();

If the activation token is rotated server-side, the SDK invalidates its cache and retries the originating request once on a 401.

Migration from per-service SDKs

The legacy per-service packages are deprecated in favour of @heossihq/qnsi. They are not being republished under the @heossihq scope; new code should use this consolidated package.

| Before | After | |---|---| | Legacy VaultClient | import { QnsiClient } from "@heossihq/qnsi" then qnsi.vault | | Legacy KmsClient | qnsi.kms | | Legacy AuthClient | qnsi.auth | | Legacy TenantClient | qnsi.tenant | | Legacy AccessControlClient | qnsi.access | | Legacy BillingClient | qnsi.billing | | Legacy CryptoInventoryClient | qnsi.cryptoInventory | | Legacy StorageClient | qnsi.storage | | Legacy SearchClient | qnsi.search | | Legacy AiOrchestratorClient | qnsi.ai | | Legacy AuditClient | qnsi.audit |

The constructor signature is simpler — one apiKey for everything, instead of a per-service config:

// One package, one activation, one client
import { QnsiClient } from "@heossihq/qnsi";

const qnsi = new QnsiClient({ apiKey });
// qnsi.vault, qnsi.kms, qnsi.audit, ... all share one connection pool + one activation cache

The historical per-service packages and @heossihq/qnsi are independently versioned. Review each typed request contract while migrating; do not assume historical packages or other language SDKs have identical wire shapes.

License

Apache-2.0. See LICENSE.