@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gameap/debug",
3
- "version": "0.2.17",
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-dev8",
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.4'
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
- import { startMockServiceWorker, setPluginContent, updateDebugState } from './mocks/browser'
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
- // Start MSW
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
 
@@ -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.
@@ -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
- return worker.start({
17
- onUnhandledRequest: 'bypass', // Don't warn about unhandled requests
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
  }
@@ -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": "Логи",