7.9 KiB
IRC Webchat Package - Declarative Conversion Guide
Overview
The IRC Webchat component has been successfully converted from a traditional React TypeScript component to a fully declarative JSON and Lua-based package. This conversion demonstrates the power of the MetaBuilder package system, where complex interactive components can be defined entirely through configuration and scripting.
Package Structure
The IRC Webchat package (irc-webchat) is now defined in /src/lib/package-catalog.ts and includes:
1. Manifest
{
"id": "irc-webchat",
"name": "IRC-Style Webchat",
"version": "1.0.0",
"category": "social",
"icon": "💬"
}
2. Data Schemas
Three database schemas define the chat data structure:
- ChatChannel: Chat channels/rooms with name, description, topic
- ChatMessage: Individual messages with type (message, system, join, leave)
- ChatUser: Online users per channel
3. Pages
The package includes a pre-configured /chat page at Level 2 (user area) with authentication required.
4. Lua Scripts
Five Lua scripts handle all chat logic:
lua_irc_send_message
Creates a chat message object with unique ID, timestamp, and user information.
function sendMessage(channelId, username, userId, message)
-- Returns a message object
end
lua_irc_handle_command
Processes IRC-style commands like /help, /users, /clear, /me.
function handleCommand(command, channelId, username, onlineUsers)
-- Returns system response or command result
end
lua_irc_format_time
Formats Unix timestamps into human-readable 12-hour format.
function formatTime(timestamp)
-- Returns formatted time string like "02:45 PM"
end
lua_irc_user_join
Generates join messages when users enter a channel.
function userJoin(channelId, username, userId)
-- Returns a join-type message
end
lua_irc_user_leave
Generates leave messages when users exit a channel.
function userLeave(channelId, username, userId)
-- Returns a leave-type message
end
5. Component Configuration
The package defines a declarative component structure using JSON:
{
"type": "IRCWebchat",
"config": {
"layout": "Card",
"children": [
{
"id": "header",
"type": "CardHeader",
"children": [...]
},
{
"id": "content",
"type": "CardContent",
"children": [
{
"id": "messages_area",
"type": "ScrollArea",
...
},
{
"id": "input_area",
"type": "Container",
...
}
]
}
]
}
}
6. Seed Data
Pre-configured chat channels:
general: General discussionrandom: Random conversations
How It Works
Component Loading
- Package Initialization:
initializePackageSystem()is called inApp.tsxon startup - Script Registration: All Lua scripts are registered with the
DeclarativeComponentRenderer - Component Registration: Component configurations are registered for use in the builder
Runtime Execution
When the IRC component is used:
- User Join: Calls
lua_irc_user_jointo create a join message - Send Message: Calls
lua_irc_send_messagewith user input - Commands: Calls
lua_irc_handle_commandwhen message starts with/ - Time Formatting: Calls
lua_irc_format_timefor each message timestamp - User Leave: Calls
lua_irc_user_leaveon component unmount
Data Flow
User Action → React Component (IRCWebchatDeclarative)
↓
getDeclarativeRenderer().executeLuaScript(scriptId, params)
↓
LuaEngine.execute(wrappedCode, context)
↓
Lua Function Execution (Fengari)
↓
Result Conversion (Lua table → JavaScript object)
↓
React State Update (useKV for persistence)
Migration from TSX
Before (IRCWebchat.tsx)
const handleSendMessage = () => {
const newMessage: ChatMessage = {
id: `msg_${Date.now()}_${Math.random()}`,
username: user.username,
userId: user.id,
message: trimmed,
timestamp: Date.now(),
type: 'message',
}
setMessages((current) => [...(current || []), newMessage])
}
After (Declarative + Lua)
const newMessage = await renderer.executeLuaScript('lua_irc_send_message', [
`chat_${channelName}`,
user.username,
user.id,
trimmed,
])
setMessages((current) => [...(current || []), newMessage])
Benefits of Declarative Approach
1. No Code Deployment
- Changes to chat logic require only JSON/Lua updates
- No TypeScript compilation needed
- Hot-swappable functionality
2. Package System Integration
- IRC can be installed/uninstalled like any package
- Export/import as ZIP with all configurations
- Share with other MetaBuilder instances
3. GUI Configuration
- Chat commands can be modified in Level 4/5 panels
- Time format can be changed without code
- New message types can be added dynamically
4. Multi-Tenancy Ready
- Each tenant can customize chat behavior
- Lua scripts can be overridden per tenant
- Database schemas are tenant-isolated
5. Security Sandboxing
- Lua execution is sandboxed (can be enhanced)
- Scripts can be scanned for malicious code
- Limited API surface for Lua scripts
File Structure
/src
/components
IRCWebchat.tsx [DEPRECATED - Can be removed]
IRCWebchatDeclarative.tsx [NEW - Uses declarative system]
/lib
package-catalog.ts [Contains irc-webchat package]
declarative-component-renderer.ts [Executes Lua scripts]
lua-engine.ts [Fengari Lua runtime]
package-loader.ts [Loads packages on init]
Next Steps
For Developers
- Review the Lua scripts in
package-catalog.ts - Test IRC functionality in Level 2 user area
- Consider removing
IRCWebchat.tsx(old component) - Add more Lua scripts for advanced features
For Users (Level 4/5)
- Navigate to Package Manager
- View installed
irc-webchatpackage - Modify Lua scripts to customize behavior
- Add new commands via Lua Editor
- Export package to share with others
Testing the Conversion
- Login as a regular user
- Navigate to Level 2 (User Area)
- Go to the Chat tab
- Test the following:
- Send messages
- Use
/helpcommand - Use
/userscommand - Use
/me dancescommand - Use
/clearcommand - Open another window and see online users update
Troubleshooting
Lua Script Not Found
- Ensure
initializePackageSystem()is called before component renders - Check that
irc-webchatpackage exists inPACKAGE_CATALOG
Messages Not Sending
- Check browser console for Lua execution errors
- Verify parameter types match Lua script expectations
- Ensure
useKVkeys are correctly formatted
Time Format Issues
- Review
lua_irc_format_timescript - Check timestamp is in milliseconds (JavaScript format)
- Lua
os.time()returns seconds, multiply by 1000
Future Enhancements
- Channel Management: Lua scripts for creating/deleting channels
- User Mentions: Parse
@usernameand notify users - Message Reactions: Add emoji reactions via Lua
- File Sharing: Integrate with asset management
- Moderation: Kick/ban users, message filtering
- Bots: AI-powered chat bots using
spark.llm - Persistence: Save message history to database schemas
- Notifications: Browser notifications for new messages
Conclusion
The IRC Webchat conversion demonstrates that even complex, interactive components can be fully defined using JSON and Lua. This approach enables:
- Rapid iteration without deployments
- User customization at the highest levels
- Package sharing across instances
- Multi-tenant flexibility
- Security through sandboxing
The declarative pattern can be extended to other components like forums, comments, notifications, and more.