https://github.com/notrab/unlocked
https://github.com/notrab/unlocked
Last synced: 19 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/notrab/unlocked
- Owner: notrab
- Created: 2025-09-09T12:07:15.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2025-09-09T15:12:35.000Z (4 months ago)
- Last Synced: 2025-12-24T03:35:53.273Z (19 days ago)
- Size: 4.88 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# XP for Saas
Add a game-like XP system to your SaaS app (think Fortnite XP, Xbox Achievements, COD Battle Pass), with a clean, NextAuth-inspired developer experience.
Users earn XP for actions (profile complete, purchase, daily login, referrals, etc.), progress through tiers, and unlock rewards.
Bring your own database (Redis, Prisma, Postgres, etc.) via adapters.
## 1. Install
```bash
npm install @notrab/xp
```
## 2. Define your config
Create a `xp.ts` file in your app:
```ts
// lib/xp.ts
import { createXP, XPRoutes } from '@notrab/xp/server'
import { createRedisAdapter } from '@notrab/xp/adapters/redis-adapter'
import { auth } from '@/lib/auth' // NextAuth, Clerk, etc.
import { redis } from './redis'
// Define tiers, actions, hooks
export const xp = createXP({
config: {
tiers: [
{ name: 'Newcomer', threshold: 0, color: '#94a3b8', badge: '🌱' },
{ name: 'Explorer', threshold: 100, color: '#3b82f6', badge: '🔍' },
{ name: 'Expert', threshold: 500, color: '#8b5cf6', badge: '⭐' },
{ name: 'Master', threshold: 1500, color: '#f59e0b', badge: '👑' },
],
actions: {
profile_complete: { xp: 50, label: 'Complete Profile', unique: true },
first_purchase: { xp: 200, label: 'First Purchase', unique: true },
daily_login: { xp: 10, label: 'Daily Login', cooldownSeconds: 86400 },
},
hooks: {
onAction: async ({ userId, actionKey, amount }) => {
console.log(`[xp] ${userId} +${amount} XP for ${actionKey}`)
},
onLevelUp: async ({ userId, toTier }) => {
if (toTier.name === 'Explorer') {
await sendDiscountEmail(userId, 'WELCOME10')
}
if (toTier.name === 'Expert') {
await promotePlanUpgrade(userId)
}
},
},
},
adapter: createRedisAdapter(redis),
getUserId: async (req) => {
const session = await auth()
return session?.user?.id ?? null
},
})
// Export API routes
export const { GET, POST } = XPRoutes(xp)
```
## 3. API Route
Create `app/api/xp/route.ts`:
```ts
export { GET, POST } from '@/lib/xp'
```
## 4. Wrap your App
```tsx
// app/layout.tsx
import { XPProvider } from '@notrab/xp'
import { xp } from '@/lib/xp'
import { useAuth } from '@clerk/nextjs'
export default function RootLayout({ children }) {
const { user } = useAuth()
return (
{children}
)
}
```
## 5. Use in components
```tsx
import { XPProgressBar, useXP, useXPAction } from '@notrab/xp'
export function Dashboard() {
const { xp, tier, isLoading } = useXP()
const triggerProfileComplete = useXPAction('profile_complete')
if (isLoading) return
Loading...
return (
Welcome back!
Level: {tier} ({xp} XP)
triggerProfileComplete()}>
Complete Profile (+50 XP)
)
}
```