@interopio/bridge 0.0.1-alpha

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.
Files changed (84) hide show
  1. package/bin/bridge.js +9 -0
  2. package/gen/instance/GeneratedBuildInfo.ts +4 -0
  3. package/license.md +5 -0
  4. package/package.json +40 -0
  5. package/readme.md +10 -0
  6. package/src/cluster/Address.ts +57 -0
  7. package/src/cluster/Cluster.ts +13 -0
  8. package/src/cluster/Endpoint.ts +5 -0
  9. package/src/cluster/Member.ts +9 -0
  10. package/src/cluster/MembershipListener.ts +6 -0
  11. package/src/config/Config.ts +100 -0
  12. package/src/config/DiscoveryConfig.ts +21 -0
  13. package/src/config/Duration.ts +168 -0
  14. package/src/config/KubernetesConfig.ts +7 -0
  15. package/src/config/NamedDiscoveryConfig.ts +17 -0
  16. package/src/config/Properties.ts +49 -0
  17. package/src/config/index.ts +1 -0
  18. package/src/discovery/SimpleDiscoveryNode.ts +14 -0
  19. package/src/discovery/index.ts +207 -0
  20. package/src/discovery/multicast/MulticastDiscoveryStrategy.ts +141 -0
  21. package/src/discovery/multicast/MulticastDiscoveryStrategyFactory.ts +30 -0
  22. package/src/discovery/multicast/MulticastProperties.ts +4 -0
  23. package/src/discovery/settings.ts +37 -0
  24. package/src/error/RequestFailure.ts +48 -0
  25. package/src/gossip/ApplicationState.ts +48 -0
  26. package/src/gossip/EndpointState.ts +141 -0
  27. package/src/gossip/FailureDetector.ts +235 -0
  28. package/src/gossip/Gossiper.ts +1133 -0
  29. package/src/gossip/HeartbeatState.ts +66 -0
  30. package/src/gossip/Messenger.ts +130 -0
  31. package/src/gossip/VersionedValue.ts +59 -0
  32. package/src/index.ts +3 -0
  33. package/src/instance/AddressPicker.ts +245 -0
  34. package/src/instance/BridgeNode.ts +141 -0
  35. package/src/instance/ClusterTopologyIntentTracker.ts +4 -0
  36. package/src/io/VersionedSerializer.ts +230 -0
  37. package/src/io/util.ts +117 -0
  38. package/src/kubernetes/DnsEndpointResolver.ts +70 -0
  39. package/src/kubernetes/KubernetesApiEndpointResolver.ts +111 -0
  40. package/src/kubernetes/KubernetesApiProvider.ts +75 -0
  41. package/src/kubernetes/KubernetesClient.ts +264 -0
  42. package/src/kubernetes/KubernetesConfig.ts +130 -0
  43. package/src/kubernetes/KubernetesDiscoveryStrategy.ts +30 -0
  44. package/src/kubernetes/KubernetesDiscoveryStrategyFactory.ts +71 -0
  45. package/src/kubernetes/KubernetesEndpointResolver.ts +43 -0
  46. package/src/kubernetes/KubernetesProperties.ts +22 -0
  47. package/src/license/BridgeLicenseValidator.ts +19 -0
  48. package/src/license/LicenseValidator.ts +114 -0
  49. package/src/license/types.ts +40 -0
  50. package/src/logging.ts +22 -0
  51. package/src/main.mts +53 -0
  52. package/src/net/Action.ts +143 -0
  53. package/src/net/AddressSerializer.ts +44 -0
  54. package/src/net/ByteBufferAllocator.ts +27 -0
  55. package/src/net/FrameDecoder.ts +314 -0
  56. package/src/net/FrameEncoder.ts +138 -0
  57. package/src/net/HandshakeProtocol.ts +143 -0
  58. package/src/net/InboundConnection.ts +108 -0
  59. package/src/net/InboundConnectionInitiator.ts +150 -0
  60. package/src/net/InboundMessageHandler.ts +377 -0
  61. package/src/net/InboundSink.ts +38 -0
  62. package/src/net/Message.ts +428 -0
  63. package/src/net/OutboundConnection.ts +1141 -0
  64. package/src/net/OutboundConnectionInitiator.ts +76 -0
  65. package/src/net/RequestCallbacks.ts +148 -0
  66. package/src/net/ResponseHandler.ts +30 -0
  67. package/src/net/ShareableBytes.ts +125 -0
  68. package/src/net/internal/AsyncResourceExecutor.ts +464 -0
  69. package/src/net/internal/AsyncSocketPromise.ts +37 -0
  70. package/src/net/internal/channel/ChannelHandlerAdapter.ts +99 -0
  71. package/src/net/internal/channel/types.ts +188 -0
  72. package/src/utils/bigint.ts +23 -0
  73. package/src/utils/buffer.ts +434 -0
  74. package/src/utils/clock.ts +148 -0
  75. package/src/utils/collections.ts +283 -0
  76. package/src/utils/crc.ts +39 -0
  77. package/src/utils/internal/IpAddressUtil.ts +161 -0
  78. package/src/utils/memory/BufferPools.ts +40 -0
  79. package/src/utils/network.ts +130 -0
  80. package/src/utils/promise.ts +38 -0
  81. package/src/utils/uuid.ts +5 -0
  82. package/src/utils/vint.ts +238 -0
  83. package/src/version/MemberVersion.ts +42 -0
  84. package/src/version/Version.ts +12 -0
package/bin/bridge.js ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ "use strict";
4
+
5
+ import module from 'node:module';
6
+
7
+ module.enableCompileCache?.()
8
+
9
+ await import('../src/main.mts');
@@ -0,0 +1,4 @@
1
+ // eslint-disable
2
+ //generated
3
+
4
+ export const VERSION = '0.0.1-alpha';
package/license.md ADDED
@@ -0,0 +1,5 @@
1
+ # License Information
2
+
3
+ This package is subject to the interop.io Developer License Agreement. For full details, please visit the link below. If you have questions regarding licensing or usage, reach out to our support team at [support@interop.io](mailto:support@interop.io).
4
+
5
+ - [Interop.io Developer License Agreement](https://interop.io/developer-license-agreement/)
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@interopio/bridge",
3
+ "version": "0.0.1-alpha",
4
+ "license": "see license in license.md",
5
+ "author": "interop.io",
6
+ "homepage": "https://docs.interop.io/bridge",
7
+ "keywords": [
8
+ "io.bridge",
9
+ "bridge",
10
+ "io.connect",
11
+ "glue42",
12
+ "interop.io"
13
+ ],
14
+ "type": "module",
15
+ "exports": {
16
+ "./package.json": "./package.json",
17
+ ".": {
18
+ "import": "./src/index.ts"
19
+ }
20
+ },
21
+ "bin": {
22
+ "bridge": "./bin/bridge.js"
23
+ },
24
+ "scripts": {
25
+ "test": "mocha test --recursive"
26
+ },
27
+ "dependencies": {
28
+ "@interopio/gateway-server": "^0.5.0-beta",
29
+ "dotenv": "^17.2.0",
30
+ "jsrsasign": "^11.1.0",
31
+ "nanoid": "^5.0.9"
32
+ },
33
+ "devDependencies": {
34
+ "@types/jsrsasign": "^10.5.15",
35
+ "rand-seed": "^3.0.0"
36
+ },
37
+ "engines": {
38
+ "node": ">=22.2.0"
39
+ }
40
+ }
package/readme.md ADDED
@@ -0,0 +1,10 @@
1
+ # @interopio/bridge
2
+
3
+ ## Getting Started
4
+
5
+ - Install Node.js 24.3+
6
+ - Set IO_BRIDGE_LICENSE_KEY environment variable
7
+ - From command line, run:
8
+ ```shell
9
+ npx @interopio/bridge
10
+ ```
@@ -0,0 +1,57 @@
1
+ import {getByName, type IpAddress} from '../utils/network.ts';
2
+ import {type Comparator, compareArrays} from '../utils/collections.ts';
3
+
4
+ export type Address = Readonly<{type: 4 | 6, host: string, port: number, address: IpAddress}>;
5
+ export function addressAsString(address: Pick<Address, 'host' | 'port' | 'type'>): string {
6
+ // todo: do better for ipv6
7
+ return `${address.host}:${address.port}`;
8
+ }
9
+ export async function toIpAddress(address: Address): Promise<IpAddress> {
10
+ return await getByName(scopedHost(address));
11
+ }
12
+
13
+ export async function fromHostname(hostname: string, port: number): Promise<Address> {
14
+ return new AddressImpl(hostname, await getByName(hostname), port);
15
+ }
16
+ export function fromIpAddress(address: IpAddress, port: number): Address {
17
+
18
+ return new AddressImpl(undefined, address, port);
19
+ }
20
+
21
+ class AddressImpl {
22
+ readonly type: 4 | 6;
23
+ readonly host: string;
24
+ readonly port: number;
25
+ readonly address: IpAddress;
26
+
27
+ constructor(hostname: string | undefined, ipAddress: IpAddress, port : number) {
28
+ const type = ipAddress.family;
29
+ if (type !== 4 && type !== 6) {
30
+ throw new Error('unexpected address type');
31
+ }
32
+ this.type= type;
33
+ this.host = hostname ?? ipAddress.address;
34
+ this.port = port;
35
+ this.address = ipAddress;
36
+ }
37
+ }
38
+
39
+ function scopedHost(address: Address): string {
40
+ if (address.type === 6) {
41
+ return `[${address.host}]`;
42
+ }
43
+ return address.host;
44
+ }
45
+
46
+ export const compareAddress: Comparator<Address> = (a1: Address, a2: Address) => {
47
+ const addressBytes1 = a1.address.addressBytes;
48
+ const addressBytes2 = a2.address.addressBytes;
49
+ const result = compareArrays(addressBytes1, 0, addressBytes1.length, addressBytes2, 0, addressBytes2.length, (b1, b2) => {
50
+ return b1 === b2 ? 0 : (b1 > b2 ? 1 : -1);
51
+ });
52
+ if (result !== 0) {
53
+ return result;
54
+ }
55
+
56
+ return a1.port === a2.port ? 0 : (a1.port > a2.port ? 1 : -1);
57
+ }
@@ -0,0 +1,13 @@
1
+ import { Version } from '../version/Version.ts';
2
+ import { type Member } from './Member.ts';
3
+ import { type MembershipListener } from './MembershipListener.ts';
4
+
5
+ type RegistrationId = number
6
+
7
+ interface Cluster {
8
+ addMembershipListener(listener: MembershipListener) : RegistrationId
9
+ readonly version: Version
10
+ readonly members: ReadonlySet<Member>
11
+ readonly localMember: Member
12
+ readonly clusterTime: number
13
+ }
@@ -0,0 +1,5 @@
1
+ import {SocketAddress} from 'node:net';
2
+
3
+ interface Endpoint {
4
+ readonly socketAddress: SocketAddress;
5
+ }
@@ -0,0 +1,9 @@
1
+ import { type MemberVersion } from '../version/MemberVersion.ts';
2
+ import { type Address } from './Address.ts';
3
+
4
+ export interface Member {
5
+ readonly local: boolean
6
+ readonly address: Address
7
+ readonly uuid: string
8
+ readonly version: MemberVersion
9
+ }
@@ -0,0 +1,6 @@
1
+ import {type Member} from './Member.ts';
2
+
3
+ export interface MembershipListener {
4
+ onMemberAdded(member: Member): void
5
+ onMemberRemoved(member: Member): void
6
+ }
@@ -0,0 +1,100 @@
1
+ import {type Properties, type PropertyType} from './Properties.ts';
2
+ import {KubernetesConfig} from './KubernetesConfig.ts';
3
+ import {
4
+ DefaultDiscoveryConfig,
5
+ type DiscoveryConfig
6
+ } from './DiscoveryConfig.ts';
7
+
8
+ export class AutoDetectionConfig {
9
+ enabled: boolean = true;
10
+ }
11
+
12
+ export interface MulticastConfig {
13
+ readonly group: string
14
+ readonly port: number
15
+ }
16
+ class DefaultMulticastConfig implements MulticastConfig {
17
+ enabled: boolean = false;
18
+ group: string = '239.1.2.3';
19
+ port: number = 34567;
20
+ }
21
+ export interface TcpIpConfig {
22
+ members: string[]
23
+ }
24
+ class DefaultTcpIpConfig implements TcpIpConfig {
25
+ enabled: boolean = false;
26
+ members: string[] = [];
27
+ }
28
+ export class JoinConfig {
29
+ private _multicast= new DefaultMulticastConfig();
30
+ private _tcpIp = new DefaultTcpIpConfig();
31
+ private _kubernetes = new KubernetesConfig();
32
+ private _discovery = new DefaultDiscoveryConfig();
33
+ private _autoDetection = new AutoDetectionConfig();
34
+
35
+ get discovery(): DiscoveryConfig {
36
+ return this._discovery;
37
+ }
38
+
39
+ get multicast(): MulticastConfig {
40
+ return this._multicast;
41
+ }
42
+
43
+ get autoDetectionEnabled(): boolean {
44
+ return this._autoDetection.enabled
45
+ && !this._multicast.enabled
46
+ && !this._tcpIp.enabled
47
+ && !this._kubernetes.enabled
48
+ && !this._discovery.enabled;
49
+ }
50
+ }
51
+
52
+ export class NetworkConfig {
53
+ public static readonly DEFAULT_PORT: number = 8383;
54
+ port: number = NetworkConfig.DEFAULT_PORT;
55
+ reuseAddress: boolean;
56
+ publicAddress?: string;
57
+ join = new JoinConfig();
58
+
59
+ constructor() {
60
+ this.reuseAddress = process.platform !== "win32";
61
+ }
62
+ }
63
+
64
+ export class ServerConfig {
65
+ port?: number = undefined;
66
+ host?: string = undefined;
67
+ mesh: {
68
+ ping?: number
69
+ } = {};
70
+ gateway: {
71
+ enabled?: boolean,
72
+ contexts: {
73
+ lifetime: 'retained' | 'ref-counted' | 'ownership'
74
+ }
75
+ } = {
76
+ contexts: {
77
+ lifetime: 'retained'
78
+ }
79
+ }
80
+ }
81
+
82
+ export class Config {
83
+ properties: Properties = {};
84
+ network = new NetworkConfig();
85
+ license: string
86
+ readonly server: ServerConfig;
87
+ constructor() {
88
+ this.server = new ServerConfig();
89
+ }
90
+
91
+ get<T extends PropertyType>(name: string): T {
92
+ const value = this.properties[name] as T;
93
+ return value;
94
+ }
95
+
96
+ set<T extends PropertyType>(name: string, value: T): Config {
97
+ this.properties[name] = value;
98
+ return this;
99
+ }
100
+ }
@@ -0,0 +1,21 @@
1
+ import type {DiscoveryServiceFactory, DiscoveryStrategyFactory} from '../discovery/index.ts';
2
+ import type {Properties} from './Properties.ts';
3
+
4
+ export interface DiscoveryStrategyConfig {
5
+ readonly discoveryStrategyFactory?: DiscoveryStrategyFactory
6
+ readonly properties: Properties
7
+ }
8
+ export interface DiscoveryConfig {
9
+ readonly discoveryStrategyConfigs: ReadonlyArray<DiscoveryStrategyConfig>
10
+ readonly discoveryServiceFactory?: DiscoveryServiceFactory
11
+ }
12
+
13
+ export class DefaultDiscoveryConfig implements DiscoveryConfig
14
+ {
15
+ discoveryStrategyConfigs: DiscoveryStrategyConfig[] = [];
16
+ discoveryServiceFactory?: DiscoveryServiceFactory;
17
+
18
+ get enabled() {
19
+ return this.discoveryStrategyConfigs.length > 0;
20
+ }
21
+ }
@@ -0,0 +1,168 @@
1
+ const UNITS_PATTERN = /^(\d+)(d|h|m|s|ms|us|µs|ns)$/;
2
+
3
+ export type Unit = keyof typeof SCALES;
4
+
5
+ export function unitForSymbol(symbol: string): Unit {
6
+ switch (symbol.toLowerCase()) {
7
+ case 'ns':
8
+ return 'nanoseconds';
9
+ case 'us':
10
+ case 'µs':
11
+ return 'microseconds';
12
+ case 'ms':
13
+ return 'milliseconds';
14
+ case 's':
15
+ return 'seconds';
16
+ case 'm':
17
+ return 'minutes';
18
+ case 'h':
19
+ return 'hours';
20
+ case 'd':
21
+ return 'days';
22
+ }
23
+ throw new Error(`Unsupported unit symbol: ${symbol}`);
24
+ }
25
+
26
+ export function symbolForUnit(unit: Unit): string {
27
+ switch (unit) {
28
+ case 'days': return 'd';
29
+ case 'hours': return 'h';
30
+ case 'minutes': return 'm';
31
+ case 'seconds': return 's';
32
+ case 'milliseconds': return 'ms';
33
+ case 'microseconds': return 'us';
34
+ case 'nanoseconds': return 'ns';
35
+ }
36
+ }
37
+
38
+ const SCALES: { [key :string ]: bigint } = {
39
+ nanoseconds: 1n,
40
+ microseconds: 1000n,
41
+ milliseconds: 1000000n,
42
+ seconds: 1000000000n,
43
+ minutes: 60n * 1000000000n,
44
+ hours: 60n * 60n * 1000000000n,
45
+ days: 24n * 60n * 60n * 1000000000n,
46
+ }
47
+
48
+ function toNanos(unit: Unit, duration: number | bigint) {
49
+ const scale = SCALES[unit];
50
+ const ns = BigInt(duration) * scale;
51
+ return ns;
52
+ }
53
+
54
+ function toMicros(unit: Unit, duration: number | bigint): bigint {
55
+ const scale = SCALES[unit];
56
+ let microScale = SCALES.microseconds;
57
+ if (scale <= microScale) {
58
+ return scale === microScale ? BigInt(duration) : BigInt(duration) / (microScale / scale);
59
+ }
60
+ else {
61
+ return BigInt(duration) * (scale / microScale);
62
+ }
63
+ }
64
+
65
+ function toMillis(unit: Unit, duration: number | bigint) : bigint {
66
+ const scale = SCALES[unit];
67
+ let milliScale = SCALES.milliseconds;
68
+ if (scale <= milliScale) {
69
+ return scale === milliScale ? BigInt(duration) : BigInt(duration) / (milliScale / scale);
70
+ }
71
+ else {
72
+ return BigInt(duration) * (scale / milliScale);
73
+ }
74
+ }
75
+
76
+ function toSeconds(unit: Unit, duration: number | bigint): bigint {
77
+ const scale = SCALES[unit];
78
+ const secondScale = SCALES.seconds;
79
+ if (scale <= secondScale) {
80
+ return scale === secondScale ? BigInt(duration) : BigInt(duration) / (secondScale / scale);
81
+ }
82
+ else {
83
+ return BigInt(duration) * (scale / secondScale);
84
+ }
85
+ }
86
+
87
+ export function convert(targetUnit: Unit, quantity: number | bigint, sourceUnit: Unit): bigint {
88
+ switch (targetUnit) {
89
+ case 'nanoseconds': return toNanos(sourceUnit, quantity);
90
+ case 'microseconds': return toMicros(sourceUnit, quantity);
91
+ case 'milliseconds': return toMillis(sourceUnit, quantity);
92
+ case 'seconds': return toSeconds(sourceUnit, quantity);
93
+ default: throw new Error('not implemented');
94
+ }
95
+ }
96
+
97
+ abstract class Duration {
98
+ readonly unit: Unit;
99
+ readonly quantity: number;
100
+
101
+ /*protected*/ constructor(value: string, minUnit: Unit, max?: number) {
102
+ const match = UNITS_PATTERN.exec(value);
103
+ if (!match) {
104
+ throw new Error(`Invalid duration: ${value}`);
105
+ }
106
+ this.quantity = parseInt(match[1]);
107
+ this.unit = unitForSymbol(match[2]);
108
+ if (max) {
109
+ if (SCALES[this.unit] < SCALES[minUnit]) {
110
+ throw new Error(`Duration must be at least ${minUnit}`);
111
+ }
112
+ if (convert(minUnit, this.quantity, this.unit) > max) {
113
+ throw new Error(`Invalid Duration: ${value}. Must be at most ${max - 1} in ${minUnit}`);
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ export class NanosecondsDuration extends Duration {
120
+ constructor(value: string) {
121
+ super(value, 'nanoseconds', Number.MAX_SAFE_INTEGER);
122
+ }
123
+
124
+ toNanoseconds() {
125
+ return toNanos(this.unit, this.quantity);
126
+ }
127
+ }
128
+ export class MicrosecondsDuration extends Duration {
129
+ constructor(value: string) {
130
+ super(value, 'microseconds', Number.MAX_SAFE_INTEGER);
131
+ }
132
+
133
+ toMicroseconds() {
134
+ return convert('microseconds', this.quantity, this.unit);
135
+ }
136
+
137
+ toSeconds() {
138
+ return convert('seconds', this.quantity, this.unit);
139
+ }
140
+ }
141
+
142
+ export class MillisecondsDuration extends Duration {
143
+ constructor(value: string) {
144
+ super(value, 'milliseconds', Number.MAX_SAFE_INTEGER);
145
+ }
146
+
147
+ toMilliseconds() {
148
+ return convert('milliseconds', this.quantity, this.unit);
149
+ }
150
+ }
151
+
152
+ export class SecondsDuration extends Duration {
153
+ constructor(value: string) {
154
+ super(value, 'seconds', Number.MAX_SAFE_INTEGER);
155
+ }
156
+
157
+ toMilliseconds() {
158
+ return toMillis(this.unit, this.quantity);
159
+ }
160
+
161
+ toNanoSeconds() {
162
+ return toNanos(this.unit, this.quantity);
163
+ }
164
+
165
+ toSeconds() {
166
+ return toSeconds(this.unit, this.quantity);
167
+ }
168
+ }
@@ -0,0 +1,7 @@
1
+ import { NamedDiscoveryConfig } from './NamedDiscoveryConfig.ts';
2
+
3
+ export class KubernetesConfig extends NamedDiscoveryConfig<KubernetesConfig> {
4
+ constructor() {
5
+ super("kubernetes");
6
+ }
7
+ }
@@ -0,0 +1,17 @@
1
+ export abstract class NamedDiscoveryConfig<T extends NamedDiscoveryConfig<T>> {
2
+ readonly tag;
3
+ private _enabled: boolean = false;
4
+
5
+ constructor(tag: string) {
6
+ this.tag = tag;
7
+ }
8
+
9
+ setEnabled(enabled: boolean): T {
10
+ this._enabled = enabled;
11
+ return this as unknown as T;
12
+ }
13
+
14
+ get enabled(): boolean {
15
+ return this._enabled;
16
+ }
17
+ }
@@ -0,0 +1,49 @@
1
+ export interface PropertyDefinition {
2
+ readonly key: string
3
+ readonly optional: boolean
4
+ readonly converter: PropertyTypeConverter<PropertyType>
5
+ }
6
+
7
+ export type PropertyType = string | number | boolean;
8
+ export type Properties = { [key: string]: PropertyType };
9
+
10
+ export interface PropertyTypeConverter<T extends PropertyType> {
11
+ convert(value: unknown): T
12
+ }
13
+
14
+ export const BOOLEAN = new class implements PropertyTypeConverter<boolean> {
15
+ convert(value: unknown): boolean {
16
+ if (typeof value === 'boolean') {
17
+ return value;
18
+ }
19
+ else if (typeof value === "string") {
20
+ return value.toLowerCase() === "true";
21
+ }
22
+ throw new Error("Cannot convert value to boolean: " + value);
23
+ }
24
+ };
25
+
26
+ export const STRING = new class implements PropertyTypeConverter<string> {
27
+ convert(value: unknown): string {
28
+ if (value === undefined) {
29
+ throw new Error("Cannot convert undefined ");
30
+ }
31
+ return String(value);
32
+ }
33
+ }
34
+
35
+ export const NUMBER = new class implements PropertyTypeConverter<number> {
36
+ convert(value: unknown): number {
37
+ if (value === undefined) {
38
+ throw new Error("Cannot convert undefined ");
39
+ }
40
+ if (typeof value === "object") {
41
+ throw new Error("Cannot convert object/array to number: " + value);
42
+ }
43
+ return Number(value);
44
+ }
45
+ }
46
+
47
+ export function property<T extends PropertyType>(name: string, converter: PropertyTypeConverter<T>): PropertyDefinition {
48
+ return {key: name, optional: true, converter: converter};
49
+ }
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,14 @@
1
+ import {type DiscoveryNode} from './index.ts';
2
+ import {type Address} from '../cluster/Address.ts';
3
+
4
+ export class SimpleDiscoveryNode implements DiscoveryNode {
5
+ readonly privateAddress: Address;
6
+ readonly publicAddress: Address;
7
+ readonly properties: ReadonlyMap<string, unknown>;
8
+ constructor(privateAddress: Address, publicAddress?: Address, properties?: ReadonlyMap<string, unknown>)
9
+ {
10
+ this.privateAddress = privateAddress;
11
+ this.publicAddress = publicAddress ?? privateAddress;
12
+ this.properties = properties ?? new Map();
13
+ }
14
+ }