@sylphx/sdk
v0.3.2
Published
Sylphx SDK - State-of-the-art platform SDK with pure functions
Readme
@sylphx/sdk
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/sdkQuick Start (Next.js)
1. Environment Variables
Two keys from your Platform Console:
# .env.local
SYLPHX_SECRET_KEY=sk_dev_xxxxxxxxxxxxxxxxxxxx # server-only
NEXT_PUBLIC_SYLPHX_APP_ID=app_dev_xxxxxxxxxxxx # safe to exposeThat's it. No other config needed.
Key formats
sk_dev_*/sk_stg_*/sk_prod_*— Secret key (server only, never expose)app_dev_*/app_stg_*/app_prod_*— App ID (safe for client-side)Get both from Console → Your App → API Keys.
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'
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const config = await getAppConfig({
secretKey: process.env.SYLPHX_SECRET_KEY!,
appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID!,
})
return (
<html>
<body>
<SylphxProvider
config={config}
appId={process.env.NEXT_PUBLIC_SYLPHX_APP_ID!}
>
{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 } from '@sylphx/sdk/server'
const client = createServerClient({
secretKey: process.env.SYLPHX_SECRET_KEY!,
})
// GET /billing/plans
const plans = await client.GET('/billing/plans')
// POST /analytics/track
await client.POST('/analytics/track', {
body: { events: [{ 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'
const config = await getAppConfig({
secretKey: process.env.SYLPHX_SECRET_KEY!,
appId: process.env.NEXT_PUBLIC_SYLPHX_APP_ID!,
})
// config.plans, config.featureFlags, config.oauthProviders, config.consentTypesVerify 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_idReact 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 captureUI 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 { createConfig, signIn, track, getPlans } from '@sylphx/sdk'
const config = createConfig({ secretKey: process.env.SYLPHX_SECRET_KEY! })
// 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() |
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
If you're running your own Sylphx Platform deployment:
# .env.local — only needed for self-hosting
SYLPHX_PLATFORM_URL=https://platform.your-domain.comYou will not need this if you're using the hosted platform at sylphx.com.
