Skip to Content
AdvancedBuilt-In Helpers

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

HelperLines SavedComplexity Reduced
createJWTAuth()30-40High
createTokenAuth()40-50High
Serialization30-50Medium
createRetryPolicy()20-30Medium
createSnapshotCache()20-30Medium
createValidator()15-25Low

Total: 155-225 lines eliminated per project! 🎉

Next Steps

Last updated on