wire-mesh-core 1.54.0 → 1.55.0
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/dist/domain/gossip-expansion.cjs +44 -0
- package/dist/domain/gossip-expansion.d.cts +29 -0
- package/dist/domain/gossip-expansion.d.mts +29 -0
- package/dist/domain/gossip-expansion.mjs +43 -0
- package/dist/domain/mesh-session.cjs +7 -5
- package/dist/domain/mesh-session.d.cts +5 -1
- package/dist/domain/mesh-session.d.mts +5 -1
- package/dist/domain/mesh-session.mjs +7 -5
- package/package.json +5 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_domain_device_id = require("./device-id.cjs");
|
|
3
|
+
//#region src/domain/gossip-expansion.ts
|
|
4
|
+
function toError(value) {
|
|
5
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
6
|
+
}
|
|
7
|
+
/** Builds the per-device expansion state machine: ask once, dial every advertised address in order on approval, report exactly one outcome. */
|
|
8
|
+
function createGossipExpansion(options) {
|
|
9
|
+
const selfHex = require_domain_device_id.deviceIdToHex(options.selfDeviceId);
|
|
10
|
+
const considered = /* @__PURE__ */ new Set();
|
|
11
|
+
async function expand(candidate) {
|
|
12
|
+
let approved;
|
|
13
|
+
try {
|
|
14
|
+
approved = await options.shouldExpand(candidate);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
options.onExpansionFailed?.(candidate, [toError(error)]);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (!approved) {
|
|
20
|
+
options.onExpansionDeclined?.(candidate);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const errors = [];
|
|
24
|
+
for (const address of candidate.addresses) try {
|
|
25
|
+
const session = await options.dial(address);
|
|
26
|
+
options.onExpanded(candidate, address, session);
|
|
27
|
+
return;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
errors.push(toError(error));
|
|
30
|
+
}
|
|
31
|
+
options.onExpansionFailed?.(candidate, errors);
|
|
32
|
+
}
|
|
33
|
+
return { considerAdvert(advert) {
|
|
34
|
+
const hex = require_domain_device_id.deviceIdToHex(advert.device);
|
|
35
|
+
if (hex === selfHex || considered.has(hex) || advert.addresses.length === 0) return;
|
|
36
|
+
considered.add(hex);
|
|
37
|
+
expand({
|
|
38
|
+
device: advert.device,
|
|
39
|
+
addresses: advert.addresses
|
|
40
|
+
});
|
|
41
|
+
} };
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
exports.createGossipExpansion = createGossipExpansion;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { D as DeviceId, et as PeerAdvert } from "../protocol-PhUVprXA.cjs";
|
|
2
|
+
import { MeshSession } from "./mesh-session.cjs";
|
|
3
|
+
//#region src/domain/gossip-expansion.d.ts
|
|
4
|
+
/** One not-yet-considered device this session's gossip directory has surfaced, carrying only what a dial/trust decision needs: the device-id to decide identity, and the "host:port" addresses its own peer-advert claims are directly reachable at, in the order it advertised them. */
|
|
5
|
+
export interface GossipExpansionCandidate {
|
|
6
|
+
readonly device: DeviceId;
|
|
7
|
+
readonly addresses: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export interface GossipExpansionOptions {
|
|
10
|
+
/** This session's own device-id, so its own self-advert (looped back through gossip forwarding or a hub's catch-up frame) is never offered to shouldExpand as if it were a distinct peer. */
|
|
11
|
+
selfDeviceId: DeviceId;
|
|
12
|
+
/** Decides whether to attempt a direct connection to a newly-discovered device at all -- called at most once per device for this GossipExpansion instance's lifetime, never re-asked if the same device later re-adverts (an address change, a fresher snapshot-seconds). Returning true does not guarantee a connection: dial may still fail for every one of the candidate's addresses, reported via onExpansionFailed. */
|
|
13
|
+
shouldExpand: (candidate: Readonly<GossipExpansionCandidate>) => Promise<boolean> | boolean;
|
|
14
|
+
/** Attempts one direct connection to `address`, resolving with a fully connected MeshSession or rejecting if the dial/handshake fails. Typically wraps createMeshSession(transport, identity, ...) followed by session.connect(address, localDomains). Called once per address of an approved candidate, in the order it advertised them, stopping at the first that succeeds -- the caller owns cleanup of any partially-established session behind a rejected dial, since this module never holds a reference to one that didn't resolve. */
|
|
15
|
+
dial: (address: string) => Promise<MeshSession>;
|
|
16
|
+
/** Called once a candidate's dial succeeds, with the specific address that connected (one of candidate.addresses, not necessarily the first -- earlier ones may have failed) and the now-connected session, so the caller can wire it into whatever it already does for its own sessions (render it, merge its directory, route messages). */
|
|
17
|
+
onExpanded: (candidate: Readonly<GossipExpansionCandidate>, address: string, session: MeshSession) => void;
|
|
18
|
+
/** Called when shouldExpand itself declines a candidate. */
|
|
19
|
+
onExpansionDeclined?: (candidate: Readonly<GossipExpansionCandidate>) => void;
|
|
20
|
+
/** Called once every one of an approved candidate's addresses has failed to connect, or shouldExpand itself rejected -- in the latter case, errors holds exactly the one rejection reason, so a caller doesn't need two separate failure channels to observe every way expansion can fail short of success. */
|
|
21
|
+
onExpansionFailed?: (candidate: Readonly<GossipExpansionCandidate>, errors: readonly Error[]) => void;
|
|
22
|
+
}
|
|
23
|
+
export interface GossipExpansion {
|
|
24
|
+
/** Feed one just-received peer-advert -- from the session whose peer-adverts this expansion watches, via its own onPeerAdvert hook -- to decide whether it names a newly-discoverable peer worth expanding to, and if so kick off an expansion attempt for it. Never awaits a dial to completion inline: expansion happens in the background, observable only through onExpanded/onExpansionDeclined/onExpansionFailed. */
|
|
25
|
+
considerAdvert: (advert: Readonly<PeerAdvert>) => void;
|
|
26
|
+
}
|
|
27
|
+
/** Builds the per-device expansion state machine: ask once, dial every advertised address in order on approval, report exactly one outcome. */
|
|
28
|
+
export declare function createGossipExpansion(options: Readonly<GossipExpansionOptions>): GossipExpansion;
|
|
29
|
+
//#endregion
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { D as DeviceId, et as PeerAdvert } from "../protocol-PhUVprXA.mjs";
|
|
2
|
+
import { MeshSession } from "./mesh-session.mjs";
|
|
3
|
+
//#region src/domain/gossip-expansion.d.ts
|
|
4
|
+
/** One not-yet-considered device this session's gossip directory has surfaced, carrying only what a dial/trust decision needs: the device-id to decide identity, and the "host:port" addresses its own peer-advert claims are directly reachable at, in the order it advertised them. */
|
|
5
|
+
export interface GossipExpansionCandidate {
|
|
6
|
+
readonly device: DeviceId;
|
|
7
|
+
readonly addresses: readonly string[];
|
|
8
|
+
}
|
|
9
|
+
export interface GossipExpansionOptions {
|
|
10
|
+
/** This session's own device-id, so its own self-advert (looped back through gossip forwarding or a hub's catch-up frame) is never offered to shouldExpand as if it were a distinct peer. */
|
|
11
|
+
selfDeviceId: DeviceId;
|
|
12
|
+
/** Decides whether to attempt a direct connection to a newly-discovered device at all -- called at most once per device for this GossipExpansion instance's lifetime, never re-asked if the same device later re-adverts (an address change, a fresher snapshot-seconds). Returning true does not guarantee a connection: dial may still fail for every one of the candidate's addresses, reported via onExpansionFailed. */
|
|
13
|
+
shouldExpand: (candidate: Readonly<GossipExpansionCandidate>) => Promise<boolean> | boolean;
|
|
14
|
+
/** Attempts one direct connection to `address`, resolving with a fully connected MeshSession or rejecting if the dial/handshake fails. Typically wraps createMeshSession(transport, identity, ...) followed by session.connect(address, localDomains). Called once per address of an approved candidate, in the order it advertised them, stopping at the first that succeeds -- the caller owns cleanup of any partially-established session behind a rejected dial, since this module never holds a reference to one that didn't resolve. */
|
|
15
|
+
dial: (address: string) => Promise<MeshSession>;
|
|
16
|
+
/** Called once a candidate's dial succeeds, with the specific address that connected (one of candidate.addresses, not necessarily the first -- earlier ones may have failed) and the now-connected session, so the caller can wire it into whatever it already does for its own sessions (render it, merge its directory, route messages). */
|
|
17
|
+
onExpanded: (candidate: Readonly<GossipExpansionCandidate>, address: string, session: MeshSession) => void;
|
|
18
|
+
/** Called when shouldExpand itself declines a candidate. */
|
|
19
|
+
onExpansionDeclined?: (candidate: Readonly<GossipExpansionCandidate>) => void;
|
|
20
|
+
/** Called once every one of an approved candidate's addresses has failed to connect, or shouldExpand itself rejected -- in the latter case, errors holds exactly the one rejection reason, so a caller doesn't need two separate failure channels to observe every way expansion can fail short of success. */
|
|
21
|
+
onExpansionFailed?: (candidate: Readonly<GossipExpansionCandidate>, errors: readonly Error[]) => void;
|
|
22
|
+
}
|
|
23
|
+
export interface GossipExpansion {
|
|
24
|
+
/** Feed one just-received peer-advert -- from the session whose peer-adverts this expansion watches, via its own onPeerAdvert hook -- to decide whether it names a newly-discoverable peer worth expanding to, and if so kick off an expansion attempt for it. Never awaits a dial to completion inline: expansion happens in the background, observable only through onExpanded/onExpansionDeclined/onExpansionFailed. */
|
|
25
|
+
considerAdvert: (advert: Readonly<PeerAdvert>) => void;
|
|
26
|
+
}
|
|
27
|
+
/** Builds the per-device expansion state machine: ask once, dial every advertised address in order on approval, report exactly one outcome. */
|
|
28
|
+
export declare function createGossipExpansion(options: Readonly<GossipExpansionOptions>): GossipExpansion;
|
|
29
|
+
//#endregion
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { deviceIdToHex } from "./device-id.mjs";
|
|
2
|
+
//#region src/domain/gossip-expansion.ts
|
|
3
|
+
function toError(value) {
|
|
4
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
5
|
+
}
|
|
6
|
+
/** Builds the per-device expansion state machine: ask once, dial every advertised address in order on approval, report exactly one outcome. */
|
|
7
|
+
function createGossipExpansion(options) {
|
|
8
|
+
const selfHex = deviceIdToHex(options.selfDeviceId);
|
|
9
|
+
const considered = /* @__PURE__ */ new Set();
|
|
10
|
+
async function expand(candidate) {
|
|
11
|
+
let approved;
|
|
12
|
+
try {
|
|
13
|
+
approved = await options.shouldExpand(candidate);
|
|
14
|
+
} catch (error) {
|
|
15
|
+
options.onExpansionFailed?.(candidate, [toError(error)]);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (!approved) {
|
|
19
|
+
options.onExpansionDeclined?.(candidate);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const errors = [];
|
|
23
|
+
for (const address of candidate.addresses) try {
|
|
24
|
+
const session = await options.dial(address);
|
|
25
|
+
options.onExpanded(candidate, address, session);
|
|
26
|
+
return;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
errors.push(toError(error));
|
|
29
|
+
}
|
|
30
|
+
options.onExpansionFailed?.(candidate, errors);
|
|
31
|
+
}
|
|
32
|
+
return { considerAdvert(advert) {
|
|
33
|
+
const hex = deviceIdToHex(advert.device);
|
|
34
|
+
if (hex === selfHex || considered.has(hex) || advert.addresses.length === 0) return;
|
|
35
|
+
considered.add(hex);
|
|
36
|
+
expand({
|
|
37
|
+
device: advert.device,
|
|
38
|
+
addresses: advert.addresses
|
|
39
|
+
});
|
|
40
|
+
} };
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { createGossipExpansion };
|
|
@@ -530,8 +530,8 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
530
530
|
}
|
|
531
531
|
};
|
|
532
532
|
}
|
|
533
|
-
function createMeshSession(transport, identity, clock = { now: () => Date.now() }, reconnect = null, addresses = []) {
|
|
534
|
-
const { session } = createSessionCore(identity, clock, reconnect, async (address) => transport.connect(address),
|
|
533
|
+
function createMeshSession(transport, identity, clock = { now: () => Date.now() }, reconnect = null, addresses = [], onPeerAdvert) {
|
|
534
|
+
const { session } = createSessionCore(identity, clock, reconnect, async (address) => transport.connect(address), onPeerAdvert, addresses);
|
|
535
535
|
return session;
|
|
536
536
|
}
|
|
537
537
|
/** Wires an already-accepted Connection up as a full MeshSession, mirroring exactly what createMeshSession's own dial path does once a connection exists (send handshake, send self-advert, negotiate, consume frames) -- the wire-mesh#45 prerequisite agent-comms needs, since its peers both listen and dial rather than only ever dialing the way web-console's own console UI does. Reconnect does not apply here: if this connection drops, only the remote redialing and being accepted again produces a new connection, and therefore a new session -- there is nothing on this side to retry. */
|
|
@@ -543,9 +543,11 @@ async function acceptMeshSession(connection, identity, localDomains, options = {
|
|
|
543
543
|
});
|
|
544
544
|
let peerDeviceIdResolved = false;
|
|
545
545
|
const { session, wireUpConnection } = createSessionCore(identity, clock, null, null, (advert) => {
|
|
546
|
-
if (peerDeviceIdResolved)
|
|
547
|
-
|
|
548
|
-
|
|
546
|
+
if (!peerDeviceIdResolved) {
|
|
547
|
+
peerDeviceIdResolved = true;
|
|
548
|
+
resolvePeerDeviceId?.(advert.device);
|
|
549
|
+
}
|
|
550
|
+
options.onPeerAdvert?.(advert);
|
|
549
551
|
}, options.addresses, options.onFrame, options.onSessionEnd);
|
|
550
552
|
await wireUpConnection(connection, options.label ?? "accepted", localDomains);
|
|
551
553
|
return {
|
|
@@ -95,7 +95,9 @@ export interface MeshSession {
|
|
|
95
95
|
}
|
|
96
96
|
export declare function createMeshSession(transport: Readonly<Transport>, identity: Readonly<IdentityPort>, clock?: Readonly<Clock>, reconnect?: ReconnectPolicy | null,
|
|
97
97
|
/** This node's own directly-reachable "host:port" candidates (wire-mesh#38), advertised in this session's self-advert so other peers can attempt a direct connection instead of always falling back to a relay. Omit (or pass none) for a caller with nothing to offer, e.g. a browser client. */
|
|
98
|
-
addresses?: readonly string[]
|
|
98
|
+
addresses?: readonly string[],
|
|
99
|
+
/** Fired for every peer-advert entry as it's applied to the directory, regardless of source -- the hook a gossip-expansion consumer (wire-mesh#187, gossip-expansion.ts's own createGossipExpansion) uses to observe newly-gossiped peers without becoming a second, competing consumer of this session's own single-reader events stream (each emitted SessionEvent wakes at most one waiter, so a second for-await loop over events would silently steal events from whichever consumer already reads it). Omit for a caller with no use for it, exactly today's behaviour. */
|
|
100
|
+
onPeerAdvert?: (advert: PeerAdvert) => void): MeshSession;
|
|
99
101
|
/** A MeshSession built over a connection that already exists (a Transport's own listen() handed it to onConnection), extended with the one thing a dial-side session can't offer: the device-id of the specific peer at the other end. Unlike createMeshSession, which may end up talking to a relay gossiping about many devices at once, an accepted connection is the agent-comms case -- exactly two peers, directly connected -- so "the peer" is well-defined here in a way it structurally isn't for the dial side. */
|
|
100
102
|
export interface AcceptedMeshSession extends MeshSession {
|
|
101
103
|
/** Resolves with the device-id carried by the first peer-advert this connection's remote sends -- the same self-advertisement mechanism createMeshSession's own directory already relies on for every peer, just narrowed to "the one peer this specific connection is with" rather than accumulated into a directory of possibly many. There is no transport-level authentication behind this yet (see wire-mesh#45's own createTlsTransport item): it is only as trustworthy as the remote's own gossip, exactly the same trust level the dial-side directory already has for every entry in it. */
|
|
@@ -111,6 +113,8 @@ export interface AcceptedMeshSessionOptions {
|
|
|
111
113
|
onFrame?: (connection: Readonly<Connection>, frame: Frame) => void | Promise<void>;
|
|
112
114
|
/** Fired once this session's own connection.receive() stream ends -- the counterpart a RelayHub's own forgetConnection needs, since its registry is keyed by this exact Connection and must be cleaned up when it specifically ends. */
|
|
113
115
|
onSessionEnd?: (connection: Readonly<Connection>) => void;
|
|
116
|
+
/** Fired for every peer-advert entry as it's applied to the directory, regardless of source -- alongside (never instead of) this session's own internal peerDeviceId resolution, which uses this identical hook internally and keeps working unchanged. See createMeshSession's own onPeerAdvert doc comment for why this exists: a gossip-expansion consumer (wire-mesh#187) needs to observe every advert without becoming a second, competing consumer of this session's own single-reader events stream. */
|
|
117
|
+
onPeerAdvert?: (advert: PeerAdvert) => void;
|
|
114
118
|
}
|
|
115
119
|
/** Wires an already-accepted Connection up as a full MeshSession, mirroring exactly what createMeshSession's own dial path does once a connection exists (send handshake, send self-advert, negotiate, consume frames) -- the wire-mesh#45 prerequisite agent-comms needs, since its peers both listen and dial rather than only ever dialing the way web-console's own console UI does. Reconnect does not apply here: if this connection drops, only the remote redialing and being accepted again produces a new connection, and therefore a new session -- there is nothing on this side to retry. */
|
|
116
120
|
export declare function acceptMeshSession(connection: Readonly<Connection>, identity: Readonly<IdentityPort>, localDomains: readonly string[], options?: Readonly<AcceptedMeshSessionOptions>): Promise<AcceptedMeshSession>;
|
|
@@ -95,7 +95,9 @@ export interface MeshSession {
|
|
|
95
95
|
}
|
|
96
96
|
export declare function createMeshSession(transport: Readonly<Transport>, identity: Readonly<IdentityPort>, clock?: Readonly<Clock>, reconnect?: ReconnectPolicy | null,
|
|
97
97
|
/** This node's own directly-reachable "host:port" candidates (wire-mesh#38), advertised in this session's self-advert so other peers can attempt a direct connection instead of always falling back to a relay. Omit (or pass none) for a caller with nothing to offer, e.g. a browser client. */
|
|
98
|
-
addresses?: readonly string[]
|
|
98
|
+
addresses?: readonly string[],
|
|
99
|
+
/** Fired for every peer-advert entry as it's applied to the directory, regardless of source -- the hook a gossip-expansion consumer (wire-mesh#187, gossip-expansion.ts's own createGossipExpansion) uses to observe newly-gossiped peers without becoming a second, competing consumer of this session's own single-reader events stream (each emitted SessionEvent wakes at most one waiter, so a second for-await loop over events would silently steal events from whichever consumer already reads it). Omit for a caller with no use for it, exactly today's behaviour. */
|
|
100
|
+
onPeerAdvert?: (advert: PeerAdvert) => void): MeshSession;
|
|
99
101
|
/** A MeshSession built over a connection that already exists (a Transport's own listen() handed it to onConnection), extended with the one thing a dial-side session can't offer: the device-id of the specific peer at the other end. Unlike createMeshSession, which may end up talking to a relay gossiping about many devices at once, an accepted connection is the agent-comms case -- exactly two peers, directly connected -- so "the peer" is well-defined here in a way it structurally isn't for the dial side. */
|
|
100
102
|
export interface AcceptedMeshSession extends MeshSession {
|
|
101
103
|
/** Resolves with the device-id carried by the first peer-advert this connection's remote sends -- the same self-advertisement mechanism createMeshSession's own directory already relies on for every peer, just narrowed to "the one peer this specific connection is with" rather than accumulated into a directory of possibly many. There is no transport-level authentication behind this yet (see wire-mesh#45's own createTlsTransport item): it is only as trustworthy as the remote's own gossip, exactly the same trust level the dial-side directory already has for every entry in it. */
|
|
@@ -111,6 +113,8 @@ export interface AcceptedMeshSessionOptions {
|
|
|
111
113
|
onFrame?: (connection: Readonly<Connection>, frame: Frame) => void | Promise<void>;
|
|
112
114
|
/** Fired once this session's own connection.receive() stream ends -- the counterpart a RelayHub's own forgetConnection needs, since its registry is keyed by this exact Connection and must be cleaned up when it specifically ends. */
|
|
113
115
|
onSessionEnd?: (connection: Readonly<Connection>) => void;
|
|
116
|
+
/** Fired for every peer-advert entry as it's applied to the directory, regardless of source -- alongside (never instead of) this session's own internal peerDeviceId resolution, which uses this identical hook internally and keeps working unchanged. See createMeshSession's own onPeerAdvert doc comment for why this exists: a gossip-expansion consumer (wire-mesh#187) needs to observe every advert without becoming a second, competing consumer of this session's own single-reader events stream. */
|
|
117
|
+
onPeerAdvert?: (advert: PeerAdvert) => void;
|
|
114
118
|
}
|
|
115
119
|
/** Wires an already-accepted Connection up as a full MeshSession, mirroring exactly what createMeshSession's own dial path does once a connection exists (send handshake, send self-advert, negotiate, consume frames) -- the wire-mesh#45 prerequisite agent-comms needs, since its peers both listen and dial rather than only ever dialing the way web-console's own console UI does. Reconnect does not apply here: if this connection drops, only the remote redialing and being accepted again produces a new connection, and therefore a new session -- there is nothing on this side to retry. */
|
|
116
120
|
export declare function acceptMeshSession(connection: Readonly<Connection>, identity: Readonly<IdentityPort>, localDomains: readonly string[], options?: Readonly<AcceptedMeshSessionOptions>): Promise<AcceptedMeshSession>;
|
|
@@ -529,8 +529,8 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
529
529
|
}
|
|
530
530
|
};
|
|
531
531
|
}
|
|
532
|
-
function createMeshSession(transport, identity, clock = { now: () => Date.now() }, reconnect = null, addresses = []) {
|
|
533
|
-
const { session } = createSessionCore(identity, clock, reconnect, async (address) => transport.connect(address),
|
|
532
|
+
function createMeshSession(transport, identity, clock = { now: () => Date.now() }, reconnect = null, addresses = [], onPeerAdvert) {
|
|
533
|
+
const { session } = createSessionCore(identity, clock, reconnect, async (address) => transport.connect(address), onPeerAdvert, addresses);
|
|
534
534
|
return session;
|
|
535
535
|
}
|
|
536
536
|
/** Wires an already-accepted Connection up as a full MeshSession, mirroring exactly what createMeshSession's own dial path does once a connection exists (send handshake, send self-advert, negotiate, consume frames) -- the wire-mesh#45 prerequisite agent-comms needs, since its peers both listen and dial rather than only ever dialing the way web-console's own console UI does. Reconnect does not apply here: if this connection drops, only the remote redialing and being accepted again produces a new connection, and therefore a new session -- there is nothing on this side to retry. */
|
|
@@ -542,9 +542,11 @@ async function acceptMeshSession(connection, identity, localDomains, options = {
|
|
|
542
542
|
});
|
|
543
543
|
let peerDeviceIdResolved = false;
|
|
544
544
|
const { session, wireUpConnection } = createSessionCore(identity, clock, null, null, (advert) => {
|
|
545
|
-
if (peerDeviceIdResolved)
|
|
546
|
-
|
|
547
|
-
|
|
545
|
+
if (!peerDeviceIdResolved) {
|
|
546
|
+
peerDeviceIdResolved = true;
|
|
547
|
+
resolvePeerDeviceId?.(advert.device);
|
|
548
|
+
}
|
|
549
|
+
options.onPeerAdvert?.(advert);
|
|
548
550
|
}, options.addresses, options.onFrame, options.onSessionEnd);
|
|
549
551
|
await wireUpConnection(connection, options.label ?? "accepted", localDomains);
|
|
550
552
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wire-mesh-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.55.0",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"cbor2": "2.3.0",
|
|
6
6
|
"cddl.js": "1.0.1",
|
|
@@ -91,6 +91,10 @@
|
|
|
91
91
|
"import": "./dist/domain/erasure-coding.mjs",
|
|
92
92
|
"require": "./dist/domain/erasure-coding.cjs"
|
|
93
93
|
},
|
|
94
|
+
"./domain/gossip-expansion": {
|
|
95
|
+
"import": "./dist/domain/gossip-expansion.mjs",
|
|
96
|
+
"require": "./dist/domain/gossip-expansion.cjs"
|
|
97
|
+
},
|
|
94
98
|
"./domain/grant-candidates": {
|
|
95
99
|
"import": "./dist/domain/grant-candidates.mjs",
|
|
96
100
|
"require": "./dist/domain/grant-candidates.cjs"
|