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

@lunarhue/stdb-helpers

v0.0.3

Published

Helpers for building React apps with SpacetimeDB — like convex-helpers but for SpacetimeDB

Readme

spacetimedb-helpers

A collection of helpers for building apps with SpacetimeDB — like convex-helpers but for SpacetimeDB.

Installation

bun add @lunarhue/stdb-helpers spacetimedb @tanstack/react-query

Note: This package has a peer dependency on spacetimedb ^2.0.3 and @tanstack/react-query ^5.


Setup

Wrap your app with both QueryClientProvider and SpacetimeDB's SpacetimeDBProvider.

// providers.tsx
'use client'

import { useMemo } from 'react'
import { SpacetimeDBProvider } from 'spacetimedb/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { DbConnection } from './module_bindings'

const queryClient = new QueryClient()

const connectionBuilder = DbConnection.builder()
  .withUri(process.env.NEXT_PUBLIC_SPACETIMEDB_HOST!)
  .withDatabaseName(process.env.NEXT_PUBLIC_SPACETIMEDB_DB_NAME!)

export function Providers({ children }: { children: React.ReactNode }) {
  const builder = useMemo(() => connectionBuilder, [])

  return (
    <QueryClientProvider client={queryClient}>
      <SpacetimeDBProvider connectionBuilder={builder}>
        {children}
      </SpacetimeDBProvider>
    </QueryClientProvider>
  )
}

API

useQuery(query, options?)

Subscribe to a SpacetimeDB table and expose the rows through TanStack Query. The initial snapshot is read synchronously from the in-memory SpacetimeDB store, then SpacetimeDB's event listeners (onInsert, onDelete, onUpdate) keep the TanStack Query cache live.

import { useQuery } from '@lunarhue/stdb-helpers/tanstack/use-query'
import { tables } from './module_bindings'

function PlayerList() {
  const { data: players = [], isReady, queryKey } = useQuery(tables.player)

  if (!isReady) return <p>Connecting...</p>

  return (
    <ul>
      {players.map((p) => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  )
}

Returns everything useQuery from TanStack returns, plus:

| Field | Type | Description | | ---------- | ---------------------------------- | -------------------------------------------------------------- | | queryKey | ['spacetimedb', 'table', string] | Use with queryClient.setQueryData / cancelQueries | | isReady | boolean | true once the initial subscription snapshot has been applied |

Options — accepts all standard TanStack UseQueryOptions except queryKey and queryFn. Useful options:

| Option | Description | | ------------- | ----------------------------------------------------------------- | | initialData | Seed the cache with server-prefetched data (see createPrefetch) |


useMutation(reducer, options?)

Call a SpacetimeDB reducer as a TanStack mutation. If the connection isn't established yet, calls are queued and flushed automatically once connected.

import { useMutation } from '@lunarhue/stdb-helpers/tanstack/use-mutation'
import { reducers } from './module_bindings'

function AddPlayerForm() {
  const { mutate: addPlayer, isPending } = useMutation(reducers.addPlayer)

  return (
    <button onClick={() => addPlayer({ name: 'Alice' })} disabled={isPending}>
      Add Player
    </button>
  )
}

Returns everything useMutation from TanStack returns, plus:

| Field | Type | Description | | ------------- | --------------------------------- | --------------------------- | | mutationKey | ['spacetimedb', string, string] | Stable key for this reducer |

Options — accepts all standard TanStack UseMutationOptions except mutationFn.


Optimistic Updates

useQuery and useMutation compose directly with TanStack Query's optimistic update pattern:

function PersonList() {
  const queryClient = useQueryClient()
  const { data: people = [], queryKey } = useQuery(tables.person)

  const { mutate: addPerson } = useMutation(reducers.add, {
    onMutate: async (newPerson) => {
      await queryClient.cancelQueries({ queryKey })
      const previous = queryClient.getQueryData(queryKey)
      queryClient.setQueryData(queryKey, (prev: Person[]) => [
        ...prev,
        newPerson,
      ])
      return { previous }
    },
    onError: (_err, _args, ctx) => {
      queryClient.setQueryData(queryKey, ctx?.previous)
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey })
    },
  })

  return (
    <>
      <ul>
        {people.map((p, i) => (
          <li key={i}>{p.name}</li>
        ))}
      </ul>
      <button onClick={() => addPerson({ name: 'Alice' })}>Add</button>
    </>
  )
}

createPrefetch(connection | Builder, config?)

Create a prefetch function for fetching table data outside of React — useful for SSR and React Server Components.

Two overloads:

With an existing live connection (recommended when you can reuse a connection):

// lib/prefetch.ts
import { createPrefetch } from '@lunarhue/stdb-helpers/react/prefetch'
import { DbConnection } from './module_bindings'

export const prefetch = createPrefetch(DbConnection.builder().build())

With a builder + config (creates a short-lived connection per call, disconnects after snapshot):

import { createPrefetch } from '@lunarhue/stdb-helpers/react/prefetch'
import { DbConnection } from './module_bindings'

export const prefetch = createPrefetch(DbConnection.builder(), {
  uri: 'wss://maincloud.spacetimedb.com',
  databaseName: 'my-db',
  timeout: 10_000, // ms, default
})

Usage in a Server Component:

// app/page.tsx
import { prefetch } from '@/lib/prefetch'
import { tables } from './module_bindings'

export default async function Page() {
  const [error, initialPeople] = await prefetch(tables.person)

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

  return <PersonList initialPeople={initialPeople} />
}

Client-side hydration — pass the prefetched data as initialData to useQuery:

'use client'

export function PersonList({ initialPeople }: { initialPeople: Person[] }) {
  const { data: people = [] } = useQuery(tables.person, {
    initialData: initialPeople,
  })

  // ...
}

prefetch return type — a tuple, never throws:

type PrefetchResult<T> = [error: null, data: T[]] | [error: Error, data: null]

createPrefetch config options (builder overload only):

| Option | Type | Default | Description | | ---------------- | --------------------------- | ------- | ------------------------------------------- | | uri | string | — | WebSocket URL of your SpacetimeDB host | | databaseName | string | — | Database name | | token | string | — | Optional auth token | | timeout | number | 10000 | Connection timeout in ms | | onConnect | (identity, token) => void | — | Called on successful connection | | onDisconnect | () => void | — | Called when the ephemeral connection closes | | onConnectError | (err: Error) => void | — | Called if the connection fails |


Example

See the full Next.js example in examples/nextjs/ which demonstrates:

  • Provider setup with SpacetimeDBProvider + QueryClientProvider
  • Server-side prefetch in a React Server Component
  • Client-side real-time subscription with useQuery
  • Optimistic adds with useMutation
  • Auth token persistence via localStorage

Local Development

bun install
bun run dev

Requires Bun