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