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 DatabaseSettingsAPI 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.