@gxp-dev/tools 2.0.5

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 (145) hide show
  1. package/.github/workflows/npm-publish.yml +48 -0
  2. package/CLAUDE.md +400 -0
  3. package/README.md +247 -0
  4. package/REFACTOR_PLAN.md +194 -0
  5. package/bin/gx-devtools.js +87 -0
  6. package/bin/lib/cli.js +251 -0
  7. package/bin/lib/commands/assets.js +337 -0
  8. package/bin/lib/commands/build.js +259 -0
  9. package/bin/lib/commands/datastore.js +433 -0
  10. package/bin/lib/commands/dev.js +328 -0
  11. package/bin/lib/commands/extensions.js +298 -0
  12. package/bin/lib/commands/index.js +35 -0
  13. package/bin/lib/commands/init.js +307 -0
  14. package/bin/lib/commands/publish.js +189 -0
  15. package/bin/lib/commands/socket.js +158 -0
  16. package/bin/lib/commands/ssl.js +47 -0
  17. package/bin/lib/constants.js +120 -0
  18. package/bin/lib/tui/App.tsx +600 -0
  19. package/bin/lib/tui/components/CommandInput.tsx +278 -0
  20. package/bin/lib/tui/components/GeminiPanel.tsx +161 -0
  21. package/bin/lib/tui/components/Header.tsx +27 -0
  22. package/bin/lib/tui/components/LogPanel.tsx +122 -0
  23. package/bin/lib/tui/components/TabBar.tsx +56 -0
  24. package/bin/lib/tui/components/WelcomeScreen.tsx +80 -0
  25. package/bin/lib/tui/index.tsx +63 -0
  26. package/bin/lib/tui/services/ExtensionService.ts +122 -0
  27. package/bin/lib/tui/services/GeminiService.ts +395 -0
  28. package/bin/lib/tui/services/ServiceManager.ts +336 -0
  29. package/bin/lib/tui/services/SocketService.ts +204 -0
  30. package/bin/lib/tui/services/ViteService.ts +107 -0
  31. package/bin/lib/tui/services/index.ts +13 -0
  32. package/bin/lib/utils/files.js +180 -0
  33. package/bin/lib/utils/index.js +17 -0
  34. package/bin/lib/utils/paths.js +138 -0
  35. package/bin/lib/utils/prompts.js +71 -0
  36. package/bin/lib/utils/ssl.js +233 -0
  37. package/browser-extensions/README.md +1 -0
  38. package/browser-extensions/chrome/background.js +857 -0
  39. package/browser-extensions/chrome/content.js +51 -0
  40. package/browser-extensions/chrome/devtools.html +9 -0
  41. package/browser-extensions/chrome/devtools.js +23 -0
  42. package/browser-extensions/chrome/icons/gx_off_128.png +0 -0
  43. package/browser-extensions/chrome/icons/gx_off_16.png +0 -0
  44. package/browser-extensions/chrome/icons/gx_off_32.png +0 -0
  45. package/browser-extensions/chrome/icons/gx_off_64.png +0 -0
  46. package/browser-extensions/chrome/icons/gx_on_128.png +0 -0
  47. package/browser-extensions/chrome/icons/gx_on_16.png +0 -0
  48. package/browser-extensions/chrome/icons/gx_on_32.png +0 -0
  49. package/browser-extensions/chrome/icons/gx_on_64.png +0 -0
  50. package/browser-extensions/chrome/inspector.js +1087 -0
  51. package/browser-extensions/chrome/manifest.json +70 -0
  52. package/browser-extensions/chrome/panel.html +638 -0
  53. package/browser-extensions/chrome/panel.js +862 -0
  54. package/browser-extensions/chrome/popup.html +399 -0
  55. package/browser-extensions/chrome/popup.js +515 -0
  56. package/browser-extensions/chrome/rules.json +1 -0
  57. package/browser-extensions/chrome/test-chrome.html +145 -0
  58. package/browser-extensions/chrome/test-mixed-content.html +190 -0
  59. package/browser-extensions/chrome/test-uri-pattern.html +199 -0
  60. package/browser-extensions/firefox/README.md +134 -0
  61. package/browser-extensions/firefox/background.js +804 -0
  62. package/browser-extensions/firefox/content.js +120 -0
  63. package/browser-extensions/firefox/debug-errors.html +229 -0
  64. package/browser-extensions/firefox/debug-https.html +113 -0
  65. package/browser-extensions/firefox/devtools.html +9 -0
  66. package/browser-extensions/firefox/devtools.js +24 -0
  67. package/browser-extensions/firefox/icons/gx_off_128.png +0 -0
  68. package/browser-extensions/firefox/icons/gx_off_16.png +0 -0
  69. package/browser-extensions/firefox/icons/gx_off_32.png +0 -0
  70. package/browser-extensions/firefox/icons/gx_off_64.png +0 -0
  71. package/browser-extensions/firefox/icons/gx_on_128.png +0 -0
  72. package/browser-extensions/firefox/icons/gx_on_16.png +0 -0
  73. package/browser-extensions/firefox/icons/gx_on_32.png +0 -0
  74. package/browser-extensions/firefox/icons/gx_on_64.png +0 -0
  75. package/browser-extensions/firefox/inspector.js +1087 -0
  76. package/browser-extensions/firefox/manifest.json +67 -0
  77. package/browser-extensions/firefox/panel.html +638 -0
  78. package/browser-extensions/firefox/panel.js +862 -0
  79. package/browser-extensions/firefox/popup.html +525 -0
  80. package/browser-extensions/firefox/popup.js +536 -0
  81. package/browser-extensions/firefox/test-gramercy.html +126 -0
  82. package/browser-extensions/firefox/test-imports.html +58 -0
  83. package/browser-extensions/firefox/test-masking.html +147 -0
  84. package/browser-extensions/firefox/test-uri-pattern.html +199 -0
  85. package/docs/DOCUSAURUS_IMPORT.md +378 -0
  86. package/docs/_category_.json +8 -0
  87. package/docs/app-manifest.md +272 -0
  88. package/docs/building-for-platform.md +315 -0
  89. package/docs/dev-tools.md +291 -0
  90. package/docs/getting-started.md +180 -0
  91. package/docs/gxp-store.md +305 -0
  92. package/docs/index.md +44 -0
  93. package/package.json +77 -0
  94. package/runtime/PortalContainer.vue +326 -0
  95. package/runtime/dev-tools/DevToolsModal.vue +217 -0
  96. package/runtime/dev-tools/LayoutSwitcher.vue +221 -0
  97. package/runtime/dev-tools/MockDataEditor.vue +621 -0
  98. package/runtime/dev-tools/SocketSimulator.vue +562 -0
  99. package/runtime/dev-tools/StoreInspector.vue +644 -0
  100. package/runtime/dev-tools/index.js +6 -0
  101. package/runtime/gxpStringsPlugin.js +428 -0
  102. package/runtime/index.html +22 -0
  103. package/runtime/main.js +32 -0
  104. package/runtime/mock-api/auth-middleware.js +97 -0
  105. package/runtime/mock-api/image-generator.js +221 -0
  106. package/runtime/mock-api/index.js +197 -0
  107. package/runtime/mock-api/response-generator.js +394 -0
  108. package/runtime/mock-api/route-generator.js +323 -0
  109. package/runtime/mock-api/socket-triggers.js +371 -0
  110. package/runtime/mock-api/spec-loader.js +300 -0
  111. package/runtime/server.js +180 -0
  112. package/runtime/stores/gxpPortalConfigStore.js +554 -0
  113. package/runtime/stores/index.js +6 -0
  114. package/runtime/vite-inspector-plugin.js +749 -0
  115. package/runtime/vite-source-tracker-plugin.js +232 -0
  116. package/runtime/vite.config.js +402 -0
  117. package/scripts/launch-chrome.js +90 -0
  118. package/scripts/pack-chrome.js +91 -0
  119. package/socket-events/AiSessionMessageCreated.json +18 -0
  120. package/socket-events/SocialStreamPostCreated.json +24 -0
  121. package/socket-events/SocialStreamPostVariantCompleted.json +23 -0
  122. package/template/README.md +332 -0
  123. package/template/app-manifest.json +32 -0
  124. package/template/dev-assets/images/avatar-placeholder.png +0 -0
  125. package/template/dev-assets/images/background-placeholder.jpg +0 -0
  126. package/template/dev-assets/images/banner-placeholder.jpg +0 -0
  127. package/template/dev-assets/images/icon-placeholder.png +0 -0
  128. package/template/dev-assets/images/logo-placeholder.png +0 -0
  129. package/template/dev-assets/images/product-placeholder.jpg +0 -0
  130. package/template/dev-assets/images/thumbnail-placeholder.jpg +0 -0
  131. package/template/env.example +51 -0
  132. package/template/gitignore +53 -0
  133. package/template/index.html +22 -0
  134. package/template/main.js +28 -0
  135. package/template/src/DemoPage.vue +459 -0
  136. package/template/src/Plugin.vue +38 -0
  137. package/template/src/stores/index.js +9 -0
  138. package/template/src/stores/test-data.json +173 -0
  139. package/template/theme-layouts/AdditionalStyling.css +0 -0
  140. package/template/theme-layouts/PrivateLayout.vue +39 -0
  141. package/template/theme-layouts/PublicLayout.vue +39 -0
  142. package/template/theme-layouts/SystemLayout.vue +39 -0
  143. package/template/vite.config.js +333 -0
  144. package/tsconfig.tui.json +21 -0
  145. package/vite.config.js +164 -0
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Init Command
3
+ *
4
+ * Sets up a new GxP project or updates an existing one.
5
+ */
6
+
7
+ const path = require("path");
8
+ const fs = require("fs");
9
+ const { REQUIRED_DEPENDENCIES } = require("../constants");
10
+ const {
11
+ findProjectRoot,
12
+ resolveGxPaths,
13
+ promptUser,
14
+ safeCopyFile,
15
+ createPackageJson,
16
+ installDependencies,
17
+ updateExistingProject,
18
+ ensureMkcertInstalled,
19
+ generateSSLCertificates,
20
+ updateEnvWithCertPaths,
21
+ } = require("../utils");
22
+
23
+ /**
24
+ * Initialize command - sets up a new GxP project or updates existing one
25
+ */
26
+ async function initCommand(argv) {
27
+ const currentDir = process.cwd();
28
+ const hasPackageJson = fs.existsSync(path.join(currentDir, "package.json"));
29
+ let projectPath = currentDir;
30
+ let projectName;
31
+ let sslSetup = false;
32
+
33
+ if (!hasPackageJson && !argv.name) {
34
+ // New project - prompt for name
35
+ projectName = await promptUser("Enter project name: ");
36
+ if (!projectName) {
37
+ console.error("Project name is required!");
38
+ process.exit(1);
39
+ }
40
+
41
+ // Create project directory
42
+ projectPath = path.join(currentDir, projectName);
43
+ if (fs.existsSync(projectPath)) {
44
+ console.error(`Directory ${projectName} already exists!`);
45
+ process.exit(1);
46
+ }
47
+
48
+ console.log(`Creating new project: ${projectName}`);
49
+ fs.mkdirSync(projectPath, { recursive: true });
50
+
51
+ // Create package.json
52
+ createPackageJson(projectPath, projectName);
53
+
54
+ // Install dependencies
55
+ installDependencies(projectPath);
56
+ } else if (hasPackageJson) {
57
+ // Existing project - update it
58
+ console.log("Updating existing project...");
59
+ updateExistingProject(projectPath);
60
+ } else if (argv.name) {
61
+ // New project with provided name
62
+ projectName = argv.name;
63
+ projectPath = path.join(currentDir, projectName);
64
+
65
+ if (fs.existsSync(projectPath)) {
66
+ console.error(`Directory ${projectName} already exists!`);
67
+ process.exit(1);
68
+ }
69
+
70
+ console.log(`Creating new project: ${projectName}`);
71
+ fs.mkdirSync(projectPath, { recursive: true });
72
+ createPackageJson(projectPath, projectName);
73
+ installDependencies(projectPath);
74
+ }
75
+
76
+ // Copy template files
77
+ // Note: PortalContainer.vue (formerly App.vue) is now in runtime/ and accessed via @gx-runtime alias
78
+ // Users don't need a copy - it's immutable and loaded from node_modules
79
+ const paths = resolveGxPaths();
80
+ // Note: main.js, index.html, and vite.config.js are NOT copied by default.
81
+ // They are served from the runtime directory. Users can publish them
82
+ // for customization using: gxdev publish main.js / index.html / vite.config.js
83
+ const filesToCopy = [
84
+ {
85
+ src: "theme-layouts/SystemLayout.vue",
86
+ dest: "theme-layouts/SystemLayout.vue",
87
+ desc: "SystemLayout.vue",
88
+ },
89
+ {
90
+ src: "theme-layouts/PrivateLayout.vue",
91
+ dest: "theme-layouts/PrivateLayout.vue",
92
+ desc: "PrivateLayout.vue",
93
+ },
94
+ {
95
+ src: "theme-layouts/PublicLayout.vue",
96
+ dest: "theme-layouts/PublicLayout.vue",
97
+ desc: "PublicLayout.vue",
98
+ },
99
+ {
100
+ src: "theme-layouts/AdditionalStyling.css",
101
+ dest: "theme-layouts/AdditionalStyling.css",
102
+ desc: "AdditionalStyling.css",
103
+ },
104
+ {
105
+ src: "src/stores/index.js",
106
+ dest: "src/stores/index.js",
107
+ desc: "Pinia store setup",
108
+ },
109
+ {
110
+ src: "src/Plugin.vue",
111
+ dest: "src/Plugin.vue",
112
+ desc: "Plugin.vue (Your app entry point)",
113
+ },
114
+ {
115
+ src: "src/DemoPage.vue",
116
+ dest: "src/DemoPage.vue",
117
+ desc: "DemoPage.vue (Example component)",
118
+ },
119
+ {
120
+ src: "app-manifest.json",
121
+ dest: "app-manifest.json",
122
+ desc: "app-manifest.json",
123
+ },
124
+ { src: "env.example", dest: ".env.example", desc: ".env.example" },
125
+ { src: "gitignore", dest: ".gitignore", desc: ".gitignore" },
126
+ {
127
+ src: "README.md",
128
+ dest: "README.md",
129
+ desc: "README.md (Project documentation)",
130
+ },
131
+ ];
132
+
133
+ // Copy template files
134
+ filesToCopy.forEach((file) => {
135
+ const srcPath = path.join(paths.templateDir, file.src);
136
+ const destPath = path.join(projectPath, file.dest);
137
+ safeCopyFile(srcPath, destPath, file.desc);
138
+ });
139
+
140
+ // Create /src/assets/ directory for user assets
141
+ const assetsDir = path.join(projectPath, "src", "assets");
142
+ if (!fs.existsSync(assetsDir)) {
143
+ fs.mkdirSync(assetsDir, { recursive: true });
144
+ // Add a .gitkeep to ensure the directory is tracked
145
+ fs.writeFileSync(path.join(assetsDir, ".gitkeep"), "");
146
+ console.log("✓ Created src/assets/ directory for project assets");
147
+ }
148
+
149
+ // Create .env file from .env.example
150
+ const envExamplePath = path.join(projectPath, ".env.example");
151
+ const envPath = path.join(projectPath, ".env");
152
+ if (fs.existsSync(envExamplePath) && !fs.existsSync(envPath)) {
153
+ fs.copyFileSync(envExamplePath, envPath);
154
+ console.log("✓ Created .env file from .env.example");
155
+ }
156
+
157
+ // Copy extension management scripts for new projects
158
+ if (!hasPackageJson || argv.name) {
159
+ const scriptsDir = path.join(projectPath, "scripts");
160
+ if (!fs.existsSync(scriptsDir)) {
161
+ fs.mkdirSync(scriptsDir, { recursive: true });
162
+ }
163
+
164
+ // Copy launch-chrome.js script
165
+ const launchChromeSource = path.join(
166
+ paths.templateDir,
167
+ "../scripts/launch-chrome.js"
168
+ );
169
+ const launchChromeDest = path.join(scriptsDir, "launch-chrome.js");
170
+ if (fs.existsSync(launchChromeSource)) {
171
+ safeCopyFile(
172
+ launchChromeSource,
173
+ launchChromeDest,
174
+ "Chrome launcher script"
175
+ );
176
+ }
177
+
178
+ // Copy pack-chrome.js script
179
+ const packChromeSource = path.join(
180
+ paths.templateDir,
181
+ "../scripts/pack-chrome.js"
182
+ );
183
+ const packChromeDest = path.join(scriptsDir, "pack-chrome.js");
184
+ if (fs.existsSync(packChromeSource)) {
185
+ safeCopyFile(packChromeSource, packChromeDest, "Chrome packaging script");
186
+ }
187
+
188
+ // Copy socket events directory for simulation (root level for CLI access)
189
+ const socketEventsSource = paths.socketEventsDir;
190
+ const socketEventsDest = path.join(projectPath, "socket-events");
191
+ if (fs.existsSync(socketEventsSource)) {
192
+ if (!fs.existsSync(socketEventsDest)) {
193
+ fs.mkdirSync(socketEventsDest, { recursive: true });
194
+ }
195
+
196
+ const eventFiles = fs
197
+ .readdirSync(socketEventsSource)
198
+ .filter((file) => file.endsWith(".json"));
199
+ eventFiles.forEach((file) => {
200
+ const srcPath = path.join(socketEventsSource, file);
201
+ const destPath = path.join(socketEventsDest, file);
202
+ safeCopyFile(srcPath, destPath, `Socket event: ${file}`);
203
+ });
204
+ }
205
+ }
206
+
207
+ // Setup SSL certificates for new projects
208
+ if (!hasPackageJson || argv.name) {
209
+ // Ask user if they want to set up SSL certificates
210
+ const sslChoice = await promptUser(
211
+ "Do you want to set up SSL certificates for HTTPS development? (Y/n): "
212
+ );
213
+ sslSetup =
214
+ sslChoice.toLowerCase() !== "n" && sslChoice.toLowerCase() !== "no";
215
+
216
+ if (sslSetup) {
217
+ console.log("\n🔒 Setting up HTTPS development environment...");
218
+ ensureMkcertInstalled();
219
+ const certs = generateSSLCertificates(projectPath);
220
+
221
+ // Update .env file with actual certificate names if SSL setup was successful
222
+ if (certs) {
223
+ updateEnvWithCertPaths(projectPath, certs);
224
+ }
225
+ } else {
226
+ console.log(
227
+ "\n⚠️ Skipping SSL setup. You can set it up later with: npm run setup-ssl"
228
+ );
229
+ }
230
+ }
231
+
232
+ console.log("✅ Project setup complete!");
233
+ console.log(
234
+ "🎨 GX ComponentKit component library included for rapid kiosk development!"
235
+ );
236
+ console.log("🗃️ GxP Datastore included with Pinia integration!");
237
+ if (!hasPackageJson) {
238
+ console.log(`📁 Navigate to your project: cd ${projectName}`);
239
+ }
240
+ console.log("⚙️ Environment file (.env) ready - customize as needed");
241
+
242
+ if (sslSetup) {
243
+ console.log("🔒 Start HTTPS development with Socket.IO: npm run dev");
244
+ console.log("🔒 Start HTTPS development only: npm run dev-app");
245
+ console.log("🌐 Start HTTP development: npm run dev-http");
246
+ } else {
247
+ console.log("🌐 Start development: npm run dev-http");
248
+ console.log("🔧 Setup SSL certificates: npm run setup-ssl");
249
+ console.log("🔒 Then use HTTPS development: npm run dev");
250
+ }
251
+ console.log("");
252
+ console.log("📖 Project structure:");
253
+ console.log(" • src/Plugin.vue - Your app entry point (customize this!)");
254
+ console.log(" • src/DemoPage.vue - Example component");
255
+ console.log(" • theme-layouts/ - Customizable layout templates");
256
+ console.log(
257
+ " • main.js - Development entry (loads PortalContainer from toolkit)"
258
+ );
259
+ console.log("📚 Check README.md for detailed usage instructions");
260
+
261
+ // For new projects, offer to launch TUI
262
+ if (projectName) {
263
+ console.log("");
264
+ const launchChoice = await promptUser(
265
+ "Would you like to open the project in the interactive TUI? (Y/n): "
266
+ );
267
+ const shouldLaunch =
268
+ launchChoice.toLowerCase() !== "n" && launchChoice.toLowerCase() !== "no";
269
+
270
+ if (shouldLaunch) {
271
+ console.log(`\n🚀 Launching gxdev TUI in ${projectName}...`);
272
+ // Change to project directory and launch TUI
273
+ process.chdir(projectPath);
274
+
275
+ // Try to launch TUI
276
+ const tuiPath = path.join(
277
+ __dirname,
278
+ "..",
279
+ "..",
280
+ "..",
281
+ "dist",
282
+ "tui",
283
+ "index.js"
284
+ );
285
+ if (fs.existsSync(tuiPath)) {
286
+ try {
287
+ const { startTUI } = await import(tuiPath);
288
+ startTUI({ autoStart: [], args: {} });
289
+ } catch (err) {
290
+ console.error("Could not launch TUI:", err.message);
291
+ console.log(`\nTo start manually:\n cd ${projectName}\n gxdev`);
292
+ }
293
+ } else {
294
+ console.log(
295
+ 'TUI not available. Run "npm run build:tui" in gx-devtools first.'
296
+ );
297
+ console.log(`\nTo start manually:\n cd ${projectName}\n gxdev`);
298
+ }
299
+ } else {
300
+ console.log(`\nTo get started:\n cd ${projectName}\n gxdev`);
301
+ }
302
+ }
303
+ }
304
+
305
+ module.exports = {
306
+ initCommand,
307
+ };
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Publish Command
3
+ *
4
+ * Copies package files to local project for customization.
5
+ */
6
+
7
+ const path = require("path");
8
+ const fs = require("fs");
9
+ const {
10
+ findProjectRoot,
11
+ resolveGxPaths,
12
+ promptUser,
13
+ safeCopyFile,
14
+ } = require("../utils");
15
+
16
+ /**
17
+ * Publish command - copies package files to local project
18
+ */
19
+ async function publishCommand(argv) {
20
+ const projectPath = findProjectRoot();
21
+ const paths = resolveGxPaths();
22
+
23
+ const fileName = argv.file || argv._[1]; // Support both --file and positional argument
24
+
25
+ if (!fileName) {
26
+ console.log("📦 Available files to publish:");
27
+ console.log("");
28
+ console.log(" Development files (customize dev environment):");
29
+ console.log(" • main.js - Development entry point");
30
+ console.log(" • index.html - HTML template");
31
+ console.log(" • vite.config.js - Vite build configuration");
32
+ console.log("");
33
+ console.log(" Runtime files (advanced customization):");
34
+ console.log(" • server.js - Socket.IO server file");
35
+ console.log(" • gxpPortalConfigStore.js - GxP datastore");
36
+ console.log("");
37
+ console.log("💡 Usage:");
38
+ console.log(" gxdev publish main.js");
39
+ console.log(" gxdev publish vite.config.js");
40
+ console.log(" gxdev publish server.js");
41
+ return;
42
+ }
43
+
44
+ const publishableFiles = {
45
+ "main.js": {
46
+ src: "main.js",
47
+ dest: "main.js",
48
+ desc: "Development entry point",
49
+ location: "runtime",
50
+ },
51
+ "index.html": {
52
+ src: "index.html",
53
+ dest: "index.html",
54
+ desc: "HTML template",
55
+ location: "runtime",
56
+ },
57
+ "vite.config.js": {
58
+ src: "vite.config.js",
59
+ dest: "vite.config.js",
60
+ desc: "Vite build configuration",
61
+ location: "runtime",
62
+ },
63
+ "server.js": {
64
+ src: "server.js",
65
+ dest: "server.js",
66
+ desc: "Socket.IO server file",
67
+ location: "runtime",
68
+ },
69
+ "gxpPortalConfigStore.js": {
70
+ src: "stores/gxpPortalConfigStore.js",
71
+ dest: "src/stores/gxpPortalConfigStore.js",
72
+ desc: "GxP datastore",
73
+ location: "runtime",
74
+ },
75
+ };
76
+
77
+ const fileConfig = publishableFiles[fileName];
78
+ if (!fileConfig) {
79
+ console.error(`❌ Unknown file: ${fileName}`);
80
+ console.log(
81
+ "📦 Available files:",
82
+ Object.keys(publishableFiles).join(", ")
83
+ );
84
+ process.exit(1);
85
+ }
86
+
87
+ // Get source path from appropriate directory
88
+ const sourceDir =
89
+ fileConfig.location === "runtime" ? paths.runtimeDir : paths.templateDir;
90
+ const srcPath = path.join(sourceDir, fileConfig.src);
91
+ const destPath = path.join(projectPath, fileConfig.dest);
92
+
93
+ if (!fs.existsSync(srcPath)) {
94
+ console.error(`❌ Source file not found: ${srcPath}`);
95
+ process.exit(1);
96
+ }
97
+
98
+ // Check if local file already exists
99
+ if (fs.existsSync(destPath)) {
100
+ const overwrite = await promptUser(
101
+ `📁 ${fileConfig.dest} already exists. Overwrite? (y/N): `
102
+ );
103
+ if (overwrite.toLowerCase() !== "y" && overwrite.toLowerCase() !== "yes") {
104
+ console.log("📦 Publish cancelled");
105
+ return;
106
+ }
107
+ }
108
+
109
+ // Ensure destination directory exists
110
+ const destDir = path.dirname(destPath);
111
+ if (!fs.existsSync(destDir)) {
112
+ fs.mkdirSync(destDir, { recursive: true });
113
+ }
114
+
115
+ // Copy the file
116
+ fs.copyFileSync(srcPath, destPath);
117
+ console.log(`Creating ${fileConfig.desc}`);
118
+ console.log(`✅ Published ${fileName} to project`);
119
+ console.log(`📁 Local file: ${fileConfig.dest}`);
120
+
121
+ // Special handling for index.html - update main.js reference to local path
122
+ if (fileName === "index.html") {
123
+ try {
124
+ let content = fs.readFileSync(destPath, "utf-8");
125
+ // Update the runtime reference to local reference
126
+ if (content.includes('src="/@gx-runtime/main.js"')) {
127
+ content = content.replace(
128
+ 'src="/@gx-runtime/main.js"',
129
+ 'src="/main.js"'
130
+ );
131
+ fs.writeFileSync(destPath, content);
132
+ console.log("📝 Updated index.html to reference local main.js");
133
+ console.log(
134
+ "💡 Make sure to also publish main.js: gxdev publish main.js"
135
+ );
136
+ }
137
+ } catch (error) {
138
+ console.warn("⚠️ Could not update index.html:", error.message);
139
+ }
140
+ }
141
+
142
+ // Special handling for gxpPortalConfigStore.js - update the import in stores/index.js
143
+ if (fileName === "gxpPortalConfigStore.js") {
144
+ const storeIndexPath = path.join(projectPath, "src/stores/index.js");
145
+ if (fs.existsSync(storeIndexPath)) {
146
+ try {
147
+ let content = fs.readFileSync(storeIndexPath, "utf-8");
148
+ // Match both old (config) and new (runtime) import paths
149
+ const oldImportPatterns = [
150
+ "import { useGxpStore } from '@gramercytech/gx-devtools/config/stores/gxpPortalConfigStore.js';",
151
+ "import { useGxpStore } from '@gramercytech/gx-devtools/config/stores/gxpPortalConfigStore';",
152
+ "import { useGxpStore } from '@gramercytech/gx-devtools/runtime/stores/gxpPortalConfigStore.js';",
153
+ "import { useGxpStore } from '@gramercytech/gx-devtools/runtime/stores/gxpPortalConfigStore';",
154
+ 'import { useGxpStore } from "@gramercytech/gx-devtools/runtime/stores/gxpPortalConfigStore";',
155
+ ];
156
+ const newImport =
157
+ "import { useGxpStore } from './gxpPortalConfigStore.js';";
158
+
159
+ let updated = false;
160
+ for (const oldImport of oldImportPatterns) {
161
+ if (content.includes(oldImport)) {
162
+ content = content.replace(oldImport, newImport);
163
+ updated = true;
164
+ break;
165
+ }
166
+ }
167
+
168
+ if (updated) {
169
+ fs.writeFileSync(storeIndexPath, content);
170
+ console.log(
171
+ "📝 Updated stores/index.js to use local gxpPortalConfigStore.js"
172
+ );
173
+ }
174
+ } catch (error) {
175
+ console.warn(
176
+ "⚠️ Could not update stores/index.js import:",
177
+ error.message
178
+ );
179
+ }
180
+ }
181
+ }
182
+
183
+ console.log("💡 Future gxdev commands will now use your local copy");
184
+ console.log(" Delete the local file to fall back to package version");
185
+ }
186
+
187
+ module.exports = {
188
+ publishCommand,
189
+ };
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Socket Command
3
+ *
4
+ * Simulates socket events for development testing.
5
+ */
6
+
7
+ const path = require("path");
8
+ const fs = require("fs");
9
+ const { findProjectRoot, resolveGxPaths } = require("../utils");
10
+
11
+ /**
12
+ * Socket simulation command - sends JSON events to the Socket.IO server
13
+ */
14
+ async function socketCommand(argv) {
15
+ const action = argv.action;
16
+
17
+ if (action === "list") {
18
+ listSocketEvents();
19
+ } else if (action === "send") {
20
+ await sendSocketEvent(argv.event, argv.identifier);
21
+ } else {
22
+ console.error("❌ Invalid socket action. Use 'list' or 'send'");
23
+ process.exit(1);
24
+ }
25
+ }
26
+
27
+ function listSocketEvents() {
28
+ const projectPath = findProjectRoot();
29
+ const paths = resolveGxPaths();
30
+
31
+ // Check local project socket-events first, then fall back to toolkit's socket-events
32
+ let eventsDir = path.join(projectPath, "socket-events");
33
+ if (!fs.existsSync(eventsDir)) {
34
+ eventsDir = paths.socketEventsDir;
35
+ }
36
+
37
+ if (!fs.existsSync(eventsDir)) {
38
+ console.log("❌ No socket events directory found");
39
+ console.log(`📁 Looking in: ${eventsDir}`);
40
+ return;
41
+ }
42
+
43
+ const eventFiles = fs
44
+ .readdirSync(eventsDir)
45
+ .filter((file) => file.endsWith(".json"));
46
+
47
+ if (eventFiles.length === 0) {
48
+ console.log("❌ No socket event files found");
49
+ return;
50
+ }
51
+
52
+ console.log("📡 Available socket events:");
53
+ console.log("");
54
+
55
+ eventFiles.forEach((file) => {
56
+ const eventPath = path.join(eventsDir, file);
57
+ try {
58
+ const eventData = JSON.parse(fs.readFileSync(eventPath, "utf-8"));
59
+ const eventName = path.basename(file, ".json");
60
+ console.log(`🎯 ${eventName}`);
61
+ console.log(` Event: ${eventData.event}`);
62
+ console.log(` Channel: ${eventData.channel}`);
63
+ if (eventData.data.id) {
64
+ console.log(` Data ID: ${eventData.data.id}`);
65
+ }
66
+ console.log("");
67
+ } catch (error) {
68
+ console.error(`❌ Error reading ${file}: ${error.message}`);
69
+ }
70
+ });
71
+
72
+ console.log("💡 Usage:");
73
+ console.log(" gxdev socket send --event AiSessionMessageCreated");
74
+ console.log(
75
+ " gxdev socket send --event SocialStreamPostCreated --identifier social_stream"
76
+ );
77
+ }
78
+
79
+ async function sendSocketEvent(eventName, identifier) {
80
+ if (!eventName) {
81
+ console.error("❌ Event name is required");
82
+ console.log("💡 Use: gxdev socket send --event <EventName>");
83
+ process.exit(1);
84
+ }
85
+
86
+ const projectPath = findProjectRoot();
87
+ const paths = resolveGxPaths();
88
+ const socketIoPort = process.env.SOCKET_IO_PORT || 3069;
89
+
90
+ // Check local project socket-events first, then fall back to toolkit's socket-events
91
+ let eventsDir = path.join(projectPath, "socket-events");
92
+ if (!fs.existsSync(eventsDir)) {
93
+ eventsDir = paths.socketEventsDir;
94
+ }
95
+
96
+ const eventPath = path.join(eventsDir, `${eventName}.json`);
97
+
98
+ if (!fs.existsSync(eventPath)) {
99
+ console.error(`❌ Event file not found: ${eventName}.json`);
100
+ console.log(`📁 Looking in: ${eventsDir}`);
101
+ console.log("💡 Use 'gxdev socket list' to see available events");
102
+ process.exit(1);
103
+ }
104
+
105
+ try {
106
+ let eventData = JSON.parse(fs.readFileSync(eventPath, "utf-8"));
107
+
108
+ // If identifier is provided, update the channel
109
+ if (identifier) {
110
+ // Try to extract model from the original channel
111
+ const channelParts = eventData.channel.split(".");
112
+ if (channelParts.length >= 2) {
113
+ const model = channelParts[1];
114
+ eventData.channel = `private.${model}.${identifier}`;
115
+ }
116
+ }
117
+
118
+ // Send the event via HTTP to the Socket.IO server
119
+ const socketUrl = `https://localhost:${socketIoPort}`;
120
+
121
+ console.log(`📡 Sending socket event: ${eventData.event}`);
122
+ console.log(`📺 Channel: ${eventData.channel}`);
123
+ console.log(`📦 Data:`, JSON.stringify(eventData.data, null, 2));
124
+
125
+ // Use axios to send the event to our Socket.IO server
126
+ const axios = require("axios");
127
+
128
+ try {
129
+ await axios.post(`${socketUrl}/emit`, {
130
+ event: eventData.event,
131
+ channel: eventData.channel,
132
+ data: eventData.data,
133
+ });
134
+
135
+ console.log("✅ Socket event sent successfully!");
136
+ console.log(
137
+ "👂 Check your app console for the received event in the store"
138
+ );
139
+ } catch (error) {
140
+ if (error.code === "ECONNREFUSED") {
141
+ console.error("❌ Cannot connect to Socket.IO server");
142
+ console.log("💡 Make sure the server is running:");
143
+ console.log(" npm run dev");
144
+ console.log(" or");
145
+ console.log(" nodemon server.js");
146
+ } else {
147
+ console.error(`❌ Error sending event: ${error.message}`);
148
+ }
149
+ }
150
+ } catch (error) {
151
+ console.error(`❌ Error reading event file: ${error.message}`);
152
+ process.exit(1);
153
+ }
154
+ }
155
+
156
+ module.exports = {
157
+ socketCommand,
158
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * SSL Command
3
+ *
4
+ * Sets up SSL certificates for HTTPS development.
5
+ */
6
+
7
+ const {
8
+ findProjectRoot,
9
+ ensureMkcertInstalled,
10
+ generateSSLCertificates,
11
+ updateEnvWithCertPaths,
12
+ } = require("../utils");
13
+
14
+ /**
15
+ * Setup SSL certificates command
16
+ */
17
+ function setupSSLCommand() {
18
+ const projectPath = findProjectRoot();
19
+
20
+ console.log("Setting up SSL certificates for HTTPS development...");
21
+
22
+ // Ensure mkcert is available
23
+ ensureMkcertInstalled();
24
+
25
+ // Generate certificates
26
+ const certs = generateSSLCertificates(projectPath);
27
+
28
+ if (certs) {
29
+ // Update .env file with actual certificate names
30
+ updateEnvWithCertPaths(projectPath, certs);
31
+
32
+ console.log("✅ SSL setup complete!");
33
+ console.log("🔒 Your development server will now use HTTPS");
34
+ console.log("📁 Certificates stored in .certs/ directory");
35
+ console.log(
36
+ "🚀 Run 'npm run dev' to start HTTPS development with Socket.IO"
37
+ );
38
+ } else {
39
+ console.log(
40
+ "❌ SSL setup failed. You can still use HTTP with 'npm run dev-http'"
41
+ );
42
+ }
43
+ }
44
+
45
+ module.exports = {
46
+ setupSSLCommand,
47
+ };