You're Invited:Meet the Socket Team at RSAC and BSidesSF 2026, March 23–26.RSVP
Socket
Book a DemoSign in
Socket

@metamask/remote-feature-flag-controller

Package Overview
Dependencies
Maintainers
3
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@metamask/remote-feature-flag-controller - npm Package Compare versions

Comparing version
1.9.1
to
2.0.0
+11
-1
CHANGELOG.md

@@ -10,2 +10,11 @@ # Changelog

## [2.0.0]
### Changed
- **BREAKING:** Use new `Messenger` from `@metamask/messenger` ([#6502](https://github.com/MetaMask/core/pull/6502))
- Previously, `RemoteFeatureFlagController` accepted a `RestrictedMessenger` instance from `@metamask/base-controller`.
- **BREAKING:** Metadata property `anonymous` renamed to `includeInDebugSnapshot` ([#6502](https://github.com/MetaMask/core/pull/6502))
- Bump `@metamask/base-controller` from `^8.4.2` to `^9.0.0` ([#6962](https://github.com/MetaMask/core/pull/6962))
## [1.9.1]

@@ -121,3 +130,4 @@

[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@1.9.1...HEAD
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@2.0.0...HEAD
[2.0.0]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@1.9.1...@metamask/remote-feature-flag-controller@2.0.0
[1.9.1]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@1.9.0...@metamask/remote-feature-flag-controller@1.9.1

@@ -124,0 +134,0 @@ [1.9.0]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@1.8.0...@metamask/remote-feature-flag-controller@1.9.0

+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uFAA+E;AAAtE,6IAAA,2BAA2B,OAAA;AASpC,mGAIgD;AAH9C,kIAAA,UAAU,OAAA;AACV,wIAAA,gBAAgB,OAAA;AAChB,uIAAA,eAAe,OAAA;AAOjB,uGAA+F;AAAtF,mIAAA,sBAAsB,OAAA;AAC/B,+EAAoF;AAA3E,4IAAA,iCAAiC,OAAA","sourcesContent":["export { RemoteFeatureFlagController } from './remote-feature-flag-controller';\nexport type {\n RemoteFeatureFlagControllerMessenger,\n RemoteFeatureFlagControllerActions,\n RemoteFeatureFlagControllerGetStateAction,\n RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction,\n RemoteFeatureFlagControllerEvents,\n RemoteFeatureFlagControllerStateChangeEvent,\n} from './remote-feature-flag-controller';\nexport {\n ClientType,\n DistributionType,\n EnvironmentType,\n} from './remote-feature-flag-controller-types';\n\nexport type {\n RemoteFeatureFlagControllerState,\n FeatureFlags,\n} from './remote-feature-flag-controller-types';\nexport { ClientConfigApiService } from './client-config-api-service/client-config-api-service';\nexport { generateDeterministicRandomNumber } from './utils/user-segmentation-utils';\n"]}
{"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uFAA+E;AAAtE,6IAAA,2BAA2B,OAAA;AAUpC,mGAIgD;AAH9C,kIAAA,UAAU,OAAA;AACV,wIAAA,gBAAgB,OAAA;AAChB,uIAAA,eAAe,OAAA;AAIjB,uGAA+F;AAAtF,mIAAA,sBAAsB,OAAA;AAC/B,+EAAoF;AAA3E,4IAAA,iCAAiC,OAAA","sourcesContent":["export { RemoteFeatureFlagController } from './remote-feature-flag-controller';\nexport type {\n RemoteFeatureFlagControllerState,\n RemoteFeatureFlagControllerMessenger,\n RemoteFeatureFlagControllerActions,\n RemoteFeatureFlagControllerGetStateAction,\n RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction,\n RemoteFeatureFlagControllerEvents,\n RemoteFeatureFlagControllerStateChangeEvent,\n} from './remote-feature-flag-controller';\nexport {\n ClientType,\n DistributionType,\n EnvironmentType,\n} from './remote-feature-flag-controller-types';\n\nexport type { FeatureFlags } from './remote-feature-flag-controller-types';\nexport { ClientConfigApiService } from './client-config-api-service/client-config-api-service';\nexport { generateDeterministicRandomNumber } from './utils/user-segmentation-utils';\n"]}
export { RemoteFeatureFlagController } from "./remote-feature-flag-controller.cjs";
export type { RemoteFeatureFlagControllerMessenger, RemoteFeatureFlagControllerActions, RemoteFeatureFlagControllerGetStateAction, RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction, RemoteFeatureFlagControllerEvents, RemoteFeatureFlagControllerStateChangeEvent, } from "./remote-feature-flag-controller.cjs";
export type { RemoteFeatureFlagControllerState, RemoteFeatureFlagControllerMessenger, RemoteFeatureFlagControllerActions, RemoteFeatureFlagControllerGetStateAction, RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction, RemoteFeatureFlagControllerEvents, RemoteFeatureFlagControllerStateChangeEvent, } from "./remote-feature-flag-controller.cjs";
export { ClientType, DistributionType, EnvironmentType, } from "./remote-feature-flag-controller-types.cjs";
export type { RemoteFeatureFlagControllerState, FeatureFlags, } from "./remote-feature-flag-controller-types.cjs";
export type { FeatureFlags } from "./remote-feature-flag-controller-types.cjs";
export { ClientConfigApiService } from "./client-config-api-service/client-config-api-service.cjs";
export { generateDeterministicRandomNumber } from "./utils/user-segmentation-utils.cjs";
//# sourceMappingURL=index.d.cts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,6CAAyC;AAC/E,YAAY,EACV,oCAAoC,EACpC,kCAAkC,EAClC,yCAAyC,EACzC,yDAAyD,EACzD,iCAAiC,EACjC,2CAA2C,GAC5C,6CAAyC;AAC1C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,mDAA+C;AAEhD,YAAY,EACV,gCAAgC,EAChC,YAAY,GACb,mDAA+C;AAChD,OAAO,EAAE,sBAAsB,EAAE,kEAA8D;AAC/F,OAAO,EAAE,iCAAiC,EAAE,4CAAwC"}
{"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,6CAAyC;AAC/E,YAAY,EACV,gCAAgC,EAChC,oCAAoC,EACpC,kCAAkC,EAClC,yCAAyC,EACzC,yDAAyD,EACzD,iCAAiC,EACjC,2CAA2C,GAC5C,6CAAyC;AAC1C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,mDAA+C;AAEhD,YAAY,EAAE,YAAY,EAAE,mDAA+C;AAC3E,OAAO,EAAE,sBAAsB,EAAE,kEAA8D;AAC/F,OAAO,EAAE,iCAAiC,EAAE,4CAAwC"}
export { RemoteFeatureFlagController } from "./remote-feature-flag-controller.mjs";
export type { RemoteFeatureFlagControllerMessenger, RemoteFeatureFlagControllerActions, RemoteFeatureFlagControllerGetStateAction, RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction, RemoteFeatureFlagControllerEvents, RemoteFeatureFlagControllerStateChangeEvent, } from "./remote-feature-flag-controller.mjs";
export type { RemoteFeatureFlagControllerState, RemoteFeatureFlagControllerMessenger, RemoteFeatureFlagControllerActions, RemoteFeatureFlagControllerGetStateAction, RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction, RemoteFeatureFlagControllerEvents, RemoteFeatureFlagControllerStateChangeEvent, } from "./remote-feature-flag-controller.mjs";
export { ClientType, DistributionType, EnvironmentType, } from "./remote-feature-flag-controller-types.mjs";
export type { RemoteFeatureFlagControllerState, FeatureFlags, } from "./remote-feature-flag-controller-types.mjs";
export type { FeatureFlags } from "./remote-feature-flag-controller-types.mjs";
export { ClientConfigApiService } from "./client-config-api-service/client-config-api-service.mjs";
export { generateDeterministicRandomNumber } from "./utils/user-segmentation-utils.mjs";
//# sourceMappingURL=index.d.mts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,6CAAyC;AAC/E,YAAY,EACV,oCAAoC,EACpC,kCAAkC,EAClC,yCAAyC,EACzC,yDAAyD,EACzD,iCAAiC,EACjC,2CAA2C,GAC5C,6CAAyC;AAC1C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,mDAA+C;AAEhD,YAAY,EACV,gCAAgC,EAChC,YAAY,GACb,mDAA+C;AAChD,OAAO,EAAE,sBAAsB,EAAE,kEAA8D;AAC/F,OAAO,EAAE,iCAAiC,EAAE,4CAAwC"}
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,6CAAyC;AAC/E,YAAY,EACV,gCAAgC,EAChC,oCAAoC,EACpC,kCAAkC,EAClC,yCAAyC,EACzC,yDAAyD,EACzD,iCAAiC,EACjC,2CAA2C,GAC5C,6CAAyC;AAC1C,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,mDAA+C;AAEhD,YAAY,EAAE,YAAY,EAAE,mDAA+C;AAC3E,OAAO,EAAE,sBAAsB,EAAE,kEAA8D;AAC/F,OAAO,EAAE,iCAAiC,EAAE,4CAAwC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,6CAAyC;AAS/E,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,eAAe,EAChB,mDAA+C;AAMhD,OAAO,EAAE,sBAAsB,EAAE,kEAA8D;AAC/F,OAAO,EAAE,iCAAiC,EAAE,4CAAwC","sourcesContent":["export { RemoteFeatureFlagController } from './remote-feature-flag-controller';\nexport type {\n RemoteFeatureFlagControllerMessenger,\n RemoteFeatureFlagControllerActions,\n RemoteFeatureFlagControllerGetStateAction,\n RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction,\n RemoteFeatureFlagControllerEvents,\n RemoteFeatureFlagControllerStateChangeEvent,\n} from './remote-feature-flag-controller';\nexport {\n ClientType,\n DistributionType,\n EnvironmentType,\n} from './remote-feature-flag-controller-types';\n\nexport type {\n RemoteFeatureFlagControllerState,\n FeatureFlags,\n} from './remote-feature-flag-controller-types';\nexport { ClientConfigApiService } from './client-config-api-service/client-config-api-service';\nexport { generateDeterministicRandomNumber } from './utils/user-segmentation-utils';\n"]}
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,6CAAyC;AAU/E,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,eAAe,EAChB,mDAA+C;AAGhD,OAAO,EAAE,sBAAsB,EAAE,kEAA8D;AAC/F,OAAO,EAAE,iCAAiC,EAAE,4CAAwC","sourcesContent":["export { RemoteFeatureFlagController } from './remote-feature-flag-controller';\nexport type {\n RemoteFeatureFlagControllerState,\n RemoteFeatureFlagControllerMessenger,\n RemoteFeatureFlagControllerActions,\n RemoteFeatureFlagControllerGetStateAction,\n RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction,\n RemoteFeatureFlagControllerEvents,\n RemoteFeatureFlagControllerStateChangeEvent,\n} from './remote-feature-flag-controller';\nexport {\n ClientType,\n DistributionType,\n EnvironmentType,\n} from './remote-feature-flag-controller-types';\n\nexport type { FeatureFlags } from './remote-feature-flag-controller-types';\nexport { ClientConfigApiService } from './client-config-api-service/client-config-api-service';\nexport { generateDeterministicRandomNumber } from './utils/user-segmentation-utils';\n"]}

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller-types.cjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":";;;AAEA,mEAAmE;AACnE,IAAY,UAGX;AAHD,WAAY,UAAU;IACpB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;AACnB,CAAC,EAHW,UAAU,0BAAV,UAAU,QAGrB;AAED,IAAY,gBAOX;AAPD,WAAY,gBAAgB;IAC1B,iCAAa,CAAA;IACb,mCAAe,CAAA;IACf;;OAEG;IACH,iCAAa,CAAA;AACf,CAAC,EAPW,gBAAgB,gCAAhB,gBAAgB,QAO3B;AAED,IAAY,eAOX;AAPD,WAAY,eAAe;IACzB,sCAAmB,CAAA;IACnB,0CAAuB,CAAA;IACvB,sCAAmB,CAAA;IACnB,gCAAa,CAAA;IACb,gCAAa,CAAA;IACb,8BAAW,CAAA;AACb,CAAC,EAPW,eAAe,+BAAf,eAAe,QAO1B","sourcesContent":["import type { Json } from '@metamask/utils';\n\n// Define accepted values for client, distribution, and environment\nexport enum ClientType {\n Extension = 'extension',\n Mobile = 'mobile',\n}\n\nexport enum DistributionType {\n Main = 'main',\n Flask = 'flask',\n /**\n * @deprecated Use DistributionType Main with EnvironmentType Beta instead\n */\n Beta = 'beta',\n}\n\nexport enum EnvironmentType {\n Production = 'prod',\n ReleaseCandidate = 'rc',\n Development = 'dev',\n Beta = 'beta',\n Test = 'test',\n Exp = 'exp',\n}\n\n/** Type representing the feature flags collection */\nexport type FeatureFlags = {\n [key: string]: Json;\n};\n\nexport type FeatureFlagScope = {\n type: string;\n value: number;\n};\n\nexport type FeatureFlagScopeValue = {\n name: string;\n scope: FeatureFlagScope;\n value: Json;\n};\n\nexport type ApiDataResponse = FeatureFlags[];\n\nexport type ServiceResponse = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number | null;\n};\n\n/**\n * Describes the shape of the state object for the {@link RemoteFeatureFlagController}.\n */\nexport type RemoteFeatureFlagControllerState = {\n /**\n * The collection of feature flags and their respective values, which can be objects.\n */\n remoteFeatureFlags: FeatureFlags;\n /**\n * The timestamp of the last successful feature flag cache.\n */\n cacheTimestamp: number;\n};\n"]}
{"version":3,"file":"remote-feature-flag-controller-types.cjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":";;;AAEA,mEAAmE;AACnE,IAAY,UAGX;AAHD,WAAY,UAAU;IACpB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;AACnB,CAAC,EAHW,UAAU,0BAAV,UAAU,QAGrB;AAED,IAAY,gBAOX;AAPD,WAAY,gBAAgB;IAC1B,iCAAa,CAAA;IACb,mCAAe,CAAA;IACf;;OAEG;IACH,iCAAa,CAAA;AACf,CAAC,EAPW,gBAAgB,gCAAhB,gBAAgB,QAO3B;AAED,IAAY,eAOX;AAPD,WAAY,eAAe;IACzB,sCAAmB,CAAA;IACnB,0CAAuB,CAAA;IACvB,sCAAmB,CAAA;IACnB,gCAAa,CAAA;IACb,gCAAa,CAAA;IACb,8BAAW,CAAA;AACb,CAAC,EAPW,eAAe,+BAAf,eAAe,QAO1B","sourcesContent":["import type { Json } from '@metamask/utils';\n\n// Define accepted values for client, distribution, and environment\nexport enum ClientType {\n Extension = 'extension',\n Mobile = 'mobile',\n}\n\nexport enum DistributionType {\n Main = 'main',\n Flask = 'flask',\n /**\n * @deprecated Use DistributionType Main with EnvironmentType Beta instead\n */\n Beta = 'beta',\n}\n\nexport enum EnvironmentType {\n Production = 'prod',\n ReleaseCandidate = 'rc',\n Development = 'dev',\n Beta = 'beta',\n Test = 'test',\n Exp = 'exp',\n}\n\n/** Type representing the feature flags collection */\nexport type FeatureFlags = {\n [key: string]: Json;\n};\n\nexport type FeatureFlagScope = {\n type: string;\n value: number;\n};\n\nexport type FeatureFlagScopeValue = {\n name: string;\n scope: FeatureFlagScope;\n value: Json;\n};\n\nexport type ApiDataResponse = FeatureFlags[];\n\nexport type ServiceResponse = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number | null;\n};\n"]}

@@ -40,15 +40,2 @@ import type { Json } from "@metamask/utils";

};
/**
* Describes the shape of the state object for the {@link RemoteFeatureFlagController}.
*/
export type RemoteFeatureFlagControllerState = {
/**
* The collection of feature flags and their respective values, which can be objects.
*/
remoteFeatureFlags: FeatureFlags;
/**
* The timestamp of the last successful feature flag cache.
*/
cacheTimestamp: number;
};
//# sourceMappingURL=remote-feature-flag-controller-types.d.cts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller-types.d.cts","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAG5C,oBAAY,UAAU;IACpB,SAAS,cAAc;IACvB,MAAM,WAAW;CAClB;AAED,oBAAY,gBAAgB;IAC1B,IAAI,SAAS;IACb,KAAK,UAAU;IACf;;OAEG;IACH,IAAI,SAAS;CACd;AAED,oBAAY,eAAe;IACzB,UAAU,SAAS;IACnB,gBAAgB,OAAO;IACvB,WAAW,QAAQ;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,GAAG,QAAQ;CACZ;AAED,qDAAqD;AACrD,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,IAAI,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,YAAY,EAAE,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG;IAC5B,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C;;OAEG;IACH,kBAAkB,EAAE,YAAY,CAAC;IACjC;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC"}
{"version":3,"file":"remote-feature-flag-controller-types.d.cts","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAG5C,oBAAY,UAAU;IACpB,SAAS,cAAc;IACvB,MAAM,WAAW;CAClB;AAED,oBAAY,gBAAgB;IAC1B,IAAI,SAAS;IACb,KAAK,UAAU;IACf;;OAEG;IACH,IAAI,SAAS;CACd;AAED,oBAAY,eAAe;IACzB,UAAU,SAAS;IACnB,gBAAgB,OAAO;IACvB,WAAW,QAAQ;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,GAAG,QAAQ;CACZ;AAED,qDAAqD;AACrD,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,IAAI,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,YAAY,EAAE,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG;IAC5B,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC"}

@@ -40,15 +40,2 @@ import type { Json } from "@metamask/utils";

};
/**
* Describes the shape of the state object for the {@link RemoteFeatureFlagController}.
*/
export type RemoteFeatureFlagControllerState = {
/**
* The collection of feature flags and their respective values, which can be objects.
*/
remoteFeatureFlags: FeatureFlags;
/**
* The timestamp of the last successful feature flag cache.
*/
cacheTimestamp: number;
};
//# sourceMappingURL=remote-feature-flag-controller-types.d.mts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller-types.d.mts","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAG5C,oBAAY,UAAU;IACpB,SAAS,cAAc;IACvB,MAAM,WAAW;CAClB;AAED,oBAAY,gBAAgB;IAC1B,IAAI,SAAS;IACb,KAAK,UAAU;IACf;;OAEG;IACH,IAAI,SAAS;CACd;AAED,oBAAY,eAAe;IACzB,UAAU,SAAS;IACnB,gBAAgB,OAAO;IACvB,WAAW,QAAQ;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,GAAG,QAAQ;CACZ;AAED,qDAAqD;AACrD,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,IAAI,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,YAAY,EAAE,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG;IAC5B,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C;;OAEG;IACH,kBAAkB,EAAE,YAAY,CAAC;IACjC;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC"}
{"version":3,"file":"remote-feature-flag-controller-types.d.mts","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAG5C,oBAAY,UAAU;IACpB,SAAS,cAAc;IACvB,MAAM,WAAW;CAClB;AAED,oBAAY,gBAAgB;IAC1B,IAAI,SAAS;IACb,KAAK,UAAU;IACf;;OAEG;IACH,IAAI,SAAS;CACd;AAED,oBAAY,eAAe;IACzB,UAAU,SAAS;IACnB,gBAAgB,OAAO;IACvB,WAAW,QAAQ;IACnB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,GAAG,QAAQ;CACZ;AAED,qDAAqD;AACrD,MAAM,MAAM,YAAY,GAAG;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,gBAAgB,CAAC;IACxB,KAAK,EAAE,IAAI,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,YAAY,EAAE,CAAC;AAE7C,MAAM,MAAM,eAAe,GAAG;IAC5B,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B,CAAC"}

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller-types.mjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":"AAEA,mEAAmE;AACnE,MAAM,CAAN,IAAY,UAGX;AAHD,WAAY,UAAU;IACpB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;AACnB,CAAC,EAHW,UAAU,KAAV,UAAU,QAGrB;AAED,MAAM,CAAN,IAAY,gBAOX;AAPD,WAAY,gBAAgB;IAC1B,iCAAa,CAAA;IACb,mCAAe,CAAA;IACf;;OAEG;IACH,iCAAa,CAAA;AACf,CAAC,EAPW,gBAAgB,KAAhB,gBAAgB,QAO3B;AAED,MAAM,CAAN,IAAY,eAOX;AAPD,WAAY,eAAe;IACzB,sCAAmB,CAAA;IACnB,0CAAuB,CAAA;IACvB,sCAAmB,CAAA;IACnB,gCAAa,CAAA;IACb,gCAAa,CAAA;IACb,8BAAW,CAAA;AACb,CAAC,EAPW,eAAe,KAAf,eAAe,QAO1B","sourcesContent":["import type { Json } from '@metamask/utils';\n\n// Define accepted values for client, distribution, and environment\nexport enum ClientType {\n Extension = 'extension',\n Mobile = 'mobile',\n}\n\nexport enum DistributionType {\n Main = 'main',\n Flask = 'flask',\n /**\n * @deprecated Use DistributionType Main with EnvironmentType Beta instead\n */\n Beta = 'beta',\n}\n\nexport enum EnvironmentType {\n Production = 'prod',\n ReleaseCandidate = 'rc',\n Development = 'dev',\n Beta = 'beta',\n Test = 'test',\n Exp = 'exp',\n}\n\n/** Type representing the feature flags collection */\nexport type FeatureFlags = {\n [key: string]: Json;\n};\n\nexport type FeatureFlagScope = {\n type: string;\n value: number;\n};\n\nexport type FeatureFlagScopeValue = {\n name: string;\n scope: FeatureFlagScope;\n value: Json;\n};\n\nexport type ApiDataResponse = FeatureFlags[];\n\nexport type ServiceResponse = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number | null;\n};\n\n/**\n * Describes the shape of the state object for the {@link RemoteFeatureFlagController}.\n */\nexport type RemoteFeatureFlagControllerState = {\n /**\n * The collection of feature flags and their respective values, which can be objects.\n */\n remoteFeatureFlags: FeatureFlags;\n /**\n * The timestamp of the last successful feature flag cache.\n */\n cacheTimestamp: number;\n};\n"]}
{"version":3,"file":"remote-feature-flag-controller-types.mjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller-types.ts"],"names":[],"mappings":"AAEA,mEAAmE;AACnE,MAAM,CAAN,IAAY,UAGX;AAHD,WAAY,UAAU;IACpB,qCAAuB,CAAA;IACvB,+BAAiB,CAAA;AACnB,CAAC,EAHW,UAAU,KAAV,UAAU,QAGrB;AAED,MAAM,CAAN,IAAY,gBAOX;AAPD,WAAY,gBAAgB;IAC1B,iCAAa,CAAA;IACb,mCAAe,CAAA;IACf;;OAEG;IACH,iCAAa,CAAA;AACf,CAAC,EAPW,gBAAgB,KAAhB,gBAAgB,QAO3B;AAED,MAAM,CAAN,IAAY,eAOX;AAPD,WAAY,eAAe;IACzB,sCAAmB,CAAA;IACnB,0CAAuB,CAAA;IACvB,sCAAmB,CAAA;IACnB,gCAAa,CAAA;IACb,gCAAa,CAAA;IACb,8BAAW,CAAA;AACb,CAAC,EAPW,eAAe,KAAf,eAAe,QAO1B","sourcesContent":["import type { Json } from '@metamask/utils';\n\n// Define accepted values for client, distribution, and environment\nexport enum ClientType {\n Extension = 'extension',\n Mobile = 'mobile',\n}\n\nexport enum DistributionType {\n Main = 'main',\n Flask = 'flask',\n /**\n * @deprecated Use DistributionType Main with EnvironmentType Beta instead\n */\n Beta = 'beta',\n}\n\nexport enum EnvironmentType {\n Production = 'prod',\n ReleaseCandidate = 'rc',\n Development = 'dev',\n Beta = 'beta',\n Test = 'test',\n Exp = 'exp',\n}\n\n/** Type representing the feature flags collection */\nexport type FeatureFlags = {\n [key: string]: Json;\n};\n\nexport type FeatureFlagScope = {\n type: string;\n value: number;\n};\n\nexport type FeatureFlagScopeValue = {\n name: string;\n scope: FeatureFlagScope;\n value: Json;\n};\n\nexport type ApiDataResponse = FeatureFlags[];\n\nexport type ServiceResponse = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number | null;\n};\n"]}

@@ -15,7 +15,7 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.RemoteFeatureFlagController = exports.getDefaultRemoteFeatureFlagControllerState = exports.DEFAULT_CACHE_DURATION = exports.controllerName = void 0;
exports.RemoteFeatureFlagController = exports.getDefaultRemoteFeatureFlagControllerState = exports.DEFAULT_CACHE_DURATION = void 0;
const base_controller_1 = require("@metamask/base-controller");
const user_segmentation_utils_1 = require("./utils/user-segmentation-utils.cjs");
// === GENERAL ===
exports.controllerName = 'RemoteFeatureFlagController';
const controllerName = 'RemoteFeatureFlagController';
exports.DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day

@@ -26,3 +26,3 @@ const remoteFeatureFlagControllerMetadata = {

persist: true,
anonymous: true,
includeInDebugSnapshot: true,
usedInUi: true,

@@ -33,3 +33,3 @@ },

persist: true,
anonymous: true,
includeInDebugSnapshot: true,
usedInUi: false,

@@ -70,3 +70,3 @@ },

super({
name: exports.controllerName,
name: controllerName,
metadata: remoteFeatureFlagControllerMetadata,

@@ -73,0 +73,0 @@ messenger,

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller.cjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\n\nimport type { AbstractClientConfigApiService } from './client-config-api-service/abstract-client-config-api-service';\nimport type {\n FeatureFlags,\n ServiceResponse,\n FeatureFlagScopeValue,\n} from './remote-feature-flag-controller-types';\nimport {\n generateDeterministicRandomNumber,\n isFeatureFlagWithScopeValue,\n} from './utils/user-segmentation-utils';\n\n// === GENERAL ===\n\nexport const controllerName = 'RemoteFeatureFlagController';\nexport const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day\n\n// === STATE ===\n\nexport type RemoteFeatureFlagControllerState = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number;\n};\n\nconst remoteFeatureFlagControllerMetadata = {\n remoteFeatureFlags: {\n includeInStateLogs: true,\n persist: true,\n anonymous: true,\n usedInUi: true,\n },\n cacheTimestamp: {\n includeInStateLogs: true,\n persist: true,\n anonymous: true,\n usedInUi: false,\n },\n};\n\n// === MESSENGER ===\n\n/**\n * The action to retrieve the state of the {@link RemoteFeatureFlagController}.\n */\nexport type RemoteFeatureFlagControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction = {\n type: `${typeof controllerName}:updateRemoteFeatureFlags`;\n handler: RemoteFeatureFlagController['updateRemoteFeatureFlags'];\n};\n\nexport type RemoteFeatureFlagControllerActions =\n | RemoteFeatureFlagControllerGetStateAction\n | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction;\n\nexport type AllowedActions = never;\n\nexport type RemoteFeatureFlagControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerEvents =\n RemoteFeatureFlagControllerStateChangeEvent;\n\nexport type AllowedEvents = never;\n\nexport type RemoteFeatureFlagControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n RemoteFeatureFlagControllerActions | AllowedActions,\n RemoteFeatureFlagControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Returns the default state for the RemoteFeatureFlagController.\n *\n * @returns The default controller state.\n */\nexport function getDefaultRemoteFeatureFlagControllerState(): RemoteFeatureFlagControllerState {\n return {\n remoteFeatureFlags: {},\n cacheTimestamp: 0,\n };\n}\n\n/**\n * The RemoteFeatureFlagController manages the retrieval and caching of remote feature flags.\n * It fetches feature flags from a remote API, caches them, and provides methods to access\n * and manage these flags. The controller ensures that feature flags are refreshed based on\n * a specified interval and handles cases where the controller is disabled or the network is unavailable.\n */\nexport class RemoteFeatureFlagController extends BaseController<\n typeof controllerName,\n RemoteFeatureFlagControllerState,\n RemoteFeatureFlagControllerMessenger\n> {\n readonly #fetchInterval: number;\n\n #disabled: boolean;\n\n readonly #clientConfigApiService: AbstractClientConfigApiService;\n\n #inProgressFlagUpdate?: Promise<ServiceResponse>;\n\n #getMetaMetricsId: () => string;\n\n /**\n * Constructs a new RemoteFeatureFlagController instance.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger used for communication.\n * @param options.state - The initial state of the controller.\n * @param options.clientConfigApiService - The service instance to fetch remote feature flags.\n * @param options.fetchInterval - The interval in milliseconds before cached flags expire. Defaults to 1 day.\n * @param options.disabled - Determines if the controller should be disabled initially. Defaults to false.\n * @param options.getMetaMetricsId - Returns metaMetricsId.\n */\n constructor({\n messenger,\n state,\n clientConfigApiService,\n fetchInterval = DEFAULT_CACHE_DURATION,\n disabled = false,\n getMetaMetricsId,\n }: {\n messenger: RemoteFeatureFlagControllerMessenger;\n state?: Partial<RemoteFeatureFlagControllerState>;\n clientConfigApiService: AbstractClientConfigApiService;\n getMetaMetricsId: () => string;\n fetchInterval?: number;\n disabled?: boolean;\n }) {\n super({\n name: controllerName,\n metadata: remoteFeatureFlagControllerMetadata,\n messenger,\n state: {\n ...getDefaultRemoteFeatureFlagControllerState(),\n ...state,\n },\n });\n\n this.#fetchInterval = fetchInterval;\n this.#disabled = disabled;\n this.#clientConfigApiService = clientConfigApiService;\n this.#getMetaMetricsId = getMetaMetricsId;\n }\n\n /**\n * Checks if the cached feature flags are expired based on the fetch interval.\n *\n * @returns Whether the cache is expired (`true`) or still valid (`false`).\n * @private\n */\n #isCacheExpired(): boolean {\n return Date.now() - this.state.cacheTimestamp > this.#fetchInterval;\n }\n\n /**\n * Retrieves the remote feature flags, fetching from the API if necessary.\n * Uses caching to prevent redundant API calls and handles concurrent fetches.\n *\n * @returns A promise that resolves to the current set of feature flags.\n */\n async updateRemoteFeatureFlags(): Promise<void> {\n if (this.#disabled || !this.#isCacheExpired()) {\n return;\n }\n\n let serverData;\n\n if (this.#inProgressFlagUpdate) {\n await this.#inProgressFlagUpdate;\n return;\n }\n\n try {\n this.#inProgressFlagUpdate =\n this.#clientConfigApiService.fetchRemoteFeatureFlags();\n\n serverData = await this.#inProgressFlagUpdate;\n } finally {\n this.#inProgressFlagUpdate = undefined;\n }\n\n await this.#updateCache(serverData.remoteFeatureFlags);\n }\n\n /**\n * Updates the controller's state with new feature flags and resets the cache timestamp.\n *\n * @param remoteFeatureFlags - The new feature flags to cache.\n * @private\n */\n async #updateCache(remoteFeatureFlags: FeatureFlags) {\n const processedRemoteFeatureFlags =\n await this.#processRemoteFeatureFlags(remoteFeatureFlags);\n this.update(() => {\n return {\n remoteFeatureFlags: processedRemoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n });\n }\n\n async #processRemoteFeatureFlags(\n remoteFeatureFlags: FeatureFlags,\n ): Promise<FeatureFlags> {\n const processedRemoteFeatureFlags: FeatureFlags = {};\n const metaMetricsId = this.#getMetaMetricsId();\n const thresholdValue = generateDeterministicRandomNumber(metaMetricsId);\n\n for (const [\n remoteFeatureFlagName,\n remoteFeatureFlagValue,\n ] of Object.entries(remoteFeatureFlags)) {\n let processedValue = remoteFeatureFlagValue;\n\n if (Array.isArray(remoteFeatureFlagValue) && thresholdValue) {\n const selectedGroup = remoteFeatureFlagValue.find(\n (featureFlag): featureFlag is FeatureFlagScopeValue => {\n if (!isFeatureFlagWithScopeValue(featureFlag)) {\n return false;\n }\n\n return thresholdValue <= featureFlag.scope.value;\n },\n );\n if (selectedGroup) {\n processedValue = {\n name: selectedGroup.name,\n value: selectedGroup.value,\n };\n }\n }\n\n processedRemoteFeatureFlags[remoteFeatureFlagName] = processedValue;\n }\n return processedRemoteFeatureFlags;\n }\n\n /**\n * Enables the controller, allowing it to make network requests.\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Disables the controller, preventing it from making network requests.\n */\n disable(): void {\n this.#disabled = true;\n }\n}\n"]}
{"version":3,"file":"remote-feature-flag-controller.cjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { AbstractClientConfigApiService } from './client-config-api-service/abstract-client-config-api-service';\nimport type {\n FeatureFlags,\n ServiceResponse,\n FeatureFlagScopeValue,\n} from './remote-feature-flag-controller-types';\nimport {\n generateDeterministicRandomNumber,\n isFeatureFlagWithScopeValue,\n} from './utils/user-segmentation-utils';\n\n// === GENERAL ===\n\nconst controllerName = 'RemoteFeatureFlagController';\nexport const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day\n\n// === STATE ===\n\nexport type RemoteFeatureFlagControllerState = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number;\n};\n\nconst remoteFeatureFlagControllerMetadata = {\n remoteFeatureFlags: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n cacheTimestamp: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n};\n\n// === MESSENGER ===\n\n/**\n * The action to retrieve the state of the {@link RemoteFeatureFlagController}.\n */\nexport type RemoteFeatureFlagControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction = {\n type: `${typeof controllerName}:updateRemoteFeatureFlags`;\n handler: RemoteFeatureFlagController['updateRemoteFeatureFlags'];\n};\n\nexport type RemoteFeatureFlagControllerActions =\n | RemoteFeatureFlagControllerGetStateAction\n | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction;\n\nexport type RemoteFeatureFlagControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerEvents =\n RemoteFeatureFlagControllerStateChangeEvent;\n\nexport type RemoteFeatureFlagControllerMessenger = Messenger<\n typeof controllerName,\n RemoteFeatureFlagControllerActions,\n RemoteFeatureFlagControllerEvents\n>;\n\n/**\n * Returns the default state for the RemoteFeatureFlagController.\n *\n * @returns The default controller state.\n */\nexport function getDefaultRemoteFeatureFlagControllerState(): RemoteFeatureFlagControllerState {\n return {\n remoteFeatureFlags: {},\n cacheTimestamp: 0,\n };\n}\n\n/**\n * The RemoteFeatureFlagController manages the retrieval and caching of remote feature flags.\n * It fetches feature flags from a remote API, caches them, and provides methods to access\n * and manage these flags. The controller ensures that feature flags are refreshed based on\n * a specified interval and handles cases where the controller is disabled or the network is unavailable.\n */\nexport class RemoteFeatureFlagController extends BaseController<\n typeof controllerName,\n RemoteFeatureFlagControllerState,\n RemoteFeatureFlagControllerMessenger\n> {\n readonly #fetchInterval: number;\n\n #disabled: boolean;\n\n readonly #clientConfigApiService: AbstractClientConfigApiService;\n\n #inProgressFlagUpdate?: Promise<ServiceResponse>;\n\n #getMetaMetricsId: () => string;\n\n /**\n * Constructs a new RemoteFeatureFlagController instance.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger used for communication.\n * @param options.state - The initial state of the controller.\n * @param options.clientConfigApiService - The service instance to fetch remote feature flags.\n * @param options.fetchInterval - The interval in milliseconds before cached flags expire. Defaults to 1 day.\n * @param options.disabled - Determines if the controller should be disabled initially. Defaults to false.\n * @param options.getMetaMetricsId - Returns metaMetricsId.\n */\n constructor({\n messenger,\n state,\n clientConfigApiService,\n fetchInterval = DEFAULT_CACHE_DURATION,\n disabled = false,\n getMetaMetricsId,\n }: {\n messenger: RemoteFeatureFlagControllerMessenger;\n state?: Partial<RemoteFeatureFlagControllerState>;\n clientConfigApiService: AbstractClientConfigApiService;\n getMetaMetricsId: () => string;\n fetchInterval?: number;\n disabled?: boolean;\n }) {\n super({\n name: controllerName,\n metadata: remoteFeatureFlagControllerMetadata,\n messenger,\n state: {\n ...getDefaultRemoteFeatureFlagControllerState(),\n ...state,\n },\n });\n\n this.#fetchInterval = fetchInterval;\n this.#disabled = disabled;\n this.#clientConfigApiService = clientConfigApiService;\n this.#getMetaMetricsId = getMetaMetricsId;\n }\n\n /**\n * Checks if the cached feature flags are expired based on the fetch interval.\n *\n * @returns Whether the cache is expired (`true`) or still valid (`false`).\n * @private\n */\n #isCacheExpired(): boolean {\n return Date.now() - this.state.cacheTimestamp > this.#fetchInterval;\n }\n\n /**\n * Retrieves the remote feature flags, fetching from the API if necessary.\n * Uses caching to prevent redundant API calls and handles concurrent fetches.\n *\n * @returns A promise that resolves to the current set of feature flags.\n */\n async updateRemoteFeatureFlags(): Promise<void> {\n if (this.#disabled || !this.#isCacheExpired()) {\n return;\n }\n\n let serverData;\n\n if (this.#inProgressFlagUpdate) {\n await this.#inProgressFlagUpdate;\n return;\n }\n\n try {\n this.#inProgressFlagUpdate =\n this.#clientConfigApiService.fetchRemoteFeatureFlags();\n\n serverData = await this.#inProgressFlagUpdate;\n } finally {\n this.#inProgressFlagUpdate = undefined;\n }\n\n await this.#updateCache(serverData.remoteFeatureFlags);\n }\n\n /**\n * Updates the controller's state with new feature flags and resets the cache timestamp.\n *\n * @param remoteFeatureFlags - The new feature flags to cache.\n * @private\n */\n async #updateCache(remoteFeatureFlags: FeatureFlags) {\n const processedRemoteFeatureFlags =\n await this.#processRemoteFeatureFlags(remoteFeatureFlags);\n this.update(() => {\n return {\n remoteFeatureFlags: processedRemoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n });\n }\n\n async #processRemoteFeatureFlags(\n remoteFeatureFlags: FeatureFlags,\n ): Promise<FeatureFlags> {\n const processedRemoteFeatureFlags: FeatureFlags = {};\n const metaMetricsId = this.#getMetaMetricsId();\n const thresholdValue = generateDeterministicRandomNumber(metaMetricsId);\n\n for (const [\n remoteFeatureFlagName,\n remoteFeatureFlagValue,\n ] of Object.entries(remoteFeatureFlags)) {\n let processedValue = remoteFeatureFlagValue;\n\n if (Array.isArray(remoteFeatureFlagValue) && thresholdValue) {\n const selectedGroup = remoteFeatureFlagValue.find(\n (featureFlag): featureFlag is FeatureFlagScopeValue => {\n if (!isFeatureFlagWithScopeValue(featureFlag)) {\n return false;\n }\n\n return thresholdValue <= featureFlag.scope.value;\n },\n );\n if (selectedGroup) {\n processedValue = {\n name: selectedGroup.name,\n value: selectedGroup.value,\n };\n }\n }\n\n processedRemoteFeatureFlags[remoteFeatureFlagName] = processedValue;\n }\n return processedRemoteFeatureFlags;\n }\n\n /**\n * Enables the controller, allowing it to make network requests.\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Disables the controller, preventing it from making network requests.\n */\n disable(): void {\n this.#disabled = true;\n }\n}\n"]}

@@ -1,6 +0,6 @@

import { BaseController } from "@metamask/base-controller";
import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMessenger } from "@metamask/base-controller";
import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent } from "@metamask/base-controller";
import type { Messenger } from "@metamask/messenger";
import type { AbstractClientConfigApiService } from "./client-config-api-service/abstract-client-config-api-service.cjs";
import type { FeatureFlags } from "./remote-feature-flag-controller-types.cjs";
export declare const controllerName = "RemoteFeatureFlagController";
declare const controllerName = "RemoteFeatureFlagController";
export declare const DEFAULT_CACHE_DURATION: number;

@@ -20,7 +20,5 @@ export type RemoteFeatureFlagControllerState = {

export type RemoteFeatureFlagControllerActions = RemoteFeatureFlagControllerGetStateAction | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction;
export type AllowedActions = never;
export type RemoteFeatureFlagControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, RemoteFeatureFlagControllerState>;
export type RemoteFeatureFlagControllerEvents = RemoteFeatureFlagControllerStateChangeEvent;
export type AllowedEvents = never;
export type RemoteFeatureFlagControllerMessenger = RestrictedMessenger<typeof controllerName, RemoteFeatureFlagControllerActions | AllowedActions, RemoteFeatureFlagControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
export type RemoteFeatureFlagControllerMessenger = Messenger<typeof controllerName, RemoteFeatureFlagControllerActions, RemoteFeatureFlagControllerEvents>;
/**

@@ -75,2 +73,3 @@ * Returns the default state for the RemoteFeatureFlagController.

}
export {};
//# sourceMappingURL=remote-feature-flag-controller.d.cts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller.d.cts","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AAEnC,OAAO,KAAK,EAAE,8BAA8B,EAAE,2EAAuE;AACrH,OAAO,KAAK,EACV,YAAY,EAGb,mDAA+C;AAQhD,eAAO,MAAM,cAAc,gCAAgC,CAAC;AAC5D,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAI1D,MAAM,MAAM,gCAAgC,GAAG;IAC7C,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAmBF;;GAEG;AACH,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,yDAAyD,GAAG;IACtE,IAAI,EAAE,GAAG,OAAO,cAAc,2BAA2B,CAAC;IAC1D,OAAO,EAAE,2BAA2B,CAAC,0BAA0B,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,yDAAyD,CAAC;AAE9D,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC;AAEnC,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC;AAElC,MAAM,MAAM,oCAAoC,GAAG,mBAAmB,CACpE,OAAO,cAAc,EACrB,kCAAkC,GAAG,cAAc,EACnD,iCAAiC,GAAG,aAAa,EACjD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0CAA0C,IAAI,gCAAgC,CAK7F;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IAWC;;;;;;;;;;OAUG;gBACS,EACV,SAAS,EACT,KAAK,EACL,sBAAsB,EACtB,aAAsC,EACtC,QAAgB,EAChB,gBAAgB,GACjB,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;QAClD,sBAAsB,EAAE,8BAA8B,CAAC;QACvD,gBAAgB,EAAE,MAAM,MAAM,CAAC;QAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;IA2BD;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6E/C;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}
{"version":3,"file":"remote-feature-flag-controller.d.cts","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAChC,kCAAkC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,8BAA8B,EAAE,2EAAuE;AACrH,OAAO,KAAK,EACV,YAAY,EAGb,mDAA+C;AAQhD,QAAA,MAAM,cAAc,gCAAgC,CAAC;AACrD,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAI1D,MAAM,MAAM,gCAAgC,GAAG;IAC7C,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAmBF;;GAEG;AACH,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,yDAAyD,GAAG;IACtE,IAAI,EAAE,GAAG,OAAO,cAAc,2BAA2B,CAAC;IAC1D,OAAO,EAAE,2BAA2B,CAAC,0BAA0B,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,yDAAyD,CAAC;AAE9D,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C,MAAM,MAAM,oCAAoC,GAAG,SAAS,CAC1D,OAAO,cAAc,EACrB,kCAAkC,EAClC,iCAAiC,CAClC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0CAA0C,IAAI,gCAAgC,CAK7F;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IAWC;;;;;;;;;;OAUG;gBACS,EACV,SAAS,EACT,KAAK,EACL,sBAAsB,EACtB,aAAsC,EACtC,QAAgB,EAChB,gBAAgB,GACjB,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;QAClD,sBAAsB,EAAE,8BAA8B,CAAC;QACvD,gBAAgB,EAAE,MAAM,MAAM,CAAC;QAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;IA2BD;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6E/C;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}

@@ -1,6 +0,6 @@

import { BaseController } from "@metamask/base-controller";
import type { ControllerGetStateAction, ControllerStateChangeEvent, RestrictedMessenger } from "@metamask/base-controller";
import { BaseController, type ControllerGetStateAction, type ControllerStateChangeEvent } from "@metamask/base-controller";
import type { Messenger } from "@metamask/messenger";
import type { AbstractClientConfigApiService } from "./client-config-api-service/abstract-client-config-api-service.mjs";
import type { FeatureFlags } from "./remote-feature-flag-controller-types.mjs";
export declare const controllerName = "RemoteFeatureFlagController";
declare const controllerName = "RemoteFeatureFlagController";
export declare const DEFAULT_CACHE_DURATION: number;

@@ -20,7 +20,5 @@ export type RemoteFeatureFlagControllerState = {

export type RemoteFeatureFlagControllerActions = RemoteFeatureFlagControllerGetStateAction | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction;
export type AllowedActions = never;
export type RemoteFeatureFlagControllerStateChangeEvent = ControllerStateChangeEvent<typeof controllerName, RemoteFeatureFlagControllerState>;
export type RemoteFeatureFlagControllerEvents = RemoteFeatureFlagControllerStateChangeEvent;
export type AllowedEvents = never;
export type RemoteFeatureFlagControllerMessenger = RestrictedMessenger<typeof controllerName, RemoteFeatureFlagControllerActions | AllowedActions, RemoteFeatureFlagControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
export type RemoteFeatureFlagControllerMessenger = Messenger<typeof controllerName, RemoteFeatureFlagControllerActions, RemoteFeatureFlagControllerEvents>;
/**

@@ -75,2 +73,3 @@ * Returns the default state for the RemoteFeatureFlagController.

}
export {};
//# sourceMappingURL=remote-feature-flag-controller.d.mts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller.d.mts","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACpB,kCAAkC;AAEnC,OAAO,KAAK,EAAE,8BAA8B,EAAE,2EAAuE;AACrH,OAAO,KAAK,EACV,YAAY,EAGb,mDAA+C;AAQhD,eAAO,MAAM,cAAc,gCAAgC,CAAC;AAC5D,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAI1D,MAAM,MAAM,gCAAgC,GAAG;IAC7C,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAmBF;;GAEG;AACH,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,yDAAyD,GAAG;IACtE,IAAI,EAAE,GAAG,OAAO,cAAc,2BAA2B,CAAC;IAC1D,OAAO,EAAE,2BAA2B,CAAC,0BAA0B,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,yDAAyD,CAAC;AAE9D,MAAM,MAAM,cAAc,GAAG,KAAK,CAAC;AAEnC,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C,MAAM,MAAM,aAAa,GAAG,KAAK,CAAC;AAElC,MAAM,MAAM,oCAAoC,GAAG,mBAAmB,CACpE,OAAO,cAAc,EACrB,kCAAkC,GAAG,cAAc,EACnD,iCAAiC,GAAG,aAAa,EACjD,cAAc,CAAC,MAAM,CAAC,EACtB,aAAa,CAAC,MAAM,CAAC,CACtB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0CAA0C,IAAI,gCAAgC,CAK7F;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IAWC;;;;;;;;;;OAUG;gBACS,EACV,SAAS,EACT,KAAK,EACL,sBAAsB,EACtB,aAAsC,EACtC,QAAgB,EAChB,gBAAgB,GACjB,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;QAClD,sBAAsB,EAAE,8BAA8B,CAAC;QACvD,gBAAgB,EAAE,MAAM,MAAM,CAAC;QAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;IA2BD;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6E/C;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}
{"version":3,"file":"remote-feature-flag-controller.d.mts","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAChC,kCAAkC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,KAAK,EAAE,8BAA8B,EAAE,2EAAuE;AACrH,OAAO,KAAK,EACV,YAAY,EAGb,mDAA+C;AAQhD,QAAA,MAAM,cAAc,gCAAgC,CAAC;AACrD,eAAO,MAAM,sBAAsB,QAAsB,CAAC;AAI1D,MAAM,MAAM,gCAAgC,GAAG;IAC7C,kBAAkB,EAAE,YAAY,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAmBF;;GAEG;AACH,MAAM,MAAM,yCAAyC,GACnD,wBAAwB,CACtB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,yDAAyD,GAAG;IACtE,IAAI,EAAE,GAAG,OAAO,cAAc,2BAA2B,CAAC;IAC1D,OAAO,EAAE,2BAA2B,CAAC,0BAA0B,CAAC,CAAC;CAClE,CAAC;AAEF,MAAM,MAAM,kCAAkC,GAC1C,yCAAyC,GACzC,yDAAyD,CAAC;AAE9D,MAAM,MAAM,2CAA2C,GACrD,0BAA0B,CACxB,OAAO,cAAc,EACrB,gCAAgC,CACjC,CAAC;AAEJ,MAAM,MAAM,iCAAiC,GAC3C,2CAA2C,CAAC;AAE9C,MAAM,MAAM,oCAAoC,GAAG,SAAS,CAC1D,OAAO,cAAc,EACrB,kCAAkC,EAClC,iCAAiC,CAClC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,0CAA0C,IAAI,gCAAgC,CAK7F;AAED;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,cAAc,CAC7D,OAAO,cAAc,EACrB,gCAAgC,EAChC,oCAAoC,CACrC;;IAWC;;;;;;;;;;OAUG;gBACS,EACV,SAAS,EACT,KAAK,EACL,sBAAsB,EACtB,aAAsC,EACtC,QAAgB,EAChB,gBAAgB,GACjB,EAAE;QACD,SAAS,EAAE,oCAAoC,CAAC;QAChD,KAAK,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;QAClD,sBAAsB,EAAE,8BAA8B,CAAC;QACvD,gBAAgB,EAAE,MAAM,MAAM,CAAC;QAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB;IA2BD;;;;;OAKG;IACG,wBAAwB,IAAI,OAAO,CAAC,IAAI,CAAC;IA6E/C;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,OAAO,IAAI,IAAI;CAGhB"}

@@ -16,3 +16,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {

// === GENERAL ===
export const controllerName = 'RemoteFeatureFlagController';
const controllerName = 'RemoteFeatureFlagController';
export const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day

@@ -23,3 +23,3 @@ const remoteFeatureFlagControllerMetadata = {

persist: true,
anonymous: true,
includeInDebugSnapshot: true,
usedInUi: true,

@@ -30,3 +30,3 @@ },

persist: true,
anonymous: true,
includeInDebugSnapshot: true,
usedInUi: false,

@@ -33,0 +33,0 @@ },

@@ -1,1 +0,1 @@

{"version":3,"file":"remote-feature-flag-controller.mjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n} from '@metamask/base-controller';\n\nimport type { AbstractClientConfigApiService } from './client-config-api-service/abstract-client-config-api-service';\nimport type {\n FeatureFlags,\n ServiceResponse,\n FeatureFlagScopeValue,\n} from './remote-feature-flag-controller-types';\nimport {\n generateDeterministicRandomNumber,\n isFeatureFlagWithScopeValue,\n} from './utils/user-segmentation-utils';\n\n// === GENERAL ===\n\nexport const controllerName = 'RemoteFeatureFlagController';\nexport const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day\n\n// === STATE ===\n\nexport type RemoteFeatureFlagControllerState = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number;\n};\n\nconst remoteFeatureFlagControllerMetadata = {\n remoteFeatureFlags: {\n includeInStateLogs: true,\n persist: true,\n anonymous: true,\n usedInUi: true,\n },\n cacheTimestamp: {\n includeInStateLogs: true,\n persist: true,\n anonymous: true,\n usedInUi: false,\n },\n};\n\n// === MESSENGER ===\n\n/**\n * The action to retrieve the state of the {@link RemoteFeatureFlagController}.\n */\nexport type RemoteFeatureFlagControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction = {\n type: `${typeof controllerName}:updateRemoteFeatureFlags`;\n handler: RemoteFeatureFlagController['updateRemoteFeatureFlags'];\n};\n\nexport type RemoteFeatureFlagControllerActions =\n | RemoteFeatureFlagControllerGetStateAction\n | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction;\n\nexport type AllowedActions = never;\n\nexport type RemoteFeatureFlagControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerEvents =\n RemoteFeatureFlagControllerStateChangeEvent;\n\nexport type AllowedEvents = never;\n\nexport type RemoteFeatureFlagControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n RemoteFeatureFlagControllerActions | AllowedActions,\n RemoteFeatureFlagControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * Returns the default state for the RemoteFeatureFlagController.\n *\n * @returns The default controller state.\n */\nexport function getDefaultRemoteFeatureFlagControllerState(): RemoteFeatureFlagControllerState {\n return {\n remoteFeatureFlags: {},\n cacheTimestamp: 0,\n };\n}\n\n/**\n * The RemoteFeatureFlagController manages the retrieval and caching of remote feature flags.\n * It fetches feature flags from a remote API, caches them, and provides methods to access\n * and manage these flags. The controller ensures that feature flags are refreshed based on\n * a specified interval and handles cases where the controller is disabled or the network is unavailable.\n */\nexport class RemoteFeatureFlagController extends BaseController<\n typeof controllerName,\n RemoteFeatureFlagControllerState,\n RemoteFeatureFlagControllerMessenger\n> {\n readonly #fetchInterval: number;\n\n #disabled: boolean;\n\n readonly #clientConfigApiService: AbstractClientConfigApiService;\n\n #inProgressFlagUpdate?: Promise<ServiceResponse>;\n\n #getMetaMetricsId: () => string;\n\n /**\n * Constructs a new RemoteFeatureFlagController instance.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger used for communication.\n * @param options.state - The initial state of the controller.\n * @param options.clientConfigApiService - The service instance to fetch remote feature flags.\n * @param options.fetchInterval - The interval in milliseconds before cached flags expire. Defaults to 1 day.\n * @param options.disabled - Determines if the controller should be disabled initially. Defaults to false.\n * @param options.getMetaMetricsId - Returns metaMetricsId.\n */\n constructor({\n messenger,\n state,\n clientConfigApiService,\n fetchInterval = DEFAULT_CACHE_DURATION,\n disabled = false,\n getMetaMetricsId,\n }: {\n messenger: RemoteFeatureFlagControllerMessenger;\n state?: Partial<RemoteFeatureFlagControllerState>;\n clientConfigApiService: AbstractClientConfigApiService;\n getMetaMetricsId: () => string;\n fetchInterval?: number;\n disabled?: boolean;\n }) {\n super({\n name: controllerName,\n metadata: remoteFeatureFlagControllerMetadata,\n messenger,\n state: {\n ...getDefaultRemoteFeatureFlagControllerState(),\n ...state,\n },\n });\n\n this.#fetchInterval = fetchInterval;\n this.#disabled = disabled;\n this.#clientConfigApiService = clientConfigApiService;\n this.#getMetaMetricsId = getMetaMetricsId;\n }\n\n /**\n * Checks if the cached feature flags are expired based on the fetch interval.\n *\n * @returns Whether the cache is expired (`true`) or still valid (`false`).\n * @private\n */\n #isCacheExpired(): boolean {\n return Date.now() - this.state.cacheTimestamp > this.#fetchInterval;\n }\n\n /**\n * Retrieves the remote feature flags, fetching from the API if necessary.\n * Uses caching to prevent redundant API calls and handles concurrent fetches.\n *\n * @returns A promise that resolves to the current set of feature flags.\n */\n async updateRemoteFeatureFlags(): Promise<void> {\n if (this.#disabled || !this.#isCacheExpired()) {\n return;\n }\n\n let serverData;\n\n if (this.#inProgressFlagUpdate) {\n await this.#inProgressFlagUpdate;\n return;\n }\n\n try {\n this.#inProgressFlagUpdate =\n this.#clientConfigApiService.fetchRemoteFeatureFlags();\n\n serverData = await this.#inProgressFlagUpdate;\n } finally {\n this.#inProgressFlagUpdate = undefined;\n }\n\n await this.#updateCache(serverData.remoteFeatureFlags);\n }\n\n /**\n * Updates the controller's state with new feature flags and resets the cache timestamp.\n *\n * @param remoteFeatureFlags - The new feature flags to cache.\n * @private\n */\n async #updateCache(remoteFeatureFlags: FeatureFlags) {\n const processedRemoteFeatureFlags =\n await this.#processRemoteFeatureFlags(remoteFeatureFlags);\n this.update(() => {\n return {\n remoteFeatureFlags: processedRemoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n });\n }\n\n async #processRemoteFeatureFlags(\n remoteFeatureFlags: FeatureFlags,\n ): Promise<FeatureFlags> {\n const processedRemoteFeatureFlags: FeatureFlags = {};\n const metaMetricsId = this.#getMetaMetricsId();\n const thresholdValue = generateDeterministicRandomNumber(metaMetricsId);\n\n for (const [\n remoteFeatureFlagName,\n remoteFeatureFlagValue,\n ] of Object.entries(remoteFeatureFlags)) {\n let processedValue = remoteFeatureFlagValue;\n\n if (Array.isArray(remoteFeatureFlagValue) && thresholdValue) {\n const selectedGroup = remoteFeatureFlagValue.find(\n (featureFlag): featureFlag is FeatureFlagScopeValue => {\n if (!isFeatureFlagWithScopeValue(featureFlag)) {\n return false;\n }\n\n return thresholdValue <= featureFlag.scope.value;\n },\n );\n if (selectedGroup) {\n processedValue = {\n name: selectedGroup.name,\n value: selectedGroup.value,\n };\n }\n }\n\n processedRemoteFeatureFlags[remoteFeatureFlagName] = processedValue;\n }\n return processedRemoteFeatureFlags;\n }\n\n /**\n * Enables the controller, allowing it to make network requests.\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Disables the controller, preventing it from making network requests.\n */\n disable(): void {\n this.#disabled = true;\n }\n}\n"]}
{"version":3,"file":"remote-feature-flag-controller.mjs","sourceRoot":"","sources":["../src/remote-feature-flag-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BaseController,\n type ControllerGetStateAction,\n type ControllerStateChangeEvent,\n} from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport type { AbstractClientConfigApiService } from './client-config-api-service/abstract-client-config-api-service';\nimport type {\n FeatureFlags,\n ServiceResponse,\n FeatureFlagScopeValue,\n} from './remote-feature-flag-controller-types';\nimport {\n generateDeterministicRandomNumber,\n isFeatureFlagWithScopeValue,\n} from './utils/user-segmentation-utils';\n\n// === GENERAL ===\n\nconst controllerName = 'RemoteFeatureFlagController';\nexport const DEFAULT_CACHE_DURATION = 24 * 60 * 60 * 1000; // 1 day\n\n// === STATE ===\n\nexport type RemoteFeatureFlagControllerState = {\n remoteFeatureFlags: FeatureFlags;\n cacheTimestamp: number;\n};\n\nconst remoteFeatureFlagControllerMetadata = {\n remoteFeatureFlags: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n cacheTimestamp: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n};\n\n// === MESSENGER ===\n\n/**\n * The action to retrieve the state of the {@link RemoteFeatureFlagController}.\n */\nexport type RemoteFeatureFlagControllerGetStateAction =\n ControllerGetStateAction<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction = {\n type: `${typeof controllerName}:updateRemoteFeatureFlags`;\n handler: RemoteFeatureFlagController['updateRemoteFeatureFlags'];\n};\n\nexport type RemoteFeatureFlagControllerActions =\n | RemoteFeatureFlagControllerGetStateAction\n | RemoteFeatureFlagControllerUpdateRemoteFeatureFlagsAction;\n\nexport type RemoteFeatureFlagControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n RemoteFeatureFlagControllerState\n >;\n\nexport type RemoteFeatureFlagControllerEvents =\n RemoteFeatureFlagControllerStateChangeEvent;\n\nexport type RemoteFeatureFlagControllerMessenger = Messenger<\n typeof controllerName,\n RemoteFeatureFlagControllerActions,\n RemoteFeatureFlagControllerEvents\n>;\n\n/**\n * Returns the default state for the RemoteFeatureFlagController.\n *\n * @returns The default controller state.\n */\nexport function getDefaultRemoteFeatureFlagControllerState(): RemoteFeatureFlagControllerState {\n return {\n remoteFeatureFlags: {},\n cacheTimestamp: 0,\n };\n}\n\n/**\n * The RemoteFeatureFlagController manages the retrieval and caching of remote feature flags.\n * It fetches feature flags from a remote API, caches them, and provides methods to access\n * and manage these flags. The controller ensures that feature flags are refreshed based on\n * a specified interval and handles cases where the controller is disabled or the network is unavailable.\n */\nexport class RemoteFeatureFlagController extends BaseController<\n typeof controllerName,\n RemoteFeatureFlagControllerState,\n RemoteFeatureFlagControllerMessenger\n> {\n readonly #fetchInterval: number;\n\n #disabled: boolean;\n\n readonly #clientConfigApiService: AbstractClientConfigApiService;\n\n #inProgressFlagUpdate?: Promise<ServiceResponse>;\n\n #getMetaMetricsId: () => string;\n\n /**\n * Constructs a new RemoteFeatureFlagController instance.\n *\n * @param options - The controller options.\n * @param options.messenger - The messenger used for communication.\n * @param options.state - The initial state of the controller.\n * @param options.clientConfigApiService - The service instance to fetch remote feature flags.\n * @param options.fetchInterval - The interval in milliseconds before cached flags expire. Defaults to 1 day.\n * @param options.disabled - Determines if the controller should be disabled initially. Defaults to false.\n * @param options.getMetaMetricsId - Returns metaMetricsId.\n */\n constructor({\n messenger,\n state,\n clientConfigApiService,\n fetchInterval = DEFAULT_CACHE_DURATION,\n disabled = false,\n getMetaMetricsId,\n }: {\n messenger: RemoteFeatureFlagControllerMessenger;\n state?: Partial<RemoteFeatureFlagControllerState>;\n clientConfigApiService: AbstractClientConfigApiService;\n getMetaMetricsId: () => string;\n fetchInterval?: number;\n disabled?: boolean;\n }) {\n super({\n name: controllerName,\n metadata: remoteFeatureFlagControllerMetadata,\n messenger,\n state: {\n ...getDefaultRemoteFeatureFlagControllerState(),\n ...state,\n },\n });\n\n this.#fetchInterval = fetchInterval;\n this.#disabled = disabled;\n this.#clientConfigApiService = clientConfigApiService;\n this.#getMetaMetricsId = getMetaMetricsId;\n }\n\n /**\n * Checks if the cached feature flags are expired based on the fetch interval.\n *\n * @returns Whether the cache is expired (`true`) or still valid (`false`).\n * @private\n */\n #isCacheExpired(): boolean {\n return Date.now() - this.state.cacheTimestamp > this.#fetchInterval;\n }\n\n /**\n * Retrieves the remote feature flags, fetching from the API if necessary.\n * Uses caching to prevent redundant API calls and handles concurrent fetches.\n *\n * @returns A promise that resolves to the current set of feature flags.\n */\n async updateRemoteFeatureFlags(): Promise<void> {\n if (this.#disabled || !this.#isCacheExpired()) {\n return;\n }\n\n let serverData;\n\n if (this.#inProgressFlagUpdate) {\n await this.#inProgressFlagUpdate;\n return;\n }\n\n try {\n this.#inProgressFlagUpdate =\n this.#clientConfigApiService.fetchRemoteFeatureFlags();\n\n serverData = await this.#inProgressFlagUpdate;\n } finally {\n this.#inProgressFlagUpdate = undefined;\n }\n\n await this.#updateCache(serverData.remoteFeatureFlags);\n }\n\n /**\n * Updates the controller's state with new feature flags and resets the cache timestamp.\n *\n * @param remoteFeatureFlags - The new feature flags to cache.\n * @private\n */\n async #updateCache(remoteFeatureFlags: FeatureFlags) {\n const processedRemoteFeatureFlags =\n await this.#processRemoteFeatureFlags(remoteFeatureFlags);\n this.update(() => {\n return {\n remoteFeatureFlags: processedRemoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n });\n }\n\n async #processRemoteFeatureFlags(\n remoteFeatureFlags: FeatureFlags,\n ): Promise<FeatureFlags> {\n const processedRemoteFeatureFlags: FeatureFlags = {};\n const metaMetricsId = this.#getMetaMetricsId();\n const thresholdValue = generateDeterministicRandomNumber(metaMetricsId);\n\n for (const [\n remoteFeatureFlagName,\n remoteFeatureFlagValue,\n ] of Object.entries(remoteFeatureFlags)) {\n let processedValue = remoteFeatureFlagValue;\n\n if (Array.isArray(remoteFeatureFlagValue) && thresholdValue) {\n const selectedGroup = remoteFeatureFlagValue.find(\n (featureFlag): featureFlag is FeatureFlagScopeValue => {\n if (!isFeatureFlagWithScopeValue(featureFlag)) {\n return false;\n }\n\n return thresholdValue <= featureFlag.scope.value;\n },\n );\n if (selectedGroup) {\n processedValue = {\n name: selectedGroup.name,\n value: selectedGroup.value,\n };\n }\n }\n\n processedRemoteFeatureFlags[remoteFeatureFlagName] = processedValue;\n }\n return processedRemoteFeatureFlags;\n }\n\n /**\n * Enables the controller, allowing it to make network requests.\n */\n enable(): void {\n this.#disabled = false;\n }\n\n /**\n * Disables the controller, preventing it from making network requests.\n */\n disable(): void {\n this.#disabled = true;\n }\n}\n"]}
{
"name": "@metamask/remote-feature-flag-controller",
"version": "1.9.1",
"version": "2.0.0",
"description": "The RemoteFeatureFlagController manages the retrieval and caching of remote feature flags",

@@ -50,4 +50,5 @@ "keywords": [

"dependencies": {
"@metamask/base-controller": "^8.4.2",
"@metamask/base-controller": "^9.0.0",
"@metamask/controller-utils": "^11.14.1",
"@metamask/messenger": "^0.3.0",
"@metamask/utils": "^11.8.1",

@@ -54,0 +55,0 @@ "uuid": "^8.3.2"