@dynamic-labs/waas 5.9.6 → 5.10.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,18 @@
1
1
 
2
+ ## [5.10.0](https://github.com/dynamic-labs/dynamic-auth/compare/v5.9.6...v5.10.0) (2026-10-09)
3
+
4
+
5
+ ### Features
6
+
7
+ * add lockWallets/lockWallet to re-lock password-encrypted WaaS wallets ([#12461](https://github.com/dynamic-labs/dynamic-auth/issues/12461)) ([090f544](https://github.com/dynamic-labs/dynamic-auth/commit/090f544150f4359bbfd9c0ffb4c450868adb6759))
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * **logger:** scope server error forwarding per instance ([#12477](https://github.com/dynamic-labs/dynamic-auth/issues/12477)) ([baa8c78](https://github.com/dynamic-labs/dynamic-auth/commit/baa8c780f4ef3cc35d62c363e03e74412ece91b9))
13
+ * **waas:** fall back when crypto.randomUUID is unavailable ([#12435](https://github.com/dynamic-labs/dynamic-auth/issues/12435)) ([5756f53](https://github.com/dynamic-labs/dynamic-auth/commit/5756f53423bd8316bce97e46ce38fc923fd5d574))
14
+ * **waas:** include every wallet in password update batches ([#12462](https://github.com/dynamic-labs/dynamic-auth/issues/12462)) ([80218f7](https://github.com/dynamic-labs/dynamic-auth/commit/80218f702dadfee9673cec4037889449bcd5ceb6))
15
+
2
16
  ### [5.9.6](https://github.com/dynamic-labs/dynamic-auth/compare/v5.9.5...v5.9.6) (2026-10-06)
3
17
 
4
18
  ### [5.9.5](https://github.com/dynamic-labs/dynamic-auth/compare/v5.9.4...v5.9.5) (2026-10-06)
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "5.9.6";
6
+ var version = "5.10.0";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "5.9.6";
2
+ var version = "5.10.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": "5.9.6",
3
+ "version": "5.10.0",
4
4
  "type": "module",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -17,19 +17,19 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@dynamic-labs-sdk/client": "1.37.0",
20
- "@dynamic-labs/assert-package-version": "5.9.6",
20
+ "@dynamic-labs/assert-package-version": "5.10.0",
21
21
  "@dynamic-labs/sdk-api-core": "0.70.0",
22
- "@dynamic-labs-wallet/browser-wallet-client": "1.1.27",
23
- "@dynamic-labs-wallet/core": "1.1.27",
22
+ "@dynamic-labs-wallet/browser-wallet-client": "1.1.33",
23
+ "@dynamic-labs-wallet/core": "1.1.29",
24
24
  "@dynamic-labs-wallet/forward-mpc-client": "1.0.2",
25
25
  "zod": "4.0.5",
26
- "@dynamic-labs/ethereum-core": "5.9.6",
27
- "@dynamic-labs/logger": "5.9.6",
28
- "@dynamic-labs/solana-core": "5.9.6",
29
- "@dynamic-labs/sui-core": "5.9.6",
30
- "@dynamic-labs/utils": "5.9.6",
31
- "@dynamic-labs/wallet-book": "5.9.6",
32
- "@dynamic-labs/wallet-connector-core": "5.9.6"
26
+ "@dynamic-labs/ethereum-core": "5.10.0",
27
+ "@dynamic-labs/logger": "5.10.0",
28
+ "@dynamic-labs/solana-core": "5.10.0",
29
+ "@dynamic-labs/sui-core": "5.10.0",
30
+ "@dynamic-labs/utils": "5.10.0",
31
+ "@dynamic-labs/wallet-book": "5.10.0",
32
+ "@dynamic-labs/wallet-connector-core": "5.10.0"
33
33
  },
34
34
  "peerDependencies": {}
35
35
  }
@@ -11,11 +11,23 @@ var _package = require('../package.cjs');
11
11
  var constants = require('../utils/constants.cjs');
12
12
  var createWaasClientSecureStorage = require('../utils/createWaasClientSecureStorage.cjs');
13
13
  var instrumentation = require('../utils/instrumentation.cjs');
14
+ var generateUUID = require('../utils/generateUUID.cjs');
14
15
  var tokenHasPendingAuthScope = require('../utils/tokenHasPendingAuthScope.cjs');
15
16
 
16
17
  // Fallback error code used when a thrown value carries no code, or when
17
18
  // formatting the error itself fails.
18
19
  const UNKNOWN_ERROR_CODE = 'unknown';
20
+ const PASSWORD_UPDATE_ACTIVATED_STATUS = 'activated';
21
+ const PASSWORD_UPDATE_NOT_ACTIVATED_CODE = 'password_update_not_activated';
22
+ // The server activates a password-update batch on the last wallet's check-in. Unless a
23
+ // wallet reports 'activated', the new password never took effect. A missing status is
24
+ // not proof of activation, so it fails closed too.
25
+ const assertPasswordUpdateActivated = (results) => {
26
+ const isActivated = results.some((result) => (result === null || result === void 0 ? void 0 : result.passwordUpdateStatus) === PASSWORD_UPDATE_ACTIVATED_STATUS);
27
+ if (!isActivated) {
28
+ throw new utils.DynamicError('Password update was not applied to all wallets. Please try again.', PASSWORD_UPDATE_NOT_ACTIVATED_CODE);
29
+ }
30
+ };
19
31
  // This class is common across all waas connectors
20
32
  class WaasExportHandler {
21
33
  constructor() {
@@ -729,13 +741,14 @@ const withDynamicWaas = (BaseClass) => {
729
741
  if (!this.getSignedSessionId) {
730
742
  throw new utils.DynamicError('Signed session ID is required', 'signed_session_id_is_required');
731
743
  }
744
+ // The server only activates the batch once every wallet of the user has
745
+ // checked in, so wallets that are not password-encrypted yet are included too.
732
746
  const wallets = yield walletClient.getAllWallets();
733
- const encryptedWallets = wallets.filter((w) => { var _a; return (_a = w.clientKeySharesBackupInfo) === null || _a === void 0 ? void 0 : _a.passwordEncrypted; });
734
- const passwordUpdateBatchId = crypto.randomUUID();
735
- yield Promise.all(encryptedWallets.map((wallet) => _tslib.__awaiter(this, void 0, void 0, function* () {
747
+ const passwordUpdateBatchId = generateUUID.generateUUID();
748
+ const results = yield Promise.all(wallets.map((wallet) => _tslib.__awaiter(this, void 0, void 0, function* () {
736
749
  var _b, _c;
737
750
  const signedSessionId = yield this.getSignedSessionId();
738
- yield walletClient.updatePassword({
751
+ return walletClient.updatePassword({
739
752
  accountAddress: wallet.accountAddress,
740
753
  authToken: (_b = this.getAuthToken) === null || _b === void 0 ? void 0 : _b.call(this),
741
754
  existingPassword: resolvedExistingPassword,
@@ -745,6 +758,7 @@ const withDynamicWaas = (BaseClass) => {
745
758
  signedSessionId,
746
759
  });
747
760
  })));
761
+ assertPasswordUpdateActivated(results);
748
762
  });
749
763
  }
750
764
  setPassword(_a) {
@@ -757,11 +771,11 @@ const withDynamicWaas = (BaseClass) => {
757
771
  throw new utils.DynamicError('Signed session ID is required', 'signed_session_id_is_required');
758
772
  }
759
773
  const wallets = yield walletClient.getAllWallets();
760
- const passwordUpdateBatchId = crypto.randomUUID();
761
- yield Promise.all(wallets.map((wallet) => _tslib.__awaiter(this, void 0, void 0, function* () {
774
+ const passwordUpdateBatchId = generateUUID.generateUUID();
775
+ const results = yield Promise.all(wallets.map((wallet) => _tslib.__awaiter(this, void 0, void 0, function* () {
762
776
  var _b, _c;
763
777
  const signedSessionId = yield this.getSignedSessionId();
764
- yield walletClient.setPassword({
778
+ return walletClient.setPassword({
765
779
  accountAddress: wallet.accountAddress,
766
780
  authToken: (_b = this.getAuthToken) === null || _b === void 0 ? void 0 : _b.call(this),
767
781
  newPassword,
@@ -770,6 +784,7 @@ const withDynamicWaas = (BaseClass) => {
770
784
  signedSessionId,
771
785
  });
772
786
  })));
787
+ assertPasswordUpdateActivated(results);
773
788
  });
774
789
  }
775
790
  signRawMessage(_a) {
@@ -825,6 +840,31 @@ const withDynamicWaas = (BaseClass) => {
825
840
  });
826
841
  });
827
842
  }
843
+ /**
844
+ * Re-locks every password-encrypted wallet: the iframe clears its stored
845
+ * decrypted client key shares, so the next wallet operation prompts for
846
+ * the wallet password again.
847
+ */
848
+ lockWallets() {
849
+ return _tslib.__awaiter(this, void 0, void 0, function* () {
850
+ var _a;
851
+ const walletClient = yield this.getWaasWalletClient();
852
+ return walletClient.lockWallets({ authToken: (_a = this.getAuthToken) === null || _a === void 0 ? void 0 : _a.call(this) });
853
+ });
854
+ }
855
+ /**
856
+ * Same re-lock semantics as `lockWallets`, scoped to a single wallet.
857
+ */
858
+ lockWallet(_a) {
859
+ return _tslib.__awaiter(this, arguments, void 0, function* ({ accountAddress }) {
860
+ var _b;
861
+ const walletClient = yield this.getWaasWalletClient();
862
+ return walletClient.lockWallets({
863
+ accountAddress,
864
+ authToken: (_b = this.getAuthToken) === null || _b === void 0 ? void 0 : _b.call(this),
865
+ });
866
+ });
867
+ }
828
868
  getWalletRecoveryState(_a) {
829
869
  return _tslib.__awaiter(this, arguments, void 0, function* ({ accountAddress, }) {
830
870
  var _b, _c;
@@ -206,6 +206,18 @@ export declare const withDynamicWaas: <T extends abstract new (...args: any[]) =
206
206
  accountAddress: string;
207
207
  password?: string;
208
208
  }): Promise<import("@dynamic-labs-wallet/browser-wallet-client").GetWalletResponse>;
209
+ /**
210
+ * Re-locks every password-encrypted wallet: the iframe clears its stored
211
+ * decrypted client key shares, so the next wallet operation prompts for
212
+ * the wallet password again.
213
+ */
214
+ lockWallets(): Promise<void>;
215
+ /**
216
+ * Same re-lock semantics as `lockWallets`, scoped to a single wallet.
217
+ */
218
+ lockWallet({ accountAddress }: {
219
+ accountAddress: string;
220
+ }): Promise<void>;
209
221
  getWalletRecoveryState({ accountAddress, }: {
210
222
  accountAddress: string;
211
223
  }): Promise<import("@dynamic-labs-wallet/browser-wallet-client").WalletRecoveryState>;
@@ -7,11 +7,23 @@ import { version } from '../package.js';
7
7
  import { DEFAULT_BASE_API_URL, DEFAULT_BASE_MPC_RELAY_API_URL } from '../utils/constants.js';
8
8
  import { createWaasClientSecureStorage } from '../utils/createWaasClientSecureStorage.js';
9
9
  import { InstrumentationTimer } from '../utils/instrumentation.js';
10
+ import { generateUUID } from '../utils/generateUUID.js';
10
11
  import { tokenHasPendingAuthScope } from '../utils/tokenHasPendingAuthScope.js';
11
12
 
12
13
  // Fallback error code used when a thrown value carries no code, or when
13
14
  // formatting the error itself fails.
14
15
  const UNKNOWN_ERROR_CODE = 'unknown';
16
+ const PASSWORD_UPDATE_ACTIVATED_STATUS = 'activated';
17
+ const PASSWORD_UPDATE_NOT_ACTIVATED_CODE = 'password_update_not_activated';
18
+ // The server activates a password-update batch on the last wallet's check-in. Unless a
19
+ // wallet reports 'activated', the new password never took effect. A missing status is
20
+ // not proof of activation, so it fails closed too.
21
+ const assertPasswordUpdateActivated = (results) => {
22
+ const isActivated = results.some((result) => (result === null || result === void 0 ? void 0 : result.passwordUpdateStatus) === PASSWORD_UPDATE_ACTIVATED_STATUS);
23
+ if (!isActivated) {
24
+ throw new DynamicError('Password update was not applied to all wallets. Please try again.', PASSWORD_UPDATE_NOT_ACTIVATED_CODE);
25
+ }
26
+ };
15
27
  // This class is common across all waas connectors
16
28
  class WaasExportHandler {
17
29
  constructor() {
@@ -725,13 +737,14 @@ const withDynamicWaas = (BaseClass) => {
725
737
  if (!this.getSignedSessionId) {
726
738
  throw new DynamicError('Signed session ID is required', 'signed_session_id_is_required');
727
739
  }
740
+ // The server only activates the batch once every wallet of the user has
741
+ // checked in, so wallets that are not password-encrypted yet are included too.
728
742
  const wallets = yield walletClient.getAllWallets();
729
- const encryptedWallets = wallets.filter((w) => { var _a; return (_a = w.clientKeySharesBackupInfo) === null || _a === void 0 ? void 0 : _a.passwordEncrypted; });
730
- const passwordUpdateBatchId = crypto.randomUUID();
731
- yield Promise.all(encryptedWallets.map((wallet) => __awaiter(this, void 0, void 0, function* () {
743
+ const passwordUpdateBatchId = generateUUID();
744
+ const results = yield Promise.all(wallets.map((wallet) => __awaiter(this, void 0, void 0, function* () {
732
745
  var _b, _c;
733
746
  const signedSessionId = yield this.getSignedSessionId();
734
- yield walletClient.updatePassword({
747
+ return walletClient.updatePassword({
735
748
  accountAddress: wallet.accountAddress,
736
749
  authToken: (_b = this.getAuthToken) === null || _b === void 0 ? void 0 : _b.call(this),
737
750
  existingPassword: resolvedExistingPassword,
@@ -741,6 +754,7 @@ const withDynamicWaas = (BaseClass) => {
741
754
  signedSessionId,
742
755
  });
743
756
  })));
757
+ assertPasswordUpdateActivated(results);
744
758
  });
745
759
  }
746
760
  setPassword(_a) {
@@ -753,11 +767,11 @@ const withDynamicWaas = (BaseClass) => {
753
767
  throw new DynamicError('Signed session ID is required', 'signed_session_id_is_required');
754
768
  }
755
769
  const wallets = yield walletClient.getAllWallets();
756
- const passwordUpdateBatchId = crypto.randomUUID();
757
- yield Promise.all(wallets.map((wallet) => __awaiter(this, void 0, void 0, function* () {
770
+ const passwordUpdateBatchId = generateUUID();
771
+ const results = yield Promise.all(wallets.map((wallet) => __awaiter(this, void 0, void 0, function* () {
758
772
  var _b, _c;
759
773
  const signedSessionId = yield this.getSignedSessionId();
760
- yield walletClient.setPassword({
774
+ return walletClient.setPassword({
761
775
  accountAddress: wallet.accountAddress,
762
776
  authToken: (_b = this.getAuthToken) === null || _b === void 0 ? void 0 : _b.call(this),
763
777
  newPassword,
@@ -766,6 +780,7 @@ const withDynamicWaas = (BaseClass) => {
766
780
  signedSessionId,
767
781
  });
768
782
  })));
783
+ assertPasswordUpdateActivated(results);
769
784
  });
770
785
  }
771
786
  signRawMessage(_a) {
@@ -821,6 +836,31 @@ const withDynamicWaas = (BaseClass) => {
821
836
  });
822
837
  });
823
838
  }
839
+ /**
840
+ * Re-locks every password-encrypted wallet: the iframe clears its stored
841
+ * decrypted client key shares, so the next wallet operation prompts for
842
+ * the wallet password again.
843
+ */
844
+ lockWallets() {
845
+ return __awaiter(this, void 0, void 0, function* () {
846
+ var _a;
847
+ const walletClient = yield this.getWaasWalletClient();
848
+ return walletClient.lockWallets({ authToken: (_a = this.getAuthToken) === null || _a === void 0 ? void 0 : _a.call(this) });
849
+ });
850
+ }
851
+ /**
852
+ * Same re-lock semantics as `lockWallets`, scoped to a single wallet.
853
+ */
854
+ lockWallet(_a) {
855
+ return __awaiter(this, arguments, void 0, function* ({ accountAddress }) {
856
+ var _b;
857
+ const walletClient = yield this.getWaasWalletClient();
858
+ return walletClient.lockWallets({
859
+ accountAddress,
860
+ authToken: (_b = this.getAuthToken) === null || _b === void 0 ? void 0 : _b.call(this),
861
+ });
862
+ });
863
+ }
824
864
  getWalletRecoveryState(_a) {
825
865
  return __awaiter(this, arguments, void 0, function* ({ accountAddress, }) {
826
866
  var _b, _c;
@@ -0,0 +1,23 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ // crypto.randomUUID is unavailable on older webviews (< Chrome 92) and in
7
+ // non-secure contexts; fall back to a getRandomValues-based v4 UUID there.
8
+ const generateUUID = () => {
9
+ const cryptoProvider = globalThis.crypto;
10
+ if (typeof (cryptoProvider === null || cryptoProvider === void 0 ? void 0 : cryptoProvider.randomUUID) === 'function') {
11
+ return cryptoProvider.randomUUID();
12
+ }
13
+ if (typeof (cryptoProvider === null || cryptoProvider === void 0 ? void 0 : cryptoProvider.getRandomValues) !== 'function') {
14
+ throw new TypeError('Secure UUID generation is unavailable');
15
+ }
16
+ const bytes = cryptoProvider.getRandomValues(new Uint8Array(16));
17
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
18
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
19
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
20
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
21
+ };
22
+
23
+ exports.generateUUID = generateUUID;
@@ -0,0 +1 @@
1
+ export declare const generateUUID: () => string;
@@ -0,0 +1,19 @@
1
+ 'use client'
2
+ // crypto.randomUUID is unavailable on older webviews (< Chrome 92) and in
3
+ // non-secure contexts; fall back to a getRandomValues-based v4 UUID there.
4
+ const generateUUID = () => {
5
+ const cryptoProvider = globalThis.crypto;
6
+ if (typeof (cryptoProvider === null || cryptoProvider === void 0 ? void 0 : cryptoProvider.randomUUID) === 'function') {
7
+ return cryptoProvider.randomUUID();
8
+ }
9
+ if (typeof (cryptoProvider === null || cryptoProvider === void 0 ? void 0 : cryptoProvider.getRandomValues) !== 'function') {
10
+ throw new TypeError('Secure UUID generation is unavailable');
11
+ }
12
+ const bytes = cryptoProvider.getRandomValues(new Uint8Array(16));
13
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
14
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
15
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
16
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
17
+ };
18
+
19
+ export { generateUUID };