@qontinui/ui-bridge 0.2.0 → 0.3.1

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 (140) hide show
  1. package/dist/ai/index.d.mts +312 -155
  2. package/dist/ai/index.d.ts +312 -155
  3. package/dist/ai/index.js +2363 -67
  4. package/dist/ai/index.js.map +1 -1
  5. package/dist/ai/index.mjs +2328 -68
  6. package/dist/ai/index.mjs.map +1 -1
  7. package/dist/annotations/index.d.mts +218 -0
  8. package/dist/annotations/index.d.ts +218 -0
  9. package/dist/annotations/index.js +246 -0
  10. package/dist/annotations/index.js.map +1 -0
  11. package/dist/annotations/index.mjs +241 -0
  12. package/dist/annotations/index.mjs.map +1 -0
  13. package/dist/assertions-BSR3afVr.d.ts +161 -0
  14. package/dist/assertions-CTw1hfOx.d.mts +161 -0
  15. package/dist/babel-plugin/index.js +504 -0
  16. package/dist/babel-plugin/index.js.map +1 -0
  17. package/dist/babel-plugin/index.mjs +488 -0
  18. package/dist/babel-plugin/index.mjs.map +1 -0
  19. package/dist/browser-capture-Bms60T6f.d.mts +47 -0
  20. package/dist/browser-capture-CsTU29mb.d.ts +47 -0
  21. package/dist/control/index.d.mts +26 -7
  22. package/dist/control/index.d.ts +26 -7
  23. package/dist/control/index.js +276 -48
  24. package/dist/control/index.js.map +1 -1
  25. package/dist/control/index.mjs +276 -48
  26. package/dist/control/index.mjs.map +1 -1
  27. package/dist/core/index.d.mts +115 -44
  28. package/dist/core/index.d.ts +115 -44
  29. package/dist/core/index.js +0 -1560
  30. package/dist/core/index.js.map +1 -1
  31. package/dist/core/index.mjs +1 -1549
  32. package/dist/core/index.mjs.map +1 -1
  33. package/dist/debug/index.d.mts +5 -3
  34. package/dist/debug/index.d.ts +5 -3
  35. package/dist/debug/index.js +925 -1
  36. package/dist/debug/index.js.map +1 -1
  37. package/dist/debug/index.mjs +924 -2
  38. package/dist/debug/index.mjs.map +1 -1
  39. package/dist/index.d.mts +13 -9
  40. package/dist/index.d.ts +13 -9
  41. package/dist/index.js +8310 -3777
  42. package/dist/index.js.map +1 -1
  43. package/dist/index.mjs +8246 -3766
  44. package/dist/index.mjs.map +1 -1
  45. package/dist/{metrics-NC3csD0R.d.mts → metrics-DuA2qIIz.d.mts} +2 -2
  46. package/dist/{metrics-C9XRi_mL.d.ts → metrics-KFAAKNEB.d.ts} +2 -2
  47. package/dist/native/control/index.js +448 -0
  48. package/dist/native/control/index.js.map +1 -0
  49. package/dist/native/control/index.mjs +445 -0
  50. package/dist/native/control/index.mjs.map +1 -0
  51. package/dist/native/core/index.js +486 -0
  52. package/dist/native/core/index.js.map +1 -0
  53. package/dist/native/core/index.mjs +475 -0
  54. package/dist/native/core/index.mjs.map +1 -0
  55. package/dist/native/debug/index.js +408 -0
  56. package/dist/native/debug/index.js.map +1 -0
  57. package/dist/native/debug/index.mjs +406 -0
  58. package/dist/native/debug/index.mjs.map +1 -0
  59. package/dist/native/index.js +2232 -0
  60. package/dist/native/index.js.map +1 -0
  61. package/dist/native/index.mjs +2204 -0
  62. package/dist/native/index.mjs.map +1 -0
  63. package/dist/native/react/index.js +1377 -0
  64. package/dist/native/react/index.js.map +1 -0
  65. package/dist/native/react/index.mjs +1365 -0
  66. package/dist/native/react/index.mjs.map +1 -0
  67. package/dist/native/server/index.js +440 -0
  68. package/dist/native/server/index.js.map +1 -0
  69. package/dist/native/server/index.mjs +435 -0
  70. package/dist/native/server/index.mjs.map +1 -0
  71. package/dist/react/index.d.mts +121 -9
  72. package/dist/react/index.d.ts +121 -9
  73. package/dist/react/index.js +2239 -91
  74. package/dist/react/index.js.map +1 -1
  75. package/dist/react/index.mjs +2239 -92
  76. package/dist/react/index.mjs.map +1 -1
  77. package/dist/{registry-CIEDjbQ9.d.ts → registry-C6dDtn1v.d.ts} +34 -15
  78. package/dist/{registry-SsSDq46X.d.mts → registry-POtcxnal.d.mts} +34 -15
  79. package/dist/render-log/index.d.mts +1 -1
  80. package/dist/render-log/index.d.ts +1 -1
  81. package/dist/server/express.d.mts +37 -0
  82. package/dist/server/express.d.ts +37 -0
  83. package/dist/server/express.js +298 -0
  84. package/dist/server/express.js.map +1 -0
  85. package/dist/server/express.mjs +294 -0
  86. package/dist/server/express.mjs.map +1 -0
  87. package/dist/server/handlers.d.mts +124 -0
  88. package/dist/server/handlers.d.ts +124 -0
  89. package/dist/server/handlers.js +7183 -0
  90. package/dist/server/handlers.js.map +1 -0
  91. package/dist/server/handlers.mjs +7180 -0
  92. package/dist/server/handlers.mjs.map +1 -0
  93. package/dist/server/index.d.mts +12 -0
  94. package/dist/server/index.d.ts +12 -0
  95. package/dist/server/index.js +8384 -0
  96. package/dist/server/index.js.map +1 -0
  97. package/dist/server/index.mjs +8369 -0
  98. package/dist/server/index.mjs.map +1 -0
  99. package/dist/server/nextjs.d.mts +128 -0
  100. package/dist/server/nextjs.d.ts +128 -0
  101. package/dist/server/nextjs.js +390 -0
  102. package/dist/server/nextjs.js.map +1 -0
  103. package/dist/server/nextjs.mjs +385 -0
  104. package/dist/server/nextjs.mjs.map +1 -0
  105. package/dist/server/standalone.d.mts +7 -0
  106. package/dist/server/standalone.d.ts +7 -0
  107. package/dist/server/standalone.js +845 -0
  108. package/dist/server/standalone.js.map +1 -0
  109. package/dist/server/standalone.mjs +841 -0
  110. package/dist/server/standalone.mjs.map +1 -0
  111. package/dist/specs/index.d.mts +365 -0
  112. package/dist/specs/index.d.ts +365 -0
  113. package/dist/specs/index.js +2809 -0
  114. package/dist/specs/index.js.map +1 -0
  115. package/dist/specs/index.mjs +2786 -0
  116. package/dist/specs/index.mjs.map +1 -0
  117. package/dist/standalone-B6GLIEmR.d.ts +216 -0
  118. package/dist/standalone-CjdYqj3P.d.mts +216 -0
  119. package/dist/swc-plugin/index.d.mts +79 -0
  120. package/dist/swc-plugin/index.d.ts +79 -0
  121. package/dist/swc-plugin/index.js +15 -0
  122. package/dist/swc-plugin/index.js.map +1 -0
  123. package/dist/swc-plugin/index.mjs +9 -0
  124. package/dist/swc-plugin/index.mjs.map +1 -0
  125. package/dist/types-B2EfvEaq.d.ts +236 -0
  126. package/dist/{types-Dr6tH-bm.d.mts → types-C7gVYRnF.d.ts} +72 -2
  127. package/dist/{types-oCTrRxSw.d.ts → types-CJGrBEhC.d.mts} +72 -2
  128. package/dist/types-CebMQj76.d.ts +1275 -0
  129. package/dist/types-D_ypYl3T.d.mts +1275 -0
  130. package/dist/types-UBtp7R0u.d.mts +132 -0
  131. package/dist/types-UBtp7R0u.d.ts +132 -0
  132. package/dist/types-gO696T_t.d.mts +236 -0
  133. package/dist/{types-CPMbN_Iw.d.mts → types-suaYwWWg.d.mts} +519 -152
  134. package/dist/{types-CPMbN_Iw.d.ts → types-suaYwWWg.d.ts} +519 -152
  135. package/package.json +123 -4
  136. package/swc-plugin-wasm/ui_bridge_swc_plugin.wasm +0 -0
  137. package/dist/types-BvCfFuEV.d.ts +0 -534
  138. package/dist/types-CFT3Dnx4.d.mts +0 -534
  139. package/dist/websocket-client-CX4QJesI.d.ts +0 -124
  140. package/dist/websocket-client-C_Na0OSp.d.mts +0 -124
@@ -0,0 +1,841 @@
1
+ // src/server/types.ts
2
+ var UI_BRIDGE_ROUTES = [
3
+ // Render log
4
+ { method: "GET", path: "/render-log", handler: "getRenderLog" },
5
+ { method: "DELETE", path: "/render-log", handler: "clearRenderLog" },
6
+ { method: "POST", path: "/render-log/snapshot", handler: "captureSnapshot" },
7
+ { method: "GET", path: "/render-log/path", handler: "getRenderLogPath" },
8
+ // Control - Elements
9
+ { method: "GET", path: "/control/elements", handler: "getElements" },
10
+ { method: "GET", path: "/control/element/:id", handler: "getElement", params: ["id"] },
11
+ { method: "GET", path: "/control/element/:id/state", handler: "getElementState", params: ["id"] },
12
+ {
13
+ method: "POST",
14
+ path: "/control/element/:id/action",
15
+ handler: "executeElementAction",
16
+ params: ["id"],
17
+ bodyRequired: true
18
+ },
19
+ // Control - Components
20
+ { method: "GET", path: "/control/components", handler: "getComponents" },
21
+ { method: "GET", path: "/control/component/:id", handler: "getComponent", params: ["id"] },
22
+ {
23
+ method: "GET",
24
+ path: "/control/component/:id/state",
25
+ handler: "getComponentState",
26
+ params: ["id"]
27
+ },
28
+ {
29
+ method: "POST",
30
+ path: "/control/component/:id/action/:actionId",
31
+ handler: "executeComponentAction",
32
+ params: ["id", "actionId"],
33
+ bodyRequired: true
34
+ },
35
+ // Find (formerly Discovery)
36
+ { method: "POST", path: "/control/find", handler: "find" },
37
+ { method: "POST", path: "/control/discover", handler: "discover" },
38
+ // @deprecated Use /control/find
39
+ { method: "GET", path: "/control/snapshot", handler: "getControlSnapshot" },
40
+ // Workflows
41
+ { method: "GET", path: "/control/workflows", handler: "getWorkflows" },
42
+ { method: "POST", path: "/control/workflow/:id/run", handler: "runWorkflow", params: ["id"] },
43
+ {
44
+ method: "GET",
45
+ path: "/control/workflow/:runId/status",
46
+ handler: "getWorkflowStatus",
47
+ params: ["runId"]
48
+ },
49
+ // Debug
50
+ { method: "GET", path: "/debug/action-history", handler: "getActionHistory" },
51
+ { method: "GET", path: "/debug/metrics", handler: "getMetrics" },
52
+ { method: "POST", path: "/debug/highlight/:id", handler: "highlightElement", params: ["id"] },
53
+ { method: "GET", path: "/debug/element-tree", handler: "getElementTree" },
54
+ { method: "GET", path: "/control/console-errors", handler: "getConsoleErrors" },
55
+ { method: "POST", path: "/control/console-errors/clear", handler: "clearConsoleErrors" },
56
+ // AI-native endpoints
57
+ { method: "POST", path: "/ai/search", handler: "aiSearch", bodyRequired: true },
58
+ { method: "POST", path: "/ai/execute", handler: "aiExecute", bodyRequired: true },
59
+ { method: "POST", path: "/ai/assert", handler: "aiAssert", bodyRequired: true },
60
+ { method: "POST", path: "/ai/assert/batch", handler: "aiAssertBatch", bodyRequired: true },
61
+ { method: "GET", path: "/ai/snapshot", handler: "getSemanticSnapshot" },
62
+ { method: "GET", path: "/ai/diff", handler: "getSemanticDiff" },
63
+ { method: "GET", path: "/ai/summary", handler: "getPageSummary" },
64
+ { method: "POST", path: "/ai/semantic-search", handler: "aiSemanticSearch", bodyRequired: true },
65
+ // State management (static routes before parameterized)
66
+ { method: "GET", path: "/control/states", handler: "getStates" },
67
+ { method: "GET", path: "/control/states/active", handler: "getActiveStates" },
68
+ { method: "GET", path: "/control/states/snapshot", handler: "getStateSnapshot" },
69
+ { method: "POST", path: "/control/states/find-path", handler: "findPath", bodyRequired: true },
70
+ { method: "POST", path: "/control/states/navigate", handler: "navigateTo", bodyRequired: true },
71
+ { method: "GET", path: "/control/state/:id", handler: "getState", params: ["id"] },
72
+ { method: "POST", path: "/control/state/:id/activate", handler: "activateState", params: ["id"] },
73
+ {
74
+ method: "POST",
75
+ path: "/control/state/:id/deactivate",
76
+ handler: "deactivateState",
77
+ params: ["id"]
78
+ },
79
+ { method: "GET", path: "/control/state-groups", handler: "getStateGroups" },
80
+ {
81
+ method: "POST",
82
+ path: "/control/state-group/:id/activate",
83
+ handler: "activateStateGroup",
84
+ params: ["id"]
85
+ },
86
+ {
87
+ method: "POST",
88
+ path: "/control/state-group/:id/deactivate",
89
+ handler: "deactivateStateGroup",
90
+ params: ["id"]
91
+ },
92
+ { method: "GET", path: "/control/transitions", handler: "getTransitions" },
93
+ {
94
+ method: "GET",
95
+ path: "/control/transition/:id/can-execute",
96
+ handler: "canExecuteTransition",
97
+ params: ["id"]
98
+ },
99
+ {
100
+ method: "POST",
101
+ path: "/control/transition/:id/execute",
102
+ handler: "executeTransition",
103
+ params: ["id"]
104
+ },
105
+ // Intent endpoints
106
+ { method: "GET", path: "/ai/intents", handler: "listIntents" },
107
+ { method: "POST", path: "/ai/intents/execute", handler: "executeIntent", bodyRequired: true },
108
+ { method: "POST", path: "/ai/intents/find", handler: "findIntent", bodyRequired: true },
109
+ { method: "POST", path: "/ai/intents/register", handler: "registerIntent", bodyRequired: true },
110
+ {
111
+ method: "POST",
112
+ path: "/ai/intents/execute-from-query",
113
+ handler: "executeIntentFromQuery",
114
+ bodyRequired: true
115
+ },
116
+ // Recovery endpoints
117
+ {
118
+ method: "POST",
119
+ path: "/ai/recovery/attempt",
120
+ handler: "attemptRecovery",
121
+ bodyRequired: true
122
+ },
123
+ // Cross-app analysis endpoints
124
+ { method: "GET", path: "/ai/analyze/data", handler: "analyzePageData" },
125
+ { method: "GET", path: "/ai/analyze/regions", handler: "analyzePageRegions" },
126
+ { method: "GET", path: "/ai/analyze/structured-data", handler: "analyzeStructuredData" },
127
+ {
128
+ method: "POST",
129
+ path: "/ai/analyze/cross-app-compare",
130
+ handler: "crossAppCompare",
131
+ bodyRequired: true
132
+ },
133
+ // Page navigation
134
+ { method: "POST", path: "/control/page/refresh", handler: "pageRefresh" },
135
+ { method: "POST", path: "/control/page/navigate", handler: "pageNavigate", bodyRequired: true },
136
+ { method: "POST", path: "/control/page/back", handler: "pageGoBack" },
137
+ { method: "POST", path: "/control/page/forward", handler: "pageGoForward" },
138
+ // Annotations (static routes before parameterized)
139
+ { method: "GET", path: "/annotations", handler: "getAnnotations" },
140
+ { method: "GET", path: "/annotations/export", handler: "exportAnnotations" },
141
+ { method: "GET", path: "/annotations/coverage", handler: "getAnnotationCoverage" },
142
+ { method: "POST", path: "/annotations/import", handler: "importAnnotations", bodyRequired: true },
143
+ { method: "GET", path: "/annotations/:id", handler: "getAnnotation", params: ["id"] },
144
+ {
145
+ method: "PUT",
146
+ path: "/annotations/:id",
147
+ handler: "setAnnotation",
148
+ params: ["id"],
149
+ bodyRequired: true
150
+ },
151
+ { method: "DELETE", path: "/annotations/:id", handler: "deleteAnnotation", params: ["id"] },
152
+ // Performance diagnostics
153
+ { method: "GET", path: "/control/performance-entries", handler: "getPerformanceEntries" },
154
+ {
155
+ method: "POST",
156
+ path: "/control/performance-entries/clear",
157
+ handler: "clearPerformanceEntries"
158
+ },
159
+ { method: "GET", path: "/control/browser-events", handler: "getBrowserEvents" }
160
+ ];
161
+
162
+ // src/server/websocket-handler.ts
163
+ function generateId() {
164
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
165
+ }
166
+ var VERSION = "0.1.0";
167
+ var UIBridgeWSHandler = class {
168
+ constructor(handlers, options = {}) {
169
+ this.clients = /* @__PURE__ */ new Map();
170
+ this.handlers = handlers;
171
+ this.verbose = options.verbose ?? false;
172
+ this.log = options.log ?? console.log;
173
+ }
174
+ /**
175
+ * Handle new WebSocket connection
176
+ */
177
+ handleConnection(ws) {
178
+ const clientId = generateId();
179
+ const client = {
180
+ id: clientId,
181
+ ws,
182
+ subscription: {
183
+ events: /* @__PURE__ */ new Set(),
184
+ elementIds: /* @__PURE__ */ new Set(),
185
+ componentIds: /* @__PURE__ */ new Set()
186
+ },
187
+ connectedAt: Date.now()
188
+ };
189
+ this.clients.set(clientId, client);
190
+ if (this.verbose) {
191
+ this.log(`[WS] Client connected: ${clientId}`);
192
+ }
193
+ ws.onmessage = (event) => {
194
+ this.handleMessage(clientId, event.data);
195
+ };
196
+ ws.onclose = () => {
197
+ this.handleDisconnect(clientId);
198
+ };
199
+ this.sendToClient(clientId, {
200
+ id: generateId(),
201
+ type: "welcome",
202
+ timestamp: Date.now(),
203
+ payload: {
204
+ version: VERSION,
205
+ features: {
206
+ renderLog: true,
207
+ control: true,
208
+ debug: true
209
+ },
210
+ clientId
211
+ }
212
+ });
213
+ return clientId;
214
+ }
215
+ /**
216
+ * Handle client disconnect
217
+ */
218
+ handleDisconnect(clientId) {
219
+ this.clients.delete(clientId);
220
+ if (this.verbose) {
221
+ this.log(`[WS] Client disconnected: ${clientId}`);
222
+ }
223
+ }
224
+ /**
225
+ * Handle incoming message
226
+ */
227
+ async handleMessage(clientId, data) {
228
+ const client = this.clients.get(clientId);
229
+ if (!client) return;
230
+ let message;
231
+ try {
232
+ message = JSON.parse(data);
233
+ } catch (error) {
234
+ this.sendError(clientId, void 0, "PARSE_ERROR", "Invalid JSON message");
235
+ return;
236
+ }
237
+ if (this.verbose) {
238
+ this.log(`[WS] ${clientId} -> ${message.type}`);
239
+ }
240
+ try {
241
+ switch (message.type) {
242
+ case "ping":
243
+ this.handlePing(clientId, message.id);
244
+ break;
245
+ case "subscribe":
246
+ await this.handleSubscribe(clientId, message);
247
+ break;
248
+ case "unsubscribe":
249
+ await this.handleUnsubscribe(clientId, message);
250
+ break;
251
+ case "find":
252
+ await this.handleFind(clientId, message);
253
+ break;
254
+ case "discover":
255
+ await this.handleFind(clientId, message);
256
+ break;
257
+ case "getElement":
258
+ await this.handleGetElement(clientId, message);
259
+ break;
260
+ case "getSnapshot":
261
+ await this.handleGetSnapshot(clientId, message);
262
+ break;
263
+ case "executeAction":
264
+ await this.handleExecuteAction(clientId, message);
265
+ break;
266
+ case "executeComponentAction":
267
+ await this.handleExecuteComponentAction(clientId, message);
268
+ break;
269
+ case "executeWorkflow":
270
+ await this.handleExecuteWorkflow(clientId, message);
271
+ break;
272
+ default:
273
+ this.sendError(
274
+ clientId,
275
+ message.id,
276
+ "UNKNOWN_MESSAGE",
277
+ `Unknown message type: ${message.type}`
278
+ );
279
+ }
280
+ } catch (error) {
281
+ const err = error instanceof Error ? error : new Error(String(error));
282
+ this.sendError(clientId, message.id, "HANDLER_ERROR", err.message);
283
+ }
284
+ }
285
+ /**
286
+ * Handle ping message
287
+ */
288
+ handlePing(clientId, _requestId) {
289
+ this.sendToClient(clientId, {
290
+ id: generateId(),
291
+ type: "pong",
292
+ timestamp: Date.now()
293
+ });
294
+ }
295
+ /**
296
+ * Handle subscribe message
297
+ */
298
+ async handleSubscribe(clientId, message) {
299
+ const client = this.clients.get(clientId);
300
+ if (!client) return;
301
+ const { events, elementIds, componentIds } = message.payload;
302
+ if (events?.length) {
303
+ for (const event of events) {
304
+ client.subscription.events.add(event);
305
+ }
306
+ }
307
+ if (elementIds?.length) {
308
+ for (const id of elementIds) {
309
+ client.subscription.elementIds.add(id);
310
+ }
311
+ }
312
+ if (componentIds?.length) {
313
+ for (const id of componentIds) {
314
+ client.subscription.componentIds.add(id);
315
+ }
316
+ }
317
+ this.sendToClient(clientId, {
318
+ id: generateId(),
319
+ type: "subscribed",
320
+ timestamp: Date.now(),
321
+ payload: {
322
+ events: Array.from(client.subscription.events)
323
+ }
324
+ });
325
+ }
326
+ /**
327
+ * Handle unsubscribe message
328
+ */
329
+ async handleUnsubscribe(clientId, message) {
330
+ const client = this.clients.get(clientId);
331
+ if (!client) return;
332
+ const { events } = message.payload;
333
+ let removedEvents;
334
+ if (events?.length) {
335
+ removedEvents = events.filter((e) => client.subscription.events.has(e));
336
+ for (const event of events) {
337
+ client.subscription.events.delete(event);
338
+ }
339
+ } else {
340
+ removedEvents = Array.from(client.subscription.events);
341
+ client.subscription.events.clear();
342
+ client.subscription.elementIds.clear();
343
+ client.subscription.componentIds.clear();
344
+ }
345
+ this.sendToClient(clientId, {
346
+ id: generateId(),
347
+ type: "unsubscribed",
348
+ timestamp: Date.now(),
349
+ payload: {
350
+ events: removedEvents
351
+ }
352
+ });
353
+ }
354
+ /**
355
+ * Handle find message
356
+ */
357
+ async handleFind(clientId, message) {
358
+ const result = await this.handlers.find(message.payload || {});
359
+ if (result.success && result.data) {
360
+ this.sendResponse(clientId, message.id, true, { elements: result.data.elements });
361
+ } else {
362
+ this.sendResponse(clientId, message.id, false, void 0, result.error);
363
+ }
364
+ }
365
+ /**
366
+ * Handle getElement message
367
+ */
368
+ async handleGetElement(clientId, message) {
369
+ const { elementId } = message.payload;
370
+ const result = await this.handlers.getElement(elementId);
371
+ if (result.success) {
372
+ this.sendResponse(clientId, message.id, true, { element: result.data });
373
+ } else {
374
+ this.sendResponse(clientId, message.id, false, void 0, result.error);
375
+ }
376
+ }
377
+ /**
378
+ * Handle getSnapshot message
379
+ */
380
+ async handleGetSnapshot(clientId, message) {
381
+ const result = await this.handlers.getControlSnapshot();
382
+ if (result.success) {
383
+ this.sendResponse(clientId, message.id, true, result.data);
384
+ } else {
385
+ this.sendResponse(clientId, message.id, false, void 0, result.error);
386
+ }
387
+ }
388
+ /**
389
+ * Handle executeAction message
390
+ */
391
+ async handleExecuteAction(clientId, message) {
392
+ const { elementId, action } = message.payload;
393
+ const result = await this.handlers.executeElementAction(elementId, action);
394
+ this.sendResponse(clientId, message.id, result.success, result.data, result.error);
395
+ }
396
+ /**
397
+ * Handle executeComponentAction message
398
+ */
399
+ async handleExecuteComponentAction(clientId, message) {
400
+ const { componentId, action, params } = message.payload;
401
+ const result = await this.handlers.executeComponentAction(componentId, { action, params });
402
+ this.sendResponse(clientId, message.id, result.success, result.data, result.error);
403
+ }
404
+ /**
405
+ * Handle executeWorkflow message
406
+ */
407
+ async handleExecuteWorkflow(clientId, message) {
408
+ const { workflowId, params } = message.payload;
409
+ const result = await this.handlers.runWorkflow(workflowId, { params });
410
+ this.sendResponse(clientId, message.id, result.success, result.data, result.error);
411
+ }
412
+ /**
413
+ * Broadcast event to all subscribed clients
414
+ */
415
+ broadcastEvent(event) {
416
+ for (const [clientId, client] of this.clients) {
417
+ if (client.subscription.events.size === 0 || client.subscription.events.has(event.type)) {
418
+ const eventData = event.data;
419
+ if (eventData.elementId && client.subscription.elementIds.size > 0 && !client.subscription.elementIds.has(eventData.elementId)) {
420
+ continue;
421
+ }
422
+ if (eventData.componentId && client.subscription.componentIds.size > 0 && !client.subscription.componentIds.has(eventData.componentId)) {
423
+ continue;
424
+ }
425
+ this.sendToClient(clientId, {
426
+ id: generateId(),
427
+ type: "event",
428
+ timestamp: Date.now(),
429
+ payload: event
430
+ });
431
+ }
432
+ }
433
+ }
434
+ /**
435
+ * Send message to specific client
436
+ */
437
+ sendToClient(clientId, message) {
438
+ const client = this.clients.get(clientId);
439
+ if (!client || client.ws.readyState !== 1) return;
440
+ try {
441
+ client.ws.send(JSON.stringify(message));
442
+ if (this.verbose && message.type !== "pong") {
443
+ this.log(`[WS] ${clientId} <- ${message.type}`);
444
+ }
445
+ } catch (error) {
446
+ console.error(`Failed to send message to ${clientId}:`, error);
447
+ }
448
+ }
449
+ /**
450
+ * Send response message
451
+ */
452
+ sendResponse(clientId, requestId, success, data, error) {
453
+ this.sendToClient(clientId, {
454
+ id: generateId(),
455
+ type: "response",
456
+ timestamp: Date.now(),
457
+ requestId,
458
+ payload: {
459
+ success,
460
+ data,
461
+ error
462
+ }
463
+ });
464
+ }
465
+ /**
466
+ * Send error message
467
+ */
468
+ sendError(clientId, requestId, code, message) {
469
+ this.sendToClient(clientId, {
470
+ id: generateId(),
471
+ type: "error",
472
+ timestamp: Date.now(),
473
+ requestId,
474
+ payload: {
475
+ code,
476
+ message
477
+ }
478
+ });
479
+ }
480
+ /**
481
+ * Get connected client count
482
+ */
483
+ get clientCount() {
484
+ return this.clients.size;
485
+ }
486
+ /**
487
+ * Get all connected client IDs
488
+ */
489
+ get clientIds() {
490
+ return Array.from(this.clients.keys());
491
+ }
492
+ /**
493
+ * Disconnect all clients
494
+ */
495
+ disconnectAll() {
496
+ for (const [_clientId, client] of this.clients) {
497
+ try {
498
+ client.ws.close();
499
+ } catch {
500
+ }
501
+ }
502
+ this.clients.clear();
503
+ }
504
+ };
505
+
506
+ // src/server/standalone.ts
507
+ var DEFAULT_CONFIG = {
508
+ host: "localhost",
509
+ port: 9876,
510
+ websocket: false,
511
+ websocketPort: 9876,
512
+ log: console.log
513
+ };
514
+ function wrapError(error, code) {
515
+ return {
516
+ success: false,
517
+ error: typeof error === "string" ? error : error.message,
518
+ code,
519
+ timestamp: Date.now()
520
+ };
521
+ }
522
+ var StandaloneServer = class {
523
+ constructor(handlers, config = {}) {
524
+ this.server = null;
525
+ this.wsServer = null;
526
+ this.wsHandler = null;
527
+ this.wsConnections = /* @__PURE__ */ new Set();
528
+ this.handlers = handlers;
529
+ this.config = { ...DEFAULT_CONFIG, ...config };
530
+ if (this.config.websocket) {
531
+ this.wsHandler = new UIBridgeWSHandler(handlers, {
532
+ verbose: true,
533
+ log: this.config.log
534
+ });
535
+ }
536
+ }
537
+ /**
538
+ * Get enabled capabilities based on handlers
539
+ */
540
+ getCapabilities() {
541
+ return ["elements", "components", "actions", "search", "workflows"];
542
+ }
543
+ /**
544
+ * Start the server
545
+ */
546
+ async start() {
547
+ const http = await import('http');
548
+ this.server = http.createServer(async (req, res) => {
549
+ await this.handleRequest(req, res);
550
+ });
551
+ if (this.config.websocket && this.wsHandler) {
552
+ await this.startWebSocketServer();
553
+ }
554
+ return new Promise((resolve, reject) => {
555
+ this.server.listen(this.config.port, this.config.host, () => {
556
+ this.config.log(
557
+ `UI Bridge server listening on http://${this.config.host}:${this.config.port}`
558
+ );
559
+ if (this.config.websocket) {
560
+ const wsPort = this.config.websocketPort || this.config.port;
561
+ this.config.log(
562
+ `UI Bridge WebSocket server listening on ws://${this.config.host}:${wsPort}`
563
+ );
564
+ }
565
+ resolve();
566
+ });
567
+ this.server.on("error", reject);
568
+ });
569
+ }
570
+ /**
571
+ * Start WebSocket server
572
+ */
573
+ async startWebSocketServer() {
574
+ try {
575
+ const { WebSocketServer } = await import('ws');
576
+ const wsPort = this.config.websocketPort || this.config.port;
577
+ const useSamePort = wsPort === this.config.port;
578
+ if (useSamePort && this.server) {
579
+ this.wsServer = new WebSocketServer({ server: this.server });
580
+ } else {
581
+ this.wsServer = new WebSocketServer({
582
+ host: this.config.host,
583
+ port: wsPort
584
+ });
585
+ }
586
+ const wss = this.wsServer;
587
+ wss.on("connection", (ws) => {
588
+ this.wsConnections.add(ws);
589
+ this.wsHandler.handleConnection(ws);
590
+ ws.onclose = () => {
591
+ this.wsConnections.delete(ws);
592
+ };
593
+ });
594
+ wss.on("error", (error) => {
595
+ this.config.log(`WebSocket server error: ${error.message}`);
596
+ });
597
+ } catch (error) {
598
+ this.config.log(
599
+ 'Warning: WebSocket support requires the "ws" package. Install it with: npm install ws'
600
+ );
601
+ this.wsHandler = null;
602
+ }
603
+ }
604
+ /**
605
+ * Stop the server
606
+ */
607
+ async stop() {
608
+ if (this.wsHandler) {
609
+ this.wsHandler.disconnectAll();
610
+ }
611
+ if (this.wsServer) {
612
+ const wss = this.wsServer;
613
+ wss.close();
614
+ this.wsServer = null;
615
+ }
616
+ for (const ws of this.wsConnections) {
617
+ ws.close();
618
+ }
619
+ this.wsConnections.clear();
620
+ return new Promise((resolve, reject) => {
621
+ if (!this.server) {
622
+ resolve();
623
+ return;
624
+ }
625
+ this.server.close((err) => {
626
+ if (err) reject(err);
627
+ else resolve();
628
+ });
629
+ });
630
+ }
631
+ /**
632
+ * Handle an HTTP request
633
+ */
634
+ async handleRequest(req, res) {
635
+ const url = new URL(req.url || "/", `http://${req.headers.host}`);
636
+ const method = req.method || "GET";
637
+ const basePath = this.config.basePath || "/ui-bridge";
638
+ if (this.config.cors) {
639
+ res.setHeader("Access-Control-Allow-Origin", "*");
640
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
641
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
642
+ }
643
+ if (method === "OPTIONS") {
644
+ res.writeHead(204);
645
+ res.end();
646
+ return;
647
+ }
648
+ if (url.pathname === "/health") {
649
+ const healthResponse = { status: "ok", timestamp: Date.now() };
650
+ if (this.config.appInfo) {
651
+ const uiBridge = {
652
+ version: "0.3.0",
653
+ ...this.config.appInfo,
654
+ capabilities: this.getCapabilities()
655
+ };
656
+ try {
657
+ const snapshotResult = await this.handlers.getControlSnapshot?.();
658
+ if (snapshotResult?.success && snapshotResult.data) {
659
+ const data = snapshotResult.data;
660
+ uiBridge.elementCount = data.elements?.length ?? 0;
661
+ uiBridge.componentCount = data.components?.length ?? 0;
662
+ }
663
+ } catch {
664
+ }
665
+ healthResponse.uiBridge = uiBridge;
666
+ }
667
+ this.sendJSON(res, healthResponse);
668
+ return;
669
+ }
670
+ let path = url.pathname;
671
+ if (path.startsWith(basePath)) {
672
+ path = path.slice(basePath.length) || "/";
673
+ }
674
+ const route = this.findRoute(path, method);
675
+ if (!route) {
676
+ this.sendJSON(res, wrapError("Not found", "NOT_FOUND"), 404);
677
+ return;
678
+ }
679
+ try {
680
+ let body = {};
681
+ if (method === "POST" || method === "PUT" || method === "PATCH" || route.bodyRequired) {
682
+ body = await this.parseBody(req);
683
+ }
684
+ const params = this.extractParams(path, route.path);
685
+ const handlerName = route.handler;
686
+ const handler = this.handlers[handlerName];
687
+ if (!handler) {
688
+ this.sendJSON(res, wrapError("Not implemented", "NOT_IMPLEMENTED"), 501);
689
+ return;
690
+ }
691
+ const args = [];
692
+ if (route.params) {
693
+ for (const param of route.params) {
694
+ args.push(params[param]);
695
+ }
696
+ }
697
+ if (route.bodyRequired || method === "POST" || method === "PUT" || method === "PATCH") {
698
+ args.push(body);
699
+ }
700
+ if (method === "GET") {
701
+ const query = Object.fromEntries(url.searchParams);
702
+ if (Object.keys(query).length > 0) {
703
+ args.push(query);
704
+ }
705
+ }
706
+ const result = await handler(
707
+ ...args
708
+ );
709
+ this.sendJSON(res, result);
710
+ } catch (error) {
711
+ this.config.log(`Error handling ${method} ${path}: ${error}`);
712
+ this.sendJSON(res, wrapError(error, "INTERNAL_ERROR"), 500);
713
+ }
714
+ }
715
+ /**
716
+ * Find a matching route
717
+ */
718
+ findRoute(path, method) {
719
+ for (const route of UI_BRIDGE_ROUTES) {
720
+ if (route.method !== method) continue;
721
+ const routeRegex = route.path.replace(/:[^/]+/g, "([^/]+)").replace(/\//g, "\\/");
722
+ const regex = new RegExp(`^${routeRegex}$`);
723
+ if (regex.test(path)) {
724
+ return route;
725
+ }
726
+ }
727
+ return null;
728
+ }
729
+ /**
730
+ * Extract params from path
731
+ */
732
+ extractParams(path, routePath) {
733
+ const params = {};
734
+ const routeParts = routePath.split("/");
735
+ const pathParts = path.split("/");
736
+ for (let i = 0; i < routeParts.length; i++) {
737
+ if (routeParts[i].startsWith(":")) {
738
+ params[routeParts[i].slice(1)] = pathParts[i];
739
+ }
740
+ }
741
+ return params;
742
+ }
743
+ /**
744
+ * Parse request body
745
+ */
746
+ parseBody(req) {
747
+ return new Promise((resolve, reject) => {
748
+ let data = "";
749
+ req.on("data", (chunk) => data += chunk);
750
+ req.on("end", () => {
751
+ try {
752
+ resolve(data ? JSON.parse(data) : {});
753
+ } catch {
754
+ resolve({});
755
+ }
756
+ });
757
+ req.on("error", reject);
758
+ });
759
+ }
760
+ /**
761
+ * Send JSON response
762
+ */
763
+ sendJSON(res, data, status = 200) {
764
+ res.writeHead(status, { "Content-Type": "application/json" });
765
+ res.end(JSON.stringify(data));
766
+ }
767
+ /**
768
+ * Broadcast a message to all WebSocket connections (legacy)
769
+ */
770
+ broadcast(message) {
771
+ const data = JSON.stringify(message);
772
+ for (const ws of this.wsConnections) {
773
+ if (ws.readyState === 1) {
774
+ ws.send(data);
775
+ }
776
+ }
777
+ }
778
+ /**
779
+ * Broadcast an event to all subscribed WebSocket clients
780
+ */
781
+ broadcastEvent(event) {
782
+ if (this.wsHandler) {
783
+ this.wsHandler.broadcastEvent(event);
784
+ }
785
+ }
786
+ /**
787
+ * Get WebSocket handler for direct access
788
+ */
789
+ getWSHandler() {
790
+ return this.wsHandler;
791
+ }
792
+ /**
793
+ * Get number of connected WebSocket clients
794
+ */
795
+ get wsClientCount() {
796
+ return this.wsHandler?.clientCount ?? 0;
797
+ }
798
+ /**
799
+ * Get the server address
800
+ */
801
+ getAddress() {
802
+ const address = this.server?.address();
803
+ if (!address || typeof address === "string") return null;
804
+ return { host: this.config.host, port: address.port };
805
+ }
806
+ };
807
+ async function createStandaloneServer(handlers, config) {
808
+ const server = new StandaloneServer(handlers, config);
809
+ await server.start();
810
+ return server;
811
+ }
812
+ async function startCLI(handlers, args = process.argv.slice(2)) {
813
+ const config = {};
814
+ for (let i = 0; i < args.length; i++) {
815
+ const arg = args[i];
816
+ const nextArg = args[i + 1];
817
+ if (arg === "--port" || arg === "-p") {
818
+ config.port = parseInt(nextArg);
819
+ i++;
820
+ } else if (arg === "--host" || arg === "-h") {
821
+ config.host = nextArg;
822
+ i++;
823
+ } else if (arg === "--cors") {
824
+ config.cors = true;
825
+ }
826
+ }
827
+ const server = await createStandaloneServer(handlers, config);
828
+ process.on("SIGINT", async () => {
829
+ console.log("\nShutting down...");
830
+ await server.stop();
831
+ process.exit(0);
832
+ });
833
+ process.on("SIGTERM", async () => {
834
+ await server.stop();
835
+ process.exit(0);
836
+ });
837
+ }
838
+
839
+ export { StandaloneServer, createStandaloneServer, startCLI };
840
+ //# sourceMappingURL=standalone.mjs.map
841
+ //# sourceMappingURL=standalone.mjs.map