@qontinui/ui-bridge-native 0.3.0 → 0.3.2

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 (39) hide show
  1. package/dist/{StateAnnotation-WmK1YjwP.d.ts → StateAnnotation--zm0Jfqj.d.ts} +4 -4
  2. package/dist/{StateAnnotation-D8reaRcS.d.mts → StateAnnotation-BgFoVWFy.d.mts} +4 -4
  3. package/dist/control/index.d.mts +4 -4
  4. package/dist/control/index.d.ts +4 -4
  5. package/dist/core/index.d.mts +3 -3
  6. package/dist/core/index.d.ts +3 -3
  7. package/dist/core/index.js +89 -6
  8. package/dist/core/index.js.map +1 -1
  9. package/dist/core/index.mjs +89 -6
  10. package/dist/core/index.mjs.map +1 -1
  11. package/dist/design/index.d.mts +1 -1
  12. package/dist/design/index.d.ts +1 -1
  13. package/dist/{http-server-D2U1k48d.d.mts → http-server--550eD1F.d.mts} +106 -4
  14. package/dist/{http-server-ck8clUsZ.d.ts → http-server-C9NaNBEP.d.ts} +106 -4
  15. package/dist/index.d.mts +5 -5
  16. package/dist/index.d.ts +5 -5
  17. package/dist/index.js +576 -49
  18. package/dist/index.js.map +1 -1
  19. package/dist/index.mjs +576 -49
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/react/index.d.mts +5 -5
  22. package/dist/react/index.d.ts +5 -5
  23. package/dist/react/index.js +576 -49
  24. package/dist/react/index.js.map +1 -1
  25. package/dist/react/index.mjs +576 -49
  26. package/dist/react/index.mjs.map +1 -1
  27. package/dist/{registry-KdUW_koV.d.mts → registry-B5JadBN9.d.mts} +49 -2
  28. package/dist/{registry-BxXaxmsT.d.ts → registry-pAUpQq2O.d.ts} +49 -2
  29. package/dist/server/index.d.mts +65 -6
  30. package/dist/server/index.d.ts +65 -6
  31. package/dist/server/index.js +438 -2
  32. package/dist/server/index.js.map +1 -1
  33. package/dist/server/index.mjs +437 -3
  34. package/dist/server/index.mjs.map +1 -1
  35. package/dist/{types-DjB0zJJH.d.mts → types-B0XA4vOF.d.mts} +1 -1
  36. package/dist/{types-BwdPNpII.d.mts → types-CGVut7mc.d.mts} +43 -1
  37. package/dist/{types-BwdPNpII.d.ts → types-CGVut7mc.d.ts} +43 -1
  38. package/dist/{types-DCEv5qb6.d.ts → types-CjEKTDYT.d.ts} +1 -1
  39. package/package.json +1 -1
@@ -1021,7 +1021,8 @@ function createServerHandlers(registry, executor, config) {
1021
1021
  },
1022
1022
  getSnapshot: async (ctx) => {
1023
1023
  const visibleOnly = ctx.query?.visibleOnly === "true" || ctx.body?.visibleOnly === true;
1024
- const snapshot = registry.createSnapshot(void 0, { visibleOnly });
1024
+ const currentRouteOnly = ctx.query?.currentRouteOnly === "true" || ctx.body?.currentRouteOnly === true;
1025
+ const snapshot = registry.createSnapshot(void 0, { visibleOnly, currentRouteOnly });
1025
1026
  return success2(snapshot);
1026
1027
  },
1027
1028
  // Workflows
@@ -1188,6 +1189,134 @@ function createServerHandlers(registry, executor, config) {
1188
1189
  const failedCount = results.length - succeededCount;
1189
1190
  return success2({ results, succeededCount, failedCount });
1190
1191
  },
1192
+ // Coord-based tap
1193
+ //
1194
+ // Synthesizes a press at the given screen coordinates by scanning the
1195
+ // registered elements' layout rects for a containing match. We prefer the
1196
+ // *topmost* match (smallest area = innermost child) since native UIs
1197
+ // generally render parents before children, and the user's tap should
1198
+ // logically hit the leaf-most interactive element.
1199
+ //
1200
+ // Coords are interpreted in the absolute (screen) space published by
1201
+ // `measureInWindow`; we compare against `pageX/pageY` when available and
1202
+ // fall back to the layout's relative `x/y` so this works in test fixtures
1203
+ // that don't measure (the fallback only matches single-rooted screens but
1204
+ // is good enough for the unit suite).
1205
+ tapAt: async (ctx) => {
1206
+ const body = ctx.body;
1207
+ const x = body?.x;
1208
+ const y = body?.y;
1209
+ if (typeof x !== "number" || !Number.isFinite(x)) {
1210
+ return error2('"x" must be a finite number', "INVALID_REQUEST");
1211
+ }
1212
+ if (typeof y !== "number" || !Number.isFinite(y)) {
1213
+ return error2('"y" must be a finite number', "INVALID_REQUEST");
1214
+ }
1215
+ const action = body?.action ?? "press";
1216
+ const allowedActions = [
1217
+ "press",
1218
+ "longPress",
1219
+ "doubleTap"
1220
+ ];
1221
+ if (!allowedActions.includes(action)) {
1222
+ return error2(
1223
+ `"action" must be one of: ${allowedActions.join(", ")}`,
1224
+ "INVALID_REQUEST"
1225
+ );
1226
+ }
1227
+ const candidates = [];
1228
+ for (const el of registry.getAllElements()) {
1229
+ const state = el.getState();
1230
+ const layout = state?.layout;
1231
+ if (!layout) continue;
1232
+ if (typeof layout.width !== "number" || typeof layout.height !== "number" || layout.width <= 0 || layout.height <= 0) {
1233
+ continue;
1234
+ }
1235
+ const hasPage = typeof layout.pageX === "number" && typeof layout.pageY === "number" && Number.isFinite(layout.pageX) && Number.isFinite(layout.pageY);
1236
+ const left = hasPage ? layout.pageX : layout.x;
1237
+ const top = hasPage ? layout.pageY : layout.y;
1238
+ if (x >= left && x <= left + layout.width && y >= top && y <= top + layout.height) {
1239
+ candidates.push({
1240
+ elementId: el.id,
1241
+ layout,
1242
+ area: layout.width * layout.height
1243
+ });
1244
+ }
1245
+ }
1246
+ if (candidates.length === 0) {
1247
+ return error2(
1248
+ `No element registered at (${x}, ${y})`,
1249
+ "no_element_at_coords"
1250
+ );
1251
+ }
1252
+ candidates.sort((a, b) => a.area - b.area);
1253
+ const target = candidates[0];
1254
+ const response = await executor.executeAction(target.elementId, { action });
1255
+ if (!response.success) {
1256
+ return error2(response.error || "Action failed", "ACTION_FAILED");
1257
+ }
1258
+ return success2({
1259
+ elementId: target.elementId,
1260
+ action,
1261
+ layout: {
1262
+ x: target.layout.x,
1263
+ y: target.layout.y,
1264
+ width: target.layout.width,
1265
+ height: target.layout.height,
1266
+ pageX: target.layout.pageX,
1267
+ pageY: target.layout.pageY
1268
+ }
1269
+ });
1270
+ },
1271
+ // Observability — console error / network request ring buffers.
1272
+ //
1273
+ // The buffers are owned by NativeUIBridgeServer and patched onto the
1274
+ // globals on `start()` (gated behind `features.testHooks`). When no
1275
+ // buffer is provided (no testHooks, or a stripped-down server fixture),
1276
+ // these handlers gracefully return empty arrays so callers can probe
1277
+ // without 500ing.
1278
+ getConsoleErrors: async (ctx) => {
1279
+ const buf = config?.consoleErrorBuffer;
1280
+ const since = ctx.query?.since !== void 0 ? Number(ctx.query.since) : void 0;
1281
+ const limit = ctx.query?.limit !== void 0 ? Number(ctx.query.limit) : void 0;
1282
+ if (!buf) {
1283
+ return success2({
1284
+ entries: [],
1285
+ count: 0,
1286
+ bufferSize: 0
1287
+ });
1288
+ }
1289
+ const entries = buf.entries({
1290
+ since: typeof since === "number" && Number.isFinite(since) ? since : void 0,
1291
+ limit: typeof limit === "number" && Number.isFinite(limit) ? limit : void 0
1292
+ });
1293
+ return success2({
1294
+ entries,
1295
+ count: entries.length,
1296
+ bufferSize: buf.size()
1297
+ });
1298
+ },
1299
+ getNetworkRequests: async (ctx) => {
1300
+ const buf = config?.networkRequestBuffer;
1301
+ const since = ctx.query?.since !== void 0 ? Number(ctx.query.since) : void 0;
1302
+ const limit = ctx.query?.limit !== void 0 ? Number(ctx.query.limit) : void 0;
1303
+ if (!buf) {
1304
+ return success2({
1305
+ entries: [],
1306
+ count: 0,
1307
+ bufferSize: 0
1308
+ });
1309
+ }
1310
+ const entries = buf.entries({
1311
+ since: typeof since === "number" && Number.isFinite(since) ? since : void 0,
1312
+ limit: typeof limit === "number" && Number.isFinite(limit) ? limit : void 0
1313
+ });
1314
+ return success2({
1315
+ entries,
1316
+ count: entries.length,
1317
+ bufferSize: buf.size()
1318
+ });
1319
+ },
1191
1320
  // Test hooks — modal stack manipulation
1192
1321
  //
1193
1322
  // These two endpoints exist so external automation runners can drive
@@ -1289,6 +1418,266 @@ function createServerHandlers(registry, executor, config) {
1289
1418
  };
1290
1419
  }
1291
1420
 
1421
+ // src/server/observability.ts
1422
+ var RingBuffer = class {
1423
+ constructor(capacity) {
1424
+ this.capacity = capacity;
1425
+ this.items = [];
1426
+ }
1427
+ push(entry) {
1428
+ this.items.push(entry);
1429
+ if (this.items.length > this.capacity) {
1430
+ this.items.splice(0, this.items.length - this.capacity);
1431
+ }
1432
+ }
1433
+ /**
1434
+ * Return entries optionally filtered by `since` (timestamp ms) and capped
1435
+ * at `limit`. Newest-end is preserved when `limit` would otherwise truncate.
1436
+ */
1437
+ entries(opts = {}) {
1438
+ const { since, limit } = opts;
1439
+ let filtered = this.items;
1440
+ if (typeof since === "number") {
1441
+ filtered = filtered.filter((e) => e.timestamp >= since);
1442
+ }
1443
+ if (typeof limit === "number" && limit >= 0 && filtered.length > limit) {
1444
+ filtered = filtered.slice(filtered.length - limit);
1445
+ }
1446
+ return filtered.slice();
1447
+ }
1448
+ size() {
1449
+ return this.items.length;
1450
+ }
1451
+ clear() {
1452
+ this.items.length = 0;
1453
+ }
1454
+ };
1455
+ function formatConsoleArgs(args) {
1456
+ return args.map((a) => {
1457
+ if (a instanceof Error) return a.message;
1458
+ if (typeof a === "string") return a;
1459
+ try {
1460
+ return JSON.stringify(a);
1461
+ } catch {
1462
+ return String(a);
1463
+ }
1464
+ }).join(" ");
1465
+ }
1466
+ function extractStack(args) {
1467
+ for (const a of args) {
1468
+ if (a instanceof Error && a.stack) return a.stack;
1469
+ }
1470
+ return void 0;
1471
+ }
1472
+ var ConsoleErrorBuffer = class {
1473
+ constructor(capacity = 100) {
1474
+ this.installed = false;
1475
+ this.buffer = new RingBuffer(capacity);
1476
+ }
1477
+ install() {
1478
+ if (this.installed) return;
1479
+ if (typeof console === "undefined") return;
1480
+ this.originalError = console.error;
1481
+ this.originalWarn = console.warn;
1482
+ const buffer = this.buffer;
1483
+ const origError = this.originalError;
1484
+ const origWarn = this.originalWarn;
1485
+ console.error = (...args) => {
1486
+ try {
1487
+ buffer.push({
1488
+ timestamp: Date.now(),
1489
+ level: "error",
1490
+ message: formatConsoleArgs(args),
1491
+ stack: extractStack(args)
1492
+ });
1493
+ } catch {
1494
+ }
1495
+ origError.apply(console, args);
1496
+ };
1497
+ console.warn = (...args) => {
1498
+ try {
1499
+ buffer.push({
1500
+ timestamp: Date.now(),
1501
+ level: "warn",
1502
+ message: formatConsoleArgs(args),
1503
+ stack: extractStack(args)
1504
+ });
1505
+ } catch {
1506
+ }
1507
+ origWarn.apply(console, args);
1508
+ };
1509
+ this.installed = true;
1510
+ }
1511
+ uninstall() {
1512
+ if (!this.installed) return;
1513
+ if (typeof console === "undefined") return;
1514
+ if (this.originalError) console.error = this.originalError;
1515
+ if (this.originalWarn) console.warn = this.originalWarn;
1516
+ this.originalError = void 0;
1517
+ this.originalWarn = void 0;
1518
+ this.installed = false;
1519
+ }
1520
+ entries(opts = {}) {
1521
+ return this.buffer.entries(opts);
1522
+ }
1523
+ size() {
1524
+ return this.buffer.size();
1525
+ }
1526
+ clear() {
1527
+ this.buffer.clear();
1528
+ }
1529
+ isInstalled() {
1530
+ return this.installed;
1531
+ }
1532
+ };
1533
+ function extractUrl(input) {
1534
+ if (typeof input === "string") return input;
1535
+ if (input && typeof input === "object") {
1536
+ const obj = input;
1537
+ if (typeof obj.url === "string") return obj.url;
1538
+ try {
1539
+ return String(input);
1540
+ } catch {
1541
+ return "";
1542
+ }
1543
+ }
1544
+ return "";
1545
+ }
1546
+ function extractMethod(input, init) {
1547
+ if (init && typeof init.method === "string") return init.method.toUpperCase();
1548
+ if (input && typeof input === "object") {
1549
+ const obj = input;
1550
+ if (typeof obj.method === "string") return obj.method.toUpperCase();
1551
+ }
1552
+ return "GET";
1553
+ }
1554
+ var NetworkRequestBuffer = class {
1555
+ constructor(capacity = 100) {
1556
+ this.installed = false;
1557
+ this.buffer = new RingBuffer(capacity);
1558
+ }
1559
+ install() {
1560
+ if (this.installed) return;
1561
+ const g = globalThis;
1562
+ if (typeof g.fetch === "function") {
1563
+ this.originalFetch = g.fetch;
1564
+ const buffer = this.buffer;
1565
+ const original = this.originalFetch;
1566
+ const patched = async (input, init) => {
1567
+ const start = Date.now();
1568
+ const url = extractUrl(input);
1569
+ const method = extractMethod(input, init);
1570
+ try {
1571
+ const res = await original.call(globalThis, input, init);
1572
+ buffer.push({
1573
+ timestamp: start,
1574
+ method,
1575
+ url,
1576
+ status: res.status,
1577
+ durationMs: Date.now() - start,
1578
+ ok: res.ok
1579
+ });
1580
+ return res;
1581
+ } catch (err) {
1582
+ buffer.push({
1583
+ timestamp: start,
1584
+ method,
1585
+ url,
1586
+ status: 0,
1587
+ durationMs: Date.now() - start,
1588
+ ok: false,
1589
+ error: err instanceof Error ? err.message : String(err)
1590
+ });
1591
+ throw err;
1592
+ }
1593
+ };
1594
+ g.fetch = patched;
1595
+ }
1596
+ if (typeof g.XMLHttpRequest === "function") {
1597
+ const Xhr = g.XMLHttpRequest;
1598
+ this.originalXhrOpen = Xhr.prototype.open;
1599
+ this.originalXhrSend = Xhr.prototype.send;
1600
+ const buffer = this.buffer;
1601
+ const origOpen = this.originalXhrOpen;
1602
+ Xhr.prototype.open = function(method, url, ...rest) {
1603
+ this.__uiBridgeMethod = method.toUpperCase();
1604
+ this.__uiBridgeUrl = typeof url === "string" ? url : String(url);
1605
+ return origOpen.call(
1606
+ this,
1607
+ method,
1608
+ url,
1609
+ ...rest
1610
+ );
1611
+ };
1612
+ const origSend = this.originalXhrSend;
1613
+ Xhr.prototype.send = function(body) {
1614
+ const start = Date.now();
1615
+ const method = this.__uiBridgeMethod ?? "GET";
1616
+ const url = this.__uiBridgeUrl ?? "";
1617
+ const finalize = (status, ok, error3) => {
1618
+ buffer.push({
1619
+ timestamp: start,
1620
+ method,
1621
+ url,
1622
+ status,
1623
+ durationMs: Date.now() - start,
1624
+ ok,
1625
+ error: error3
1626
+ });
1627
+ };
1628
+ const onLoadEnd = () => {
1629
+ this.removeEventListener("loadend", onLoadEnd);
1630
+ this.removeEventListener("error", onError);
1631
+ finalize(this.status, this.status >= 200 && this.status < 300);
1632
+ };
1633
+ const onError = () => {
1634
+ this.removeEventListener("loadend", onLoadEnd);
1635
+ this.removeEventListener("error", onError);
1636
+ finalize(0, false, "XMLHttpRequest error");
1637
+ };
1638
+ this.addEventListener("loadend", onLoadEnd);
1639
+ this.addEventListener("error", onError);
1640
+ return origSend.call(
1641
+ this,
1642
+ body
1643
+ );
1644
+ };
1645
+ }
1646
+ this.installed = true;
1647
+ }
1648
+ uninstall() {
1649
+ if (!this.installed) return;
1650
+ const g = globalThis;
1651
+ if (this.originalFetch) {
1652
+ g.fetch = this.originalFetch;
1653
+ this.originalFetch = void 0;
1654
+ }
1655
+ if (typeof g.XMLHttpRequest === "function") {
1656
+ if (this.originalXhrOpen) {
1657
+ g.XMLHttpRequest.prototype.open = this.originalXhrOpen;
1658
+ }
1659
+ if (this.originalXhrSend) {
1660
+ g.XMLHttpRequest.prototype.send = this.originalXhrSend;
1661
+ }
1662
+ }
1663
+ this.originalXhrOpen = void 0;
1664
+ this.originalXhrSend = void 0;
1665
+ this.installed = false;
1666
+ }
1667
+ entries(opts = {}) {
1668
+ return this.buffer.entries(opts);
1669
+ }
1670
+ size() {
1671
+ return this.buffer.size();
1672
+ }
1673
+ clear() {
1674
+ this.buffer.clear();
1675
+ }
1676
+ isInstalled() {
1677
+ return this.installed;
1678
+ }
1679
+ };
1680
+
1292
1681
  // src/server/ws-types.ts
1293
1682
  function isBatchRequest(msg) {
1294
1683
  return typeof msg === "object" && msg !== null && "batch" in msg && Array.isArray(msg.batch);
@@ -1339,6 +1728,10 @@ var WS_ROUTES = [
1339
1728
  },
1340
1729
  // Discovery
1341
1730
  { pattern: "control/find", handler: "find", httpMethods: ["POST"] },
1731
+ // Runner-parity alias for `control/find`; the runner exposes its
1732
+ // AI-powered element search at `/ui-bridge/ai/find`, so mobile mounts the
1733
+ // same handler at both paths to keep agents portable across platforms.
1734
+ { pattern: "ai/find", handler: "find", httpMethods: ["POST"] },
1342
1735
  { pattern: "control/snapshot", handler: "getSnapshot", httpMethods: ["GET"] },
1343
1736
  { pattern: "control/discover", handler: "getSnapshot" },
1344
1737
  // Workflows
@@ -1377,6 +1770,9 @@ var WS_ROUTES = [
1377
1770
  { pattern: "meta/methods", handler: "getMethods", httpMethods: ["GET"] },
1378
1771
  // AI helpers — mobile parity with the runner's `/ui-bridge/ai/*` family.
1379
1772
  { pattern: "ai/fill-form", handler: "fillForm", httpMethods: ["POST"] },
1773
+ // Coord-based tap — synthesizes a press at the given screen coords by
1774
+ // matching against registered elements' layout rects.
1775
+ { pattern: "control/tap", handler: "tapAt", httpMethods: ["POST"] },
1380
1776
  // Test hooks — gated behind `features.testHooks`. Let external runners
1381
1777
  // drive the ModalDetector over HTTP so tests can flip `snapshot.modalStack`
1382
1778
  // without mounting React components.
@@ -1391,6 +1787,20 @@ var WS_ROUTES = [
1391
1787
  handler: "dismissModal",
1392
1788
  httpMethods: ["POST"],
1393
1789
  requiresTestHooks: true
1790
+ },
1791
+ // Observability — last-N console errors + network requests. testHooks-gated
1792
+ // because patching `console.error` / `fetch` is invasive in production.
1793
+ {
1794
+ pattern: "control/console-errors",
1795
+ handler: "getConsoleErrors",
1796
+ httpMethods: ["GET"],
1797
+ requiresTestHooks: true
1798
+ },
1799
+ {
1800
+ pattern: "sdk/network-requests",
1801
+ handler: "getNetworkRequests",
1802
+ httpMethods: ["GET"],
1803
+ requiresTestHooks: true
1394
1804
  }
1395
1805
  ];
1396
1806
  var HANDLER_DESCRIPTIONS = {
@@ -1426,6 +1836,9 @@ var HANDLER_DESCRIPTIONS = {
1426
1836
  diffBaseline: "Diff current UI against a saved baseline",
1427
1837
  getMethods: "List every handler name (legacy introspection)",
1428
1838
  fillForm: "Fill multiple inputs in one call: body { fields: [{elementId, value}] } \u2014 each field dispatches `type` + `clear:true`",
1839
+ tapAt: "Synthesize a press at given screen coords by matching registered element layout rects: body { x, y, action? }",
1840
+ getConsoleErrors: "TEST HOOK \u2014 last-N console.error/console.warn entries; ?since=<ms>&limit=<n>",
1841
+ getNetworkRequests: "TEST HOOK \u2014 last-N fetch/XHR entries with status + duration; ?since=<ms>&limit=<n>",
1429
1842
  pushModal: "TEST HOOK \u2014 push a modal onto the snapshot.modalStack via the registry ModalDetector",
1430
1843
  dismissModal: "TEST HOOK \u2014 dismiss a modal by id from the snapshot.modalStack via the registry ModalDetector"
1431
1844
  };
@@ -1494,8 +1907,15 @@ var NativeUIBridgeServer = class {
1494
1907
  cors: true,
1495
1908
  ...config
1496
1909
  };
1910
+ this.consoleErrorBuffer = new ConsoleErrorBuffer();
1911
+ this.networkRequestBuffer = new NetworkRequestBuffer();
1912
+ if (this.config.appInfo) {
1913
+ this.registry.setAppInfo(this.config.appInfo);
1914
+ }
1497
1915
  this.handlers = createServerHandlers(registry, executor, {
1498
- appInfo: this.config.appInfo
1916
+ appInfo: this.config.appInfo,
1917
+ consoleErrorBuffer: this.consoleErrorBuffer,
1918
+ networkRequestBuffer: this.networkRequestBuffer
1499
1919
  });
1500
1920
  this.handlers.getMethods = async () => {
1501
1921
  const testHooks = this.config.testHooks === true;
@@ -1623,8 +2043,16 @@ var NativeUIBridgeServer = class {
1623
2043
  /**
1624
2044
  * Set a route provider for reporting the current navigation route.
1625
2045
  * When set, `control/snapshot` responses include `currentRoute` and `segments`.
2046
+ *
2047
+ * Also forwards the provider into the registry so the *default*
2048
+ * `getSnapshot` handler (and any other call site of
2049
+ * `registry.createSnapshot`) reads the route too — without this the
2050
+ * cloud-relay/bare-server path returned `currentRoute: null` even when
2051
+ * a `RouteTracker` was wired, because that path never installed the
2052
+ * server-level handler override below.
1626
2053
  */
1627
2054
  setRouteProvider(provider) {
2055
+ this.registry.setRouteProvider(provider);
1628
2056
  const baseGetElements = this.handlers.getElements;
1629
2057
  this.handlers.getElements = async (ctx) => {
1630
2058
  const currentRouteOnly = ctx.query?.currentRouteOnly === "true" || ctx.body?.currentRouteOnly === true;
@@ -1693,6 +2121,10 @@ var NativeUIBridgeServer = class {
1693
2121
  console.warn("[ui-bridge-native] See documentation for supported adapters.");
1694
2122
  return;
1695
2123
  }
2124
+ if (this.config.testHooks === true) {
2125
+ this.consoleErrorBuffer.install();
2126
+ this.networkRequestBuffer.install();
2127
+ }
1696
2128
  await this.adapter.start(this.config.serverPort, this.handleRequest.bind(this));
1697
2129
  this.running = true;
1698
2130
  console.log(`[ui-bridge-native] HTTP server started on port ${this.config.serverPort}`);
@@ -1706,6 +2138,8 @@ var NativeUIBridgeServer = class {
1706
2138
  }
1707
2139
  await this.adapter.stop();
1708
2140
  this.running = false;
2141
+ this.consoleErrorBuffer.uninstall();
2142
+ this.networkRequestBuffer.uninstall();
1709
2143
  console.log("[ui-bridge-native] HTTP server stopped");
1710
2144
  }
1711
2145
  /**
@@ -3002,6 +3436,6 @@ var WebSocketConnection = class {
3002
3436
  }
3003
3437
  };
3004
3438
 
3005
- export { NativeUIBridgeServer, OPCODE_BINARY, OPCODE_CLOSE, OPCODE_CONTINUATION, OPCODE_PING, OPCODE_PONG, OPCODE_TEXT, UI_BRIDGE_NATIVE_ROUTES, WebSocketConnection, WebSocketEventBridge, buildUpgradeResponse, computeAcceptKey, createDesignHandlers, createNativeServer, createServerHandlers, decodeFrames, decodeTextPayload, encodeCloseFrame, encodePingFrame, encodePongFrame, encodeTextFrame, isBatchRequest, isSubscribe, isUnsubscribe };
3439
+ export { ConsoleErrorBuffer, NativeUIBridgeServer, NetworkRequestBuffer, OPCODE_BINARY, OPCODE_CLOSE, OPCODE_CONTINUATION, OPCODE_PING, OPCODE_PONG, OPCODE_TEXT, UI_BRIDGE_NATIVE_ROUTES, WebSocketConnection, WebSocketEventBridge, buildUpgradeResponse, computeAcceptKey, createDesignHandlers, createNativeServer, createServerHandlers, decodeFrames, decodeTextPayload, encodeCloseFrame, encodePingFrame, encodePongFrame, encodeTextFrame, isBatchRequest, isSubscribe, isUnsubscribe };
3006
3440
  //# sourceMappingURL=index.mjs.map
3007
3441
  //# sourceMappingURL=index.mjs.map