Counter / View Tracker

Track page views, link clicks, or any incrementing value without giving you direct UPDATE access to the counter field.

Mark the counter field as noUpdate: true so regular CRUD can't touch it. Then expose an action that increments it.

Config

typescript
// teenybase.ts
import { DatabaseSettings, sql, sqlValue, TableRulesExtensionData } from 'teenybase'
import { baseFields, createdTrigger, updatedTrigger } from 'teenybase/scaffolds/fields'

export default {
    appUrl: 'http://localhost:8787',
    jwtSecret: '$JWT_SECRET',
    tables: [{
        name: 'links',
        autoSetUid: true,
        fields: [
            ...baseFields,
            { name: 'url', type: 'url', sqlType: 'text', notNull: true },
            { name: 'title', type: 'text', sqlType: 'text', notNull: true },
            { name: 'clicks', type: 'integer', sqlType: 'integer', notNull: true,
              default: sqlValue(0), noInsert: true, noUpdate: true },
        ],
        triggers: [createdTrigger, updatedTrigger],
        extensions: [{
            name: 'rules',
            listRule: 'true',
            viewRule: 'true',
            createRule: 'auth.uid != null',
            updateRule: 'auth.uid != null',
            deleteRule: 'auth.uid != null',
        } as TableRulesExtensionData],
    }],
    actions: [{
        name: 'click',
        params: { link_id: 'string' },
        applyTableRules: false,
        sql: {
            type: 'UPDATE',
            table: 'links',
            set: { clicks: sql`clicks + 1` },
            where: sql`id = {:link_id}`,
            returning: ['clicks'],
        },
    }],
} satisfies DatabaseSettings

API calls

bash
# Create a link (authenticated)
curl -X POST http://localhost:8787/api/v1/table/links/insert \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"values": {"url": "https://example.com", "title": "Example"}}'

# Increment clicks (no auth required — public counter)
curl -X POST http://localhost:8787/api/v1/action/click \
  -H 'Content-Type: application/json' \
  -d '{"link_id": "abc123"}'
# → [[{"clicks": 1}]]

# Increment again
curl -X POST http://localhost:8787/api/v1/action/click \
  -H 'Content-Type: application/json' \
  -d '{"link_id": "abc123"}'
# → [[{"clicks": 2}]]

Why this is safe: The noUpdate: true on the clicks field prevents you from setting clicks to 999 via the regular /update endpoint. Only the action can modify it, because actions with applyTableRules: false bypass field restrictions and execute raw SQL.