@gxp-dev/tools 2.0.63 → 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 +191 -139
  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,42 +98,79 @@ 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
111
  }
112
112
 
113
- export default defineConfig(({ mode }) => {
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
147
+ }
148
+
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 = {
@@ -144,47 +181,45 @@ export default defineConfig(({ mode }) => {
144
181
  // (unless local index.html is opted in). SPA fallback is required so
145
182
  // client-side routers (e.g. vue-router createWebHistory) can handle
146
183
  // deep links when no physical index.html exists at the project root.
147
- const rawUrl = req.url || "";
148
- const urlPath = rawUrl.split("?")[0];
149
- const accept = req.headers.accept || "";
150
- const isGetOrHead = req.method === "GET" || req.method === "HEAD";
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"
151
188
  const isInternalPath =
152
189
  urlPath.startsWith("/@") ||
153
190
  urlPath.startsWith("/__") ||
154
191
  urlPath.startsWith("/node_modules/") ||
155
192
  urlPath.startsWith("/src/") ||
156
193
  urlPath.startsWith("/dev-assets/") ||
157
- urlPath.startsWith("/api-proxy/");
158
- const hasExtension = path.extname(urlPath) !== "";
194
+ urlPath.startsWith("/api-proxy/")
195
+ const hasExtension = path.extname(urlPath) !== ""
159
196
  const isSpaNavigation =
160
197
  isGetOrHead &&
161
198
  !isInternalPath &&
162
199
  !hasExtension &&
163
- accept.includes("text/html");
200
+ accept.includes("text/html")
164
201
 
165
202
  if (
166
203
  !useLocalIndex &&
167
- (urlPath === "/" ||
168
- urlPath === "/index.html" ||
169
- isSpaNavigation)
204
+ (urlPath === "/" || urlPath === "/index.html" || isSpaNavigation)
170
205
  ) {
171
- const runtimeIndexPath = path.join(runtimeDir, "index.html");
206
+ const runtimeIndexPath = path.join(runtimeDir, "index.html")
172
207
  if (fs.existsSync(runtimeIndexPath)) {
173
208
  // Read and transform the runtime index.html
174
209
  server
175
210
  .transformIndexHtml(
176
211
  rawUrl,
177
- fs.readFileSync(runtimeIndexPath, "utf-8")
212
+ fs.readFileSync(runtimeIndexPath, "utf-8"),
178
213
  )
179
214
  .then((html) => {
180
- res.setHeader("Content-Type", "text/html");
181
- res.end(html);
215
+ res.setHeader("Content-Type", "text/html")
216
+ res.end(html)
182
217
  })
183
218
  .catch((err) => {
184
- console.error("Error transforming index.html:", err);
185
- next(err);
186
- });
187
- return;
219
+ console.error("Error transforming index.html:", err)
220
+ next(err)
221
+ })
222
+ return
188
223
  }
189
224
  }
190
225
 
@@ -194,77 +229,81 @@ export default defineConfig(({ mode }) => {
194
229
  (req.url === "/@gx-runtime/main.js" ||
195
230
  req.url?.startsWith("/@gx-runtime/main.js?"))
196
231
  ) {
197
- const runtimeMainPath = path.join(runtimeDir, "main.js");
232
+ const runtimeMainPath = path.join(runtimeDir, "main.js")
198
233
  if (fs.existsSync(runtimeMainPath)) {
199
234
  // Use the real path to handle symlinks correctly
200
- const realMainPath = fs.realpathSync(runtimeMainPath);
235
+ const realMainPath = fs.realpathSync(runtimeMainPath)
201
236
  server
202
237
  .transformRequest(realMainPath)
203
238
  .then((result) => {
204
239
  if (result) {
205
- res.setHeader("Content-Type", "application/javascript");
206
- res.end(result.code);
240
+ res.setHeader("Content-Type", "application/javascript")
241
+ res.end(result.code)
207
242
  } else {
208
- next();
243
+ next()
209
244
  }
210
245
  })
211
246
  .catch((err) => {
212
- console.error("Error transforming main.js:", err);
213
- next(err);
214
- });
215
- return;
247
+ console.error("Error transforming main.js:", err)
248
+ next(err)
249
+ })
250
+ return
216
251
  }
217
252
  }
218
253
 
219
- next();
220
- });
254
+ next()
255
+ })
221
256
  },
222
- };
257
+ }
223
258
 
224
259
  // Resolve @layouts: use project's theme-layouts/ if it exists,
225
260
  // otherwise fall back to toolkit's runtime/fallback-layouts/
226
- const projectLayoutsDir = path.resolve(process.cwd(), "theme-layouts");
227
- const fallbackLayoutsDir = path.resolve(runtimeDir, "fallback-layouts");
228
- 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
229
266
 
230
267
  if (layoutsDir === fallbackLayoutsDir) {
231
- console.log("📐 Layouts: using toolkit fallbacks (no theme-layouts/ directory)");
268
+ console.log(
269
+ "📐 Layouts: using toolkit fallbacks (no theme-layouts/ directory)",
270
+ )
232
271
  } else {
233
- console.log("📐 Layouts: using project theme-layouts/");
272
+ console.log("📐 Layouts: using project theme-layouts/")
234
273
  }
235
274
 
236
275
  // Determine if HTTPS is enabled
237
- const useHttps = getHttpsConfig(env) !== false;
276
+ const useHttps = getHttpsConfig(env) !== undefined
238
277
 
239
278
  // Get API proxy target for non-mock environments
240
- const apiProxyTarget = getApiProxyTarget(env);
279
+ const apiProxyTarget = getApiProxyTarget(env)
241
280
  if (apiProxyTarget) {
242
- console.log(`🔀 API Proxy: /api-proxy -> ${apiProxyTarget}`);
281
+ console.log(`🔀 API Proxy: /api-proxy -> ${apiProxyTarget}`)
243
282
  }
244
283
 
245
- return {
284
+ const runtimeConfig = {
246
285
  // Root is always the project directory
247
286
  root: process.cwd(),
248
287
  // Expose environment variables to the browser
249
288
  define: {
250
289
  "import.meta.env.VITE_API_ENV": JSON.stringify(env.API_ENV || "mock"),
251
290
  "import.meta.env.VITE_API_BASE_URL": JSON.stringify(
252
- env.API_BASE_URL || ""
291
+ env.API_BASE_URL || "",
253
292
  ),
254
293
  "import.meta.env.VITE_API_KEY": JSON.stringify(env.API_KEY || ""),
255
294
  "import.meta.env.VITE_API_PROJECT_ID": JSON.stringify(
256
- env.API_PROJECT_ID || ""
295
+ env.API_PROJECT_ID || "",
257
296
  ),
258
297
  "import.meta.env.VITE_USE_HTTPS": JSON.stringify(
259
- useHttps ? "true" : "false"
298
+ useHttps ? "true" : "false",
260
299
  ),
261
300
  "import.meta.env.VITE_NODE_PORT": JSON.stringify(env.NODE_PORT || "3060"),
262
301
  "import.meta.env.VITE_SOCKET_IO_PORT": JSON.stringify(
263
- env.SOCKET_IO_PORT || "3069"
302
+ env.SOCKET_IO_PORT || "3069",
264
303
  ),
265
304
  "import.meta.env.SOCKET_URL": JSON.stringify(env.SOCKET_URL || ""),
266
305
  "import.meta.env.SOCKET_DRIVER": JSON.stringify(
267
- env.SOCKET_DRIVER || "io"
306
+ env.SOCKET_DRIVER || "io",
268
307
  ),
269
308
  },
270
309
  plugins: [
@@ -283,7 +322,7 @@ export default defineConfig(({ mode }) => {
283
322
  },
284
323
  {
285
324
  include: ["src/**"],
286
- }
325
+ },
287
326
  ),
288
327
  // Custom request logging and CORS plugin
289
328
  {
@@ -292,47 +331,47 @@ export default defineConfig(({ mode }) => {
292
331
  server.middlewares.use((req, res, next) => {
293
332
  // Health check route
294
333
  if (req.url === "/__health") {
295
- res.statusCode = 200;
296
- res.setHeader("Content-Type", "application/json");
297
- res.end(JSON.stringify({ status: "ok" }));
298
- return;
334
+ res.statusCode = 200
335
+ res.setHeader("Content-Type", "application/json")
336
+ res.end(JSON.stringify({ status: "ok" }))
337
+ return
299
338
  }
300
339
 
301
- const start = Date.now();
302
- const originalEnd = res.end;
340
+ const start = Date.now()
341
+ const originalEnd = res.end
303
342
 
304
343
  // Add CORS headers to all responses
305
- res.setHeader("Access-Control-Allow-Origin", "*");
344
+ res.setHeader("Access-Control-Allow-Origin", "*")
306
345
  res.setHeader(
307
346
  "Access-Control-Allow-Methods",
308
- "GET, POST, PUT, DELETE, OPTIONS"
309
- );
310
- res.setHeader("Access-Control-Allow-Headers", "*");
311
- 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")
312
351
 
313
352
  // Handle preflight requests
314
353
  if (req.method === "OPTIONS") {
315
- res.statusCode = 200;
316
- res.end();
317
- return;
354
+ res.statusCode = 200
355
+ res.end()
356
+ return
318
357
  }
319
358
 
320
359
  res.end = function (...args) {
321
- const duration = Date.now() - start;
322
- const status = res.statusCode;
323
- const method = req.method;
324
- const url = req.url;
325
- const referer = req.headers.referer || "direct";
326
- 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"
327
366
 
328
367
  console.log(
329
- `[${new Date().toISOString()}] ${method} ${url} ${status} (${duration}ms) - Origin: ${origin} - Referer: ${referer}`
330
- );
331
- originalEnd.apply(this, args);
332
- };
368
+ `[${new Date().toISOString()}] ${method} ${url} ${status} (${duration}ms) - Origin: ${origin} - Referer: ${referer}`,
369
+ )
370
+ originalEnd.apply(this, args)
371
+ }
333
372
 
334
- next();
335
- });
373
+ next()
374
+ })
336
375
  },
337
376
  },
338
377
  ],
@@ -343,11 +382,13 @@ export default defineConfig(({ mode }) => {
343
382
  strictPort: true,
344
383
  https: getHttpsConfig(env),
345
384
  allowedHosts: env.ALLOWED_HOSTS
346
- ? env.ALLOWED_HOSTS.split(",").map((h) => h.trim()).filter(Boolean)
347
- : "all",
385
+ ? env.ALLOWED_HOSTS.split(",")
386
+ .map((h) => h.trim())
387
+ .filter(Boolean)
388
+ : true,
348
389
  cors: {
349
390
  origin: "*",
350
- methods: ["GET", "POST", "PUT, DELETE", "OPTIONS"],
391
+ methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
351
392
  allowedHeaders: ["*"],
352
393
  credentials: false,
353
394
  },
@@ -355,13 +396,21 @@ export default defineConfig(({ mode }) => {
355
396
  ? {
356
397
  protocol: env.HMR_PROTOCOL || "wss",
357
398
  host: env.HMR_HOST,
358
- port: parseInt(env.HMR_PORT) || parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
359
- clientPort: parseInt(env.HMR_CLIENT_PORT) || parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
360
- }
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
+ }
361
410
  : {
362
411
  clientPort:
363
412
  parseInt(env.CLIENT_PORT) || parseInt(env.NODE_PORT) || 3060,
364
- },
413
+ },
365
414
  host: true, // Allow access from network
366
415
  // Allow serving files from the toolkit runtime directory
367
416
  // Also resolve symlinks to allow files from the real path
@@ -379,30 +428,30 @@ export default defineConfig(({ mode }) => {
379
428
  configure: (proxy, options) => {
380
429
  proxy.on("proxyReq", (proxyReq, req) => {
381
430
  // Forward the API key as Authorization header if set
382
- const apiKey = env.API_KEY;
431
+ const apiKey = env.API_KEY
383
432
  if (apiKey) {
384
- proxyReq.setHeader("Authorization", `Bearer ${apiKey}`);
433
+ proxyReq.setHeader("Authorization", `Bearer ${apiKey}`)
385
434
  }
386
435
  console.log(
387
436
  `[API Proxy] ${req.method} ${
388
437
  req.url
389
438
  } -> ${apiProxyTarget}${req.url.replace(
390
439
  /^\/api-proxy/,
391
- ""
392
- )}`
393
- );
394
- });
440
+ "",
441
+ )}`,
442
+ )
443
+ })
395
444
  proxy.on("proxyRes", (proxyRes, req) => {
396
445
  console.log(
397
- `[API Proxy] ${req.method} ${req.url} <- ${proxyRes.statusCode}`
398
- );
399
- });
446
+ `[API Proxy] ${req.method} ${req.url} <- ${proxyRes.statusCode}`,
447
+ )
448
+ })
400
449
  proxy.on("error", (err, req) => {
401
- console.error(`[API Proxy] Error: ${err.message}`);
402
- });
450
+ console.error(`[API Proxy] Error: ${err.message}`)
451
+ })
403
452
  },
404
453
  },
405
- }
454
+ }
406
455
  : {},
407
456
  },
408
457
  build: {
@@ -450,5 +499,8 @@ export default defineConfig(({ mode }) => {
450
499
  ssr: {
451
500
  external: ["vue", "pinia"],
452
501
  },
453
- };
454
- });
502
+ }
503
+
504
+ const extension = await loadExtensionConfig(ctx, runtimeConfig)
505
+ return extension ? mergeConfig(runtimeConfig, extension) : runtimeConfig
506
+ })