GlobalCode - Serverless Functions
GlobalCode is Globio's serverless function platform. Deploy backend logic with zero cold starts and edge performance.
🚀 Quick Start
import { GlobalCode } from '@stanlink/globio'
const functions = new GlobalCode({
apiKey: 'your-api-key',
projectId: 'your-project-id'
})
// Call a function
const result = await functions.httpsCallable('calculateScore')({
playerId: 'player123',
gameData: { kills: 5, time: 300 }
})📝 Writing Functions
Basic Function
// functions/calculateScore.js
export default async function calculateScore(data, context) {
const { playerId, gameData } = data
// Calculate score based on game data
const baseScore = gameData.kills * 100
const timeBonus = Math.max(0, 600 - gameData.time)
const totalScore = baseScore + timeBonus
return {
playerId,
score: totalScore,
breakdown: {
kills: baseScore,
timeBonus: timeBonus
}
}
}Database Integration
// functions/updateLeaderboard.js
import { GlobalDoc } from '@stanlink/globio'
export default async function updateLeaderboard(data, context) {
const { playerId, score } = data
const db = new GlobalDoc({ apiKey: context.apiKey })
// Update player's best score
await db.collection('leaderboard').doc(playerId).set({
playerId,
bestScore: score,
lastUpdated: new Date()
}, { merge: true })
// Get player's rank
const betterPlayers = await db.collection('leaderboard')
.where('bestScore', '>', score)
.get()
const rank = betterPlayers.size + 1
return { rank, score }
}🎮 Gaming Examples
Matchmaking Function
// functions/findMatch.js
export default async function findMatch(data, context) {
const { playerId, skillLevel, gameMode } = data
const db = new GlobalDoc({ apiKey: context.apiKey })
// Find players looking for match
const waitingPlayers = await db.collection('matchmaking')
.where('gameMode', '==', gameMode)
.where('skillLevel', '>=', skillLevel - 100)
.where('skillLevel', '<=', skillLevel + 100)
.where('status', '==', 'waiting')
.limit(3)
.get()
if (waitingPlayers.size >= 3) {
// Create match
const matchId = `match_${Date.now()}`
const players = [playerId, ...waitingPlayers.docs.map(doc => doc.id)]
await db.collection('matches').doc(matchId).set({
players,
gameMode,
status: 'starting',
createdAt: new Date()
})
return { matchId, players }
} else {
// Add to waiting queue
await db.collection('matchmaking').doc(playerId).set({
playerId,
skillLevel,
gameMode,
status: 'waiting',
joinedAt: new Date()
})
return { status: 'waiting' }
}
}Anti-Cheat Validation
// functions/validateScore.js
export default async function validateScore(data, context) {
const { playerId, score, gameData, timestamp } = data
// Basic validation checks
const maxPossibleScore = gameData.timeLimit * 10 // 10 points per second max
const timeDiff = Date.now() - timestamp
if (score > maxPossibleScore) {
return { valid: false, reason: 'Score too high' }
}
if (timeDiff > 60000) { // 1 minute tolerance
return { valid: false, reason: 'Submission too late' }
}
// Advanced checks could include:
// - Pattern analysis
// - Historical player data
// - Machine learning models
return { valid: true, score }
}Tournament Management
// functions/manageTournament.js
export default async function manageTournament(data, context) {
const { tournamentId, action, playerId } = data
const db = new GlobalDoc({ apiKey: context.apiKey })
const tournament = await db.collection('tournaments').doc(tournamentId).get()
const tournamentData = tournament.data()
switch (action) {
case 'join':
if (tournamentData.players.length < tournamentData.maxPlayers) {
await tournament.ref.update({
players: [...tournamentData.players, playerId],
updatedAt: new Date()
})
return { success: true, message: 'Joined tournament' }
}
return { success: false, message: 'Tournament is full' }
case 'start':
if (tournamentData.players.length >= tournamentData.minPlayers) {
// Create bracket
const bracket = generateBracket(tournamentData.players)
await tournament.ref.update({
status: 'active',
bracket,
startedAt: new Date()
})
return { success: true, bracket }
}
return { success: false, message: 'Not enough players' }
case 'advance':
// Handle match results and advance winners
const updatedBracket = advanceWinner(tournamentData.bracket, data.matchResult)
await tournament.ref.update({
bracket: updatedBracket,
updatedAt: new Date()
})
return { success: true, bracket: updatedBracket }
}
}🔄 Triggers and Events
Database Triggers
// functions/onPlayerUpdate.js
// Triggered when a player document is updated
export default async function onPlayerUpdate(change, context) {
const { before, after } = change
const playerId = context.params.playerId
// Check if level increased
if (after.level > before.level) {
// Award level-up bonus
await after.ref.update({
coins: after.coins + (after.level * 10),
lastLevelUp: new Date()
})
// Send notification
await sendNotification(playerId, {
title: 'Level Up!',
body: `Congratulations! You reached level ${after.level}`,
data: { type: 'level_up', level: after.level }
})
}
}Scheduled Functions
// functions/dailyRewards.js
// Runs every day at midnight
export default async function dailyRewards(context) {
const db = new GlobalDoc({ apiKey: context.apiKey })
// Get all active players
const activePlayers = await db.collection('players')
.where('lastLogin', '>=', new Date(Date.now() - 7 * 24 * 60 * 60 * 1000))
.get()
const batch = db.batch()
activePlayers.forEach(doc => {
const player = doc.data()
const dailyReward = calculateDailyReward(player.level, player.streak)
batch.update(doc.ref, {
coins: player.coins + dailyReward.coins,
gems: player.gems + dailyReward.gems,
streak: player.streak + 1,
lastDailyReward: new Date()
})
})
await batch.commit()
console.log(`Processed daily rewards for ${activePlayers.size} players`)
}🔒 Security and Validation
Authentication Context
// functions/secureFunction.js
export default async function secureFunction(data, context) {
// Check if user is authenticated
if (!context.auth) {
throw new Error('Authentication required')
}
const userId = context.auth.uid
const userClaims = context.auth.token
// Check user permissions
if (!userClaims.admin && data.adminAction) {
throw new Error('Admin privileges required')
}
// Proceed with function logic
return { success: true, userId }
}Input Validation
// functions/validateInput.js
import Joi from 'joi'
const schema = Joi.object({
playerId: Joi.string().required(),
score: Joi.number().integer().min(0).max(1000000).required(),
gameMode: Joi.string().valid('classic', 'blitz', 'tournament').required()
})
export default async function validateInput(data, context) {
// Validate input data
const { error, value } = schema.validate(data)
if (error) {
throw new Error(`Invalid input: ${error.details[0].message}`)
}
// Process validated data
return processGameScore(value)
}📊 Performance and Monitoring
Function Metrics
// functions/monitoredFunction.js
export default async function monitoredFunction(data, context) {
const startTime = Date.now()
try {
// Function logic here
const result = await processData(data)
// Log success metrics
console.log('Function completed', {
duration: Date.now() - startTime,
success: true,
dataSize: JSON.stringify(data).length
})
return result
} catch (error) {
// Log error metrics
console.error('Function failed', {
duration: Date.now() - startTime,
success: false,
error: error.message
})
throw error
}
}Caching Strategies
// functions/cachedFunction.js
const cache = new Map()
const CACHE_TTL = 5 * 60 * 1000 // 5 minutes
export default async function cachedFunction(data, context) {
const cacheKey = `${data.type}_${data.id}`
const cached = cache.get(cacheKey)
// Return cached result if valid
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.data
}
// Compute new result
const result = await expensiveComputation(data)
// Cache the result
cache.set(cacheKey, {
data: result,
timestamp: Date.now()
})
return result
}🚀 Deployment and Testing
Local Development
// Test functions locally
import { GlobalCode } from '@stanlink/globio'
const functions = new GlobalCode({
apiKey: 'test-key',
projectId: 'test-project',
emulator: true // Use local emulator
})
// Test function call
const result = await functions.httpsCallable('calculateScore')({
playerId: 'test-player',
gameData: { kills: 5, time: 300 }
})
console.log('Test result:', result)Function Configuration
// globio.config.js
export default {
functions: {
calculateScore: {
memory: '256MB',
timeout: '30s',
regions: ['us-east1', 'europe-west1']
},
dailyRewards: {
schedule: '0 0 * * *', // Daily at midnight
memory: '512MB',
timeout: '300s'
}
}
}💡 Best Practices
Error Handling
export default async function robustFunction(data, context) {
try {
// Validate input
if (!data.playerId) {
throw new Error('Player ID is required')
}
// Process data
const result = await processPlayerData(data)
return { success: true, data: result }
} catch (error) {
console.error('Function error:', error)
// Return structured error response
return {
success: false,
error: {
code: error.code || 'UNKNOWN_ERROR',
message: error.message
}
}
}
}Resource Management
// Efficient database operations
export default async function efficientFunction(data, context) {
const db = new GlobalDoc({ apiKey: context.apiKey })
// Use batch operations for multiple writes
const batch = db.batch()
data.updates.forEach(update => {
const docRef = db.collection('players').doc(update.playerId)
batch.update(docRef, update.data)
})
await batch.commit()
// Close connections properly
await db.terminate()
}Next: Learn about GlobioID Authentication →