@gxp-dev/tools 2.0.62 → 2.0.64

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.
Files changed (182) hide show
  1. package/README.md +32 -31
  2. package/bin/gx-devtools.js +74 -54
  3. package/bin/lib/cli.js +23 -21
  4. package/bin/lib/commands/add-dependency.js +366 -325
  5. package/bin/lib/commands/assets.js +137 -139
  6. package/bin/lib/commands/build.js +169 -174
  7. package/bin/lib/commands/datastore.js +181 -183
  8. package/bin/lib/commands/dev.js +127 -131
  9. package/bin/lib/commands/extensions.js +147 -149
  10. package/bin/lib/commands/extract-config.js +73 -67
  11. package/bin/lib/commands/index.js +12 -12
  12. package/bin/lib/commands/init.js +342 -240
  13. package/bin/lib/commands/publish.js +69 -75
  14. package/bin/lib/commands/socket.js +69 -69
  15. package/bin/lib/commands/ssl.js +14 -14
  16. package/bin/lib/constants.js +10 -24
  17. package/bin/lib/tui/App.tsx +761 -705
  18. package/bin/lib/tui/components/AIPanel.tsx +191 -171
  19. package/bin/lib/tui/components/CommandInput.tsx +394 -343
  20. package/bin/lib/tui/components/GeminiPanel.tsx +175 -151
  21. package/bin/lib/tui/components/Header.tsx +23 -21
  22. package/bin/lib/tui/components/LogPanel.tsx +244 -220
  23. package/bin/lib/tui/components/TabBar.tsx +50 -48
  24. package/bin/lib/tui/components/WelcomeScreen.tsx +126 -71
  25. package/bin/lib/tui/index.tsx +37 -39
  26. package/bin/lib/tui/services/AIService.ts +518 -462
  27. package/bin/lib/tui/services/ExtensionService.ts +140 -129
  28. package/bin/lib/tui/services/GeminiService.ts +367 -337
  29. package/bin/lib/tui/services/ServiceManager.ts +344 -322
  30. package/bin/lib/tui/services/SocketService.ts +168 -168
  31. package/bin/lib/tui/services/ViteService.ts +88 -88
  32. package/bin/lib/tui/services/index.ts +47 -22
  33. package/bin/lib/utils/ai-scaffold.js +291 -280
  34. package/bin/lib/utils/extract-config.js +157 -140
  35. package/bin/lib/utils/files.js +82 -86
  36. package/bin/lib/utils/index.js +7 -7
  37. package/bin/lib/utils/paths.js +34 -34
  38. package/bin/lib/utils/prompts.js +194 -169
  39. package/bin/lib/utils/ssl.js +79 -81
  40. package/browser-extensions/README.md +0 -1
  41. package/browser-extensions/chrome/background.js +244 -237
  42. package/browser-extensions/chrome/content.js +32 -29
  43. package/browser-extensions/chrome/devtools.html +7 -7
  44. package/browser-extensions/chrome/devtools.js +19 -19
  45. package/browser-extensions/chrome/inspector.js +802 -767
  46. package/browser-extensions/chrome/manifest.json +71 -63
  47. package/browser-extensions/chrome/panel.html +674 -636
  48. package/browser-extensions/chrome/panel.js +722 -712
  49. package/browser-extensions/chrome/popup.html +586 -543
  50. package/browser-extensions/chrome/popup.js +282 -244
  51. package/browser-extensions/chrome/rules.json +1 -1
  52. package/browser-extensions/chrome/test-chrome.html +216 -136
  53. package/browser-extensions/chrome/test-mixed-content.html +284 -189
  54. package/browser-extensions/chrome/test-uri-pattern.html +221 -198
  55. package/browser-extensions/firefox/README.md +9 -6
  56. package/browser-extensions/firefox/background.js +221 -218
  57. package/browser-extensions/firefox/content.js +55 -52
  58. package/browser-extensions/firefox/debug-errors.html +386 -228
  59. package/browser-extensions/firefox/debug-https.html +153 -105
  60. package/browser-extensions/firefox/devtools.html +7 -7
  61. package/browser-extensions/firefox/devtools.js +23 -20
  62. package/browser-extensions/firefox/inspector.js +802 -767
  63. package/browser-extensions/firefox/manifest.json +68 -68
  64. package/browser-extensions/firefox/panel.html +674 -636
  65. package/browser-extensions/firefox/panel.js +722 -712
  66. package/browser-extensions/firefox/popup.html +572 -535
  67. package/browser-extensions/firefox/popup.js +281 -236
  68. package/browser-extensions/firefox/test-gramercy.html +170 -125
  69. package/browser-extensions/firefox/test-imports.html +59 -55
  70. package/browser-extensions/firefox/test-masking.html +231 -140
  71. package/browser-extensions/firefox/test-uri-pattern.html +221 -198
  72. package/dist/tui/App.d.ts +1 -1
  73. package/dist/tui/App.d.ts.map +1 -1
  74. package/dist/tui/App.js +154 -150
  75. package/dist/tui/App.js.map +1 -1
  76. package/dist/tui/components/AIPanel.d.ts.map +1 -1
  77. package/dist/tui/components/AIPanel.js +42 -35
  78. package/dist/tui/components/AIPanel.js.map +1 -1
  79. package/dist/tui/components/CommandInput.d.ts +1 -1
  80. package/dist/tui/components/CommandInput.d.ts.map +1 -1
  81. package/dist/tui/components/CommandInput.js +92 -62
  82. package/dist/tui/components/CommandInput.js.map +1 -1
  83. package/dist/tui/components/GeminiPanel.d.ts.map +1 -1
  84. package/dist/tui/components/GeminiPanel.js +37 -30
  85. package/dist/tui/components/GeminiPanel.js.map +1 -1
  86. package/dist/tui/components/Header.d.ts.map +1 -1
  87. package/dist/tui/components/Header.js +1 -1
  88. package/dist/tui/components/Header.js.map +1 -1
  89. package/dist/tui/components/LogPanel.d.ts +1 -1
  90. package/dist/tui/components/LogPanel.d.ts.map +1 -1
  91. package/dist/tui/components/LogPanel.js +26 -24
  92. package/dist/tui/components/LogPanel.js.map +1 -1
  93. package/dist/tui/components/TabBar.d.ts +2 -2
  94. package/dist/tui/components/TabBar.d.ts.map +1 -1
  95. package/dist/tui/components/TabBar.js +11 -11
  96. package/dist/tui/components/TabBar.js.map +1 -1
  97. package/dist/tui/components/WelcomeScreen.d.ts.map +1 -1
  98. package/dist/tui/components/WelcomeScreen.js +6 -6
  99. package/dist/tui/components/WelcomeScreen.js.map +1 -1
  100. package/dist/tui/index.d.ts.map +1 -1
  101. package/dist/tui/index.js +8 -8
  102. package/dist/tui/index.js.map +1 -1
  103. package/dist/tui/services/AIService.d.ts +2 -2
  104. package/dist/tui/services/AIService.d.ts.map +1 -1
  105. package/dist/tui/services/AIService.js +165 -125
  106. package/dist/tui/services/AIService.js.map +1 -1
  107. package/dist/tui/services/ExtensionService.d.ts +1 -1
  108. package/dist/tui/services/ExtensionService.d.ts.map +1 -1
  109. package/dist/tui/services/ExtensionService.js +33 -26
  110. package/dist/tui/services/ExtensionService.js.map +1 -1
  111. package/dist/tui/services/GeminiService.d.ts +1 -1
  112. package/dist/tui/services/GeminiService.d.ts.map +1 -1
  113. package/dist/tui/services/GeminiService.js +87 -76
  114. package/dist/tui/services/GeminiService.js.map +1 -1
  115. package/dist/tui/services/ServiceManager.d.ts +3 -3
  116. package/dist/tui/services/ServiceManager.d.ts.map +1 -1
  117. package/dist/tui/services/ServiceManager.js +72 -58
  118. package/dist/tui/services/ServiceManager.js.map +1 -1
  119. package/dist/tui/services/SocketService.d.ts.map +1 -1
  120. package/dist/tui/services/SocketService.js +32 -32
  121. package/dist/tui/services/SocketService.js.map +1 -1
  122. package/dist/tui/services/ViteService.d.ts.map +1 -1
  123. package/dist/tui/services/ViteService.js +26 -28
  124. package/dist/tui/services/ViteService.js.map +1 -1
  125. package/dist/tui/services/index.d.ts +6 -6
  126. package/dist/tui/services/index.d.ts.map +1 -1
  127. package/dist/tui/services/index.js +6 -6
  128. package/dist/tui/services/index.js.map +1 -1
  129. package/mcp/gxp-api-server.js +83 -81
  130. package/package.json +109 -93
  131. package/runtime/PortalContainer.vue +258 -234
  132. package/runtime/dev-tools/DevToolsModal.vue +153 -155
  133. package/runtime/dev-tools/LayoutSwitcher.vue +144 -140
  134. package/runtime/dev-tools/MockDataEditor.vue +456 -433
  135. package/runtime/dev-tools/SocketSimulator.vue +379 -371
  136. package/runtime/dev-tools/StoreInspector.vue +517 -455
  137. package/runtime/dev-tools/index.js +5 -5
  138. package/runtime/fallback-layouts/PrivateLayout.vue +2 -2
  139. package/runtime/fallback-layouts/PublicLayout.vue +2 -2
  140. package/runtime/fallback-layouts/SystemLayout.vue +2 -2
  141. package/runtime/gxpStringsPlugin.js +159 -134
  142. package/runtime/index.html +17 -19
  143. package/runtime/main.js +24 -22
  144. package/runtime/mock-api/auth-middleware.js +15 -15
  145. package/runtime/mock-api/image-generator.js +46 -46
  146. package/runtime/mock-api/index.js +55 -55
  147. package/runtime/mock-api/response-generator.js +116 -105
  148. package/runtime/mock-api/route-generator.js +107 -84
  149. package/runtime/mock-api/socket-triggers.js +94 -93
  150. package/runtime/mock-api/spec-loader.js +79 -80
  151. package/runtime/package.json +3 -0
  152. package/runtime/server.js +68 -68
  153. package/runtime/stores/gxpPortalConfigStore.js +204 -186
  154. package/runtime/stores/index.js +2 -2
  155. package/runtime/vite-inspector-plugin.js +858 -707
  156. package/runtime/vite-source-tracker-plugin.js +132 -113
  157. package/runtime/vite.config.js +207 -132
  158. package/scripts/launch-chrome.js +41 -41
  159. package/scripts/pack-chrome.js +38 -39
  160. package/socket-events/AiSessionMessageCreated.json +17 -17
  161. package/socket-events/SocialStreamPostCreated.json +23 -23
  162. package/socket-events/SocialStreamPostVariantCompleted.json +22 -22
  163. package/template/.claude/agents/gxp-developer.md +100 -99
  164. package/template/.claude/settings.json +7 -7
  165. package/template/AGENTS.md +30 -23
  166. package/template/GEMINI.md +20 -20
  167. package/template/README.md +70 -53
  168. package/template/app-manifest.json +2 -4
  169. package/template/configuration.json +10 -10
  170. package/template/default-styling.css +1 -1
  171. package/template/index.html +18 -20
  172. package/template/main.js +24 -22
  173. package/template/src/DemoPage.vue +415 -362
  174. package/template/src/Plugin.vue +76 -85
  175. package/template/src/stores/index.js +3 -3
  176. package/template/src/stores/test-data.json +164 -172
  177. package/template/theme-layouts/AdditionalStyling.css +50 -50
  178. package/template/theme-layouts/PrivateLayout.vue +8 -12
  179. package/template/theme-layouts/PublicLayout.vue +8 -12
  180. package/template/theme-layouts/SystemLayout.vue +8 -12
  181. package/template/vite.extend.js +45 -0
  182. package/template/vite.config.js +0 -409
@@ -1,11 +1,11 @@
1
- import { defineConfig, loadEnv } from "vite";
2
- import vue from "@vitejs/plugin-vue";
3
- import path from "path";
4
- import fs from "fs";
5
- import { fileURLToPath } from "url";
6
- import externalGlobals from "rollup-plugin-external-globals";
7
- import { gxpInspectorPlugin } from "./vite-inspector-plugin.js";
8
- import { gxpSourceTrackerPlugin } from "./vite-source-tracker-plugin.js";
1
+ import { defineConfig, loadEnv, mergeConfig } from "vite"
2
+ import { fileURLToPath, pathToFileURL } from "url"
3
+ import vue from "@vitejs/plugin-vue"
4
+ import path from "path"
5
+ import fs from "fs"
6
+ import externalGlobals from "rollup-plugin-external-globals"
7
+ import { gxpInspectorPlugin } from "./vite-inspector-plugin.js"
8
+ import { gxpSourceTrackerPlugin } from "./vite-source-tracker-plugin.js"
9
9
 
10
10
  // Environment URL configuration for API proxy
11
11
  const ENVIRONMENT_URLS = {
@@ -14,26 +14,26 @@ const ENVIRONMENT_URLS = {
14
14
  testing: "https://api.zenith-develop-testing.env.eventfinity.app",
15
15
  develop: "https://api.zenith-develop.env.eventfinity.app",
16
16
  local: "https://dashboard.eventfinity.test",
17
- };
17
+ }
18
18
 
19
19
  /**
20
20
  * Get the API proxy target URL based on environment
21
21
  */
22
22
  function getApiProxyTarget(env) {
23
- const apiEnv = env.API_ENV || "mock";
23
+ const apiEnv = env.API_ENV || "mock"
24
24
 
25
25
  // Custom URL takes precedence
26
26
  if (env.API_BASE_URL) {
27
- return env.API_BASE_URL;
27
+ return env.API_BASE_URL
28
28
  }
29
29
 
30
30
  // Mock uses local mock-api server (no proxy needed, handled separately)
31
31
  if (apiEnv === "mock") {
32
- return null;
32
+ return null
33
33
  }
34
34
 
35
35
  // Look up environment URL
36
- return ENVIRONMENT_URLS[apiEnv] || ENVIRONMENT_URLS.production;
36
+ return ENVIRONMENT_URLS[apiEnv] || ENVIRONMENT_URLS.production
37
37
  }
38
38
 
39
39
  /**
@@ -41,53 +41,53 @@ function getApiProxyTarget(env) {
41
41
  */
42
42
  function getLibName() {
43
43
  try {
44
- const packageJsonPath = path.resolve(process.cwd(), "package.json");
44
+ const packageJsonPath = path.resolve(process.cwd(), "package.json")
45
45
  if (fs.existsSync(packageJsonPath)) {
46
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
46
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"))
47
47
  // Convert package name to a valid JS identifier
48
48
  // e.g., "@company/my-plugin" -> "MyPlugin"
49
- const name = packageJson.name || "Plugin";
49
+ const name = packageJson.name || "Plugin"
50
50
  return name
51
51
  .replace(/[@\/\-]/g, " ")
52
52
  .replace(/\b\w/g, (l) => l.toUpperCase())
53
- .replace(/\s/g, "");
53
+ .replace(/\s/g, "")
54
54
  }
55
55
  } catch (error) {
56
- console.warn("Could not read package.json, using default lib name");
56
+ console.warn("Could not read package.json, using default lib name")
57
57
  }
58
- return "Plugin";
58
+ return "Plugin"
59
59
  }
60
60
 
61
61
  /**
62
62
  * Setup HTTPS configuration if certificates are available
63
63
  */
64
64
  function getHttpsConfig(env) {
65
- const useHttps = env.USE_HTTPS === "true";
66
- const certPath = env.CERT_PATH;
67
- const keyPath = env.KEY_PATH;
65
+ const useHttps = env.USE_HTTPS === "true"
66
+ const certPath = env.CERT_PATH
67
+ const keyPath = env.KEY_PATH
68
68
 
69
69
  if (!useHttps || !certPath || !keyPath) {
70
- return false;
70
+ return undefined
71
71
  }
72
72
 
73
73
  // Resolve paths relative to project root
74
- const resolvedCertPath = path.resolve(process.cwd(), certPath);
75
- const resolvedKeyPath = path.resolve(process.cwd(), keyPath);
74
+ const resolvedCertPath = path.resolve(process.cwd(), certPath)
75
+ const resolvedKeyPath = path.resolve(process.cwd(), keyPath)
76
76
 
77
77
  // Check if certificate files exist
78
78
  if (!fs.existsSync(resolvedCertPath) || !fs.existsSync(resolvedKeyPath)) {
79
- console.warn("⚠ SSL certificate files not found, falling back to HTTP");
80
- return false;
79
+ console.warn("⚠ SSL certificate files not found, falling back to HTTP")
80
+ return undefined
81
81
  }
82
82
 
83
83
  try {
84
84
  return {
85
85
  key: fs.readFileSync(resolvedKeyPath),
86
86
  cert: fs.readFileSync(resolvedCertPath),
87
- };
87
+ }
88
88
  } catch (error) {
89
- console.warn("⚠ Failed to read SSL certificates, falling back to HTTP");
90
- return false;
89
+ console.warn("⚠ Failed to read SSL certificates, falling back to HTTP")
90
+ return undefined
91
91
  }
92
92
  }
93
93
 
@@ -98,70 +98,128 @@ function findToolkitPath() {
98
98
  // Derive from this config file's own location — always reliable regardless
99
99
  // of how the package is installed (local, global, npm link, CI, etc.)
100
100
  // This file lives at <toolkit>/runtime/vite.config.js, so toolkit root is one level up.
101
- const configFileDir = path.dirname(fileURLToPath(import.meta.url));
102
- return path.resolve(configFileDir, "..");
101
+ const configFileDir = path.dirname(fileURLToPath(import.meta.url))
102
+ return path.resolve(configFileDir, "..")
103
103
  }
104
104
 
105
105
  /**
106
106
  * Check if a file exists locally in the project
107
107
  */
108
108
  function hasLocalFile(fileName) {
109
- const localPath = path.resolve(process.cwd(), fileName);
110
- return fs.existsSync(localPath);
109
+ const localPath = path.resolve(process.cwd(), fileName)
110
+ return fs.existsSync(localPath)
111
+ }
112
+
113
+ /**
114
+ * Load the project-local `vite.extend.js` (or `.mjs`) if one exists.
115
+ *
116
+ * The file may export either a config object or a function
117
+ * `(ctx) => config | Promise<config>`, where `ctx` is
118
+ * `{ mode, command, env, runtimeConfig }`. The returned config is deep-merged
119
+ * into the runtime config via Vite's `mergeConfig` — arrays (plugins) are
120
+ * concatenated, objects (resolve.alias, define, etc.) are merged key-by-key,
121
+ * primitives are overwritten.
122
+ */
123
+ async function loadExtensionConfig(ctx, runtimeConfig) {
124
+ const candidates = ["vite.extend.js", "vite.extend.mjs"]
125
+ for (const name of candidates) {
126
+ const abs = path.resolve(process.cwd(), name)
127
+ if (!fs.existsSync(abs)) {
128
+ continue
129
+ }
130
+ try {
131
+ const mod = await import(pathToFileURL(abs).href)
132
+ const exported = mod.default ?? mod
133
+ const extension =
134
+ typeof exported === "function"
135
+ ? await exported({ ...ctx, runtimeConfig })
136
+ : exported
137
+ if (extension && typeof extension === "object") {
138
+ console.log(`🧩 Loaded ${name}`)
139
+ return extension
140
+ }
141
+ } catch (err) {
142
+ console.warn(`⚠ Failed to load ${name}:`, err.message)
143
+ }
144
+ return null
145
+ }
146
+ return null
111
147
  }
112
148
 
113
- export default defineConfig(({ mode }) => {
149
+ export default defineConfig(async (ctx) => {
150
+ const { mode } = ctx
114
151
  // Load environment variables from project directory
115
- const env = loadEnv(mode, process.cwd(), "");
152
+ const env = loadEnv(mode, process.cwd(), "")
116
153
 
117
154
  // Get lib name from package.json
118
- const libName = getLibName();
155
+ const libName = getLibName()
119
156
 
120
157
  // Find the toolkit path for runtime imports
121
- const toolkitPath = findToolkitPath();
122
- const runtimeDir = path.resolve(toolkitPath, "runtime");
158
+ const toolkitPath = findToolkitPath()
159
+ const runtimeDir = path.resolve(toolkitPath, "runtime")
123
160
 
124
161
  // Check for local dev files (requires both env var AND file to exist)
125
- const hasLocalIndexHtml = hasLocalFile("index.html");
126
- const hasLocalMainJs = hasLocalFile("main.js");
127
- const useLocalIndex = env.USE_LOCAL_INDEX === "true" && hasLocalIndexHtml;
128
- const useLocalMain = env.USE_LOCAL_MAIN === "true" && hasLocalMainJs;
162
+ const hasLocalIndexHtml = hasLocalFile("index.html")
163
+ const hasLocalMainJs = hasLocalFile("main.js")
164
+ const useLocalIndex = env.USE_LOCAL_INDEX === "true" && hasLocalIndexHtml
165
+ const useLocalMain = env.USE_LOCAL_MAIN === "true" && hasLocalMainJs
129
166
 
130
167
  // Plugin enable/disable flags
131
- const useSourceTracker = env.DISABLE_SOURCE_TRACKER !== "true";
132
- const useInspector = env.DISABLE_INSPECTOR !== "true";
168
+ const useSourceTracker = env.DISABLE_SOURCE_TRACKER !== "true"
169
+ const useInspector = env.DISABLE_INSPECTOR !== "true"
133
170
 
134
171
  // Log which files are being used
135
- console.log(`📄 index.html: ${useLocalIndex ? "local" : "runtime"}`);
136
- console.log(`📄 main.js: ${useLocalMain ? "local" : "runtime"}`);
172
+ console.log(`📄 index.html: ${useLocalIndex ? "local" : "runtime"}`)
173
+ console.log(`📄 main.js: ${useLocalMain ? "local" : "runtime"}`)
137
174
 
138
175
  // Create plugin to serve runtime files (index.html and main.js) if no local ones exist
139
176
  const runtimeFilesPlugin = {
140
177
  name: "runtime-files",
141
178
  configureServer(server) {
142
179
  server.middlewares.use((req, res, next) => {
143
- // Serve runtime index.html for root requests (unless local index.html is opted in)
180
+ // Serve runtime index.html for root requests and SPA navigation requests
181
+ // (unless local index.html is opted in). SPA fallback is required so
182
+ // client-side routers (e.g. vue-router createWebHistory) can handle
183
+ // deep links when no physical index.html exists at the project root.
184
+ const rawUrl = req.url || ""
185
+ const urlPath = rawUrl.split("?")[0]
186
+ const accept = req.headers.accept || ""
187
+ const isGetOrHead = req.method === "GET" || req.method === "HEAD"
188
+ const isInternalPath =
189
+ urlPath.startsWith("/@") ||
190
+ urlPath.startsWith("/__") ||
191
+ urlPath.startsWith("/node_modules/") ||
192
+ urlPath.startsWith("/src/") ||
193
+ urlPath.startsWith("/dev-assets/") ||
194
+ urlPath.startsWith("/api-proxy/")
195
+ const hasExtension = path.extname(urlPath) !== ""
196
+ const isSpaNavigation =
197
+ isGetOrHead &&
198
+ !isInternalPath &&
199
+ !hasExtension &&
200
+ accept.includes("text/html")
201
+
144
202
  if (
145
203
  !useLocalIndex &&
146
- (req.url === "/" || req.url === "/index.html")
204
+ (urlPath === "/" || urlPath === "/index.html" || isSpaNavigation)
147
205
  ) {
148
- const runtimeIndexPath = path.join(runtimeDir, "index.html");
206
+ const runtimeIndexPath = path.join(runtimeDir, "index.html")
149
207
  if (fs.existsSync(runtimeIndexPath)) {
150
208
  // Read and transform the runtime index.html
151
209
  server
152
210
  .transformIndexHtml(
153
- req.url,
154
- fs.readFileSync(runtimeIndexPath, "utf-8")
211
+ rawUrl,
212
+ fs.readFileSync(runtimeIndexPath, "utf-8"),
155
213
  )
156
214
  .then((html) => {
157
- res.setHeader("Content-Type", "text/html");
158
- res.end(html);
215
+ res.setHeader("Content-Type", "text/html")
216
+ res.end(html)
159
217
  })
160
218
  .catch((err) => {
161
- console.error("Error transforming index.html:", err);
162
- next(err);
163
- });
164
- return;
219
+ console.error("Error transforming index.html:", err)
220
+ next(err)
221
+ })
222
+ return
165
223
  }
166
224
  }
167
225
 
@@ -171,77 +229,81 @@ export default defineConfig(({ mode }) => {
171
229
  (req.url === "/@gx-runtime/main.js" ||
172
230
  req.url?.startsWith("/@gx-runtime/main.js?"))
173
231
  ) {
174
- const runtimeMainPath = path.join(runtimeDir, "main.js");
232
+ const runtimeMainPath = path.join(runtimeDir, "main.js")
175
233
  if (fs.existsSync(runtimeMainPath)) {
176
234
  // Use the real path to handle symlinks correctly
177
- const realMainPath = fs.realpathSync(runtimeMainPath);
235
+ const realMainPath = fs.realpathSync(runtimeMainPath)
178
236
  server
179
237
  .transformRequest(realMainPath)
180
238
  .then((result) => {
181
239
  if (result) {
182
- res.setHeader("Content-Type", "application/javascript");
183
- res.end(result.code);
240
+ res.setHeader("Content-Type", "application/javascript")
241
+ res.end(result.code)
184
242
  } else {
185
- next();
243
+ next()
186
244
  }
187
245
  })
188
246
  .catch((err) => {
189
- console.error("Error transforming main.js:", err);
190
- next(err);
191
- });
192
- return;
247
+ console.error("Error transforming main.js:", err)
248
+ next(err)
249
+ })
250
+ return
193
251
  }
194
252
  }
195
253
 
196
- next();
197
- });
254
+ next()
255
+ })
198
256
  },
199
- };
257
+ }
200
258
 
201
259
  // Resolve @layouts: use project's theme-layouts/ if it exists,
202
260
  // otherwise fall back to toolkit's runtime/fallback-layouts/
203
- const projectLayoutsDir = path.resolve(process.cwd(), "theme-layouts");
204
- const fallbackLayoutsDir = path.resolve(runtimeDir, "fallback-layouts");
205
- const layoutsDir = fs.existsSync(projectLayoutsDir) ? projectLayoutsDir : fallbackLayoutsDir;
261
+ const projectLayoutsDir = path.resolve(process.cwd(), "theme-layouts")
262
+ const fallbackLayoutsDir = path.resolve(runtimeDir, "fallback-layouts")
263
+ const layoutsDir = fs.existsSync(projectLayoutsDir)
264
+ ? projectLayoutsDir
265
+ : fallbackLayoutsDir
206
266
 
207
267
  if (layoutsDir === fallbackLayoutsDir) {
208
- console.log("📐 Layouts: using toolkit fallbacks (no theme-layouts/ directory)");
268
+ console.log(
269
+ "📐 Layouts: using toolkit fallbacks (no theme-layouts/ directory)",
270
+ )
209
271
  } else {
210
- console.log("📐 Layouts: using project theme-layouts/");
272
+ console.log("📐 Layouts: using project theme-layouts/")
211
273
  }
212
274
 
213
275
  // Determine if HTTPS is enabled
214
- const useHttps = getHttpsConfig(env) !== false;
276
+ const useHttps = getHttpsConfig(env) !== undefined
215
277
 
216
278
  // Get API proxy target for non-mock environments
217
- const apiProxyTarget = getApiProxyTarget(env);
279
+ const apiProxyTarget = getApiProxyTarget(env)
218
280
  if (apiProxyTarget) {
219
- console.log(`🔀 API Proxy: /api-proxy -> ${apiProxyTarget}`);
281
+ console.log(`🔀 API Proxy: /api-proxy -> ${apiProxyTarget}`)
220
282
  }
221
283
 
222
- return {
284
+ const runtimeConfig = {
223
285
  // Root is always the project directory
224
286
  root: process.cwd(),
225
287
  // Expose environment variables to the browser
226
288
  define: {
227
289
  "import.meta.env.VITE_API_ENV": JSON.stringify(env.API_ENV || "mock"),
228
290
  "import.meta.env.VITE_API_BASE_URL": JSON.stringify(
229
- env.API_BASE_URL || ""
291
+ env.API_BASE_URL || "",
230
292
  ),
231
293
  "import.meta.env.VITE_API_KEY": JSON.stringify(env.API_KEY || ""),
232
294
  "import.meta.env.VITE_API_PROJECT_ID": JSON.stringify(
233
- env.API_PROJECT_ID || ""
295
+ env.API_PROJECT_ID || "",
234
296
  ),
235
297
  "import.meta.env.VITE_USE_HTTPS": JSON.stringify(
236
- useHttps ? "true" : "false"
298
+ useHttps ? "true" : "false",
237
299
  ),
238
300
  "import.meta.env.VITE_NODE_PORT": JSON.stringify(env.NODE_PORT || "3060"),
239
301
  "import.meta.env.VITE_SOCKET_IO_PORT": JSON.stringify(
240
- env.SOCKET_IO_PORT || "3069"
302
+ env.SOCKET_IO_PORT || "3069",
241
303
  ),
242
304
  "import.meta.env.SOCKET_URL": JSON.stringify(env.SOCKET_URL || ""),
243
305
  "import.meta.env.SOCKET_DRIVER": JSON.stringify(
244
- env.SOCKET_DRIVER || "io"
306
+ env.SOCKET_DRIVER || "io",
245
307
  ),
246
308
  },
247
309
  plugins: [
@@ -260,7 +322,7 @@ export default defineConfig(({ mode }) => {
260
322
  },
261
323
  {
262
324
  include: ["src/**"],
263
- }
325
+ },
264
326
  ),
265
327
  // Custom request logging and CORS plugin
266
328
  {
@@ -269,47 +331,47 @@ export default defineConfig(({ mode }) => {
269
331
  server.middlewares.use((req, res, next) => {
270
332
  // Health check route
271
333
  if (req.url === "/__health") {
272
- res.statusCode = 200;
273
- res.setHeader("Content-Type", "application/json");
274
- res.end(JSON.stringify({ status: "ok" }));
275
- return;
334
+ res.statusCode = 200
335
+ res.setHeader("Content-Type", "application/json")
336
+ res.end(JSON.stringify({ status: "ok" }))
337
+ return
276
338
  }
277
339
 
278
- const start = Date.now();
279
- const originalEnd = res.end;
340
+ const start = Date.now()
341
+ const originalEnd = res.end
280
342
 
281
343
  // Add CORS headers to all responses
282
- res.setHeader("Access-Control-Allow-Origin", "*");
344
+ res.setHeader("Access-Control-Allow-Origin", "*")
283
345
  res.setHeader(
284
346
  "Access-Control-Allow-Methods",
285
- "GET, POST, PUT, DELETE, OPTIONS"
286
- );
287
- res.setHeader("Access-Control-Allow-Headers", "*");
288
- res.setHeader("Access-Control-Allow-Credentials", "false");
347
+ "GET, POST, PUT, DELETE, OPTIONS",
348
+ )
349
+ res.setHeader("Access-Control-Allow-Headers", "*")
350
+ res.setHeader("Access-Control-Allow-Credentials", "false")
289
351
 
290
352
  // Handle preflight requests
291
353
  if (req.method === "OPTIONS") {
292
- res.statusCode = 200;
293
- res.end();
294
- return;
354
+ res.statusCode = 200
355
+ res.end()
356
+ return
295
357
  }
296
358
 
297
359
  res.end = function (...args) {
298
- const duration = Date.now() - start;
299
- const status = res.statusCode;
300
- const method = req.method;
301
- const url = req.url;
302
- const referer = req.headers.referer || "direct";
303
- const origin = req.headers.origin || "unknown";
360
+ const duration = Date.now() - start
361
+ const status = res.statusCode
362
+ const method = req.method
363
+ const url = req.url
364
+ const referer = req.headers.referer || "direct"
365
+ const origin = req.headers.origin || "unknown"
304
366
 
305
367
  console.log(
306
- `[${new Date().toISOString()}] ${method} ${url} ${status} (${duration}ms) - Origin: ${origin} - Referer: ${referer}`
307
- );
308
- originalEnd.apply(this, args);
309
- };
368
+ `[${new Date().toISOString()}] ${method} ${url} ${status} (${duration}ms) - Origin: ${origin} - Referer: ${referer}`,
369
+ )
370
+ originalEnd.apply(this, args)
371
+ }
310
372
 
311
- next();
312
- });
373
+ next()
374
+ })
313
375
  },
314
376
  },
315
377
  ],
@@ -320,11 +382,13 @@ export default defineConfig(({ mode }) => {
320
382
  strictPort: true,
321
383
  https: getHttpsConfig(env),
322
384
  allowedHosts: env.ALLOWED_HOSTS
323
- ? env.ALLOWED_HOSTS.split(",").map((h) => h.trim()).filter(Boolean)
324
- : "all",
385
+ ? env.ALLOWED_HOSTS.split(",")
386
+ .map((h) => h.trim())
387
+ .filter(Boolean)
388
+ : true,
325
389
  cors: {
326
390
  origin: "*",
327
- methods: ["GET", "POST", "PUT, DELETE", "OPTIONS"],
391
+ methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
328
392
  allowedHeaders: ["*"],
329
393
  credentials: false,
330
394
  },
@@ -332,13 +396,21 @@ export default defineConfig(({ mode }) => {
332
396
  ? {
333
397
  protocol: env.HMR_PROTOCOL || "wss",
334
398
  host: env.HMR_HOST,
335
- port: parseInt(env.HMR_PORT) || parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
336
- clientPort: parseInt(env.HMR_CLIENT_PORT) || parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
337
- }
399
+ port:
400
+ parseInt(env.HMR_PORT) ||
401
+ parseInt(env.CLIENT_PORT) ||
402
+ parseInt(env.NODE_PORT) ||
403
+ 3060,
404
+ clientPort:
405
+ parseInt(env.HMR_CLIENT_PORT) ||
406
+ parseInt(env.CLIENT_PORT) ||
407
+ parseInt(env.NODE_PORT) ||
408
+ 3060,
409
+ }
338
410
  : {
339
411
  clientPort:
340
412
  parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
341
- },
413
+ },
342
414
  host: true, // Allow access from network
343
415
  // Allow serving files from the toolkit runtime directory
344
416
  // Also resolve symlinks to allow files from the real path
@@ -356,30 +428,30 @@ export default defineConfig(({ mode }) => {
356
428
  configure: (proxy, options) => {
357
429
  proxy.on("proxyReq", (proxyReq, req) => {
358
430
  // Forward the API key as Authorization header if set
359
- const apiKey = env.API_KEY;
431
+ const apiKey = env.API_KEY
360
432
  if (apiKey) {
361
- proxyReq.setHeader("Authorization", `Bearer ${apiKey}`);
433
+ proxyReq.setHeader("Authorization", `Bearer ${apiKey}`)
362
434
  }
363
435
  console.log(
364
436
  `[API Proxy] ${req.method} ${
365
437
  req.url
366
438
  } -> ${apiProxyTarget}${req.url.replace(
367
439
  /^\/api-proxy/,
368
- ""
369
- )}`
370
- );
371
- });
440
+ "",
441
+ )}`,
442
+ )
443
+ })
372
444
  proxy.on("proxyRes", (proxyRes, req) => {
373
445
  console.log(
374
- `[API Proxy] ${req.method} ${req.url} <- ${proxyRes.statusCode}`
375
- );
376
- });
446
+ `[API Proxy] ${req.method} ${req.url} <- ${proxyRes.statusCode}`,
447
+ )
448
+ })
377
449
  proxy.on("error", (err, req) => {
378
- console.error(`[API Proxy] Error: ${err.message}`);
379
- });
450
+ console.error(`[API Proxy] Error: ${err.message}`)
451
+ })
380
452
  },
381
453
  },
382
- }
454
+ }
383
455
  : {},
384
456
  },
385
457
  build: {
@@ -427,5 +499,8 @@ export default defineConfig(({ mode }) => {
427
499
  ssr: {
428
500
  external: ["vue", "pinia"],
429
501
  },
430
- };
431
- });
502
+ }
503
+
504
+ const extension = await loadExtensionConfig(ctx, runtimeConfig)
505
+ return extension ? mergeConfig(runtimeConfig, extension) : runtimeConfig
506
+ })