@qontinui/ui-bridge 0.1.1 → 0.3.0

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 (112) hide show
  1. package/dist/ai/index.d.mts +893 -0
  2. package/dist/ai/index.d.ts +893 -0
  3. package/dist/ai/index.js +3897 -0
  4. package/dist/ai/index.js.map +1 -0
  5. package/dist/ai/index.mjs +3839 -0
  6. package/dist/ai/index.mjs.map +1 -0
  7. package/dist/babel-plugin/index.js +515 -0
  8. package/dist/babel-plugin/index.js.map +1 -0
  9. package/dist/babel-plugin/index.mjs +499 -0
  10. package/dist/babel-plugin/index.mjs.map +1 -0
  11. package/dist/control/index.d.mts +5 -4
  12. package/dist/control/index.d.ts +5 -4
  13. package/dist/core/index.d.mts +115 -42
  14. package/dist/core/index.d.ts +115 -42
  15. package/dist/core/index.js +0 -983
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/core/index.mjs +1 -972
  18. package/dist/core/index.mjs.map +1 -1
  19. package/dist/debug/index.d.mts +3 -3
  20. package/dist/debug/index.d.ts +3 -3
  21. package/dist/index.d.mts +8 -7
  22. package/dist/index.d.ts +8 -7
  23. package/dist/index.js +8249 -4163
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.mjs +8193 -4152
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/{metrics-QCnK0EFw.d.ts → metrics-BfiT_rhZ.d.ts} +2 -2
  28. package/dist/{metrics-BCG7z7Aq.d.mts → metrics-DTA2bwG7.d.mts} +2 -2
  29. package/dist/native/control/index.js +453 -0
  30. package/dist/native/control/index.js.map +1 -0
  31. package/dist/native/control/index.mjs +450 -0
  32. package/dist/native/control/index.mjs.map +1 -0
  33. package/dist/native/core/index.js +486 -0
  34. package/dist/native/core/index.js.map +1 -0
  35. package/dist/native/core/index.mjs +475 -0
  36. package/dist/native/core/index.mjs.map +1 -0
  37. package/dist/native/debug/index.js +451 -0
  38. package/dist/native/debug/index.js.map +1 -0
  39. package/dist/native/debug/index.mjs +449 -0
  40. package/dist/native/debug/index.mjs.map +1 -0
  41. package/dist/native/index.js +2274 -0
  42. package/dist/native/index.js.map +1 -0
  43. package/dist/native/index.mjs +2246 -0
  44. package/dist/native/index.mjs.map +1 -0
  45. package/dist/native/react/index.js +1401 -0
  46. package/dist/native/react/index.js.map +1 -0
  47. package/dist/native/react/index.mjs +1389 -0
  48. package/dist/native/react/index.mjs.map +1 -0
  49. package/dist/native/server/index.js +415 -0
  50. package/dist/native/server/index.js.map +1 -0
  51. package/dist/native/server/index.mjs +410 -0
  52. package/dist/native/server/index.mjs.map +1 -0
  53. package/dist/react/index.d.mts +20 -6
  54. package/dist/react/index.d.ts +20 -6
  55. package/dist/react/index.js +629 -14
  56. package/dist/react/index.js.map +1 -1
  57. package/dist/react/index.mjs +629 -14
  58. package/dist/react/index.mjs.map +1 -1
  59. package/dist/{registry-CT6BVVKr.d.mts → registry-BKLEm-yk.d.ts} +29 -14
  60. package/dist/{registry-D4mQ01B3.d.ts → registry-BmZgyCz8.d.mts} +29 -14
  61. package/dist/render-log/index.d.mts +1 -1
  62. package/dist/render-log/index.d.ts +1 -1
  63. package/dist/server/express.d.mts +36 -0
  64. package/dist/server/express.d.ts +36 -0
  65. package/dist/server/express.js +196 -0
  66. package/dist/server/express.js.map +1 -0
  67. package/dist/server/express.mjs +192 -0
  68. package/dist/server/express.mjs.map +1 -0
  69. package/dist/server/handlers.d.mts +93 -0
  70. package/dist/server/handlers.d.ts +93 -0
  71. package/dist/server/handlers.js +4278 -0
  72. package/dist/server/handlers.js.map +1 -0
  73. package/dist/server/handlers.mjs +4275 -0
  74. package/dist/server/handlers.mjs.map +1 -0
  75. package/dist/server/index.d.mts +10 -0
  76. package/dist/server/index.d.ts +10 -0
  77. package/dist/server/index.js +5352 -0
  78. package/dist/server/index.js.map +1 -0
  79. package/dist/server/index.mjs +5337 -0
  80. package/dist/server/index.mjs.map +1 -0
  81. package/dist/server/nextjs.d.mts +126 -0
  82. package/dist/server/nextjs.d.ts +126 -0
  83. package/dist/server/nextjs.js +287 -0
  84. package/dist/server/nextjs.js.map +1 -0
  85. package/dist/server/nextjs.mjs +282 -0
  86. package/dist/server/nextjs.mjs.map +1 -0
  87. package/dist/server/standalone.d.mts +6 -0
  88. package/dist/server/standalone.d.ts +6 -0
  89. package/dist/server/standalone.js +719 -0
  90. package/dist/server/standalone.js.map +1 -0
  91. package/dist/server/standalone.mjs +715 -0
  92. package/dist/server/standalone.mjs.map +1 -0
  93. package/dist/standalone-BURj8J3G.d.ts +212 -0
  94. package/dist/standalone-Dwmel29d.d.mts +212 -0
  95. package/dist/swc-plugin/index.d.mts +79 -0
  96. package/dist/swc-plugin/index.d.ts +79 -0
  97. package/dist/swc-plugin/index.js +15 -0
  98. package/dist/swc-plugin/index.js.map +1 -0
  99. package/dist/swc-plugin/index.mjs +9 -0
  100. package/dist/swc-plugin/index.mjs.map +1 -0
  101. package/dist/types-B5Q0GVo0.d.mts +646 -0
  102. package/dist/{types-DdJD9yw5.d.mts → types-B7J7noLK.d.mts} +1 -1
  103. package/dist/{types-BDkXy5si.d.ts → types-BkNRILUa.d.ts} +1 -1
  104. package/dist/types-CEQLnFMv.d.mts +156 -0
  105. package/dist/types-CHnlwiTK.d.ts +156 -0
  106. package/dist/types-DfPqwU-i.d.ts +646 -0
  107. package/dist/{types-BpvpStn3.d.mts → types-jKVgTI6_.d.mts} +364 -160
  108. package/dist/{types-BpvpStn3.d.ts → types-jKVgTI6_.d.ts} +364 -160
  109. package/package.json +111 -3
  110. package/swc-plugin-wasm/ui_bridge_swc_plugin.wasm +0 -0
  111. package/dist/websocket-client-B2LC9CYc.d.mts +0 -124
  112. package/dist/websocket-client-DupH0X7B.d.ts +0 -124
@@ -0,0 +1,719 @@
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
+ { method: "GET", path: "/control/component/:id/state", handler: "getComponentState", params: ["id"] },
25
+ {
26
+ method: "POST",
27
+ path: "/control/component/:id/action/:actionId",
28
+ handler: "executeComponentAction",
29
+ params: ["id", "actionId"],
30
+ bodyRequired: true
31
+ },
32
+ // Find (formerly Discovery)
33
+ { method: "POST", path: "/control/find", handler: "find" },
34
+ { method: "POST", path: "/control/discover", handler: "discover" },
35
+ // @deprecated Use /control/find
36
+ { method: "GET", path: "/control/snapshot", handler: "getControlSnapshot" },
37
+ // Workflows
38
+ { method: "GET", path: "/control/workflows", handler: "getWorkflows" },
39
+ { method: "POST", path: "/control/workflow/:id/run", handler: "runWorkflow", params: ["id"] },
40
+ {
41
+ method: "GET",
42
+ path: "/control/workflow/:runId/status",
43
+ handler: "getWorkflowStatus",
44
+ params: ["runId"]
45
+ },
46
+ // Debug
47
+ { method: "GET", path: "/debug/action-history", handler: "getActionHistory" },
48
+ { method: "GET", path: "/debug/metrics", handler: "getMetrics" },
49
+ { method: "POST", path: "/debug/highlight/:id", handler: "highlightElement", params: ["id"] },
50
+ { method: "GET", path: "/debug/element-tree", handler: "getElementTree" },
51
+ // AI-native endpoints
52
+ { method: "POST", path: "/ai/search", handler: "aiSearch", bodyRequired: true },
53
+ { method: "POST", path: "/ai/execute", handler: "aiExecute", bodyRequired: true },
54
+ { method: "POST", path: "/ai/assert", handler: "aiAssert", bodyRequired: true },
55
+ { method: "POST", path: "/ai/assert/batch", handler: "aiAssertBatch", bodyRequired: true },
56
+ { method: "GET", path: "/ai/snapshot", handler: "getSemanticSnapshot" },
57
+ { method: "GET", path: "/ai/diff", handler: "getSemanticDiff" },
58
+ { method: "GET", path: "/ai/summary", handler: "getPageSummary" },
59
+ { method: "POST", path: "/ai/semantic-search", handler: "aiSemanticSearch", bodyRequired: true }
60
+ ];
61
+
62
+ // src/server/websocket-handler.ts
63
+ function generateId() {
64
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
65
+ }
66
+ var VERSION = "0.1.0";
67
+ var UIBridgeWSHandler = class {
68
+ constructor(handlers, options = {}) {
69
+ this.clients = /* @__PURE__ */ new Map();
70
+ this.handlers = handlers;
71
+ this.verbose = options.verbose ?? false;
72
+ this.log = options.log ?? console.log;
73
+ }
74
+ /**
75
+ * Handle new WebSocket connection
76
+ */
77
+ handleConnection(ws) {
78
+ const clientId = generateId();
79
+ const client = {
80
+ id: clientId,
81
+ ws,
82
+ subscription: {
83
+ events: /* @__PURE__ */ new Set(),
84
+ elementIds: /* @__PURE__ */ new Set(),
85
+ componentIds: /* @__PURE__ */ new Set()
86
+ },
87
+ connectedAt: Date.now()
88
+ };
89
+ this.clients.set(clientId, client);
90
+ if (this.verbose) {
91
+ this.log(`[WS] Client connected: ${clientId}`);
92
+ }
93
+ ws.onmessage = (event) => {
94
+ this.handleMessage(clientId, event.data);
95
+ };
96
+ ws.onclose = () => {
97
+ this.handleDisconnect(clientId);
98
+ };
99
+ this.sendToClient(clientId, {
100
+ id: generateId(),
101
+ type: "welcome",
102
+ timestamp: Date.now(),
103
+ payload: {
104
+ version: VERSION,
105
+ features: {
106
+ renderLog: true,
107
+ control: true,
108
+ debug: true
109
+ },
110
+ clientId
111
+ }
112
+ });
113
+ return clientId;
114
+ }
115
+ /**
116
+ * Handle client disconnect
117
+ */
118
+ handleDisconnect(clientId) {
119
+ this.clients.delete(clientId);
120
+ if (this.verbose) {
121
+ this.log(`[WS] Client disconnected: ${clientId}`);
122
+ }
123
+ }
124
+ /**
125
+ * Handle incoming message
126
+ */
127
+ async handleMessage(clientId, data) {
128
+ const client = this.clients.get(clientId);
129
+ if (!client) return;
130
+ let message;
131
+ try {
132
+ message = JSON.parse(data);
133
+ } catch (error) {
134
+ this.sendError(clientId, void 0, "PARSE_ERROR", "Invalid JSON message");
135
+ return;
136
+ }
137
+ if (this.verbose) {
138
+ this.log(`[WS] ${clientId} -> ${message.type}`);
139
+ }
140
+ try {
141
+ switch (message.type) {
142
+ case "ping":
143
+ this.handlePing(clientId, message.id);
144
+ break;
145
+ case "subscribe":
146
+ await this.handleSubscribe(clientId, message);
147
+ break;
148
+ case "unsubscribe":
149
+ await this.handleUnsubscribe(clientId, message);
150
+ break;
151
+ case "find":
152
+ await this.handleFind(clientId, message);
153
+ break;
154
+ case "discover":
155
+ await this.handleFind(clientId, message);
156
+ break;
157
+ case "getElement":
158
+ await this.handleGetElement(clientId, message);
159
+ break;
160
+ case "getSnapshot":
161
+ await this.handleGetSnapshot(clientId, message);
162
+ break;
163
+ case "executeAction":
164
+ await this.handleExecuteAction(clientId, message);
165
+ break;
166
+ case "executeComponentAction":
167
+ await this.handleExecuteComponentAction(clientId, message);
168
+ break;
169
+ case "executeWorkflow":
170
+ await this.handleExecuteWorkflow(clientId, message);
171
+ break;
172
+ default:
173
+ this.sendError(
174
+ clientId,
175
+ message.id,
176
+ "UNKNOWN_MESSAGE",
177
+ `Unknown message type: ${message.type}`
178
+ );
179
+ }
180
+ } catch (error) {
181
+ const err = error instanceof Error ? error : new Error(String(error));
182
+ this.sendError(clientId, message.id, "HANDLER_ERROR", err.message);
183
+ }
184
+ }
185
+ /**
186
+ * Handle ping message
187
+ */
188
+ handlePing(clientId, _requestId) {
189
+ this.sendToClient(clientId, {
190
+ id: generateId(),
191
+ type: "pong",
192
+ timestamp: Date.now()
193
+ });
194
+ }
195
+ /**
196
+ * Handle subscribe message
197
+ */
198
+ async handleSubscribe(clientId, message) {
199
+ const client = this.clients.get(clientId);
200
+ if (!client) return;
201
+ const { events, elementIds, componentIds } = message.payload;
202
+ if (events?.length) {
203
+ for (const event of events) {
204
+ client.subscription.events.add(event);
205
+ }
206
+ }
207
+ if (elementIds?.length) {
208
+ for (const id of elementIds) {
209
+ client.subscription.elementIds.add(id);
210
+ }
211
+ }
212
+ if (componentIds?.length) {
213
+ for (const id of componentIds) {
214
+ client.subscription.componentIds.add(id);
215
+ }
216
+ }
217
+ this.sendToClient(clientId, {
218
+ id: generateId(),
219
+ type: "subscribed",
220
+ timestamp: Date.now(),
221
+ payload: {
222
+ events: Array.from(client.subscription.events)
223
+ }
224
+ });
225
+ }
226
+ /**
227
+ * Handle unsubscribe message
228
+ */
229
+ async handleUnsubscribe(clientId, message) {
230
+ const client = this.clients.get(clientId);
231
+ if (!client) return;
232
+ const { events } = message.payload;
233
+ let removedEvents;
234
+ if (events?.length) {
235
+ removedEvents = events.filter((e) => client.subscription.events.has(e));
236
+ for (const event of events) {
237
+ client.subscription.events.delete(event);
238
+ }
239
+ } else {
240
+ removedEvents = Array.from(client.subscription.events);
241
+ client.subscription.events.clear();
242
+ client.subscription.elementIds.clear();
243
+ client.subscription.componentIds.clear();
244
+ }
245
+ this.sendToClient(clientId, {
246
+ id: generateId(),
247
+ type: "unsubscribed",
248
+ timestamp: Date.now(),
249
+ payload: {
250
+ events: removedEvents
251
+ }
252
+ });
253
+ }
254
+ /**
255
+ * Handle find message
256
+ */
257
+ async handleFind(clientId, message) {
258
+ const result = await this.handlers.find(message.payload || {});
259
+ if (result.success && result.data) {
260
+ this.sendResponse(clientId, message.id, true, { elements: result.data.elements });
261
+ } else {
262
+ this.sendResponse(clientId, message.id, false, void 0, result.error);
263
+ }
264
+ }
265
+ /**
266
+ * Handle getElement message
267
+ */
268
+ async handleGetElement(clientId, message) {
269
+ const { elementId } = message.payload;
270
+ const result = await this.handlers.getElement(elementId);
271
+ if (result.success) {
272
+ this.sendResponse(clientId, message.id, true, { element: result.data });
273
+ } else {
274
+ this.sendResponse(clientId, message.id, false, void 0, result.error);
275
+ }
276
+ }
277
+ /**
278
+ * Handle getSnapshot message
279
+ */
280
+ async handleGetSnapshot(clientId, message) {
281
+ const result = await this.handlers.getControlSnapshot();
282
+ if (result.success) {
283
+ this.sendResponse(clientId, message.id, true, result.data);
284
+ } else {
285
+ this.sendResponse(clientId, message.id, false, void 0, result.error);
286
+ }
287
+ }
288
+ /**
289
+ * Handle executeAction message
290
+ */
291
+ async handleExecuteAction(clientId, message) {
292
+ const { elementId, action } = message.payload;
293
+ const result = await this.handlers.executeElementAction(elementId, action);
294
+ this.sendResponse(clientId, message.id, result.success, result.data, result.error);
295
+ }
296
+ /**
297
+ * Handle executeComponentAction message
298
+ */
299
+ async handleExecuteComponentAction(clientId, message) {
300
+ const { componentId, action, params } = message.payload;
301
+ const result = await this.handlers.executeComponentAction(componentId, { action, params });
302
+ this.sendResponse(clientId, message.id, result.success, result.data, result.error);
303
+ }
304
+ /**
305
+ * Handle executeWorkflow message
306
+ */
307
+ async handleExecuteWorkflow(clientId, message) {
308
+ const { workflowId, params } = message.payload;
309
+ const result = await this.handlers.runWorkflow(workflowId, { params });
310
+ this.sendResponse(clientId, message.id, result.success, result.data, result.error);
311
+ }
312
+ /**
313
+ * Broadcast event to all subscribed clients
314
+ */
315
+ broadcastEvent(event) {
316
+ for (const [clientId, client] of this.clients) {
317
+ if (client.subscription.events.size === 0 || client.subscription.events.has(event.type)) {
318
+ const eventData = event.data;
319
+ if (eventData.elementId && client.subscription.elementIds.size > 0 && !client.subscription.elementIds.has(eventData.elementId)) {
320
+ continue;
321
+ }
322
+ if (eventData.componentId && client.subscription.componentIds.size > 0 && !client.subscription.componentIds.has(eventData.componentId)) {
323
+ continue;
324
+ }
325
+ this.sendToClient(clientId, {
326
+ id: generateId(),
327
+ type: "event",
328
+ timestamp: Date.now(),
329
+ payload: event
330
+ });
331
+ }
332
+ }
333
+ }
334
+ /**
335
+ * Send message to specific client
336
+ */
337
+ sendToClient(clientId, message) {
338
+ const client = this.clients.get(clientId);
339
+ if (!client || client.ws.readyState !== 1) return;
340
+ try {
341
+ client.ws.send(JSON.stringify(message));
342
+ if (this.verbose && message.type !== "pong") {
343
+ this.log(`[WS] ${clientId} <- ${message.type}`);
344
+ }
345
+ } catch (error) {
346
+ console.error(`Failed to send message to ${clientId}:`, error);
347
+ }
348
+ }
349
+ /**
350
+ * Send response message
351
+ */
352
+ sendResponse(clientId, requestId, success, data, error) {
353
+ this.sendToClient(clientId, {
354
+ id: generateId(),
355
+ type: "response",
356
+ timestamp: Date.now(),
357
+ requestId,
358
+ payload: {
359
+ success,
360
+ data,
361
+ error
362
+ }
363
+ });
364
+ }
365
+ /**
366
+ * Send error message
367
+ */
368
+ sendError(clientId, requestId, code, message) {
369
+ this.sendToClient(clientId, {
370
+ id: generateId(),
371
+ type: "error",
372
+ timestamp: Date.now(),
373
+ requestId,
374
+ payload: {
375
+ code,
376
+ message
377
+ }
378
+ });
379
+ }
380
+ /**
381
+ * Get connected client count
382
+ */
383
+ get clientCount() {
384
+ return this.clients.size;
385
+ }
386
+ /**
387
+ * Get all connected client IDs
388
+ */
389
+ get clientIds() {
390
+ return Array.from(this.clients.keys());
391
+ }
392
+ /**
393
+ * Disconnect all clients
394
+ */
395
+ disconnectAll() {
396
+ for (const [_clientId, client] of this.clients) {
397
+ try {
398
+ client.ws.close();
399
+ } catch {
400
+ }
401
+ }
402
+ this.clients.clear();
403
+ }
404
+ };
405
+
406
+ // src/server/standalone.ts
407
+ var DEFAULT_CONFIG = {
408
+ host: "localhost",
409
+ port: 9876,
410
+ websocket: false,
411
+ websocketPort: 9876,
412
+ log: console.log
413
+ };
414
+ function wrapError(error, code) {
415
+ return {
416
+ success: false,
417
+ error: typeof error === "string" ? error : error.message,
418
+ code,
419
+ timestamp: Date.now()
420
+ };
421
+ }
422
+ var StandaloneServer = class {
423
+ constructor(handlers, config = {}) {
424
+ this.server = null;
425
+ this.wsServer = null;
426
+ this.wsHandler = null;
427
+ this.wsConnections = /* @__PURE__ */ new Set();
428
+ this.handlers = handlers;
429
+ this.config = { ...DEFAULT_CONFIG, ...config };
430
+ if (this.config.websocket) {
431
+ this.wsHandler = new UIBridgeWSHandler(handlers, {
432
+ verbose: true,
433
+ log: this.config.log
434
+ });
435
+ }
436
+ }
437
+ /**
438
+ * Start the server
439
+ */
440
+ async start() {
441
+ const http = await import('http');
442
+ this.server = http.createServer(async (req, res) => {
443
+ await this.handleRequest(req, res);
444
+ });
445
+ if (this.config.websocket && this.wsHandler) {
446
+ await this.startWebSocketServer();
447
+ }
448
+ return new Promise((resolve, reject) => {
449
+ this.server.listen(this.config.port, this.config.host, () => {
450
+ this.config.log(
451
+ `UI Bridge server listening on http://${this.config.host}:${this.config.port}`
452
+ );
453
+ if (this.config.websocket) {
454
+ const wsPort = this.config.websocketPort || this.config.port;
455
+ this.config.log(
456
+ `UI Bridge WebSocket server listening on ws://${this.config.host}:${wsPort}`
457
+ );
458
+ }
459
+ resolve();
460
+ });
461
+ this.server.on("error", reject);
462
+ });
463
+ }
464
+ /**
465
+ * Start WebSocket server
466
+ */
467
+ async startWebSocketServer() {
468
+ try {
469
+ const { WebSocketServer } = await import('ws');
470
+ const wsPort = this.config.websocketPort || this.config.port;
471
+ const useSamePort = wsPort === this.config.port;
472
+ if (useSamePort && this.server) {
473
+ this.wsServer = new WebSocketServer({ server: this.server });
474
+ } else {
475
+ this.wsServer = new WebSocketServer({
476
+ host: this.config.host,
477
+ port: wsPort
478
+ });
479
+ }
480
+ const wss = this.wsServer;
481
+ wss.on("connection", (ws) => {
482
+ this.wsConnections.add(ws);
483
+ this.wsHandler.handleConnection(ws);
484
+ ws.onclose = () => {
485
+ this.wsConnections.delete(ws);
486
+ };
487
+ });
488
+ wss.on("error", (error) => {
489
+ this.config.log(`WebSocket server error: ${error.message}`);
490
+ });
491
+ } catch (error) {
492
+ this.config.log(
493
+ 'Warning: WebSocket support requires the "ws" package. Install it with: npm install ws'
494
+ );
495
+ this.wsHandler = null;
496
+ }
497
+ }
498
+ /**
499
+ * Stop the server
500
+ */
501
+ async stop() {
502
+ if (this.wsHandler) {
503
+ this.wsHandler.disconnectAll();
504
+ }
505
+ if (this.wsServer) {
506
+ const wss = this.wsServer;
507
+ wss.close();
508
+ this.wsServer = null;
509
+ }
510
+ for (const ws of this.wsConnections) {
511
+ ws.close();
512
+ }
513
+ this.wsConnections.clear();
514
+ return new Promise((resolve, reject) => {
515
+ if (!this.server) {
516
+ resolve();
517
+ return;
518
+ }
519
+ this.server.close((err) => {
520
+ if (err) reject(err);
521
+ else resolve();
522
+ });
523
+ });
524
+ }
525
+ /**
526
+ * Handle an HTTP request
527
+ */
528
+ async handleRequest(req, res) {
529
+ const url = new URL(req.url || "/", `http://${req.headers.host}`);
530
+ const method = req.method || "GET";
531
+ const basePath = this.config.basePath || "/ui-bridge";
532
+ if (this.config.cors) {
533
+ res.setHeader("Access-Control-Allow-Origin", "*");
534
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
535
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
536
+ }
537
+ if (method === "OPTIONS") {
538
+ res.writeHead(204);
539
+ res.end();
540
+ return;
541
+ }
542
+ if (url.pathname === "/health") {
543
+ this.sendJSON(res, { status: "ok", timestamp: Date.now() });
544
+ return;
545
+ }
546
+ let path = url.pathname;
547
+ if (path.startsWith(basePath)) {
548
+ path = path.slice(basePath.length) || "/";
549
+ }
550
+ const route = this.findRoute(path, method);
551
+ if (!route) {
552
+ this.sendJSON(res, wrapError("Not found", "NOT_FOUND"), 404);
553
+ return;
554
+ }
555
+ try {
556
+ let body = {};
557
+ if (method === "POST") {
558
+ body = await this.parseBody(req);
559
+ }
560
+ const params = this.extractParams(path, route.path);
561
+ const handlerName = route.handler;
562
+ const handler = this.handlers[handlerName];
563
+ if (!handler) {
564
+ this.sendJSON(res, wrapError("Not implemented", "NOT_IMPLEMENTED"), 501);
565
+ return;
566
+ }
567
+ const args = [];
568
+ if (route.params) {
569
+ for (const param of route.params) {
570
+ args.push(params[param]);
571
+ }
572
+ }
573
+ if (method === "POST") {
574
+ args.push(body);
575
+ }
576
+ if (method === "GET") {
577
+ const query = Object.fromEntries(url.searchParams);
578
+ if (Object.keys(query).length > 0) {
579
+ args.push(query);
580
+ }
581
+ }
582
+ const result = await handler(
583
+ ...args
584
+ );
585
+ this.sendJSON(res, result);
586
+ } catch (error) {
587
+ this.config.log(`Error handling ${method} ${path}: ${error}`);
588
+ this.sendJSON(res, wrapError(error, "INTERNAL_ERROR"), 500);
589
+ }
590
+ }
591
+ /**
592
+ * Find a matching route
593
+ */
594
+ findRoute(path, method) {
595
+ for (const route of UI_BRIDGE_ROUTES) {
596
+ if (route.method !== method) continue;
597
+ const routeRegex = route.path.replace(/:[^/]+/g, "([^/]+)").replace(/\//g, "\\/");
598
+ const regex = new RegExp(`^${routeRegex}$`);
599
+ if (regex.test(path)) {
600
+ return route;
601
+ }
602
+ }
603
+ return null;
604
+ }
605
+ /**
606
+ * Extract params from path
607
+ */
608
+ extractParams(path, routePath) {
609
+ const params = {};
610
+ const routeParts = routePath.split("/");
611
+ const pathParts = path.split("/");
612
+ for (let i = 0; i < routeParts.length; i++) {
613
+ if (routeParts[i].startsWith(":")) {
614
+ params[routeParts[i].slice(1)] = pathParts[i];
615
+ }
616
+ }
617
+ return params;
618
+ }
619
+ /**
620
+ * Parse request body
621
+ */
622
+ parseBody(req) {
623
+ return new Promise((resolve, reject) => {
624
+ let data = "";
625
+ req.on("data", (chunk) => data += chunk);
626
+ req.on("end", () => {
627
+ try {
628
+ resolve(data ? JSON.parse(data) : {});
629
+ } catch {
630
+ resolve({});
631
+ }
632
+ });
633
+ req.on("error", reject);
634
+ });
635
+ }
636
+ /**
637
+ * Send JSON response
638
+ */
639
+ sendJSON(res, data, status = 200) {
640
+ res.writeHead(status, { "Content-Type": "application/json" });
641
+ res.end(JSON.stringify(data));
642
+ }
643
+ /**
644
+ * Broadcast a message to all WebSocket connections (legacy)
645
+ */
646
+ broadcast(message) {
647
+ const data = JSON.stringify(message);
648
+ for (const ws of this.wsConnections) {
649
+ if (ws.readyState === 1) {
650
+ ws.send(data);
651
+ }
652
+ }
653
+ }
654
+ /**
655
+ * Broadcast an event to all subscribed WebSocket clients
656
+ */
657
+ broadcastEvent(event) {
658
+ if (this.wsHandler) {
659
+ this.wsHandler.broadcastEvent(event);
660
+ }
661
+ }
662
+ /**
663
+ * Get WebSocket handler for direct access
664
+ */
665
+ getWSHandler() {
666
+ return this.wsHandler;
667
+ }
668
+ /**
669
+ * Get number of connected WebSocket clients
670
+ */
671
+ get wsClientCount() {
672
+ return this.wsHandler?.clientCount ?? 0;
673
+ }
674
+ /**
675
+ * Get the server address
676
+ */
677
+ getAddress() {
678
+ const address = this.server?.address();
679
+ if (!address || typeof address === "string") return null;
680
+ return { host: this.config.host, port: address.port };
681
+ }
682
+ };
683
+ async function createStandaloneServer(handlers, config) {
684
+ const server = new StandaloneServer(handlers, config);
685
+ await server.start();
686
+ return server;
687
+ }
688
+ async function startCLI(handlers, args = process.argv.slice(2)) {
689
+ const config = {};
690
+ for (let i = 0; i < args.length; i++) {
691
+ const arg = args[i];
692
+ const nextArg = args[i + 1];
693
+ if (arg === "--port" || arg === "-p") {
694
+ config.port = parseInt(nextArg);
695
+ i++;
696
+ } else if (arg === "--host" || arg === "-h") {
697
+ config.host = nextArg;
698
+ i++;
699
+ } else if (arg === "--cors") {
700
+ config.cors = true;
701
+ }
702
+ }
703
+ const server = await createStandaloneServer(handlers, config);
704
+ process.on("SIGINT", async () => {
705
+ console.log("\nShutting down...");
706
+ await server.stop();
707
+ process.exit(0);
708
+ });
709
+ process.on("SIGTERM", async () => {
710
+ await server.stop();
711
+ process.exit(0);
712
+ });
713
+ }
714
+
715
+ exports.StandaloneServer = StandaloneServer;
716
+ exports.createStandaloneServer = createStandaloneServer;
717
+ exports.startCLI = startCLI;
718
+ //# sourceMappingURL=standalone.js.map
719
+ //# sourceMappingURL=standalone.js.map