# GameForge Integration - Implementation Examples This document provides practical examples for integrating AeThex Connect with GameForge. --- ## Example 1: Complete Project Lifecycle ### Step 1: Create Project in GameForge ```javascript // GameForge: src/services/projectService.js const crypto = require('crypto'); function generateSignature(payload, secret) { const timestamp = Date.now().toString(); const data = JSON.stringify(payload); return { signature: crypto .createHmac('sha256', secret) .update(`${timestamp}.${data}`) .digest('hex'), timestamp }; } async function createProject(projectData, userId) { // 1. Create project in GameForge database const project = await db.projects.create({ name: projectData.name, description: projectData.description, owner_id: userId, created_at: new Date() }); // 2. Get owner's AeThex identifier const owner = await db.users.findById(userId); const ownerIdentifier = `${owner.username}@dev.aethex.dev`; // 3. Provision AeThex Connect channels const connectPayload = { projectId: project.id, name: project.name, ownerId: userId, ownerIdentifier: ownerIdentifier, teamMembers: [], settings: { autoProvisionChannels: true, defaultChannels: ['general', 'dev', 'art', 'design'], customChannels: [] } }; const { signature, timestamp } = generateSignature( connectPayload, process.env.AETHEX_CONNECT_API_SECRET ); try { const response = await fetch('https://connect.aethex.app/api/gameforge/projects', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(connectPayload) }); const connectData = await response.json(); if (connectData.success) { // Store integration data await db.projects.update(project.id, { connect_domain: connectData.integration.domain, connect_channels: connectData.integration.channels }); console.log(`✅ Provisioned ${connectData.integration.channels.length} channels`); } else { console.error('Failed to provision AeThex Connect:', connectData.error); } } catch (error) { console.error('AeThex Connect provisioning error:', error); // Non-critical - project still created } return project; } ``` ### Step 2: Add Team Members ```javascript // GameForge: src/services/teamService.js async function addTeamMember(projectId, userId, role) { // 1. Add to GameForge team const teamMember = await db.projectTeams.create({ project_id: projectId, user_id: userId, role: role, joined_at: new Date() }); // 2. Get user's AeThex identifier const user = await db.users.findById(userId); const identifier = `${user.username}@dev.aethex.dev`; // 3. Update AeThex Connect const payload = { action: 'add', members: [{ userId: userId, identifier: identifier, role: role }] }; const { signature, timestamp } = generateSignature( payload, process.env.AETHEX_CONNECT_API_SECRET ); try { const response = await fetch( `https://connect.aethex.app/api/gameforge/projects/${projectId}/team`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(payload) } ); const data = await response.json(); console.log(`✅ Added to ${data.updated[0].addedToChannels.length} channels`); } catch (error) { console.error('Failed to update AeThex Connect team:', error); } return teamMember; } async function removeTeamMember(projectId, userId) { // 1. Remove from GameForge team await db.projectTeams.delete({ project_id: projectId, user_id: userId }); // 2. Remove from AeThex Connect const payload = { action: 'remove', members: [{ userId: userId }] }; const { signature, timestamp } = generateSignature( payload, process.env.AETHEX_CONNECT_API_SECRET ); await fetch( `https://connect.aethex.app/api/gameforge/projects/${projectId}/team`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(payload) } ); } async function updateMemberRole(projectId, userId, newRole) { // 1. Update in GameForge await db.projectTeams.update({ project_id: projectId, user_id: userId }, { role: newRole }); // 2. Update in AeThex Connect const user = await db.users.findById(userId); const payload = { action: 'update_role', members: [{ userId: userId, identifier: `${user.username}@dev.aethex.dev`, role: newRole }] }; const { signature, timestamp } = generateSignature( payload, process.env.AETHEX_CONNECT_API_SECRET ); await fetch( `https://connect.aethex.app/api/gameforge/projects/${projectId}/team`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(payload) } ); } ``` ### Step 3: Send Notifications ```javascript // GameForge: src/services/buildService.js async function onBuildComplete(buildId, projectId, status) { const build = await db.builds.findById(buildId); const notification = { channelName: 'dev', type: 'build', title: `Build #${build.number} ${status === 'success' ? 'Completed' : 'Failed'}`, message: status === 'success' ? `Build completed successfully in ${formatDuration(build.duration)}` : `Build failed: ${build.error}`, metadata: { buildNumber: build.number, status: status, duration: build.duration, commitHash: build.commit_hash.substring(0, 7), branch: build.branch }, actions: [ { label: 'View Build', url: `https://gameforge.aethex.dev/projects/${projectId}/builds/${buildId}` }, { label: 'View Logs', url: `https://gameforge.aethex.dev/projects/${projectId}/builds/${buildId}/logs` } ] }; const { signature, timestamp } = generateSignature( notification, process.env.AETHEX_CONNECT_API_SECRET ); await fetch( `https://connect.aethex.app/api/gameforge/projects/${projectId}/notify`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(notification) } ); } // GameForge: src/services/gitService.js async function onCommitPushed(commitData, projectId) { const notification = { channelName: 'dev', type: 'commit', title: 'New Commit Pushed', message: commitData.message, metadata: { author: commitData.author, hash: commitData.hash.substring(0, 7), branch: commitData.branch, filesChanged: commitData.stats.filesChanged }, actions: [ { label: 'View Commit', url: `https://gameforge.aethex.dev/projects/${projectId}/commits/${commitData.hash}` } ] }; const { signature, timestamp } = generateSignature( notification, process.env.AETHEX_CONNECT_API_SECRET ); await fetch( `https://connect.aethex.app/api/gameforge/projects/${projectId}/notify`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(notification) } ); } // GameForge: src/services/deploymentService.js async function onDeploymentComplete(deploymentId, projectId, status) { const deployment = await db.deployments.findById(deploymentId); const notification = { channelName: 'general', type: 'deployment', title: `Deployment ${status === 'success' ? 'Successful' : 'Failed'}`, message: status === 'success' ? `Successfully deployed to ${deployment.environment}` : `Deployment to ${deployment.environment} failed`, metadata: { environment: deployment.environment, version: deployment.version, status: status }, actions: [ { label: 'View Deployment', url: `https://gameforge.aethex.dev/projects/${projectId}/deployments/${deploymentId}` } ] }; const { signature, timestamp } = generateSignature( notification, process.env.AETHEX_CONNECT_API_SECRET ); await fetch( `https://connect.aethex.app/api/gameforge/projects/${projectId}/notify`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(notification) } ); } ``` ### Step 4: Archive Project ```javascript // GameForge: src/services/projectService.js async function archiveProject(projectId) { // 1. Archive in GameForge await db.projects.update(projectId, { is_archived: true, archived_at: new Date() }); // 2. Archive AeThex Connect channels const { signature, timestamp } = generateSignature( {}, process.env.AETHEX_CONNECT_API_SECRET ); await fetch( `https://connect.aethex.app/api/gameforge/projects/${projectId}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp } } ); } ``` --- ## Example 2: Embedded Chat Component ### React Integration ```javascript // GameForge: src/pages/ProjectPage.jsx import React from 'react'; import { useParams } from 'react-router-dom'; import GameForgeChat from '@aethex/connect/components/GameForgeChat'; export default function ProjectPage() { const { projectId } = useParams(); return (

My Game Project

); } ``` ### Iframe Integration ```html {{ project.name }} - GameForge

Team Chat

``` --- ## Example 3: Testing Integration ### Integration Test Suite ```javascript // GameForge: tests/aethex-connect.test.js const { generateSignature } = require('../utils/signature'); describe('AeThex Connect Integration', () => { let testProjectId; beforeAll(async () => { // Setup test environment }); test('should provision project with channels', async () => { const payload = { projectId: 'test-project-1', name: 'Test Game', ownerId: 'test-user-1', ownerIdentifier: 'testuser@dev.aethex.dev', teamMembers: [], settings: { autoProvisionChannels: true, defaultChannels: ['general', 'dev'] } }; const { signature, timestamp } = generateSignature( payload, process.env.AETHEX_CONNECT_API_SECRET ); const response = await fetch('https://connect.aethex.app/api/gameforge/projects', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(payload) }); const data = await response.json(); expect(data.success).toBe(true); expect(data.integration.channels).toHaveLength(2); expect(data.integration.domain).toBe('test-game@forge.aethex.dev'); testProjectId = 'test-project-1'; }); test('should add team member to appropriate channels', async () => { const payload = { action: 'add', members: [{ userId: 'test-user-2', identifier: 'developer@dev.aethex.dev', role: 'developer' }] }; const { signature, timestamp } = generateSignature( payload, process.env.AETHEX_CONNECT_API_SECRET ); const response = await fetch( `https://connect.aethex.app/api/gameforge/projects/${testProjectId}/team`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(payload) } ); const data = await response.json(); expect(data.success).toBe(true); expect(data.updated[0].addedToChannels.length).toBeGreaterThan(0); }); test('should send system notification', async () => { const notification = { channelName: 'dev', type: 'build', title: 'Build #1 Completed', message: 'Test build completed successfully', metadata: { buildNumber: 1, status: 'success' } }; const { signature, timestamp } = generateSignature( notification, process.env.AETHEX_CONNECT_API_SECRET ); const response = await fetch( `https://connect.aethex.app/api/gameforge/projects/${testProjectId}/notify`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': process.env.AETHEX_CONNECT_API_KEY, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: JSON.stringify(notification) } ); const data = await response.json(); expect(data.success).toBe(true); expect(data.messageId).toBeDefined(); expect(data.channelId).toBeDefined(); }); afterAll(async () => { // Cleanup test data }); }); ``` --- ## Example 4: Error Handling ```javascript // GameForge: src/utils/aethexConnect.js class AeThexConnectClient { constructor(apiKey, apiSecret, baseUrl = 'https://connect.aethex.app') { this.apiKey = apiKey; this.apiSecret = apiSecret; this.baseUrl = baseUrl; } generateSignature(payload) { const crypto = require('crypto'); const timestamp = Date.now().toString(); const data = JSON.stringify(payload); const signature = crypto .createHmac('sha256', this.apiSecret) .update(`${timestamp}.${data}`) .digest('hex'); return { signature, timestamp }; } async request(endpoint, method, payload) { const { signature, timestamp } = this.generateSignature(payload); try { const response = await fetch(`${this.baseUrl}${endpoint}`, { method, headers: { 'Content-Type': 'application/json', 'X-GameForge-API-Key': this.apiKey, 'X-GameForge-Signature': signature, 'X-GameForge-Timestamp': timestamp }, body: method !== 'GET' ? JSON.stringify(payload) : undefined }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Request failed'); } return data; } catch (error) { console.error(`AeThex Connect ${method} ${endpoint} failed:`, error); throw error; } } async provisionProject(projectData) { return this.request('/api/gameforge/projects', 'POST', projectData); } async updateTeam(projectId, action, members) { return this.request( `/api/gameforge/projects/${projectId}/team`, 'PATCH', { action, members } ); } async sendNotification(projectId, notification) { return this.request( `/api/gameforge/projects/${projectId}/notify`, 'POST', notification ); } async archiveProject(projectId) { return this.request( `/api/gameforge/projects/${projectId}`, 'DELETE', {} ); } } // Usage const connectClient = new AeThexConnectClient( process.env.AETHEX_CONNECT_API_KEY, process.env.AETHEX_CONNECT_API_SECRET ); // Provision with error handling try { const result = await connectClient.provisionProject({ projectId: project.id, name: project.name, ownerId: userId, ownerIdentifier: `${user.username}@dev.aethex.dev`, teamMembers: [], settings: { autoProvisionChannels: true, defaultChannels: ['general', 'dev'] } }); console.log('✅ Provisioned:', result.integration.domain); } catch (error) { console.error('❌ Provisioning failed:', error.message); // Handle gracefully - project still usable without chat } ``` --- ## Utility Functions ```javascript // GameForge: src/utils/helpers.js function formatDuration(seconds) { const minutes = Math.floor(seconds / 60); const secs = seconds % 60; return minutes > 0 ? `${minutes}m ${secs}s` : `${secs}s`; } function getChannelForNotificationType(type) { const channelMap = { 'build': 'dev', 'commit': 'dev', 'deployment': 'general', 'issue': 'dev', 'playtesting': 'playtesting', 'announcement': 'announcements' }; return channelMap[type] || 'general'; } module.exports = { formatDuration, getChannelForNotificationType }; ``` --- These examples demonstrate complete integration patterns for GameForge projects with AeThex Connect.