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

cloudark

v0.8.0

Published

Encrypted key-value storage with pluggable adapters

Readme

cloudark

Encrypted cloud storage for TypeScript applications. The backend is blind — it stores only ciphertext. Encryption and decryption happen on the client, using the Web Crypto API.

npm install cloudark

How it works

your data  →  AES-256-GCM encrypt  →  cloud backend (sees nothing)
                     ↑
              key derived from
              your password (PBKDF2)

cloudark wraps any cloud storage backend with a transparent encryption layer. Your backend — S3-compatible storage, IndexedDB, or anything else — stores base64-encoded ciphertext. Without the password, the data is unreadable.


Quick start

The example below uses MemoryAdapter, which is included in the package and requires no peer dependencies. It is ideal for local development, tests, and getting familiar with the API.

import { Cloudark } from 'cloudark'
import { MemoryAdapter } from 'cloudark/adapters/memory'

const store = new Cloudark({
  adapter: new MemoryAdapter(),
  password: 'a-strong-password-known-only-to-the-user',
  compress: true, // Optional: gzip data before encryption
})

// Write
await store.set('budget/2024', { income: 3200, expenses: 2100 })

// Read
const budget = await store.get<{ income: number; expenses: number }>('budget/2024')
console.log(budget) // { income: 3200, expenses: 2100 }

// List keys by prefix
const keys = await store.list('budget/')
console.log(keys) // ['budget/2024']

// Delete
await store.delete('budget/2024')

IndexedDB

Perfect for browser-based offline-first applications. It requires no configuration or peer dependencies.

import { Cloudark } from 'cloudark'
import { IndexedDBAdapter } from 'cloudark/adapters/indexeddb'

const store = new Cloudark({
  adapter: new IndexedDBAdapter('my-app-db', 'encrypted-records'),
  password: 'user-password',
})

await store.set('key', { some: 'data' })

S3-Compatible Storage (AWS, Cloudflare R2, MinIO, B2)

Install the peer dependency first:

npm install @aws-sdk/client-s3

Then swap the adapter:

import { Cloudark } from 'cloudark'
import { S3Adapter } from 'cloudark/adapters/s3'

const store = new Cloudark({
  adapter: new S3Adapter({
    region: 'auto',
    endpoint: process.env.S3_ENDPOINT,
    accessKeyId: process.env.S3_ACCESS_KEY_ID,
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
    bucket: process.env.S3_BUCKET,
  }),
  password: 'shared-secret-known-only-to-users',
})

await store.set('budget/2024', { income: 3200, expenses: 2100 })

See S3 setup for how to configure the adapter, or read the full S3 usage guide for a step-by-step walkthrough.


Core concepts

Password-derived keys. cloudark derives an AES-256 key from your password using PBKDF2 (310,000 iterations, SHA-256). The derived key is held in memory only — it never leaves the device and is never stored anywhere.

Per-payload IV and salt. Every set operation generates a fresh random IV (12 bytes) and salt (16 bytes). The same data encrypted twice produces different ciphertext. IV and salt are stored alongside the ciphertext in the payload — there is no state to synchronise.

Authenticated encryption. AES-GCM provides both confidentiality and integrity. Tampered ciphertext will throw a DecryptionError on read — it will never silently return wrong data.

Backend-agnostic. The StorageAdapter interface is four methods: get, set, delete, list. Swap backends by changing one import.


Adapters

| Adapter | Import | Peer dependency | Status | |---|---|---|---| | Memory (dev / testing) | cloudark/adapters/memory | none | ✅ v0.1 | | S3-Compatible | cloudark/adapters/s3 | @aws-sdk/client-s3 ^3 | ✅ v0.6 | | IndexedDB | cloudark/adapters/indexeddb | none | ✅ v0.5 |

Writing your own adapter

import type { StorageAdapter } from 'cloudark'

class MyAdapter implements StorageAdapter {
  async get(key: string): Promise<string | null> { /* ... */ }
  async set(key: string, value: string): Promise<void> { /* ... */ }
  async delete(key: string): Promise<void> { /* ... */ }
  async list(prefix?: string): Promise<string[]> { /* ... */ }
}

The adapter deals only with raw strings. cloudark handles all serialisation and encryption before calling the adapter.


S3 setup

1. Credentials and Bucket

You will need an S3-compatible bucket and an API key (Access Key ID and Secret Access Key) with read/write permissions for that bucket.

For Cloudflare R2:

  • Endpoint: https://<accountid>.r2.cloudflarestorage.com
  • Region: auto

For AWS S3:

  • Endpoint: (Optional) https://s3.<region>.amazonaws.com
  • Region: e.g., us-east-1

Store these values in environment variables:

S3_ENDPOINT=your-endpoint-url
S3_ACCESS_KEY_ID=your-access-key-id
S3_SECRET_ACCESS_KEY=your-secret-access-key
S3_BUCKET=your-bucket-name
S3_REGION=auto

2. Configure CORS (browser applications only)

If your application runs in a browser, the bucket must allow cross-origin requests from your domain. Without CORS, the browser will block every request.

Example CORS policy (JSON):

[
  {
    "AllowedOrigins": ["https://your-app-domain.com"],
    "AllowedMethods": ["GET", "PUT", "DELETE", "HEAD"],
    "AllowedHeaders": ["*"],
    "MaxAgeSeconds": 3600
  }
]

Replace https://your-app-domain.com with your actual origin. For local development you can add "http://localhost:3000" (or whichever port you use) as an additional entry.

Note: CORS is only needed in browser environments. Node.js and server-side runtimes make requests directly and are not subject to the browser same-origin policy.


Shared repositories

Multiple users can share access to the same encrypted data. Cloudark supports two modes:

  1. Shared password: All members know the same password (v0.2).
  2. Multi-user repositories: Each member has their own keypair, allowing for easy member addition and removal with key rotation (v0.3).

For more details on how this is implemented, see the Storage and Multi-user Structure guide.


Security model

  • Data is encrypted before it touches the network. The cloud backend never sees plaintext.
  • The password is never stored or transmitted. Losing the password means losing access to the data — there is no recovery mechanism.
  • cloudark does not provide authentication or access control. Use your backend's auth layer (e.g. Cloudflare R2 bucket policies) to control who can read and write the ciphertext.
  • cloudark does not protect against a malicious backend that silently drops writes or replays old ciphertext. It guarantees confidentiality and integrity of individual payloads, not consistency of the store.

For the full threat model and cryptographic choices, see specs/tech-stack.md.


Browser and runtime support

| Runtime | Support | |---|---| | Modern browsers | ✅ Native Web Crypto API | | Node.js 18+ | ✅ Native Web Crypto API | | React Native | ⚠️ Requires react-native-quick-crypto polyfill |


Development

git clone https://github.com/urizev/cloudark
cd cloudark
npm install

npm test          # run tests
npm run build     # produce ESM output in dist/
npm run typecheck # type-check
npm run lint      # lint

Roadmap

See specs/roadmap.md.

Contributing

Issues and pull requests are welcome. Please open an issue before starting significant work so we can discuss the approach.

License

MIT