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

@monkeyhub/sdk

v0.2.2

Published

TypeScript SDK for MonkeyHub. Zero dependencies, works in Node.js 18+.

Readme

@monkeyhub/sdk

TypeScript SDK for MonkeyHub. Zero dependencies, works in Node.js 18+.

Install

npm install @monkeyhub/sdk

Quick Start

import { Monkey } from '@monkeyhub/sdk'

const monkey = new Monkey('mk_live_...')

// Get a collection (auto-registers on first use)
const users = monkey.collection<User>('users')

// Save
await users.save({ id: 'user_1', name: 'Ada', email: '[email protected]' })

// Fetch
const user = await users.findOne('user_1')

MonkeyDB

Collections

Collections are typed key-value stores backed by DynamoDB. They auto-register on first use — no setup step required.

interface Order {
  id: string
  customerId: string
  status: string
  total: number
  createdAt: number
}

const orders = monkey.collection<Order>('orders', {
  key: { hashKey: 'id' },
  indexes: [
    'status',
    { name: 'by-customer', hashKey: 'customerId', rangeKey: 'createdAt' },
  ],
})

Databases

Collections live inside a database. If you don't specify one, they go into default. Use databases to logically group collections.

// These are equivalent:
monkey.collection('users')
monkey.db('default').collection('users')

// Organize by domain:
const analytics = monkey.db('analytics')
const events = analytics.collection<Event>('events')
const metrics = analytics.collection<Metric>('metrics')

// List collections in a database:
const collections = await analytics.listCollections()

Save Items

// Single item
const saved = await orders.save({ id: 'ord_1', customerId: 'cust_1', status: 'pending', total: 49.99, createdAt: Date.now() })

// Batch (up to 25 per request, auto-chunked for larger arrays)
const savedItems = await orders.save([
  { id: 'ord_2', customerId: 'cust_1', status: 'pending', total: 29.99, createdAt: Date.now() },
  { id: 'ord_3', customerId: 'cust_2', status: 'shipped', total: 89.99, createdAt: Date.now() },
])

save() requires the full key field and returns the saved item(s). Use create() for auto-key collections where the key is optional.

Auto-Generated Keys

Set hashKeyType: 'auto' and use create() to insert items without providing a key. The server generates a UUID and returns the full item:

const logs = monkey.db('telemetry').collection<Log>('logs', {
  key: { hashKey: 'id', hashKeyType: 'auto' },
})

// create() — key is optional, server generates it
const log = await logs.create({ level: 'info', message: 'deployed v2.1' })
console.log(log.id) // "a1b2c3d4-..."

// Batch create
const items = await logs.create([
  { level: 'info', message: 'starting' },
  { level: 'warn', message: 'slow query' },
])

// save() — key is required, for upserts with explicit IDs
await logs.save({ id: 'custom_id', level: 'error', message: 'oops' })

create() accepts Partial<T> — the hash key field is optional, everything else is up to you. The return type is always the full T with the generated key populated.

Fetch Items

// Single item by key
const order = await orders.findOne('ord_1')

// Batch fetch by keys
const items = await orders.find(['ord_1', 'ord_2', 'ord_3'])

// For collections with a range key:
const item = await orders.findOne('parent_key', 'sort_key')

findOne returns null if the item doesn't exist.

Query

Query by primary key or a declared index:

// By index
const pending = await orders.query({
  index: 'status',
  hashKey: 'pending',
})

// Compound index with range condition
const recentOrders = await orders.query({
  index: 'by-customer',
  hashKey: 'cust_1',
  rangeKey: Date.now() - 86400000,
  rangeKeyOp: '>=',
  limit: 20,
  reverse: true,
})

// Primary key query
const exact = await orders.query({ hashKey: 'ord_1' })

// Pagination
const page1 = await orders.query({ index: 'status', hashKey: 'shipped', limit: 10 })
const page2 = await orders.query({ index: 'status', hashKey: 'shipped', limit: 10, cursor: page1.cursor })

Range key operators: =, <, <=, >, >=, begins_with.

Remove Items

await orders.remove('ord_1')

// With range key:
await orders.remove('parent_key', 'sort_key')

Drop a Collection

Permanently deletes all items and removes the collection config. Requires typing the collection name to confirm:

await orders.drop('orders')

Backups

Export a collection to NDJSON in MonkeyBuckets:

const backup = await orders.backup()
console.log(backup.id, backup.status) // "bak_abc123", "pending"

// Check status later
const info = await orders.getBackup(backup.id)
console.log(info.status, info.itemCount)

// List all backups for this collection
const backups = await orders.listBackups()

Key Schema Options

| Option | Values | Description | |--------|--------|-------------| | hashKey | field name | Primary key field (default: "id") | | hashKeyType | "string", "number", "auto" | Key type. "auto" generates UUIDs server-side | | rangeKey | field name | Optional sort key for composite keys |

Index Types

Simple indexes — a single field name becomes a hash-only index:

indexes: ['status', 'region']

Compound indexes — hash + optional range key for sorted queries:

indexes: [
  { name: 'by-customer-date', hashKey: 'customerId', rangeKey: 'createdAt' },
]

Up to 5 indexes per collection (varies by plan).

Error Handling

All API errors throw typed error classes:

import { MonkeyNotFoundError, MonkeyValidationError, MonkeyRateLimitError } from '@monkeyhub/sdk'

try {
  await users.save({ /* missing key */ })
} catch (err) {
  if (err instanceof MonkeyValidationError) {
    console.log(err.message)
  }
  if (err instanceof MonkeyRateLimitError) {
    // Auto-retried by default (3 attempts with backoff)
  }
}

Client Options

const monkey = new Monkey('mk_live_...', {
  baseUrl: 'https://api.monkeyhub.ai',  // default
  timeout: 30000,                         // request timeout in ms
  retry: {
    maxRetries429: 3,    // rate limit retries
    maxRetries503: 3,    // service unavailable retries
    maxRetriesNetwork: 1, // network error retries
  },
})

API Keys

  • mk_live_* — full read/write access
  • mk_pub_* — read-only access (cannot write data, create collections, or drop)

Generate keys in the MonkeyHub dashboard or via the API.