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

mirrorworld-sonic-hyperfuse-node-sdk

v0.1.5

Published

TypeScript SDK for client-side WebSocket connection with validator backend to validate batch block hash

Readme

Hyperfuse Client SDK

TypeScript SDK for client-side WebSocket connection with validator backend to validate batch block hash in client side.

npm version License: MIT

Features

  • 🔌 WebSocket-based real-time validator connection
  • 🔐 Secure keypair management with AES encryption
  • 🌐 Support for both browser and Node.js environments
  • 📦 Service Worker support for background validation
  • 🎯 Comprehensive API coverage for validators, delegations, rewards, and voting

Installation

npm install mirrorworld-sonic-hyperfuse-node-sdk

or

yarn add mirrorworld-sonic-hyperfuse-node-sdk

Quick Start

Initialize SDK

import { SDK } from 'mirrorworld-sonic-hyperfuse-node-sdk';
import { Keypair } from '@solana/web3.js';
import bs58 from 'bs58';

// Initialize SDK
const sdk = new SDK({
  sonicRpc: process.env.SONIC_RPC!,
  backendDomain: process.env.BACKEND_DOMAIN!,
  backendWssDomain: process.env.BACKEND_WSS_DOMAIN!,
  runtime: 'browser', // or 'node'
});

Configuration Options

| Option | Type | Required | Description | Default | |--------|------|----------|-------------|---------| | sonicRpc | string | Yes | Sonic RPC endpoint URL | - | | backendDomain | string | Yes | Backend API domain URL | - | | backendWssDomain | string | Yes | Backend WebSocket domain URL | - | | runtime | 'browser' | 'node' | No | Runtime environment | 'browser' | | storage | KeypairStorage | No | Custom storage implementation | localStorage | | backendWssEndpoint | string | No | Custom WebSocket endpoint | 'ws/node/light_client' | | heartBeatInterval | number | No | WebSocket heartbeat interval (ms) | 15000 | | limitConcurrency | number | No | Concurrent connection limit | 3 | | retryTimes | number | No | Connection retry attempts | 3 | | secretKeyPrefix | string | No | Storage key prefix | 'KEY_FOR_ADDR_' | | hexKey | string | No | AES encryption key (hex) | (default key) | | hexIv | string | No | AES encryption IV (hex) | (default IV) |

API Reference

User API

Add User

Register a new user in the system.

const keypair = Keypair.fromSecretKey(bs58.decode(process.env.USER_SECRET!));

const result = await sdk.user.addUser({
  owner: keypair.publicKey.toBase58(),
  receive_rewards_account: 'REWARD_ACCOUNT_ADDRESS',
  name: 'My Username', // optional
  sign_callback: async (msg: Uint8Array) => {
    return keypair.sign(msg).signature;
  }
});

Get User Info

Retrieve user information including NFT nodes, rewards, and delegation stats.

const userInfo = await sdk.user.getUser('USER_WALLET_ADDRESS');

// Response includes:
// - owner: string
// - name: string
// - receive_rewards_account: string
// - all_rewards: string
// - node_work_load: number
// - validator_work_load: number
// - all_nft_nodes: number
// - running_nodes: number
// - other_delegated_nft_nodes: number
// - remain_nft_nodes: number
// - stake_amount: string
// - auto_stake: boolean

Change Rewards Account

Update the account where rewards will be sent.

const result = await sdk.user.changeReceiveRewardsAccount({
  owner: keypair.publicKey.toBase58(),
  receive_rewards_account: 'NEW_REWARD_ACCOUNT_ADDRESS',
  sign_callback: async (msg: Uint8Array) => {
    return keypair.sign(msg).signature;
  }
});

Refresh User NFT Nodes

Sync user NFT information from on-chain to backend.

const result = await sdk.user.refreshUserNftNode('USER_WALLET_ADDRESS');

Get User Activity

Retrieve user activity history with pagination.

const activities = await sdk.user.getActivity({
  owner: 'USER_WALLET_ADDRESS',
  action_type: 1, // Optional: 1=delegate, 2=undelegate, 3=run node, 4=disable node, 5=create validator, 6=receive return nodes
  page_index: 0,
  page_size: 20,
  sort_type: 'create_at,desc' // Optional: sort by field,order
});

Validator API

Register Validator

Create and register a new validator node with automatic keypair storage.

const validatorKeypair = Keypair.generate();
const ownerKeypair = Keypair.fromSecretKey(bs58.decode(process.env.OWNER_SECRET!));

const result = await sdk.registerValidatorForLocalStorage({
  owner: ownerKeypair.publicKey.toBase58(),
  keypair: validatorKeypair,
  name: 'My Validator',
  max_delegate_num: 1000,
  delegate_fee: 5, // 5% commission
  delegate_nft_node_num: 10,
  sign_callback: async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  }
});

Get Validators

Query validators with flexible filtering.

const validators = await sdk.validator.getValidators({
  owner: 'OWNER_WALLET_ADDRESS', // Optional: filter by owner
  show_delegatable: 'true', // Optional: show only validators accepting delegations
  page_index: 0,
  page_size: 20,
  sort_type: 'last_1_day_online_perc,desc' // Sort by daily uptime
});

// Each validator includes:
// - pk: string (validator address)
// - name: string
// - is_online: boolean
// - all_online_time: number
// - all_online_perc: number
// - last_1_day_online_perc: number (Daily Uptime)
// - last_7_day_online_perc: number
// - rewards: number
// - work_load: number
// - max_delegate_num: number
// - current_delegate_num: number
// - owner_delegate_num: number
// - delegate_fee: number
// - status: number

Get Delegated Validators for User

Get validators that a user has delegated to.

const delegatedValidators = await sdk.validator.getDelegetedValidatorsForUser({
  delegated_user: 'USER_WALLET_ADDRESS',
  page_index: 0,
  page_size: 20
});

Get Brief Validator Stats

Get summary statistics for validators.

const briefInfo = await sdk.validator.getBriefValidators('OWNER_WALLET_ADDRESS');

// Returns:
// - validator_num: number
// - delegated_num: number
// - community_num: number
// - running_num: number
// - not_running_num: number
// - avg_daily_uptime: number

Disable Validator

Disable a validator and stop its WebSocket connection.

const result = await sdk.disableValidatorForLocalStorage({
  owner: ownerKeypair.publicKey.toBase58(),
  validator: 'VALIDATOR_PUBLIC_KEY',
  sign_callback: async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  }
});

Re-import Validator

Re-import an existing validator's private key.

const validatorKeypair = Keypair.fromSecretKey(bs58.decode(process.env.VALIDATOR_SECRET!));

const result = await sdk.reImportSecretForLocalStorage({
  validator: 'VALIDATOR_PUBLIC_KEY',
  keypair: validatorKeypair
});

Delegation API

Delegate to Validator

Delegate NFT nodes to a validator.

const result = await sdk.delegation.delegateTo({
  owner: ownerKeypair.publicKey.toBase58(),
  validator: 'VALIDATOR_PUBLIC_KEY',
  num: 10, // Number of NFT nodes to delegate
  sign_callback: async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  }
});

Undelegate from Validator

Remove delegated NFT nodes from a validator (note: validators cannot undelegate their own nodes).

const result = await sdk.delegation.undelegate({
  owner: ownerKeypair.publicKey.toBase58(),
  validator: 'VALIDATOR_PUBLIC_KEY',
  num: 5, // Number of NFT nodes to undelegate
  sign_callback: async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  }
});

Get Delegation Info

Query delegation information with filtering.

const delegationInfo = await sdk.delegation.getDelegationInfo({
  validator: 'VALIDATOR_PUBLIC_KEY', // Optional
  owner: 'OWNER_WALLET_ADDRESS', // Optional
  if_exclude_owner: 'true', // Optional: exclude validator owner's delegation
  page_index: 0,
  page_size: 20
});

// Each delegation record includes:
// - owner: string (delegator address)
// - delegate_to: string (validator address)
// - delegate_num: number (number of NFT nodes)

Reward API

Get Rewards Activity

Retrieve rewards activity history.

const rewardsActivity = await sdk.reward.getRewardsActivity({
  owner: 'USER_WALLET_ADDRESS',
  action_type: 0, // Optional: 0=node rewards, 1=validator rewards as delegator, 2=claim rewards
  page_index: 0,
  page_size: 20
});

// Each activity includes:
// - id: string
// - owner: string
// - amount: number
// - action_type: number
// - other_address: string
// - desc: string
// - create_at: number

Get Rewards Chart Data

Get historical rewards data for charting.

const rewardsData = await sdk.reward.getRewardsData({
  owner: 'USER_WALLET_ADDRESS',
  start_time: '2024-01-01' // ISO date string
});

Claim Rewards

Claim accumulated rewards (two-step process).

// Step 1: Prepare claim request
const claimRequest = await sdk.reward.claimRewards({
  owner: ownerKeypair.publicKey.toBase58(),
  claim_rewards: '1000.5', // Amount to claim
  sign_callback: async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  }
});

// Step 2: Process the claim
const result = await sdk.reward.processClaimRewards({
  base64_tx: claimRequest.data.base64_tx,
  sign_data: claimRequest.data.sign_data,
  extra_data: claimRequest.data.extra_data
});

Change Stake Amount

Adjust the amount of rewards to stake.

const result = await sdk.reward.changeStakeAmount({
  owner: ownerKeypair.publicKey.toBase58(),
  amount: 100, // Amount to stake
  sign_callback: async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  }
});

Change Auto-Stake Setting

Enable or disable automatic staking of rewards.

const result = await sdk.reward.changeAutoStake({
  owner: 'USER_WALLET_ADDRESS',
  auto_stake: true
});

Get Stake Amount Records

Retrieve staking history.

const records = await sdk.reward.getStakeAmountRecord({
  owner: 'USER_WALLET_ADDRESS',
  change_type: 0, // 0=increase, 1=decrease, 2=auto stake
  page_index: 0,
  page_size: 20
});

Sync On-chain Rewards

Synchronize on-chain rewards data.

const result = await sdk.reward.syncOnchainRewards('WALLET_ADDRESS');

Vote API

Get Voting Projects

Retrieve available voting projects.

const projects = await sdk.vote.getVotingProjects({
  id: 'PROJECT_ID', // Optional: filter by project ID
  page_index: 0,
  page_size: 20
});

Get Voting Records

Query voting history.

const votingRecords = await sdk.vote.getVotingRecords({
  user: 'USER_WALLET_ADDRESS', // Optional
  project_id: 'PROJECT_ID', // Optional
  page_index: 0,
  page_size: 20
});

Vote for Project

Cast a vote on a project.

const result = await sdk.vote.voteForProject({
  user: userKeypair.publicKey.toBase58(),
  project_id: 'PROJECT_ID',
  amount: 100, // Must be a positive integer
  vote_type: 0, // 0=vote yes, 1=vote no
  sign_callback: async (msg: Uint8Array) => {
    return userKeypair.sign(msg).signature;
  }
});

Get User Voting Stats

Get voting statistics for a user.

const stats = await sdk.vote.getUserVotingStats({
  user: 'USER_WALLET_ADDRESS'
});

WebSocket Listener (Node.js)

Start Validator WebSocket

In Node.js environment, start a single validator WebSocket connection.

const validatorKeypair = Keypair.fromSecretKey(bs58.decode(process.env.VALIDATOR_SECRET!));

await sdk.listener.startClientValidator(validatorKeypair);

Start All Validators

Start all validators stored in local storage (automatically filters validators with keys).

const ownerAddress = 'OWNER_WALLET_ADDRESS';
await sdk.startAllValidatorFromLocalStorage(ownerAddress);

Close WebSocket

await sdk.listener.closeWebSocket('VALIDATOR_PUBLIC_KEY');

Service Worker Support (Browser)

For browser environments, the SDK supports running validators in a Service Worker for background processing.

Build Service Worker

Generate the service worker file:

yarn webpack

This creates dist/hyperfuseServiceWorker.js.

Register Service Worker

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/hyperfuseServiceWorker.js')
    .then(registration => {
      console.log('Service Worker registered:', registration);
    });
}

Service Worker Commands

Get WebSocket State

sdk.getTimestampForWsStateInServiceWorker();

Start Validator in Service Worker

sdk.startValidatorInServiceWorker('VALIDATOR_PUBLIC_KEY');

Stop Validator in Service Worker

sdk.stopValidatorInServiceWorker('VALIDATOR_PUBLIC_KEY');

Local Storage Management

Store Keypair

const keypair = Keypair.generate();
sdk.storeSecretInLocalStorage(keypair);

Get Keypair from Storage

const secretKey = sdk.getSecretInLocalStorage('PUBLIC_KEY');
if (secretKey) {
  const keypair = Keypair.fromSecretKey(bs58.decode(secretKey));
}

Remove Keypair

sdk.removeSecretInLocalStorage('PUBLIC_KEY');

Get Cached Validators

Get list of validators with keys in local storage (with caching).

const validators = await sdk.getCachedValidators('OWNER_WALLET_ADDRESS');
// Returns array of validator public keys

Response Format

All API methods return a standard response format:

interface ApiResponse<T> {
  code: number;      // 0 = success, non-zero = error
  data: T;           // Response data
  err_msg: string;   // Error message (empty on success)
}

Paginated Responses

List endpoints return paginated data:

interface PageResp<T> {
  total_count: number;  // Total number of items
  list: T[];            // Current page items
}

Pagination Parameters

interface PageReq {
  page_index?: number;  // Page number (starts from 0)
  page_size?: number;   // Items per page
  sort_type?: string;   // e.g., "create_at,desc" or "status,asc"
}

Error Handling

try {
  const result = await sdk.user.getUser('WALLET_ADDRESS');
  
  if (result.code === 0) {
    console.log('Success:', result.data);
  } else {
    console.error('API Error:', result.err_msg);
  }
} catch (error) {
  console.error('Network Error:', error);
}

Advanced Examples

Complete Validator Setup

import { SDK } from 'mirrorworld-sonic-hyperfuse-node-sdk';
import { Keypair } from '@solana/web3.js';
import bs58 from 'bs58';

async function setupValidator() {
  // Initialize SDK
  const sdk = new SDK({
    sonicRpc: process.env.SONIC_RPC!,
    backendDomain: process.env.BACKEND_DOMAIN!,
    backendWssDomain: process.env.BACKEND_WSS_DOMAIN!,
    runtime: 'node'
  });

  // Create keypairs
  const ownerKeypair = Keypair.fromSecretKey(bs58.decode(process.env.OWNER_SECRET!));
  const validatorKeypair = Keypair.generate();

  // Sign callback
  const signCallback = async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  };

  // Register user if needed
  await sdk.user.addUser({
    owner: ownerKeypair.publicKey.toBase58(),
    receive_rewards_account: ownerKeypair.publicKey.toBase58(),
    name: 'My Node',
    sign_callback: signCallback
  });

  // Register validator
  const result = await sdk.registerValidatorForLocalStorage({
    owner: ownerKeypair.publicKey.toBase58(),
    keypair: validatorKeypair,
    name: 'My Validator Node',
    max_delegate_num: 1000,
    delegate_fee: 5,
    delegate_nft_node_num: 10,
    sign_callback: signCallback
  });

  console.log('Validator registered:', result);
}

setupValidator();

Monitor Validator Performance

async function monitorValidator(validatorPk: string) {
  // Get validator info
  const validators = await sdk.validator.getValidators({
    owner: ownerAddress,
    page_index: 0,
    page_size: 1000
  });

  const validator = validators.data.list.find(v => v.pk === validatorPk);
  
  if (validator) {
    console.log({
      name: validator.name,
      isOnline: validator.is_online,
      dailyUptime: validator.last_1_day_online_perc,
      weeklyUptime: validator.last_7_day_online_perc,
      totalRewards: validator.rewards,
      delegations: validator.current_delegate_num,
      commission: validator.delegate_fee
    });
  }
}

Delegate and Claim Workflow

async function delegateAndClaim() {
  const ownerKeypair = Keypair.fromSecretKey(bs58.decode(process.env.OWNER_SECRET!));
  const signCallback = async (msg: Uint8Array) => {
    return ownerKeypair.sign(msg).signature;
  };

  // Delegate nodes
  await sdk.delegation.delegateTo({
    owner: ownerKeypair.publicKey.toBase58(),
    validator: 'VALIDATOR_PUBLIC_KEY',
    num: 10,
    sign_callback: signCallback
  });

  // Check rewards after some time
  const userInfo = await sdk.user.getUser(ownerKeypair.publicKey.toBase58());
  console.log('Total rewards:', userInfo.data.all_rewards);

  // Claim rewards
  const claimRequest = await sdk.reward.claimRewards({
    owner: ownerKeypair.publicKey.toBase58(),
    claim_rewards: userInfo.data.all_rewards,
    sign_callback: signCallback
  });

  await sdk.reward.processClaimRewards({
    base64_tx: claimRequest.data.base64_tx,
    sign_data: claimRequest.data.sign_data,
    extra_data: claimRequest.data.extra_data
  });
}

TypeScript Support

The SDK is written in TypeScript and provides full type definitions. Import types as needed:

import {
  SDK,
  Config,
  ValidatorInfo,
  DelegatationInfo,
  RewardsActivity,
  GetUserResp,
  ApiResponse,
  PageResp
} from 'mirrorworld-sonic-hyperfuse-node-sdk';

Development

Build

Build both CommonJS and ES modules:

yarn build

Testing

Run tests:

yarn test

Run specific test:

yarn test tests/validator.test.ts

Build Service Worker

yarn webpack

Publishing

yarn build
yarn publish

Environment Variables

Create a .env file for local development:

SONIC_RPC=https://api.mainnet-beta.sonic.game
BACKEND_DOMAIN=https://your-backend-domain.com
BACKEND_WSS_DOMAIN=wss://your-wss-domain.com
OWNER_SECRET=your_base58_encoded_private_key
VALIDATOR_SECRET=your_validator_base58_encoded_private_key

Security Notes

  • Never expose private keys: Always use environment variables or secure key management systems
  • AES Encryption: Keypairs are encrypted before storage using AES-256
  • Signature Verification: All state-changing operations require Ed25519 signatures
  • Service Worker: Runs validators in isolated context for enhanced security

Browser Compatibility

  • Chrome/Edge: ✅ Full support
  • Firefox: ✅ Full support
  • Safari: ✅ Full support
  • Service Worker: Requires HTTPS in production

Node.js Compatibility

  • Node.js 14+: ✅ Supported
  • Node.js 16+: ✅ Recommended
  • Node.js 18+: ✅ Recommended

License

MIT License - see LICENSE file for details

Support

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Changelog

See CHANGELOG.md for version history and updates.