@foruai/gatekeeper-client
v0.2.0
Published
TypeScript client for the ForU Gatekeeper AI API — badges, Discord, profiles, and AI chat
Maintainers
Readme
@foruai/gatekeeper-client
Full-featured TypeScript client for the ForU Gatekeeper AI API. Badge verification, Discord membership checks, user profiles, and AI chat — with built-in HMAC and Bearer authentication.
Installation
npm install @foruai/gatekeeper-client
# or
pnpm add @foruai/gatekeeper-client
# or
bun add @foruai/gatekeeper-clientQuick Start
Server-side (with HMAC secret)
import { GatekeeperClient } from '@foruai/gatekeeper-client'
const client = new GatekeeperClient({
baseUrl: 'https://gatekeeper.foruai.io',
secret: process.env.HMAC_SECRET!, // auto-signs every request
})
// Chat with the AI agent
const reply = await client.chat('check badges for @user123')
console.log(reply)
// Verify badges
const badges = await client.verifyBadges({ user_address: '0x...' })
console.log(badges.badges)
// Check Discord membership
const discord = await client.checkDiscord({ username: 'user123' })
console.log(discord.servers)Server-side (with Bearer token)
const client = new GatekeeperClient({
baseUrl: 'https://gatekeeper.foruai.io',
bearerToken: process.env.API_KEY!,
})
const profile = await client.getProfile({ user_address: '0x...' })Browser (with pre-signed HMAC token)
Your backend generates the token, frontend uses it:
// 1. Get token from your backend
const tokenRes = await fetch('/api/gatekeeper-token')
const token = await tokenRes.json() // HmacToken
// 2. Use it with the client
import { GatekeeperClient } from '@foruai/gatekeeper-client'
const client = new GatekeeperClient({
baseUrl: 'https://gatekeeper.foruai.io',
})
const reply = await client.chat('check badges for @user123', { token })API Reference
Constructor
new GatekeeperClient(options: GatekeeperClientOptions)| Option | Type | Required | Description |
|--------|------|----------|-------------|
| baseUrl | string | Yes | API base URL (e.g. https://gatekeeper.foruai.io) |
| secret | string | No | HMAC secret — auto-signs all requests |
| bearerToken | string | No | API key for Bearer authentication |
| sessionId | string | No | Default chat session ID for conversation continuity |
Auth priority: per-request token > HMAC secret > Bearer token.
Chat
client.chat(message, options?): Promise<string>
Send a message and get the AI reply.
const reply = await client.chat('does @user123 have the OG badge?')
// => "Yes! @user123 holds the OG Badge (verified, 100% confidence)..."client.chatWithSession(message, options?): Promise<ChatResult>
Same as chat() but returns the full response including session ID and routing info.
const result = await client.chatWithSession('check badges for @user123', {
mode: 'hybrid', // 'hybrid' | 'fast' | 'agent'
})
console.log(result.reply) // AI-formatted response
console.log(result.sessionId) // session ID for follow-ups
console.log(result.routed) // matched intent (e.g. 'verify_badge')Chat options:
| Option | Type | Description |
|--------|------|-------------|
| token | HmacToken | Per-request HMAC token (overrides client auth) |
| mode | 'hybrid' \| 'fast' \| 'agent' | hybrid (default): intent routing + AI formatting. fast: intent routing only. agent: full AI agent. |
| sessionId | string | Session ID for conversation continuity |
Badge Verification
client.verifyBadges(params): Promise<VerifyBadgeResponse>
Verify badge ownership with confidence scoring, on-chain proofs, and rule breakdowns.
const result = await client.verifyBadges({
user_address: '0x1234...',
// or: username: 'user123'
// or: discord_username: 'user#1234'
badge_id: 5, // optional: filter to specific badge
})
for (const badge of result.badges) {
console.log(`${badge.name}: ${badge.status} (${badge.confidence * 100}%)`)
console.log(` Type: ${badge.badge_type}`)
console.log(` Rules: ${badge.rules_breakdown.total} total`)
if (badge.onchain_proof) {
console.log(` On-chain: ${badge.onchain_proof.verified_onchain}`)
}
if (badge.awarded_via) {
console.log(` From: ${badge.awarded_via.campaign_name || badge.awarded_via.quest_name}`)
}
if (badge.minting?.is_minted) {
console.log(` Minted: ${badge.minting.chain_name} tx ${badge.minting.mint_hash}`)
}
}Badge Catalog
client.listBadges(): Promise<{ badges: BadgeInfo[] }>
List all available badges (no auth required).
const { badges } = await client.listBadges()
for (const badge of badges) {
console.log(`#${badge.id} ${badge.name} — ${badge.description}`)
}Discord
client.checkDiscord(params): Promise<DiscordCheckResponse>
Check Discord server membership and roles.
const result = await client.checkDiscord({
username: 'user123',
server_id: '123456789', // optional: filter to specific server
})
console.log(`Discord linked: ${result.linked}`)
console.log(`Username: ${result.discord_username}`)
for (const server of result.servers) {
console.log(`${server.server_name}: ${server.is_member ? 'Member' : 'Not member'}`)
if (server.roles?.length) {
console.log(` Roles: ${server.roles.join(', ')}`)
}
}Profile
client.getProfile(params): Promise<ProfileResponse>
Get a user's linked accounts and badge summary.
const profile = await client.getProfile({ user_address: '0x...' })
console.log('Wallets:', profile.wallets.map(w => w.address))
console.log('Twitter:', profile.twitter.username)
console.log('Discord:', profile.discord.username)
console.log(`Badges: ${profile.badges.total} total, ${profile.badges.minted} minted`)Discovery
client.getServices(): Promise<ServicesCatalog>
Get the API service catalog (no auth required).
const catalog = await client.getServices()
for (const service of catalog.services) {
console.log(`${service.name}: ${service.endpoint}`)
}client.health(): Promise<HealthResponse>
Health check (no auth required).
const health = await client.health()
console.log(health.status) // 'ok'
console.log(health.db) // 'connected'Session Management
The client tracks sessionId automatically for chat conversations:
const client = new GatekeeperClient({ baseUrl: '...', secret: '...' })
await client.chat('check badges for @user123')
// client.sessionId is now set
await client.chat('what about their Discord?')
// uses same session — AI remembers context
// Reset session
client.sessionId = nullAuthentication Modes
| Mode | Use Case | Setup |
|------|----------|-------|
| HMAC (auto) | Server-side apps | Pass secret to constructor |
| Bearer | Server-to-server | Pass bearerToken to constructor |
| HMAC (per-request) | Browser apps | Pass token to each method call |
HMAC Flow for Browser Apps
Browser → Your Backend → GatekeeperSigner.createToken() → token
Browser → client.chat(msg, { token }) → Gatekeeper API → replyUse @foruai/gatekeeper-server on your backend to generate tokens.
Error Handling
All methods throw on HTTP errors with the server's error message:
try {
await client.verifyBadges({ user_address: '0xinvalid' })
} catch (err) {
console.error(err.message) // e.g. "User not found"
}Runtime Compatibility
| Runtime | Status |
|---------|--------|
| Node.js 18+ | Supported (native fetch) |
| Bun | Supported |
| Deno | Supported |
| Browsers | Supported |
| Edge (Cloudflare Workers, Vercel Edge) | Supported |
Zero dependencies beyond @foruai/shared and @foruai/gatekeeper-server.
Companion Packages
@foruai/shared— Shared types and constants@foruai/gatekeeper-server— Server-side HMAC token signing
License
MIT
