Skip to main content
Version: v1 (Current)

Socket.IO Events

The GxP Toolkit includes a Socket.IO server for simulating real-time events during development. This allows you to test how your plugin responds to events from the platform without connecting to production systems.

Overview

The Socket.IO system consists of:

  1. Socket.IO Server - Node.js server that broadcasts events
  2. Event Templates - JSON files defining event structure
  3. Store Integration - Methods to listen and emit events
  4. CLI Tools - Commands to list and send events

Quick Start

Start the Socket Server

# Start with development server
gxdev dev --with-socket

# Or start standalone
gxdev socket

The server runs on port 3069 by default (configurable via SOCKET_IO_PORT).

Send a Test Event

# List available events
gxdev socket list

# Send an event
gxdev socket send --event AiSessionMessageCreated

Listen in Your Plugin

import { useGxpStore } from '@gx-runtime/stores/gxpPortalConfigStore';

const store = useGxpStore();

// Listen for events on the primary socket
store.listenSocket('primary', 'AiSessionMessageCreated', (data) => {
console.log('Message received:', data);
});

Socket Server

Starting the Server

The Socket.IO server can be started in several ways:

# Via TUI command
/socket

# With Mock API
/socket --with-mock

# Via CLI
gxdev dev --with-socket

# Standalone
node server.js # (if published to project)

Server Configuration

Environment variables:

VariableDefaultDescription
SOCKET_IO_PORT3069Socket server port
USE_HTTPStrueUse secure WebSocket
CERT_PATHSSL certificate path
KEY_PATHSSL private key path

Server Features

  • CORS enabled - Accepts connections from dev server
  • HTTPS support - Uses same certificates as dev server
  • Event emit endpoint - HTTP endpoint for sending events
  • Channel support - Events sent on specific channels

Event Templates

File Location

Event templates are JSON files in the socket-events/ directory:

socket-events/
├── AiSessionMessageCreated.json
├── SocialStreamPostCreated.json
└── SocialStreamPostVariantCompleted.json

Template Structure

{
"event": "EventName",
"channel": "private.Model.identifier",
"data": {
"id": 123,
"field1": "value1",
"field2": "value2",
"created_at": "2024-01-15T10:30:00Z"
}
}
FieldDescription
eventEvent name (must match what your code listens for)
channelBroadcasting channel (follows pattern)
dataEvent payload (any JSON structure)

Channel Format

Channels follow the pattern:

private.{Model}.{identifier}

Examples:

  • private.AiInterface.ai_interface_background_remover
  • private.SocialStream.social_stream_main
  • private.CheckIn.checkin_kiosk_1

Example Templates

AI Session Message

{
"event": "AiSessionMessageCreated",
"channel": "private.AiInterface.ai_interface_background_remover",
"data": {
"id": 1234,
"ai_session_id": 567,
"message": "Background removal process completed successfully",
"type": "completion",
"metadata": {
"processing_time": 2.3,
"input_image": "/dev-assets/images/product-placeholder.jpg",
"output_image": "/dev-assets/images/background-placeholder.jpg",
"confidence": 0.95
},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
}

Social Stream Post

{
"event": "SocialStreamPostCreated",
"channel": "private.SocialStream.social_stream_main",
"data": {
"id": 789,
"social_stream_id": 101,
"content": "Just arrived at the conference! #TechConf2024",
"author": {
"name": "Jane Smith",
"avatar": "/dev-assets/images/avatar-placeholder.jpg",
"handle": "@janesmith"
},
"media": [],
"likes": 0,
"shares": 0,
"created_at": "2024-01-15T14:22:00Z"
}
}

Creating Custom Events

  1. Create a new JSON file in socket-events/:
{
"event": "AttendeeCheckedIn",
"channel": "private.CheckIn.checkin_kiosk_lobby",
"data": {
"id": 456,
"attendee_id": 789,
"attendee_name": "John Doe",
"badge_number": "A-0042",
"check_in_time": "2024-01-15T09:15:00Z",
"kiosk_id": "kiosk_lobby"
}
}
  1. Send the event:
gxdev socket send --event AttendeeCheckedIn

Store Integration

Primary Socket

The GxP store automatically connects to the Socket.IO server:

import { useGxpStore } from '@gx-runtime/stores/gxpPortalConfigStore';

const store = useGxpStore();

Listening for Events

Basic Listener

// Listen on primary socket
store.listenSocket('primary', 'EventName', (data) => {
console.log('Event received:', data);
});

With Dependency

For events tied to specific dependencies:

// Listen for dependency-specific events
store.useSocketListener('badge-printer', 'print-complete', (result) => {
if (result.success) {
console.log('Badge printed!');
}
});

Emitting Events

Send events from your plugin:

// Emit on primary socket
store.emitSocket('primary', 'user-action', {
action: 'button_click',
button_id: 'checkin-submit',
timestamp: new Date().toISOString()
});

State Change Listener

Listen for state change broadcasts:

const socket = store.sockets.primary;
socket.listenForStateChange((newState) => {
console.log('State changed:', newState);
store.updateState('remote_value', newState.value);
});

Dependency-Based Sockets

Configure dependencies in your manifest to set up automatic socket listeners:

{
"dependencies": [
{
"identifier": "badge_printer_1",
"model": "BadgePrinter",
"events": {
"created": "BadgePrintJobCreated",
"updated": "BadgePrintJobUpdated",
"completed": "BadgePrintJobCompleted"
}
}
]
}

The store automatically sets up listeners:

// Listeners are created automatically
store.sockets['badge_printer_1'].created.listen((data) => {
console.log('Print job created:', data);
});

store.sockets['badge_printer_1'].completed.listen((data) => {
console.log('Print job done:', data);
});

CLI Commands

List Events

gxdev socket list

Output:

📡 Available socket events:

🎯 AiSessionMessageCreated
Event: AiSessionMessageCreated
Channel: private.AiInterface.ai_interface_background_remover

🎯 SocialStreamPostCreated
Event: SocialStreamPostCreated
Channel: private.SocialStream.social_stream_main

💡 Usage:
gxdev socket send --event AiSessionMessageCreated
gxdev socket send --event SocialStreamPostCreated --identifier social_stream

Send Event

# Basic send
gxdev socket send --event EventName

# With custom identifier (updates channel)
gxdev socket send --event AttendeeCheckedIn --identifier kiosk_2

The --identifier flag updates the channel:

  • Original: private.CheckIn.checkin_kiosk_lobby
  • With --identifier kiosk_2: private.CheckIn.kiosk_2

TUI Commands

In the interactive TUI:

# Start socket server
/socket

# With mock API
/socket --with-mock

# List events
/socket list

# Send event
/socket send AiSessionMessageCreated

# Send with identifier
/socket send AttendeeCheckedIn kiosk_2

In-Browser Dev Tools

The Dev Tools (Ctrl+Shift+D) include a Socket Simulator:

  1. Open Dev Tools → Socket Simulator tab
  2. Select an event from the dropdown
  3. Modify the JSON payload if needed
  4. Click Send to emit the event

The simulator:

  • Shows all available events
  • Allows payload editing
  • Shows send confirmation
  • Displays any errors

Mock API Server

Start with mock API for HTTP endpoint simulation:

gxdev dev --with-socket --with-mock
# or
/socket --with-mock

The mock API provides:

  • /mock-api/* endpoints
  • Automatic response generation
  • Request logging

Real-World Usage Patterns

Check-In Flow

// Setup: Listen for check-in events
onMounted(() => {
store.listenSocket('primary', 'AttendeeCheckedIn', handleCheckIn);
});

function handleCheckIn(data) {
// Update UI with check-in data
store.updateState('last_checkin', data);

// Trigger badge print
store.emitSocket('primary', 'PrintBadge', {
attendee_id: data.attendee_id,
badge_number: data.badge_number
});
}

Social Wall

const posts = ref([]);

onMounted(() => {
// Listen for new posts
store.listenSocket('primary', 'SocialStreamPostCreated', (post) => {
posts.value.unshift(post);
});

// Listen for post updates (likes, shares)
store.listenSocket('primary', 'SocialStreamPostUpdated', (update) => {
const idx = posts.value.findIndex(p => p.id === update.id);
if (idx >= 0) {
posts.value[idx] = { ...posts.value[idx], ...update };
}
});
});

AI Processing

const processing = ref(false);
const result = ref(null);

async function startAiProcessing(imageUrl) {
processing.value = true;

// Request processing
await store.apiPost('/ai/process', { image: imageUrl });

// Listen for completion
store.listenSocket('primary', 'AiSessionMessageCreated', (data) => {
if (data.type === 'completion') {
processing.value = false;
result.value = data;
}
});
}

Troubleshooting

Socket not connecting

Error: Cannot connect to Socket.IO server

Solutions:

  1. Ensure server is running (gxdev dev --with-socket)
  2. Check port isn't blocked (SOCKET_IO_PORT)
  3. Verify HTTPS certificates are valid

Events not received

  1. Check event name matches exactly (case-sensitive)
  2. Verify channel matches dependency configuration
  3. Look for connection errors in browser console

Event file not found

Error: Event file not found: MyEvent.json

Solutions:

  1. Check file exists in socket-events/
  2. Verify filename matches event name
  3. Check JSON syntax is valid

CORS errors

If you see CORS errors:

  1. Ensure dev server and socket server use same protocol (both HTTP or both HTTPS)
  2. Check socket server port is correct in environment

Server Customization

Publish the server for customization:

gxdev publish server.js

Then modify server.js in your project root to:

  • Add custom endpoints
  • Modify CORS settings
  • Add authentication
  • Custom event handling
// Example: Add custom endpoint
app.post('/custom-emit', (req, res) => {
const { event, data } = req.body;
io.emit(event, data);
res.json({ success: true });
});