@gxp-dev/tools 2.0.63 → 2.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,562 +1,570 @@
1
1
  <template>
2
- <div class="socket-simulator">
3
- <div class="simulator-header">
4
- <div class="connection-status" :class="{ connected: isConnected }">
5
- <span class="status-dot"></span>
6
- {{ isConnected ? 'Connected' : 'Disconnected' }}
7
- </div>
8
- <span class="socket-port">Port: {{ socketPort }}</span>
9
- </div>
10
-
11
- <div class="event-list">
12
- <h4>Available Events</h4>
13
- <p class="helper-text">
14
- Click an event to send it. Events are loaded from <code>socket-events/</code> directory.
15
- </p>
16
-
17
- <div v-if="events.length === 0" class="empty-state">
18
- <p>No socket events found.</p>
19
- <p class="hint">Create JSON files in <code>socket-events/</code> to add events.</p>
20
- </div>
21
-
22
- <div v-else class="events-grid">
23
- <div
24
- v-for="event in events"
25
- :key="event.name"
26
- class="event-card"
27
- @click="selectEvent(event)"
28
- :class="{ selected: selectedEvent?.name === event.name }"
29
- >
30
- <div class="event-name">{{ event.name }}</div>
31
- <div class="event-type">{{ event.event }}</div>
32
- </div>
33
- </div>
34
- </div>
35
-
36
- <div v-if="selectedEvent" class="event-editor">
37
- <h4>Event Details: {{ selectedEvent.name }}</h4>
38
-
39
- <div class="editor-field">
40
- <label>Event Type:</label>
41
- <input v-model="editableEvent.event" class="field-input" />
42
- </div>
43
-
44
- <div class="editor-field">
45
- <label>Channel:</label>
46
- <input v-model="editableEvent.channel" class="field-input" />
47
- </div>
48
-
49
- <div class="editor-field">
50
- <label>Data (JSON):</label>
51
- <textarea
52
- v-model="editableEventData"
53
- class="field-textarea"
54
- rows="8"
55
- @input="validateJson"
56
- ></textarea>
57
- <span v-if="jsonError" class="json-error">{{ jsonError }}</span>
58
- </div>
59
-
60
- <div class="editor-actions">
61
- <button class="btn btn-primary" @click="sendEvent" :disabled="!!jsonError">
62
- Send Event
63
- </button>
64
- <button class="btn btn-secondary" @click="resetEvent">
65
- Reset
66
- </button>
67
- </div>
68
- </div>
69
-
70
- <div class="event-log">
71
- <div class="log-header">
72
- <h4>Event Log</h4>
73
- <button class="btn-clear" @click="clearLog">Clear</button>
74
- </div>
75
- <div class="log-entries">
76
- <div v-if="eventLog.length === 0" class="empty-log">
77
- No events sent yet
78
- </div>
79
- <div
80
- v-for="(entry, index) in eventLog"
81
- :key="index"
82
- class="log-entry"
83
- :class="entry.type"
84
- >
85
- <span class="log-time">{{ entry.time }}</span>
86
- <span class="log-direction">{{ entry.direction }}</span>
87
- <span class="log-event">{{ entry.event }}</span>
88
- <span class="log-status">{{ entry.status }}</span>
89
- </div>
90
- </div>
91
- </div>
92
- </div>
2
+ <div class="socket-simulator">
3
+ <div class="simulator-header">
4
+ <div class="connection-status" :class="{ connected: isConnected }">
5
+ <span class="status-dot"></span>
6
+ {{ isConnected ? "Connected" : "Disconnected" }}
7
+ </div>
8
+ <span class="socket-port">Port: {{ socketPort }}</span>
9
+ </div>
10
+
11
+ <div class="event-list">
12
+ <h4>Available Events</h4>
13
+ <p class="helper-text">
14
+ Click an event to send it. Events are loaded from
15
+ <code>socket-events/</code> directory.
16
+ </p>
17
+
18
+ <div v-if="events.length === 0" class="empty-state">
19
+ <p>No socket events found.</p>
20
+ <p class="hint">
21
+ Create JSON files in <code>socket-events/</code> to add events.
22
+ </p>
23
+ </div>
24
+
25
+ <div v-else class="events-grid">
26
+ <div
27
+ v-for="event in events"
28
+ :key="event.name"
29
+ class="event-card"
30
+ @click="selectEvent(event)"
31
+ :class="{ selected: selectedEvent?.name === event.name }"
32
+ >
33
+ <div class="event-name">{{ event.name }}</div>
34
+ <div class="event-type">{{ event.event }}</div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+
39
+ <div v-if="selectedEvent" class="event-editor">
40
+ <h4>Event Details: {{ selectedEvent.name }}</h4>
41
+
42
+ <div class="editor-field">
43
+ <label>Event Type:</label>
44
+ <input v-model="editableEvent.event" class="field-input" />
45
+ </div>
46
+
47
+ <div class="editor-field">
48
+ <label>Channel:</label>
49
+ <input v-model="editableEvent.channel" class="field-input" />
50
+ </div>
51
+
52
+ <div class="editor-field">
53
+ <label>Data (JSON):</label>
54
+ <textarea
55
+ v-model="editableEventData"
56
+ class="field-textarea"
57
+ rows="8"
58
+ @input="validateJson"
59
+ ></textarea>
60
+ <span v-if="jsonError" class="json-error">{{ jsonError }}</span>
61
+ </div>
62
+
63
+ <div class="editor-actions">
64
+ <button
65
+ class="btn btn-primary"
66
+ @click="sendEvent"
67
+ :disabled="!!jsonError"
68
+ >
69
+ Send Event
70
+ </button>
71
+ <button class="btn btn-secondary" @click="resetEvent">Reset</button>
72
+ </div>
73
+ </div>
74
+
75
+ <div class="event-log">
76
+ <div class="log-header">
77
+ <h4>Event Log</h4>
78
+ <button class="btn-clear" @click="clearLog">Clear</button>
79
+ </div>
80
+ <div class="log-entries">
81
+ <div v-if="eventLog.length === 0" class="empty-log">
82
+ No events sent yet
83
+ </div>
84
+ <div
85
+ v-for="(entry, index) in eventLog"
86
+ :key="index"
87
+ class="log-entry"
88
+ :class="entry.type"
89
+ >
90
+ <span class="log-time">{{ entry.time }}</span>
91
+ <span class="log-direction">{{ entry.direction }}</span>
92
+ <span class="log-event">{{ entry.event }}</span>
93
+ <span class="log-status">{{ entry.status }}</span>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
93
98
  </template>
94
99
 
95
100
  <script setup>
96
- import { ref, reactive, computed, onMounted } from 'vue';
101
+ import { ref, reactive, computed, onMounted } from "vue"
97
102
 
98
103
  const props = defineProps({
99
- store: {
100
- type: Object,
101
- required: true
102
- }
103
- });
104
-
105
- const socketPort = ref(3069);
106
- const isConnected = ref(false);
107
- const events = ref([]);
108
- const selectedEvent = ref(null);
104
+ store: {
105
+ type: Object,
106
+ required: true,
107
+ },
108
+ })
109
+
110
+ const socketPort = ref(3069)
111
+ const isConnected = ref(false)
112
+ const events = ref([])
113
+ const selectedEvent = ref(null)
109
114
  const editableEvent = reactive({
110
- event: '',
111
- channel: '',
112
- data: {}
113
- });
114
- const editableEventData = ref('');
115
- const jsonError = ref('');
116
- const eventLog = ref([]);
115
+ event: "",
116
+ channel: "",
117
+ data: {},
118
+ })
119
+ const editableEventData = ref("")
120
+ const jsonError = ref("")
121
+ const eventLog = ref([])
117
122
 
118
123
  // Default events if none are loaded
119
124
  const defaultEvents = [
120
- {
121
- name: 'AiSessionMessageCreated',
122
- event: 'AiSessionMessageCreated',
123
- channel: 'private.ai_session.1',
124
- data: {
125
- id: 1,
126
- message: 'Test AI response',
127
- session_id: 1,
128
- created_at: new Date().toISOString()
129
- }
130
- },
131
- {
132
- name: 'SocialStreamPostCreated',
133
- event: 'SocialStreamPostCreated',
134
- channel: 'private.social_stream.1',
135
- data: {
136
- id: 1,
137
- content: 'Test social post',
138
- author: 'Test User',
139
- created_at: new Date().toISOString()
140
- }
141
- },
142
- {
143
- name: 'StateChange',
144
- event: 'state-change',
145
- channel: 'broadcast',
146
- data: {
147
- key: 'test_key',
148
- value: 'test_value',
149
- timestamp: new Date().toISOString()
150
- }
151
- }
152
- ];
125
+ {
126
+ name: "AiSessionMessageCreated",
127
+ event: "AiSessionMessageCreated",
128
+ channel: "private.ai_session.1",
129
+ data: {
130
+ id: 1,
131
+ message: "Test AI response",
132
+ session_id: 1,
133
+ created_at: new Date().toISOString(),
134
+ },
135
+ },
136
+ {
137
+ name: "SocialStreamPostCreated",
138
+ event: "SocialStreamPostCreated",
139
+ channel: "private.social_stream.1",
140
+ data: {
141
+ id: 1,
142
+ content: "Test social post",
143
+ author: "Test User",
144
+ created_at: new Date().toISOString(),
145
+ },
146
+ },
147
+ {
148
+ name: "StateChange",
149
+ event: "state-change",
150
+ channel: "broadcast",
151
+ data: {
152
+ key: "test_key",
153
+ value: "test_value",
154
+ timestamp: new Date().toISOString(),
155
+ },
156
+ },
157
+ ]
153
158
 
154
159
  onMounted(() => {
155
- // Load events - in a real implementation, this would load from socket-events directory
156
- events.value = defaultEvents;
160
+ // Load events - in a real implementation, this would load from socket-events directory
161
+ events.value = defaultEvents
157
162
 
158
- // Check socket connection
159
- checkConnection();
160
- });
163
+ // Check socket connection
164
+ checkConnection()
165
+ })
161
166
 
162
167
  function checkConnection() {
163
- // Try to connect to socket server
164
- const socket = props.store?.sockets?.primary;
165
- isConnected.value = !!socket;
168
+ // Try to connect to socket server
169
+ const socket = props.store?.sockets?.primary
170
+ isConnected.value = !!socket
166
171
  }
167
172
 
168
173
  function selectEvent(event) {
169
- selectedEvent.value = event;
170
- editableEvent.event = event.event;
171
- editableEvent.channel = event.channel;
172
- editableEvent.data = { ...event.data };
173
- editableEventData.value = JSON.stringify(event.data, null, 2);
174
- jsonError.value = '';
174
+ selectedEvent.value = event
175
+ editableEvent.event = event.event
176
+ editableEvent.channel = event.channel
177
+ editableEvent.data = { ...event.data }
178
+ editableEventData.value = JSON.stringify(event.data, null, 2)
179
+ jsonError.value = ""
175
180
  }
176
181
 
177
182
  function validateJson() {
178
- try {
179
- JSON.parse(editableEventData.value);
180
- jsonError.value = '';
181
- } catch (e) {
182
- jsonError.value = 'Invalid JSON: ' + e.message;
183
- }
183
+ try {
184
+ JSON.parse(editableEventData.value)
185
+ jsonError.value = ""
186
+ } catch (e) {
187
+ jsonError.value = "Invalid JSON: " + e.message
188
+ }
184
189
  }
185
190
 
186
191
  function resetEvent() {
187
- if (selectedEvent.value) {
188
- selectEvent(selectedEvent.value);
189
- }
192
+ if (selectedEvent.value) {
193
+ selectEvent(selectedEvent.value)
194
+ }
190
195
  }
191
196
 
192
197
  async function sendEvent() {
193
- if (jsonError.value) return;
194
-
195
- let data;
196
- try {
197
- data = JSON.parse(editableEventData.value);
198
- } catch {
199
- return;
200
- }
201
-
202
- const eventPayload = {
203
- event: editableEvent.event,
204
- channel: editableEvent.channel,
205
- data: data
206
- };
207
-
208
- // Log the send attempt
209
- addLogEntry('send', editableEvent.event, 'pending');
210
-
211
- try {
212
- // Try to send via the store's socket
213
- const socket = props.store?.sockets?.primary;
214
- if (socket && socket.broadcast) {
215
- socket.broadcast(editableEvent.event, data);
216
- updateLastLogEntry('success');
217
- console.log('[DevTools] Socket event sent:', eventPayload);
218
- } else {
219
- // Fallback: try to send via HTTP to the socket server
220
- const response = await fetch(`https://localhost:${socketPort.value}/emit`, {
221
- method: 'POST',
222
- headers: {
223
- 'Content-Type': 'application/json'
224
- },
225
- body: JSON.stringify(eventPayload)
226
- });
227
-
228
- if (response.ok) {
229
- updateLastLogEntry('success');
230
- console.log('[DevTools] Socket event sent via HTTP:', eventPayload);
231
- } else {
232
- throw new Error('HTTP request failed');
233
- }
234
- }
235
- } catch (err) {
236
- updateLastLogEntry('error');
237
- console.error('[DevTools] Failed to send event:', err);
238
- }
198
+ if (jsonError.value) return
199
+
200
+ let data
201
+ try {
202
+ data = JSON.parse(editableEventData.value)
203
+ } catch {
204
+ return
205
+ }
206
+
207
+ const eventPayload = {
208
+ event: editableEvent.event,
209
+ channel: editableEvent.channel,
210
+ data: data,
211
+ }
212
+
213
+ // Log the send attempt
214
+ addLogEntry("send", editableEvent.event, "pending")
215
+
216
+ try {
217
+ // Try to send via the store's socket
218
+ const socket = props.store?.sockets?.primary
219
+ if (socket && socket.broadcast) {
220
+ socket.broadcast(editableEvent.event, data)
221
+ updateLastLogEntry("success")
222
+ console.log("[DevTools] Socket event sent:", eventPayload)
223
+ } else {
224
+ // Fallback: try to send via HTTP to the socket server
225
+ const response = await fetch(
226
+ `https://localhost:${socketPort.value}/emit`,
227
+ {
228
+ method: "POST",
229
+ headers: {
230
+ "Content-Type": "application/json",
231
+ },
232
+ body: JSON.stringify(eventPayload),
233
+ },
234
+ )
235
+
236
+ if (response.ok) {
237
+ updateLastLogEntry("success")
238
+ console.log("[DevTools] Socket event sent via HTTP:", eventPayload)
239
+ } else {
240
+ throw new Error("HTTP request failed")
241
+ }
242
+ }
243
+ } catch (err) {
244
+ updateLastLogEntry("error")
245
+ console.error("[DevTools] Failed to send event:", err)
246
+ }
239
247
  }
240
248
 
241
249
  function addLogEntry(direction, event, status) {
242
- const now = new Date();
243
- const time = now.toLocaleTimeString('en-US', { hour12: false });
250
+ const now = new Date()
251
+ const time = now.toLocaleTimeString("en-US", { hour12: false })
244
252
 
245
- eventLog.value.unshift({
246
- time,
247
- direction: direction === 'send' ? '' : '',
248
- event,
249
- status,
250
- type: status
251
- });
253
+ eventLog.value.unshift({
254
+ time,
255
+ direction: direction === "send" ? "" : "",
256
+ event,
257
+ status,
258
+ type: status,
259
+ })
252
260
 
253
- // Keep only last 50 entries
254
- if (eventLog.value.length > 50) {
255
- eventLog.value.pop();
256
- }
261
+ // Keep only last 50 entries
262
+ if (eventLog.value.length > 50) {
263
+ eventLog.value.pop()
264
+ }
257
265
  }
258
266
 
259
267
  function updateLastLogEntry(status) {
260
- if (eventLog.value.length > 0) {
261
- eventLog.value[0].status = status;
262
- eventLog.value[0].type = status;
263
- }
268
+ if (eventLog.value.length > 0) {
269
+ eventLog.value[0].status = status
270
+ eventLog.value[0].type = status
271
+ }
264
272
  }
265
273
 
266
274
  function clearLog() {
267
- eventLog.value = [];
275
+ eventLog.value = []
268
276
  }
269
277
  </script>
270
278
 
271
279
  <style scoped>
272
280
  .socket-simulator {
273
- display: flex;
274
- flex-direction: column;
275
- gap: 20px;
281
+ display: flex;
282
+ flex-direction: column;
283
+ gap: 20px;
276
284
  }
277
285
 
278
286
  .simulator-header {
279
- display: flex;
280
- justify-content: space-between;
281
- align-items: center;
282
- padding: 12px 16px;
283
- background: #2d2d2d;
284
- border-radius: 8px;
287
+ display: flex;
288
+ justify-content: space-between;
289
+ align-items: center;
290
+ padding: 12px 16px;
291
+ background: #2d2d2d;
292
+ border-radius: 8px;
285
293
  }
286
294
 
287
295
  .connection-status {
288
- display: flex;
289
- align-items: center;
290
- gap: 8px;
291
- font-size: 13px;
292
- color: #ff6b6b;
296
+ display: flex;
297
+ align-items: center;
298
+ gap: 8px;
299
+ font-size: 13px;
300
+ color: #ff6b6b;
293
301
  }
294
302
 
295
303
  .connection-status.connected {
296
- color: #51cf66;
304
+ color: #51cf66;
297
305
  }
298
306
 
299
307
  .status-dot {
300
- width: 8px;
301
- height: 8px;
302
- border-radius: 50%;
303
- background: currentColor;
308
+ width: 8px;
309
+ height: 8px;
310
+ border-radius: 50%;
311
+ background: currentColor;
304
312
  }
305
313
 
306
314
  .socket-port {
307
- font-size: 12px;
308
- color: #888;
309
- font-family: 'SF Mono', Monaco, monospace;
315
+ font-size: 12px;
316
+ color: #888;
317
+ font-family: "SF Mono", Monaco, monospace;
310
318
  }
311
319
 
312
320
  .event-list h4,
313
321
  .event-editor h4,
314
322
  .event-log h4 {
315
- margin: 0 0 8px 0;
316
- font-size: 13px;
317
- color: #e0e0e0;
323
+ margin: 0 0 8px 0;
324
+ font-size: 13px;
325
+ color: #e0e0e0;
318
326
  }
319
327
 
320
328
  .helper-text {
321
- font-size: 12px;
322
- color: #888;
323
- margin: 0 0 12px 0;
329
+ font-size: 12px;
330
+ color: #888;
331
+ margin: 0 0 12px 0;
324
332
  }
325
333
 
326
334
  .helper-text code,
327
335
  .hint code {
328
- background: #3d3d3d;
329
- padding: 2px 6px;
330
- border-radius: 3px;
331
- font-family: 'SF Mono', Monaco, monospace;
332
- font-size: 11px;
336
+ background: #3d3d3d;
337
+ padding: 2px 6px;
338
+ border-radius: 3px;
339
+ font-family: "SF Mono", Monaco, monospace;
340
+ font-size: 11px;
333
341
  }
334
342
 
335
343
  .empty-state {
336
- padding: 20px;
337
- text-align: center;
338
- color: #666;
339
- background: #2d2d2d;
340
- border-radius: 8px;
344
+ padding: 20px;
345
+ text-align: center;
346
+ color: #666;
347
+ background: #2d2d2d;
348
+ border-radius: 8px;
341
349
  }
342
350
 
343
351
  .empty-state p {
344
- margin: 0;
352
+ margin: 0;
345
353
  }
346
354
 
347
355
  .hint {
348
- font-size: 11px;
349
- margin-top: 8px !important;
356
+ font-size: 11px;
357
+ margin-top: 8px !important;
350
358
  }
351
359
 
352
360
  .events-grid {
353
- display: grid;
354
- grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
355
- gap: 12px;
361
+ display: grid;
362
+ grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
363
+ gap: 12px;
356
364
  }
357
365
 
358
366
  .event-card {
359
- background: #2d2d2d;
360
- border-radius: 8px;
361
- padding: 12px;
362
- cursor: pointer;
363
- border: 2px solid transparent;
364
- transition: all 0.2s;
367
+ background: #2d2d2d;
368
+ border-radius: 8px;
369
+ padding: 12px;
370
+ cursor: pointer;
371
+ border: 2px solid transparent;
372
+ transition: all 0.2s;
365
373
  }
366
374
 
367
375
  .event-card:hover {
368
- border-color: #3d3d3d;
369
- background: #333;
376
+ border-color: #3d3d3d;
377
+ background: #333;
370
378
  }
371
379
 
372
380
  .event-card.selected {
373
- border-color: #61dafb;
374
- background: #2a3a4a;
381
+ border-color: #61dafb;
382
+ background: #2a3a4a;
375
383
  }
376
384
 
377
385
  .event-name {
378
- font-size: 13px;
379
- font-weight: 500;
380
- color: #e0e0e0;
381
- margin-bottom: 4px;
386
+ font-size: 13px;
387
+ font-weight: 500;
388
+ color: #e0e0e0;
389
+ margin-bottom: 4px;
382
390
  }
383
391
 
384
392
  .event-type {
385
- font-size: 11px;
386
- color: #888;
387
- font-family: 'SF Mono', Monaco, monospace;
393
+ font-size: 11px;
394
+ color: #888;
395
+ font-family: "SF Mono", Monaco, monospace;
388
396
  }
389
397
 
390
398
  .event-editor {
391
- background: #2d2d2d;
392
- border-radius: 8px;
393
- padding: 16px;
399
+ background: #2d2d2d;
400
+ border-radius: 8px;
401
+ padding: 16px;
394
402
  }
395
403
 
396
404
  .editor-field {
397
- margin-bottom: 12px;
405
+ margin-bottom: 12px;
398
406
  }
399
407
 
400
408
  .editor-field label {
401
- display: block;
402
- font-size: 12px;
403
- color: #888;
404
- margin-bottom: 4px;
409
+ display: block;
410
+ font-size: 12px;
411
+ color: #888;
412
+ margin-bottom: 4px;
405
413
  }
406
414
 
407
415
  .field-input,
408
416
  .field-textarea {
409
- width: 100%;
410
- background: #1e1e1e;
411
- border: 1px solid #3d3d3d;
412
- color: #e0e0e0;
413
- padding: 8px 12px;
414
- border-radius: 4px;
415
- font-family: 'SF Mono', Monaco, monospace;
416
- font-size: 12px;
417
- box-sizing: border-box;
417
+ width: 100%;
418
+ background: #1e1e1e;
419
+ border: 1px solid #3d3d3d;
420
+ color: #e0e0e0;
421
+ padding: 8px 12px;
422
+ border-radius: 4px;
423
+ font-family: "SF Mono", Monaco, monospace;
424
+ font-size: 12px;
425
+ box-sizing: border-box;
418
426
  }
419
427
 
420
428
  .field-input:focus,
421
429
  .field-textarea:focus {
422
- outline: none;
423
- border-color: #61dafb;
430
+ outline: none;
431
+ border-color: #61dafb;
424
432
  }
425
433
 
426
434
  .field-textarea {
427
- resize: vertical;
428
- min-height: 100px;
435
+ resize: vertical;
436
+ min-height: 100px;
429
437
  }
430
438
 
431
439
  .json-error {
432
- display: block;
433
- color: #ff6b6b;
434
- font-size: 11px;
435
- margin-top: 4px;
440
+ display: block;
441
+ color: #ff6b6b;
442
+ font-size: 11px;
443
+ margin-top: 4px;
436
444
  }
437
445
 
438
446
  .editor-actions {
439
- display: flex;
440
- gap: 8px;
441
- margin-top: 16px;
447
+ display: flex;
448
+ gap: 8px;
449
+ margin-top: 16px;
442
450
  }
443
451
 
444
452
  .btn {
445
- padding: 8px 16px;
446
- border: none;
447
- border-radius: 4px;
448
- cursor: pointer;
449
- font-size: 12px;
450
- transition: all 0.2s;
453
+ padding: 8px 16px;
454
+ border: none;
455
+ border-radius: 4px;
456
+ cursor: pointer;
457
+ font-size: 12px;
458
+ transition: all 0.2s;
451
459
  }
452
460
 
453
461
  .btn-primary {
454
- background: #61dafb;
455
- color: #1e1e1e;
462
+ background: #61dafb;
463
+ color: #1e1e1e;
456
464
  }
457
465
 
458
466
  .btn-primary:hover {
459
- background: #4fc3f7;
467
+ background: #4fc3f7;
460
468
  }
461
469
 
462
470
  .btn-primary:disabled {
463
- background: #3d3d3d;
464
- color: #666;
465
- cursor: not-allowed;
471
+ background: #3d3d3d;
472
+ color: #666;
473
+ cursor: not-allowed;
466
474
  }
467
475
 
468
476
  .btn-secondary {
469
- background: #3d3d3d;
470
- color: #e0e0e0;
477
+ background: #3d3d3d;
478
+ color: #e0e0e0;
471
479
  }
472
480
 
473
481
  .btn-secondary:hover {
474
- background: #4d4d4d;
482
+ background: #4d4d4d;
475
483
  }
476
484
 
477
485
  .event-log {
478
- background: #2d2d2d;
479
- border-radius: 8px;
480
- overflow: hidden;
486
+ background: #2d2d2d;
487
+ border-radius: 8px;
488
+ overflow: hidden;
481
489
  }
482
490
 
483
491
  .log-header {
484
- display: flex;
485
- justify-content: space-between;
486
- align-items: center;
487
- padding: 12px 16px;
488
- border-bottom: 1px solid #3d3d3d;
492
+ display: flex;
493
+ justify-content: space-between;
494
+ align-items: center;
495
+ padding: 12px 16px;
496
+ border-bottom: 1px solid #3d3d3d;
489
497
  }
490
498
 
491
499
  .log-header h4 {
492
- margin: 0;
500
+ margin: 0;
493
501
  }
494
502
 
495
503
  .btn-clear {
496
- background: transparent;
497
- border: none;
498
- color: #888;
499
- cursor: pointer;
500
- font-size: 11px;
504
+ background: transparent;
505
+ border: none;
506
+ color: #888;
507
+ cursor: pointer;
508
+ font-size: 11px;
501
509
  }
502
510
 
503
511
  .btn-clear:hover {
504
- color: #e0e0e0;
512
+ color: #e0e0e0;
505
513
  }
506
514
 
507
515
  .log-entries {
508
- max-height: 200px;
509
- overflow-y: auto;
516
+ max-height: 200px;
517
+ overflow-y: auto;
510
518
  }
511
519
 
512
520
  .empty-log {
513
- padding: 20px;
514
- text-align: center;
515
- color: #666;
516
- font-size: 12px;
521
+ padding: 20px;
522
+ text-align: center;
523
+ color: #666;
524
+ font-size: 12px;
517
525
  }
518
526
 
519
527
  .log-entry {
520
- display: flex;
521
- gap: 12px;
522
- padding: 8px 16px;
523
- font-size: 11px;
524
- font-family: 'SF Mono', Monaco, monospace;
525
- border-bottom: 1px solid #252525;
528
+ display: flex;
529
+ gap: 12px;
530
+ padding: 8px 16px;
531
+ font-size: 11px;
532
+ font-family: "SF Mono", Monaco, monospace;
533
+ border-bottom: 1px solid #252525;
526
534
  }
527
535
 
528
536
  .log-entry:last-child {
529
- border-bottom: none;
537
+ border-bottom: none;
530
538
  }
531
539
 
532
540
  .log-time {
533
- color: #666;
534
- min-width: 70px;
541
+ color: #666;
542
+ min-width: 70px;
535
543
  }
536
544
 
537
545
  .log-direction {
538
- color: #61dafb;
546
+ color: #61dafb;
539
547
  }
540
548
 
541
549
  .log-event {
542
- color: #e0e0e0;
543
- flex: 1;
550
+ color: #e0e0e0;
551
+ flex: 1;
544
552
  }
545
553
 
546
554
  .log-status {
547
- min-width: 60px;
548
- text-align: right;
555
+ min-width: 60px;
556
+ text-align: right;
549
557
  }
550
558
 
551
559
  .log-entry.success .log-status {
552
- color: #51cf66;
560
+ color: #51cf66;
553
561
  }
554
562
 
555
563
  .log-entry.error .log-status {
556
- color: #ff6b6b;
564
+ color: #ff6b6b;
557
565
  }
558
566
 
559
567
  .log-entry.pending .log-status {
560
- color: #ffd43b;
568
+ color: #ffd43b;
561
569
  }
562
570
  </style>