@dynamic-labs-wallet/browser 0.0.239 → 0.0.241

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/index.cjs.js CHANGED
@@ -658,16 +658,6 @@ const downloadStringAsFile = ({ filename, content, mimeType = 'application/json'
658
658
  URL.revokeObjectURL(url);
659
659
  };
660
660
 
661
- // CloudKit Web Services API token for public operations
662
- // This token only allows access to the iCloud.KeyShareBackup container
663
- // and is safe to include in client-side code
664
- const DEFAULT_CONFIG = {
665
- containerIdentifier: 'iCloud.KeyShareBackup',
666
- // apiToken: '1221c5ccdf2ddb9abdb035befe7c197b07102972b30bbcbe363f6d722f3127a1', // prod
667
- apiToken: '332a46c457183332f8d2a3d94d2ac87e9e9ae2af81d8a6d1ea89c27bb2fc0e97',
668
- // environment: 'production',
669
- environment: 'development'
670
- };
671
661
  const CLOUDKIT_CDN_URL = 'https://cdn.apple-cloudkit.com/ck/2/cloudkit.js';
672
662
  const BACKUP_RECORD_TYPE = 'Backup';
673
663
  let cloudKitLoaded = false;
@@ -703,7 +693,6 @@ const loadCloudKit = ()=>{
703
693
  script.src = CLOUDKIT_CDN_URL;
704
694
  script.onload = ()=>{
705
695
  cloudKitLoaded = true;
706
- logger.debug('[iCloud] CloudKit JS loaded successfully');
707
696
  resolve();
708
697
  };
709
698
  script.onerror = (error)=>{
@@ -717,17 +706,16 @@ const configureCloudKit = (config, signInButtonId)=>{
717
706
  if (cloudKitConfigured && currentSignInButtonId === signInButtonId) {
718
707
  return;
719
708
  }
720
- const mergedConfig = _extends({}, DEFAULT_CONFIG, config);
709
+ if (!(config == null ? void 0 : config.containerIdentifier) || !(config == null ? void 0 : config.apiToken) || !(config == null ? void 0 : config.environment)) {
710
+ throw new Error('iCloud configuration is incomplete. Please configure iCloud settings in the dashboard.');
711
+ }
721
712
  const containerConfig = {
722
- containerIdentifier: mergedConfig.containerIdentifier,
723
- environment: mergedConfig.environment,
713
+ containerIdentifier: config.containerIdentifier,
714
+ environment: config.environment,
724
715
  apiTokenAuth: {
725
- apiToken: mergedConfig.apiToken,
716
+ apiToken: config.apiToken,
726
717
  persist: true,
727
- signInButton: signInButtonId ? {
728
- id: signInButtonId,
729
- theme: 'black'
730
- } : undefined
718
+ signInButton: undefined
731
719
  }
732
720
  };
733
721
  CloudKit.configure({
@@ -736,16 +724,7 @@ const configureCloudKit = (config, signInButtonId)=>{
736
724
  ]
737
725
  });
738
726
  cloudKitConfigured = true;
739
- currentSignInButtonId = signInButtonId || null;
740
- logger.debug('[iCloud] CloudKit configured', {
741
- containerIdentifier: mergedConfig.containerIdentifier,
742
- environment: mergedConfig.environment
743
- });
744
- };
745
- const resetCloudKitConfig = ()=>{
746
- cloudKitConfigured = false;
747
727
  currentSignInButtonId = null;
748
- logger.debug('[iCloud] CloudKit config reset');
749
728
  };
750
729
  /**
751
730
  * Check if user is already authenticated using fetchCurrentUserIdentity.
@@ -765,7 +744,6 @@ const resetCloudKitConfig = ()=>{
765
744
  if (authenticationAbortController) {
766
745
  authenticationAbortController.abort();
767
746
  authenticationAbortController = null;
768
- logger.info('[iCloud] Authentication cancelled by user');
769
747
  }
770
748
  };
771
749
  const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatusUpdate, options)=>{
@@ -784,7 +762,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
784
762
  // First, check if user is already authenticated (more reliable than setUpAuth)
785
763
  const alreadyAuthenticated = await isUserAuthenticated(container);
786
764
  if (alreadyAuthenticated) {
787
- logger.info('[iCloud] User already authenticated');
788
765
  onAuthStatusUpdate == null ? void 0 : onAuthStatusUpdate('Authenticated');
789
766
  return;
790
767
  }
@@ -793,12 +770,10 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
793
770
  await container.setUpAuth();
794
771
  // Double-check authentication after setUpAuth
795
772
  if (await isUserAuthenticated(container)) {
796
- logger.info('[iCloud] User authenticated after setUpAuth');
797
773
  onAuthStatusUpdate == null ? void 0 : onAuthStatusUpdate('Authenticated');
798
774
  return;
799
775
  }
800
776
  // User needs to sign in
801
- logger.info('[iCloud] User authentication required');
802
777
  onAuthStatusUpdate == null ? void 0 : onAuthStatusUpdate('Waiting for sign-in...');
803
778
  if (onSignInRequired) ;
804
779
  return new Promise((resolve, reject)=>{
@@ -829,7 +804,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
829
804
  if (await isUserAuthenticated(container)) {
830
805
  resolved = true;
831
806
  cleanup();
832
- logger.info('[iCloud] Authentication successful');
833
807
  onAuthStatusUpdate == null ? void 0 : onAuthStatusUpdate('Authenticated');
834
808
  if (onSignInComplete) ;
835
809
  resolve();
@@ -843,7 +817,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
843
817
  resolved = true;
844
818
  cleanup();
845
819
  if (onSignInComplete) ;
846
- logger.warn('[iCloud] Authentication timed out');
847
820
  reject(new Error('iCloud sign-in timed out. Please ensure you are signed into iCloud ' + 'in your browser settings and try again. If the problem persists, ' + 'check your internet connection or try a different backup method.'));
848
821
  }
849
822
  }, timeoutMs);
@@ -859,7 +832,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
859
832
  };
860
833
  /**
861
834
  * Save backup data to iCloud with retry logic
862
- * Stores data in the same format as Google Drive for consistency
863
835
  */ const saveBackupToICloud = async (backupData, retryOptions)=>{
864
836
  const { maxAttempts = 3, retryInterval = 1000 } = {};
865
837
  return retryPromise(async ()=>{
@@ -868,16 +840,11 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
868
840
  const record = {
869
841
  recordType: BACKUP_RECORD_TYPE,
870
842
  fields: {
871
- // Store as JSON string to match Google Drive format
872
843
  backupData: {
873
844
  value: JSON.stringify(backupData)
874
- },
875
- timestamp: {
876
- value: Date.now()
877
845
  }
878
846
  }
879
847
  };
880
- logger.debug('[iCloud] Saving backup record to CloudKit');
881
848
  const response = await privateDB.saveRecords([
882
849
  record
883
850
  ]);
@@ -887,9 +854,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
887
854
  throw new Error(errorMessage);
888
855
  }
889
856
  const savedRecord = response.records[0];
890
- logger.info('[iCloud] Backup saved successfully', {
891
- recordName: savedRecord.recordName
892
- });
893
857
  return savedRecord;
894
858
  }, {
895
859
  maxAttempts,
@@ -904,12 +868,11 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
904
868
  const container = CloudKit.getDefaultContainer();
905
869
  const privateDB = container.privateCloudDatabase;
906
870
  try {
907
- logger.debug('[iCloud] Querying backup records');
908
871
  const response = await privateDB.performQuery({
909
872
  recordType: BACKUP_RECORD_TYPE,
910
873
  sortBy: [
911
874
  {
912
- fieldName: 'timestamp',
875
+ fieldName: 'created',
913
876
  ascending: false
914
877
  }
915
878
  ]
@@ -931,9 +894,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
931
894
  backupData: JSON.parse(fields.backupData.value)
932
895
  };
933
896
  });
934
- logger.info('[iCloud] Found backups', {
935
- count: records.length
936
- });
937
897
  return records;
938
898
  } catch (error) {
939
899
  logger.error('[iCloud] Failed to list backups:', error);
@@ -947,9 +907,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
947
907
  const privateDB = container.privateCloudDatabase;
948
908
  try {
949
909
  var _fields_backupData;
950
- logger.debug('[iCloud] Fetching backup record', {
951
- recordName
952
- });
953
910
  const response = await privateDB.fetchRecords([
954
911
  recordName
955
912
  ]);
@@ -959,9 +916,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
959
916
  }
960
917
  const record = response.records[0];
961
918
  if (!record) {
962
- logger.warn('[iCloud] Backup record not found', {
963
- recordName
964
- });
965
919
  return null;
966
920
  }
967
921
  const fields = record.fields;
@@ -974,9 +928,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
974
928
  modified: record.modified.timestamp,
975
929
  backupData: JSON.parse(fields.backupData.value)
976
930
  };
977
- logger.info('[iCloud] Backup retrieved successfully', {
978
- recordName
979
- });
980
931
  return backupRecord;
981
932
  } catch (error) {
982
933
  logger.error('[iCloud] Failed to get backup:', error);
@@ -989,9 +940,6 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
989
940
  const container = CloudKit.getDefaultContainer();
990
941
  const privateDB = container.privateCloudDatabase;
991
942
  try {
992
- logger.debug('[iCloud] Deleting backup record', {
993
- recordName
994
- });
995
943
  const response = await privateDB.deleteRecords([
996
944
  recordName
997
945
  ]);
@@ -999,20 +947,13 @@ const ensureICloudAuth = async (onSignInRequired, onSignInComplete, onAuthStatus
999
947
  logger.error('[iCloud] Delete error:', response.errors);
1000
948
  throw new Error(mapCloudKitError(response.errors[0]));
1001
949
  }
1002
- logger.info('[iCloud] Backup deleted successfully', {
1003
- recordName
1004
- });
1005
950
  } catch (error) {
1006
951
  logger.error('[iCloud] Failed to delete backup:', error);
1007
952
  throw error;
1008
953
  }
1009
954
  };
1010
955
  const initializeCloudKit = async (config, signInButtonId, onSignInRequired, onSignInComplete, onAuthStatusUpdate, authOptions)=>{
1011
- logger.info('[iCloud] Initializing CloudKit');
1012
956
  await loadCloudKit();
1013
- if (signInButtonId) {
1014
- resetCloudKitConfig();
1015
- }
1016
957
  configureCloudKit(config, signInButtonId);
1017
958
  await ensureICloudAuth(onSignInRequired, onSignInComplete, onAuthStatusUpdate);
1018
959
  };
@@ -1217,42 +1158,82 @@ class WalletBusyError extends Error {
1217
1158
  this.accountAddress = accountAddress;
1218
1159
  }
1219
1160
  }
1220
- const createDelegationWithGoogleDriveDistribution = ({ existingShares, delegatedShare })=>({
1161
+ /**
1162
+ * Creates distribution where shares go to specified cloud providers
1163
+ * Last share goes to cloud providers, rest to Dynamic backend
1164
+ * @param providers - Array of cloud providers to backup to
1165
+ * @param allShares - All key shares to distribute
1166
+ */ const createCloudProviderDistribution = ({ providers, allShares })=>{
1167
+ const cloudProviderShares = {};
1168
+ // Last share goes to cloud providers, rest to Dynamic
1169
+ const sharesForCloud = allShares.slice(-1);
1170
+ providers.forEach((provider)=>{
1171
+ cloudProviderShares[provider] = sharesForCloud;
1172
+ });
1173
+ return {
1174
+ clientShares: allShares.slice(0, -1),
1175
+ cloudProviderShares
1176
+ };
1177
+ };
1178
+ /**
1179
+ * Creates distribution with delegation + cloud backup
1180
+ * Client shares backed up to Dynamic AND cloud providers
1181
+ * Delegated share goes to webhook
1182
+ */ const createDelegationWithCloudProviderDistribution = ({ providers, existingShares, delegatedShare })=>{
1183
+ const cloudProviderShares = {};
1184
+ providers.forEach((provider)=>{
1185
+ cloudProviderShares[provider] = existingShares;
1186
+ });
1187
+ return {
1221
1188
  clientShares: existingShares,
1222
- googleDriveShares: existingShares,
1189
+ cloudProviderShares,
1223
1190
  delegatedShare
1191
+ };
1192
+ };
1193
+ /**
1194
+ * Creates distribution for adding cloud backup to existing delegation
1195
+ * Client shares go to both Dynamic AND cloud providers
1196
+ * delegatedShare is undefined - we don't re-publish, but preserve the location
1197
+ */ const createAddCloudProviderToExistingDelegationDistribution = ({ providers, clientShares })=>{
1198
+ const cloudProviderShares = {};
1199
+ providers.forEach((provider)=>{
1200
+ cloudProviderShares[provider] = clientShares;
1224
1201
  });
1202
+ return {
1203
+ clientShares,
1204
+ cloudProviderShares
1205
+ };
1206
+ };
1207
+ /**
1208
+ * Checks if wallet has backup on any of the specified providers
1209
+ */ const hasCloudProviderBackup = (backupInfo, providers)=>{
1210
+ if (!(backupInfo == null ? void 0 : backupInfo.backups)) return false;
1211
+ return providers.some((provider)=>{
1212
+ var _backupInfo_backups_provider;
1213
+ var _backupInfo_backups_provider_length;
1214
+ return ((_backupInfo_backups_provider_length = (_backupInfo_backups_provider = backupInfo.backups[provider]) == null ? void 0 : _backupInfo_backups_provider.length) != null ? _backupInfo_backups_provider_length : 0) > 0;
1215
+ });
1216
+ };
1217
+ /**
1218
+ * Gets all cloud providers that have backups for this wallet
1219
+ */ const getActiveCloudProviders = (backupInfo)=>{
1220
+ if (!(backupInfo == null ? void 0 : backupInfo.backups)) return [];
1221
+ return Object.entries(backupInfo.backups).filter(([location, backups])=>location !== core.BackupLocation.DYNAMIC && location !== core.BackupLocation.DELEGATED && backups.length > 0).map(([location])=>location);
1222
+ };
1225
1223
  const createDelegationOnlyDistribution = ({ existingShares, delegatedShare })=>({
1226
1224
  clientShares: existingShares,
1227
- googleDriveShares: [],
1225
+ cloudProviderShares: {},
1228
1226
  delegatedShare
1229
1227
  });
1230
- const createGoogleDriveOnlyDistribution = ({ allShares })=>({
1231
- clientShares: allShares.slice(0, -1),
1232
- googleDriveShares: allShares.slice(-1)
1233
- });
1234
1228
  const createDynamicOnlyDistribution = ({ allShares })=>({
1235
1229
  clientShares: allShares,
1236
- googleDriveShares: []
1230
+ cloudProviderShares: {}
1237
1231
  });
1238
- const hasGoogleDriveBackup = (backupInfo)=>{
1239
- var _backupInfo_backups_BackupLocation_GOOGLE_DRIVE, _backupInfo_backups;
1240
- var _backupInfo_backups_BackupLocation_GOOGLE_DRIVE_length;
1241
- return ((_backupInfo_backups_BackupLocation_GOOGLE_DRIVE_length = backupInfo == null ? void 0 : (_backupInfo_backups = backupInfo.backups) == null ? void 0 : (_backupInfo_backups_BackupLocation_GOOGLE_DRIVE = _backupInfo_backups[core.BackupLocation.GOOGLE_DRIVE]) == null ? void 0 : _backupInfo_backups_BackupLocation_GOOGLE_DRIVE.length) != null ? _backupInfo_backups_BackupLocation_GOOGLE_DRIVE_length : 0) > 0;
1242
- };
1243
1232
  const hasDelegatedBackup = (backupInfo)=>{
1244
1233
  var _backupInfo_backups_BackupLocation_DELEGATED, _backupInfo_backups;
1245
1234
  var _backupInfo_backups_BackupLocation_DELEGATED_length;
1246
1235
  return ((_backupInfo_backups_BackupLocation_DELEGATED_length = backupInfo == null ? void 0 : (_backupInfo_backups = backupInfo.backups) == null ? void 0 : (_backupInfo_backups_BackupLocation_DELEGATED = _backupInfo_backups[core.BackupLocation.DELEGATED]) == null ? void 0 : _backupInfo_backups_BackupLocation_DELEGATED.length) != null ? _backupInfo_backups_BackupLocation_DELEGATED_length : 0) > 0;
1247
1236
  };
1248
- /**
1249
- * Distribution for adding Google Drive backup to an existing delegation.
1250
- * Client's shares go to both Dynamic and Google Drive.
1251
- * delegatedShare is undefined - we don't re-publish, but preserve the location.
1252
- */ const createAddGoogleDriveToExistingDelegationDistribution = ({ clientShares })=>({
1253
- clientShares: clientShares,
1254
- googleDriveShares: clientShares
1255
- });
1256
1237
 
1257
1238
  // eslint-disable-next-line @nx/enforce-module-boundaries
1258
1239
  class DynamicWalletClient {
@@ -2021,7 +2002,7 @@ class DynamicWalletClient {
2021
2002
  existingClientKeyShares
2022
2003
  };
2023
2004
  }
2024
- async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, backupToGoogleDrive = false, delegateToProjectEnvironment = false, mfaToken, revokeDelegation = false }) {
2005
+ async reshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, cloudProviders = [], delegateToProjectEnvironment = false, mfaToken, revokeDelegation = false }) {
2025
2006
  return this.withWalletBusyLock({
2026
2007
  accountAddress,
2027
2008
  operation: core.WalletOperation.RESHARE,
@@ -2032,14 +2013,14 @@ class DynamicWalletClient {
2032
2013
  newThresholdSignatureScheme,
2033
2014
  password,
2034
2015
  signedSessionId,
2035
- backupToGoogleDrive,
2016
+ cloudProviders,
2036
2017
  delegateToProjectEnvironment,
2037
2018
  mfaToken,
2038
2019
  revokeDelegation
2039
2020
  })
2040
2021
  });
2041
2022
  }
2042
- async internalReshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, backupToGoogleDrive = false, delegateToProjectEnvironment = false, mfaToken, revokeDelegation = false }) {
2023
+ async internalReshare({ chainName, accountAddress, oldThresholdSignatureScheme, newThresholdSignatureScheme, password = undefined, signedSessionId, cloudProviders = [], delegateToProjectEnvironment = false, mfaToken, revokeDelegation = false }) {
2043
2024
  const dynamicRequestId = uuid.v4();
2044
2025
  try {
2045
2026
  await this.verifyPassword({
@@ -2106,28 +2087,31 @@ class DynamicWalletClient {
2106
2087
  ...newReshareResults
2107
2088
  ];
2108
2089
  let distribution;
2109
- if (delegateToProjectEnvironment && backupToGoogleDrive) {
2110
- // Delegation + Google Drive: Client's existing share backs up to both Dynamic and Google Drive.
2090
+ // Generic distribution logic - works with any cloud providers
2091
+ if (delegateToProjectEnvironment && cloudProviders.length > 0) {
2092
+ // Delegation + Cloud Providers: Client's existing share backs up to both Dynamic and cloud providers.
2111
2093
  // The new share goes to the webhook for delegation.
2112
- distribution = createDelegationWithGoogleDriveDistribution({
2094
+ distribution = createDelegationWithCloudProviderDistribution({
2095
+ providers: cloudProviders,
2113
2096
  existingShares: existingReshareResults,
2114
2097
  delegatedShare: newReshareResults[0]
2115
2098
  });
2116
2099
  } else if (delegateToProjectEnvironment) {
2117
2100
  // Delegation only: Client's existing share backs up to Dynamic.
2118
- // The new share goes to the webhook for delegation. No Google Drive backup.
2101
+ // The new share goes to the webhook for delegation. No cloud provider backup.
2119
2102
  distribution = createDelegationOnlyDistribution({
2120
2103
  existingShares: existingReshareResults,
2121
2104
  delegatedShare: newReshareResults[0]
2122
2105
  });
2123
- } else if (backupToGoogleDrive) {
2124
- // Google Drive only: Split shares between Dynamic (N-1) and Google Drive (1).
2125
- // The last share (new share) goes to Google Drive.
2126
- distribution = createGoogleDriveOnlyDistribution({
2106
+ } else if (cloudProviders.length > 0) {
2107
+ // Cloud Providers only: Split shares between Dynamic (N-1) and cloud providers (1).
2108
+ // The last share (new share) goes to cloud providers.
2109
+ distribution = createCloudProviderDistribution({
2110
+ providers: cloudProviders,
2127
2111
  allShares: allClientShares
2128
2112
  });
2129
2113
  } else {
2130
- // No delegation, no Google Drive: All shares go to Dynamic backend only.
2114
+ // No delegation, no cloud providers: All shares go to Dynamic backend only.
2131
2115
  distribution = createDynamicOnlyDistribution({
2132
2116
  allShares: allClientShares
2133
2117
  });
@@ -2155,7 +2139,7 @@ class DynamicWalletClient {
2155
2139
  chainName,
2156
2140
  oldThresholdSignatureScheme,
2157
2141
  newThresholdSignatureScheme,
2158
- backupToGoogleDrive,
2142
+ cloudProviders,
2159
2143
  dynamicRequestId
2160
2144
  }
2161
2145
  });
@@ -2188,6 +2172,8 @@ class DynamicWalletClient {
2188
2172
  throw new Error('Delegation is not allowed for SUI');
2189
2173
  }
2190
2174
  const currentThresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
2175
+ // Get active cloud providers to maintain existing backups
2176
+ const activeProviders = getActiveCloudProviders((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.clientKeySharesBackupInfo);
2191
2177
  await this.reshare({
2192
2178
  chainName: this.walletMap[accountAddress].chainName,
2193
2179
  accountAddress,
@@ -2195,7 +2181,7 @@ class DynamicWalletClient {
2195
2181
  newThresholdSignatureScheme,
2196
2182
  password,
2197
2183
  signedSessionId,
2198
- backupToGoogleDrive: hasGoogleDriveBackup((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.clientKeySharesBackupInfo),
2184
+ cloudProviders: activeProviders,
2199
2185
  delegateToProjectEnvironment: true,
2200
2186
  mfaToken,
2201
2187
  revokeDelegation
@@ -2494,17 +2480,21 @@ class DynamicWalletClient {
2494
2480
  externalKeyShareId: data.keyShareIds[0]
2495
2481
  });
2496
2482
  }
2497
- if (distribution.googleDriveShares.length > 0) {
2498
- const encryptedGoogleDriveShares = await Promise.all(distribution.googleDriveShares.map((keyShare)=>this.encryptKeyShare({
2483
+ // Handle all cloud provider backups generically
2484
+ for (const [provider, shares] of Object.entries(distribution.cloudProviderShares)){
2485
+ if (!shares || shares.length === 0) continue;
2486
+ const backupLocation = provider;
2487
+ const encryptedCloudShares = await Promise.all(shares.map((keyShare)=>this.encryptKeyShare({
2499
2488
  keyShare,
2500
2489
  password
2501
2490
  })));
2502
- await this.uploadKeySharesToGoogleDrive({
2491
+ await this.uploadToCloudProvider({
2492
+ provider: backupLocation,
2503
2493
  accountAddress,
2504
- encryptedKeyShares: encryptedGoogleDriveShares
2494
+ encryptedKeyShares: encryptedCloudShares
2505
2495
  });
2506
2496
  locations.push({
2507
- location: core.BackupLocation.GOOGLE_DRIVE
2497
+ location: backupLocation
2508
2498
  });
2509
2499
  }
2510
2500
  if (distribution.delegatedShare) {
@@ -2601,44 +2591,52 @@ class DynamicWalletClient {
2601
2591
  * @param params.signedSessionId - Optional signed session ID for authentication
2602
2592
  * @param params.backupToGoogleDrive - Whether to backup to Google Drive (defaults to false)
2603
2593
  * @returns Promise with backup metadata including share locations and IDs
2604
- */ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId, backupToGoogleDrive = false, delegatedKeyshare = undefined }) {
2594
+ */ async storeEncryptedBackupByWallet({ accountAddress, clientKeyShares = undefined, password = undefined, signedSessionId, cloudProviders = [], delegatedKeyshare = undefined }) {
2605
2595
  var _this_walletMap_accountAddress, _this_walletMap_accountAddress1;
2606
2596
  const keySharesToBackup = clientKeyShares != null ? clientKeyShares : await this.getClientKeySharesFromLocalStorage({
2607
2597
  accountAddress
2608
2598
  });
2609
- const shouldBackupToGoogleDrive = backupToGoogleDrive || hasGoogleDriveBackup((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.clientKeySharesBackupInfo);
2599
+ // Check if we should backup to cloud providers (either requested or already exists)
2600
+ const activeCloudProviders = getActiveCloudProviders((_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.clientKeySharesBackupInfo);
2601
+ const shouldBackupToCloudProviders = cloudProviders.length > 0 || activeCloudProviders.length > 0;
2602
+ // Use requested providers, or fall back to existing active providers
2603
+ const providersToBackup = cloudProviders.length > 0 ? cloudProviders : activeCloudProviders;
2610
2604
  const hasExistingDelegation = hasDelegatedBackup((_this_walletMap_accountAddress1 = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress1.clientKeySharesBackupInfo);
2611
2605
  let distribution;
2612
2606
  let preserveDelegatedLocation = false;
2613
- if (delegatedKeyshare && shouldBackupToGoogleDrive) {
2614
- // NEW delegation + Google Drive: Client's shares back up to both Dynamic and Google Drive.
2607
+ // Generic distribution logic - works with any cloud providers
2608
+ if (delegatedKeyshare && shouldBackupToCloudProviders) {
2609
+ // NEW delegation + Cloud Providers: Client's shares back up to both Dynamic and cloud providers.
2615
2610
  // The delegated share goes to the webhook.
2616
- distribution = createDelegationWithGoogleDriveDistribution({
2611
+ distribution = createDelegationWithCloudProviderDistribution({
2612
+ providers: providersToBackup,
2617
2613
  existingShares: keySharesToBackup,
2618
2614
  delegatedShare: delegatedKeyshare
2619
2615
  });
2620
2616
  } else if (delegatedKeyshare) {
2621
2617
  // NEW delegation only: Client's shares back up to Dynamic.
2622
- // The delegated share goes to the webhook. No Google Drive backup.
2618
+ // The delegated share goes to the webhook. No cloud provider backup.
2623
2619
  distribution = createDelegationOnlyDistribution({
2624
2620
  existingShares: keySharesToBackup,
2625
2621
  delegatedShare: delegatedKeyshare
2626
2622
  });
2627
- } else if (hasExistingDelegation && shouldBackupToGoogleDrive) {
2628
- // ADD Google Drive to EXISTING delegation: Client's share backs up to both Dynamic and GD.
2623
+ } else if (hasExistingDelegation && shouldBackupToCloudProviders) {
2624
+ // ADD Cloud Providers to EXISTING delegation: Client's share backs up to both Dynamic and cloud providers.
2629
2625
  // Don't re-publish delegated share, just preserve the location.
2630
- distribution = createAddGoogleDriveToExistingDelegationDistribution({
2626
+ distribution = createAddCloudProviderToExistingDelegationDistribution({
2627
+ providers: providersToBackup,
2631
2628
  clientShares: keySharesToBackup
2632
2629
  });
2633
2630
  preserveDelegatedLocation = true;
2634
- } else if (shouldBackupToGoogleDrive && keySharesToBackup.length >= 2) {
2635
- // Google Drive only (no delegation): Split shares between Dynamic (N-1) and Google Drive (1).
2636
- // The last share (new share) goes to Google Drive.
2637
- distribution = createGoogleDriveOnlyDistribution({
2631
+ } else if (shouldBackupToCloudProviders && keySharesToBackup.length >= 2) {
2632
+ // Cloud Providers only (no delegation): Split shares between Dynamic (N-1) and cloud providers (1).
2633
+ // The last share (new share) goes to cloud providers.
2634
+ distribution = createCloudProviderDistribution({
2635
+ providers: providersToBackup,
2638
2636
  allShares: keySharesToBackup
2639
2637
  });
2640
2638
  } else {
2641
- // No delegation, no Google Drive: All shares go to Dynamic backend only.
2639
+ // No delegation, no cloud providers: All shares go to Dynamic backend only.
2642
2640
  distribution = createDynamicOnlyDistribution({
2643
2641
  allShares: keySharesToBackup
2644
2642
  });
@@ -2807,16 +2805,10 @@ class DynamicWalletClient {
2807
2805
  this.walletMap = JSON.parse(wallets);
2808
2806
  }
2809
2807
  /**
2810
- * This method handles the complete flow for ensuring wallet key shares are backed up to Google Drive:
2811
- * - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to Google Drive)
2812
- * - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and Google Drive
2813
- *
2814
- * @param params - The backup parameters
2815
- * @param params.accountAddress - The wallet account address to backup
2816
- * @param params.password - Optional password for encryption (uses environment ID if not provided)
2817
- * @param params.signedSessionId - Optional signed session ID for authentication
2818
- * @returns Promise<string[]> - Array of Google Drive key share IDs that were backed up
2819
- */ async backupKeySharesToGoogleDrive({ accountAddress, password, signedSessionId }) {
2808
+ * Internal helper method that handles the complete flow for ensuring wallet key shares are backed up to a cloud provider.
2809
+ * - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to cloud)
2810
+ * - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and cloud
2811
+ */ async backupKeySharesToCloudProvider({ accountAddress, password, signedSessionId, backupLocation }) {
2820
2812
  try {
2821
2813
  await this.getWallet({
2822
2814
  accountAddress,
@@ -2834,93 +2826,86 @@ class DynamicWalletClient {
2834
2826
  newThresholdSignatureScheme: core.ThresholdSignatureScheme.TWO_OF_THREE,
2835
2827
  password,
2836
2828
  signedSessionId,
2837
- backupToGoogleDrive: true
2838
- });
2839
- const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
2840
- const googleDriveShares = backupInfo.backups[core.BackupLocation.GOOGLE_DRIVE] || [];
2841
- return googleDriveShares.map((ks)=>{
2842
- var _ks_externalKeyShareId;
2843
- return (_ks_externalKeyShareId = ks.externalKeyShareId) != null ? _ks_externalKeyShareId : '';
2829
+ cloudProviders: [
2830
+ backupLocation
2831
+ ]
2844
2832
  });
2845
2833
  } else {
2846
2834
  await this.storeEncryptedBackupByWallet({
2847
2835
  accountAddress,
2848
2836
  password,
2849
2837
  signedSessionId,
2850
- backupToGoogleDrive: true
2851
- });
2852
- const backupInfo = this.walletMap[accountAddress].clientKeySharesBackupInfo;
2853
- const googleDriveShares = backupInfo.backups[core.BackupLocation.GOOGLE_DRIVE] || [];
2854
- return googleDriveShares.map((ks)=>{
2855
- var _ks_externalKeyShareId;
2856
- return (_ks_externalKeyShareId = ks.externalKeyShareId) != null ? _ks_externalKeyShareId : '';
2838
+ cloudProviders: [
2839
+ backupLocation
2840
+ ]
2857
2841
  });
2858
2842
  }
2859
2843
  } catch (error) {
2860
2844
  logError({
2861
- message: 'Error in backupKeySharesToGoogleDrive',
2845
+ message: `Error in backupKeySharesToCloudProvider (${backupLocation})`,
2862
2846
  error: error,
2863
2847
  context: {
2864
- accountAddress
2848
+ accountAddress,
2849
+ backupLocation
2865
2850
  }
2866
2851
  });
2867
2852
  throw error;
2868
2853
  }
2869
2854
  }
2870
- async backupKeySharesToICloud({ accountAddress, password, signedSessionId, signInButtonId, onProgress, onAuthStatusUpdate }) {
2871
- try {
2872
- var _environmentSettings_sdk_waas, _environmentSettings_sdk;
2873
- await this.getWallet({
2874
- accountAddress,
2875
- walletOperation: core.WalletOperation.REACH_THRESHOLD,
2876
- password,
2877
- signedSessionId
2878
- });
2879
- const environmentSettings = await this.apiClient.getEnvironmentSettings();
2880
- const iCloudConfig = environmentSettings == null ? void 0 : (_environmentSettings_sdk = environmentSettings.sdk) == null ? void 0 : (_environmentSettings_sdk_waas = _environmentSettings_sdk.waas) == null ? void 0 : _environmentSettings_sdk_waas.icloud;
2881
- await initializeCloudKit(iCloudConfig, signInButtonId, undefined, undefined, onAuthStatusUpdate);
2882
- const clientKeyShares = await this.getClientKeySharesFromLocalStorage({
2883
- accountAddress
2884
- });
2885
- if (clientKeyShares.length === 0) {
2886
- throw new Error('No key shares found to backup');
2887
- }
2888
- const wallet = this.walletMap[accountAddress];
2889
- const thresholdSignatureScheme = (wallet == null ? void 0 : wallet.thresholdSignatureScheme) || core.ThresholdSignatureScheme.TWO_OF_TWO;
2890
- const savedRecords = [];
2891
- const encryptedKeyShares = [];
2892
- for(let i = 0; i < clientKeyShares.length; i++){
2893
- const keyShare = clientKeyShares[i];
2894
- const encryptedKeyShare = await this.encryptKeyShare({
2895
- keyShare,
2896
- password
2855
+ /**
2856
+ * This method handles the complete flow for ensuring wallet key shares are backed up to Google Drive:
2857
+ * - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to Google Drive)
2858
+ * - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and Google Drive
2859
+ *
2860
+ * @param params - The backup parameters
2861
+ * @param params.accountAddress - The wallet account address to backup
2862
+ * @param params.password - Optional password for encryption (uses environment ID if not provided)
2863
+ * @param params.signedSessionId - Optional signed session ID for authentication
2864
+ */ async backupKeySharesToGoogleDrive({ accountAddress, password, signedSessionId }) {
2865
+ return this.backupKeySharesToCloudProvider({
2866
+ accountAddress,
2867
+ password,
2868
+ signedSessionId,
2869
+ backupLocation: core.BackupLocation.GOOGLE_DRIVE
2870
+ });
2871
+ }
2872
+ /**
2873
+ * This method handles the complete flow for ensuring wallet key shares are backed up to iCloud:
2874
+ * - For 2-of-2 wallets: Automatically reshares to 2-of-3 threshold, then distributes shares (1 to backend, 1 to iCloud)
2875
+ * - For 2-of-3 wallets: Call storeEncryptedBackupByWallet to backup for backend and iCloud
2876
+ *
2877
+ * @param params - The backup parameters
2878
+ * @param params.accountAddress - The wallet account address to backup
2879
+ * @param params.password - Optional password for encryption (uses environment ID if not provided)
2880
+ * @param params.signedSessionId - Optional signed session ID for authentication
2881
+ */ async backupKeySharesToICloud({ accountAddress, password, signedSessionId }) {
2882
+ return this.backupKeySharesToCloudProvider({
2883
+ accountAddress,
2884
+ password,
2885
+ signedSessionId,
2886
+ backupLocation: core.BackupLocation.ICLOUD
2887
+ });
2888
+ }
2889
+ /**
2890
+ * Generic router method that uploads encrypted key shares to the specified cloud provider
2891
+ * @param provider - The cloud backup provider (GOOGLE_DRIVE, ICLOUD, etc.)
2892
+ * @param accountAddress - Wallet account address
2893
+ * @param encryptedKeyShares - Already encrypted key shares to upload
2894
+ * @returns Promise<void>
2895
+ */ async uploadToCloudProvider({ provider, accountAddress, encryptedKeyShares }) {
2896
+ switch(provider){
2897
+ case core.BackupLocation.GOOGLE_DRIVE:
2898
+ return this.uploadKeySharesToGoogleDrive({
2899
+ accountAddress,
2900
+ encryptedKeyShares
2897
2901
  });
2898
- encryptedKeyShares.push(encryptedKeyShare);
2899
- }
2900
- const backupData = createBackupData({
2901
- encryptedKeyShares,
2902
- accountAddress,
2903
- thresholdSignatureScheme,
2904
- hasPassword: !!password
2905
- });
2906
- if (onProgress) {
2907
- onProgress(0, 1);
2908
- }
2909
- const savedRecord = await saveBackupToICloud(backupData);
2910
- savedRecords.push(savedRecord);
2911
- if (onProgress) {
2912
- onProgress(1, 1);
2913
- }
2914
- return savedRecords;
2915
- } catch (error) {
2916
- logError({
2917
- message: 'Error in backupKeySharesToICloud',
2918
- error: error,
2919
- context: {
2920
- accountAddress
2921
- }
2922
- });
2923
- throw error;
2902
+ case core.BackupLocation.ICLOUD:
2903
+ return this.uploadKeySharesToICloud({
2904
+ accountAddress,
2905
+ encryptedKeyShares
2906
+ });
2907
+ default:
2908
+ throw new Error(`Unsupported cloud provider: ${provider}`);
2924
2909
  }
2925
2910
  }
2926
2911
  /**
@@ -2972,6 +2957,40 @@ class DynamicWalletClient {
2972
2957
  throw error;
2973
2958
  }
2974
2959
  }
2960
+ /**
2961
+ * Private method that handles only the iCloud upload mechanics without any reshare logic.
2962
+ * It takes already encrypted key shares and uploads them to iCloud.
2963
+ * @param accountAddress - The wallet account address
2964
+ * @param encryptedKeyShares - Already encrypted key shares to upload
2965
+ * @returns Promise<void>
2966
+ */ async uploadKeySharesToICloud({ accountAddress, encryptedKeyShares }) {
2967
+ try {
2968
+ var _environmentSettings_sdk_waas, _environmentSettings_sdk;
2969
+ if (encryptedKeyShares.length === 0) {
2970
+ throw new Error('No key shares found');
2971
+ }
2972
+ const environmentSettings = await this.apiClient.getEnvironmentSettings();
2973
+ const iCloudConfig = environmentSettings == null ? void 0 : (_environmentSettings_sdk = environmentSettings.sdk) == null ? void 0 : (_environmentSettings_sdk_waas = _environmentSettings_sdk.waas) == null ? void 0 : _environmentSettings_sdk_waas.iCloud;
2974
+ await initializeCloudKit(iCloudConfig);
2975
+ const thresholdSignatureScheme = this.walletMap[accountAddress].thresholdSignatureScheme;
2976
+ const backupData = createBackupData({
2977
+ encryptedKeyShares,
2978
+ accountAddress,
2979
+ thresholdSignatureScheme
2980
+ });
2981
+ await saveBackupToICloud(backupData);
2982
+ return;
2983
+ } catch (error) {
2984
+ logError({
2985
+ message: 'Error in uploadKeySharesToICloud',
2986
+ error: error,
2987
+ context: {
2988
+ accountAddress
2989
+ }
2990
+ });
2991
+ throw error;
2992
+ }
2993
+ }
2975
2994
  async exportClientKeysharesFromGoogleDrive({ accountAddress, password, signedSessionId }) {
2976
2995
  try {
2977
2996
  await this.getWallet({
@@ -3624,25 +3643,26 @@ exports.ERROR_VERIFY_MESSAGE_SIGNATURE = ERROR_VERIFY_MESSAGE_SIGNATURE;
3624
3643
  exports.ERROR_VERIFY_TRANSACTION_SIGNATURE = ERROR_VERIFY_TRANSACTION_SIGNATURE;
3625
3644
  exports.WalletBusyError = WalletBusyError;
3626
3645
  exports.cancelICloudAuth = cancelICloudAuth;
3627
- exports.createAddGoogleDriveToExistingDelegationDistribution = createAddGoogleDriveToExistingDelegationDistribution;
3646
+ exports.createAddCloudProviderToExistingDelegationDistribution = createAddCloudProviderToExistingDelegationDistribution;
3628
3647
  exports.createBackupData = createBackupData;
3648
+ exports.createCloudProviderDistribution = createCloudProviderDistribution;
3629
3649
  exports.createDelegationOnlyDistribution = createDelegationOnlyDistribution;
3630
- exports.createDelegationWithGoogleDriveDistribution = createDelegationWithGoogleDriveDistribution;
3650
+ exports.createDelegationWithCloudProviderDistribution = createDelegationWithCloudProviderDistribution;
3631
3651
  exports.createDynamicOnlyDistribution = createDynamicOnlyDistribution;
3632
- exports.createGoogleDriveOnlyDistribution = createGoogleDriveOnlyDistribution;
3633
3652
  exports.deleteICloudBackup = deleteICloudBackup;
3634
3653
  exports.downloadStringAsFile = downloadStringAsFile;
3635
3654
  exports.extractPubkey = extractPubkey;
3636
3655
  exports.formatEvmMessage = formatEvmMessage;
3637
3656
  exports.formatMessage = formatMessage;
3657
+ exports.getActiveCloudProviders = getActiveCloudProviders;
3638
3658
  exports.getClientKeyShareBackupInfo = getClientKeyShareBackupInfo;
3639
3659
  exports.getClientKeyShareExportFileName = getClientKeyShareExportFileName;
3640
3660
  exports.getGoogleOAuthAccountId = getGoogleOAuthAccountId;
3641
3661
  exports.getICloudBackup = getICloudBackup;
3642
3662
  exports.getMPCSignatureScheme = getMPCSignatureScheme;
3643
3663
  exports.getMPCSigner = getMPCSigner;
3664
+ exports.hasCloudProviderBackup = hasCloudProviderBackup;
3644
3665
  exports.hasDelegatedBackup = hasDelegatedBackup;
3645
- exports.hasGoogleDriveBackup = hasGoogleDriveBackup;
3646
3666
  exports.isBrowser = isBrowser;
3647
3667
  exports.isHexString = isHexString;
3648
3668
  exports.listICloudBackups = listICloudBackups;