wire-mesh-core 1.56.0 → 1.58.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.
Files changed (99) hide show
  1. package/dist/adapters/frame-codec.d.cts +1 -1
  2. package/dist/adapters/frame-codec.d.mts +1 -1
  3. package/dist/adapters/node-identity.d.cts +2 -2
  4. package/dist/adapters/node-identity.d.mts +2 -2
  5. package/dist/adapters/tcp-transport.d.cts +1 -1
  6. package/dist/adapters/tcp-transport.d.mts +1 -1
  7. package/dist/adapters/threshold-identity.d.cts +2 -2
  8. package/dist/adapters/threshold-identity.d.mts +2 -2
  9. package/dist/adapters/threshold-wasm.d.cts +1 -1
  10. package/dist/adapters/threshold-wasm.d.mts +1 -1
  11. package/dist/adapters/tls-transport.d.cts +1 -1
  12. package/dist/adapters/tls-transport.d.mts +1 -1
  13. package/dist/domain/async-queue.cjs +30 -0
  14. package/dist/domain/async-queue.d.cts +10 -0
  15. package/dist/domain/async-queue.d.mts +10 -0
  16. package/dist/domain/async-queue.mjs +29 -0
  17. package/dist/domain/bulk.d.cts +2 -2
  18. package/dist/domain/bulk.d.mts +2 -2
  19. package/dist/domain/capability-grant.d.cts +3 -3
  20. package/dist/domain/capability-grant.d.mts +3 -3
  21. package/dist/domain/capability-request.d.cts +2 -2
  22. package/dist/domain/capability-request.d.mts +2 -2
  23. package/dist/domain/data-sync.d.cts +2 -2
  24. package/dist/domain/data-sync.d.mts +2 -2
  25. package/dist/domain/device-id.d.cts +1 -1
  26. package/dist/domain/device-id.d.mts +1 -1
  27. package/dist/domain/direct-manage-request.d.cts +2 -2
  28. package/dist/domain/direct-manage-request.d.mts +2 -2
  29. package/dist/domain/gossip-expansion.d.cts +1 -1
  30. package/dist/domain/gossip-expansion.d.mts +1 -1
  31. package/dist/domain/gossip-extensions.cjs +4 -0
  32. package/dist/domain/gossip-extensions.d.cts +6 -0
  33. package/dist/domain/gossip-extensions.d.mts +6 -0
  34. package/dist/domain/gossip-extensions.mjs +2 -0
  35. package/dist/domain/grant-candidates.d.cts +1 -1
  36. package/dist/domain/grant-candidates.d.mts +1 -1
  37. package/dist/domain/handshake.d.cts +1 -1
  38. package/dist/domain/handshake.d.mts +1 -1
  39. package/dist/domain/mesh-session.cjs +30 -148
  40. package/dist/domain/mesh-session.d.cts +5 -3
  41. package/dist/domain/mesh-session.d.mts +5 -3
  42. package/dist/domain/mesh-session.mjs +25 -141
  43. package/dist/domain/notice-board.d.cts +3 -3
  44. package/dist/domain/notice-board.d.mts +3 -3
  45. package/dist/domain/path-trace.cjs +58 -0
  46. package/dist/domain/path-trace.d.cts +44 -0
  47. package/dist/domain/path-trace.d.mts +44 -0
  48. package/dist/domain/path-trace.mjs +52 -0
  49. package/dist/domain/ping-round-trips.cjs +38 -0
  50. package/dist/domain/ping-round-trips.d.cts +13 -0
  51. package/dist/domain/ping-round-trips.d.mts +13 -0
  52. package/dist/domain/ping-round-trips.mjs +37 -0
  53. package/dist/domain/relay-hub.d.cts +2 -2
  54. package/dist/domain/relay-hub.d.mts +2 -2
  55. package/dist/domain/relay-use-gate.d.cts +2 -2
  56. package/dist/domain/relay-use-gate.d.mts +2 -2
  57. package/dist/domain/revocation-view.d.cts +2 -2
  58. package/dist/domain/revocation-view.d.mts +2 -2
  59. package/dist/domain/room-rekey.d.cts +3 -3
  60. package/dist/domain/room-rekey.d.mts +3 -3
  61. package/dist/domain/room-token-verification.d.cts +1 -1
  62. package/dist/domain/room-token-verification.d.mts +1 -1
  63. package/dist/domain/room.d.cts +4 -4
  64. package/dist/domain/room.d.mts +4 -4
  65. package/dist/domain/shard-manifest.d.cts +1 -1
  66. package/dist/domain/shard-manifest.d.mts +1 -1
  67. package/dist/domain/tokens.d.cts +1 -1
  68. package/dist/domain/tokens.d.mts +1 -1
  69. package/dist/domain/topology-snapshot.cjs +39 -0
  70. package/dist/domain/topology-snapshot.d.cts +31 -0
  71. package/dist/domain/topology-snapshot.d.mts +31 -0
  72. package/dist/domain/topology-snapshot.mjs +37 -0
  73. package/dist/domain/topology.cjs +87 -0
  74. package/dist/domain/topology.d.cts +38 -0
  75. package/dist/domain/topology.d.mts +38 -0
  76. package/dist/domain/topology.mjs +81 -0
  77. package/dist/domain/webrtc-signaling.d.cts +2 -2
  78. package/dist/domain/webrtc-signaling.d.mts +2 -2
  79. package/dist/generated/protocol.cjs +11 -0
  80. package/dist/generated/protocol.d.cts +2 -2
  81. package/dist/generated/protocol.d.mts +2 -2
  82. package/dist/generated/protocol.mjs +10 -1
  83. package/dist/gossip-extensions-Cdy5mQhY.mjs +41 -0
  84. package/dist/gossip-extensions-Dr_T7hk_.cjs +78 -0
  85. package/dist/{identity-Br6e0Rx5.d.mts → identity-BRlM-Krs.d.cts} +1 -1
  86. package/dist/{identity-pOt5KxJB.d.cts → identity-DiuayfEd.d.mts} +1 -1
  87. package/dist/ports/identity.d.cts +1 -1
  88. package/dist/ports/identity.d.mts +1 -1
  89. package/dist/ports/transport.d.cts +1 -1
  90. package/dist/ports/transport.d.mts +1 -1
  91. package/dist/{protocol-D2Ue2nd2.d.cts → protocol-BnbpCk0Z.d.cts} +23 -1
  92. package/dist/{protocol-D2Ue2nd2.d.mts → protocol-BnbpCk0Z.d.mts} +23 -1
  93. package/dist/{room-token-verification-CNXMjIQd.d.cts → room-token-verification-D9ogJTO3.d.cts} +2 -2
  94. package/dist/{room-token-verification-ZHgJhnsu.d.mts → room-token-verification-NjaqYY4k.d.mts} +2 -2
  95. package/dist/{tokens-BtczHfrc.d.cts → tokens-BL2BzOmN.d.cts} +2 -2
  96. package/dist/{tokens-Hnq9oURj.d.mts → tokens-DtjdYS_a.d.mts} +2 -2
  97. package/dist/{transport-C5wU0UtA.d.mts → transport-BH8kGWXt.d.mts} +1 -1
  98. package/dist/{transport-fUY3alfO.d.cts → transport-Ca_ZyyZe.d.cts} +1 -1
  99. package/package.json +25 -1
@@ -0,0 +1,58 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_generated_protocol = require("../generated/protocol.cjs");
3
+ //#region src/domain/path-trace.ts
4
+ /** path:trace names no real capability -- see spec/management.cddl's own comment -- and is registered purely as a namespaced wire identifier so manage-command.verb's own capability-verb grammar has something syntactically valid to carry (registry/core-capabilities.md). */
5
+ const PATH_TRACE_VERB = "path:trace";
6
+ /** No path: there is no filesystem subtree or other resource involved, only the node itself -- carried on the wire but never actually checked, since path.trace verifies no scope or token at all. */
7
+ const PATH_TRACE_SCOPE = { kind: "node" };
8
+ function isPathTrace(params) {
9
+ return typeof params === "object" && "verb" in params && params.verb === "path.trace";
10
+ }
11
+ function buildPathTraceCommand() {
12
+ return {
13
+ verb: PATH_TRACE_VERB,
14
+ params: { verb: "path.trace" }
15
+ };
16
+ }
17
+ /** Builds this side's own answer to an incoming path.trace. relayed is exactly whether THIS request arrived wrapped in relay-data -- incoming.fromDevice is only ever set for a relay-wrapped request (see mesh-session.ts's own applyManageRequest) -- and hubAddress, when given and relayed, is the address this receiver itself dialled to reach the hub the request arrived over, ordinarily read straight off this session's own ConnectionState.address (already tracked by every caller consuming session.events, no new bookkeeping needed). Omitted entirely when not relayed, or when the caller has no address to report (e.g. an accepted, never-dialled connection). */
18
+ function buildPathTraceResponse(incoming, hubAddress) {
19
+ const relayed = incoming.fromDevice !== void 0;
20
+ return {
21
+ result: "ok",
22
+ relayed,
23
+ ...relayed && hubAddress !== void 0 ? { "hub-address": hubAddress } : {}
24
+ };
25
+ }
26
+ /** Sends path.trace and measures the real end-to-end round trip, combining it with this side's own local relay knowledge (no wire round trip needed for that half -- see PathTraceLocal's own doc comment) and the receiver's reported relay knowledge parsed out of a successful outcome's own extension fields. Throws if the outcome resolves ok but its extension fields don't match path-trace-ok's own shape (relayed missing or the wrong type) -- a receiver that answers path.trace at all is expected to answer it correctly; this is a protocol violation to surface loudly, not a case to silently treat as "remote unknown". */
27
+ async function tracePath(options) {
28
+ const startedAt = options.clock.now();
29
+ const outcome = await options.session.sendManageRequest(buildPathTraceCommand(), options.scope ?? PATH_TRACE_SCOPE, options.targetDevice, options.token, options.timeoutMs);
30
+ const rttMs = options.clock.now() - startedAt;
31
+ const local = {
32
+ relayed: options.targetDevice !== void 0,
33
+ ...options.targetDevice !== void 0 && options.localHubAddress !== void 0 ? { hubAddress: options.localHubAddress } : {}
34
+ };
35
+ if (outcome.result === "error") return {
36
+ rttMs,
37
+ local,
38
+ outcome
39
+ };
40
+ const parsed = require_generated_protocol.pathTraceOkSchema.safeParse(outcome);
41
+ if (!parsed.success) throw new Error(`path.trace response did not match path-trace-ok's own shape: ${parsed.error.message}`);
42
+ return {
43
+ rttMs,
44
+ local,
45
+ remote: {
46
+ relayed: parsed.data.relayed,
47
+ ...parsed.data["hub-address"] !== void 0 ? { hubAddress: parsed.data["hub-address"] } : {}
48
+ },
49
+ outcome
50
+ };
51
+ }
52
+ //#endregion
53
+ exports.PATH_TRACE_SCOPE = PATH_TRACE_SCOPE;
54
+ exports.PATH_TRACE_VERB = PATH_TRACE_VERB;
55
+ exports.buildPathTraceCommand = buildPathTraceCommand;
56
+ exports.buildPathTraceResponse = buildPathTraceResponse;
57
+ exports.isPathTrace = isPathTrace;
58
+ exports.tracePath = tracePath;
@@ -0,0 +1,44 @@
1
+ import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.cjs";
2
+ import { t as Clock } from "../clock-DiSx-WKM.cjs";
3
+ import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
4
+ //#region src/domain/path-trace.d.ts
5
+ /** path:trace names no real capability -- see spec/management.cddl's own comment -- and is registered purely as a namespaced wire identifier so manage-command.verb's own capability-verb grammar has something syntactically valid to carry (registry/core-capabilities.md). */
6
+ export declare const PATH_TRACE_VERB = "path:trace";
7
+ /** No path: there is no filesystem subtree or other resource involved, only the node itself -- carried on the wire but never actually checked, since path.trace verifies no scope or token at all. */
8
+ export declare const PATH_TRACE_SCOPE: CapabilityScope;
9
+ export declare function isPathTrace(params: ManageCommandParams): params is PathTrace;
10
+ export declare function buildPathTraceCommand(): ManageCommand;
11
+ /** Builds this side's own answer to an incoming path.trace. relayed is exactly whether THIS request arrived wrapped in relay-data -- incoming.fromDevice is only ever set for a relay-wrapped request (see mesh-session.ts's own applyManageRequest) -- and hubAddress, when given and relayed, is the address this receiver itself dialled to reach the hub the request arrived over, ordinarily read straight off this session's own ConnectionState.address (already tracked by every caller consuming session.events, no new bookkeeping needed). Omitted entirely when not relayed, or when the caller has no address to report (e.g. an accepted, never-dialled connection). */
12
+ export declare function buildPathTraceResponse(incoming: Readonly<IncomingManageRequest>, hubAddress?: string): ManageOutcome;
13
+ export interface PathTraceLocal {
14
+ /** Whether reaching the traced device required an established relay pairing on this session -- true exactly when targetDevice was given, mirroring sendManageRequest's own targetDevice semantics (mesh-session.ts): a session holds at most one connection at a time, so relaying to ANY device on it means every relay pairing rides the identical hub connection. */
15
+ relayed: boolean;
16
+ /** The address this session dialled to reach that hub, when relayed and known -- this side's own equivalent of the remote's reported hub-address, needing no wire round trip since it is already local knowledge. */
17
+ hubAddress?: string;
18
+ }
19
+ export interface PathTraceRemote {
20
+ relayed: boolean;
21
+ hubAddress?: string;
22
+ }
23
+ export interface PathTraceResult {
24
+ /** Real end-to-end round-trip time in milliseconds: the elapsed time between sending path.trace and receiving its manage-response, exactly what the manage-request/manage-response round trip already gives for free. */
25
+ rttMs: number;
26
+ local: PathTraceLocal;
27
+ /** The receiver's own reported relayed/hub-address, parsed from path-trace-ok's own extension fields -- absent when the outcome was a manage-error rather than a malformed/missing pathTraceOkSchema match, since a malformed ok response is a protocol violation this function surfaces by throwing, not by silently reporting "unknown". */
28
+ remote?: PathTraceRemote;
29
+ /** The raw manage-response outcome, for a caller that wants to inspect a manage-error's own code/message directly rather than only knowing remote is absent. */
30
+ outcome: ManageOutcome;
31
+ }
32
+ export interface TracePathOptions {
33
+ session: Pick<MeshSession, "sendManageRequest">;
34
+ clock: Pick<Clock, "now">;
35
+ scope?: CapabilityScope;
36
+ targetDevice?: DeviceId;
37
+ token?: CapabilityToken;
38
+ timeoutMs?: number;
39
+ /** This session's own currently-dialled address, reported back as local.hubAddress when targetDevice makes this a relayed trace -- omit when unknown (e.g. this session never dialled anything itself). */
40
+ localHubAddress?: string;
41
+ }
42
+ /** Sends path.trace and measures the real end-to-end round trip, combining it with this side's own local relay knowledge (no wire round trip needed for that half -- see PathTraceLocal's own doc comment) and the receiver's reported relay knowledge parsed out of a successful outcome's own extension fields. Throws if the outcome resolves ok but its extension fields don't match path-trace-ok's own shape (relayed missing or the wrong type) -- a receiver that answers path.trace at all is expected to answer it correctly; this is a protocol violation to surface loudly, not a case to silently treat as "remote unknown". */
43
+ export declare function tracePath(options: Readonly<TracePathOptions>): Promise<PathTraceResult>;
44
+ //#endregion
@@ -0,0 +1,44 @@
1
+ import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.mjs";
2
+ import { t as Clock } from "../clock-DiSx-WKM.mjs";
3
+ import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
4
+ //#region src/domain/path-trace.d.ts
5
+ /** path:trace names no real capability -- see spec/management.cddl's own comment -- and is registered purely as a namespaced wire identifier so manage-command.verb's own capability-verb grammar has something syntactically valid to carry (registry/core-capabilities.md). */
6
+ export declare const PATH_TRACE_VERB = "path:trace";
7
+ /** No path: there is no filesystem subtree or other resource involved, only the node itself -- carried on the wire but never actually checked, since path.trace verifies no scope or token at all. */
8
+ export declare const PATH_TRACE_SCOPE: CapabilityScope;
9
+ export declare function isPathTrace(params: ManageCommandParams): params is PathTrace;
10
+ export declare function buildPathTraceCommand(): ManageCommand;
11
+ /** Builds this side's own answer to an incoming path.trace. relayed is exactly whether THIS request arrived wrapped in relay-data -- incoming.fromDevice is only ever set for a relay-wrapped request (see mesh-session.ts's own applyManageRequest) -- and hubAddress, when given and relayed, is the address this receiver itself dialled to reach the hub the request arrived over, ordinarily read straight off this session's own ConnectionState.address (already tracked by every caller consuming session.events, no new bookkeeping needed). Omitted entirely when not relayed, or when the caller has no address to report (e.g. an accepted, never-dialled connection). */
12
+ export declare function buildPathTraceResponse(incoming: Readonly<IncomingManageRequest>, hubAddress?: string): ManageOutcome;
13
+ export interface PathTraceLocal {
14
+ /** Whether reaching the traced device required an established relay pairing on this session -- true exactly when targetDevice was given, mirroring sendManageRequest's own targetDevice semantics (mesh-session.ts): a session holds at most one connection at a time, so relaying to ANY device on it means every relay pairing rides the identical hub connection. */
15
+ relayed: boolean;
16
+ /** The address this session dialled to reach that hub, when relayed and known -- this side's own equivalent of the remote's reported hub-address, needing no wire round trip since it is already local knowledge. */
17
+ hubAddress?: string;
18
+ }
19
+ export interface PathTraceRemote {
20
+ relayed: boolean;
21
+ hubAddress?: string;
22
+ }
23
+ export interface PathTraceResult {
24
+ /** Real end-to-end round-trip time in milliseconds: the elapsed time between sending path.trace and receiving its manage-response, exactly what the manage-request/manage-response round trip already gives for free. */
25
+ rttMs: number;
26
+ local: PathTraceLocal;
27
+ /** The receiver's own reported relayed/hub-address, parsed from path-trace-ok's own extension fields -- absent when the outcome was a manage-error rather than a malformed/missing pathTraceOkSchema match, since a malformed ok response is a protocol violation this function surfaces by throwing, not by silently reporting "unknown". */
28
+ remote?: PathTraceRemote;
29
+ /** The raw manage-response outcome, for a caller that wants to inspect a manage-error's own code/message directly rather than only knowing remote is absent. */
30
+ outcome: ManageOutcome;
31
+ }
32
+ export interface TracePathOptions {
33
+ session: Pick<MeshSession, "sendManageRequest">;
34
+ clock: Pick<Clock, "now">;
35
+ scope?: CapabilityScope;
36
+ targetDevice?: DeviceId;
37
+ token?: CapabilityToken;
38
+ timeoutMs?: number;
39
+ /** This session's own currently-dialled address, reported back as local.hubAddress when targetDevice makes this a relayed trace -- omit when unknown (e.g. this session never dialled anything itself). */
40
+ localHubAddress?: string;
41
+ }
42
+ /** Sends path.trace and measures the real end-to-end round trip, combining it with this side's own local relay knowledge (no wire round trip needed for that half -- see PathTraceLocal's own doc comment) and the receiver's reported relay knowledge parsed out of a successful outcome's own extension fields. Throws if the outcome resolves ok but its extension fields don't match path-trace-ok's own shape (relayed missing or the wrong type) -- a receiver that answers path.trace at all is expected to answer it correctly; this is a protocol violation to surface loudly, not a case to silently treat as "remote unknown". */
43
+ export declare function tracePath(options: Readonly<TracePathOptions>): Promise<PathTraceResult>;
44
+ //#endregion
@@ -0,0 +1,52 @@
1
+ import { pathTraceOkSchema } from "../generated/protocol.mjs";
2
+ //#region src/domain/path-trace.ts
3
+ /** path:trace names no real capability -- see spec/management.cddl's own comment -- and is registered purely as a namespaced wire identifier so manage-command.verb's own capability-verb grammar has something syntactically valid to carry (registry/core-capabilities.md). */
4
+ const PATH_TRACE_VERB = "path:trace";
5
+ /** No path: there is no filesystem subtree or other resource involved, only the node itself -- carried on the wire but never actually checked, since path.trace verifies no scope or token at all. */
6
+ const PATH_TRACE_SCOPE = { kind: "node" };
7
+ function isPathTrace(params) {
8
+ return typeof params === "object" && "verb" in params && params.verb === "path.trace";
9
+ }
10
+ function buildPathTraceCommand() {
11
+ return {
12
+ verb: PATH_TRACE_VERB,
13
+ params: { verb: "path.trace" }
14
+ };
15
+ }
16
+ /** Builds this side's own answer to an incoming path.trace. relayed is exactly whether THIS request arrived wrapped in relay-data -- incoming.fromDevice is only ever set for a relay-wrapped request (see mesh-session.ts's own applyManageRequest) -- and hubAddress, when given and relayed, is the address this receiver itself dialled to reach the hub the request arrived over, ordinarily read straight off this session's own ConnectionState.address (already tracked by every caller consuming session.events, no new bookkeeping needed). Omitted entirely when not relayed, or when the caller has no address to report (e.g. an accepted, never-dialled connection). */
17
+ function buildPathTraceResponse(incoming, hubAddress) {
18
+ const relayed = incoming.fromDevice !== void 0;
19
+ return {
20
+ result: "ok",
21
+ relayed,
22
+ ...relayed && hubAddress !== void 0 ? { "hub-address": hubAddress } : {}
23
+ };
24
+ }
25
+ /** Sends path.trace and measures the real end-to-end round trip, combining it with this side's own local relay knowledge (no wire round trip needed for that half -- see PathTraceLocal's own doc comment) and the receiver's reported relay knowledge parsed out of a successful outcome's own extension fields. Throws if the outcome resolves ok but its extension fields don't match path-trace-ok's own shape (relayed missing or the wrong type) -- a receiver that answers path.trace at all is expected to answer it correctly; this is a protocol violation to surface loudly, not a case to silently treat as "remote unknown". */
26
+ async function tracePath(options) {
27
+ const startedAt = options.clock.now();
28
+ const outcome = await options.session.sendManageRequest(buildPathTraceCommand(), options.scope ?? PATH_TRACE_SCOPE, options.targetDevice, options.token, options.timeoutMs);
29
+ const rttMs = options.clock.now() - startedAt;
30
+ const local = {
31
+ relayed: options.targetDevice !== void 0,
32
+ ...options.targetDevice !== void 0 && options.localHubAddress !== void 0 ? { hubAddress: options.localHubAddress } : {}
33
+ };
34
+ if (outcome.result === "error") return {
35
+ rttMs,
36
+ local,
37
+ outcome
38
+ };
39
+ const parsed = pathTraceOkSchema.safeParse(outcome);
40
+ if (!parsed.success) throw new Error(`path.trace response did not match path-trace-ok's own shape: ${parsed.error.message}`);
41
+ return {
42
+ rttMs,
43
+ local,
44
+ remote: {
45
+ relayed: parsed.data.relayed,
46
+ ...parsed.data["hub-address"] !== void 0 ? { hubAddress: parsed.data["hub-address"] } : {}
47
+ },
48
+ outcome
49
+ };
50
+ }
51
+ //#endregion
52
+ export { PATH_TRACE_SCOPE, PATH_TRACE_VERB, buildPathTraceCommand, buildPathTraceResponse, isPathTrace, tracePath };
@@ -0,0 +1,38 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/domain/ping-round-trips.ts
3
+ function createPingRoundTrips() {
4
+ const pending = [];
5
+ function cancel(sentAt) {
6
+ const index = pending.findIndex((entry) => entry.sentAt === sentAt);
7
+ if (index === -1) return false;
8
+ pending.splice(index, 1);
9
+ return true;
10
+ }
11
+ return {
12
+ resolveOldest(nowMs) {
13
+ const entry = pending.shift();
14
+ if (entry !== void 0) entry.resolve(nowMs - entry.sentAt);
15
+ },
16
+ rejectAll(reason) {
17
+ for (const entry of pending.splice(0)) entry.reject(new Error(reason));
18
+ },
19
+ async sendAndAwait(sentAt, sendPing, timeoutMs) {
20
+ const rtt = new Promise((resolve, reject) => {
21
+ pending.push({
22
+ sentAt,
23
+ resolve,
24
+ reject
25
+ });
26
+ });
27
+ await sendPing();
28
+ if (timeoutMs === void 0) return rtt;
29
+ return Promise.race([rtt, new Promise((_resolve, reject) => {
30
+ setTimeout(() => {
31
+ if (cancel(sentAt)) reject(/* @__PURE__ */ new Error("timed out waiting for pong"));
32
+ }, timeoutMs);
33
+ })]);
34
+ }
35
+ };
36
+ }
37
+ //#endregion
38
+ exports.createPingRoundTrips = createPingRoundTrips;
@@ -0,0 +1,13 @@
1
+ //#region src/domain/ping-round-trips.d.ts
2
+ export interface PingRoundTrips {
3
+ /** Resolves the oldest still-pending call with (nowMs - itsOwnSentAt) -- called once per pong-frame received. A no-op if nothing is pending (a stray pong with no outstanding call). */
4
+ resolveOldest: (nowMs: number) => void;
5
+ /** Rejects and clears every still-pending call -- called on disconnect. */
6
+ rejectAll: (reason: string) => void;
7
+ /**
8
+ * Registers sentAt, awaits sendPing (the caller's own "build the ping-frame, log it, transmit it, emit" sequence -- mesh-session.ts's own concern, not this module's), then resolves once resolveOldest/rejectAll settles the registration, racing an optional timeoutMs that cancels the registration and rejects instead of leaving it to resolve later against a pong that arrives after giving up.
9
+ */
10
+ sendAndAwait: (sentAt: number, sendPing: () => Promise<void>, timeoutMs?: number) => Promise<number>;
11
+ }
12
+ export declare function createPingRoundTrips(): PingRoundTrips;
13
+ //#endregion
@@ -0,0 +1,13 @@
1
+ //#region src/domain/ping-round-trips.d.ts
2
+ export interface PingRoundTrips {
3
+ /** Resolves the oldest still-pending call with (nowMs - itsOwnSentAt) -- called once per pong-frame received. A no-op if nothing is pending (a stray pong with no outstanding call). */
4
+ resolveOldest: (nowMs: number) => void;
5
+ /** Rejects and clears every still-pending call -- called on disconnect. */
6
+ rejectAll: (reason: string) => void;
7
+ /**
8
+ * Registers sentAt, awaits sendPing (the caller's own "build the ping-frame, log it, transmit it, emit" sequence -- mesh-session.ts's own concern, not this module's), then resolves once resolveOldest/rejectAll settles the registration, racing an optional timeoutMs that cancels the registration and rejects instead of leaving it to resolve later against a pong that arrives after giving up.
9
+ */
10
+ sendAndAwait: (sentAt: number, sendPing: () => Promise<void>, timeoutMs?: number) => Promise<number>;
11
+ }
12
+ export declare function createPingRoundTrips(): PingRoundTrips;
13
+ //#endregion
@@ -0,0 +1,37 @@
1
+ //#region src/domain/ping-round-trips.ts
2
+ function createPingRoundTrips() {
3
+ const pending = [];
4
+ function cancel(sentAt) {
5
+ const index = pending.findIndex((entry) => entry.sentAt === sentAt);
6
+ if (index === -1) return false;
7
+ pending.splice(index, 1);
8
+ return true;
9
+ }
10
+ return {
11
+ resolveOldest(nowMs) {
12
+ const entry = pending.shift();
13
+ if (entry !== void 0) entry.resolve(nowMs - entry.sentAt);
14
+ },
15
+ rejectAll(reason) {
16
+ for (const entry of pending.splice(0)) entry.reject(new Error(reason));
17
+ },
18
+ async sendAndAwait(sentAt, sendPing, timeoutMs) {
19
+ const rtt = new Promise((resolve, reject) => {
20
+ pending.push({
21
+ sentAt,
22
+ resolve,
23
+ reject
24
+ });
25
+ });
26
+ await sendPing();
27
+ if (timeoutMs === void 0) return rtt;
28
+ return Promise.race([rtt, new Promise((_resolve, reject) => {
29
+ setTimeout(() => {
30
+ if (cancel(sentAt)) reject(/* @__PURE__ */ new Error("timed out waiting for pong"));
31
+ }, timeoutMs);
32
+ })]);
33
+ }
34
+ };
35
+ }
36
+ //#endregion
37
+ export { createPingRoundTrips };
@@ -1,5 +1,5 @@
1
- import { N as Frame } from "../protocol-D2Ue2nd2.cjs";
2
- import { t as Connection } from "../transport-fUY3alfO.cjs";
1
+ import { N as Frame } from "../protocol-BnbpCk0Z.cjs";
2
+ import { t as Connection } from "../transport-Ca_ZyyZe.cjs";
3
3
  //#region src/domain/relay-hub.d.ts
4
4
  export interface RelayHub {
5
5
  /** Drives one accepted connection until it closes: registers gossip-advertised devices, re-broadcasts each gossip frame to every other connected client and replies to the gossiping connection with a catch-up frame of every other already-known device, answers relay-connect by pairing and notifying the target, forwards relay-data within established pairings, and replies to a bare ping with a bare pong (wire-mesh#181) so a client can time its own sender-to-hub leg independent of anything being relayed. Resolves when the connection's frame stream ends. Internally just registerConnection followed by a loop of onFrame calls and a final onDisconnect -- kept as its own method since a dedicated hub deployment (wire-mesh-node/cloudflare-hub) has nothing else driving the connection and wants the whole lifecycle in one call. */
@@ -1,5 +1,5 @@
1
- import { N as Frame } from "../protocol-D2Ue2nd2.mjs";
2
- import { t as Connection } from "../transport-C5wU0UtA.mjs";
1
+ import { N as Frame } from "../protocol-BnbpCk0Z.mjs";
2
+ import { t as Connection } from "../transport-BH8kGWXt.mjs";
3
3
  //#region src/domain/relay-hub.d.ts
4
4
  export interface RelayHub {
5
5
  /** Drives one accepted connection until it closes: registers gossip-advertised devices, re-broadcasts each gossip frame to every other connected client and replies to the gossiping connection with a catch-up frame of every other already-known device, answers relay-connect by pairing and notifying the target, forwards relay-data within established pairings, and replies to a bare ping with a bare pong (wire-mesh#181) so a client can time its own sender-to-hub leg independent of anything being relayed. Resolves when the connection's frame stream ends. Internally just registerConnection followed by a loop of onFrame calls and a final onDisconnect -- kept as its own method since a dedicated hub deployment (wire-mesh-node/cloudflare-hub) has nothing else driving the connection and wants the whole lifecycle in one call. */
@@ -1,5 +1,5 @@
1
- import { N as Frame } from "../protocol-D2Ue2nd2.cjs";
2
- import { t as Connection } from "../transport-fUY3alfO.cjs";
1
+ import { N as Frame } from "../protocol-BnbpCk0Z.cjs";
2
+ import { t as Connection } from "../transport-Ca_ZyyZe.cjs";
3
3
  //#region src/domain/relay-use-gate.d.ts
4
4
  export interface RelayUseAuthorizationTracker {
5
5
  /** True once authorize() has been called for this exact connection and revoke() has not been called since. */
@@ -1,5 +1,5 @@
1
- import { N as Frame } from "../protocol-D2Ue2nd2.mjs";
2
- import { t as Connection } from "../transport-C5wU0UtA.mjs";
1
+ import { N as Frame } from "../protocol-BnbpCk0Z.mjs";
2
+ import { t as Connection } from "../transport-BH8kGWXt.mjs";
3
3
  //#region src/domain/relay-use-gate.d.ts
4
4
  export interface RelayUseAuthorizationTracker {
5
5
  /** True once authorize() has been called for this exact connection and revoke() has not been called since. */
@@ -1,5 +1,5 @@
1
- import { bt as RevocationEntry } from "../protocol-D2Ue2nd2.cjs";
2
- import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-BtczHfrc.cjs";
1
+ import { bt as RevocationEntry } from "../protocol-BnbpCk0Z.cjs";
2
+ import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-BL2BzOmN.cjs";
3
3
  //#region src/domain/revocation-view.d.ts
4
4
  /**
5
5
  * An in-memory RevocationCheck fed by ingested revocation-announce frames. Keyed by token-id alone, per management.cddl's contract: a token-id can legitimately carry multiple recorded entries from different issuers (the token's own issuer, and/or any number of parties holding a delegated manage:revoke authorization over it) -- entriesFor returns every one of them unfiltered, since checking which actually apply (issuer-match, or a verified authorization) is verifyTokenChain's own obligation, not this store's.
@@ -1,5 +1,5 @@
1
- import { bt as RevocationEntry } from "../protocol-D2Ue2nd2.mjs";
2
- import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-Hnq9oURj.mjs";
1
+ import { bt as RevocationEntry } from "../protocol-BnbpCk0Z.mjs";
2
+ import { a as RevocationCheck, d as VerifyRevocationEntryOptions, o as RevocationEntryVerdict } from "../tokens-DtjdYS_a.mjs";
3
3
  //#region src/domain/revocation-view.d.ts
4
4
  /**
5
5
  * An in-memory RevocationCheck fed by ingested revocation-announce frames. Keyed by token-id alone, per management.cddl's contract: a token-id can legitimately carry multiple recorded entries from different issuers (the token's own issuer, and/or any number of parties holding a delegated manage:revoke authorization over it) -- entriesFor returns every one of them unfiltered, since checking which actually apply (issuer-match, or a verified authorization) is verifyTokenChain's own obligation, not this store's.
@@ -1,8 +1,8 @@
1
- import { D as DeviceId, V as ManageCommand, p as CapabilityToken } from "../protocol-D2Ue2nd2.cjs";
2
- import { t as IdentityPort } from "../identity-pOt5KxJB.cjs";
1
+ import { D as DeviceId, V as ManageCommand, p as CapabilityToken } from "../protocol-BnbpCk0Z.cjs";
2
+ import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
4
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
5
- import { a as RevocationCheck } from "../tokens-BtczHfrc.cjs";
5
+ import { a as RevocationCheck } from "../tokens-BL2BzOmN.cjs";
6
6
  //#region src/domain/room-rekey.d.ts
7
7
  /**
8
8
  * Builds a room.rekey command per room.cddl. The outer verb is room:member, the same "one resource, several inner verbs" pattern room.send/room.leave/room.members already establish -- not a new capability of its own.
@@ -1,8 +1,8 @@
1
- import { D as DeviceId, V as ManageCommand, p as CapabilityToken } from "../protocol-D2Ue2nd2.mjs";
2
- import { t as IdentityPort } from "../identity-Br6e0Rx5.mjs";
1
+ import { D as DeviceId, V as ManageCommand, p as CapabilityToken } from "../protocol-BnbpCk0Z.mjs";
2
+ import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
4
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
5
- import { a as RevocationCheck } from "../tokens-Hnq9oURj.mjs";
5
+ import { a as RevocationCheck } from "../tokens-DtjdYS_a.mjs";
6
6
  //#region src/domain/room-rekey.d.ts
7
7
  /**
8
8
  * Builds a room.rekey command per room.cddl. The outer verb is room:member, the same "one resource, several inner verbs" pattern room.send/room.leave/room.members already establish -- not a new capability of its own.
@@ -1,2 +1,2 @@
1
- import { a as verifyRoomToken, i as VerifyRoomTokenOptions, n as RoomTokenVerdict, r as RoomTokenVerdictReason, t as ROOM_MEMBER_CAPABILITY } from "../room-token-verification-CNXMjIQd.cjs";
1
+ import { a as verifyRoomToken, i as VerifyRoomTokenOptions, n as RoomTokenVerdict, r as RoomTokenVerdictReason, t as ROOM_MEMBER_CAPABILITY } from "../room-token-verification-D9ogJTO3.cjs";
2
2
  export { ROOM_MEMBER_CAPABILITY, RoomTokenVerdict, RoomTokenVerdictReason, VerifyRoomTokenOptions, verifyRoomToken };
@@ -1,2 +1,2 @@
1
- import { a as verifyRoomToken, i as VerifyRoomTokenOptions, n as RoomTokenVerdict, r as RoomTokenVerdictReason, t as ROOM_MEMBER_CAPABILITY } from "../room-token-verification-ZHgJhnsu.mjs";
1
+ import { a as verifyRoomToken, i as VerifyRoomTokenOptions, n as RoomTokenVerdict, r as RoomTokenVerdictReason, t as ROOM_MEMBER_CAPABILITY } from "../room-token-verification-NjaqYY4k.mjs";
2
2
  export { ROOM_MEMBER_CAPABILITY, RoomTokenVerdict, RoomTokenVerdictReason, VerifyRoomTokenOptions, verifyRoomToken };
@@ -1,8 +1,8 @@
1
- import { At as RoomPath, Ot as RoomNotice, kt as RoomNoticeClaims, p as CapabilityToken, q as MessageRef } from "../protocol-D2Ue2nd2.cjs";
2
- import { t as IdentityPort } from "../identity-pOt5KxJB.cjs";
1
+ import { At as RoomPath, Ot as RoomNotice, kt as RoomNoticeClaims, p as CapabilityToken, q as MessageRef } from "../protocol-BnbpCk0Z.cjs";
2
+ import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
- import { a as RevocationCheck } from "../tokens-BtczHfrc.cjs";
5
- import { r as RoomTokenVerdictReason } from "../room-token-verification-CNXMjIQd.cjs";
4
+ import { a as RevocationCheck } from "../tokens-BL2BzOmN.cjs";
5
+ import { r as RoomTokenVerdictReason } from "../room-token-verification-D9ogJTO3.cjs";
6
6
  //#region src/domain/room.d.ts
7
7
  export type RoomNoticeVerdictReason = "malformed" | "wrong_room" | "bad_signature" | "wrong_poster" | "content_expired" | "key_epoch_mismatch" | RoomTokenVerdictReason;
8
8
  export type RoomNoticeVerdict = {
@@ -1,8 +1,8 @@
1
- import { At as RoomPath, Ot as RoomNotice, kt as RoomNoticeClaims, p as CapabilityToken, q as MessageRef } from "../protocol-D2Ue2nd2.mjs";
2
- import { t as IdentityPort } from "../identity-Br6e0Rx5.mjs";
1
+ import { At as RoomPath, Ot as RoomNotice, kt as RoomNoticeClaims, p as CapabilityToken, q as MessageRef } from "../protocol-BnbpCk0Z.mjs";
2
+ import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
- import { a as RevocationCheck } from "../tokens-Hnq9oURj.mjs";
5
- import { r as RoomTokenVerdictReason } from "../room-token-verification-ZHgJhnsu.mjs";
4
+ import { a as RevocationCheck } from "../tokens-DtjdYS_a.mjs";
5
+ import { r as RoomTokenVerdictReason } from "../room-token-verification-NjaqYY4k.mjs";
6
6
  //#region src/domain/room.d.ts
7
7
  export type RoomNoticeVerdictReason = "malformed" | "wrong_room" | "bad_signature" | "wrong_poster" | "content_expired" | "key_epoch_mismatch" | RoomTokenVerdictReason;
8
8
  export type RoomNoticeVerdict = {
@@ -1,4 +1,4 @@
1
- import { D as DeviceId } from "../protocol-D2Ue2nd2.cjs";
1
+ import { D as DeviceId } from "../protocol-BnbpCk0Z.cjs";
2
2
  import { PresentedShard, ShardConfig } from "./erasure-coding.cjs";
3
3
  //#region src/domain/shard-manifest.d.ts
4
4
  /** The content-type a core/data entry carrying a shard manifest declares. */
@@ -1,4 +1,4 @@
1
- import { D as DeviceId } from "../protocol-D2Ue2nd2.mjs";
1
+ import { D as DeviceId } from "../protocol-BnbpCk0Z.mjs";
2
2
  import { PresentedShard, ShardConfig } from "./erasure-coding.mjs";
3
3
  //#region src/domain/shard-manifest.d.ts
4
4
  /** The content-type a core/data entry carrying a shard manifest declares. */
@@ -1,2 +1,2 @@
1
- import { _ as verifyRevocationEntry, a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyCapabilityToken, h as sig1ToBeSigned, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-BtczHfrc.cjs";
1
+ import { _ as verifyRevocationEntry, a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyCapabilityToken, h as sig1ToBeSigned, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-BL2BzOmN.cjs";
2
2
  export { MintCapabilityTokenOptions, MintRefusalReason, MintRevocationEntryOptions, MintVerdict, RevocationCheck, RevocationEntryVerdict, RevocationEntryVerdictReason, TokenVerdict, TokenVerdictReason, VerifyCapabilityTokenOptions, VerifyRevocationEntryOptions, canGrant, mintCapabilityToken, mintRevocationEntry, sig1ToBeSigned, verifyCapabilityToken, verifyRevocationEntry };
@@ -1,2 +1,2 @@
1
- import { _ as verifyRevocationEntry, a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyCapabilityToken, h as sig1ToBeSigned, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-Hnq9oURj.mjs";
1
+ import { _ as verifyRevocationEntry, a as RevocationCheck, c as TokenVerdict, d as VerifyRevocationEntryOptions, f as canGrant, g as verifyCapabilityToken, h as sig1ToBeSigned, i as MintVerdict, l as TokenVerdictReason, m as mintRevocationEntry, n as MintRefusalReason, o as RevocationEntryVerdict, p as mintCapabilityToken, r as MintRevocationEntryOptions, s as RevocationEntryVerdictReason, t as MintCapabilityTokenOptions, u as VerifyCapabilityTokenOptions } from "../tokens-DtjdYS_a.mjs";
2
2
  export { MintCapabilityTokenOptions, MintRefusalReason, MintRevocationEntryOptions, MintVerdict, RevocationCheck, RevocationEntryVerdict, RevocationEntryVerdictReason, TokenVerdict, TokenVerdictReason, VerifyCapabilityTokenOptions, VerifyRevocationEntryOptions, canGrant, mintCapabilityToken, mintRevocationEntry, sig1ToBeSigned, verifyCapabilityToken, verifyRevocationEntry };
@@ -0,0 +1,39 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/domain/topology-snapshot.ts
3
+ /** This session's own direct peer, when it can be honestly known -- see TopologyPeersInputs' own field comments for the priority order and why the gossip-derived fallback is gated on isAccepted. */
4
+ function directPeerDevice(inputs) {
5
+ if (inputs.authenticatedPeer !== void 0) return inputs.authenticatedPeer;
6
+ return inputs.isAccepted ? inputs.firstAdvertisedPeer ?? void 0 : void 0;
7
+ }
8
+ /** This session's own current topology self-advertisement: the peer this connection is directly with, when known, and every device this connection currently holds a relay pairing with, each named alongside the hub it is reached via -- always this same direct peer, since a session has exactly one connection and a relay pairing on it can only ever have been established through that connection's own remote end. `via` is omitted, not guessed, when the hub itself has no known device-id (an anonymous relay-only hub, e.g. wire-mesh-node/cloudflare-hub's bare RelayHub, never gossips a self-advert of its own to learn one from). */
9
+ function computeTopologyPeers(inputs) {
10
+ const direct = directPeerDevice(inputs);
11
+ return {
12
+ direct: direct !== void 0 ? [direct] : [],
13
+ relayed: inputs.relayedDevices.map((device) => ({
14
+ device,
15
+ ...direct !== void 0 ? { via: direct } : {}
16
+ }))
17
+ };
18
+ }
19
+ /** Bundles firstAdvertisedPeer's own mutable tracking together with computeTopologyPeers, so mesh-session.ts's createSessionCore holds one small object instead of a bare `let` plus a wrapper function around this module's own computeTopologyPeers -- sources' own closures are captured once here, so compute() itself takes no arguments at either of buildSelfAdvert/getTopologyPeers' own call sites. */
20
+ function createTopologySnapshotTracker(sources) {
21
+ let firstAdvertisedPeer = null;
22
+ return {
23
+ recordAdvert: (device) => {
24
+ firstAdvertisedPeer ??= device;
25
+ },
26
+ compute: () => {
27
+ const authenticatedPeer = sources.getAuthenticatedPeer();
28
+ return computeTopologyPeers({
29
+ ...authenticatedPeer !== void 0 ? { authenticatedPeer } : {},
30
+ firstAdvertisedPeer,
31
+ isAccepted: sources.isAccepted,
32
+ relayedDevices: sources.getRelayedDevices()
33
+ });
34
+ }
35
+ };
36
+ }
37
+ //#endregion
38
+ exports.computeTopologyPeers = computeTopologyPeers;
39
+ exports.createTopologySnapshotTracker = createTopologySnapshotTracker;
@@ -0,0 +1,31 @@
1
+ import { D as DeviceId, en as TopologyPeers } from "../protocol-BnbpCk0Z.cjs";
2
+ //#region src/domain/topology-snapshot.d.ts
3
+ export interface TopologyPeersInputs {
4
+ /** connection?.peerDeviceId -- the transport-authenticated direct peer, when the adapter gives one. Takes priority over firstAdvertisedPeer below. */
5
+ authenticatedPeer?: DeviceId;
6
+ /** The device named by this session's own first-ever peer-advert -- only trustworthy when isAccepted is true; see mesh-session.ts's own firstPeerDevice doc comment for why a dial-side session may end up naming a merely-relayed third device instead. */
7
+ firstAdvertisedPeer: DeviceId | null;
8
+ /** True for an accepted connection (dial === null in mesh-session.ts), where firstAdvertisedPeer is structurally sound; false for a dial-side session, where it is not. */
9
+ isAccepted: boolean;
10
+ /** Every device this session's own connection currently holds a relay pairing with (relayPairings.list()). */
11
+ relayedDevices: readonly DeviceId[];
12
+ }
13
+ /** This session's own current topology self-advertisement: the peer this connection is directly with, when known, and every device this connection currently holds a relay pairing with, each named alongside the hub it is reached via -- always this same direct peer, since a session has exactly one connection and a relay pairing on it can only ever have been established through that connection's own remote end. `via` is omitted, not guessed, when the hub itself has no known device-id (an anonymous relay-only hub, e.g. wire-mesh-node/cloudflare-hub's bare RelayHub, never gossips a self-advert of its own to learn one from). */
14
+ export declare function computeTopologyPeers(inputs: Readonly<TopologyPeersInputs>): TopologyPeers;
15
+ export interface TopologySnapshotSources {
16
+ /** Reads connection?.peerDeviceId live at compute() time -- a closure rather than a plain value, since the connection itself can be replaced (reconnect) between one self-advert and the next. */
17
+ getAuthenticatedPeer: () => DeviceId | undefined;
18
+ /** dial === null, fixed for a session's entire lifetime (never reconnects, so not read live). */
19
+ isAccepted: boolean;
20
+ /** Reads relayPairings.list() live at compute() time. */
21
+ getRelayedDevices: () => readonly DeviceId[];
22
+ }
23
+ export interface TopologySnapshotTracker {
24
+ /** Records one peer-advert entry as it is applied to a session's own directory -- see TopologyPeersInputs.firstAdvertisedPeer's own comment for what this is used for and why only the first call matters. */
25
+ recordAdvert: (device: DeviceId) => void;
26
+ /** Computes this session's own current TopologyPeers from the live connection/relayPairings state given at createTopologySnapshotTracker's own construction time. */
27
+ compute: () => TopologyPeers;
28
+ }
29
+ /** Bundles firstAdvertisedPeer's own mutable tracking together with computeTopologyPeers, so mesh-session.ts's createSessionCore holds one small object instead of a bare `let` plus a wrapper function around this module's own computeTopologyPeers -- sources' own closures are captured once here, so compute() itself takes no arguments at either of buildSelfAdvert/getTopologyPeers' own call sites. */
30
+ export declare function createTopologySnapshotTracker(sources: Readonly<TopologySnapshotSources>): TopologySnapshotTracker;
31
+ //#endregion
@@ -0,0 +1,31 @@
1
+ import { D as DeviceId, en as TopologyPeers } from "../protocol-BnbpCk0Z.mjs";
2
+ //#region src/domain/topology-snapshot.d.ts
3
+ export interface TopologyPeersInputs {
4
+ /** connection?.peerDeviceId -- the transport-authenticated direct peer, when the adapter gives one. Takes priority over firstAdvertisedPeer below. */
5
+ authenticatedPeer?: DeviceId;
6
+ /** The device named by this session's own first-ever peer-advert -- only trustworthy when isAccepted is true; see mesh-session.ts's own firstPeerDevice doc comment for why a dial-side session may end up naming a merely-relayed third device instead. */
7
+ firstAdvertisedPeer: DeviceId | null;
8
+ /** True for an accepted connection (dial === null in mesh-session.ts), where firstAdvertisedPeer is structurally sound; false for a dial-side session, where it is not. */
9
+ isAccepted: boolean;
10
+ /** Every device this session's own connection currently holds a relay pairing with (relayPairings.list()). */
11
+ relayedDevices: readonly DeviceId[];
12
+ }
13
+ /** This session's own current topology self-advertisement: the peer this connection is directly with, when known, and every device this connection currently holds a relay pairing with, each named alongside the hub it is reached via -- always this same direct peer, since a session has exactly one connection and a relay pairing on it can only ever have been established through that connection's own remote end. `via` is omitted, not guessed, when the hub itself has no known device-id (an anonymous relay-only hub, e.g. wire-mesh-node/cloudflare-hub's bare RelayHub, never gossips a self-advert of its own to learn one from). */
14
+ export declare function computeTopologyPeers(inputs: Readonly<TopologyPeersInputs>): TopologyPeers;
15
+ export interface TopologySnapshotSources {
16
+ /** Reads connection?.peerDeviceId live at compute() time -- a closure rather than a plain value, since the connection itself can be replaced (reconnect) between one self-advert and the next. */
17
+ getAuthenticatedPeer: () => DeviceId | undefined;
18
+ /** dial === null, fixed for a session's entire lifetime (never reconnects, so not read live). */
19
+ isAccepted: boolean;
20
+ /** Reads relayPairings.list() live at compute() time. */
21
+ getRelayedDevices: () => readonly DeviceId[];
22
+ }
23
+ export interface TopologySnapshotTracker {
24
+ /** Records one peer-advert entry as it is applied to a session's own directory -- see TopologyPeersInputs.firstAdvertisedPeer's own comment for what this is used for and why only the first call matters. */
25
+ recordAdvert: (device: DeviceId) => void;
26
+ /** Computes this session's own current TopologyPeers from the live connection/relayPairings state given at createTopologySnapshotTracker's own construction time. */
27
+ compute: () => TopologyPeers;
28
+ }
29
+ /** Bundles firstAdvertisedPeer's own mutable tracking together with computeTopologyPeers, so mesh-session.ts's createSessionCore holds one small object instead of a bare `let` plus a wrapper function around this module's own computeTopologyPeers -- sources' own closures are captured once here, so compute() itself takes no arguments at either of buildSelfAdvert/getTopologyPeers' own call sites. */
30
+ export declare function createTopologySnapshotTracker(sources: Readonly<TopologySnapshotSources>): TopologySnapshotTracker;
31
+ //#endregion
@@ -0,0 +1,37 @@
1
+ //#region src/domain/topology-snapshot.ts
2
+ /** This session's own direct peer, when it can be honestly known -- see TopologyPeersInputs' own field comments for the priority order and why the gossip-derived fallback is gated on isAccepted. */
3
+ function directPeerDevice(inputs) {
4
+ if (inputs.authenticatedPeer !== void 0) return inputs.authenticatedPeer;
5
+ return inputs.isAccepted ? inputs.firstAdvertisedPeer ?? void 0 : void 0;
6
+ }
7
+ /** This session's own current topology self-advertisement: the peer this connection is directly with, when known, and every device this connection currently holds a relay pairing with, each named alongside the hub it is reached via -- always this same direct peer, since a session has exactly one connection and a relay pairing on it can only ever have been established through that connection's own remote end. `via` is omitted, not guessed, when the hub itself has no known device-id (an anonymous relay-only hub, e.g. wire-mesh-node/cloudflare-hub's bare RelayHub, never gossips a self-advert of its own to learn one from). */
8
+ function computeTopologyPeers(inputs) {
9
+ const direct = directPeerDevice(inputs);
10
+ return {
11
+ direct: direct !== void 0 ? [direct] : [],
12
+ relayed: inputs.relayedDevices.map((device) => ({
13
+ device,
14
+ ...direct !== void 0 ? { via: direct } : {}
15
+ }))
16
+ };
17
+ }
18
+ /** Bundles firstAdvertisedPeer's own mutable tracking together with computeTopologyPeers, so mesh-session.ts's createSessionCore holds one small object instead of a bare `let` plus a wrapper function around this module's own computeTopologyPeers -- sources' own closures are captured once here, so compute() itself takes no arguments at either of buildSelfAdvert/getTopologyPeers' own call sites. */
19
+ function createTopologySnapshotTracker(sources) {
20
+ let firstAdvertisedPeer = null;
21
+ return {
22
+ recordAdvert: (device) => {
23
+ firstAdvertisedPeer ??= device;
24
+ },
25
+ compute: () => {
26
+ const authenticatedPeer = sources.getAuthenticatedPeer();
27
+ return computeTopologyPeers({
28
+ ...authenticatedPeer !== void 0 ? { authenticatedPeer } : {},
29
+ firstAdvertisedPeer,
30
+ isAccepted: sources.isAccepted,
31
+ relayedDevices: sources.getRelayedDevices()
32
+ });
33
+ }
34
+ };
35
+ }
36
+ //#endregion
37
+ export { computeTopologyPeers, createTopologySnapshotTracker };