upshift-config 0.5.14
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/LICENSE +21 -0
- package/README.md +349 -0
- package/lib/abis/AddressResolver.d.ts +28 -0
- package/lib/abis/AddressResolver.js +23 -0
- package/lib/abis/ChainlinkV3.d.ts +87 -0
- package/lib/abis/ChainlinkV3.js +117 -0
- package/lib/abis/ERC20.d.ts +168 -0
- package/lib/abis/ERC20.js +226 -0
- package/lib/abis/ERC20_Bytes32.d.ts +139 -0
- package/lib/abis/ERC20_Bytes32.js +196 -0
- package/lib/abis/ERC4626.d.ts +364 -0
- package/lib/abis/ERC4626.js +507 -0
- package/lib/abis/ERC721.d.ts +231 -0
- package/lib/abis/ERC721.js +321 -0
- package/lib/abis/FeeOracle.d.ts +120 -0
- package/lib/abis/FeeOracle.js +162 -0
- package/lib/abis/LendingPool.d.ts +1393 -0
- package/lib/abis/LendingPool.js +1807 -0
- package/lib/abis/LendingPoolV2.d.ts +1413 -0
- package/lib/abis/LendingPoolV2.js +1833 -0
- package/lib/abis/LendingPoolV3.d.ts +1677 -0
- package/lib/abis/LendingPoolV3.js +1160 -0
- package/lib/abis/Loan.d.ts +837 -0
- package/lib/abis/Loan.js +1080 -0
- package/lib/abis/MultiAssetNativeDepositWrapper.d.ts +137 -0
- package/lib/abis/MultiAssetNativeDepositWrapper.js +125 -0
- package/lib/abis/Multicall3.d.ts +30 -0
- package/lib/abis/Multicall3.js +97 -0
- package/lib/abis/OFT.d.ts +116 -0
- package/lib/abis/OFT.js +85 -0
- package/lib/abis/PoolAdapter.d.ts +36 -0
- package/lib/abis/PoolAdapter.js +51 -0
- package/lib/abis/RewardDistributor.d.ts +267 -0
- package/lib/abis/RewardDistributor.js +352 -0
- package/lib/abis/RwaRedeemSubaccount.d.ts +747 -0
- package/lib/abis/RwaRedeemSubaccount.js +548 -0
- package/lib/abis/SmartAccount.d.ts +17 -0
- package/lib/abis/SmartAccount.js +19 -0
- package/lib/abis/SwapRouter.d.ts +1043 -0
- package/lib/abis/SwapRouter.js +740 -0
- package/lib/abis/TextResolver.d.ts +16 -0
- package/lib/abis/TextResolver.js +16 -0
- package/lib/abis/TokenizedVaultV2.d.ts +1364 -0
- package/lib/abis/TokenizedVaultV2.js +1041 -0
- package/lib/abis/TokenizedVaultV2DepositWithPermit.d.ts +1456 -0
- package/lib/abis/TokenizedVaultV2DepositWithPermit.js +1878 -0
- package/lib/abis/TokenizedVaultV2Receipt.d.ts +1568 -0
- package/lib/abis/TokenizedVaultV2Receipt.js +1061 -0
- package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.d.ts +454 -0
- package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.js +327 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAllocation.d.ts +1466 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAllocation.js +1092 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAssets.d.ts +274 -0
- package/lib/abis/TokenizedVaultV2WhitelistedAssets.js +167 -0
- package/lib/abis/UniversalResolverResolve.d.ts +69 -0
- package/lib/abis/UniversalResolverResolve.js +35 -0
- package/lib/abis/UniversalSignatureValidator.d.ts +17 -0
- package/lib/abis/UniversalSignatureValidator.js +30 -0
- package/lib/abis/WrapperAdapter.d.ts +71 -0
- package/lib/abis/WrapperAdapter.js +77 -0
- package/lib/abis/index.d.ts +34 -0
- package/lib/abis/index.js +51 -0
- package/lib/adapters/evm/getters.d.ts +19 -0
- package/lib/adapters/evm/getters.js +209 -0
- package/lib/adapters/evm/index.d.ts +353 -0
- package/lib/adapters/evm/index.js +434 -0
- package/lib/adapters/evm/utils.d.ts +8 -0
- package/lib/adapters/evm/utils.js +51 -0
- package/lib/adapters/solana/constants.d.ts +33 -0
- package/lib/adapters/solana/constants.js +52 -0
- package/lib/adapters/solana/getters.d.ts +11 -0
- package/lib/adapters/solana/getters.js +165 -0
- package/lib/adapters/solana/idl/vault-idl.d.ts +272 -0
- package/lib/adapters/solana/idl/vault-idl.js +1084 -0
- package/lib/adapters/solana/index.d.ts +233 -0
- package/lib/adapters/solana/index.js +291 -0
- package/lib/adapters/solana/types.d.ts +67 -0
- package/lib/adapters/solana/types.js +3 -0
- package/lib/adapters/solana/utils.d.ts +141 -0
- package/lib/adapters/solana/utils.js +595 -0
- package/lib/adapters/solana/vault.actions.d.ts +57 -0
- package/lib/adapters/solana/vault.actions.js +379 -0
- package/lib/adapters/stellar/actions.d.ts +28 -0
- package/lib/adapters/stellar/actions.js +77 -0
- package/lib/adapters/stellar/constants.d.ts +43 -0
- package/lib/adapters/stellar/constants.js +53 -0
- package/lib/adapters/stellar/getters.d.ts +68 -0
- package/lib/adapters/stellar/getters.js +290 -0
- package/lib/adapters/stellar/index.d.ts +114 -0
- package/lib/adapters/stellar/index.js +175 -0
- package/lib/adapters/stellar/soroban.d.ts +123 -0
- package/lib/adapters/stellar/soroban.js +613 -0
- package/lib/adapters/stellar/submit.d.ts +34 -0
- package/lib/adapters/stellar/submit.js +149 -0
- package/lib/adapters/stellar/types.d.ts +58 -0
- package/lib/adapters/stellar/types.js +6 -0
- package/lib/adapters/stellar/utils.d.ts +24 -0
- package/lib/adapters/stellar/utils.js +34 -0
- package/lib/adapters/sui/constants.d.ts +14 -0
- package/lib/adapters/sui/constants.js +29 -0
- package/lib/adapters/sui/getters.d.ts +9 -0
- package/lib/adapters/sui/getters.js +60 -0
- package/lib/adapters/sui/index.d.ts +45 -0
- package/lib/adapters/sui/index.js +101 -0
- package/lib/adapters/sui/transformer.d.ts +10 -0
- package/lib/adapters/sui/transformer.js +107 -0
- package/lib/adapters/sui/types.d.ts +66 -0
- package/lib/adapters/sui/types.js +3 -0
- package/lib/adapters/sui/utils.d.ts +10 -0
- package/lib/adapters/sui/utils.js +29 -0
- package/lib/core/analytics/chain-name.d.ts +9 -0
- package/lib/core/analytics/chain-name.js +34 -0
- package/lib/core/analytics/constants.d.ts +5 -0
- package/lib/core/analytics/constants.js +9 -0
- package/lib/core/analytics/env.d.ts +29 -0
- package/lib/core/analytics/env.js +59 -0
- package/lib/core/analytics/index.d.ts +36 -0
- package/lib/core/analytics/index.js +79 -0
- package/lib/core/analytics/instrumentation.d.ts +29 -0
- package/lib/core/analytics/instrumentation.js +277 -0
- package/lib/core/analytics/method-taxonomy.d.ts +19 -0
- package/lib/core/analytics/method-taxonomy.js +128 -0
- package/lib/core/analytics/metrics.d.ts +33 -0
- package/lib/core/analytics/metrics.js +116 -0
- package/lib/core/analytics/sanitize.d.ts +44 -0
- package/lib/core/analytics/sanitize.js +260 -0
- package/lib/core/analytics/sentry-runtime.d.ts +15 -0
- package/lib/core/analytics/sentry-runtime.js +97 -0
- package/lib/core/analytics/sentry.d.ts +67 -0
- package/lib/core/analytics/sentry.js +613 -0
- package/lib/core/analytics/types.d.ts +48 -0
- package/lib/core/analytics/types.js +3 -0
- package/lib/core/analytics/user-identity.d.ts +41 -0
- package/lib/core/analytics/user-identity.js +141 -0
- package/lib/core/analytics/version.d.ts +6 -0
- package/lib/core/analytics/version.js +10 -0
- package/lib/core/attribution.d.ts +111 -0
- package/lib/core/attribution.js +142 -0
- package/lib/core/auth/index.d.ts +1 -0
- package/lib/core/auth/index.js +18 -0
- package/lib/core/auth/verify.d.ts +2 -0
- package/lib/core/auth/verify.js +31 -0
- package/lib/core/base.class.d.ts +152 -0
- package/lib/core/base.class.js +172 -0
- package/lib/core/cache.d.ts +9 -0
- package/lib/core/cache.js +31 -0
- package/lib/core/constants/adapters.d.ts +103 -0
- package/lib/core/constants/adapters.js +180 -0
- package/lib/core/constants/core.d.ts +133 -0
- package/lib/core/constants/core.js +209 -0
- package/lib/core/constants/swap-router.d.ts +150 -0
- package/lib/core/constants/swap-router.js +169 -0
- package/lib/core/constants/vaults.d.ts +93 -0
- package/lib/core/constants/vaults.js +273 -0
- package/lib/core/constants/web3.d.ts +91 -0
- package/lib/core/constants/web3.js +229 -0
- package/lib/core/errors/index.d.ts +114 -0
- package/lib/core/errors/index.js +183 -0
- package/lib/core/fetcher.d.ts +198 -0
- package/lib/core/fetcher.js +903 -0
- package/lib/core/helpers/adapters.d.ts +13 -0
- package/lib/core/helpers/adapters.js +39 -0
- package/lib/core/helpers/chain-address.d.ts +13 -0
- package/lib/core/helpers/chain-address.js +47 -0
- package/lib/core/helpers/chain-error.d.ts +207 -0
- package/lib/core/helpers/chain-error.js +682 -0
- package/lib/core/helpers/chain-support.d.ts +80 -0
- package/lib/core/helpers/chain-support.js +115 -0
- package/lib/core/helpers/core.d.ts +68 -0
- package/lib/core/helpers/core.js +285 -0
- package/lib/core/helpers/explorer-link.d.ts +16 -0
- package/lib/core/helpers/explorer-link.js +26 -0
- package/lib/core/helpers/multicall.d.ts +68 -0
- package/lib/core/helpers/multicall.js +103 -0
- package/lib/core/helpers/revert-decode.d.ts +248 -0
- package/lib/core/helpers/revert-decode.js +515 -0
- package/lib/core/helpers/signer.d.ts +52 -0
- package/lib/core/helpers/signer.js +145 -0
- package/lib/core/helpers/swap-router.d.ts +211 -0
- package/lib/core/helpers/swap-router.js +480 -0
- package/lib/core/helpers/vault-version.d.ts +23 -0
- package/lib/core/helpers/vault-version.js +75 -0
- package/lib/core/helpers/vaults.d.ts +89 -0
- package/lib/core/helpers/vaults.js +235 -0
- package/lib/core/helpers/web3.d.ts +353 -0
- package/lib/core/helpers/web3.js +992 -0
- package/lib/core/index.d.ts +23 -0
- package/lib/core/index.js +40 -0
- package/lib/core/logger/index.d.ts +98 -0
- package/lib/core/logger/index.js +144 -0
- package/lib/core/logger/slack.d.ts +16 -0
- package/lib/core/logger/slack.js +57 -0
- package/lib/core/vault-metadata.d.ts +12 -0
- package/lib/core/vault-metadata.js +42 -0
- package/lib/core/version-check.d.ts +58 -0
- package/lib/core/version-check.js +182 -0
- package/lib/evm/index.d.ts +2 -0
- package/lib/evm/index.js +19 -0
- package/lib/evm/methods/crossChainVault.d.ts +128 -0
- package/lib/evm/methods/crossChainVault.js +853 -0
- package/lib/evm/methods/crossChainVaultRegistry.d.ts +93 -0
- package/lib/evm/methods/crossChainVaultRegistry.js +240 -0
- package/lib/evm/methods/index.d.ts +2 -0
- package/lib/evm/methods/index.js +19 -0
- package/lib/evm/types/crossChain.d.ts +363 -0
- package/lib/evm/types/crossChain.js +20 -0
- package/lib/evm/types/index.d.ts +1 -0
- package/lib/evm/types/index.js +18 -0
- package/lib/index.d.ts +30 -0
- package/lib/index.js +52 -0
- package/lib/main.d.ts +527 -0
- package/lib/main.js +601 -0
- package/lib/modules/api/fetcher.d.ts +82 -0
- package/lib/modules/api/fetcher.js +150 -0
- package/lib/modules/api/index.d.ts +1 -0
- package/lib/modules/api/index.js +6 -0
- package/lib/modules/api/main.d.ts +313 -0
- package/lib/modules/api/main.js +479 -0
- package/lib/modules/sub-accounts/fetcher.d.ts +53 -0
- package/lib/modules/sub-accounts/fetcher.js +120 -0
- package/lib/modules/sub-accounts/index.d.ts +2 -0
- package/lib/modules/sub-accounts/index.js +19 -0
- package/lib/modules/sub-accounts/main.d.ts +243 -0
- package/lib/modules/sub-accounts/main.js +205 -0
- package/lib/modules/sub-accounts/utils.d.ts +106 -0
- package/lib/modules/sub-accounts/utils.js +112 -0
- package/lib/modules/vaults/adapter.helpers.d.ts +64 -0
- package/lib/modules/vaults/adapter.helpers.js +184 -0
- package/lib/modules/vaults/fetcher.d.ts +147 -0
- package/lib/modules/vaults/fetcher.js +368 -0
- package/lib/modules/vaults/getters.d.ts +570 -0
- package/lib/modules/vaults/getters.js +3051 -0
- package/lib/modules/vaults/index.d.ts +20 -0
- package/lib/modules/vaults/index.js +44 -0
- package/lib/modules/vaults/main.d.ts +601 -0
- package/lib/modules/vaults/main.js +1623 -0
- package/lib/modules/vaults/prefetch.d.ts +65 -0
- package/lib/modules/vaults/prefetch.js +120 -0
- package/lib/modules/vaults/read.actions.d.ts +225 -0
- package/lib/modules/vaults/read.actions.js +596 -0
- package/lib/modules/vaults/types.d.ts +71 -0
- package/lib/modules/vaults/types.js +3 -0
- package/lib/modules/vaults/utils/call-data-decoder.d.ts +61 -0
- package/lib/modules/vaults/utils/call-data-decoder.js +194 -0
- package/lib/modules/vaults/utils/date-utils.d.ts +50 -0
- package/lib/modules/vaults/utils/date-utils.js +84 -0
- package/lib/modules/vaults/utils.d.ts +140 -0
- package/lib/modules/vaults/utils.js +799 -0
- package/lib/modules/vaults/write.actions.d.ts +529 -0
- package/lib/modules/vaults/write.actions.js +1749 -0
- package/lib/polyfills.d.ts +1 -0
- package/lib/polyfills.js +12 -0
- package/lib/sdk.d.ts +26721 -0
- package/lib/services/coingecko/fetcher.d.ts +15 -0
- package/lib/services/coingecko/fetcher.js +67 -0
- package/lib/services/coingecko/index.d.ts +2 -0
- package/lib/services/coingecko/index.js +19 -0
- package/lib/services/coingecko/utils.d.ts +1 -0
- package/lib/services/coingecko/utils.js +24 -0
- package/lib/services/debank/fetcher.d.ts +126 -0
- package/lib/services/debank/fetcher.js +47 -0
- package/lib/services/debank/index.d.ts +2 -0
- package/lib/services/debank/index.js +19 -0
- package/lib/services/debank/utils.d.ts +38 -0
- package/lib/services/debank/utils.js +297 -0
- package/lib/services/layerzero/deposits.d.ts +49 -0
- package/lib/services/layerzero/deposits.js +166 -0
- package/lib/services/layerzero/redeems.d.ts +20 -0
- package/lib/services/layerzero/redeems.js +92 -0
- package/lib/services/layerzero/utils.d.ts +9 -0
- package/lib/services/layerzero/utils.js +22 -0
- package/lib/services/octavfi/fetcher.d.ts +9 -0
- package/lib/services/octavfi/fetcher.js +103 -0
- package/lib/services/octavfi/index.d.ts +3 -0
- package/lib/services/octavfi/index.js +20 -0
- package/lib/services/octavfi/types.d.ts +34 -0
- package/lib/services/octavfi/types.js +3 -0
- package/lib/services/octavfi/utils.d.ts +16 -0
- package/lib/services/octavfi/utils.js +212 -0
- package/lib/services/subgraph/fetcher.d.ts +2 -0
- package/lib/services/subgraph/fetcher.js +61 -0
- package/lib/services/subgraph/index.d.ts +2 -0
- package/lib/services/subgraph/index.js +19 -0
- package/lib/services/subgraph/schema.d.ts +45 -0
- package/lib/services/subgraph/schema.js +75 -0
- package/lib/services/subgraph/vaults.d.ts +25 -0
- package/lib/services/subgraph/vaults.js +1106 -0
- package/lib/services/swap-quotes/index.d.ts +105 -0
- package/lib/services/swap-quotes/index.js +77 -0
- package/lib/services/swap-quotes/paraswap.d.ts +51 -0
- package/lib/services/swap-quotes/paraswap.js +138 -0
- package/lib/types/api.d.ts +280 -0
- package/lib/types/api.js +3 -0
- package/lib/types/index.d.ts +12 -0
- package/lib/types/index.js +28 -0
- package/lib/types/points.d.ts +28 -0
- package/lib/types/points.js +3 -0
- package/lib/types/pools.d.ts +144 -0
- package/lib/types/pools.js +3 -0
- package/lib/types/staking.d.ts +28 -0
- package/lib/types/staking.js +3 -0
- package/lib/types/sub-accounts.d.ts +140 -0
- package/lib/types/sub-accounts.js +3 -0
- package/lib/types/subgraph.d.ts +74 -0
- package/lib/types/subgraph.js +3 -0
- package/lib/types/typed-contract.d.ts +102 -0
- package/lib/types/typed-contract.js +3 -0
- package/lib/types/user.d.ts +1 -0
- package/lib/types/user.js +3 -0
- package/lib/types/vaults.d.ts +714 -0
- package/lib/types/vaults.js +24 -0
- package/lib/types/web3.d.ts +51 -0
- package/lib/types/web3.js +14 -0
- package/lib/types/webserver.d.ts +698 -0
- package/lib/types/webserver.js +3 -0
- package/package.json +78 -0
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resetErrorDedupe = resetErrorDedupe;
|
|
4
|
+
exports.initializeSentry = initializeSentry;
|
|
5
|
+
exports.updateUser = updateUser;
|
|
6
|
+
exports.clearUser = clearUser;
|
|
7
|
+
exports.isAnalyticsEnabled = isAnalyticsEnabled;
|
|
8
|
+
exports.getSentry = getSentry;
|
|
9
|
+
exports.resetAnalytics = resetAnalytics;
|
|
10
|
+
exports.captureSdkException = captureSdkException;
|
|
11
|
+
const logger_1 = require("../logger");
|
|
12
|
+
const constants_1 = require("./constants");
|
|
13
|
+
const env_1 = require("./env");
|
|
14
|
+
const sentry_runtime_1 = require("./sentry-runtime");
|
|
15
|
+
const user_identity_1 = require("./user-identity");
|
|
16
|
+
/** Track initialization state */
|
|
17
|
+
let isInitialized = false;
|
|
18
|
+
/** Track if analytics is enabled */
|
|
19
|
+
let isEnabled = true;
|
|
20
|
+
/** Current user identity */
|
|
21
|
+
let currentIdentity = null;
|
|
22
|
+
/** Cached API key for identity updates */
|
|
23
|
+
let cachedApiKey;
|
|
24
|
+
/**
|
|
25
|
+
* Get the SDK version from the generated version file.
|
|
26
|
+
* Falls back to 'development' if file doesn't exist (during local dev).
|
|
27
|
+
*/
|
|
28
|
+
function getSDKVersion() {
|
|
29
|
+
try {
|
|
30
|
+
// version.ts is generated at publish time and gitignored
|
|
31
|
+
return require('./version').SDK_VERSION || 'development';
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// version.ts doesn't exist in dev - use fallback
|
|
35
|
+
return 'development';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if running on localhost.
|
|
40
|
+
*/
|
|
41
|
+
function isLocalhost() {
|
|
42
|
+
try {
|
|
43
|
+
if (typeof window !== 'undefined' && window.location) {
|
|
44
|
+
const hostname = window.location.hostname;
|
|
45
|
+
return (hostname === 'localhost' ||
|
|
46
|
+
hostname === '127.0.0.1' ||
|
|
47
|
+
hostname === '0.0.0.0' ||
|
|
48
|
+
hostname.startsWith('192.168.') ||
|
|
49
|
+
hostname.startsWith('10.') ||
|
|
50
|
+
hostname.endsWith('.local'));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Silently fail
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Safely set a Sentry tag. Silently fails on error.
|
|
60
|
+
*/
|
|
61
|
+
function safeSetTag(key, value) {
|
|
62
|
+
try {
|
|
63
|
+
const sdk = (0, sentry_runtime_1.getSentrySDK)();
|
|
64
|
+
sdk?.setTag(key, value);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Silently fail - analytics should never break SDK
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Safely set Sentry user. Silently fails on error.
|
|
72
|
+
*/
|
|
73
|
+
function safeSetUser(user) {
|
|
74
|
+
try {
|
|
75
|
+
const sdk = (0, sentry_runtime_1.getSentrySDK)();
|
|
76
|
+
sdk?.setUser(user);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Silently fail - analytics should never break SDK
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Chains whose errors are dropped before reaching Sentry.
|
|
84
|
+
*
|
|
85
|
+
* Mezo is muted by request: its public dRPC endpoint is unreliable enough that
|
|
86
|
+
* its failures dominated the error stream without ever describing an SDK
|
|
87
|
+
* defect. This is a deliberate blind spot — Mezo bugs (bad vault data, reverts,
|
|
88
|
+
* decode failures) are silenced along with the transport noise. Remove the
|
|
89
|
+
* entry to restore reporting; nothing else needs to change.
|
|
90
|
+
*
|
|
91
|
+
* Keyed by both the `chainIdToTagValue` slug and the numeric chain ID, because
|
|
92
|
+
* the two arrive on different events.
|
|
93
|
+
*/
|
|
94
|
+
const MUTED_CHAIN_SLUGS = new Set(['mezo']);
|
|
95
|
+
/** Numeric chain IDs matching {@link MUTED_CHAIN_SLUGS}. */
|
|
96
|
+
const MUTED_CHAIN_IDS = new Set(['31612']);
|
|
97
|
+
/**
|
|
98
|
+
* Substrings that identify an event as Mezo-related regardless of tags.
|
|
99
|
+
*
|
|
100
|
+
* Tag-based matching alone is not enough: `sdk.chain` / `sdk.last_chainId`
|
|
101
|
+
* record the last *instrumented method's* chain, not the chain of the RPC that
|
|
102
|
+
* actually failed — the production Mezo batch-rejection events are tagged
|
|
103
|
+
* `sdk.chain: ethereum` while carrying `"requestUrl": "https://mezo.drpc.org"`
|
|
104
|
+
* in the message. Matching the message body catches those.
|
|
105
|
+
*/
|
|
106
|
+
const MUTED_CHAIN_MESSAGE_PATTERNS = [/mezo/i];
|
|
107
|
+
/**
|
|
108
|
+
* Whether an event belongs to a muted chain and must not be sent.
|
|
109
|
+
*
|
|
110
|
+
* Checks, in order: the chain tags, then the event message and every exception
|
|
111
|
+
* value/type in the chain (an RPC failure's identifying detail often lives in a
|
|
112
|
+
* wrapped inner error rather than the top-level message).
|
|
113
|
+
*
|
|
114
|
+
* @param event - The Sentry event about to be sent.
|
|
115
|
+
* @returns `true` when the event should be dropped.
|
|
116
|
+
*/
|
|
117
|
+
function isMutedChainEvent(event) {
|
|
118
|
+
const chainTag = event.tags?.['sdk.chain'];
|
|
119
|
+
if (typeof chainTag === 'string' && MUTED_CHAIN_SLUGS.has(chainTag)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
const chainIdTag = event.tags?.['sdk.last_chainId'];
|
|
123
|
+
if (typeof chainIdTag === 'string' && MUTED_CHAIN_IDS.has(chainIdTag)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
const haystacks = [];
|
|
127
|
+
if (typeof event.message === 'string')
|
|
128
|
+
haystacks.push(event.message);
|
|
129
|
+
for (const exception of event.exception?.values ?? []) {
|
|
130
|
+
if (typeof exception.value === 'string')
|
|
131
|
+
haystacks.push(exception.value);
|
|
132
|
+
if (typeof exception.type === 'string')
|
|
133
|
+
haystacks.push(exception.type);
|
|
134
|
+
}
|
|
135
|
+
return haystacks.some((text) => MUTED_CHAIN_MESSAGE_PATTERNS.some((pattern) => pattern.test(text)));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Rolling window, in milliseconds, over which identical errors are counted.
|
|
139
|
+
*/
|
|
140
|
+
const ERROR_DEDUPE_WINDOW_MS = 60_000;
|
|
141
|
+
/**
|
|
142
|
+
* Maximum captures of one error signature per {@link ERROR_DEDUPE_WINDOW_MS}.
|
|
143
|
+
* Chosen so a genuine, ongoing failure is still visible (and its rate
|
|
144
|
+
* observable via `sdk.suppressed_since_last`) while a hot loop hammering a
|
|
145
|
+
* broken RPC or a 404-per-borrower fan-out cannot bill thousands of identical
|
|
146
|
+
* events. Beyond this, further captures in the window are dropped.
|
|
147
|
+
*/
|
|
148
|
+
const ERROR_DEDUPE_MAX_PER_WINDOW = 3;
|
|
149
|
+
/** Hard cap on tracked signatures, so the map cannot grow without bound. */
|
|
150
|
+
const ERROR_DEDUPE_MAX_KEYS = 500;
|
|
151
|
+
/**
|
|
152
|
+
* Per-signature capture bookkeeping for the dedupe window.
|
|
153
|
+
*
|
|
154
|
+
* Deliberately process-global, matching the Sentry client it feeds: the client
|
|
155
|
+
* is a singleton, so every `AugustSDK` instance in the process shares one
|
|
156
|
+
* event stream and one quota. The signature intentionally omits partner/app
|
|
157
|
+
* identity — a host serving several partners reports an identical upstream
|
|
158
|
+
* failure ≤{@link ERROR_DEDUPE_MAX_PER_WINDOW} times per window in aggregate,
|
|
159
|
+
* not per partner, because the failure is one event regardless of how many
|
|
160
|
+
* tenants observed it. Per-tenant attribution comes from the `partner.id` tag
|
|
161
|
+
* on the events that are sent, and `sdk.suppressed_since_last` preserves the
|
|
162
|
+
* true rate. `resetAnalytics()` clears this map for the whole process.
|
|
163
|
+
*/
|
|
164
|
+
const errorDedupeState = new Map();
|
|
165
|
+
/**
|
|
166
|
+
* Build a low-cardinality signature for an error.
|
|
167
|
+
*
|
|
168
|
+
* Message tails carry the variable parts (addresses, block ranges, response
|
|
169
|
+
* bodies), so only the leading 120 characters participate — enough to separate
|
|
170
|
+
* distinct failure modes without splitting one failure mode into thousands of
|
|
171
|
+
* unique keys.
|
|
172
|
+
*
|
|
173
|
+
* @param error - The normalized error being captured.
|
|
174
|
+
* @param origin - The `sdk.origin` call-site tag, when present.
|
|
175
|
+
* @returns A stable key identifying this class of failure.
|
|
176
|
+
*/
|
|
177
|
+
function errorSignature(error, origin) {
|
|
178
|
+
const tag = typeof origin === 'string' ? origin : '';
|
|
179
|
+
return `${tag}|${error.name}|${(error.message || '').slice(0, 120)}`;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Decide whether an error should be sent to Sentry, applying a per-signature
|
|
183
|
+
* rolling rate limit.
|
|
184
|
+
*
|
|
185
|
+
* Why this exists: the SDK is called from server-rendered pages that fan out
|
|
186
|
+
* per vault and per borrower, so a single upstream condition (a 502 from the
|
|
187
|
+
* backend, an RPC rejecting a batch) reproduces on every iteration of every
|
|
188
|
+
* request. Those are the same event, and paying Sentry per copy buys no extra
|
|
189
|
+
* signal.
|
|
190
|
+
*
|
|
191
|
+
* Side effect: mutates {@link errorDedupeState}.
|
|
192
|
+
*
|
|
193
|
+
* @param error - The normalized error about to be captured.
|
|
194
|
+
* @param origin - The `sdk.origin` call-site tag, when present.
|
|
195
|
+
* @returns `send: false` to drop the event. When `send: true`, `suppressed` is
|
|
196
|
+
* the number of copies dropped since the last event that was sent, and is
|
|
197
|
+
* attached to the outgoing event so the true rate stays recoverable.
|
|
198
|
+
*/
|
|
199
|
+
function admitError(error, origin) {
|
|
200
|
+
const key = errorSignature(error, origin);
|
|
201
|
+
const now = Date.now();
|
|
202
|
+
const entry = errorDedupeState.get(key);
|
|
203
|
+
// Touch the key on every access so iteration order is true
|
|
204
|
+
// least-recently-used, not first-inserted: a Map's `set` on an existing key
|
|
205
|
+
// does NOT reorder it, so without the delete a signature that keeps
|
|
206
|
+
// recurring would hold its original position and be evicted ahead of a stale
|
|
207
|
+
// one-shot signature registered after it — silently handing the hot
|
|
208
|
+
// signature a fresh allowance every time it churned out of the map.
|
|
209
|
+
errorDedupeState.delete(key);
|
|
210
|
+
if (!entry || now - entry.windowStart >= ERROR_DEDUPE_WINDOW_MS) {
|
|
211
|
+
// Bound the map: drop the least-recently-used signature before inserting.
|
|
212
|
+
if (errorDedupeState.size >= ERROR_DEDUPE_MAX_KEYS) {
|
|
213
|
+
const oldest = errorDedupeState.keys().next();
|
|
214
|
+
if (!oldest.done)
|
|
215
|
+
errorDedupeState.delete(oldest.value);
|
|
216
|
+
}
|
|
217
|
+
const suppressed = entry?.suppressed ?? 0;
|
|
218
|
+
errorDedupeState.set(key, { windowStart: now, captured: 1, suppressed: 0 });
|
|
219
|
+
return { send: true, suppressed };
|
|
220
|
+
}
|
|
221
|
+
errorDedupeState.set(key, entry);
|
|
222
|
+
if (entry.captured < ERROR_DEDUPE_MAX_PER_WINDOW) {
|
|
223
|
+
// `suppressed` can only be non-zero once the allowance is exhausted, so
|
|
224
|
+
// inside the allowance there is never a carried count to report.
|
|
225
|
+
entry.captured += 1;
|
|
226
|
+
return { send: true, suppressed: 0 };
|
|
227
|
+
}
|
|
228
|
+
entry.suppressed += 1;
|
|
229
|
+
return { send: false, suppressed: entry.suppressed };
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Clear the error dedupe bookkeeping. Test-only — the rate limiter is process
|
|
233
|
+
* lifetime state and would otherwise leak between test cases.
|
|
234
|
+
*
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
function resetErrorDedupe() {
|
|
238
|
+
errorDedupeState.clear();
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Build the SDK's internal Sentry sink — the bridge that forwards
|
|
242
|
+
* `Logger.log.*` output to the resolved Sentry SDK. Errors are captured as
|
|
243
|
+
* issues; warnings are recorded as breadcrumbs (see the severity policy on
|
|
244
|
+
* `SDKSentrySink`). The SDK reference is resolved lazily on each call so the
|
|
245
|
+
* sink tracks runtime swaps and stays correct under the test harness's mock.
|
|
246
|
+
*
|
|
247
|
+
* Every method is fully wrapped: a telemetry failure must never propagate back
|
|
248
|
+
* into the caller that was only trying to log.
|
|
249
|
+
*/
|
|
250
|
+
function createSentrySink() {
|
|
251
|
+
return {
|
|
252
|
+
captureException(error, context) {
|
|
253
|
+
try {
|
|
254
|
+
const sdk = (0, sentry_runtime_1.getSentrySDK)();
|
|
255
|
+
if (!sdk)
|
|
256
|
+
return;
|
|
257
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
258
|
+
// Rate-limit identical failures before touching Sentry at all — the
|
|
259
|
+
// scope work and the event payload are both wasted if it is dropped.
|
|
260
|
+
const admission = admitError(normalized, context?.tag);
|
|
261
|
+
if (!admission.send)
|
|
262
|
+
return;
|
|
263
|
+
sdk.withScope((scope) => {
|
|
264
|
+
// `beforeSend` drops any event not tagged as ours; the tag is global
|
|
265
|
+
// already, but set it on the scope defensively in case a future
|
|
266
|
+
// Sentry version starts withScope() from a clean slate.
|
|
267
|
+
scope.setTag('sdk', 'august-digital');
|
|
268
|
+
if (context) {
|
|
269
|
+
for (const [key, value] of Object.entries(context)) {
|
|
270
|
+
// Promote the call-site label (e.g. 'getVault:loans') to a
|
|
271
|
+
// scoped tag for grouping/filtering. Cardinality is bounded by
|
|
272
|
+
// the number of Logger call sites (~150) and the tag is
|
|
273
|
+
// event-scoped, not a global sticky tag — so it does not run
|
|
274
|
+
// afoul of the bounded-tag rule in CLAUDE.md §8.4.
|
|
275
|
+
if (key === 'tag' && typeof value === 'string') {
|
|
276
|
+
scope.setTag('sdk.origin', value);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
scope.setExtra(key, value);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Preserve the true failure rate even though copies were dropped.
|
|
284
|
+
if (admission.suppressed > 0) {
|
|
285
|
+
scope.setExtra('sdk.suppressed_since_last', admission.suppressed);
|
|
286
|
+
}
|
|
287
|
+
sdk.captureException(normalized);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
// Telemetry must never break the SDK.
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
addBreadcrumb(breadcrumb) {
|
|
295
|
+
try {
|
|
296
|
+
(0, sentry_runtime_1.getSentrySDK)()?.addBreadcrumb(breadcrumb);
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
// Telemetry must never break the SDK.
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Initialize Sentry with SDK-specific configuration. Idempotent: re-calls
|
|
306
|
+
* only refresh user identity and the cached API-key hash.
|
|
307
|
+
*
|
|
308
|
+
* @param config - Analytics configuration. Pass `tracesSampleRate` to
|
|
309
|
+
* override the default of `0.1`.
|
|
310
|
+
* @param environment - Current environment (DEV or PROD).
|
|
311
|
+
* @param walletAddress - Optional wallet address for user identification.
|
|
312
|
+
* @param apiKey - Optional API key (hashed for identification).
|
|
313
|
+
* @param appName - Optional app-name slug. Set as the global `app.name`
|
|
314
|
+
* tag on every event; falls back to `'unverified:anonymous'` when
|
|
315
|
+
* omitted.
|
|
316
|
+
*/
|
|
317
|
+
function initializeSentry(config, environment, walletAddress, apiKey, appName) {
|
|
318
|
+
// SDK construction runs this multiple times (base + adapter constructors).
|
|
319
|
+
// Short-circuit so the disable-reason logs only once per process.
|
|
320
|
+
if (isInitialized) {
|
|
321
|
+
if (isEnabled) {
|
|
322
|
+
// Refresh cached apiKey before updateUser — otherwise a second SDK
|
|
323
|
+
// instance built with a different key is attributed to the first hash.
|
|
324
|
+
if (apiKey !== undefined && apiKey !== cachedApiKey) {
|
|
325
|
+
cachedApiKey = apiKey;
|
|
326
|
+
updateUser(walletAddress, environment);
|
|
327
|
+
}
|
|
328
|
+
else if (walletAddress !== currentIdentity?.walletAddress ||
|
|
329
|
+
environment !== currentIdentity?.environment) {
|
|
330
|
+
updateUser(walletAddress, environment);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
// Constructor config wins outright — no env override can re-enable it.
|
|
336
|
+
if (config.enabled === false) {
|
|
337
|
+
isEnabled = false;
|
|
338
|
+
isInitialized = true;
|
|
339
|
+
logger_1.Logger.log.info('analytics.disabled', { reason: 'config' });
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
const forced = (0, env_1.isAnalyticsForcedOnViaEnv)();
|
|
343
|
+
if (!forced && (0, env_1.isAnalyticsDisabledViaEnv)()) {
|
|
344
|
+
isEnabled = false;
|
|
345
|
+
isInitialized = true;
|
|
346
|
+
logger_1.Logger.log.info('analytics.disabled', {
|
|
347
|
+
reason: 'AUGUST_SDK_DISABLE_ANALYTICS',
|
|
348
|
+
});
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (!forced && (0, env_1.isNodeDevOrTestEnv)()) {
|
|
352
|
+
isEnabled = false;
|
|
353
|
+
isInitialized = true;
|
|
354
|
+
logger_1.Logger.log.info('analytics.disabled', {
|
|
355
|
+
reason: 'NODE_ENV',
|
|
356
|
+
nodeEnv: (0, env_1.readEnv)('NODE_ENV'),
|
|
357
|
+
hint: 'set AUGUST_SDK_FORCE_ANALYTICS=1 to override',
|
|
358
|
+
});
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
if (!forced && isLocalhost()) {
|
|
362
|
+
isEnabled = false;
|
|
363
|
+
isInitialized = true;
|
|
364
|
+
logger_1.Logger.log.info('analytics.disabled', { reason: 'localhost' });
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
cachedApiKey = apiKey;
|
|
368
|
+
try {
|
|
369
|
+
const sdk = (0, sentry_runtime_1.getSentrySDK)();
|
|
370
|
+
if (!sdk) {
|
|
371
|
+
// Both @sentry/node and @sentry/browser failed to resolve. Surface this
|
|
372
|
+
// because the alternative is silent telemetry loss.
|
|
373
|
+
logger_1.Logger.log.warn('analytics.init.sentry-unavailable', {
|
|
374
|
+
runtime: (0, sentry_runtime_1.getSentryRuntime)(),
|
|
375
|
+
hint: 'Confirm @sentry/browser (or @sentry/node) is installed and reachable.',
|
|
376
|
+
});
|
|
377
|
+
isEnabled = false;
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
// Clamp to Sentry's accepted [0, 1] so a typo'd rate doesn't silently
|
|
381
|
+
// reject the init.
|
|
382
|
+
const rawSampleRate = typeof config.tracesSampleRate === 'number' &&
|
|
383
|
+
Number.isFinite(config.tracesSampleRate)
|
|
384
|
+
? config.tracesSampleRate
|
|
385
|
+
: 0.1; // Phase 2 default — verified partners can opt into 1.0 explicitly
|
|
386
|
+
const tracesSampleRate = Math.max(0, Math.min(1, rawSampleRate));
|
|
387
|
+
sdk.init({
|
|
388
|
+
dsn: constants_1.SENTRY_DSN,
|
|
389
|
+
tracesSampleRate,
|
|
390
|
+
enableTracing: true,
|
|
391
|
+
environment: environment.toLowerCase(),
|
|
392
|
+
release: `august-sdk@${getSDKVersion()}`,
|
|
393
|
+
sendDefaultPii: true,
|
|
394
|
+
// SDK errors route through Logger.setSentrySink → captureException directly,
|
|
395
|
+
// so captureConsoleIntegration is redundant here. Omitting it also prevents
|
|
396
|
+
// consumer app console.error calls from being billed as SDK error events (the
|
|
397
|
+
// global sdk:'august-digital' tag would otherwise cause them to pass beforeSend).
|
|
398
|
+
integrations: [],
|
|
399
|
+
// Drop classes of event that are never SDK signal, as a backstop to the
|
|
400
|
+
// call-site demotions (see `logChainError` / `isUserRejectionError`).
|
|
401
|
+
// Scope is deliberately narrow: only categories that are noise in EVERY
|
|
402
|
+
// code path. Generic contract reverts (`CALL_EXCEPTION` / "missing revert
|
|
403
|
+
// data") are intentionally NOT listed — a reverted *write* tx is a real
|
|
404
|
+
// error we keep at `error` level, and only read-path reverts are demoted
|
|
405
|
+
// (surgically, at the call site).
|
|
406
|
+
ignoreErrors: [
|
|
407
|
+
// Wallet user-rejections are normal product behaviour, not an SDK fault.
|
|
408
|
+
/user rejected/i,
|
|
409
|
+
/user denied/i,
|
|
410
|
+
'ACTION_REJECTED',
|
|
411
|
+
// Local dev/test node leaking into a prod DSN: :8545 is the canonical
|
|
412
|
+
// Anvil/Hardhat port and is never a production RPC endpoint.
|
|
413
|
+
/ECONNREFUSED .*:8545/,
|
|
414
|
+
// AugustHistoryUnavailableError is a designed, documented outcome:
|
|
415
|
+
// the getter refuses to return a fabricated number when the indexer
|
|
416
|
+
// has no deposit/withdrawal history. It is thrown to the caller, who
|
|
417
|
+
// renders "temporarily unavailable" — the SDK is behaving correctly,
|
|
418
|
+
// so it is not an SDK issue. Indexer health is monitored separately.
|
|
419
|
+
/transaction history unavailable/i,
|
|
420
|
+
],
|
|
421
|
+
beforeSend(event) {
|
|
422
|
+
// Only send events tagged as SDK-related
|
|
423
|
+
if (event.tags?.sdk !== 'august-digital') {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
// Muted chains (see MUTED_CHAIN_SLUGS) are dropped wholesale.
|
|
427
|
+
if (isMutedChainEvent(event)) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
return event;
|
|
431
|
+
},
|
|
432
|
+
beforeSendTransaction(transaction) {
|
|
433
|
+
// Sub-sample the high-frequency network bookkeeping category (switchNetwork,
|
|
434
|
+
// updateWallet, clearWallet, setSigner) to 10% of whatever tracesSampleRate
|
|
435
|
+
// already passed — these fire on every wallet/chain update and are low signal
|
|
436
|
+
// for the partner-usage dashboard relative to read/write calls.
|
|
437
|
+
if (transaction.tags?.['sdk.category'] === 'network' &&
|
|
438
|
+
Math.random() > 0.1) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
return transaction;
|
|
442
|
+
},
|
|
443
|
+
});
|
|
444
|
+
// Set initial user identity
|
|
445
|
+
updateUser(walletAddress, environment);
|
|
446
|
+
// Set global SDK tags
|
|
447
|
+
safeSetTag('sdk', 'august-digital');
|
|
448
|
+
safeSetTag('sdk.version', getSDKVersion());
|
|
449
|
+
safeSetTag('sdk.runtime', (0, sentry_runtime_1.getSentryRuntime)());
|
|
450
|
+
// `app.name` is the dimension we filter on in Sentry to attribute
|
|
451
|
+
// events to a specific consuming application — see SDK quickstart docs.
|
|
452
|
+
if (appName) {
|
|
453
|
+
safeSetTag('app.name', appName);
|
|
454
|
+
}
|
|
455
|
+
// `unverified:` prefix until the backend API-key → partner-id endpoint exists.
|
|
456
|
+
safeSetTag('partner.id', appName ? `unverified:${appName}` : 'unverified:anonymous');
|
|
457
|
+
safeSetTag('partner.tier', 'unverified');
|
|
458
|
+
// Bridge the SDK's structured logger into Sentry now that the SDK is live.
|
|
459
|
+
// Without this, Logger.log.error/warn are no-ops in production (no
|
|
460
|
+
// SDKLogger/structured logger is wired by default), so SDK-internal
|
|
461
|
+
// diagnostics never reach the dashboard. Errors → issues, warns →
|
|
462
|
+
// breadcrumbs.
|
|
463
|
+
logger_1.Logger.setSentrySink(createSentrySink());
|
|
464
|
+
isInitialized = true;
|
|
465
|
+
logger_1.Logger.log.info('analytics.initialized', {
|
|
466
|
+
runtime: (0, sentry_runtime_1.getSentryRuntime)(),
|
|
467
|
+
hint: 'Disable with { analytics: { enabled: false } } or AUGUST_SDK_DISABLE_ANALYTICS=1',
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
catch (err) {
|
|
471
|
+
logger_1.Logger.log.warn('analytics.init.failed', {
|
|
472
|
+
runtime: (0, sentry_runtime_1.getSentryRuntime)(),
|
|
473
|
+
error: err instanceof Error ? err.message : String(err),
|
|
474
|
+
});
|
|
475
|
+
isEnabled = false;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Update the current user identity in Sentry.
|
|
480
|
+
* Called when wallet address changes.
|
|
481
|
+
*
|
|
482
|
+
* @param walletAddress - New wallet address (or undefined to clear)
|
|
483
|
+
* @param environment - Current environment
|
|
484
|
+
*/
|
|
485
|
+
function updateUser(walletAddress, environment = 'PROD') {
|
|
486
|
+
if (!isEnabled)
|
|
487
|
+
return;
|
|
488
|
+
try {
|
|
489
|
+
currentIdentity = (0, user_identity_1.createUserIdentity)(cachedApiKey, walletAddress, environment);
|
|
490
|
+
const userId = (0, user_identity_1.getUserId)(currentIdentity);
|
|
491
|
+
safeSetUser({
|
|
492
|
+
id: userId,
|
|
493
|
+
username: userId, // Duplicate to username which is less likely to be filtered
|
|
494
|
+
ip_address: '{{auto}}',
|
|
495
|
+
data: {
|
|
496
|
+
userId, // Also store in data for redundancy
|
|
497
|
+
sessionId: currentIdentity.sessionId,
|
|
498
|
+
fingerprint: currentIdentity.fingerprint,
|
|
499
|
+
hasWallet: !!walletAddress,
|
|
500
|
+
hasApiKey: !!currentIdentity.apiKeyHash,
|
|
501
|
+
environment: currentIdentity.environment,
|
|
502
|
+
walletAddress: walletAddress || undefined,
|
|
503
|
+
},
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
catch {
|
|
507
|
+
// Silently fail
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Clear wallet from user identity.
|
|
512
|
+
* Called when user disconnects wallet.
|
|
513
|
+
*/
|
|
514
|
+
function clearUser() {
|
|
515
|
+
if (!isEnabled)
|
|
516
|
+
return;
|
|
517
|
+
try {
|
|
518
|
+
const environment = currentIdentity?.environment || 'PROD';
|
|
519
|
+
currentIdentity = (0, user_identity_1.createUserIdentity)(cachedApiKey, undefined, environment);
|
|
520
|
+
const userId = (0, user_identity_1.getUserId)(currentIdentity);
|
|
521
|
+
safeSetUser({
|
|
522
|
+
id: userId,
|
|
523
|
+
username: userId,
|
|
524
|
+
ip_address: '{{auto}}',
|
|
525
|
+
data: {
|
|
526
|
+
userId,
|
|
527
|
+
sessionId: currentIdentity.sessionId,
|
|
528
|
+
fingerprint: currentIdentity.fingerprint,
|
|
529
|
+
hasWallet: false,
|
|
530
|
+
hasApiKey: !!currentIdentity.apiKeyHash,
|
|
531
|
+
environment: currentIdentity.environment,
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
catch {
|
|
536
|
+
// Silently fail
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Check if analytics is enabled and initialized.
|
|
541
|
+
*/
|
|
542
|
+
function isAnalyticsEnabled() {
|
|
543
|
+
return isEnabled && isInitialized;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Get the current Sentry instance for advanced usage.
|
|
547
|
+
* Returns null if analytics is disabled.
|
|
548
|
+
*/
|
|
549
|
+
function getSentry() {
|
|
550
|
+
if (!isAnalyticsEnabled())
|
|
551
|
+
return null;
|
|
552
|
+
return (0, sentry_runtime_1.getSentrySDK)();
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Reset analytics state (useful for testing).
|
|
556
|
+
*/
|
|
557
|
+
function resetAnalytics() {
|
|
558
|
+
isInitialized = false;
|
|
559
|
+
isEnabled = true;
|
|
560
|
+
currentIdentity = null;
|
|
561
|
+
cachedApiKey = undefined;
|
|
562
|
+
logger_1.Logger.setSentrySink(null);
|
|
563
|
+
(0, sentry_runtime_1.resetSentryRuntime)();
|
|
564
|
+
// The error rate limiter is process-lifetime state; a reset analytics layer
|
|
565
|
+
// must not inherit a half-full dedupe window from the previous one.
|
|
566
|
+
resetErrorDedupe();
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Capture an exception into Sentry with SDK-specific context. Use from
|
|
570
|
+
* top-level error handlers (CLI, middleware, unhandled rejections) to
|
|
571
|
+
* report failures that don't flow through the auto-instrumented method
|
|
572
|
+
* surface. No-ops when analytics is disabled.
|
|
573
|
+
*
|
|
574
|
+
* @param error - Thrown value. Non-Error values are wrapped.
|
|
575
|
+
* @param options - `surface` ('cli' | 'sdk' | 'react' | string), extra `tags`,
|
|
576
|
+
* `extra` data, and a `flushTimeoutMs` to await before resolving (needed
|
|
577
|
+
* in Node when the process is about to exit).
|
|
578
|
+
*/
|
|
579
|
+
async function captureSdkException(error, options) {
|
|
580
|
+
if (!isAnalyticsEnabled())
|
|
581
|
+
return;
|
|
582
|
+
try {
|
|
583
|
+
const sdk = (0, sentry_runtime_1.getSentrySDK)();
|
|
584
|
+
if (!sdk)
|
|
585
|
+
return;
|
|
586
|
+
sdk.withScope((scope) => {
|
|
587
|
+
// Required so `beforeSend` doesn't drop the event.
|
|
588
|
+
scope.setTag('sdk', 'august-digital');
|
|
589
|
+
if (options?.surface) {
|
|
590
|
+
scope.setTag('sdk.surface', options.surface);
|
|
591
|
+
}
|
|
592
|
+
if (options?.tags) {
|
|
593
|
+
for (const [k, v] of Object.entries(options.tags)) {
|
|
594
|
+
scope.setTag(k, v);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
if (options?.extra) {
|
|
598
|
+
for (const [k, v] of Object.entries(options.extra)) {
|
|
599
|
+
scope.setExtra(k, v);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
603
|
+
sdk.captureException(normalized);
|
|
604
|
+
});
|
|
605
|
+
if (options?.flushTimeoutMs && options.flushTimeoutMs > 0) {
|
|
606
|
+
await sdk.flush(options.flushTimeoutMs);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
catch {
|
|
610
|
+
// Silently fail - analytics should never block error propagation
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
//# sourceMappingURL=sentry.js.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { IEnv } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for SDK analytics/telemetry.
|
|
4
|
+
* Analytics are enabled by default (opt-out model).
|
|
5
|
+
*/
|
|
6
|
+
export interface IAnalyticsConfig {
|
|
7
|
+
/** Set to false to disable analytics. Default: true */
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Sentry trace sample rate. Defaults to `1.0` for the Phase 1/2 rollout;
|
|
11
|
+
* values outside `[0, 1]` are clamped.
|
|
12
|
+
*/
|
|
13
|
+
tracesSampleRate?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* User identity for analytics tracking.
|
|
17
|
+
* Multiple identifiers are used with priority: apiKeyHash > wallet > fingerprint > session
|
|
18
|
+
*/
|
|
19
|
+
export interface IUserIdentity {
|
|
20
|
+
/** SHA-256 hash prefix of API key (first 16 chars). Never stores raw key. */
|
|
21
|
+
apiKeyHash?: string;
|
|
22
|
+
/** User's wallet address (lowercased) */
|
|
23
|
+
walletAddress?: string;
|
|
24
|
+
/** Random UUID generated per SDK instance */
|
|
25
|
+
sessionId: string;
|
|
26
|
+
/** Browser/environment fingerprint for cross-session tracking */
|
|
27
|
+
fingerprint?: string;
|
|
28
|
+
/** Current environment */
|
|
29
|
+
environment: IEnv;
|
|
30
|
+
/** Domain of the current environment */
|
|
31
|
+
domain?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Metrics for tracking SDK method calls.
|
|
35
|
+
*/
|
|
36
|
+
export interface IMethodCallMetrics {
|
|
37
|
+
method: string;
|
|
38
|
+
/**
|
|
39
|
+
* Coarse-grained category from {@link METHOD_CATEGORIES} — e.g. `'read.vault'`,
|
|
40
|
+
* `'write.deposit'`. Used to roll calls up in the partner-usage dashboard
|
|
41
|
+
* without having to enumerate every method name.
|
|
42
|
+
*/
|
|
43
|
+
category?: string;
|
|
44
|
+
chainId?: number;
|
|
45
|
+
duration: number;
|
|
46
|
+
success: boolean;
|
|
47
|
+
errorType?: string;
|
|
48
|
+
}
|