@dynamic-labs-wallet/browser 0.0.323 → 0.0.324

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.
Files changed (55) hide show
  1. package/index.cjs.js +192 -72
  2. package/index.esm.js +192 -72
  3. package/package.json +3 -3
  4. package/src/backup/encryption/argon2.d.ts +10 -0
  5. package/src/backup/encryption/argon2.d.ts.map +1 -0
  6. package/src/backup/encryption/config.d.ts +39 -0
  7. package/src/backup/encryption/config.d.ts.map +1 -0
  8. package/src/backup/encryption/constants.d.ts +35 -0
  9. package/src/backup/encryption/constants.d.ts.map +1 -0
  10. package/src/backup/encryption/core.d.ts +31 -0
  11. package/src/backup/encryption/core.d.ts.map +1 -0
  12. package/src/backup/encryption/pbkdf2.d.ts +10 -0
  13. package/src/backup/encryption/pbkdf2.d.ts.map +1 -0
  14. package/src/backup/encryption/types.d.ts +46 -0
  15. package/src/backup/encryption/types.d.ts.map +1 -0
  16. package/src/backup/encryption/utils.d.ts +9 -0
  17. package/src/backup/encryption/utils.d.ts.map +1 -0
  18. package/src/backup/providers/googleDrive.d.ts +19 -0
  19. package/src/backup/providers/googleDrive.d.ts.map +1 -0
  20. package/src/backup/providers/iCloud.d.ts +64 -0
  21. package/src/backup/providers/iCloud.d.ts.map +1 -0
  22. package/src/backup/utils.d.ts +23 -0
  23. package/src/backup/utils.d.ts.map +1 -0
  24. package/src/client.d.ts +787 -0
  25. package/src/client.d.ts.map +1 -0
  26. package/src/constants.d.ts +9 -0
  27. package/src/constants.d.ts.map +1 -0
  28. package/src/errorConstants.d.ts +13 -0
  29. package/src/errorConstants.d.ts.map +1 -0
  30. package/src/index.d.ts +14 -0
  31. package/src/index.d.ts.map +1 -0
  32. package/src/mpc/index.d.ts +5 -0
  33. package/src/mpc/index.d.ts.map +1 -0
  34. package/src/mpc/mpc.d.ts +20 -0
  35. package/src/mpc/mpc.d.ts.map +1 -0
  36. package/src/mpc/types.d.ts +6 -0
  37. package/src/mpc/types.d.ts.map +1 -0
  38. package/src/normalizeAddress.d.ts +7 -0
  39. package/src/normalizeAddress.d.ts.map +1 -0
  40. package/src/passwordValidation.d.ts +29 -0
  41. package/src/passwordValidation.d.ts.map +1 -0
  42. package/src/queue.d.ts +96 -0
  43. package/src/queue.d.ts.map +1 -0
  44. package/src/services/encryption.d.ts +19 -0
  45. package/src/services/encryption.d.ts.map +1 -0
  46. package/src/services/localStorage.d.ts +34 -0
  47. package/src/services/localStorage.d.ts.map +1 -0
  48. package/src/services/logger.d.ts +6 -0
  49. package/src/services/logger.d.ts.map +1 -0
  50. package/src/types.d.ts +129 -0
  51. package/src/types.d.ts.map +1 -0
  52. package/src/utils.d.ts +90 -0
  53. package/src/utils.d.ts.map +1 -0
  54. package/src/walletState.d.ts +28 -0
  55. package/src/walletState.d.ts.map +1 -0
package/index.esm.js CHANGED
@@ -373,6 +373,22 @@ const uploadFileToGoogleDrivePersonal = async ({ accessToken, fileName, jsonData
373
373
  ]
374
374
  });
375
375
  };
376
+ /**
377
+ * Verifies that a file exists on Google Drive by fetching its metadata
378
+ */ const verifyUpload = async ({ accessToken, fileId })=>{
379
+ const verifyResponse = await fetch(`${GOOGLE_DRIVE_UPLOAD_API}/drive/v3/files/${fileId}?fields=id,name`, {
380
+ headers: {
381
+ Authorization: `Bearer ${accessToken}`
382
+ }
383
+ });
384
+ if (!verifyResponse.ok) {
385
+ throw new Error(`Upload verification failed: file ${fileId} not accessible after upload`);
386
+ }
387
+ const verifyResult = await verifyResponse.json();
388
+ if (verifyResult.id !== fileId) {
389
+ throw new Error(`Upload verification failed: expected file ID ${fileId}, got ${verifyResult.id}`);
390
+ }
391
+ };
376
392
  const uploadFileToGoogleDrive = async ({ accessToken, fileName, jsonData, parents })=>{
377
393
  const metadata = {
378
394
  name: fileName,
@@ -401,6 +417,14 @@ const uploadFileToGoogleDrive = async ({ accessToken, fileName, jsonData, parent
401
417
  throw new Error('Error uploading file');
402
418
  }
403
419
  const result = await response.json();
420
+ const fileId = result.id;
421
+ if (!fileId) {
422
+ throw new Error('Upload response missing file ID');
423
+ }
424
+ await verifyUpload({
425
+ accessToken,
426
+ fileId
427
+ });
404
428
  return result; // Return file metadata, including file ID
405
429
  };
406
430
  const listFilesFromGoogleDrive = async ({ accessToken, fileName })=>{
@@ -555,6 +579,32 @@ const getClientKeyShareBackupInfo = (params)=>{
555
579
  const timeoutPromise = ({ timeInMs, activity = 'Ceremony' })=>{
556
580
  return new Promise((_, reject)=>setTimeout(()=>reject(new Error(`${activity} did not complete in ${timeInMs}ms`)), timeInMs));
557
581
  };
582
+ const buildErrorContext = (error)=>{
583
+ var _error_response, _error_response1;
584
+ return {
585
+ error: error instanceof Error ? error.message : 'Unknown error',
586
+ errorStack: error instanceof Error ? error.stack : undefined,
587
+ axiosError: error instanceof AxiosError ? (_error_response = error.response) == null ? void 0 : _error_response.data : undefined,
588
+ axiosStatus: error instanceof AxiosError ? (_error_response1 = error.response) == null ? void 0 : _error_response1.status : undefined
589
+ };
590
+ };
591
+ const logRetrySuccess = (operationName, attempts, logContext)=>{
592
+ Logger.info(`Successfully executed ${operationName} after ${attempts + 1} attempts`, _extends({}, logContext, {
593
+ attemptsTaken: attempts + 1
594
+ }));
595
+ };
596
+ const logRetryFailure = (operationName, attempts, maxAttempts, errorContext, logContext)=>{
597
+ Logger.warn(`Failed to execute ${operationName} on attempt ${attempts}/${maxAttempts}`, _extends({}, logContext, errorContext, {
598
+ attempt: attempts,
599
+ maxAttempts,
600
+ willRetry: attempts < maxAttempts
601
+ }));
602
+ };
603
+ const logRetryExhausted = (operationName, maxAttempts, errorContext, logContext)=>{
604
+ Logger.error(`Failed to execute ${operationName} after ${maxAttempts} attempts - stopping retry`, _extends({}, logContext, errorContext, {
605
+ totalAttempts: maxAttempts
606
+ }));
607
+ };
558
608
  /**
559
609
  * Generic helper function to retry a promise-based operations
560
610
  *
@@ -566,24 +616,24 @@ const timeoutPromise = ({ timeInMs, activity = 'Ceremony' })=>{
566
616
  let attempts = 0;
567
617
  while(attempts < maxAttempts){
568
618
  try {
569
- return await operation();
619
+ const result = await operation();
620
+ if (attempts > 0) {
621
+ logRetrySuccess(operationName, attempts, logContext);
622
+ }
623
+ return result;
570
624
  } catch (error) {
571
- var _error_response;
572
625
  attempts++;
573
- Logger.warn(`Failed to execute ${operationName} on attempt ${attempts}`, _extends({}, logContext, {
574
- error: error instanceof Error ? error.message : 'Unknown error',
575
- axiosError: error instanceof AxiosError ? (_error_response = error.response) == null ? void 0 : _error_response.data : undefined
576
- }));
626
+ const errorContext = buildErrorContext(error);
627
+ logRetryFailure(operationName, attempts, maxAttempts, errorContext, logContext);
577
628
  if (attempts === maxAttempts) {
578
- var _error_response1;
579
- Logger.error(`Failed to execute ${operationName} after ${maxAttempts} attempts`, _extends({}, logContext, {
580
- error: error instanceof Error ? error.message : 'Unknown error',
581
- axiosError: error instanceof AxiosError ? (_error_response1 = error.response) == null ? void 0 : _error_response1.data : undefined
582
- }));
629
+ logRetryExhausted(operationName, maxAttempts, errorContext, logContext);
583
630
  throw error;
584
631
  }
585
- // Calculate exponential backoff delay
586
632
  const exponentialDelay = retryInterval * 2 ** (attempts - 1);
633
+ Logger.debug(`Retrying ${operationName} in ${exponentialDelay}ms`, _extends({}, logContext, {
634
+ nextAttempt: attempts + 1,
635
+ delayMs: exponentialDelay
636
+ }));
587
637
  await new Promise((resolve)=>setTimeout(resolve, exponentialDelay));
588
638
  }
589
639
  }
@@ -1063,49 +1113,81 @@ const initializeCloudKit = async (config, signInButtonId, onSignInRequired, onSi
1063
1113
  await ensureICloudAuth(onSignInRequired, onSignInComplete, onAuthStatusUpdate, authOptions);
1064
1114
  };
1065
1115
 
1116
+ /**
1117
+ * Extracts error message and stack from an unknown error value
1118
+ */ const getErrorDetails = (error)=>{
1119
+ const message = error instanceof Error ? error.message : String(error);
1120
+ const stack = error instanceof Error ? error.stack : undefined;
1121
+ return {
1122
+ message,
1123
+ stack
1124
+ };
1125
+ };
1126
+ /**
1127
+ * Processes a single upload result and logs appropriately
1128
+ * @returns Error message if failed, undefined if successful
1129
+ */ const processUploadResult = (result, locationName, logContext, logger)=>{
1130
+ if (result.status === 'fulfilled') {
1131
+ logger.info(`[DynamicWaasWalletClient] Successfully uploaded keyshares to ${locationName}`, logContext);
1132
+ return undefined;
1133
+ }
1134
+ const { message, stack } = getErrorDetails(result.reason);
1135
+ logger.error(`[DynamicWaasWalletClient] Failed to upload keyshares to ${locationName}`, _extends({}, logContext, {
1136
+ error: message,
1137
+ errorStack: stack
1138
+ }));
1139
+ return `Failed to backup keyshares to ${locationName}: ${message}`;
1140
+ };
1066
1141
  /**
1067
1142
  * Uploads a backup to Google Drive App
1068
1143
  * @param accessToken - The access token for the Google Drive API
1069
1144
  * @param fileName - The name of the file to upload
1070
1145
  * @param backupData - The data to upload
1071
1146
  * @param accountAddress - The account address associated with the backup
1072
- */ const uploadBackupToGoogleDrive = async ({ accessToken, fileName, backupData, accountAddress })=>{
1147
+ * @param walletId - The wallet ID for logging context
1148
+ * @param environmentId - The environment ID for logging context
1149
+ * @param chainName - The chain name for logging context
1150
+ * @param logger - The logger instance to use for logging
1151
+ */ const uploadBackupToGoogleDrive = async ({ accessToken, fileName, backupData, accountAddress, walletId, environmentId, chainName, logger })=>{
1152
+ const logContext = {
1153
+ accountAddress,
1154
+ walletId,
1155
+ environmentId,
1156
+ chainName,
1157
+ fileName
1158
+ };
1159
+ logger.info('[DynamicWaasWalletClient] Starting Google Drive backup upload', logContext);
1073
1160
  const uploadPromises = [
1074
1161
  retryPromise(()=>uploadFileToGoogleDriveAppStorage({
1075
1162
  accessToken,
1076
1163
  fileName,
1077
1164
  jsonData: backupData
1078
- })),
1165
+ }), {
1166
+ operationName: 'Google Drive App Storage upload',
1167
+ logContext
1168
+ }),
1079
1169
  retryPromise(()=>uploadFileToGoogleDrivePersonal({
1080
1170
  accessToken,
1081
1171
  fileName,
1082
1172
  jsonData: backupData
1083
- }))
1173
+ }), {
1174
+ operationName: 'Google Drive Personal upload',
1175
+ logContext
1176
+ })
1084
1177
  ];
1085
1178
  const results = await Promise.allSettled(uploadPromises);
1086
- const errors = [];
1087
- // Check App Storage result
1088
- if (results[0].status === 'rejected') {
1089
- const error = results[0].reason;
1090
- Logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive App Storage', {
1091
- accountAddress,
1092
- error
1093
- });
1094
- errors.push(`Failed to backup keyshares to Google Drive App Storage: ${error instanceof Error ? error.message : String(error)}`);
1095
- }
1096
- // Check Personal Drive result
1097
- if (results[1].status === 'rejected') {
1098
- const error = results[1].reason;
1099
- Logger.error('[DynamicWaasWalletClient] Failed to upload keyshares to Google Drive Personal', {
1100
- accountAddress,
1101
- error
1102
- });
1103
- errors.push(`Failed to backup keyshares to Google Drive Personal: ${error instanceof Error ? error.message : String(error)}`);
1104
- }
1105
- // Throw if any uploads failed
1179
+ const errors = [
1180
+ processUploadResult(results[0], 'Google Drive App Storage', logContext, logger),
1181
+ processUploadResult(results[1], 'Google Drive Personal', logContext, logger)
1182
+ ].filter((error)=>error !== undefined);
1106
1183
  if (errors.length > 0) {
1184
+ logger.error('[DynamicWaasWalletClient] Google Drive backup failed', _extends({}, logContext, {
1185
+ errorCount: errors.length,
1186
+ errors
1187
+ }));
1107
1188
  throw new Error(`[DynamicWaasWalletClient] ${errors.join('; ')}`);
1108
1189
  }
1190
+ logger.info('[DynamicWaasWalletClient] Google Drive backup completed successfully', logContext);
1109
1191
  };
1110
1192
 
1111
1193
  const ERROR_PASSWORD_MISMATCH = '[DynamicWaasWalletClient]: Password does not match the password used for existing wallets. All wallets must use the same password for encrypted backups.';
@@ -2477,6 +2559,17 @@ class DynamicWalletClient {
2477
2559
  }, this.getTraceContext(traceContext)));
2478
2560
  }
2479
2561
  }
2562
+ // Create a rejection handler that will be wired up synchronously below.
2563
+ // Promise executors run synchronously, so rejectOnSSEError is guaranteed
2564
+ // to be assigned before serverSign is called.
2565
+ let rejectOnSSEError;
2566
+ const sseErrorPromise = new Promise((_, reject)=>{
2567
+ rejectOnSSEError = reject;
2568
+ });
2569
+ // Prevent unhandled rejection if SSE errors before serverSignPromise resolves
2570
+ // (sseErrorPromise would never reach Promise.race in that path)
2571
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
2572
+ sseErrorPromise.catch(()=>{});
2480
2573
  // Perform the server sign
2481
2574
  const serverSignPromise = this.serverSign({
2482
2575
  walletId: wallet.walletId,
@@ -2486,7 +2579,10 @@ class DynamicWalletClient {
2486
2579
  elevatedAccessToken,
2487
2580
  roomId,
2488
2581
  context,
2489
- onError,
2582
+ onError: (error)=>{
2583
+ onError == null ? void 0 : onError(error);
2584
+ rejectOnSSEError(error);
2585
+ },
2490
2586
  dynamicRequestId,
2491
2587
  traceContext,
2492
2588
  bitcoinConfig
@@ -2504,7 +2600,10 @@ class DynamicWalletClient {
2504
2600
  }, this.getTraceContext(traceContext)));
2505
2601
  let signature;
2506
2602
  try {
2507
- signature = await this.clientSign({
2603
+ // Race clientSign against SSE errors so that server-side failures
2604
+ // (e.g. policy violations) immediately reject instead of hanging
2605
+ // until viem's task queue timeout.
2606
+ const clientSignPromise = this.clientSign({
2508
2607
  chainName,
2509
2608
  message,
2510
2609
  roomId,
@@ -2515,6 +2614,15 @@ class DynamicWalletClient {
2515
2614
  traceContext,
2516
2615
  bitcoinConfig
2517
2616
  });
2617
+ // Prevent unhandled rejection from the losing promise in the race:
2618
+ // if sseErrorPromise wins, clientSign keeps running and will eventually
2619
+ // reject (MPC timeout); if clientSign wins, sseErrorPromise may never settle.
2620
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
2621
+ clientSignPromise.catch(()=>{});
2622
+ signature = await Promise.race([
2623
+ clientSignPromise,
2624
+ sseErrorPromise
2625
+ ]);
2518
2626
  } catch (signError) {
2519
2627
  // If public key mismatch and haven't tried recovery yet, recover and retry entire operation
2520
2628
  if (!hasAttemptedKeyShareRecovery) {
@@ -3570,11 +3678,28 @@ class DynamicWalletClient {
3570
3678
  }
3571
3679
  async backupSharesWithDistribution({ accountAddress, password, signedSessionId, distribution, preserveDelegatedLocation = false, passwordUpdateBatchId }) {
3572
3680
  const dynamicRequestId = v4();
3681
+ // Get wallet data early for logging context (also used in catch block)
3682
+ const walletData = this.getWalletFromMap(accountAddress);
3683
+ // Common context for all logs in this method
3684
+ const logContext = {
3685
+ accountAddress,
3686
+ dynamicRequestId,
3687
+ walletId: walletData == null ? void 0 : walletData.walletId,
3688
+ userId: this.userId,
3689
+ environmentId: this.environmentId
3690
+ };
3691
+ this.logger.info('[backupSharesWithDistribution] Starting backup', _extends({}, logContext, {
3692
+ hasPassword: !!password,
3693
+ preserveDelegatedLocation,
3694
+ passwordUpdateBatchId,
3695
+ dynamicShareCount: distribution.clientShares.length,
3696
+ cloudProviders: Object.keys(distribution.cloudProviderShares),
3697
+ hasDelegatedShare: !!distribution.delegatedShare
3698
+ }));
3573
3699
  try {
3574
- var _backupData_locationsWithKeyShares;
3700
+ var _backupData_locationsWithKeyShares, _backupData_locationsWithKeyShares1;
3575
3701
  // Resolve signed session ID lazily once, so all downstream calls receive a string.
3576
3702
  const resolvedSignedSessionId = await this.resolveSignedSessionId(signedSessionId);
3577
- const walletData = this.getWalletFromMap(accountAddress);
3578
3703
  if (!(walletData == null ? void 0 : walletData.walletId)) {
3579
3704
  const error = new Error(`WalletId not found for accountAddress ${accountAddress}`);
3580
3705
  logError({
@@ -3598,13 +3723,11 @@ class DynamicWalletClient {
3598
3723
  maxAttempts: 3,
3599
3724
  operationName: 'encrypt key share'
3600
3725
  });
3601
- this.logger.debug('[backupSharesWithDistribution] Pre-encrypting shares', {
3726
+ this.logger.debug('[backupSharesWithDistribution] Pre-encrypting shares', _extends({}, logContext, {
3602
3727
  dynamicShareCount: distribution.clientShares.length,
3603
3728
  cloudProviders: Object.keys(distribution.cloudProviderShares),
3604
- hasDelegatedShare: !!distribution.delegatedShare,
3605
- accountAddress,
3606
- dynamicRequestId
3607
- });
3729
+ hasDelegatedShare: !!distribution.delegatedShare
3730
+ }));
3608
3731
  const preEncryptedDynamicShares = distribution.clientShares.length > 0 ? await Promise.all(distribution.clientShares.map(encryptWithRetry)) : [];
3609
3732
  const cloudEntries = Object.entries(distribution.cloudProviderShares).filter(([, shares])=>shares && shares.length > 0);
3610
3733
  const preEncryptedCloudShares = await Promise.all(cloudEntries.map(async ([provider, shares])=>({
@@ -3612,12 +3735,10 @@ class DynamicWalletClient {
3612
3735
  shares: shares,
3613
3736
  encrypted: await Promise.all(shares.map(encryptWithRetry))
3614
3737
  })));
3615
- this.logger.debug('[backupSharesWithDistribution] Encryption complete, starting uploads', {
3738
+ this.logger.debug('[backupSharesWithDistribution] Encryption complete, starting uploads', _extends({}, logContext, {
3616
3739
  dynamicShareCount: preEncryptedDynamicShares.length,
3617
- cloudProviderCount: preEncryptedCloudShares.length,
3618
- accountAddress,
3619
- dynamicRequestId
3620
- });
3740
+ cloudProviderCount: preEncryptedCloudShares.length
3741
+ }));
3621
3742
  // Step 1: Upload shares in parallel, each with its own retry
3622
3743
  const uploadPromises = [];
3623
3744
  if (distribution.clientShares.length > 0) {
@@ -3666,12 +3787,10 @@ class DynamicWalletClient {
3666
3787
  }
3667
3788
  const uploadResults = await Promise.all(uploadPromises);
3668
3789
  const locations = uploadResults.filter((loc)=>loc !== undefined);
3669
- this.logger.debug('[backupSharesWithDistribution] Uploads complete, activating shares', {
3790
+ this.logger.info('[backupSharesWithDistribution] Uploads complete, activating shares on server', _extends({}, logContext, {
3670
3791
  locationCount: locations.length,
3671
- locations: locations.map((l)=>l.location),
3672
- accountAddress,
3673
- dynamicRequestId
3674
- });
3792
+ locations: locations.map((l)=>l.location)
3793
+ }));
3675
3794
  // Preserve existing delegated location
3676
3795
  if (preserveDelegatedLocation && !distribution.delegatedShare) {
3677
3796
  const location = this.createPreservedDelegatedLocation({
@@ -3691,10 +3810,7 @@ class DynamicWalletClient {
3691
3810
  });
3692
3811
  // For password update pending responses, skip walletMap update — shares aren't active yet
3693
3812
  if (backupData.passwordUpdateStatus === 'pending') {
3694
- this.logger.debug('[backupSharesWithDistribution] Password update pending, skipping walletMap update', {
3695
- accountAddress,
3696
- dynamicRequestId
3697
- });
3813
+ this.logger.debug('[backupSharesWithDistribution] Password update pending, skipping walletMap update', logContext);
3698
3814
  return backupData;
3699
3815
  }
3700
3816
  if (passwordUpdateBatchId) {
@@ -3708,11 +3824,11 @@ class DynamicWalletClient {
3708
3824
  preEncryptedDynamicShares
3709
3825
  });
3710
3826
  }
3711
- var _backupData_locationsWithKeyShares1;
3827
+ var _backupData_locationsWithKeyShares2;
3712
3828
  const updatedBackupInfo = getClientKeyShareBackupInfo({
3713
3829
  walletProperties: {
3714
3830
  derivationPath: walletData.derivationPath,
3715
- keyShares: ((_backupData_locationsWithKeyShares1 = backupData.locationsWithKeyShares) != null ? _backupData_locationsWithKeyShares1 : []).map((ks)=>({
3831
+ keyShares: ((_backupData_locationsWithKeyShares2 = backupData.locationsWithKeyShares) != null ? _backupData_locationsWithKeyShares2 : []).map((ks)=>({
3716
3832
  id: ks.id,
3717
3833
  keygenId: ks.keygenId,
3718
3834
  backupLocation: ks.location,
@@ -3726,21 +3842,20 @@ class DynamicWalletClient {
3726
3842
  clientKeySharesBackupInfo: updatedBackupInfo
3727
3843
  });
3728
3844
  await this.storage.setItem(this.storageKey, JSON.stringify(this.walletMap));
3729
- var _backupData_locationsWithKeyShares_length;
3730
- this.logger.debug('[backupSharesWithDistribution] Backup complete', {
3731
- accountAddress,
3732
- dynamicRequestId,
3733
- locationCount: (_backupData_locationsWithKeyShares_length = (_backupData_locationsWithKeyShares = backupData.locationsWithKeyShares) == null ? void 0 : _backupData_locationsWithKeyShares.length) != null ? _backupData_locationsWithKeyShares_length : 0
3734
- });
3845
+ var _backupData_locationsWithKeyShares_length, _backupData_locationsWithKeyShares_map;
3846
+ this.logger.info('[backupSharesWithDistribution] Backup complete', _extends({}, logContext, {
3847
+ locationCount: (_backupData_locationsWithKeyShares_length = (_backupData_locationsWithKeyShares = backupData.locationsWithKeyShares) == null ? void 0 : _backupData_locationsWithKeyShares.length) != null ? _backupData_locationsWithKeyShares_length : 0,
3848
+ locations: (_backupData_locationsWithKeyShares_map = (_backupData_locationsWithKeyShares1 = backupData.locationsWithKeyShares) == null ? void 0 : _backupData_locationsWithKeyShares1.map((ks)=>ks.location)) != null ? _backupData_locationsWithKeyShares_map : []
3849
+ }));
3735
3850
  return backupData;
3736
3851
  } catch (error) {
3737
3852
  logError({
3738
3853
  message: 'Error in backupSharesWithDistribution',
3739
3854
  error: error,
3740
- context: {
3741
- accountAddress,
3742
- dynamicRequestId
3743
- }
3855
+ context: _extends({}, logContext, {
3856
+ chainName: walletData == null ? void 0 : walletData.chainName,
3857
+ errorStack: error instanceof Error ? error.stack : undefined
3858
+ })
3744
3859
  });
3745
3860
  throw error;
3746
3861
  }
@@ -4351,7 +4466,8 @@ class DynamicWalletClient {
4351
4466
  const accessToken = await this.apiClient.getAccessToken({
4352
4467
  oauthAccountId
4353
4468
  });
4354
- const thresholdSignatureScheme = this.getWalletFromMap(accountAddress).thresholdSignatureScheme;
4469
+ const walletData = this.getWalletFromMap(accountAddress);
4470
+ const thresholdSignatureScheme = walletData.thresholdSignatureScheme;
4355
4471
  const fileName = getClientKeyShareExportFileName({
4356
4472
  thresholdSignatureScheme,
4357
4473
  accountAddress,
@@ -4366,7 +4482,11 @@ class DynamicWalletClient {
4366
4482
  accessToken,
4367
4483
  fileName,
4368
4484
  backupData,
4369
- accountAddress
4485
+ accountAddress,
4486
+ walletId: walletData == null ? void 0 : walletData.walletId,
4487
+ environmentId: this.environmentId,
4488
+ chainName: walletData == null ? void 0 : walletData.chainName,
4489
+ logger: this.logger
4370
4490
  });
4371
4491
  return;
4372
4492
  } catch (error) {
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@dynamic-labs-wallet/browser",
3
- "version": "0.0.323",
3
+ "version": "0.0.324",
4
4
  "license": "Licensed under the Dynamic Labs, Inc. Terms Of Service (https://www.dynamic.xyz/terms-conditions)",
5
5
  "type": "module",
6
6
  "dependencies": {
7
- "@dynamic-labs-wallet/core": "0.0.323",
7
+ "@dynamic-labs-wallet/core": "0.0.324",
8
8
  "@dynamic-labs/sdk-api-core": "^0.0.900",
9
9
  "argon2id": "1.0.1",
10
- "axios": "1.13.5",
10
+ "axios": "1.15.0",
11
11
  "p-queue": "9.1.0",
12
12
  "semver": "^7.7.2",
13
13
  "tsl-apple-cloudkit": "0.2.34",
@@ -0,0 +1,10 @@
1
+ import type { EncryptionConfig } from './config.js';
2
+ import type { KeyDerivationParams } from './types.js';
3
+ /**
4
+ * Derives a key using Argon2id algorithm
5
+ * @param params - Key derivation parameters
6
+ * @param encryptionConfig - Encryption configuration
7
+ * @returns Promise<CryptoKey>
8
+ */
9
+ export declare const deriveArgon2Key: ({ password, salt }: KeyDerivationParams, encryptionConfig: EncryptionConfig) => Promise<CryptoKey>;
10
+ //# sourceMappingURL=argon2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argon2.d.ts","sourceRoot":"","sources":["../../../src/backup/encryption/argon2.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,KAAK,EAA0B,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,eAAe,uBACN,mBAAmB,oBACrB,gBAAgB,KACjC,OAAO,CAAC,SAAS,CAyBnB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { EncryptionVersion } from './constants.js';
2
+ import type { Argon2EncryptionConfig, BaseEncryptionConfig } from './types.js';
3
+ /**
4
+ * Encryption configuration for each version
5
+ */
6
+ export declare const ENCRYPTION_VERSIONS: {
7
+ readonly v1: {
8
+ readonly version: EncryptionVersion.V1_LEGACY;
9
+ readonly algorithm: "AES-GCM";
10
+ readonly keyDerivation: "PBKDF2";
11
+ readonly iterations: 100000;
12
+ readonly hashAlgorithm: "SHA-256";
13
+ readonly algorithmLength: 256;
14
+ };
15
+ readonly v2: {
16
+ readonly version: EncryptionVersion.V2_PBKDF2;
17
+ readonly algorithm: "AES-GCM";
18
+ readonly keyDerivation: "PBKDF2";
19
+ readonly iterations: 1000000;
20
+ readonly hashAlgorithm: "SHA-256";
21
+ readonly algorithmLength: 256;
22
+ };
23
+ readonly v3: Argon2EncryptionConfig;
24
+ };
25
+ /**
26
+ * Type for the encryption configuration
27
+ */
28
+ export type EncryptionConfig = BaseEncryptionConfig | Argon2EncryptionConfig;
29
+ /**
30
+ * Helper function to get encryption configuration by version string
31
+ * @param version - The version string (e.g., 'v1', 'v2', 'v3')
32
+ * @returns The encryption configuration for the specified version
33
+ */
34
+ export declare const getEncryptionConfig: (version?: string) => EncryptionConfig;
35
+ /**
36
+ * Check if a configuration uses Argon2
37
+ */
38
+ export declare const isArgon2Config: (config: EncryptionConfig) => config is Argon2EncryptionConfig;
39
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/backup/encryption/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,iBAAiB,EAKlB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE/E;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;iBA2BzB,sBAAsB;CACnB,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,sBAAsB,CAAC;AAE7E;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,aAAc,MAAM,KAAG,gBAYtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,WAAY,gBAAgB,KAAG,MAAM,IAAI,sBAEnE,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Encryption version identifiers
3
+ */
4
+ export declare enum EncryptionVersion {
5
+ V1_LEGACY = "v1",
6
+ V2_PBKDF2 = "v2",
7
+ V3_ARGON2 = "v3"
8
+ }
9
+ /**
10
+ * Current default version for new encryptions
11
+ */
12
+ export declare const ENCRYPTION_VERSION_CURRENT = EncryptionVersion.V3_ARGON2;
13
+ /**
14
+ * Algorithm constants
15
+ */
16
+ export declare const PBKDF2_ALGORITHM = "PBKDF2";
17
+ export declare const PBKDF2_HASH_ALGORITHM = "SHA-256";
18
+ export declare const HASH_ALGORITHM = "SHA-256";
19
+ export declare const ARGON2_ALGORITHM = "Argon2id";
20
+ export declare const AES_GCM_ALGORITHM = "AES-GCM";
21
+ export declare const AES_GCM_LENGTH = 256;
22
+ /**
23
+ * Argon2 configuration constants, values were chosen based on RFC (https://www.rfc-editor.org/rfc/rfc9106.html#name-parameter-choice)
24
+ * taking into account that this runs in the client, possibly in smartphones with limited resources
25
+ */
26
+ export declare const ARGON2_MEMORY_SIZE = 65536;
27
+ export declare const ARGON2_ITERATIONS = 3;
28
+ export declare const ARGON2_PARALLELISM = 2;
29
+ export declare const ARGON2_HASH_LENGTH = 32;
30
+ /**
31
+ * PBKDF2 configuration constants
32
+ */
33
+ export declare const PBKDF2_ITERATIONS_V1 = 100000;
34
+ export declare const PBKDF2_ITERATIONS_V2 = 1000000;
35
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/backup/encryption/constants.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,iBAAiB;IAC3B,SAAS,OAAO;IAChB,SAAS,OAAO;IAChB,SAAS,OAAO;CACjB;AAED;;GAEG;AACH,eAAO,MAAM,0BAA0B,8BAA8B,CAAC;AAEtE;;GAEG;AACH,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,eAAO,MAAM,qBAAqB,YAAY,CAAC;AAC/C,eAAO,MAAM,cAAc,YAAY,CAAC;AACxC,eAAO,MAAM,gBAAgB,aAAa,CAAC;AAC3C,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAC3C,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AACnC,eAAO,MAAM,kBAAkB,IAAI,CAAC;AACpC,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,oBAAoB,UAAU,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { EncryptionMetadata } from '@dynamic-labs-wallet/core';
2
+ import type { DecryptionData, EncryptedData } from './types.js';
3
+ export declare const INVALID_PASSWORD_ERROR = "Decryption failed: Invalid password. Please check your password and try again.";
4
+ export declare class InvalidPasswordError extends Error {
5
+ constructor();
6
+ }
7
+ /**
8
+ * Encrypts data using the specified encryption version.
9
+ * Always uses the latest encryption configuration for new encryptions by default.
10
+ */
11
+ export declare const encryptData: ({ data, password, version, }: {
12
+ data: string;
13
+ password: string;
14
+ version?: string;
15
+ }) => Promise<EncryptedData>;
16
+ /**
17
+ * Decrypts data with version-based configuration.
18
+ * Uses the version field from the data to determine encryption parameters.
19
+ * Falls back to legacy version for backward compatibility if no version is specified.
20
+ * For v3 (Argon2), retries with parallelism=1 if an OperationError occurs.
21
+ */
22
+ export declare const decryptData: ({ data, password }: {
23
+ data: DecryptionData;
24
+ password: string;
25
+ }) => Promise<string>;
26
+ /**
27
+ * Gets encryption metadata for a specific version.
28
+ * Used when we need to include metadata in legacy systems or APIs that require it.
29
+ */
30
+ export declare const getEncryptionMetadataForVersion: (version: string) => EncryptionMetadata;
31
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/backup/encryption/core.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAMpE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAuB,MAAM,YAAY,CAAC;AAGrF,eAAO,MAAM,sBAAsB,mFAAmF,CAAC;AAEvH,qBAAa,oBAAqB,SAAQ,KAAK;;CAK9C;AAoBD;;;GAGG;AACH,eAAO,MAAM,WAAW,iCAIrB;IACD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KAAG,OAAO,CAAC,aAAa,CA2BxB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,WAAW,uBAA8B;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,KAAG,OAAO,CAAC,MAAM,CAyDhH,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,+BAA+B,YAAa,MAAM,KAAG,kBAmBjE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { EncryptionConfig } from './config.js';
2
+ import type { KeyDerivationParams } from './types.js';
3
+ /**
4
+ * Derives a key using PBKDF2 algorithm
5
+ * @param params - Key derivation parameters
6
+ * @param encryptionConfig - Encryption configuration
7
+ * @returns Promise<CryptoKey>
8
+ */
9
+ export declare const derivePBKDF2Key: ({ password, salt }: KeyDerivationParams, encryptionConfig: EncryptionConfig) => Promise<CryptoKey>;
10
+ //# sourceMappingURL=pbkdf2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbkdf2.d.ts","sourceRoot":"","sources":["../../../src/backup/encryption/pbkdf2.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGtD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,uBACN,mBAAmB,oBACrB,gBAAgB,KACjC,OAAO,CAAC,SAAS,CAoBnB,CAAC"}
@@ -0,0 +1,46 @@
1
+ import type { EncryptionVersion } from './constants.js';
2
+ /**
3
+ * Base encryption configuration
4
+ */
5
+ export interface BaseEncryptionConfig {
6
+ version: EncryptionVersion;
7
+ algorithm: string;
8
+ keyDerivation: string;
9
+ iterations: number;
10
+ hashAlgorithm: string;
11
+ algorithmLength: number;
12
+ }
13
+ /**
14
+ * Argon2-specific encryption configuration
15
+ */
16
+ export interface Argon2EncryptionConfig extends BaseEncryptionConfig {
17
+ memorySize: number;
18
+ parallelism: number;
19
+ hashLength: number;
20
+ }
21
+ /**
22
+ * Encrypted data structure
23
+ */
24
+ export interface EncryptedData {
25
+ salt: string;
26
+ iv: string;
27
+ cipher: string;
28
+ version: string;
29
+ }
30
+ /**
31
+ * Decryption input data structure
32
+ */
33
+ export interface DecryptionData {
34
+ salt: string;
35
+ iv: string;
36
+ cipher: string;
37
+ version?: string;
38
+ }
39
+ /**
40
+ * Key derivation parameters
41
+ */
42
+ export interface KeyDerivationParams {
43
+ password: string;
44
+ salt: Uint8Array;
45
+ }
46
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/backup/encryption/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,iBAAiB,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;CAClB"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Utility functions for encryption operations
3
+ * These functions are separated to avoid circular dependencies
4
+ */
5
+ export declare const bytesToBase64: (arr: Uint8Array) => string;
6
+ export declare const stringToBytes: (str: string) => Uint8Array;
7
+ export declare const base64ToBytes: (base64: string) => Uint8Array;
8
+ export declare const ensureBase64Padding: (str: string) => string;
9
+ //# sourceMappingURL=utils.d.ts.map