@lingxia/bridge 0.5.1 → 0.6.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.
@@ -1,5 +1,5 @@
1
1
  import { BRIDGE_ERROR } from "./types";
2
- import { toBridgeError } from "./invocation";
2
+ import { toBridgeError, toNativeError } from "./invocation";
3
3
  import { installNativeComponentCoverageMonitor } from "./nativecomponents/coverage-monitor";
4
4
  import { BRIDGE_CONFIG, getCommunicationMethod, getPlatformOS, isAndroid, isHarmony, isIOS, isMacOS, isDesktop, } from "./runtime-env";
5
5
  const NATIVE_HANDLER_NAME = "LingXia";
@@ -11,7 +11,7 @@ const LOG_PREFIX = "[LX.Bridge]";
11
11
  const MESSAGE_PORT_TYPE = "messageport";
12
12
  const JS_INTERFACE_TYPE = "jsinterface";
13
13
  const OUTBOX_LIMIT = 256;
14
- const APPLE_DOWNSTREAM_PATH = "/__lingxia/bridge/downstream";
14
+ const APPLE_DOWNSTREAM_URL = "lx-apple://bridge/downstream";
15
15
  const APPLE_RECONNECT_BASE_MS = 200;
16
16
  const APPLE_RECONNECT_MAX_MS = 2000;
17
17
  const debugFlags = { data: false, proto: false, all: false };
@@ -188,7 +188,7 @@ async function runAppleDownstream() {
188
188
  appleDownstreamAbortController = controller;
189
189
  let response;
190
190
  try {
191
- response = await fetch(APPLE_DOWNSTREAM_PATH, {
191
+ response = await fetch(APPLE_DOWNSTREAM_URL, {
192
192
  method: "GET",
193
193
  cache: "no-store",
194
194
  headers: { Accept: "application/x-ndjson" },
@@ -891,7 +891,7 @@ function subscribeState(callback) {
891
891
  };
892
892
  }
893
893
  function requestStateRecovery(scope) {
894
- LingXiaBridge.call("state.getSnapshot", { scope }).catch(() => { });
894
+ rawBridge.call("state.getSnapshot", { scope }).catch(() => { });
895
895
  }
896
896
  function applySnapshotFromResult(result) {
897
897
  if (!result || typeof result !== "object")
@@ -1201,8 +1201,8 @@ function attachAbortSignal(id, signal, onAbort) {
1201
1201
  };
1202
1202
  signal.addEventListener("abort", abortListener);
1203
1203
  }
1204
- // Public interface
1205
- export const LingXiaBridge = {
1204
+ // Low-level protocol interface. Public consumers should use LingXiaBridge.invoke/stream/channel.
1205
+ const rawBridge = {
1206
1206
  call(method, params, options) {
1207
1207
  return new Promise((resolve, reject) => {
1208
1208
  if (!method || typeof method !== "string") {
@@ -1345,6 +1345,31 @@ export const LingXiaBridge = {
1345
1345
  });
1346
1346
  },
1347
1347
  },
1348
+ };
1349
+ // Public interface
1350
+ export const LingXiaBridge = {
1351
+ invoke(route, input, options) {
1352
+ return rawBridge
1353
+ .call(nativeRoute(route), input, nativeOptions(options))
1354
+ .then((value) => value)
1355
+ .catch((error) => Promise.reject(toNativeError(error)));
1356
+ },
1357
+ notify(route, input, options) {
1358
+ rawBridge.notify(nativeRoute(route), input, nativeOptions(options));
1359
+ },
1360
+ stream(route, input, options) {
1361
+ return wrapNativeStream(rawBridge.stream(nativeRoute(route), input, nativeOptions(options)));
1362
+ },
1363
+ channel(route, input, options) {
1364
+ return rawBridge.channel
1365
+ .open(nativeRoute(route), input, nativeOptions(options))
1366
+ .then((handle) => wrapNativeChannel(handle))
1367
+ .catch((error) => Promise.reject(toNativeError(error)));
1368
+ },
1369
+ raw: rawBridge,
1370
+ state: {
1371
+ subscribe: subscribeState,
1372
+ },
1348
1373
  _connectWebMessagePort(port) {
1349
1374
  if (communicationMethod !== MESSAGE_PORT_TYPE)
1350
1375
  return;
@@ -1452,89 +1477,88 @@ export const LingXiaBridge = {
1452
1477
  return handshakeDone;
1453
1478
  },
1454
1479
  };
1455
- function createHostPathProxy(path) {
1456
- const callable = () => { };
1457
- return new Proxy(callable, {
1458
- apply(_target, _thisArg, args) {
1459
- const method = path.join(".");
1460
- const payload = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
1461
- // Always use stream — it works for both unary and stream host handlers.
1462
- // Unary handlers return a single `res`; stream handlers emit `event`s then `res`.
1463
- // The returned handle is also thenable so `await host.x.y()` just works.
1464
- const handle = LingXiaBridge.stream(`host.${method}`, payload, { cap: "host", timeoutMs: 0 });
1465
- // Make thenable: `await host.x.y()` resolves to the final result,
1466
- // while `host.x.y().on('data', ...)` works for streams.
1467
- const result = handle.result;
1468
- return new Proxy(handle, {
1469
- get(target, prop) {
1470
- if (prop === "then")
1471
- return result.then.bind(result);
1472
- if (prop === "catch")
1473
- return result.catch.bind(result);
1474
- const val = target[prop];
1475
- return typeof val === "function" ? val.bind(target) : val;
1476
- },
1477
- });
1480
+ function nativeRoute(route) {
1481
+ return route.startsWith("host.") ? route : `host.${route}`;
1482
+ }
1483
+ function nativeOptions(options) {
1484
+ return { ...(options || {}), cap: options?.cap || "host" };
1485
+ }
1486
+ function wrapNativeStream(handle) {
1487
+ const eventListeners = new Set();
1488
+ const errorListeners = new Set();
1489
+ handle.on("data", (event) => {
1490
+ for (const listener of eventListeners)
1491
+ listener(event);
1492
+ });
1493
+ handle.on("error", (error) => {
1494
+ const nativeError = toNativeError(error);
1495
+ for (const listener of errorListeners)
1496
+ listener(nativeError);
1497
+ });
1498
+ return {
1499
+ onEvent(listener) {
1500
+ eventListeners.add(listener);
1501
+ return () => {
1502
+ eventListeners.delete(listener);
1503
+ };
1478
1504
  },
1479
- get(_target, prop) {
1480
- if (prop === "then")
1481
- return undefined;
1482
- if (prop === "__funcName")
1483
- return `host.${path.join(".")}`;
1484
- if (prop === "__bridgeMode")
1485
- return "stream";
1486
- if (typeof prop !== "string")
1487
- return undefined;
1488
- return createHostPathProxy([...path, prop]);
1505
+ onError(listener) {
1506
+ errorListeners.add(listener);
1507
+ return () => {
1508
+ errorListeners.delete(listener);
1509
+ };
1489
1510
  },
1490
- });
1511
+ result: handle.result.catch((error) => Promise.reject(toNativeError(error))),
1512
+ cancel() {
1513
+ handle.cancel();
1514
+ },
1515
+ };
1491
1516
  }
1492
- function createHostChannelProxy(path) {
1493
- const callable = () => { };
1494
- return new Proxy(callable, {
1495
- apply(_target, _thisArg, args) {
1496
- const method = path.join(".");
1497
- const payload = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
1498
- return LingXiaBridge.channel.open(`host.${method}`, payload, { cap: "host" });
1517
+ function wrapNativeChannel(channel) {
1518
+ const messageListeners = new Set();
1519
+ const closeListeners = new Set();
1520
+ channel.on("data", (message) => {
1521
+ for (const listener of messageListeners)
1522
+ listener(message);
1523
+ });
1524
+ channel.on("close", (code, reason) => {
1525
+ const event = { code, reason };
1526
+ for (const listener of closeListeners)
1527
+ listener(event);
1528
+ });
1529
+ return {
1530
+ send(message) {
1531
+ channel.send(message);
1499
1532
  },
1500
- get(_target, prop) {
1501
- if (prop === "then")
1502
- return undefined;
1503
- if (prop === "__funcName")
1504
- return `host.${path.join(".")}`;
1505
- if (prop === "__bridgeMode")
1506
- return "channel";
1507
- if (prop === "open") {
1508
- return (...args) => {
1509
- const method = path.join(".");
1510
- const payload = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
1511
- return LingXiaBridge.channel.open(`host.${method}`, payload, { cap: "host" });
1512
- };
1513
- }
1514
- if (typeof prop !== "string")
1515
- return undefined;
1516
- return createHostChannelProxy([...path, prop]);
1533
+ onMessage(listener) {
1534
+ messageListeners.add(listener);
1535
+ return () => {
1536
+ messageListeners.delete(listener);
1537
+ };
1517
1538
  },
1518
- });
1539
+ onClose(listener) {
1540
+ closeListeners.add(listener);
1541
+ return () => {
1542
+ closeListeners.delete(listener);
1543
+ };
1544
+ },
1545
+ close(code, reason) {
1546
+ channel.close(code, reason);
1547
+ },
1548
+ };
1549
+ }
1550
+ export function invoke(route, input, options) {
1551
+ return LingXiaBridge.invoke(route, input, options);
1552
+ }
1553
+ export function notify(route, input, options) {
1554
+ rawBridge.notify(nativeRoute(route), input, nativeOptions(options));
1555
+ }
1556
+ export function stream(route, input, options) {
1557
+ return wrapNativeStream(rawBridge.stream(nativeRoute(route), input, nativeOptions(options)));
1558
+ }
1559
+ export function channel(route, input, options) {
1560
+ return LingXiaBridge.channel(route, input, options);
1519
1561
  }
1520
- export const host = new Proxy({}, {
1521
- get(_target, prop) {
1522
- if (typeof prop !== "string") {
1523
- return undefined;
1524
- }
1525
- if (prop === "channel") {
1526
- return new Proxy({}, {
1527
- get(_target, channelProp) {
1528
- if (typeof channelProp !== "string") {
1529
- return undefined;
1530
- }
1531
- return createHostChannelProxy([channelProp]);
1532
- },
1533
- });
1534
- }
1535
- return createHostPathProxy([prop]);
1536
- },
1537
- });
1538
1562
  export function initBridge() {
1539
1563
  if (window.__LX_BRIDGE_INIT_STATE) {
1540
1564
  log(`Bridge already ${window.__LX_BRIDGE_INIT_STATE}, skipping duplicate init`);
@@ -1559,7 +1583,6 @@ export function initBridge() {
1559
1583
  warn("Unknown method");
1560
1584
  }
1561
1585
  window.LingXiaBridge = LingXiaBridge;
1562
- window.host = host;
1563
1586
  installNativeComponentCoverageMonitor({
1564
1587
  os: getPlatformOS(),
1565
1588
  send: sendNativeComponentMessage,
@@ -5,7 +5,8 @@
5
5
  * - Bridge initialization for native communication
6
6
  * - Error UI rendering when page cannot be loaded
7
7
  */
8
- export { LingXiaBridge, host, initBridge } from './bridge';
8
+ export { LingXiaBridge, channel, initBridge, invoke, notify, stream, } from './bridge';
9
+ export { isNativeError } from './invocation';
9
10
  export { renderErrorUI, hasError, getErrorInfo } from './error';
10
11
  export { boot, bootWhenReady } from './boot';
11
12
  import { bootWhenReady } from './boot';
@@ -27,6 +27,26 @@ export function toBridgeError(err) {
27
27
  const message = err instanceof Error ? err.message : typeof err === "string" ? err : "Unknown error";
28
28
  return new BridgeInvocationError(BRIDGE_ERROR.INTERNAL_ERROR, message);
29
29
  }
30
+ export function toNativeError(err) {
31
+ const bridgeError = toBridgeError(err);
32
+ return {
33
+ code: String(bridgeError.code || BRIDGE_ERROR.INTERNAL_ERROR),
34
+ message: typeof bridgeError.message === "string" && bridgeError.message.trim() !== ""
35
+ ? bridgeError.message
36
+ : "Unknown error",
37
+ ...(bridgeError.data === undefined ? {} : { data: bridgeError.data }),
38
+ };
39
+ }
40
+ export function isNativeError(error, code) {
41
+ if (!error || typeof error !== "object")
42
+ return false;
43
+ const candidate = error;
44
+ if (typeof candidate.code !== "string" || candidate.code.trim() === "")
45
+ return false;
46
+ if (typeof candidate.message !== "string")
47
+ return false;
48
+ return code === undefined || candidate.code === code;
49
+ }
30
50
  export function resolveParams(source) {
31
51
  if (typeof source === "function") {
32
52
  return source();
@@ -1,3 +1,14 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
1
12
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
13
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
14
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -71,7 +82,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
71
82
  return to.concat(ar || Array.prototype.slice.call(from));
72
83
  };
73
84
  import { BRIDGE_ERROR } from "./types";
74
- import { toBridgeError } from "./invocation";
85
+ import { toBridgeError, toNativeError } from "./invocation";
75
86
  import { installNativeComponentCoverageMonitor } from "./nativecomponents/coverage-monitor";
76
87
  import { BRIDGE_CONFIG, getCommunicationMethod, getPlatformOS, isAndroid, isHarmony, isIOS, isMacOS, isDesktop, } from "./runtime-env";
77
88
  var NATIVE_HANDLER_NAME = "LingXia";
@@ -83,7 +94,7 @@ var LOG_PREFIX = "[LX.Bridge]";
83
94
  var MESSAGE_PORT_TYPE = "messageport";
84
95
  var JS_INTERFACE_TYPE = "jsinterface";
85
96
  var OUTBOX_LIMIT = 256;
86
- var APPLE_DOWNSTREAM_PATH = "/__lingxia/bridge/downstream";
97
+ var APPLE_DOWNSTREAM_URL = "lx-apple://bridge/downstream";
87
98
  var APPLE_RECONNECT_BASE_MS = 200;
88
99
  var APPLE_RECONNECT_MAX_MS = 2000;
89
100
  var debugFlags = { data: false, proto: false, all: false };
@@ -234,9 +245,9 @@ function closeActiveChannelsFromTransport(reason) {
234
245
  var e_2, _a;
235
246
  try {
236
247
  for (var _b = __values(Array.from(activeChannels.entries())), _c = _b.next(); !_c.done; _c = _b.next()) {
237
- var _d = __read(_c.value, 2), id = _d[0], channel = _d[1];
248
+ var _d = __read(_c.value, 2), id = _d[0], channel_1 = _d[1];
238
249
  activeChannels.delete(id);
239
- channel._emitClose(BRIDGE_ERROR.STREAM_CLOSED, reason);
250
+ channel_1._emitClose(BRIDGE_ERROR.STREAM_CLOSED, reason);
240
251
  }
241
252
  }
242
253
  catch (e_2_1) { e_2 = { error: e_2_1 }; }
@@ -322,7 +333,7 @@ function runAppleDownstream() {
322
333
  _b.label = 1;
323
334
  case 1:
324
335
  _b.trys.push([1, 3, , 4]);
325
- return [4 /*yield*/, fetch(APPLE_DOWNSTREAM_PATH, {
336
+ return [4 /*yield*/, fetch(APPLE_DOWNSTREAM_URL, {
326
337
  method: "GET",
327
338
  cache: "no-store",
328
339
  headers: { Accept: "application/x-ndjson" },
@@ -1149,7 +1160,7 @@ function subscribeState(callback) {
1149
1160
  };
1150
1161
  }
1151
1162
  function requestStateRecovery(scope) {
1152
- LingXiaBridge.call("state.getSnapshot", { scope: scope }).catch(function () { });
1163
+ rawBridge.call("state.getSnapshot", { scope: scope }).catch(function () { });
1153
1164
  }
1154
1165
  function applySnapshotFromResult(result) {
1155
1166
  if (!result || typeof result !== "object")
@@ -1331,10 +1342,10 @@ function handleIncomingMessage(msg) {
1331
1342
  return;
1332
1343
  }
1333
1344
  case "ch.data": {
1334
- var channel = activeChannels.get(message.id);
1335
- if (!channel)
1345
+ var channel_2 = activeChannels.get(message.id);
1346
+ if (!channel_2)
1336
1347
  return;
1337
- channel._emitData(message.payload);
1348
+ channel_2._emitData(message.payload);
1338
1349
  return;
1339
1350
  }
1340
1351
  case "ch.close": {
@@ -1344,11 +1355,11 @@ function handleIncomingMessage(msg) {
1344
1355
  pendingChannel.channel._emitClose(message.code, message.reason);
1345
1356
  return;
1346
1357
  }
1347
- var channel = activeChannels.get(message.id);
1348
- if (!channel)
1358
+ var channel_3 = activeChannels.get(message.id);
1359
+ if (!channel_3)
1349
1360
  return;
1350
1361
  activeChannels.delete(message.id);
1351
- channel._emitClose(message.code, message.reason);
1362
+ channel_3._emitClose(message.code, message.reason);
1352
1363
  return;
1353
1364
  }
1354
1365
  case "req": {
@@ -1473,8 +1484,8 @@ function attachAbortSignal(id, signal, onAbort) {
1473
1484
  };
1474
1485
  signal.addEventListener("abort", abortListener);
1475
1486
  }
1476
- // Public interface
1477
- export var LingXiaBridge = {
1487
+ // Low-level protocol interface. Public consumers should use LingXiaBridge.invoke/stream/channel.
1488
+ var rawBridge = {
1478
1489
  call: function (method, params, options) {
1479
1490
  return new Promise(function (resolve, reject) {
1480
1491
  var _a;
@@ -1619,6 +1630,31 @@ export var LingXiaBridge = {
1619
1630
  });
1620
1631
  },
1621
1632
  },
1633
+ };
1634
+ // Public interface
1635
+ export var LingXiaBridge = {
1636
+ invoke: function (route, input, options) {
1637
+ return rawBridge
1638
+ .call(nativeRoute(route), input, nativeOptions(options))
1639
+ .then(function (value) { return value; })
1640
+ .catch(function (error) { return Promise.reject(toNativeError(error)); });
1641
+ },
1642
+ notify: function (route, input, options) {
1643
+ rawBridge.notify(nativeRoute(route), input, nativeOptions(options));
1644
+ },
1645
+ stream: function (route, input, options) {
1646
+ return wrapNativeStream(rawBridge.stream(nativeRoute(route), input, nativeOptions(options)));
1647
+ },
1648
+ channel: function (route, input, options) {
1649
+ return rawBridge.channel
1650
+ .open(nativeRoute(route), input, nativeOptions(options))
1651
+ .then(function (handle) { return wrapNativeChannel(handle); })
1652
+ .catch(function (error) { return Promise.reject(toNativeError(error)); });
1653
+ },
1654
+ raw: rawBridge,
1655
+ state: {
1656
+ subscribe: subscribeState,
1657
+ },
1622
1658
  _connectWebMessagePort: function (port) {
1623
1659
  if (communicationMethod !== MESSAGE_PORT_TYPE)
1624
1660
  return;
@@ -1726,93 +1762,136 @@ export var LingXiaBridge = {
1726
1762
  return handshakeDone;
1727
1763
  },
1728
1764
  };
1729
- function createHostPathProxy(path) {
1730
- var callable = function () { };
1731
- return new Proxy(callable, {
1732
- apply: function (_target, _thisArg, args) {
1733
- var method = path.join(".");
1734
- var payload = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
1735
- // Always use stream — it works for both unary and stream host handlers.
1736
- // Unary handlers return a single `res`; stream handlers emit `event`s then `res`.
1737
- // The returned handle is also thenable so `await host.x.y()` just works.
1738
- var handle = LingXiaBridge.stream("host.".concat(method), payload, { cap: "host", timeoutMs: 0 });
1739
- // Make thenable: `await host.x.y()` resolves to the final result,
1740
- // while `host.x.y().on('data', ...)` works for streams.
1741
- var result = handle.result;
1742
- return new Proxy(handle, {
1743
- get: function (target, prop) {
1744
- if (prop === "then")
1745
- return result.then.bind(result);
1746
- if (prop === "catch")
1747
- return result.catch.bind(result);
1748
- var val = target[prop];
1749
- return typeof val === "function" ? val.bind(target) : val;
1750
- },
1751
- });
1752
- },
1753
- get: function (_target, prop) {
1754
- if (prop === "then")
1755
- return undefined;
1756
- if (prop === "__funcName")
1757
- return "host.".concat(path.join("."));
1758
- if (prop === "__bridgeMode")
1759
- return "stream";
1760
- if (typeof prop !== "string")
1761
- return undefined;
1762
- return createHostPathProxy(__spreadArray(__spreadArray([], __read(path), false), [prop], false));
1763
- },
1764
- });
1765
+ function nativeRoute(route) {
1766
+ return route.startsWith("host.") ? route : "host.".concat(route);
1767
+ }
1768
+ function nativeOptions(options) {
1769
+ return __assign(__assign({}, (options || {})), { cap: (options === null || options === void 0 ? void 0 : options.cap) || "host" });
1765
1770
  }
1766
- function createHostChannelProxy(path) {
1767
- var callable = function () { };
1768
- return new Proxy(callable, {
1769
- apply: function (_target, _thisArg, args) {
1770
- var method = path.join(".");
1771
- var payload = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
1772
- return LingXiaBridge.channel.open("host.".concat(method), payload, { cap: "host" });
1771
+ function wrapNativeStream(handle) {
1772
+ var eventListeners = new Set();
1773
+ var errorListeners = new Set();
1774
+ handle.on("data", function (event) {
1775
+ var e_16, _a;
1776
+ try {
1777
+ for (var eventListeners_1 = __values(eventListeners), eventListeners_1_1 = eventListeners_1.next(); !eventListeners_1_1.done; eventListeners_1_1 = eventListeners_1.next()) {
1778
+ var listener = eventListeners_1_1.value;
1779
+ listener(event);
1780
+ }
1781
+ }
1782
+ catch (e_16_1) { e_16 = { error: e_16_1 }; }
1783
+ finally {
1784
+ try {
1785
+ if (eventListeners_1_1 && !eventListeners_1_1.done && (_a = eventListeners_1.return)) _a.call(eventListeners_1);
1786
+ }
1787
+ finally { if (e_16) throw e_16.error; }
1788
+ }
1789
+ });
1790
+ handle.on("error", function (error) {
1791
+ var e_17, _a;
1792
+ var nativeError = toNativeError(error);
1793
+ try {
1794
+ for (var errorListeners_1 = __values(errorListeners), errorListeners_1_1 = errorListeners_1.next(); !errorListeners_1_1.done; errorListeners_1_1 = errorListeners_1.next()) {
1795
+ var listener = errorListeners_1_1.value;
1796
+ listener(nativeError);
1797
+ }
1798
+ }
1799
+ catch (e_17_1) { e_17 = { error: e_17_1 }; }
1800
+ finally {
1801
+ try {
1802
+ if (errorListeners_1_1 && !errorListeners_1_1.done && (_a = errorListeners_1.return)) _a.call(errorListeners_1);
1803
+ }
1804
+ finally { if (e_17) throw e_17.error; }
1805
+ }
1806
+ });
1807
+ return {
1808
+ onEvent: function (listener) {
1809
+ eventListeners.add(listener);
1810
+ return function () {
1811
+ eventListeners.delete(listener);
1812
+ };
1773
1813
  },
1774
- get: function (_target, prop) {
1775
- if (prop === "then")
1776
- return undefined;
1777
- if (prop === "__funcName")
1778
- return "host.".concat(path.join("."));
1779
- if (prop === "__bridgeMode")
1780
- return "channel";
1781
- if (prop === "open") {
1782
- return function () {
1783
- var args = [];
1784
- for (var _i = 0; _i < arguments.length; _i++) {
1785
- args[_i] = arguments[_i];
1786
- }
1787
- var method = path.join(".");
1788
- var payload = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
1789
- return LingXiaBridge.channel.open("host.".concat(method), payload, { cap: "host" });
1790
- };
1791
- }
1792
- if (typeof prop !== "string")
1793
- return undefined;
1794
- return createHostChannelProxy(__spreadArray(__spreadArray([], __read(path), false), [prop], false));
1814
+ onError: function (listener) {
1815
+ errorListeners.add(listener);
1816
+ return function () {
1817
+ errorListeners.delete(listener);
1818
+ };
1795
1819
  },
1796
- });
1820
+ result: handle.result.catch(function (error) { return Promise.reject(toNativeError(error)); }),
1821
+ cancel: function () {
1822
+ handle.cancel();
1823
+ },
1824
+ };
1797
1825
  }
1798
- export var host = new Proxy({}, {
1799
- get: function (_target, prop) {
1800
- if (typeof prop !== "string") {
1801
- return undefined;
1826
+ function wrapNativeChannel(channel) {
1827
+ var messageListeners = new Set();
1828
+ var closeListeners = new Set();
1829
+ channel.on("data", function (message) {
1830
+ var e_18, _a;
1831
+ try {
1832
+ for (var messageListeners_1 = __values(messageListeners), messageListeners_1_1 = messageListeners_1.next(); !messageListeners_1_1.done; messageListeners_1_1 = messageListeners_1.next()) {
1833
+ var listener = messageListeners_1_1.value;
1834
+ listener(message);
1835
+ }
1802
1836
  }
1803
- if (prop === "channel") {
1804
- return new Proxy({}, {
1805
- get: function (_target, channelProp) {
1806
- if (typeof channelProp !== "string") {
1807
- return undefined;
1808
- }
1809
- return createHostChannelProxy([channelProp]);
1810
- },
1811
- });
1837
+ catch (e_18_1) { e_18 = { error: e_18_1 }; }
1838
+ finally {
1839
+ try {
1840
+ if (messageListeners_1_1 && !messageListeners_1_1.done && (_a = messageListeners_1.return)) _a.call(messageListeners_1);
1841
+ }
1842
+ finally { if (e_18) throw e_18.error; }
1812
1843
  }
1813
- return createHostPathProxy([prop]);
1814
- },
1815
- });
1844
+ });
1845
+ channel.on("close", function (code, reason) {
1846
+ var e_19, _a;
1847
+ var event = { code: code, reason: reason };
1848
+ try {
1849
+ for (var closeListeners_1 = __values(closeListeners), closeListeners_1_1 = closeListeners_1.next(); !closeListeners_1_1.done; closeListeners_1_1 = closeListeners_1.next()) {
1850
+ var listener = closeListeners_1_1.value;
1851
+ listener(event);
1852
+ }
1853
+ }
1854
+ catch (e_19_1) { e_19 = { error: e_19_1 }; }
1855
+ finally {
1856
+ try {
1857
+ if (closeListeners_1_1 && !closeListeners_1_1.done && (_a = closeListeners_1.return)) _a.call(closeListeners_1);
1858
+ }
1859
+ finally { if (e_19) throw e_19.error; }
1860
+ }
1861
+ });
1862
+ return {
1863
+ send: function (message) {
1864
+ channel.send(message);
1865
+ },
1866
+ onMessage: function (listener) {
1867
+ messageListeners.add(listener);
1868
+ return function () {
1869
+ messageListeners.delete(listener);
1870
+ };
1871
+ },
1872
+ onClose: function (listener) {
1873
+ closeListeners.add(listener);
1874
+ return function () {
1875
+ closeListeners.delete(listener);
1876
+ };
1877
+ },
1878
+ close: function (code, reason) {
1879
+ channel.close(code, reason);
1880
+ },
1881
+ };
1882
+ }
1883
+ export function invoke(route, input, options) {
1884
+ return LingXiaBridge.invoke(route, input, options);
1885
+ }
1886
+ export function notify(route, input, options) {
1887
+ rawBridge.notify(nativeRoute(route), input, nativeOptions(options));
1888
+ }
1889
+ export function stream(route, input, options) {
1890
+ return wrapNativeStream(rawBridge.stream(nativeRoute(route), input, nativeOptions(options)));
1891
+ }
1892
+ export function channel(route, input, options) {
1893
+ return LingXiaBridge.channel(route, input, options);
1894
+ }
1816
1895
  export function initBridge() {
1817
1896
  if (window.__LX_BRIDGE_INIT_STATE) {
1818
1897
  log("Bridge already ".concat(window.__LX_BRIDGE_INIT_STATE, ", skipping duplicate init"));
@@ -1837,7 +1916,6 @@ export function initBridge() {
1837
1916
  warn("Unknown method");
1838
1917
  }
1839
1918
  window.LingXiaBridge = LingXiaBridge;
1840
- window.host = host;
1841
1919
  installNativeComponentCoverageMonitor({
1842
1920
  os: getPlatformOS(),
1843
1921
  send: sendNativeComponentMessage,
package/dist/es5/index.js CHANGED
@@ -5,7 +5,8 @@
5
5
  * - Bridge initialization for native communication
6
6
  * - Error UI rendering when page cannot be loaded
7
7
  */
8
- export { LingXiaBridge, host, initBridge } from './bridge';
8
+ export { LingXiaBridge, channel, initBridge, invoke, notify, stream, } from './bridge';
9
+ export { isNativeError } from './invocation';
9
10
  export { renderErrorUI, hasError, getErrorInfo } from './error';
10
11
  export { boot, bootWhenReady } from './boot';
11
12
  import { bootWhenReady } from './boot';