wire-mesh-core 4.0.3 → 4.0.4

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 (67) hide show
  1. package/dist/adapters/byte-stream-connection.cjs +15 -4
  2. package/dist/adapters/byte-stream-connection.mjs +15 -4
  3. package/dist/adapters/memory-storage.d.cts +1 -1
  4. package/dist/adapters/memory-storage.d.mts +1 -1
  5. package/dist/adapters/node-fs-storage.cjs +4 -3
  6. package/dist/adapters/node-fs-storage.d.cts +1 -1
  7. package/dist/adapters/node-fs-storage.d.mts +1 -1
  8. package/dist/adapters/node-fs-storage.mjs +4 -3
  9. package/dist/adapters/system-clock.d.cts +1 -1
  10. package/dist/adapters/system-clock.d.mts +1 -1
  11. package/dist/clock-DhUPRfLh.d.cts +10 -0
  12. package/dist/clock-DhUPRfLh.d.mts +10 -0
  13. package/dist/domain/bulk.cjs +21 -12
  14. package/dist/domain/bulk.d.cts +1 -1
  15. package/dist/domain/bulk.d.mts +1 -1
  16. package/dist/domain/bulk.mjs +21 -12
  17. package/dist/domain/capability-grant.d.cts +1 -1
  18. package/dist/domain/capability-grant.d.mts +1 -1
  19. package/dist/domain/capability-request.d.cts +2 -2
  20. package/dist/domain/capability-request.d.mts +2 -2
  21. package/dist/domain/data-sync.cjs +22 -19
  22. package/dist/domain/data-sync.d.cts +1 -1
  23. package/dist/domain/data-sync.d.mts +1 -1
  24. package/dist/domain/data-sync.mjs +22 -19
  25. package/dist/domain/gossip-expansion.cjs +11 -5
  26. package/dist/domain/gossip-expansion.mjs +11 -5
  27. package/dist/domain/hub-mailbox.d.cts +1 -1
  28. package/dist/domain/hub-mailbox.d.mts +1 -1
  29. package/dist/domain/mesh-session.cjs +27 -14
  30. package/dist/domain/mesh-session.d.cts +1 -1
  31. package/dist/domain/mesh-session.d.mts +1 -1
  32. package/dist/domain/mesh-session.mjs +27 -14
  33. package/dist/domain/notice-board.cjs +4 -1
  34. package/dist/domain/notice-board.d.cts +2 -2
  35. package/dist/domain/notice-board.d.mts +2 -2
  36. package/dist/domain/notice-board.mjs +4 -1
  37. package/dist/domain/path-trace.d.cts +1 -1
  38. package/dist/domain/path-trace.d.mts +1 -1
  39. package/dist/domain/relay-hub.cjs +15 -10
  40. package/dist/domain/relay-hub.mjs +15 -10
  41. package/dist/domain/room-rekey.d.cts +1 -1
  42. package/dist/domain/room-rekey.d.mts +1 -1
  43. package/dist/domain/room.d.cts +1 -1
  44. package/dist/domain/room.d.mts +1 -1
  45. package/dist/domain/token-predicates.cjs +10 -10
  46. package/dist/domain/token-predicates.d.cts +1 -1
  47. package/dist/domain/token-predicates.d.mts +1 -1
  48. package/dist/domain/token-predicates.mjs +10 -10
  49. package/dist/domain/tokens.cjs +16 -4
  50. package/dist/domain/tokens.d.cts +2 -2
  51. package/dist/domain/tokens.d.mts +2 -2
  52. package/dist/domain/tokens.mjs +16 -4
  53. package/dist/ports/clock.d.cts +1 -1
  54. package/dist/ports/clock.d.mts +1 -1
  55. package/dist/ports/storage.d.cts +1 -1
  56. package/dist/ports/storage.d.mts +1 -1
  57. package/dist/sequential-CtQVlW8M.cjs +31 -0
  58. package/dist/sequential-D_W3THly.mjs +20 -0
  59. package/dist/storage-jbGFAYIV.d.cts +13 -0
  60. package/dist/storage-jbGFAYIV.d.mts +13 -0
  61. package/dist/{token-predicates-DqpG8VZZ.d.mts → token-predicates-CrieP1WI.d.mts} +1 -1
  62. package/dist/{token-predicates-D4NNPLnp.d.cts → token-predicates-lg4TtUxm.d.cts} +1 -1
  63. package/package.json +2 -2
  64. package/dist/clock-DiSx-WKM.d.cts +0 -7
  65. package/dist/clock-DiSx-WKM.d.mts +0 -7
  66. package/dist/storage-B403CRyu.d.cts +0 -10
  67. package/dist/storage-B403CRyu.d.mts +0 -10
@@ -131,7 +131,7 @@ function ivFor(counter) {
131
131
  function associatedData(sender, recipient, counter) {
132
132
  return concat(DATA_CONTEXT, sender, recipient, counterBytes(counter));
133
133
  }
134
- async function deriveDirectionKey(secret, salt, low, high, label) {
134
+ async function deriveDirectionKey({ secret, salt, low, high, label }) {
135
135
  const material = await crypto.subtle.importKey("raw", Uint8Array.from(secret), "HKDF", false, ["deriveKey"]);
136
136
  return crypto.subtle.deriveKey({
137
137
  name: "HKDF",
@@ -163,8 +163,20 @@ async function establishChannel(identity, pending, remote, peer) {
163
163
  const low = localIsLow ? identity.deviceId : peer.deviceId;
164
164
  const high = localIsLow ? peer.deviceId : identity.deviceId;
165
165
  const salt = concat(localIsLow ? pending.hello.nonce : remote.nonce, localIsLow ? remote.nonce : pending.hello.nonce);
166
- const lowToHigh = await deriveDirectionKey(secret, salt, low, high, LABEL_LOW_TO_HIGH);
167
- const highToLow = await deriveDirectionKey(secret, salt, low, high, LABEL_HIGH_TO_LOW);
166
+ const lowToHigh = await deriveDirectionKey({
167
+ secret,
168
+ salt,
169
+ low,
170
+ high,
171
+ label: LABEL_LOW_TO_HIGH
172
+ });
173
+ const highToLow = await deriveDirectionKey({
174
+ secret,
175
+ salt,
176
+ low,
177
+ high,
178
+ label: LABEL_HIGH_TO_LOW
179
+ });
168
180
  const sendKey = localIsLow ? lowToHigh : highToLow;
169
181
  const receiveKey = localIsLow ? highToLow : lowToHigh;
170
182
  let nextSendCounter = 0;
@@ -194,7 +206,7 @@ async function establishChannel(identity, pending, remote, peer) {
194
206
  } catch {
195
207
  return;
196
208
  }
197
- highestReceived = data.counter;
209
+ highestReceived = Math.max(highestReceived, data.counter);
198
210
  return require_adapters_frame_codec.tryDecodeFrame(plaintext) ?? void 0;
199
211
  }
200
212
  return {
@@ -479,16 +491,17 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
479
491
  frame
480
492
  });
481
493
  if (frame.type === "handshake") applyRemoteHandshake(frame);
482
- else if (frame.type === "gossip") for (const advert of frame.peers) {
483
- if (!await require_domain_peer_advert.verifyPeerAdvert(identity, advert)) continue;
484
- directory.set(require_domain_device_id.deviceIdToHex(advert.device), {
485
- device: advert.device,
486
- advert
487
- });
488
- topology.recordAdvert(advert.device);
489
- onPeerAdvert?.(advert);
490
- }
491
- else if (frame.type === "relay-inbound") relayPairings.add(frame["source-device"]);
494
+ else if (frame.type === "gossip") {
495
+ const verdicts = await Promise.all(frame.peers.map(async (advert) => require_domain_peer_advert.verifyPeerAdvert(identity, advert)));
496
+ for (const advert of frame.peers.filter((_, i) => verdicts[i] === true)) {
497
+ directory.set(require_domain_device_id.deviceIdToHex(advert.device), {
498
+ device: advert.device,
499
+ advert
500
+ });
501
+ topology.recordAdvert(advert.device);
502
+ onPeerAdvert?.(advert);
503
+ }
504
+ } else if (frame.type === "relay-inbound") relayPairings.add(frame["source-device"]);
492
505
  else if (frame.type === "manage-response") applyManageResponse(frame);
493
506
  else if (frame.type === "manage-request") applyManageRequest(frame);
494
507
  else if (frame.type === "pong") pingRoundTrips.resolveOldest(clock.now());
@@ -1,7 +1,7 @@
1
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, et as PeerAdvert, f as CapabilityScope, g as CoordinatorFrame, lt as ProtocolVersion, nn as TopologyPeers, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-DzmpxxUr.cjs";
2
2
  import { r as Transport, t as Connection } from "../transport-gDbSHO-r.cjs";
3
3
  import { t as IdentityPort } from "../identity-B6nhlSOT.cjs";
4
- import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
+ import { t as Clock } from "../clock-DhUPRfLh.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
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, et as PeerAdvert, f as CapabilityScope, g as CoordinatorFrame, lt as ProtocolVersion, nn as TopologyPeers, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-DzmpxxUr.mjs";
2
2
  import { r as Transport, t as Connection } from "../transport-bD3p_TO_.mjs";
3
3
  import { t as IdentityPort } from "../identity-EV-HHv_D.mjs";
4
- import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
+ import { t as Clock } from "../clock-DhUPRfLh.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;
@@ -130,7 +130,7 @@ function ivFor(counter) {
130
130
  function associatedData(sender, recipient, counter) {
131
131
  return concat(DATA_CONTEXT, sender, recipient, counterBytes(counter));
132
132
  }
133
- async function deriveDirectionKey(secret, salt, low, high, label) {
133
+ async function deriveDirectionKey({ secret, salt, low, high, label }) {
134
134
  const material = await crypto.subtle.importKey("raw", Uint8Array.from(secret), "HKDF", false, ["deriveKey"]);
135
135
  return crypto.subtle.deriveKey({
136
136
  name: "HKDF",
@@ -162,8 +162,20 @@ async function establishChannel(identity, pending, remote, peer) {
162
162
  const low = localIsLow ? identity.deviceId : peer.deviceId;
163
163
  const high = localIsLow ? peer.deviceId : identity.deviceId;
164
164
  const salt = concat(localIsLow ? pending.hello.nonce : remote.nonce, localIsLow ? remote.nonce : pending.hello.nonce);
165
- const lowToHigh = await deriveDirectionKey(secret, salt, low, high, LABEL_LOW_TO_HIGH);
166
- const highToLow = await deriveDirectionKey(secret, salt, low, high, LABEL_HIGH_TO_LOW);
165
+ const lowToHigh = await deriveDirectionKey({
166
+ secret,
167
+ salt,
168
+ low,
169
+ high,
170
+ label: LABEL_LOW_TO_HIGH
171
+ });
172
+ const highToLow = await deriveDirectionKey({
173
+ secret,
174
+ salt,
175
+ low,
176
+ high,
177
+ label: LABEL_HIGH_TO_LOW
178
+ });
167
179
  const sendKey = localIsLow ? lowToHigh : highToLow;
168
180
  const receiveKey = localIsLow ? highToLow : lowToHigh;
169
181
  let nextSendCounter = 0;
@@ -193,7 +205,7 @@ async function establishChannel(identity, pending, remote, peer) {
193
205
  } catch {
194
206
  return;
195
207
  }
196
- highestReceived = data.counter;
208
+ highestReceived = Math.max(highestReceived, data.counter);
197
209
  return tryDecodeFrame(plaintext) ?? void 0;
198
210
  }
199
211
  return {
@@ -478,16 +490,17 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
478
490
  frame
479
491
  });
480
492
  if (frame.type === "handshake") applyRemoteHandshake(frame);
481
- else if (frame.type === "gossip") for (const advert of frame.peers) {
482
- if (!await verifyPeerAdvert(identity, advert)) continue;
483
- directory.set(deviceIdToHex(advert.device), {
484
- device: advert.device,
485
- advert
486
- });
487
- topology.recordAdvert(advert.device);
488
- onPeerAdvert?.(advert);
489
- }
490
- else if (frame.type === "relay-inbound") relayPairings.add(frame["source-device"]);
493
+ else if (frame.type === "gossip") {
494
+ const verdicts = await Promise.all(frame.peers.map(async (advert) => verifyPeerAdvert(identity, advert)));
495
+ for (const advert of frame.peers.filter((_, i) => verdicts[i] === true)) {
496
+ directory.set(deviceIdToHex(advert.device), {
497
+ device: advert.device,
498
+ advert
499
+ });
500
+ topology.recordAdvert(advert.device);
501
+ onPeerAdvert?.(advert);
502
+ }
503
+ } else if (frame.type === "relay-inbound") relayPairings.add(frame["source-device"]);
491
504
  else if (frame.type === "manage-response") applyManageResponse(frame);
492
505
  else if (frame.type === "manage-request") applyManageRequest(frame);
493
506
  else if (frame.type === "pong") pingRoundTrips.resolveOldest(clock.now());
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_generated_protocol = require("../generated/protocol.cjs");
3
+ const require_sequential = require("../sequential-CtQVlW8M.cjs");
3
4
  const require_domain_data_sync = require("./data-sync.cjs");
4
5
  const require_domain_group_key = require("./group-key.cjs");
5
6
  const require_domain_room = require("./room.cjs");
@@ -59,7 +60,9 @@ function createNoticeBoard(options) {
59
60
  async function readLog(peer, room, dmRootPolicy) {
60
61
  const entries = await require_domain_data_sync.readEntries(storage, peer, 0);
61
62
  const out = [];
62
- for (const entry of entries) out.push(await readOne(entry, room, dmRootPolicy));
63
+ await require_sequential.eachInOrder(entries, async (entry) => {
64
+ out.push(await readOne(entry, room, dmRootPolicy));
65
+ });
63
66
  return out;
64
67
  }
65
68
  async function readOne(entry, room, dmRootPolicy) {
@@ -1,7 +1,7 @@
1
1
  import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-DzmpxxUr.cjs";
2
- import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
2
+ import { t as KeyValueStorage } from "../storage-jbGFAYIV.cjs";
3
3
  import { t as IdentityPort } from "../identity-B6nhlSOT.cjs";
4
- import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
+ import { t as Clock } from "../clock-DhUPRfLh.cjs";
5
5
  import { RevocationCheck } from "./tokens.cjs";
6
6
  import { RoomNoticeVerdictReason } from "./room.cjs";
7
7
  //#region src/domain/notice-board.d.ts
@@ -1,7 +1,7 @@
1
1
  import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-DzmpxxUr.mjs";
2
- import { t as KeyValueStorage } from "../storage-B403CRyu.mjs";
2
+ import { t as KeyValueStorage } from "../storage-jbGFAYIV.mjs";
3
3
  import { t as IdentityPort } from "../identity-EV-HHv_D.mjs";
4
- import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
+ import { t as Clock } from "../clock-DhUPRfLh.mjs";
5
5
  import { RevocationCheck } from "./tokens.mjs";
6
6
  import { RoomNoticeVerdictReason } from "./room.mjs";
7
7
  //#region src/domain/notice-board.d.ts
@@ -1,4 +1,5 @@
1
1
  import { roomNoticeSchema } from "../generated/protocol.mjs";
2
+ import { t as eachInOrder } from "../sequential-D_W3THly.mjs";
2
3
  import { appendOwnEntry, handleDataEntries, headSeqFor, readEntries } from "./data-sync.mjs";
3
4
  import { decryptNoticeContent, encryptNoticeContent, encryptedContentType, isEncryptedContentType, plaintextContentType } from "./group-key.mjs";
4
5
  import { createRoomNotice, verifyRoomNotice } from "./room.mjs";
@@ -58,7 +59,9 @@ function createNoticeBoard(options) {
58
59
  async function readLog(peer, room, dmRootPolicy) {
59
60
  const entries = await readEntries(storage, peer, 0);
60
61
  const out = [];
61
- for (const entry of entries) out.push(await readOne(entry, room, dmRootPolicy));
62
+ await eachInOrder(entries, async (entry) => {
63
+ out.push(await readOne(entry, room, dmRootPolicy));
64
+ });
62
65
  return out;
63
66
  }
64
67
  async function readOne(entry, room, dmRootPolicy) {
@@ -1,5 +1,5 @@
1
1
  import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-DzmpxxUr.cjs";
2
- import { t as Clock } from "../clock-DiSx-WKM.cjs";
2
+ import { t as Clock } from "../clock-DhUPRfLh.cjs";
3
3
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
4
4
  //#region src/domain/path-trace.d.ts
5
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). */
@@ -1,5 +1,5 @@
1
1
  import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-DzmpxxUr.mjs";
2
- import { t as Clock } from "../clock-DiSx-WKM.mjs";
2
+ import { t as Clock } from "../clock-DhUPRfLh.mjs";
3
3
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
4
4
  //#region src/domain/path-trace.d.ts
5
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). */
@@ -49,6 +49,9 @@ function createRelayHub(options) {
49
49
  mostRecentPairing.set(a, b);
50
50
  mostRecentPairing.set(b, a);
51
51
  }
52
+ function forgetPairingsWith(own, connection) {
53
+ for (const [key, paired] of own) if (paired === connection) own.delete(key);
54
+ }
52
55
  function forgetConnection(connection) {
53
56
  connections.delete(connection);
54
57
  for (const [key, registration] of devices) if (registration.connection === connection) devices.delete(key);
@@ -59,9 +62,7 @@ function createRelayHub(options) {
59
62
  if (own) {
60
63
  for (const peer of own.values()) {
61
64
  const peerOwn = pairings.get(peer);
62
- if (peerOwn) {
63
- for (const [key, paired] of peerOwn) if (paired === connection) peerOwn.delete(key);
64
- }
65
+ if (peerOwn) forgetPairingsWith(peerOwn, connection);
65
66
  if (mostRecentPairing.get(peer) === connection) mostRecentPairing.delete(peer);
66
67
  stateChanged(peer);
67
68
  }
@@ -142,8 +143,9 @@ function createRelayHub(options) {
142
143
  if (frame.type === "gossip") {
143
144
  const supplanted = /* @__PURE__ */ new Set();
144
145
  const accepted = [];
145
- for (const advert of frame.peers) {
146
- if (!await require_domain_peer_advert.verifyPeerAdvert(options.identity, advert)) continue;
146
+ const verified = await Promise.all(frame.peers.map(async (advert) => await require_domain_peer_advert.verifyPeerAdvert(options.identity, advert) ? advert : void 0));
147
+ for (const advert of verified) {
148
+ if (advert === void 0) continue;
147
149
  if (options.extensionPolicy !== void 0) {
148
150
  const verdict = require_domain_advert_extension_policy.checkAdvertExtensions(advert, options.extensionPolicy);
149
151
  if (!verdict.ok) {
@@ -175,12 +177,15 @@ function createRelayHub(options) {
175
177
  type: "gossip",
176
178
  peers: accepted
177
179
  };
178
- for (const other of connections) {
179
- if (other === connection) continue;
180
- try {
181
- await other.send(forwarded);
180
+ const forwardTo = async (remaining) => {
181
+ const next = remaining.next();
182
+ if (next.done === true) return;
183
+ if (next.value !== connection) try {
184
+ await next.value.send(forwarded);
182
185
  } catch {}
183
- }
186
+ await forwardTo(remaining);
187
+ };
188
+ await forwardTo(connections.values());
184
189
  const catchUp = [];
185
190
  for (const registration of devices.values()) if (registration.connection !== connection) catchUp.push(registration.advert);
186
191
  if (catchUp.length > 0 && connection !== uplink) try {
@@ -48,6 +48,9 @@ function createRelayHub(options) {
48
48
  mostRecentPairing.set(a, b);
49
49
  mostRecentPairing.set(b, a);
50
50
  }
51
+ function forgetPairingsWith(own, connection) {
52
+ for (const [key, paired] of own) if (paired === connection) own.delete(key);
53
+ }
51
54
  function forgetConnection(connection) {
52
55
  connections.delete(connection);
53
56
  for (const [key, registration] of devices) if (registration.connection === connection) devices.delete(key);
@@ -58,9 +61,7 @@ function createRelayHub(options) {
58
61
  if (own) {
59
62
  for (const peer of own.values()) {
60
63
  const peerOwn = pairings.get(peer);
61
- if (peerOwn) {
62
- for (const [key, paired] of peerOwn) if (paired === connection) peerOwn.delete(key);
63
- }
64
+ if (peerOwn) forgetPairingsWith(peerOwn, connection);
64
65
  if (mostRecentPairing.get(peer) === connection) mostRecentPairing.delete(peer);
65
66
  stateChanged(peer);
66
67
  }
@@ -141,8 +142,9 @@ function createRelayHub(options) {
141
142
  if (frame.type === "gossip") {
142
143
  const supplanted = /* @__PURE__ */ new Set();
143
144
  const accepted = [];
144
- for (const advert of frame.peers) {
145
- if (!await verifyPeerAdvert(options.identity, advert)) continue;
145
+ const verified = await Promise.all(frame.peers.map(async (advert) => await verifyPeerAdvert(options.identity, advert) ? advert : void 0));
146
+ for (const advert of verified) {
147
+ if (advert === void 0) continue;
146
148
  if (options.extensionPolicy !== void 0) {
147
149
  const verdict = checkAdvertExtensions(advert, options.extensionPolicy);
148
150
  if (!verdict.ok) {
@@ -174,12 +176,15 @@ function createRelayHub(options) {
174
176
  type: "gossip",
175
177
  peers: accepted
176
178
  };
177
- for (const other of connections) {
178
- if (other === connection) continue;
179
- try {
180
- await other.send(forwarded);
179
+ const forwardTo = async (remaining) => {
180
+ const next = remaining.next();
181
+ if (next.done === true) return;
182
+ if (next.value !== connection) try {
183
+ await next.value.send(forwarded);
181
184
  } catch {}
182
- }
185
+ await forwardTo(remaining);
186
+ };
187
+ await forwardTo(connections.values());
183
188
  const catchUp = [];
184
189
  for (const registration of devices.values()) if (registration.connection !== connection) catchUp.push(registration.advert);
185
190
  if (catchUp.length > 0 && connection !== uplink) try {
@@ -1,6 +1,6 @@
1
1
  import { D as DeviceId, V as ManageCommand, p as CapabilityToken } from "../protocol-DzmpxxUr.cjs";
2
2
  import { t as IdentityPort } from "../identity-B6nhlSOT.cjs";
3
- import { t as Clock } from "../clock-DiSx-WKM.cjs";
3
+ import { t as Clock } from "../clock-DhUPRfLh.cjs";
4
4
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
5
5
  import { RevocationCheck } from "./tokens.cjs";
6
6
  //#region src/domain/room-rekey.d.ts
@@ -1,6 +1,6 @@
1
1
  import { D as DeviceId, V as ManageCommand, p as CapabilityToken } from "../protocol-DzmpxxUr.mjs";
2
2
  import { t as IdentityPort } from "../identity-EV-HHv_D.mjs";
3
- import { t as Clock } from "../clock-DiSx-WKM.mjs";
3
+ import { t as Clock } from "../clock-DhUPRfLh.mjs";
4
4
  import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
5
5
  import { RevocationCheck } from "./tokens.mjs";
6
6
  //#region src/domain/room-rekey.d.ts
@@ -1,6 +1,6 @@
1
1
  import { At as RoomPath, Ot as RoomNotice, kt as RoomNoticeClaims, p as CapabilityToken, q as MessageRef } from "../protocol-DzmpxxUr.cjs";
2
2
  import { t as IdentityPort } from "../identity-B6nhlSOT.cjs";
3
- import { t as Clock } from "../clock-DiSx-WKM.cjs";
3
+ import { t as Clock } from "../clock-DhUPRfLh.cjs";
4
4
  import { RevocationCheck } from "./tokens.cjs";
5
5
  import { r as RoomTokenVerdictReason } from "../room-token-verification-Dh7SGJfK.cjs";
6
6
  //#region src/domain/room.d.ts
@@ -1,6 +1,6 @@
1
1
  import { At as RoomPath, Ot as RoomNotice, kt as RoomNoticeClaims, p as CapabilityToken, q as MessageRef } from "../protocol-DzmpxxUr.mjs";
2
2
  import { t as IdentityPort } from "../identity-EV-HHv_D.mjs";
3
- import { t as Clock } from "../clock-DiSx-WKM.mjs";
3
+ import { t as Clock } from "../clock-DhUPRfLh.mjs";
4
4
  import { RevocationCheck } from "./tokens.mjs";
5
5
  import { r as RoomTokenVerdictReason } from "../room-token-verification-Hb1LkpFh.mjs";
6
6
  //#region src/domain/room.d.ts
@@ -1,5 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_domain_device_id = require("./device-id.cjs");
3
+ const require_sequential = require("../sequential-CtQVlW8M.cjs");
3
4
  const require_domain_token_scope = require("./token-scope.cjs");
4
5
  let zod = require("zod");
5
6
  let trilean = require("trilean");
@@ -125,10 +126,10 @@ async function evaluateNarrowing(parentClaims, childIssuer, candidate) {
125
126
  return narrowingHandlers[system](payload, context);
126
127
  }
127
128
  };
128
- for (const system of NARROWING_SYSTEMS) {
129
+ return require_sequential.firstAsync(NARROWING_SYSTEMS, async (system) => {
129
130
  const result = await (0, trilean.evaluatePredicate)(delegateIsTrue(system), context, resolvers);
130
- if (result.status !== "definite" || !result.value) return system;
131
- }
131
+ return result.status !== "definite" || !result.value;
132
+ });
132
133
  }
133
134
  /**
134
135
  * Evaluates token-claims' own `conditions` field (issue #85): additional, issuer-chosen predicates strictly additive to the five mandatory narrowing checks above, which are computed structurally (from a delegated token's own claims and its parent's) and never read from this field -- the five built-ins are inherently about a parent/child relationship, so they are not meaningfully reusable inside a bare, parent-less conditions evaluation, unlike a genuine domain-specific condition (a message TTL, #84's future revoke-authorization check) which reasons about the presented token's own claims directly. `extraHandlers` is the registration point for those: none exist yet, so a `conditions` entry naming any system with no registered handler resolves `{found: false}` -- indeterminate, fail-closed. Absent `nodes` (an empty array, the caller's own signal for "no conditions field present") is trivially `{ok: true}` -- no extra restrictions, exactly today's behaviour. Every entry MUST evaluate to a definite `true`; the loop short-circuits on the first indeterminate or false result.
@@ -161,14 +162,13 @@ async function evaluateConditions(nodes, claims, clock, extraHandlers = {}, subj
161
162
  }
162
163
  }
163
164
  };
164
- for (const node of nodes) {
165
+ return await require_sequential.firstAsync(nodes, async (node) => {
165
166
  const result = await (0, trilean.evaluatePredicate)(node, context, resolvers);
166
- if (result.status !== "definite" || !result.value) return {
167
- ok: false,
168
- reason: "not_satisfied"
169
- };
170
- }
171
- return { ok: true };
167
+ return result.status !== "definite" || !result.value;
168
+ }) === void 0 ? { ok: true } : {
169
+ ok: false,
170
+ reason: "not_satisfied"
171
+ };
172
172
  }
173
173
  //#endregion
174
174
  exports.BEARER_IS = BEARER_IS;
@@ -1,2 +1,2 @@
1
- import { _ as evaluateConditions, a as DEPTH_REMAINING, c as GRANTEE_IS, d as NarrowingSystem, f as SCOPE_NARROWS, g as conditionsListSchema, h as TokenPredicateContext, i as ConditionsVerdict, l as GrantSubject, m as TokenDelegateHandler, n as CAPABILITY_IS, o as EXPIRES_AT, p as SubjectSystem, r as ConditionsContext, s as GRANTED_CAPABILITY_IS, t as BEARER_IS, u as NarrowingCandidate, v as evaluateNarrowing, y as noSelfGrantBar } from "../token-predicates-D4NNPLnp.cjs";
1
+ import { _ as evaluateConditions, a as DEPTH_REMAINING, c as GRANTEE_IS, d as NarrowingSystem, f as SCOPE_NARROWS, g as conditionsListSchema, h as TokenPredicateContext, i as ConditionsVerdict, l as GrantSubject, m as TokenDelegateHandler, n as CAPABILITY_IS, o as EXPIRES_AT, p as SubjectSystem, r as ConditionsContext, s as GRANTED_CAPABILITY_IS, t as BEARER_IS, u as NarrowingCandidate, v as evaluateNarrowing, y as noSelfGrantBar } from "../token-predicates-lg4TtUxm.cjs";
2
2
  export { BEARER_IS, CAPABILITY_IS, ConditionsContext, ConditionsVerdict, DEPTH_REMAINING, EXPIRES_AT, GRANTED_CAPABILITY_IS, GRANTEE_IS, GrantSubject, NarrowingCandidate, NarrowingSystem, SCOPE_NARROWS, SubjectSystem, TokenDelegateHandler, TokenPredicateContext, conditionsListSchema, evaluateConditions, evaluateNarrowing, noSelfGrantBar };
@@ -1,2 +1,2 @@
1
- import { _ as evaluateConditions, a as DEPTH_REMAINING, c as GRANTEE_IS, d as NarrowingSystem, f as SCOPE_NARROWS, g as conditionsListSchema, h as TokenPredicateContext, i as ConditionsVerdict, l as GrantSubject, m as TokenDelegateHandler, n as CAPABILITY_IS, o as EXPIRES_AT, p as SubjectSystem, r as ConditionsContext, s as GRANTED_CAPABILITY_IS, t as BEARER_IS, u as NarrowingCandidate, v as evaluateNarrowing, y as noSelfGrantBar } from "../token-predicates-DqpG8VZZ.mjs";
1
+ import { _ as evaluateConditions, a as DEPTH_REMAINING, c as GRANTEE_IS, d as NarrowingSystem, f as SCOPE_NARROWS, g as conditionsListSchema, h as TokenPredicateContext, i as ConditionsVerdict, l as GrantSubject, m as TokenDelegateHandler, n as CAPABILITY_IS, o as EXPIRES_AT, p as SubjectSystem, r as ConditionsContext, s as GRANTED_CAPABILITY_IS, t as BEARER_IS, u as NarrowingCandidate, v as evaluateNarrowing, y as noSelfGrantBar } from "../token-predicates-CrieP1WI.mjs";
2
2
  export { BEARER_IS, CAPABILITY_IS, ConditionsContext, ConditionsVerdict, DEPTH_REMAINING, EXPIRES_AT, GRANTED_CAPABILITY_IS, GRANTEE_IS, GrantSubject, NarrowingCandidate, NarrowingSystem, SCOPE_NARROWS, SubjectSystem, TokenDelegateHandler, TokenPredicateContext, conditionsListSchema, evaluateConditions, evaluateNarrowing, noSelfGrantBar };
@@ -1,4 +1,5 @@
1
1
  import { deviceIdToHex } from "./device-id.mjs";
2
+ import { n as firstAsync } from "../sequential-D_W3THly.mjs";
2
3
  import { bytesEqual, scopeNarrows } from "./token-scope.mjs";
3
4
  import { z } from "zod";
4
5
  import { PredicateNodeSchema, evaluatePredicate } from "trilean";
@@ -124,10 +125,10 @@ async function evaluateNarrowing(parentClaims, childIssuer, candidate) {
124
125
  return narrowingHandlers[system](payload, context);
125
126
  }
126
127
  };
127
- for (const system of NARROWING_SYSTEMS) {
128
+ return firstAsync(NARROWING_SYSTEMS, async (system) => {
128
129
  const result = await evaluatePredicate(delegateIsTrue(system), context, resolvers);
129
- if (result.status !== "definite" || !result.value) return system;
130
- }
130
+ return result.status !== "definite" || !result.value;
131
+ });
131
132
  }
132
133
  /**
133
134
  * Evaluates token-claims' own `conditions` field (issue #85): additional, issuer-chosen predicates strictly additive to the five mandatory narrowing checks above, which are computed structurally (from a delegated token's own claims and its parent's) and never read from this field -- the five built-ins are inherently about a parent/child relationship, so they are not meaningfully reusable inside a bare, parent-less conditions evaluation, unlike a genuine domain-specific condition (a message TTL, #84's future revoke-authorization check) which reasons about the presented token's own claims directly. `extraHandlers` is the registration point for those: none exist yet, so a `conditions` entry naming any system with no registered handler resolves `{found: false}` -- indeterminate, fail-closed. Absent `nodes` (an empty array, the caller's own signal for "no conditions field present") is trivially `{ok: true}` -- no extra restrictions, exactly today's behaviour. Every entry MUST evaluate to a definite `true`; the loop short-circuits on the first indeterminate or false result.
@@ -160,14 +161,13 @@ async function evaluateConditions(nodes, claims, clock, extraHandlers = {}, subj
160
161
  }
161
162
  }
162
163
  };
163
- for (const node of nodes) {
164
+ return await firstAsync(nodes, async (node) => {
164
165
  const result = await evaluatePredicate(node, context, resolvers);
165
- if (result.status !== "definite" || !result.value) return {
166
- ok: false,
167
- reason: "not_satisfied"
168
- };
169
- }
170
- return { ok: true };
166
+ return result.status !== "definite" || !result.value;
167
+ }) === void 0 ? { ok: true } : {
168
+ ok: false,
169
+ reason: "not_satisfied"
170
+ };
171
171
  }
172
172
  //#endregion
173
173
  export { BEARER_IS, CAPABILITY_IS, DEPTH_REMAINING, EXPIRES_AT, GRANTED_CAPABILITY_IS, GRANTEE_IS, SCOPE_NARROWS, conditionsListSchema, evaluateConditions, evaluateNarrowing, noSelfGrantBar };
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_generated_protocol = require("../generated/protocol.cjs");
3
3
  const require_domain_device_id = require("./device-id.cjs");
4
+ const require_sequential = require("../sequential-CtQVlW8M.cjs");
4
5
  const require_domain_token_scope = require("./token-scope.cjs");
5
6
  const require_domain_token_predicates = require("./token-predicates.cjs");
6
7
  let cbor2 = require("cbor2");
@@ -82,7 +83,11 @@ async function revocationEntryGrantsRevoke(entry, targetClaims, options) {
82
83
  });
83
84
  return authorizationVerdict.ok && authorizationVerdict.claims.capability === "manage:revoke" && require_domain_token_scope.scopeNarrows(authorizationVerdict.claims.scope, targetClaims.scope);
84
85
  }
85
- async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen = /* @__PURE__ */ new Set()) {
86
+ const LEAF_LINK = {
87
+ depth: 0,
88
+ seen: /* @__PURE__ */ new Set()
89
+ };
90
+ async function verifyTokenChain(token, options, { subjectClaims, depth, seen } = LEAF_LINK) {
86
91
  const [protectedHeader, , payload, signature] = token;
87
92
  if (payload === null) return {
88
93
  ok: false,
@@ -137,7 +142,7 @@ async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen =
137
142
  reason: "content_expired"
138
143
  };
139
144
  const revocationEntries = await options.revocation.entriesFor(claims["token-id"]);
140
- for (const entry of revocationEntries) if (await revocationEntryGrantsRevoke(entry, claims, options)) return {
145
+ if (await require_sequential.firstAsync(revocationEntries, async (entry) => revocationEntryGrantsRevoke(entry, claims, options)) !== void 0) return {
141
146
  ok: false,
142
147
  reason: "revoked"
143
148
  };
@@ -186,7 +191,10 @@ async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen =
186
191
  ok: false,
187
192
  reason: "parent_invalid"
188
193
  };
189
- const parentVerdict = await verifyTokenChain(parentResult.data, options, void 0, depth + 1, deeperSeen);
194
+ const parentVerdict = await verifyTokenChain(parentResult.data, options, {
195
+ depth: depth + 1,
196
+ seen: deeperSeen
197
+ });
190
198
  if (!parentVerdict.ok) {
191
199
  if (parentVerdict.reason === "chain_too_deep" || parentVerdict.reason === "chain_cycle") return {
192
200
  ok: false,
@@ -230,7 +238,11 @@ async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen =
230
238
  ok: false,
231
239
  reason: "authorisation_invalid"
232
240
  };
233
- const authoriserVerdict = await verifyTokenChain(authoriserResult.data, options, claims, depth + 1, deeperSeen);
241
+ const authoriserVerdict = await verifyTokenChain(authoriserResult.data, options, {
242
+ subjectClaims: claims,
243
+ depth: depth + 1,
244
+ seen: deeperSeen
245
+ });
234
246
  if (!authoriserVerdict.ok) {
235
247
  if (authoriserVerdict.reason === "chain_too_deep" || authoriserVerdict.reason === "chain_cycle") return {
236
248
  ok: false,
@@ -1,7 +1,7 @@
1
1
  import { B as IdentityKey, D as DeviceId, bt as RevocationEntry, en as TokenClaims, p as CapabilityToken, yt as RevocationClaims } from "../protocol-DzmpxxUr.cjs";
2
2
  import { t as IdentityPort } from "../identity-B6nhlSOT.cjs";
3
- import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
- import { l as GrantSubject, m as TokenDelegateHandler, r as ConditionsContext, u as NarrowingCandidate } from "../token-predicates-D4NNPLnp.cjs";
3
+ import { t as Clock } from "../clock-DhUPRfLh.cjs";
4
+ import { l as GrantSubject, m as TokenDelegateHandler, r as ConditionsContext, u as NarrowingCandidate } from "../token-predicates-lg4TtUxm.cjs";
5
5
  import { PredicateNode } from "trilean";
6
6
  //#region src/domain/tokens.d.ts
7
7
  /** The capability verb of a grant-capability (wire-mesh#323): authority to mint other capability tokens, the same register manage:revoke already established for authority over tokens. */
@@ -1,7 +1,7 @@
1
1
  import { B as IdentityKey, D as DeviceId, bt as RevocationEntry, en as TokenClaims, p as CapabilityToken, yt as RevocationClaims } from "../protocol-DzmpxxUr.mjs";
2
2
  import { t as IdentityPort } from "../identity-EV-HHv_D.mjs";
3
- import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
- import { l as GrantSubject, m as TokenDelegateHandler, r as ConditionsContext, u as NarrowingCandidate } from "../token-predicates-DqpG8VZZ.mjs";
3
+ import { t as Clock } from "../clock-DhUPRfLh.mjs";
4
+ import { l as GrantSubject, m as TokenDelegateHandler, r as ConditionsContext, u as NarrowingCandidate } from "../token-predicates-CrieP1WI.mjs";
5
5
  import { PredicateNode } from "trilean";
6
6
  //#region src/domain/tokens.d.ts
7
7
  /** The capability verb of a grant-capability (wire-mesh#323): authority to mint other capability tokens, the same register manage:revoke already established for authority over tokens. */
@@ -1,5 +1,6 @@
1
1
  import { capabilityTokenSchema, revocationClaimsSchema, tokenClaimsSchema } from "../generated/protocol.mjs";
2
2
  import { bytesToHex } from "./device-id.mjs";
3
+ import { n as firstAsync } from "../sequential-D_W3THly.mjs";
3
4
  import { bytesEqual, scopeNarrows } from "./token-scope.mjs";
4
5
  import { conditionsListSchema, evaluateConditions, evaluateNarrowing } from "./token-predicates.mjs";
5
6
  import { cdeDecodeOptions, cdeEncodeOptions, decode, encode } from "cbor2";
@@ -81,7 +82,11 @@ async function revocationEntryGrantsRevoke(entry, targetClaims, options) {
81
82
  });
82
83
  return authorizationVerdict.ok && authorizationVerdict.claims.capability === "manage:revoke" && scopeNarrows(authorizationVerdict.claims.scope, targetClaims.scope);
83
84
  }
84
- async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen = /* @__PURE__ */ new Set()) {
85
+ const LEAF_LINK = {
86
+ depth: 0,
87
+ seen: /* @__PURE__ */ new Set()
88
+ };
89
+ async function verifyTokenChain(token, options, { subjectClaims, depth, seen } = LEAF_LINK) {
85
90
  const [protectedHeader, , payload, signature] = token;
86
91
  if (payload === null) return {
87
92
  ok: false,
@@ -136,7 +141,7 @@ async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen =
136
141
  reason: "content_expired"
137
142
  };
138
143
  const revocationEntries = await options.revocation.entriesFor(claims["token-id"]);
139
- for (const entry of revocationEntries) if (await revocationEntryGrantsRevoke(entry, claims, options)) return {
144
+ if (await firstAsync(revocationEntries, async (entry) => revocationEntryGrantsRevoke(entry, claims, options)) !== void 0) return {
140
145
  ok: false,
141
146
  reason: "revoked"
142
147
  };
@@ -185,7 +190,10 @@ async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen =
185
190
  ok: false,
186
191
  reason: "parent_invalid"
187
192
  };
188
- const parentVerdict = await verifyTokenChain(parentResult.data, options, void 0, depth + 1, deeperSeen);
193
+ const parentVerdict = await verifyTokenChain(parentResult.data, options, {
194
+ depth: depth + 1,
195
+ seen: deeperSeen
196
+ });
189
197
  if (!parentVerdict.ok) {
190
198
  if (parentVerdict.reason === "chain_too_deep" || parentVerdict.reason === "chain_cycle") return {
191
199
  ok: false,
@@ -229,7 +237,11 @@ async function verifyTokenChain(token, options, subjectClaims, depth = 0, seen =
229
237
  ok: false,
230
238
  reason: "authorisation_invalid"
231
239
  };
232
- const authoriserVerdict = await verifyTokenChain(authoriserResult.data, options, claims, depth + 1, deeperSeen);
240
+ const authoriserVerdict = await verifyTokenChain(authoriserResult.data, options, {
241
+ subjectClaims: claims,
242
+ depth: depth + 1,
243
+ seen: deeperSeen
244
+ });
233
245
  if (!authoriserVerdict.ok) {
234
246
  if (authoriserVerdict.reason === "chain_too_deep" || authoriserVerdict.reason === "chain_cycle") return {
235
247
  ok: false,
@@ -1,2 +1,2 @@
1
- import { t as Clock } from "../clock-DiSx-WKM.cjs";
1
+ import { t as Clock } from "../clock-DhUPRfLh.cjs";
2
2
  export { Clock };
@@ -1,2 +1,2 @@
1
- import { t as Clock } from "../clock-DiSx-WKM.mjs";
1
+ import { t as Clock } from "../clock-DhUPRfLh.mjs";
2
2
  export { Clock };
@@ -1,2 +1,2 @@
1
- import { t as KeyValueStorage } from "../storage-B403CRyu.cjs";
1
+ import { t as KeyValueStorage } from "../storage-jbGFAYIV.cjs";
2
2
  export { KeyValueStorage };