@luxexchange/gating 1.0.0
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 +38 -0
- package/project.json +18 -0
- package/src/LocalOverrideAdapterWrapper.ts +63 -0
- package/src/configs.ts +289 -0
- package/src/constants.ts +4 -0
- package/src/experiments.ts +90 -0
- package/src/flags.ts +234 -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 +97 -0
- package/src/sdk/statsig.native.ts +33 -0
- package/src/sdk/statsig.ts +44 -0
- package/src/utils.ts +24 -0
- package/tsconfig.json +22 -0
- package/tsconfig.lint.json +8 -0
package/.depcheckrc
ADDED
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
extends: ['@luxfi/eslint-config/lib'],
|
|
3
|
+
parserOptions: {
|
|
4
|
+
tsconfigRootDir: __dirname,
|
|
5
|
+
},
|
|
6
|
+
overrides: [
|
|
7
|
+
{
|
|
8
|
+
files: ['*.ts', '*.tsx'],
|
|
9
|
+
rules: {
|
|
10
|
+
'no-relative-import-paths/no-relative-import-paths': [
|
|
11
|
+
'error',
|
|
12
|
+
{
|
|
13
|
+
allowSameFolder: false,
|
|
14
|
+
prefix: '@luxfi/gating',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
'@typescript-eslint/prefer-enum-initializers': 'off',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
}
|
package/README.md
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@luxexchange/gating",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"@statsig/client-core": "3.12.2",
|
|
6
|
+
"@statsig/js-client": "3.12.2",
|
|
7
|
+
"@statsig/js-local-overrides": "3.12.2",
|
|
8
|
+
"@statsig/react-bindings": "3.12.2",
|
|
9
|
+
"@statsig/react-native-bindings": "3.12.2",
|
|
10
|
+
"@luxexchange/api": "^1.0.0",
|
|
11
|
+
"@luxfi/utilities": "^1.0.0"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "22.13.1",
|
|
15
|
+
"@typescript/native-preview": "7.0.0-dev.20260108.1",
|
|
16
|
+
"@luxfi/eslint-config": "^1.0.0",
|
|
17
|
+
"depcheck": "1.4.7",
|
|
18
|
+
"eslint": "8.57.1",
|
|
19
|
+
"typescript": "5.8.3"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"typecheck": "nx typecheck gating",
|
|
23
|
+
"typecheck:tsgo": "nx typecheck:tsgo gating",
|
|
24
|
+
"lint": "nx lint gating",
|
|
25
|
+
"lint:fix": "nx lint:fix gating",
|
|
26
|
+
"lint:biome": "nx lint:biome gating",
|
|
27
|
+
"lint:biome:fix": "nx lint:biome:fix gating",
|
|
28
|
+
"lint:eslint": "nx lint:eslint gating",
|
|
29
|
+
"lint:eslint:fix": "nx lint:eslint:fix gating",
|
|
30
|
+
"check:deps:usage": "nx check:deps:usage gating"
|
|
31
|
+
},
|
|
32
|
+
"nx": {
|
|
33
|
+
"includedScripts": []
|
|
34
|
+
},
|
|
35
|
+
"main": "src/index.ts",
|
|
36
|
+
"private": false,
|
|
37
|
+
"sideEffects": false
|
|
38
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@luxfi/gating",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "pkgs/gating/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": ["scope:gating", "type:lib"],
|
|
7
|
+
"targets": {
|
|
8
|
+
"typecheck": {},
|
|
9
|
+
"typecheck:tsgo": {},
|
|
10
|
+
"lint:biome": {},
|
|
11
|
+
"lint:biome:fix": {},
|
|
12
|
+
"lint:eslint": {},
|
|
13
|
+
"lint:eslint:fix": {},
|
|
14
|
+
"lint": {},
|
|
15
|
+
"lint:fix": {},
|
|
16
|
+
"check:deps:usage": {}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { LocalOverrideAdapter } from '@statsig/js-local-overrides'
|
|
2
|
+
import { getStatsigClient } from '@luxfi/gating/src/sdk/statsig'
|
|
3
|
+
|
|
4
|
+
// Workaround for @statsig 3.x.x refreshing client after applying overrides to get the result without reloading
|
|
5
|
+
// Should be removed after statsig add real time override apply functionality
|
|
6
|
+
// Adds refresh only to used LocalOverrideAdapter methods. Other methods need to be added if refresh is required.
|
|
7
|
+
export class LocalOverrideAdapterWrapper extends LocalOverrideAdapter {
|
|
8
|
+
constructor(sdkKey: string) {
|
|
9
|
+
super(sdkKey)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
refreshStatsig(): void {
|
|
13
|
+
const statsigClient = getStatsigClient()
|
|
14
|
+
const statsigUser = statsigClient.getContext().user
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
16
|
+
statsigClient.updateUserAsync(statsigUser)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
overrideGate(name: string, value: boolean): void {
|
|
20
|
+
super.overrideGate(name, value)
|
|
21
|
+
this.refreshStatsig()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
removeGateOverride(name: string): void {
|
|
25
|
+
super.removeGateOverride(name)
|
|
26
|
+
this.refreshStatsig()
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
overrideDynamicConfig(name: string, value: Record<string, unknown>): void {
|
|
30
|
+
super.overrideDynamicConfig(name, value)
|
|
31
|
+
this.refreshStatsig()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
removeDynamicConfigOverride(name: string): void {
|
|
35
|
+
super.removeDynamicConfigOverride(name)
|
|
36
|
+
this.refreshStatsig()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
removeAllOverrides(): void {
|
|
40
|
+
super.removeAllOverrides()
|
|
41
|
+
this.refreshStatsig()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
removeExperimentOverride(name: string): void {
|
|
45
|
+
super.removeExperimentOverride(name)
|
|
46
|
+
this.refreshStatsig()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
overrideExperiment(name: string, value: Record<string, unknown>): void {
|
|
50
|
+
super.overrideExperiment(name, value)
|
|
51
|
+
this.refreshStatsig()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
overrideLayer(name: string, value: Record<string, unknown>): void {
|
|
55
|
+
super.overrideLayer(name, value)
|
|
56
|
+
this.refreshStatsig()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
removeLayerOverride(name: string): void {
|
|
60
|
+
super.removeLayerOverride(name)
|
|
61
|
+
this.refreshStatsig()
|
|
62
|
+
}
|
|
63
|
+
}
|
package/src/configs.ts
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { GasStrategy } from '@luxfi/api'
|
|
2
|
+
|
|
3
|
+
// TODO: move to own package
|
|
4
|
+
export enum Locale {
|
|
5
|
+
Afrikaans = 'af-ZA',
|
|
6
|
+
ArabicSaudi = 'ar-SA',
|
|
7
|
+
Catalan = 'ca-ES',
|
|
8
|
+
ChineseSimplified = 'zh-Hans',
|
|
9
|
+
ChineseTraditional = 'zh-Hant',
|
|
10
|
+
CzechCzechia = 'cs-CZ',
|
|
11
|
+
DanishDenmark = 'da-DK',
|
|
12
|
+
DutchNetherlands = 'nl-NL',
|
|
13
|
+
EnglishUnitedStates = 'en-US',
|
|
14
|
+
FinnishFinland = 'fi-FI',
|
|
15
|
+
FrenchFrance = 'fr-FR',
|
|
16
|
+
GreekGreece = 'el-GR',
|
|
17
|
+
HebrewIsrael = 'he-IL',
|
|
18
|
+
HindiIndia = 'hi-IN',
|
|
19
|
+
HungarianHungarian = 'hu-HU',
|
|
20
|
+
IndonesianIndonesia = 'id-ID',
|
|
21
|
+
ItalianItaly = 'it-IT',
|
|
22
|
+
JapaneseJapan = 'ja-JP',
|
|
23
|
+
KoreanKorea = 'ko-KR',
|
|
24
|
+
MalayMalaysia = 'ms-MY',
|
|
25
|
+
NorwegianNorway = 'no-NO',
|
|
26
|
+
PolishPoland = 'pl-PL',
|
|
27
|
+
PortugueseBrazil = 'pt-BR',
|
|
28
|
+
PortuguesePortugal = 'pt-PT',
|
|
29
|
+
RomanianRomania = 'ro-RO',
|
|
30
|
+
RussianRussia = 'ru-RU',
|
|
31
|
+
Serbian = 'sr-SP',
|
|
32
|
+
SpanishLatam = 'es-419',
|
|
33
|
+
SpanishBelize = 'es-BZ',
|
|
34
|
+
SpanishCuba = 'es-CU',
|
|
35
|
+
SpanishDominicanRepublic = 'es-DO',
|
|
36
|
+
SpanishGuatemala = 'es-GT',
|
|
37
|
+
SpanishHonduras = 'es-HN',
|
|
38
|
+
SpanishMexico = 'es-MX',
|
|
39
|
+
SpanishNicaragua = 'es-NI',
|
|
40
|
+
SpanishPanama = 'es-PA',
|
|
41
|
+
SpanishPeru = 'es-PE',
|
|
42
|
+
SpanishPuertoRico = 'es-PR',
|
|
43
|
+
SpanishElSalvador = 'es-SV',
|
|
44
|
+
SpanishUnitedStates = 'es-US',
|
|
45
|
+
SpanishArgentina = 'es-AR',
|
|
46
|
+
SpanishBolivia = 'es-BO',
|
|
47
|
+
SpanishChile = 'es-CL',
|
|
48
|
+
SpanishColombia = 'es-CO',
|
|
49
|
+
SpanishCostaRica = 'es-CR',
|
|
50
|
+
SpanishEcuador = 'es-EC',
|
|
51
|
+
SpanishSpain = 'es-ES',
|
|
52
|
+
SpanishParaguay = 'es-PY',
|
|
53
|
+
SpanishUruguay = 'es-UY',
|
|
54
|
+
SpanishVenezuela = 'es-VE',
|
|
55
|
+
SwahiliTanzania = 'sw-TZ',
|
|
56
|
+
SwedishSweden = 'sv-SE',
|
|
57
|
+
TurkishTurkey = 'tr-TR',
|
|
58
|
+
UkrainianUkraine = 'uk-UA',
|
|
59
|
+
UrduPakistan = 'ur-PK',
|
|
60
|
+
VietnameseVietnam = 'vi-VN',
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Dynamic Configs
|
|
65
|
+
* These should match the dynamic config's `Config Name` on Statsig
|
|
66
|
+
*/
|
|
67
|
+
export enum DynamicConfigs {
|
|
68
|
+
// Shared
|
|
69
|
+
Swap = 'swap_config',
|
|
70
|
+
NetworkRequests = 'network_requests',
|
|
71
|
+
Chains = 'chains',
|
|
72
|
+
SyncTransactionSubmissionChainIds = 'sync_transaction_submission_chain_ids',
|
|
73
|
+
BlockedAsyncSubmissionChainIds = 'blocked_async_submission_chain_ids',
|
|
74
|
+
|
|
75
|
+
// Wallet
|
|
76
|
+
HomeScreenExploreTokens = 'home_screen_explore_tokens',
|
|
77
|
+
ForceUpgrade = 'force_upgrade',
|
|
78
|
+
OnDeviceRecovery = 'on_device_recovery',
|
|
79
|
+
UwuLink = 'uwulink_config',
|
|
80
|
+
GasStrategies = 'gas_strategy',
|
|
81
|
+
DatadogSessionSampleRate = 'datadog_session_sample_rate',
|
|
82
|
+
DatadogIgnoredErrors = 'datadog_ignored_errors',
|
|
83
|
+
EmbeddedWalletConfig = 'embedded_wallet_config',
|
|
84
|
+
ExtensionBiometricUnlock = 'extension_biometric_unlock_config',
|
|
85
|
+
|
|
86
|
+
// Web
|
|
87
|
+
AstroChain = 'astro_chain',
|
|
88
|
+
BlockedNftCollections = 'blocked_nft_collections',
|
|
89
|
+
ExternallyConnectableExtension = 'externally_connectable_extension',
|
|
90
|
+
LPConfig = 'lp_config',
|
|
91
|
+
AllowedV4WethHookAddresses = 'allowed_v4_weth_hook_addresses',
|
|
92
|
+
OutageBannerChainId = 'outage_banner_chain_id',
|
|
93
|
+
VerifiedAuctions = 'verified_auctions',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Config values go here for easy access
|
|
97
|
+
|
|
98
|
+
// Shared
|
|
99
|
+
export enum SwapConfigKey {
|
|
100
|
+
AverageL1BlockTimeMs = 'averageL1BlockTimeMs',
|
|
101
|
+
AverageL2BlockTimeMs = 'averageL2BlockTimeMs',
|
|
102
|
+
TradingApiSwapRequestMs = 'tradingApiSwapRequestMs',
|
|
103
|
+
|
|
104
|
+
MinAutoSlippageToleranceL2 = 'minAutoSlippageToleranceL2',
|
|
105
|
+
|
|
106
|
+
EthSwapMinGasAmount = 'ethSwapMinGasAmount',
|
|
107
|
+
EthSendMinGasAmount = 'ethSendMinGasAmount',
|
|
108
|
+
PolygonSwapMinGasAmount = 'polygonSwapMinGasAmount',
|
|
109
|
+
PolygonSendMinGasAmount = 'polygonSendMinGasAmount',
|
|
110
|
+
AvalancheSwapMinGasAmount = 'avalancheSwapMinGasAmount',
|
|
111
|
+
AvalancheSendMinGasAmount = 'avalancheSendMinGasAmount',
|
|
112
|
+
CeloSwapMinGasAmount = 'celoSwapMinGasAmount',
|
|
113
|
+
CeloSendMinGasAmount = 'celoSendMinGasAmount',
|
|
114
|
+
MonSwapMinGasAmount = 'monSwapMinGasAmount',
|
|
115
|
+
MonSendMinGasAmount = 'monSendMinGasAmount',
|
|
116
|
+
SolanaSwapMinGasAmount = 'solanaSwapMinGasAmount',
|
|
117
|
+
SolanaSendMinGasAmount = 'solanaSendMinGasAmount',
|
|
118
|
+
GenericL2SwapMinGasAmount = 'genericL2SwapMinGasAmount',
|
|
119
|
+
GenericL2SendMinGasAmount = 'genericL2SendMinGasAmount',
|
|
120
|
+
|
|
121
|
+
LowBalanceWarningGasPercentage = 'lowBalanceWarningGasPercentage',
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export enum NetworkRequestsConfigKey {
|
|
125
|
+
BalanceMaxRefetchAttempts = 'balanceMaxRefetchAttempts',
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export enum ChainsConfigKey {
|
|
129
|
+
OrderedChainIds = 'orderedChainIds',
|
|
130
|
+
NewChainIds = 'newChainIds',
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Wallet
|
|
134
|
+
export enum ForceUpgradeConfigKey {
|
|
135
|
+
Status = 'status',
|
|
136
|
+
Translations = 'translations',
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export type ForceUpgradeStatus = 'recommended' | 'required' | 'not-required'
|
|
140
|
+
|
|
141
|
+
type SupportedLocale = `${Extract<Locale[keyof Locale], string>}`
|
|
142
|
+
|
|
143
|
+
type ContentMessage = {
|
|
144
|
+
title: string
|
|
145
|
+
description: string
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export type ForceUpgradeTranslations = Record<SupportedLocale, ContentMessage>
|
|
149
|
+
|
|
150
|
+
export enum EmbeddedWalletConfigKey {
|
|
151
|
+
BaseUrl = 'baseUrl',
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export enum ExtensionBiometricUnlockConfigKey {
|
|
155
|
+
EnableOnboardingEnrollment = 'enableOnboardingEnrollment',
|
|
156
|
+
EnableSettingsEnrollment = 'enableSettingsEnrollment',
|
|
157
|
+
EnableUnlocking = 'enableUnlocking',
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export enum SyncTransactionSubmissionChainIdsConfigKey {
|
|
161
|
+
ChainIds = 'chainIds',
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export enum BlockedAsyncSubmissionChainIdsConfigKey {
|
|
165
|
+
ChainIds = 'chainIds',
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export enum HomeScreenExploreTokensConfigKey {
|
|
169
|
+
EthChainId = 'ethChainId',
|
|
170
|
+
Tokens = 'tokens',
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export enum OnDeviceRecoveryConfigKey {
|
|
174
|
+
AppLoadingTimeoutMs = 'appLoadingTimeoutMs',
|
|
175
|
+
MaxMnemonicsToLoad = 'maxMnemonicsToLoad',
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export enum UwuLinkConfigKey {
|
|
179
|
+
Allowlist = 'allowlist',
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export enum DatadogIgnoredErrorsConfigKey {
|
|
183
|
+
Errors = 'errors',
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export enum DatadogSessionSampleRateKey {
|
|
187
|
+
Rate = 'rate',
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export enum BlockedNftCollectionsConfigKey {
|
|
191
|
+
BlocklistedCollections = 'blocklistedCollections',
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export enum ExternallyConnectableExtensionConfigKey {
|
|
195
|
+
ExtensionId = 'extensionId',
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export type DatadogIgnoredErrorsValType = Array<{ messageContains: string; sampleRate: number }>
|
|
199
|
+
|
|
200
|
+
export type DatadogSessionSampleRateValType = number
|
|
201
|
+
|
|
202
|
+
export type GasStrategyType = 'general' | 'swap'
|
|
203
|
+
|
|
204
|
+
export type GasStrategyConditions = {
|
|
205
|
+
name: string
|
|
206
|
+
chainId: number
|
|
207
|
+
types: GasStrategyType
|
|
208
|
+
isActive: boolean
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export type GasStrategyWithConditions = {
|
|
212
|
+
strategy: GasStrategy
|
|
213
|
+
conditions: GasStrategyConditions
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export type GasStrategies = {
|
|
217
|
+
strategies: GasStrategyWithConditions[]
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Web
|
|
221
|
+
export enum QuickRouteChainsConfigKey {
|
|
222
|
+
Chains = 'quick_route_chains',
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export enum AstroChainConfigKey {
|
|
226
|
+
Url = 'url',
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export enum LPConfigKey {
|
|
230
|
+
DefaultSlippage = 'defaultSlippage',
|
|
231
|
+
V4SlippageOverride = 'v4SlippageOverride',
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export enum AllowedV4WethHookAddressesConfigKey {
|
|
235
|
+
HookAddresses = 'hookAddresses',
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export enum VerifiedAuctionsConfigKey {
|
|
239
|
+
VerifiedAuctionIds = 'verifiedAuctionIds',
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export enum OutageBannerChainIdConfigKey {
|
|
243
|
+
ChainId = 'chainId',
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export type DynamicConfigKeys = {
|
|
247
|
+
// Shared
|
|
248
|
+
[DynamicConfigs.Swap]: SwapConfigKey
|
|
249
|
+
[DynamicConfigs.NetworkRequests]: NetworkRequestsConfigKey
|
|
250
|
+
[DynamicConfigs.Chains]: ChainsConfigKey
|
|
251
|
+
|
|
252
|
+
// Wallet
|
|
253
|
+
[DynamicConfigs.HomeScreenExploreTokens]: HomeScreenExploreTokensConfigKey
|
|
254
|
+
[DynamicConfigs.ForceUpgrade]: ForceUpgradeConfigKey
|
|
255
|
+
[DynamicConfigs.OnDeviceRecovery]: OnDeviceRecoveryConfigKey
|
|
256
|
+
[DynamicConfigs.UwuLink]: UwuLinkConfigKey
|
|
257
|
+
[DynamicConfigs.DatadogIgnoredErrors]: DatadogIgnoredErrorsConfigKey
|
|
258
|
+
[DynamicConfigs.DatadogSessionSampleRate]: DatadogSessionSampleRateKey
|
|
259
|
+
[DynamicConfigs.EmbeddedWalletConfig]: EmbeddedWalletConfigKey
|
|
260
|
+
[DynamicConfigs.ExtensionBiometricUnlock]: ExtensionBiometricUnlockConfigKey
|
|
261
|
+
[DynamicConfigs.SyncTransactionSubmissionChainIds]: SyncTransactionSubmissionChainIdsConfigKey
|
|
262
|
+
|
|
263
|
+
// Web
|
|
264
|
+
[DynamicConfigs.AstroChain]: AstroChainConfigKey
|
|
265
|
+
[DynamicConfigs.BlockedNftCollections]: BlockedNftCollectionsConfigKey
|
|
266
|
+
[DynamicConfigs.ExternallyConnectableExtension]: ExternallyConnectableExtensionConfigKey
|
|
267
|
+
[DynamicConfigs.LPConfig]: LPConfigKey
|
|
268
|
+
[DynamicConfigs.AllowedV4WethHookAddresses]: AllowedV4WethHookAddressesConfigKey
|
|
269
|
+
[DynamicConfigs.VerifiedAuctions]: VerifiedAuctionsConfigKey
|
|
270
|
+
[DynamicConfigs.BlockedAsyncSubmissionChainIds]: BlockedAsyncSubmissionChainIdsConfigKey
|
|
271
|
+
[DynamicConfigs.OutageBannerChainId]: OutageBannerChainIdConfigKey
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// This type must match the format in statsig dynamic config for uwulink
|
|
275
|
+
// https://console.statsig.com/5HjUux4OvSGzgqWIfKFt8i/dynamic_configs/uwulink_config
|
|
276
|
+
export type UwULinkAllowlistItem = {
|
|
277
|
+
chainId: number
|
|
278
|
+
address: string
|
|
279
|
+
name: string
|
|
280
|
+
logo?: {
|
|
281
|
+
dark?: string
|
|
282
|
+
light?: string
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export type UwULinkAllowlist = {
|
|
287
|
+
contracts: UwULinkAllowlistItem[]
|
|
288
|
+
tokenRecipients: UwULinkAllowlistItem[]
|
|
289
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Experiment parameter names. Ordered alphabetically.
|
|
3
|
+
*
|
|
4
|
+
* These must match parameter names on Statsig within an experiment
|
|
5
|
+
*/
|
|
6
|
+
export enum Experiments {
|
|
7
|
+
EthAsErc20DEX = 'eth_as_erc20_luxx_experiment',
|
|
8
|
+
ExploreBackendSorting = 'explore_backend_sorting',
|
|
9
|
+
NativeTokenPercentageBuffer = 'lp_native_buffer',
|
|
10
|
+
PriceUxUpdate = 'price_ux_update',
|
|
11
|
+
PrivateRpc = 'private_rpc',
|
|
12
|
+
SwapConfirmation = 'swap-confirmation',
|
|
13
|
+
UnichainFlashblocksModal = 'unichain_flashblocks_modal',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum Layers {
|
|
17
|
+
ExplorePage = 'explore-page',
|
|
18
|
+
SwapPage = 'swap-page',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// experiment groups
|
|
22
|
+
|
|
23
|
+
export enum NativeTokenPercentageBufferExperimentGroup {
|
|
24
|
+
Control = 'Control',
|
|
25
|
+
Buffer1 = 'Buffer1',
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// experiment properties
|
|
29
|
+
|
|
30
|
+
export enum ArbitrumXV2SamplingProperties {
|
|
31
|
+
RoutingType = 'routingType',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export enum PrivateRpcProperties {
|
|
35
|
+
FlashbotsEnabled = 'flashbots_enabled',
|
|
36
|
+
RefundPercent = 'refund_percent',
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export enum NativeTokenPercentageBufferProperties {
|
|
40
|
+
BufferSize = 'bufferSize',
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export enum SwapConfirmationProperties {
|
|
44
|
+
WaitTimes = 'wait_times',
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export enum ExploreBackendSortingProperties {
|
|
48
|
+
BackendSortingEnabled = 'backendSortingEnabled',
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Swap Layer experiment properties
|
|
52
|
+
|
|
53
|
+
export enum SwapLayerProperties {
|
|
54
|
+
UpdatedPriceUX = 'updatedPriceUX',
|
|
55
|
+
FlashblocksModalEnabled = 'flashblocksModalEnabled',
|
|
56
|
+
EthAsErc20DEXEnabled = 'ethAsErc20DEXEnabled',
|
|
57
|
+
MinEthErc20USDValueThresholdByChain = 'minEthErc20USDValueThresholdByChain',
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export enum PriceUxUpdateProperties {
|
|
61
|
+
UpdatedPriceUX = SwapLayerProperties.UpdatedPriceUX,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export enum UnichainFlashblocksProperties {
|
|
65
|
+
FlashblocksModalEnabled = SwapLayerProperties.FlashblocksModalEnabled,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export enum EthAsErc20DEXProperties {
|
|
69
|
+
EthAsErc20DEXEnabled = SwapLayerProperties.EthAsErc20DEXEnabled,
|
|
70
|
+
MinEthErc20USDValueThresholdByChain = SwapLayerProperties.MinEthErc20USDValueThresholdByChain,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Ordered alphabetically.
|
|
74
|
+
export type ExperimentProperties = {
|
|
75
|
+
[Experiments.EthAsErc20DEX]: EthAsErc20DEXProperties
|
|
76
|
+
[Experiments.ExploreBackendSorting]: ExploreBackendSortingProperties
|
|
77
|
+
[Experiments.NativeTokenPercentageBuffer]: NativeTokenPercentageBufferProperties
|
|
78
|
+
[Experiments.PriceUxUpdate]: PriceUxUpdateProperties
|
|
79
|
+
[Experiments.PrivateRpc]: PrivateRpcProperties
|
|
80
|
+
[Experiments.SwapConfirmation]: SwapConfirmationProperties
|
|
81
|
+
[Experiments.UnichainFlashblocksModal]: UnichainFlashblocksProperties
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// will be a spread of all experiment properties in that layer
|
|
85
|
+
export const LayerProperties: Record<Layers, string[]> = {
|
|
86
|
+
[Layers.ExplorePage]: Object.values({
|
|
87
|
+
...ExploreBackendSortingProperties,
|
|
88
|
+
}),
|
|
89
|
+
[Layers.SwapPage]: Object.values(SwapLayerProperties),
|
|
90
|
+
}
|
package/src/flags.ts
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { logger } from '@luxfi/utilities/src/logger/logger'
|
|
2
|
+
import { isWebApp } from '@luxfi/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
|
+
BridgedAssetsBannerV2,
|
|
16
|
+
CentralizedPrices,
|
|
17
|
+
ChainedActions,
|
|
18
|
+
DisableSwap7702,
|
|
19
|
+
DisableSessionsForPlan,
|
|
20
|
+
EmbeddedWallet,
|
|
21
|
+
EnablePermitMismatchUX,
|
|
22
|
+
ForceDisableWalletGetCapabilities,
|
|
23
|
+
ForcePermitTransactions,
|
|
24
|
+
ForSessionsEnabled,
|
|
25
|
+
ForUrlMigration,
|
|
26
|
+
HashcashSolverEnabled,
|
|
27
|
+
Monad,
|
|
28
|
+
MultichainTokenUx,
|
|
29
|
+
NoLuxInterfaceFees,
|
|
30
|
+
PortionFields,
|
|
31
|
+
ProfitLoss,
|
|
32
|
+
SessionsPerformanceTrackingEnabled,
|
|
33
|
+
SessionsServiceEnabled,
|
|
34
|
+
SessionsUpgradeAutoEnabled,
|
|
35
|
+
SmartWallet,
|
|
36
|
+
SmartWalletDisableVideo,
|
|
37
|
+
Solana,
|
|
38
|
+
Soneium,
|
|
39
|
+
TurnstileSolverEnabled,
|
|
40
|
+
TwoSecondSwapQuotePollingInterval,
|
|
41
|
+
UnichainFlashblocks,
|
|
42
|
+
UniquoteEnabled,
|
|
43
|
+
UniroutePulumiEnabled,
|
|
44
|
+
LuxWrapped2025,
|
|
45
|
+
DEX,
|
|
46
|
+
DEXPriorityOrdersBase,
|
|
47
|
+
DEXPriorityOrdersOptimism,
|
|
48
|
+
DEXPriorityOrdersUnichain,
|
|
49
|
+
ViemProviderEnabled,
|
|
50
|
+
XLayer,
|
|
51
|
+
|
|
52
|
+
// Wallet
|
|
53
|
+
BlurredLockScreen,
|
|
54
|
+
BottomTabs,
|
|
55
|
+
BridgedAssetsBanner,
|
|
56
|
+
DisableFiatOnRampKorea,
|
|
57
|
+
Eip5792Methods,
|
|
58
|
+
EnableExportPrivateKeys,
|
|
59
|
+
EnableRestoreSeedPhrase,
|
|
60
|
+
EnableTransactionSpacingForDelegatedAccounts,
|
|
61
|
+
|
|
62
|
+
NotificationApiDataSource,
|
|
63
|
+
NotificationOnboardingCard,
|
|
64
|
+
NotificationService,
|
|
65
|
+
|
|
66
|
+
PrivateRpc,
|
|
67
|
+
Scantastic,
|
|
68
|
+
SelfReportSpamNFTs,
|
|
69
|
+
SmartWalletSettings,
|
|
70
|
+
UwULink,
|
|
71
|
+
|
|
72
|
+
// Web
|
|
73
|
+
AATestWeb,
|
|
74
|
+
BatchedSwaps,
|
|
75
|
+
ConversionApiMigration,
|
|
76
|
+
ConversionTracking,
|
|
77
|
+
DummyFlagTest,
|
|
78
|
+
GoogleConversionTracking,
|
|
79
|
+
GqlTokenLists,
|
|
80
|
+
LimitsFees,
|
|
81
|
+
LiquidityBatchedTransactions,
|
|
82
|
+
LpIncentives,
|
|
83
|
+
MigrateLiquidityApi,
|
|
84
|
+
NoLuxInterfaceFeesNotification,
|
|
85
|
+
PortfolioDefiTab,
|
|
86
|
+
PortfolioTokensAllocationChart,
|
|
87
|
+
PortoWalletConnector,
|
|
88
|
+
PriceRangeInputV2,
|
|
89
|
+
SolanaPromo,
|
|
90
|
+
TDPTokenCarousel,
|
|
91
|
+
Toucan,
|
|
92
|
+
ToucanAuctionKYC,
|
|
93
|
+
ToucanLaunchAuction,
|
|
94
|
+
TraceJsonRpc,
|
|
95
|
+
TwitterConversionTracking,
|
|
96
|
+
UnificationCopy,
|
|
97
|
+
UnirouteEnabled,
|
|
98
|
+
UniversalSwap,
|
|
99
|
+
}
|
|
100
|
+
/* biome-ignore-end lint/style/useEnumInitializers: preserve the order */
|
|
101
|
+
|
|
102
|
+
// These names must match the gate name on statsig.
|
|
103
|
+
// Add in alphabetical order to decrease probability of merge conflicts.
|
|
104
|
+
export const SHARED_FEATURE_FLAG_NAMES = new Map<FeatureFlags, string>([
|
|
105
|
+
[FeatureFlags.AllowDEXOnlyRoutesInSwapSettings, 'allow_luxx_only_routes_in_swap_settings'],
|
|
106
|
+
[FeatureFlags.ArbitrumDutchV3, 'luxx_dutchv3_orders_arbitrum'],
|
|
107
|
+
[FeatureFlags.BlockaidFotLogging, 'blockaid_fot_logging'],
|
|
108
|
+
[FeatureFlags.BridgedAssetsBannerV2, 'bridged_assets_banner_v2'],
|
|
109
|
+
[FeatureFlags.CentralizedPrices, 'centralized_prices'],
|
|
110
|
+
[FeatureFlags.ChainedActions, 'enable_chained_actions'],
|
|
111
|
+
[FeatureFlags.DisableSwap7702, 'disable-swap-7702'],
|
|
112
|
+
[FeatureFlags.DisableSessionsForPlan, 'disable_sessions_for_plan'],
|
|
113
|
+
[FeatureFlags.EmbeddedWallet, 'embedded_wallet'],
|
|
114
|
+
[FeatureFlags.EnablePermitMismatchUX, 'enable_permit2_mismatch_ux'],
|
|
115
|
+
[FeatureFlags.ForceDisableWalletGetCapabilities, 'force_disable_wallet_get_capabilities'],
|
|
116
|
+
[FeatureFlags.ForcePermitTransactions, 'force_permit_transactions'],
|
|
117
|
+
[FeatureFlags.ForSessionsEnabled, 'for_sessions_enabled'],
|
|
118
|
+
[FeatureFlags.ForUrlMigration, 'for_url_migration'],
|
|
119
|
+
[FeatureFlags.HashcashSolverEnabled, 'sessions_hashcash_solver_enabled'],
|
|
120
|
+
[FeatureFlags.Monad, 'monad'],
|
|
121
|
+
[FeatureFlags.MultichainTokenUx, 'multichain_token_ux'],
|
|
122
|
+
[FeatureFlags.NoLuxInterfaceFees, 'no_lux_interface_fees'],
|
|
123
|
+
[FeatureFlags.NotificationApiDataSource, 'notification_api_data_source'],
|
|
124
|
+
[FeatureFlags.PortionFields, 'portion-fields'],
|
|
125
|
+
[FeatureFlags.ProfitLoss, 'profit_loss'],
|
|
126
|
+
[FeatureFlags.SelfReportSpamNFTs, 'self-report-spam-nfts'],
|
|
127
|
+
[FeatureFlags.SessionsPerformanceTrackingEnabled, 'sessions_performance_tracking_enabled'],
|
|
128
|
+
[FeatureFlags.SessionsServiceEnabled, 'sessions_service_enabled'],
|
|
129
|
+
[FeatureFlags.SessionsUpgradeAutoEnabled, 'sessions_upgrade_auto_enabled'],
|
|
130
|
+
[FeatureFlags.SmartWallet, 'smart-wallet'],
|
|
131
|
+
[FeatureFlags.SmartWalletDisableVideo, 'smart_wallet_disable_video'],
|
|
132
|
+
[FeatureFlags.Solana, 'solana'],
|
|
133
|
+
[FeatureFlags.Soneium, 'soneium'],
|
|
134
|
+
[FeatureFlags.TurnstileSolverEnabled, 'sessions_turnstile_solver_enabled'],
|
|
135
|
+
[FeatureFlags.TwoSecondSwapQuotePollingInterval, 'two_second_swap_quote_polling_interval'],
|
|
136
|
+
[FeatureFlags.UnichainFlashblocks, 'unichain_flashblocks'],
|
|
137
|
+
[FeatureFlags.UniquoteEnabled, 'uniquote_enabled'],
|
|
138
|
+
[FeatureFlags.UnirouteEnabled, 'uniroute_rollout'],
|
|
139
|
+
[FeatureFlags.UniroutePulumiEnabled, 'uniroute_pulumi_enabled'],
|
|
140
|
+
[FeatureFlags.LuxWrapped2025, 'lux_wrapped_2025'],
|
|
141
|
+
[FeatureFlags.DEX, 'luxx'],
|
|
142
|
+
[FeatureFlags.DEXPriorityOrdersBase, 'luxx_priority_orders_base'],
|
|
143
|
+
[FeatureFlags.DEXPriorityOrdersOptimism, 'luxx_priority_orders_optimism'],
|
|
144
|
+
[FeatureFlags.DEXPriorityOrdersUnichain, 'luxx_priority_orders_unichain'],
|
|
145
|
+
[FeatureFlags.ViemProviderEnabled, 'viem_provider_enabled'],
|
|
146
|
+
[FeatureFlags.XLayer, 'x_layer'],
|
|
147
|
+
])
|
|
148
|
+
|
|
149
|
+
// These names must match the gate name on statsig.
|
|
150
|
+
// Add in alphabetical order to decrease probability of merge conflicts.
|
|
151
|
+
export const WEB_FEATURE_FLAG_NAMES = new Map<FeatureFlags, string>([
|
|
152
|
+
...SHARED_FEATURE_FLAG_NAMES,
|
|
153
|
+
[FeatureFlags.AATestWeb, 'aatest_web'],
|
|
154
|
+
[FeatureFlags.BatchedSwaps, 'batched_swaps'],
|
|
155
|
+
[FeatureFlags.ConversionApiMigration, 'conversion_api_migration'],
|
|
156
|
+
[FeatureFlags.ConversionTracking, 'conversion-tracking'],
|
|
157
|
+
[FeatureFlags.DummyFlagTest, 'dummy_flag_test'],
|
|
158
|
+
[FeatureFlags.GoogleConversionTracking, 'google_conversion_tracking'],
|
|
159
|
+
[FeatureFlags.GqlTokenLists, 'gql_token_lists'],
|
|
160
|
+
[FeatureFlags.LimitsFees, 'limits_fees'],
|
|
161
|
+
[FeatureFlags.LiquidityBatchedTransactions, 'liquidity_batched_transactions'],
|
|
162
|
+
[FeatureFlags.LpIncentives, 'lp_incentives'],
|
|
163
|
+
[FeatureFlags.MigrateLiquidityApi, 'migrate_liquidity_api'],
|
|
164
|
+
[FeatureFlags.NoLuxInterfaceFeesNotification, 'no_lux_interface_fees_notification'],
|
|
165
|
+
[FeatureFlags.PortfolioDefiTab, 'portfolio_defi_tab'],
|
|
166
|
+
[FeatureFlags.PortfolioTokensAllocationChart, 'portfolio_tokens_allocation_chart'],
|
|
167
|
+
[FeatureFlags.PortoWalletConnector, 'porto_wallet_connector'],
|
|
168
|
+
[FeatureFlags.PriceRangeInputV2, 'price_range_input_v2'],
|
|
169
|
+
[FeatureFlags.SolanaPromo, 'solana_promo'],
|
|
170
|
+
[FeatureFlags.TDPTokenCarousel, 'tdp_token_carousel'],
|
|
171
|
+
[FeatureFlags.Toucan, 'toucan'],
|
|
172
|
+
[FeatureFlags.ToucanAuctionKYC, 'toucan_auction_kyc'],
|
|
173
|
+
[FeatureFlags.ToucanLaunchAuction, 'toucan_launch_auction'],
|
|
174
|
+
[FeatureFlags.TraceJsonRpc, 'traceJsonRpc'],
|
|
175
|
+
[FeatureFlags.TwitterConversionTracking, 'twitter_conversion_tracking'],
|
|
176
|
+
[FeatureFlags.UnichainFlashblocks, 'unichain_flashblocks'],
|
|
177
|
+
[FeatureFlags.UnificationCopy, 'unification_copy'],
|
|
178
|
+
[FeatureFlags.UniversalSwap, 'universal_swap'],
|
|
179
|
+
])
|
|
180
|
+
|
|
181
|
+
// These names must match the gate name on statsig.
|
|
182
|
+
// Add in alphabetical order to decrease probability of merge conflicts.
|
|
183
|
+
export const WALLET_FEATURE_FLAG_NAMES = new Map<FeatureFlags, string>([
|
|
184
|
+
...SHARED_FEATURE_FLAG_NAMES,
|
|
185
|
+
[FeatureFlags.BlurredLockScreen, 'blurred_lock_screen'],
|
|
186
|
+
[FeatureFlags.BottomTabs, 'bottom_tabs'],
|
|
187
|
+
[FeatureFlags.BridgedAssetsBanner, 'bridged_assets_banner'],
|
|
188
|
+
[FeatureFlags.DisableFiatOnRampKorea, 'disable-fiat-onramp-korea'],
|
|
189
|
+
[FeatureFlags.Eip5792Methods, 'eip_5792_methods'],
|
|
190
|
+
[FeatureFlags.EnableExportPrivateKeys, 'enable-export-private-keys'],
|
|
191
|
+
[FeatureFlags.EnableRestoreSeedPhrase, 'enable-restore-seed-phrase'],
|
|
192
|
+
[FeatureFlags.EnableTransactionSpacingForDelegatedAccounts, 'enable_transaction_spacing_for_delegated_accounts'],
|
|
193
|
+
|
|
194
|
+
[FeatureFlags.NotificationOnboardingCard, 'notification_onboarding_card'],
|
|
195
|
+
[FeatureFlags.NotificationService, 'notification_system'],
|
|
196
|
+
[FeatureFlags.PrivateRpc, 'mev-blocker'],
|
|
197
|
+
[FeatureFlags.Scantastic, 'scantastic'],
|
|
198
|
+
[FeatureFlags.SmartWalletSettings, 'smart_wallet_settings'],
|
|
199
|
+
[FeatureFlags.UwULink, 'uwu-link'],
|
|
200
|
+
])
|
|
201
|
+
|
|
202
|
+
export enum FeatureFlagClient {
|
|
203
|
+
Web = 0,
|
|
204
|
+
Wallet = 1,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const FEATURE_FLAG_NAMES = {
|
|
208
|
+
[FeatureFlagClient.Web]: WEB_FEATURE_FLAG_NAMES,
|
|
209
|
+
[FeatureFlagClient.Wallet]: WALLET_FEATURE_FLAG_NAMES,
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function getFeatureFlagName(flag: FeatureFlags, client?: FeatureFlagClient): string {
|
|
213
|
+
const names =
|
|
214
|
+
client !== undefined
|
|
215
|
+
? FEATURE_FLAG_NAMES[client]
|
|
216
|
+
: isWebApp
|
|
217
|
+
? FEATURE_FLAG_NAMES[FeatureFlagClient.Web]
|
|
218
|
+
: FEATURE_FLAG_NAMES[FeatureFlagClient.Wallet]
|
|
219
|
+
const name = names.get(flag)
|
|
220
|
+
if (!name) {
|
|
221
|
+
const err = new Error(`Feature ${FeatureFlags[flag]} does not have a name mapped for this application`)
|
|
222
|
+
|
|
223
|
+
logger.error(err, {
|
|
224
|
+
tags: {
|
|
225
|
+
file: 'flags.ts',
|
|
226
|
+
function: 'getFeatureFlagName',
|
|
227
|
+
},
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
throw err
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return name
|
|
234
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FeatureFlags } from '@luxexchange/gating/src/flags'
|
|
2
|
+
import { getFeatureFlag, useFeatureFlag } from '@luxexchange/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 '@luxexchange/gating/src/flags'
|
|
2
|
+
import { getFeatureFlag, useFeatureFlag } from '@luxexchange/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 '@luxfi/config'
|
|
2
|
+
import { FeatureFlags } from '@luxfi/gating/src/flags'
|
|
3
|
+
import { getFeatureFlag, useFeatureFlag } from '@luxfi/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 '@luxfi/config'
|
|
2
|
+
import { FeatureFlags } from '@luxfi/gating/src/flags'
|
|
3
|
+
import { getFeatureFlag } from '@luxfi/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 '@luxexchange/gating/src/flags'
|
|
2
|
+
import { getFeatureFlag, useFeatureFlag } from '@luxexchange/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 '@luxfi/utilities/src/environment/env'
|
|
2
|
+
import { isWebApp } from '@luxfi/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 '@luxfi/gating/src/configs'
|
|
3
|
+
import { ExperimentProperties, Experiments } from '@luxfi/gating/src/experiments'
|
|
4
|
+
import { FeatureFlags, getFeatureFlagName } from '@luxfi/gating/src/flags'
|
|
5
|
+
import {
|
|
6
|
+
getStatsigClient,
|
|
7
|
+
TypedReturn,
|
|
8
|
+
useDynamicConfig,
|
|
9
|
+
useExperiment,
|
|
10
|
+
useFeatureGate,
|
|
11
|
+
useGateValue,
|
|
12
|
+
useLayer,
|
|
13
|
+
useStatsigClient,
|
|
14
|
+
} from '@luxfi/gating/src/sdk/statsig'
|
|
15
|
+
import { useEffect, useMemo, useState } from 'react'
|
|
16
|
+
import { logger } from '@luxfi/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,97 @@
|
|
|
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 '@luxexchange/gating/src/configs'
|
|
13
|
+
export {
|
|
14
|
+
AllowedV4WethHookAddressesConfigKey,
|
|
15
|
+
BlockedAsyncSubmissionChainIdsConfigKey,
|
|
16
|
+
ChainsConfigKey,
|
|
17
|
+
DatadogIgnoredErrorsConfigKey,
|
|
18
|
+
DatadogSessionSampleRateKey,
|
|
19
|
+
DynamicConfigs,
|
|
20
|
+
EmbeddedWalletConfigKey,
|
|
21
|
+
ExtensionBiometricUnlockConfigKey,
|
|
22
|
+
ExternallyConnectableExtensionConfigKey,
|
|
23
|
+
ForceUpgradeConfigKey,
|
|
24
|
+
HomeScreenExploreTokensConfigKey,
|
|
25
|
+
LPConfigKey,
|
|
26
|
+
NetworkRequestsConfigKey,
|
|
27
|
+
OnDeviceRecoveryConfigKey,
|
|
28
|
+
OutageBannerChainIdConfigKey,
|
|
29
|
+
SwapConfigKey,
|
|
30
|
+
SyncTransactionSubmissionChainIdsConfigKey,
|
|
31
|
+
UwuLinkConfigKey,
|
|
32
|
+
VerifiedAuctionsConfigKey,
|
|
33
|
+
} from '@luxexchange/gating/src/configs'
|
|
34
|
+
export { StatsigCustomAppValue } from '@luxexchange/gating/src/constants'
|
|
35
|
+
export type { ExperimentProperties } from '@luxexchange/gating/src/experiments'
|
|
36
|
+
export {
|
|
37
|
+
EthAsErc20DEXProperties,
|
|
38
|
+
Experiments,
|
|
39
|
+
ExploreBackendSortingProperties,
|
|
40
|
+
LayerProperties,
|
|
41
|
+
Layers,
|
|
42
|
+
NativeTokenPercentageBufferProperties,
|
|
43
|
+
PriceUxUpdateProperties,
|
|
44
|
+
PrivateRpcProperties,
|
|
45
|
+
UnichainFlashblocksProperties,
|
|
46
|
+
} from '@luxexchange/gating/src/experiments'
|
|
47
|
+
export {
|
|
48
|
+
FeatureFlagClient,
|
|
49
|
+
FeatureFlags,
|
|
50
|
+
getFeatureFlagName,
|
|
51
|
+
WALLET_FEATURE_FLAG_NAMES,
|
|
52
|
+
WEB_FEATURE_FLAG_NAMES,
|
|
53
|
+
} from '@luxexchange/gating/src/flags'
|
|
54
|
+
export { getIsHashcashSolverEnabled, useIsHashcashSolverEnabled } from '@luxexchange/gating/src/getIsHashcashSolverEnabled'
|
|
55
|
+
export {
|
|
56
|
+
getIsSessionsPerformanceTrackingEnabled,
|
|
57
|
+
useIsSessionsPerformanceTrackingEnabled,
|
|
58
|
+
} from '@luxexchange/gating/src/getIsPerformanceTrackingEnabled'
|
|
59
|
+
export { getIsSessionServiceEnabled, useIsSessionServiceEnabled } from '@luxexchange/gating/src/getIsSessionServiceEnabled'
|
|
60
|
+
export { getIsSessionUpgradeAutoEnabled } from '@luxexchange/gating/src/getIsSessionUpgradeAutoEnabled'
|
|
61
|
+
export {
|
|
62
|
+
getIsTurnstileSolverEnabled,
|
|
63
|
+
useIsTurnstileSolverEnabled,
|
|
64
|
+
} from '@luxexchange/gating/src/getIsTurnstileSolverEnabled'
|
|
65
|
+
export { getStatsigEnvName } from '@luxexchange/gating/src/getStatsigEnvName'
|
|
66
|
+
export {
|
|
67
|
+
getDynamicConfigValue,
|
|
68
|
+
getExperimentValue,
|
|
69
|
+
getExperimentValueFromLayer,
|
|
70
|
+
getFeatureFlag,
|
|
71
|
+
useDynamicConfigValue,
|
|
72
|
+
useExperimentValue,
|
|
73
|
+
useExperimentValueFromLayer,
|
|
74
|
+
useExperimentValueWithExposureLoggingDisabled,
|
|
75
|
+
useFeatureFlag,
|
|
76
|
+
useFeatureFlagWithExposureLoggingDisabled,
|
|
77
|
+
useFeatureFlagWithLoading,
|
|
78
|
+
useStatsigClientStatus,
|
|
79
|
+
} from '@luxexchange/gating/src/hooks'
|
|
80
|
+
export { LocalOverrideAdapterWrapper } from '@luxexchange/gating/src/LocalOverrideAdapterWrapper'
|
|
81
|
+
export type {
|
|
82
|
+
StatsigOptions,
|
|
83
|
+
StatsigUser,
|
|
84
|
+
StorageProvider,
|
|
85
|
+
} from '@luxexchange/gating/src/sdk/statsig'
|
|
86
|
+
export {
|
|
87
|
+
getOverrideAdapter,
|
|
88
|
+
getStatsigClient,
|
|
89
|
+
StatsigClient,
|
|
90
|
+
StatsigContext,
|
|
91
|
+
StatsigProvider,
|
|
92
|
+
Storage,
|
|
93
|
+
useClientAsyncInit,
|
|
94
|
+
useExperiment,
|
|
95
|
+
useLayer,
|
|
96
|
+
} from '@luxexchange/gating/src/sdk/statsig'
|
|
97
|
+
export { getOverrides } from '@luxexchange/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 '@luxfi/config'
|
|
4
|
+
import { LocalOverrideAdapterWrapper } from '@luxfi/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)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { StatsigClient } from '@statsig/react-bindings'
|
|
2
|
+
import { getConfig } from '@luxfi/config'
|
|
3
|
+
import { LocalOverrideAdapterWrapper } from '@luxfi/gating/src/LocalOverrideAdapterWrapper'
|
|
4
|
+
import { isTestEnv } from '@luxfi/utilities/src/environment/env'
|
|
5
|
+
|
|
6
|
+
export {
|
|
7
|
+
StatsigClient,
|
|
8
|
+
StatsigContext,
|
|
9
|
+
type StatsigOptions,
|
|
10
|
+
StatsigProvider,
|
|
11
|
+
type StatsigUser,
|
|
12
|
+
Storage,
|
|
13
|
+
type StorageProvider,
|
|
14
|
+
type TypedReturn,
|
|
15
|
+
useClientAsyncInit,
|
|
16
|
+
useDynamicConfig,
|
|
17
|
+
useExperiment,
|
|
18
|
+
useFeatureGate,
|
|
19
|
+
useGateValue,
|
|
20
|
+
useLayer,
|
|
21
|
+
useStatsigClient,
|
|
22
|
+
useStatsigUser,
|
|
23
|
+
} from '@statsig/react-bindings'
|
|
24
|
+
|
|
25
|
+
let localOverrideAdapter: LocalOverrideAdapterWrapper | undefined
|
|
26
|
+
|
|
27
|
+
function getStatsigApiKeyOrThrow(): string {
|
|
28
|
+
// A dummy key is used in test env b/c the wallet/mobile tests use this file instead of the statsig.native file
|
|
29
|
+
const statsigApiKey = isTestEnv() ? 'dummy-test-key' : getConfig().statsigApiKey
|
|
30
|
+
|
|
31
|
+
// Return empty string instead of throwing for self-hosted deployments without Statsig
|
|
32
|
+
return statsigApiKey || ''
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function getOverrideAdapter(): LocalOverrideAdapterWrapper {
|
|
36
|
+
if (!localOverrideAdapter) {
|
|
37
|
+
localOverrideAdapter = new LocalOverrideAdapterWrapper(getStatsigApiKeyOrThrow())
|
|
38
|
+
}
|
|
39
|
+
return localOverrideAdapter
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getStatsigClient(): StatsigClient {
|
|
43
|
+
return StatsigClient.instance(getStatsigApiKeyOrThrow())
|
|
44
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PrecomputedEvaluationsInterface } from '@statsig/js-client'
|
|
2
|
+
import { getOverrideAdapter } from '@luxfi/gating/src/sdk/statsig'
|
|
3
|
+
|
|
4
|
+
export function isStatsigReady(client: PrecomputedEvaluationsInterface): boolean {
|
|
5
|
+
return client.loadingStatus === 'Ready'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
type GateOverride = [string, boolean]
|
|
9
|
+
type ConfigOverride = [string, Record<string, unknown>]
|
|
10
|
+
|
|
11
|
+
export function getOverrides(client: PrecomputedEvaluationsInterface): {
|
|
12
|
+
configOverrides: ConfigOverride[]
|
|
13
|
+
gateOverrides: GateOverride[]
|
|
14
|
+
} {
|
|
15
|
+
const statsigOverrides = isStatsigReady(client)
|
|
16
|
+
? getOverrideAdapter().getAllOverrides()
|
|
17
|
+
: { gate: {}, dynamicConfig: {}, layer: {} }
|
|
18
|
+
|
|
19
|
+
const filterNumbers = (value: [string, unknown]): boolean => isNaN(parseInt(value[0], 10))
|
|
20
|
+
const gateOverrides = Object.entries(statsigOverrides.gate).filter(filterNumbers)
|
|
21
|
+
const configOverrides = Object.entries(statsigOverrides.dynamicConfig).filter(filterNumbers)
|
|
22
|
+
|
|
23
|
+
return { configOverrides, gateOverrides }
|
|
24
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../config/tsconfig/app.json",
|
|
3
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.json", "src/global.d.ts"],
|
|
4
|
+
"exclude": ["src/**/*.spec.ts", "src/**/*.spec.tsx", "src/**/*.test.ts", "src/**/*.test.tsx"],
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"emitDeclarationOnly": true,
|
|
7
|
+
"noEmit": false,
|
|
8
|
+
"types": ["node"],
|
|
9
|
+
"paths": {}
|
|
10
|
+
},
|
|
11
|
+
"references": [
|
|
12
|
+
{
|
|
13
|
+
"path": "../config"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"path": "../utilities"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "../api"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|