Files
metabuilder/old/IRC_CONVERSION_GUIDE.md
2026-01-08 22:59:15 +00:00

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 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)

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

  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.