@dynamic-labs/waas 4.88.6 → 4.89.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.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,19 @@
1
1
 
2
+ ## [4.89.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.88.6...v4.89.0) (2026-06-16)
3
+
4
+
5
+ ### Features
6
+
7
+ * **moonpay:** add useMoonPayOnramp hook ([#11405](https://github.com/dynamic-labs/dynamic-auth/issues/11405)) ([48cb62f](https://github.com/dynamic-labs/dynamic-auth/commit/48cb62fefecb511fcba9359ee6f6096dfef0b125))
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * get wallet metadata from wallet-book when its present ([#11566](https://github.com/dynamic-labs/dynamic-auth/issues/11566)) ([a1a8ad5](https://github.com/dynamic-labs/dynamic-auth/commit/a1a8ad53c063157b189aea138fa338fcc67dc4dd))
13
+ * **waas:** instant logout — clear key share host-side, background iframe cleanup ([#11583](https://github.com/dynamic-labs/dynamic-auth/issues/11583)) ([0ab3378](https://github.com/dynamic-labs/dynamic-auth/commit/0ab3378efdbbe233069b17fad62b0c126397bc3a))
14
+ * **wagmi-connector:** await disconnect before connect to defuse SyncDynamicWagmi race DYNT-549 ([#11579](https://github.com/dynamic-labs/dynamic-auth/issues/11579)) ([6ac7c0e](https://github.com/dynamic-labs/dynamic-auth/commit/6ac7c0e02ed863342047bc5a1e60be3a66b8a425)), closes [#11131](https://github.com/dynamic-labs/dynamic-auth/issues/11131) [#11513](https://github.com/dynamic-labs/dynamic-auth/issues/11513) [#11516](https://github.com/dynamic-labs/dynamic-auth/issues/11516) [#11496](https://github.com/dynamic-labs/dynamic-auth/issues/11496) [#11513](https://github.com/dynamic-labs/dynamic-auth/issues/11513) [/github.com/dynamic-labs/dynamic-auth/blob/main/packages/wagmi-connector/src/lib/hooks/useConnectorId/useConnectorId.ts#L19-L26](https://github.com/dynamic-labs//github.com/dynamic-labs/dynamic-auth/blob/main/packages/wagmi-connector/src/lib/hooks/useConnectorId/useConnectorId.ts/issues/L19-L26) [#11131](https://github.com/dynamic-labs/dynamic-auth/issues/11131) [#11516](https://github.com/dynamic-labs/dynamic-auth/issues/11516) [#11513](https://github.com/dynamic-labs/dynamic-auth/issues/11513)
15
+ * **react-native:** resolve intermittent "Wallet with id <uuid> not found" after login ([#11575](https://github.com/dynamic-labs/dynamic-auth/issues/11575)) ([9d7a246](https://github.com/dynamic-labs/dynamic-auth/commit/9d7a246167927b9339dc33c10977c6d12783ab88))
16
+
2
17
  ### [4.88.6](https://github.com/dynamic-labs/dynamic-auth/compare/v4.88.5...v4.88.6) (2026-06-13)
3
18
 
4
19
 
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.88.6";
6
+ var version = "4.89.0";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "4.88.6";
2
+ var version = "4.89.0";
3
3
 
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/waas",
3
- "version": "4.88.6",
3
+ "version": "4.89.0",
4
4
  "type": "module",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -17,17 +17,17 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@dynamic-labs-sdk/client": "1.8.2",
20
- "@dynamic-labs/assert-package-version": "4.88.6",
20
+ "@dynamic-labs/assert-package-version": "4.89.0",
21
21
  "@dynamic-labs/sdk-api-core": "0.0.1015",
22
22
  "@dynamic-labs-wallet/browser-wallet-client": "1.0.16",
23
23
  "@dynamic-labs-wallet/forward-mpc-client": "0.10.1",
24
- "@dynamic-labs/ethereum-core": "4.88.6",
25
- "@dynamic-labs/logger": "4.88.6",
26
- "@dynamic-labs/solana-core": "4.88.6",
27
- "@dynamic-labs/sui-core": "4.88.6",
28
- "@dynamic-labs/utils": "4.88.6",
29
- "@dynamic-labs/wallet-book": "4.88.6",
30
- "@dynamic-labs/wallet-connector-core": "4.88.6"
24
+ "@dynamic-labs/ethereum-core": "4.89.0",
25
+ "@dynamic-labs/logger": "4.89.0",
26
+ "@dynamic-labs/solana-core": "4.89.0",
27
+ "@dynamic-labs/sui-core": "4.89.0",
28
+ "@dynamic-labs/utils": "4.89.0",
29
+ "@dynamic-labs/wallet-book": "4.89.0",
30
+ "@dynamic-labs/wallet-connector-core": "4.89.0"
31
31
  },
32
32
  "peerDependencies": {}
33
33
  }
@@ -12,6 +12,9 @@ var constants = require('../utils/constants.cjs');
12
12
  var createWaasClientSecureStorage = require('../utils/createWaasClientSecureStorage.cjs');
13
13
  var instrumentation = require('../utils/instrumentation.cjs');
14
14
 
15
+ // Fallback error code used when a thrown value carries no code, or when
16
+ // formatting the error itself fails.
17
+ const UNKNOWN_ERROR_CODE = 'unknown';
15
18
  // This class is common across all waas connectors
16
19
  class WaasExportHandler {
17
20
  constructor() {
@@ -624,7 +627,28 @@ const withDynamicWaas = (BaseClass) => {
624
627
  // in. On explicit user-initiated logout, shares are always cleared for
625
628
  // security.
626
629
  if (reason !== 'token-expired') {
627
- yield waasClient.cleanup();
630
+ // Clear the MPC key share directly on the host's local secure storage.
631
+ // This is fast and guaranteed, independent of the iframe round-trip
632
+ // cleanup below — whose request-channel timeout (plus a recovery retry)
633
+ // can block logout for ~10s on slow devices where secureStorage is slow
634
+ // to ACK. Awaited because it is a local operation (milliseconds).
635
+ const accountAddress = yield this.getActiveAccountAddress();
636
+ if (accountAddress) {
637
+ try {
638
+ yield createWaasClientSecureStorage.createWaasClientSecureStorage().removeClientKeyShare(accountAddress);
639
+ }
640
+ catch (error) {
641
+ this.instrument('[endSession] direct key share removal failed', Object.assign({ key: 'endSession-removeClientKeyShare-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
642
+ }
643
+ }
644
+ // Tear down the iframe and run its best-effort storage cleanup in the
645
+ // background so logout returns immediately instead of blocking on the
646
+ // iframe cleanup's request-channel timeout. The iframe handler already
647
+ // swallows its own errors, and the DOM teardown obsoletes anything it
648
+ // misses. Promise.resolve guards against a non-promise return in tests.
649
+ void Promise.resolve(waasClient.cleanup()).catch((error) => {
650
+ this.instrument('[endSession] background iframe cleanup failed', Object.assign({ key: 'endSession-cleanup-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
651
+ });
628
652
  }
629
653
  this.dynamicWaasClient = undefined;
630
654
  });
@@ -661,6 +685,33 @@ const withDynamicWaas = (BaseClass) => {
661
685
  .map((byte) => byte.toString(16).padStart(2, '0'))
662
686
  .join('');
663
687
  }
688
+ /**
689
+ * Normalizes an unknown thrown value into the error fields used across
690
+ * instrumentation so callers don't re-derive them at each catch site.
691
+ *
692
+ * Wrapped in try/catch: this is best-effort logging, and a value that
693
+ * resists formatting (e.g. an object whose toString throws) must never
694
+ * turn a log line into an exception that blocks the calling flow such as
695
+ * logout.
696
+ *
697
+ * `public` (not `private`) because the TS `private` keyword can't be used
698
+ * on this mixin's exported class expression (TS4094), and ECMAScript
699
+ * `#private` isn't supported by the package's Jest/Babel transform. It is
700
+ * internal-only despite the modifier — same constraint as `instrument`.
701
+ */
702
+ buildErrorInstrumentContext(error) {
703
+ var _a, _b;
704
+ try {
705
+ return {
706
+ errorCode: (_a = error === null || error === void 0 ? void 0 : error.code) !== null && _a !== void 0 ? _a : UNKNOWN_ERROR_CODE,
707
+ errorMessage: error instanceof Error ? error.message : String(error),
708
+ errorType: (_b = error === null || error === void 0 ? void 0 : error.constructor) === null || _b === void 0 ? void 0 : _b.name,
709
+ };
710
+ }
711
+ catch (_c) {
712
+ return { errorCode: UNKNOWN_ERROR_CODE };
713
+ }
714
+ }
664
715
  /**
665
716
  * Helper method to instrument with automatic properties inclusion
666
717
  */
@@ -676,7 +727,6 @@ const withDynamicWaas = (BaseClass) => {
676
727
  }
677
728
  instrumentAsync(_a) {
678
729
  return _tslib.__awaiter(this, arguments, void 0, function* ({ operation, resource, fn, context, }) {
679
- var _b, _c;
680
730
  const timing = new instrumentation.InstrumentationTimer(context === null || context === void 0 ? void 0 : context.startTime);
681
731
  if (context === null || context === void 0 ? void 0 : context.stepStartTime) {
682
732
  timing.setStepStartTime(context.stepStartTime);
@@ -693,11 +743,7 @@ const withDynamicWaas = (BaseClass) => {
693
743
  catch (error) {
694
744
  const isUserRejection = error instanceof utils.UserRejectedRequestError ||
695
745
  (error === null || error === void 0 ? void 0 : error.code) === 'user_rejected_request';
696
- const errorContext = {
697
- errorCode: (_b = error === null || error === void 0 ? void 0 : error.code) !== null && _b !== void 0 ? _b : 'unknown',
698
- errorMessage: error instanceof Error ? error.message : String(error),
699
- errorType: (_c = error === null || error === void 0 ? void 0 : error.constructor) === null || _c === void 0 ? void 0 : _c.name,
700
- };
746
+ const errorContext = this.buildErrorInstrumentContext(error);
701
747
  if (isUserRejection) {
702
748
  // User-initiated cancellations are expected — debug only, no backend noise
703
749
  this.logger.debug(`[${operation}] ${resource} - cancelled`, Object.assign(Object.assign({ key: `${resource}-cancelled`, operation, stepTime: timing.getStepElapsed(), time: timing.getElapsed() }, context), errorContext));
@@ -166,6 +166,29 @@ export declare const withDynamicWaas: <T extends abstract new (...args: any[]) =
166
166
  */
167
167
  getConnectedAccounts(): Promise<string[]>;
168
168
  generateTraceId(): string;
169
+ /**
170
+ * Normalizes an unknown thrown value into the error fields used across
171
+ * instrumentation so callers don't re-derive them at each catch site.
172
+ *
173
+ * Wrapped in try/catch: this is best-effort logging, and a value that
174
+ * resists formatting (e.g. an object whose toString throws) must never
175
+ * turn a log line into an exception that blocks the calling flow such as
176
+ * logout.
177
+ *
178
+ * `public` (not `private`) because the TS `private` keyword can't be used
179
+ * on this mixin's exported class expression (TS4094), and ECMAScript
180
+ * `#private` isn't supported by the package's Jest/Babel transform. It is
181
+ * internal-only despite the modifier — same constraint as `instrument`.
182
+ */
183
+ buildErrorInstrumentContext(error: unknown): {
184
+ errorCode: string | import("@dynamic-labs/utils").ErrorCode;
185
+ errorMessage: string;
186
+ errorType: string | undefined;
187
+ } | {
188
+ errorCode: string;
189
+ errorMessage?: undefined;
190
+ errorType?: undefined;
191
+ };
169
192
  /**
170
193
  * Helper method to instrument with automatic properties inclusion
171
194
  */
@@ -8,6 +8,9 @@ import { DEFAULT_BASE_API_URL, DEFAULT_BASE_MPC_RELAY_API_URL } from '../utils/c
8
8
  import { createWaasClientSecureStorage } from '../utils/createWaasClientSecureStorage.js';
9
9
  import { InstrumentationTimer } from '../utils/instrumentation.js';
10
10
 
11
+ // Fallback error code used when a thrown value carries no code, or when
12
+ // formatting the error itself fails.
13
+ const UNKNOWN_ERROR_CODE = 'unknown';
11
14
  // This class is common across all waas connectors
12
15
  class WaasExportHandler {
13
16
  constructor() {
@@ -620,7 +623,28 @@ const withDynamicWaas = (BaseClass) => {
620
623
  // in. On explicit user-initiated logout, shares are always cleared for
621
624
  // security.
622
625
  if (reason !== 'token-expired') {
623
- yield waasClient.cleanup();
626
+ // Clear the MPC key share directly on the host's local secure storage.
627
+ // This is fast and guaranteed, independent of the iframe round-trip
628
+ // cleanup below — whose request-channel timeout (plus a recovery retry)
629
+ // can block logout for ~10s on slow devices where secureStorage is slow
630
+ // to ACK. Awaited because it is a local operation (milliseconds).
631
+ const accountAddress = yield this.getActiveAccountAddress();
632
+ if (accountAddress) {
633
+ try {
634
+ yield createWaasClientSecureStorage().removeClientKeyShare(accountAddress);
635
+ }
636
+ catch (error) {
637
+ this.instrument('[endSession] direct key share removal failed', Object.assign({ key: 'endSession-removeClientKeyShare-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
638
+ }
639
+ }
640
+ // Tear down the iframe and run its best-effort storage cleanup in the
641
+ // background so logout returns immediately instead of blocking on the
642
+ // iframe cleanup's request-channel timeout. The iframe handler already
643
+ // swallows its own errors, and the DOM teardown obsoletes anything it
644
+ // misses. Promise.resolve guards against a non-promise return in tests.
645
+ void Promise.resolve(waasClient.cleanup()).catch((error) => {
646
+ this.instrument('[endSession] background iframe cleanup failed', Object.assign({ key: 'endSession-cleanup-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
647
+ });
624
648
  }
625
649
  this.dynamicWaasClient = undefined;
626
650
  });
@@ -657,6 +681,33 @@ const withDynamicWaas = (BaseClass) => {
657
681
  .map((byte) => byte.toString(16).padStart(2, '0'))
658
682
  .join('');
659
683
  }
684
+ /**
685
+ * Normalizes an unknown thrown value into the error fields used across
686
+ * instrumentation so callers don't re-derive them at each catch site.
687
+ *
688
+ * Wrapped in try/catch: this is best-effort logging, and a value that
689
+ * resists formatting (e.g. an object whose toString throws) must never
690
+ * turn a log line into an exception that blocks the calling flow such as
691
+ * logout.
692
+ *
693
+ * `public` (not `private`) because the TS `private` keyword can't be used
694
+ * on this mixin's exported class expression (TS4094), and ECMAScript
695
+ * `#private` isn't supported by the package's Jest/Babel transform. It is
696
+ * internal-only despite the modifier — same constraint as `instrument`.
697
+ */
698
+ buildErrorInstrumentContext(error) {
699
+ var _a, _b;
700
+ try {
701
+ return {
702
+ errorCode: (_a = error === null || error === void 0 ? void 0 : error.code) !== null && _a !== void 0 ? _a : UNKNOWN_ERROR_CODE,
703
+ errorMessage: error instanceof Error ? error.message : String(error),
704
+ errorType: (_b = error === null || error === void 0 ? void 0 : error.constructor) === null || _b === void 0 ? void 0 : _b.name,
705
+ };
706
+ }
707
+ catch (_c) {
708
+ return { errorCode: UNKNOWN_ERROR_CODE };
709
+ }
710
+ }
660
711
  /**
661
712
  * Helper method to instrument with automatic properties inclusion
662
713
  */
@@ -672,7 +723,6 @@ const withDynamicWaas = (BaseClass) => {
672
723
  }
673
724
  instrumentAsync(_a) {
674
725
  return __awaiter(this, arguments, void 0, function* ({ operation, resource, fn, context, }) {
675
- var _b, _c;
676
726
  const timing = new InstrumentationTimer(context === null || context === void 0 ? void 0 : context.startTime);
677
727
  if (context === null || context === void 0 ? void 0 : context.stepStartTime) {
678
728
  timing.setStepStartTime(context.stepStartTime);
@@ -689,11 +739,7 @@ const withDynamicWaas = (BaseClass) => {
689
739
  catch (error) {
690
740
  const isUserRejection = error instanceof UserRejectedRequestError ||
691
741
  (error === null || error === void 0 ? void 0 : error.code) === 'user_rejected_request';
692
- const errorContext = {
693
- errorCode: (_b = error === null || error === void 0 ? void 0 : error.code) !== null && _b !== void 0 ? _b : 'unknown',
694
- errorMessage: error instanceof Error ? error.message : String(error),
695
- errorType: (_c = error === null || error === void 0 ? void 0 : error.constructor) === null || _c === void 0 ? void 0 : _c.name,
696
- };
742
+ const errorContext = this.buildErrorInstrumentContext(error);
697
743
  if (isUserRejection) {
698
744
  // User-initiated cancellations are expected — debug only, no backend noise
699
745
  this.logger.debug(`[${operation}] ${resource} - cancelled`, Object.assign(Object.assign({ key: `${resource}-cancelled`, operation, stepTime: timing.getStepElapsed(), time: timing.getElapsed() }, context), errorContext));