@metamask/ramps-controller 15.0.0 → 16.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -1
- package/LICENSE +1 -0
- package/dist/RampsController-method-action-types.cjs.map +1 -1
- package/dist/RampsController-method-action-types.d.cts +5 -3
- package/dist/RampsController-method-action-types.d.cts.map +1 -1
- package/dist/RampsController-method-action-types.d.mts +5 -3
- package/dist/RampsController-method-action-types.d.mts.map +1 -1
- package/dist/RampsController-method-action-types.mjs.map +1 -1
- package/dist/RampsController.cjs +185 -26
- package/dist/RampsController.cjs.map +1 -1
- package/dist/RampsController.d.cts +38 -5
- package/dist/RampsController.d.cts.map +1 -1
- package/dist/RampsController.d.mts +38 -5
- package/dist/RampsController.d.mts.map +1 -1
- package/dist/RampsController.mjs +184 -24
- package/dist/RampsController.mjs.map +1 -1
- package/dist/index.cjs +1 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/RampsController.cjs
CHANGED
|
@@ -10,9 +10,9 @@ 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_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_getSupportingProvidersForRegion, _RampsController_filterProviderIdsBySupport, _RampsController_resolveProviderIdsForQuote, _RampsController_getPreferredProviderIdsFromOrders, _RampsController_refreshOrder, _RampsController_pollPendingOrders, _RampsController_syncTransakAuthOnError, _RampsController_getNormalizedTransakError;
|
|
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;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.RampsController = exports.getInternalOrderCode = exports.
|
|
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
18
|
const rampsErrorCodes_1 = require("./rampsErrorCodes.cjs");
|
|
@@ -135,7 +135,7 @@ const rampsControllerMetadata = {
|
|
|
135
135
|
usedInUi: true,
|
|
136
136
|
},
|
|
137
137
|
countries: {
|
|
138
|
-
persist:
|
|
138
|
+
persist: false,
|
|
139
139
|
includeInDebugSnapshot: true,
|
|
140
140
|
includeInStateLogs: true,
|
|
141
141
|
usedInUi: true,
|
|
@@ -329,10 +329,6 @@ function findRegionFromCode(regionCode, countries) {
|
|
|
329
329
|
regionCode: normalizedCode,
|
|
330
330
|
};
|
|
331
331
|
}
|
|
332
|
-
function normalizeProviderCode(providerCode) {
|
|
333
|
-
return providerCode.replace(/^\/providers\//u, '');
|
|
334
|
-
}
|
|
335
|
-
exports.normalizeProviderCode = normalizeProviderCode;
|
|
336
332
|
/**
|
|
337
333
|
* Returns the internal MetaMask order code used for state lookups and polling.
|
|
338
334
|
* Prefers the code embedded in the canonical order `id` path over `providerOrderId`,
|
|
@@ -441,8 +437,13 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
441
437
|
* controller. Missing properties will be filled in with defaults.
|
|
442
438
|
* @param args.requestCacheTTL - Time to live for cached requests in milliseconds.
|
|
443
439
|
* @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
|
+
* @param args.getDefaultRedirectUrl - Optional callback returning the default
|
|
443
|
+
* redirect URL used for the widened in-app quote fetch when the caller omits
|
|
444
|
+
* `redirectUrl`. Defaults to a callback returning `undefined`.
|
|
444
445
|
*/
|
|
445
|
-
constructor({ messenger, state = {}, requestCacheTTL = RequestCache_1.DEFAULT_REQUEST_CACHE_TTL, requestCacheMaxSize = RequestCache_1.DEFAULT_REQUEST_CACHE_MAX_SIZE, }) {
|
|
446
|
+
constructor({ messenger, state = {}, requestCacheTTL = RequestCache_1.DEFAULT_REQUEST_CACHE_TTL, requestCacheMaxSize = RequestCache_1.DEFAULT_REQUEST_CACHE_MAX_SIZE, getProviderScope, getDefaultRedirectUrl, }) {
|
|
446
447
|
super({
|
|
447
448
|
messenger,
|
|
448
449
|
metadata: rampsControllerMetadata,
|
|
@@ -463,6 +464,17 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
463
464
|
* Maximum number of entries in the request cache.
|
|
464
465
|
*/
|
|
465
466
|
_RampsController_requestCacheMaxSize.set(this, void 0);
|
|
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
|
|
474
|
+
* the caller omits `redirectUrl`. Defaults to `() => undefined` when no
|
|
475
|
+
* callback is injected.
|
|
476
|
+
*/
|
|
477
|
+
_RampsController_getDefaultRedirectUrl.set(this, void 0);
|
|
466
478
|
/**
|
|
467
479
|
* Map of pending requests for deduplication.
|
|
468
480
|
* Key is the cache key, value is the pending request with abort controller.
|
|
@@ -484,6 +496,8 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
484
496
|
_RampsController_initPromise.set(this, null);
|
|
485
497
|
__classPrivateFieldSet(this, _RampsController_requestCacheTTL, requestCacheTTL, "f");
|
|
486
498
|
__classPrivateFieldSet(this, _RampsController_requestCacheMaxSize, requestCacheMaxSize, "f");
|
|
499
|
+
__classPrivateFieldSet(this, _RampsController_getProviderScope, getProviderScope ?? (() => 'off'), "f");
|
|
500
|
+
__classPrivateFieldSet(this, _RampsController_getDefaultRedirectUrl, getDefaultRedirectUrl ?? (() => undefined), "f");
|
|
487
501
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
488
502
|
}
|
|
489
503
|
/**
|
|
@@ -721,8 +735,10 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
721
735
|
* This should be called once at app startup to set up the initial region.
|
|
722
736
|
*
|
|
723
737
|
* Idempotent: subsequent calls return the same promise unless forceRefresh is set.
|
|
724
|
-
*
|
|
725
|
-
*
|
|
738
|
+
* Force-refetches the countries catalog on startup (bypassing the in-session
|
|
739
|
+
* request cache) so region preset amounts stay current. The catalog is not
|
|
740
|
+
* persisted, so a cold start always re-fetches it regardless. Skips
|
|
741
|
+
* geolocation when userRegion already exists.
|
|
726
742
|
*
|
|
727
743
|
* @param options - Options for cache behavior. forceRefresh bypasses idempotency and re-runs the full flow.
|
|
728
744
|
* @returns Promise that resolves when initialization is complete.
|
|
@@ -759,6 +775,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
759
775
|
this.update((state) => {
|
|
760
776
|
state.countries.data = Array.isArray(countries) ? [...countries] : [];
|
|
761
777
|
});
|
|
778
|
+
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_syncUserRegionFromCountriesCatalog).call(this);
|
|
762
779
|
return countries;
|
|
763
780
|
}
|
|
764
781
|
/**
|
|
@@ -995,7 +1012,19 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
995
1012
|
if (normalizedAssetIdForValidation === '') {
|
|
996
1013
|
throw new Error('assetId is required.');
|
|
997
1014
|
}
|
|
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
|
|
1019
|
+
// `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 &&
|
|
1024
|
+
(options.autoSelectProvider === true ||
|
|
1025
|
+
options.restrictToKnownOrNativeProviders === true);
|
|
998
1026
|
let providersToUse;
|
|
1027
|
+
let inAppProviderCatalog = this.state.providers.data;
|
|
999
1028
|
if (options.providers) {
|
|
1000
1029
|
providersToUse = options.restrictToKnownOrNativeProviders
|
|
1001
1030
|
? await __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_filterProviderIdsBySupport).call(this, {
|
|
@@ -1005,6 +1034,17 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1005
1034
|
})
|
|
1006
1035
|
: options.providers;
|
|
1007
1036
|
}
|
|
1037
|
+
else if (widenToInAppProviders) {
|
|
1038
|
+
// `#getSupportingProvidersForRegion` also hydrates the provider catalog
|
|
1039
|
+
// when controller state is empty, so all-provider quoting cannot silently
|
|
1040
|
+
// return zero providers here.
|
|
1041
|
+
const { supporting } = await __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_getSupportingProvidersForRegion).call(this, {
|
|
1042
|
+
assetId: normalizedAssetIdForValidation,
|
|
1043
|
+
region: regionToUse,
|
|
1044
|
+
});
|
|
1045
|
+
inAppProviderCatalog = supporting;
|
|
1046
|
+
providersToUse = supporting.map((provider) => provider.id);
|
|
1047
|
+
}
|
|
1008
1048
|
else if (options.autoSelectProvider ||
|
|
1009
1049
|
options.restrictToKnownOrNativeProviders) {
|
|
1010
1050
|
// The restriction flag implies resolution: it must narrow the provider
|
|
@@ -1034,8 +1074,12 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1034
1074
|
// Under headless-buy gating, an empty resolved provider list means no
|
|
1035
1075
|
// eligible (native/supporting) provider exists. Return an empty response
|
|
1036
1076
|
// rather than passing `[]` to the service, which omits the provider filter
|
|
1037
|
-
// and would quote every provider.
|
|
1038
|
-
|
|
1077
|
+
// and would quote every provider. This also guards the widened in-app path:
|
|
1078
|
+
// a caller may trigger widening with `autoSelectProvider` alone (no
|
|
1079
|
+
// `restrictToKnownOrNativeProviders`), and an empty supporting set must not
|
|
1080
|
+
// fall through to unfiltered quotes from providers that do not support the
|
|
1081
|
+
// asset.
|
|
1082
|
+
if ((options.restrictToKnownOrNativeProviders || widenToInAppProviders) &&
|
|
1039
1083
|
providersToUse.length === 0) {
|
|
1040
1084
|
return { success: [], sorted: [], error: [], customActions: [] };
|
|
1041
1085
|
}
|
|
@@ -1043,6 +1087,12 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1043
1087
|
const normalizedFiat = fiatToUse.toLowerCase().trim();
|
|
1044
1088
|
const normalizedAssetId = normalizedAssetIdForValidation;
|
|
1045
1089
|
const normalizedWalletAddress = options.walletAddress.trim();
|
|
1090
|
+
// 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
|
|
1092
|
+
// injected default so aggregator quotes carry a usable widget URL. An
|
|
1093
|
+
// explicit caller `redirectUrl` always wins, and scope `off` never injects.
|
|
1094
|
+
const effectiveRedirectUrl = options.redirectUrl ??
|
|
1095
|
+
(widenToInAppProviders ? __classPrivateFieldGet(this, _RampsController_getDefaultRedirectUrl, "f").call(this) : undefined);
|
|
1046
1096
|
const cacheKey = (0, RequestCache_1.createCacheKey)('getQuotes', [
|
|
1047
1097
|
normalizedRegion,
|
|
1048
1098
|
normalizedFiat,
|
|
@@ -1051,7 +1101,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1051
1101
|
normalizedWalletAddress,
|
|
1052
1102
|
[...paymentMethodsToUse].sort().join(','),
|
|
1053
1103
|
[...providersToUse].sort().join(','),
|
|
1054
|
-
|
|
1104
|
+
effectiveRedirectUrl,
|
|
1055
1105
|
action,
|
|
1056
1106
|
]);
|
|
1057
1107
|
const params = {
|
|
@@ -1062,15 +1112,45 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1062
1112
|
walletAddress: normalizedWalletAddress,
|
|
1063
1113
|
paymentMethods: paymentMethodsToUse,
|
|
1064
1114
|
providers: providersToUse,
|
|
1065
|
-
redirectUrl:
|
|
1115
|
+
redirectUrl: effectiveRedirectUrl,
|
|
1066
1116
|
action,
|
|
1067
1117
|
};
|
|
1068
|
-
|
|
1118
|
+
const response = await this.executeRequest(cacheKey, async () => {
|
|
1069
1119
|
return this.messenger.call('RampsService:getQuotes', params);
|
|
1070
1120
|
}, {
|
|
1071
1121
|
forceRefresh: options.forceRefresh,
|
|
1072
1122
|
ttl: options.ttl ?? DEFAULT_QUOTES_TTL,
|
|
1073
1123
|
});
|
|
1124
|
+
if (!widenToInAppProviders) {
|
|
1125
|
+
return response;
|
|
1126
|
+
}
|
|
1127
|
+
// Reduce the widened multi-provider result to the single best in-app quote
|
|
1128
|
+
// and place it at `success[0]`, since single-pick consumers
|
|
1129
|
+
// (`getRampsQuote` -> `success?.[0]`) rely on index 0 while `success[]`
|
|
1130
|
+
// order is server-defined rather than ranked.
|
|
1131
|
+
const selectedQuote = __classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_pickInAppQuote).call(this, response, {
|
|
1132
|
+
scope: providerScope,
|
|
1133
|
+
amount: options.amount,
|
|
1134
|
+
fiat: normalizedFiat,
|
|
1135
|
+
providers: inAppProviderCatalog,
|
|
1136
|
+
});
|
|
1137
|
+
if (!selectedQuote) {
|
|
1138
|
+
// No usable in-app quote: surface "no quote" rather than leaking an
|
|
1139
|
+
// external/custom quote to the single-pick consumer.
|
|
1140
|
+
return {
|
|
1141
|
+
success: [],
|
|
1142
|
+
sorted: response.sorted,
|
|
1143
|
+
error: response.error,
|
|
1144
|
+
customActions: response.customActions,
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
return {
|
|
1148
|
+
...response,
|
|
1149
|
+
success: [
|
|
1150
|
+
selectedQuote,
|
|
1151
|
+
...response.success.filter((quote) => quote !== selectedQuote),
|
|
1152
|
+
],
|
|
1153
|
+
};
|
|
1074
1154
|
}
|
|
1075
1155
|
// === ORDER MANAGEMENT ===
|
|
1076
1156
|
/**
|
|
@@ -1169,7 +1249,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1169
1249
|
*
|
|
1170
1250
|
* @param params - Object containing order identifiers and wallet info.
|
|
1171
1251
|
* @param params.orderId - Full order ID (e.g. "/providers/paypal/orders/abc123") or order code.
|
|
1172
|
-
* @param params.providerCode -
|
|
1252
|
+
* @param params.providerCode - Canonical provider code (e.g. "paypal", "transak").
|
|
1173
1253
|
* @param params.walletAddress - Wallet address for the order.
|
|
1174
1254
|
* @param params.chainId - Optional chain ID for the order.
|
|
1175
1255
|
*/
|
|
@@ -1179,11 +1259,10 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1179
1259
|
if (!orderCode?.trim()) {
|
|
1180
1260
|
return;
|
|
1181
1261
|
}
|
|
1182
|
-
const normalizedProviderCode = normalizeProviderCode(providerCode);
|
|
1183
1262
|
const stubOrder = {
|
|
1184
1263
|
providerOrderId: orderCode,
|
|
1185
1264
|
provider: {
|
|
1186
|
-
id:
|
|
1265
|
+
id: providerCode,
|
|
1187
1266
|
name: '',
|
|
1188
1267
|
environmentType: '',
|
|
1189
1268
|
description: '',
|
|
@@ -1687,7 +1766,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1687
1766
|
}
|
|
1688
1767
|
}
|
|
1689
1768
|
exports.RampsController = RampsController;
|
|
1690
|
-
_RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheMaxSize = 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() {
|
|
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() {
|
|
1691
1770
|
for (const resourceType of DEPENDENT_RESOURCE_KEYS) {
|
|
1692
1771
|
__classPrivateFieldGet(this, _RampsController_pendingResourceCount, "f").delete(resourceType);
|
|
1693
1772
|
const generation = __classPrivateFieldGet(this, _RampsController_pendingResourceGeneration, "f").get(resourceType) ?? 0;
|
|
@@ -1773,20 +1852,100 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
|
|
|
1773
1852
|
}
|
|
1774
1853
|
});
|
|
1775
1854
|
}, _RampsController_runInit = async function _RampsController_runInit(options) {
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
}
|
|
1855
|
+
// Force-refetch the catalog on startup so region preset amounts stay
|
|
1856
|
+
// current, bypassing the in-session request cache. The catalog is not
|
|
1857
|
+
// persisted, so a cold start always re-fetches it regardless.
|
|
1858
|
+
await this.getCountries({ ...options, forceRefresh: true });
|
|
1781
1859
|
// Always prefer the user's persisted region. Geolocation is only used to
|
|
1782
1860
|
// seed the initial value; once the user (or a prior init) has set a region
|
|
1783
1861
|
// we must respect that choice — even on forceRefresh.
|
|
1784
|
-
|
|
1785
|
-
|
|
1862
|
+
const persistedRegionCode = this.state.userRegion?.regionCode;
|
|
1863
|
+
const regionCode = persistedRegionCode ??
|
|
1864
|
+
(await this.messenger.call('RampsService:getGeolocation'));
|
|
1786
1865
|
if (!regionCode) {
|
|
1787
1866
|
throw new Error('Failed to fetch geolocation. Cannot initialize controller without valid region information.');
|
|
1788
1867
|
}
|
|
1868
|
+
// For an already-persisted region, getCountries() has already re-synced it
|
|
1869
|
+
// from the fresh catalog (see #syncUserRegionFromCountriesCatalog). Calling
|
|
1870
|
+
// setUserRegion here would re-validate against that catalog and, if it is
|
|
1871
|
+
// momentarily empty or no longer lists the region (e.g. a transient/partial
|
|
1872
|
+
// catalog response or a region with no current provider coverage), throw and
|
|
1873
|
+
// wipe the persisted region via #cleanupState. Preserve the existing region
|
|
1874
|
+
// instead; only resolve a brand-new region (from geolocation) strictly.
|
|
1875
|
+
if (persistedRegionCode) {
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1789
1878
|
await this.setUserRegion(regionCode, options);
|
|
1879
|
+
}, _RampsController_syncUserRegionFromCountriesCatalog = function _RampsController_syncUserRegionFromCountriesCatalog() {
|
|
1880
|
+
const regionCode = this.state.userRegion?.regionCode;
|
|
1881
|
+
if (!regionCode) {
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
const countriesData = this.state.countries.data;
|
|
1885
|
+
if (!countriesData.length) {
|
|
1886
|
+
return;
|
|
1887
|
+
}
|
|
1888
|
+
const userRegion = findRegionFromCode(regionCode, countriesData);
|
|
1889
|
+
if (!userRegion) {
|
|
1890
|
+
return;
|
|
1891
|
+
}
|
|
1892
|
+
this.update((state) => {
|
|
1893
|
+
state.userRegion = userRegion;
|
|
1894
|
+
});
|
|
1895
|
+
}, _RampsController_pickInAppQuote = function _RampsController_pickInAppQuote(response, { scope, amount, fiat, providers, }) {
|
|
1896
|
+
const providerByCode = new Map(providers.map((provider) => [provider.id, provider]));
|
|
1897
|
+
const customActionProviderCodes = new Set(response.customActions.map((action) => action.buy.providerId));
|
|
1898
|
+
const fitsProviderLimits = (quote) => {
|
|
1899
|
+
const provider = providerByCode.get(quote.provider);
|
|
1900
|
+
const limit = provider?.limits?.fiat?.[fiat]?.[quote.quote.paymentMethod];
|
|
1901
|
+
if (!limit) {
|
|
1902
|
+
// No published limits for this provider/payment method: treat as
|
|
1903
|
+
// eligible and let the provider enforce limits at checkout.
|
|
1904
|
+
return true;
|
|
1905
|
+
}
|
|
1906
|
+
return amount >= limit.minAmount && amount <= limit.maxAmount;
|
|
1907
|
+
};
|
|
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);
|
|
1928
|
+
if (candidates.length === 0) {
|
|
1929
|
+
return undefined;
|
|
1930
|
+
}
|
|
1931
|
+
const candidateByCode = new Map(candidates.map((quote) => [quote.provider, quote]));
|
|
1932
|
+
const pickBySortOrder = (sortBy) => {
|
|
1933
|
+
const order = response.sorted.find((entry) => entry.sortBy === sortBy)?.ids;
|
|
1934
|
+
if (!order) {
|
|
1935
|
+
return undefined;
|
|
1936
|
+
}
|
|
1937
|
+
for (const providerId of order) {
|
|
1938
|
+
const match = candidateByCode.get(providerId);
|
|
1939
|
+
if (match) {
|
|
1940
|
+
return match;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
return undefined;
|
|
1944
|
+
};
|
|
1945
|
+
// Reliability first, then price, then the first surviving candidate.
|
|
1946
|
+
return (pickBySortOrder('reliability') ??
|
|
1947
|
+
pickBySortOrder('price') ??
|
|
1948
|
+
candidates[0]);
|
|
1790
1949
|
}, _RampsController_getSupportingProvidersForRegion =
|
|
1791
1950
|
/**
|
|
1792
1951
|
* Returns the region's providers that support the given asset, plus the full
|