Action Type DSL
The Action Type DSL (Domain-Specific Language) defines action types declaratively, configuring validation rules, processing behavior, and lifecycle hooks without modifying core code.
ActionDefinition Structure
Each action type is defined by an ActionDefinition:
struct ActionDefinition {
action_type: String, // e.g., "POST", "CMNT", "FLLW"
version: u32, // Schema version
metadata: Metadata, // Display name, description, etc.
subtypes: Vec<String>, // e.g., POST:IMG, POST:VID
fields: Vec<FieldDef>, // Field definitions
schema: Schema, // JSON Schema for validation
behavior: Behavior, // Processing behavior flags
hooks: Hooks, // Lifecycle hooks
permissions: Permissions, // Permission requirements
key_pattern: String, // Database key pattern for overriding
}Fields
Each field in an action is defined with validation rules:
struct FieldDef {
name: String, // Field name in JWT (e.g., "c", "p", "vis")
field_type: FieldType, // string, object, array, number, boolean
required: bool, // Is this field required?
validate: Option<Schema>, // Additional validation rules
}Behavior Flags
Behavior flags control how actions are processed:
| Flag | Description | Example Types |
|---|---|---|
broadcast |
Send to multiple recipients (followers) | POST, REPOST |
allow_unknown |
Accept actions from unknown senders | CONN |
ephemeral |
Don’t persist to database | PRES (presence) |
approvable |
Can be approved/rejected by recipient | CONN, FLLW |
requires_subscription |
Sender must be subscribed | MSG, CONV |
deliver_subject |
Deliver to subject owner | CMNT, REACT |
deliver_to_subject_owner |
Alternative delivery to subject owner | CMNT |
Behavior Examples
POST Action (broadcast content):
Behavior {
broadcast: true, // Send to all followers
allow_unknown: false, // Must be from followed/connected user
ephemeral: false, // Persist to database
approvable: false, // No approval needed
requires_subscription: false, // No subscription required
deliver_subject: false, // Not a reply
}CONN Action (connection request):
Behavior {
broadcast: false, // Send only to audience
allow_unknown: true, // Accept from anyone (with PoW)
ephemeral: false, // Persist to database
approvable: true, // Recipient can accept/reject
requires_subscription: false, // No subscription required
deliver_subject: false, // Direct to audience
}Hook System
Hooks allow custom logic at different points in the action lifecycle:
struct Hooks {
on_create: Option<HookFn>, // Called when action is created locally
on_receive: Option<HookFn>, // Called when action is received from federation
on_accept: Option<HookFn>, // Called when approvable action is accepted
on_reject: Option<HookFn>, // Called when approvable action is rejected
}Hooks handle tasks such as: validating business logic and generating notifications on create/receive, establishing connections or granting permissions on accept, and cleaning up pending state on reject.
Permissions
Define who can perform which operations:
struct Permissions {
create: PermissionRule, // Who can create this action type
read: PermissionRule, // Who can read actions of this type
delete: PermissionRule, // Who can delete (owner only typically)
}Permission Rules
| Rule | Description |
|---|---|
Owner |
Only the action issuer |
Audience |
The action’s audience field |
Connected |
Mutually connected users |
Follower |
Users who follow the issuer |
Verified |
Any authenticated user |
Public |
Anyone, including unauthenticated |
Key Pattern
The key_pattern determines how actions are stored and whether they can be overridden:
| Action Type | Key Pattern | Override Behavior |
|---|---|---|
| POST | {iss}:{id} |
Each post is unique |
| CMNT | {iss}:{p}:{id} |
Each comment is unique (p = parent) |
| REACT | {iss}:{sub} |
One reaction per user per subject |
| FLLW | {iss}:{aud} |
One follow per user per target |
| CONN | {iss}:{aud} |
One connection request per pair |
Override example:
User reacts to post with LIKE
→ Stored at key: "alice.example.com:a1~post123"
User changes reaction to LOVE
→ Same key: "alice.example.com:a1~post123"
→ Previous LIKE is REPLACED by LOVEExample Definition
POST Definition
ActionDefinition {
action_type: "POST",
version: 1,
metadata: Metadata {
display_name: "Post",
description: "A public post or status update",
category: Category::Content,
},
subtypes: vec!["IMG", "VID", "LNK", "TXT"],
fields: vec![
FieldDef { name: "c", field_type: String, required: true },
FieldDef { name: "a", field_type: Array, required: false },
FieldDef { name: "vis", field_type: String, required: false },
FieldDef { name: "f", field_type: String, required: false },
],
behavior: Behavior {
broadcast: true,
allow_unknown: false,
ephemeral: false,
approvable: false,
requires_subscription: false,
deliver_subject: false,
},
hooks: Hooks {
on_create: Some(post_on_create),
on_receive: Some(post_on_receive),
on_accept: None,
on_reject: None,
},
permissions: Permissions {
create: PermissionRule::Owner,
read: PermissionRule::ByVisibility,
delete: PermissionRule::Owner,
},
key_pattern: "{iss}:{id}",
}Other action types (CMNT, CONV, etc.) follow the same pattern with type-specific fields, behavior flags, and hooks.
DSL Validation
When an action is created or received, it’s validated against its DSL definition:
validate_action(action, definition):
1. Check required fields exist
2. Validate field types
3. Run schema validation
4. Check behavior constraints:
- If requires_subscription: verify sender is subscribed
- If !allow_unknown: verify sender is known (following/connected)
- If approvable: set initial status to pending
5. Return validation resultSee Also
- Actions & Action Tokens - Overview of the action system
- Action Delivery - How actions are distributed
- ABAC Permissions - Permission system