Documentation is English-only for now. The rest of the site follows your language.
Hooks
Typed actions, gates, and filters — the complete core hook list and how to register them.
10 min read
Hooks are how you change what Justflows does without changing Justflows. Write the plugin in plugins/<name>/ (copy plugins/hello-world) and register hooks in activate(). Names autocomplete from @justflows/sdk.
| I want to… | Use a… | Names look like |
|---|---|---|
| React after something happened | action | content.published |
| Stop something before it commits | gate | content.beforeCreate |
| Change a value on the way through | filter | content.render |
Actions
Observe only. Cannot cancel. If your handler throws, Justflows logs it against your plugin and continues — a broken analytics plugin must not block publishing. Treat payloads as read-only. Async handlers are awaited in order.
| Action | When |
|---|---|
app.starting / app.started / app.stopping | Process lifecycle |
content.created / updated / deleted / published / unpublished | Content |
media.uploaded / media.deleted | Media |
user.created / updated / deleted | Users (needs users:read) |
auth.login / logout / loginFailed | Auth (needs auth:hook) |
plugin.installed / activated / deactivated / uninstalled | Plugins |
theme.installed / theme.activated | Themes |
request.before / request.after | HTTP |
site.underConstruction.viewed | Unpublished site hit |
cache.revalidated | After selective cache revalidate |
Gates
Run before commit. Call event.cancel("Human-readable reason") to abort. Fail closed: if your gate throws, the operation is aborted and attributed to your plugin. Priority order; first cancellation wins.
content.beforeCreate/beforeUpdate/beforeDelete/beforePublishmedia.beforeUpload/media.beforeDelete
ctx.hooks.gate("media.beforeUpload", (event) => {
if (event.sizeBytes > 10_000_000) {
event.cancel("Files must be under 10 MB.");
}
});Filters
You must return a value. On core hooks TypeScript enforces it. If a custom filter returns undefined, the previous value is kept and a warning is logged. Throws skip your filter and keep the last good value.
| Filter | Transforms |
|---|---|
content.input / content.output | Content records in/out |
content.render | HTML string (must be sync) |
media.metadata | Metadata object |
navigation.items | Menu tree |
http.responseHeaders | Header map (must be sync) |
site.underConstruction.render | Under-construction HTML (must be sync) |
SYNC_FILTERS: content.render, http.responseHeaders, site.underConstruction.render — handlers must not be async.
Options and ownership
priority— lower runs earlier (default 100).once— auto-dispose after first dispatch.id— stable label in diagnostics.- Plugins may emit only hooks under their own manifest id (
acme.seo.scoreCalculated). - Declaration merging on
ActionEventMap/GateEventMap/FilterValueMaptypes your own names.
Note
Longer narrative and cleanup rules: docs/HOOKS.md in justflows-platform-ce.