@dynamic-labs/sdk-react-core 4.31.3 → 4.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.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,23 @@
1
1
 
2
+ ## [4.32.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.31.4...v4.32.0) (2025-09-17)
3
+
4
+
5
+ ### Features
6
+
7
+ * add methods to check if mfa recovery codes are ackowledged and generate new ones ([#9511](https://github.com/dynamic-labs/dynamic-auth/issues/9511)) ([23598b3](https://github.com/dynamic-labs/dynamic-auth/commit/23598b38b1b3ec75b9aa601a00971a9d5268ab8f))
8
+
9
+
10
+ ### Bug Fixes
11
+
12
+ * primaryWalletChanged not emitted on login with same wallet ([#9515](https://github.com/dynamic-labs/dynamic-auth/issues/9515)) ([cf42dfa](https://github.com/dynamic-labs/dynamic-auth/commit/cf42dfa69daf123c4a796d0fc926c72b44427734))
13
+
14
+ ### [4.31.4](https://github.com/dynamic-labs/dynamic-auth/compare/v4.31.3...v4.31.4) (2025-09-16)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * prevent useUserWallets from returning empty array when cancelling wallet connect connection ([#9500](https://github.com/dynamic-labs/dynamic-auth/issues/9500)) ([850f03c](https://github.com/dynamic-labs/dynamic-auth/commit/850f03cdc954da5a2af5285d873fc02a2f95e09e))
20
+
2
21
  ### [4.31.3](https://github.com/dynamic-labs/dynamic-auth/compare/v4.31.2...v4.31.3) (2025-09-15)
3
22
 
4
23
 
package/package.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "4.31.3";
6
+ var version = "4.32.0";
7
7
  var dependencies = {
8
8
  "@dynamic-labs/sdk-api-core": "0.0.762",
9
9
  "@dynamic-labs-sdk/client": "0.1.0-alpha.3",
package/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- var version = "4.31.3";
2
+ var version = "4.32.0";
3
3
  var dependencies = {
4
4
  "@dynamic-labs/sdk-api-core": "0.0.762",
5
5
  "@dynamic-labs-sdk/client": "0.1.0-alpha.3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/sdk-react-core",
3
- "version": "4.31.3",
3
+ "version": "4.32.0",
4
4
  "dependencies": {
5
5
  "@dynamic-labs/sdk-api-core": "0.0.762",
6
6
  "@dynamic-labs-sdk/client": "0.1.0-alpha.3",
@@ -15,16 +15,16 @@
15
15
  "yup": "0.32.11",
16
16
  "react-international-phone": "4.5.0",
17
17
  "bs58": "5.0.0",
18
- "@dynamic-labs/assert-package-version": "4.31.3",
19
- "@dynamic-labs/iconic": "4.31.3",
20
- "@dynamic-labs/logger": "4.31.3",
21
- "@dynamic-labs/multi-wallet": "4.31.3",
22
- "@dynamic-labs/rpc-providers": "4.31.3",
23
- "@dynamic-labs/store": "4.31.3",
24
- "@dynamic-labs/types": "4.31.3",
25
- "@dynamic-labs/utils": "4.31.3",
26
- "@dynamic-labs/wallet-book": "4.31.3",
27
- "@dynamic-labs/wallet-connector-core": "4.31.3",
18
+ "@dynamic-labs/assert-package-version": "4.32.0",
19
+ "@dynamic-labs/iconic": "4.32.0",
20
+ "@dynamic-labs/logger": "4.32.0",
21
+ "@dynamic-labs/multi-wallet": "4.32.0",
22
+ "@dynamic-labs/rpc-providers": "4.32.0",
23
+ "@dynamic-labs/store": "4.32.0",
24
+ "@dynamic-labs/types": "4.32.0",
25
+ "@dynamic-labs/utils": "4.32.0",
26
+ "@dynamic-labs/wallet-book": "4.32.0",
27
+ "@dynamic-labs/wallet-connector-core": "4.32.0",
28
28
  "eventemitter3": "5.0.1"
29
29
  },
30
30
  "devDependencies": {
@@ -7,6 +7,7 @@ var jsxRuntime = require('react/jsx-runtime');
7
7
  var React = require('react');
8
8
  var useDynamicEvents = require('../../utils/hooks/events/useDynamicEvents/useDynamicEvents.cjs');
9
9
  var ErrorContext = require('../ErrorContext/ErrorContext.cjs');
10
+ var dynamicEvents = require('../../events/dynamicEvents.cjs');
10
11
 
11
12
  const ViewContext = React.createContext(undefined);
12
13
  const ViewContextProvider = ({ children, initialViewType }) => {
@@ -45,6 +46,7 @@ const ViewContextProvider = ({ children, initialViewType }) => {
45
46
  return;
46
47
  clearError();
47
48
  setStack((prev) => prev.slice(0, -1));
49
+ dynamicEvents.dynamicEvents.emit('goBack');
48
50
  }, [canGoBack, clearError]);
49
51
  const clearStackAndPush = React.useCallback((type, props, events) => {
50
52
  clearError();
@@ -3,6 +3,7 @@ import { jsx } from 'react/jsx-runtime';
3
3
  import { createContext, useContext, useState, useMemo, useCallback } from 'react';
4
4
  import { useInternalDynamicEvents } from '../../utils/hooks/events/useDynamicEvents/useDynamicEvents.js';
5
5
  import { useErrorContext } from '../ErrorContext/ErrorContext.js';
6
+ import { dynamicEvents } from '../../events/dynamicEvents.js';
6
7
 
7
8
  const ViewContext = createContext(undefined);
8
9
  const ViewContextProvider = ({ children, initialViewType }) => {
@@ -41,6 +42,7 @@ const ViewContextProvider = ({ children, initialViewType }) => {
41
42
  return;
42
43
  clearError();
43
44
  setStack((prev) => prev.slice(0, -1));
45
+ dynamicEvents.emit('goBack');
44
46
  }, [canGoBack, clearError]);
45
47
  const clearStackAndPush = useCallback((type, props, events) => {
46
48
  clearError();
@@ -17,4 +17,8 @@ export type UIEvents = {
17
17
  }) => void;
18
18
  userProfileOpen: () => void;
19
19
  userProfileClose: () => void;
20
+ /**
21
+ * Triggered when the user clicks the back button
22
+ */
23
+ goBack: () => void;
20
24
  };
@@ -163,11 +163,18 @@ const useConnectAndSign = ({ shouldUpdateWallets = true, shouldCallCallback = tr
163
163
  };
164
164
  return (_a) => _tslib.__awaiter(void 0, [_a], void 0, function* ({ walletConnector, getAddressOpts = undefined, }) {
165
165
  var _b;
166
+ const connectionCancelPromise = new utils.DeferredPromise();
167
+ const onGoBack = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
168
+ loadingAndLifecycle.setIsInitialWalletVerificationInProgress(false);
169
+ connectionCancelPromise.reject(new utils.GetAddressCancelledError());
170
+ });
166
171
  try {
172
+ dynamicEvents.dynamicEvents.on('goBack', onGoBack);
173
+ dynamicEvents.dynamicEvents.on('authFlowClose', onGoBack);
174
+ dynamicEvents.dynamicEvents.once('walletAdded', unsetInitialWalletVerificationFlag.unsetInitialWalletVerificationFlag);
167
175
  // Lock the variable that indicates that the login wallet verification is in progress
168
176
  // Read UserWalletsContext.tsx explanation for more context
169
177
  loadingAndLifecycle.setIsInitialWalletVerificationInProgress(true);
170
- dynamicEvents.dynamicEvents.once('walletAdded', unsetInitialWalletVerificationFlag.unsetInitialWalletVerificationFlag);
171
178
  yield showPendingConnectView.showPendingConnectView(walletConnector, pushView);
172
179
  if (walletConnectorCore.isEmailWalletConnector(walletConnector)) {
173
180
  if (walletConnectorCore.isEmailOTPWalletConnector(walletConnector)) {
@@ -177,16 +184,20 @@ const useConnectAndSign = ({ shouldUpdateWallets = true, shouldCallCallback = tr
177
184
  pushView('wait-for-email-confirmation-view');
178
185
  }
179
186
  }
180
- let connectionResult;
187
+ const connectionPromise = connectWallet(walletConnector, getAddressOpts, {
188
+ applyHandleConnectedWallet: shouldCallCallback,
189
+ });
181
190
  try {
182
- connectionResult = yield connectWallet(walletConnector, getAddressOpts, {
183
- applyHandleConnectedWallet: shouldCallCallback,
184
- });
191
+ yield Promise.race([
192
+ connectionPromise,
193
+ connectionCancelPromise.promise,
194
+ ]);
185
195
  }
186
196
  catch (error) {
187
197
  handleWalletConnectionError(error);
188
198
  return;
189
199
  }
200
+ const connectionResult = yield connectionPromise;
190
201
  // Fallback to catch any errors that were missed.
191
202
  if (!(connectionResult === null || connectionResult === void 0 ? void 0 : connectionResult.address)) {
192
203
  handleWalletConnectionError();
@@ -246,6 +257,8 @@ const useConnectAndSign = ({ shouldUpdateWallets = true, shouldCallCallback = tr
246
257
  // 3. The SDK will enter a broken state. Try signing a message with wagmi.
247
258
  // You can also add a "pause on exception" breakpoint in the debugger and see what happens during verification.
248
259
  unsetInitialWalletVerificationFlag.unsetInitialWalletVerificationFlagWithTimeout();
260
+ dynamicEvents.dynamicEvents.removeListener('goBack', onGoBack);
261
+ dynamicEvents.dynamicEvents.removeListener('authFlowClose', onGoBack);
249
262
  }
250
263
  });
251
264
  };
@@ -1,6 +1,6 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../../_virtual/_tslib.js';
3
- import { StorageService, CustomError, GetAddressCancelledError } from '@dynamic-labs/utils';
3
+ import { DeferredPromise, StorageService, CustomError, GetAddressCancelledError } from '@dynamic-labs/utils';
4
4
  import { isEmailWalletConnector, isEmailOTPWalletConnector, isBloctoConnector } from '@dynamic-labs/wallet-connector-core';
5
5
  import { useCaptchaContext } from '../../../../context/CaptchaContext/CaptchaContext.js';
6
6
  import 'react';
@@ -159,11 +159,18 @@ const useConnectAndSign = ({ shouldUpdateWallets = true, shouldCallCallback = tr
159
159
  };
160
160
  return (_a) => __awaiter(void 0, [_a], void 0, function* ({ walletConnector, getAddressOpts = undefined, }) {
161
161
  var _b;
162
+ const connectionCancelPromise = new DeferredPromise();
163
+ const onGoBack = () => __awaiter(void 0, void 0, void 0, function* () {
164
+ setIsInitialWalletVerificationInProgress(false);
165
+ connectionCancelPromise.reject(new GetAddressCancelledError());
166
+ });
162
167
  try {
168
+ dynamicEvents.on('goBack', onGoBack);
169
+ dynamicEvents.on('authFlowClose', onGoBack);
170
+ dynamicEvents.once('walletAdded', unsetInitialWalletVerificationFlag);
163
171
  // Lock the variable that indicates that the login wallet verification is in progress
164
172
  // Read UserWalletsContext.tsx explanation for more context
165
173
  setIsInitialWalletVerificationInProgress(true);
166
- dynamicEvents.once('walletAdded', unsetInitialWalletVerificationFlag);
167
174
  yield showPendingConnectView(walletConnector, pushView);
168
175
  if (isEmailWalletConnector(walletConnector)) {
169
176
  if (isEmailOTPWalletConnector(walletConnector)) {
@@ -173,16 +180,20 @@ const useConnectAndSign = ({ shouldUpdateWallets = true, shouldCallCallback = tr
173
180
  pushView('wait-for-email-confirmation-view');
174
181
  }
175
182
  }
176
- let connectionResult;
183
+ const connectionPromise = connectWallet(walletConnector, getAddressOpts, {
184
+ applyHandleConnectedWallet: shouldCallCallback,
185
+ });
177
186
  try {
178
- connectionResult = yield connectWallet(walletConnector, getAddressOpts, {
179
- applyHandleConnectedWallet: shouldCallCallback,
180
- });
187
+ yield Promise.race([
188
+ connectionPromise,
189
+ connectionCancelPromise.promise,
190
+ ]);
181
191
  }
182
192
  catch (error) {
183
193
  handleWalletConnectionError(error);
184
194
  return;
185
195
  }
196
+ const connectionResult = yield connectionPromise;
186
197
  // Fallback to catch any errors that were missed.
187
198
  if (!(connectionResult === null || connectionResult === void 0 ? void 0 : connectionResult.address)) {
188
199
  handleWalletConnectionError();
@@ -242,6 +253,8 @@ const useConnectAndSign = ({ shouldUpdateWallets = true, shouldCallCallback = tr
242
253
  // 3. The SDK will enter a broken state. Try signing a message with wagmi.
243
254
  // You can also add a "pause on exception" breakpoint in the debugger and see what happens during verification.
244
255
  unsetInitialWalletVerificationFlagWithTimeout();
256
+ dynamicEvents.removeListener('goBack', onGoBack);
257
+ dynamicEvents.removeListener('authFlowClose', onGoBack);
245
258
  }
246
259
  });
247
260
  };
@@ -178,7 +178,11 @@ const useMfa = () => {
178
178
  }
179
179
  throw new Error('Unsupported MFA device type');
180
180
  }), []);
181
- const getRecoveryCodes = React.useCallback((...args_4) => _tslib.__awaiter(void 0, [...args_4], void 0, function* (generateNewCodes = false) {
181
+ const getRecoveryCodes = React.useCallback((...args_4) => _tslib.__awaiter(void 0, [...args_4], void 0, function* (
182
+ /**
183
+ * @deprecated use getNewRecoveryCodes instead
184
+ */
185
+ generateNewCodes = false) {
182
186
  if (generateNewCodes) {
183
187
  const { recoveryCodes } = yield client.createNewMfaRecoveryCodes();
184
188
  return recoveryCodes;
@@ -188,6 +192,11 @@ const useMfa = () => {
188
192
  return recoveryCodes;
189
193
  }
190
194
  }), []);
195
+ const getNewRecoveryCodes = React.useCallback(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
196
+ const { recoveryCodes } = yield client.createNewMfaRecoveryCodes();
197
+ return recoveryCodes;
198
+ }), []);
199
+ const isPendingRecoveryCodesAcknowledgment = React.useCallback(() => _tslib.__awaiter(void 0, void 0, void 0, function* () { return client.isPendingRecoveryCodesAcknowledgment(); }), []);
191
200
  const completeAcknowledgement = React.useCallback(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
192
201
  yield client.acknowledgeRecoveryCodes();
193
202
  }), []);
@@ -199,8 +208,10 @@ const useMfa = () => {
199
208
  authenticateRecoveryCode,
200
209
  completeAcknowledgement,
201
210
  deleteUserDevice,
211
+ getNewRecoveryCodes,
202
212
  getRecoveryCodes,
203
213
  getUserDevices,
214
+ isPendingRecoveryCodesAcknowledgment,
204
215
  updateUserDevice,
205
216
  verifyDevice,
206
217
  };
@@ -42,15 +42,37 @@ type UseMfaHookResult = {
42
42
  */
43
43
  deleteUserDevice: (deviceId: string, mfaAuthToken: string) => Promise<void>;
44
44
  /**
45
- * Get the user's recovery codes
45
+ * Get the current recovery codes for this user.
46
+ *
47
+ * Note: This will throw an error if the user has already acknowledged their recovery codes.
48
+ * In this scenario, you should use getNewRecoveryCodes instead.
49
+ */
50
+ getRecoveryCodes: (
51
+ /**
52
+ * @deprecated use getNewRecoveryCodes instead
53
+ */
54
+ generateNewCodes?: boolean) => Promise<string[]>;
55
+ /**
56
+ * Get the user's devices
46
57
  */
47
- getRecoveryCodes: (generateNewCodes?: boolean) => Promise<string[]>;
48
58
  getUserDevices: () => Promise<MFADevice[]>;
49
59
  updateUserDevice: (deviceId: string) => Promise<void>;
50
60
  /**
51
61
  * @deprecated use authenticateDevice instead
52
62
  */
53
63
  verifyDevice: (code: string, type?: MFADeviceType) => Promise<MFADevice>;
64
+ /**
65
+ * Get new recovery codes for this user.
66
+ * The user will need to acknowledge the new recovery codes.
67
+ */
68
+ getNewRecoveryCodes: () => Promise<string[]>;
69
+ /**
70
+ * Check if the user has already acknowledged their recovery codes.
71
+ *
72
+ * Once the user has acknowledged their recovery codes, the recovery codes will no
73
+ * longer be accessible via getRecoveryCodes.
74
+ */
75
+ isPendingRecoveryCodesAcknowledgment: () => Promise<boolean>;
54
76
  };
55
77
  export declare const useMfa: () => UseMfaHookResult;
56
78
  export {};
@@ -1,7 +1,7 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
3
  import { useCallback } from 'react';
4
- import { authenticateTotpMfaDevice, getMfaDevices, setDefaultMfaDevice, deleteMfaDevice, registerTotpMfaDevice, authenticateMfaRecoveryCode, createNewMfaRecoveryCodes, getMfaRecoveryCodes, acknowledgeRecoveryCodes } from '@dynamic-labs-sdk/client';
4
+ import { authenticateTotpMfaDevice, getMfaDevices, setDefaultMfaDevice, deleteMfaDevice, registerTotpMfaDevice, authenticateMfaRecoveryCode, createNewMfaRecoveryCodes, getMfaRecoveryCodes, isPendingRecoveryCodesAcknowledgment, acknowledgeRecoveryCodes } from '@dynamic-labs-sdk/client';
5
5
  import { MFADeviceType } from '@dynamic-labs/sdk-api-core';
6
6
  import { verifyTotpMfaDevice } from '../../../client/extension/deprecated/mfa/verifyTotpMfaDevice/verifyTotpMfaDevice.js';
7
7
  import '../../../client/client.js';
@@ -174,7 +174,11 @@ const useMfa = () => {
174
174
  }
175
175
  throw new Error('Unsupported MFA device type');
176
176
  }), []);
177
- const getRecoveryCodes = useCallback((...args_4) => __awaiter(void 0, [...args_4], void 0, function* (generateNewCodes = false) {
177
+ const getRecoveryCodes = useCallback((...args_4) => __awaiter(void 0, [...args_4], void 0, function* (
178
+ /**
179
+ * @deprecated use getNewRecoveryCodes instead
180
+ */
181
+ generateNewCodes = false) {
178
182
  if (generateNewCodes) {
179
183
  const { recoveryCodes } = yield createNewMfaRecoveryCodes();
180
184
  return recoveryCodes;
@@ -184,6 +188,11 @@ const useMfa = () => {
184
188
  return recoveryCodes;
185
189
  }
186
190
  }), []);
191
+ const getNewRecoveryCodes = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
192
+ const { recoveryCodes } = yield createNewMfaRecoveryCodes();
193
+ return recoveryCodes;
194
+ }), []);
195
+ const isPendingRecoveryCodesAcknowledgment$1 = useCallback(() => __awaiter(void 0, void 0, void 0, function* () { return isPendingRecoveryCodesAcknowledgment(); }), []);
187
196
  const completeAcknowledgement = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
188
197
  yield acknowledgeRecoveryCodes();
189
198
  }), []);
@@ -195,8 +204,10 @@ const useMfa = () => {
195
204
  authenticateRecoveryCode,
196
205
  completeAcknowledgement,
197
206
  deleteUserDevice,
207
+ getNewRecoveryCodes,
198
208
  getRecoveryCodes,
199
209
  getUserDevices,
210
+ isPendingRecoveryCodesAcknowledgment: isPendingRecoveryCodesAcknowledgment$1,
200
211
  updateUserDevice,
201
212
  verifyDevice,
202
213
  };
@@ -83,9 +83,9 @@ const useWalletConnectors = ({ connectedWallets, walletConnectorOptions, setMult
83
83
  // emit primaryWalletChanged event if the primary wallet changes
84
84
  React.useEffect(() => {
85
85
  if (primaryWallet && primaryWallet.id !== lastPrimaryWalletId.current) {
86
- lastPrimaryWalletId.current = primaryWallet.id;
87
86
  dynamicEvents.dynamicEvents.emit('primaryWalletChanged', primaryWallet);
88
87
  }
88
+ lastPrimaryWalletId.current = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.id;
89
89
  }, [primaryWallet]);
90
90
  const secondaryWallets = React.useMemo(() => canHaveMultipleWalletsConnected
91
91
  ? wallets.filter((wallet) => wallet.id !== primaryWalletId)
@@ -79,9 +79,9 @@ const useWalletConnectors = ({ connectedWallets, walletConnectorOptions, setMult
79
79
  // emit primaryWalletChanged event if the primary wallet changes
80
80
  useEffect(() => {
81
81
  if (primaryWallet && primaryWallet.id !== lastPrimaryWalletId.current) {
82
- lastPrimaryWalletId.current = primaryWallet.id;
83
82
  dynamicEvents.emit('primaryWalletChanged', primaryWallet);
84
83
  }
84
+ lastPrimaryWalletId.current = primaryWallet === null || primaryWallet === void 0 ? void 0 : primaryWallet.id;
85
85
  }, [primaryWallet]);
86
86
  const secondaryWallets = useMemo(() => canHaveMultipleWalletsConnected
87
87
  ? wallets.filter((wallet) => wallet.id !== primaryWalletId)