@livestore/webmesh 0.3.0-dev.36 → 0.3.0-dev.38
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/README.md +19 -3
- package/dist/.tsbuildinfo +1 -1
- package/dist/channel/{message-channel-internal.d.ts → direct-channel-internal.d.ts} +7 -7
- package/dist/channel/direct-channel-internal.d.ts.map +1 -0
- package/dist/channel/{message-channel-internal.js → direct-channel-internal.js} +22 -22
- package/dist/channel/direct-channel-internal.js.map +1 -0
- package/dist/channel/{message-channel.d.ts → direct-channel.d.ts} +3 -3
- package/dist/channel/direct-channel.d.ts.map +1 -0
- package/dist/channel/{message-channel.js → direct-channel.js} +17 -17
- package/dist/channel/direct-channel.js.map +1 -0
- package/dist/channel/proxy-channel.d.ts.map +1 -1
- package/dist/channel/proxy-channel.js +84 -21
- package/dist/channel/proxy-channel.js.map +1 -1
- package/dist/common.d.ts +11 -5
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +6 -1
- package/dist/common.js.map +1 -1
- package/dist/mesh-schema.d.ts +15 -15
- package/dist/mesh-schema.d.ts.map +1 -1
- package/dist/mesh-schema.js +9 -9
- package/dist/mesh-schema.js.map +1 -1
- package/dist/node.d.ts +10 -5
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +68 -30
- package/dist/node.js.map +1 -1
- package/dist/node.test.js +114 -17
- package/dist/node.test.js.map +1 -1
- package/dist/websocket-edge.d.ts +2 -1
- package/dist/websocket-edge.d.ts.map +1 -1
- package/dist/websocket-edge.js +6 -2
- package/dist/websocket-edge.js.map +1 -1
- package/package.json +8 -4
- package/src/channel/{message-channel-internal.ts → direct-channel-internal.ts} +29 -29
- package/src/channel/{message-channel.ts → direct-channel.ts} +20 -20
- package/src/channel/proxy-channel.ts +107 -25
- package/src/common.ts +12 -4
- package/src/mesh-schema.ts +16 -19
- package/src/node.test.ts +185 -17
- package/src/node.ts +97 -35
- package/src/websocket-edge.ts +7 -1
- package/dist/channel/message-channel-internal.d.ts.map +0 -1
- package/dist/channel/message-channel-internal.js.map +0 -1
- package/dist/channel/message-channel.d.ts.map +0 -1
- package/dist/channel/message-channel.js.map +0 -1
- package/tmp/pack.tgz +0 -0
- package/tsconfig.json +0 -11
package/dist/common.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type Effect, Schema } from '@livestore/utils/effect';
|
|
2
|
-
import type {
|
|
2
|
+
import type { DirectChannelPacket, Packet, ProxyChannelPacket } from './mesh-schema.js';
|
|
3
3
|
export type ProxyQueueItem = {
|
|
4
4
|
packet: typeof ProxyChannelPacket.Type;
|
|
5
5
|
respondToSender: (msg: typeof ProxyChannelPacket.Type) => Effect.Effect<void>;
|
|
6
6
|
};
|
|
7
7
|
export type MessageQueueItem = {
|
|
8
|
-
packet: typeof
|
|
9
|
-
respondToSender: (msg: typeof
|
|
8
|
+
packet: typeof DirectChannelPacket.Type;
|
|
9
|
+
respondToSender: (msg: typeof DirectChannelPacket.Type) => Effect.Effect<void>;
|
|
10
10
|
};
|
|
11
11
|
export type MeshNodeName = string;
|
|
12
12
|
export type ChannelName = string;
|
|
@@ -29,7 +29,7 @@ export declare const packetAsOtelAttributes: (packet: typeof Packet.Type) => {
|
|
|
29
29
|
readonly source: string;
|
|
30
30
|
readonly channelName: string;
|
|
31
31
|
readonly hops: readonly string[];
|
|
32
|
-
readonly _tag: "
|
|
32
|
+
readonly _tag: "DirectChannelRequest";
|
|
33
33
|
} | {
|
|
34
34
|
readonly remainingHops: readonly string[];
|
|
35
35
|
readonly reqId: string;
|
|
@@ -38,7 +38,7 @@ export declare const packetAsOtelAttributes: (packet: typeof Packet.Type) => {
|
|
|
38
38
|
readonly source: string;
|
|
39
39
|
readonly channelName: string;
|
|
40
40
|
readonly hops: readonly string[];
|
|
41
|
-
readonly _tag: "
|
|
41
|
+
readonly _tag: "DirectChannelResponseNoTransferables";
|
|
42
42
|
} | {
|
|
43
43
|
readonly remainingHops?: undefined;
|
|
44
44
|
readonly id: string;
|
|
@@ -101,5 +101,11 @@ export declare const packetAsOtelAttributes: (packet: typeof Packet.Type) => {
|
|
|
101
101
|
packetId: string;
|
|
102
102
|
'span.label': string;
|
|
103
103
|
};
|
|
104
|
+
export declare const ListenForChannelResult: Schema.Struct<{
|
|
105
|
+
channelName: typeof Schema.String;
|
|
106
|
+
source: typeof Schema.String;
|
|
107
|
+
mode: Schema.Union<[Schema.Literal<["proxy"]>, Schema.Literal<["direct"]>]>;
|
|
108
|
+
}>;
|
|
109
|
+
export type ListenForChannelResult = typeof ListenForChannelResult.Type;
|
|
104
110
|
export {};
|
|
105
111
|
//# sourceMappingURL=common.d.ts.map
|
package/dist/common.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAExE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAa,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAExE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAEvF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,OAAO,kBAAkB,CAAC,IAAI,CAAA;IACtC,eAAe,EAAE,CAAC,GAAG,EAAE,OAAO,kBAAkB,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;CAC9E,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,OAAO,mBAAmB,CAAC,IAAI,CAAA;IACvC,eAAe,EAAE,CAAC,GAAG,EAAE,OAAO,mBAAmB,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;CAC/E,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,CAAA;AAEjC,MAAM,MAAM,WAAW,GAAG,MAAM,CAAA;AAChC,MAAM,MAAM,UAAU,GAAG,UAAU,YAAY,iBAAiB,WAAW,EAAE,CAAA;;;;;;AAQ7E,qBAAa,sBAAuB,SAAQ,2BAE1C;CAAG;AAEL,eAAO,MAAM,sBAAsB,GAAI,QAAQ,OAAO,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAK/D,CAAA;AAEF,eAAO,MAAM,sBAAsB;;;;EAIjC,CAAA;AAEF,MAAM,MAAM,sBAAsB,GAAG,OAAO,sBAAsB,CAAC,IAAI,CAAA"}
|
package/dist/common.js
CHANGED
|
@@ -11,6 +11,11 @@ export class EdgeAlreadyExistsError extends Schema.TaggedError()('EdgeAlreadyExi
|
|
|
11
11
|
export const packetAsOtelAttributes = (packet) => ({
|
|
12
12
|
packetId: packet.id,
|
|
13
13
|
'span.label': packet.id + (Predicate.hasProperty(packet, 'reqId') && packet.reqId !== undefined ? ` for ${packet.reqId}` : ''),
|
|
14
|
-
...(packet._tag !== '
|
|
14
|
+
...(packet._tag !== 'DirectChannelResponseSuccess' && packet._tag !== 'ProxyChannelPayload' ? { packet } : {}),
|
|
15
|
+
});
|
|
16
|
+
export const ListenForChannelResult = Schema.Struct({
|
|
17
|
+
channelName: Schema.String,
|
|
18
|
+
source: Schema.String,
|
|
19
|
+
mode: Schema.Union(Schema.Literal('proxy'), Schema.Literal('direct')),
|
|
15
20
|
});
|
|
16
21
|
//# sourceMappingURL=common.js.map
|
package/dist/common.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,SAAS,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAmBxE,4DAA4D;AAC5D,8FAA8F;AAC9F,+BAA+B;AAC/B,QAAQ;AACR,OAAO;AAEP,MAAM,OAAO,sBAAuB,SAAQ,MAAM,CAAC,WAAW,EAA0B,CAAC,wBAAwB,EAAE;IACjH,MAAM,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC;CAAG;AAEL,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,MAA0B,EAAE,EAAE,CAAC,CAAC;IACrE,QAAQ,EAAE,MAAM,CAAC,EAAE;IACnB,YAAY,EACV,MAAM,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClH,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,SAAS,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAmBxE,4DAA4D;AAC5D,8FAA8F;AAC9F,+BAA+B;AAC/B,QAAQ;AACR,OAAO;AAEP,MAAM,OAAO,sBAAuB,SAAQ,MAAM,CAAC,WAAW,EAA0B,CAAC,wBAAwB,EAAE;IACjH,MAAM,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC;CAAG;AAEL,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,MAA0B,EAAE,EAAE,CAAC,CAAC;IACrE,QAAQ,EAAE,MAAM,CAAC,EAAE;IACnB,YAAY,EACV,MAAM,CAAC,EAAE,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClH,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,8BAA8B,IAAI,MAAM,CAAC,IAAI,KAAK,qBAAqB,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAC/G,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,MAAM,CAAC,MAAM,CAAC;IAClD,WAAW,EAAE,MAAM,CAAC,MAAM;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtE,CAAC,CAAA"}
|
package/dist/mesh-schema.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Schema } from '@livestore/utils/effect';
|
|
2
|
-
declare const
|
|
2
|
+
declare const DirectChannelRequest_base: Schema.TaggedStruct<"DirectChannelRequest", {
|
|
3
3
|
remainingHops: Schema.optional<Schema.Array$<typeof Schema.String>>;
|
|
4
4
|
channelVersion: typeof Schema.Number;
|
|
5
5
|
/** Only set if the request is in response to an incoming request */
|
|
@@ -16,15 +16,15 @@ declare const MessageChannelRequest_base: Schema.TaggedStruct<"MessageChannelReq
|
|
|
16
16
|
hops: Schema.Array$<typeof Schema.String>;
|
|
17
17
|
}>;
|
|
18
18
|
/**
|
|
19
|
-
* Needs to go through already existing
|
|
19
|
+
* Needs to go through already existing DirectChannel edges, times out otherwise
|
|
20
20
|
*
|
|
21
21
|
* Can't yet contain the `port` because the request might be duplicated while forwarding to multiple nodes.
|
|
22
22
|
* We need a clear path back to the sender to avoid this, thus we respond with a separate
|
|
23
|
-
* `
|
|
23
|
+
* `DirectChannelResponseSuccess` which contains the `port`.
|
|
24
24
|
*/
|
|
25
|
-
export declare class
|
|
25
|
+
export declare class DirectChannelRequest extends DirectChannelRequest_base {
|
|
26
26
|
}
|
|
27
|
-
declare const
|
|
27
|
+
declare const DirectChannelResponseSuccess_base: Schema.TaggedStruct<"DirectChannelResponseSuccess", {
|
|
28
28
|
reqId: typeof Schema.String;
|
|
29
29
|
port: Schema.Schema<MessagePort, MessagePort, never>;
|
|
30
30
|
remainingHops: Schema.Array$<typeof Schema.String>;
|
|
@@ -35,9 +35,9 @@ declare const MessageChannelResponseSuccess_base: Schema.TaggedStruct<"MessageCh
|
|
|
35
35
|
channelName: typeof Schema.String;
|
|
36
36
|
hops: Schema.Array$<typeof Schema.String>;
|
|
37
37
|
}>;
|
|
38
|
-
export declare class
|
|
38
|
+
export declare class DirectChannelResponseSuccess extends DirectChannelResponseSuccess_base {
|
|
39
39
|
}
|
|
40
|
-
declare const
|
|
40
|
+
declare const DirectChannelResponseNoTransferables_base: Schema.TaggedStruct<"DirectChannelResponseNoTransferables", {
|
|
41
41
|
reqId: typeof Schema.String;
|
|
42
42
|
remainingHops: Schema.Array$<typeof Schema.String>;
|
|
43
43
|
id: Schema.PropertySignature<":", string, never, "?:", string | undefined, true, never>;
|
|
@@ -46,7 +46,7 @@ declare const MessageChannelResponseNoTransferables_base: Schema.TaggedStruct<"M
|
|
|
46
46
|
channelName: typeof Schema.String;
|
|
47
47
|
hops: Schema.Array$<typeof Schema.String>;
|
|
48
48
|
}>;
|
|
49
|
-
export declare class
|
|
49
|
+
export declare class DirectChannelResponseNoTransferables extends DirectChannelResponseNoTransferables_base {
|
|
50
50
|
}
|
|
51
51
|
declare const ProxyChannelRequest_base: Schema.TaggedStruct<"ProxyChannelRequest", {
|
|
52
52
|
remainingHops: Schema.optional<typeof Schema.Undefined>;
|
|
@@ -140,13 +140,13 @@ export declare const BroadcastChannelPacket: Schema.TaggedStruct<"BroadcastChann
|
|
|
140
140
|
source: typeof Schema.String;
|
|
141
141
|
target: Schema.Literal<["-"]>;
|
|
142
142
|
}>;
|
|
143
|
-
declare const
|
|
144
|
-
export declare class
|
|
143
|
+
declare const DirectChannelPacket_base: Schema.Union<[typeof DirectChannelRequest, typeof DirectChannelResponseSuccess, typeof DirectChannelResponseNoTransferables]>;
|
|
144
|
+
export declare class DirectChannelPacket extends DirectChannelPacket_base {
|
|
145
145
|
}
|
|
146
146
|
declare const ProxyChannelPacket_base: Schema.Union<[typeof ProxyChannelRequest, typeof ProxyChannelResponseSuccess, typeof ProxyChannelPayload, typeof ProxyChannelPayloadAck]>;
|
|
147
147
|
export declare class ProxyChannelPacket extends ProxyChannelPacket_base {
|
|
148
148
|
}
|
|
149
|
-
declare const Packet_base: Schema.Union<[typeof
|
|
149
|
+
declare const Packet_base: Schema.Union<[typeof DirectChannelPacket, typeof ProxyChannelPacket, typeof NetworkEdgeAdded, typeof NetworkTopologyRequest, typeof NetworkTopologyResponse, Schema.TaggedStruct<"BroadcastChannelPacket", {
|
|
150
150
|
id: Schema.PropertySignature<":", string, never, "?:", string | undefined, true, never>;
|
|
151
151
|
channelName: typeof Schema.String;
|
|
152
152
|
/**
|
|
@@ -160,11 +160,11 @@ declare const Packet_base: Schema.Union<[typeof MessageChannelPacket, typeof Pro
|
|
|
160
160
|
}>]>;
|
|
161
161
|
export declare class Packet extends Packet_base {
|
|
162
162
|
}
|
|
163
|
-
declare const
|
|
164
|
-
export declare class
|
|
163
|
+
declare const DirectChannelPing_base: Schema.TaggedStruct<"DirectChannelPing", {}>;
|
|
164
|
+
export declare class DirectChannelPing extends DirectChannelPing_base {
|
|
165
165
|
}
|
|
166
|
-
declare const
|
|
167
|
-
export declare class
|
|
166
|
+
declare const DirectChannelPong_base: Schema.TaggedStruct<"DirectChannelPong", {}>;
|
|
167
|
+
export declare class DirectChannelPong extends DirectChannelPong_base {
|
|
168
168
|
}
|
|
169
169
|
export {};
|
|
170
170
|
//# sourceMappingURL=mesh-schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh-schema.d.ts","sourceRoot":"","sources":["../src/mesh-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,yBAAyB,CAAA;;;;IA6B5D,oEAAoE;;IAEpE;;;OAGG;;;;;;;;AAhBL;;;;;;GAMG;AACH,qBAAa,
|
|
1
|
+
{"version":3,"file":"mesh-schema.d.ts","sourceRoot":"","sources":["../src/mesh-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,yBAAyB,CAAA;;;;IA6B5D,oEAAoE;;IAEpE;;;OAGG;;;;;;;;AAhBL;;;;;;GAMG;AACH,qBAAa,oBAAqB,SAAQ,yBAWxC;CAAG;;;;;;;;;;;;AAEL,qBAAa,4BAA6B,SAAQ,iCAOhD;CAAG;;;;;;;;;;AAEL,qBAAa,oCAAqC,SAAQ,yCAIxD;CAAG;;;;;;;;;;AAEL,qBAAa,mBAAoB,SAAQ,wBAIvC;CAAG;;;;;;;;;;;;AAEL,qBAAa,2BAA4B,SAAQ,gCAM/C;CAAG;;;;;;;;;;;AAEL,qBAAa,mBAAoB,SAAQ,wBAKvC;CAAG;;;;;;;;;;;AAEL,qBAAa,sBAAuB,SAAQ,2BAK1C;CAAG;;;;;;AAEL;;;GAGG;AACH,qBAAa,gBAAiB,SAAQ,qBAIpC;CAAG;;;;IAKH,iDAAiD;;;;AAHnD,qBAAa,sBAAuB,SAAQ,2BAM1C;CAAG;;;;;;;IAQH,iDAAiD;;;;AANnD,qBAAa,uBAAwB,SAAQ,4BAS3C;CAAG;AAEL,eAAO,MAAM,sBAAsB;;;IAGjC;;;OAGG;;;;;EAKH,CAAA;;AAEF,qBAAa,mBAAoB,SAAQ,wBAIxC;CAAG;;AAEJ,qBAAa,kBAAmB,SAAQ,uBAKvC;CAAG;;;;IArBF;;;OAGG;;;;;;AAoBL,qBAAa,MAAO,SAAQ,WAO3B;CAAG;;AAEJ,qBAAa,iBAAkB,SAAQ,sBAA4C;CAAG;;AACtF,qBAAa,iBAAkB,SAAQ,sBAA4C;CAAG"}
|
package/dist/mesh-schema.js
CHANGED
|
@@ -10,13 +10,13 @@ const defaultPacketFields = {
|
|
|
10
10
|
};
|
|
11
11
|
const remainingHopsUndefined = Schema.Undefined.pipe(Schema.optional);
|
|
12
12
|
/**
|
|
13
|
-
* Needs to go through already existing
|
|
13
|
+
* Needs to go through already existing DirectChannel edges, times out otherwise
|
|
14
14
|
*
|
|
15
15
|
* Can't yet contain the `port` because the request might be duplicated while forwarding to multiple nodes.
|
|
16
16
|
* We need a clear path back to the sender to avoid this, thus we respond with a separate
|
|
17
|
-
* `
|
|
17
|
+
* `DirectChannelResponseSuccess` which contains the `port`.
|
|
18
18
|
*/
|
|
19
|
-
export class
|
|
19
|
+
export class DirectChannelRequest extends Schema.TaggedStruct('DirectChannelRequest', {
|
|
20
20
|
...defaultPacketFields,
|
|
21
21
|
remainingHops: Schema.Array(Schema.String).pipe(Schema.optional),
|
|
22
22
|
channelVersion: Schema.Number,
|
|
@@ -29,7 +29,7 @@ export class MessageChannelRequest extends Schema.TaggedStruct('MessageChannelRe
|
|
|
29
29
|
sourceId: Schema.String,
|
|
30
30
|
}) {
|
|
31
31
|
}
|
|
32
|
-
export class
|
|
32
|
+
export class DirectChannelResponseSuccess extends Schema.TaggedStruct('DirectChannelResponseSuccess', {
|
|
33
33
|
...defaultPacketFields,
|
|
34
34
|
reqId: Schema.String,
|
|
35
35
|
port: Transferable.MessagePort,
|
|
@@ -38,7 +38,7 @@ export class MessageChannelResponseSuccess extends Schema.TaggedStruct('MessageC
|
|
|
38
38
|
channelVersion: Schema.Number,
|
|
39
39
|
}) {
|
|
40
40
|
}
|
|
41
|
-
export class
|
|
41
|
+
export class DirectChannelResponseNoTransferables extends Schema.TaggedStruct('DirectChannelResponseNoTransferables', {
|
|
42
42
|
...defaultPacketFields,
|
|
43
43
|
reqId: Schema.String,
|
|
44
44
|
remainingHops: Schema.Array(Schema.String),
|
|
@@ -113,14 +113,14 @@ export const BroadcastChannelPacket = Schema.TaggedStruct('BroadcastChannelPacke
|
|
|
113
113
|
source: Schema.String,
|
|
114
114
|
target: Schema.Literal('-'),
|
|
115
115
|
});
|
|
116
|
-
export class
|
|
116
|
+
export class DirectChannelPacket extends Schema.Union(DirectChannelRequest, DirectChannelResponseSuccess, DirectChannelResponseNoTransferables) {
|
|
117
117
|
}
|
|
118
118
|
export class ProxyChannelPacket extends Schema.Union(ProxyChannelRequest, ProxyChannelResponseSuccess, ProxyChannelPayload, ProxyChannelPayloadAck) {
|
|
119
119
|
}
|
|
120
|
-
export class Packet extends Schema.Union(
|
|
120
|
+
export class Packet extends Schema.Union(DirectChannelPacket, ProxyChannelPacket, NetworkEdgeAdded, NetworkTopologyRequest, NetworkTopologyResponse, BroadcastChannelPacket) {
|
|
121
121
|
}
|
|
122
|
-
export class
|
|
122
|
+
export class DirectChannelPing extends Schema.TaggedStruct('DirectChannelPing', {}) {
|
|
123
123
|
}
|
|
124
|
-
export class
|
|
124
|
+
export class DirectChannelPong extends Schema.TaggedStruct('DirectChannelPong', {}) {
|
|
125
125
|
}
|
|
126
126
|
//# sourceMappingURL=mesh-schema.js.map
|
package/dist/mesh-schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh-schema.js","sourceRoot":"","sources":["../src/mesh-schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAEhD,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAC3B,MAAM,CAAC,QAAQ,EACf,MAAM,CAAC,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CACnF,CAAA;AAED,MAAM,mBAAmB,GAAG;IAC1B,EAAE;IACF,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM;IAC1B,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;CAClC,CAAA;AAED,MAAM,sBAAsB,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;AAErE;;;;;;GAMG;AACH,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"mesh-schema.js","sourceRoot":"","sources":["../src/mesh-schema.ts"],"names":[],"mappings":"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"}
|
package/dist/node.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Cause, Duration, Effect, Schema, Scope, WebChannel } from '@livestore/utils/effect';
|
|
2
|
-
import type { MeshNodeName } from './common.js';
|
|
1
|
+
import { Cause, Duration, Effect, Schema, Scope, Stream, WebChannel } from '@livestore/utils/effect';
|
|
2
|
+
import type { ListenForChannelResult, MeshNodeName } from './common.js';
|
|
3
3
|
import { EdgeAlreadyExistsError } from './common.js';
|
|
4
4
|
import * as WebmeshSchema from './mesh-schema.js';
|
|
5
5
|
type EdgeChannel = WebChannel.WebChannel<typeof WebmeshSchema.Packet.Type, typeof WebmeshSchema.Packet.Type>;
|
|
@@ -37,8 +37,12 @@ export interface MeshNode<TName extends MeshNodeName = MeshNodeName> {
|
|
|
37
37
|
}): Effect.Effect<void, EdgeAlreadyExistsError, Scope.Scope>;
|
|
38
38
|
};
|
|
39
39
|
removeEdge: (targetNodeName: MeshNodeName) => Effect.Effect<void, Cause.NoSuchElementException>;
|
|
40
|
+
hasChannel: ({ target, channelName, }: {
|
|
41
|
+
target: MeshNodeName;
|
|
42
|
+
channelName: string;
|
|
43
|
+
}) => Effect.Effect<boolean, never, Scope.Scope>;
|
|
40
44
|
/**
|
|
41
|
-
* Tries to broker a
|
|
45
|
+
* Tries to broker a DirectChannel edge between the nodes, otherwise will proxy messages via hop-nodes
|
|
42
46
|
*
|
|
43
47
|
* For a channel to successfully open, both sides need to have a edge and call `makeChannel`.
|
|
44
48
|
*
|
|
@@ -63,9 +67,9 @@ export interface MeshNode<TName extends MeshNodeName = MeshNodeName> {
|
|
|
63
67
|
send: Schema.Schema<MsgSend, any>;
|
|
64
68
|
};
|
|
65
69
|
/**
|
|
66
|
-
* If possible, prefer using a
|
|
70
|
+
* If possible, prefer using a DirectChannel with transferables (i.e. transferring memory instead of copying it).
|
|
67
71
|
*/
|
|
68
|
-
mode: '
|
|
72
|
+
mode: 'direct' | 'proxy';
|
|
69
73
|
/**
|
|
70
74
|
* Amount of time before we consider a channel creation failed and retry when a new edge is available
|
|
71
75
|
*
|
|
@@ -73,6 +77,7 @@ export interface MeshNode<TName extends MeshNodeName = MeshNodeName> {
|
|
|
73
77
|
*/
|
|
74
78
|
timeout?: Duration.DurationInput;
|
|
75
79
|
}) => Effect.Effect<WebChannel.WebChannel<MsgListen, MsgSend>, never, Scope.Scope>;
|
|
80
|
+
listenForChannel: Stream.Stream<ListenForChannelResult>;
|
|
76
81
|
/**
|
|
77
82
|
* Creates a WebChannel that is broadcasted to all connected nodes.
|
|
78
83
|
* Messages won't be buffered for nodes that join the network after the broadcast channel has been created.
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,EAEL,QAAQ,EACR,MAAM,EAMN,MAAM,EACN,KAAK,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
|
package/dist/node.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { indent, LS_DEV, shouldNeverHappen } from '@livestore/utils';
|
|
2
2
|
import { Cause, Deferred, Duration, Effect, Exit, Fiber, Option, PubSub, Queue, Schema, Scope, Stream, WebChannel, } from '@livestore/utils/effect';
|
|
3
|
-
import {
|
|
3
|
+
import { makeDirectChannel } from './channel/direct-channel.js';
|
|
4
4
|
import { makeProxyChannel } from './channel/proxy-channel.js';
|
|
5
5
|
import { EdgeAlreadyExistsError, packetAsOtelAttributes } from './common.js';
|
|
6
6
|
import * as WebmeshSchema from './mesh-schema.js';
|
|
@@ -15,16 +15,17 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
15
15
|
// Effect.acquireRelease(Queue.shutdown),
|
|
16
16
|
// )
|
|
17
17
|
const channelMap = new Map();
|
|
18
|
+
const channelRequestsQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
|
|
18
19
|
const topologyRequestsMap = new Map();
|
|
19
20
|
const broadcastChannelListenQueueMap = new Map();
|
|
20
21
|
const checkTransferableEdges = (packet) => {
|
|
21
|
-
if ((packet._tag === '
|
|
22
|
+
if ((packet._tag === 'DirectChannelRequest' &&
|
|
22
23
|
(edgeChannels.size === 0 ||
|
|
23
24
|
// Either if direct edge does not support transferables ...
|
|
24
25
|
edgeChannels.get(packet.target)?.channel.supportsTransferables === false)) ||
|
|
25
26
|
// ... or if no forward-edges support transferables
|
|
26
27
|
![...edgeChannels.values()].some((c) => c.channel.supportsTransferables === true)) {
|
|
27
|
-
return WebmeshSchema.
|
|
28
|
+
return WebmeshSchema.DirectChannelResponseNoTransferables.make({
|
|
28
29
|
reqId: packet.id,
|
|
29
30
|
channelName: packet.channelName,
|
|
30
31
|
// NOTE for now we're "pretending" that the message is coming from the target node
|
|
@@ -113,6 +114,7 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
113
114
|
if (edgeChannels.has(packet.target)) {
|
|
114
115
|
const edgeChannel = edgeChannels.get(packet.target).channel;
|
|
115
116
|
const hops = packet.source === nodeName ? [] : [...packet.hops, nodeName];
|
|
117
|
+
yield* Effect.annotateCurrentSpan({ hasDirectEdge: true });
|
|
116
118
|
yield* edgeChannel.send({ ...packet, hops });
|
|
117
119
|
}
|
|
118
120
|
// In this case we have an expected route back we should follow
|
|
@@ -136,15 +138,18 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
136
138
|
// Optimization: filter out edge where packet just came from
|
|
137
139
|
const edgesToForwardTo = Array.from(edgeChannels)
|
|
138
140
|
.filter(([name]) => name !== packet.source)
|
|
139
|
-
.map(([
|
|
141
|
+
.map(([name, con]) => ({ name, channel: con.channel }));
|
|
140
142
|
// TODO if hops-depth=0, we should fail right away with no route found
|
|
141
143
|
if (hops.length === 0 && edgesToForwardTo.length === 0 && LS_DEV) {
|
|
142
|
-
|
|
144
|
+
yield* Effect.logWarning(nodeName, 'no route found to', packet.target, packet._tag, 'TODO handle better');
|
|
143
145
|
// TODO return a expected failure
|
|
144
146
|
}
|
|
145
147
|
const packetToSend = { ...packet, hops };
|
|
146
148
|
// console.debug(nodeName, 'sendPacket:forwarding', packetToSend)
|
|
147
|
-
yield* Effect.
|
|
149
|
+
yield* Effect.annotateCurrentSpan({ edgesToForwardTo: edgesToForwardTo.map(({ name }) => name) });
|
|
150
|
+
yield* Effect.forEach(edgesToForwardTo, ({ channel }) => channel.send(packetToSend), {
|
|
151
|
+
concurrency: 'unbounded',
|
|
152
|
+
});
|
|
148
153
|
}
|
|
149
154
|
}).pipe(Effect.withSpan(`sendPacket:${packet._tag}:${packet.source}→${packet.target}`, {
|
|
150
155
|
attributes: packetAsOtelAttributes(packet),
|
|
@@ -161,7 +166,7 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
161
166
|
// TODO use a priority queue instead to prioritize network-changes/edge-requests over payloads
|
|
162
167
|
const listenFiber = yield* edgeChannel.listen.pipe(Stream.flatten(), Stream.tap((message) => Effect.gen(function* () {
|
|
163
168
|
const packet = yield* Schema.decodeUnknown(WebmeshSchema.Packet)(message);
|
|
164
|
-
// console.debug(nodeName, '
|
|
169
|
+
// console.debug(nodeName, 'recv', packet._tag, packet.source, packet.target)
|
|
165
170
|
if (handledPacketIds.has(packet.id))
|
|
166
171
|
return;
|
|
167
172
|
handledPacketIds.add(packet.id);
|
|
@@ -176,22 +181,29 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
176
181
|
if (packet.target === nodeName) {
|
|
177
182
|
const channelKey = `target:${packet.source}, channelName:${packet.channelName}`;
|
|
178
183
|
if (!channelMap.has(channelKey)) {
|
|
179
|
-
const
|
|
180
|
-
channelMap.set(channelKey, { queue, debugInfo: undefined });
|
|
184
|
+
const channelQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
|
|
185
|
+
channelMap.set(channelKey, { queue: channelQueue, debugInfo: undefined });
|
|
181
186
|
}
|
|
182
|
-
const
|
|
187
|
+
const channelQueue = channelMap.get(channelKey).queue;
|
|
183
188
|
const respondToSender = (outgoingPacket) => edgeChannel
|
|
184
189
|
.send(outgoingPacket)
|
|
185
190
|
.pipe(Effect.withSpan(`respondToSender:${outgoingPacket._tag}:${outgoingPacket.source}→${outgoingPacket.target}`, { attributes: packetAsOtelAttributes(outgoingPacket) }), Effect.orDie);
|
|
186
191
|
if (Schema.is(WebmeshSchema.ProxyChannelPacket)(packet)) {
|
|
187
|
-
yield* Queue.offer(
|
|
192
|
+
yield* Queue.offer(channelQueue, { packet, respondToSender });
|
|
188
193
|
}
|
|
189
|
-
else if (Schema.is(WebmeshSchema.
|
|
190
|
-
yield* Queue.offer(
|
|
194
|
+
else if (Schema.is(WebmeshSchema.DirectChannelPacket)(packet)) {
|
|
195
|
+
yield* Queue.offer(channelQueue, { packet, respondToSender });
|
|
196
|
+
}
|
|
197
|
+
if (packet._tag === 'ProxyChannelRequest' || packet._tag === 'DirectChannelRequest') {
|
|
198
|
+
yield* Queue.offer(channelRequestsQueue, {
|
|
199
|
+
channelName: packet.channelName,
|
|
200
|
+
source: packet.source,
|
|
201
|
+
mode: packet._tag === 'ProxyChannelRequest' ? 'proxy' : 'direct',
|
|
202
|
+
});
|
|
191
203
|
}
|
|
192
204
|
}
|
|
193
205
|
else {
|
|
194
|
-
if (Schema.is(WebmeshSchema.
|
|
206
|
+
if (Schema.is(WebmeshSchema.DirectChannelPacket)(packet)) {
|
|
195
207
|
const noTransferableResponse = checkTransferableEdges(packet);
|
|
196
208
|
if (noTransferableResponse !== undefined) {
|
|
197
209
|
yield* Effect.spanEvent(`No transferable edges found for ${packet.source}→${packet.target}`);
|
|
@@ -211,7 +223,7 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
211
223
|
target: targetNodeName,
|
|
212
224
|
});
|
|
213
225
|
yield* sendPacket(edgeAddedPacket).pipe(Effect.orDie);
|
|
214
|
-
}).pipe(Effect.annotateLogs({ 'addEdge:target': targetNodeName }), Effect.withSpan(`addEdge:${nodeName}→${targetNodeName}`, {
|
|
226
|
+
}).pipe(Effect.annotateLogs({ 'addEdge:target': targetNodeName, nodeName }), Effect.withSpan(`addEdge:${nodeName}→${targetNodeName}`, {
|
|
215
227
|
attributes: { supportsTransferables: edgeChannel.supportsTransferables },
|
|
216
228
|
})); // any-cast needed for error/never overload
|
|
217
229
|
const removeEdge = (targetNodeName) => Effect.gen(function* () {
|
|
@@ -221,10 +233,11 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
221
233
|
yield* Fiber.interrupt(edgeChannels.get(targetNodeName).listenFiber);
|
|
222
234
|
edgeChannels.delete(targetNodeName);
|
|
223
235
|
});
|
|
236
|
+
const hasChannel = ({ target, channelName }) => Effect.sync(() => channelMap.has(`target:${target}, channelName:${channelName}`));
|
|
224
237
|
// TODO add heartbeat to detect dead edges (for both e2e and proxying)
|
|
225
238
|
// TODO when a channel is established in the same origin, we can use a weblock to detect disconnects
|
|
226
239
|
const makeChannel = ({ target, channelName, schema: inputSchema,
|
|
227
|
-
// TODO in the future we could have a mode that prefers
|
|
240
|
+
// TODO in the future we could have a mode that prefers directs and then falls back to proxies if needed
|
|
228
241
|
mode, timeout = Duration.seconds(1), }) => Effect.gen(function* () {
|
|
229
242
|
const schema = WebChannel.mapSchema(inputSchema);
|
|
230
243
|
const channelKey = `target:${target}, channelName:${channelName}`;
|
|
@@ -235,20 +248,20 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
235
248
|
}
|
|
236
249
|
}
|
|
237
250
|
else {
|
|
238
|
-
const
|
|
239
|
-
channelMap.set(channelKey, { queue, debugInfo: undefined });
|
|
251
|
+
const channelQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
|
|
252
|
+
channelMap.set(channelKey, { queue: channelQueue, debugInfo: undefined });
|
|
240
253
|
}
|
|
241
|
-
const
|
|
254
|
+
const channelQueue = channelMap.get(channelKey).queue;
|
|
242
255
|
yield* Effect.addFinalizer(() => Effect.sync(() => channelMap.delete(channelKey)));
|
|
243
|
-
if (mode === '
|
|
256
|
+
if (mode === 'direct') {
|
|
244
257
|
const incomingPacketsQueue = yield* Queue.unbounded().pipe(Effect.acquireRelease(Queue.shutdown));
|
|
245
258
|
// We're we're draining the queue into another new queue.
|
|
246
259
|
// It's a bit of a mystery why this is needed, since the unit tests also work without it.
|
|
247
260
|
// But for the LiveStore devtools to actually work, we need to do this.
|
|
248
261
|
// We should figure out some day why this is needed and further simplify if possible.
|
|
249
|
-
yield* Queue.takeBetween(
|
|
262
|
+
yield* Queue.takeBetween(channelQueue, 1, 10).pipe(Effect.tap((_) => Queue.offerAll(incomingPacketsQueue, _)), Effect.forever, Effect.interruptible, Effect.tapCauseLogPretty, Effect.forkScoped);
|
|
250
263
|
// NOTE already retries internally when transferables are required
|
|
251
|
-
const { webChannel, initialEdgeDeferred } = yield*
|
|
264
|
+
const { webChannel, initialEdgeDeferred } = yield* makeDirectChannel({
|
|
252
265
|
nodeName,
|
|
253
266
|
incomingPacketsQueue,
|
|
254
267
|
newEdgeAvailablePubSub,
|
|
@@ -258,7 +271,7 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
258
271
|
sendPacket,
|
|
259
272
|
checkTransferableEdges,
|
|
260
273
|
});
|
|
261
|
-
channelMap.set(channelKey, { queue, debugInfo: { channel: webChannel, target } });
|
|
274
|
+
channelMap.set(channelKey, { queue: channelQueue, debugInfo: { channel: webChannel, target } });
|
|
262
275
|
yield* initialEdgeDeferred;
|
|
263
276
|
return webChannel;
|
|
264
277
|
}
|
|
@@ -269,17 +282,36 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
269
282
|
target,
|
|
270
283
|
channelName,
|
|
271
284
|
schema,
|
|
272
|
-
queue,
|
|
285
|
+
queue: channelQueue,
|
|
273
286
|
sendPacket,
|
|
274
287
|
});
|
|
275
|
-
channelMap.set(channelKey, { queue, debugInfo: { channel, target } });
|
|
288
|
+
channelMap.set(channelKey, { queue: channelQueue, debugInfo: { channel, target } });
|
|
276
289
|
return channel;
|
|
277
290
|
}
|
|
278
291
|
}).pipe(
|
|
279
292
|
// Effect.timeout(timeout),
|
|
280
293
|
Effect.withSpanScoped(`makeChannel:${nodeName}→${target}(${channelName})`, {
|
|
281
294
|
attributes: { target, channelName, mode, timeout },
|
|
282
|
-
}), Effect.annotateLogs({ nodeName }));
|
|
295
|
+
}), Effect.annotateLogs({ nodeName, target, channelName }));
|
|
296
|
+
// TODO consider supporting multiple listeners
|
|
297
|
+
// TODO also provide a way to allow for reconnects
|
|
298
|
+
let listenAlreadyStarted = false;
|
|
299
|
+
const listenForChannel = Stream.suspend(() => {
|
|
300
|
+
if (listenAlreadyStarted) {
|
|
301
|
+
return shouldNeverHappen('listenForChannel already started');
|
|
302
|
+
}
|
|
303
|
+
listenAlreadyStarted = true;
|
|
304
|
+
const hash = (res) => `${res.channelName}:${res.source}:${res.mode}`;
|
|
305
|
+
const seen = new Set();
|
|
306
|
+
return Stream.fromQueue(channelRequestsQueue).pipe(Stream.filter((res) => {
|
|
307
|
+
const hashed = hash(res);
|
|
308
|
+
if (seen.has(hashed)) {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
seen.add(hashed);
|
|
312
|
+
return true;
|
|
313
|
+
}));
|
|
314
|
+
});
|
|
283
315
|
const makeBroadcastChannel = ({ channelName, schema }) => Effect.scopeWithCloseable((scope) => Effect.gen(function* () {
|
|
284
316
|
if (broadcastChannelListenQueueMap.has(channelName)) {
|
|
285
317
|
return shouldNeverHappen(`Broadcast channel ${channelName} already exists`, broadcastChannelListenQueueMap.get(channelName));
|
|
@@ -305,7 +337,7 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
305
337
|
send,
|
|
306
338
|
listen,
|
|
307
339
|
closedDeferred,
|
|
308
|
-
supportsTransferables:
|
|
340
|
+
supportsTransferables: false,
|
|
309
341
|
schema: { listen: schema, send: schema },
|
|
310
342
|
shutdown: Scope.close(scope, Exit.void),
|
|
311
343
|
debugInfo,
|
|
@@ -337,14 +369,17 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
337
369
|
},
|
|
338
370
|
ping: (payload) => {
|
|
339
371
|
Effect.gen(function* () {
|
|
340
|
-
const msg = (via) => WebChannel.DebugPingMessage.make({ message: `ping from ${nodeName} via
|
|
372
|
+
const msg = (via) => WebChannel.DebugPingMessage.make({ message: `ping from ${nodeName} via ${via}`, payload });
|
|
341
373
|
for (const [channelName, con] of edgeChannels) {
|
|
342
374
|
yield* Effect.logDebug(`sending ping via edge ${channelName}`);
|
|
343
375
|
yield* con.channel.send(msg(`edge ${channelName}`));
|
|
344
376
|
}
|
|
345
377
|
for (const [channelKey, channel] of channelMap) {
|
|
346
|
-
if (channel.debugInfo === undefined)
|
|
378
|
+
if (channel.debugInfo === undefined) {
|
|
379
|
+
yield* Effect.logDebug(`channel ${channelKey} has no debug info`);
|
|
347
380
|
continue;
|
|
381
|
+
}
|
|
382
|
+
// if (channel.debugInfo === undefined) continue
|
|
348
383
|
yield* Effect.logDebug(`sending ping via channel ${channelKey}`);
|
|
349
384
|
yield* channel.debugInfo.channel.send(msg(`channel ${channelKey}`));
|
|
350
385
|
}
|
|
@@ -362,8 +397,9 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
362
397
|
yield* sendPacket(packet);
|
|
363
398
|
yield* Effect.logDebug(`Waiting ${timeoutMs}ms for topology response`);
|
|
364
399
|
yield* Effect.sleep(timeoutMs);
|
|
400
|
+
yield* Effect.logDebug(`Topology response (from ${nodeName}):`);
|
|
365
401
|
for (const [key, value] of item) {
|
|
366
|
-
yield* Effect.logDebug(`node '${key}'
|
|
402
|
+
yield* Effect.logDebug(` node '${key}' has edge to: ${Array.from(value.values()).join(', ')}`);
|
|
367
403
|
}
|
|
368
404
|
}).pipe(Effect.provide(runtime), Effect.tapCauseLogPretty, Effect.runPromise),
|
|
369
405
|
};
|
|
@@ -371,7 +407,9 @@ export const makeMeshNode = (nodeName) => Effect.gen(function* () {
|
|
|
371
407
|
nodeName,
|
|
372
408
|
addEdge,
|
|
373
409
|
removeEdge,
|
|
410
|
+
hasChannel,
|
|
374
411
|
makeChannel,
|
|
412
|
+
listenForChannel,
|
|
375
413
|
makeBroadcastChannel,
|
|
376
414
|
edgeKeys,
|
|
377
415
|
debug,
|