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

@seedts/jsx-runtime

v0.1.1

Published

JSX runtime for SeedTS seed definitions

Downloads

2

Readme

@seedts/jsx-runtime

JSX runtime for declarative seed definitions in SeedTS

The JSX runtime package enables you to write database seeds using familiar React-like JSX syntax. This provides a clean, declarative way to define seeds with full TypeScript support.

Installation

pnpm add @seedts/jsx-runtime

Note: This package is automatically included when you install the main seedts package.

Setup

TypeScript Configuration

Add JSX support to your tsconfig.json:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "seedts"
  }
}

File Extension

Use .tsx extension for seed files:

  • users.seed.tsx
  • users.seed.ts ❌ (won't work with JSX)

Quick Start

Basic Example

import { Seed, Action, Entity, Attribute } from 'seedts/jsx-runtime';
import { PostgreSQLAdapter } from '@seedts/adapter-postgresql';

const adapter = new PostgreSQLAdapter(pool);

export const UsersSeed = (
  <Seed name="users" adapter={adapter}>
    <Action count={10}>
      <Entity>
        <Attribute
          name="email"
          factory={(ctx) => `user${ctx.index}@example.com`}
        />
        <Attribute
          name="name"
          factory={(ctx) => `User ${ctx.index}`}
        />
        <Attribute
          name="role"
          factory={() => 'user'}
        />
      </Entity>
    </Action>
  </Seed>
);

Components

<Seed> - Seed Container

The root component for a seed definition.

<Seed
  name="users"              // Seed name (required)
  adapter={adapter}         // Database adapter (required)
  dependsOn="other-seed"   // Single dependency
  dependsOn={["a", "b"]}   // Multiple dependencies
  beforeInsert={fn}        // Hook: before insert
  afterInsert={fn}         // Hook: after insert
  onSuccess={fn}           // Hook: on success
  onError={fn}             // Hook: on error
>
  {/* Actions go here */}
</Seed>

Props:

  • name: string - Unique seed identifier
  • adapter: SeedAdapter - Database adapter instance
  • dependsOn?: string | string[] - Seed dependencies
  • beforeInsert?: (data) => Promise<T[]> | T[] - Pre-insert hook
  • afterInsert?: (data, inserted) => Promise<void> | void - Post-insert hook
  • onSuccess?: (data, metadata) => Promise<void> | void - Success hook
  • onError?: (error) => Promise<void> | void - Error hook

<Action> - Data Generation Action

Defines a batch of data to generate and insert.

<Action
  count={100}                    // Number of records
  run={condition}                // Conditional execution
  condition={asyncFn}            // Async condition check
  beforeInsert={transformFn}     // Transform before insert
  onConflict="skip"              // Conflict strategy
>
  <Entity />
</Action>

Props:

  • count: number - Number of records to generate
  • run?: boolean - Conditional execution (default: true)
  • condition?: (ctx) => Promise<boolean> | boolean - Async condition
  • beforeInsert?: (data) => Promise<T[]> | T[] - Transform data
  • onConflict?: 'skip' | 'update' | 'error' - Conflict resolution

<Entity> - Record Definition

Defines the structure of a single record.

<Entity
  data={{name: 'Static', value: 123}}  // Static data
  factory={factoryFn}                   // Dynamic generation
>
  <Attribute name="field1" factory={fn1} />
  <Attribute name="field2" factory={fn2} />
</Entity>

Props:

  • data?: Partial<T> - Static data for all records
  • factory?: (ctx) => Partial<T> - Dynamic data generation

<Attribute> - Field Definition

Defines a single field/column in a record.

<Attribute
  name="email"                    // Field name
  factory={factoryFn}             // Value generator
  transform={transformFn}         // Value transformer
  required={true}                 // Validation
  unique={true}                   // Uniqueness check
/>

Props:

  • name: string - Field/column name
  • factory: (ctx) => any - Value generation function
  • transform?: (value) => any - Value transformation
  • required?: boolean - Field is required
  • unique?: boolean - Value must be unique

Examples

With Dependencies

// users.seed.tsx
export const UsersSeed = (
  <Seed name="users" adapter={adapter}>
    <Action count={50}>
      <Entity>
        <Attribute name="email" factory={faker.email()} />
        <Attribute name="name" factory={faker.fullName()} />
      </Entity>
    </Action>
  </Seed>
);

// posts.seed.tsx
export const PostsSeed = (
  <Seed name="posts" dependsOn="users" adapter={adapter}>
    <Action count={100}>
      <Entity factory={async (ctx) => {
        const users = await ctx.getSeed('users');
        return {
          userId: users[ctx.index % users.length].id,
        };
      }}>
        <Attribute name="title" factory={faker.sentence()} />
        <Attribute name="content" factory={faker.paragraph()} />
      </Entity>
    </Action>
  </Seed>
);

Conditional Seeding

<Seed name="demo-users" adapter={adapter}>
  <Action
    count={50}
    run={process.env.NODE_ENV === 'development'}
  >
    <Entity>
      <Attribute name="email" factory={faker.email()} />
    </Entity>
  </Action>

  <Action
    count={1}
    condition={async (ctx) => {
      const users = await ctx.getSeed('users');
      return users.length === 0;
    }}
  >
    <Entity data={{ email: '[email protected]', role: 'admin' }} />
  </Action>
</Seed>

Data Transformers

<Seed name="users" adapter={adapter}>
  <Action count={10}>
    <Entity>
      <Attribute
        name="email"
        factory={faker.email()}
        transform={(email) => email.toLowerCase()}
      />
      <Attribute
        name="password"
        factory={() => 'password123'}
        transform={hashPassword}
      />
      <Attribute
        name="createdAt"
        factory={() => new Date()}
      />
    </Entity>
  </Action>
</Seed>

Lifecycle Hooks

<Seed
  name="users"
  adapter={adapter}
  beforeInsert={(data) => {
    console.log(`Inserting ${data.length} users`);
    return data.map(user => ({
      ...user,
      createdAt: new Date(),
    }));
  }}
  afterInsert={(data, inserted) => {
    console.log(`Inserted ${inserted.length} users`);
  }}
  onSuccess={(data, metadata) => {
    console.log(`Success! Duration: ${metadata.duration}ms`);
  }}
  onError={(error) => {
    console.error('Seeding failed:', error);
  }}
>
  <Action count={100}>
    <Entity>
      <Attribute name="email" factory={faker.email()} />
    </Entity>
  </Action>
</Seed>

Multiple Actions

<Seed name="users" adapter={adapter}>
  {/* Admin users */}
  <Action count={5}>
    <Entity>
      <Attribute name="email" factory={faker.email()} />
      <Attribute name="role" factory={() => 'admin'} />
    </Entity>
  </Action>

  {/* Regular users */}
  <Action count={100}>
    <Entity>
      <Attribute name="email" factory={faker.email()} />
      <Attribute name="role" factory={() => 'user'} />
    </Entity>
  </Action>

  {/* Premium users */}
  <Action count={20}>
    <Entity>
      <Attribute name="email" factory={faker.email()} />
      <Attribute name="role" factory={() => 'premium'} />
      <Attribute name="subscriptionEnd" factory={() => {
        const date = new Date();
        date.setFullYear(date.getFullYear() + 1);
        return date;
      }} />
    </Entity>
  </Action>
</Seed>

Static Data

<Seed name="categories" adapter={adapter}>
  <Action count={1}>
    <Entity data={{
      name: 'Technology',
      slug: 'technology',
      order: 1,
    }} />
  </Action>
  <Action count={1}>
    <Entity data={{
      name: 'Science',
      slug: 'science',
      order: 2,
    }} />
  </Action>
</Seed>

With Faker Integration

import { faker } from '@seedts/faker';

<Seed name="users" adapter={adapter}>
  <Action count={100}>
    <Entity>
      <Attribute name="email" factory={faker.email()} />
      <Attribute name="firstName" factory={faker.firstName()} />
      <Attribute name="lastName" factory={faker.lastName()} />
      <Attribute name="age" factory={faker.int({ min: 18, max: 80 })} />
      <Attribute name="bio" factory={faker.paragraph()} />
      <Attribute name="avatar" factory={faker.imageUrl()} />
      <Attribute name="website" factory={faker.url()} />
    </Entity>
  </Action>
</Seed>

Execution Context

Access execution context in factory functions:

<Attribute
  name="email"
  factory={(ctx) => {
    // Current index (0-based)
    const index = ctx.index;

    // Total count
    const total = ctx.count;

    // Seed name
    const seedName = ctx.seedName;

    // Get data from other seeds
    const otherData = await ctx.getSeed('other-seed');

    return `user${index}@example.com`;
  }}
/>

Type Safety

Full TypeScript support with type inference:

type User = {
  id?: number;
  email: string;
  name: string;
  role: 'admin' | 'user';
};

export const UsersSeed = (
  <Seed<User> name="users" adapter={adapter}>
    <Action count={10}>
      <Entity>
        {/* TypeScript will enforce correct types */}
        <Attribute<User, 'email'>
          name="email"
          factory={(ctx) => `user${ctx.index}@example.com`}
        />
        <Attribute<User, 'role'>
          name="role"
          factory={() => 'user'} // Type-checked!
        />
      </Entity>
    </Action>
  </Seed>
);

Running JSX Seeds

import { Executor } from '@seedts/core';
import { UsersSeed } from './seeds/users.seed';
import { PostsSeed } from './seeds/posts.seed';

const executor = new Executor([UsersSeed, PostsSeed]);
await executor.execute();

API Reference

For detailed API documentation, visit:

Related Packages

Contributing

Contributions are welcome! Please see our Contributing Guide.

License

MIT © SeedTS Contributors