@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/sdkQuick 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 accessmk_pub_*— read-only access (cannot write data, create collections, or drop)
Generate keys in the MonkeyHub dashboard or via the API.
