@interopio/bridge 0.0.6-beta.0 → 1.0.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.
package/dist/main.js CHANGED
@@ -1,3 +1,152 @@
1
+ // ../bridge-mesh/src/mesh/relays.ts
2
+ import { IOGateway } from "@interopio/gateway";
3
+ import { EventEmitter } from "node:events";
4
+ var codec = IOGateway.Encoding.transit({
5
+ keywordize: /* @__PURE__ */ new Map([
6
+ ["/type", "*"],
7
+ ["/message/body/type", "*"],
8
+ ["/message/origin", "*"],
9
+ ["/message/receiver/type", "*"],
10
+ ["/message/source/type", "*"],
11
+ ["/message/body/type", "*"]
12
+ ])
13
+ });
14
+ function isEncoded(msg) {
15
+ return typeof msg === "string" || Buffer.isBuffer(msg);
16
+ }
17
+ var InternalRelays = class {
18
+ #logger;
19
+ // key -> handler
20
+ #handlersByKey = /* @__PURE__ */ new Map();
21
+ // node -> keyed link
22
+ #links = /* @__PURE__ */ new Map();
23
+ #eventEmitter = new EventEmitter();
24
+ constructor(logger) {
25
+ this.#logger = logger;
26
+ }
27
+ add(key, handler) {
28
+ this.#handlersByKey.set(key, handler);
29
+ }
30
+ remove(key) {
31
+ this.#handlersByKey.delete(key);
32
+ this.#disconnect(key);
33
+ }
34
+ #disconnect(key, from) {
35
+ for (const [node, k] of this.#links) {
36
+ if (k.key === key && (from === void 0 || k.node === from)) {
37
+ const links = k.linksByNode;
38
+ if (this.#logger.enabledFor("info")) {
39
+ this.#logger.info(`${key} unregisters node ${node}, linked to ${Array.from(links.keys()).join(", ")}`);
40
+ }
41
+ this.#links.delete(node);
42
+ this.#eventEmitter.emit("disconnect", key, node, links);
43
+ }
44
+ }
45
+ }
46
+ #connect(key, node) {
47
+ if (this.#logger.enabledFor("info")) {
48
+ this.#logger.info(`${key} registers node ${node}`);
49
+ }
50
+ this.#links.set(node, { key, node, linksByNode: /* @__PURE__ */ new Map() });
51
+ this.#eventEmitter.emit("connect", key, node);
52
+ }
53
+ receive(key, msg) {
54
+ const { node, decoded, encoded } = this.link(key, msg);
55
+ if (node) {
56
+ this.#eventEmitter.emit("message", key, node, encoded, decoded);
57
+ }
58
+ }
59
+ link(key, msg) {
60
+ try {
61
+ const decoded = isEncoded(msg) ? codec.decode(msg) : msg;
62
+ const { type, from, to } = decoded;
63
+ if (to === "all") {
64
+ switch (type) {
65
+ case "hello": {
66
+ this.#connect(key, from);
67
+ break;
68
+ }
69
+ case "bye": {
70
+ this.#disconnect(key, from);
71
+ break;
72
+ }
73
+ }
74
+ return { decoded };
75
+ } else {
76
+ const node = decoded.to;
77
+ const link = decoded.from;
78
+ const type2 = decoded.type;
79
+ const senderLinkData = this.#links.get(link);
80
+ switch (type2) {
81
+ case "hello":
82
+ if (this.#logger.enabledFor("debug")) {
83
+ this.#logger.debug(`${key} connecting ${link} to ${node}`);
84
+ }
85
+ senderLinkData?.linksByNode.set(decoded.to, key);
86
+ break;
87
+ case "bye":
88
+ if (this.#logger.enabledFor("debug")) {
89
+ this.#logger.debug(`${key} disconnecting ${link} from ${node}`);
90
+ }
91
+ senderLinkData?.linksByNode.delete(decoded.to);
92
+ break;
93
+ }
94
+ }
95
+ const encoded = isEncoded(msg) ? msg : codec.encode(msg);
96
+ return { node: from, decoded, encoded };
97
+ } catch (e) {
98
+ if (!this.#eventEmitter.emit("error", key, e instanceof Error ? e : new Error(`link failed :${e}`))) {
99
+ this.#logger.warn(`${key} unable to process ${msg}`, e);
100
+ }
101
+ }
102
+ }
103
+ on(event, listener) {
104
+ this.#eventEmitter.on(event, listener);
105
+ return this;
106
+ }
107
+ send(key, node, msg, cb) {
108
+ if (this.#logger.enabledFor("trace")) {
109
+ this.#logger.debug(`${key} sending msg to ${node}`);
110
+ }
111
+ const encoded = isEncoded(msg) ? msg : codec.encode(msg);
112
+ const decoded = isEncoded(msg) ? codec.decode(msg) : msg;
113
+ {
114
+ node ??= decoded.to;
115
+ const link = decoded.from;
116
+ const type = decoded.type;
117
+ const senderLinkData = this.#links.get(link);
118
+ switch (type) {
119
+ case "hello":
120
+ if (this.#logger.enabledFor("debug")) {
121
+ this.#logger.debug(`${key} connecting ${link} to ${node}`);
122
+ }
123
+ senderLinkData?.linksByNode.set(node, key);
124
+ break;
125
+ case "bye":
126
+ if (this.#logger.enabledFor("debug")) {
127
+ this.#logger.debug(`${key} disconnecting ${link} from ${node}`);
128
+ }
129
+ senderLinkData?.linksByNode.delete(node);
130
+ break;
131
+ }
132
+ }
133
+ {
134
+ const receiverLinkData = this.#links.get(node);
135
+ if (receiverLinkData?.key) {
136
+ const handler = this.#handlersByKey.get(receiverLinkData?.key);
137
+ if (handler) {
138
+ handler(encoded, decoded, cb);
139
+ return;
140
+ }
141
+ }
142
+ }
143
+ if (decoded.type === "bye") {
144
+ return;
145
+ }
146
+ throw new Error(`${key} no active link for ${node}`);
147
+ }
148
+ };
149
+
1
150
  // src/utils/uuid.ts
2
151
  import { nanoid } from "nanoid";
3
152
  function newUUID() {
@@ -201,9 +350,9 @@ var DefaultDiscoveryConfig = class {
201
350
  };
202
351
 
203
352
  // src/logging.ts
204
- import { IOGateway } from "@interopio/gateway";
353
+ import { getLogger as getGatewayLogger } from "@interopio/gateway/logging/core";
205
354
  function getLogger(name) {
206
- return IOGateway.Logging.getLogger(`gateway.bridge.${name}`);
355
+ return getGatewayLogger(`gateway.bridge.${name}`);
207
356
  }
208
357
 
209
358
  // src/kubernetes/KubernetesDiscoveryStrategyFactory.ts
@@ -697,6 +846,9 @@ var ServerConfig = class {
697
846
  type: "none",
698
847
  basic: {
699
848
  realm: "io.Bridge"
849
+ },
850
+ oauth2: {
851
+ jwt: { issuerUri: "" }
700
852
  }
701
853
  };
702
854
  wsPingInterval = 3e4;
@@ -1209,7 +1361,7 @@ function parseVersion(version) {
1209
1361
  // package.json
1210
1362
  var package_default = {
1211
1363
  name: "@interopio/bridge",
1212
- version: "0.0.6-beta.0",
1364
+ version: "1.0.0",
1213
1365
  license: "see license in license.md",
1214
1366
  author: "interop.io",
1215
1367
  homepage: "https://docs.interop.io/bridge",
@@ -1220,6 +1372,11 @@ var package_default = {
1220
1372
  "glue42",
1221
1373
  "interop.io"
1222
1374
  ],
1375
+ repository: {
1376
+ type: "git",
1377
+ url: "git+https://github.com/InteropIO/bridge.git",
1378
+ directory: "packages/bridge"
1379
+ },
1223
1380
  type: "module",
1224
1381
  exports: {
1225
1382
  "./package.json": "./package.json",
@@ -1234,7 +1391,7 @@ var package_default = {
1234
1391
  }
1235
1392
  },
1236
1393
  bin: {
1237
- bridge: "./bin/bridge.js"
1394
+ bridge: "bin/bridge.js"
1238
1395
  },
1239
1396
  scripts: {
1240
1397
  test: "mocha test --recursive",
@@ -1244,12 +1401,13 @@ var package_default = {
1244
1401
  build: "npm run build:main && npm run build:index"
1245
1402
  },
1246
1403
  dependencies: {
1247
- "@interopio/gateway-server": "^0.10.0-beta.0",
1248
- dotenv: "^17.2.2",
1404
+ "@interopio/gateway-server": "^0.17.0",
1405
+ dotenv: "^17.2.3",
1249
1406
  jsrsasign: "^11.1.0",
1250
- nanoid: "^5.0.9"
1407
+ nanoid: "^5.1.6"
1251
1408
  },
1252
1409
  devDependencies: {
1410
+ "@interopio/gateway": "^0.20.0",
1253
1411
  "@types/jsrsasign": "^10.5.15",
1254
1412
  "@types/ws": "^8.18.1",
1255
1413
  "rand-seed": "^3.0.0"
@@ -1579,195 +1737,6 @@ var BridgeLicenseValidator = (logger) => new LicenseValidator({ validationKey, l
1579
1737
  // src/instance/BridgeNode.ts
1580
1738
  import { userInfo } from "node:os";
1581
1739
 
1582
- // ../bridge-mesh/src/mesh/connections.ts
1583
- import "@interopio/gateway";
1584
- var InMemoryNodeConnections = class {
1585
- #logger;
1586
- #nodes = /* @__PURE__ */ new Map();
1587
- #nodesByEndpoint = /* @__PURE__ */ new Map();
1588
- #memberIds = 0;
1589
- #timeout;
1590
- constructor(logger, timeout = 6e4) {
1591
- this.#logger = logger;
1592
- this.#timeout = timeout;
1593
- }
1594
- announce(nodes) {
1595
- for (const node of nodes) {
1596
- const { node: nodeId, users, endpoint } = node;
1597
- const foundId = this.#nodesByEndpoint.get(endpoint);
1598
- if (foundId) {
1599
- if (foundId !== nodeId) {
1600
- this.#logger.warn(`endpoint ${endpoint} clash. replacing node ${foundId} with ${nodeId}`);
1601
- this.#nodesByEndpoint.set(endpoint, nodeId);
1602
- this.#nodes.delete(foundId);
1603
- }
1604
- } else {
1605
- this.#logger.info(`endpoint ${endpoint} announced for ${nodeId}`);
1606
- this.#nodesByEndpoint.set(endpoint, nodeId);
1607
- }
1608
- this.#nodes.set(nodeId, this.updateNode(node, new Set(users ?? []), nodeId, this.#nodes.get(nodeId)));
1609
- }
1610
- this.cleanupOldNodes();
1611
- const sortedNodes = this.sortedNodeValues();
1612
- return nodes.map((e) => {
1613
- const { node } = e;
1614
- const connect = this.findConnections(sortedNodes, this.#nodes.get(node));
1615
- return { node, connect };
1616
- });
1617
- }
1618
- find(nodeId) {
1619
- const e = this.#nodes.get(nodeId);
1620
- if (e !== void 0) {
1621
- const sortedNodes = this.sortedNodeValues();
1622
- const { node } = e;
1623
- return this.findConnections(sortedNodes, this.#nodes.get(node));
1624
- }
1625
- return void 0;
1626
- }
1627
- remove(nodeId) {
1628
- const removed = this.#nodes.get(nodeId);
1629
- if (removed !== void 0) {
1630
- this.#nodes.delete(nodeId);
1631
- const endpoint = removed.endpoint;
1632
- this.#nodesByEndpoint.delete(endpoint);
1633
- this.#logger.info(`endpoint ${endpoint} removed for ${nodeId}`);
1634
- return true;
1635
- }
1636
- return false;
1637
- }
1638
- updateNode(newNode, users, _key, oldNode) {
1639
- const node = oldNode ?? { ...newNode, memberId: this.#memberIds++ };
1640
- return { ...node, users, lastAccess: Date.now() };
1641
- }
1642
- sortedNodeValues() {
1643
- return Array.from(this.#nodes.values()).sort((a, b) => a.memberId - b.memberId);
1644
- }
1645
- cleanupOldNodes() {
1646
- const threshold = Date.now() - this.#timeout;
1647
- for (const [nodeId, v] of this.#nodes) {
1648
- if (v.lastAccess < threshold) {
1649
- if (this.#logger.enabledFor("debug")) {
1650
- this.#logger.debug(`${nodeId} expired - no announcement since ${new Date(v.lastAccess).toISOString()}, timeout is ${this.#timeout} ms.`);
1651
- }
1652
- this.#nodes.delete(nodeId);
1653
- }
1654
- }
1655
- }
1656
- findConnections(sortedNodes, node) {
1657
- return sortedNodes.reduce((l, c) => {
1658
- if (node !== void 0 && c.memberId < node.memberId) {
1659
- const intersection = new Set(c.users);
1660
- node.users.forEach((user) => {
1661
- if (!c.users.has(user)) {
1662
- intersection.delete(user);
1663
- }
1664
- });
1665
- c.users.forEach((user) => {
1666
- if (!node.users.has(user)) {
1667
- intersection.delete(user);
1668
- }
1669
- });
1670
- if (intersection.size > 0) {
1671
- const e = { node: c.node, endpoint: c.endpoint };
1672
- return l.concat(e);
1673
- }
1674
- }
1675
- return l;
1676
- }, new Array());
1677
- }
1678
- };
1679
-
1680
- // ../bridge-mesh/src/mesh/relays.ts
1681
- import { IOGateway as IOGateway3 } from "@interopio/gateway";
1682
- var codec = IOGateway3.Encoding.transit({
1683
- keywordize: /* @__PURE__ */ new Map([
1684
- ["/type", "*"],
1685
- ["/message/body/type", "*"],
1686
- ["/message/origin", "*"],
1687
- ["/message/receiver/type", "*"],
1688
- ["/message/source/type", "*"],
1689
- ["/message/body/type", "*"]
1690
- ])
1691
- });
1692
- var InternalRelays = class {
1693
- #logger;
1694
- // key -> socket
1695
- #clients = /* @__PURE__ */ new Map();
1696
- // node -> key
1697
- #links = /* @__PURE__ */ new Map();
1698
- onMsg;
1699
- onErr;
1700
- constructor(logger) {
1701
- this.#logger = logger;
1702
- }
1703
- add(key, soc) {
1704
- this.#clients.set(key, soc);
1705
- }
1706
- remove(key) {
1707
- this.#clients.delete(key);
1708
- for (const [node, k] of this.#links) {
1709
- if (k === key) {
1710
- this.#links.delete(node);
1711
- }
1712
- }
1713
- }
1714
- receive(key, msg) {
1715
- const node = this.link(key, msg);
1716
- if (node && this.onMsg) {
1717
- this.onMsg(key, node, msg);
1718
- }
1719
- }
1720
- link(key, msg) {
1721
- try {
1722
- const decoded = codec.decode(msg);
1723
- const { type, from, to } = decoded;
1724
- if (to === "all") {
1725
- switch (type) {
1726
- case "hello": {
1727
- if (this.#logger.enabledFor("debug")) {
1728
- this.#logger.debug(`${key} registers node ${from}`);
1729
- }
1730
- this.#links.set(from, key);
1731
- break;
1732
- }
1733
- case "bye": {
1734
- if (this.#logger.enabledFor("debug")) {
1735
- this.#logger.debug(`${key} unregisters node ${from}`);
1736
- }
1737
- this.#links.delete(from);
1738
- break;
1739
- }
1740
- }
1741
- return;
1742
- }
1743
- return from;
1744
- } catch (e) {
1745
- if (this.onErr) {
1746
- this.onErr(key, e instanceof Error ? e : new Error(`link failed :${e}`));
1747
- } else {
1748
- this.#logger.warn(`${key} unable to process ${msg}`, e);
1749
- }
1750
- }
1751
- }
1752
- send(key, node, msg, cb) {
1753
- const decoded = codec.decode(msg);
1754
- if (this.#logger.enabledFor("debug")) {
1755
- this.#logger.debug(`${key} sending msg to ${node} ${JSON.stringify(decoded)}`);
1756
- }
1757
- const clientKey = this.#links.get(node);
1758
- if (clientKey) {
1759
- const client = this.#clients.get(clientKey);
1760
- if (client) {
1761
- client.send(msg, { binary: false }, (err) => {
1762
- cb(clientKey, err);
1763
- });
1764
- return;
1765
- }
1766
- }
1767
- throw new Error(`${key} no active link for ${decoded.to}`);
1768
- }
1769
- };
1770
-
1771
1740
  // ../bridge-mesh/src/mesh/rest-directory/routes.ts
1772
1741
  function buildCanonicalBaseURL(request) {
1773
1742
  const requestURL = request.URL;
@@ -1817,9 +1786,13 @@ function routes(config, { handle }) {
1817
1786
  );
1818
1787
  await response.end();
1819
1788
  } else {
1820
- const nodes = json.map((node) => fromRequestNode(node, request));
1789
+ const nodes = json.map((node) => {
1790
+ return fromRequestNode(node, request);
1791
+ });
1821
1792
  const result = connections.announce(nodes).map((connection) => {
1822
- const connect = connection.connect?.map((node) => toRequestNode(node, request));
1793
+ const connect = connection.connect?.map((node) => {
1794
+ return toRequestNode(node, request);
1795
+ });
1823
1796
  return { ...connection, connect };
1824
1797
  });
1825
1798
  const buffer = Buffer.from(JSON.stringify(result), "utf8");
@@ -1885,10 +1858,15 @@ async function create(log, internal, env) {
1885
1858
  log.info(`relays-${id} server is listening on ${env.endpoint}`);
1886
1859
  let keyId = 0;
1887
1860
  return async ({ socket, handshake }) => {
1888
- const logPrefix = handshake.logPrefix;
1861
+ const logPrefix = handshake.logPrefix ?? "";
1862
+ const query = handshake.url.searchParams;
1889
1863
  const key = `r.${id}.${++keyId}`;
1890
- log.info(`${logPrefix}connected on /relays with assigned key ${key}`);
1891
- internal.add(key, socket);
1864
+ log.info(`${logPrefix}connected on /relays with ${query} and assigned key ${key}`);
1865
+ internal.add(key, (msg, c, cb) => {
1866
+ socket.send(msg, { binary: false }, (err) => {
1867
+ cb(key, err);
1868
+ });
1869
+ });
1892
1870
  socket.on("error", (err) => {
1893
1871
  log.error(`${logPrefix}websocket error: ${err.message}`, err);
1894
1872
  });
@@ -1908,9 +1886,9 @@ async function create(log, internal, env) {
1908
1886
  });
1909
1887
  };
1910
1888
  }
1911
- var meshRelays = ({ logger, internal }) => {
1889
+ var meshRelays = ({ logger, relays }) => {
1912
1890
  return async (env) => {
1913
- return await create(logger, internal, env);
1891
+ return await create(logger, relays, env);
1914
1892
  };
1915
1893
  };
1916
1894
 
@@ -1923,7 +1901,7 @@ function onMessage(relays, log, key, node, socketsByNodeId, msg) {
1923
1901
  log.warn(`${k} error writing msg ${msg}: ${err}`);
1924
1902
  return;
1925
1903
  }
1926
- if (log.enabledFor("debug")) {
1904
+ if (log.enabledFor("trace")) {
1927
1905
  log.debug(`${k} sent msg ${msg}`);
1928
1906
  }
1929
1907
  });
@@ -1938,17 +1916,20 @@ function onMessage(relays, log, key, node, socketsByNodeId, msg) {
1938
1916
  var handlerId2 = 0;
1939
1917
  async function create2(log, relays, env) {
1940
1918
  const socketsByNodeId = /* @__PURE__ */ new Map();
1941
- relays.onMsg = (k, nodeId, msg) => {
1919
+ relays.on("message", (k, nodeId, msg) => {
1942
1920
  try {
1943
1921
  const sockets = socketsByNodeId.get(nodeId);
1944
1922
  if (sockets && sockets.size > 0) {
1923
+ if (log.enabledFor("trace")) {
1924
+ log.debug(`${k} sending message to ${[...sockets.keys()]}`);
1925
+ }
1945
1926
  for (const [key, socket] of sockets) {
1946
1927
  socket.send(msg, { binary: false }, (err) => {
1947
1928
  if (err) {
1948
1929
  log.warn(`${key} error writing from ${k} msg ${msg}: ${err}`);
1949
1930
  return;
1950
1931
  }
1951
- if (log.enabledFor("debug")) {
1932
+ if (log.enabledFor("trace")) {
1952
1933
  log.debug(`${key} sent from ${k} msg ${msg}`);
1953
1934
  }
1954
1935
  });
@@ -1959,14 +1940,23 @@ async function create2(log, relays, env) {
1959
1940
  } catch (ex) {
1960
1941
  log.error(`${k} unable to process message`, ex);
1961
1942
  }
1962
- };
1943
+ });
1944
+ relays.on("disconnect", (k, nodeId) => {
1945
+ const sockets = socketsByNodeId.get(nodeId);
1946
+ if (sockets) {
1947
+ for (const [key, socket] of sockets) {
1948
+ socket.terminate();
1949
+ log.info(`${key} terminated because ${k} disconnected ${nodeId}`);
1950
+ }
1951
+ }
1952
+ });
1963
1953
  const id = ++handlerId2;
1964
1954
  let keyId = 0;
1965
1955
  return async ({ socket, handshake }) => {
1966
1956
  const logPrefix = handshake.logPrefix ?? "";
1967
1957
  const query = handshake.url.searchParams;
1968
1958
  const key = `c.${id}.${++keyId}`;
1969
- log.info(`${logPrefix}connected on /cluster with ${query} with assigned key ${key}`);
1959
+ log.info(`${logPrefix}connected on /cluster with ${query} and assigned key ${key}`);
1970
1960
  const node = query.get("node");
1971
1961
  if (node) {
1972
1962
  let sockets = socketsByNodeId.get(node);
@@ -2008,19 +1998,231 @@ var meshCluster = ({ logger, relays }) => {
2008
1998
 
2009
1999
  // ../bridge-mesh/src/index.ts
2010
2000
  import "@interopio/gateway-server";
2011
- import "@interopio/gateway";
2001
+
2002
+ // ../bridge-mesh/src/mesh/gateway/mesh.ts
2003
+ import { nanoid as nanoid2 } from "nanoid";
2004
+ import gateway from "@interopio/gateway/package.json" with { type: "json" };
2005
+ var instanceId = 0;
2006
+ var BridgeMeshChannel = class {
2007
+ #logger;
2008
+ #relays;
2009
+ #connections;
2010
+ #state;
2011
+ #keyPrefix;
2012
+ constructor(relays, nodes, logger) {
2013
+ this.#relays = relays;
2014
+ this.#connections = nodes;
2015
+ this.#logger = logger;
2016
+ this.#state = /* @__PURE__ */ new Map();
2017
+ this.#keyPrefix = `g.${++instanceId}`;
2018
+ }
2019
+ get relays() {
2020
+ return this.#relays;
2021
+ }
2022
+ get connections() {
2023
+ return this.#connections;
2024
+ }
2025
+ #intervalId;
2026
+ subscribe(node, subscriber) {
2027
+ node ??= nanoid2();
2028
+ const key = `${this.#keyPrefix}-${node}`;
2029
+ if (this.#state.has(key)) {
2030
+ throw new Error(`already subscribed to node ${node}`);
2031
+ }
2032
+ this.#state.set(node, { subscriber, users: /* @__PURE__ */ new Set(), members: /* @__PURE__ */ new Set() });
2033
+ this.#relays.receive(key, { type: "hello", from: node, to: "all" });
2034
+ this.#relays.add(key, this.createRelayClient(key, node));
2035
+ this.#intervalId ??= setInterval(() => this.#announce(), 3e4);
2036
+ return node;
2037
+ }
2038
+ createRelayClient(key, node) {
2039
+ return (_msg, command, cb) => {
2040
+ switch (command.type) {
2041
+ case "hello":
2042
+ case "bye":
2043
+ break;
2044
+ case "data": {
2045
+ try {
2046
+ const event = {
2047
+ type: "message-received",
2048
+ message: command.data
2049
+ };
2050
+ this.#state.get(node)?.subscriber(event, node, this);
2051
+ } catch (err) {
2052
+ cb(key, err);
2053
+ }
2054
+ break;
2055
+ }
2056
+ }
2057
+ };
2058
+ }
2059
+ unsubscribe(node) {
2060
+ this.#delete(node);
2061
+ this.#relays.remove(`${this.#keyPrefix}-${node}`);
2062
+ }
2063
+ execute(node, action) {
2064
+ switch (action.type) {
2065
+ case "publish-message": {
2066
+ this.#onMessage(node, action.message);
2067
+ break;
2068
+ }
2069
+ case "add-users": {
2070
+ this.#onAddUsers(node, action.added);
2071
+ break;
2072
+ }
2073
+ case "remove-users": {
2074
+ this.#onRemoveUsers(node, action.removed);
2075
+ break;
2076
+ }
2077
+ }
2078
+ }
2079
+ #onMessage(node, data) {
2080
+ const nodes = this.#connections.find(node);
2081
+ if (nodes !== void 0) {
2082
+ const key = `${this.#keyPrefix}-${node}`;
2083
+ const command = { type: "data", from: node, data };
2084
+ nodes.forEach((connection) => {
2085
+ const to = connection.node;
2086
+ if (to === node) {
2087
+ return;
2088
+ }
2089
+ try {
2090
+ this.#relays.send(key, to, { ...command, to }, (k, err) => {
2091
+ if (err) {
2092
+ this.#logger.warn(`failed to send message from ${node} to ${to} via ${k}: ${err.message}`);
2093
+ }
2094
+ });
2095
+ } catch (err) {
2096
+ this.#logger.warn(`failed to send message from ${node} to ${to} via ${key}: ${err.message}`);
2097
+ }
2098
+ });
2099
+ }
2100
+ }
2101
+ #onAddUsers(node, usersToAdd) {
2102
+ let shouldAnnounce = false;
2103
+ const nodeState = this.#state.get(node);
2104
+ const nodeUsers = nodeState?.users;
2105
+ if (nodeUsers === void 0) {
2106
+ nodeState.users = new Set(usersToAdd);
2107
+ shouldAnnounce = true;
2108
+ } else {
2109
+ for (const u of usersToAdd) {
2110
+ if (nodeUsers.has(u)) {
2111
+ continue;
2112
+ }
2113
+ nodeUsers.add(u);
2114
+ shouldAnnounce = true;
2115
+ }
2116
+ }
2117
+ if (shouldAnnounce) {
2118
+ this.#announce(node);
2119
+ }
2120
+ }
2121
+ #onRemoveUsers(node, usersToRemove) {
2122
+ const nodeState = this.#state.get(node);
2123
+ const nodeUsers = nodeState?.users;
2124
+ if (nodeUsers === void 0) {
2125
+ return;
2126
+ }
2127
+ let shouldAnnounce = false;
2128
+ for (const u of usersToRemove) {
2129
+ if (!nodeUsers.has(u)) {
2130
+ continue;
2131
+ }
2132
+ nodeUsers.delete(u);
2133
+ shouldAnnounce = true;
2134
+ }
2135
+ if (nodeUsers.size === 0) {
2136
+ this.#delete(node);
2137
+ } else if (shouldAnnounce) {
2138
+ this.#announce(node);
2139
+ }
2140
+ }
2141
+ #announce(node) {
2142
+ const entries = node === void 0 ? this.#state.entries() : [[node, this.#state.get(node)]];
2143
+ const nodes = Array.from(entries, entryToNode);
2144
+ const nodeConnections = this.#connections.announce(nodes);
2145
+ for (const { node: n, connect } of nodeConnections) {
2146
+ const state = this.#state.get(n);
2147
+ if (state === void 0) {
2148
+ continue;
2149
+ }
2150
+ const toRemove = new Set(state.members);
2151
+ for (const c of connect) {
2152
+ if (c.node === n) {
2153
+ continue;
2154
+ }
2155
+ toRemove.delete(c.node);
2156
+ if (state.members.has(c.node)) {
2157
+ continue;
2158
+ }
2159
+ state.members.add(c.node);
2160
+ state.subscriber({ type: "member-added", node: c.node }, n, this);
2161
+ }
2162
+ for (const r of toRemove) {
2163
+ state.members.delete(r);
2164
+ state.subscriber({ type: "member-removed", node: r }, n, this);
2165
+ }
2166
+ }
2167
+ }
2168
+ #delete(node) {
2169
+ this.#state.delete(node);
2170
+ this.#connections.remove(node);
2171
+ }
2172
+ async init(gossipTimestamp = 0) {
2173
+ await this.#connections.init(gossipTimestamp);
2174
+ }
2175
+ async close() {
2176
+ for (const node of this.#state.keys()) {
2177
+ this.#delete(node);
2178
+ this.#relays.remove(`${this.#keyPrefix}-${node}`);
2179
+ }
2180
+ clearInterval(this.#intervalId);
2181
+ await this.#connections.close();
2182
+ }
2183
+ };
2184
+ var entryToNode = ([node, state]) => {
2185
+ const users = Array.from(state?.users);
2186
+ return { node, users, metadata: { version: gateway.version, type: "bridge" } };
2187
+ };
2188
+
2189
+ // ../bridge-mesh/src/index.ts
2190
+ function connectNodeRelays(logger, relays, connections) {
2191
+ relays.on("disconnect", (key, node, links) => {
2192
+ try {
2193
+ connections.remove(node);
2194
+ } catch (e) {
2195
+ logger.warn(`${key} error removing node ${node} from connections: ${e}`);
2196
+ }
2197
+ for (const [linkNode, linkKey] of links) {
2198
+ try {
2199
+ relays.send(linkKey, linkNode, { type: "bye", from: node, to: linkNode }, (k, err) => {
2200
+ if (err) {
2201
+ logger.warn(`${k} error writing 'bye' msg to ${linkNode}: ${err}`);
2202
+ return;
2203
+ }
2204
+ if (logger.enabledFor("debug")) {
2205
+ logger.debug(`${k} sent 'bye' msg to ${linkNode} from ${node}`);
2206
+ }
2207
+ });
2208
+ } catch (err) {
2209
+ logger.warn(`${linkKey} exception writing 'bye' msg to ${linkNode} from ${node}: ${err}`);
2210
+ }
2211
+ }
2212
+ });
2213
+ }
2012
2214
  var mesh = async (options, configurer, config) => {
2013
- const { enabled, logger } = options;
2215
+ const { enabled, logger, relays, connections } = options;
2014
2216
  if (enabled !== true) {
2015
- logger.debug(`no mesh`);
2217
+ if (logger.enabledFor("debug")) {
2218
+ logger.debug(`no mesh`);
2219
+ }
2016
2220
  return;
2017
2221
  }
2018
- let { socket, timeout } = options;
2222
+ let { socket } = options;
2019
2223
  const authorize = socket.authorize ?? { access: config.auth.type === "none" ? "permitted" : "authenticated" };
2020
2224
  socket = { ping: 3e4, authorize, ...socket };
2021
- timeout ??= 6e4;
2022
- const connections = new InMemoryNodeConnections(logger, timeout);
2023
- const relays = new InternalRelays(logger);
2225
+ connectNodeRelays(logger, relays, connections);
2024
2226
  routes_default({ connections, authorize }, configurer);
2025
2227
  configurer.socket(
2026
2228
  {
@@ -2031,11 +2233,321 @@ var mesh = async (options, configurer, config) => {
2031
2233
  {
2032
2234
  path: "/relays",
2033
2235
  options: socket,
2034
- factory: meshRelays({ logger, internal: relays })
2236
+ factory: meshRelays({ logger, relays })
2035
2237
  }
2036
2238
  );
2037
2239
  };
2038
2240
 
2241
+ // ../bridge-mesh/src/mesh/connections.ts
2242
+ import { hrwHash } from "hrw-hash";
2243
+
2244
+ // ../bridge-mesh/src/mesh/lamport.ts
2245
+ import { appendFile, readFile, rename, writeFile } from "node:fs/promises";
2246
+ var LamportClock = class _LamportClock {
2247
+ static #FLUSH_INTERVAL = 5e3;
2248
+ // 5 seconds
2249
+ static #CLOCK_FILE = "./lamport.clock";
2250
+ static #WAL_FILE = "./lamport.wal";
2251
+ #timestamp;
2252
+ #instanceId;
2253
+ #flushIntervalId;
2254
+ #pendingWrites = 0;
2255
+ constructor(instanceId2) {
2256
+ this.#instanceId = instanceId2;
2257
+ this.#timestamp = 0;
2258
+ this.#flushIntervalId = setInterval(() => {
2259
+ this.#flush().catch((err) => {
2260
+ });
2261
+ }, _LamportClock.#FLUSH_INTERVAL);
2262
+ }
2263
+ async init(gossipTimestamp = 0) {
2264
+ const baseTimestamp = await this.#loadSnapshot();
2265
+ const journaledIncrements = await this.#replayWal();
2266
+ this.#timestamp = Math.max(baseTimestamp + journaledIncrements, gossipTimestamp);
2267
+ }
2268
+ tick() {
2269
+ this.#timestamp += 1;
2270
+ this.#pendingWrites += 1;
2271
+ this.#appendToWal().catch((_err) => {
2272
+ });
2273
+ return { timestamp: this.#timestamp, instanceId: this.#instanceId };
2274
+ }
2275
+ observe(gossipTimestamp) {
2276
+ this.#timestamp = Math.max(this.#timestamp, gossipTimestamp) + 1;
2277
+ this.#pendingWrites += 1;
2278
+ this.#appendToWal().catch((_err) => {
2279
+ });
2280
+ return { timestamp: this.#timestamp, instanceId: this.#instanceId };
2281
+ }
2282
+ timestamp() {
2283
+ return { timestamp: this.#timestamp, instanceId: this.#instanceId };
2284
+ }
2285
+ async shutdown() {
2286
+ clearInterval(this.#flushIntervalId);
2287
+ await this.#flush();
2288
+ }
2289
+ async #appendToWal() {
2290
+ const data = `${this.#timestamp}
2291
+ `;
2292
+ await appendFile(_LamportClock.#WAL_FILE, data, "utf-8");
2293
+ }
2294
+ async #replayWal() {
2295
+ try {
2296
+ const data = await readFile(_LamportClock.#WAL_FILE, "utf-8");
2297
+ return data.trim().split("\n").filter(Boolean).length;
2298
+ } catch {
2299
+ }
2300
+ return 0;
2301
+ }
2302
+ async #loadSnapshot() {
2303
+ try {
2304
+ const data = await readFile(_LamportClock.#CLOCK_FILE, "utf-8");
2305
+ return parseInt(data, 10) || 0;
2306
+ } catch {
2307
+ }
2308
+ return 0;
2309
+ }
2310
+ async #flush() {
2311
+ if (this.#pendingWrites === 0) {
2312
+ return;
2313
+ }
2314
+ const tmp = `${_LamportClock.#CLOCK_FILE}.tmp`;
2315
+ const data = `${this.#timestamp}
2316
+ `;
2317
+ await writeFile(tmp, data, { flag: "w" });
2318
+ await rename(tmp, _LamportClock.#CLOCK_FILE);
2319
+ await writeFile(_LamportClock.#WAL_FILE, "", { flag: "w" });
2320
+ this.#pendingWrites = 0;
2321
+ }
2322
+ };
2323
+
2324
+ // ../bridge-mesh/src/mesh/connections.ts
2325
+ import { EventEmitter as EventEmitter2 } from "node:events";
2326
+ var InMemoryNodeConnections = class {
2327
+ #logger;
2328
+ #eventEmitter = new EventEmitter2();
2329
+ #nodes = /* @__PURE__ */ new Map();
2330
+ #clusterNodes;
2331
+ #lamport;
2332
+ #timeout;
2333
+ constructor(logger, instanceId2, timeout = 6e4) {
2334
+ this.#logger = logger;
2335
+ this.#clusterNodes = [instanceId2];
2336
+ this.#lamport = new LamportClock(instanceId2);
2337
+ this.#timeout = timeout;
2338
+ }
2339
+ async init(gossipTimestamp = 0) {
2340
+ await this.#lamport.init(gossipTimestamp);
2341
+ }
2342
+ async close() {
2343
+ await this.#lamport.shutdown();
2344
+ }
2345
+ announce(announcements) {
2346
+ const now = Date.now();
2347
+ for (const announcement of announcements) {
2348
+ const { node: nodeId, users, endpoint: announcedEndpoint, metadata } = announcement;
2349
+ const replicas = hrwHash(nodeId, this.#clusterNodes);
2350
+ const owner = replicas[0];
2351
+ const externalEndpoint = announcedEndpoint !== void 0 && announcedEndpoint !== `/cluster?node=${nodeId}`;
2352
+ const endpoint = externalEndpoint ? announcedEndpoint : `/cluster?node=${nodeId}&owner=${owner}`;
2353
+ const lamport = this.#lamport.tick();
2354
+ const userSet = new Set(users ?? []);
2355
+ let node = this.#nodes.get(nodeId);
2356
+ if (!node) {
2357
+ node = { node: nodeId, users: userSet, firstSeen: lamport, lastSeen: now, owner, replicas, endpoint, metadata };
2358
+ this.#nodes.set(nodeId, node);
2359
+ this.#logger.info(`${nodeId} announced at endpoint ${endpoint} with meta: ${JSON.stringify(metadata)}`);
2360
+ }
2361
+ node.owner = owner;
2362
+ if (!externalEndpoint) {
2363
+ node.endpoint = endpoint;
2364
+ }
2365
+ node.replicas = replicas;
2366
+ node.lastSeen = now;
2367
+ node.users = userSet;
2368
+ this.#eventEmitter.emit("node-announced", nodeId, endpoint, userSet);
2369
+ }
2370
+ this.cleanupOldNodes();
2371
+ const sortedNodes = this.#sortedNodeValues();
2372
+ return announcements.map((e) => {
2373
+ const node = this.#nodes.get(e.node);
2374
+ const connect = this.#findConnections(sortedNodes, node);
2375
+ return { node: node.node, owner: node.owner, connect };
2376
+ });
2377
+ }
2378
+ find(nodeId) {
2379
+ const e = this.#nodes.get(nodeId);
2380
+ if (e !== void 0) {
2381
+ const sortedNodes = this.#sortedNodeValues();
2382
+ return this.#findConnections(sortedNodes, e);
2383
+ }
2384
+ return void 0;
2385
+ }
2386
+ remove(nodeId) {
2387
+ const removed = this.#nodes.get(nodeId);
2388
+ if (removed !== void 0) {
2389
+ this.#nodes.delete(nodeId);
2390
+ const endpoint = removed.endpoint;
2391
+ this.#logger.info(`endpoint ${endpoint} removed for ${nodeId}`);
2392
+ this.#eventEmitter.emit("node-deleted", nodeId, endpoint, "removed");
2393
+ return true;
2394
+ }
2395
+ return false;
2396
+ }
2397
+ #sortedNodeValues() {
2398
+ return Array.from(this.#nodes.values()).sort((a, b) => {
2399
+ const diff = a.firstSeen.timestamp - b.firstSeen.timestamp;
2400
+ if (diff === 0) {
2401
+ return a.node.localeCompare(b.node);
2402
+ }
2403
+ return diff;
2404
+ });
2405
+ }
2406
+ cleanupOldNodes() {
2407
+ const threshold = Date.now() - this.#timeout;
2408
+ for (const [nodeId, v] of this.#nodes) {
2409
+ if (v.lastSeen < threshold) {
2410
+ if (this.#logger.enabledFor("debug")) {
2411
+ this.#logger.debug(`${nodeId} expired - no announcement since ${new Date(v.lastSeen).toISOString()}, timeout is ${this.#timeout} ms.`);
2412
+ }
2413
+ this.#nodes.delete(nodeId);
2414
+ const endpoint = v.endpoint;
2415
+ this.#eventEmitter.emit("node-deleted", nodeId, endpoint, "expired");
2416
+ }
2417
+ }
2418
+ }
2419
+ on(event, listener) {
2420
+ this.#eventEmitter.on(event, listener);
2421
+ return this;
2422
+ }
2423
+ off(event, listener) {
2424
+ this.#eventEmitter.off(event, listener);
2425
+ return this;
2426
+ }
2427
+ #findConnections(sortedNodes, node) {
2428
+ const connections = sortedNodes.reduce((l, c) => {
2429
+ if (node !== void 0 && c.firstSeen.timestamp < node.firstSeen.timestamp) {
2430
+ const intersection = new Set(c.users);
2431
+ node.users.forEach((user) => {
2432
+ if (!c.users.has(user)) {
2433
+ intersection.delete(user);
2434
+ }
2435
+ });
2436
+ c.users.forEach((user) => {
2437
+ if (!node.users.has(user)) {
2438
+ intersection.delete(user);
2439
+ }
2440
+ });
2441
+ if (intersection.size > 0) {
2442
+ const e = { node: c.node, endpoint: c.endpoint, owner: c.owner };
2443
+ return l.concat(e);
2444
+ }
2445
+ }
2446
+ return l;
2447
+ }, new Array());
2448
+ if (this.#logger.enabledFor("debug")) {
2449
+ this.#logger.debug(`found ${connections.length} connection(s) for node ${node?.node}: [${connections.map((e) => `${e.node}@${e.endpoint}`).join(", ")}]`);
2450
+ }
2451
+ return connections;
2452
+ }
2453
+ };
2454
+
2455
+ // ../bridge-gateway/src/desktop.ts
2456
+ function isRunningInConnectDesktop(env = process.env) {
2457
+ return env._GD_STARTING_CONTEXT_ !== void 0;
2458
+ }
2459
+ function parseStartingContext(env = process.env) {
2460
+ if (!isRunningInConnectDesktop(env)) {
2461
+ throw new Error("Not running in io.Connect Desktop");
2462
+ }
2463
+ return JSON.parse(env._GD_STARTING_CONTEXT_);
2464
+ }
2465
+
2466
+ // ../bridge-gateway/src/index.ts
2467
+ import { tmpdir } from "node:os";
2468
+ import { createServer as createServer2 } from "node:net";
2469
+ import { join } from "node:path";
2470
+ import "@interopio/gateway";
2471
+ import "@interopio/gateway-server";
2472
+ function onGatewayStarted(log) {
2473
+ return (gateway2) => {
2474
+ const info = JSON.stringify({ ...gateway2.info(), pid: process.pid });
2475
+ if (isRunningInConnectDesktop()) {
2476
+ const env = process.env["GLUE-ENV"] || "DEMO";
2477
+ const region = process.env["GLUE-REGION"] || "INTEROP.IO";
2478
+ const user = process.env.USERNAME ?? process.env.USER;
2479
+ const pipe = `glue42-${env}-${region}-${user}`;
2480
+ const pipeName = process.platform === "win32" ? `\\\\.\\pipe\\${pipe}` : `${join(tmpdir(), pipe + ".sock")}`;
2481
+ log.info(`gateway started: ${info}, opening ${pipeName}`);
2482
+ const server = createServer2((stream) => {
2483
+ log.info(`stream connected, sending info...`);
2484
+ stream.write(info);
2485
+ stream.end(() => {
2486
+ server.close();
2487
+ });
2488
+ });
2489
+ server.listen(pipeName);
2490
+ } else {
2491
+ log.info(`gateway started: ${info}`);
2492
+ }
2493
+ };
2494
+ }
2495
+ async function serverGatewayConfig(gateway2, bridge, env = process.env) {
2496
+ let enabled = gateway2.enabled;
2497
+ if (enabled === void 0) {
2498
+ if (isRunningInConnectDesktop(env)) {
2499
+ const applicationConfig = parseStartingContext(env)?.applicationConfig;
2500
+ enabled = applicationConfig?.customProperties?.gatewayApp === true || applicationConfig?.name === "io-connect-gateway";
2501
+ }
2502
+ }
2503
+ let contextsLifetime = gateway2.contexts.lifetime;
2504
+ if (contextsLifetime === void 0) {
2505
+ if (isRunningInConnectDesktop(env)) {
2506
+ contextsLifetime = "retained";
2507
+ }
2508
+ }
2509
+ if (enabled) {
2510
+ return {
2511
+ // globals: { websocket },
2512
+ clients: {
2513
+ inactive_seconds: 0
2514
+ },
2515
+ ping: bridge.wsPingInterval ?? void 0,
2516
+ mesh: {
2517
+ auth: { user: null },
2518
+ node: "bridge-gateway",
2519
+ channel: bridge.meshChannel
2520
+ },
2521
+ contexts: {
2522
+ lifetime: contextsLifetime,
2523
+ visibility: [
2524
+ { context: /___channel___.+/, restrictions: "cluster" },
2525
+ { context: /T42\..*/, restrictions: "local" },
2526
+ { context: "___platform_prefs___", restrictions: "local" },
2527
+ { context: /___workspace___.+/, restrictions: "local" },
2528
+ { context: /___window-hibernation___.+/, restrictions: "local" },
2529
+ { context: /___instance___.+/, restrictions: "local" },
2530
+ { context: /___window___.+/, restrictions: "local" },
2531
+ { restrictions: "cluster" }
2532
+ ]
2533
+ },
2534
+ methods: {
2535
+ visibility: [
2536
+ { method: /T42\..*/, restrictions: "local" },
2537
+ { restrictions: "cluster" }
2538
+ ]
2539
+ },
2540
+ peers: {
2541
+ visibility: [
2542
+ { domain: "context", restrictions: "cluster" },
2543
+ { domain: "interop", restrictions: "cluster" },
2544
+ { domain: "bus", restrictions: "local" }
2545
+ ]
2546
+ }
2547
+ };
2548
+ }
2549
+ }
2550
+
2039
2551
  // src/instance/BridgeNode.ts
2040
2552
  function logStartingInfo(logger) {
2041
2553
  logger.info(`Starting io.Bridge v${package_default.version} using Node.js ${process.version} with PID ${process.pid} (started by ${userInfo().username} in ${process.cwd()})`);
@@ -2061,12 +2573,13 @@ var BridgeNode = class {
2061
2573
  config;
2062
2574
  uuid;
2063
2575
  discoveryService;
2576
+ meshChannel;
2064
2577
  version;
2065
2578
  server;
2066
2579
  licenseValidator;
2067
2580
  constructor(config) {
2068
2581
  this.config = config;
2069
- this.licenseValidator = BridgeLicenseValidator(this.getLogger("license-validator"));
2582
+ this.licenseValidator = BridgeLicenseValidator(this.getLogger("license"));
2070
2583
  this.licenseValidator.validate(config.license);
2071
2584
  this.uuid = newUUID();
2072
2585
  this.version = parseVersion(package_default.version);
@@ -2082,7 +2595,10 @@ var BridgeNode = class {
2082
2595
  const joinConfig = config.network.join;
2083
2596
  const isAutoDetectionEnabled = joinConfig.autoDetectionEnabled;
2084
2597
  const discoveryConfig = joinConfig.discovery;
2085
- this.discoveryService = createDiscoveryService(getLogger("discovery-service"), discoveryConfig, isAutoDetectionEnabled, localMemberPromise);
2598
+ this.discoveryService = createDiscoveryService(getLogger("discovery"), discoveryConfig, isAutoDetectionEnabled, localMemberPromise);
2599
+ const relays = new InternalRelays(this.getLogger("relays"));
2600
+ const connections = new InMemoryNodeConnections(this.getLogger("nodes"), this.uuid, this.config.mesh.timeout ?? 6e4);
2601
+ this.meshChannel = new BridgeMeshChannel(relays, connections, this.getLogger("channel"));
2086
2602
  }
2087
2603
  getLogger(name) {
2088
2604
  return getLogger(name);
@@ -2101,6 +2617,7 @@ var BridgeNode = class {
2101
2617
  return setInterval(task, licenseCheckInterval);
2102
2618
  }
2103
2619
  async start() {
2620
+ await this.meshChannel.init();
2104
2621
  const config = {
2105
2622
  port: this.config.server.port,
2106
2623
  host: this.config.server.host,
@@ -2108,8 +2625,8 @@ var BridgeNode = class {
2108
2625
  await mesh({
2109
2626
  logger: this.getLogger("mesh"),
2110
2627
  enabled: true,
2111
- timeout: this.config.mesh.timeout ?? 6e4,
2112
- // 60 seconds
2628
+ relays: this.meshChannel.relays,
2629
+ connections: this.meshChannel.connections,
2113
2630
  socket: {
2114
2631
  ping: this.config.server.wsPingInterval ?? 3e4
2115
2632
  // 30 seconds
@@ -2119,50 +2636,15 @@ var BridgeNode = class {
2119
2636
  auth: { type: "none", ...this.config.server.auth },
2120
2637
  cors: this.config.server.cors.disabled ? false : this.config.server.cors
2121
2638
  };
2122
- if (this.config.gateway.enabled) {
2123
- const { WebSocket: websocket } = await import("ws");
2124
- config.gateway = {
2125
- globals: { websocket },
2126
- clients: {
2127
- inactive_seconds: 0
2128
- },
2129
- ping: this.config.server.wsPingInterval ?? void 0,
2130
- mesh: {
2131
- cluster: {
2132
- endpoint: `http://localhost:${this.config.server.port}`,
2133
- directory: { interval: 1e3 * 30 }
2134
- // 30 seconds
2135
- }
2136
- },
2137
- contexts: {
2138
- lifetime: this.config.gateway.contexts.lifetime,
2139
- visibility: [
2140
- { context: /___channel___.+/, restrictions: "cluster" },
2141
- { context: /T42\..*/, restrictions: "local" },
2142
- { context: "___platform_prefs___", restrictions: "local" },
2143
- { restrictions: "cluster" }
2144
- ]
2145
- },
2146
- methods: {
2147
- visibility: [
2148
- { method: /T42\..*/, restrictions: "local" },
2149
- { restrictions: "cluster" }
2150
- ]
2151
- },
2152
- peers: {
2153
- visibility: [
2154
- { domain: "context", restrictions: "cluster" },
2155
- { domain: "interop", restrictions: "cluster" },
2156
- { domain: "bus", restrictions: "local" }
2157
- ]
2158
- }
2159
- };
2160
- }
2639
+ config.gateway = await serverGatewayConfig(this.config.gateway, { meshChannel: this.meshChannel, wsPingInterval: this.config.server.wsPingInterval });
2161
2640
  logStartingInfo(this.getLogger("node"));
2162
2641
  this.server = await gatewayServer(config);
2163
2642
  if (false) {
2164
2643
  await this.discoveryService.start();
2165
2644
  }
2645
+ if (config.gateway !== void 0) {
2646
+ onGatewayStarted(this.getLogger("gw"))(this.server.gateway);
2647
+ }
2166
2648
  await this.scheduleLicenseCheck();
2167
2649
  }
2168
2650
  async stop() {
@@ -2173,6 +2655,7 @@ var BridgeNode = class {
2173
2655
  await this.discoveryService.close();
2174
2656
  } catch (e) {
2175
2657
  }
2658
+ await this.meshChannel.close();
2176
2659
  }
2177
2660
  };
2178
2661
 
@@ -2234,12 +2717,15 @@ try {
2234
2717
  await import("dotenv/config");
2235
2718
  const config = new Config();
2236
2719
  config.license ??= loadLicense();
2237
- config.server.port ??= loadConfig("server.port", NUMBER) ?? 8383;
2720
+ config.server.port ??= loadConfig("server.port", NUMBER) ?? 8084;
2238
2721
  config.server.host ??= loadConfig("server.host", STRING);
2239
2722
  config.server.wsPingInterval ??= loadConfig("server.ws-ping-interval", NUMBER);
2240
2723
  config.gateway.enabled ??= loadConfig("gateway.enabled", BOOLEAN);
2241
2724
  config.gateway.contexts.lifetime ??= loadConfig("gateway.contexts.lifetime", STRING);
2242
2725
  config.server.auth.type = loadConfig("server.auth.type", STRING) ?? "none";
2726
+ config.server.auth.oauth2.jwt.issuerUri = loadConfig("server.auth.oauth2.jwt.issuer-uri", STRING) ?? void 0;
2727
+ config.server.auth.oauth2.jwt.issuer = loadConfig("server.auth.oauth2.jwt.issuer", STRING) ?? void 0;
2728
+ config.server.auth.oauth2.jwt.audience = loadConfig("server.auth.oauth2.jwt.audience", STRING) ?? void 0;
2243
2729
  config.server.cors.allowOrigin = loadConfig("server.cors.allow-origin", STRING) ?? "*";
2244
2730
  config.server.cors.allowCredentials = loadConfig("server.cors.allow-credentials", BOOLEAN) ?? true;
2245
2731
  config.server.cors.disabled = loadConfig("server.cors.disabled", BOOLEAN) ?? false ? true : void 0;