Logic Hooks
Logic Hooks
Hooks (often called "Triggers" in SQL databases) allow you to intercept database operations to inject custom logic. They are transaction-aware and fully typed.
1. Registration Methods
You can define hooks in two ways: File-based (Static) or Programmatic (Dynamic).
A. File-based (Recommended)
Place a *.hook.ts file next to your object definition. The loader automatically discovers it.
File: src/objects/project.hook.ts
B. Programmatic (Dynamic)
Use the app.on() API, typically inside a Plugin.
2. Event Lifecycle
| Event Name | Description | Common Use Case |
|---|---|---|
before:create | Before inserting a new record. | Validation, Default Values, ID generation. |
after:create | After insertion is committed. | Notifications, downstream sync. |
before:update | Before modifying an existing record. | Permission checks, Immutable field protection. |
after:update | After modification is committed. | Audit logging, history tracking. |
before:delete | Before removing a record. | Referential integrity checks. |
after:delete | After removal is committed. | Clean up related resources (e.g. S3 files). |
before:find | Before executing a query. | Row-Level Security (RLS), Force filters. |
after:find | After fetching results. | Decryption, Sensitive data masking. |
3. The Hook Context
The context object (ctx) changes based on the event type.
Common Properties (Available Everywhere)
| Property | Type | Description |
|---|---|---|
objectName | string | The name of the object being operated on. |
user | ObjectQLUser | Current user session/context. |
broker | IStation | (If Microservices enabled) Station broker instance. |
Mutation Context (Create/Update/Delete)
| Property | Type | Available In | Description |
|---|---|---|---|
data | Any | Create/Update | The data payload being written. Mutable. |
id | string | Update/Delete | The ID of the record being acted upon. |
previousData | Any | Update/Delete | The existing record fetched from DB before operation. |
result | Any | After * | The final result returned from the driver. |
Query Context (Find)
| Property | Type | Description |
|---|---|---|
query | steedos-filters | The query AST (filters, fields, sort). Mutable. |
result | Any[] | (After Find) The array of records found. Mutable. |
4. Common Patterns & Examples
A. Validation & Default Values
Throwing an error inside a before hook aborts the transaction.
B. Immutable Fields Protection
Prevent users from changing critical fields during update.
C. Row-Level Security (RLS)
The most secure place to enforce permissions is before:find. This injects filters into every query (API, GraphQL, or internal).
D. Side Effects (Notifications)
Use after hooks for logic that strictly relies on success.
E. Result Masking
Hide sensitive fields based on rules.
F. Auto-Numbering / ID Generation
Generate complex business keys.
G. Conditional Deletion
Use previousData in delete hooks to prevent deleting records based on their state.
5. Transaction Safety
Hooks participate in the database transaction.
- If a
beforehook throws -> The DB operation is never executed. - If the DB operation fails ->
afterhooks are never executed. - If an
afterhook throws -> The entire transaction rolls back (including the DB write).
Tip: If you want a "Fire and Forget" action that shouldn't rollback the transaction (e.g. sending an email), wrap your logic in a
try/catchor execute it withoutawait.