@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 +18 -0
- package/dist/main.js +207 -42
- package/dist/main.js.map +4 -4
- package/package.json +3 -3
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.
|
|
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.
|
|
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.
|
|
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
|
|
1519
|
+
return /* @__PURE__ */ new Map([["member", this.#server]]);
|
|
1509
1520
|
}
|
|
1510
1521
|
async getPublicAddressByPortSearch() {
|
|
1511
1522
|
const bindAddressDef = await this.pickAddressDef();
|
|
1512
|
-
this
|
|
1513
|
-
const port = this
|
|
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
|
-
|
|
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 (
|
|
2122
|
+
if (nodeState.users.has(u)) {
|
|
2113
2123
|
continue;
|
|
2114
2124
|
}
|
|
2115
|
-
|
|
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
|
|
2429
|
-
const
|
|
2430
|
-
const
|
|
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
|
-
|
|
2507
|
-
|
|
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
|
|
2511
|
-
const
|
|
2512
|
-
const
|
|
2513
|
-
const
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
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)
|
|
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:
|
|
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
|
-
|
|
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, {
|
|
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
|
-
|
|
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
|
|