wire-mesh-core 1.30.1 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/adapters/frame-codec.d.cts +1 -1
  2. package/dist/adapters/frame-codec.d.mts +1 -1
  3. package/dist/adapters/node-identity.cjs +26 -2
  4. package/dist/adapters/node-identity.d.cts +5 -3
  5. package/dist/adapters/node-identity.d.mts +5 -3
  6. package/dist/adapters/node-identity.mjs +26 -2
  7. package/dist/adapters/tcp-transport.d.cts +1 -1
  8. package/dist/adapters/tcp-transport.d.mts +1 -1
  9. package/dist/adapters/tls-transport.d.cts +1 -1
  10. package/dist/adapters/tls-transport.d.mts +1 -1
  11. package/dist/domain/bulk.d.cts +2 -2
  12. package/dist/domain/bulk.d.mts +2 -2
  13. package/dist/domain/capability-grant.d.cts +3 -3
  14. package/dist/domain/capability-grant.d.mts +3 -3
  15. package/dist/domain/capability-request.d.cts +2 -2
  16. package/dist/domain/capability-request.d.mts +2 -2
  17. package/dist/domain/data-sync.d.cts +2 -2
  18. package/dist/domain/data-sync.d.mts +2 -2
  19. package/dist/domain/device-id.d.cts +1 -1
  20. package/dist/domain/device-id.d.mts +1 -1
  21. package/dist/domain/grant-candidates.d.cts +1 -1
  22. package/dist/domain/grant-candidates.d.mts +1 -1
  23. package/dist/domain/group-key.cjs +93 -0
  24. package/dist/domain/group-key.d.cts +24 -0
  25. package/dist/domain/group-key.d.mts +24 -0
  26. package/dist/domain/group-key.mjs +87 -0
  27. package/dist/domain/handshake.d.cts +1 -1
  28. package/dist/domain/handshake.d.mts +1 -1
  29. package/dist/domain/mesh-session.d.cts +3 -3
  30. package/dist/domain/mesh-session.d.mts +3 -3
  31. package/dist/domain/relay-hub.d.cts +2 -2
  32. package/dist/domain/relay-hub.d.mts +2 -2
  33. package/dist/domain/relay-use-gate.d.cts +2 -2
  34. package/dist/domain/relay-use-gate.d.mts +2 -2
  35. package/dist/domain/revocation-view.d.cts +2 -2
  36. package/dist/domain/revocation-view.d.mts +2 -2
  37. package/dist/domain/room-token-verification.d.cts +2 -2
  38. package/dist/domain/room-token-verification.d.mts +2 -2
  39. package/dist/domain/room.d.cts +3 -3
  40. package/dist/domain/room.d.mts +3 -3
  41. package/dist/domain/tokens.d.cts +1 -1
  42. package/dist/domain/tokens.d.mts +1 -1
  43. package/dist/generated/protocol.cjs +9 -1
  44. package/dist/generated/protocol.d.cts +2 -2
  45. package/dist/generated/protocol.d.mts +2 -2
  46. package/dist/generated/protocol.mjs +9 -2
  47. package/dist/{identity-C5N86BPz.d.mts → identity-B4XBWkqg.d.cts} +3 -1
  48. package/dist/{identity-DJ06jn4k.d.cts → identity-CIb9dGkJ.d.mts} +3 -1
  49. package/dist/ports/identity.d.cts +1 -1
  50. package/dist/ports/identity.d.mts +1 -1
  51. package/dist/ports/transport.d.cts +1 -1
  52. package/dist/ports/transport.d.mts +1 -1
  53. package/dist/{protocol-sW8d6Og-.d.cts → protocol-gbXtNeOc.d.cts} +33 -6
  54. package/dist/{protocol-sW8d6Og-.d.mts → protocol-gbXtNeOc.d.mts} +33 -6
  55. package/dist/{tokens-DfVfE00W.d.cts → tokens-CNQirfHi.d.cts} +2 -2
  56. package/dist/{tokens-CpLDI5Fo.d.mts → tokens-C_LvOuYO.d.mts} +2 -2
  57. package/dist/{transport-B5E896PN.d.mts → transport-DAsFqDDS.d.cts} +1 -1
  58. package/dist/{transport-DxZ4JWZc.d.cts → transport-Dy4h2eNY.d.mts} +1 -1
  59. package/package.json +5 -1
@@ -1,4 +1,4 @@
1
- import { N as Frame } from "../protocol-sW8d6Og-.cjs";
1
+ import { N as Frame } from "../protocol-gbXtNeOc.cjs";
2
2
  //#region src/adapters/frame-codec.d.ts
3
3
  export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
4
4
  /** A frame that fails schema validation, caught separately from a decode failure so it can be dropped without disconnecting. */
@@ -1,4 +1,4 @@
1
- import { N as Frame } from "../protocol-sW8d6Og-.mjs";
1
+ import { N as Frame } from "../protocol-gbXtNeOc.mjs";
2
2
  //#region src/adapters/frame-codec.d.ts
3
3
  export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
4
4
  /** A frame that fails schema validation, caught separately from a decode failure so it can be dropped without disconnecting. */
@@ -31,14 +31,25 @@ async function verifyWithPublicKey(key, message, signature) {
31
31
  return node_crypto.webcrypto.subtle.verify(algParams(key.alg), cryptoKey, toBufferSource(signature), toBufferSource(message));
32
32
  }
33
33
  /**
34
+ * Imports a peer's ES256 identity-key for ECDH deriveBits usage. Only ever called with an already-published public key (this node's own peers' identity-keys), never private material, so there is no custody concern here the way there is for the local node's own private key.
35
+ */
36
+ async function importEs256PublicKeyForEcdh(key) {
37
+ return node_crypto.webcrypto.subtle.importKey("raw", toBufferSource(key["public-key"]), {
38
+ name: "ECDH",
39
+ namedCurve: "P-256"
40
+ }, false, []);
41
+ }
42
+ /**
34
43
  * Builds an IdentityPort from a Web Crypto private key already generated for this node -- ECDSA P-256 (alg -7) or Ed25519 (alg -8), the two algorithms identity-key.alg actually carries in the spec's own conformance vectors. Device-id derivation and signature verification are pure functions of the given key bytes (exported separately above), so they work for an arbitrary issuer-key too, not just this node's own.
44
+ *
45
+ * `ecdhPrivateKey`, when given, must be a `{name: "ECDH", namedCurve: "P-256"}`-usage `deriveBits`-capable CryptoKey imported from the SAME underlying scalar as `privateKey` -- Web Crypto permanently binds a CryptoKey to the one algorithm it was imported for, so an ECDSA-usage key can never itself be used for `deriveBits`, even though ECDH and ECDSA share the identical P-256 curve and scalar. Room rekey's own ECIES construction reuses each member's existing identity-key rather than minting a separate encryption key (wire-mesh#141), so a caller wanting `deriveSharedSecret` imports the same scalar a second time under `{name: "ECDH"}` and passes both keys here -- deliberately the CALLER's own choice, not done automatically inside this function, so a caller that generated `privateKey` as `extractable: false` for signing-only isn't forced to also make it extractable (the only way to obtain a second, differently-algorithmed CryptoKey from the same scalar) just to satisfy a capability it never asked for.
35
46
  */
36
- async function createNodeIdentity(privateKey, publicKeyBytes, alg) {
47
+ async function createNodeIdentity(privateKey, publicKeyBytes, alg, ecdhPrivateKey) {
37
48
  const identityKey = {
38
49
  alg,
39
50
  "public-key": toBufferSource(publicKeyBytes)
40
51
  };
41
- return {
52
+ const base = {
42
53
  deviceId: await deriveDeviceId(publicKeyBytes),
43
54
  identityKey,
44
55
  async sign(message) {
@@ -48,6 +59,19 @@ async function createNodeIdentity(privateKey, publicKeyBytes, alg) {
48
59
  verify: verifyWithPublicKey,
49
60
  deriveDeviceId
50
61
  };
62
+ if (alg !== ES256 || ecdhPrivateKey === void 0) return base;
63
+ return {
64
+ ...base,
65
+ async deriveSharedSecret(peerKey) {
66
+ if (peerKey.alg !== ES256) throw new Error(`ECDH is only defined for an ES256 peer identity-key, got alg ${String(peerKey.alg)}`);
67
+ const peerPublicKey = await importEs256PublicKeyForEcdh(peerKey);
68
+ const bits = await node_crypto.webcrypto.subtle.deriveBits({
69
+ name: "ECDH",
70
+ public: peerPublicKey
71
+ }, ecdhPrivateKey, 256);
72
+ return new Uint8Array(bits);
73
+ }
74
+ };
51
75
  }
52
76
  //#endregion
53
77
  exports.createNodeIdentity = createNodeIdentity;
@@ -1,11 +1,13 @@
1
- import { B as IdentityKey, D as DeviceId } from "../protocol-sW8d6Og-.cjs";
2
- import { t as IdentityPort } from "../identity-DJ06jn4k.cjs";
1
+ import { B as IdentityKey, D as DeviceId } from "../protocol-gbXtNeOc.cjs";
2
+ import { t as IdentityPort } from "../identity-B4XBWkqg.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>;
6
6
  export declare function verifyWithPublicKey(key: IdentityKey, message: Uint8Array, signature: Uint8Array): Promise<boolean>;
7
7
  /**
8
8
  * Builds an IdentityPort from a Web Crypto private key already generated for this node -- ECDSA P-256 (alg -7) or Ed25519 (alg -8), the two algorithms identity-key.alg actually carries in the spec's own conformance vectors. Device-id derivation and signature verification are pure functions of the given key bytes (exported separately above), so they work for an arbitrary issuer-key too, not just this node's own.
9
+ *
10
+ * `ecdhPrivateKey`, when given, must be a `{name: "ECDH", namedCurve: "P-256"}`-usage `deriveBits`-capable CryptoKey imported from the SAME underlying scalar as `privateKey` -- Web Crypto permanently binds a CryptoKey to the one algorithm it was imported for, so an ECDSA-usage key can never itself be used for `deriveBits`, even though ECDH and ECDSA share the identical P-256 curve and scalar. Room rekey's own ECIES construction reuses each member's existing identity-key rather than minting a separate encryption key (wire-mesh#141), so a caller wanting `deriveSharedSecret` imports the same scalar a second time under `{name: "ECDH"}` and passes both keys here -- deliberately the CALLER's own choice, not done automatically inside this function, so a caller that generated `privateKey` as `extractable: false` for signing-only isn't forced to also make it extractable (the only way to obtain a second, differently-algorithmed CryptoKey from the same scalar) just to satisfy a capability it never asked for.
9
11
  */
10
- export declare function createNodeIdentity(privateKey: webcrypto.CryptoKey, publicKeyBytes: Uint8Array, alg: number): Promise<IdentityPort>;
12
+ export declare function createNodeIdentity(privateKey: webcrypto.CryptoKey, publicKeyBytes: Uint8Array, alg: number, ecdhPrivateKey?: webcrypto.CryptoKey): Promise<IdentityPort>;
11
13
  //#endregion
@@ -1,11 +1,13 @@
1
- import { B as IdentityKey, D as DeviceId } from "../protocol-sW8d6Og-.mjs";
2
- import { t as IdentityPort } from "../identity-C5N86BPz.mjs";
1
+ import { B as IdentityKey, D as DeviceId } from "../protocol-gbXtNeOc.mjs";
2
+ import { t as IdentityPort } from "../identity-CIb9dGkJ.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>;
6
6
  export declare function verifyWithPublicKey(key: IdentityKey, message: Uint8Array, signature: Uint8Array): Promise<boolean>;
7
7
  /**
8
8
  * Builds an IdentityPort from a Web Crypto private key already generated for this node -- ECDSA P-256 (alg -7) or Ed25519 (alg -8), the two algorithms identity-key.alg actually carries in the spec's own conformance vectors. Device-id derivation and signature verification are pure functions of the given key bytes (exported separately above), so they work for an arbitrary issuer-key too, not just this node's own.
9
+ *
10
+ * `ecdhPrivateKey`, when given, must be a `{name: "ECDH", namedCurve: "P-256"}`-usage `deriveBits`-capable CryptoKey imported from the SAME underlying scalar as `privateKey` -- Web Crypto permanently binds a CryptoKey to the one algorithm it was imported for, so an ECDSA-usage key can never itself be used for `deriveBits`, even though ECDH and ECDSA share the identical P-256 curve and scalar. Room rekey's own ECIES construction reuses each member's existing identity-key rather than minting a separate encryption key (wire-mesh#141), so a caller wanting `deriveSharedSecret` imports the same scalar a second time under `{name: "ECDH"}` and passes both keys here -- deliberately the CALLER's own choice, not done automatically inside this function, so a caller that generated `privateKey` as `extractable: false` for signing-only isn't forced to also make it extractable (the only way to obtain a second, differently-algorithmed CryptoKey from the same scalar) just to satisfy a capability it never asked for.
9
11
  */
10
- export declare function createNodeIdentity(privateKey: webcrypto.CryptoKey, publicKeyBytes: Uint8Array, alg: number): Promise<IdentityPort>;
12
+ export declare function createNodeIdentity(privateKey: webcrypto.CryptoKey, publicKeyBytes: Uint8Array, alg: number, ecdhPrivateKey?: webcrypto.CryptoKey): Promise<IdentityPort>;
11
13
  //#endregion
@@ -30,14 +30,25 @@ async function verifyWithPublicKey(key, message, signature) {
30
30
  return webcrypto.subtle.verify(algParams(key.alg), cryptoKey, toBufferSource(signature), toBufferSource(message));
31
31
  }
32
32
  /**
33
+ * Imports a peer's ES256 identity-key for ECDH deriveBits usage. Only ever called with an already-published public key (this node's own peers' identity-keys), never private material, so there is no custody concern here the way there is for the local node's own private key.
34
+ */
35
+ async function importEs256PublicKeyForEcdh(key) {
36
+ return webcrypto.subtle.importKey("raw", toBufferSource(key["public-key"]), {
37
+ name: "ECDH",
38
+ namedCurve: "P-256"
39
+ }, false, []);
40
+ }
41
+ /**
33
42
  * Builds an IdentityPort from a Web Crypto private key already generated for this node -- ECDSA P-256 (alg -7) or Ed25519 (alg -8), the two algorithms identity-key.alg actually carries in the spec's own conformance vectors. Device-id derivation and signature verification are pure functions of the given key bytes (exported separately above), so they work for an arbitrary issuer-key too, not just this node's own.
43
+ *
44
+ * `ecdhPrivateKey`, when given, must be a `{name: "ECDH", namedCurve: "P-256"}`-usage `deriveBits`-capable CryptoKey imported from the SAME underlying scalar as `privateKey` -- Web Crypto permanently binds a CryptoKey to the one algorithm it was imported for, so an ECDSA-usage key can never itself be used for `deriveBits`, even though ECDH and ECDSA share the identical P-256 curve and scalar. Room rekey's own ECIES construction reuses each member's existing identity-key rather than minting a separate encryption key (wire-mesh#141), so a caller wanting `deriveSharedSecret` imports the same scalar a second time under `{name: "ECDH"}` and passes both keys here -- deliberately the CALLER's own choice, not done automatically inside this function, so a caller that generated `privateKey` as `extractable: false` for signing-only isn't forced to also make it extractable (the only way to obtain a second, differently-algorithmed CryptoKey from the same scalar) just to satisfy a capability it never asked for.
34
45
  */
35
- async function createNodeIdentity(privateKey, publicKeyBytes, alg) {
46
+ async function createNodeIdentity(privateKey, publicKeyBytes, alg, ecdhPrivateKey) {
36
47
  const identityKey = {
37
48
  alg,
38
49
  "public-key": toBufferSource(publicKeyBytes)
39
50
  };
40
- return {
51
+ const base = {
41
52
  deviceId: await deriveDeviceId(publicKeyBytes),
42
53
  identityKey,
43
54
  async sign(message) {
@@ -47,6 +58,19 @@ async function createNodeIdentity(privateKey, publicKeyBytes, alg) {
47
58
  verify: verifyWithPublicKey,
48
59
  deriveDeviceId
49
60
  };
61
+ if (alg !== ES256 || ecdhPrivateKey === void 0) return base;
62
+ return {
63
+ ...base,
64
+ async deriveSharedSecret(peerKey) {
65
+ if (peerKey.alg !== ES256) throw new Error(`ECDH is only defined for an ES256 peer identity-key, got alg ${String(peerKey.alg)}`);
66
+ const peerPublicKey = await importEs256PublicKeyForEcdh(peerKey);
67
+ const bits = await webcrypto.subtle.deriveBits({
68
+ name: "ECDH",
69
+ public: peerPublicKey
70
+ }, ecdhPrivateKey, 256);
71
+ return new Uint8Array(bits);
72
+ }
73
+ };
50
74
  }
51
75
  //#endregion
52
76
  export { createNodeIdentity, deriveDeviceId, verifyWithPublicKey };
@@ -1,4 +1,4 @@
1
- import { r as Transport } from "../transport-DxZ4JWZc.cjs";
1
+ import { r as Transport } from "../transport-DAsFqDDS.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-B5E896PN.mjs";
1
+ import { r as Transport } from "../transport-Dy4h2eNY.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,4 +1,4 @@
1
- import { r as Transport } from "../transport-DxZ4JWZc.cjs";
1
+ import { r as Transport } from "../transport-DAsFqDDS.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-B5E896PN.mjs";
1
+ import { r as Transport } from "../transport-Dy4h2eNY.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-sW8d6Og-.cjs";
1
+ import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-gbXtNeOc.cjs";
2
2
  import { KeyValueStorage } from "../ports/storage.cjs";
3
- import { t as Connection } from "../transport-DxZ4JWZc.cjs";
3
+ import { t as Connection } from "../transport-DAsFqDDS.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-sW8d6Og-.mjs";
1
+ import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-gbXtNeOc.mjs";
2
2
  import { KeyValueStorage } from "../ports/storage.mjs";
3
- import { t as Connection } from "../transport-B5E896PN.mjs";
3
+ import { t as Connection } from "../transport-Dy4h2eNY.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-sW8d6Og-.cjs";
2
- import { t as IdentityPort } from "../identity-DJ06jn4k.cjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-gbXtNeOc.cjs";
2
+ import { t as IdentityPort } from "../identity-B4XBWkqg.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-DfVfE00W.cjs";
5
+ import { a as RevocationCheck } from "../tokens-CNQirfHi.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-sW8d6Og-.mjs";
2
- import { t as IdentityPort } from "../identity-C5N86BPz.mjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-gbXtNeOc.mjs";
2
+ import { t as IdentityPort } from "../identity-CIb9dGkJ.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-CpLDI5Fo.mjs";
5
+ import { a as RevocationCheck } from "../tokens-C_LvOuYO.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-sW8d6Og-.cjs";
2
- import { t as IdentityPort } from "../identity-DJ06jn4k.cjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-gbXtNeOc.cjs";
2
+ import { t as IdentityPort } from "../identity-B4XBWkqg.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-sW8d6Og-.mjs";
2
- import { t as IdentityPort } from "../identity-C5N86BPz.mjs";
1
+ import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-gbXtNeOc.mjs";
2
+ import { t as IdentityPort } from "../identity-CIb9dGkJ.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-sW8d6Og-.cjs";
1
+ import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-gbXtNeOc.cjs";
2
2
  import { KeyValueStorage } from "../ports/storage.cjs";
3
- import { t as IdentityPort } from "../identity-DJ06jn4k.cjs";
3
+ import { t as IdentityPort } from "../identity-B4XBWkqg.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-sW8d6Og-.mjs";
1
+ import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-gbXtNeOc.mjs";
2
2
  import { KeyValueStorage } from "../ports/storage.mjs";
3
- import { t as IdentityPort } from "../identity-C5N86BPz.mjs";
3
+ import { t as IdentityPort } from "../identity-CIb9dGkJ.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-sW8d6Og-.cjs";
1
+ import { D as DeviceId } from "../protocol-gbXtNeOc.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-sW8d6Og-.mjs";
1
+ import { D as DeviceId } from "../protocol-gbXtNeOc.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,4 +1,4 @@
1
- import { D as DeviceId, f as CapabilityScope } from "../protocol-sW8d6Og-.cjs";
1
+ import { D as DeviceId, f as CapabilityScope } from "../protocol-gbXtNeOc.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-sW8d6Og-.mjs";
1
+ import { D as DeviceId, f as CapabilityScope } from "../protocol-gbXtNeOc.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
@@ -0,0 +1,93 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/domain/group-key.ts
3
+ const AES_KEY_BYTE_LENGTH = 32;
4
+ const AES_KEY_BIT_LENGTH = 256;
5
+ const GCM_IV_BYTE_LENGTH = 12;
6
+ const UINT32_BYTE_LENGTH = 4;
7
+ const UINT64_BYTE_LENGTH = 8;
8
+ const HKDF_INFO_PREFIX = new TextEncoder().encode("wire-mesh/room-rekey/v1\0");
9
+ /** Generates a fresh, random 256-bit room content-encryption key (the thing room.rekey wraps and distributes, and that encryptNoticeContent/decryptNoticeContent use directly). */
10
+ function generateContentKey() {
11
+ return crypto.getRandomValues(new Uint8Array(AES_KEY_BYTE_LENGTH));
12
+ }
13
+ /**
14
+ * Binds HKDF's own `info` parameter to exactly the (room, key-epoch) pair a wrapping key is for, so a wrapping key derived for one room or one epoch can never successfully unwrap ciphertext produced under another -- domain separation from the derivation itself, not merely a convention callers must remember to check. Length-prefixing the room path (rather than a bare separator byte) keeps the encoding unambiguous regardless of what characters a room path itself may contain.
15
+ */
16
+ function hkdfInfo(context) {
17
+ const roomBytes = new TextEncoder().encode(context.room);
18
+ const roomLength = new Uint8Array(UINT32_BYTE_LENGTH);
19
+ new DataView(roomLength.buffer).setUint32(0, roomBytes.length, false);
20
+ const keyEpoch = new Uint8Array(UINT64_BYTE_LENGTH);
21
+ new DataView(keyEpoch.buffer).setBigUint64(0, BigInt(context.keyEpoch), false);
22
+ const info = new Uint8Array(HKDF_INFO_PREFIX.length + roomLength.length + roomBytes.length + keyEpoch.length);
23
+ let offset = 0;
24
+ info.set(HKDF_INFO_PREFIX, offset);
25
+ offset += HKDF_INFO_PREFIX.length;
26
+ info.set(roomLength, offset);
27
+ offset += roomLength.length;
28
+ info.set(roomBytes, offset);
29
+ offset += roomBytes.length;
30
+ info.set(keyEpoch, offset);
31
+ return info;
32
+ }
33
+ /**
34
+ * Derives an AES-256-GCM wrapping key from a raw ECDH shared secret (IdentityPort.deriveSharedSecret's own output) via HKDF-SHA256, with `info` binding the result to exactly one (room, key-epoch) pair -- see hkdfInfo. No explicit salt: static-static ECDH already produces a high-entropy, uniformly-distributed shared secret, so an empty salt is the standard, RFC 5869-sanctioned choice here rather than a corner cut (a salt matters most when the input key material's own entropy is questionable, which a P-256 ECDH output is not).
35
+ */
36
+ async function deriveWrappingKey(sharedSecret, context) {
37
+ const ikm = await crypto.subtle.importKey("raw", Uint8Array.from(sharedSecret), "HKDF", false, ["deriveKey"]);
38
+ return crypto.subtle.deriveKey({
39
+ name: "HKDF",
40
+ hash: "SHA-256",
41
+ salt: Uint8Array.from(/* @__PURE__ */ new Uint8Array(0)),
42
+ info: Uint8Array.from(hkdfInfo(context))
43
+ }, ikm, {
44
+ name: "AES-GCM",
45
+ length: AES_KEY_BIT_LENGTH
46
+ }, false, ["encrypt", "decrypt"]);
47
+ }
48
+ async function aesGcmEncrypt(key, plaintext) {
49
+ const iv = crypto.getRandomValues(new Uint8Array(GCM_IV_BYTE_LENGTH));
50
+ const ciphertext = new Uint8Array(await crypto.subtle.encrypt({
51
+ name: "AES-GCM",
52
+ iv
53
+ }, key, Uint8Array.from(plaintext)));
54
+ const out = new Uint8Array(iv.length + ciphertext.length);
55
+ out.set(iv, 0);
56
+ out.set(ciphertext, iv.length);
57
+ return out;
58
+ }
59
+ async function aesGcmDecrypt(key, ivAndCiphertext) {
60
+ if (ivAndCiphertext.length < GCM_IV_BYTE_LENGTH) throw new Error("ciphertext shorter than the AES-GCM IV it must carry");
61
+ const iv = ivAndCiphertext.slice(0, GCM_IV_BYTE_LENGTH);
62
+ const ciphertext = ivAndCiphertext.slice(GCM_IV_BYTE_LENGTH);
63
+ return new Uint8Array(await crypto.subtle.decrypt({
64
+ name: "AES-GCM",
65
+ iv
66
+ }, key, ciphertext));
67
+ }
68
+ /** Wraps a room content-encryption key for delivery in room.rekey's own `wrapped-key` field. */
69
+ async function wrapContentKey(wrappingKey, contentKey) {
70
+ return aesGcmEncrypt(wrappingKey, contentKey);
71
+ }
72
+ /** Unwraps a room.rekey `wrapped-key` entry back into the room content-encryption key it carries. Rejects (never returns a garbage key) if the wrapping key or ciphertext don't match -- AES-GCM's own authentication tag catches both a wrong key and any tampering. */
73
+ async function unwrapContentKey(wrappingKey, wrapped) {
74
+ return aesGcmDecrypt(wrappingKey, wrapped);
75
+ }
76
+ async function importContentKey(contentKey) {
77
+ return crypto.subtle.importKey("raw", Uint8Array.from(contentKey), "AES-GCM", false, ["encrypt", "decrypt"]);
78
+ }
79
+ /** Encrypts a room-notice's own `content` under the room's current content-encryption key -- encrypt-then-sign, layered underneath room-notice's existing cose-sign1 envelope (see room.cddl's key-epoch obligation), never a replacement for it. */
80
+ async function encryptNoticeContent(contentKey, plaintext) {
81
+ return aesGcmEncrypt(await importContentKey(contentKey), plaintext);
82
+ }
83
+ /** Decrypts a room-notice's own `content`, given the content-encryption key for the epoch its key-epoch field names. Rejects on a wrong key or tampered ciphertext, same as unwrapContentKey. */
84
+ async function decryptNoticeContent(contentKey, ciphertext) {
85
+ return aesGcmDecrypt(await importContentKey(contentKey), ciphertext);
86
+ }
87
+ //#endregion
88
+ exports.decryptNoticeContent = decryptNoticeContent;
89
+ exports.deriveWrappingKey = deriveWrappingKey;
90
+ exports.encryptNoticeContent = encryptNoticeContent;
91
+ exports.generateContentKey = generateContentKey;
92
+ exports.unwrapContentKey = unwrapContentKey;
93
+ exports.wrapContentKey = wrapContentKey;
@@ -0,0 +1,24 @@
1
+ //#region src/domain/group-key.d.ts
2
+ /**
3
+ * The symmetric half of room.rekey's own ECIES key-wrapping construction (wire-mesh#141): HKDF-SHA256 turning a raw ECDH shared secret into a per-(room, key-epoch) AES-256-GCM wrapping key, and AES-256-GCM itself for wrapping a room's content-encryption key and for encrypting a room-notice's own content under it. The asymmetric half (producing the shared secret) lives behind IdentityPort.deriveSharedSecret instead -- these functions operate only on plain bytes already in hand, with no platform-specific key-custody concern, so they need no port of their own (see IdentityPort.deriveSharedSecret's own doc comment).
4
+ *
5
+ * A fresh random IV is generated for every AES-256-GCM operation here and prepended to the output -- never a fixed or derived IV -- since a wrapping key derived once per (room, key-epoch) may legitimately wrap more than once (e.g. a resent room.rekey), and reusing an AES-GCM IV under the same key is catastrophic (it discloses the authentication key and lets an attacker forge subsequent messages).
6
+ */
7
+ /** Generates a fresh, random 256-bit room content-encryption key (the thing room.rekey wraps and distributes, and that encryptNoticeContent/decryptNoticeContent use directly). */
8
+ export declare function generateContentKey(): Uint8Array<ArrayBuffer>;
9
+ /**
10
+ * Derives an AES-256-GCM wrapping key from a raw ECDH shared secret (IdentityPort.deriveSharedSecret's own output) via HKDF-SHA256, with `info` binding the result to exactly one (room, key-epoch) pair -- see hkdfInfo. No explicit salt: static-static ECDH already produces a high-entropy, uniformly-distributed shared secret, so an empty salt is the standard, RFC 5869-sanctioned choice here rather than a corner cut (a salt matters most when the input key material's own entropy is questionable, which a P-256 ECDH output is not).
11
+ */
12
+ export declare function deriveWrappingKey(sharedSecret: Uint8Array, context: Readonly<{
13
+ room: string;
14
+ keyEpoch: number;
15
+ }>): Promise<CryptoKey>;
16
+ /** Wraps a room content-encryption key for delivery in room.rekey's own `wrapped-key` field. */
17
+ export declare function wrapContentKey(wrappingKey: CryptoKey, contentKey: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
18
+ /** Unwraps a room.rekey `wrapped-key` entry back into the room content-encryption key it carries. Rejects (never returns a garbage key) if the wrapping key or ciphertext don't match -- AES-GCM's own authentication tag catches both a wrong key and any tampering. */
19
+ export declare function unwrapContentKey(wrappingKey: CryptoKey, wrapped: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
20
+ /** Encrypts a room-notice's own `content` under the room's current content-encryption key -- encrypt-then-sign, layered underneath room-notice's existing cose-sign1 envelope (see room.cddl's key-epoch obligation), never a replacement for it. */
21
+ export declare function encryptNoticeContent(contentKey: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
22
+ /** Decrypts a room-notice's own `content`, given the content-encryption key for the epoch its key-epoch field names. Rejects on a wrong key or tampered ciphertext, same as unwrapContentKey. */
23
+ export declare function decryptNoticeContent(contentKey: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
24
+ //#endregion
@@ -0,0 +1,24 @@
1
+ //#region src/domain/group-key.d.ts
2
+ /**
3
+ * The symmetric half of room.rekey's own ECIES key-wrapping construction (wire-mesh#141): HKDF-SHA256 turning a raw ECDH shared secret into a per-(room, key-epoch) AES-256-GCM wrapping key, and AES-256-GCM itself for wrapping a room's content-encryption key and for encrypting a room-notice's own content under it. The asymmetric half (producing the shared secret) lives behind IdentityPort.deriveSharedSecret instead -- these functions operate only on plain bytes already in hand, with no platform-specific key-custody concern, so they need no port of their own (see IdentityPort.deriveSharedSecret's own doc comment).
4
+ *
5
+ * A fresh random IV is generated for every AES-256-GCM operation here and prepended to the output -- never a fixed or derived IV -- since a wrapping key derived once per (room, key-epoch) may legitimately wrap more than once (e.g. a resent room.rekey), and reusing an AES-GCM IV under the same key is catastrophic (it discloses the authentication key and lets an attacker forge subsequent messages).
6
+ */
7
+ /** Generates a fresh, random 256-bit room content-encryption key (the thing room.rekey wraps and distributes, and that encryptNoticeContent/decryptNoticeContent use directly). */
8
+ export declare function generateContentKey(): Uint8Array<ArrayBuffer>;
9
+ /**
10
+ * Derives an AES-256-GCM wrapping key from a raw ECDH shared secret (IdentityPort.deriveSharedSecret's own output) via HKDF-SHA256, with `info` binding the result to exactly one (room, key-epoch) pair -- see hkdfInfo. No explicit salt: static-static ECDH already produces a high-entropy, uniformly-distributed shared secret, so an empty salt is the standard, RFC 5869-sanctioned choice here rather than a corner cut (a salt matters most when the input key material's own entropy is questionable, which a P-256 ECDH output is not).
11
+ */
12
+ export declare function deriveWrappingKey(sharedSecret: Uint8Array, context: Readonly<{
13
+ room: string;
14
+ keyEpoch: number;
15
+ }>): Promise<CryptoKey>;
16
+ /** Wraps a room content-encryption key for delivery in room.rekey's own `wrapped-key` field. */
17
+ export declare function wrapContentKey(wrappingKey: CryptoKey, contentKey: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
18
+ /** Unwraps a room.rekey `wrapped-key` entry back into the room content-encryption key it carries. Rejects (never returns a garbage key) if the wrapping key or ciphertext don't match -- AES-GCM's own authentication tag catches both a wrong key and any tampering. */
19
+ export declare function unwrapContentKey(wrappingKey: CryptoKey, wrapped: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
20
+ /** Encrypts a room-notice's own `content` under the room's current content-encryption key -- encrypt-then-sign, layered underneath room-notice's existing cose-sign1 envelope (see room.cddl's key-epoch obligation), never a replacement for it. */
21
+ export declare function encryptNoticeContent(contentKey: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
22
+ /** Decrypts a room-notice's own `content`, given the content-encryption key for the epoch its key-epoch field names. Rejects on a wrong key or tampered ciphertext, same as unwrapContentKey. */
23
+ export declare function decryptNoticeContent(contentKey: Uint8Array, ciphertext: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
24
+ //#endregion
@@ -0,0 +1,87 @@
1
+ //#region src/domain/group-key.ts
2
+ const AES_KEY_BYTE_LENGTH = 32;
3
+ const AES_KEY_BIT_LENGTH = 256;
4
+ const GCM_IV_BYTE_LENGTH = 12;
5
+ const UINT32_BYTE_LENGTH = 4;
6
+ const UINT64_BYTE_LENGTH = 8;
7
+ const HKDF_INFO_PREFIX = new TextEncoder().encode("wire-mesh/room-rekey/v1\0");
8
+ /** Generates a fresh, random 256-bit room content-encryption key (the thing room.rekey wraps and distributes, and that encryptNoticeContent/decryptNoticeContent use directly). */
9
+ function generateContentKey() {
10
+ return crypto.getRandomValues(new Uint8Array(AES_KEY_BYTE_LENGTH));
11
+ }
12
+ /**
13
+ * Binds HKDF's own `info` parameter to exactly the (room, key-epoch) pair a wrapping key is for, so a wrapping key derived for one room or one epoch can never successfully unwrap ciphertext produced under another -- domain separation from the derivation itself, not merely a convention callers must remember to check. Length-prefixing the room path (rather than a bare separator byte) keeps the encoding unambiguous regardless of what characters a room path itself may contain.
14
+ */
15
+ function hkdfInfo(context) {
16
+ const roomBytes = new TextEncoder().encode(context.room);
17
+ const roomLength = new Uint8Array(UINT32_BYTE_LENGTH);
18
+ new DataView(roomLength.buffer).setUint32(0, roomBytes.length, false);
19
+ const keyEpoch = new Uint8Array(UINT64_BYTE_LENGTH);
20
+ new DataView(keyEpoch.buffer).setBigUint64(0, BigInt(context.keyEpoch), false);
21
+ const info = new Uint8Array(HKDF_INFO_PREFIX.length + roomLength.length + roomBytes.length + keyEpoch.length);
22
+ let offset = 0;
23
+ info.set(HKDF_INFO_PREFIX, offset);
24
+ offset += HKDF_INFO_PREFIX.length;
25
+ info.set(roomLength, offset);
26
+ offset += roomLength.length;
27
+ info.set(roomBytes, offset);
28
+ offset += roomBytes.length;
29
+ info.set(keyEpoch, offset);
30
+ return info;
31
+ }
32
+ /**
33
+ * Derives an AES-256-GCM wrapping key from a raw ECDH shared secret (IdentityPort.deriveSharedSecret's own output) via HKDF-SHA256, with `info` binding the result to exactly one (room, key-epoch) pair -- see hkdfInfo. No explicit salt: static-static ECDH already produces a high-entropy, uniformly-distributed shared secret, so an empty salt is the standard, RFC 5869-sanctioned choice here rather than a corner cut (a salt matters most when the input key material's own entropy is questionable, which a P-256 ECDH output is not).
34
+ */
35
+ async function deriveWrappingKey(sharedSecret, context) {
36
+ const ikm = await crypto.subtle.importKey("raw", Uint8Array.from(sharedSecret), "HKDF", false, ["deriveKey"]);
37
+ return crypto.subtle.deriveKey({
38
+ name: "HKDF",
39
+ hash: "SHA-256",
40
+ salt: Uint8Array.from(/* @__PURE__ */ new Uint8Array(0)),
41
+ info: Uint8Array.from(hkdfInfo(context))
42
+ }, ikm, {
43
+ name: "AES-GCM",
44
+ length: AES_KEY_BIT_LENGTH
45
+ }, false, ["encrypt", "decrypt"]);
46
+ }
47
+ async function aesGcmEncrypt(key, plaintext) {
48
+ const iv = crypto.getRandomValues(new Uint8Array(GCM_IV_BYTE_LENGTH));
49
+ const ciphertext = new Uint8Array(await crypto.subtle.encrypt({
50
+ name: "AES-GCM",
51
+ iv
52
+ }, key, Uint8Array.from(plaintext)));
53
+ const out = new Uint8Array(iv.length + ciphertext.length);
54
+ out.set(iv, 0);
55
+ out.set(ciphertext, iv.length);
56
+ return out;
57
+ }
58
+ async function aesGcmDecrypt(key, ivAndCiphertext) {
59
+ if (ivAndCiphertext.length < GCM_IV_BYTE_LENGTH) throw new Error("ciphertext shorter than the AES-GCM IV it must carry");
60
+ const iv = ivAndCiphertext.slice(0, GCM_IV_BYTE_LENGTH);
61
+ const ciphertext = ivAndCiphertext.slice(GCM_IV_BYTE_LENGTH);
62
+ return new Uint8Array(await crypto.subtle.decrypt({
63
+ name: "AES-GCM",
64
+ iv
65
+ }, key, ciphertext));
66
+ }
67
+ /** Wraps a room content-encryption key for delivery in room.rekey's own `wrapped-key` field. */
68
+ async function wrapContentKey(wrappingKey, contentKey) {
69
+ return aesGcmEncrypt(wrappingKey, contentKey);
70
+ }
71
+ /** Unwraps a room.rekey `wrapped-key` entry back into the room content-encryption key it carries. Rejects (never returns a garbage key) if the wrapping key or ciphertext don't match -- AES-GCM's own authentication tag catches both a wrong key and any tampering. */
72
+ async function unwrapContentKey(wrappingKey, wrapped) {
73
+ return aesGcmDecrypt(wrappingKey, wrapped);
74
+ }
75
+ async function importContentKey(contentKey) {
76
+ return crypto.subtle.importKey("raw", Uint8Array.from(contentKey), "AES-GCM", false, ["encrypt", "decrypt"]);
77
+ }
78
+ /** Encrypts a room-notice's own `content` under the room's current content-encryption key -- encrypt-then-sign, layered underneath room-notice's existing cose-sign1 envelope (see room.cddl's key-epoch obligation), never a replacement for it. */
79
+ async function encryptNoticeContent(contentKey, plaintext) {
80
+ return aesGcmEncrypt(await importContentKey(contentKey), plaintext);
81
+ }
82
+ /** Decrypts a room-notice's own `content`, given the content-encryption key for the epoch its key-epoch field names. Rejects on a wrong key or tampered ciphertext, same as unwrapContentKey. */
83
+ async function decryptNoticeContent(contentKey, ciphertext) {
84
+ return aesGcmDecrypt(await importContentKey(contentKey), ciphertext);
85
+ }
86
+ //#endregion
87
+ export { decryptNoticeContent, deriveWrappingKey, encryptNoticeContent, generateContentKey, unwrapContentKey, wrapContentKey };
@@ -1,4 +1,4 @@
1
- import { A as DomainId, R as HandshakeFrame, ot as ProtocolVersion } from "../protocol-sW8d6Og-.cjs";
1
+ import { A as DomainId, R as HandshakeFrame, ot as ProtocolVersion } from "../protocol-gbXtNeOc.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, ot as ProtocolVersion } from "../protocol-sW8d6Og-.mjs";
1
+ import { A as DomainId, R as HandshakeFrame, ot as ProtocolVersion } from "../protocol-gbXtNeOc.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;
@@ -1,7 +1,7 @@
1
- import { D as DeviceId, N as Frame, Q as PeerAdvert, U as ManageError, V as ManageCommand, W as ManageOk, _t as RevocationEntry, f as CapabilityScope, ot as ProtocolVersion, p as CapabilityToken } from "../protocol-sW8d6Og-.cjs";
2
- import { t as IdentityPort } from "../identity-DJ06jn4k.cjs";
1
+ import { D as DeviceId, N as Frame, Q as PeerAdvert, U as ManageError, V as ManageCommand, W as ManageOk, _t as RevocationEntry, f as CapabilityScope, ot as ProtocolVersion, p as CapabilityToken } from "../protocol-gbXtNeOc.cjs";
2
+ import { t as IdentityPort } from "../identity-B4XBWkqg.cjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.cjs";
4
- import { r as Transport, t as Connection } from "../transport-DxZ4JWZc.cjs";
4
+ import { r as Transport, t as Connection } from "../transport-DAsFqDDS.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, N as Frame, Q as PeerAdvert, U as ManageError, V as ManageCommand, W as ManageOk, _t as RevocationEntry, f as CapabilityScope, ot as ProtocolVersion, p as CapabilityToken } from "../protocol-sW8d6Og-.mjs";
2
- import { t as IdentityPort } from "../identity-C5N86BPz.mjs";
1
+ import { D as DeviceId, N as Frame, Q as PeerAdvert, U as ManageError, V as ManageCommand, W as ManageOk, _t as RevocationEntry, f as CapabilityScope, ot as ProtocolVersion, p as CapabilityToken } from "../protocol-gbXtNeOc.mjs";
2
+ import { t as IdentityPort } from "../identity-CIb9dGkJ.mjs";
3
3
  import { t as Clock } from "../clock-DiSx-WKM.mjs";
4
- import { r as Transport, t as Connection } from "../transport-B5E896PN.mjs";
4
+ import { r as Transport, t as Connection } from "../transport-Dy4h2eNY.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;
@@ -1,5 +1,5 @@
1
- import { N as Frame } from "../protocol-sW8d6Og-.cjs";
2
- import { t as Connection } from "../transport-DxZ4JWZc.cjs";
1
+ import { N as Frame } from "../protocol-gbXtNeOc.cjs";
2
+ import { t as Connection } from "../transport-DAsFqDDS.cjs";
3
3
  //#region src/domain/relay-hub.d.ts
4
4
  export interface RelayHub {
5
5
  /** Drives one accepted connection until it closes: registers gossip-advertised devices, re-broadcasts each gossip frame to every other connected client and replies to the gossiping connection with a catch-up frame of every other already-known device, answers relay-connect by pairing and notifying the target, and forwards relay-data within established pairings. Resolves when the connection's frame stream ends. Internally just registerConnection followed by a loop of onFrame calls and a final onDisconnect -- kept as its own method since a dedicated hub deployment (wire-mesh-node/cloudflare-hub) has nothing else driving the connection and wants the whole lifecycle in one call. */
@@ -1,5 +1,5 @@
1
- import { N as Frame } from "../protocol-sW8d6Og-.mjs";
2
- import { t as Connection } from "../transport-B5E896PN.mjs";
1
+ import { N as Frame } from "../protocol-gbXtNeOc.mjs";
2
+ import { t as Connection } from "../transport-Dy4h2eNY.mjs";
3
3
  //#region src/domain/relay-hub.d.ts
4
4
  export interface RelayHub {
5
5
  /** Drives one accepted connection until it closes: registers gossip-advertised devices, re-broadcasts each gossip frame to every other connected client and replies to the gossiping connection with a catch-up frame of every other already-known device, answers relay-connect by pairing and notifying the target, and forwards relay-data within established pairings. Resolves when the connection's frame stream ends. Internally just registerConnection followed by a loop of onFrame calls and a final onDisconnect -- kept as its own method since a dedicated hub deployment (wire-mesh-node/cloudflare-hub) has nothing else driving the connection and wants the whole lifecycle in one call. */
@@ -1,5 +1,5 @@
1
- import { N as Frame } from "../protocol-sW8d6Og-.cjs";
2
- import { t as Connection } from "../transport-DxZ4JWZc.cjs";
1
+ import { N as Frame } from "../protocol-gbXtNeOc.cjs";
2
+ import { t as Connection } from "../transport-DAsFqDDS.cjs";
3
3
  //#region src/domain/relay-use-gate.d.ts
4
4
  export interface RelayUseAuthorizationTracker {
5
5
  /** True once authorize() has been called for this exact connection and revoke() has not been called since. */