Appearance
The Execution Lifecycle: Intelligent, Performant, & Predictable
A Record Behavior script is more than just code; it's a set of rules that executes within a sophisticated, event-driven lifecycle. Understanding this lifecycle is key to unlocking the full power of the Simple Platform. Our architecture is designed to solve the classic problems of client-server logic — performance bottlenecks, data inconsistency, and poor user experience — at the platform level.
Script Signature
Your script must be an export default async function that receives a single object argument. This modern, self-documenting signature allows you to destructure only the APIs you need.
javascript
export default async ({ $ai, $db, $form, $user }) => {
// Your logic here
const status = $form('status').value()
}The Secure WASM Sandbox
All Record Behavior scripts — whether running on the client or the server — execute within an isolated WebAssembly (WASM) sandbox. This is a critical architectural feature that guarantees your logic is secure and behaves identically in both environments.
Sandbox Limitations
Because scripts run in an isolated sandbox, they DO NOT have access to browser-specific or Node.js-specific APIs.
- DO NOT USE:
window,document,localStorage,fetch(),setTimeout(),process, etc. - DO USE: Standard JavaScript (ES2020) and the provided
{ $form, $db, $user, $ai }APIs.
Attempting to use a forbidden API will cause your script to fail.
The Event Lifecycle
Your script can react to three distinct events. The context in which they run — client-side or server-side — is critical to understanding their purpose.
| Event | Execution Context | Purpose |
|---|---|---|
load | Client and Server | Initialization: Sets default values for new records. This runs once when a new record form is opened in the UI, and also when a new record is created programmatically on the backend. |
update | Client-Side Only | Real-time UI Feedback: Reacts to user input in the browser to perform live calculations and make the form dynamic. It is optimized for performance and a smooth user experience. |
submit | Client and Server | Data Integrity: Provides final, authoritative validation before a new record or an update is saved to the database. It runs on the client for an instant pre-check, and again on the server as the final guarantee. |
Intelligent UI Execution: The Single-Window Model
In legacy platforms, running logic on every keystroke leads to a "janky," unresponsive user experience and bombards the server with requests. Simple solves this with an intelligent, blur-triggered execution model.
Instead of firing on every change, Record Behaviors on the update event are executed within a single 500ms window that begins after the user first moves away from a field (a blur event). The timer is not reset by subsequent blurs within that window.
This intelligently batches multiple rapid changes into a single, efficient execution.
The Simple Advantage
This approach provides the perfect balance: a hyper-responsive UI for the user, who never feels interrupted while typing, and an efficient, predictable execution model for the developer. Your logic runs exactly when it needs to, without overwhelming the browser.
Data Integrity: Atomic vs. Freeform Fields
What happens if a behavior runs while a user is still typing in a field? Legacy systems would send partial, incomplete data (like "Joh" instead of "John"), leading to incorrect calculations and validation errors.
Simple solves this by distinguishing between two types of fields:
- Atomic Fields: Their value is complete and finalized in a single user action. This includes dropdowns (
enum), lookups (reference_belongs_to), date pickers, and checkboxes (boolean). - Freeform Fields: Their value is built up over time. This includes text inputs, number inputs, and text areas.
The Rule: When a Record Behavior executes, it always excludes the value of the currently active freeform field from its payload. Atomic fields are always included, even when active.
This guarantees your scripts never operate on incomplete data.
Example: Imagine a user has filled out the Status (atomic) and is actively typing in the Email (freeform) field when a behavior triggers.
The $form.record() payload your script receives will look like this:
json
{
"status": "In Progress",
"email": undefined // Excluded because it's the active, freeform field
}The Simple Advantage
This simple but powerful rule guarantees data integrity at the platform level. Competitors like Salesforce and ServiceNow leave this complex state management to the developer, forcing them to write defensive, brittle code. Simple solves it for you, eliminating an entire class of subtle bugs.
Script Structure: Always Use Event Guards
Any code written in the global scope of your script (outside of an if ($form.event === ...) block) will execute on every single event. This is inefficient and can lead to unpredictable behavior. Always wrap your logic in event guards.
javascript
export default async ({ $form }) => {
// 🛑 BAD: This will run on 'load', 'update', AND 'submit'.
console.log('This runs on every event!')
// ✅ GOOD: This logic is properly guarded and runs only when intended.
if ($form.event === 'load') {
// Logic for setting default values on new records.
}
if ($form.event === 'update') {
// For performance, only run logic when relevant fields change.
if ($form.updated('quantity', 'unit_price')) {
// Calculate total price...
}
}
if ($form.event === 'submit') {
// Final validation logic.
}
}