@interopio/bridge 1.0.5 → 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,15 @@
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
+
5
14
  ## 1.0.5 (2025-11-23)
6
15
  ### Changed
7
16
  - bump @interopio/gateway-server to 0.19.1
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.5",
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.19.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.22.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
  }
@@ -2358,10 +2369,10 @@ var InMemoryNodeConnections = class {
2358
2369
  const owner = replicas[0];
2359
2370
  const externalEndpoint = announcedEndpoint !== void 0 && announcedEndpoint !== `/cluster?node=${nodeId}`;
2360
2371
  const endpoint = externalEndpoint ? announcedEndpoint : `/cluster?node=${nodeId}&owner=${owner}`;
2361
- const lamport = this.#lamport.tick();
2362
- const userSet = new Set(users ?? []);
2363
2372
  let node = this.#nodes.get(nodeId);
2373
+ const userSet = new Set(users ?? []);
2364
2374
  if (!node) {
2375
+ const lamport = this.#lamport.tick();
2365
2376
  node = { node: nodeId, users: userSet, firstSeen: lamport, lastSeen: now, owner, replicas, endpoint, metadata, status: "announced" };
2366
2377
  this.#nodes.set(nodeId, node);
2367
2378
  this.#logger.info(`${nodeId} announced at endpoint ${endpoint} with meta: ${JSON.stringify(metadata)}`);
@@ -2424,9 +2435,10 @@ var InMemoryNodeConnections = class {
2424
2435
  });
2425
2436
  }
2426
2437
  #cleanupOldNodes() {
2427
- const expiredTimestamp = Date.now() - this.#timeout;
2428
- const removedTimestamp = Date.now() - this.#timeout * 2;
2429
- 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;
2430
2442
  for (const [nodeId, v] of this.#nodes) {
2431
2443
  if (v.lastSeen < compactTimestamp && v.status === "removed") {
2432
2444
  if (this.#logger.enabledFor("debug")) {
@@ -2497,29 +2509,171 @@ function parseStartingContext(env = process.env) {
2497
2509
  }
2498
2510
 
2499
2511
  // ../bridge-gateway/src/index.ts
2500
- import { tmpdir } from "node:os";
2501
- import { createServer as createServer2 } from "node:net";
2502
- import { join } from "node:path";
2503
2512
  import "@interopio/gateway";
2504
2513
  import "@interopio/gateway-server";
2505
- function onGatewayStarted(log) {
2506
- 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) => {
2507
2657
  const info = JSON.stringify({ ...gateway2.info(), pid: process.pid });
2508
2658
  if (isRunningInConnectDesktop()) {
2509
- const env = process.env["GLUE-ENV"] || "DEMO";
2510
- const region = process.env["GLUE-REGION"] || "INTEROP.IO";
2511
- const user = process.env.USERNAME ?? process.env.USER;
2512
- const pipe = `glue42-${env}-${region}-${user}`;
2513
- const pipeName = process.platform === "win32" ? `\\\\.\\pipe\\${pipe}` : `${join(tmpdir(), pipe + ".sock")}`;
2514
- log.info(`gateway started: ${info}, opening ${pipeName}`);
2515
- const server = createServer2((stream) => {
2516
- log.info(`stream connected, sending info...`);
2517
- stream.write(info);
2518
- stream.end(() => {
2519
- server.close();
2520
- });
2521
- });
2522
- 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);
2523
2677
  } else {
2524
2678
  log.info(`gateway started: ${info}`);
2525
2679
  }
@@ -2529,7 +2683,7 @@ async function serverGatewayConfig(gateway2, bridge, env = process.env) {
2529
2683
  let enabled = gateway2.enabled;
2530
2684
  if (enabled === void 0) {
2531
2685
  if (isRunningInConnectDesktop(env)) {
2532
- const applicationConfig = parseStartingContext(env)?.applicationConfig;
2686
+ const applicationConfig = parseStartingContext(env).applicationConfig;
2533
2687
  enabled = applicationConfig?.customProperties?.gatewayApp === true || applicationConfig?.name === "io-connect-gateway";
2534
2688
  }
2535
2689
  }
@@ -2541,14 +2695,13 @@ async function serverGatewayConfig(gateway2, bridge, env = process.env) {
2541
2695
  }
2542
2696
  if (enabled) {
2543
2697
  return {
2544
- // globals: { websocket },
2545
2698
  clients: {
2546
2699
  inactive_seconds: 0
2547
2700
  },
2548
2701
  ping: bridge.wsPingInterval ?? void 0,
2549
2702
  mesh: {
2550
2703
  auth: { user: null },
2551
- node: "bridge-gateway",
2704
+ node: bridge.uuid,
2552
2705
  channel: bridge.meshChannel
2553
2706
  },
2554
2707
  contexts: {
@@ -2610,6 +2763,7 @@ var BridgeNode = class {
2610
2763
  version;
2611
2764
  server;
2612
2765
  licenseValidator;
2766
+ #licenseCheckIntervalId;
2613
2767
  constructor(config) {
2614
2768
  this.config = config;
2615
2769
  this.licenseValidator = BridgeLicenseValidator(this.getLogger("license"));
@@ -2624,6 +2778,8 @@ var BridgeNode = class {
2624
2778
  uuid: this.uuid,
2625
2779
  version: this.version
2626
2780
  };
2781
+ }).finally(() => {
2782
+ addressPicker.close();
2627
2783
  });
2628
2784
  const joinConfig = config.network.join;
2629
2785
  const isAutoDetectionEnabled = joinConfig.autoDetectionEnabled;
@@ -2636,7 +2792,7 @@ var BridgeNode = class {
2636
2792
  getLogger(name) {
2637
2793
  return getLogger(name);
2638
2794
  }
2639
- async scheduleLicenseCheck() {
2795
+ scheduleLicenseCheck() {
2640
2796
  const task = async () => {
2641
2797
  try {
2642
2798
  this.licenseValidator.validate(this.config.license, {
@@ -2669,16 +2825,22 @@ var BridgeNode = class {
2669
2825
  auth: { type: "none", ...this.config.server.auth },
2670
2826
  cors: this.config.server.cors.disabled ? false : this.config.server.cors
2671
2827
  };
2672
- 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
+ });
2673
2833
  logStartingInfo(this.getLogger("node"));
2674
2834
  this.server = await gatewayServer(config);
2675
2835
  if (false) {
2676
2836
  await this.discoveryService.start();
2677
2837
  }
2678
2838
  if (config.gateway !== void 0) {
2679
- onGatewayStarted(this.getLogger("gw"))(this.server.gateway);
2839
+ onGatewayStarted(this.getLogger("gw"))(this.server.gateway, async () => {
2840
+ await this.stop();
2841
+ });
2680
2842
  }
2681
- await this.scheduleLicenseCheck();
2843
+ this.#licenseCheckIntervalId = this.scheduleLicenseCheck();
2682
2844
  }
2683
2845
  async stop() {
2684
2846
  if (this.server) {
@@ -2689,6 +2851,10 @@ var BridgeNode = class {
2689
2851
  } catch (e) {
2690
2852
  }
2691
2853
  await this.meshChannel.close();
2854
+ if (this.#licenseCheckIntervalId !== void 0) {
2855
+ clearInterval(this.#licenseCheckIntervalId);
2856
+ this.#licenseCheckIntervalId = void 0;
2857
+ }
2692
2858
  }
2693
2859
  };
2694
2860