@dynamic-labs-wallet/forward-mpc-client 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -216,7 +216,7 @@ interface ForwardMPCClientV2Options {
216
216
  }
217
217
  interface ClientV2Events {
218
218
  connected: () => void;
219
- disconnected: () => void;
219
+ disconnected: (closeCode: number) => void;
220
220
  error: (error: Error) => void;
221
221
  }
222
222
  declare class ForwardMPCClientV2 extends EventEmitter$1<ClientV2Events> {
@@ -270,10 +270,11 @@ declare class ForwardMPCClientV2 extends EventEmitter$1<ClientV2Events> {
270
270
  private onTransportDisconnected;
271
271
  }
272
272
 
273
+ /**
274
+ * @deprecated Use {@link ForwardMPCClientV2} directly and manage the instance
275
+ * lifecycle yourself. This class will be removed in a future version.
276
+ */
273
277
  declare class ForwardMPCClientSingleton extends ForwardMPCClientV2 {
274
- private static _instance;
275
- constructor(url: string, options?: ForwardMPCClientV2Options);
276
- disconnect(): void;
277
278
  }
278
279
 
279
280
  declare const ErrorCode: {
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import EventEmitter2, { EventEmitter } from 'eventemitter3';
2
2
  import * as ws from 'ws';
3
- import { messageRegistry, generateMlKem768Keypair, HandshakeV1RequestMessage, decapsulateMlKem768, encryptKeyshare, SignMessageV1RequestMessage, encryptKeygenInit, KeygenV1RequestMessage, decryptKeygenResult, ReceiveKeyV1RequestMessage, fromDynamicSigningAlgorithm } from '@dynamic-labs-wallet/forward-mpc-shared';
3
+ import { messageRegistry, generateMlKem768Keypair, HandshakeV1RequestMessage, decapsulateMlKem768, encryptKeyshare, SignMessageV1RequestMessage, encryptKeygenInit, KeygenV1RequestMessage, decryptKeygenResult, ReceiveKeyV1RequestMessage, WebSocketCloseCode, fromDynamicSigningAlgorithm } from '@dynamic-labs-wallet/forward-mpc-shared';
4
4
  import init, { PCRs, validateAttestationDocPcrs, getUserData, getNonce } from '@evervault/wasm-attestation-bindings';
5
5
  import { sha256 } from '@noble/hashes/sha2.js';
6
6
  import { randomBytes, hexToBytes } from '@noble/hashes/utils.js';
@@ -563,8 +563,6 @@ var ForwardMPCClient = class extends EventEmitter {
563
563
  }
564
564
  }
565
565
  };
566
-
567
- // src/client-v2/errors.ts
568
566
  var ErrorCode = {
569
567
  // Transport
570
568
  CONNECTION_FAILED: "CONNECTION_FAILED",
@@ -805,7 +803,7 @@ var ForwardMPCTransport = class extends EventEmitter2 {
805
803
  this.ws = null;
806
804
  }
807
805
  this._isConnected = false;
808
- this.emit("disconnected");
806
+ this.emit("disconnected", WebSocketCloseCode.NORMAL);
809
807
  }
810
808
  send(data) {
811
809
  if (!this._isConnected || !this.ws) {
@@ -863,23 +861,35 @@ var ForwardMPCTransport = class extends EventEmitter2 {
863
861
  });
864
862
  this.emit("message", event.data);
865
863
  };
866
- this.ws.onclose = () => {
864
+ this.ws.onclose = (event) => {
867
865
  this._isConnected = false;
866
+ this.logger?.warn("WebSocket closed", {
867
+ url: this.url,
868
+ closeCode: event.code
869
+ });
868
870
  if (!this._destroyed) {
869
- this.emit("disconnected");
871
+ this.emit("disconnected", event.code);
870
872
  }
871
- this.maybeReconnect();
873
+ this.maybeReconnect(event.code);
872
874
  };
873
875
  });
874
876
  }
875
877
  /**
876
878
  * Attempts mid-session reconnects after a drop, up to `reconnectAttempts`
877
- * times. Only fires when a successful connection was previously established.
879
+ * times. Only fires when a successful connection was previously established
880
+ * and the close was unexpected (not a normal or idle-timeout close).
878
881
  */
879
- maybeReconnect() {
882
+ maybeReconnect(closeCode) {
880
883
  if (this._destroyed) return;
881
884
  if (!this._hadSuccessfulConnection) return;
882
885
  if (this._midSessionReconnectCount >= this.options.reconnectAttempts) return;
886
+ if (closeCode === WebSocketCloseCode.NORMAL || closeCode === WebSocketCloseCode.IDLE_TIMEOUT) {
887
+ this.logger?.info("WebSocket closed gracefully \u2014 not reconnecting", {
888
+ url: this.url,
889
+ closeCode
890
+ });
891
+ return;
892
+ }
883
893
  this._midSessionReconnectCount++;
884
894
  this.logger?.warn("WebSocket disconnected \u2014 attempting reconnect", {
885
895
  url: this.url,
@@ -1169,7 +1179,7 @@ var ForwardMPCClientV2 = class extends EventEmitter2 {
1169
1179
  requestTimeout: options.requestTimeout
1170
1180
  };
1171
1181
  this.transport.on("connected", () => this.onTransportConnected());
1172
- this.transport.on("disconnected", () => this.onTransportDisconnected());
1182
+ this.transport.on("disconnected", (closeCode) => this.onTransportDisconnected(closeCode));
1173
1183
  this.transport.on("error", (error) => this.emit("error", error));
1174
1184
  }
1175
1185
  get connected() {
@@ -1328,7 +1338,7 @@ var ForwardMPCClientV2 = class extends EventEmitter2 {
1328
1338
  }, "doHandshake");
1329
1339
  this._connectPromise = doHandshake();
1330
1340
  }
1331
- onTransportDisconnected() {
1341
+ onTransportDisconnected(closeCode) {
1332
1342
  const intentional = this._disconnectedIntentionally;
1333
1343
  this._disconnectedIntentionally = false;
1334
1344
  this.session?.dispose();
@@ -1336,54 +1346,15 @@ var ForwardMPCClientV2 = class extends EventEmitter2 {
1336
1346
  if (!intentional) {
1337
1347
  this.logger.warn("Unexpected WebSocket disconnect");
1338
1348
  }
1339
- this.emit("disconnected");
1349
+ this.emit("disconnected", closeCode);
1340
1350
  }
1341
1351
  };
1342
1352
 
1343
- // src/client-v2/utils.ts
1344
- function deepEqual(obj1, obj2) {
1345
- if (obj1 === obj2) return true;
1346
- if (typeof obj1 !== "object" || obj1 === null || typeof obj2 !== "object" || obj2 === null) {
1347
- return false;
1348
- }
1349
- const keys1 = Object.keys(obj1);
1350
- const keys2 = Object.keys(obj2);
1351
- if (keys1.length !== keys2.length) return false;
1352
- for (const key of keys1) {
1353
- if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
1354
- return false;
1355
- }
1356
- }
1357
- return true;
1358
- }
1359
- __name(deepEqual, "deepEqual");
1360
-
1361
1353
  // src/client-v2/singleton.ts
1362
- var ForwardMPCClientSingleton = class _ForwardMPCClientSingleton extends ForwardMPCClientV2 {
1354
+ var ForwardMPCClientSingleton = class extends ForwardMPCClientV2 {
1363
1355
  static {
1364
1356
  __name(this, "ForwardMPCClientSingleton");
1365
1357
  }
1366
- static _instance = null;
1367
- constructor(url, options) {
1368
- const existing = _ForwardMPCClientSingleton._instance;
1369
- if (existing !== null) {
1370
- if (existing.url !== url) {
1371
- throw new Error(`ForwardMPCClientSingleton already exists for "${existing.url}". Call disconnect() first to create a new instance.`);
1372
- }
1373
- if (!deepEqual(options, existing.options)) {
1374
- throw new Error(`ForwardMPCClientSingleton already exists for the same URL but with different options.Call disconnect() first to create a new instance.`);
1375
- }
1376
- return existing;
1377
- }
1378
- super(url, options);
1379
- _ForwardMPCClientSingleton._instance = this;
1380
- }
1381
- disconnect() {
1382
- super.disconnect();
1383
- if (_ForwardMPCClientSingleton._instance === this) {
1384
- _ForwardMPCClientSingleton._instance = null;
1385
- }
1386
- }
1387
1358
  };
1388
1359
 
1389
1360
  export { ClientError, ClientSessionEstablishFailedError, ClientUnsupportedAlgorithmError, ErrorCode, ForwardMPCClient, ForwardMPCClientSingleton, ForwardMPCClientV2, ForwardMPCError, ForwardMPCErrorType, NitroAttestationVerifier, SessionAttestationError, SessionAttestationNonceMissingError, SessionDisposedError, SessionError, SessionHandshakeError, SessionHandshakeInvalidResponseError, SessionMessageParseError, SessionRemoteError, SessionRequestTimeoutError, SessionServerError, TransportConnectionError, TransportConnectionTimeoutError, TransportError, TransportNotConnectedError };