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 🙏

© 2025 – Pkg Stats / Ryan Hefner

jotdb

v0.1.8

Published

[![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/acoyfellow/jotdb)

Readme

JotDB

Deploy to Cloudflare

A lightweight, schema-less database built on Cloudflare Durable Objects. Think of it as Firestore's security rules, but with Zod validation built-in. Perfect for both internal and external APIs, with automatic type safety and validation.

Cloudflare Products: JotDB works with any Cloudflare product that supports Durable Objects:

  • Cloudflare Workers
  • Cloudflare Pages (with Functions)
  • Cloudflare Workflows
  • Cloudflare Queues
  • Cloudflare Cron Triggers

Why JotDB?

JotDB combines the best of both worlds: the simplicity of NoSQL with the safety of schema validation. Here's what makes it special:

  • Built-in Type Safety: Automatic Zod validation ensures your data is always in the right shape
  • Edge-Native: Runs directly on Cloudflare's edge network, with sub-millisecond latency
  • RPC-First: Direct method calls instead of HTTP endpoints (though you can easily wrap it in HTTP)
  • Durable Storage: Built on Durable Objects for reliable, consistent storage
  • Zero Setup: No database configuration, no connection strings, just instantiate and go
  • Perfect for APIs: Use it as an internal database or wrap it with auth for external APIs
  • Real-time Ready: Durable Objects provide strong consistency guarantees

Perfect for:

  • Quick prototypes that need data validation
  • Small to medium applications that need reliable storage
  • Serverless environments where you want type safety
  • Real-time data storage with strong consistency
  • Collaborative applications that need data validation
  • APIs that need both flexibility and safety

Design Patterns

JotDB uses Cloudflare Durable Objects under the hood, which means you can organize your data in several ways:

  1. Global Store: Use a single instance for your entire application

    const db = env.JOTDB.get(env.JOTDB.idFromName("global"));
  2. Per-User Store: Create a separate instance for each user

    const userDb = env.JOTDB.get(env.JOTDB.idFromName(`user:${userId}`));
  3. Per-Event Store: Create temporary stores for events or sessions

    const eventDb = env.JOTDB.get(env.JOTDB.idFromName(`event:${eventId}`));

Each instance is isolated and can have its own schema and options. This follows the Actor Model pattern, where each instance is an independent actor that manages its own state.

Installation

# Using npm
npm install jotdb

# Using yarn
yarn add jotdb

# Using pnpm
pnpm add jotdb

Configure wrangler.jsonc

{
  "durable_objects": {
    "bindings": [
      {
        "name": "JOTDB",
        "class_name": "JotDB"
      }
    ]
  }
}

Full Example

import { JotDB } from 'jotdb';

export interface Env {
  JOTDB: DurableObjectNamespace;
}

export default {
  async fetch(request: Request, env: Env) {
    // Initialize the database
    const jotId = env.JOTDB.idFromName("my-db");
    const db = env.JOTDB.get(jotId);

    // Example operations
    await db.set("user:123", { name: "John", age: 30 });
    const user = await db.get("user:123");
    await db.delete("user:123");

    // Return the result
    return new Response(JSON.stringify({ user }), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
};

API Reference

| Method | Description | Parameters | Returns | |--------|-------------|------------|---------| | set(key, value) | Store a value | key: string, value: any | Promise<void> | | get(key) | Retrieve a value | key: string | Promise<any> | | delete(key) | Remove a value | key: string | Promise<void> | | clear() | Remove all values | none | Promise<void> | | keys() | Get all keys | none | Promise<string[]> | | has(key) | Check if key exists | key: string | Promise<boolean> | | getAll() | Get all data | none | Promise<Record<string, unknown> \| unknown[]> | | setAll(objOrArr) | Set all data at once | objOrArr: Record<string, unknown> \| unknown[] | Promise<void> | | push(item) | Add item to array | item: unknown | Promise<void> | | getSchema() | Get current schema | none | Promise<SchemaDefinition> | | setSchema(schema) | Set data schema | schema: SchemaDefinition | Promise<void> | | getOptions() | Get current options | none | Promise<JotDBOptions> | | setOptions(opts) | Set database options | opts: Partial<JotDBOptions> | Promise<void> | | getAuditLog() | Get audit log entries | none | Promise<AuditLogEntry[]> | | clearAuditLog() | Clear audit log | none | Promise<void> |

Options

interface JotDBOptions {
  autoStrip: boolean;  // Automatically strip unknown fields
  readOnly: boolean;   // Enable read-only mode
}

Schema Types

type SchemaType = "string" | "number" | "boolean" | "email" | "array" | "object" | "any";

License

MIT License - feel free to use this in your own projects!

Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Testing

Currently, testing is done manually in production. We're working on adding a comprehensive test suite. For now, you can test the functionality by:

  1. Deploying to Cloudflare Workers
  2. Using the example endpoints
  3. Verifying data persistence