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

@sylphx/sdk

v0.8.0-rc.2

Published

Sylphx SDK - State-of-the-art platform SDK with pure functions

Readme

@sylphx/sdk

npm version License: MIT TypeScript docs

Auth, billing, analytics, AI, storage, and more — in one SDK.

📖 Full docs: sylphx.com/docs


Installation

npm install @sylphx/sdk
# or
pnpm add @sylphx/sdk
bun add @sylphx/sdk

Quick Start (Next.js)

1. Environment Variables

Your server connection URL and environment app ID from your Platform Console:

# .env.local
SYLPHX_URL=sylphx://sk_dev_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@bold-river-a1b2c3.api.sylphx.com
NEXT_PUBLIC_SYLPHX_APP_ID=app_dev_xxxxxxxxxxxx

That's it. No other config needed.

Key formats

  • sylphx://sk_*@<tenant-slug>.api.sylphx.com — Server connection URL (server only, never expose)
  • app_dev_* / app_stg_* / app_prod_* — App ID (safe for client-side)

Get both from Console → Your App → API Keys. The hosted BaaS API is always addressed as <tenant-slug>.api.sylphx.com.


2. Middleware

Handles auth routes (/auth/callback, /auth/signout) and route protection automatically.

// middleware.ts
import { createSylphxMiddleware } from '@sylphx/sdk/nextjs'

export default createSylphxMiddleware({
  publicRoutes: ['/', '/about', '/pricing', '/login'],
})

export const config = {
  matcher: ['/((?!_next|.*\\..*).*)', '/'],
}

No manual /api/auth/* routes needed — the middleware handles everything.


3. Root Layout

Fetch config server-side once, pass to the provider:

// app/layout.tsx
import { getAppConfig } from '@sylphx/sdk/server'
import { SylphxProvider } from '@sylphx/sdk/react'
import { createServerClient } from '@sylphx/sdk'

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const sylphx = createServerClient(process.env.SYLPHX_URL!)
  const apiUrl = sylphx.baseUrl.replace(/\/v[0-9]+$/, '')

  const config = await getAppConfig({
    secretKey: sylphx.secretKey!,
    appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID!,
    platformUrl: apiUrl,
  })

  return (
    <html>
      <body>
        <SylphxProvider
          config={config}
          appId={process.env.NEXT_PUBLIC_SYLPHX_APP_ID!}
          platformUrl={apiUrl}
        >
          {children}
        </SylphxProvider>
      </body>
    </html>
  )
}

4. Protect Pages (Server Components)

// app/dashboard/page.tsx
import { currentUser } from '@sylphx/sdk/nextjs'
import { redirect } from 'next/navigation'

export default async function Dashboard() {
  const user = await currentUser()
  if (!user) redirect('/login')

  return <h1>Hello, {user.name}</h1>
}

5. Auth UI (Client Components)

'use client'
import { useUser, SignedIn, SignedOut, UserButton } from '@sylphx/sdk/react'

export default function Header() {
  const { user } = useUser()

  return (
    <header>
      <SignedOut>
        <a href="/login">Sign in</a>
      </SignedOut>
      <SignedIn>
        <span>Hello, {user?.name}</span>
        <UserButton afterSignOutUrl="/" />
      </SignedIn>
    </header>
  )
}

Server-Side

Get Current User

import { auth, currentUser, currentUserId } from '@sylphx/sdk/nextjs'

// Full auth state
const { userId, user, sessionToken } = await auth()

// Just the user object (null if not signed in)
const user = await currentUser()

// Just the user ID
const userId = await currentUserId()

Server API Client

import { createServerClient, getPlans, track } from '@sylphx/sdk'

const sylphx = createServerClient(process.env.SYLPHX_URL!)

// Billing
const plans = await getPlans(sylphx)

// Analytics
await track(sylphx, { event: 'purchase', properties: { amount: 99 } })

Prefetch App Config

import {
  getAppConfig,    // All config in one call (recommended)
  getPlans,        // Billing plans
  getFeatureFlags, // Feature flag definitions
  getConsentTypes, // GDPR consent config
} from '@sylphx/sdk/server'
import { createServerClient } from '@sylphx/sdk'

const sylphx = createServerClient(process.env.SYLPHX_URL!)

const config = await getAppConfig({
  secretKey: sylphx.secretKey!,
  appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID!,
  platformUrl: sylphx.baseUrl.replace(/\/v[0-9]+$/, ''),
})
// config.plans, config.featureFlags, config.oauthProviders, config.consentTypes

Verify Webhooks

import { verifyWebhook } from '@sylphx/sdk/server'

export async function POST(request: Request) {
  const body = await request.text()

  const result = await verifyWebhook({
    payload: body,
    signatureHeader: request.headers.get('x-webhook-signature'),
    secret: process.env.SYLPHX_SECRET_KEY!,
  })

  if (!result.valid) {
    return new Response('Unauthorized', { status: 401 })
  }

  const { event, data } = result.payload!
  // handle event...
  return Response.json({ received: true })
}

Or use the handler factory:

import { createWebhookHandler } from '@sylphx/sdk/server'

export const POST = createWebhookHandler({
  secret: process.env.SYLPHX_SECRET_KEY!,
  handlers: {
    'user.created': async (data) => { /* ... */ },
    'subscription.updated': async (data) => { /* ... */ },
  },
})

JWT Verification

import { verifyAccessToken } from '@sylphx/sdk/server'

const payload = await verifyAccessToken(token, {
  secretKey: process.env.SYLPHX_SECRET_KEY!,
})
// payload.sub, payload.email, payload.role, payload.app_id

React Hooks

Auth

import { useUser, useAuth } from '@sylphx/sdk/react'

const { user, isLoading, isSignedIn } = useUser()
const { signIn, signUp, signOut, forgotPassword } = useAuth()

await signIn({ email: '[email protected]', password: '...' })
await signOut()

Billing

import { useBilling } from '@sylphx/sdk/react'

const { subscription, isPremium, plans, createCheckout, openPortal } = useBilling()

// Check access
if (!isPremium) return <UpgradePrompt />

// Start checkout
const url = await createCheckout('pro', 'monthly')
window.location.href = url

// Manage subscription
await openPortal()

Analytics

import { useAnalytics } from '@sylphx/sdk/react'

const { track, identify, page } = useAnalytics()

track('button_clicked', { button: 'upgrade' })
identify({ name: 'John', email: '[email protected]' })

Feature Flags

import { useFeatureFlag } from '@sylphx/sdk/react'

const { isEnabled } = useFeatureFlag('new-dashboard')
if (isEnabled) return <NewDashboard />

AI

import { useChat, useCompletion } from '@sylphx/sdk/react'

const { messages, send, isLoading } = useChat({
  model: 'anthropic/claude-3.5-sonnet',
})

await send('What is the meaning of life?')

Storage

import { useStorage } from '@sylphx/sdk/react'

const { upload, uploadAvatar, isUploading, progress } = useStorage()

const url = await upload(file, { path: 'documents/' })
const avatarUrl = await uploadAvatar(imageFile)

More Hooks

import { useConsent }       from '@sylphx/sdk/react' // GDPR consent
import { useFeatureFlags }  from '@sylphx/sdk/react' // All flags at once
import { useNotifications } from '@sylphx/sdk/react' // In-app notifications
import { useReferral }      from '@sylphx/sdk/react' // Referral program
import { useOrganization }  from '@sylphx/sdk/react' // Multi-tenant orgs
import { useJobs }          from '@sylphx/sdk/react' // Background jobs
import { useErrorTracking } from '@sylphx/sdk/react' // Error capture

UI Components

Auth

import { SignIn, SignUp, UserButton, SignedIn, SignedOut } from '@sylphx/sdk/react'

<SignedOut><SignIn mode="embedded" afterSignInUrl="/dashboard" /></SignedOut>
<SignedIn><UserButton afterSignOutUrl="/" /></SignedIn>

Billing

import { PricingTable, CheckoutButton } from '@sylphx/sdk/react'

<PricingTable plans={plans} />
<CheckoutButton planSlug="pro" interval="monthly">Upgrade</CheckoutButton>

Route Protection

import { Protect } from '@sylphx/sdk/react'

<Protect role="admin">
  <AdminPanel />
</Protect>

Pure Functions (Server or Client)

For non-React environments or maximum control:

import { createClient, signIn, track, getPlans } from '@sylphx/sdk'

const config = createClient(process.env.SYLPHX_URL!)

// Auth
const tokens = await signIn(config, { email, password })
const authedConfig = withToken(config, tokens.accessToken)

// Analytics
await track(config, { event: 'purchase', properties: { amount: 99 } })

// Billing
const plans = await getPlans(config)

Entry Points

| Import path | Use for | |---|---| | @sylphx/sdk | Pure functions (server or client, no React) | | @sylphx/sdk/react | React hooks, components, SylphxProvider | | @sylphx/sdk/server | JWT verification, webhook verification, server client | | @sylphx/sdk/nextjs | createSylphxMiddleware, auth(), currentUser() | | @sylphx/sdk/web-analytics | Standalone web-analytics tracker (rrweb + web-vitals) | | @sylphx/sdk/health | Multi-signal health score for the sylphx-health-agent sidecar (ADR-111 Phase B) |

@sylphx/sdk/health — Phase B health score (ADR-111)

Apps register signals (event-loop lag, queue depth, error rate, memory pressure) and the SDK folds them into a continuous score in [0, 1]. The sylphx-health-agent sidecar polls the score and decides liveness / readiness / drain via the three-tier gate. See src/health/README.md for the full guide.

import { sylphxHealth, eventLoopLagSignal, queueDepthSignal } from '@sylphx/sdk/health'

const health = sylphxHealth({
  signals: [
    eventLoopLagSignal({ degradedMs: 5000, deadMs: 30000 }),
    queueDepthSignal({ getter: () => queue.size, fullThreshold: 1000 }),
  ],
})

app.get('/healthz', health.handler())
// Or — Unix-socket transport for the sidecar:
health.serveUnixSocket() // → /var/run/sylphx/health.sock

TypeScript

All types are fully inferred. Import them directly:

import type { User, Plan, Subscription, AppConfig } from '@sylphx/sdk'
import type { AuthResult } from '@sylphx/sdk/nextjs'

Self-Hosting / Custom Deployment

If you're running your own Sylphx Platform deployment, configure the base URL via the CLI:

SYLPHX_API_URL=https://platform.your-domain.com sylphx deploy

Or in the SDK via an explicit custom-domain connection URL:

import { createServerClient } from '@sylphx/sdk'

const config = createServerClient(
  'sylphx://sk_prod_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@acme.api.example.com',
)

Note: hosted Sylphx uses <tenant-slug>.api.sylphx.com. Only use a custom host for self-hosted deployments or a documented legacy migration.


Architecture — contract-first

This SDK is part of the two-plane architecture (ADR-083) with a single source of truth (ADR-084):

  • @sylphx/contract (Effect Schema) drives the types you see here. The types are not hand-written and not separately maintained — add an endpoint to the contract and both this SDK and the sibling @sylphx/management inherit it. Hand-written shims are a bug.
  • Promise surface, Effect-free. Internally @sylphx/contract is Effect Schema, but the published .d.ts is stripped of Effect imports (strip-at-publish CI guard). You get clean Promise<User> / Promise<Plan[]> signatures with zero Effect dependency in your bundle.
  • Standard Schema compliant. Every input schema in the contract exposes the ~standard interface — compatible with Zod, Valibot, ArkType, TypeBox, Effect Schema, and any future Standard-Schema-compliant validator.
  • Agent surface via the CLI. The sylphx CLI is the first-class agent entry point (Claude Code, Cursor, ChatGPT Apps). If you want a custom MCP, compose it on top of @sylphx/management yourself — Sylphx does not ship a standalone stdio MCP binary.

See ADR-084 for the full design rationale.