@interopio/bridge 1.0.4 → 1.0.6

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/changelog.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  # Change Log
4
4
 
5
+ ## 1.0.6 (2025-12-05)
6
+ ### Changed
7
+ - bump @interopio/gateway-server to 0.19.3
8
+ - bump @interopio/gateway to 0.22.3 (fix log)
9
+ - embedded gateway now uses bridge node id as gateway node id
10
+
11
+ ### Added
12
+ - start management pipe when connect desktop is detected
13
+
14
+ ## 1.0.5 (2025-11-23)
15
+ ### Changed
16
+ - bump @interopio/gateway-server to 0.19.1
17
+ - bump @interopio/gateway to 0.22.1
18
+
19
+ ### Fixed
20
+ - embedded gateway error on user addition
21
+
5
22
  ## 1.0.4 (2025-11-19)
6
23
  ### Changed
7
24
  - bump @interopio/gateway-server to 0.18.1
@@ -19,6 +36,7 @@
19
36
  ### Fixed
20
37
  - declare dependency to "hrw-hash": "^2.0.3"
21
38
  - embedded gateway is announced on start
39
+
22
40
  ### Changed
23
41
  - soft deletion of gateways
24
42
 
package/dist/main.js CHANGED
@@ -1361,7 +1361,7 @@ function parseVersion(version) {
1361
1361
  // package.json
1362
1362
  var package_default = {
1363
1363
  name: "@interopio/bridge",
1364
- version: "1.0.4",
1364
+ version: "1.0.6",
1365
1365
  license: "see license in license.md",
1366
1366
  author: "interop.io",
1367
1367
  homepage: "https://docs.interop.io/bridge",
@@ -1401,14 +1401,14 @@ var package_default = {
1401
1401
  build: "npm run build:main && npm run build:index"
1402
1402
  },
1403
1403
  dependencies: {
1404
- "@interopio/gateway-server": "^0.18.1",
1404
+ "@interopio/gateway-server": "^0.19.3",
1405
1405
  dotenv: "^17.2.3",
1406
1406
  jsrsasign: "^11.1.0",
1407
1407
  "hrw-hash": "^2.0.3",
1408
1408
  nanoid: "^5.1.6"
1409
1409
  },
1410
1410
  devDependencies: {
1411
- "@interopio/gateway": "^0.21.1",
1411
+ "@interopio/gateway": "^0.22.3",
1412
1412
  "@types/jsrsasign": "^10.5.15",
1413
1413
  "@types/ws": "^8.18.1",
1414
1414
  "rand-seed": "^3.0.0"
@@ -1486,7 +1486,7 @@ var DefaultAddressPicker = class {
1486
1486
  #publicAddressConfig;
1487
1487
  #publicAddress;
1488
1488
  #bindAddress;
1489
- server;
1489
+ #server;
1490
1490
  #port;
1491
1491
  constructor(config, logger) {
1492
1492
  this.#logger = logger;
@@ -1494,6 +1494,17 @@ var DefaultAddressPicker = class {
1494
1494
  this.#port = config.network.port;
1495
1495
  this.#publicAddressConfig = config.network.publicAddress;
1496
1496
  }
1497
+ async close() {
1498
+ await new Promise((resolve, reject) => {
1499
+ this.#server.close((err) => {
1500
+ if (err) {
1501
+ reject(err);
1502
+ } else {
1503
+ resolve();
1504
+ }
1505
+ });
1506
+ });
1507
+ }
1497
1508
  async pickAddress() {
1498
1509
  if (this.#publicAddress || this.#bindAddress) {
1499
1510
  return;
@@ -1505,12 +1516,12 @@ var DefaultAddressPicker = class {
1505
1516
  return this.#publicAddress;
1506
1517
  }
1507
1518
  getServers() {
1508
- return /* @__PURE__ */ new Map([["member", this.server]]);
1519
+ return /* @__PURE__ */ new Map([["member", this.#server]]);
1509
1520
  }
1510
1521
  async getPublicAddressByPortSearch() {
1511
1522
  const bindAddressDef = await this.pickAddressDef();
1512
- this.server = await createNetServer(this.#logger, "0.0.0.0", bindAddressDef.port === 0 ? this.#port : bindAddressDef.port);
1513
- const port = this.server.address().port;
1523
+ this.#server = await createNetServer(this.#logger, "0.0.0.0", bindAddressDef.port === 0 ? this.#port : bindAddressDef.port);
1524
+ const port = this.#server.address().port;
1514
1525
  this.#bindAddress = await createAddress(bindAddressDef, port);
1515
1526
  return this.getPublicAddress(port);
1516
1527
  }
@@ -2103,16 +2114,15 @@ var BridgeMeshChannel = class {
2103
2114
  #onAddUsers(node, usersToAdd) {
2104
2115
  let shouldAnnounce = false;
2105
2116
  const nodeState = this.#state.get(node);
2106
- const nodeUsers = nodeState?.users;
2107
- if (nodeUsers === void 0) {
2117
+ if (nodeState?.users === void 0) {
2108
2118
  nodeState.users = new Set(usersToAdd);
2109
2119
  shouldAnnounce = true;
2110
2120
  } else {
2111
2121
  for (const u of usersToAdd) {
2112
- if (nodeUsers.has(u)) {
2122
+ if (nodeState.users.has(u)) {
2113
2123
  continue;
2114
2124
  }
2115
- nodeUsers.add(u);
2125
+ nodeState.users.add(u);
2116
2126
  shouldAnnounce = true;
2117
2127
  }
2118
2128
  }
@@ -2359,10 +2369,10 @@ var InMemoryNodeConnections = class {
2359
2369
  const owner = replicas[0];
2360
2370
  const externalEndpoint = announcedEndpoint !== void 0 && announcedEndpoint !== `/cluster?node=${nodeId}`;
2361
2371
  const endpoint = externalEndpoint ? announcedEndpoint : `/cluster?node=${nodeId}&owner=${owner}`;
2362
- const lamport = this.#lamport.tick();
2363
- const userSet = new Set(users ?? []);
2364
2372
  let node = this.#nodes.get(nodeId);
2373
+ const userSet = new Set(users ?? []);
2365
2374
  if (!node) {
2375
+ const lamport = this.#lamport.tick();
2366
2376
  node = { node: nodeId, users: userSet, firstSeen: lamport, lastSeen: now, owner, replicas, endpoint, metadata, status: "announced" };
2367
2377
  this.#nodes.set(nodeId, node);
2368
2378
  this.#logger.info(`${nodeId} announced at endpoint ${endpoint} with meta: ${JSON.stringify(metadata)}`);
@@ -2425,9 +2435,10 @@ var InMemoryNodeConnections = class {
2425
2435
  });
2426
2436
  }
2427
2437
  #cleanupOldNodes() {
2428
- const expiredTimestamp = Date.now() - this.#timeout;
2429
- const removedTimestamp = Date.now() - this.#timeout * 2;
2430
- const compactTimestamp = Date.now() - this.#timeout * 10;
2438
+ const now = Date.now();
2439
+ const expiredTimestamp = now - this.#timeout;
2440
+ const removedTimestamp = now - this.#timeout * 2;
2441
+ const compactTimestamp = now - this.#timeout * 10;
2431
2442
  for (const [nodeId, v] of this.#nodes) {
2432
2443
  if (v.lastSeen < compactTimestamp && v.status === "removed") {
2433
2444
  if (this.#logger.enabledFor("debug")) {
@@ -2498,29 +2509,171 @@ function parseStartingContext(env = process.env) {
2498
2509
  }
2499
2510
 
2500
2511
  // ../bridge-gateway/src/index.ts
2501
- import { tmpdir } from "node:os";
2502
- import { createServer as createServer2 } from "node:net";
2503
- import { join } from "node:path";
2504
2512
  import "@interopio/gateway";
2505
2513
  import "@interopio/gateway-server";
2506
- function onGatewayStarted(log) {
2507
- return (gateway2) => {
2514
+
2515
+ // ../bridge-gateway/src/pipes/common.ts
2516
+ import { tmpdir } from "node:os";
2517
+ import { join } from "node:path";
2518
+ function isWinOS() {
2519
+ return process.platform === "win32";
2520
+ }
2521
+ function getPipeFileName(pipe) {
2522
+ return isWinOS() ? `\\\\.\\pipe\\${pipe}` : join(tmpdir(), `${pipe}.sock`);
2523
+ }
2524
+
2525
+ // ../bridge-gateway/src/pipes/discovery.ts
2526
+ import { createServer as createServer2 } from "node:net";
2527
+ function getDiscoveryPipeFileName({ environment, region, user }) {
2528
+ return getPipeFileName(`glue42-${environment}-${region}-${user}`);
2529
+ }
2530
+ function gatewayDiscoveryPipeServer({ logger, info, pipeNameProps }) {
2531
+ const pipeName = getDiscoveryPipeFileName(pipeNameProps);
2532
+ logger.info(`gateway started: ${info}, opening ${pipeName}`);
2533
+ const server = createServer2((stream) => {
2534
+ logger.info(`stream connected, sending info...`);
2535
+ stream.write(info);
2536
+ stream.end(() => {
2537
+ server.close();
2538
+ });
2539
+ });
2540
+ server.listen(pipeName);
2541
+ return server;
2542
+ }
2543
+
2544
+ // ../bridge-gateway/src/pipes/command.ts
2545
+ import { createServer as createServer3 } from "node:net";
2546
+ function getGWPipeFileName({ environment, region, user }) {
2547
+ return getPipeFileName(`glue42-gateway-${environment}-${region}-${user}`);
2548
+ }
2549
+ function createPipeCommandServer({ logger, pipeName, handler, onClose }) {
2550
+ if (logger.enabledFor("info")) {
2551
+ logger.info(`[${pipeName}] opening command server pipe, waiting for the data...`);
2552
+ }
2553
+ try {
2554
+ const server = createServer3((stream) => {
2555
+ if (logger.enabledFor("debug")) {
2556
+ logger.debug(`[${pipeName}] command pipe server got client, waiting for the data...`);
2557
+ }
2558
+ stream.on("close", () => {
2559
+ if (logger.enabledFor("debug")) {
2560
+ logger.debug(`[${pipeName}] client closed`);
2561
+ }
2562
+ });
2563
+ stream.on("error", (error) => {
2564
+ logger.error(`[${pipeName}] error on pipe stream`, error);
2565
+ });
2566
+ stream.on("data", async (...args) => {
2567
+ try {
2568
+ const asString = args.toString();
2569
+ const msg = JSON.parse(asString);
2570
+ if (logger.enabledFor("info")) {
2571
+ logger.info(`[${pipeName}] received command ${msg.command}`);
2572
+ }
2573
+ handler(msg).then((result) => {
2574
+ const response = JSON.stringify({ result });
2575
+ if (logger.enabledFor("info")) {
2576
+ logger.info(`[${pipeName}] command ${msg.command} processed successfully. sending : ${response}`);
2577
+ }
2578
+ stream.write(response, (e) => {
2579
+ if (e) {
2580
+ if (logger.enabledFor("debug")) {
2581
+ logger.debug(`[${pipeName}] error while sending response for command ${msg.command}`, e);
2582
+ }
2583
+ }
2584
+ });
2585
+ }).catch((error) => {
2586
+ const response = JSON.stringify({ error: error.message });
2587
+ logger.error(`[${pipeName}] processing command ${msg.command} failed, sending ${response}`, error);
2588
+ stream.write(response, (e) => {
2589
+ if (e) {
2590
+ if (logger.enabledFor("debug")) {
2591
+ logger.debug(`[${pipeName}] error while sending error response for command ${msg.command}`, e);
2592
+ }
2593
+ }
2594
+ });
2595
+ }).finally(() => {
2596
+ if (msg.command === "shutdown") {
2597
+ if (logger.enabledFor("info")) {
2598
+ logger.info(`[${pipeName}] stopping management pipe server`);
2599
+ }
2600
+ server.close(onClose);
2601
+ }
2602
+ });
2603
+ } catch (error) {
2604
+ logger.error(`[${pipeName}] unable to parse the data`, error);
2605
+ }
2606
+ });
2607
+ });
2608
+ server.on("listening", () => {
2609
+ if (logger.enabledFor("info")) {
2610
+ logger.info(`[${pipeName}] connected to the pipe, waiting for the data...`);
2611
+ }
2612
+ });
2613
+ server.on("error", (error) => {
2614
+ logger.error(`[${pipeName}] error while opening the pipe - ${pipeName}`, error);
2615
+ throw error;
2616
+ });
2617
+ server.listen(pipeName);
2618
+ } catch (cause) {
2619
+ const msg = `error while opening the pipe - ${pipeName}`;
2620
+ logger.error(msg, cause);
2621
+ const error = new Error(msg);
2622
+ error.cause = cause;
2623
+ throw error;
2624
+ }
2625
+ }
2626
+ function gatewayCommandPipeServer({ logger, shutdownHandler, info, pipeNameProps }) {
2627
+ const pipeName = getGWPipeFileName(pipeNameProps);
2628
+ createPipeCommandServer({
2629
+ pipeName,
2630
+ logger,
2631
+ onClose: () => {
2632
+ if (logger.enabledFor("info")) {
2633
+ logger.info(`[${pipeName}] command server closed, exiting bridge process`);
2634
+ }
2635
+ process.exit(0);
2636
+ },
2637
+ handler: async (msg) => {
2638
+ if (msg.command === "shutdown") {
2639
+ await shutdownHandler?.();
2640
+ return "gateway stopped";
2641
+ } else if (msg.command === "get-info") {
2642
+ return info;
2643
+ } else if (msg.command === "update-auth") {
2644
+ if (msg.auth) {
2645
+ throw new Error("auth update not implemented");
2646
+ } else {
2647
+ throw new Error("no auth provided");
2648
+ }
2649
+ }
2650
+ }
2651
+ });
2652
+ }
2653
+
2654
+ // ../bridge-gateway/src/index.ts
2655
+ function onGatewayStarted(log, env = process.env) {
2656
+ return (gateway2, shutdownHandler) => {
2508
2657
  const info = JSON.stringify({ ...gateway2.info(), pid: process.pid });
2509
2658
  if (isRunningInConnectDesktop()) {
2510
- const env = process.env["GLUE-ENV"] || "DEMO";
2511
- const region = process.env["GLUE-REGION"] || "INTEROP.IO";
2512
- const user = process.env.USERNAME ?? process.env.USER;
2513
- const pipe = `glue42-${env}-${region}-${user}`;
2514
- const pipeName = process.platform === "win32" ? `\\\\.\\pipe\\${pipe}` : `${join(tmpdir(), pipe + ".sock")}`;
2515
- log.info(`gateway started: ${info}, opening ${pipeName}`);
2516
- const server = createServer2((stream) => {
2517
- log.info(`stream connected, sending info...`);
2518
- stream.write(info);
2519
- stream.end(() => {
2520
- server.close();
2521
- });
2522
- });
2523
- server.listen(pipeName);
2659
+ const startingContext = parseStartingContext(env);
2660
+ const environment = startingContext.env ?? env.IO_CD_ENV ?? env["GLUE-ENV"] ?? "DEMO";
2661
+ const region = startingContext.region ?? env.IO_CD_REGION ?? env["GLUE-REGION"] ?? "INTEROP.IO";
2662
+ const user = env.USERNAME ?? env.USER;
2663
+ let discoveryServer;
2664
+ const options = {
2665
+ logger: log,
2666
+ shutdownHandler: async () => {
2667
+ if (discoveryServer) {
2668
+ discoveryServer.close();
2669
+ }
2670
+ return await shutdownHandler();
2671
+ },
2672
+ info,
2673
+ pipeNameProps: { environment, region, user }
2674
+ };
2675
+ discoveryServer = gatewayDiscoveryPipeServer(options);
2676
+ gatewayCommandPipeServer(options);
2524
2677
  } else {
2525
2678
  log.info(`gateway started: ${info}`);
2526
2679
  }
@@ -2530,7 +2683,7 @@ async function serverGatewayConfig(gateway2, bridge, env = process.env) {
2530
2683
  let enabled = gateway2.enabled;
2531
2684
  if (enabled === void 0) {
2532
2685
  if (isRunningInConnectDesktop(env)) {
2533
- const applicationConfig = parseStartingContext(env)?.applicationConfig;
2686
+ const applicationConfig = parseStartingContext(env).applicationConfig;
2534
2687
  enabled = applicationConfig?.customProperties?.gatewayApp === true || applicationConfig?.name === "io-connect-gateway";
2535
2688
  }
2536
2689
  }
@@ -2542,14 +2695,13 @@ async function serverGatewayConfig(gateway2, bridge, env = process.env) {
2542
2695
  }
2543
2696
  if (enabled) {
2544
2697
  return {
2545
- // globals: { websocket },
2546
2698
  clients: {
2547
2699
  inactive_seconds: 0
2548
2700
  },
2549
2701
  ping: bridge.wsPingInterval ?? void 0,
2550
2702
  mesh: {
2551
2703
  auth: { user: null },
2552
- node: "bridge-gateway",
2704
+ node: bridge.uuid,
2553
2705
  channel: bridge.meshChannel
2554
2706
  },
2555
2707
  contexts: {
@@ -2611,6 +2763,7 @@ var BridgeNode = class {
2611
2763
  version;
2612
2764
  server;
2613
2765
  licenseValidator;
2766
+ #licenseCheckIntervalId;
2614
2767
  constructor(config) {
2615
2768
  this.config = config;
2616
2769
  this.licenseValidator = BridgeLicenseValidator(this.getLogger("license"));
@@ -2625,6 +2778,8 @@ var BridgeNode = class {
2625
2778
  uuid: this.uuid,
2626
2779
  version: this.version
2627
2780
  };
2781
+ }).finally(() => {
2782
+ addressPicker.close();
2628
2783
  });
2629
2784
  const joinConfig = config.network.join;
2630
2785
  const isAutoDetectionEnabled = joinConfig.autoDetectionEnabled;
@@ -2637,7 +2792,7 @@ var BridgeNode = class {
2637
2792
  getLogger(name) {
2638
2793
  return getLogger(name);
2639
2794
  }
2640
- async scheduleLicenseCheck() {
2795
+ scheduleLicenseCheck() {
2641
2796
  const task = async () => {
2642
2797
  try {
2643
2798
  this.licenseValidator.validate(this.config.license, {
@@ -2670,16 +2825,22 @@ var BridgeNode = class {
2670
2825
  auth: { type: "none", ...this.config.server.auth },
2671
2826
  cors: this.config.server.cors.disabled ? false : this.config.server.cors
2672
2827
  };
2673
- config.gateway = await serverGatewayConfig(this.config.gateway, { meshChannel: this.meshChannel, wsPingInterval: this.config.server.wsPingInterval });
2828
+ config.gateway = await serverGatewayConfig(this.config.gateway, {
2829
+ meshChannel: this.meshChannel,
2830
+ wsPingInterval: this.config.server.wsPingInterval,
2831
+ uuid: this.uuid
2832
+ });
2674
2833
  logStartingInfo(this.getLogger("node"));
2675
2834
  this.server = await gatewayServer(config);
2676
2835
  if (false) {
2677
2836
  await this.discoveryService.start();
2678
2837
  }
2679
2838
  if (config.gateway !== void 0) {
2680
- onGatewayStarted(this.getLogger("gw"))(this.server.gateway);
2839
+ onGatewayStarted(this.getLogger("gw"))(this.server.gateway, async () => {
2840
+ await this.stop();
2841
+ });
2681
2842
  }
2682
- await this.scheduleLicenseCheck();
2843
+ this.#licenseCheckIntervalId = this.scheduleLicenseCheck();
2683
2844
  }
2684
2845
  async stop() {
2685
2846
  if (this.server) {
@@ -2690,6 +2851,10 @@ var BridgeNode = class {
2690
2851
  } catch (e) {
2691
2852
  }
2692
2853
  await this.meshChannel.close();
2854
+ if (this.#licenseCheckIntervalId !== void 0) {
2855
+ clearInterval(this.#licenseCheckIntervalId);
2856
+ this.#licenseCheckIntervalId = void 0;
2857
+ }
2693
2858
  }
2694
2859
  };
2695
2860