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