Registered Hooks
Registered hooks fire for all collections at a given lifecycle event. Register them in init.lua using crap.hooks.register().
Registration
-- init.lua
crap.hooks.register("before_change", function(ctx)
crap.log.info("[audit] " .. ctx.operation .. " on " .. ctx.collection)
return ctx
end)
Unlike collection-level hooks (which are string references), registered hooks are Lua functions passed directly.
API
crap.hooks.register(event, fn)
Register a hook function for a lifecycle event.
| Parameter | Type | Description |
|---|---|---|
event | string | One of the lifecycle events |
fn | function | Hook function receiving a context table |
crap.hooks.remove(event, fn)
Remove a previously registered hook. Uses rawequal for identity-based matching — you must pass the exact same function reference.
local my_hook = function(ctx)
-- ...
return ctx
end
crap.hooks.register("before_change", my_hook)
-- Later:
crap.hooks.remove("before_change", my_hook)
CRUD Access
Registered hooks follow the same rules as collection-level hooks:
- Before-event hooks (
before_validate,before_change,before_delete) have CRUD access via the shared transaction - Write after-event hooks (
after_change,after_delete) have CRUD access — they run inside the same transaction viarun_hooks_with_conn - Read after-event hooks (
after_read) do NOT have CRUD access — they run without a transaction
Execution Order
Registered hooks run after field-level and collection-level hooks at each lifecycle stage.
Example: Audit Log
-- init.lua
crap.hooks.register("before_change", function(ctx)
crap.log.info(string.format(
"[audit] %s %s: %s",
ctx.operation,
ctx.collection,
ctx.data.id or "(new)"
))
return ctx
end)
Example: Auto-Set Created By
-- init.lua (requires auth + access context in hooks)
crap.hooks.register("before_change", function(ctx)
if ctx.operation == "create" then
-- Set created_by to current user ID if field exists
-- (requires the collection to have a created_by field)
end
return ctx
end)