Hanzo Base

Cloud Functions

Server-side JavaScript hooks, custom routes, and scheduled tasks running inside Base.

Base includes a built-in JavaScript runtime (JSVM) for server-side logic. Write hooks, custom API routes, and cron jobs without a separate service.

Hooks

Hooks run before or after database operations:

// hz_hooks/main.pb.js

// Before creating a record
onRecordCreate((e) => {
  // Validate
  if (e.record.get('title').length < 3) {
    throw new BadRequestError('Title too short')
  }
  // Transform
  e.record.set('slug', slugify(e.record.get('title')))
  return e.next()
}, 'posts')

// After creating a record
onRecordAfterCreateSuccess((e) => {
  // Send notification
  const author = $app.findRecordById('users', e.record.get('author'))
  sendEmail(author.get('email'), 'Your post was published!')
}, 'posts')

// Before updating
onRecordUpdate((e) => {
  e.record.set('updatedBy', e.requestInfo().auth?.id)
  return e.next()
}, 'tasks')

// Before deleting
onRecordDelete((e) => {
  // Soft delete instead
  e.record.set('deletedAt', new Date().toISOString())
  $app.save(e.record)
  // Prevent actual deletion
  throw new Error('Record soft-deleted')
}, 'posts')

Custom Routes

Add API endpoints alongside the auto-generated collection routes:

// hz_hooks/routes.pb.js

// GET /api/stats
routerAdd('GET', '/api/stats', (e) => {
  const totalPosts = $app.findRecordsByFilter('posts', '1=1').length
  const totalUsers = $app.findRecordsByFilter('users', '1=1').length

  return e.json(200, {
    posts: totalPosts,
    users: totalUsers,
  })
})

// POST /api/webhook
routerAdd('POST', '/api/webhook', (e) => {
  const body = e.requestBody()
  // Process webhook payload
  $app.findRecordById('events', body.eventId)
  return e.json(200, { ok: true })
})

// Protected route
routerAdd('GET', '/api/me/dashboard', (e) => {
  const auth = e.requestInfo().auth
  if (!auth) {
    throw new UnauthorizedError('Login required')
  }

  const tasks = $app.findRecordsByFilter('tasks',
    `assignee = "${auth.id}" && status = "active"`)

  return e.json(200, { tasks })
})

Scheduled Functions

Run functions on a cron schedule:

// hz_hooks/cron.pb.js

// Every hour — cleanup expired sessions
cronAdd('cleanup sessions', '0 * * * *', () => {
  const expired = $app.findRecordsByFilter('sessions',
    `expiresAt < "${new Date().toISOString()}"`)
  for (const session of expired) {
    $app.delete(session)
  }
})

// Daily at 3am — generate reports
cronAdd('daily report', '0 3 * * *', () => {
  const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0]
  const events = $app.findRecordsByFilter('events',
    `created >= "${yesterday}"`)

  $app.save(new Record($app.findCollectionByNameOrId('reports'), {
    date: yesterday,
    eventCount: events.length,
  }))
})

// Every 5 minutes — sync external data
cronAdd('sync feed', '*/5 * * * *', () => {
  const response = $http.send({
    url: 'https://api.example.com/feed',
    method: 'GET',
  })

  if (response.statusCode === 200) {
    // Process and save
  }
})

Available APIs

The JSVM provides access to:

APIDescription
$appApplication instance (find, save, delete records)
$httpHTTP client for external requests
$osOS utilities (env vars, file system)
$securityCrypto functions (hash, encrypt, JWT)
$mailEmail sending

Last updated on

On this page