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

@nodatachat/sdk

v1.0.0

Published

NoData M2M SDK — Blind relay encryption, secure channels, and zero-knowledge delivery for machine-to-machine communication.

Readme

@nodatachat/sdk

Your server should never see what it doesn't need to know.

NoData is a blind relay. Data passes through — encrypted, audited, untouched. Your server stores ciphertext. NoData stores nothing. Not the key. Not the plaintext. Not even metadata about what was encrypted.

One package. Five lines. Full SOC compliance.


Install

npm install @nodatachat/sdk

Zero dependencies. Works in Node.js, Bun, Deno, Cloudflare Workers, and any runtime with fetch.


Quick start

import { NoData } from '@nodatachat/sdk';

const nd = new NoData({ apiKey: 'sk_live_...' });

// Encrypt a credit card — server-blind
const { ciphertext } = await nd.encrypt({
  field: 'credit_card',
  value: '4111111111111111',
});

// Store `ciphertext` in YOUR database. NoData stores nothing.

// Later — decrypt
const { value } = await nd.decrypt({
  field: 'credit_card',
  ciphertext,
  requester: 'billing-service',
});

That's it. AES-256-GCM. Audit trail. Zero plaintext on any server.


What this does

| You call | What happens | What NoData stores | |----------|-------------|-------------------| | nd.encrypt() | AES-256-GCM encryption, key material returned to you | Nothing | | nd.decrypt() | Decryption, audit log entry created | Metadata only (who, when, which field) | | nd.channel.create() | Encrypted tunnel between two systems | Channel metadata, no content | | nd.deliver.send() | Burn-after-read secret delivery | Encrypted blob, deleted on read | | nd.evidence.query() | Returns audit trail for compliance | - |


Batch — 100 fields, one call

const result = await nd.batchNative([
  { op: 'encrypt', field: 'phone',  value: '0501234567' },
  { op: 'encrypt', field: 'email',  value: '[email protected]' },
  { op: 'encrypt', field: 'id',     value: '123456789' },
  { op: 'decrypt', field: 'ssn',    ciphertext: 'aes256gcm:v1:...' },
]);
// result.ok === 4, result.failed === 0

Or encrypt an entire object — deep walk, nested fields included:

const customer = {
  name: 'David',
  phone: '0501234567',
  email: '[email protected]',
  address: { street: '123 Main', city: 'Tel Aviv' },
  age: 30,
};

const encrypted = await nd.encryptObject(customer, ['phone', 'email']);
// { name: 'David', phone: 'aes256gcm:v1:...', email: 'aes256gcm:v1:...', address: {...}, age: 30 }

Secure channels — system to system

Two systems need to exchange sensitive data. Neither trusts the other's infrastructure.

// System A — creates a channel
const ch = await nd.channel.create({
  ttl: '1h',
  requireVerification: true,
});
// Share ch.channel_token with System B
// Share ch.verification_code with the human approver

// System B — sends the data
await nd.channel.send({
  token: ch.channel_token,
  data: { card: '4111111111111111', cvv: '123', exp: '12/28' },
  burnAfterRead: true,
});

// System A — receives
const result = await nd.channel.receive({
  token: ch.channel_token,
  verificationCode: '482901',
});
const card = JSON.parse(result.data);

The server relays encrypted bytes. It never sees the card number.


Burn-after-read delivery

Send a secret. Recipient opens the link. Content self-destructs.

const d = await nd.deliver.send({
  content: 'DATABASE_PASSWORD=s3cr3t_p@ss!',
  ttl: '30m',
  burn: true,
  maxViews: 1,
});

console.log(d.delivery_url);
// https://www.nodatachat.com/d/abc123
// Opened once → gone forever

Webhooks — encrypted at rest

Receive webhooks from Stripe, Twilio, or any service. Payloads encrypted before storage.

const wh = await nd.webhook.create({
  label: 'stripe-payments',
  ttl: '30d',
});

// Point Stripe to: wh.ingest_url
// Store wh.secret — you need it to decrypt

// Poll for events
const events = await nd.webhook.events(wh.channel_token);

Evidence — SOC audit trail

Every encrypt/decrypt is logged. Metadata only — never content.

const trail = await nd.evidence.query({
  field: 'credit_card',
  action: 'decrypt',
  from: '2026-03-01',
  to: '2026-03-27',
});

// WHO decrypted WHAT field WHEN — ready for SOC 2 auditor

Vault — zero-knowledge storage

You encrypt client-side. Server stores blindly.

const vault = await nd.vault.create({
  label: 'customer-contracts',
  encrypted_blob: myEncrypt(data, myKey),
  iv: myIv,
  metadata: { customer_id: 'cust_123' },
});

const entry = await nd.vault.read(vault.vault_id);
const data = myDecrypt(entry.encrypted_blob, entry.iv, myKey);

Express plugin — one line

import express from 'express';
import { nodataExpress } from '@nodatachat/sdk/express';

const app = express();

app.use('/api/customers', nodataExpress({
  apiKey: 'sk_live_...',
  encryptFields: ['phone', 'email', 'id_number'],
  decryptFields: ['phone', 'email'],
  decryptHeader: 'X-NoData-Decrypt',
}));

app.get('/api/customers', async (req, res) => {
  const rows = await db.query('SELECT * FROM customers');
  res.json(rows);
  // phone, email, id_number → automatically encrypted in response
});

Also available: @nodatachat/sdk/fastify.


Service accounts — scoped M2M keys

Your master key creates restricted child keys for each service:

// POST /api/v1/service-account
const svc = await fetch('https://www.nodatachat.com/api/v1/service-account', {
  method: 'POST',
  headers: { Authorization: 'Bearer sk_live_MASTER_KEY' },
  body: JSON.stringify({
    name: 'payment-service',
    scopes: ['encrypt', 'decrypt'],
    rate_limit_per_minute: 500,
    daily_quota: 100000,
    expires_in_days: 90,
    allowed_ips: ['10.0.0.0/8'],
  }),
});
// { key: "svc_live_abc123..." } — shown ONCE

| Key prefix | Purpose | Can create child keys | |-----------|---------|----------------------| | sk_live_ | Master key | Yes | | svc_live_ | Service account | No |


Configuration

const nd = new NoData({
  apiKey: 'sk_live_...',
  baseUrl: 'https://www.nodatachat.com',  // default
  timeout: 30000,                          // ms
  retries: 2,                              // on 5xx / network error
  headers: { 'X-Custom': 'value' },        // added to every request

  // Hooks
  onRequest: (url, init) => console.log(`→ ${url}`),
  onResponse: (url, status, ms) => console.log(`← ${status} ${ms}ms`),
  onError: (url, err) => console.error(`! ${url}: ${err.message}`),
});

Error handling

import { NoData, NoDataError } from '@nodatachat/sdk';

try {
  await nd.encrypt({ field: 'ssn', value: '123-45-6789' });
} catch (err) {
  if (err instanceof NoDataError) {
    console.log(err.status);     // 429
    console.log(err.message);    // "Rate limit exceeded"
    console.log(err.retryAfter); // 45 (seconds)
  }
}

Rate limits are handled automatically — the SDK waits and retries on 429.


API reference

Core

| Method | Description | |--------|------------| | nd.encrypt(req) | Encrypt a single field | | nd.decrypt(req) | Decrypt a single field | | nd.batchEncrypt(fields) | Parallel encrypt (N HTTP calls) | | nd.batchDecrypt(fields) | Parallel decrypt (N HTTP calls) | | nd.batchNative(items) | Single-call batch (1 HTTP call, up to 100 ops) | | nd.encryptObject(obj, fields) | Deep-walk encrypt matching fields | | nd.decryptObject(obj, fields) | Deep-walk decrypt matching fields | | nd.ping() | Health check + latency |

Channels

| Method | Description | |--------|------------| | nd.channel.create(opts) | Create encrypted channel | | nd.channel.send(req) | Send data through channel | | nd.channel.receive(req) | Receive data from channel | | nd.channel.verify(token, code) | Verify recipient | | nd.channel.proof(token) | Get delivery proof |

Webhooks

| Method | Description | |--------|------------| | nd.webhook.create(opts) | Create webhook channel | | nd.webhook.events(token) | Poll encrypted events | | nd.webhook.list() | List all channels |

Delivery

| Method | Description | |--------|------------| | nd.deliver.send(req) | Burn-after-read delivery | | nd.deliver.burn(content) | Anonymous burn drop | | nd.deliver.read(dropId) | Read + self-destruct |

Evidence

| Method | Description | |--------|------------| | nd.evidence.query(q) | Query audit trail | | nd.evidence.certificate(id) | Proof certificate | | nd.evidence.verify(hash) | Verify proof |

Vault

| Method | Description | |--------|------------| | nd.vault.create(req) | Store encrypted blob | | nd.vault.read(id) | Retrieve encrypted blob | | nd.vault.delete(id) | Delete entry | | nd.vault.status() | Storage stats |


Architecture

┌─────────────┐         ┌──────────────┐         ┌─────────────┐
│  Your App   │ ──────→ │  NoData API  │ ──────→ │  Your DB    │
│             │         │              │         │             │
│  plaintext  │         │  ciphertext  │         │  ciphertext │
│  lives here │         │  passes thru │         │  stored here│
│             │         │  stores: 0   │         │             │
└─────────────┘         └──────────────┘         └─────────────┘

NoData is a relay, not a vault. Data flows through, gets encrypted, and leaves. The server is blind by design — not by policy, by architecture.


Why

Most encryption SDKs ask you to trust their server. We don't.

  • No plaintext on our servers — ever
  • No key storage — you hold the keys
  • No data retention — we're a relay, not a warehouse
  • Full audit trail — every operation logged (metadata only)
  • SOC 2 ready — evidence endpoint = auditor-friendly

The simplest way to add field-level encryption to any system. Five lines of code. Zero trust required.


Get your API key

nodatachat.com/developers