@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.
@@ -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