@ledgerhq/live-config 1.0.0-next.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/.eslintignore +2 -0
- package/.eslintrc.js +20 -0
- package/.turbo/turbo-build.log +4 -0
- package/.unimportedrc.json +5 -0
- package/CHANGELOG.md +14 -0
- package/LICENSE.txt +21 -0
- package/jest.config.js +10 -0
- package/lib/featureFlags/FeatureFlagsContext.d.ts +41 -0
- package/lib/featureFlags/FeatureFlagsContext.d.ts.map +1 -0
- package/lib/featureFlags/FeatureFlagsContext.js +26 -0
- package/lib/featureFlags/FeatureFlagsContext.js.map +1 -0
- package/lib/featureFlags/FeatureFlagsContext.test.d.ts +2 -0
- package/lib/featureFlags/FeatureFlagsContext.test.d.ts.map +1 -0
- package/lib/featureFlags/FeatureFlagsContext.test.js +15 -0
- package/lib/featureFlags/FeatureFlagsContext.test.js.map +1 -0
- package/lib/featureFlags/FeatureToggle.d.ts +10 -0
- package/lib/featureFlags/FeatureToggle.d.ts.map +1 -0
- package/lib/featureFlags/FeatureToggle.js +16 -0
- package/lib/featureFlags/FeatureToggle.js.map +1 -0
- package/lib/featureFlags/LiveConfig.d.ts +25 -0
- package/lib/featureFlags/LiveConfig.d.ts.map +1 -0
- package/lib/featureFlags/LiveConfig.js +30 -0
- package/lib/featureFlags/LiveConfig.js.map +1 -0
- package/lib/featureFlags/defaultFeatures.d.ts +61 -0
- package/lib/featureFlags/defaultFeatures.d.ts.map +1 -0
- package/lib/featureFlags/defaultFeatures.js +319 -0
- package/lib/featureFlags/defaultFeatures.js.map +1 -0
- package/lib/featureFlags/firebaseFeatureFlags.d.ts +109 -0
- package/lib/featureFlags/firebaseFeatureFlags.d.ts.map +1 -0
- package/lib/featureFlags/firebaseFeatureFlags.js +90 -0
- package/lib/featureFlags/firebaseFeatureFlags.js.map +1 -0
- package/lib/featureFlags/groupedFeatures.d.ts +6 -0
- package/lib/featureFlags/groupedFeatures.d.ts.map +1 -0
- package/lib/featureFlags/groupedFeatures.js +22 -0
- package/lib/featureFlags/groupedFeatures.js.map +1 -0
- package/lib/featureFlags/helper.d.ts +2 -0
- package/lib/featureFlags/helper.d.ts.map +1 -0
- package/lib/featureFlags/helper.js +10 -0
- package/lib/featureFlags/helper.js.map +1 -0
- package/lib/featureFlags/index.d.ts +11 -0
- package/lib/featureFlags/index.d.ts.map +1 -0
- package/lib/featureFlags/index.js +32 -0
- package/lib/featureFlags/index.js.map +1 -0
- package/lib/featureFlags/mock.d.ts +11 -0
- package/lib/featureFlags/mock.d.ts.map +1 -0
- package/lib/featureFlags/mock.js +25 -0
- package/lib/featureFlags/mock.js.map +1 -0
- package/lib/featureFlags/useFeature.d.ts +14 -0
- package/lib/featureFlags/useFeature.d.ts.map +1 -0
- package/lib/featureFlags/useFeature.js +21 -0
- package/lib/featureFlags/useFeature.js.map +1 -0
- package/lib/featureFlags/useFeature.test.d.ts +2 -0
- package/lib/featureFlags/useFeature.test.d.ts.map +1 -0
- package/lib/featureFlags/useFeature.test.js +27 -0
- package/lib/featureFlags/useFeature.test.js.map +1 -0
- package/lib/featureFlags/useHasOverriddenFeatureFlags.d.ts +6 -0
- package/lib/featureFlags/useHasOverriddenFeatureFlags.d.ts.map +1 -0
- package/lib/featureFlags/useHasOverriddenFeatureFlags.js +24 -0
- package/lib/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +18 -0
- package/lib/index.js.map +1 -0
- package/lib-es/featureFlags/FeatureFlagsContext.d.ts +41 -0
- package/lib-es/featureFlags/FeatureFlagsContext.d.ts.map +1 -0
- package/lib-es/featureFlags/FeatureFlagsContext.js +22 -0
- package/lib-es/featureFlags/FeatureFlagsContext.js.map +1 -0
- package/lib-es/featureFlags/FeatureFlagsContext.test.d.ts +2 -0
- package/lib-es/featureFlags/FeatureFlagsContext.test.d.ts.map +1 -0
- package/lib-es/featureFlags/FeatureFlagsContext.test.js +13 -0
- package/lib-es/featureFlags/FeatureFlagsContext.test.js.map +1 -0
- package/lib-es/featureFlags/FeatureToggle.d.ts +10 -0
- package/lib-es/featureFlags/FeatureToggle.d.ts.map +1 -0
- package/lib-es/featureFlags/FeatureToggle.js +11 -0
- package/lib-es/featureFlags/FeatureToggle.js.map +1 -0
- package/lib-es/featureFlags/LiveConfig.d.ts +25 -0
- package/lib-es/featureFlags/LiveConfig.d.ts.map +1 -0
- package/lib-es/featureFlags/LiveConfig.js +26 -0
- package/lib-es/featureFlags/LiveConfig.js.map +1 -0
- package/lib-es/featureFlags/defaultFeatures.d.ts +61 -0
- package/lib-es/featureFlags/defaultFeatures.d.ts.map +1 -0
- package/lib-es/featureFlags/defaultFeatures.js +314 -0
- package/lib-es/featureFlags/defaultFeatures.js.map +1 -0
- package/lib-es/featureFlags/firebaseFeatureFlags.d.ts +109 -0
- package/lib-es/featureFlags/firebaseFeatureFlags.d.ts.map +1 -0
- package/lib-es/featureFlags/firebaseFeatureFlags.js +80 -0
- package/lib-es/featureFlags/firebaseFeatureFlags.js.map +1 -0
- package/lib-es/featureFlags/groupedFeatures.d.ts +6 -0
- package/lib-es/featureFlags/groupedFeatures.d.ts.map +1 -0
- package/lib-es/featureFlags/groupedFeatures.js +19 -0
- package/lib-es/featureFlags/groupedFeatures.js.map +1 -0
- package/lib-es/featureFlags/helper.d.ts +2 -0
- package/lib-es/featureFlags/helper.d.ts.map +1 -0
- package/lib-es/featureFlags/helper.js +6 -0
- package/lib-es/featureFlags/helper.js.map +1 -0
- package/lib-es/featureFlags/index.d.ts +11 -0
- package/lib-es/featureFlags/index.d.ts.map +1 -0
- package/lib-es/featureFlags/index.js +11 -0
- package/lib-es/featureFlags/index.js.map +1 -0
- package/lib-es/featureFlags/mock.d.ts +11 -0
- package/lib-es/featureFlags/mock.d.ts.map +1 -0
- package/lib-es/featureFlags/mock.js +17 -0
- package/lib-es/featureFlags/mock.js.map +1 -0
- package/lib-es/featureFlags/useFeature.d.ts +14 -0
- package/lib-es/featureFlags/useFeature.d.ts.map +1 -0
- package/lib-es/featureFlags/useFeature.js +19 -0
- package/lib-es/featureFlags/useFeature.js.map +1 -0
- package/lib-es/featureFlags/useFeature.test.d.ts +2 -0
- package/lib-es/featureFlags/useFeature.test.d.ts.map +1 -0
- package/lib-es/featureFlags/useFeature.test.js +22 -0
- package/lib-es/featureFlags/useFeature.test.js.map +1 -0
- package/lib-es/featureFlags/useHasOverriddenFeatureFlags.d.ts +6 -0
- package/lib-es/featureFlags/useHasOverriddenFeatureFlags.d.ts.map +1 -0
- package/lib-es/featureFlags/useHasOverriddenFeatureFlags.js +20 -0
- package/lib-es/featureFlags/useHasOverriddenFeatureFlags.js.map +1 -0
- package/lib-es/index.d.ts +2 -0
- package/lib-es/index.d.ts.map +1 -0
- package/lib-es/index.js +2 -0
- package/lib-es/index.js.map +1 -0
- package/package.json +82 -0
- package/src/featureFlags/FeatureFlagsContext.test.tsx +13 -0
- package/src/featureFlags/FeatureFlagsContext.tsx +62 -0
- package/src/featureFlags/FeatureToggle.tsx +22 -0
- package/src/featureFlags/LiveConfig.ts +45 -0
- package/src/featureFlags/defaultFeatures.ts +428 -0
- package/src/featureFlags/firebaseFeatureFlags.ts +115 -0
- package/src/featureFlags/groupedFeatures.ts +25 -0
- package/src/featureFlags/helper.tsx +9 -0
- package/src/featureFlags/index.ts +12 -0
- package/src/featureFlags/mock.tsx +28 -0
- package/src/featureFlags/useFeature.test.tsx +23 -0
- package/src/featureFlags/useFeature.ts +21 -0
- package/src/featureFlags/useHasOverriddenFeatureFlags.ts +24 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +15 -0
- package/types.ts +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock.js","sourceRoot":"","sources":["../../src/featureFlags/mock.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAA4B,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAEvF,MAAM,UAAU,sBAAsB,CACpC,cAAmD;IAEnD,OAAO;QACL,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI;QACrB,UAAU,EAAE,CAAC,SAAoB,EAAE,EAAE,CAAC,cAAc,CAAC,SAAS,CAAC,IAAI,IAAI;QACvE,eAAe,EAAE,GAAG,EAAE,GAAE,CAAC;QACzB,YAAY,EAAE,GAAG,EAAE,GAAE,CAAC;QACtB,aAAa,EAAE,GAAG,EAAE,GAAE,CAAC;KACxB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qCAAqC,CACnD,kBAA4C;IAE5C,MAAM,4BAA4B,GAAmD,CAAC,EACpF,QAAQ,GACT,EAAE,EAAE,CAAC,oBAAC,oBAAoB,IAAC,KAAK,EAAE,kBAAkB,IAAG,QAAQ,CAAwB,CAAC;IACzF,OAAO,4BAA4B,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,MAAM,sCAAsC,GAAG,qCAAqC,CACzF,sBAAsB,CAAC,EAAE,CAAC,CAC3B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Feature, FeatureParam } from "@ledgerhq/types-live";
|
|
2
|
+
/**
|
|
3
|
+
* Hook that returns the value of a feature flag based on its `featureId`.
|
|
4
|
+
*
|
|
5
|
+
* @dev do not modify this function to make it return a default arbitrary value
|
|
6
|
+
* instead of null, this should not be handled at this level.
|
|
7
|
+
*
|
|
8
|
+
* @param featureId
|
|
9
|
+
* @returns a feature flag value or null if the feature flag is not found
|
|
10
|
+
* (neither in the remote configuration, in the cache or in the local defaults).
|
|
11
|
+
*/
|
|
12
|
+
declare const useFeature: <T extends keyof import("@ledgerhq/types-live").CurrencyFeatures | "learn" | "brazePushNotifications" | "brazeLearn" | "llmNewDeviceSelection" | "llmNewFirmwareUpdateUx" | "ratingsPrompt" | "npsRatingsPrompt" | "counterValue" | "deviceInitialApps" | "buyDeviceFromLive" | "ptxEarn" | "depositNetworkBannerMobile" | "depositWithdrawBannerMobile" | "mockFeature" | "multibuyNavigation" | "syncOnboarding" | "walletConnectEntryPoint" | "customImage" | "referralProgramDiscoverCard" | "referralProgramDesktopBanner" | "referralProgramDesktopSidebar" | "referralProgramMobile" | "disableNftSend" | "disableNftLedgerMarket" | "disableNftRaribleOpensea" | "walletNftGallery" | "receiveStakingFlowConfigDesktop" | "ethStakingProviders" | "storyly" | "staxWelcomeScreen" | "postOnboardingClaimNft" | "postOnboardingAssetsTransfer" | "firebaseEnvironmentReadOnly" | "protectServicesMobile" | "protectServicesDesktop" | "ptxServiceCtaExchangeDrawer" | "ptxServiceCtaScreens" | "swapWalletApiPartnerList" | "stakePrograms" | "portfolioExchangeBanner" | "objkt" | "editEvmTx" | "stakeAccountBanner" | "newsfeedPage" | "domainInputResolution" | "discover" | "protectServicesDiscoverDesktop" | "transactionsAlerts" | "listAppsV2minor1" | "llmWalletQuickActions" | "cexDepositEntryPointsDesktop" | "cexDepositEntryPointsMobile" | "fetchAdditionalCoins" | "ptxSwapLiveApp" | "ptxSwapMoonpayProvider">(featureId: T) => Feature<FeatureParam<T>> | null;
|
|
13
|
+
export default useFeature;
|
|
14
|
+
//# sourceMappingURL=useFeature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeature.d.ts","sourceRoot":"","sources":["../../src/featureFlags/useFeature.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAExE;;;;;;;;;GASG;AACH,QAAA,MAAM,UAAU,05CAIf,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useFeatureFlags } from "./FeatureFlagsContext";
|
|
3
|
+
/**
|
|
4
|
+
* Hook that returns the value of a feature flag based on its `featureId`.
|
|
5
|
+
*
|
|
6
|
+
* @dev do not modify this function to make it return a default arbitrary value
|
|
7
|
+
* instead of null, this should not be handled at this level.
|
|
8
|
+
*
|
|
9
|
+
* @param featureId
|
|
10
|
+
* @returns a feature flag value or null if the feature flag is not found
|
|
11
|
+
* (neither in the remote configuration, in the cache or in the local defaults).
|
|
12
|
+
*/
|
|
13
|
+
const useFeature = (featureId) => {
|
|
14
|
+
const featureFlags = useFeatureFlags();
|
|
15
|
+
const value = useMemo(() => featureFlags.getFeature(featureId), [featureFlags, featureId]);
|
|
16
|
+
return value;
|
|
17
|
+
};
|
|
18
|
+
export default useFeature;
|
|
19
|
+
//# sourceMappingURL=useFeature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeature.js","sourceRoot":"","sources":["../../src/featureFlags/useFeature.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,CAAsB,SAAY,EAAmC,EAAE;IACxF,MAAM,YAAY,GAAG,eAAe,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;IAC3F,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeature.test.d.ts","sourceRoot":"","sources":["../../src/featureFlags/useFeature.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
2
|
+
import useFeature from "./useFeature";
|
|
3
|
+
import { makeMockedFeatureFlagsProviderWrapper, makeMockedContextValue } from "./mock";
|
|
4
|
+
describe("useFeature hook", () => {
|
|
5
|
+
it("should return null if a flag is not defined remotely", () => {
|
|
6
|
+
const mockedFeatures = {};
|
|
7
|
+
const { result } = renderHook(() => useFeature("mockFeature"), {
|
|
8
|
+
wrapper: makeMockedFeatureFlagsProviderWrapper(makeMockedContextValue(mockedFeatures)),
|
|
9
|
+
});
|
|
10
|
+
expect(result.current).toBeNull();
|
|
11
|
+
});
|
|
12
|
+
it("should return the feature flag value if the feature flag is defined", () => {
|
|
13
|
+
const mockedFeatures = {
|
|
14
|
+
mockFeature: { enabled: true, params: { blabla: "hello" } },
|
|
15
|
+
};
|
|
16
|
+
const { result } = renderHook(() => useFeature("mockFeature"), {
|
|
17
|
+
wrapper: makeMockedFeatureFlagsProviderWrapper(makeMockedContextValue(mockedFeatures)),
|
|
18
|
+
});
|
|
19
|
+
expect(result.current).toBe(mockedFeatures.mockFeature);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=useFeature.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFeature.test.js","sourceRoot":"","sources":["../../src/featureFlags/useFeature.test.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,UAAU,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,qCAAqC,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAEvF,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,cAAc,GAAG,EAAE,CAAC;QAC1B,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;YAC7D,OAAO,EAAE,qCAAqC,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;SACvF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,cAAc,GAAG;YACrB,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE;SAC5D,CAAC;QACF,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;YAC7D,OAAO,EAAE,qCAAqC,CAAC,sBAAsB,CAAC,cAAc,CAAC,CAAC;SACvF,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useHasOverriddenFeatureFlags.d.ts","sourceRoot":"","sources":["../../src/featureFlags/useHasOverriddenFeatureFlags.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,wBAAgB,mCAAmC,IAAI,OAAO,CAc7D"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useFeatureFlags } from "./FeatureFlagsContext";
|
|
3
|
+
import { DEFAULT_FEATURES } from "./defaultFeatures";
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @returns whether one or more flags are locally overridden
|
|
7
|
+
*/
|
|
8
|
+
export function useHasLocallyOverriddenFeatureFlags() {
|
|
9
|
+
const { getFeature } = useFeatureFlags();
|
|
10
|
+
return useMemo(() => Object.entries(DEFAULT_FEATURES).some(([featureId]) => {
|
|
11
|
+
try {
|
|
12
|
+
const val = getFeature(featureId);
|
|
13
|
+
return (val === null || val === void 0 ? void 0 : val.overridesRemote) || (val === null || val === void 0 ? void 0 : val.overriddenByEnv);
|
|
14
|
+
}
|
|
15
|
+
catch (e) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}), [getFeature]);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=useHasOverriddenFeatureFlags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useHasOverriddenFeatureFlags.js","sourceRoot":"","sources":["../../src/featureFlags/useHasOverriddenFeatureFlags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;GAGG;AACH,MAAM,UAAU,mCAAmC;IACjD,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAAC;IACzC,OAAO,OAAO,CACZ,GAAG,EAAE,CACH,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE;QACpD,IAAI;YACF,MAAM,GAAG,GAAG,UAAU,CAAC,SAAsB,CAAC,CAAC;YAC/C,OAAO,CAAA,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,eAAe,MAAI,GAAG,aAAH,GAAG,uBAAH,GAAG,CAAE,eAAe,CAAA,CAAC;SACrD;QAAC,OAAO,CAAC,EAAE;YACV,OAAO,KAAK,CAAC;SACd;IACH,CAAC,CAAC,EACJ,CAAC,UAAU,CAAC,CACb,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
package/lib-es/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ledgerhq/live-config",
|
|
3
|
+
"version": "1.0.0-next.0",
|
|
4
|
+
"description": "Ledger Live configuration tools",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"Ledger"
|
|
8
|
+
],
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/LedgerHQ/ledger-live.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/LedgerHQ/ledger-live/issues"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/live-config",
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"lodash": "^4.17.21",
|
|
22
|
+
"@ledgerhq/errors": "^6.16.1-next.0",
|
|
23
|
+
"@ledgerhq/live-env": "^0.8.0-next.0",
|
|
24
|
+
"@ledgerhq/live-promise": "^0.0.3",
|
|
25
|
+
"@ledgerhq/logs": "^6.12.0",
|
|
26
|
+
"@ledgerhq/types-live": "^6.43.1-next.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@testing-library/react": "12",
|
|
30
|
+
"@testing-library/react-hooks": "^8.0.0",
|
|
31
|
+
"@types/invariant": "^2.2.35",
|
|
32
|
+
"@types/jest": "^29.5.4",
|
|
33
|
+
"@types/lodash": "^4.14.182",
|
|
34
|
+
"@types/node": "^20.2.5",
|
|
35
|
+
"jest": "^28.1.1",
|
|
36
|
+
"jest-environment-jsdom": "28",
|
|
37
|
+
"react": "^18.2.0",
|
|
38
|
+
"react-dom": "18.2.0",
|
|
39
|
+
"semver": "^7.3.5",
|
|
40
|
+
"ts-jest": "^28.0.5"
|
|
41
|
+
},
|
|
42
|
+
"typesVersions": {
|
|
43
|
+
"*": {
|
|
44
|
+
"*.json": [
|
|
45
|
+
"*.json"
|
|
46
|
+
],
|
|
47
|
+
"*": [
|
|
48
|
+
"lib/*"
|
|
49
|
+
],
|
|
50
|
+
"lib/*": [
|
|
51
|
+
"lib/*"
|
|
52
|
+
],
|
|
53
|
+
"lib-es/*": [
|
|
54
|
+
"lib-es/*"
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"exports": {
|
|
59
|
+
"./lib/*": "./lib/*.js",
|
|
60
|
+
"./lib/*.js": "./lib/*.js",
|
|
61
|
+
"./lib-es/*": "./lib-es/*.js",
|
|
62
|
+
"./lib-es/*.js": "./lib-es/*.js",
|
|
63
|
+
"./*": {
|
|
64
|
+
"require": "./lib/*.js",
|
|
65
|
+
"default": "./lib-es/*.js"
|
|
66
|
+
},
|
|
67
|
+
"./*.js": {
|
|
68
|
+
"require": "./lib/*.js",
|
|
69
|
+
"default": "./lib-es/*.js"
|
|
70
|
+
},
|
|
71
|
+
"./package.json": "./package.json"
|
|
72
|
+
},
|
|
73
|
+
"scripts": {
|
|
74
|
+
"clean": "rimraf lib lib-es",
|
|
75
|
+
"build": "tsc && tsc -m ES6 --outDir lib-es",
|
|
76
|
+
"prewatch": "pnpm build",
|
|
77
|
+
"watch": "tsc --watch",
|
|
78
|
+
"lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx",
|
|
79
|
+
"lint:fix": "pnpm lint --fix",
|
|
80
|
+
"test": "jest"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { renderHook } from "@testing-library/react-hooks";
|
|
2
|
+
import { makeMockedContextValue, makeMockedFeatureFlagsProviderWrapper } from "./mock";
|
|
3
|
+
import { useFeatureFlags } from "./FeatureFlagsContext";
|
|
4
|
+
|
|
5
|
+
describe("useFeatureFlags hook", () => {
|
|
6
|
+
it("should return the context value if it is used inside a context provider", () => {
|
|
7
|
+
const mockedContextValue = makeMockedContextValue({});
|
|
8
|
+
const { result } = renderHook(() => useFeatureFlags(), {
|
|
9
|
+
wrapper: makeMockedFeatureFlagsProviderWrapper(mockedContextValue),
|
|
10
|
+
});
|
|
11
|
+
expect(result?.current).toStrictEqual(mockedContextValue);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { createContext, useContext } from "react";
|
|
2
|
+
import type { FeatureId, Feature } from "@ledgerhq/types-live";
|
|
3
|
+
|
|
4
|
+
export type FeatureFlagsContextValue = {
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param featureId featureId identifying a potential feature flag
|
|
8
|
+
* @returns true if and only if the parameter matches a feature that is configured.
|
|
9
|
+
*/
|
|
10
|
+
isFeature: (featureId: string) => boolean;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param featureId featureId identifying a feature flag
|
|
15
|
+
* @returns the value of the feature flag if it is defined (remotely or through a default value), otherwise returns null
|
|
16
|
+
*/
|
|
17
|
+
getFeature: (featureId: FeatureId) => Feature | null;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* function that allows to override the value of a feature flag
|
|
21
|
+
*
|
|
22
|
+
* @param featureId featureId identifying a feature flag
|
|
23
|
+
* @param newValue new value of the feature flag
|
|
24
|
+
* @returns undefined
|
|
25
|
+
*/
|
|
26
|
+
overrideFeature: (featureId: FeatureId, newValue: Feature) => void;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* resets the overridden feature flag value for a given featureId
|
|
30
|
+
* @param featureId featureId identifying a feature flag
|
|
31
|
+
* @returns undefined
|
|
32
|
+
*/
|
|
33
|
+
resetFeature: (featureId: FeatureId) => void;
|
|
34
|
+
/**
|
|
35
|
+
* resets all the overridden feature flags
|
|
36
|
+
* @returns undefined
|
|
37
|
+
*/
|
|
38
|
+
resetFeatures: () => void;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Context used for injecting the feature flagging implementation logic.
|
|
43
|
+
*
|
|
44
|
+
* @dev do not export this, it should be accessed exclusively through
|
|
45
|
+
* useFeatureFlags and FeatureFlagsProvider
|
|
46
|
+
*/
|
|
47
|
+
const FeatureFlagsContext = createContext<FeatureFlagsContextValue>({
|
|
48
|
+
isFeature: _ => false,
|
|
49
|
+
getFeature: _ => null,
|
|
50
|
+
overrideFeature: _ => {},
|
|
51
|
+
resetFeature: _ => {},
|
|
52
|
+
resetFeatures: () => {},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
export const FeatureFlagsProvider = FeatureFlagsContext.Provider;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Hook to consume a FeatureFlagsContext
|
|
59
|
+
*/
|
|
60
|
+
export function useFeatureFlags(): FeatureFlagsContextValue {
|
|
61
|
+
return useContext(FeatureFlagsContext);
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
import useFeature from "./useFeature";
|
|
4
|
+
import type { FeatureId } from "@ledgerhq/types-live";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
featureId: FeatureId;
|
|
8
|
+
fallback?: ReactNode;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const FeatureToggle = ({ featureId, fallback, children }: Props): JSX.Element => {
|
|
13
|
+
const feature = useFeature(featureId);
|
|
14
|
+
|
|
15
|
+
if (!feature || !feature.enabled) {
|
|
16
|
+
return <>{fallback || null}</>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return <>{children || null}</>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default FeatureToggle;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// refer to https://github.com/firebase/firebase-js-sdk/blob/master/packages/remote-config/src/public_types.ts#L71 for the firebase config value interface
|
|
2
|
+
export declare interface Value {
|
|
3
|
+
asBoolean(): boolean;
|
|
4
|
+
asNumber(): number;
|
|
5
|
+
asString(): string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class LiveConfig {
|
|
9
|
+
public appVersion?: string;
|
|
10
|
+
public platform?: string;
|
|
11
|
+
public environment?: string;
|
|
12
|
+
public providerGetvalueMethod?: { [provider: string]: (key: string) => Value };
|
|
13
|
+
|
|
14
|
+
private static instance: LiveConfig; // Singleton instance
|
|
15
|
+
private constructor() {}
|
|
16
|
+
public static init(config: { appVersion: string; platform: string; environment: string }) {
|
|
17
|
+
if (!LiveConfig.instance) {
|
|
18
|
+
LiveConfig.instance = new LiveConfig();
|
|
19
|
+
LiveConfig.instance.appVersion = config.appVersion;
|
|
20
|
+
LiveConfig.instance.platform = config.platform;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public static setProviderGetValueMethod(provider2Method: {
|
|
25
|
+
[provider: string]: (key: string) => Value;
|
|
26
|
+
}) {
|
|
27
|
+
if (!LiveConfig.instance) {
|
|
28
|
+
throw new Error("LiveConfig instance is not initialized. Call init() first.");
|
|
29
|
+
}
|
|
30
|
+
if (!LiveConfig.instance.providerGetvalueMethod) {
|
|
31
|
+
LiveConfig.instance.providerGetvalueMethod = {};
|
|
32
|
+
}
|
|
33
|
+
LiveConfig.instance.providerGetvalueMethod = {
|
|
34
|
+
...LiveConfig.instance.providerGetvalueMethod,
|
|
35
|
+
...provider2Method,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static getInstance(): LiveConfig {
|
|
40
|
+
if (!LiveConfig.instance) {
|
|
41
|
+
throw new Error("LiveConfig instance is not initialized. Call init() first.");
|
|
42
|
+
}
|
|
43
|
+
return LiveConfig.instance;
|
|
44
|
+
}
|
|
45
|
+
}
|