@l.x/gating 1.0.3 → 1.0.4
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/.depcheckrc +13 -0
- package/.eslintrc.js +21 -0
- package/README.md +3 -0
- package/package.json +39 -1
- package/project.json +18 -0
- package/src/LocalOverrideAdapterWrapper.ts +63 -0
- package/src/configs.ts +296 -0
- package/src/constants.ts +4 -0
- package/src/experiments.ts +83 -0
- package/src/flags.ts +222 -0
- package/src/getIsHashcashSolverEnabled.ts +12 -0
- package/src/getIsPerformanceTrackingEnabled.ts +19 -0
- package/src/getIsSessionServiceEnabled.ts +14 -0
- package/src/getIsSessionUpgradeAutoEnabled.ts +9 -0
- package/src/getIsTurnstileSolverEnabled.ts +12 -0
- package/src/getStatsigEnvName.ts +19 -0
- package/src/hooks.ts +244 -0
- package/src/index.ts +99 -0
- package/src/sdk/statsig.native.ts +33 -0
- package/src/sdk/statsig.ts +47 -0
- package/src/utils.ts +24 -0
- package/tsconfig.json +35 -0
- package/tsconfig.lint.json +8 -0
- package/index.d.ts +0 -1
- package/index.js +0 -1
package/src/flags.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { logger } from 'utilities/src/logger/logger'
|
|
2
|
+
import { isWebApp } from 'utilities/src/platform'
|
|
3
|
+
|
|
4
|
+
// only disable for this enum
|
|
5
|
+
/**
|
|
6
|
+
* Feature flag names.
|
|
7
|
+
* Add in alphabetical order for each section to decrease probability of merge conflicts.
|
|
8
|
+
*/
|
|
9
|
+
/* biome-ignore-start lint/style/useEnumInitializers: preserve the order */
|
|
10
|
+
export enum FeatureFlags {
|
|
11
|
+
// Shared
|
|
12
|
+
AllowDEXOnlyRoutesInSwapSettings,
|
|
13
|
+
ArbitrumDutchV3,
|
|
14
|
+
BlockaidFotLogging,
|
|
15
|
+
CentralizedPrices,
|
|
16
|
+
ChainedActions,
|
|
17
|
+
DisableSwap7702,
|
|
18
|
+
DisableSessionsForPlan,
|
|
19
|
+
EmbeddedWallet,
|
|
20
|
+
EnablePermitMismatchUX,
|
|
21
|
+
ForceDisableWalletGetCapabilities,
|
|
22
|
+
ForcePermitTransactions,
|
|
23
|
+
ForSessionsEnabled,
|
|
24
|
+
ForUrlMigration,
|
|
25
|
+
GasServiceV2,
|
|
26
|
+
HashcashSolverEnabled,
|
|
27
|
+
Monad,
|
|
28
|
+
MultichainTokenUx,
|
|
29
|
+
NetworkFilterV2,
|
|
30
|
+
NoLxInterfaceFees,
|
|
31
|
+
PortionFields,
|
|
32
|
+
ProfitLoss,
|
|
33
|
+
SessionsPerformanceTrackingEnabled,
|
|
34
|
+
SessionsServiceEnabled,
|
|
35
|
+
SessionsUpgradeAutoEnabled,
|
|
36
|
+
SmartWallet,
|
|
37
|
+
SmartWalletDisableVideo,
|
|
38
|
+
Solana,
|
|
39
|
+
Soneium,
|
|
40
|
+
Tempo,
|
|
41
|
+
TurnstileSolverEnabled,
|
|
42
|
+
TwoSecondSwapQuotePollingInterval,
|
|
43
|
+
UnichainFlashblocks,
|
|
44
|
+
UniquoteEnabled,
|
|
45
|
+
UniroutePulumiEnabled,
|
|
46
|
+
LuxWrapped2025,
|
|
47
|
+
DEX,
|
|
48
|
+
DEXPriorityOrdersBase,
|
|
49
|
+
DEXPriorityOrdersOptimism,
|
|
50
|
+
DEXPriorityOrdersUnichain,
|
|
51
|
+
ViemProviderEnabled,
|
|
52
|
+
XLayer,
|
|
53
|
+
|
|
54
|
+
// Wallet
|
|
55
|
+
BottomTabs,
|
|
56
|
+
DisableFiatOnRampKorea,
|
|
57
|
+
Eip5792Methods,
|
|
58
|
+
EnableExportPrivateKeys,
|
|
59
|
+
EnableRestoreSeedPhrase,
|
|
60
|
+
EnableTransactionSpacingForDelegatedAccounts,
|
|
61
|
+
ExpoImage,
|
|
62
|
+
|
|
63
|
+
NotificationApiDataSource,
|
|
64
|
+
NotificationOnboardingCard,
|
|
65
|
+
NotificationService,
|
|
66
|
+
|
|
67
|
+
PrivateRpc,
|
|
68
|
+
Scantastic,
|
|
69
|
+
SelfReportSpamNFTs,
|
|
70
|
+
SmartWalletSettings,
|
|
71
|
+
UwULink,
|
|
72
|
+
|
|
73
|
+
// Web
|
|
74
|
+
AATestWeb,
|
|
75
|
+
AuctionDetailsV2,
|
|
76
|
+
BatchedSwaps,
|
|
77
|
+
DummyFlagTest,
|
|
78
|
+
LimitsFees,
|
|
79
|
+
LiquidityBatchedTransactions,
|
|
80
|
+
LpDynamicNativeSlippage,
|
|
81
|
+
LpIncentives,
|
|
82
|
+
NoLxInterfaceFeesNotification,
|
|
83
|
+
PortfolioDefiTab,
|
|
84
|
+
PortoWalletConnector,
|
|
85
|
+
SolanaPromo,
|
|
86
|
+
TDPTokenCarousel,
|
|
87
|
+
ToucanAuctionKYC,
|
|
88
|
+
ToucanLaunchAuction,
|
|
89
|
+
TraceJsonRpc,
|
|
90
|
+
UnificationCopy,
|
|
91
|
+
UnirouteEnabled,
|
|
92
|
+
UniversalSwap,
|
|
93
|
+
}
|
|
94
|
+
/* biome-ignore-end lint/style/useEnumInitializers: preserve the order */
|
|
95
|
+
|
|
96
|
+
// These names must match the gate name on statsig.
|
|
97
|
+
// Add in alphabetical order to decrease probability of merge conflicts.
|
|
98
|
+
export const SHARED_FEATURE_FLAG_NAMES = new Map<FeatureFlags, string>([
|
|
99
|
+
[FeatureFlags.AllowDEXOnlyRoutesInSwapSettings, 'allow_luxx_only_routes_in_swap_settings'],
|
|
100
|
+
[FeatureFlags.ArbitrumDutchV3, 'luxx_dutchv3_orders_arbitrum'],
|
|
101
|
+
[FeatureFlags.BlockaidFotLogging, 'blockaid_fot_logging'],
|
|
102
|
+
[FeatureFlags.CentralizedPrices, 'centralized_prices'],
|
|
103
|
+
[FeatureFlags.ChainedActions, 'enable_chained_actions'],
|
|
104
|
+
[FeatureFlags.DisableSwap7702, 'disable-swap-7702'],
|
|
105
|
+
[FeatureFlags.DisableSessionsForPlan, 'disable_sessions_for_plan'],
|
|
106
|
+
[FeatureFlags.EmbeddedWallet, 'embedded_wallet'],
|
|
107
|
+
[FeatureFlags.EnablePermitMismatchUX, 'enable_permit2_mismatch_ux'],
|
|
108
|
+
[FeatureFlags.ForceDisableWalletGetCapabilities, 'force_disable_wallet_get_capabilities'],
|
|
109
|
+
[FeatureFlags.ForcePermitTransactions, 'force_permit_transactions'],
|
|
110
|
+
[FeatureFlags.ForSessionsEnabled, 'for_sessions_enabled'],
|
|
111
|
+
[FeatureFlags.ForUrlMigration, 'for_url_migration'],
|
|
112
|
+
[FeatureFlags.GasServiceV2, 'gas_service_v2'],
|
|
113
|
+
[FeatureFlags.HashcashSolverEnabled, 'sessions_hashcash_solver_enabled'],
|
|
114
|
+
[FeatureFlags.Monad, 'monad'],
|
|
115
|
+
[FeatureFlags.MultichainTokenUx, 'multichain_token_ux'],
|
|
116
|
+
[FeatureFlags.NetworkFilterV2, 'network_filter_v2'],
|
|
117
|
+
[FeatureFlags.NoLxInterfaceFees, 'no_lx_interface_fees'],
|
|
118
|
+
[FeatureFlags.NotificationApiDataSource, 'notification_api_data_source'],
|
|
119
|
+
[FeatureFlags.PortionFields, 'portion-fields'],
|
|
120
|
+
[FeatureFlags.ProfitLoss, 'profit_loss'],
|
|
121
|
+
[FeatureFlags.SelfReportSpamNFTs, 'self-report-spam-nfts'],
|
|
122
|
+
[FeatureFlags.SessionsPerformanceTrackingEnabled, 'sessions_performance_tracking_enabled'],
|
|
123
|
+
[FeatureFlags.SessionsServiceEnabled, 'sessions_service_enabled'],
|
|
124
|
+
[FeatureFlags.SessionsUpgradeAutoEnabled, 'sessions_upgrade_auto_enabled'],
|
|
125
|
+
[FeatureFlags.SmartWallet, 'smart-wallet'],
|
|
126
|
+
[FeatureFlags.SmartWalletDisableVideo, 'smart_wallet_disable_video'],
|
|
127
|
+
[FeatureFlags.Solana, 'solana'],
|
|
128
|
+
[FeatureFlags.Soneium, 'soneium'],
|
|
129
|
+
[FeatureFlags.Tempo, 'tempo'],
|
|
130
|
+
[FeatureFlags.TurnstileSolverEnabled, 'sessions_turnstile_solver_enabled'],
|
|
131
|
+
[FeatureFlags.TwoSecondSwapQuotePollingInterval, 'two_second_swap_quote_polling_interval'],
|
|
132
|
+
[FeatureFlags.UnichainFlashblocks, 'unichain_flashblocks'],
|
|
133
|
+
[FeatureFlags.UniquoteEnabled, 'uniquote_enabled'],
|
|
134
|
+
[FeatureFlags.UnirouteEnabled, 'uniroute_rollout'],
|
|
135
|
+
[FeatureFlags.UniroutePulumiEnabled, 'uniroute_pulumi_enabled'],
|
|
136
|
+
[FeatureFlags.LuxWrapped2025, 'lux_wrapped_2025'],
|
|
137
|
+
[FeatureFlags.DEX, 'luxx'],
|
|
138
|
+
[FeatureFlags.DEXPriorityOrdersBase, 'luxx_priority_orders_base'],
|
|
139
|
+
[FeatureFlags.DEXPriorityOrdersOptimism, 'luxx_priority_orders_optimism'],
|
|
140
|
+
[FeatureFlags.DEXPriorityOrdersUnichain, 'luxx_priority_orders_unichain'],
|
|
141
|
+
[FeatureFlags.ViemProviderEnabled, 'viem_provider_enabled'],
|
|
142
|
+
[FeatureFlags.XLayer, 'x_layer'],
|
|
143
|
+
])
|
|
144
|
+
|
|
145
|
+
// These names must match the gate name on statsig.
|
|
146
|
+
// Add in alphabetical order to decrease probability of merge conflicts.
|
|
147
|
+
export const WEB_FEATURE_FLAG_NAMES = new Map<FeatureFlags, string>([
|
|
148
|
+
...SHARED_FEATURE_FLAG_NAMES,
|
|
149
|
+
[FeatureFlags.AATestWeb, 'aatest_web'],
|
|
150
|
+
[FeatureFlags.AuctionDetailsV2, 'auction_details_v2'],
|
|
151
|
+
[FeatureFlags.BatchedSwaps, 'batched_swaps'],
|
|
152
|
+
[FeatureFlags.DummyFlagTest, 'dummy_flag_test'],
|
|
153
|
+
[FeatureFlags.LimitsFees, 'limits_fees'],
|
|
154
|
+
[FeatureFlags.LiquidityBatchedTransactions, 'liquidity_batched_transactions'],
|
|
155
|
+
[FeatureFlags.LpDynamicNativeSlippage, 'lp_dynamic_native_slippage'],
|
|
156
|
+
[FeatureFlags.LpIncentives, 'lp_incentives'],
|
|
157
|
+
[FeatureFlags.NoLxInterfaceFeesNotification, 'no_lx_interface_fees_notification'],
|
|
158
|
+
[FeatureFlags.PortfolioDefiTab, 'portfolio_defi_tab'],
|
|
159
|
+
[FeatureFlags.PortoWalletConnector, 'porto_wallet_connector'],
|
|
160
|
+
[FeatureFlags.SolanaPromo, 'solana_promo'],
|
|
161
|
+
[FeatureFlags.TDPTokenCarousel, 'tdp_token_carousel'],
|
|
162
|
+
[FeatureFlags.ToucanAuctionKYC, 'toucan_auction_kyc'],
|
|
163
|
+
[FeatureFlags.ToucanLaunchAuction, 'toucan_launch_auction'],
|
|
164
|
+
[FeatureFlags.TraceJsonRpc, 'traceJsonRpc'],
|
|
165
|
+
[FeatureFlags.UnichainFlashblocks, 'unichain_flashblocks'],
|
|
166
|
+
[FeatureFlags.UnificationCopy, 'unification_copy'],
|
|
167
|
+
[FeatureFlags.UniversalSwap, 'universal_swap'],
|
|
168
|
+
])
|
|
169
|
+
|
|
170
|
+
// These names must match the gate name on statsig.
|
|
171
|
+
// Add in alphabetical order to decrease probability of merge conflicts.
|
|
172
|
+
export const WALLET_FEATURE_FLAG_NAMES = new Map<FeatureFlags, string>([
|
|
173
|
+
...SHARED_FEATURE_FLAG_NAMES,
|
|
174
|
+
[FeatureFlags.BottomTabs, 'bottom_tabs'],
|
|
175
|
+
[FeatureFlags.DisableFiatOnRampKorea, 'disable-fiat-onramp-korea'],
|
|
176
|
+
[FeatureFlags.Eip5792Methods, 'eip_5792_methods'],
|
|
177
|
+
[FeatureFlags.EnableExportPrivateKeys, 'enable-export-private-keys'],
|
|
178
|
+
[FeatureFlags.EnableRestoreSeedPhrase, 'enable-restore-seed-phrase'],
|
|
179
|
+
[FeatureFlags.EnableTransactionSpacingForDelegatedAccounts, 'enable_transaction_spacing_for_delegated_accounts'],
|
|
180
|
+
[FeatureFlags.ExpoImage, 'expo_image'],
|
|
181
|
+
|
|
182
|
+
[FeatureFlags.NotificationOnboardingCard, 'notification_onboarding_card'],
|
|
183
|
+
[FeatureFlags.NotificationService, 'notification_system'],
|
|
184
|
+
[FeatureFlags.PrivateRpc, 'mev-blocker'],
|
|
185
|
+
[FeatureFlags.Scantastic, 'scantastic'],
|
|
186
|
+
[FeatureFlags.SmartWalletSettings, 'smart_wallet_settings'],
|
|
187
|
+
[FeatureFlags.UwULink, 'uwu-link'],
|
|
188
|
+
])
|
|
189
|
+
|
|
190
|
+
export enum FeatureFlagClient {
|
|
191
|
+
Web = 0,
|
|
192
|
+
Wallet = 1,
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const FEATURE_FLAG_NAMES = {
|
|
196
|
+
[FeatureFlagClient.Web]: WEB_FEATURE_FLAG_NAMES,
|
|
197
|
+
[FeatureFlagClient.Wallet]: WALLET_FEATURE_FLAG_NAMES,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function getFeatureFlagName(flag: FeatureFlags, client?: FeatureFlagClient): string {
|
|
201
|
+
const names =
|
|
202
|
+
client !== undefined
|
|
203
|
+
? FEATURE_FLAG_NAMES[client]
|
|
204
|
+
: isWebApp
|
|
205
|
+
? FEATURE_FLAG_NAMES[FeatureFlagClient.Web]
|
|
206
|
+
: FEATURE_FLAG_NAMES[FeatureFlagClient.Wallet]
|
|
207
|
+
const name = names.get(flag)
|
|
208
|
+
if (!name) {
|
|
209
|
+
const err = new Error(`Feature ${FeatureFlags[flag]} does not have a name mapped for this application`)
|
|
210
|
+
|
|
211
|
+
logger.error(err, {
|
|
212
|
+
tags: {
|
|
213
|
+
file: 'flags.ts',
|
|
214
|
+
function: 'getFeatureFlagName',
|
|
215
|
+
},
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
throw err
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return name
|
|
222
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FeatureFlags } from '@l.x/gating/src/flags'
|
|
2
|
+
import { getFeatureFlag, useFeatureFlag } from '@l.x/gating/src/hooks'
|
|
3
|
+
|
|
4
|
+
function getIsHashcashSolverEnabled(): boolean {
|
|
5
|
+
return getFeatureFlag(FeatureFlags.HashcashSolverEnabled)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function useIsHashcashSolverEnabled(): boolean {
|
|
9
|
+
return useFeatureFlag(FeatureFlags.HashcashSolverEnabled)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { getIsHashcashSolverEnabled, useIsHashcashSolverEnabled }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FeatureFlags } from '@l.x/gating/src/flags'
|
|
2
|
+
import { getFeatureFlag, useFeatureFlag } from '@l.x/gating/src/hooks'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns whether sessions performance tracking is enabled.
|
|
6
|
+
*
|
|
7
|
+
* Defaults to false (disabled) - must be explicitly enabled via Statsig flag.
|
|
8
|
+
* When enabled, session analytics will include duration measurements.
|
|
9
|
+
* When disabled, duration values will be -1 (sentinel value).
|
|
10
|
+
*/
|
|
11
|
+
function getIsSessionsPerformanceTrackingEnabled(): boolean {
|
|
12
|
+
return getFeatureFlag(FeatureFlags.SessionsPerformanceTrackingEnabled)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function useIsSessionsPerformanceTrackingEnabled(): boolean {
|
|
16
|
+
return useFeatureFlag(FeatureFlags.SessionsPerformanceTrackingEnabled)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { getIsSessionsPerformanceTrackingEnabled, useIsSessionsPerformanceTrackingEnabled }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getConfig } from '@l.x/config'
|
|
2
|
+
import { FeatureFlags } from '@l.x/gating/src/flags'
|
|
3
|
+
import { getFeatureFlag, useFeatureFlag } from '@l.x/gating/src/hooks'
|
|
4
|
+
|
|
5
|
+
function getIsSessionServiceEnabled(): boolean {
|
|
6
|
+
return getConfig().enableSessionService || getFeatureFlag(FeatureFlags.SessionsServiceEnabled)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function useIsSessionServiceEnabled(): boolean {
|
|
10
|
+
const featureFlagEnabled = useFeatureFlag(FeatureFlags.SessionsServiceEnabled)
|
|
11
|
+
return getConfig().enableSessionService || featureFlagEnabled
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { getIsSessionServiceEnabled, useIsSessionServiceEnabled }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getConfig } from '@l.x/config'
|
|
2
|
+
import { FeatureFlags } from '@l.x/gating/src/flags'
|
|
3
|
+
import { getFeatureFlag } from '@l.x/gating/src/hooks'
|
|
4
|
+
|
|
5
|
+
function getIsSessionUpgradeAutoEnabled(): boolean {
|
|
6
|
+
return getConfig().enableSessionUpgradeAuto || getFeatureFlag(FeatureFlags.SessionsUpgradeAutoEnabled)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { getIsSessionUpgradeAutoEnabled }
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FeatureFlags } from '@l.x/gating/src/flags'
|
|
2
|
+
import { getFeatureFlag, useFeatureFlag } from '@l.x/gating/src/hooks'
|
|
3
|
+
|
|
4
|
+
function getIsTurnstileSolverEnabled(): boolean {
|
|
5
|
+
return getFeatureFlag(FeatureFlags.TurnstileSolverEnabled)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function useIsTurnstileSolverEnabled(): boolean {
|
|
9
|
+
return useFeatureFlag(FeatureFlags.TurnstileSolverEnabled)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { getIsTurnstileSolverEnabled, useIsTurnstileSolverEnabled }
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { isBetaEnv, isProdEnv } from 'utilities/src/environment/env'
|
|
2
|
+
import { isWebApp } from 'utilities/src/platform'
|
|
3
|
+
|
|
4
|
+
export enum StatsigEnvName {
|
|
5
|
+
Beta = 'beta', // mobile and extension environment-specific
|
|
6
|
+
Development = 'development',
|
|
7
|
+
Production = 'production',
|
|
8
|
+
Staging = 'staging', // interface (web) environment-specific
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function getStatsigEnvName(): StatsigEnvName {
|
|
12
|
+
if (isBetaEnv()) {
|
|
13
|
+
return isWebApp ? StatsigEnvName.Staging : StatsigEnvName.Beta
|
|
14
|
+
}
|
|
15
|
+
if (isProdEnv()) {
|
|
16
|
+
return StatsigEnvName.Production
|
|
17
|
+
}
|
|
18
|
+
return StatsigEnvName.Development
|
|
19
|
+
}
|
package/src/hooks.ts
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { StatsigClientEventCallback, StatsigLoadingStatus } from '@statsig/client-core'
|
|
2
|
+
import { DynamicConfigKeys } from '@l.x/gating/src/configs'
|
|
3
|
+
import { ExperimentProperties, Experiments } from '@l.x/gating/src/experiments'
|
|
4
|
+
import { FeatureFlags, getFeatureFlagName } from '@l.x/gating/src/flags'
|
|
5
|
+
import {
|
|
6
|
+
getStatsigClient,
|
|
7
|
+
TypedReturn,
|
|
8
|
+
useDynamicConfig,
|
|
9
|
+
useExperiment,
|
|
10
|
+
useFeatureGate,
|
|
11
|
+
useGateValue,
|
|
12
|
+
useLayer,
|
|
13
|
+
useStatsigClient,
|
|
14
|
+
} from '@l.x/gating/src/sdk/statsig'
|
|
15
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
16
|
+
import { logger } from 'utilities/src/logger/logger'
|
|
17
|
+
|
|
18
|
+
export function useFeatureFlag(flag: FeatureFlags): boolean {
|
|
19
|
+
const name = getFeatureFlagName(flag)
|
|
20
|
+
const value = useGateValue(name)
|
|
21
|
+
return value
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function useFeatureFlagWithLoading(flag: FeatureFlags): { value: boolean; isLoading: boolean } {
|
|
25
|
+
const { isStatsigLoading } = useStatsigClientStatus()
|
|
26
|
+
const name = getFeatureFlagName(flag)
|
|
27
|
+
const { value } = useFeatureGate(name)
|
|
28
|
+
return { value, isLoading: isStatsigLoading }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getFeatureFlag(flag: FeatureFlags): boolean {
|
|
32
|
+
try {
|
|
33
|
+
const name = getFeatureFlagName(flag)
|
|
34
|
+
return getStatsigClient().checkGate(name)
|
|
35
|
+
} catch (e) {
|
|
36
|
+
logger.debug('gating/hooks.ts', 'getFeatureFlag', JSON.stringify({ e }))
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useFeatureFlagWithExposureLoggingDisabled(flag: FeatureFlags): boolean {
|
|
42
|
+
const name = getFeatureFlagName(flag)
|
|
43
|
+
const value = useGateValue(name, { disableExposureLog: true })
|
|
44
|
+
return value
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function getFeatureFlagWithExposureLoggingDisabled(flag: FeatureFlags): boolean {
|
|
48
|
+
const name = getFeatureFlagName(flag)
|
|
49
|
+
return getStatsigClient().checkGate(name, { disableExposureLog: true })
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function useExperimentGroupNameWithLoading(experiment: Experiments): {
|
|
53
|
+
value: string | null
|
|
54
|
+
isLoading: boolean
|
|
55
|
+
} {
|
|
56
|
+
const { isStatsigLoading } = useStatsigClientStatus()
|
|
57
|
+
const statsigExperiment = useExperiment(experiment)
|
|
58
|
+
return { value: statsigExperiment.groupName, isLoading: isStatsigLoading }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function useExperimentGroupName(experiment: Experiments): string | null {
|
|
62
|
+
const { groupName } = useExperiment(experiment)
|
|
63
|
+
return groupName
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function useExperimentValue<
|
|
67
|
+
Exp extends keyof ExperimentProperties,
|
|
68
|
+
Param extends ExperimentProperties[Exp],
|
|
69
|
+
ValType,
|
|
70
|
+
>({
|
|
71
|
+
experiment,
|
|
72
|
+
param,
|
|
73
|
+
defaultValue,
|
|
74
|
+
customTypeGuard,
|
|
75
|
+
}: {
|
|
76
|
+
experiment: Exp
|
|
77
|
+
param: Param
|
|
78
|
+
defaultValue: ValType
|
|
79
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
80
|
+
}): ValType {
|
|
81
|
+
const statsigExperiment = useExperiment(experiment)
|
|
82
|
+
const value = statsigExperiment.get(param, defaultValue)
|
|
83
|
+
return checkTypeGuard({ value, defaultValue, customTypeGuard })
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function getExperimentValue<
|
|
87
|
+
Exp extends keyof ExperimentProperties,
|
|
88
|
+
Param extends ExperimentProperties[Exp],
|
|
89
|
+
ValType,
|
|
90
|
+
>({
|
|
91
|
+
experiment,
|
|
92
|
+
param,
|
|
93
|
+
defaultValue,
|
|
94
|
+
customTypeGuard,
|
|
95
|
+
}: {
|
|
96
|
+
experiment: Exp
|
|
97
|
+
param: Param
|
|
98
|
+
defaultValue: ValType
|
|
99
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
100
|
+
}): ValType {
|
|
101
|
+
const statsigExperiment = getStatsigClient().getExperiment(experiment)
|
|
102
|
+
const value = statsigExperiment.get(param, defaultValue)
|
|
103
|
+
return checkTypeGuard({ value, defaultValue, customTypeGuard })
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function useExperimentValueWithExposureLoggingDisabled<
|
|
107
|
+
Exp extends keyof ExperimentProperties,
|
|
108
|
+
Param extends ExperimentProperties[Exp],
|
|
109
|
+
ValType,
|
|
110
|
+
>({
|
|
111
|
+
experiment,
|
|
112
|
+
param,
|
|
113
|
+
defaultValue,
|
|
114
|
+
customTypeGuard,
|
|
115
|
+
}: {
|
|
116
|
+
experiment: Exp
|
|
117
|
+
param: Param
|
|
118
|
+
defaultValue: ValType
|
|
119
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
120
|
+
}): ValType {
|
|
121
|
+
const statsigExperiment = useExperiment(experiment, { disableExposureLog: true })
|
|
122
|
+
const value = statsigExperiment.get(param, defaultValue)
|
|
123
|
+
return checkTypeGuard({ value, defaultValue, customTypeGuard })
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function useDynamicConfigValue<
|
|
127
|
+
Conf extends keyof DynamicConfigKeys,
|
|
128
|
+
Key extends DynamicConfigKeys[Conf],
|
|
129
|
+
ValType,
|
|
130
|
+
>({
|
|
131
|
+
config,
|
|
132
|
+
key,
|
|
133
|
+
defaultValue,
|
|
134
|
+
customTypeGuard,
|
|
135
|
+
}: {
|
|
136
|
+
config: Conf
|
|
137
|
+
key: Key
|
|
138
|
+
defaultValue: ValType
|
|
139
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
140
|
+
}): ValType {
|
|
141
|
+
const dynamicConfig = useDynamicConfig(config)
|
|
142
|
+
const value = dynamicConfig.get(key, defaultValue)
|
|
143
|
+
return checkTypeGuard({ value, defaultValue, customTypeGuard })
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function getDynamicConfigValue<
|
|
147
|
+
Conf extends keyof DynamicConfigKeys,
|
|
148
|
+
Key extends DynamicConfigKeys[Conf],
|
|
149
|
+
ValType,
|
|
150
|
+
>({
|
|
151
|
+
config,
|
|
152
|
+
key,
|
|
153
|
+
defaultValue,
|
|
154
|
+
customTypeGuard,
|
|
155
|
+
}: {
|
|
156
|
+
config: Conf
|
|
157
|
+
key: Key
|
|
158
|
+
defaultValue: ValType
|
|
159
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
160
|
+
}): ValType {
|
|
161
|
+
const dynamicConfig = getStatsigClient().getDynamicConfig(config)
|
|
162
|
+
const value = dynamicConfig.get(key, defaultValue)
|
|
163
|
+
return checkTypeGuard({ value, defaultValue, customTypeGuard })
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function getExperimentValueFromLayer<Layer extends string, Exp extends keyof ExperimentProperties, ValType>({
|
|
167
|
+
layerName,
|
|
168
|
+
param,
|
|
169
|
+
defaultValue,
|
|
170
|
+
customTypeGuard,
|
|
171
|
+
}: {
|
|
172
|
+
layerName: Layer
|
|
173
|
+
param: ExperimentProperties[Exp]
|
|
174
|
+
defaultValue: ValType
|
|
175
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
176
|
+
}): ValType {
|
|
177
|
+
const layer = getStatsigClient().getLayer(layerName)
|
|
178
|
+
const value = layer.get(param, defaultValue)
|
|
179
|
+
// we directly get param from layer; these are spread from experiments
|
|
180
|
+
return checkTypeGuard({ value, defaultValue, customTypeGuard })
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function useExperimentValueFromLayer<Layer extends string, Exp extends keyof ExperimentProperties, ValType>({
|
|
184
|
+
layerName,
|
|
185
|
+
param,
|
|
186
|
+
defaultValue,
|
|
187
|
+
customTypeGuard,
|
|
188
|
+
}: {
|
|
189
|
+
layerName: Layer
|
|
190
|
+
param: ExperimentProperties[Exp]
|
|
191
|
+
defaultValue: ValType
|
|
192
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
193
|
+
}): ValType {
|
|
194
|
+
const layer = useLayer(layerName)
|
|
195
|
+
const value = layer.get(param, defaultValue)
|
|
196
|
+
// we directly get param from layer; these are spread from experiments
|
|
197
|
+
return checkTypeGuard({ value, defaultValue, customTypeGuard })
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function checkTypeGuard<ValType>({
|
|
201
|
+
value,
|
|
202
|
+
defaultValue,
|
|
203
|
+
customTypeGuard,
|
|
204
|
+
}: {
|
|
205
|
+
value: TypedReturn<ValType>
|
|
206
|
+
defaultValue: ValType
|
|
207
|
+
customTypeGuard?: (x: unknown) => x is ValType
|
|
208
|
+
}): ValType {
|
|
209
|
+
const isOfDefaultValueType = (val: unknown): val is ValType => typeof val === typeof defaultValue
|
|
210
|
+
|
|
211
|
+
if (customTypeGuard?.(value) || isOfDefaultValueType(value)) {
|
|
212
|
+
return value
|
|
213
|
+
} else {
|
|
214
|
+
return defaultValue
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function useStatsigClientStatus(): {
|
|
219
|
+
isStatsigLoading: boolean
|
|
220
|
+
isStatsigReady: boolean
|
|
221
|
+
isStatsigUninitialized: boolean
|
|
222
|
+
} {
|
|
223
|
+
const { client } = useStatsigClient()
|
|
224
|
+
const [statsigStatus, setStatsigStatus] = useState<StatsigLoadingStatus>(client.loadingStatus)
|
|
225
|
+
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
const handler: StatsigClientEventCallback<'values_updated'> = (event) => {
|
|
228
|
+
setStatsigStatus(event.status)
|
|
229
|
+
}
|
|
230
|
+
client.on('values_updated', handler)
|
|
231
|
+
return () => {
|
|
232
|
+
client.off('values_updated', handler)
|
|
233
|
+
}
|
|
234
|
+
}, [client])
|
|
235
|
+
|
|
236
|
+
return useMemo(
|
|
237
|
+
() => ({
|
|
238
|
+
isStatsigLoading: statsigStatus === 'Loading',
|
|
239
|
+
isStatsigReady: statsigStatus === 'Ready',
|
|
240
|
+
isStatsigUninitialized: statsigStatus === 'Uninitialized',
|
|
241
|
+
}),
|
|
242
|
+
[statsigStatus],
|
|
243
|
+
)
|
|
244
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
DatadogIgnoredErrorsValType,
|
|
3
|
+
DatadogSessionSampleRateValType,
|
|
4
|
+
DynamicConfigKeys,
|
|
5
|
+
ForceUpgradeStatus,
|
|
6
|
+
ForceUpgradeTranslations,
|
|
7
|
+
GasStrategies,
|
|
8
|
+
GasStrategyType,
|
|
9
|
+
GasStrategyWithConditions,
|
|
10
|
+
UwULinkAllowlist,
|
|
11
|
+
UwULinkAllowlistItem,
|
|
12
|
+
} from '@l.x/gating/src/configs'
|
|
13
|
+
export {
|
|
14
|
+
AllowedV4WethHookAddressesConfigKey,
|
|
15
|
+
BlockedAsyncSubmissionChainIdsConfigKey,
|
|
16
|
+
ChainsConfigKey,
|
|
17
|
+
CreateAuctionConfigKey,
|
|
18
|
+
DatadogIgnoredErrorsConfigKey,
|
|
19
|
+
DatadogSessionSampleRateKey,
|
|
20
|
+
DynamicConfigs,
|
|
21
|
+
EmbeddedWalletBetaPassphrasesKey,
|
|
22
|
+
EmbeddedWalletConfigKey,
|
|
23
|
+
ExtensionBiometricUnlockConfigKey,
|
|
24
|
+
ExternallyConnectableExtensionConfigKey,
|
|
25
|
+
ForceUpgradeConfigKey,
|
|
26
|
+
HomeScreenExploreTokensConfigKey,
|
|
27
|
+
LPConfigKey,
|
|
28
|
+
NetworkRequestsConfigKey,
|
|
29
|
+
OnDeviceRecoveryConfigKey,
|
|
30
|
+
OutageBannerChainIdConfigKey,
|
|
31
|
+
SwapConfigKey,
|
|
32
|
+
SyncTransactionSubmissionChainIdsConfigKey,
|
|
33
|
+
UwuLinkConfigKey,
|
|
34
|
+
VerifiedAuctionsConfigKey,
|
|
35
|
+
} from '@l.x/gating/src/configs'
|
|
36
|
+
export { StatsigCustomAppValue } from '@l.x/gating/src/constants'
|
|
37
|
+
export type { ExperimentProperties } from '@l.x/gating/src/experiments'
|
|
38
|
+
export {
|
|
39
|
+
EthAsErc20DEXProperties,
|
|
40
|
+
Experiments,
|
|
41
|
+
ExploreBackendSortingProperties,
|
|
42
|
+
LayerProperties,
|
|
43
|
+
Layers,
|
|
44
|
+
NativeTokenPercentageBufferProperties,
|
|
45
|
+
PrivateRpcProperties,
|
|
46
|
+
UnichainFlashblocksProperties,
|
|
47
|
+
} from '@l.x/gating/src/experiments'
|
|
48
|
+
export {
|
|
49
|
+
FeatureFlagClient,
|
|
50
|
+
FeatureFlags,
|
|
51
|
+
getFeatureFlagName,
|
|
52
|
+
WALLET_FEATURE_FLAG_NAMES,
|
|
53
|
+
WEB_FEATURE_FLAG_NAMES,
|
|
54
|
+
} from '@l.x/gating/src/flags'
|
|
55
|
+
export { getIsHashcashSolverEnabled, useIsHashcashSolverEnabled } from '@l.x/gating/src/getIsHashcashSolverEnabled'
|
|
56
|
+
export {
|
|
57
|
+
getIsSessionsPerformanceTrackingEnabled,
|
|
58
|
+
useIsSessionsPerformanceTrackingEnabled,
|
|
59
|
+
} from '@l.x/gating/src/getIsPerformanceTrackingEnabled'
|
|
60
|
+
export { getIsSessionServiceEnabled, useIsSessionServiceEnabled } from '@l.x/gating/src/getIsSessionServiceEnabled'
|
|
61
|
+
export { getIsSessionUpgradeAutoEnabled } from '@l.x/gating/src/getIsSessionUpgradeAutoEnabled'
|
|
62
|
+
export {
|
|
63
|
+
getIsTurnstileSolverEnabled,
|
|
64
|
+
useIsTurnstileSolverEnabled,
|
|
65
|
+
} from '@l.x/gating/src/getIsTurnstileSolverEnabled'
|
|
66
|
+
export { getStatsigEnvName } from '@l.x/gating/src/getStatsigEnvName'
|
|
67
|
+
export {
|
|
68
|
+
getDynamicConfigValue,
|
|
69
|
+
getExperimentValue,
|
|
70
|
+
getExperimentValueFromLayer,
|
|
71
|
+
getFeatureFlag,
|
|
72
|
+
useDynamicConfigValue,
|
|
73
|
+
useExperimentValue,
|
|
74
|
+
useExperimentValueFromLayer,
|
|
75
|
+
useExperimentValueWithExposureLoggingDisabled,
|
|
76
|
+
useFeatureFlag,
|
|
77
|
+
useFeatureFlagWithExposureLoggingDisabled,
|
|
78
|
+
useFeatureFlagWithLoading,
|
|
79
|
+
useStatsigClientStatus,
|
|
80
|
+
} from '@l.x/gating/src/hooks'
|
|
81
|
+
export { LocalOverrideAdapterWrapper } from '@l.x/gating/src/LocalOverrideAdapterWrapper'
|
|
82
|
+
export type {
|
|
83
|
+
StatsigOptions,
|
|
84
|
+
StatsigUser,
|
|
85
|
+
StorageProvider,
|
|
86
|
+
} from '@l.x/gating/src/sdk/statsig'
|
|
87
|
+
export {
|
|
88
|
+
getOverrideAdapter,
|
|
89
|
+
getStatsigClient,
|
|
90
|
+
StatsigClient,
|
|
91
|
+
StatsigContext,
|
|
92
|
+
StatsigProvider,
|
|
93
|
+
Storage,
|
|
94
|
+
useClientAsyncInit,
|
|
95
|
+
useExperiment,
|
|
96
|
+
useGateValue,
|
|
97
|
+
useLayer,
|
|
98
|
+
} from '@l.x/gating/src/sdk/statsig'
|
|
99
|
+
export { getOverrides } from '@l.x/gating/src/utils'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type StatsigClient } from '@statsig/react-bindings'
|
|
2
|
+
import { StatsigClientRN } from '@statsig/react-native-bindings'
|
|
3
|
+
import { getConfig } from '@l.x/config'
|
|
4
|
+
import { LocalOverrideAdapterWrapper } from '@l.x/gating/src/LocalOverrideAdapterWrapper'
|
|
5
|
+
|
|
6
|
+
const config = getConfig()
|
|
7
|
+
|
|
8
|
+
export type { StatsigOptions, StatsigUser, StorageProvider, TypedReturn } from '@statsig/react-native-bindings'
|
|
9
|
+
export {
|
|
10
|
+
StatsigClient,
|
|
11
|
+
StatsigContext,
|
|
12
|
+
StatsigProviderRN as StatsigProvider,
|
|
13
|
+
Storage,
|
|
14
|
+
useClientAsyncInitRN as useClientAsyncInit,
|
|
15
|
+
useDynamicConfig,
|
|
16
|
+
useExperiment,
|
|
17
|
+
useFeatureGate,
|
|
18
|
+
useGateValue,
|
|
19
|
+
useLayer,
|
|
20
|
+
useStatsigClient,
|
|
21
|
+
useStatsigUser,
|
|
22
|
+
} from '@statsig/react-native-bindings'
|
|
23
|
+
|
|
24
|
+
let localOverrideAdapter: LocalOverrideAdapterWrapper | undefined
|
|
25
|
+
|
|
26
|
+
export const getOverrideAdapter = (): LocalOverrideAdapterWrapper => {
|
|
27
|
+
if (!localOverrideAdapter) {
|
|
28
|
+
localOverrideAdapter = new LocalOverrideAdapterWrapper(config.statsigApiKey)
|
|
29
|
+
}
|
|
30
|
+
return localOverrideAdapter
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const getStatsigClient = (): StatsigClient => StatsigClientRN.instance(config.statsigApiKey)
|