better-waitlist
v1.1.3
Published
Waitlist plugin for Better Auth - manage waitlists with email signup, position tracking, and admin approval
Maintainers
Readme
Better Waitlist
Waitlist plugin for Better Auth
Made by haxurn
Installation
npm install better-waitlistpnpm add better-waitlistyarn add better-waitlistUsage
Server
Add the plugin to your Better Auth configuration:
import { betterAuth } from 'better-auth';
import { waitlist } from 'better-waitlist';
export const auth = betterAuth({
plugins: [waitlist()],
});Database Migration
Run the migration to add the waitlist table to your database:
npx @better-auth/cli migrateOr generate the schema for your ORM:
npx @better-auth/cli generateClient
Add the client plugin:
import { createAuthClient } from 'better-auth/client';
import { waitlistClient } from 'better-waitlist';
export const authClient = createAuthClient({
plugins: [waitlistClient()],
});Options
import { waitlist } from 'better-waitlist';
export const auth = betterAuth({
plugins: [
waitlist({
// Authentication
requireAdmin: true, // require session for admin endpoints (default: true)
// Entry Management
maxEntries: 0, // maximum entries allowed (0 = unlimited, default: 0)
enabled: true, // allow new waitlist joins (default: true)
// Public Features
allowStatusCheck: true, // allow public status checks (default: true)
showPosition: false, // show position in status response (default: false)
// Invitations
markInvitedOnApprove: false, // mark as invited when approving (default: false)
// Position Management
recalculatePositionOnApprove: false, // recalculate positions when entries are approved/rejected (default: false)
// Callbacks
onJoin: async (entry) => {
// Called when user joins waitlist
console.log('New entry:', entry.email);
},
onApprove: async (entry) => {
// Called when entry is approved
console.log('Approved:', entry.email);
},
onReject: async (entry) => {
// Called when entry is rejected
console.log('Rejected:', entry.email);
},
onComplete: async (entry) => {
// Called when entry is completed (user signs up)
console.log('Completed:', entry.email);
},
}),
],
});API
Join Waitlist
// Anonymous user
await authClient.waitlist.join({ email: '[email protected]' });
// Logged-in user
await authClient.waitlist.join({
email: '[email protected]',
userId: 'user-123',
});Check Status
const { data, error } = await authClient.waitlist.getStatus({
email: '[email protected]',
});
if (data) {
console.log(data.status); // "pending" | "approved" | "rejected"
}Check Position
const { data, error } = await authClient.waitlist.getPosition({
email: '[email protected]',
});
if (data) {
console.log(data.position); // real-time position among pending entries
}Admin: List Entries
const { data, error } = await authClient.waitlist.list({
status: 'pending', // optional filter
limit: 20,
offset: 0,
});
if (data) {
console.log(data.entries);
console.log(data.total);
}Admin: Get Stats
const { data, error } = await authClient.waitlist.stats();
if (data) {
console.log(data.total);
console.log(data.pending);
console.log(data.approved);
console.log(data.rejected);
}Admin: Approve Entry
const { data, error } = await authClient.waitlist.approve({
email: '[email protected]',
});
// With mark as invited
const { data: data2 } = await authClient.waitlist.approve({
email: '[email protected]',
sendInvite: true, // override plugin setting for this call
});Admin: Reject Entry
const { data, error } = await authClient.waitlist.reject({
email: '[email protected]',
});Admin: Promote Entry
Send an invite to an approved user:
const { data, error } = await authClient.waitlist.promote({
email: '[email protected]',
});Admin: Promote All
Send invites to all approved users:
const { data, error } = await authClient.waitlist.promoteAll({
status: 'approved', // default: 'approved'
});
if (data) {
console.log(data.promoted); // count of promoted entries
}Admin: Complete Entry
Mark an entry as complete (e.g., after user signs up):
const { data, error } = await authClient.waitlist.complete({
email: '[email protected]',
});
if (data) {
console.log(data.entry); // the completed entry data
}Schema
The plugin adds a waitlist table with the following fields:
| Field | Type | Description |
| ------------ | -------- | ------------------------------------- |
| id | string | Unique identifier |
| email | string | User's email (unique) |
| status | string | pending | approved | rejected |
| position | number | Position in queue |
| userId | string? | Optional relation to user |
| invitedAt | date? | Timestamp when invite was sent |
| createdAt | date | Timestamp when joined |
API Endpoints
| Method | Endpoint | Auth | Description |
| ------ | ---------------------- | ------- | ------------------------- |
| POST | /waitlist/join | None | Join waitlist |
| GET | /waitlist/status | None | Check status |
| GET | /waitlist/position | None | Get position |
| GET | /waitlist/list | Session | List entries |
| GET | /waitlist/stats | Session | Get waitlist statistics |
| POST | /waitlist/approve | Session | Approve entry |
| POST | /waitlist/reject | Session | Reject entry |
| POST | /waitlist/promote | Session | Send invite to user |
| POST | /waitlist/promote-all | Session | Send invites to all |
| POST | /waitlist/complete | Session | Complete entry |
TypeScript
The plugin provides full TypeScript support. Types are automatically inferred when using the client:
// Full type inference
const result = await authClient.waitlist.join({
email: '[email protected]',
});
// result.data is typed as WaitlistEntry
// result.error is typed as { message: string }Contributing
Contributions are welcome! Please see our CONTRIBUTING.md for details.
Code of Conduct
Please read our CODE_OF_CONDUCT.md before participating in our community.
