@dynamic-labs-wallet/browser 1.0.89 → 1.0.90
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 +149 -50
- package/index.esm.js +150 -52
- package/internal/web/generated/libmpc_executor.js +1 -1
- package/internal/web/index.js +1 -1
- package/package.json +3 -3
- package/src/backup/utils.d.ts.map +1 -1
- package/src/client.d.ts +14 -0
- package/src/client.d.ts.map +1 -1
- package/src/index.d.ts +1 -0
- package/src/index.d.ts.map +1 -1
- package/src/observability.d.ts.map +1 -1
- package/src/services/logger.d.ts +15 -0
- package/src/services/logger.d.ts.map +1 -1
- package/src/services/signedSession.d.ts.map +1 -1
package/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BitcoinAddressType, MPC_RELAY_PROD_API_URL, getMPCChainConfig, parseNamespacedVersion, WalletApiError, BackupLocation, ENCRYPTED_SHARES_STORAGE_SUFFIX, Logger, handleAxiosError, WalletOperation, WalletReadyState, classifyForwardMpcError, isRecoveredForwardMpcConnectionChurn, FEATURE_FLAGS, ThresholdSignatureScheme, getClientThreshold, MPC_CONFIG, getTSSConfig, serializeMessageForForwardMPC, isEvmCompatibleChain, serializeError, getReshareConfig, getRequiredExternalKeyShareId, verifiedCredentialNameToChainEnum, AuthMode, NoopLogger, DynamicApiClient, BusinessAccountClient, getEnvironmentFromUrl, IFRAME_DOMAIN_MAP } from '@dynamic-labs-wallet/core';
|
|
1
|
+
import { BitcoinAddressType, MPC_RELAY_PROD_API_URL, getMPCChainConfig, parseNamespacedVersion, WalletApiError, BackupLocation, ENCRYPTED_SHARES_STORAGE_SUFFIX, Logger, NETWORK_ERROR_STATUS, handleAxiosError, WalletOperation, WalletReadyState, classifyForwardMpcError, isRecoveredForwardMpcConnectionChurn, FEATURE_FLAGS, ThresholdSignatureScheme, getClientThreshold, MPC_CONFIG, getTSSConfig, serializeMessageForForwardMPC, isEvmCompatibleChain, serializeError, getReshareConfig, getRequiredExternalKeyShareId, verifiedCredentialNameToChainEnum, AuthMode, NoopLogger, DynamicApiClient, BusinessAccountClient, getEnvironmentFromUrl, IFRAME_DOMAIN_MAP } from '@dynamic-labs-wallet/core';
|
|
2
2
|
export * from '@dynamic-labs-wallet/core';
|
|
3
3
|
export { Logger } from '@dynamic-labs-wallet/core';
|
|
4
4
|
import { EdBls12377, BIP340, ExportableEd25519, Ecdsa, MessageHash, EcdsaSignature, EcdsaKeygenResult, ExportableEd25519KeygenResult, BIP340KeygenResult } from '#internal/web';
|
|
@@ -653,13 +653,17 @@ function meetsMinVersion(sdkVersion, { minVersionByNamespace, fallbackMinVersion
|
|
|
653
653
|
// canRefresh only proves a local callback exists, not that the host answers it.
|
|
654
654
|
if (!this.supportsReverseChannel()) {
|
|
655
655
|
this.logger.warn(`[${operationName}] host SDK version predates the signed-session reverse channel, declining nonce refresh`, _extends({
|
|
656
|
-
|
|
656
|
+
http: {
|
|
657
|
+
status_code: status
|
|
658
|
+
}
|
|
657
659
|
}, logContext));
|
|
658
660
|
return alsoRetry ? alsoRetry(status) : false;
|
|
659
661
|
}
|
|
660
662
|
onRefreshed(await this.resolve());
|
|
661
663
|
this.logger.info(`[${operationName}] refreshed signed session, retrying`, _extends({
|
|
662
|
-
|
|
664
|
+
http: {
|
|
665
|
+
status_code: status
|
|
666
|
+
}
|
|
663
667
|
}, logContext));
|
|
664
668
|
return true;
|
|
665
669
|
}
|
|
@@ -675,7 +679,9 @@ function meetsMinVersion(sdkVersion, { minVersionByNamespace, fallbackMinVersion
|
|
|
675
679
|
this.logger.info(NONCE_FAILURE_EVENT, _extends({}, logContext, {
|
|
676
680
|
operationName,
|
|
677
681
|
attempt,
|
|
678
|
-
|
|
682
|
+
http: {
|
|
683
|
+
status_code: status
|
|
684
|
+
},
|
|
679
685
|
reason: classifyNonceFailure(body),
|
|
680
686
|
errorCode: body.code,
|
|
681
687
|
errorMessage: body.message,
|
|
@@ -2115,17 +2121,21 @@ const initializeCloudKit = async (config, signInButtonId, onSignInRequired, onSi
|
|
|
2115
2121
|
// Downgrade them to warn so monitors can filter on status:error and
|
|
2116
2122
|
// still catch real system-side failures (5xx/network/unknown) without
|
|
2117
2123
|
// the user-side noise drowning out the signal.
|
|
2118
|
-
const logFn = isUserActionable ? logger.warn : logger.error;
|
|
2119
2124
|
// When every location failed for the same reason (the dominant case)
|
|
2120
2125
|
// surface a single string; otherwise emit the array so consumers can
|
|
2121
2126
|
// see the mix.
|
|
2122
2127
|
const logErrorReason = uniqueReasons.length === 1 ? uniqueReasons[0] : uniqueReasons;
|
|
2123
|
-
|
|
2128
|
+
const logPayload = _extends({}, logContext, {
|
|
2124
2129
|
errorCount: failures.length,
|
|
2125
2130
|
errorReason: logErrorReason,
|
|
2126
2131
|
isUserActionable,
|
|
2127
2132
|
errors: failures.map((f)=>`Failed to backup keyshares to ${f.locationName}: ${f.message}`)
|
|
2128
|
-
})
|
|
2133
|
+
});
|
|
2134
|
+
if (isUserActionable) {
|
|
2135
|
+
logger.warn('[DynamicWaasWalletClient] Google Drive backup failed', logPayload);
|
|
2136
|
+
} else {
|
|
2137
|
+
logger.error('[DynamicWaasWalletClient] Google Drive backup failed', logPayload);
|
|
2138
|
+
}
|
|
2129
2139
|
// Both upload destinations (appDataFolder + personal) commonly fail with
|
|
2130
2140
|
// the same underlying error (e.g., missing OAuth scope). When all failures
|
|
2131
2141
|
// share one message, surface it once without per-location wrapping;
|
|
@@ -2172,7 +2182,12 @@ const classifyWaasErrorKind = (error)=>{
|
|
|
2172
2182
|
// only if the deadline passes; per-attempt we just tag the kind.
|
|
2173
2183
|
const classifyTransientPollError = (error)=>{
|
|
2174
2184
|
const status = readHttpStatus(error);
|
|
2175
|
-
|
|
2185
|
+
// `NETWORK_ERROR_STATUS` (0) is "no response received" — as transient as a 5xx.
|
|
2186
|
+
// It previously arrived here as 500 because handleAxiosError coerced every
|
|
2187
|
+
// unmapped failure to that, so it must stay classified as transient.
|
|
2188
|
+
if (status === 429 || status === NETWORK_ERROR_STATUS || status !== undefined && status >= 500) {
|
|
2189
|
+
return 'transient_exhausted';
|
|
2190
|
+
}
|
|
2176
2191
|
return classifyWaasErrorKind(error);
|
|
2177
2192
|
};
|
|
2178
2193
|
// Builds a structured log payload tagged with the HTTPS transport, dropping
|
|
@@ -2188,18 +2203,35 @@ const buildHttpCeremonyMeta = (fields)=>_extends({
|
|
|
2188
2203
|
* so they don't pollute error dashboards with user mistakes.
|
|
2189
2204
|
*/ const isExpectedUserError = (error)=>error instanceof InvalidPasswordError;
|
|
2190
2205
|
/**
|
|
2191
|
-
*
|
|
2192
|
-
*
|
|
2193
|
-
* `
|
|
2194
|
-
*
|
|
2195
|
-
|
|
2206
|
+
* Reads the HTTP status off a `WalletApiError`.
|
|
2207
|
+
*
|
|
2208
|
+
* Matches on `name` as well as `instanceof` because core is inlined into more
|
|
2209
|
+
* than one bundle, and a second copy of the class makes `instanceof` fail
|
|
2210
|
+
* against the first — which would silently defeat every downgrade below. An
|
|
2211
|
+
* error without a numeric status is treated as unrecognised (fail safe: stays
|
|
2212
|
+
* at the caller's fallback level).
|
|
2213
|
+
*/ const getWalletApiErrorStatus = (error)=>{
|
|
2214
|
+
const isWalletApiError = error instanceof WalletApiError || error instanceof Error && error.name === 'WalletApiError';
|
|
2215
|
+
if (!isWalletApiError) return undefined;
|
|
2216
|
+
const { status } = error;
|
|
2217
|
+
return typeof status === 'number' ? status : undefined;
|
|
2218
|
+
};
|
|
2196
2219
|
/**
|
|
2197
|
-
* Returns true for
|
|
2198
|
-
*
|
|
2199
|
-
*
|
|
2200
|
-
*
|
|
2201
|
-
*
|
|
2202
|
-
|
|
2220
|
+
* Returns true for client-class API errors (4xx, including 429 and 401)
|
|
2221
|
+
* surfaced as `WalletApiError`. A bad request, missing/invalid auth, forbidden,
|
|
2222
|
+
* or rate-limit is caused by the caller or is transient, so none of them are
|
|
2223
|
+
* actionable as backend errors — the catch-site `logError` logs them at `warn`
|
|
2224
|
+
* to keep them out of error-level dashboards. 401 in particular was the
|
|
2225
|
+
* dominant `Error in getWallet` catch-all contributor.
|
|
2226
|
+
*
|
|
2227
|
+
* 5xx is deliberately NOT downgraded: those are genuine backend failures and
|
|
2228
|
+
* the 500 monitors depend on them staying at `error`. The `handleAxiosError`
|
|
2229
|
+
* HTTP-layer log also records them with fuller context, now that it no longer
|
|
2230
|
+
* collides with Datadog's reserved `status` field.
|
|
2231
|
+
*/ const isDowngradableApiError = (error)=>{
|
|
2232
|
+
const status = getWalletApiErrorStatus(error);
|
|
2233
|
+
return status !== undefined && status < 500;
|
|
2234
|
+
};
|
|
2203
2235
|
/**
|
|
2204
2236
|
* Returns true for p-queue TimeoutError. These are transient and
|
|
2205
2237
|
* retryable client-side, so logging at `warn` prevents them from
|
|
@@ -2219,12 +2251,33 @@ const CLIENT_NETWORK_ERROR_MESSAGES = new Set([
|
|
|
2219
2251
|
const msg = error.message.toLowerCase();
|
|
2220
2252
|
return CLIENT_NETWORK_ERROR_MESSAGES.has(msg) || msg.startsWith('webassembly compilation aborted: network error');
|
|
2221
2253
|
};
|
|
2222
|
-
const
|
|
2223
|
-
if (isExpectedUserError(error))
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2254
|
+
const classifyOne = (error)=>{
|
|
2255
|
+
if (isExpectedUserError(error)) return 'info';
|
|
2256
|
+
if (isDowngradableApiError(error) || isQueueTimeoutError(error) || isClientNetworkError(error)) return 'warn';
|
|
2257
|
+
return undefined;
|
|
2258
|
+
};
|
|
2259
|
+
/** Bounded so a self-referencing or cyclic `cause` chain cannot spin. */ const MAX_CAUSE_DEPTH = 5;
|
|
2260
|
+
/**
|
|
2261
|
+
* Single source of truth for "how bad is this error". Exported so callers
|
|
2262
|
+
* classify identically instead of hard-coding `logger.error` for every failure.
|
|
2263
|
+
*
|
|
2264
|
+
* Walks the `cause` chain, because the outermost error is frequently a wrapper
|
|
2265
|
+
* that carries no information about severity — a chain client throws
|
|
2266
|
+
* `new Error(ERROR_SIGN_MESSAGE, { cause })`, so classifying only the top link
|
|
2267
|
+
* sees a bare `Error` and falls through to `error`. That is how a Cloudflare WAF
|
|
2268
|
+
* 429 kept being reported as a hard SDK failure even after the direct call sites
|
|
2269
|
+
* were fixed: the wrapper, not the cause, was being classified.
|
|
2270
|
+
*
|
|
2271
|
+
* The first classifiable link wins, so the most specific known failure in the
|
|
2272
|
+
* chain decides.
|
|
2273
|
+
*/ const resolveLogLevel = (error, fallback)=>{
|
|
2274
|
+
let current = error;
|
|
2275
|
+
for(let depth = 0; current !== undefined && current !== null && depth < MAX_CAUSE_DEPTH; depth += 1){
|
|
2276
|
+
const level = classifyOne(current);
|
|
2277
|
+
if (level) return level;
|
|
2278
|
+
const next = current instanceof Error ? current.cause : undefined;
|
|
2279
|
+
if (next === current) break;
|
|
2280
|
+
current = next;
|
|
2228
2281
|
}
|
|
2229
2282
|
return fallback;
|
|
2230
2283
|
};
|
|
@@ -2991,6 +3044,17 @@ class DynamicWalletClient {
|
|
|
2991
3044
|
return this.walletMap[normalizeAddress(accountAddress)];
|
|
2992
3045
|
}
|
|
2993
3046
|
/**
|
|
3047
|
+
* Sync variant of {@link requireWalletFromMap} (no refetch). Replaces the
|
|
3048
|
+
* `getWalletFromMap(...)!` non-null assertions that surfaced a missing
|
|
3049
|
+
* wallet as an opaque property-access TypeError at some later line.
|
|
3050
|
+
*/ getRequiredWalletFromMap(accountAddress) {
|
|
3051
|
+
const walletData = this.getWalletFromMap(accountAddress);
|
|
3052
|
+
if (!walletData) {
|
|
3053
|
+
throw new Error(`Wallet not found for address: ${accountAddress}`);
|
|
3054
|
+
}
|
|
3055
|
+
return walletData;
|
|
3056
|
+
}
|
|
3057
|
+
/**
|
|
2994
3058
|
* Get wallet properties from the map, refetching once if not found.
|
|
2995
3059
|
* Uses getWallet (with NO_OPERATION) when signedSessionId is available for a
|
|
2996
3060
|
* more robust fetch, otherwise falls back to getWallets().
|
|
@@ -4883,7 +4947,7 @@ class DynamicWalletClient {
|
|
|
4883
4947
|
signedSessionId
|
|
4884
4948
|
});
|
|
4885
4949
|
const walletId = wallet.walletId;
|
|
4886
|
-
const currentScheme = this.
|
|
4950
|
+
const currentScheme = this.getRequiredWalletFromMap(accountAddress).thresholdSignatureScheme;
|
|
4887
4951
|
const bitcoinConfig = this.getBitcoinConfigForChain(chainName, accountAddress);
|
|
4888
4952
|
// Same-parties reshare — only the caller's share participates.
|
|
4889
4953
|
const [existingClientShare] = await this.ensureClientShare(accountAddress);
|
|
@@ -5798,7 +5862,7 @@ class DynamicWalletClient {
|
|
|
5798
5862
|
useShareSetReshare,
|
|
5799
5863
|
initialSignerRules
|
|
5800
5864
|
});
|
|
5801
|
-
const backupInfo = this.
|
|
5865
|
+
const backupInfo = this.getRequiredWalletFromMap(accountAddress).clientKeySharesBackupInfo;
|
|
5802
5866
|
const delegatedKeyShares = backupInfo.backups[BackupLocation.DELEGATED] || [];
|
|
5803
5867
|
return delegatedKeyShares;
|
|
5804
5868
|
}
|
|
@@ -6261,7 +6325,7 @@ class DynamicWalletClient {
|
|
|
6261
6325
|
if (shares.length > 1) {
|
|
6262
6326
|
this.logger.warn('[DynamicWaasWalletClient] Multiple client key shares found in storage', {
|
|
6263
6327
|
accountAddress,
|
|
6264
|
-
source,
|
|
6328
|
+
shareSource: source,
|
|
6265
6329
|
count: shares.length
|
|
6266
6330
|
});
|
|
6267
6331
|
}
|
|
@@ -6312,7 +6376,7 @@ class DynamicWalletClient {
|
|
|
6312
6376
|
*/ logSharePersistence({ accountAddress, clientKeyShares, source }) {
|
|
6313
6377
|
this.logger.info('[DynamicWaasWalletClient] Persisting client key shares', {
|
|
6314
6378
|
accountAddress,
|
|
6315
|
-
source,
|
|
6379
|
+
shareSource: source,
|
|
6316
6380
|
inputCount: clientKeyShares.length
|
|
6317
6381
|
});
|
|
6318
6382
|
}
|
|
@@ -6819,8 +6883,8 @@ class DynamicWalletClient {
|
|
|
6819
6883
|
} catch (error) {
|
|
6820
6884
|
var _error_cause_context;
|
|
6821
6885
|
const errorReason = classifyPasswordBackupError(error);
|
|
6822
|
-
const
|
|
6823
|
-
|
|
6886
|
+
const isUserActionable = isUserActionablePasswordBackupErrorReason(errorReason);
|
|
6887
|
+
const logPayload = _extends({}, logContext, {
|
|
6824
6888
|
chainName: walletData == null ? void 0 : walletData.chainName,
|
|
6825
6889
|
errorReason,
|
|
6826
6890
|
errorName: error instanceof Error ? error.name : undefined,
|
|
@@ -6830,7 +6894,12 @@ class DynamicWalletClient {
|
|
|
6830
6894
|
// failures show the underlying KeyShareDecryptionError / kdfVersion.
|
|
6831
6895
|
errorCauseName: error instanceof Error && error.cause instanceof Error ? error.cause.name : undefined,
|
|
6832
6896
|
kdfVersion: error instanceof Error && error.cause instanceof KeyShareDecryptionError ? (_error_cause_context = error.cause.context) == null ? void 0 : _error_cause_context.kdfVersion : undefined
|
|
6833
|
-
})
|
|
6897
|
+
});
|
|
6898
|
+
if (isUserActionable) {
|
|
6899
|
+
this.logger.warn('[backupSharesWithDistribution] failed', logPayload);
|
|
6900
|
+
} else {
|
|
6901
|
+
this.logger.error('[backupSharesWithDistribution] failed', logPayload);
|
|
6902
|
+
}
|
|
6834
6903
|
logError({
|
|
6835
6904
|
message: 'Error in backupSharesWithDistribution',
|
|
6836
6905
|
error: error,
|
|
@@ -7081,9 +7150,9 @@ class DynamicWalletClient {
|
|
|
7081
7150
|
// they don't count against the dashboard's System-side Success Rate metric.
|
|
7082
7151
|
logPasswordOperationFailure(passwordOperation, error, context) {
|
|
7083
7152
|
const errorReason = classifyPasswordBackupError(error);
|
|
7084
|
-
const
|
|
7153
|
+
const isUserActionable = isUserActionablePasswordBackupErrorReason(errorReason);
|
|
7085
7154
|
const errorContext = error instanceof KeyShareDecryptionError ? error.context : undefined;
|
|
7086
|
-
|
|
7155
|
+
const logPayload = _extends({}, context, {
|
|
7087
7156
|
passwordOperation,
|
|
7088
7157
|
errorReason,
|
|
7089
7158
|
environmentId: this.environmentId,
|
|
@@ -7093,7 +7162,12 @@ class DynamicWalletClient {
|
|
|
7093
7162
|
errorStack: error instanceof Error ? error.stack : undefined
|
|
7094
7163
|
}, errorContext ? {
|
|
7095
7164
|
errorContext
|
|
7096
|
-
} : {})
|
|
7165
|
+
} : {});
|
|
7166
|
+
if (isUserActionable) {
|
|
7167
|
+
this.logger.warn(`[${passwordOperation}] failed`, logPayload);
|
|
7168
|
+
} else {
|
|
7169
|
+
this.logger.error(`[${passwordOperation}] failed`, logPayload);
|
|
7170
|
+
}
|
|
7097
7171
|
}
|
|
7098
7172
|
async updatePassword({ accountAddress, existingPassword, newPassword, signedSessionId, sessionPublicKey, passwordUpdateBatchId }) {
|
|
7099
7173
|
const dynamicRequestId = v4();
|
|
@@ -7408,7 +7482,14 @@ class DynamicWalletClient {
|
|
|
7408
7482
|
*/ recoverStrategy({ clientKeyShareBackupInfo, thresholdSignatureScheme, walletOperation, shareCount = undefined }) {
|
|
7409
7483
|
var _clientKeyShareBackupInfo_backups_BackupLocation_DYNAMIC;
|
|
7410
7484
|
const { backups } = clientKeyShareBackupInfo;
|
|
7411
|
-
|
|
7485
|
+
// Wallet metadata can carry a missing/unknown scheme (e.g. legacy or
|
|
7486
|
+
// partially-created wallets); indexing MPC_CONFIG with it used to throw a
|
|
7487
|
+
// bare destructuring TypeError that hid the actual problem.
|
|
7488
|
+
const mpcConfig = MPC_CONFIG[thresholdSignatureScheme];
|
|
7489
|
+
if (!mpcConfig) {
|
|
7490
|
+
throw new Error(`Unsupported or missing thresholdSignatureScheme: ${String(thresholdSignatureScheme)}`);
|
|
7491
|
+
}
|
|
7492
|
+
const { clientThreshold } = mpcConfig;
|
|
7412
7493
|
let requiredShareCount = walletOperation === WalletOperation.REFRESH || walletOperation === WalletOperation.REACH_ALL_PARTIES || walletOperation === WalletOperation.RESHARE ? clientThreshold : 1;
|
|
7413
7494
|
// Override requiredShareCount if shareCount is provided
|
|
7414
7495
|
if (shareCount !== undefined) {
|
|
@@ -7477,7 +7558,7 @@ class DynamicWalletClient {
|
|
|
7477
7558
|
}
|
|
7478
7559
|
async internalRecoverEncryptedBackupByWallet({ accountAddress, password, walletOperation, signedSessionId, shareCount = undefined, storeRecoveredShares = true, mfaToken }) {
|
|
7479
7560
|
try {
|
|
7480
|
-
const wallet = this.
|
|
7561
|
+
const wallet = this.getRequiredWalletFromMap(accountAddress);
|
|
7481
7562
|
this.logger.debug(`recoverEncryptedBackupByWallet wallet: ${walletOperation}`, wallet);
|
|
7482
7563
|
const { shares } = this.recoverStrategy({
|
|
7483
7564
|
clientKeyShareBackupInfo: wallet.clientKeySharesBackupInfo,
|
|
@@ -7586,7 +7667,7 @@ class DynamicWalletClient {
|
|
|
7586
7667
|
password,
|
|
7587
7668
|
signedSessionId
|
|
7588
7669
|
});
|
|
7589
|
-
const walletData = this.
|
|
7670
|
+
const walletData = this.getRequiredWalletFromMap(accountAddress);
|
|
7590
7671
|
const currentThresholdSignatureScheme = walletData.thresholdSignatureScheme;
|
|
7591
7672
|
if (currentThresholdSignatureScheme === ThresholdSignatureScheme.TWO_OF_TWO) {
|
|
7592
7673
|
// Reshare to 2-of-3, which will automatically handle the backup distribution
|
|
@@ -7645,7 +7726,7 @@ class DynamicWalletClient {
|
|
|
7645
7726
|
* every provider already holding a backup plus the requested one,
|
|
7646
7727
|
* restricted to providers the reshare can deliver to.
|
|
7647
7728
|
*/ async reshareNonDelegatedTwoOfThree({ accountAddress, backupLocation, password, signedSessionId, sessionPublicKey, googleDriveAccessToken, googleDriveTokenSource }) {
|
|
7648
|
-
const walletData = this.
|
|
7729
|
+
const walletData = this.getRequiredWalletFromMap(accountAddress);
|
|
7649
7730
|
const cloudProviders = new Set([
|
|
7650
7731
|
...getActiveCloudProviders(walletData.clientKeySharesBackupInfo).filter((provider)=>provider === BackupLocation.GOOGLE_DRIVE || provider === BackupLocation.ICLOUD),
|
|
7651
7732
|
backupLocation
|
|
@@ -7784,14 +7865,18 @@ class DynamicWalletClient {
|
|
|
7784
7865
|
// misuse of an externally-supplied token (e.g. repeated failures) is
|
|
7785
7866
|
// traceable, not just completed backups. Enum only; the original error
|
|
7786
7867
|
// still propagates after this. Failures log at warn to surface them.
|
|
7787
|
-
const
|
|
7788
|
-
logFn.call(this.logger, '[DynamicWaasWalletClient] Google Drive backup token source', {
|
|
7868
|
+
const logPayload = {
|
|
7789
7869
|
accountAddress,
|
|
7790
7870
|
environmentId: this.environmentId,
|
|
7791
7871
|
userId: this.userId,
|
|
7792
7872
|
tokenSource,
|
|
7793
7873
|
success
|
|
7794
|
-
}
|
|
7874
|
+
};
|
|
7875
|
+
if (success) {
|
|
7876
|
+
this.logger.info('[DynamicWaasWalletClient] Google Drive backup token source', logPayload);
|
|
7877
|
+
} else {
|
|
7878
|
+
this.logger.warn('[DynamicWaasWalletClient] Google Drive backup token source', logPayload);
|
|
7879
|
+
}
|
|
7795
7880
|
}
|
|
7796
7881
|
}
|
|
7797
7882
|
/**
|
|
@@ -7810,8 +7895,7 @@ class DynamicWalletClient {
|
|
|
7810
7895
|
]);
|
|
7811
7896
|
const { blocking } = preflightResult;
|
|
7812
7897
|
if (blocking) {
|
|
7813
|
-
const
|
|
7814
|
-
logFn.call(this.logger, '[DynamicWaasWalletClient] Google Drive backup failed (preflight)', {
|
|
7898
|
+
const logPayload = {
|
|
7815
7899
|
accountAddress,
|
|
7816
7900
|
environmentId: this.environmentId,
|
|
7817
7901
|
userId: this.userId,
|
|
@@ -7822,8 +7906,13 @@ class DynamicWalletClient {
|
|
|
7822
7906
|
`Preflight (${blocking.source}): ${blocking.message}`
|
|
7823
7907
|
],
|
|
7824
7908
|
preflight: true,
|
|
7825
|
-
|
|
7826
|
-
}
|
|
7909
|
+
preflightSource: blocking.source
|
|
7910
|
+
};
|
|
7911
|
+
if (blocking.isUserActionable) {
|
|
7912
|
+
this.logger.warn('[DynamicWaasWalletClient] Google Drive backup failed (preflight)', logPayload);
|
|
7913
|
+
} else {
|
|
7914
|
+
this.logger.error('[DynamicWaasWalletClient] Google Drive backup failed (preflight)', logPayload);
|
|
7915
|
+
}
|
|
7827
7916
|
throw createGoogleDriveError({
|
|
7828
7917
|
message: blocking.message,
|
|
7829
7918
|
isRetryable: false,
|
|
@@ -7939,7 +8028,7 @@ class DynamicWalletClient {
|
|
|
7939
8028
|
if (encryptedKeyShares.length === 0) {
|
|
7940
8029
|
throw new Error('No key shares found');
|
|
7941
8030
|
}
|
|
7942
|
-
const thresholdSignatureScheme = this.
|
|
8031
|
+
const thresholdSignatureScheme = this.getRequiredWalletFromMap(accountAddress).thresholdSignatureScheme;
|
|
7943
8032
|
const backupData = createBackupData({
|
|
7944
8033
|
encryptedKeyShares,
|
|
7945
8034
|
accountAddress,
|
|
@@ -7966,7 +8055,7 @@ class DynamicWalletClient {
|
|
|
7966
8055
|
signedSessionId
|
|
7967
8056
|
});
|
|
7968
8057
|
const accessToken = googleDriveAccessToken != null ? googleDriveAccessToken : await this.fetchGoogleDriveAccessToken(accountAddress);
|
|
7969
|
-
const thresholdSignatureScheme = this.
|
|
8058
|
+
const thresholdSignatureScheme = this.getRequiredWalletFromMap(accountAddress).thresholdSignatureScheme;
|
|
7970
8059
|
const backupFileName = getClientKeyShareExportFileName({
|
|
7971
8060
|
thresholdSignatureScheme,
|
|
7972
8061
|
accountAddress,
|
|
@@ -8186,7 +8275,7 @@ class DynamicWalletClient {
|
|
|
8186
8275
|
});
|
|
8187
8276
|
const { requiredShareCount } = this.recoverStrategy({
|
|
8188
8277
|
clientKeyShareBackupInfo: clientKeySharesBackupInfo,
|
|
8189
|
-
thresholdSignatureScheme: this.
|
|
8278
|
+
thresholdSignatureScheme: this.getRequiredWalletFromMap(accountAddress).thresholdSignatureScheme,
|
|
8190
8279
|
walletOperation
|
|
8191
8280
|
});
|
|
8192
8281
|
if (clientKeyShares.length >= requiredShareCount) {
|
|
@@ -8291,7 +8380,7 @@ class DynamicWalletClient {
|
|
|
8291
8380
|
accountAddress,
|
|
8292
8381
|
walletOperation
|
|
8293
8382
|
})) {
|
|
8294
|
-
const walletData = this.
|
|
8383
|
+
const walletData = this.getRequiredWalletFromMap(accountAddress);
|
|
8295
8384
|
const isPasswordEncrypted = isWalletPasswordEncrypted(walletData);
|
|
8296
8385
|
// Locked wallet (password-encrypted, no password supplied): its shares need the
|
|
8297
8386
|
// user's password, not the environmentId. Return it ENCRYPTED for any operation
|
|
@@ -8596,7 +8685,7 @@ class DynamicWalletClient {
|
|
|
8596
8685
|
additionalWalletsUnlocked,
|
|
8597
8686
|
additionalWalletsFailed
|
|
8598
8687
|
});
|
|
8599
|
-
return this.
|
|
8688
|
+
return this.getRequiredWalletFromMap(accountAddress);
|
|
8600
8689
|
} catch (error) {
|
|
8601
8690
|
this.logPasswordOperationFailure('unlockWallet', error, {
|
|
8602
8691
|
accountAddress
|
|
@@ -9043,6 +9132,15 @@ class DynamicWalletClient {
|
|
|
9043
9132
|
time: (traceContext == null ? void 0 : traceContext.startTime) ? now - traceContext.startTime : 0
|
|
9044
9133
|
}, traceContext);
|
|
9045
9134
|
}
|
|
9135
|
+
/**
|
|
9136
|
+
* Log a chain-client operation failure at a severity that matches the
|
|
9137
|
+
* underlying cause. Logs through `this.logger` (not `logError`) so the
|
|
9138
|
+
* structured `error.causes` chain survives — that chain is what makes these
|
|
9139
|
+
* failures diagnosable — while still honouring the shared level policy, so a
|
|
9140
|
+
* transient 429/401/network blip does not read as a hard SDK error.
|
|
9141
|
+
*/ logOperationFailure(message, error) {
|
|
9142
|
+
this.logger[resolveLogLevel(error, 'error')](message, error);
|
|
9143
|
+
}
|
|
9046
9144
|
constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, storageKey, debug, featureFlags, argon2idRebackupTargets, authMode = AuthMode.HEADER, authToken = undefined, backupServiceAuthToken, // Represents the version of the client SDK used by developer
|
|
9047
9145
|
sdkVersion, forwardMPCClient, baseClientKeysharesRelayApiUrl, iCloudConfig, logger }, internalOptions){
|
|
9048
9146
|
this.userId = undefined;
|
|
@@ -9146,4 +9244,4 @@ DynamicWalletClient.roomsPersistDirty = false;
|
|
|
9146
9244
|
// rooms back into the new user's storage (TOCTOU on the create→merge gap).
|
|
9147
9245
|
DynamicWalletClient.roomsGeneration = 0;
|
|
9148
9246
|
|
|
9149
|
-
export { BACKUP_FILENAME, CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX, DynamicWalletClient, ENVIRONMENT_SETTINGS_STORAGE_KEY, ERROR_ACCOUNT_ADDRESS_REQUIRED, ERROR_CREATE_WALLET_ACCOUNT, ERROR_EXPORT_PRIVATE_KEY, ERROR_IMPORT_PRIVATE_KEY, ERROR_INCORRECT_PASSWORD, ERROR_KEYGEN_FAILED, ERROR_MULTIPLE_WALLETS_PER_CHAIN, ERROR_NO_KEY_SHARES_BACKED_UP, ERROR_PASSWORD_MISMATCH, ERROR_PASSWORD_REQUIRED, ERROR_PASSWORD_REQUIRED_FOR_ENCRYPTED_WALLET, ERROR_PUBLIC_KEY_MISMATCH, ERROR_REFRESH_NOT_SUPPORTED_FOR_TWO_OF_THREE, ERROR_SIGN_MESSAGE, ERROR_SIGN_TYPED_DATA, ERROR_VERIFY_MESSAGE_SIGNATURE, ERROR_VERIFY_TRANSACTION_SIGNATURE, HEAVY_QUEUE_OPERATIONS, OperationSource, RECOVER_QUEUE_OPERATIONS, ROOM_CACHE_COUNT, ROOM_EXPIRATION_TIME, SIGNED_SESSION_ID_MIN_VERSION, SIGNED_SESSION_ID_MIN_VERSION_BY_NAMESPACE, SIGNED_SESSION_REVERSE_CHANNEL_MIN_VERSION, SIGNED_SESSION_REVERSE_CHANNEL_MIN_VERSION_BY_NAMESPACE, SIGN_QUEUE_OPERATIONS, STORAGE_KEY, StaleLocalSharesError, WalletBusyError, WalletNotReadyError, cancelICloudAuth, createAddCloudProviderToExistingDelegationDistribution, createBackupData, createCloudProviderDistribution, createDelegationOnlyDistribution, createDelegationWithCloudProviderDistribution, createDynamicOnlyDistribution, deleteICloudBackup, downloadStringAsFile, extractPubkey, formatEvmMessage, formatMessage, formatTronMessage, getActiveCloudProviders, getBitcoinAddressTypeFromAddress, getBitcoinAddressTypeFromDerivationPath, getClientKeyShareBackupInfo, getClientKeyShareExportFileName, getDelegatedShareSet, getGoogleOAuthAccountId, getHttpStatus, getICloudBackup, getMPCSignatureScheme, getMPCSigner, hasCloudProviderBackup, hasDelegatedBackup, hasEncryptedSharesCached, initializeCloudKit, isBrowser, isHeavyQueueOperation, isHexString, isICloudAuthenticated, isNonRetryableCeremonyError, isPublicKeyMismatchError, isRecoverQueueOperation, isRoomIdAlreadyUsedError, isSignQueueOperation, isStaleClientSharesError, listICloudBackups, markCeremonyErrorNonRetryable, readEnvironmentSettings, retryPromise, shouldReshareToSameBackups, timeoutPromise };
|
|
9247
|
+
export { BACKUP_FILENAME, CLIENT_KEYSHARE_EXPORT_FILENAME_PREFIX, DynamicWalletClient, ENVIRONMENT_SETTINGS_STORAGE_KEY, ERROR_ACCOUNT_ADDRESS_REQUIRED, ERROR_CREATE_WALLET_ACCOUNT, ERROR_EXPORT_PRIVATE_KEY, ERROR_IMPORT_PRIVATE_KEY, ERROR_INCORRECT_PASSWORD, ERROR_KEYGEN_FAILED, ERROR_MULTIPLE_WALLETS_PER_CHAIN, ERROR_NO_KEY_SHARES_BACKED_UP, ERROR_PASSWORD_MISMATCH, ERROR_PASSWORD_REQUIRED, ERROR_PASSWORD_REQUIRED_FOR_ENCRYPTED_WALLET, ERROR_PUBLIC_KEY_MISMATCH, ERROR_REFRESH_NOT_SUPPORTED_FOR_TWO_OF_THREE, ERROR_SIGN_MESSAGE, ERROR_SIGN_TYPED_DATA, ERROR_VERIFY_MESSAGE_SIGNATURE, ERROR_VERIFY_TRANSACTION_SIGNATURE, HEAVY_QUEUE_OPERATIONS, OperationSource, RECOVER_QUEUE_OPERATIONS, ROOM_CACHE_COUNT, ROOM_EXPIRATION_TIME, SIGNED_SESSION_ID_MIN_VERSION, SIGNED_SESSION_ID_MIN_VERSION_BY_NAMESPACE, SIGNED_SESSION_REVERSE_CHANNEL_MIN_VERSION, SIGNED_SESSION_REVERSE_CHANNEL_MIN_VERSION_BY_NAMESPACE, SIGN_QUEUE_OPERATIONS, STORAGE_KEY, StaleLocalSharesError, WalletBusyError, WalletNotReadyError, cancelICloudAuth, createAddCloudProviderToExistingDelegationDistribution, createBackupData, createCloudProviderDistribution, createDelegationOnlyDistribution, createDelegationWithCloudProviderDistribution, createDynamicOnlyDistribution, deleteICloudBackup, downloadStringAsFile, extractPubkey, formatEvmMessage, formatMessage, formatTronMessage, getActiveCloudProviders, getBitcoinAddressTypeFromAddress, getBitcoinAddressTypeFromDerivationPath, getClientKeyShareBackupInfo, getClientKeyShareExportFileName, getDelegatedShareSet, getGoogleOAuthAccountId, getHttpStatus, getICloudBackup, getMPCSignatureScheme, getMPCSigner, hasCloudProviderBackup, hasDelegatedBackup, hasEncryptedSharesCached, initializeCloudKit, isBrowser, isHeavyQueueOperation, isHexString, isICloudAuthenticated, isNonRetryableCeremonyError, isPublicKeyMismatchError, isRecoverQueueOperation, isRoomIdAlreadyUsedError, isSignQueueOperation, isStaleClientSharesError, listICloudBackups, markCeremonyErrorNonRetryable, readEnvironmentSettings, resolveLogLevel, retryPromise, shouldReshareToSameBackups, timeoutPromise };
|