mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-26 14:54:55 +00:00
Generated by Spark: Convert Forum component to declarative JSON and Lua
This commit is contained in:
293
IRC_CONVERSION_GUIDE.md
Normal file
293
IRC_CONVERSION_GUIDE.md
Normal file
@@ -0,0 +1,293 @@
|
||||
# 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
|
||||
```json
|
||||
{
|
||||
"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.
|
||||
|
||||
```lua
|
||||
function sendMessage(channelId, username, userId, message)
|
||||
-- Returns a message object
|
||||
end
|
||||
```
|
||||
|
||||
#### `lua_irc_handle_command`
|
||||
Processes IRC-style commands like `/help`, `/users`, `/clear`, `/me`.
|
||||
|
||||
```lua
|
||||
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.
|
||||
|
||||
```lua
|
||||
function formatTime(timestamp)
|
||||
-- Returns formatted time string like "02:45 PM"
|
||||
end
|
||||
```
|
||||
|
||||
#### `lua_irc_user_join`
|
||||
Generates join messages when users enter a channel.
|
||||
|
||||
```lua
|
||||
function userJoin(channelId, username, userId)
|
||||
-- Returns a join-type message
|
||||
end
|
||||
```
|
||||
|
||||
#### `lua_irc_user_leave`
|
||||
Generates leave messages when users exit a channel.
|
||||
|
||||
```lua
|
||||
function userLeave(channelId, username, userId)
|
||||
-- Returns a leave-type message
|
||||
end
|
||||
```
|
||||
|
||||
### 5. Component Configuration
|
||||
|
||||
The package defines a declarative component structure using JSON:
|
||||
|
||||
```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 discussion
|
||||
- `random`: Random conversations
|
||||
|
||||
## How It Works
|
||||
|
||||
### Component Loading
|
||||
|
||||
1. **Package Initialization**: `initializePackageSystem()` is called in `App.tsx` on startup
|
||||
2. **Script Registration**: All Lua scripts are registered with the `DeclarativeComponentRenderer`
|
||||
3. **Component Registration**: Component configurations are registered for use in the builder
|
||||
|
||||
### Runtime Execution
|
||||
|
||||
When the IRC component is used:
|
||||
|
||||
1. **User Join**: Calls `lua_irc_user_join` to create a join message
|
||||
2. **Send Message**: Calls `lua_irc_send_message` with user input
|
||||
3. **Commands**: Calls `lua_irc_handle_command` when message starts with `/`
|
||||
4. **Time Formatting**: Calls `lua_irc_format_time` for each message timestamp
|
||||
5. **User Leave**: Calls `lua_irc_user_leave` on 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)
|
||||
```typescript
|
||||
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)
|
||||
```typescript
|
||||
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
|
||||
1. Review the Lua scripts in `package-catalog.ts`
|
||||
2. Test IRC functionality in Level 2 user area
|
||||
3. Consider removing `IRCWebchat.tsx` (old component)
|
||||
4. Add more Lua scripts for advanced features
|
||||
|
||||
### For Users (Level 4/5)
|
||||
1. Navigate to Package Manager
|
||||
2. View installed `irc-webchat` package
|
||||
3. Modify Lua scripts to customize behavior
|
||||
4. Add new commands via Lua Editor
|
||||
5. Export package to share with others
|
||||
|
||||
## Testing the Conversion
|
||||
|
||||
1. **Login** as a regular user
|
||||
2. Navigate to **Level 2** (User Area)
|
||||
3. Go to the **Chat** tab
|
||||
4. Test the following:
|
||||
- Send messages
|
||||
- Use `/help` command
|
||||
- Use `/users` command
|
||||
- Use `/me dances` command
|
||||
- Use `/clear` command
|
||||
- Open another window and see online users update
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Lua Script Not Found
|
||||
- Ensure `initializePackageSystem()` is called before component renders
|
||||
- Check that `irc-webchat` package exists in `PACKAGE_CATALOG`
|
||||
|
||||
### Messages Not Sending
|
||||
- Check browser console for Lua execution errors
|
||||
- Verify parameter types match Lua script expectations
|
||||
- Ensure `useKV` keys are correctly formatted
|
||||
|
||||
### Time Format Issues
|
||||
- Review `lua_irc_format_time` script
|
||||
- Check timestamp is in milliseconds (JavaScript format)
|
||||
- Lua `os.time()` returns seconds, multiply by 1000
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Channel Management**: Lua scripts for creating/deleting channels
|
||||
2. **User Mentions**: Parse `@username` and notify users
|
||||
3. **Message Reactions**: Add emoji reactions via Lua
|
||||
4. **File Sharing**: Integrate with asset management
|
||||
5. **Moderation**: Kick/ban users, message filtering
|
||||
6. **Bots**: AI-powered chat bots using `spark.llm`
|
||||
7. **Persistence**: Save message history to database schemas
|
||||
8. **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.
|
||||
@@ -62,13 +62,20 @@ export class DeclarativeComponentRenderer {
|
||||
}
|
||||
})
|
||||
|
||||
const paramAssignments = script.parameters
|
||||
.map(p => `local ${p.name} = context.data.params["${p.name}"]`)
|
||||
.join('\n')
|
||||
|
||||
const paramList = script.parameters.map(p => p.name).join(', ')
|
||||
|
||||
const wrappedCode = `
|
||||
${paramAssignments}
|
||||
|
||||
${script.code}
|
||||
local fn = ...
|
||||
if fn then
|
||||
local args = {}
|
||||
${script.parameters.map(p => `table.insert(args, context.params.${p.name})`).join('\n ')}
|
||||
return fn(table.unpack(args))
|
||||
|
||||
local result_fn = sendMessage or handleCommand or formatTime or userJoin or userLeave or countThreads
|
||||
if result_fn and type(result_fn) == "function" then
|
||||
return result_fn(${paramList})
|
||||
end
|
||||
`
|
||||
|
||||
@@ -77,7 +84,7 @@ end
|
||||
})
|
||||
|
||||
if (!result.success) {
|
||||
console.error(`Lua script error (${scriptId}):`, result.error)
|
||||
console.error(`Lua script error (${scriptId}):`, result.error, result.logs)
|
||||
throw new Error(result.error || 'Lua script execution failed')
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user