@metamask-previews/ramps-controller 15.1.0-preview-a511f243f → 16.0.0-preview-2fd14c0c3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +21 -1
  2. package/dist/RampsController.cjs +42 -70
  3. package/dist/RampsController.cjs.map +1 -1
  4. package/dist/RampsController.d.cts +9 -26
  5. package/dist/RampsController.d.cts.map +1 -1
  6. package/dist/RampsController.d.mts +9 -26
  7. package/dist/RampsController.d.mts.map +1 -1
  8. package/dist/RampsController.mjs +42 -70
  9. package/dist/RampsController.mjs.map +1 -1
  10. package/dist/errorNormalization.cjs +84 -0
  11. package/dist/errorNormalization.cjs.map +1 -0
  12. package/dist/errorNormalization.d.cts +56 -0
  13. package/dist/errorNormalization.d.cts.map +1 -0
  14. package/dist/errorNormalization.d.mts +56 -0
  15. package/dist/errorNormalization.d.mts.map +1 -0
  16. package/dist/errorNormalization.mjs +78 -0
  17. package/dist/errorNormalization.mjs.map +1 -0
  18. package/dist/featureFlags.cjs +39 -0
  19. package/dist/featureFlags.cjs.map +1 -0
  20. package/dist/featureFlags.d.cts +40 -0
  21. package/dist/featureFlags.d.cts.map +1 -0
  22. package/dist/featureFlags.d.mts +40 -0
  23. package/dist/featureFlags.d.mts.map +1 -0
  24. package/dist/featureFlags.mjs +35 -0
  25. package/dist/featureFlags.mjs.map +1 -0
  26. package/dist/index.cjs +17 -1
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +7 -1
  29. package/dist/index.d.cts.map +1 -1
  30. package/dist/index.d.mts +7 -1
  31. package/dist/index.d.mts.map +1 -1
  32. package/dist/index.mjs +4 -0
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/providerAvailability.cjs +103 -0
  35. package/dist/providerAvailability.cjs.map +1 -0
  36. package/dist/providerAvailability.d.cts +76 -0
  37. package/dist/providerAvailability.d.cts.map +1 -0
  38. package/dist/providerAvailability.d.mts +76 -0
  39. package/dist/providerAvailability.d.mts.map +1 -0
  40. package/dist/providerAvailability.mjs +96 -0
  41. package/dist/providerAvailability.mjs.map +1 -0
  42. package/dist/quoteClassification.cjs +44 -0
  43. package/dist/quoteClassification.cjs.map +1 -0
  44. package/dist/quoteClassification.d.cts +33 -0
  45. package/dist/quoteClassification.d.cts.map +1 -0
  46. package/dist/quoteClassification.d.mts +33 -0
  47. package/dist/quoteClassification.d.mts.map +1 -0
  48. package/dist/quoteClassification.mjs +38 -0
  49. package/dist/quoteClassification.mjs.map +1 -0
  50. package/package.json +3 -2
package/CHANGELOG.md CHANGED
@@ -7,9 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - Add the `MONEY_HEADLESS_ALL_PROVIDERS_FLAG_KEY` constant (`moneyHeadlessAllProviders`) and the pure `isHeadlessAllProvidersEnabled(remoteFeatureFlagState)` helper (with a `HeadlessFeatureFlagsLookup` type) that own the flag key lookup, `localOverrides`-over-`remoteFeatureFlags` merging, and boolean coercion (only the literal `true` enables), so UI consumers resolve the flag exactly like the controller does ([#9409](https://github.com/MetaMask/core/pull/9409))
13
+ - Add pure provider-availability helpers `providerServesAsset`, `getProvidersServingAsset`, `regionHasProviderForAsset`, and `isFiatDepositAvailable` so headless-buy consumers can share the controller's case-insensitive CAIP-19 asset matching and flag-aware region/availability gating instead of re-deriving it, keeping the two from disagreeing; `regionHasProviderForAsset` and `isFiatDepositAvailable` take an `allProvidersEnabled` boolean ([#9409](https://github.com/MetaMask/core/pull/9409))
14
+ - Add pure quote-classification helpers `isExternalBrowserQuote`, `isCustomActionQuote`, and `isInAppOnlyQuote` so consumers can share the in-app-vs-external browser-mode classification without owning host redirect/deeplink concerns ([#9409](https://github.com/MetaMask/core/pull/9409))
15
+ - Add pure error-normalization helpers `getErrorMessage`, `extractExplicitTypedError`, and `normalizeToTypedError` (with a `TypedError<Code>` type) so consumers can share error-shape extraction while keeping their own error-code taxonomy ([#9409](https://github.com/MetaMask/core/pull/9409))
16
+ - Add `@metamask/remote-feature-flag-controller` `^4.2.2` as a runtime dependency ([#9409](https://github.com/MetaMask/core/pull/9409))
17
+
18
+ ### Changed
19
+
20
+ - **BREAKING:** Replace the `getProviderScope` constructor option and the exported `ProviderScope` type (`'off' | 'in-app' | 'all'`) with a controller-side read of the `moneyHeadlessAllProviders` boolean remote feature flag ([#9409](https://github.com/MetaMask/core/pull/9409))
21
+ - `RampsController.getQuotes` resolves the flag through the `RemoteFeatureFlagController:getState` messenger action on each auto-selection call, so a remote fetch or a local dev override takes effect at runtime; consumers should delegate that action to the controller's messenger (when it is missing, the flag read fails closed and quoting stays native-only)
22
+ - When the flag is `true`, the auto-selection path (`autoSelectProvider` / `restrictToKnownOrNativeProviders`) widens to every supporting provider class (native, in-app WebView aggregator, and external-browser / custom-action) and returns the best quote at `success[0]`, enforcing per-provider fiat limits; when the flag is `false`, missing, or any non-boolean value, the path stays native-only
23
+ - The intermediate `in-app` scope (which excluded external-browser and custom-action quotes from selection) is removed
24
+ - `RampsController` now derives its internal region provider-asset matching from the shared `providerAvailability` helpers, so the exposed helpers stay behaviourally identical to the controller's own selection ([#9409](https://github.com/MetaMask/core/pull/9409))
25
+
26
+ ## [16.0.0]
27
+
10
28
  ### Changed
11
29
 
12
30
  - **BREAKING:** Provider IDs are no longer normalized by stripping a `/providers/` prefix. `RampsController.getQuotes` now matches provider IDs from the providers list, quotes, custom actions, and sort order as-is, and a precreated stub order's `provider.id` is the canonical provider code passed to the create-order call rather than a `/providers/`-prefixed value. Consumers must supply non-prefixed (canonical) provider IDs ([#9448](https://github.com/MetaMask/core/pull/9448))
31
+ - Update `LICENSE` text ([#9472](https://github.com/MetaMask/core/pull/9472))
13
32
  - Bump `@metamask/profile-sync-controller` from `^28.2.0` to `^28.3.0` ([#9463](https://github.com/MetaMask/core/pull/9463))
14
33
 
15
34
  ### Removed
@@ -420,7 +439,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
420
439
  - Add `OnRampService` for interacting with the OnRamp API
421
440
  - Add geolocation detection via IP address lookup
422
441
 
423
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@15.1.0...HEAD
442
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@16.0.0...HEAD
443
+ [16.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@15.1.0...@metamask/ramps-controller@16.0.0
424
444
  [15.1.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@15.0.0...@metamask/ramps-controller@15.1.0
425
445
  [15.0.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@14.3.0...@metamask/ramps-controller@15.0.0
426
446
  [14.3.0]: https://github.com/MetaMask/core/compare/@metamask/ramps-controller@14.2.0...@metamask/ramps-controller@14.3.0
@@ -10,11 +10,13 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
12
  };
13
- var _RampsController_instances, _RampsController_requestCacheTTL, _RampsController_requestCacheMaxSize, _RampsController_getProviderScope, _RampsController_getDefaultRedirectUrl, _RampsController_pendingRequests, _RampsController_pendingResourceCount, _RampsController_pendingResourceGeneration, _RampsController_orderPollingMeta, _RampsController_orderPollingTimer, _RampsController_isPolling, _RampsController_initPromise, _RampsController_clearPendingResourceCountForDependentResources, _RampsController_abortDependentRequests, _RampsController_mutateRequests, _RampsController_removeRequestState, _RampsController_cleanupState, _RampsController_requireRegion, _RampsController_isRegionCurrent, _RampsController_isTokenCurrent, _RampsController_isProviderCurrent, _RampsController_updateResourceField, _RampsController_setResourceLoading, _RampsController_setResourceError, _RampsController_updateRequestState, _RampsController_runInit, _RampsController_syncUserRegionFromCountriesCatalog, _RampsController_pickInAppQuote, _RampsController_getSupportingProvidersForRegion, _RampsController_filterProviderIdsBySupport, _RampsController_resolveProviderIdsForQuote, _RampsController_getPreferredProviderIdsFromOrders, _RampsController_refreshOrder, _RampsController_pollPendingOrders, _RampsController_syncTransakAuthOnError, _RampsController_getNormalizedTransakError;
13
+ var _RampsController_instances, _RampsController_requestCacheTTL, _RampsController_requestCacheMaxSize, _RampsController_getDefaultRedirectUrl, _RampsController_pendingRequests, _RampsController_pendingResourceCount, _RampsController_pendingResourceGeneration, _RampsController_orderPollingMeta, _RampsController_orderPollingTimer, _RampsController_isPolling, _RampsController_initPromise, _RampsController_clearPendingResourceCountForDependentResources, _RampsController_abortDependentRequests, _RampsController_isAllProvidersEnabled, _RampsController_mutateRequests, _RampsController_removeRequestState, _RampsController_cleanupState, _RampsController_requireRegion, _RampsController_isRegionCurrent, _RampsController_isTokenCurrent, _RampsController_isProviderCurrent, _RampsController_updateResourceField, _RampsController_setResourceLoading, _RampsController_setResourceError, _RampsController_updateRequestState, _RampsController_runInit, _RampsController_syncUserRegionFromCountriesCatalog, _RampsController_pickWidenedQuote, _RampsController_getSupportingProvidersForRegion, _RampsController_filterProviderIdsBySupport, _RampsController_resolveProviderIdsForQuote, _RampsController_getPreferredProviderIdsFromOrders, _RampsController_refreshOrder, _RampsController_pollPendingOrders, _RampsController_syncTransakAuthOnError, _RampsController_getNormalizedTransakError;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.RampsController = exports.getInternalOrderCode = exports.getDefaultRampsControllerState = exports.RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS = exports.controllerName = void 0;
16
16
  const base_controller_1 = require("@metamask/base-controller");
17
17
  const controller_utils_1 = require("@metamask/controller-utils");
18
+ const featureFlags_1 = require("./featureFlags.cjs");
19
+ const providerAvailability_1 = require("./providerAvailability.cjs");
18
20
  const rampsErrorCodes_1 = require("./rampsErrorCodes.cjs");
19
21
  const RampsService_1 = require("./RampsService.cjs");
20
22
  const RequestCache_1 = require("./RequestCache.cjs");
@@ -437,13 +439,11 @@ class RampsController extends base_controller_1.BaseController {
437
439
  * controller. Missing properties will be filled in with defaults.
438
440
  * @param args.requestCacheTTL - Time to live for cached requests in milliseconds.
439
441
  * @param args.requestCacheMaxSize - Maximum number of entries in the request cache.
440
- * @param args.getProviderScope - Optional callback returning the current
441
- * provider-class scope for fiat quote widening. Defaults to `off`.
442
442
  * @param args.getDefaultRedirectUrl - Optional callback returning the default
443
- * redirect URL used for the widened in-app quote fetch when the caller omits
443
+ * redirect URL used for the widened quote fetch when the caller omits
444
444
  * `redirectUrl`. Defaults to a callback returning `undefined`.
445
445
  */
446
- constructor({ messenger, state = {}, requestCacheTTL = RequestCache_1.DEFAULT_REQUEST_CACHE_TTL, requestCacheMaxSize = RequestCache_1.DEFAULT_REQUEST_CACHE_MAX_SIZE, getProviderScope, getDefaultRedirectUrl, }) {
446
+ constructor({ messenger, state = {}, requestCacheTTL = RequestCache_1.DEFAULT_REQUEST_CACHE_TTL, requestCacheMaxSize = RequestCache_1.DEFAULT_REQUEST_CACHE_MAX_SIZE, getDefaultRedirectUrl, }) {
447
447
  super({
448
448
  messenger,
449
449
  metadata: rampsControllerMetadata,
@@ -465,12 +465,7 @@ class RampsController extends base_controller_1.BaseController {
465
465
  */
466
466
  _RampsController_requestCacheMaxSize.set(this, void 0);
467
467
  /**
468
- * Resolves the current provider-class scope for fiat quote widening. Defaults
469
- * to `() => 'off'` (native-only) when no callback is injected.
470
- */
471
- _RampsController_getProviderScope.set(this, void 0);
472
- /**
473
- * Resolves the default redirect URL for the widened in-app quote fetch when
468
+ * Resolves the default redirect URL for the widened quote fetch when
474
469
  * the caller omits `redirectUrl`. Defaults to `() => undefined` when no
475
470
  * callback is injected.
476
471
  */
@@ -496,7 +491,6 @@ class RampsController extends base_controller_1.BaseController {
496
491
  _RampsController_initPromise.set(this, null);
497
492
  __classPrivateFieldSet(this, _RampsController_requestCacheTTL, requestCacheTTL, "f");
498
493
  __classPrivateFieldSet(this, _RampsController_requestCacheMaxSize, requestCacheMaxSize, "f");
499
- __classPrivateFieldSet(this, _RampsController_getProviderScope, getProviderScope ?? (() => 'off'), "f");
500
494
  __classPrivateFieldSet(this, _RampsController_getDefaultRedirectUrl, getDefaultRedirectUrl ?? (() => undefined), "f");
501
495
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
502
496
  }
@@ -1012,19 +1006,17 @@ class RampsController extends base_controller_1.BaseController {
1012
1006
  if (normalizedAssetIdForValidation === '') {
1013
1007
  throw new Error('assetId is required.');
1014
1008
  }
1015
- // When a non-`off` provider scope is active, widen the native-only
1016
- // auto-selection path to every supporting provider and pick the best in-app
1017
- // quote from the results (in-app vs external is only knowable per-quote via
1018
- // `buyWidget.browser`). Only the auto-select/restrict path that MM Pay's
1009
+ // When the all-providers feature flag is enabled, widen the native-only
1010
+ // auto-selection path to every supporting provider and pick the best
1011
+ // quote from the results. Only the auto-select/restrict path that MM Pay's
1019
1012
  // `getRampsQuote` uses is affected; explicit-`providers` callers and the
1020
- // plain all-provider path are untouched.
1021
- const providerScope = __classPrivateFieldGet(this, _RampsController_getProviderScope, "f").call(this);
1022
- const widenToInAppProviders = providerScope !== 'off' &&
1023
- !options.providers &&
1013
+ // plain all-provider path are untouched (and never read the flag).
1014
+ const wantsAutoSelection = !options.providers &&
1024
1015
  (options.autoSelectProvider === true ||
1025
1016
  options.restrictToKnownOrNativeProviders === true);
1017
+ const widenToAllProviders = wantsAutoSelection && __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_isAllProvidersEnabled).call(this);
1026
1018
  let providersToUse;
1027
- let inAppProviderCatalog = this.state.providers.data;
1019
+ let widenedProviderCatalog = this.state.providers.data;
1028
1020
  if (options.providers) {
1029
1021
  providersToUse = options.restrictToKnownOrNativeProviders
1030
1022
  ? await __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_filterProviderIdsBySupport).call(this, {
@@ -1034,7 +1026,7 @@ class RampsController extends base_controller_1.BaseController {
1034
1026
  })
1035
1027
  : options.providers;
1036
1028
  }
1037
- else if (widenToInAppProviders) {
1029
+ else if (widenToAllProviders) {
1038
1030
  // `#getSupportingProvidersForRegion` also hydrates the provider catalog
1039
1031
  // when controller state is empty, so all-provider quoting cannot silently
1040
1032
  // return zero providers here.
@@ -1042,7 +1034,7 @@ class RampsController extends base_controller_1.BaseController {
1042
1034
  assetId: normalizedAssetIdForValidation,
1043
1035
  region: regionToUse,
1044
1036
  });
1045
- inAppProviderCatalog = supporting;
1037
+ widenedProviderCatalog = supporting;
1046
1038
  providersToUse = supporting.map((provider) => provider.id);
1047
1039
  }
1048
1040
  else if (options.autoSelectProvider ||
@@ -1074,12 +1066,12 @@ class RampsController extends base_controller_1.BaseController {
1074
1066
  // Under headless-buy gating, an empty resolved provider list means no
1075
1067
  // eligible (native/supporting) provider exists. Return an empty response
1076
1068
  // rather than passing `[]` to the service, which omits the provider filter
1077
- // and would quote every provider. This also guards the widened in-app path:
1069
+ // and would quote every provider. This also guards the widened path:
1078
1070
  // a caller may trigger widening with `autoSelectProvider` alone (no
1079
1071
  // `restrictToKnownOrNativeProviders`), and an empty supporting set must not
1080
1072
  // fall through to unfiltered quotes from providers that do not support the
1081
1073
  // asset.
1082
- if ((options.restrictToKnownOrNativeProviders || widenToInAppProviders) &&
1074
+ if ((options.restrictToKnownOrNativeProviders || widenToAllProviders) &&
1083
1075
  providersToUse.length === 0) {
1084
1076
  return { success: [], sorted: [], error: [], customActions: [] };
1085
1077
  }
@@ -1088,11 +1080,12 @@ class RampsController extends base_controller_1.BaseController {
1088
1080
  const normalizedAssetId = normalizedAssetIdForValidation;
1089
1081
  const normalizedWalletAddress = options.walletAddress.trim();
1090
1082
  // The quotes API only embeds a `buyURL`/`buyWidget` when a `redirectUrl` is
1091
- // present, so on the widened in-app path (where MM Pay omits one) supply the
1083
+ // present, so on the widened path (where MM Pay omits one) supply the
1092
1084
  // injected default so aggregator quotes carry a usable widget URL. An
1093
- // explicit caller `redirectUrl` always wins, and scope `off` never injects.
1085
+ // explicit caller `redirectUrl` always wins, and the native-only path
1086
+ // (flag off) never injects.
1094
1087
  const effectiveRedirectUrl = options.redirectUrl ??
1095
- (widenToInAppProviders ? __classPrivateFieldGet(this, _RampsController_getDefaultRedirectUrl, "f").call(this) : undefined);
1088
+ (widenToAllProviders ? __classPrivateFieldGet(this, _RampsController_getDefaultRedirectUrl, "f").call(this) : undefined);
1096
1089
  const cacheKey = (0, RequestCache_1.createCacheKey)('getQuotes', [
1097
1090
  normalizedRegion,
1098
1091
  normalizedFiat,
@@ -1121,22 +1114,21 @@ class RampsController extends base_controller_1.BaseController {
1121
1114
  forceRefresh: options.forceRefresh,
1122
1115
  ttl: options.ttl ?? DEFAULT_QUOTES_TTL,
1123
1116
  });
1124
- if (!widenToInAppProviders) {
1117
+ if (!widenToAllProviders) {
1125
1118
  return response;
1126
1119
  }
1127
- // Reduce the widened multi-provider result to the single best in-app quote
1120
+ // Reduce the widened multi-provider result to the single best quote
1128
1121
  // and place it at `success[0]`, since single-pick consumers
1129
1122
  // (`getRampsQuote` -> `success?.[0]`) rely on index 0 while `success[]`
1130
1123
  // order is server-defined rather than ranked.
1131
- const selectedQuote = __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_pickInAppQuote).call(this, response, {
1132
- scope: providerScope,
1124
+ const selectedQuote = __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_pickWidenedQuote).call(this, response, {
1133
1125
  amount: options.amount,
1134
1126
  fiat: normalizedFiat,
1135
- providers: inAppProviderCatalog,
1127
+ providers: widenedProviderCatalog,
1136
1128
  });
1137
1129
  if (!selectedQuote) {
1138
- // No usable in-app quote: surface "no quote" rather than leaking an
1139
- // external/custom quote to the single-pick consumer.
1130
+ // No quote fits the published provider limits: surface "no quote"
1131
+ // rather than handing the single-pick consumer an out-of-limits quote.
1140
1132
  return {
1141
1133
  success: [],
1142
1134
  sorted: response.sorted,
@@ -1766,7 +1758,7 @@ class RampsController extends base_controller_1.BaseController {
1766
1758
  }
1767
1759
  }
1768
1760
  exports.RampsController = RampsController;
1769
- _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheMaxSize = new WeakMap(), _RampsController_getProviderScope = new WeakMap(), _RampsController_getDefaultRedirectUrl = new WeakMap(), _RampsController_pendingRequests = new WeakMap(), _RampsController_pendingResourceCount = new WeakMap(), _RampsController_pendingResourceGeneration = new WeakMap(), _RampsController_orderPollingMeta = new WeakMap(), _RampsController_orderPollingTimer = new WeakMap(), _RampsController_isPolling = new WeakMap(), _RampsController_initPromise = new WeakMap(), _RampsController_instances = new WeakSet(), _RampsController_clearPendingResourceCountForDependentResources = function _RampsController_clearPendingResourceCountForDependentResources() {
1761
+ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheMaxSize = new WeakMap(), _RampsController_getDefaultRedirectUrl = new WeakMap(), _RampsController_pendingRequests = new WeakMap(), _RampsController_pendingResourceCount = new WeakMap(), _RampsController_pendingResourceGeneration = new WeakMap(), _RampsController_orderPollingMeta = new WeakMap(), _RampsController_orderPollingTimer = new WeakMap(), _RampsController_isPolling = new WeakMap(), _RampsController_initPromise = new WeakMap(), _RampsController_instances = new WeakSet(), _RampsController_clearPendingResourceCountForDependentResources = function _RampsController_clearPendingResourceCountForDependentResources() {
1770
1762
  for (const resourceType of DEPENDENT_RESOURCE_KEYS) {
1771
1763
  __classPrivateFieldGet(this, _RampsController_pendingResourceCount, "f").delete(resourceType);
1772
1764
  const generation = __classPrivateFieldGet(this, _RampsController_pendingResourceGeneration, "f").get(resourceType) ?? 0;
@@ -1781,6 +1773,14 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
1781
1773
  __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_removeRequestState).call(this, cacheKey);
1782
1774
  }
1783
1775
  }
1776
+ }, _RampsController_isAllProvidersEnabled = function _RampsController_isAllProvidersEnabled() {
1777
+ try {
1778
+ const remoteFeatureFlagState = this.messenger.call('RemoteFeatureFlagController:getState');
1779
+ return (0, featureFlags_1.isHeadlessAllProvidersEnabled)(remoteFeatureFlagState);
1780
+ }
1781
+ catch {
1782
+ return false;
1783
+ }
1784
1784
  }, _RampsController_mutateRequests = function _RampsController_mutateRequests(fn) {
1785
1785
  this.update((state) => {
1786
1786
  const requests = state.requests;
@@ -1892,9 +1892,8 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
1892
1892
  this.update((state) => {
1893
1893
  state.userRegion = userRegion;
1894
1894
  });
1895
- }, _RampsController_pickInAppQuote = function _RampsController_pickInAppQuote(response, { scope, amount, fiat, providers, }) {
1895
+ }, _RampsController_pickWidenedQuote = function _RampsController_pickWidenedQuote(response, { amount, fiat, providers, }) {
1896
1896
  const providerByCode = new Map(providers.map((provider) => [provider.id, provider]));
1897
- const customActionProviderCodes = new Set(response.customActions.map((action) => action.buy.providerId));
1898
1897
  const fitsProviderLimits = (quote) => {
1899
1898
  const provider = providerByCode.get(quote.provider);
1900
1899
  const limit = provider?.limits?.fiat?.[fiat]?.[quote.quote.paymentMethod];
@@ -1905,26 +1904,7 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
1905
1904
  }
1906
1905
  return amount >= limit.minAmount && amount <= limit.maxAmount;
1907
1906
  };
1908
- const isEligible = (quote) => {
1909
- // `all` (Phase 2) skips the in-app-only exclusions; both scopes still
1910
- // enforce provider limits up front.
1911
- if (scope !== 'all') {
1912
- const providerCode = quote.provider;
1913
- if (customActionProviderCodes.has(providerCode)) {
1914
- return false;
1915
- }
1916
- // Defensive: the wire may carry an inline `isCustomAction` flag that is
1917
- // absent from the published `Quote` type.
1918
- if (quote.quote.isCustomAction === true) {
1919
- return false;
1920
- }
1921
- if (quote.quote.buyWidget?.browser === 'IN_APP_OS_BROWSER') {
1922
- return false;
1923
- }
1924
- }
1925
- return fitsProviderLimits(quote);
1926
- };
1927
- const candidates = response.success.filter(isEligible);
1907
+ const candidates = response.success.filter(fitsProviderLimits);
1928
1908
  if (candidates.length === 0) {
1929
1909
  return undefined;
1930
1910
  }
@@ -1969,18 +1949,10 @@ async function _RampsController_getSupportingProvidersForRegion({ assetId, regio
1969
1949
  else {
1970
1950
  ({ providers } = await this.getProviders(normalizedRegion));
1971
1951
  }
1972
- // EVM CAIP-19 asset IDs may arrive checksummed or lowercased, and the
1973
- // providers API returns both forms, so match case-insensitively on both
1974
- // sides. Only the lowercased forms are compared (the original IDs are never
1975
- // returned), so case-sensitive non-EVM asset IDs are not corrupted.
1976
- const normalizedAssetId = assetId.toLowerCase();
1977
- const supporting = providers.filter((provider) => {
1978
- const map = provider?.supportedCryptoCurrencies;
1979
- if (!map) {
1980
- return false;
1981
- }
1982
- return Object.keys(map).some((key) => key.toLowerCase() === normalizedAssetId);
1983
- });
1952
+ // Case-insensitive CAIP-19 matching is shared with headless-buy consumers
1953
+ // via `getProvidersServingAsset`, so the controller and the UI region gate
1954
+ // cannot disagree about which providers serve the asset.
1955
+ const supporting = (0, providerAvailability_1.getProvidersServingAsset)(providers, assetId);
1984
1956
  return { supporting, all: providers };
1985
1957
  }, _RampsController_filterProviderIdsBySupport =
1986
1958
  /**