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

@curator-studio/sdk

v0.2.1

Published

TypeScript SDK and React hooks for the Curator Studio capital allocation protocol

Readme

@curator-studio/sdk

TypeScript SDK and React hooks for the Curator Studio capital allocation protocol.

Install

npm install @curator-studio/sdk

Core usage (Node scripts, non-React apps) only needs viem as a peer dependency.

React apps that use hooks should also install:

npm install @tanstack/react-query react wagmi viem

react, wagmi, and @tanstack/react-query are optional peers: the default @curator-studio/sdk entry is core-only (no React in the import graph). Hooks live under @curator-studio/sdk/react.

The published package bundles deployment artifacts from the monorepo’s contracts package at build time; you do not need to publish or install @curator-studio/contracts separately when consuming this SDK from npm.

Mutation hooks do not show toasts; handle success and errors in your UI (for example with React Query’s onSuccess / onError or a global handler).

Package exports

| Import path | Use case | |-------------|----------| | @curator-studio/sdk | CuratorSDK, indexer types, createIndexer, pure helpers (allocations, tokens, …) | | @curator-studio/sdk/react | CuratorProvider, useCuratorSDK, and all React Query hooks |

Quick Start

Standalone (no React)

import { CuratorSDK } from "@curator-studio/sdk";
import { zeroAddress } from "viem";

const sdk = new CuratorSDK(walletClient, {
  tenant: "support.eth",
  chain: 84532,
  indexerUrl: "https://your-indexer.example.com/graphql",
  uploadMetadata: async (metadata) => {
    // Upload JSON and return a public metadata URI
    return "https://example.com/meta/abc.json";
  },
});

const { strategy } = await sdk.strategy.create({
  owner: "0xYourAddress",
  sourceStrategy: zeroAddress,
  ensLabel: "my-strategy",
  metadata: {
    title: "My strategy",
    description: "Funding allocation",
  },
  allocations: [
    { recipient: "0xProjectA...", weight: 4000n, label: "Project A" },
    { recipient: "0xProjectB...", weight: 3500n, label: "Project B" },
    { recipient: "0xCurator...", weight: 2500n, label: "Curator Fee" },
  ],
});

await sdk.strategy.distribute(strategy, tokenAddress);

React

import { createUploadFn } from "@curator-studio/sdk";
import {
  CuratorProvider,
  useStrategies,
} from "@curator-studio/sdk/react";

function App() {
  return (
    <CuratorProvider
      tenant="support.eth"
      defaultChain={84532}
      indexerUrl="https://your-indexer.example.com/graphql"
      uploadMetadata={createUploadFn("/api/upload/metadata", "<server-upload-secret>")}
    >
      <StrategiesList />
    </CuratorProvider>
  );
}

function StrategiesList() {
  const { data, isPending } = useStrategies({
    orderBy: "timesForked",
    orderDirection: "desc",
    limit: 10,
  });

  if (isPending) return <div>Loading…</div>;
  return data?.items.map((s) => <div key={s.id}>{s.metadata?.title}</div>);
}

Types: allocations

Shared naming in @curator-studio/sdk:

  • OnChainAllocationweight: bigint (contracts / sdk.strategy)
  • IndexerAllocationweight: string (GraphQL indexer rows; also exported as deprecated alias Allocation on indexer types)
  • FormAllocationweight: number (forms and allocations.ts helpers)

Helpers such as toFormAllocations, toOnChainAllocations, and validateAllocations live on the main entry.

API

CuratorSDK

const sdk = new CuratorSDK(wallet?, options?)

| Option | Type | Description | |--------|------|-------------| | chain | SupportedChainId | Chain ID (1, 11155111, 84532, 31337) | | tenant | string | Tenant id (e.g. "support.eth"). Used for indexer tenant filter and tenant-specific factory addresses. | | indexerUrl | string | GraphQL endpoint for the indexer (required for createIndexer; empty string throws) | | uploadMetadata | UploadMetadataFn | Required for strategy.create / rebalance when using those methods |

sdk.strategy

| Method | Description | |--------|-------------| | create(config) | Deploy a new strategy | | getData(address) | Read on-chain strategy data | | balanceOf(address, token) | Token balance held by a strategy | | rebalance(address, allocations, metadata) | Update allocations (owner only) | | distribute(address, token) | Distribute funds to recipients | | setENSName(address, label) | Set ENS subdomain for a strategy |

sdk.warehouse

| Method | Description | |--------|-------------| | withdraw(owner, token) | Withdraw from SplitsWarehouse | | balanceOf(owner, token) | Check warehouse balance |

sdk.yieldRedirector

| Method | Description | |--------|-------------| | create(sourceVault, yieldRecipient, owner) | Deploy a yield redirector | | createDeterministic(sourceVault, yieldRecipient, owner, salt) | Deploy at a predictable address | | harvest(address) | Harvest yield and distribute | | surplus(address) | Check available yield | | principal(address) | Check deposited principal | | sourceVaultValue(address) | Total value in source vault | | setYieldRecipient(address, newRecipient) | Change yield recipient |

sdk.ens

| Method | Description | |--------|-------------| | available(label) | Check if ENS label is available | | register(label, owner?) | Register ENS subdomain | | getAddress(name) | Resolve ENS name to address | | setAddress(name, address) | Set forward resolution | | setReverseRecord(name) | Set reverse resolution | | registerWithAddress(label, address, owner?) | Register with forward + reverse resolution |

sdk.indexer.draft

Authenticated REST methods for managing off-chain strategy drafts. Requires authToken.

When the SDK is constructed with tenant, draft.create sends that tenant as tenantId automatically, and draft.list filters by it unless you pass tenantId explicitly.

| Method | Description | |--------|-------------| | create(input) | Create a new draft | | get(id) | Get a draft by ID | | list(params?) | List drafts (filterable by tenantId, curator, sourceStrategyId, sourceDraftId, mergeStatus, …) | | update(id, input) | Update draft title, description, or allocations (creates new version) | | fork(input) | Fork a strategy or draft (accepts sourceStrategyId or sourceDraftId) | | proposeMerge(id) | Propose merging a fork into its parent | | acceptMerge(id, input?) | Accept a merge proposal (parent owner) | | rejectMerge(id, input?) | Reject a merge proposal (parent owner) | | withdrawMerge(id) | Withdraw a merge proposal (fork author) | | updateVisibility(id, visibility) | Set draft visibility (private / unlisted / public) | | publish(id, onchainId) | Mark draft as published and link to on-chain strategy | | delete(id) | Soft-delete a draft |

sdk.indexer.comment

| Method | Description | |--------|-------------| | create(input) | Post a comment on a strategy or draft (supports parentCommentId for threads) | | list(params) | List comments for a target (targetId + targetType required) | | update(id, body) | Edit a comment body | | delete(id) | Soft-delete a comment |

sdk.indexer.reaction

| Method | Description | |--------|-------------| | toggle(input) | Toggle an upvote or flag on a comment, draft, or strategy | | get(targetId, targetType) | Get reaction counts and the current user's reactions |

sdk.indexer.notification

| Method | Description | |--------|-------------| | list(params?) | List notifications for the authenticated user | | unreadCount() | Get the number of unread notifications | | markRead() | Mark all notifications as read | | markOneRead(id) | Mark a single notification as read |

React hooks (@curator-studio/sdk/react)

Provider and auth

<CuratorProvider
  tenant="support.eth"
  defaultChain={11155111}
  indexerUrl="https://..."
  uploadMetadata={createUploadFn("/api/upload", secret)}
>

CuratorProvider exposes authToken / setAuthToken via useCuratorSDK(). When set, the token is sent as Bearer for REST APIs (drafts, comments, reactions, notifications).

const { setAuthToken } = useCuratorSDK();
setAuthToken(jwt);

Strategy query hooks

| Hook | Description | |------|-------------| | useCuratorSDK() | Access the SDK instance | | useStrategies(variables?) | List strategies | | useStrategyById(id) | Get strategy by address | | useStrategyData(address) | On-chain strategy data | | useStrategyBalance(address, token) | On-chain token balance | | useDistributions(variables?) | List distributions | | usePayouts(variables?) | List payouts | | useDonors(variables?) | List donors | | useStrategyBalances(variables?) | List strategy balances | | useForks(variables?) | List forks | | useWarehouseBalances(variables?) | List warehouse balances | | useWarehouseBalance(user, token) | Single warehouse balance | | useYieldRedirectors(variables?) | List yield redirectors | | useYieldRedirectorById(id) | Get yield redirector by address | | useHarvests(variables?) | List harvests | | useTrendingStrategies(options?) | Trending strategies | | useProtocolStats() | Protocol-wide stats | | useStrategyLineage(address) | Fork tree | | useENSGetAddress(name) | Resolve ENS name | | useENSAvailable(label) | Check ENS availability | | useCuratorStats(address) | Get curator stats (strategies, drafts, forks) |

Strategy mutation hooks

| Hook | Description | |------|-------------| | useCreateStrategy() | Create a strategy | | useRebalanceStrategy() | Rebalance allocations | | useDistributeStrategy() | Distribute funds | | useSetENSName() | Set ENS name | | useWithdrawFromWarehouse() | Withdraw from warehouse | | useCreateYieldRedirector() | Create yield redirector | | useHarvestYield() | Harvest yield |

Draft hooks

| Hook | Description | |------|-------------| | useDrafts(params?, opts?) | List drafts with optional filters | | useDraft(id, opts?) | Get a single draft by ID | | useDraftForks(source, params?, opts?) | List forks of a strategy or draft (source: { sourceStrategyId } \| { sourceDraftId }) | | useVersions(draftId, opts?) | List version history for a draft | | useCreateDraft() | Create a new draft | | useUpdateDraft() | Update a draft ({ id, ...input }) | | useForkDraft() | Fork a strategy or draft ({ sourceStrategyId } \| { sourceDraftId }) | | usePublishDraft() | Publish draft on-chain ({ draftId, ensLabel? }) | | useDeleteDraft() | Delete a draft | | useProposeMerge() | Propose merging a fork into its parent | | useAcceptMerge() | Accept a merge proposal (calls rebalance() for strategy targets) | | useRejectMerge() | Reject a merge proposal ({ draftId, reason? }) | | useWithdrawMerge() | Withdraw a merge proposal | | useUpdateDraftVisibility() | Change draft visibility ({ id, visibility }) |

Comment hooks

| Hook | Description | |------|-------------| | useComments(params, opts?) | List comments for a target | | useCreateComment() | Post a comment ({ targetId, targetType, body, parentCommentId? }) | | useUpdateComment() | Edit a comment ({ id, body }) | | useDeleteComment() | Delete a comment |

Reaction hooks

| Hook | Description | |------|-------------| | useReactions(targetId, targetType, opts?) | Get reaction counts for a target | | useToggleReaction() | Toggle a reaction ({ targetId, targetType, type }) |

Notification hooks

| Hook | Description | |------|-------------| | useNotifications(params?, opts?) | List notifications (requires auth) | | useUnreadNotificationCount(opts?) | Unread count (polls every 30s by default) | | useMarkNotificationsRead() | Mark one or all notifications read (id?) |

Utility hooks

| Hook | Description | |------|-------------| | useInvalidate() | Invalidate query cache keys | | useInvalidateENS() | Invalidate ENS-related queries |

Development

From the monorepo root:

pnpm --filter @curator-studio/sdk test
pnpm --filter @curator-studio/sdk build

Optional on-chain integration test (requires local Hardhat on http://127.0.0.1:8545 with deployments matching deployments.json for chain 31337):

RUN_SDK_CHAIN_TESTS=1 pnpm --filter @curator-studio/sdk test -- src/__tests__/strategy-lifecycle.test.ts

Supported chains

| Network | Chain ID | |---------|----------| | Mainnet | 1 | | Sepolia | 11155111 | | Base Sepolia | 84532 | | Hardhat | 31337 |

License

MIT