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

dynamodb-reactive

v0.1.22

Published

A Serverless, Reactive tRPC replacement for AWS DynamoDB

Downloads

1,953

Readme

dynamodb-reactive

Tagline: A Serverless, Reactive tRPC replacement for AWS - unified package.

1. Overview

dynamodb-reactive provides type-safe, real-time DynamoDB subscriptions with automatic JSON Patch diffing over WebSockets.

Key Features:

  • Full TypeScript Support: End-to-end type safety from schema definition to React hooks.

2. Installation

npm install dynamodb-reactive zod
# or
pnpm add dynamodb-reactive zod

Peer Dependencies (install as needed):

| Dependency | Required For | | :--- | :--- | | zod | Schema definitions (required) | | react | React hooks | | aws-cdk-lib | Infrastructure | | constructs | Infrastructure |

3. Package Exports

| Import Path | Purpose | | :--- | :--- | | dynamodb-reactive | Core exports (DynamoTable, schemas) | | dynamodb-reactive/core | Core table definitions | | dynamodb-reactive/server | Server runtime (Router, handlers) | | dynamodb-reactive/client | Frontend client | | dynamodb-reactive/react | React hooks | | dynamodb-reactive/infra | CDK constructs |

4. Quick Start

Step 1: Define Your Schema

import { z } from 'zod';
import { DynamoTable } from 'dynamodb-reactive/core';

export const TodoTable = new DynamoTable({
  tableName: 'my-table',
  schema: z.object({
    PK: z.string(),
    SK: z.string(),
    id: z.string(),
    text: z.string(),
    completed: z.boolean(),
    createdAt: z.number(),
  }),
  pk: 'PK',
  sk: 'SK',
});

Step 2: Create the Router

import { z } from 'zod';
import { initReactive } from 'dynamodb-reactive/server';
import { TodoTable } from './schema';

type AppContext = Record<string, unknown>;
const t = initReactive<AppContext>();

export const appRouter = t.router({
  todos: {
    // Query procedure
    list: t.procedure
      .input(z.object({}).optional())
      .query(async ({ ctx }) => {
        return ctx.db
          .query(TodoTable)
          .filter((q) => q.eq(TodoTable.field.PK, 'TODO'))
          .execute();
      }),

    // Mutation procedure
    create: t.procedure
      .input(z.object({ text: z.string() }))
      .mutation(async ({ ctx, input }) => {
        const item = {
          PK: 'TODO',
          SK: Date.now().toString(),
          id: Date.now().toString(),
          text: input.text,
          completed: false,
          createdAt: Date.now(),
        };
        await ctx.db.put(TodoTable, item);
        return item;
      }),
  },
});

export type AppRouter = typeof appRouter;

Step 3: Create API Handler

import { createReactiveHandler } from 'dynamodb-reactive/server';
import { appRouter } from './router';

export const handler = createReactiveHandler({
  router: appRouter,
  dbConfig: { region: 'us-east-1' },
  getContext: async () => ({}),
});

// In Next.js API route:
export async function POST(request: Request) {
  const body = await request.json();
  const response = await handler.handleRequest('client-id', body);
  return Response.json(response);
}

Step 4: Set Up React Provider

// app/layout.tsx or providers.tsx
'use client';

import { ReactiveClientProvider } from 'dynamodb-reactive/client';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ReactiveClientProvider
      config={{
        url: process.env.NEXT_PUBLIC_WS_URL!,
        httpUrl: '/api/reactive',
      }}
    >
      {children}
    </ReactiveClientProvider>
  );
}

Step 5: Use React Hooks

'use client';

import type { Todo } from './types';
import type { AppRouter } from './router';
import { useClient, useConnectionState } from 'dynamodb-reactive/client';

export function TodoList() {
  const connectionState = useConnectionState();
  const client = useClient<AppRouter>();

  // Subscribe to todos - receives real-time updates via WebSocket
  const { data: todos, loading, error } = client.todos.list.useQuery({});

  // Mutations with automatic optimistic updates
  const createMutation = client.todos.create.useMutation();
  const toggleMutation = client.todos.toggle.useMutation();
  const deleteMutation = client.todos.delete.useMutation();

  const handleCreate = async (text: string) => {
    await createMutation.mutate({ text });
  };

  const handleToggle = async (id: string) => {
    await toggleMutation.mutate({ id });
  };

  const handleDelete = async (id: string) => {
    await deleteMutation.mutate({ id }); // Removes instantly from UI
  };

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <p>WebSocket: {connectionState}</p>
      {todos?.map((todo) => (
        <div key={todo.id}>
          <input
            type="checkbox"
            checked={todo.completed}
            onChange={() => handleToggle(todo.id)}
          />
          <span>{todo.text}</span>
          <button onClick={() => handleDelete(todo.id)}>Delete</button>
        </div>
      ))}
    </div>
  );
}

5. Optimistic Updates

All mutations apply instant optimistic updates (before HTTP request):

| Update Type | Behavior | Example Input | | :--- | :--- | :--- | | 'merge' | Find item by input.id, merge input fields | { id: '123', completed: true } | | 'remove' | Remove item by input.id | { id: '123' } | | Custom function | Apply custom logic | (data, input) => [...] |

Convention: <namespace>.<action> mutations auto-invalidate <namespace>.list subscriptions.

Example - Instant Toggle:

// For instant optimistic updates, include the fields you want to change
const handleToggle = async (todo: Todo) => {
  await updateMutation.mutate({
    id: todo.id,
    completed: !todo.completed  // Include new value for instant UI update
  });
};

Custom options:

const mutation = client.todos.update.useMutation({
  invalidates: 'todos.list',           // Override auto-detection
  optimisticUpdate: 'merge',           // 'merge' | 'remove' | custom function
});

// For creates (no id), provide optimisticData
const createMutation = client.todos.create.useMutation({
  optimisticData: (input) => ({
    id: `temp-${Date.now()}`,
    ...input,
    completed: false,
    createdAt: Date.now(),
  }),
});

6. Database Context Methods

The ctx.db object provides these methods:

| Method | Description | | :--- | :--- | | query(table).filter(...).execute() | Query with filters | | get(table, key) | Get single item by key | | put(table, item) | Create/replace item | | update(table, key, updates) | Update item fields | | delete(table, key) | Delete item |

7. Requirements

  • Node.js >= 18.0.0
  • TypeScript >= 5.3.0

8. License

MIT