🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@metamask/remote-feature-flag-controller

Package Overview
Dependencies
Maintainers
3
Versions
20
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
4.2.0
to
4.2.1
+10
-1
CHANGELOG.md

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

## [4.2.1]
### Changed
- Bump `@metamask/controller-utils` from `^11.19.0` to `^12.0.0` ([#8344](https://github.com/MetaMask/core/pull/8344), [#8755](https://github.com/MetaMask/core/pull/8755))
- Bump `@metamask/messenger` from `^1.0.0` to `^1.2.0` ([#8364](https://github.com/MetaMask/core/pull/8364), [#8373](https://github.com/MetaMask/core/pull/8373), [#8632](https://github.com/MetaMask/core/pull/8632))
- Bump `@metamask/base-controller` from `^9.0.1` to `^9.1.0` ([#8457](https://github.com/MetaMask/core/pull/8457))
## [4.2.0]

@@ -207,3 +215,4 @@

[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@4.2.0...HEAD
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@4.2.1...HEAD
[4.2.1]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@4.2.0...@metamask/remote-feature-flag-controller@4.2.1
[4.2.0]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@4.1.0...@metamask/remote-feature-flag-controller@4.2.0

@@ -210,0 +219,0 @@ [4.1.0]: https://github.com/MetaMask/core/compare/@metamask/remote-feature-flag-controller@4.0.0...@metamask/remote-feature-flag-controller@4.1.0

+1
-1

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

{"version":3,"file":"client-config-api-service.cjs","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,iEAKoC;AAKpC,gDAAwC;AAUxC;;GAEG;AACH,MAAa,sBAAsB;IAwFjC,YAAY,EACV,KAAK,EAAE,aAAa,EACpB,OAAO,GAAG,sCAAmB,EAC7B,0BAA0B,GAAG,mDAAgC,EAC7D,oBAAoB,GAAG,iDAA8B,EACrD,OAAO,EACP,UAAU,EACV,MAAM,GAaP;;QA3GQ,gDAAqB;QAErB,iDAAuB;QAEvB,iDAAoB;QAEpB,uDAAgC;QAEhC,sDAA8B;QAoGrC,uBAAA,IAAI,iCAAU,aAAa,MAAA,CAAC;QAC5B,uBAAA,IAAI,kCAAW,MAAM,CAAC,MAAM,MAAA,CAAC;QAC7B,uBAAA,IAAI,wCAAiB,MAAM,CAAC,YAAY,MAAA,CAAC;QACzC,uBAAA,IAAI,uCAAgB,MAAM,CAAC,WAAW,MAAA,CAAC;QAEvC,uBAAA,IAAI,kCAAW,IAAA,sCAAmB,EAAC;YACjC,UAAU,EAAE,OAAO;YACnB,sBAAsB,EAAE,0BAA0B;YAClD,oBAAoB;SACrB,CAAC,MAAA,CAAC;QACH,IAAI,OAAO,EAAE,CAAC;YACZ,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,UAAU,EAAE,CAAC;YACf,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAA0C;QACnD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAA6C;QACzD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,uBAAuB;QAClC,MAAM,GAAG,GAAG,GAAG,oBAAQ,iBAAiB,uBAAA,IAAI,sCAAQ,iBAClD,uBAAA,IAAI,4CACN,gBAAgB,uBAAA,IAAI,2CAAa,EAAE,CAAC;QAEpC,MAAM,QAAQ,GAAG,MAAM,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAC/C,uBAAA,IAAI,qCAAO,MAAX,IAAI,EAAQ,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CACxC,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,kBAAkB,GAAG,uBAAA,IAAI,sFAAqB,MAAzB,IAAI,EAAsB,IAAI,CAAC,CAAC;QAE3D,OAAO;YACL,kBAAkB;YAClB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;SAC3B,CAAC;IACJ,CAAC;CAgBF;AApMD,wDAoMC;gZALsB,YAA6B;IAChD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACvC,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC","sourcesContent":["import {\n createServicePolicy,\n DEFAULT_CIRCUIT_BREAK_DURATION,\n DEFAULT_MAX_CONSECUTIVE_FAILURES,\n DEFAULT_MAX_RETRIES,\n} from '@metamask/controller-utils';\nimport type { ServicePolicy } from '@metamask/controller-utils';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { AbstractClientConfigApiService } from './abstract-client-config-api-service';\nimport { BASE_URL } from '../constants';\nimport type {\n FeatureFlags,\n ClientType,\n DistributionType,\n EnvironmentType,\n ServiceResponse,\n ApiDataResponse,\n} from '../remote-feature-flag-controller-types';\n\n/**\n * This service is responsible for fetching feature flags from the ClientConfig API.\n */\nexport class ClientConfigApiService implements AbstractClientConfigApiService {\n readonly #fetch: typeof fetch;\n\n readonly #policy: ServicePolicy;\n\n readonly #client: ClientType;\n\n readonly #distribution: DistributionType;\n\n readonly #environment: EnvironmentType;\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @deprecated This signature is deprecated; please use the `onBreak` and\n * `onDegraded` methods instead.\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.onBreak - Callback for when the circuit breaks, useful\n * for capturing metrics about network failures.\n * @param args.onDegraded - Callback for when the API responds successfully\n * but takes too long to respond (5 seconds or more).\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n // eslint-disable-next-line @typescript-eslint/unified-signatures\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n constructor({\n fetch: fetchFunction,\n retries = DEFAULT_MAX_RETRIES,\n maximumConsecutiveFailures = DEFAULT_MAX_CONSECUTIVE_FAILURES,\n circuitBreakDuration = DEFAULT_CIRCUIT_BREAK_DURATION,\n onBreak,\n onDegraded,\n config,\n }: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n }) {\n this.#fetch = fetchFunction;\n this.#client = config.client;\n this.#distribution = config.distribution;\n this.#environment = config.environment;\n\n this.#policy = createServicePolicy({\n maxRetries: retries,\n maxConsecutiveFailures: maximumConsecutiveFailures,\n circuitBreakDuration,\n });\n if (onBreak) {\n this.#policy.onBreak(onBreak);\n }\n if (onDegraded) {\n this.#policy.onDegraded(onDegraded);\n }\n }\n\n /**\n * Listens for when the request to the API fails too many times in a row.\n *\n * @param args - The same arguments that {@link ServicePolicy.onBreak}\n * takes.\n * @returns What {@link ServicePolicy.onBreak} returns.\n */\n onBreak(...args: Parameters<ServicePolicy['onBreak']>): IDisposable {\n return this.#policy.onBreak(...args);\n }\n\n /**\n * Listens for when the API is degraded.\n *\n * @param args - The same arguments that {@link ServicePolicy.onDegraded}\n * takes.\n * @returns What {@link ServicePolicy.onDegraded} returns.\n */\n onDegraded(...args: Parameters<ServicePolicy['onDegraded']>): IDisposable {\n return this.#policy.onDegraded(...args);\n }\n\n /**\n * Fetches feature flags from the API with specific client, distribution, and environment parameters.\n * Provides structured error handling, including fallback to cached data if available.\n *\n * @returns An object of feature flags and their boolean values or a structured error object.\n */\n public async fetchRemoteFeatureFlags(): Promise<ServiceResponse> {\n const url = `${BASE_URL}/flags?client=${this.#client}&distribution=${\n this.#distribution\n }&environment=${this.#environment}`;\n\n const response = await this.#policy.execute(() =>\n this.#fetch(url, { cache: 'no-cache' }),\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch remote feature flags');\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new Error('Feature flags api did not return an array');\n }\n\n const remoteFeatureFlags = this.#flattenFeatureFlags(data);\n\n return {\n remoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n }\n\n /**\n * Flattens an array of feature flag objects into a single feature flags object.\n *\n * @param responseData - Array of objects containing feature flag key-value pairs\n * @returns A single object containing all feature flags merged together\n * @example\n * // Input: [{ flag1: true }, { flag2: [] }]\n * // Output: { flag1: true, flag2: [] }\n */\n #flattenFeatureFlags(responseData: ApiDataResponse): FeatureFlags {\n return responseData.reduce((acc, curr) => {\n return { ...acc, ...curr };\n }, {});\n }\n}\n"]}
{"version":3,"file":"client-config-api-service.cjs","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,iEAKoC;AAIpC,gDAAwC;AAWxC;;GAEG;AACH,MAAa,sBAAsB;IAwFjC,YAAY,EACV,KAAK,EAAE,aAAa,EACpB,OAAO,GAAG,sCAAmB,EAC7B,0BAA0B,GAAG,mDAAgC,EAC7D,oBAAoB,GAAG,iDAA8B,EACrD,OAAO,EACP,UAAU,EACV,MAAM,GAaP;;QA3GQ,gDAAqB;QAErB,iDAAuB;QAEvB,iDAAoB;QAEpB,uDAAgC;QAEhC,sDAA8B;QAoGrC,uBAAA,IAAI,iCAAU,aAAa,MAAA,CAAC;QAC5B,uBAAA,IAAI,kCAAW,MAAM,CAAC,MAAM,MAAA,CAAC;QAC7B,uBAAA,IAAI,wCAAiB,MAAM,CAAC,YAAY,MAAA,CAAC;QACzC,uBAAA,IAAI,uCAAgB,MAAM,CAAC,WAAW,MAAA,CAAC;QAEvC,uBAAA,IAAI,kCAAW,IAAA,sCAAmB,EAAC;YACjC,UAAU,EAAE,OAAO;YACnB,sBAAsB,EAAE,0BAA0B;YAClD,oBAAoB;SACrB,CAAC,MAAA,CAAC;QACH,IAAI,OAAO,EAAE,CAAC;YACZ,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,UAAU,EAAE,CAAC;YACf,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAA0C;QACnD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAA6C;QACzD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,uBAAuB;QAClC,MAAM,GAAG,GAAG,GAAG,oBAAQ,iBAAiB,uBAAA,IAAI,sCAAQ,iBAClD,uBAAA,IAAI,4CACN,gBAAgB,uBAAA,IAAI,2CAAa,EAAE,CAAC;QAEpC,MAAM,QAAQ,GAAG,MAAM,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAC/C,uBAAA,IAAI,qCAAO,MAAX,IAAI,EAAQ,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CACxC,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,kBAAkB,GAAG,uBAAA,IAAI,sFAAqB,MAAzB,IAAI,EAAsB,IAAI,CAAC,CAAC;QAE3D,OAAO;YACL,kBAAkB;YAClB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;SAC3B,CAAC;IACJ,CAAC;CAgBF;AApMD,wDAoMC;gZALsB,YAA6B;IAChD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACvC,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC","sourcesContent":["import {\n createServicePolicy,\n DEFAULT_CIRCUIT_BREAK_DURATION,\n DEFAULT_MAX_CONSECUTIVE_FAILURES,\n DEFAULT_MAX_RETRIES,\n} from '@metamask/controller-utils';\nimport type { ServicePolicy } from '@metamask/controller-utils';\nimport type { IDisposable } from 'cockatiel';\n\nimport { BASE_URL } from '../constants';\nimport type {\n FeatureFlags,\n ClientType,\n DistributionType,\n EnvironmentType,\n ServiceResponse,\n ApiDataResponse,\n} from '../remote-feature-flag-controller-types';\nimport type { AbstractClientConfigApiService } from './abstract-client-config-api-service';\n\n/**\n * This service is responsible for fetching feature flags from the ClientConfig API.\n */\nexport class ClientConfigApiService implements AbstractClientConfigApiService {\n readonly #fetch: typeof fetch;\n\n readonly #policy: ServicePolicy;\n\n readonly #client: ClientType;\n\n readonly #distribution: DistributionType;\n\n readonly #environment: EnvironmentType;\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @deprecated This signature is deprecated; please use the `onBreak` and\n * `onDegraded` methods instead.\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.onBreak - Callback for when the circuit breaks, useful\n * for capturing metrics about network failures.\n * @param args.onDegraded - Callback for when the API responds successfully\n * but takes too long to respond (5 seconds or more).\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n // eslint-disable-next-line @typescript-eslint/unified-signatures\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n constructor({\n fetch: fetchFunction,\n retries = DEFAULT_MAX_RETRIES,\n maximumConsecutiveFailures = DEFAULT_MAX_CONSECUTIVE_FAILURES,\n circuitBreakDuration = DEFAULT_CIRCUIT_BREAK_DURATION,\n onBreak,\n onDegraded,\n config,\n }: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n }) {\n this.#fetch = fetchFunction;\n this.#client = config.client;\n this.#distribution = config.distribution;\n this.#environment = config.environment;\n\n this.#policy = createServicePolicy({\n maxRetries: retries,\n maxConsecutiveFailures: maximumConsecutiveFailures,\n circuitBreakDuration,\n });\n if (onBreak) {\n this.#policy.onBreak(onBreak);\n }\n if (onDegraded) {\n this.#policy.onDegraded(onDegraded);\n }\n }\n\n /**\n * Listens for when the request to the API fails too many times in a row.\n *\n * @param args - The same arguments that {@link ServicePolicy.onBreak}\n * takes.\n * @returns What {@link ServicePolicy.onBreak} returns.\n */\n onBreak(...args: Parameters<ServicePolicy['onBreak']>): IDisposable {\n return this.#policy.onBreak(...args);\n }\n\n /**\n * Listens for when the API is degraded.\n *\n * @param args - The same arguments that {@link ServicePolicy.onDegraded}\n * takes.\n * @returns What {@link ServicePolicy.onDegraded} returns.\n */\n onDegraded(...args: Parameters<ServicePolicy['onDegraded']>): IDisposable {\n return this.#policy.onDegraded(...args);\n }\n\n /**\n * Fetches feature flags from the API with specific client, distribution, and environment parameters.\n * Provides structured error handling, including fallback to cached data if available.\n *\n * @returns An object of feature flags and their boolean values or a structured error object.\n */\n public async fetchRemoteFeatureFlags(): Promise<ServiceResponse> {\n const url = `${BASE_URL}/flags?client=${this.#client}&distribution=${\n this.#distribution\n }&environment=${this.#environment}`;\n\n const response = await this.#policy.execute(() =>\n this.#fetch(url, { cache: 'no-cache' }),\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch remote feature flags');\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new Error('Feature flags api did not return an array');\n }\n\n const remoteFeatureFlags = this.#flattenFeatureFlags(data);\n\n return {\n remoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n }\n\n /**\n * Flattens an array of feature flag objects into a single feature flags object.\n *\n * @param responseData - Array of objects containing feature flag key-value pairs\n * @returns A single object containing all feature flags merged together\n * @example\n * // Input: [{ flag1: true }, { flag2: [] }]\n * // Output: { flag1: true, flag2: [] }\n */\n #flattenFeatureFlags(responseData: ApiDataResponse): FeatureFlags {\n return responseData.reduce((acc, curr) => {\n return { ...acc, ...curr };\n }, {});\n }\n}\n"]}
import type { ServicePolicy } from "@metamask/controller-utils";
import type { IDisposable } from "cockatiel";
import type { ClientType, DistributionType, EnvironmentType, ServiceResponse } from "../remote-feature-flag-controller-types.cjs";
import type { AbstractClientConfigApiService } from "./abstract-client-config-api-service.cjs";
import type { ClientType, DistributionType, EnvironmentType, ServiceResponse } from "../remote-feature-flag-controller-types.cjs";
/**

@@ -6,0 +6,0 @@ * This service is responsible for fetching feature flags from the ClientConfig API.

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

{"version":3,"file":"client-config-api-service.d.cts","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,8BAA8B,EAAE,iDAA6C;AAE3F,OAAO,KAAK,EAEV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EAEhB,oDAAgD;AAEjD;;GAEG;AACH,qBAAa,sBAAuB,YAAW,8BAA8B;;IAW3E;;;;;;;;;;;;;;;;;;;;;OAqBG;gBACS,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;gBAES,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;QACxB,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAyCD;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,GAAG,WAAW;IAInE;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,GAAG,WAAW;IAIzE;;;;;OAKG;IACU,uBAAuB,IAAI,OAAO,CAAC,eAAe,CAAC;CAyCjE"}
{"version":3,"file":"client-config-api-service.d.cts","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAG7C,OAAO,KAAK,EAEV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EAEhB,oDAAgD;AACjD,OAAO,KAAK,EAAE,8BAA8B,EAAE,iDAA6C;AAE3F;;GAEG;AACH,qBAAa,sBAAuB,YAAW,8BAA8B;;IAW3E;;;;;;;;;;;;;;;;;;;;;OAqBG;gBACS,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;gBAES,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;QACxB,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAyCD;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,GAAG,WAAW;IAInE;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,GAAG,WAAW;IAIzE;;;;;OAKG;IACU,uBAAuB,IAAI,OAAO,CAAC,eAAe,CAAC;CAyCjE"}
import type { ServicePolicy } from "@metamask/controller-utils";
import type { IDisposable } from "cockatiel";
import type { ClientType, DistributionType, EnvironmentType, ServiceResponse } from "../remote-feature-flag-controller-types.mjs";
import type { AbstractClientConfigApiService } from "./abstract-client-config-api-service.mjs";
import type { ClientType, DistributionType, EnvironmentType, ServiceResponse } from "../remote-feature-flag-controller-types.mjs";
/**

@@ -6,0 +6,0 @@ * This service is responsible for fetching feature flags from the ClientConfig API.

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

{"version":3,"file":"client-config-api-service.d.mts","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,8BAA8B,EAAE,iDAA6C;AAE3F,OAAO,KAAK,EAEV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EAEhB,oDAAgD;AAEjD;;GAEG;AACH,qBAAa,sBAAuB,YAAW,8BAA8B;;IAW3E;;;;;;;;;;;;;;;;;;;;;OAqBG;gBACS,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;gBAES,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;QACxB,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAyCD;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,GAAG,WAAW;IAInE;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,GAAG,WAAW;IAIzE;;;;;OAKG;IACU,uBAAuB,IAAI,OAAO,CAAC,eAAe,CAAC;CAyCjE"}
{"version":3,"file":"client-config-api-service.d.mts","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,mCAAmC;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAG7C,OAAO,KAAK,EAEV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EAEhB,oDAAgD;AACjD,OAAO,KAAK,EAAE,8BAA8B,EAAE,iDAA6C;AAE3F;;GAEG;AACH,qBAAa,sBAAuB,YAAW,8BAA8B;;IAW3E;;;;;;;;;;;;;;;;;;;;;OAqBG;gBACS,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;gBAES,IAAI,EAAE;QAChB,KAAK,EAAE,OAAO,KAAK,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;QACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;QACxB,MAAM,EAAE;YACN,MAAM,EAAE,UAAU,CAAC;YACnB,YAAY,EAAE,gBAAgB,CAAC;YAC/B,WAAW,EAAE,eAAe,CAAC;SAC9B,CAAC;KACH;IAyCD;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,GAAG,WAAW;IAInE;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,GAAG,WAAW;IAIzE;;;;;OAKG;IACU,uBAAuB,IAAI,OAAO,CAAC,eAAe,CAAC;CAyCjE"}

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

{"version":3,"file":"client-config-api-service.mjs","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,gCAAgC,EAChC,mBAAmB,EACpB,mCAAmC;AAKpC,OAAO,EAAE,QAAQ,EAAE,yBAAqB;AAUxC;;GAEG;AACH,MAAM,OAAO,sBAAsB;IAwFjC,YAAY,EACV,KAAK,EAAE,aAAa,EACpB,OAAO,GAAG,mBAAmB,EAC7B,0BAA0B,GAAG,gCAAgC,EAC7D,oBAAoB,GAAG,8BAA8B,EACrD,OAAO,EACP,UAAU,EACV,MAAM,GAaP;;QA3GQ,gDAAqB;QAErB,iDAAuB;QAEvB,iDAAoB;QAEpB,uDAAgC;QAEhC,sDAA8B;QAoGrC,uBAAA,IAAI,iCAAU,aAAa,MAAA,CAAC;QAC5B,uBAAA,IAAI,kCAAW,MAAM,CAAC,MAAM,MAAA,CAAC;QAC7B,uBAAA,IAAI,wCAAiB,MAAM,CAAC,YAAY,MAAA,CAAC;QACzC,uBAAA,IAAI,uCAAgB,MAAM,CAAC,WAAW,MAAA,CAAC;QAEvC,uBAAA,IAAI,kCAAW,mBAAmB,CAAC;YACjC,UAAU,EAAE,OAAO;YACnB,sBAAsB,EAAE,0BAA0B;YAClD,oBAAoB;SACrB,CAAC,MAAA,CAAC;QACH,IAAI,OAAO,EAAE,CAAC;YACZ,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,UAAU,EAAE,CAAC;YACf,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAA0C;QACnD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAA6C;QACzD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,uBAAuB;QAClC,MAAM,GAAG,GAAG,GAAG,QAAQ,iBAAiB,uBAAA,IAAI,sCAAQ,iBAClD,uBAAA,IAAI,4CACN,gBAAgB,uBAAA,IAAI,2CAAa,EAAE,CAAC;QAEpC,MAAM,QAAQ,GAAG,MAAM,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAC/C,uBAAA,IAAI,qCAAO,MAAX,IAAI,EAAQ,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CACxC,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,kBAAkB,GAAG,uBAAA,IAAI,sFAAqB,MAAzB,IAAI,EAAsB,IAAI,CAAC,CAAC;QAE3D,OAAO;YACL,kBAAkB;YAClB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;SAC3B,CAAC;IACJ,CAAC;CAgBF;gZALsB,YAA6B;IAChD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACvC,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC","sourcesContent":["import {\n createServicePolicy,\n DEFAULT_CIRCUIT_BREAK_DURATION,\n DEFAULT_MAX_CONSECUTIVE_FAILURES,\n DEFAULT_MAX_RETRIES,\n} from '@metamask/controller-utils';\nimport type { ServicePolicy } from '@metamask/controller-utils';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { AbstractClientConfigApiService } from './abstract-client-config-api-service';\nimport { BASE_URL } from '../constants';\nimport type {\n FeatureFlags,\n ClientType,\n DistributionType,\n EnvironmentType,\n ServiceResponse,\n ApiDataResponse,\n} from '../remote-feature-flag-controller-types';\n\n/**\n * This service is responsible for fetching feature flags from the ClientConfig API.\n */\nexport class ClientConfigApiService implements AbstractClientConfigApiService {\n readonly #fetch: typeof fetch;\n\n readonly #policy: ServicePolicy;\n\n readonly #client: ClientType;\n\n readonly #distribution: DistributionType;\n\n readonly #environment: EnvironmentType;\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @deprecated This signature is deprecated; please use the `onBreak` and\n * `onDegraded` methods instead.\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.onBreak - Callback for when the circuit breaks, useful\n * for capturing metrics about network failures.\n * @param args.onDegraded - Callback for when the API responds successfully\n * but takes too long to respond (5 seconds or more).\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n // eslint-disable-next-line @typescript-eslint/unified-signatures\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n constructor({\n fetch: fetchFunction,\n retries = DEFAULT_MAX_RETRIES,\n maximumConsecutiveFailures = DEFAULT_MAX_CONSECUTIVE_FAILURES,\n circuitBreakDuration = DEFAULT_CIRCUIT_BREAK_DURATION,\n onBreak,\n onDegraded,\n config,\n }: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n }) {\n this.#fetch = fetchFunction;\n this.#client = config.client;\n this.#distribution = config.distribution;\n this.#environment = config.environment;\n\n this.#policy = createServicePolicy({\n maxRetries: retries,\n maxConsecutiveFailures: maximumConsecutiveFailures,\n circuitBreakDuration,\n });\n if (onBreak) {\n this.#policy.onBreak(onBreak);\n }\n if (onDegraded) {\n this.#policy.onDegraded(onDegraded);\n }\n }\n\n /**\n * Listens for when the request to the API fails too many times in a row.\n *\n * @param args - The same arguments that {@link ServicePolicy.onBreak}\n * takes.\n * @returns What {@link ServicePolicy.onBreak} returns.\n */\n onBreak(...args: Parameters<ServicePolicy['onBreak']>): IDisposable {\n return this.#policy.onBreak(...args);\n }\n\n /**\n * Listens for when the API is degraded.\n *\n * @param args - The same arguments that {@link ServicePolicy.onDegraded}\n * takes.\n * @returns What {@link ServicePolicy.onDegraded} returns.\n */\n onDegraded(...args: Parameters<ServicePolicy['onDegraded']>): IDisposable {\n return this.#policy.onDegraded(...args);\n }\n\n /**\n * Fetches feature flags from the API with specific client, distribution, and environment parameters.\n * Provides structured error handling, including fallback to cached data if available.\n *\n * @returns An object of feature flags and their boolean values or a structured error object.\n */\n public async fetchRemoteFeatureFlags(): Promise<ServiceResponse> {\n const url = `${BASE_URL}/flags?client=${this.#client}&distribution=${\n this.#distribution\n }&environment=${this.#environment}`;\n\n const response = await this.#policy.execute(() =>\n this.#fetch(url, { cache: 'no-cache' }),\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch remote feature flags');\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new Error('Feature flags api did not return an array');\n }\n\n const remoteFeatureFlags = this.#flattenFeatureFlags(data);\n\n return {\n remoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n }\n\n /**\n * Flattens an array of feature flag objects into a single feature flags object.\n *\n * @param responseData - Array of objects containing feature flag key-value pairs\n * @returns A single object containing all feature flags merged together\n * @example\n * // Input: [{ flag1: true }, { flag2: [] }]\n * // Output: { flag1: true, flag2: [] }\n */\n #flattenFeatureFlags(responseData: ApiDataResponse): FeatureFlags {\n return responseData.reduce((acc, curr) => {\n return { ...acc, ...curr };\n }, {});\n }\n}\n"]}
{"version":3,"file":"client-config-api-service.mjs","sourceRoot":"","sources":["../../src/client-config-api-service/client-config-api-service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EACL,mBAAmB,EACnB,8BAA8B,EAC9B,gCAAgC,EAChC,mBAAmB,EACpB,mCAAmC;AAIpC,OAAO,EAAE,QAAQ,EAAE,yBAAqB;AAWxC;;GAEG;AACH,MAAM,OAAO,sBAAsB;IAwFjC,YAAY,EACV,KAAK,EAAE,aAAa,EACpB,OAAO,GAAG,mBAAmB,EAC7B,0BAA0B,GAAG,gCAAgC,EAC7D,oBAAoB,GAAG,8BAA8B,EACrD,OAAO,EACP,UAAU,EACV,MAAM,GAaP;;QA3GQ,gDAAqB;QAErB,iDAAuB;QAEvB,iDAAoB;QAEpB,uDAAgC;QAEhC,sDAA8B;QAoGrC,uBAAA,IAAI,iCAAU,aAAa,MAAA,CAAC;QAC5B,uBAAA,IAAI,kCAAW,MAAM,CAAC,MAAM,MAAA,CAAC;QAC7B,uBAAA,IAAI,wCAAiB,MAAM,CAAC,YAAY,MAAA,CAAC;QACzC,uBAAA,IAAI,uCAAgB,MAAM,CAAC,WAAW,MAAA,CAAC;QAEvC,uBAAA,IAAI,kCAAW,mBAAmB,CAAC;YACjC,UAAU,EAAE,OAAO;YACnB,sBAAsB,EAAE,0BAA0B;YAClD,oBAAoB;SACrB,CAAC,MAAA,CAAC;QACH,IAAI,OAAO,EAAE,CAAC;YACZ,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,UAAU,EAAE,CAAC;YACf,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACH,OAAO,CAAC,GAAG,IAA0C;QACnD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;IACvC,CAAC;IAED;;;;;;OAMG;IACH,UAAU,CAAC,GAAG,IAA6C;QACzD,OAAO,uBAAA,IAAI,sCAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,uBAAuB;QAClC,MAAM,GAAG,GAAG,GAAG,QAAQ,iBAAiB,uBAAA,IAAI,sCAAQ,iBAClD,uBAAA,IAAI,4CACN,gBAAgB,uBAAA,IAAI,2CAAa,EAAE,CAAC;QAEpC,MAAM,QAAQ,GAAG,MAAM,uBAAA,IAAI,sCAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,CAC/C,uBAAA,IAAI,qCAAO,MAAX,IAAI,EAAQ,GAAG,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,CACxC,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEnC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,kBAAkB,GAAG,uBAAA,IAAI,sFAAqB,MAAzB,IAAI,EAAsB,IAAI,CAAC,CAAC;QAE3D,OAAO;YACL,kBAAkB;YAClB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;SAC3B,CAAC;IACJ,CAAC;CAgBF;gZALsB,YAA6B;IAChD,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE;QACvC,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC7B,CAAC,EAAE,EAAE,CAAC,CAAC;AACT,CAAC","sourcesContent":["import {\n createServicePolicy,\n DEFAULT_CIRCUIT_BREAK_DURATION,\n DEFAULT_MAX_CONSECUTIVE_FAILURES,\n DEFAULT_MAX_RETRIES,\n} from '@metamask/controller-utils';\nimport type { ServicePolicy } from '@metamask/controller-utils';\nimport type { IDisposable } from 'cockatiel';\n\nimport { BASE_URL } from '../constants';\nimport type {\n FeatureFlags,\n ClientType,\n DistributionType,\n EnvironmentType,\n ServiceResponse,\n ApiDataResponse,\n} from '../remote-feature-flag-controller-types';\nimport type { AbstractClientConfigApiService } from './abstract-client-config-api-service';\n\n/**\n * This service is responsible for fetching feature flags from the ClientConfig API.\n */\nexport class ClientConfigApiService implements AbstractClientConfigApiService {\n readonly #fetch: typeof fetch;\n\n readonly #policy: ServicePolicy;\n\n readonly #client: ClientType;\n\n readonly #distribution: DistributionType;\n\n readonly #environment: EnvironmentType;\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n /**\n * Constructs a new ClientConfigApiService object.\n *\n * @deprecated This signature is deprecated; please use the `onBreak` and\n * `onDegraded` methods instead.\n * @param args - The arguments.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * If your JavaScript environment supports `fetch` natively, you'll probably\n * want to pass that; otherwise you can pass an equivalent (such as `fetch`\n * via `node-fetch`).\n * @param args.retries - Number of retry attempts for each fetch request.\n * @param args.maximumConsecutiveFailures - The maximum number of consecutive\n * failures allowed before breaking the circuit and pausing further fetch\n * attempts.\n * @param args.circuitBreakDuration - The amount of time to wait when the\n * circuit breaks from too many consecutive failures.\n * @param args.onBreak - Callback for when the circuit breaks, useful\n * for capturing metrics about network failures.\n * @param args.onDegraded - Callback for when the API responds successfully\n * but takes too long to respond (5 seconds or more).\n * @param args.config - The configuration object, includes client,\n * distribution, and environment.\n * @param args.config.client - The client type (e.g., 'extension', 'mobile').\n * @param args.config.distribution - The distribution type (e.g., 'main',\n * 'flask').\n * @param args.config.environment - The environment type (e.g., 'prod', 'rc',\n * 'dev').\n */\n // eslint-disable-next-line @typescript-eslint/unified-signatures\n constructor(args: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n });\n\n constructor({\n fetch: fetchFunction,\n retries = DEFAULT_MAX_RETRIES,\n maximumConsecutiveFailures = DEFAULT_MAX_CONSECUTIVE_FAILURES,\n circuitBreakDuration = DEFAULT_CIRCUIT_BREAK_DURATION,\n onBreak,\n onDegraded,\n config,\n }: {\n fetch: typeof fetch;\n retries?: number;\n maximumConsecutiveFailures?: number;\n circuitBreakDuration?: number;\n onBreak?: () => void;\n onDegraded?: () => void;\n config: {\n client: ClientType;\n distribution: DistributionType;\n environment: EnvironmentType;\n };\n }) {\n this.#fetch = fetchFunction;\n this.#client = config.client;\n this.#distribution = config.distribution;\n this.#environment = config.environment;\n\n this.#policy = createServicePolicy({\n maxRetries: retries,\n maxConsecutiveFailures: maximumConsecutiveFailures,\n circuitBreakDuration,\n });\n if (onBreak) {\n this.#policy.onBreak(onBreak);\n }\n if (onDegraded) {\n this.#policy.onDegraded(onDegraded);\n }\n }\n\n /**\n * Listens for when the request to the API fails too many times in a row.\n *\n * @param args - The same arguments that {@link ServicePolicy.onBreak}\n * takes.\n * @returns What {@link ServicePolicy.onBreak} returns.\n */\n onBreak(...args: Parameters<ServicePolicy['onBreak']>): IDisposable {\n return this.#policy.onBreak(...args);\n }\n\n /**\n * Listens for when the API is degraded.\n *\n * @param args - The same arguments that {@link ServicePolicy.onDegraded}\n * takes.\n * @returns What {@link ServicePolicy.onDegraded} returns.\n */\n onDegraded(...args: Parameters<ServicePolicy['onDegraded']>): IDisposable {\n return this.#policy.onDegraded(...args);\n }\n\n /**\n * Fetches feature flags from the API with specific client, distribution, and environment parameters.\n * Provides structured error handling, including fallback to cached data if available.\n *\n * @returns An object of feature flags and their boolean values or a structured error object.\n */\n public async fetchRemoteFeatureFlags(): Promise<ServiceResponse> {\n const url = `${BASE_URL}/flags?client=${this.#client}&distribution=${\n this.#distribution\n }&environment=${this.#environment}`;\n\n const response = await this.#policy.execute(() =>\n this.#fetch(url, { cache: 'no-cache' }),\n );\n\n if (!response.ok) {\n throw new Error('Failed to fetch remote feature flags');\n }\n\n const data = await response.json();\n\n if (!Array.isArray(data)) {\n throw new Error('Feature flags api did not return an array');\n }\n\n const remoteFeatureFlags = this.#flattenFeatureFlags(data);\n\n return {\n remoteFeatureFlags,\n cacheTimestamp: Date.now(),\n };\n }\n\n /**\n * Flattens an array of feature flag objects into a single feature flags object.\n *\n * @param responseData - Array of objects containing feature flag key-value pairs\n * @returns A single object containing all feature flags merged together\n * @example\n * // Input: [{ flag1: true }, { flag2: [] }]\n * // Output: { flag1: true, flag2: [] }\n */\n #flattenFeatureFlags(responseData: ApiDataResponse): FeatureFlags {\n return responseData.reduce((acc, curr) => {\n return { ...acc, ...curr };\n }, {});\n }\n}\n"]}
{
"name": "@metamask/remote-feature-flag-controller",
"version": "4.2.0",
"version": "4.2.1",
"description": "The RemoteFeatureFlagController manages the retrieval and caching of remote feature flags",
"keywords": [
"MetaMask",
"Ethereum"
"Ethereum",
"MetaMask"
],

@@ -13,2 +13,3 @@ "homepage": "https://github.com/MetaMask/core/tree/main/packages/remote-feature-flag-controller#readme",

},
"license": "(MIT OR Apache-2.0)",
"repository": {

@@ -18,4 +19,8 @@ "type": "git",

},
"license": "(MIT OR Apache-2.0)",
"files": [
"dist/"
],
"sideEffects": false,
"main": "./dist/index.cjs",
"types": "./dist/index.d.cts",
"exports": {

@@ -34,7 +39,6 @@ ".": {

},
"main": "./dist/index.cjs",
"types": "./dist/index.d.cts",
"files": [
"dist/"
],
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
},
"scripts": {

@@ -46,3 +50,4 @@ "build": "ts-bridge --project tsconfig.build.json --verbose --clean --no-references",

"changelog:validate": "../../scripts/validate-changelog.sh @metamask/remote-feature-flag-controller",
"generate-method-action-types": "tsx ../../scripts/generate-method-action-types.ts",
"messenger-action-types:check": "tsx ../../packages/messenger-cli/src/cli.ts --formatter oxfmt --check",
"messenger-action-types:generate": "tsx ../../packages/messenger-cli/src/cli.ts --formatter oxfmt --generate",
"since-latest-release": "../../scripts/since-latest-release.sh",

@@ -55,5 +60,5 @@ "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter",

"dependencies": {
"@metamask/base-controller": "^9.0.1",
"@metamask/controller-utils": "^11.19.0",
"@metamask/messenger": "^1.0.0",
"@metamask/base-controller": "^9.1.0",
"@metamask/controller-utils": "^12.0.0",
"@metamask/messenger": "^1.2.0",
"@metamask/utils": "^11.9.0",

@@ -64,3 +69,3 @@ "uuid": "^8.3.2"

"@lavamoat/allow-scripts": "^3.0.4",
"@metamask/auto-changelog": "^3.4.4",
"@metamask/auto-changelog": "^6.1.0",
"@ts-bridge/cli": "^0.6.4",

@@ -79,7 +84,3 @@ "@types/jest": "^29.5.14",

"node": "^18.18 || >=20"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/"
}
}