@muhkoo/connect 0.10.4-alpha.0 → 0.10.5-alpha.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.
@@ -5057,7 +5057,7 @@ function base64UrlDecode(s) {
5057
5057
  * expect (and isn't serving a stale cached bundle). Keep this in sync with
5058
5058
  * `package.json` `version`.
5059
5059
  */
5060
- const VERSION = "0.10.4-alpha.0";
5060
+ const VERSION = "0.10.5-alpha.0";
5061
5061
 
5062
5062
  /**
5063
5063
  * `HttpClient` — the one place the unified {@link Client} talks to the
@@ -8739,10 +8739,13 @@ class PeerExchange {
8739
8739
  * to Space membership. The sender (`from`) is server-stamped and can't be
8740
8740
  * spoofed; the payload is opaque to the server.
8741
8741
  *
8742
- * Envelopes carry a `to` (a member id, or `"*"` for discovery) so the
8743
- * accelerator can optionally unicast peer-pair signaling instead of broadcasting
8744
- * (a small, backward-compatible `pub` enhancement); the client filters by `to`
8745
- * regardless.
8742
+ * Peers are identified by a unique **peer id** (per device/connection), carried
8743
+ * in the envelope's `from`/`to` — NOT by the server-stamped member id. This is
8744
+ * essential: one user's own devices share a member id, so the server's `from`
8745
+ * can't tell them apart (and would make each treat the others' signals as its
8746
+ * own echo). We therefore route entirely on the envelope peer ids and broadcast
8747
+ * to the whole Space, filtering client-side. The server `from` still guarantees
8748
+ * the sender is an authenticated Space member.
8746
8749
  */
8747
8750
  const P2P_SUBJECT = "__p2p__";
8748
8751
  class SpaceSignaler {
@@ -8754,11 +8757,11 @@ class SpaceSignaler {
8754
8757
  }
8755
8758
  /** Send a signal to one peer (or `"*"`). */
8756
8759
  send(to, kind, data) {
8757
- const env = { to, kind, data };
8758
- // Ask the server to unicast for a directed target; broadcast for "*".
8759
- // `to` also stays in the envelope so a broadcast-only server still works
8760
- // (the client filters by it).
8761
- this.space.sendEphemeral(P2P_SUBJECT, env, to !== "*" ? to : undefined);
8760
+ const env = { from: this.myId, to, kind, data };
8761
+ // Always broadcast to the Space: the server can't unicast to a specific
8762
+ // DEVICE (a user's devices share a member id), so we route client-side on
8763
+ // the envelope peer id. Signaling frames are tiny.
8764
+ this.space.sendEphemeral(P2P_SUBJECT, env);
8762
8765
  }
8763
8766
  /** Announce/withdraw P2P availability to all Space members. */
8764
8767
  broadcast(kind, data) {
@@ -8766,18 +8769,22 @@ class SpaceSignaler {
8766
8769
  }
8767
8770
  /**
8768
8771
  * Subscribe to inbound signals addressed to us (or broadcast). Skips our own
8769
- * echoes. Returns an unsubscribe function.
8772
+ * echoes. Returns an unsubscribe function. Routing is entirely by the envelope
8773
+ * peer id (`env.from`/`env.to`), so a user's own devices — which share the
8774
+ * server-stamped `e.from` — are correctly distinguished.
8770
8775
  */
8771
8776
  onSignal(cb) {
8772
8777
  return this.space.onEphemeral((e) => {
8773
- if (e.subject !== P2P_SUBJECT || e.from === this.myId)
8778
+ if (e.subject !== P2P_SUBJECT)
8774
8779
  return;
8775
8780
  const env = e.data;
8776
- if (!env || typeof env.kind !== "string")
8781
+ if (!env || typeof env.kind !== "string" || typeof env.from !== "string")
8777
8782
  return;
8783
+ if (env.from === this.myId)
8784
+ return; // our own device's echo
8778
8785
  if (env.to !== this.myId && env.to !== "*")
8779
8786
  return;
8780
- cb(e.from, env.kind, env.data);
8787
+ cb(env.from, env.kind, env.data);
8781
8788
  });
8782
8789
  }
8783
8790
  }
@@ -9554,6 +9561,10 @@ class SpaceNamespace {
9554
9561
  spaceCache;
9555
9562
  /** Spaces built this session, by id — used to route offline send replays. */
9556
9563
  openSpaces = new Map();
9564
+ /** Unique id for THIS device/session — the P2P peer identity. A user's own
9565
+ * devices share a member id, so the mesh MUST distinguish them by this or a
9566
+ * device treats its siblings' signals as its own echo and never connects. */
9567
+ deviceId = `peer-${globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2)}`;
9557
9568
  constructor(deps) {
9558
9569
  this.deps = deps;
9559
9570
  if (deps.offline?.enabled) {
@@ -9752,7 +9763,7 @@ class SpaceNamespace {
9752
9763
  if (this.deps.p2p?.enabled && isP2pCapable()) {
9753
9764
  space.attachPeerNetwork(new PeerNetwork({
9754
9765
  space,
9755
- myId: memberId,
9766
+ myId: this.deviceId, // per-device peer id, NOT the shared member id
9756
9767
  workerFactory: this.deps.p2p.workerFactory,
9757
9768
  iceServers: this.deps.p2p.iceServers,
9758
9769
  maxPeers: this.deps.p2p.maxPeers,