@gameap/debug 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +222 -0
- package/empty-plugin/plugin.js +7 -0
- package/index.html +111 -0
- package/package.json +38 -0
- package/postcss.config.cjs +12 -0
- package/src/main.ts +328 -0
- package/src/mocks/README.md +68 -0
- package/src/mocks/browser.ts +22 -0
- package/src/mocks/files.ts +347 -0
- package/src/mocks/handlers.ts +940 -0
- package/src/mocks/servers.ts +397 -0
- package/src/mocks/translations-en.json +704 -0
- package/src/mocks/translations-ru.json +692 -0
- package/src/mocks/users.ts +34 -0
- package/src/shims-vue.d.ts +5 -0
- package/tailwind.config.js +25 -0
- package/tsconfig.json +31 -0
- package/tsconfig.node.json +11 -0
- package/vite.config.ts +93 -0
|
@@ -0,0 +1,940 @@
|
|
|
1
|
+
import { http, HttpResponse, delay } from 'msw'
|
|
2
|
+
import { mockFiles, mockDirectories, mockSubdirectoryFiles, mockSubdirectories, getFileByPath, type MockFile, type MockDirectory } from './files'
|
|
3
|
+
import { serverMocks, serverAbilities, mockServersList, mockServersDetails, type ServerListItem } from './servers'
|
|
4
|
+
import { userMocks } from './users'
|
|
5
|
+
import type { ServerData, UserData } from '@gameap/plugin-sdk'
|
|
6
|
+
|
|
7
|
+
// Import actual translation files (copied from backend)
|
|
8
|
+
import translationsEn from './translations-en.json'
|
|
9
|
+
import translationsRu from './translations-ru.json'
|
|
10
|
+
|
|
11
|
+
const translations: Record<string, object> = {
|
|
12
|
+
en: translationsEn,
|
|
13
|
+
ru: translationsRu,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Initialize debug state from localStorage (for persistence across reloads)
|
|
17
|
+
function getInitialUserType(): 'admin' | 'user' | 'guest' {
|
|
18
|
+
if (typeof localStorage !== 'undefined') {
|
|
19
|
+
const stored = localStorage.getItem('gameap_debug_user_type')
|
|
20
|
+
if (stored === 'admin' || stored === 'user' || stored === 'guest') {
|
|
21
|
+
return stored
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return 'admin'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Current debug state (will be controlled by debug panel)
|
|
28
|
+
export const debugState = {
|
|
29
|
+
userType: getInitialUserType(),
|
|
30
|
+
serverId: 1,
|
|
31
|
+
locale: 'en' as 'en' | 'ru',
|
|
32
|
+
networkDelay: 100, // ms
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Helper to get current user
|
|
36
|
+
function getCurrentUser(): UserData {
|
|
37
|
+
return userMocks[debugState.userType]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Get server by ID from the list (for API responses)
|
|
41
|
+
function getServerListItemById(id: number): ServerListItem | undefined {
|
|
42
|
+
return mockServersList.find(s => s.id === id)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Get server data for plugin context
|
|
46
|
+
function getServerById(id: number): ServerData | null {
|
|
47
|
+
if (id === 1) return serverMocks.minecraft
|
|
48
|
+
if (id === 2) return serverMocks.cs
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Helper to get files and directories for a path
|
|
53
|
+
function getFilesForPath(path: string): { files: MockFile[], directories: MockDirectory[] } {
|
|
54
|
+
// Normalize path: empty string or '/' means root
|
|
55
|
+
const normalizedPath = path === '/' ? '' : path.replace(/^\//, '').replace(/\/$/, '')
|
|
56
|
+
|
|
57
|
+
if (normalizedPath === '') {
|
|
58
|
+
// Root directory
|
|
59
|
+
return {
|
|
60
|
+
files: mockFiles.map(f => ({
|
|
61
|
+
path: f.path,
|
|
62
|
+
timestamp: f.timestamp,
|
|
63
|
+
type: f.type,
|
|
64
|
+
visibility: f.visibility,
|
|
65
|
+
size: f.size,
|
|
66
|
+
dirname: f.dirname,
|
|
67
|
+
basename: f.basename,
|
|
68
|
+
extension: f.extension,
|
|
69
|
+
filename: f.filename,
|
|
70
|
+
})),
|
|
71
|
+
directories: mockDirectories,
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Subdirectory
|
|
76
|
+
const files = mockSubdirectoryFiles[normalizedPath] || []
|
|
77
|
+
const directories = mockSubdirectories[normalizedPath] || []
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
files: files.map(f => ({
|
|
81
|
+
path: f.path,
|
|
82
|
+
timestamp: f.timestamp,
|
|
83
|
+
type: f.type,
|
|
84
|
+
visibility: f.visibility,
|
|
85
|
+
size: f.size,
|
|
86
|
+
dirname: f.dirname,
|
|
87
|
+
basename: f.basename,
|
|
88
|
+
extension: f.extension,
|
|
89
|
+
filename: f.filename,
|
|
90
|
+
})),
|
|
91
|
+
directories,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Mock games
|
|
96
|
+
const mockGames = [
|
|
97
|
+
{ code: 'minecraft', name: 'Minecraft', engine: 'source', engine_version: '1.0', steam_app_id: null },
|
|
98
|
+
{ code: 'cs2', name: 'Counter-Strike 2', engine: 'source2', engine_version: '1.0', steam_app_id: 730 },
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
// Mock game mods
|
|
102
|
+
const mockGameMods = [
|
|
103
|
+
{ id: 1, game_code: 'minecraft', name: 'Vanilla', default_start_cmd: 'java -jar server.jar' },
|
|
104
|
+
{ id: 2, game_code: 'cs2', name: 'Competitive', default_start_cmd: './cs2 -dedicated' },
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
// Mock nodes
|
|
108
|
+
const mockNodes = [
|
|
109
|
+
{
|
|
110
|
+
id: 1,
|
|
111
|
+
name: 'Local Node',
|
|
112
|
+
enabled: true,
|
|
113
|
+
ip: ['192.168.1.100'],
|
|
114
|
+
os: 'linux',
|
|
115
|
+
location: 'Local',
|
|
116
|
+
gdaemon_host: '192.168.1.100',
|
|
117
|
+
gdaemon_port: 31717,
|
|
118
|
+
gdaemon_api_key: '***',
|
|
119
|
+
gdaemon_version: '3.1.0',
|
|
120
|
+
work_path: '/home/gameap',
|
|
121
|
+
steamcmd_path: '/home/gameap/steamcmd',
|
|
122
|
+
servers_count: 2,
|
|
123
|
+
},
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
// Mock users list
|
|
127
|
+
const mockUsersList = [
|
|
128
|
+
{ id: 1, login: 'admin', name: 'Administrator', roles: ['admin'], created_at: '2024-01-01' },
|
|
129
|
+
{ id: 2, login: 'player1', name: 'Regular Player', roles: ['user'], created_at: '2024-01-15' },
|
|
130
|
+
]
|
|
131
|
+
|
|
132
|
+
// Mock console output
|
|
133
|
+
let consoleOutput = [
|
|
134
|
+
'[00:00:01] Server starting...',
|
|
135
|
+
'[00:00:02] Loading world...',
|
|
136
|
+
'[00:00:05] Done! Server ready.',
|
|
137
|
+
'[00:00:10] Player1 joined the game',
|
|
138
|
+
]
|
|
139
|
+
|
|
140
|
+
// Plugin JS/CSS content (empty by default, will be injected when plugin is loaded)
|
|
141
|
+
let pluginJsContent = ''
|
|
142
|
+
let pluginCssContent = ''
|
|
143
|
+
|
|
144
|
+
export function setPluginContent(js: string, css: string) {
|
|
145
|
+
pluginJsContent = js
|
|
146
|
+
pluginCssContent = css
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const handlers = [
|
|
150
|
+
// ==================== Auth & Profile ====================
|
|
151
|
+
http.get('/api/profile', async () => {
|
|
152
|
+
await delay(debugState.networkDelay)
|
|
153
|
+
const user = getCurrentUser()
|
|
154
|
+
if (!user.isAuthenticated) {
|
|
155
|
+
return new HttpResponse(null, { status: 401 })
|
|
156
|
+
}
|
|
157
|
+
return HttpResponse.json({
|
|
158
|
+
id: user.id,
|
|
159
|
+
login: user.login,
|
|
160
|
+
name: user.name,
|
|
161
|
+
roles: user.roles,
|
|
162
|
+
})
|
|
163
|
+
}),
|
|
164
|
+
|
|
165
|
+
http.put('/api/profile', async () => {
|
|
166
|
+
await delay(debugState.networkDelay)
|
|
167
|
+
return HttpResponse.json({ success: true })
|
|
168
|
+
}),
|
|
169
|
+
|
|
170
|
+
http.get('/api/user/servers_abilities', async () => {
|
|
171
|
+
await delay(debugState.networkDelay)
|
|
172
|
+
// Return abilities for all servers the user can access
|
|
173
|
+
const abilities: Record<number, Record<string, boolean>> = {}
|
|
174
|
+
mockServersList.forEach(s => {
|
|
175
|
+
abilities[s.id] = serverAbilities[s.id] || {
|
|
176
|
+
'game-server-common': true,
|
|
177
|
+
'game-server-start': true,
|
|
178
|
+
'game-server-stop': true,
|
|
179
|
+
'game-server-restart': true,
|
|
180
|
+
}
|
|
181
|
+
})
|
|
182
|
+
return HttpResponse.json(abilities)
|
|
183
|
+
}),
|
|
184
|
+
|
|
185
|
+
http.post('/api/password/reset', async () => {
|
|
186
|
+
await delay(debugState.networkDelay)
|
|
187
|
+
return HttpResponse.json({ success: true })
|
|
188
|
+
}),
|
|
189
|
+
|
|
190
|
+
// ==================== Servers ====================
|
|
191
|
+
http.get('/api/servers', async () => {
|
|
192
|
+
await delay(debugState.networkDelay)
|
|
193
|
+
return HttpResponse.json(mockServersList)
|
|
194
|
+
}),
|
|
195
|
+
|
|
196
|
+
http.get('/api/servers/summary', async () => {
|
|
197
|
+
await delay(debugState.networkDelay)
|
|
198
|
+
return HttpResponse.json({
|
|
199
|
+
total: mockServersList.length,
|
|
200
|
+
active: mockServersList.filter(s => s.process_active).length,
|
|
201
|
+
inactive: mockServersList.filter(s => !s.process_active).length,
|
|
202
|
+
})
|
|
203
|
+
}),
|
|
204
|
+
|
|
205
|
+
http.get('/api/servers/search', async ({ request }) => {
|
|
206
|
+
await delay(debugState.networkDelay)
|
|
207
|
+
const url = new URL(request.url)
|
|
208
|
+
const q = url.searchParams.get('q') || ''
|
|
209
|
+
const filtered = mockServersList.filter(s =>
|
|
210
|
+
s.name.toLowerCase().includes(q.toLowerCase())
|
|
211
|
+
)
|
|
212
|
+
return HttpResponse.json(filtered)
|
|
213
|
+
}),
|
|
214
|
+
|
|
215
|
+
http.get('/api/servers/:id', async ({ params }) => {
|
|
216
|
+
await delay(debugState.networkDelay)
|
|
217
|
+
const serverId = Number(params.id)
|
|
218
|
+
const serverDetails = mockServersDetails[serverId]
|
|
219
|
+
if (!serverDetails) {
|
|
220
|
+
return new HttpResponse(null, { status: 404 })
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Check if user is admin - return full details
|
|
224
|
+
const user = getCurrentUser()
|
|
225
|
+
if (user.roles.includes('admin')) {
|
|
226
|
+
return HttpResponse.json(serverDetails)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// For regular users, return limited info
|
|
230
|
+
const {
|
|
231
|
+
id, enabled, installed, blocked, name, game_id, game_mod_id,
|
|
232
|
+
expires, server_ip, server_port, query_port, rcon_port,
|
|
233
|
+
game, last_process_check, online, process_active
|
|
234
|
+
} = serverDetails
|
|
235
|
+
|
|
236
|
+
return HttpResponse.json({
|
|
237
|
+
id, enabled, installed, blocked, name, game_id, game_mod_id,
|
|
238
|
+
expires, server_ip, server_port, query_port, rcon_port,
|
|
239
|
+
game: {
|
|
240
|
+
code: game.code,
|
|
241
|
+
name: game.name,
|
|
242
|
+
engine: game.engine,
|
|
243
|
+
engine_version: game.engine_version,
|
|
244
|
+
},
|
|
245
|
+
last_process_check, online, process_active,
|
|
246
|
+
})
|
|
247
|
+
}),
|
|
248
|
+
|
|
249
|
+
http.get('/api/servers/:id/abilities', async ({ params }) => {
|
|
250
|
+
await delay(debugState.networkDelay)
|
|
251
|
+
const serverId = Number(params.id)
|
|
252
|
+
const abilities = serverAbilities[serverId]
|
|
253
|
+
if (!abilities) {
|
|
254
|
+
// Return default abilities for unknown servers
|
|
255
|
+
return HttpResponse.json({
|
|
256
|
+
'game-server-common': true,
|
|
257
|
+
'game-server-start': true,
|
|
258
|
+
'game-server-stop': true,
|
|
259
|
+
'game-server-restart': true,
|
|
260
|
+
})
|
|
261
|
+
}
|
|
262
|
+
return HttpResponse.json(abilities)
|
|
263
|
+
}),
|
|
264
|
+
|
|
265
|
+
http.get('/api/servers/:id/settings', async () => {
|
|
266
|
+
await delay(debugState.networkDelay)
|
|
267
|
+
return HttpResponse.json({
|
|
268
|
+
vars: {
|
|
269
|
+
maxplayers: '20',
|
|
270
|
+
hostname: 'Test Server',
|
|
271
|
+
},
|
|
272
|
+
})
|
|
273
|
+
}),
|
|
274
|
+
|
|
275
|
+
http.put('/api/servers/:id', async () => {
|
|
276
|
+
await delay(debugState.networkDelay)
|
|
277
|
+
return HttpResponse.json({ success: true })
|
|
278
|
+
}),
|
|
279
|
+
|
|
280
|
+
http.put('/api/servers/:id/settings', async () => {
|
|
281
|
+
await delay(debugState.networkDelay)
|
|
282
|
+
return HttpResponse.json({ success: true })
|
|
283
|
+
}),
|
|
284
|
+
|
|
285
|
+
http.post('/api/servers', async () => {
|
|
286
|
+
await delay(debugState.networkDelay)
|
|
287
|
+
return HttpResponse.json({ success: true, id: 3 })
|
|
288
|
+
}),
|
|
289
|
+
|
|
290
|
+
http.post('/api/servers/reinstall', async () => {
|
|
291
|
+
await delay(debugState.networkDelay)
|
|
292
|
+
return HttpResponse.json({ success: true, task_id: 100 })
|
|
293
|
+
}),
|
|
294
|
+
|
|
295
|
+
// Server control
|
|
296
|
+
http.post('/api/servers/:id/:action', async ({ params }) => {
|
|
297
|
+
await delay(debugState.networkDelay)
|
|
298
|
+
const action = params.action as string
|
|
299
|
+
if (['start', 'stop', 'restart', 'update', 'reinstall'].includes(action)) {
|
|
300
|
+
return HttpResponse.json({
|
|
301
|
+
success: true,
|
|
302
|
+
gdaemon_task_id: Math.floor(Math.random() * 1000)
|
|
303
|
+
})
|
|
304
|
+
}
|
|
305
|
+
return new HttpResponse(null, { status: 400 })
|
|
306
|
+
}),
|
|
307
|
+
|
|
308
|
+
http.get('/api/servers/:id/status', async ({ params }) => {
|
|
309
|
+
await delay(debugState.networkDelay)
|
|
310
|
+
const server = getServerById(Number(params.id))
|
|
311
|
+
return HttpResponse.json({
|
|
312
|
+
status: server?.process_active ? 'active' : 'inactive',
|
|
313
|
+
process_active: server?.process_active ?? false,
|
|
314
|
+
})
|
|
315
|
+
}),
|
|
316
|
+
|
|
317
|
+
http.get('/api/servers/:id/query', async ({ params }) => {
|
|
318
|
+
await delay(debugState.networkDelay)
|
|
319
|
+
const server = getServerById(Number(params.id))
|
|
320
|
+
if (!server?.process_active) {
|
|
321
|
+
return HttpResponse.json({ online: false })
|
|
322
|
+
}
|
|
323
|
+
return HttpResponse.json({
|
|
324
|
+
online: true,
|
|
325
|
+
players: 5,
|
|
326
|
+
max_players: 20,
|
|
327
|
+
map: 'de_dust2',
|
|
328
|
+
hostname: server.name,
|
|
329
|
+
})
|
|
330
|
+
}),
|
|
331
|
+
|
|
332
|
+
// Server console
|
|
333
|
+
http.get('/api/servers/:id/console', async () => {
|
|
334
|
+
await delay(debugState.networkDelay)
|
|
335
|
+
return HttpResponse.json({
|
|
336
|
+
console: consoleOutput.join('\n'),
|
|
337
|
+
})
|
|
338
|
+
}),
|
|
339
|
+
|
|
340
|
+
http.post('/api/servers/:id/console', async ({ request }) => {
|
|
341
|
+
await delay(debugState.networkDelay)
|
|
342
|
+
const body = await request.json() as { command: string }
|
|
343
|
+
consoleOutput.push(`> ${body.command}`)
|
|
344
|
+
consoleOutput.push(`[Server] Command executed: ${body.command}`)
|
|
345
|
+
return HttpResponse.json({ success: true })
|
|
346
|
+
}),
|
|
347
|
+
|
|
348
|
+
// Server tasks
|
|
349
|
+
http.get('/api/servers/:id/tasks', async () => {
|
|
350
|
+
await delay(debugState.networkDelay)
|
|
351
|
+
return HttpResponse.json([
|
|
352
|
+
{ id: 1, command: 'restart', repeat: 'daily', repeat_period: 86400, execute_date: '2024-12-18 00:00:00' },
|
|
353
|
+
])
|
|
354
|
+
}),
|
|
355
|
+
|
|
356
|
+
http.post('/api/servers/:id/tasks', async () => {
|
|
357
|
+
await delay(debugState.networkDelay)
|
|
358
|
+
return HttpResponse.json({ success: true, id: 2 })
|
|
359
|
+
}),
|
|
360
|
+
|
|
361
|
+
http.put('/api/servers/:id/tasks/:taskId', async () => {
|
|
362
|
+
await delay(debugState.networkDelay)
|
|
363
|
+
return HttpResponse.json({ success: true })
|
|
364
|
+
}),
|
|
365
|
+
|
|
366
|
+
http.delete('/api/servers/:id/tasks/:taskId', async () => {
|
|
367
|
+
await delay(debugState.networkDelay)
|
|
368
|
+
return HttpResponse.json({ success: true })
|
|
369
|
+
}),
|
|
370
|
+
|
|
371
|
+
// RCON
|
|
372
|
+
http.get('/api/servers/:id/rcon/features', async () => {
|
|
373
|
+
await delay(debugState.networkDelay)
|
|
374
|
+
return HttpResponse.json({
|
|
375
|
+
players: true,
|
|
376
|
+
fast_rcon: true,
|
|
377
|
+
console: true,
|
|
378
|
+
})
|
|
379
|
+
}),
|
|
380
|
+
|
|
381
|
+
http.get('/api/servers/:id/rcon/fast_rcon', async () => {
|
|
382
|
+
await delay(debugState.networkDelay)
|
|
383
|
+
return HttpResponse.json([
|
|
384
|
+
{ command: 'say Hello', label: 'Say Hello' },
|
|
385
|
+
{ command: 'changelevel de_dust2', label: 'Change to Dust2' },
|
|
386
|
+
])
|
|
387
|
+
}),
|
|
388
|
+
|
|
389
|
+
http.post('/api/servers/:id/rcon', async ({ request }) => {
|
|
390
|
+
await delay(debugState.networkDelay)
|
|
391
|
+
const body = await request.json() as { command: string }
|
|
392
|
+
return HttpResponse.json({
|
|
393
|
+
output: `Executed: ${body.command}\nResult: OK`,
|
|
394
|
+
})
|
|
395
|
+
}),
|
|
396
|
+
|
|
397
|
+
http.get('/api/servers/:id/rcon/players', async () => {
|
|
398
|
+
await delay(debugState.networkDelay)
|
|
399
|
+
return HttpResponse.json([
|
|
400
|
+
{ id: 1, name: 'Player1', score: 10, ping: 45 },
|
|
401
|
+
{ id: 2, name: 'Player2', score: 8, ping: 60 },
|
|
402
|
+
])
|
|
403
|
+
}),
|
|
404
|
+
|
|
405
|
+
http.post('/api/servers/:id/rcon/players/kick', async () => {
|
|
406
|
+
await delay(debugState.networkDelay)
|
|
407
|
+
return HttpResponse.json({ success: true })
|
|
408
|
+
}),
|
|
409
|
+
|
|
410
|
+
http.post('/api/servers/:id/rcon/players/ban', async () => {
|
|
411
|
+
await delay(debugState.networkDelay)
|
|
412
|
+
return HttpResponse.json({ success: true })
|
|
413
|
+
}),
|
|
414
|
+
|
|
415
|
+
http.post('/api/servers/:id/rcon/players/message', async () => {
|
|
416
|
+
await delay(debugState.networkDelay)
|
|
417
|
+
return HttpResponse.json({ success: true })
|
|
418
|
+
}),
|
|
419
|
+
|
|
420
|
+
// ==================== Games ====================
|
|
421
|
+
http.get('/api/games', async () => {
|
|
422
|
+
await delay(debugState.networkDelay)
|
|
423
|
+
return HttpResponse.json(mockGames)
|
|
424
|
+
}),
|
|
425
|
+
|
|
426
|
+
http.get('/api/games/:code', async ({ params }) => {
|
|
427
|
+
await delay(debugState.networkDelay)
|
|
428
|
+
const game = mockGames.find(g => g.code === params.code)
|
|
429
|
+
if (!game) {
|
|
430
|
+
return new HttpResponse(null, { status: 404 })
|
|
431
|
+
}
|
|
432
|
+
return HttpResponse.json(game)
|
|
433
|
+
}),
|
|
434
|
+
|
|
435
|
+
http.get('/api/games/:code/mods', async ({ params }) => {
|
|
436
|
+
await delay(debugState.networkDelay)
|
|
437
|
+
const mods = mockGameMods.filter(m => m.game_code === params.code)
|
|
438
|
+
return HttpResponse.json(mods)
|
|
439
|
+
}),
|
|
440
|
+
|
|
441
|
+
http.put('/api/games/:code', async () => {
|
|
442
|
+
await delay(debugState.networkDelay)
|
|
443
|
+
return HttpResponse.json({ success: true })
|
|
444
|
+
}),
|
|
445
|
+
|
|
446
|
+
http.post('/api/games', async () => {
|
|
447
|
+
await delay(debugState.networkDelay)
|
|
448
|
+
return HttpResponse.json({ success: true })
|
|
449
|
+
}),
|
|
450
|
+
|
|
451
|
+
http.delete('/api/games/:code', async () => {
|
|
452
|
+
await delay(debugState.networkDelay)
|
|
453
|
+
return HttpResponse.json({ success: true })
|
|
454
|
+
}),
|
|
455
|
+
|
|
456
|
+
// ==================== Game Mods ====================
|
|
457
|
+
http.get('/api/game_mods', async () => {
|
|
458
|
+
await delay(debugState.networkDelay)
|
|
459
|
+
return HttpResponse.json(mockGameMods)
|
|
460
|
+
}),
|
|
461
|
+
|
|
462
|
+
http.get('/api/game_mods/:id', async ({ params }) => {
|
|
463
|
+
await delay(debugState.networkDelay)
|
|
464
|
+
const mod = mockGameMods.find(m => m.id === Number(params.id))
|
|
465
|
+
if (!mod) {
|
|
466
|
+
return new HttpResponse(null, { status: 404 })
|
|
467
|
+
}
|
|
468
|
+
return HttpResponse.json(mod)
|
|
469
|
+
}),
|
|
470
|
+
|
|
471
|
+
http.get('/api/game_mods/get_list_for_game/:code', async ({ params }) => {
|
|
472
|
+
await delay(debugState.networkDelay)
|
|
473
|
+
const mods = mockGameMods.filter(m => m.game_code === params.code)
|
|
474
|
+
return HttpResponse.json(mods)
|
|
475
|
+
}),
|
|
476
|
+
|
|
477
|
+
http.post('/api/game_mods', async () => {
|
|
478
|
+
await delay(debugState.networkDelay)
|
|
479
|
+
return HttpResponse.json({ success: true, id: 3 })
|
|
480
|
+
}),
|
|
481
|
+
|
|
482
|
+
http.put('/api/game_mods/:id', async () => {
|
|
483
|
+
await delay(debugState.networkDelay)
|
|
484
|
+
return HttpResponse.json({ success: true })
|
|
485
|
+
}),
|
|
486
|
+
|
|
487
|
+
http.delete('/api/game_mods/:id', async () => {
|
|
488
|
+
await delay(debugState.networkDelay)
|
|
489
|
+
return HttpResponse.json({ success: true })
|
|
490
|
+
}),
|
|
491
|
+
|
|
492
|
+
// ==================== Nodes (Dedicated Servers) ====================
|
|
493
|
+
http.get('/api/dedicated_servers', async () => {
|
|
494
|
+
await delay(debugState.networkDelay)
|
|
495
|
+
return HttpResponse.json(mockNodes)
|
|
496
|
+
}),
|
|
497
|
+
|
|
498
|
+
http.get('/api/dedicated_servers/summary', async () => {
|
|
499
|
+
await delay(debugState.networkDelay)
|
|
500
|
+
return HttpResponse.json({
|
|
501
|
+
total: mockNodes.length,
|
|
502
|
+
online: mockNodes.length,
|
|
503
|
+
})
|
|
504
|
+
}),
|
|
505
|
+
|
|
506
|
+
http.get('/api/dedicated_servers/setup', async () => {
|
|
507
|
+
await delay(debugState.networkDelay)
|
|
508
|
+
return HttpResponse.json({
|
|
509
|
+
script: '#!/bin/bash\necho "Install GDaemon"',
|
|
510
|
+
})
|
|
511
|
+
}),
|
|
512
|
+
|
|
513
|
+
http.get('/api/dedicated_servers/:id', async ({ params }) => {
|
|
514
|
+
await delay(debugState.networkDelay)
|
|
515
|
+
const node = mockNodes.find(n => n.id === Number(params.id))
|
|
516
|
+
if (!node) {
|
|
517
|
+
return new HttpResponse(null, { status: 404 })
|
|
518
|
+
}
|
|
519
|
+
return HttpResponse.json(node)
|
|
520
|
+
}),
|
|
521
|
+
|
|
522
|
+
http.get('/api/dedicated_servers/:id/daemon', async () => {
|
|
523
|
+
await delay(debugState.networkDelay)
|
|
524
|
+
return HttpResponse.json({
|
|
525
|
+
version: '3.1.0',
|
|
526
|
+
uptime: 86400,
|
|
527
|
+
status: 'online',
|
|
528
|
+
})
|
|
529
|
+
}),
|
|
530
|
+
|
|
531
|
+
http.get('/api/dedicated_servers/:id/ip_list', async () => {
|
|
532
|
+
await delay(debugState.networkDelay)
|
|
533
|
+
return HttpResponse.json(['192.168.1.100', '192.168.1.101'])
|
|
534
|
+
}),
|
|
535
|
+
|
|
536
|
+
http.get('/api/dedicated_servers/:id/busy_ports', async () => {
|
|
537
|
+
await delay(debugState.networkDelay)
|
|
538
|
+
return HttpResponse.json([25565, 27015])
|
|
539
|
+
}),
|
|
540
|
+
|
|
541
|
+
http.post('/api/dedicated_servers', async () => {
|
|
542
|
+
await delay(debugState.networkDelay)
|
|
543
|
+
return HttpResponse.json({ success: true, id: 2 })
|
|
544
|
+
}),
|
|
545
|
+
|
|
546
|
+
http.put('/api/dedicated_servers/:id', async () => {
|
|
547
|
+
await delay(debugState.networkDelay)
|
|
548
|
+
return HttpResponse.json({ success: true })
|
|
549
|
+
}),
|
|
550
|
+
|
|
551
|
+
http.delete('/api/dedicated_servers/:id', async () => {
|
|
552
|
+
await delay(debugState.networkDelay)
|
|
553
|
+
return HttpResponse.json({ success: true })
|
|
554
|
+
}),
|
|
555
|
+
|
|
556
|
+
// ==================== Users ====================
|
|
557
|
+
http.get('/api/users/', async () => {
|
|
558
|
+
await delay(debugState.networkDelay)
|
|
559
|
+
return HttpResponse.json(mockUsersList)
|
|
560
|
+
}),
|
|
561
|
+
|
|
562
|
+
http.get('/api/users/:id', async ({ params }) => {
|
|
563
|
+
await delay(debugState.networkDelay)
|
|
564
|
+
const user = mockUsersList.find(u => u.id === Number(params.id))
|
|
565
|
+
if (!user) {
|
|
566
|
+
return new HttpResponse(null, { status: 404 })
|
|
567
|
+
}
|
|
568
|
+
return HttpResponse.json(user)
|
|
569
|
+
}),
|
|
570
|
+
|
|
571
|
+
http.get('/api/users/:id/servers', async () => {
|
|
572
|
+
await delay(debugState.networkDelay)
|
|
573
|
+
return HttpResponse.json(mockServers.map(s => ({ id: s.id, name: s.name })))
|
|
574
|
+
}),
|
|
575
|
+
|
|
576
|
+
http.get('/api/users/:id/servers/:serverId/permissions', async () => {
|
|
577
|
+
await delay(debugState.networkDelay)
|
|
578
|
+
return HttpResponse.json({
|
|
579
|
+
'console-view': true,
|
|
580
|
+
'files-view': true,
|
|
581
|
+
'settings-view': true,
|
|
582
|
+
'start-server': true,
|
|
583
|
+
'stop-server': true,
|
|
584
|
+
'restart-server': true,
|
|
585
|
+
})
|
|
586
|
+
}),
|
|
587
|
+
|
|
588
|
+
http.post('/api/users', async () => {
|
|
589
|
+
await delay(debugState.networkDelay)
|
|
590
|
+
return HttpResponse.json({ success: true, id: 3 })
|
|
591
|
+
}),
|
|
592
|
+
|
|
593
|
+
http.put('/api/users/:id', async () => {
|
|
594
|
+
await delay(debugState.networkDelay)
|
|
595
|
+
return HttpResponse.json({ success: true })
|
|
596
|
+
}),
|
|
597
|
+
|
|
598
|
+
http.put('/api/users/:id/servers/:serverId/permissions', async () => {
|
|
599
|
+
await delay(debugState.networkDelay)
|
|
600
|
+
return HttpResponse.json({ success: true })
|
|
601
|
+
}),
|
|
602
|
+
|
|
603
|
+
http.delete('/api/users/:id', async () => {
|
|
604
|
+
await delay(debugState.networkDelay)
|
|
605
|
+
return HttpResponse.json({ success: true })
|
|
606
|
+
}),
|
|
607
|
+
|
|
608
|
+
// ==================== Tokens ====================
|
|
609
|
+
http.get('/api/tokens', async () => {
|
|
610
|
+
await delay(debugState.networkDelay)
|
|
611
|
+
return HttpResponse.json([
|
|
612
|
+
{ id: 1, name: 'API Token 1', abilities: ['*'], last_used_at: '2024-12-15' },
|
|
613
|
+
])
|
|
614
|
+
}),
|
|
615
|
+
|
|
616
|
+
http.get('/api/tokens/abilities', async () => {
|
|
617
|
+
await delay(debugState.networkDelay)
|
|
618
|
+
return HttpResponse.json(['*', 'read', 'write', 'admin'])
|
|
619
|
+
}),
|
|
620
|
+
|
|
621
|
+
http.post('/api/tokens', async () => {
|
|
622
|
+
await delay(debugState.networkDelay)
|
|
623
|
+
return HttpResponse.json({
|
|
624
|
+
token: 'mock-token-abc123xyz',
|
|
625
|
+
id: 2,
|
|
626
|
+
})
|
|
627
|
+
}),
|
|
628
|
+
|
|
629
|
+
http.delete('/api/tokens/:id', async () => {
|
|
630
|
+
await delay(debugState.networkDelay)
|
|
631
|
+
return HttpResponse.json({ success: true })
|
|
632
|
+
}),
|
|
633
|
+
|
|
634
|
+
// ==================== Client Certificates ====================
|
|
635
|
+
http.get('/api/client_certificates', async () => {
|
|
636
|
+
await delay(debugState.networkDelay)
|
|
637
|
+
return HttpResponse.json([
|
|
638
|
+
{ id: 1, fingerprint: 'AB:CD:EF:12:34', expires_at: '2025-12-01' },
|
|
639
|
+
])
|
|
640
|
+
}),
|
|
641
|
+
|
|
642
|
+
http.post('/api/client_certificates', async () => {
|
|
643
|
+
await delay(debugState.networkDelay)
|
|
644
|
+
return HttpResponse.json({ success: true, id: 2 })
|
|
645
|
+
}),
|
|
646
|
+
|
|
647
|
+
http.delete('/api/client_certificates/:id', async () => {
|
|
648
|
+
await delay(debugState.networkDelay)
|
|
649
|
+
return HttpResponse.json({ success: true })
|
|
650
|
+
}),
|
|
651
|
+
|
|
652
|
+
// ==================== GDaemon Tasks ====================
|
|
653
|
+
http.get('/api/gdaemon_tasks', async () => {
|
|
654
|
+
await delay(debugState.networkDelay)
|
|
655
|
+
return HttpResponse.json({
|
|
656
|
+
data: [
|
|
657
|
+
{ id: 1, task: 'server-start', status: 'success', server_id: 1, created_at: '2024-12-17 10:00:00' },
|
|
658
|
+
{ id: 2, task: 'server-stop', status: 'working', server_id: 1, created_at: '2024-12-17 11:00:00' },
|
|
659
|
+
],
|
|
660
|
+
total: 2,
|
|
661
|
+
})
|
|
662
|
+
}),
|
|
663
|
+
|
|
664
|
+
http.get('/api/gdaemon_tasks/:id', async ({ params }) => {
|
|
665
|
+
await delay(debugState.networkDelay)
|
|
666
|
+
return HttpResponse.json({
|
|
667
|
+
id: Number(params.id),
|
|
668
|
+
task: 'server-start',
|
|
669
|
+
status: 'success',
|
|
670
|
+
output: 'Server started successfully',
|
|
671
|
+
})
|
|
672
|
+
}),
|
|
673
|
+
|
|
674
|
+
http.get('/api/gdaemon_tasks/:id/output', async () => {
|
|
675
|
+
await delay(debugState.networkDelay)
|
|
676
|
+
return HttpResponse.json({
|
|
677
|
+
output: 'Task output...\nCompleted successfully.',
|
|
678
|
+
})
|
|
679
|
+
}),
|
|
680
|
+
|
|
681
|
+
// ==================== File Manager ====================
|
|
682
|
+
// File manager initialize - new API path
|
|
683
|
+
http.get('/api/file-manager/:serverId/initialize', async () => {
|
|
684
|
+
await delay(debugState.networkDelay)
|
|
685
|
+
return HttpResponse.json({
|
|
686
|
+
result: {
|
|
687
|
+
status: 'success',
|
|
688
|
+
message: null,
|
|
689
|
+
},
|
|
690
|
+
config: {
|
|
691
|
+
leftDisk: null,
|
|
692
|
+
rightDisk: null,
|
|
693
|
+
windowsConfig: 1,
|
|
694
|
+
disks: {
|
|
695
|
+
server: {
|
|
696
|
+
driver: 'gameap',
|
|
697
|
+
},
|
|
698
|
+
},
|
|
699
|
+
lang: '',
|
|
700
|
+
},
|
|
701
|
+
})
|
|
702
|
+
}),
|
|
703
|
+
|
|
704
|
+
// File manager initialize - legacy API path
|
|
705
|
+
http.get('/api/servers/:id/filemanager/initialize', async () => {
|
|
706
|
+
await delay(debugState.networkDelay)
|
|
707
|
+
return HttpResponse.json({
|
|
708
|
+
result: {
|
|
709
|
+
status: 'success',
|
|
710
|
+
message: null,
|
|
711
|
+
},
|
|
712
|
+
config: {
|
|
713
|
+
leftDisk: null,
|
|
714
|
+
rightDisk: null,
|
|
715
|
+
windowsConfig: 1,
|
|
716
|
+
disks: {
|
|
717
|
+
server: {
|
|
718
|
+
driver: 'gameap',
|
|
719
|
+
},
|
|
720
|
+
},
|
|
721
|
+
lang: '',
|
|
722
|
+
},
|
|
723
|
+
})
|
|
724
|
+
}),
|
|
725
|
+
|
|
726
|
+
// File manager content - new API path
|
|
727
|
+
http.get('/api/file-manager/:serverId/content', async ({ request }) => {
|
|
728
|
+
await delay(debugState.networkDelay)
|
|
729
|
+
const url = new URL(request.url)
|
|
730
|
+
const path = url.searchParams.get('path') || ''
|
|
731
|
+
|
|
732
|
+
const { files, directories } = getFilesForPath(path)
|
|
733
|
+
|
|
734
|
+
return HttpResponse.json({
|
|
735
|
+
result: {
|
|
736
|
+
status: 'success',
|
|
737
|
+
message: null,
|
|
738
|
+
},
|
|
739
|
+
directories,
|
|
740
|
+
files,
|
|
741
|
+
})
|
|
742
|
+
}),
|
|
743
|
+
|
|
744
|
+
// File manager content - legacy API path
|
|
745
|
+
http.get('/api/servers/:id/filemanager/content', async ({ request }) => {
|
|
746
|
+
await delay(debugState.networkDelay)
|
|
747
|
+
const url = new URL(request.url)
|
|
748
|
+
const path = url.searchParams.get('path') || ''
|
|
749
|
+
|
|
750
|
+
const { files, directories } = getFilesForPath(path)
|
|
751
|
+
|
|
752
|
+
return HttpResponse.json({
|
|
753
|
+
result: {
|
|
754
|
+
status: 'success',
|
|
755
|
+
message: null,
|
|
756
|
+
},
|
|
757
|
+
directories,
|
|
758
|
+
files,
|
|
759
|
+
})
|
|
760
|
+
}),
|
|
761
|
+
|
|
762
|
+
http.get('/api/servers/:id/filemanager/tree', async ({ request }) => {
|
|
763
|
+
await delay(debugState.networkDelay)
|
|
764
|
+
const url = new URL(request.url)
|
|
765
|
+
const path = url.searchParams.get('path') || ''
|
|
766
|
+
|
|
767
|
+
const { directories } = getFilesForPath(path)
|
|
768
|
+
|
|
769
|
+
return HttpResponse.json({
|
|
770
|
+
result: { status: 'success', message: null },
|
|
771
|
+
directories,
|
|
772
|
+
})
|
|
773
|
+
}),
|
|
774
|
+
|
|
775
|
+
http.get('/api/servers/:id/filemanager/select-disk', async () => {
|
|
776
|
+
await delay(debugState.networkDelay)
|
|
777
|
+
return HttpResponse.json({
|
|
778
|
+
result: { status: 'success' },
|
|
779
|
+
})
|
|
780
|
+
}),
|
|
781
|
+
|
|
782
|
+
// File manager download - new API path
|
|
783
|
+
http.get('/api/file-manager/:serverId/download', async ({ request }) => {
|
|
784
|
+
await delay(debugState.networkDelay)
|
|
785
|
+
const url = new URL(request.url)
|
|
786
|
+
const path = url.searchParams.get('path') || ''
|
|
787
|
+
|
|
788
|
+
const file = getFileByPath(path)
|
|
789
|
+
if (!file) {
|
|
790
|
+
return new HttpResponse(null, { status: 404 })
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (file._contentType === 'binary') {
|
|
794
|
+
return new HttpResponse(file._content as ArrayBuffer, {
|
|
795
|
+
headers: {
|
|
796
|
+
'Content-Type': 'application/octet-stream',
|
|
797
|
+
},
|
|
798
|
+
})
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
return new HttpResponse(file._content as string, {
|
|
802
|
+
headers: {
|
|
803
|
+
'Content-Type': 'text/plain',
|
|
804
|
+
},
|
|
805
|
+
})
|
|
806
|
+
}),
|
|
807
|
+
|
|
808
|
+
// File manager download - legacy API path
|
|
809
|
+
http.get('/api/servers/:id/filemanager/download', async ({ request }) => {
|
|
810
|
+
await delay(debugState.networkDelay)
|
|
811
|
+
const url = new URL(request.url)
|
|
812
|
+
const path = url.searchParams.get('path') || ''
|
|
813
|
+
|
|
814
|
+
const file = getFileByPath(path)
|
|
815
|
+
if (!file) {
|
|
816
|
+
return new HttpResponse(null, { status: 404 })
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
if (file._contentType === 'binary') {
|
|
820
|
+
return new HttpResponse(file._content as ArrayBuffer, {
|
|
821
|
+
headers: {
|
|
822
|
+
'Content-Type': 'application/octet-stream',
|
|
823
|
+
},
|
|
824
|
+
})
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
return new HttpResponse(file._content as string, {
|
|
828
|
+
headers: {
|
|
829
|
+
'Content-Type': 'text/plain',
|
|
830
|
+
},
|
|
831
|
+
})
|
|
832
|
+
}),
|
|
833
|
+
|
|
834
|
+
http.post('/api/servers/:id/filemanager/update-file', async () => {
|
|
835
|
+
await delay(debugState.networkDelay)
|
|
836
|
+
return HttpResponse.json({
|
|
837
|
+
result: { status: 'success' },
|
|
838
|
+
})
|
|
839
|
+
}),
|
|
840
|
+
|
|
841
|
+
http.post('/api/servers/:id/filemanager/create-file', async () => {
|
|
842
|
+
await delay(debugState.networkDelay)
|
|
843
|
+
return HttpResponse.json({
|
|
844
|
+
result: { status: 'success' },
|
|
845
|
+
})
|
|
846
|
+
}),
|
|
847
|
+
|
|
848
|
+
http.post('/api/servers/:id/filemanager/create-directory', async () => {
|
|
849
|
+
await delay(debugState.networkDelay)
|
|
850
|
+
return HttpResponse.json({
|
|
851
|
+
result: { status: 'success' },
|
|
852
|
+
})
|
|
853
|
+
}),
|
|
854
|
+
|
|
855
|
+
http.post('/api/servers/:id/filemanager/delete', async () => {
|
|
856
|
+
await delay(debugState.networkDelay)
|
|
857
|
+
return HttpResponse.json({
|
|
858
|
+
result: { status: 'success' },
|
|
859
|
+
})
|
|
860
|
+
}),
|
|
861
|
+
|
|
862
|
+
http.post('/api/servers/:id/filemanager/rename', async () => {
|
|
863
|
+
await delay(debugState.networkDelay)
|
|
864
|
+
return HttpResponse.json({
|
|
865
|
+
result: { status: 'success' },
|
|
866
|
+
})
|
|
867
|
+
}),
|
|
868
|
+
|
|
869
|
+
http.post('/api/servers/:id/filemanager/paste', async () => {
|
|
870
|
+
await delay(debugState.networkDelay)
|
|
871
|
+
return HttpResponse.json({
|
|
872
|
+
result: { status: 'success' },
|
|
873
|
+
})
|
|
874
|
+
}),
|
|
875
|
+
|
|
876
|
+
http.post('/api/servers/:id/filemanager/upload', async () => {
|
|
877
|
+
await delay(debugState.networkDelay)
|
|
878
|
+
return HttpResponse.json({
|
|
879
|
+
result: { status: 'success' },
|
|
880
|
+
})
|
|
881
|
+
}),
|
|
882
|
+
|
|
883
|
+
http.post('/api/servers/:id/filemanager/zip', async () => {
|
|
884
|
+
await delay(debugState.networkDelay)
|
|
885
|
+
return HttpResponse.json({
|
|
886
|
+
result: { status: 'success' },
|
|
887
|
+
})
|
|
888
|
+
}),
|
|
889
|
+
|
|
890
|
+
http.post('/api/servers/:id/filemanager/unzip', async () => {
|
|
891
|
+
await delay(debugState.networkDelay)
|
|
892
|
+
return HttpResponse.json({
|
|
893
|
+
result: { status: 'success' },
|
|
894
|
+
})
|
|
895
|
+
}),
|
|
896
|
+
|
|
897
|
+
// ==================== Plugins ====================
|
|
898
|
+
http.get('/plugins.js', async () => {
|
|
899
|
+
await delay(debugState.networkDelay)
|
|
900
|
+
if (!pluginJsContent) {
|
|
901
|
+
return new HttpResponse('', { status: 404 })
|
|
902
|
+
}
|
|
903
|
+
return new HttpResponse(pluginJsContent, {
|
|
904
|
+
headers: {
|
|
905
|
+
'Content-Type': 'application/javascript',
|
|
906
|
+
},
|
|
907
|
+
})
|
|
908
|
+
}),
|
|
909
|
+
|
|
910
|
+
http.get('/plugins.css', async () => {
|
|
911
|
+
await delay(debugState.networkDelay)
|
|
912
|
+
if (!pluginCssContent) {
|
|
913
|
+
return new HttpResponse('', { status: 404 })
|
|
914
|
+
}
|
|
915
|
+
return new HttpResponse(pluginCssContent, {
|
|
916
|
+
headers: {
|
|
917
|
+
'Content-Type': 'text/css',
|
|
918
|
+
},
|
|
919
|
+
})
|
|
920
|
+
}),
|
|
921
|
+
|
|
922
|
+
// ==================== Language ====================
|
|
923
|
+
// Language/translations endpoint - uses actual translation files
|
|
924
|
+
http.get('/lang/:locale.json', async ({ params }) => {
|
|
925
|
+
await delay(debugState.networkDelay)
|
|
926
|
+
const locale = (params.locale as string).replace('.json', '')
|
|
927
|
+
const localeTranslations = translations[locale] || translations.en
|
|
928
|
+
return HttpResponse.json(localeTranslations)
|
|
929
|
+
}),
|
|
930
|
+
|
|
931
|
+
// Also handle without .json extension
|
|
932
|
+
http.get('/lang/:locale', async ({ params }) => {
|
|
933
|
+
await delay(debugState.networkDelay)
|
|
934
|
+
const locale = params.locale as string
|
|
935
|
+
const localeTranslations = translations[locale] || translations.en
|
|
936
|
+
return HttpResponse.json(localeTranslations)
|
|
937
|
+
}),
|
|
938
|
+
]
|
|
939
|
+
|
|
940
|
+
export default handlers
|