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

capitalsix-data-store

v0.1.2

Published

A React-first, typed in-memory data store factory for shared table state with CRUD operations and per-record async status tracking.

Readme

Data Store

Data Store is a React-first, typed in-memory store for record collections. It creates a shared hook per table name, keeps all consumers in sync, and tracks per-record operation status (working, completed, failed) while async operations run.

Install

npm install capitalsix-data-store

Why use it

  • One shared store per table name
  • Typed records with a required id: string
  • Built-in CRUD operations
  • Optional async lifecycle events (onInserted, onUpdated, onDeleted)
  • Automatic per-record status tracking for UI feedback

Core concepts

  • createDataStore() returns a hook binder.
  • Calling the binder with the same tableName shares state between components.
  • rows contains the current records.
  • states is a map from recordId -> operation state.
  • operations contains async CRUD methods you call from your UI or effects.

Quick start

import { createDataStore, type DataRecord } from 'capitalsix-data-store';
import type { JSX } from 'react';

type TodoData = {
  title: string;
  done: boolean;
};

type TodoRecord = DataRecord<TodoData>;

const useDataStore = createDataStore();

export const TodoList = (): JSX.Element => {
  const { rows, states, operations } = useDataStore<TodoRecords>('todos');

  const addTodo = async (): Promise<void> => {
    const newRecord: TodoRecord = {
      id: crypto.randomUUID(),
      title: 'New item',
      done: false,
    };

    await operations.insertRecords([newRecord]);
  };

  return (
    <div>
      <button type="button" onClick={() => void addTodo()}>
        Add
      </button>

      <ul>
        {rows.map((row) => (
          <li key={row.id}>
            {row.title} - {states[row.id] ?? 'completed'}
          </li>
        ))}
      </ul>
    </div>
  );
};

API overview

createDataStore()

Creates a binder hook for named tables.

const useDataStore = createDataStore();

useDataStore(tableName, events?)

Returns:

  • rows: current records in the table
  • states: map from record id to operation state
  • operations: CRUD-like async operations

Supported operations:

  • setRecords(rows): Promise<void>
  • insertRecords(rows): Promise<void>
  • updateRecords(rows): Promise<void>
  • upsertRecords(rows): Promise<void>
  • deleteRecords(ids): Promise<void>

Optional event callbacks:

  • onInserted(rows)
  • onUpdated(rows)
  • onDeleted(rows)

When a callback exists, touched rows move to working until the promise resolves or rejects.

Type notes

  • Every record must include id: string.
  • DataRecord<T> is a helper type for this shape.
  • Event handlers receive the affected rows and can persist to APIs.
  • If an event handler throws/rejects, record states move to failed.

Examples

Example 1: optimistic insert with async persistence

import { createDataStore, type DataRecord } from 'capitalsix-data-store';

type User = DataRecord<{ name: string }>;

const useDataStore = createDataStore();

const { operations } = useDataStore<User>('users', {
  onInserted: async (rows) => {
    await fetch('/api/users', {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify(rows),
    });
  },
});

const usersToInsert: User[] = [{ id: 'u-1', name: 'Alice' }];
await operations.insertRecords(usersToInsert);

Example 2: merge server snapshot with upsert

import { createDataStore, type DataRecord } from 'capitalsix-data-store';

type Product = DataRecord<{ name: string; price: number }>;

const useDataStore = createDataStore();

const { operations } = useDataStore<Product>('products', {
  onUpdated: async (rows) => {
    await fetch('/api/products/bulk', {
      method: 'PATCH',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify(rows),
    });
  },
});

const incoming = await fetch('/api/products').then((r) => r.json() as Promise<Product[]>);
await operations.upsertRecords(incoming);

Example 3: row-level loading and error badges

import { createDataStore, type DataRecord, type DataRecordState } from 'capitalsix-data-store';
import type { JSX } from 'react';

type Task = DataRecord<{ title: string }>;

const StatusBadge = ({ state }: { state?: DataRecordState }): JSX.Element => {
  if (state === 'working') return <span>Saving...</span>;
  if (state === 'failed') return <span>Failed</span>;
  return <span>Done</span>;
};

const useDataStore = createDataStore();

const RowsView = (): JSX.Element => {
  const { rows, states } = useDataStore<Task>('tasks');
  const taskRows = rows as Task[];

  return (
    <>
      {taskRows.map((row) => (
        <div key={row.id}>
          {row.id} <StatusBadge state={states[row.id]} />
        </div>
      ))}
    </>
  );
};

Development

npm install
npm test
npm run typecheck
npm run build