Built-In Helpers
Gluonic provides helper functions to eliminate common boilerplate.
Authentication Helpers
Server: createJWTAuth()
Eliminate JWT boilerplate on the server:
import { createJWTAuth } from '@gluonic/server/auth'
await SyncServer(app, {
auth: createJWTAuth({
secret: process.env.JWT_SECRET,
// Extract user from decoded token
getUserId: (decoded) => decoded.userId,
// Automatically handles:
// - Bearer tokens (HTTP)
// - Query params (WebSocket)
// - Token validation
// - Error messages
})
})Replaces 30-40 lines of manual auth code!
What it handles:
// Manually (before):
async function requireAuth(req) {
let token = req.headers.authorization?.replace('Bearer ', '')
if (!token && req.query?.token) token = req.query.token
if (!token) throw new Error('No token')
try {
const decoded = jwt.verify(token, JWT_SECRET)
req.user = { id: decoded.userId }
} catch (error) {
throw new Error('Invalid token')
}
}
// With helper (after):
auth: createJWTAuth({ secret, getUserId })Client: createTokenAuth()
Eliminate token management boilerplate on the client:
import { createTokenAuth } from '@gluonic/client/auth'
const { store, GraphProvider } = createSyncClient({
auth: createTokenAuth({
storage: 'asyncstorage', // or 'localstorage'
tokenKey: 'auth_token',
// Optional: Auto-refresh expired tokens
refresher: async (oldToken) => {
const res = await fetch('/auth/refresh', {
headers: { authorization: `Bearer ${oldToken}` }
})
const { token } = await res.json()
return token
},
onUnauthenticated: () => router.push('/login')
})
})Replaces 40-50 lines of token management!
What it handles:
// Manually (before):
auth: {
getToken: async () => {
const token = await AsyncStorage.getItem('auth_token')
if (!token) return null
// Check expiration
const decoded = jwt.decode(token)
if (decoded.exp < Date.now() / 1000) {
// Refresh token
const newToken = await refreshToken(token)
await AsyncStorage.setItem('auth_token', newToken)
return newToken
}
return token
},
onUnauthenticated: () => router.push('/login')
}
// With helper (after):
auth: createTokenAuth({ storage: 'asyncstorage', tokenKey: 'auth_token' })Serialization Helpers
Auto-Serialize
Built into Prisma adapter:
const adapter = PrismaAdapter({
prisma,
serialization: {
// Auto-detect conventions
dateFields: '*At', // createdAt, updatedAt → timestamps
bigIntFields: '*Time', // startTime, endTime → strings
// Or explicit
dateFields: ['createdAt', 'publishedAt'],
bigIntFields: ['eventTime'],
// Exclude sensitive fields
exclude: ['password', 'secretKey']
}
})Replaces 30-50 lines of manual serialization!
Connection State Helper
useConnectionState()
Already built-in, just use it:
import { useConnectionState } from '@gluonic/client'
const SyncStatus = observer(() => {
const {
isOnline, // Network available
isSyncing, // Currently syncing
queueLength, // Pending mutations
lastSync, // Last sync timestamp
error // Last error
} = useConnectionState()
return (
<div>
{!isOnline && <Badge>Offline</Badge>}
{isSyncing && <Spinner />}
{queueLength > 0 && <Badge>{queueLength} pending</Badge>}
{error && <Alert>{error.message}</Alert>}
</div>
)
})Retry Configuration Helper
Configure retry behavior:
import { createRetryPolicy } from '@gluonic/client/helpers'
const { store } = createSyncClient({
retry: createRetryPolicy({
maxAttempts: 3,
baseDelay: 1000, // Start at 1s
maxDelay: 30000, // Cap at 30s
multiplier: 2, // Exponential backoff
jitter: true // Add randomness
})
})Replaces manual retry logic!
Snapshot Helper
Server-side snapshot configuration:
import { createSnapshotCache } from '@gluonic/server/helpers'
await SyncServer(app, {
snapshot: createSnapshotCache({
adapter: 'auto', // Auto-detect from environment
// REDIS_URL → redis
// AWS_* vars → s3
// Otherwise → file
refreshInterval: '10 minutes',
autoDiscoverOrgs: true // Query adapter for org IDs
})
})Replaces 20-30 lines of snapshot config!
Validation Helper
Client-side validation:
import { createValidator } from '@gluonic/client/helpers'
const validator = createValidator({
user: {
email: (val) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(val),
name: (val) => val.length > 0
},
post: {
title: (val) => val.length >= 3 && val.length <= 100,
content: (val) => val.length >= 10
}
})
// Apply to store
const { store } = createSyncClient({
validation: validator
})
// Mutations validate automatically
await store.save('post', id, { title: 'ab' })
// Throws: "Validation failed: title must be 3-100 characters"Benefits
| Helper | Lines Saved | Complexity Reduced |
|---|---|---|
| createJWTAuth() | 30-40 | High |
| createTokenAuth() | 40-50 | High |
| Serialization | 30-50 | Medium |
| createRetryPolicy() | 20-30 | Medium |
| createSnapshotCache() | 20-30 | Medium |
| createValidator() | 15-25 | Low |
Total: 155-225 lines eliminated per project! 🎉
Next Steps
- Server Auth Guide - Authentication patterns
- Client Setup - Client configuration
- Advanced Adapters - Custom adapters
Last updated on