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

@withvlibe/official-sdk

v1.0.2

Published

Official SDK for Vlibe Official Apps - includes authentication, shared database, payments (Stripe Connect), and React hooks

Downloads

304

Readme

@withvlibe/official-sdk

Official SDK for Vlibe Official Apps - provides authentication, shared database access, payments (Stripe Connect), and React hooks for apps created through Vlibe Briefs.

Installation

npm install @withvlibe/official-sdk
# or
yarn add @withvlibe/official-sdk
# or
pnpm add @withvlibe/official-sdk

Quick Start

1. Environment Setup

Your Vlibe Official App already has these credentials in .env:

VLIBE_PROJECT_ID=your_project_id
VLIBE_DB_TOKEN=your_database_token

# Optional: For SSO authentication
VLIBE_APP_ID=your_app_id
VLIBE_APP_SECRET=your_app_secret

2. Database Client Setup

Create a database client file:

// lib/vlibe-db.ts
import { VlibeDatabase } from '@withvlibe/official-sdk';

let db: VlibeDatabase | null = null;

export function getDatabase(): VlibeDatabase {
  if (!db) {
    db = new VlibeDatabase({
      projectId: process.env.VLIBE_PROJECT_ID!,
      databaseToken: process.env.VLIBE_DB_TOKEN!,
    });
  }
  return db;
}

export { db };

3. Basic CRUD Operations

import { getDatabase } from '@/lib/vlibe-db';

const db = getDatabase();

// Create a table (first time only)
await db.createTable('documents', {
  columns: [
    { name: 'title', type: 'string', required: true },
    { name: 'content', type: 'string' },
    { name: 'published', type: 'boolean', defaultValue: false },
  ],
});

// Insert a record
const doc = await db.insert('documents', {
  title: 'My Document',
  content: 'Hello world',
});
console.log(doc.id); // Auto-generated ID

// Query records
const allDocs = await db.query('documents');
const publishedDocs = await db.query('documents', {
  where: { published: true },
  orderBy: { column: 'created_at', direction: 'desc' },
  limit: 10,
});

// Get single record
const doc = await db.getById('documents', 'doc-123');

// Update a record
await db.update('documents', 'doc-123', {
  title: 'Updated Title',
});

// Delete a record
await db.delete('documents', 'doc-123');

React Hooks

Import hooks from the /react entry point:

import { useCollection, useKV, useVlibeAuth } from '@withvlibe/official-sdk/react';

useCollection

Manage a collection of records with CRUD operations and optional real-time updates:

'use client';
import { useCollection } from '@withvlibe/official-sdk/react';
import { getDatabase } from '@/lib/vlibe-db';

interface Document {
  id: string;
  title: string;
  content: string;
  created_at?: string;
}

function DocumentList() {
  const db = getDatabase();
  const { data, loading, error, create, update, remove, refetch } = useCollection<Document>(
    db,
    'documents',
    { realtime: true } // Enable real-time updates
  );

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <button onClick={() => create({ title: 'New Doc', content: '' })}>
        Add Document
      </button>

      {data.map(doc => (
        <div key={doc.id}>
          <h3>{doc.title}</h3>
          <button onClick={() => update(doc.id, { title: 'Updated' })}>
            Edit
          </button>
          <button onClick={() => remove(doc.id)}>
            Delete
          </button>
        </div>
      ))}
    </div>
  );
}

useKV

Manage key-value pairs for settings, preferences, and simple state:

'use client';
import { useKV } from '@withvlibe/official-sdk/react';
import { getDatabase } from '@/lib/vlibe-db';

interface Settings {
  theme: 'light' | 'dark';
  fontSize: number;
}

function SettingsPanel() {
  const db = getDatabase();
  const { value: settings, loading, set } = useKV<Settings>(db, 'settings');

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      <select
        value={settings?.theme || 'dark'}
        onChange={(e) => set({ ...settings, theme: e.target.value as 'light' | 'dark' })}
      >
        <option value="light">Light</option>
        <option value="dark">Dark</option>
      </select>
    </div>
  );
}

useVlibeAuth

Handle SSO authentication with Vlibe:

'use client';
import { useVlibeAuth } from '@withvlibe/official-sdk/react';
import { VlibeAuth } from '@withvlibe/official-sdk';

const auth = new VlibeAuth({
  appId: process.env.NEXT_PUBLIC_VLIBE_APP_ID!,
  appSecret: process.env.VLIBE_APP_SECRET!,
});

function AuthenticatedApp() {
  const { user, loading, login, logout, hasFeature, hasSubscription } = useVlibeAuth(auth);

  if (loading) return <div>Verifying session...</div>;

  if (!user) {
    return (
      <div>
        <h1>Welcome to My App</h1>
        <button onClick={() => login('/dashboard')}>
          Login with Vlibe
        </button>
      </div>
    );
  }

  return (
    <div>
      <p>Hello, {user.name || user.email}!</p>

      {hasSubscription() && <p>Thanks for subscribing!</p>}
      {hasFeature('premium') && <PremiumFeatures />}

      <button onClick={logout}>Logout</button>
    </div>
  );
}

Key-Value Store

For simple data that doesn't need a full table:

const db = getDatabase();

// Set a value
await db.setKV('theme', 'dark');

// Set with namespace (e.g., per-user settings)
await db.setKV('preferences', { notifications: true }, 'user_123');

// Get a value
const theme = await db.getKV<string>('theme');
const prefs = await db.getKV<{ notifications: boolean }>('preferences', 'user_123');

// Delete a value
await db.deleteKV('theme');

// List all keys in a namespace
const allSettings = await db.listKV('user_123');

Real-Time Subscriptions

Subscribe to changes for live updates:

const db = getDatabase();

const subscription = db.subscribe('documents', (payload) => {
  console.log('Event:', payload.eventType); // INSERT, UPDATE, DELETE
  console.log('New data:', payload.new);
  console.log('Old data:', payload.old);
});

// Later: stop listening
subscription.unsubscribe();

// Or unsubscribe from everything
db.unsubscribeAll();

Payments (Stripe Connect)

VlibePayments handles subscriptions and revenue for Vlibe Official Apps through Stripe Connect. This class is server-side only - never import it in client code.

Setup

// lib/vlibe-payments.ts (SERVER-SIDE ONLY)
import { VlibePayments } from '@withvlibe/official-sdk';

let payments: VlibePayments | null = null;

export function getPayments(): VlibePayments {
  if (!payments) {
    payments = new VlibePayments({
      appId: process.env.VLIBE_APP_ID!,
      appSecret: process.env.VLIBE_APP_SECRET!,
    });
  }
  return payments;
}

Create Checkout Session

// app/api/subscribe/route.ts
import { NextResponse } from 'next/server';
import { getPayments } from '@/lib/vlibe-payments';

export async function POST(req: Request) {
  const { userId, userEmail, tierId } = await req.json();
  const payments = getPayments();

  const checkoutUrl = await payments.createCheckoutSession({
    userId,
    userEmail,
    tierId,
    successUrl: `${process.env.APP_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancelUrl: `${process.env.APP_URL}/pricing`,
    billingPeriod: 'monthly', // or 'yearly'
  });

  return NextResponse.json({ checkoutUrl });
}

Check Subscription Status

// app/api/subscription/route.ts
import { NextResponse } from 'next/server';
import { getPayments } from '@/lib/vlibe-payments';

export async function GET(req: Request) {
  const { searchParams } = new URL(req.url);
  const userId = searchParams.get('userId');
  const payments = getPayments();

  const subscription = await payments.getSubscription(userId!);

  if (!subscription || subscription.status !== 'active') {
    return NextResponse.json({ hasAccess: false });
  }

  return NextResponse.json({
    hasAccess: true,
    tier: subscription.tier,
    features: subscription.features,
    expiresAt: subscription.currentPeriodEnd,
  });
}

Revenue Dashboard

// app/api/dashboard/revenue/route.ts
import { NextResponse } from 'next/server';
import { getPayments } from '@/lib/vlibe-payments';

export async function GET() {
  const payments = getPayments();

  const revenue = await payments.getRevenue('month');
  const payouts = await payments.getPayoutHistory(6);

  return NextResponse.json({
    // Revenue is in cents, convert to dollars
    monthlyRevenue: revenue.netRevenue / 100,
    totalRevenue: revenue.grossRevenue / 100,
    platformFees: revenue.platformFees / 100,
    subscriberCount: revenue.subscriberCount,
    activeSubscribers: revenue.activeSubscribers,
    payouts: payouts.map(p => ({
      month: p.month,
      amount: p.netAmount / 100,
      status: p.status,
    })),
  });
}

Cancel Subscription

// app/api/subscription/cancel/route.ts
import { NextResponse } from 'next/server';
import { getPayments } from '@/lib/vlibe-payments';

export async function POST(req: Request) {
  const { userId, immediately } = await req.json();
  const payments = getPayments();

  // Cancel at period end (default) or immediately
  await payments.cancelSubscription(userId, immediately);

  return NextResponse.json({ success: true });
}

Issue Refund

// app/api/refund/route.ts
import { NextResponse } from 'next/server';
import { getPayments } from '@/lib/vlibe-payments';

export async function POST(req: Request) {
  const { userId, amount, reason } = await req.json();
  const payments = getPayments();

  const refundId = await payments.createRefund({
    userId,
    amount, // Optional - full refund if not specified
    reason: reason || 'requested_by_customer',
  });

  return NextResponse.json({ refundId });
}

API Reference

VlibeDatabase

| Method | Description | |--------|-------------| | createTable(name, schema) | Create a new table | | listTables() | List all tables for this project | | getTable(name) | Get table info | | query(table, options?) | Query records | | getById(table, id) | Get single record | | insert(table, data) | Insert a record | | update(table, id, data) | Update a record | | delete(table, id) | Delete a record | | insertMany(table, records) | Batch insert | | deleteMany(table, ids) | Batch delete | | setKV(key, value, namespace?) | Set key-value | | getKV(key, namespace?) | Get key-value | | deleteKV(key, namespace?) | Delete key-value | | listKV(namespace?) | List all key-values | | subscribe(table, callback) | Real-time subscription | | unsubscribeAll() | Remove all subscriptions | | healthCheck() | Test connection |

VlibeAuth

| Method | Description | |--------|-------------| | verifySession(token) | Verify SSO token | | getLoginUrl(redirect?) | Get SSO login URL | | getLogoutUrl(redirect?) | Get logout URL | | hasFeature(user, feature) | Check feature access | | hasSubscription(user) | Check subscription status | | getTier(user) | Get subscription tier |

VlibePayments (Server-Side Only)

| Method | Description | |--------|-------------| | createCheckoutSession(options) | Create Stripe checkout session | | getSubscription(userId) | Get user's subscription info | | hasActiveSubscription(userId) | Check if user has active subscription | | getRevenue(period?) | Get revenue data for your app | | getPayoutHistory(limit?) | Get payout history | | cancelSubscription(userId, immediately?) | Cancel a subscription | | createRefund(options) | Issue a refund | | getPricingTiers() | Get all pricing tiers |

React Hooks

| Hook | Description | |------|-------------| | useCollection(db, table, options?) | CRUD operations with real-time | | useKV(db, key, namespace?) | Key-value management | | useKVList(db, namespace?) | List all KV pairs | | useAuth(auth, options?) | Basic auth hook | | useVlibeToken() | Extract SSO token from URL | | useVlibeAuth(auth) | Full auth with auto token handling |

Column Types

When creating tables, you can use these column types:

| Type | Description | PostgreSQL | |------|-------------|------------| | string | Text data | TEXT | | number | Numeric data | DOUBLE PRECISION | | boolean | True/false | BOOLEAN | | json | JSON objects | JSONB | | timestamp | Date/time | TIMESTAMPTZ |

TypeScript Support

The SDK is fully typed. Define your record types for better IntelliSense:

interface Document {
  id: string;
  title: string;
  content: string;
  published: boolean;
  created_at?: string;
  updated_at?: string;
}

// Typed queries
const docs = await db.query<Document>('documents');
const doc = await db.insert<Document>('documents', { title: 'Hello', content: '', published: false });

License

MIT - Vlibe