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 🙏

© 2025 – Pkg Stats / Ryan Hefner

rootstockwinks

v1.2.10

Published

A NextJS component that populates meta tags based on API key

Readme

Winks SDK (Rootstock)

A React/Next.js SDK that automatically populates SEO meta tags from a secure API and provides Rootstock-ready wallet integration, token/NFT utilities, signature management, and RPC failover.

Features

  • 🚀 Easy Integration: drop-in Winks wrapper for Next.js
  • 🔑 API-keyed metadata management (server included)
  • 📱 Social meta: Open Graph, Twitter Cards
  • 🎯 Full SEO meta coverage
  • 💰 Token utilities: ERC-20 transfer/approve/balance/allowance
  • 🎨 NFT utilities: ERC-721 owner, ERC-721/1155 transfers, ERC-1155 balance
  • 🔗 Rootstock ready (Testnet 31) — SDK defaults to Testnet in the example app
  • 🌐 Wallet integration via RainbowKit + WalletConnect (styles auto-injected)
  • ✍️ Signature management (tx/message/personal/typed data)
  • 🔄 Network switching helpers
  • 🧭 RPC Management with health checks and latency-based selection
  • 🧩 EIP-1193 Provider adapter (MetaMask et al.)
  • 🧯 Signature queueing to avoid overlapping prompts
  • 🛠️ Dual builds (Rollup + Vite) outputting CJS + ESM
  • ✅ Testing setup (Jest unit, Playwright E2E)

Installation

npm install rootstockwinks

Quick Start (Next.js)

// pages/_app.js or app/layout.js
import { Winks } from 'rootstockwinks';

export default function App({ Component, pageProps }) {
  return (
    <Winks apikey="YOUR_API_KEY">
      <Component {...pageProps} />
    </Winks>
  );
}

Start the local metadata server and create an API key:

cd server
npm install
npm run build
npm start

# Create API Key
curl -X POST http://localhost:3001/api/keys \
  -H "Content-Type: application/json" \
  -d '{"name": "My Website"}'

# Set metadata
curl -X POST http://localhost:3001/api/meta/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "title": "My Awesome Website",
    "description": "The best website ever created",
    "ogTitle": "My Awesome Website",
    "ogDescription": "The best website ever created",
    "ogImage": "https://example.com/og-image.jpg",
    "ogUrl": "https://example.com",
    "twitterCard": "summary_large_image",
    "twitterTitle": "My Awesome Website",
    "twitterDescription": "The best website ever created",
    "twitterImage": "https://example.com/twitter-image.jpg",
    "canonical": "https://example.com",
    "robots": "index, follow",
    "viewport": "width=device-width, initial-scale=1",
    "charset": "utf-8",
    "author": "Your Name"
  }'

WalletConnect project ID (RainbowKit)

RainbowKit requires a WalletConnect project ID. Set it in your app (for the example app, create example/.env.local):

NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=YOUR_PROJECT_ID

Winks Component

Props:

  • apikey: string required
  • children: ReactNode required
  • fallback?: MetaData (used if server fetch fails)

MetaData shape:

interface MetaData {
  title?: string;
  description?: string;
  keywords?: string;
  ogTitle?: string;
  ogDescription?: string;
  ogImage?: string;
  ogUrl?: string;
  twitterCard?: string;
  twitterTitle?: string;
  twitterDescription?: string;
  twitterImage?: string;
  canonical?: string;
  robots?: string;
  viewport?: string;
  charset?: string;
  author?: string;
}

RPC Manager

import { RpcManager } from 'rootstockwinks';

const rpc = new RpcManager();
const provider = rpc.createProvider('mainnet'); // or 'testnet'
const bestUrl = rpc.getBestRpcUrl('mainnet');
// Health snapshot
const health = rpc.getHealth('mainnet');
  • Periodic health checks (eth_blockNumber) with timeouts
  • Chooses lowest-latency healthy endpoint; fails over automatically

EIP-1193 Provider Adapter

import { Eip1193Provider } from 'rootstockwinks';

const eip = new Eip1193Provider(window.ethereum);
await eip.request({ method: 'eth_requestAccounts' });

Signature Manager (Queued)

import { SignatureManager, Eip1193Provider } from 'rootstockwinks';

const sm = new SignatureManager(new Eip1193Provider(window.ethereum));
// Requests are queued to avoid multiple wallet prompts
await sm.requestTransactionSignature({ to: '0x...', value: 0n });
await sm.requestMessageSignature('Hello Rootstock');
await sm.requestPersonalSignature('Personal message');
await sm.requestTypedDataSignature({ domain, types, value });

Wallet Integration (RainbowKit + wagmi)

Wrap your app:

import { WalletProvider } from 'rootstockwinks';

export default function App({ Component, pageProps }) {
  return (
    <WalletProvider>
      <Component {...pageProps} />
    </WalletProvider>
  );
}

Use the connection UI:

import { WalletConnection } from 'rootstockwinks';

function MyComponent() {
  return <WalletConnection showBalance showNetwork />;
}

Advanced hook:

import { useWalletIntegration } from 'rootstockwinks';

const {
  walletState,
  connectWallet,
  disconnectWallet,
  switchToRootstockMainnet,
  switchToRootstockTestnet,
  requestTransactionSignature,
  requestMessageSignature,
  requestPersonalSignature,
  requestTypedDataSignature,
  sendTransaction,
} = useWalletIntegration();
  • sendTransaction(to, value) now powers the example app’s “Send tRBTC” flow and sends native tRBTC on Rootstock Testnet.

Send native tRBTC:

const result = await sendTransaction('0xRecipient', '0.05');
if (result.success) {
  console.log('tx hash', result.txHash);
} else {
  console.error(result.error);
}

Enhanced Token Transfer Hook

import { useEnhancedTokenTransfer } from 'rootstockwinks';

const {
  transferERC20,
  transferNFT,
  approveToken,
  getTokenBalance,
  getNFTOwner,
  getTokenAllowance,
  ensureRootstockNetwork,
  address,
  isConnected,
} = useEnhancedTokenTransfer();
  • Use this hook for ERC-20/ERC-721/ERC-1155 contracts. For native tRBTC, prefer useWalletIntegration().sendTransaction.

Simple Token/NFT Functions

import {
  transferERC20,
  approveToken,
  getTokenBalance,
  getTokenAllowance,
  getNFTOwner,
  transferNFT,
} from 'rootstockwinks';
import { ethers } from 'ethers';

const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();

await transferERC20('0xToken', '0xRecipient', '1.0', signer);
await approveToken('0xToken', '0xSpender', '100.0', signer);
const bal = await getTokenBalance('0xToken', '0xAccount', provider);
const allowance = await getTokenAllowance('0xToken', '0xOwner', '0xSpender', provider);
const owner = await getNFTOwner('0xNft', '123', provider);
await transferNFT('0xNft', '0xFrom', '0xTo', '123', signer);

Network Configuration

  • Rootstock Mainnet: Chain ID 30, RPC https://public-node.rsk.co, Explorer https://explorer.rootstock.io, Currency RBTC
  • Rootstock Testnet: Chain ID 31, RPC https://public-node.testnet.rsk.co, Explorer https://explorer.testnet.rootstock.io, Currency tRBTC

Server API (local metadata server)

  • GET /health
  • POST /api/keys{ id, key, name, createdAt, isActive }
  • GET /api/keys (auth)
  • DELETE /api/keys/:key (auth)
  • GET /api/meta/:apiKey → returns MetaData
  • POST /api/meta/:apiKey (auth) { metadata: MetaData }
  • PUT /api/meta/:apiKey (auth) { metadata: MetaData }
  • DELETE /api/meta/:apiKey (auth)

Auth header: X-API-Key: {apiKey}

Development

Build

npm run build           # TypeScript + Rollup (CJS + ESM)
npm run build:vite      # Vite library build (optional)

Testing

npm test                # Jest unit tests
npx playwright install chromium
npm run test:e2e        # Playwright (ensure example app is running or use a prod build)

License

MIT

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Commit your changes: git commit -m 'Add some amazing feature'
  4. Push: git push origin feature/amazing-feature
  5. Open a Pull Request