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

@instant3p/storybook

v0.20.12012

Published

3rd party Storybook plugin for Instant with isolated offline database instances

Readme

@instant3p/storybook

A 3rd party Storybook plugin for Instant that provides isolated offline database instances for each story.

Features

  • Isolated Database per Story: Each story gets its own unique app ID and database instance
  • Schema Support: Define typed schemas for your stories with full TypeScript support
  • Seed Data: Provide seed functions to populate your database with test data
  • Reset Functionality: Built-in reset button in Storybook toolbar to clear and re-seed data
  • Offline Mode: All databases run in offline mode using the core-offline package
  • Docs Mode Support: Shows elegant placeholders in docs mode with links to interactive stories
  • Zero Manual Typing: Component interfaces AND seed functions are automatically typed based on story parameters

Installation

npm install @instant3p/storybook

Setup

1. Add to your Storybook configuration

In your .storybook/main.js:

module.exports = {
  addons: [
    '@instant3p/storybook',
    // ... other addons
  ],
};

2. Use in your stories (Zero Manual Typing!)

import type { Meta, StoryObj } from '@storybook/react';
import { i } from '@instant3p/core-offline';
import { defineInstantDBStory } from '@instant3p/storybook';
import { MyComponent } from './MyComponent';

// Define your schema
const schema = i.schema({
  entities: {
    todos: i.entity({
      text: i.string(),
      completed: i.boolean(),
      createdAt: i.date(),
    }),
    users: i.entity({
      name: i.string(),
      email: i.string().unique(),
    }),
  },
  links: {
    todoOwner: {
      forward: { on: 'todos', label: 'owner', has: 'one' },
      reverse: { on: 'users', label: 'todos', has: 'many' },
    },
  },
});

// 🎉 Your component interface - ZERO manual typing required!
interface MyComponentProps {
  title?: string;
  // Just add this optional prop - everything is automatically typed!
  instantdb?: {
    db: InstantCoreDatabase<any>; // Becomes fully typed automatically!
    reset: () => Promise<void>;
  };
}

const meta = {
  title: 'Example/MyComponent',
  component: MyComponent,
} satisfies Meta<typeof MyComponent>;

export default meta;
type Story = StoryObj<typeof meta>;

// 🚀 Ultimate ergonomics: Zero typing ANYWHERE!
export const WithTodos: Story = {
  parameters: defineInstantDBStory({
    schema,
    seed: async (db) => { // 🎉 No types needed - db is automatically typed!
      // Create a user
      const userId = 'user-1';
      await db.transact([
        db.tx.users[userId].update({
          name: 'John Doe',
          email: '[email protected]',
        }),
      ]);

      // Create some todos - all operations are fully typed!
      await db.transact([
        db.tx.todos['todo-1'].update({
          text: 'Learn InstantDB',
          completed: false,
          createdAt: new Date().getTime(),
        }),
        db.tx.todos['todo-2'].update({
          text: 'Build awesome apps',
          completed: true,
          createdAt: new Date().getTime(),
        }),
      ]);

      // Link todos to user
      await db.transact([
        db.tx.todos['todo-1'].link({ owner: userId }),
        db.tx.todos['todo-2'].link({ owner: userId }),
      ]);
    },
  }),
};

Usage in Components

The InstantDB plugin automatically provides a typed instantdb prop to your component when you use defineInstantDBStory. The db instance is automatically typed based on your schema with ZERO manual typing required anywhere!

import React, { useEffect, useState } from 'react';
import type { InstantCoreDatabase } from '@instant3p/core-offline';

interface TodoListProps {
  // ✨ ZERO manual typing - everything is automatically typed!
  instantdb?: {
    db: InstantCoreDatabase<any>; // Becomes fully typed automatically!
    reset: () => Promise<void>;
  };
}

export function TodoList({ instantdb }: TodoListProps) {
  const [todos, setTodos] = useState([]);
  const { db } = instantdb || {};

  useEffect(() => {
    if (!db) return;
    
    const unsubscribe = db.subscribeQuery(
      { todos: {} }, // 👈 All queries are fully typed based on schema!
      (result) => {
        if (result.data) {
          setTodos(result.data.todos);
        }
      }
    );

    return unsubscribe;
  }, [db]);

  const addTodo = async (text: string) => {
    if (!db) return;
    
    // 👈 All transactions are fully typed!
    await db.transact([
      db.tx.todos[`todo-${Date.now()}`].update({
        text,
        completed: false,
        createdAt: new Date().getTime(),
      }),
    ]);
  };

  if (!db) {
    return <div>Loading InstantDB...</div>;
  }

  return (
    <div>
      <h2>Todos</h2>
      <p style={{ color: '#666', fontSize: '14px' }}>
        Use the 🗄️ button in the toolbar above to reset the database
      </p>
      {/* Your todo list UI */}
    </div>
  );
}

Reset Button

The plugin automatically adds a reset button (🗄️) to the Storybook toolbar when a story uses InstantDB. Always use this toolbar button to reset the database rather than adding reset buttons within your components.

Clicking the toolbar button will:

  1. Clear all data from the story's database using the built-in db.clear() method
  2. Re-run the seed function if provided
  3. Update the UI to reflect the reset state

Docs Mode Support

When multiple stories are displayed simultaneously (such as in Storybook's docs mode or overview pages), the plugin shows elegant placeholder cards instead of initializing multiple databases. Each placeholder includes:

  • Information about the story's schema (entities and links)
  • A button to navigate to the individual interactive story
  • Clear messaging about why the full story isn't shown

This "thoughtful limitation" prevents database conflicts while providing excellent user experience.

TypeScript Support

The plugin provides zero-configuration TypeScript support with automatic schema inference:

  • Zero manual typing: Use defineInstantDBStory() and everything is automatically typed
  • Automatic component typing: Just add optional instantdb prop - it becomes fully typed
  • Automatic seed typing: Seed function parameters are automatically typed based on schema
  • Schema-based inference: All database operations are completely type-safe with autocomplete
  • Standard Storybook patterns: Uses normal Meta and StoryObj types

How Zero Typing Works

  1. Use defineInstantDBStory(): This helper automatically infers types from your schema
  2. Add optional instantdb prop: Component gets automatic typing based on story parameters
  3. Magic happens: Both component AND seed functions become fully typed
  4. Full type safety: All queries, transactions, and operations are completely type-safe

Migration from Previous Versions

Before (manual typing required):

export const MyStory: Story = {
  parameters: {
    instantdb: {
      schema,
      seed: async (db: InstantCoreDatabase<typeof schema>) => {
        // Manual typing required
      },
    },
  },
};

After (zero typing required):

export const MyStory: Story = {
  parameters: defineInstantDBStory({
    schema,
    seed: async (db) => { // 🎉 No types needed!
      // Automatically typed based on schema
    },
  }),
};

API Reference

defineInstantDBStory(config)

The ultimate helper function that eliminates all manual typing:

defineInstantDBStory({
  schema: InstantSchemaDef;                           // Your InstantDB schema
  seed?: (db: InstantCoreDatabase<Schema>) => Promise<void> | void;  // Optional seed function (automatically typed!)
})

InstantDBContext

The context automatically provided to your component:

interface InstantDBContext<Schema> {
  db: InstantCoreDatabase<Schema>;  // The database instance (automatically typed!)
  reset: () => Promise<void>;       // Reset function (prefer toolbar button)
}

How It Works

  1. Schema Detection: defineInstantDBStory() captures your schema and automatically types everything
  2. Automatic Enhancement: Component's instantdb prop is automatically enhanced with typed db instance
  3. Type Inference: TypeScript automatically provides full type safety based on your schema
  4. Seed Function Typing: Seed functions are automatically typed based on the schema parameter
  5. Isolation: Each story gets a unique app ID for complete database isolation
  6. Lifecycle Management: Database is cleared and seeded automatically for each story
  7. Docs Mode: Multiple stories show placeholders with navigation to individual interactive stories

This ensures that your stories are completely isolated, reproducible, and type-safe with ZERO manual typing required anywhere!