@gameap/debug 0.2.17 → 0.3.1
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/package.json +2 -2
- package/public/mockServiceWorker.js +1 -1
- package/src/main.ts +107 -12
- package/src/mocks/README.md +89 -0
- package/src/mocks/browser.ts +37 -2
- package/src/mocks/handlers.ts +80 -0
- package/src/mocks/translations-en.json +10 -0
- package/src/mocks/translations-ru.json +10 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gameap/debug",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Debug harness for GameAP plugin development with mock API",
|
|
6
6
|
"scripts": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@gameap/plugin-sdk": "^0.2.0",
|
|
29
|
-
"@gameap/frontend": "4.1.0-
|
|
29
|
+
"@gameap/frontend": "4.1.0-dev9",
|
|
30
30
|
"@originjs/vite-plugin-commonjs": "^1.0.3",
|
|
31
31
|
"@tailwindcss/postcss": "^4.1.0",
|
|
32
32
|
"@vitejs/plugin-vue": "^6.0.1",
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - Please do NOT modify this file.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const PACKAGE_VERSION = '2.12.
|
|
10
|
+
const PACKAGE_VERSION = '2.12.7'
|
|
11
11
|
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
|
|
12
12
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
|
13
13
|
const activeClientIds = new Set()
|
package/src/main.ts
CHANGED
|
@@ -8,7 +8,34 @@
|
|
|
8
8
|
// Import frontend styles (bundled in vendor directory)
|
|
9
9
|
import '../vendor/frontend.css'
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
// Import and expose framework globals for the externalized @gameap/frontend package
|
|
12
|
+
import * as Vue from 'vue'
|
|
13
|
+
import * as VueRouter from 'vue-router'
|
|
14
|
+
import * as Pinia from 'pinia'
|
|
15
|
+
import axios from 'axios'
|
|
16
|
+
import * as naive from 'naive-ui'
|
|
17
|
+
|
|
18
|
+
// Expose globals before loading the frontend
|
|
19
|
+
window.Vue = Vue
|
|
20
|
+
window.VueRouter = VueRouter
|
|
21
|
+
window.Pinia = Pinia
|
|
22
|
+
window.axios = axios
|
|
23
|
+
window.naive = naive
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
startMockServiceWorker,
|
|
27
|
+
setPluginContent,
|
|
28
|
+
updateDebugState,
|
|
29
|
+
registerMockHandlers,
|
|
30
|
+
resetMockHandlers,
|
|
31
|
+
http,
|
|
32
|
+
HttpResponse,
|
|
33
|
+
delay
|
|
34
|
+
} from './mocks/browser'
|
|
35
|
+
import { mockServersList, type ServerListItem } from './mocks/servers'
|
|
36
|
+
import { userMocks } from './mocks/users'
|
|
37
|
+
import type { UserData } from '@gameap/plugin-sdk'
|
|
38
|
+
import type { RequestHandler } from 'msw'
|
|
12
39
|
|
|
13
40
|
// Declare window globals for plugin compatibility
|
|
14
41
|
declare global {
|
|
@@ -17,12 +44,28 @@ declare global {
|
|
|
17
44
|
VueRouter: typeof import('vue-router')
|
|
18
45
|
Pinia: typeof import('pinia')
|
|
19
46
|
axios: typeof import('axios').default
|
|
47
|
+
naive: typeof import('naive-ui')
|
|
20
48
|
gameapLang: string
|
|
21
49
|
i18n: Record<string, string>
|
|
22
50
|
gameapDebug: {
|
|
23
51
|
updateDebugState: typeof updateDebugState
|
|
24
52
|
setPluginContent: typeof setPluginContent
|
|
25
53
|
loadPlugin: (js: string, css?: string) => void
|
|
54
|
+
registerMockHandlers: (handlers: RequestHandler[]) => void
|
|
55
|
+
resetMockHandlers: () => void
|
|
56
|
+
msw: {
|
|
57
|
+
http: typeof http
|
|
58
|
+
HttpResponse: typeof HttpResponse
|
|
59
|
+
delay: typeof delay
|
|
60
|
+
}
|
|
61
|
+
mockData: {
|
|
62
|
+
addServer: (server: Partial<ServerListItem>) => ServerListItem
|
|
63
|
+
updateServer: (id: number, updates: Partial<ServerListItem>) => void
|
|
64
|
+
removeServer: (id: number) => void
|
|
65
|
+
getServers: () => ServerListItem[]
|
|
66
|
+
addUser: (key: string, user: UserData) => void
|
|
67
|
+
getUsers: () => Record<string, UserData>
|
|
68
|
+
}
|
|
26
69
|
}
|
|
27
70
|
}
|
|
28
71
|
}
|
|
@@ -108,7 +151,69 @@ async function init() {
|
|
|
108
151
|
setPluginContent(js, css)
|
|
109
152
|
}
|
|
110
153
|
|
|
111
|
-
//
|
|
154
|
+
// Expose debug utilities globally BEFORE starting MSW
|
|
155
|
+
// so plugins can register handlers in onInit()
|
|
156
|
+
window.gameapDebug = {
|
|
157
|
+
updateDebugState,
|
|
158
|
+
setPluginContent,
|
|
159
|
+
loadPlugin: (newJs: string, newCss?: string) => {
|
|
160
|
+
setPluginContent(newJs, newCss || '')
|
|
161
|
+
console.log('[Debug] Plugin content updated, reload to apply')
|
|
162
|
+
},
|
|
163
|
+
registerMockHandlers,
|
|
164
|
+
resetMockHandlers,
|
|
165
|
+
msw: {
|
|
166
|
+
http,
|
|
167
|
+
HttpResponse,
|
|
168
|
+
delay,
|
|
169
|
+
},
|
|
170
|
+
mockData: {
|
|
171
|
+
addServer: (server: Partial<ServerListItem>) => {
|
|
172
|
+
const id = Math.max(...mockServersList.map(s => s.id), 0) + 1
|
|
173
|
+
const newServer: ServerListItem = {
|
|
174
|
+
id,
|
|
175
|
+
enabled: true,
|
|
176
|
+
installed: 1,
|
|
177
|
+
blocked: false,
|
|
178
|
+
name: `Server ${id}`,
|
|
179
|
+
game_id: 'minecraft',
|
|
180
|
+
ds_id: 1,
|
|
181
|
+
game_mod_id: 1,
|
|
182
|
+
expires: null,
|
|
183
|
+
server_ip: '127.0.0.1',
|
|
184
|
+
server_port: 25565 + id,
|
|
185
|
+
query_port: 25565 + id,
|
|
186
|
+
rcon_port: 25575 + id,
|
|
187
|
+
process_active: false,
|
|
188
|
+
last_process_check: new Date().toISOString(),
|
|
189
|
+
game: { code: 'minecraft', name: 'Minecraft', engine: 'Minecraft', engine_version: '1' },
|
|
190
|
+
online: false,
|
|
191
|
+
...server,
|
|
192
|
+
}
|
|
193
|
+
mockServersList.push(newServer)
|
|
194
|
+
return newServer
|
|
195
|
+
},
|
|
196
|
+
updateServer: (id: number, updates: Partial<ServerListItem>) => {
|
|
197
|
+
const idx = mockServersList.findIndex(s => s.id === id)
|
|
198
|
+
if (idx !== -1) {
|
|
199
|
+
Object.assign(mockServersList[idx], updates)
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
removeServer: (id: number) => {
|
|
203
|
+
const idx = mockServersList.findIndex(s => s.id === id)
|
|
204
|
+
if (idx !== -1) {
|
|
205
|
+
mockServersList.splice(idx, 1)
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
getServers: () => [...mockServersList],
|
|
209
|
+
addUser: (key: string, user: UserData) => {
|
|
210
|
+
userMocks[key] = user
|
|
211
|
+
},
|
|
212
|
+
getUsers: () => ({ ...userMocks }),
|
|
213
|
+
},
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Start MSW (will apply any pre-registered handlers)
|
|
112
217
|
console.log('[Debug] Starting Mock Service Worker...')
|
|
113
218
|
await startMockServiceWorker()
|
|
114
219
|
console.log('[Debug] MSW started successfully')
|
|
@@ -119,16 +224,6 @@ async function init() {
|
|
|
119
224
|
// Load translations AFTER MSW starts (so MSW can intercept the request)
|
|
120
225
|
await loadTranslations()
|
|
121
226
|
|
|
122
|
-
// Expose debug utilities globally
|
|
123
|
-
window.gameapDebug = {
|
|
124
|
-
updateDebugState,
|
|
125
|
-
setPluginContent,
|
|
126
|
-
loadPlugin: (newJs: string, newCss?: string) => {
|
|
127
|
-
setPluginContent(newJs, newCss || '')
|
|
128
|
-
console.log('[Debug] Plugin content updated, reload to apply')
|
|
129
|
-
},
|
|
130
|
-
}
|
|
131
|
-
|
|
132
227
|
// Now load the real GameAP frontend
|
|
133
228
|
console.log('[Debug] Loading GameAP frontend...')
|
|
134
229
|
|
package/src/mocks/README.md
CHANGED
|
@@ -54,6 +54,7 @@ Each server has different capabilities (RCON, console access, file manager, etc.
|
|
|
54
54
|
- GDaemon Tasks
|
|
55
55
|
- File Manager (browse, upload, download, zip/unzip)
|
|
56
56
|
- Plugins (JS/CSS loading)
|
|
57
|
+
- Plugin Store (categories, labels, plugins, install/update/uninstall)
|
|
57
58
|
- Translations
|
|
58
59
|
|
|
59
60
|
## Usage
|
|
@@ -66,3 +67,91 @@ await startMockServiceWorker()
|
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
The debug panel (in main.ts) provides UI controls for switching user types, adjusting network delay, and changing locale.
|
|
70
|
+
|
|
71
|
+
## Plugin Mock API
|
|
72
|
+
|
|
73
|
+
Plugins can register custom mock handlers for their API endpoints. This is useful for:
|
|
74
|
+
- Adding mock endpoints for plugin-specific APIs
|
|
75
|
+
- Overriding default handler responses
|
|
76
|
+
- Testing different API scenarios
|
|
77
|
+
|
|
78
|
+
### Registering Mock Handlers
|
|
79
|
+
|
|
80
|
+
In your plugin's `onInit()` hook:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
export const myPlugin = {
|
|
84
|
+
id: 'my-plugin',
|
|
85
|
+
name: 'My Plugin',
|
|
86
|
+
version: '1.0.0',
|
|
87
|
+
|
|
88
|
+
onInit() {
|
|
89
|
+
if (window.gameapDebug) {
|
|
90
|
+
const { http, HttpResponse, delay } = window.gameapDebug.msw
|
|
91
|
+
|
|
92
|
+
window.gameapDebug.registerMockHandlers([
|
|
93
|
+
http.get('/api/plugins/my-plugin/data', async () => {
|
|
94
|
+
await delay(100)
|
|
95
|
+
return HttpResponse.json({
|
|
96
|
+
items: [{ id: 1, name: 'Item 1' }]
|
|
97
|
+
})
|
|
98
|
+
}),
|
|
99
|
+
])
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### MSW Utilities
|
|
106
|
+
|
|
107
|
+
The `window.gameapDebug.msw` object exposes:
|
|
108
|
+
|
|
109
|
+
| Utility | Description |
|
|
110
|
+
|---------|-------------|
|
|
111
|
+
| `http` | HTTP method handlers (`http.get()`, `http.post()`, etc.) |
|
|
112
|
+
| `HttpResponse` | Response builder for mock responses |
|
|
113
|
+
| `delay` | Async delay function for simulating network latency |
|
|
114
|
+
|
|
115
|
+
### Mock Data Utilities
|
|
116
|
+
|
|
117
|
+
Manipulate mock data programmatically via `window.gameapDebug.mockData`:
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// Add a custom server
|
|
121
|
+
const newServer = mockData.addServer({
|
|
122
|
+
name: 'My Test Server',
|
|
123
|
+
game_id: 'minecraft',
|
|
124
|
+
process_active: true
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// Update existing server
|
|
128
|
+
mockData.updateServer(1, { name: 'Updated Name' })
|
|
129
|
+
|
|
130
|
+
// Remove a server
|
|
131
|
+
mockData.removeServer(3)
|
|
132
|
+
|
|
133
|
+
// Get all servers
|
|
134
|
+
const servers = mockData.getServers()
|
|
135
|
+
|
|
136
|
+
// Add a custom user type
|
|
137
|
+
mockData.addUser('moderator', {
|
|
138
|
+
id: 3,
|
|
139
|
+
login: 'mod',
|
|
140
|
+
name: 'Moderator',
|
|
141
|
+
roles: ['moderator'],
|
|
142
|
+
isAdmin: false,
|
|
143
|
+
isAuthenticated: true
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Resetting Handlers
|
|
148
|
+
|
|
149
|
+
To restore original handlers (remove all plugin handlers):
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
window.gameapDebug.resetMockHandlers()
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Handler Priority
|
|
156
|
+
|
|
157
|
+
Plugin handlers are prepended and checked **first** before default handlers, allowing overrides.
|
package/src/mocks/browser.ts
CHANGED
|
@@ -1,22 +1,57 @@
|
|
|
1
1
|
import { setupWorker } from 'msw/browser'
|
|
2
|
+
import { http, HttpResponse, delay, type RequestHandler } from 'msw'
|
|
2
3
|
import { handlers, debugState, setPluginContent } from './handlers'
|
|
3
4
|
|
|
5
|
+
// Store initial handlers for reset capability
|
|
6
|
+
const initialHandlers = [...handlers]
|
|
7
|
+
|
|
8
|
+
// Queue for handlers registered before MSW starts
|
|
9
|
+
let pendingHandlers: RequestHandler[] = []
|
|
10
|
+
let workerStarted = false
|
|
11
|
+
|
|
4
12
|
export const worker = setupWorker(...handlers)
|
|
5
13
|
|
|
6
14
|
// Export debug state and utilities for external control
|
|
7
15
|
export { debugState, setPluginContent }
|
|
8
16
|
|
|
17
|
+
// Export MSW utilities for plugin use
|
|
18
|
+
export { http, HttpResponse, delay }
|
|
19
|
+
|
|
9
20
|
// Helper to update debug state
|
|
10
21
|
export function updateDebugState(updates: Partial<typeof debugState>) {
|
|
11
22
|
Object.assign(debugState, updates)
|
|
12
23
|
}
|
|
13
24
|
|
|
25
|
+
// Register custom mock handlers (prepends to take priority)
|
|
26
|
+
export function registerMockHandlers(customHandlers: RequestHandler[]) {
|
|
27
|
+
if (!workerStarted) {
|
|
28
|
+
pendingHandlers.push(...customHandlers)
|
|
29
|
+
} else {
|
|
30
|
+
worker.use(...customHandlers)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Reset handlers to initial state (removes all plugin handlers)
|
|
35
|
+
export function resetMockHandlers() {
|
|
36
|
+
worker.resetHandlers(...initialHandlers)
|
|
37
|
+
}
|
|
38
|
+
|
|
14
39
|
// Start the worker
|
|
15
40
|
export async function startMockServiceWorker() {
|
|
16
|
-
|
|
17
|
-
onUnhandledRequest: 'bypass',
|
|
41
|
+
const result = await worker.start({
|
|
42
|
+
onUnhandledRequest: 'bypass',
|
|
18
43
|
serviceWorker: {
|
|
19
44
|
url: '/mockServiceWorker.js',
|
|
20
45
|
},
|
|
21
46
|
})
|
|
47
|
+
|
|
48
|
+
workerStarted = true
|
|
49
|
+
|
|
50
|
+
// Apply any handlers that were registered before start
|
|
51
|
+
if (pendingHandlers.length > 0) {
|
|
52
|
+
worker.use(...pendingHandlers)
|
|
53
|
+
pendingHandlers = []
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result
|
|
22
57
|
}
|
package/src/mocks/handlers.ts
CHANGED
|
@@ -919,6 +919,86 @@ export const handlers = [
|
|
|
919
919
|
})
|
|
920
920
|
}),
|
|
921
921
|
|
|
922
|
+
// ==================== Plugin Store ====================
|
|
923
|
+
http.get('/api/plugin-store/categories', async () => {
|
|
924
|
+
await delay(debugState.networkDelay)
|
|
925
|
+
return HttpResponse.json([
|
|
926
|
+
{ id: 1, slug: 'game-management', name: 'Game Management' },
|
|
927
|
+
{ id: 2, slug: 'monitoring', name: 'Monitoring' },
|
|
928
|
+
{ id: 3, slug: 'utilities', name: 'Utilities' },
|
|
929
|
+
])
|
|
930
|
+
}),
|
|
931
|
+
|
|
932
|
+
http.get('/api/plugin-store/labels', async () => {
|
|
933
|
+
await delay(debugState.networkDelay)
|
|
934
|
+
return HttpResponse.json([
|
|
935
|
+
{ id: 1, slug: 'official', name: 'Official', color: '#4f46e5' },
|
|
936
|
+
{ id: 2, slug: 'popular', name: 'Popular', color: '#059669' },
|
|
937
|
+
])
|
|
938
|
+
}),
|
|
939
|
+
|
|
940
|
+
http.get('/api/plugin-store/plugins', async () => {
|
|
941
|
+
await delay(debugState.networkDelay)
|
|
942
|
+
return HttpResponse.json({
|
|
943
|
+
data: [
|
|
944
|
+
{
|
|
945
|
+
id: 1,
|
|
946
|
+
slug: 'example-plugin',
|
|
947
|
+
name: 'Example Plugin',
|
|
948
|
+
description: 'An example plugin for testing',
|
|
949
|
+
installed: false,
|
|
950
|
+
installed_version: null,
|
|
951
|
+
latest_version: '1.0.0',
|
|
952
|
+
category: { slug: 'utilities', name: 'Utilities' },
|
|
953
|
+
labels: [{ slug: 'official', name: 'Official', color: '#4f46e5' }],
|
|
954
|
+
},
|
|
955
|
+
],
|
|
956
|
+
current_page: 1,
|
|
957
|
+
last_page: 1,
|
|
958
|
+
total: 1,
|
|
959
|
+
})
|
|
960
|
+
}),
|
|
961
|
+
|
|
962
|
+
http.get('/api/plugin-store/plugins/:id', async ({ params }) => {
|
|
963
|
+
await delay(debugState.networkDelay)
|
|
964
|
+
return HttpResponse.json({
|
|
965
|
+
id: Number(params.id),
|
|
966
|
+
slug: 'example-plugin',
|
|
967
|
+
name: 'Example Plugin',
|
|
968
|
+
description: 'An example plugin for testing',
|
|
969
|
+
readme: '# Example Plugin\n\nThis is an example plugin.',
|
|
970
|
+
installed: false,
|
|
971
|
+
installed_version: null,
|
|
972
|
+
latest_version: '1.0.0',
|
|
973
|
+
})
|
|
974
|
+
}),
|
|
975
|
+
|
|
976
|
+
http.get('/api/plugin-store/plugins/:id/versions', async () => {
|
|
977
|
+
await delay(debugState.networkDelay)
|
|
978
|
+
return HttpResponse.json({
|
|
979
|
+
data: [
|
|
980
|
+
{ version: '1.0.0', released_at: '2024-01-01', changelog: 'Initial release' },
|
|
981
|
+
],
|
|
982
|
+
current_page: 1,
|
|
983
|
+
last_page: 1,
|
|
984
|
+
})
|
|
985
|
+
}),
|
|
986
|
+
|
|
987
|
+
http.post('/api/plugin-store/plugins/:id/install', async () => {
|
|
988
|
+
await delay(debugState.networkDelay)
|
|
989
|
+
return HttpResponse.json({ success: true })
|
|
990
|
+
}),
|
|
991
|
+
|
|
992
|
+
http.post('/api/plugin-store/plugins/:id/update', async () => {
|
|
993
|
+
await delay(debugState.networkDelay)
|
|
994
|
+
return HttpResponse.json({ success: true })
|
|
995
|
+
}),
|
|
996
|
+
|
|
997
|
+
http.delete('/api/plugin-store/plugins/:id', async () => {
|
|
998
|
+
await delay(debugState.networkDelay)
|
|
999
|
+
return HttpResponse.json({ success: true })
|
|
1000
|
+
}),
|
|
1001
|
+
|
|
922
1002
|
// ==================== Language ====================
|
|
923
1003
|
// Language/translations endpoint - uses actual translation files
|
|
924
1004
|
http.get('/lang/:locale.json', async ({ params }) => {
|
|
@@ -361,6 +361,16 @@
|
|
|
361
361
|
"disable_success_msg": "Module disabled successfully",
|
|
362
362
|
"remove_success_msg": "Module removed successfully"
|
|
363
363
|
},
|
|
364
|
+
"plugins": {
|
|
365
|
+
"plugins": "Plugins",
|
|
366
|
+
"title_list": "Plugin List",
|
|
367
|
+
"installed": "Installed",
|
|
368
|
+
"name": "Plugin name",
|
|
369
|
+
"install": "Install",
|
|
370
|
+
"update": "Update",
|
|
371
|
+
"install_success_msg": "Plugin installed successfully",
|
|
372
|
+
"remove_success_msg": "Plugin removed successfully"
|
|
373
|
+
},
|
|
364
374
|
"navbar": {
|
|
365
375
|
"main": "Home",
|
|
366
376
|
"logs": "Logs",
|
|
@@ -362,6 +362,16 @@
|
|
|
362
362
|
"disable_success_msg": "Модуль успешно выключен",
|
|
363
363
|
"remove_success_msg": "Модуль успешно удалён"
|
|
364
364
|
},
|
|
365
|
+
"plugins": {
|
|
366
|
+
"plugins": "Плагины",
|
|
367
|
+
"title_list": "Список плагинов",
|
|
368
|
+
"installed": "Установленные",
|
|
369
|
+
"name": "Имя плагина",
|
|
370
|
+
"install": "Установить",
|
|
371
|
+
"update": "Обновить",
|
|
372
|
+
"install_success_msg": "Плагин успешно установлен",
|
|
373
|
+
"remove_success_msg": "Плагин успешно удалён"
|
|
374
|
+
},
|
|
365
375
|
"navbar": {
|
|
366
376
|
"main": "Главная",
|
|
367
377
|
"logs": "Логи",
|