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

@ponzinomics/sdk

v1.0.0

Published

Official SDK for Ponzinomics - Web3 engagement platform

Readme

@sypher/sdk

Official TypeScript SDK for the Sypher platform. Manage authentication, projects, quests, memes, and leaderboards for your Web3 community.

npm version TypeScript Tests

Features

  • 🔐 Dual Authentication - JWT (user-scoped) and API Key (project-scoped)
  • 🎨 Meme Generation - AI-powered meme creation
  • 🎯 Quest System - Track Twitter, Telegram, Wallet, and custom quests
  • 🏆 Leaderboards - Points, ranks, and rewards
  • 👤 User Management - Profiles and authentication
  • 📁 Project Management - Teams and API keys
  • 💯 TypeScript First - Full type safety
  • Fully Tested - 51 tests covering all features

Installation

npm install @sypher/sdk
# or
pnpm add @sypher/sdk
# or
yarn add @sypher/sdk

Quick Start

The SDK supports two authentication modes:

Developer Mode (Ponzinomics API)

Use API keys for project-scoped operations (memes, quests, points):

import { Sypher } from '@sypher/sdk';

const sypher = new Sypher({
  apiKey: 'sypher_live_xxx',
  projectId: 'proj_xxx',
});

// Generate a meme
const meme = await sypher.meme.generate({
  prompt: 'When the code works on the first try',
});

// Complete a quest
await sypher.quests.complete('quest_123', {
  userId: 'user_456',
  proof: { twitterId: '123456789' },
});

// Get leaderboard
const leaders = await sypher.points.getLeaderboard({ limit: 10 });

User Mode (Core API)

Use JWT tokens for user-scoped operations (auth, profile, projects):

import { Sypher } from '@sypher/sdk';

const sypher = new Sypher({
  accessToken: 'jwt_token_xxx',
});

// Login
const { user, accessToken } = await sypher.auth.login({
  privyToken: 'privy_xxx',
});

// Get user profile
const profile = await sypher.users.getMe();

// List projects
const projects = await sypher.projects.list();

// Create API key
const { rawKey } = await sypher.apiKeys.create('proj_123', {
  name: 'Production Key',
});

Configuration

const sypher = new Sypher({
  // Ponzinomics API (project-scoped)
  apiKey: 'sypher_live_xxx', // Optional
  projectId: 'proj_xxx', // Optional

  // Core API (user-scoped)
  accessToken: 'jwt_token_xxx', // Optional

  // Common
  baseUrl: 'https://api.sypher.io', // Optional (default shown)
  timeout: 30000, // Optional (default: 30s)
});

Note: You must provide either (apiKey + projectId) or accessToken.


Core API (User Authentication)

Authentication

// Login with Privy
const { user, accessToken, refreshToken, expiresIn } = await sypher.auth.login({
  privyToken: 'privy_xxx',
});

// Refresh token
const { accessToken, refreshToken } = await sypher.auth.refresh({
  refreshToken: 'refresh_xxx',
});

// Get current user
const user = await sypher.auth.getMe();

User Management

// Get current user with projects
const user = await sypher.users.getMe();
console.log(user.ownedProjects);
console.log(user.projectMembers);

// Get user by ID
const otherUser = await sypher.users.get('user_456');

// Update profile
await sypher.users.updateMe({
  displayName: 'John Doe',
  twitterHandle: 'johndoe',
});

// Delete account
await sypher.users.deleteMe();

Project Management

// List projects
const projects = await sypher.projects.list();

// Create project
const project = await sypher.projects.create({
  name: 'My Web3 Project',
  description: 'Community engagement platform',
  website: 'https://example.com',
  twitter: '@myproject',
});

// Get project
const project = await sypher.projects.get('proj_123');

// Update project
await sypher.projects.update('proj_123', {
  description: 'Updated description',
});

// Delete project
await sypher.projects.delete('proj_123');

Team Management

// Get team members
const members = await sypher.projects.getMembers('proj_123');

// Add member
await sypher.projects.addMember('proj_123', {
  userId: 'user_456',
  role: 'ADMIN',
});

// Update member role
await sypher.projects.updateMemberRole('proj_123', 'member_789', {
  role: 'MEMBER',
});

// Remove member
await sypher.projects.removeMember('proj_123', 'member_789');

Roles: OWNER, ADMIN, MEMBER

API Key Management

// List API keys
const keys = await sypher.apiKeys.list('proj_123');

// Create API key
const { apiKey, rawKey } = await sypher.apiKeys.create('proj_123', {
  name: 'Production Key',
  permissions: ['meme:generate', 'quest:read'],
  expiresAt: '2025-12-31T23:59:59Z', // Optional
});

console.log('Save this key:', rawKey); // Only shown once!

// Revoke API key
await sypher.apiKeys.revoke('proj_123', 'key_456');

Ponzinomics API (Project Features)

Meme Generation

// Generate a meme
const meme = await sypher.meme.generate({
  prompt: 'When you finally fix that bug',
});

console.log(meme.id);
console.log(meme.status); // 'GENERATING' | 'READY' | 'FAILED'

// List memes
const memes = await sypher.meme.list({
  limit: 20,
  offset: 0,
  status: 'READY',
});

// Get meme by ID
const meme = await sypher.meme.get('meme_123');

// Get/update configuration
const config = await sypher.meme.getConfig();
await sypher.meme.updateConfig({
  maxGenerationsPerDay: 100,
});

// Track engagement
await sypher.meme.like('meme_123');
await sypher.meme.share('meme_123');

// Delete meme
await sypher.meme.delete('meme_123');

// Get analytics
const analytics = await sypher.meme.getAnalytics();
console.log(`Total memes: ${analytics.totalGenerated}`);

Quest System

Managing Quests (Admin)

// Create a quest
const quest = await sypher.quests.create({
  title: 'Follow us on Twitter',
  description: 'Follow @SypherApp to earn 100 points',
  type: 'TWITTER_FOLLOW',
  points: 100,
  requirements: { twitterHandle: '@SypherApp' },
  startsAt: '2024-01-01T00:00:00Z',
  endsAt: '2024-12-31T23:59:59Z',
  maxCompletions: 1000,
});

// Update quest
await sypher.quests.update('quest_123', {
  status: 'ACTIVE',
  points: 150,
});

// Delete quest
await sypher.quests.delete('quest_123');

Quest Status: DRAFT, ACTIVE, PAUSED, COMPLETED, EXPIRED

Listing Quests

// All quests
const quests = await sypher.quests.list();

// Filter by status
const activeQuests = await sypher.quests.list({
  status: 'ACTIVE',
  limit: 20,
  offset: 0,
});

// Filter by type
const twitterQuests = await sypher.quests.list({
  type: 'TWITTER_FOLLOW',
});

// Get active quests with user completion status
const quests = await sypher.quests.getActive('user_123');
quests.forEach((quest) => {
  console.log(`${quest.title}: ${quest.userCompletion ? 'Completed ✓' : 'Available'}`);
});

Completing Quests

Different quest types require different proof formats:

// Twitter Follow/Like/Retweet/Reply
await sypher.quests.complete('quest_123', {
  userId: 'user_456',
  proof: {
    twitterId: '123456789',
    twitterHandle: '@username', // Optional
  },
});

// Telegram Join
await sypher.quests.complete('quest_123', {
  userId: 'user_456',
  proof: {
    telegramId: '987654321',
    telegramUsername: 'username', // Optional
  },
});

// Wallet Connect
await sypher.quests.complete('quest_123', {
  userId: 'user_456',
  proof: {
    address: '0x1234...',
    signature: '0xabcd...',
    message: 'Sign to verify',
  },
});

// Token Hold
await sypher.quests.complete('quest_123', {
  userId: 'user_456',
  proof: {
    address: '0x1234...',
  },
});

// Custom Quest
await sypher.quests.complete('quest_123', {
  userId: 'user_456',
  proof: {
    customField: 'custom-value',
  },
});

Quest Types:

| Type | Required Proof | | ----------------- | --------------------------------- | | TWITTER_FOLLOW | twitterId | | TWITTER_LIKE | twitterId | | TWITTER_RETWEET | twitterId | | TWITTER_REPLY | twitterId | | TELEGRAM_JOIN | telegramId | | WALLET_CONNECT | address, signature, message | | TOKEN_HOLD | address | | CUSTOM | Varies by quest |

Tracking Completions

// Get user's completions
const completions = await sypher.quests.getUserCompletions('user_123');

completions.forEach((completion) => {
  console.log(`Quest ${completion.questId} completed at ${completion.completedAt}`);
  console.log(`Points awarded: ${completion.pointsAwarded}`);
});

Points & Leaderboard

// Get user balance
const balance = await sypher.points.getBalance('user_123');
console.log(`Points: ${balance.points}`);
console.log(`Tier: ${balance.tier}`);

// Get leaderboard
const leaderboard = await sypher.points.getLeaderboard({
  limit: 100,
  offset: 0,
});

leaderboard.forEach((entry) => {
  console.log(`#${entry.rank}: ${entry.userId} - ${entry.points} points`);
});

// Get user rank
const rank = await sypher.points.getUserRank('user_123');
console.log(`Rank: #${rank.rank} out of ${rank.total}`);

Admin Operations

// Award points
await sypher.points.award({
  userId: 'user_123',
  points: 100,
  reason: 'Quest completion',
  referenceId: 'quest_456',
  metadata: { questTitle: 'Follow us on Twitter' },
});

// Deduct points
await sypher.points.deduct({
  userId: 'user_123',
  points: 50,
  reason: 'Reward redemption',
  referenceId: 'reward_789',
});

// Rebuild leaderboard cache
await sypher.points.rebuildLeaderboard();

Error Handling

The SDK provides typed error classes:

import {
  Sypher,
  SypherApiError,
  SypherNetworkError,
  SypherTimeoutError,
  SypherValidationError,
} from '@sypher/sdk';

try {
  await sypher.quests.complete('quest_123', { userId: 'user_456' });
} catch (error) {
  if (error instanceof SypherApiError) {
    console.log(`API Error: ${error.message}`);
    console.log(`Status: ${error.statusCode}`);
    console.log(`Code: ${error.code}`);

    // Handle specific errors
    switch (error.code) {
      case 'ALREADY_COMPLETED':
        console.log('Quest already completed');
        break;
      case 'DAILY_LIMIT_REACHED':
        console.log('Daily generation limit reached');
        break;
      case 'UNAUTHORIZED':
        console.log('Invalid API key or token');
        break;
    }
  } else if (error instanceof SypherNetworkError) {
    console.log('Network error - please try again');
  } else if (error instanceof SypherTimeoutError) {
    console.log('Request timed out');
  } else if (error instanceof SypherValidationError) {
    console.log(`Validation error: ${error.field}`);
  }
}

TypeScript Support

The SDK is fully typed with TypeScript:

import type {
  // Config
  SypherConfig,

  // Auth types
  User,
  AuthResponse,
  TokensResponse,

  // User types
  UserWithProjects,
  UpdateUserDto,

  // Project types
  Project,
  ProjectMember,
  CreateProjectDto,

  // API Key types
  ApiKey,
  CreateApiKeyResponse,

  // Meme types
  Meme,
  MemeConfig,
  MemeAnalytics,
  GenerateMemeOptions,

  // Quest types
  Quest,
  QuestType,
  QuestStatus,
  QuestCompletion,
  CreateQuestDto,
  UpdateQuestDto,
  CompleteQuestOptions,
  TwitterProof,
  TelegramProof,
  WalletProof,

  // Points types
  UserPoints,
  LeaderboardEntry,
  UserRank,
  AwardPointsOptions,
  DeductPointsOptions,
} from '@sypher/sdk';

Health Check

const health = await sypher.healthCheck();
console.log(`API Status: ${health.status}`);
console.log(`Timestamp: ${health.timestamp}`);

Migration Guide (v0.0.1 → v0.1.0)

Breaking Changes

  1. Quest Types

    // Before
    quest.pointsReward; // ❌
    quest.status = 'INACTIVE'; // ❌
    
    // After
    quest.points; // ✅
    quest.status = 'PAUSED'; // ✅
  2. Points Types

    // Before
    balance.balance; // ❌
    rank.totalUsers; // ❌
    
    // After
    balance.points; // ✅
    rank.total; // ✅
  3. Award/Deduct Points

    // Before
    await sypher.points.award({ userId, amount: 100, reason });
    
    // After
    await sypher.points.award({ userId, points: 100, reason });

New Features

  • ✅ Quest CRUD operations (create, update, delete)
  • ✅ Core API integration (auth, users, projects, API keys)
  • ✅ Dual authentication mode
  • ✅ Additional fields in points operations (referenceId, metadata)

Examples

See the examples directory for complete working examples:


API Coverage

| Module | Endpoints | SDK Coverage | | ------------ | --------- | ------------ | | Memes | 9 | ✅ 100% | | Quests | 8 | ✅ 100% | | Points | 6 | ✅ 100% | | Auth | 3 | ✅ 100% | | Users | 5 | ✅ 100% | | Projects | 9 | ✅ 100% | | API Keys | 3 | ✅ 100% | | Total | 43 | ✅ 100% |


Development

# Install dependencies
pnpm install

# Run tests
pnpm test

# Build
pnpm build

# Lint
pnpm lint

Support


License

MIT © Sypher


Changelog

See CHANGELOG.md for release history.