@gxp-dev/tools 2.0.63 → 2.0.65
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 +32 -31
- package/bin/gx-devtools.js +74 -54
- package/bin/lib/cli.js +23 -21
- package/bin/lib/commands/add-dependency.js +366 -325
- package/bin/lib/commands/assets.js +137 -139
- package/bin/lib/commands/build.js +169 -174
- package/bin/lib/commands/datastore.js +181 -183
- package/bin/lib/commands/dev.js +127 -131
- package/bin/lib/commands/extensions.js +147 -149
- package/bin/lib/commands/extract-config.js +73 -67
- package/bin/lib/commands/index.js +12 -12
- package/bin/lib/commands/init.js +342 -240
- package/bin/lib/commands/publish.js +69 -75
- package/bin/lib/commands/socket.js +69 -69
- package/bin/lib/commands/ssl.js +14 -14
- package/bin/lib/constants.js +10 -24
- package/bin/lib/tui/App.tsx +761 -705
- package/bin/lib/tui/components/AIPanel.tsx +191 -171
- package/bin/lib/tui/components/CommandInput.tsx +394 -343
- package/bin/lib/tui/components/GeminiPanel.tsx +175 -151
- package/bin/lib/tui/components/Header.tsx +23 -21
- package/bin/lib/tui/components/LogPanel.tsx +244 -220
- package/bin/lib/tui/components/TabBar.tsx +50 -48
- package/bin/lib/tui/components/WelcomeScreen.tsx +126 -71
- package/bin/lib/tui/index.tsx +37 -39
- package/bin/lib/tui/services/AIService.ts +518 -462
- package/bin/lib/tui/services/ExtensionService.ts +140 -129
- package/bin/lib/tui/services/GeminiService.ts +367 -337
- package/bin/lib/tui/services/ServiceManager.ts +344 -322
- package/bin/lib/tui/services/SocketService.ts +168 -168
- package/bin/lib/tui/services/ViteService.ts +88 -88
- package/bin/lib/tui/services/index.ts +47 -22
- package/bin/lib/utils/ai-scaffold.js +291 -280
- package/bin/lib/utils/extract-config.js +157 -140
- package/bin/lib/utils/files.js +82 -86
- package/bin/lib/utils/index.js +7 -7
- package/bin/lib/utils/paths.js +34 -34
- package/bin/lib/utils/prompts.js +194 -169
- package/bin/lib/utils/ssl.js +79 -81
- package/browser-extensions/README.md +0 -1
- package/browser-extensions/chrome/background.js +244 -237
- package/browser-extensions/chrome/content.js +32 -29
- package/browser-extensions/chrome/devtools.html +7 -7
- package/browser-extensions/chrome/devtools.js +19 -19
- package/browser-extensions/chrome/inspector.js +802 -767
- package/browser-extensions/chrome/manifest.json +71 -63
- package/browser-extensions/chrome/panel.html +674 -636
- package/browser-extensions/chrome/panel.js +722 -712
- package/browser-extensions/chrome/popup.html +586 -543
- package/browser-extensions/chrome/popup.js +282 -244
- package/browser-extensions/chrome/rules.json +1 -1
- package/browser-extensions/chrome/test-chrome.html +216 -136
- package/browser-extensions/chrome/test-mixed-content.html +284 -189
- package/browser-extensions/chrome/test-uri-pattern.html +221 -198
- package/browser-extensions/firefox/README.md +9 -6
- package/browser-extensions/firefox/background.js +221 -218
- package/browser-extensions/firefox/content.js +55 -52
- package/browser-extensions/firefox/debug-errors.html +386 -228
- package/browser-extensions/firefox/debug-https.html +153 -105
- package/browser-extensions/firefox/devtools.html +7 -7
- package/browser-extensions/firefox/devtools.js +23 -20
- package/browser-extensions/firefox/inspector.js +802 -767
- package/browser-extensions/firefox/manifest.json +68 -68
- package/browser-extensions/firefox/panel.html +674 -636
- package/browser-extensions/firefox/panel.js +722 -712
- package/browser-extensions/firefox/popup.html +572 -535
- package/browser-extensions/firefox/popup.js +281 -236
- package/browser-extensions/firefox/test-gramercy.html +170 -125
- package/browser-extensions/firefox/test-imports.html +59 -55
- package/browser-extensions/firefox/test-masking.html +231 -140
- package/browser-extensions/firefox/test-uri-pattern.html +221 -198
- package/dist/tui/App.d.ts +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +154 -150
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/components/AIPanel.d.ts.map +1 -1
- package/dist/tui/components/AIPanel.js +42 -35
- package/dist/tui/components/AIPanel.js.map +1 -1
- package/dist/tui/components/CommandInput.d.ts +1 -1
- package/dist/tui/components/CommandInput.d.ts.map +1 -1
- package/dist/tui/components/CommandInput.js +92 -62
- package/dist/tui/components/CommandInput.js.map +1 -1
- package/dist/tui/components/GeminiPanel.d.ts.map +1 -1
- package/dist/tui/components/GeminiPanel.js +37 -30
- package/dist/tui/components/GeminiPanel.js.map +1 -1
- package/dist/tui/components/Header.d.ts.map +1 -1
- package/dist/tui/components/Header.js +1 -1
- package/dist/tui/components/Header.js.map +1 -1
- package/dist/tui/components/LogPanel.d.ts +1 -1
- package/dist/tui/components/LogPanel.d.ts.map +1 -1
- package/dist/tui/components/LogPanel.js +26 -24
- package/dist/tui/components/LogPanel.js.map +1 -1
- package/dist/tui/components/TabBar.d.ts +2 -2
- package/dist/tui/components/TabBar.d.ts.map +1 -1
- package/dist/tui/components/TabBar.js +11 -11
- package/dist/tui/components/TabBar.js.map +1 -1
- package/dist/tui/components/WelcomeScreen.d.ts.map +1 -1
- package/dist/tui/components/WelcomeScreen.js +6 -6
- package/dist/tui/components/WelcomeScreen.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +8 -8
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/services/AIService.d.ts +2 -2
- package/dist/tui/services/AIService.d.ts.map +1 -1
- package/dist/tui/services/AIService.js +165 -125
- package/dist/tui/services/AIService.js.map +1 -1
- package/dist/tui/services/ExtensionService.d.ts +1 -1
- package/dist/tui/services/ExtensionService.d.ts.map +1 -1
- package/dist/tui/services/ExtensionService.js +33 -26
- package/dist/tui/services/ExtensionService.js.map +1 -1
- package/dist/tui/services/GeminiService.d.ts +1 -1
- package/dist/tui/services/GeminiService.d.ts.map +1 -1
- package/dist/tui/services/GeminiService.js +87 -76
- package/dist/tui/services/GeminiService.js.map +1 -1
- package/dist/tui/services/ServiceManager.d.ts +3 -3
- package/dist/tui/services/ServiceManager.d.ts.map +1 -1
- package/dist/tui/services/ServiceManager.js +72 -58
- package/dist/tui/services/ServiceManager.js.map +1 -1
- package/dist/tui/services/SocketService.d.ts.map +1 -1
- package/dist/tui/services/SocketService.js +32 -32
- package/dist/tui/services/SocketService.js.map +1 -1
- package/dist/tui/services/ViteService.d.ts.map +1 -1
- package/dist/tui/services/ViteService.js +26 -28
- package/dist/tui/services/ViteService.js.map +1 -1
- package/dist/tui/services/index.d.ts +6 -6
- package/dist/tui/services/index.d.ts.map +1 -1
- package/dist/tui/services/index.js +6 -6
- package/dist/tui/services/index.js.map +1 -1
- package/mcp/gxp-api-server.js +83 -81
- package/package.json +109 -93
- package/runtime/PortalContainer.vue +258 -234
- package/runtime/dev-tools/DevToolsModal.vue +153 -155
- package/runtime/dev-tools/LayoutSwitcher.vue +144 -140
- package/runtime/dev-tools/MockDataEditor.vue +456 -433
- package/runtime/dev-tools/SocketSimulator.vue +379 -371
- package/runtime/dev-tools/StoreInspector.vue +517 -455
- package/runtime/dev-tools/index.js +5 -5
- package/runtime/fallback-layouts/PrivateLayout.vue +2 -2
- package/runtime/fallback-layouts/PublicLayout.vue +2 -2
- package/runtime/fallback-layouts/SystemLayout.vue +2 -2
- package/runtime/gxpStringsPlugin.js +159 -134
- package/runtime/index.html +17 -19
- package/runtime/main.js +24 -22
- package/runtime/mock-api/auth-middleware.js +15 -15
- package/runtime/mock-api/image-generator.js +46 -46
- package/runtime/mock-api/index.js +55 -55
- package/runtime/mock-api/response-generator.js +116 -105
- package/runtime/mock-api/route-generator.js +107 -84
- package/runtime/mock-api/socket-triggers.js +94 -93
- package/runtime/mock-api/spec-loader.js +79 -80
- package/runtime/package.json +3 -0
- package/runtime/server.js +68 -68
- package/runtime/stores/gxpPortalConfigStore.js +204 -186
- package/runtime/stores/index.js +2 -2
- package/runtime/vite-inspector-plugin.js +858 -707
- package/runtime/vite-source-tracker-plugin.js +132 -113
- package/runtime/vite.config.js +191 -139
- package/scripts/launch-chrome.js +41 -41
- package/scripts/pack-chrome.js +38 -39
- package/socket-events/AiSessionMessageCreated.json +17 -17
- package/socket-events/SocialStreamPostCreated.json +23 -23
- package/socket-events/SocialStreamPostVariantCompleted.json +22 -22
- package/template/.claude/agents/gxp-developer.md +100 -99
- package/template/.claude/settings.json +7 -7
- package/template/AGENTS.md +30 -23
- package/template/GEMINI.md +20 -20
- package/template/README.md +70 -53
- package/template/app-manifest.json +2 -4
- package/template/configuration.json +10 -10
- package/template/default-styling.css +1 -1
- package/template/index.html +18 -20
- package/template/main.js +24 -22
- package/template/src/DemoPage.vue +415 -362
- package/template/src/Plugin.vue +76 -85
- package/template/src/stores/index.js +3 -3
- package/template/src/stores/test-data.json +164 -172
- package/template/theme-layouts/AdditionalStyling.css +50 -50
- package/template/theme-layouts/PrivateLayout.vue +8 -12
- package/template/theme-layouts/PublicLayout.vue +8 -12
- package/template/theme-layouts/SystemLayout.vue +8 -12
- package/template/vite.extend.js +45 -0
- package/template/vite.config.js +0 -409
package/runtime/main.js
CHANGED
|
@@ -1,40 +1,42 @@
|
|
|
1
|
-
import { createApp } from "vue"
|
|
2
|
-
import * as Vue from "vue"
|
|
3
|
-
import * as Pinia from "pinia"
|
|
4
|
-
import { createPinia, setActivePinia } from "pinia"
|
|
1
|
+
import { createApp } from "vue"
|
|
2
|
+
import * as Vue from "vue"
|
|
3
|
+
import * as Pinia from "pinia"
|
|
4
|
+
import { createPinia, setActivePinia } from "pinia"
|
|
5
5
|
|
|
6
6
|
// Create and configure Pinia before any store imports
|
|
7
|
-
const pinia = createPinia()
|
|
8
|
-
setActivePinia(pinia)
|
|
7
|
+
const pinia = createPinia()
|
|
8
|
+
setActivePinia(pinia)
|
|
9
9
|
|
|
10
10
|
// Expose Vue and Pinia to window for dynamically loaded plugins
|
|
11
|
-
window.Vue = Vue
|
|
12
|
-
window.Pinia = Pinia
|
|
13
|
-
window.pinia = pinia
|
|
11
|
+
window.Vue = Vue
|
|
12
|
+
window.Pinia = Pinia
|
|
13
|
+
window.pinia = pinia
|
|
14
14
|
|
|
15
15
|
// Dynamic imports ensure pinia is set up before stores load
|
|
16
16
|
async function init() {
|
|
17
|
-
const { default: App } = await import("@gx-runtime/PortalContainer.vue")
|
|
18
|
-
const { useGxpStore } = await import("@/stores/index.js")
|
|
19
|
-
const { createGxpStringsPlugin } =
|
|
17
|
+
const { default: App } = await import("@gx-runtime/PortalContainer.vue")
|
|
18
|
+
const { useGxpStore } = await import("@/stores/index.js")
|
|
19
|
+
const { createGxpStringsPlugin } =
|
|
20
|
+
await import("@gx-runtime/gxpStringsPlugin.js")
|
|
20
21
|
|
|
21
|
-
window.useGxpStore = useGxpStore
|
|
22
|
+
window.useGxpStore = useGxpStore
|
|
22
23
|
|
|
23
|
-
const app = createApp(App)
|
|
24
|
-
app.use(pinia)
|
|
24
|
+
const app = createApp(App)
|
|
25
|
+
app.use(pinia)
|
|
25
26
|
|
|
26
|
-
const gxpStore = useGxpStore()
|
|
27
|
+
const gxpStore = useGxpStore()
|
|
27
28
|
|
|
28
29
|
// Build the dev server base URL so gxp-src default paths resolve to the
|
|
29
30
|
// local dev server instead of the current domain (important when the app
|
|
30
31
|
// is injected into the cloud platform via browser extension).
|
|
31
|
-
const devProtocol =
|
|
32
|
-
|
|
33
|
-
const
|
|
32
|
+
const devProtocol =
|
|
33
|
+
import.meta.env.VITE_USE_HTTPS !== "false" ? "https" : "http"
|
|
34
|
+
const devPort = import.meta.env.VITE_NODE_PORT || "3060"
|
|
35
|
+
const devServerBaseUrl = `${devProtocol}://localhost:${devPort}`
|
|
34
36
|
|
|
35
|
-
app.use(createGxpStringsPlugin(gxpStore, { devServerBaseUrl }))
|
|
37
|
+
app.use(createGxpStringsPlugin(gxpStore, { devServerBaseUrl }))
|
|
36
38
|
|
|
37
|
-
app.mount("#app")
|
|
39
|
+
app.mount("#app")
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
init()
|
|
42
|
+
init()
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* @param {function} next - Next middleware
|
|
13
13
|
*/
|
|
14
14
|
function authMiddleware(req, res, next) {
|
|
15
|
-
const auth = req.headers.authorization
|
|
15
|
+
const auth = req.headers.authorization
|
|
16
16
|
|
|
17
17
|
// Check if Authorization header exists
|
|
18
18
|
if (!auth) {
|
|
@@ -20,7 +20,7 @@ function authMiddleware(req, res, next) {
|
|
|
20
20
|
error: "Unauthorized",
|
|
21
21
|
message: "Missing Authorization header",
|
|
22
22
|
hint: "Include 'Authorization: Bearer <token>' header",
|
|
23
|
-
})
|
|
23
|
+
})
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
// Check Bearer token format
|
|
@@ -29,11 +29,11 @@ function authMiddleware(req, res, next) {
|
|
|
29
29
|
error: "Unauthorized",
|
|
30
30
|
message: "Invalid Authorization format",
|
|
31
31
|
hint: "Use 'Bearer <token>' format",
|
|
32
|
-
})
|
|
32
|
+
})
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Extract token
|
|
36
|
-
const token = auth.slice(7).trim()
|
|
36
|
+
const token = auth.slice(7).trim()
|
|
37
37
|
|
|
38
38
|
// Check token is not empty
|
|
39
39
|
if (!token) {
|
|
@@ -41,14 +41,14 @@ function authMiddleware(req, res, next) {
|
|
|
41
41
|
error: "Unauthorized",
|
|
42
42
|
message: "Empty token",
|
|
43
43
|
hint: "Provide a non-empty token after 'Bearer '",
|
|
44
|
-
})
|
|
44
|
+
})
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// Token format is valid, attach to request for potential use
|
|
48
|
-
req.mockToken = token
|
|
48
|
+
req.mockToken = token
|
|
49
49
|
|
|
50
50
|
// Continue to next middleware/handler
|
|
51
|
-
next()
|
|
51
|
+
next()
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -58,13 +58,13 @@ function authMiddleware(req, res, next) {
|
|
|
58
58
|
* @param {function} next - Next middleware
|
|
59
59
|
*/
|
|
60
60
|
function optionalAuthMiddleware(req, res, next) {
|
|
61
|
-
const auth = req.headers.authorization
|
|
61
|
+
const auth = req.headers.authorization
|
|
62
62
|
|
|
63
63
|
if (auth && auth.startsWith("Bearer ")) {
|
|
64
|
-
req.mockToken = auth.slice(7).trim()
|
|
64
|
+
req.mockToken = auth.slice(7).trim()
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
next()
|
|
67
|
+
next()
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
@@ -74,24 +74,24 @@ function optionalAuthMiddleware(req, res, next) {
|
|
|
74
74
|
*/
|
|
75
75
|
function createAuthMiddleware(operation) {
|
|
76
76
|
// Check if operation has security requirements
|
|
77
|
-
const security = operation.security
|
|
77
|
+
const security = operation.security
|
|
78
78
|
|
|
79
79
|
// If security is explicitly empty array, no auth required
|
|
80
80
|
if (Array.isArray(security) && security.length === 0) {
|
|
81
|
-
return optionalAuthMiddleware
|
|
81
|
+
return optionalAuthMiddleware
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
// If security is defined, require auth
|
|
85
85
|
if (security && security.length > 0) {
|
|
86
|
-
return authMiddleware
|
|
86
|
+
return authMiddleware
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// Default: require auth (safer default for mock API)
|
|
90
|
-
return authMiddleware
|
|
90
|
+
return authMiddleware
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
module.exports = {
|
|
94
94
|
authMiddleware,
|
|
95
95
|
optionalAuthMiddleware,
|
|
96
96
|
createAuthMiddleware,
|
|
97
|
-
}
|
|
97
|
+
}
|
|
@@ -21,9 +21,9 @@ function randomColor() {
|
|
|
21
21
|
"#e91e63", // Pink
|
|
22
22
|
"#00bcd4", // Cyan
|
|
23
23
|
"#ff5722", // Deep orange
|
|
24
|
-
]
|
|
24
|
+
]
|
|
25
25
|
|
|
26
|
-
return colors[Math.floor(Math.random() * colors.length)]
|
|
26
|
+
return colors[Math.floor(Math.random() * colors.length)]
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
@@ -33,17 +33,17 @@ function randomColor() {
|
|
|
33
33
|
*/
|
|
34
34
|
function getContrastColor(hexColor) {
|
|
35
35
|
// Remove # if present
|
|
36
|
-
const hex = hexColor.replace("#", "")
|
|
36
|
+
const hex = hexColor.replace("#", "")
|
|
37
37
|
|
|
38
38
|
// Convert to RGB
|
|
39
|
-
const r = parseInt(hex.substr(0, 2), 16)
|
|
40
|
-
const g = parseInt(hex.substr(2, 2), 16)
|
|
41
|
-
const b = parseInt(hex.substr(4, 2), 16)
|
|
39
|
+
const r = parseInt(hex.substr(0, 2), 16)
|
|
40
|
+
const g = parseInt(hex.substr(2, 2), 16)
|
|
41
|
+
const b = parseInt(hex.substr(4, 2), 16)
|
|
42
42
|
|
|
43
43
|
// Calculate luminance
|
|
44
|
-
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
|
44
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255
|
|
45
45
|
|
|
46
|
-
return luminance > 0.5 ? "#000000" : "#ffffff"
|
|
46
|
+
return luminance > 0.5 ? "#000000" : "#ffffff"
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
@@ -52,25 +52,25 @@ function getContrastColor(hexColor) {
|
|
|
52
52
|
* @returns {string} Valid hex color
|
|
53
53
|
*/
|
|
54
54
|
function parseColor(color) {
|
|
55
|
-
if (!color) return randomColor()
|
|
55
|
+
if (!color) return randomColor()
|
|
56
56
|
|
|
57
57
|
// Remove # if present
|
|
58
|
-
let hex = color.replace("#", "")
|
|
58
|
+
let hex = color.replace("#", "")
|
|
59
59
|
|
|
60
60
|
// Expand 3-digit hex
|
|
61
61
|
if (hex.length === 3) {
|
|
62
62
|
hex = hex
|
|
63
63
|
.split("")
|
|
64
64
|
.map((c) => c + c)
|
|
65
|
-
.join("")
|
|
65
|
+
.join("")
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
// Validate
|
|
69
69
|
if (/^[0-9a-fA-F]{6}$/.test(hex)) {
|
|
70
|
-
return `#${hex}
|
|
70
|
+
return `#${hex}`
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
return randomColor()
|
|
73
|
+
return randomColor()
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
/**
|
|
@@ -85,17 +85,17 @@ function parseColor(color) {
|
|
|
85
85
|
* @returns {string} SVG string
|
|
86
86
|
*/
|
|
87
87
|
function generateSvg(width, height, options = {}) {
|
|
88
|
-
const bgColor = parseColor(options.color)
|
|
89
|
-
const textColor = options.textColor || getContrastColor(bgColor)
|
|
90
|
-
const text = options.text || `${width}×${height}
|
|
88
|
+
const bgColor = parseColor(options.color)
|
|
89
|
+
const textColor = options.textColor || getContrastColor(bgColor)
|
|
90
|
+
const text = options.text || `${width}×${height}`
|
|
91
91
|
|
|
92
92
|
// Calculate font size based on dimensions
|
|
93
|
-
const minDim = Math.min(width, height)
|
|
94
|
-
const fontSize = options.fontSize || Math.max(12, Math.floor(minDim / 8))
|
|
93
|
+
const minDim = Math.min(width, height)
|
|
94
|
+
const fontSize = options.fontSize || Math.max(12, Math.floor(minDim / 8))
|
|
95
95
|
|
|
96
96
|
// Calculate text position
|
|
97
|
-
const textX = width / 2
|
|
98
|
-
const textY = height / 2
|
|
97
|
+
const textX = width / 2
|
|
98
|
+
const textY = height / 2
|
|
99
99
|
|
|
100
100
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
101
101
|
<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
@@ -109,7 +109,7 @@ function generateSvg(width, height, options = {}) {
|
|
|
109
109
|
text-anchor="middle"
|
|
110
110
|
dominant-baseline="middle"
|
|
111
111
|
>${escapeXml(text)}</text>
|
|
112
|
-
</svg
|
|
112
|
+
</svg>`
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
/**
|
|
@@ -123,7 +123,7 @@ function escapeXml(text) {
|
|
|
123
123
|
.replace(/</g, "<")
|
|
124
124
|
.replace(/>/g, ">")
|
|
125
125
|
.replace(/"/g, """)
|
|
126
|
-
.replace(/'/g, "'")
|
|
126
|
+
.replace(/'/g, "'")
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/**
|
|
@@ -133,25 +133,25 @@ function escapeXml(text) {
|
|
|
133
133
|
*/
|
|
134
134
|
function parseDimensions(dimStr) {
|
|
135
135
|
if (!dimStr) {
|
|
136
|
-
return { width: 400, height: 300 }
|
|
136
|
+
return { width: 400, height: 300 }
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
// Try width x height format
|
|
140
|
-
const match = dimStr.match(/^(\d+)[x×:](\d+)$/i)
|
|
140
|
+
const match = dimStr.match(/^(\d+)[x×:](\d+)$/i)
|
|
141
141
|
if (match) {
|
|
142
142
|
return {
|
|
143
143
|
width: parseInt(match[1], 10),
|
|
144
144
|
height: parseInt(match[2], 10),
|
|
145
|
-
}
|
|
145
|
+
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// Single number = square
|
|
149
|
-
const single = parseInt(dimStr, 10)
|
|
149
|
+
const single = parseInt(dimStr, 10)
|
|
150
150
|
if (!isNaN(single)) {
|
|
151
|
-
return { width: single, height: single }
|
|
151
|
+
return { width: single, height: single }
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
return { width: 400, height: 300 }
|
|
154
|
+
return { width: 400, height: 300 }
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
/**
|
|
@@ -161,24 +161,24 @@ function parseDimensions(dimStr) {
|
|
|
161
161
|
*/
|
|
162
162
|
function imageHandler(req, res) {
|
|
163
163
|
// Parse dimensions from URL
|
|
164
|
-
const { width: widthParam, height: heightParam } = req.params
|
|
164
|
+
const { width: widthParam, height: heightParam } = req.params
|
|
165
165
|
|
|
166
|
-
let width, height
|
|
166
|
+
let width, height
|
|
167
167
|
|
|
168
168
|
if (heightParam) {
|
|
169
169
|
// /image/:width/:height format
|
|
170
|
-
width = parseInt(widthParam, 10) || 400
|
|
171
|
-
height = parseInt(heightParam, 10) || 300
|
|
170
|
+
width = parseInt(widthParam, 10) || 400
|
|
171
|
+
height = parseInt(heightParam, 10) || 300
|
|
172
172
|
} else {
|
|
173
173
|
// /image/:dimensions format (e.g., 400x300)
|
|
174
|
-
const dims = parseDimensions(widthParam)
|
|
175
|
-
width = dims.width
|
|
176
|
-
height = dims.height
|
|
174
|
+
const dims = parseDimensions(widthParam)
|
|
175
|
+
width = dims.width
|
|
176
|
+
height = dims.height
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
// Clamp dimensions
|
|
180
|
-
width = Math.min(Math.max(width, 1), 4000)
|
|
181
|
-
height = Math.min(Math.max(height, 1), 4000)
|
|
180
|
+
width = Math.min(Math.max(width, 1), 4000)
|
|
181
|
+
height = Math.min(Math.max(height, 1), 4000)
|
|
182
182
|
|
|
183
183
|
// Parse options from query string
|
|
184
184
|
const options = {
|
|
@@ -186,15 +186,15 @@ function imageHandler(req, res) {
|
|
|
186
186
|
text: req.query.text,
|
|
187
187
|
textColor: req.query.textColor || req.query.fg,
|
|
188
188
|
fontSize: req.query.fontSize ? parseInt(req.query.fontSize, 10) : undefined,
|
|
189
|
-
}
|
|
189
|
+
}
|
|
190
190
|
|
|
191
191
|
// Generate SVG
|
|
192
|
-
const svg = generateSvg(width, height, options)
|
|
192
|
+
const svg = generateSvg(width, height, options)
|
|
193
193
|
|
|
194
194
|
// Send response
|
|
195
|
-
res.set("Content-Type", "image/svg+xml")
|
|
196
|
-
res.set("Cache-Control", "public, max-age=86400")
|
|
197
|
-
res.send(svg)
|
|
195
|
+
res.set("Content-Type", "image/svg+xml")
|
|
196
|
+
res.set("Cache-Control", "public, max-age=86400") // Cache for 24 hours
|
|
197
|
+
res.send(svg)
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/**
|
|
@@ -205,9 +205,9 @@ function imageHandler(req, res) {
|
|
|
205
205
|
* @returns {string} Data URL
|
|
206
206
|
*/
|
|
207
207
|
function generateDataUrl(width, height, options = {}) {
|
|
208
|
-
const svg = generateSvg(width, height, options)
|
|
209
|
-
const base64 = Buffer.from(svg).toString("base64")
|
|
210
|
-
return `data:image/svg+xml;base64,${base64}
|
|
208
|
+
const svg = generateSvg(width, height, options)
|
|
209
|
+
const base64 = Buffer.from(svg).toString("base64")
|
|
210
|
+
return `data:image/svg+xml;base64,${base64}`
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
module.exports = {
|
|
@@ -218,4 +218,4 @@ module.exports = {
|
|
|
218
218
|
generateDataUrl,
|
|
219
219
|
randomColor,
|
|
220
220
|
getContrastColor,
|
|
221
|
-
}
|
|
221
|
+
}
|
|
@@ -5,21 +5,21 @@
|
|
|
5
5
|
* Creates an Express router that mounts onto the existing server.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
const express = require("express")
|
|
8
|
+
const express = require("express")
|
|
9
9
|
const {
|
|
10
10
|
loadSpecs,
|
|
11
11
|
refreshSpecs,
|
|
12
12
|
getCacheStatus,
|
|
13
13
|
getCachedSpecs,
|
|
14
|
-
} = require("./spec-loader")
|
|
15
|
-
const { generateRoutes, getRouteStats } = require("./route-generator")
|
|
16
|
-
const { parseSocketTriggers, getTriggerStats } = require("./socket-triggers")
|
|
17
|
-
const { imageHandler } = require("./image-generator")
|
|
14
|
+
} = require("./spec-loader")
|
|
15
|
+
const { generateRoutes, getRouteStats } = require("./route-generator")
|
|
16
|
+
const { parseSocketTriggers, getTriggerStats } = require("./socket-triggers")
|
|
17
|
+
const { imageHandler } = require("./image-generator")
|
|
18
18
|
|
|
19
19
|
// Store state for status endpoint
|
|
20
|
-
let currentSpecs = null
|
|
21
|
-
let currentSocketTriggers = null
|
|
22
|
-
let routeStats = null
|
|
20
|
+
let currentSpecs = null
|
|
21
|
+
let currentSocketTriggers = null
|
|
22
|
+
let routeStats = null
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Create the mock API router
|
|
@@ -29,40 +29,40 @@ let routeStats = null;
|
|
|
29
29
|
* @returns {express.Router} Express router
|
|
30
30
|
*/
|
|
31
31
|
async function createMockApiRouter(io, options = {}) {
|
|
32
|
-
const router = express.Router()
|
|
33
|
-
const projectRoot = options.projectRoot || process.cwd()
|
|
32
|
+
const router = express.Router()
|
|
33
|
+
const projectRoot = options.projectRoot || process.cwd()
|
|
34
34
|
|
|
35
|
-
console.log("\n🎭 Initializing Mock API Server...")
|
|
35
|
+
console.log("\n🎭 Initializing Mock API Server...")
|
|
36
36
|
|
|
37
37
|
// Load specs
|
|
38
|
-
const specs = await loadSpecs(projectRoot)
|
|
39
|
-
currentSpecs = specs
|
|
38
|
+
const specs = await loadSpecs(projectRoot)
|
|
39
|
+
currentSpecs = specs
|
|
40
40
|
|
|
41
41
|
// Parse socket triggers from AsyncAPI
|
|
42
42
|
if (specs.asyncApi) {
|
|
43
|
-
currentSocketTriggers = parseSocketTriggers(specs.asyncApi)
|
|
43
|
+
currentSocketTriggers = parseSocketTriggers(specs.asyncApi)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// Generate routes from OpenAPI
|
|
47
47
|
if (specs.openApi) {
|
|
48
|
-
console.log("\n📍 Generating mock routes from OpenAPI spec:")
|
|
48
|
+
console.log("\n📍 Generating mock routes from OpenAPI spec:")
|
|
49
49
|
const apiRouter = generateRoutes(specs.openApi, {
|
|
50
50
|
io,
|
|
51
51
|
socketTriggers: currentSocketTriggers,
|
|
52
|
-
})
|
|
53
|
-
routeStats = getRouteStats(specs.openApi)
|
|
52
|
+
})
|
|
53
|
+
routeStats = getRouteStats(specs.openApi)
|
|
54
54
|
|
|
55
55
|
// Mount API routes under /api
|
|
56
|
-
router.use("/api", apiRouter)
|
|
56
|
+
router.use("/api", apiRouter)
|
|
57
57
|
} else {
|
|
58
|
-
console.log("⚠️ No OpenAPI spec available, mock API routes not generated")
|
|
59
|
-
routeStats = { total: 0, byMethod: {}, paths: [] }
|
|
58
|
+
console.log("⚠️ No OpenAPI spec available, mock API routes not generated")
|
|
59
|
+
routeStats = { total: 0, byMethod: {}, paths: [] }
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Status endpoint
|
|
63
63
|
router.get("/_mock/status", (req, res) => {
|
|
64
|
-
const cacheStatus = getCacheStatus()
|
|
65
|
-
const triggerStats = getTriggerStats(currentSocketTriggers)
|
|
64
|
+
const cacheStatus = getCacheStatus()
|
|
65
|
+
const triggerStats = getTriggerStats(currentSocketTriggers)
|
|
66
66
|
|
|
67
67
|
res.json({
|
|
68
68
|
enabled: true,
|
|
@@ -75,25 +75,25 @@ async function createMockApiRouter(io, options = {}) {
|
|
|
75
75
|
routes: routeStats,
|
|
76
76
|
socketTriggers: triggerStats,
|
|
77
77
|
cache: cacheStatus,
|
|
78
|
-
})
|
|
79
|
-
})
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
80
|
|
|
81
81
|
// Refresh endpoint
|
|
82
82
|
router.post("/_mock/refresh", async (req, res) => {
|
|
83
|
-
console.log("\n🔄 Refreshing mock API specs...")
|
|
83
|
+
console.log("\n🔄 Refreshing mock API specs...")
|
|
84
84
|
|
|
85
85
|
try {
|
|
86
|
-
const newSpecs = await refreshSpecs(projectRoot)
|
|
87
|
-
currentSpecs = newSpecs
|
|
86
|
+
const newSpecs = await refreshSpecs(projectRoot)
|
|
87
|
+
currentSpecs = newSpecs
|
|
88
88
|
|
|
89
89
|
// Re-parse socket triggers
|
|
90
90
|
if (newSpecs.asyncApi) {
|
|
91
|
-
currentSocketTriggers = parseSocketTriggers(newSpecs.asyncApi)
|
|
91
|
+
currentSocketTriggers = parseSocketTriggers(newSpecs.asyncApi)
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// Update route stats
|
|
95
95
|
if (newSpecs.openApi) {
|
|
96
|
-
routeStats = getRouteStats(newSpecs.openApi)
|
|
96
|
+
routeStats = getRouteStats(newSpecs.openApi)
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
res.json({
|
|
@@ -104,19 +104,19 @@ async function createMockApiRouter(io, options = {}) {
|
|
|
104
104
|
asyncApi: !!newSpecs.asyncApi,
|
|
105
105
|
webhooks: !!newSpecs.webhooks,
|
|
106
106
|
},
|
|
107
|
-
})
|
|
107
|
+
})
|
|
108
108
|
} catch (error) {
|
|
109
|
-
console.error("❌ Failed to refresh specs:", error.message)
|
|
109
|
+
console.error("❌ Failed to refresh specs:", error.message)
|
|
110
110
|
res.status(500).json({
|
|
111
111
|
success: false,
|
|
112
112
|
error: error.message,
|
|
113
|
-
})
|
|
113
|
+
})
|
|
114
114
|
}
|
|
115
|
-
})
|
|
115
|
+
})
|
|
116
116
|
|
|
117
117
|
// Image generation endpoints
|
|
118
|
-
router.get("/_mock/image/:width/:height", imageHandler)
|
|
119
|
-
router.get("/_mock/image/:width", imageHandler)
|
|
118
|
+
router.get("/_mock/image/:width/:height", imageHandler)
|
|
119
|
+
router.get("/_mock/image/:width", imageHandler) // Square or WxH format
|
|
120
120
|
|
|
121
121
|
// Info endpoint
|
|
122
122
|
router.get("/_mock/info", (req, res) => {
|
|
@@ -135,43 +135,43 @@ async function createMockApiRouter(io, options = {}) {
|
|
|
135
135
|
MOCK_API_DELAY: process.env.MOCK_API_DELAY || "0",
|
|
136
136
|
MOCK_API_CACHE_TTL: process.env.MOCK_API_CACHE_TTL || "300000",
|
|
137
137
|
},
|
|
138
|
-
})
|
|
139
|
-
})
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
140
|
|
|
141
141
|
// Spec endpoints (for debugging)
|
|
142
142
|
router.get("/_mock/specs/openapi", (req, res) => {
|
|
143
143
|
if (currentSpecs?.openApi) {
|
|
144
|
-
res.json(currentSpecs.openApi)
|
|
144
|
+
res.json(currentSpecs.openApi)
|
|
145
145
|
} else {
|
|
146
|
-
res.status(404).json({ error: "OpenAPI spec not loaded" })
|
|
146
|
+
res.status(404).json({ error: "OpenAPI spec not loaded" })
|
|
147
147
|
}
|
|
148
|
-
})
|
|
148
|
+
})
|
|
149
149
|
|
|
150
150
|
router.get("/_mock/specs/asyncapi", (req, res) => {
|
|
151
151
|
if (currentSpecs?.asyncApi) {
|
|
152
|
-
res.json(currentSpecs.asyncApi)
|
|
152
|
+
res.json(currentSpecs.asyncApi)
|
|
153
153
|
} else {
|
|
154
|
-
res.status(404).json({ error: "AsyncAPI spec not loaded" })
|
|
154
|
+
res.status(404).json({ error: "AsyncAPI spec not loaded" })
|
|
155
155
|
}
|
|
156
|
-
})
|
|
156
|
+
})
|
|
157
157
|
|
|
158
158
|
router.get("/_mock/specs/webhooks", (req, res) => {
|
|
159
159
|
if (currentSpecs?.webhooks) {
|
|
160
|
-
res.json(currentSpecs.webhooks)
|
|
160
|
+
res.json(currentSpecs.webhooks)
|
|
161
161
|
} else {
|
|
162
|
-
res.status(404).json({ error: "Webhook spec not loaded" })
|
|
162
|
+
res.status(404).json({ error: "Webhook spec not loaded" })
|
|
163
163
|
}
|
|
164
|
-
})
|
|
164
|
+
})
|
|
165
165
|
|
|
166
|
-
console.log("\n✅ Mock API Server initialized")
|
|
167
|
-
console.log(" Status: GET /_mock/status")
|
|
168
|
-
console.log(" Refresh: POST /_mock/refresh")
|
|
169
|
-
console.log(" Images: GET /_mock/image/:width/:height")
|
|
166
|
+
console.log("\n✅ Mock API Server initialized")
|
|
167
|
+
console.log(" Status: GET /_mock/status")
|
|
168
|
+
console.log(" Refresh: POST /_mock/refresh")
|
|
169
|
+
console.log(" Images: GET /_mock/image/:width/:height")
|
|
170
170
|
if (routeStats?.total > 0) {
|
|
171
|
-
console.log(` API Routes: ${routeStats.total} endpoints under /api/*`)
|
|
171
|
+
console.log(` API Routes: ${routeStats.total} endpoints under /api/*`)
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
return router
|
|
174
|
+
return router
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
/**
|
|
@@ -179,7 +179,7 @@ async function createMockApiRouter(io, options = {}) {
|
|
|
179
179
|
* @returns {object} Current specs
|
|
180
180
|
*/
|
|
181
181
|
function getSpecs() {
|
|
182
|
-
return currentSpecs
|
|
182
|
+
return currentSpecs
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
/**
|
|
@@ -187,11 +187,11 @@ function getSpecs() {
|
|
|
187
187
|
* @returns {object} Current socket triggers
|
|
188
188
|
*/
|
|
189
189
|
function getSocketTriggers() {
|
|
190
|
-
return currentSocketTriggers
|
|
190
|
+
return currentSocketTriggers
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
module.exports = {
|
|
194
194
|
createMockApiRouter,
|
|
195
195
|
getSpecs,
|
|
196
196
|
getSocketTriggers,
|
|
197
|
-
}
|
|
197
|
+
}
|