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

@ic-reactor/cli

v0.0.0-beta.1

Published

CLI tool to generate shadcn-style React hooks for ICP canisters

Readme

@ic-reactor/cli

🔧 Generate shadcn-style React hooks for ICP canisters

The @ic-reactor/cli generates customizable, user-owned React hooks for interacting with Internet Computer canisters. Unlike build-time code generation, you get full control over the generated code.

Philosophy

Like shadcn/ui, this CLI generates code into your project rather than hiding it in node_modules. This means:

  • Full control - Customize hooks to your needs
  • No magic - See exactly what's happening
  • Version controlled - Hooks are part of your codebase
  • Framework agnostic - Works with any React setup

Installation

npm install -D @ic-reactor/cli
# or
pnpm add -D @ic-reactor/cli

Quick Start

1. Initialize your project

npx @ic-reactor/cli init

This creates:

  • reactor.config.json - Configuration file
  • src/lib/client.ts - Client manager (optional)
  • src/canisters/ - Output directory for hooks

2. Add hooks for a canister

npx @ic-reactor/cli add

Interactive prompts will guide you through:

  1. Selecting a canister
  2. Choosing methods to generate hooks for
  3. Selecting hook types (Query, Suspense Query, Infinite Query, Mutation)

3. Use the hooks

import { useGetMessageQuery, getMessageQuery } from "./canisters/backend/hooks"

function MyComponent() {
  // Use the React hook
  const { data, isLoading } = useGetMessageQuery()

  // Or fetch directly (for loaders, etc.)
  await getMessageQuery.fetch()

  // Invalidate cache
  await getMessageQuery.invalidate()
}

Commands

init

Initialize ic-reactor in your project.

npx @ic-reactor/cli init [options]

Options:
  -y, --yes              Skip prompts and use defaults
  -o, --out-dir <path>   Output directory for generated hooks

add

Add hooks for canister methods (from local .did file).

npx @ic-reactor/cli add [options]

Options:
  -c, --canister <name>      Canister to add hooks for
  -m, --methods <methods...> Specific methods to generate
  -a, --all                  Add hooks for all methods

fetch

Fetch Candid from a live canister and generate hooks. No local .did file needed!

npx @ic-reactor/cli fetch [options]

Options:
  -i, --canister-id <id>     Canister ID to fetch from
  -n, --network <network>    Network: 'ic' or 'local' (default: ic)
  --name <name>              Name for the canister in generated code
  -m, --methods <methods...> Specific methods to generate
  -a, --all                  Add hooks for all methods

Example:

# Fetch from IC mainnet
npx @ic-reactor/cli fetch -i ryjl3-tyaaa-aaaaa-aaaba-cai

# Fetch from local replica
npx @ic-reactor/cli fetch -i bkyz2-fmaaa-aaaaa-qaaaq-cai -n local

list

List available methods from a canister.

npx @ic-reactor/cli list [options]

Options:
  -c, --canister <name>   Canister to list methods from

sync

Regenerate hooks after DID file changes.

npx @ic-reactor/cli sync [options]

Options:
  -c, --canister <name>   Canister to sync (default: all)

Configuration

reactor.config.json

{
  "$schema": "https://raw.githubusercontent.com/B3Pay/ic-reactor/main/packages/cli/schema.json",
  "outDir": "src/canisters",
  "canisters": {
    "backend": {
      "didFile": "./backend.did",
      "clientManagerPath": "../../lib/client",
      "useDisplayReactor": true
    }
  },
  "generatedHooks": {
    "backend": ["get_message", "set_message"]
  }
}

Configuration Options

| Option | Description | | ------------------------------------ | ----------------------------------------- | | outDir | Directory where hooks are generated | | canisters | Canister configurations | | canisters.<name>.didFile | Path to the .did file | | canisters.<name>.clientManagerPath | Import path to client manager | | canisters.<name>.useDisplayReactor | Use DisplayReactor for type transforms | | generatedHooks | Tracks which methods have hooks generated |

Generated File Structure

src/canisters/
├── backend/
│   ├── reactor.ts              # Shared reactor instance
│   └── hooks/
│       ├── index.ts            # Barrel exports
│       ├── getMessageQuery.ts  # Query hook
│       ├── setMessageMutation.ts # Mutation hook
│       └── getPostsInfiniteQuery.ts # Infinite query

Hook Types

Query (methods without side effects)

// For methods WITH arguments - factory pattern
export const getUserQuery = createQueryFactory(reactor, {
  functionName: "get_user",
})

// Usage
const query = getUserQuery([userId])
const { data } = query.useQuery()

// For methods WITHOUT arguments - static instance
export const getConfigQuery = createQuery(reactor, {
  functionName: "get_config",
})

// Usage
const { data } = getConfigQuery.useQuery()
await getConfigQuery.fetch()

Mutation (methods with side effects)

export const setMessageMutation = createMutation(reactor, {
  functionName: "set_message",
  invalidateQueries: [getMessageQuery.getQueryKey()],
})

// Usage
const { mutate, isPending } = setMessageMutation.useMutation()
mutate(["Hello, ICP!"])

Infinite Query (paginated data)

export const getPostsInfiniteQuery = createInfiniteQuery(reactor, {
  functionName: "get_posts",
  initialPageParam: 0,
  getArgs: (cursor) => [{ cursor, limit: 10 }],
  getNextPageParam: (lastPage) => lastPage.nextCursor ?? undefined,
})

// Usage
const { data, fetchNextPage, hasNextPage } =
  getPostsInfiniteQuery.useInfiniteQuery()
const allPosts = data?.pages.flatMap((page) => page.items) ?? []

Customization

Since the code is generated into your project, you can:

  1. Modify hook options - Change staleTime, select transforms, etc.
  2. Add custom logic - Error handling, optimistic updates
  3. Combine hooks - Create composite hooks
  4. Type overrides - Adjust TypeScript types

Example customization:

// getMessageQuery.ts (generated, then customized)
export const getMessageQuery = createQuery(reactor, {
  functionName: "get_message",
  staleTime: 30 * 1000, // Custom: 30 seconds
  select: (data) => data.message.toUpperCase(), // Custom transform
})

Requirements

  • Node.js 18+
  • @ic-reactor/react 3.x
  • React 18+

License

MIT