@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.
- package/index.cjs.js +192 -72
- package/index.esm.js +192 -72
- package/package.json +3 -3
- package/src/backup/encryption/argon2.d.ts +10 -0
- package/src/backup/encryption/argon2.d.ts.map +1 -0
- package/src/backup/encryption/config.d.ts +39 -0
- package/src/backup/encryption/config.d.ts.map +1 -0
- package/src/backup/encryption/constants.d.ts +35 -0
- package/src/backup/encryption/constants.d.ts.map +1 -0
- package/src/backup/encryption/core.d.ts +31 -0
- package/src/backup/encryption/core.d.ts.map +1 -0
- package/src/backup/encryption/pbkdf2.d.ts +10 -0
- package/src/backup/encryption/pbkdf2.d.ts.map +1 -0
- package/src/backup/encryption/types.d.ts +46 -0
- package/src/backup/encryption/types.d.ts.map +1 -0
- package/src/backup/encryption/utils.d.ts +9 -0
- package/src/backup/encryption/utils.d.ts.map +1 -0
- package/src/backup/providers/googleDrive.d.ts +19 -0
- package/src/backup/providers/googleDrive.d.ts.map +1 -0
- package/src/backup/providers/iCloud.d.ts +64 -0
- package/src/backup/providers/iCloud.d.ts.map +1 -0
- package/src/backup/utils.d.ts +23 -0
- package/src/backup/utils.d.ts.map +1 -0
- package/src/client.d.ts +787 -0
- package/src/client.d.ts.map +1 -0
- package/src/constants.d.ts +9 -0
- package/src/constants.d.ts.map +1 -0
- package/src/errorConstants.d.ts +13 -0
- package/src/errorConstants.d.ts.map +1 -0
- package/src/index.d.ts +14 -0
- package/src/index.d.ts.map +1 -0
- package/src/mpc/index.d.ts +5 -0
- package/src/mpc/index.d.ts.map +1 -0
- package/src/mpc/mpc.d.ts +20 -0
- package/src/mpc/mpc.d.ts.map +1 -0
- package/src/mpc/types.d.ts +6 -0
- package/src/mpc/types.d.ts.map +1 -0
- package/src/normalizeAddress.d.ts +7 -0
- package/src/normalizeAddress.d.ts.map +1 -0
- package/src/passwordValidation.d.ts +29 -0
- package/src/passwordValidation.d.ts.map +1 -0
- package/src/queue.d.ts +96 -0
- package/src/queue.d.ts.map +1 -0
- package/src/services/encryption.d.ts +19 -0
- package/src/services/encryption.d.ts.map +1 -0
- package/src/services/localStorage.d.ts +34 -0
- package/src/services/localStorage.d.ts.map +1 -0
- package/src/services/logger.d.ts +6 -0
- package/src/services/logger.d.ts.map +1 -0
- package/src/types.d.ts +129 -0
- package/src/types.d.ts.map +1 -0
- package/src/utils.d.ts +90 -0
- package/src/utils.d.ts.map +1 -0
- package/src/walletState.d.ts +28 -0
- 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
|
-
|
|
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
|
-
|
|
574
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
3827
|
+
var _backupData_locationsWithKeyShares2;
|
|
3712
3828
|
const updatedBackupInfo = getClientKeyShareBackupInfo({
|
|
3713
3829
|
walletProperties: {
|
|
3714
3830
|
derivationPath: walletData.derivationPath,
|
|
3715
|
-
keyShares: ((
|
|
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.
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
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
|
-
|
|
3742
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|