wire-mesh-core 1.59.0 → 2.0.1

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 (93) hide show
  1. package/README.md +1 -0
  2. package/dist/adapters/frame-codec.d.cts +1 -1
  3. package/dist/adapters/frame-codec.d.mts +1 -1
  4. package/dist/adapters/node-identity.d.cts +2 -2
  5. package/dist/adapters/node-identity.d.mts +2 -2
  6. package/dist/adapters/tcp-transport.d.cts +1 -1
  7. package/dist/adapters/tcp-transport.d.mts +1 -1
  8. package/dist/adapters/threshold-identity.d.cts +2 -2
  9. package/dist/adapters/threshold-identity.d.mts +2 -2
  10. package/dist/adapters/threshold-wasm.d.cts +1 -1
  11. package/dist/adapters/threshold-wasm.d.mts +1 -1
  12. package/dist/adapters/tls-transport.d.cts +1 -1
  13. package/dist/adapters/tls-transport.d.mts +1 -1
  14. package/dist/domain/bulk.d.cts +2 -2
  15. package/dist/domain/bulk.d.mts +2 -2
  16. package/dist/domain/capability-grant.d.cts +3 -3
  17. package/dist/domain/capability-grant.d.mts +3 -3
  18. package/dist/domain/capability-request.d.cts +2 -2
  19. package/dist/domain/capability-request.d.mts +2 -2
  20. package/dist/domain/data-sync.d.cts +2 -2
  21. package/dist/domain/data-sync.d.mts +2 -2
  22. package/dist/domain/device-id.d.cts +1 -1
  23. package/dist/domain/device-id.d.mts +1 -1
  24. package/dist/domain/direct-manage-request.d.cts +2 -2
  25. package/dist/domain/direct-manage-request.d.mts +2 -2
  26. package/dist/domain/gossip-expansion.d.cts +1 -1
  27. package/dist/domain/gossip-expansion.d.mts +1 -1
  28. package/dist/domain/gossip-extensions.cjs +1 -1
  29. package/dist/domain/gossip-extensions.mjs +1 -1
  30. package/dist/domain/grant-candidates.d.cts +1 -1
  31. package/dist/domain/grant-candidates.d.mts +1 -1
  32. package/dist/domain/handshake.d.cts +1 -1
  33. package/dist/domain/handshake.d.mts +1 -1
  34. package/dist/domain/mesh-session.cjs +23 -14
  35. package/dist/domain/mesh-session.d.cts +3 -3
  36. package/dist/domain/mesh-session.d.mts +3 -3
  37. package/dist/domain/mesh-session.mjs +23 -14
  38. package/dist/domain/notice-board.d.cts +3 -3
  39. package/dist/domain/notice-board.d.mts +3 -3
  40. package/dist/domain/path-trace.d.cts +1 -1
  41. package/dist/domain/path-trace.d.mts +1 -1
  42. package/dist/domain/peer-advert.cjs +61 -0
  43. package/dist/domain/peer-advert.d.cts +45 -0
  44. package/dist/domain/peer-advert.d.mts +45 -0
  45. package/dist/domain/peer-advert.mjs +55 -0
  46. package/dist/domain/relay-hub.cjs +22 -2
  47. package/dist/domain/relay-hub.d.cts +6 -3
  48. package/dist/domain/relay-hub.d.mts +6 -3
  49. package/dist/domain/relay-hub.mjs +22 -2
  50. package/dist/domain/relay-use-gate.d.cts +2 -2
  51. package/dist/domain/relay-use-gate.d.mts +2 -2
  52. package/dist/domain/revocation-view.d.cts +2 -2
  53. package/dist/domain/revocation-view.d.mts +2 -2
  54. package/dist/domain/room-rekey.d.cts +3 -3
  55. package/dist/domain/room-rekey.d.mts +3 -3
  56. package/dist/domain/room-token-verification.d.cts +1 -1
  57. package/dist/domain/room-token-verification.d.mts +1 -1
  58. package/dist/domain/room.d.cts +4 -4
  59. package/dist/domain/room.d.mts +4 -4
  60. package/dist/domain/shard-manifest.d.cts +1 -1
  61. package/dist/domain/shard-manifest.d.mts +1 -1
  62. package/dist/domain/tokens.d.cts +1 -1
  63. package/dist/domain/tokens.d.mts +1 -1
  64. package/dist/domain/topology-snapshot.d.cts +1 -1
  65. package/dist/domain/topology-snapshot.d.mts +1 -1
  66. package/dist/domain/topology.cjs +1 -1
  67. package/dist/domain/topology.d.cts +1 -1
  68. package/dist/domain/topology.d.mts +1 -1
  69. package/dist/domain/topology.mjs +1 -1
  70. package/dist/domain/webrtc-signaling.d.cts +2 -2
  71. package/dist/domain/webrtc-signaling.d.mts +2 -2
  72. package/dist/generated/protocol.cjs +3 -1
  73. package/dist/generated/protocol.d.cts +1 -1
  74. package/dist/generated/protocol.d.mts +1 -1
  75. package/dist/generated/protocol.mjs +3 -1
  76. package/dist/{gossip-extensions-Cdy5mQhY.mjs → gossip-extensions-BNiI44sU.mjs} +5 -2
  77. package/dist/{gossip-extensions-Dr_T7hk_.cjs → gossip-extensions-DRVTHKnR.cjs} +5 -2
  78. package/dist/{identity-BRlM-Krs.d.cts → identity-DImeXZcq.d.cts} +1 -1
  79. package/dist/{identity-DiuayfEd.d.mts → identity-Dc4xmwp3.d.mts} +1 -1
  80. package/dist/ports/identity.d.cts +1 -1
  81. package/dist/ports/identity.d.mts +1 -1
  82. package/dist/ports/transport.d.cts +1 -1
  83. package/dist/ports/transport.d.mts +1 -1
  84. package/dist/{protocol-BnbpCk0Z.d.cts → protocol-Bi2fzBCc.d.cts} +20 -0
  85. package/dist/{protocol-BnbpCk0Z.d.mts → protocol-Bi2fzBCc.d.mts} +20 -0
  86. package/dist/{room-token-verification-NjaqYY4k.d.mts → room-token-verification-CDXkm_Tg.d.cts} +2 -2
  87. package/dist/{room-token-verification-D9ogJTO3.d.cts → room-token-verification-CnHNaA8J.d.mts} +2 -2
  88. package/dist/{tokens-DtjdYS_a.d.mts → tokens-0r9ipK1r.d.mts} +2 -2
  89. package/dist/{tokens-BL2BzOmN.d.cts → tokens-BDVxEvl2.d.cts} +2 -2
  90. package/dist/{transport-BH8kGWXt.d.mts → transport-Cq_odHy3.d.cts} +1 -1
  91. package/dist/{transport-Ca_ZyyZe.d.cts → transport-GcJ4LYVE.d.mts} +1 -1
  92. package/package.json +5 -1
  93. package/wasm-dist/wire_mesh_threshold_wasm_bg.wasm +0 -0
package/README.md CHANGED
@@ -13,6 +13,7 @@ The TypeScript implementation of wire-mesh's protocol, built ports/adapters: dom
13
13
 
14
14
  - **Handshake negotiation** (`src/domain/handshake.ts`) -- protocol-version and capability-domain negotiation between two peers, the mechanism agent-comms issue #31 is fixed by.
15
15
  - **Capability-token verification** (`src/domain/tokens.ts`) -- the full chain tokens.cddl documents: COSE_Sign1 signature verification, the self-certifying issuer-key check (`sha256(issuer-key.public-key) == issuer`), expiry/not-before, issuer-matched revocation (only a token's own issuer's signed revocation-entry counts, checked across every ancestor in the delegation chain, not just the leaf), and recursive delegation-chain narrowing across all three axes of authority: a delegated token's issuer must be its parent's bearer (the chain is unbroken), its expiry must not exceed its parent's, and its scope must narrow its parent's (identical kind, equal-or-descendant path when the parent carries one) with an identical capability verb (the verb grammar has no sub-verb relation, so a different verb is different authority, not narrower). Also exports `verifyRevocationEntry` for ingesting gossiped revocation-announce frames: each entry is itself a signed, self-certifying COSE_Sign1 over revocation-claims, verified before it may enter the revocation view.
16
+ - **Peer-advert verification** (`src/domain/peer-advert.ts`): the two checks transport.cddl states for a gossiped advert, applied by the relay hub before it registers or forwards one and by every session before one reaches its directory: the embedded identity-key self-certifies (`sha256(identity-key.public-key) == device`), and the signature verifies under that same key over the domain-separated canonical encoding of the advert with its signature removed, which covers the open extension tail as well. Deliberately not tokens.cddl's COSE Sig_structure: an advert's open tail lets an attacker craft one whose encoding also satisfies token-claims, so the prefixed construction keeps the two byte strings disjoint. Reaches a verdict for every input rather than throwing, since an advert's algorithm and key bytes are attacker-chosen.
16
17
 
17
18
  ## Deliberately deferred
18
19
 
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-Bi2fzBCc.cjs";
2
2
  //#region src/adapters/frame-codec.d.ts
3
3
  export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
4
4
  /** Wraps frame as a relay-data-frame's own opaque payload, stamping to-device when the caller knows which established pairing to address it to (wire-mesh#30) -- the outbound counterpart to tryDecodeFrame's own doc comment below, which describes the inbound side of the same relay-data envelope. Omitting toDevice leaves the frame unaddressed, which the receiving hub then routes via its own most-recently-established-pairing fallback. */
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-Bi2fzBCc.mjs";
2
2
  //#region src/adapters/frame-codec.d.ts
3
3
  export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
4
4
  /** Wraps frame as a relay-data-frame's own opaque payload, stamping to-device when the caller knows which established pairing to address it to (wire-mesh#30) -- the outbound counterpart to tryDecodeFrame's own doc comment below, which describes the inbound side of the same relay-data envelope. Omitting toDevice leaves the frame unaddressed, which the receiving hub then routes via its own most-recently-established-pairing fallback. */
@@ -1,5 +1,5 @@
1
- import { B as IdentityKey, D as DeviceId } from "../protocol-BnbpCk0Z.cjs";
2
- import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
1
+ import { B as IdentityKey, D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
2
+ import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
3
3
  import { webcrypto } from "node:crypto";
4
4
  //#region src/adapters/node-identity.d.ts
5
5
  export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
@@ -1,5 +1,5 @@
1
- import { B as IdentityKey, D as DeviceId } from "../protocol-BnbpCk0Z.mjs";
2
- import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
1
+ import { B as IdentityKey, D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
2
+ import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
3
3
  import { webcrypto } from "node:crypto";
4
4
  //#region src/adapters/node-identity.d.ts
5
5
  export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-Ca_ZyyZe.cjs";
1
+ import { r as Transport } from "../transport-Cq_odHy3.cjs";
2
2
  //#region src/adapters/tcp-transport.d.ts
3
3
  /** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
4
4
  export declare function createTcpTransport(): Transport;
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-BH8kGWXt.mjs";
1
+ import { r as Transport } from "../transport-GcJ4LYVE.mjs";
2
2
  //#region src/adapters/tcp-transport.d.ts
3
3
  /** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
4
4
  export declare function createTcpTransport(): Transport;
@@ -1,5 +1,5 @@
1
- import { D as DeviceId } from "../protocol-BnbpCk0Z.cjs";
2
- import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
1
+ import { D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
2
+ import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
3
3
  import { DeviceKeyed } from "./threshold-wasm.cjs";
4
4
  import { ThresholdSubject } from "../domain/threshold-subject.cjs";
5
5
  //#region src/adapters/threshold-identity.d.ts
@@ -1,5 +1,5 @@
1
- import { D as DeviceId } from "../protocol-BnbpCk0Z.mjs";
2
- import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
1
+ import { D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
2
+ import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
3
3
  import { DeviceKeyed } from "./threshold-wasm.mjs";
4
4
  import { ThresholdSubject } from "../domain/threshold-subject.mjs";
5
5
  //#region src/adapters/threshold-identity.d.ts
@@ -1,4 +1,4 @@
1
- import { D as DeviceId } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
2
2
  //#region src/adapters/threshold-wasm.d.ts
3
3
  /** One `(deviceId, bytes)` pair -- the wasm boundary's own encoding of a map keyed by participant, since wasm-bindgen has no built-in `Map<Uint8Array, Uint8Array>` marshalling. */
4
4
  export interface DeviceKeyed<T extends Uint8Array = Uint8Array<ArrayBuffer>> {
@@ -1,4 +1,4 @@
1
- import { D as DeviceId } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
2
2
  //#region src/adapters/threshold-wasm.d.ts
3
3
  /** One `(deviceId, bytes)` pair -- the wasm boundary's own encoding of a map keyed by participant, since wasm-bindgen has no built-in `Map<Uint8Array, Uint8Array>` marshalling. */
4
4
  export interface DeviceKeyed<T extends Uint8Array = Uint8Array<ArrayBuffer>> {
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-Ca_ZyyZe.cjs";
1
+ import { r as Transport } from "../transport-Cq_odHy3.cjs";
2
2
  //#region src/adapters/tls-transport.d.ts
3
3
  export interface TlsIdentity {
4
4
  certificatePem: string;
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-BH8kGWXt.mjs";
1
+ import { r as Transport } from "../transport-GcJ4LYVE.mjs";
2
2
  //#region src/adapters/tls-transport.d.ts
3
3
  export interface TlsIdentity {
4
4
  certificatePem: string;
@@ -1,6 +1,6 @@
1
- import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
2
2
  import { KeyValueStorage } from "../ports/storage.cjs";
3
- import { t as Connection } from "../transport-Ca_ZyyZe.cjs";
3
+ import { t as Connection } from "../transport-Cq_odHy3.cjs";
4
4
  import { IncomingManageRequest, MeshSession } from "./mesh-session.cjs";
5
5
  //#region src/domain/bulk.d.ts
6
6
  /** The two capabilities matching the direction each manage-command actually flows (spec/bulk.cddl): the sender proves write authority to open a transfer, the receiver proves read authority to ask for one to continue. */
@@ -1,6 +1,6 @@
1
- import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
2
2
  import { KeyValueStorage } from "../ports/storage.mjs";
3
- import { t as Connection } from "../transport-BH8kGWXt.mjs";
3
+ import { t as Connection } from "../transport-GcJ4LYVE.mjs";
4
4
  import { IncomingManageRequest, MeshSession } from "./mesh-session.mjs";
5
5
  //#region src/domain/bulk.d.ts
6
6
  /** The two capabilities matching the direction each manage-command actually flows (spec/bulk.cddl): the sender proves write authority to open a transfer, the receiver proves read authority to ask for one to continue. */
@@ -1,8 +1,8 @@
1
- import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.cjs";
2
- import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
2
+ import { t as IdentityPort } from "../identity-DImeXZcq.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-BL2BzOmN.cjs";
5
+ import { a as RevocationCheck } from "../tokens-BDVxEvl2.cjs";
6
6
  //#region src/domain/capability-grant.d.ts
7
7
  /**
8
8
  * Builds a capability-grant command per management.cddl. The outer `manage-command.verb` is the capability string itself, the identical convention capability-request.ts's own buildCapabilityRequestCommand already establishes -- a receiver's per-capability handler is how it knows which grant this push is even for. `params.verb` is the fixed "capability.grant" marker. No scope or invitee field: manage-request-frame's own top-level scope already carries the former, and the request's own destination already carries the latter -- naming either a second time inside params could only ever disagree with the fact it duplicates.
@@ -1,8 +1,8 @@
1
- import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.mjs";
2
- import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
2
+ import { t as IdentityPort } from "../identity-Dc4xmwp3.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-DtjdYS_a.mjs";
5
+ import { a as RevocationCheck } from "../tokens-0r9ipK1r.mjs";
6
6
  //#region src/domain/capability-grant.d.ts
7
7
  /**
8
8
  * Builds a capability-grant command per management.cddl. The outer `manage-command.verb` is the capability string itself, the identical convention capability-request.ts's own buildCapabilityRequestCommand already establishes -- a receiver's per-capability handler is how it knows which grant this push is even for. `params.verb` is the fixed "capability.grant" marker. No scope or invitee field: manage-request-frame's own top-level scope already carries the former, and the request's own destination already carries the latter -- naming either a second time inside params could only ever disagree with the fact it duplicates.
@@ -1,5 +1,5 @@
1
- import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-BnbpCk0Z.cjs";
2
- import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-Bi2fzBCc.cjs";
2
+ import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
4
  import { IncomingManageRequest, MeshSession } from "./mesh-session.cjs";
5
5
  //#region src/domain/capability-request.d.ts
@@ -1,5 +1,5 @@
1
- import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-BnbpCk0Z.mjs";
2
- import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-Bi2fzBCc.mjs";
2
+ import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
4
  import { IncomingManageRequest, MeshSession } from "./mesh-session.mjs";
5
5
  //#region src/domain/capability-request.d.ts
@@ -1,6 +1,6 @@
1
- import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.cjs";
2
2
  import { KeyValueStorage } from "../ports/storage.cjs";
3
- import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
3
+ import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
4
4
  //#region src/domain/data-sync.d.ts
5
5
  export interface DataSyncOptions {
6
6
  identity: IdentityPort;
@@ -1,6 +1,6 @@
1
- import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.mjs";
2
2
  import { KeyValueStorage } from "../ports/storage.mjs";
3
- import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
3
+ import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
4
4
  //#region src/domain/data-sync.d.ts
5
5
  export interface DataSyncOptions {
6
6
  identity: IdentityPort;
@@ -1,4 +1,4 @@
1
- import { D as DeviceId } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
2
2
  //#region src/domain/device-id.d.ts
3
3
  /** Lowercase, byte-exact hex for an arbitrary-length byte string -- the same encoding convention deviceIdToHex uses for the fixed-length device-id case, extracted so any other byte string needing a stable, displayable, map-keyable text form (e.g. a token-id, which tokens.cddl defines as an arbitrary-length bstr rather than a 32-byte device-id) can use the identical convention without going through a device-id-shaped function. */
4
4
  export declare function bytesToHex(bytes: Uint8Array): string;
@@ -1,4 +1,4 @@
1
- import { D as DeviceId } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
2
2
  //#region src/domain/device-id.d.ts
3
3
  /** Lowercase, byte-exact hex for an arbitrary-length byte string -- the same encoding convention deviceIdToHex uses for the fixed-length device-id case, extracted so any other byte string needing a stable, displayable, map-keyable text form (e.g. a token-id, which tokens.cddl defines as an arbitrary-length bstr rather than a 32-byte device-id) can use the identical convention without going through a device-id-shaped function. */
4
4
  export declare function bytesToHex(bytes: Uint8Array): string;
@@ -1,5 +1,5 @@
1
- import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.cjs";
2
- import { r as Transport, t as Connection } from "../transport-Ca_ZyyZe.cjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
2
+ import { r as Transport, t as Connection } from "../transport-Cq_odHy3.cjs";
3
3
  import { IncomingManageRequest, ManageOutcome } from "./mesh-session.cjs";
4
4
  //#region src/domain/direct-manage-request.d.ts
5
5
  /** Reads exactly one frame off a freshly-accepted, bare connection and, if it's a manage-request, returns an IncomingManageRequest ready to hand to the same application-level dispatch logic session.incomingManageRequests already feeds elsewhere -- no handshake or gossip is ever read or sent on this connection (wire-mesh#38: the manage-request/manage-response exchange has no dependency on handshake state at the dispatch layer, confirmed against mesh-session.ts's own applyManageRequest/applyFrame). respond() sends the manage-response directly and closes the connection, since a one-off request/response is this connection's entire purpose -- unlike a real MeshSession, there is nothing further to do with it afterwards. Resolves null, without closing the connection (that's the caller's call), for any other first frame or if the connection ends before one arrives: interpreting either case is a Transport.listen() caller's own business, e.g. peeking the first frame to route between this path and acceptMeshSession's own handshake path. */
@@ -1,5 +1,5 @@
1
- import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.mjs";
2
- import { r as Transport, t as Connection } from "../transport-BH8kGWXt.mjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
2
+ import { r as Transport, t as Connection } from "../transport-GcJ4LYVE.mjs";
3
3
  import { IncomingManageRequest, ManageOutcome } from "./mesh-session.mjs";
4
4
  //#region src/domain/direct-manage-request.d.ts
5
5
  /** Reads exactly one frame off a freshly-accepted, bare connection and, if it's a manage-request, returns an IncomingManageRequest ready to hand to the same application-level dispatch logic session.incomingManageRequests already feeds elsewhere -- no handshake or gossip is ever read or sent on this connection (wire-mesh#38: the manage-request/manage-response exchange has no dependency on handshake state at the dispatch layer, confirmed against mesh-session.ts's own applyManageRequest/applyFrame). respond() sends the manage-response directly and closes the connection, since a one-off request/response is this connection's entire purpose -- unlike a real MeshSession, there is nothing further to do with it afterwards. Resolves null, without closing the connection (that's the caller's call), for any other first frame or if the connection ends before one arrives: interpreting either case is a Transport.listen() caller's own business, e.g. peeking the first frame to route between this path and acceptMeshSession's own handshake path. */
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, et as PeerAdvert } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId, et as PeerAdvert } from "../protocol-Bi2fzBCc.cjs";
2
2
  import { MeshSession } from "./mesh-session.cjs";
3
3
  //#region src/domain/gossip-expansion.d.ts
4
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. */
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, et as PeerAdvert } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId, et as PeerAdvert } from "../protocol-Bi2fzBCc.mjs";
2
2
  import { MeshSession } from "./mesh-session.mjs";
3
3
  //#region src/domain/gossip-expansion.d.ts
4
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. */
@@ -1,4 +1,4 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_gossip_extensions = require("../gossip-extensions-Dr_T7hk_.cjs");
2
+ const require_gossip_extensions = require("../gossip-extensions-DRVTHKnR.cjs");
3
3
  exports.TOPOLOGY_PEERS_GOSSIP_KEY = require_gossip_extensions.TOPOLOGY_PEERS_GOSSIP_KEY;
4
4
  exports.validateGossipExtensions = require_gossip_extensions.validateGossipExtensions;
@@ -1,2 +1,2 @@
1
- import { n as validateGossipExtensions, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-Cdy5mQhY.mjs";
1
+ import { n as validateGossipExtensions, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-BNiI44sU.mjs";
2
2
  export { TOPOLOGY_PEERS_GOSSIP_KEY, validateGossipExtensions };
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, f as CapabilityScope } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId, f as CapabilityScope } from "../protocol-Bi2fzBCc.cjs";
2
2
  import { DirectoryEntry, MeshSession } from "./mesh-session.cjs";
3
3
  import { z } from "zod";
4
4
  //#region src/domain/grant-candidates.d.ts
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, f as CapabilityScope } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId, f as CapabilityScope } from "../protocol-Bi2fzBCc.mjs";
2
2
  import { DirectoryEntry, MeshSession } from "./mesh-session.mjs";
3
3
  import { z } from "zod";
4
4
  //#region src/domain/grant-candidates.d.ts
@@ -1,4 +1,4 @@
1
- import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-BnbpCk0Z.cjs";
1
+ import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-Bi2fzBCc.cjs";
2
2
  //#region src/domain/handshake.d.ts
3
3
  /** The highest protocol version this build of core understands. */
4
4
  export declare const SUPPORTED_PROTOCOL_VERSION: ProtocolVersion;
@@ -1,4 +1,4 @@
1
- import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-BnbpCk0Z.mjs";
1
+ import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-Bi2fzBCc.mjs";
2
2
  //#region src/domain/handshake.d.ts
3
3
  /** The highest protocol version this build of core understands. */
4
4
  export declare const SUPPORTED_PROTOCOL_VERSION: ProtocolVersion;
@@ -4,7 +4,8 @@ const require_domain_handshake = require("./handshake.cjs");
4
4
  const require_domain_async_queue = require("./async-queue.cjs");
5
5
  const require_domain_ping_round_trips = require("./ping-round-trips.cjs");
6
6
  const require_domain_topology_snapshot = require("./topology-snapshot.cjs");
7
- const require_gossip_extensions = require("../gossip-extensions-Dr_T7hk_.cjs");
7
+ const require_gossip_extensions = require("../gossip-extensions-DRVTHKnR.cjs");
8
+ const require_domain_peer_advert = require("./peer-advert.cjs");
8
9
  const require_adapters_frame_codec = require("../adapters/frame-codec.cjs");
9
10
  //#region src/domain/relay-pairing.ts
10
11
  function createRelayPairings() {
@@ -14,6 +15,9 @@ function createRelayPairings() {
14
15
  add: (device) => {
15
16
  established.set(require_domain_device_id.deviceIdToHex(device), device);
16
17
  },
18
+ remove: (device) => {
19
+ established.delete(require_domain_device_id.deviceIdToHex(device));
20
+ },
17
21
  list: () => [...established.values()]
18
22
  };
19
23
  }
@@ -135,7 +139,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
135
139
  }
136
140
  incomingQueue.push(incoming);
137
141
  }
138
- function applyFrame(frame) {
142
+ async function applyFrame(frame) {
139
143
  if (frame.type === "relay-data") {
140
144
  const inner = require_adapters_frame_codec.tryDecodeFrame(frame.payload);
141
145
  if (inner !== null && (inner.type === "manage-request" || inner.type === "manage-response")) {
@@ -159,6 +163,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
159
163
  });
160
164
  if (frame.type === "handshake") applyRemoteHandshake(frame);
161
165
  else if (frame.type === "gossip") for (const advert of frame.peers) {
166
+ if (!await require_domain_peer_advert.verifyPeerAdvert(identity, advert)) continue;
162
167
  directory.set(require_domain_device_id.deviceIdToHex(advert.device), {
163
168
  device: advert.device,
164
169
  advert
@@ -241,26 +246,27 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
241
246
  async function consume(link, address, localDomains) {
242
247
  for await (const frame of link.receive()) {
243
248
  if (feedCancelled) return;
244
- applyFrame(frame);
249
+ await applyFrame(frame);
245
250
  await onFrame?.(link, frame);
246
251
  emit();
247
252
  }
248
253
  onSessionEnd?.(link);
249
254
  if (state.status === "connected") handleDisconnect("node closed the connection", address, localDomains);
250
255
  }
251
- /** Builds this side's own self-advert: this node's own directly-reachable addresses (wire-mesh#38), or none for a caller with nothing to offer (a browser client, which cannot accept inbound connections) -- either is an honest advert, not a stopgap. extensions merge onto peer-advert's own open `* tstr => any` tail -- the mechanism sendGossipUpdate uses to keep a gossiped fact (presence status, an accept/refuse policy, or any future domain's own) live over the connection's lifetime. Extensions, CORE_VERSION_GOSSIP_KEY, and topology/peers are all spread before the mandatory fields (never after) so a caller-supplied key of the same name can never shadow them on the wire -- validateGossipExtensions already rejects every such collision loudly, but the field order is kept safe in its own right rather than relying solely on the guard staying in sync. topology/peers (wire-mesh#180) is recomputed fresh on every call, the same "always current, never cached" treatment snapshot-seconds already gets, since a session's own connection identity and relay pairings can change between one self-advert and the next. */
252
- function buildSelfAdvert(extensions) {
256
+ /** Builds this side's own self-advert and signs it with this node's own key (wire-mesh#225), which is what makes it usable by a receiver that learned of it through a hub or a gateway rather than directly from here. this node's own directly-reachable addresses (wire-mesh#38) are advertised, or none for a caller with nothing to offer (a browser client, which cannot accept inbound connections) -- either is an honest advert, not a stopgap. extensions merge onto peer-advert's own open `* tstr => any` tail -- the mechanism sendGossipUpdate uses to keep a gossiped fact (presence status, an accept/refuse policy, or any future domain's own) live over the connection's lifetime, and every such key is covered by the signature. Extensions, CORE_VERSION_GOSSIP_KEY, and topology/peers are all spread before the mandatory fields (never after) so a caller-supplied key of the same name can never shadow them on the wire -- validateGossipExtensions already rejects every such collision loudly, but the field order is kept safe in its own right rather than relying solely on the guard staying in sync. topology/peers (wire-mesh#180) is recomputed fresh on every call, the same "always current, never cached" treatment snapshot-seconds already gets, since a session's own connection identity and relay pairings can change between one self-advert and the next. */
257
+ async function buildSelfAdvert(extensions) {
253
258
  if (extensions !== void 0) require_gossip_extensions.validateGossipExtensions(extensions);
254
259
  return {
255
260
  type: "gossip",
256
- peers: [{
261
+ peers: [await require_domain_peer_advert.signPeerAdvert(identity, {
257
262
  ...extensions,
258
263
  [require_gossip_extensions.CORE_VERSION_GOSSIP_KEY]: require_gossip_extensions.OWN_VERSION,
259
264
  [require_gossip_extensions.TOPOLOGY_PEERS_GOSSIP_KEY]: topology.compute(),
260
265
  device: identity.deviceId,
261
266
  addresses: [...addresses],
262
- "snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND)
263
- }]
267
+ "snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND),
268
+ "identity-key": identity.identityKey
269
+ })]
264
270
  };
265
271
  }
266
272
  /** Everything a connection needs once it exists, regardless of whether it was dialled (createMeshSession's own doConnect, below) or handed over already established (acceptMeshSession): send this side's handshake and self-advert, arm the handshake timeout, and start consuming frames. The two entry points differ only in how link itself came to exist and what address means for it -- a real dial target for one, a caller-chosen label for the other, since the Connection/Transport ports expose no remote-address concept of their own for an accepted connection. */
@@ -279,7 +285,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
279
285
  });
280
286
  await connection.send(localHandshakeSent);
281
287
  emit();
282
- const selfAdvert = buildSelfAdvert();
288
+ const selfAdvert = await buildSelfAdvert();
283
289
  frameLog.push({
284
290
  direction: "sent",
285
291
  frame: selfAdvert
@@ -375,10 +381,13 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
375
381
  if (timeoutMs === void 0) return outcome;
376
382
  return Promise.race([outcome, new Promise((resolve) => {
377
383
  setTimeout(() => {
378
- if (pendingManageRequests.delete(requestId)) resolve({
379
- result: "error",
380
- code: "timeout"
381
- });
384
+ if (pendingManageRequests.delete(requestId)) {
385
+ if (targetDevice !== void 0) relayPairings.remove(targetDevice);
386
+ resolve({
387
+ result: "error",
388
+ code: "timeout"
389
+ });
390
+ }
382
391
  }, timeoutMs);
383
392
  })]);
384
393
  },
@@ -397,7 +406,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
397
406
  },
398
407
  async sendGossipUpdate(extensions) {
399
408
  requireConnectedLink();
400
- const frame = buildSelfAdvert(extensions);
409
+ const frame = await buildSelfAdvert(extensions);
401
410
  frameLog.push({
402
411
  direction: "sent",
403
412
  frame
@@ -1,7 +1,7 @@
1
- import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-BnbpCk0Z.cjs";
2
- import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
1
+ import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.cjs";
2
+ import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
- import { r as Transport, t as Connection } from "../transport-Ca_ZyyZe.cjs";
4
+ import { r as Transport, t as Connection } from "../transport-Cq_odHy3.cjs";
5
5
  //#region src/domain/mesh-session.d.ts
6
6
  /** How long to wait for the node's handshake before calling it unanswered. A relay-only node never sends one; that is a state to display, not an error. */
7
7
  export declare const HANDSHAKE_TIMEOUT_MS = 3000;
@@ -1,7 +1,7 @@
1
- import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-BnbpCk0Z.mjs";
2
- import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
1
+ import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.mjs";
2
+ import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
- import { r as Transport, t as Connection } from "../transport-BH8kGWXt.mjs";
4
+ import { r as Transport, t as Connection } from "../transport-GcJ4LYVE.mjs";
5
5
  //#region src/domain/mesh-session.d.ts
6
6
  /** How long to wait for the node's handshake before calling it unanswered. A relay-only node never sends one; that is a state to display, not an error. */
7
7
  export declare const HANDSHAKE_TIMEOUT_MS = 3000;
@@ -3,7 +3,8 @@ import { negotiate } from "./handshake.mjs";
3
3
  import { createAsyncQueue } from "./async-queue.mjs";
4
4
  import { createPingRoundTrips } from "./ping-round-trips.mjs";
5
5
  import { createTopologySnapshotTracker } from "./topology-snapshot.mjs";
6
- import { a as isVersionGetCommand, i as OWN_VERSION, n as validateGossipExtensions, o as versionGetOutcome, r as CORE_VERSION_GOSSIP_KEY, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-Cdy5mQhY.mjs";
6
+ import { a as isVersionGetCommand, i as OWN_VERSION, n as validateGossipExtensions, o as versionGetOutcome, r as CORE_VERSION_GOSSIP_KEY, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-BNiI44sU.mjs";
7
+ import { signPeerAdvert, verifyPeerAdvert } from "./peer-advert.mjs";
7
8
  import { tryDecodeFrame, wrapRelayData } from "../adapters/frame-codec.mjs";
8
9
  //#region src/domain/relay-pairing.ts
9
10
  function createRelayPairings() {
@@ -13,6 +14,9 @@ function createRelayPairings() {
13
14
  add: (device) => {
14
15
  established.set(deviceIdToHex(device), device);
15
16
  },
17
+ remove: (device) => {
18
+ established.delete(deviceIdToHex(device));
19
+ },
16
20
  list: () => [...established.values()]
17
21
  };
18
22
  }
@@ -134,7 +138,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
134
138
  }
135
139
  incomingQueue.push(incoming);
136
140
  }
137
- function applyFrame(frame) {
141
+ async function applyFrame(frame) {
138
142
  if (frame.type === "relay-data") {
139
143
  const inner = tryDecodeFrame(frame.payload);
140
144
  if (inner !== null && (inner.type === "manage-request" || inner.type === "manage-response")) {
@@ -158,6 +162,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
158
162
  });
159
163
  if (frame.type === "handshake") applyRemoteHandshake(frame);
160
164
  else if (frame.type === "gossip") for (const advert of frame.peers) {
165
+ if (!await verifyPeerAdvert(identity, advert)) continue;
161
166
  directory.set(deviceIdToHex(advert.device), {
162
167
  device: advert.device,
163
168
  advert
@@ -240,26 +245,27 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
240
245
  async function consume(link, address, localDomains) {
241
246
  for await (const frame of link.receive()) {
242
247
  if (feedCancelled) return;
243
- applyFrame(frame);
248
+ await applyFrame(frame);
244
249
  await onFrame?.(link, frame);
245
250
  emit();
246
251
  }
247
252
  onSessionEnd?.(link);
248
253
  if (state.status === "connected") handleDisconnect("node closed the connection", address, localDomains);
249
254
  }
250
- /** Builds this side's own self-advert: this node's own directly-reachable addresses (wire-mesh#38), or none for a caller with nothing to offer (a browser client, which cannot accept inbound connections) -- either is an honest advert, not a stopgap. extensions merge onto peer-advert's own open `* tstr => any` tail -- the mechanism sendGossipUpdate uses to keep a gossiped fact (presence status, an accept/refuse policy, or any future domain's own) live over the connection's lifetime. Extensions, CORE_VERSION_GOSSIP_KEY, and topology/peers are all spread before the mandatory fields (never after) so a caller-supplied key of the same name can never shadow them on the wire -- validateGossipExtensions already rejects every such collision loudly, but the field order is kept safe in its own right rather than relying solely on the guard staying in sync. topology/peers (wire-mesh#180) is recomputed fresh on every call, the same "always current, never cached" treatment snapshot-seconds already gets, since a session's own connection identity and relay pairings can change between one self-advert and the next. */
251
- function buildSelfAdvert(extensions) {
255
+ /** Builds this side's own self-advert and signs it with this node's own key (wire-mesh#225), which is what makes it usable by a receiver that learned of it through a hub or a gateway rather than directly from here. this node's own directly-reachable addresses (wire-mesh#38) are advertised, or none for a caller with nothing to offer (a browser client, which cannot accept inbound connections) -- either is an honest advert, not a stopgap. extensions merge onto peer-advert's own open `* tstr => any` tail -- the mechanism sendGossipUpdate uses to keep a gossiped fact (presence status, an accept/refuse policy, or any future domain's own) live over the connection's lifetime, and every such key is covered by the signature. Extensions, CORE_VERSION_GOSSIP_KEY, and topology/peers are all spread before the mandatory fields (never after) so a caller-supplied key of the same name can never shadow them on the wire -- validateGossipExtensions already rejects every such collision loudly, but the field order is kept safe in its own right rather than relying solely on the guard staying in sync. topology/peers (wire-mesh#180) is recomputed fresh on every call, the same "always current, never cached" treatment snapshot-seconds already gets, since a session's own connection identity and relay pairings can change between one self-advert and the next. */
256
+ async function buildSelfAdvert(extensions) {
252
257
  if (extensions !== void 0) validateGossipExtensions(extensions);
253
258
  return {
254
259
  type: "gossip",
255
- peers: [{
260
+ peers: [await signPeerAdvert(identity, {
256
261
  ...extensions,
257
262
  [CORE_VERSION_GOSSIP_KEY]: OWN_VERSION,
258
263
  [TOPOLOGY_PEERS_GOSSIP_KEY]: topology.compute(),
259
264
  device: identity.deviceId,
260
265
  addresses: [...addresses],
261
- "snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND)
262
- }]
266
+ "snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND),
267
+ "identity-key": identity.identityKey
268
+ })]
263
269
  };
264
270
  }
265
271
  /** Everything a connection needs once it exists, regardless of whether it was dialled (createMeshSession's own doConnect, below) or handed over already established (acceptMeshSession): send this side's handshake and self-advert, arm the handshake timeout, and start consuming frames. The two entry points differ only in how link itself came to exist and what address means for it -- a real dial target for one, a caller-chosen label for the other, since the Connection/Transport ports expose no remote-address concept of their own for an accepted connection. */
@@ -278,7 +284,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
278
284
  });
279
285
  await connection.send(localHandshakeSent);
280
286
  emit();
281
- const selfAdvert = buildSelfAdvert();
287
+ const selfAdvert = await buildSelfAdvert();
282
288
  frameLog.push({
283
289
  direction: "sent",
284
290
  frame: selfAdvert
@@ -374,10 +380,13 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
374
380
  if (timeoutMs === void 0) return outcome;
375
381
  return Promise.race([outcome, new Promise((resolve) => {
376
382
  setTimeout(() => {
377
- if (pendingManageRequests.delete(requestId)) resolve({
378
- result: "error",
379
- code: "timeout"
380
- });
383
+ if (pendingManageRequests.delete(requestId)) {
384
+ if (targetDevice !== void 0) relayPairings.remove(targetDevice);
385
+ resolve({
386
+ result: "error",
387
+ code: "timeout"
388
+ });
389
+ }
381
390
  }, timeoutMs);
382
391
  })]);
383
392
  },
@@ -396,7 +405,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
396
405
  },
397
406
  async sendGossipUpdate(extensions) {
398
407
  requireConnectedLink();
399
- const frame = buildSelfAdvert(extensions);
408
+ const frame = await buildSelfAdvert(extensions);
400
409
  frameLog.push({
401
410
  direction: "sent",
402
411
  frame
@@ -1,8 +1,8 @@
1
- import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
2
2
  import { KeyValueStorage } from "../ports/storage.cjs";
3
- import { t as IdentityPort } from "../identity-BRlM-Krs.cjs";
3
+ import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
4
4
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
5
- import { a as RevocationCheck } from "../tokens-BL2BzOmN.cjs";
5
+ import { a as RevocationCheck } from "../tokens-BDVxEvl2.cjs";
6
6
  import { RoomNoticeVerdictReason } from "./room.cjs";
7
7
  //#region src/domain/notice-board.d.ts
8
8
  /**
@@ -1,8 +1,8 @@
1
- import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
2
2
  import { KeyValueStorage } from "../ports/storage.mjs";
3
- import { t as IdentityPort } from "../identity-DiuayfEd.mjs";
3
+ import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
4
4
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
5
- import { a as RevocationCheck } from "../tokens-DtjdYS_a.mjs";
5
+ import { a as RevocationCheck } from "../tokens-0r9ipK1r.mjs";
6
6
  import { RoomNoticeVerdictReason } from "./room.mjs";
7
7
  //#region src/domain/notice-board.d.ts
8
8
  /**
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.cjs";
1
+ import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
2
2
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
3
3
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
4
4
  //#region src/domain/path-trace.d.ts
@@ -1,4 +1,4 @@
1
- import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-BnbpCk0Z.mjs";
1
+ import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
2
2
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
3
3
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
4
4
  //#region src/domain/path-trace.d.ts