@metamask/ramps-controller 12.1.0 → 13.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 +17 -1
- package/dist/RampsController-method-action-types.cjs.map +1 -1
- package/dist/RampsController-method-action-types.d.cts +13 -9
- package/dist/RampsController-method-action-types.d.cts.map +1 -1
- package/dist/RampsController-method-action-types.d.mts +13 -9
- 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 +85 -91
- package/dist/RampsController.cjs.map +1 -1
- package/dist/RampsController.d.cts +15 -11
- package/dist/RampsController.d.cts.map +1 -1
- package/dist/RampsController.d.mts +15 -11
- package/dist/RampsController.d.mts.map +1 -1
- package/dist/RampsController.mjs +85 -91
- package/dist/RampsController.mjs.map +1 -1
- package/package.json +4 -4
package/dist/RampsController.cjs
CHANGED
|
@@ -10,7 +10,7 @@ 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_orderPollingMeta, _RampsController_orderPollingTimer, _RampsController_isPolling, _RampsController_initPromise, _RampsController_clearPendingResourceCountForDependentResources, _RampsController_abortDependentRequests, _RampsController_mutateRequests, _RampsController_removeRequestState, _RampsController_cleanupState,
|
|
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_refreshOrder, _RampsController_pollPendingOrders, _RampsController_syncTransakAuthOnError;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.RampsController = exports.normalizeProviderCode = exports.getDefaultRampsControllerState = exports.RAMPS_CONTROLLER_REQUIRED_SERVICE_ACTIONS = exports.controllerName = void 0;
|
|
16
16
|
const base_controller_1 = require("@metamask/base-controller");
|
|
@@ -180,12 +180,11 @@ const DEPENDENT_RESOURCE_KEYS = [
|
|
|
180
180
|
];
|
|
181
181
|
const DEPENDENT_RESOURCE_KEYS_SET = new Set(DEPENDENT_RESOURCE_KEYS);
|
|
182
182
|
function resetResource(state, resourceType, defaultResource) {
|
|
183
|
-
const def = defaultResource ?? getDefaultRampsControllerState()[resourceType];
|
|
184
183
|
const resource = state[resourceType];
|
|
185
|
-
resource.data =
|
|
186
|
-
resource.selected =
|
|
187
|
-
resource.isLoading =
|
|
188
|
-
resource.error =
|
|
184
|
+
resource.data = defaultResource.data;
|
|
185
|
+
resource.selected = defaultResource.selected;
|
|
186
|
+
resource.isLoading = defaultResource.isLoading;
|
|
187
|
+
resource.error = defaultResource.error;
|
|
189
188
|
}
|
|
190
189
|
/**
|
|
191
190
|
* Resets region-dependent resources (userRegion, providers, tokens, paymentMethods).
|
|
@@ -381,6 +380,11 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
381
380
|
* Used so isLoading is only cleared when the last request for that resource finishes.
|
|
382
381
|
*/
|
|
383
382
|
_RampsController_pendingResourceCount.set(this, new Map());
|
|
383
|
+
/**
|
|
384
|
+
* Monotonic generation per resource type used to invalidate stale in-flight
|
|
385
|
+
* requests after region/token/provider dependent-resource resets.
|
|
386
|
+
*/
|
|
387
|
+
_RampsController_pendingResourceGeneration.set(this, new Map());
|
|
384
388
|
_RampsController_orderPollingMeta.set(this, new Map());
|
|
385
389
|
_RampsController_orderPollingTimer.set(this, null);
|
|
386
390
|
_RampsController_isPolling.set(this, false);
|
|
@@ -436,6 +440,9 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
436
440
|
const abortController = new AbortController();
|
|
437
441
|
const lastFetchedAt = Date.now();
|
|
438
442
|
const { resourceType } = options ?? {};
|
|
443
|
+
const resourceGeneration = resourceType
|
|
444
|
+
? (__classPrivateFieldGet(this, _RampsController_pendingResourceGeneration, "f").get(resourceType) ?? 0)
|
|
445
|
+
: undefined;
|
|
439
446
|
// Update state to loading
|
|
440
447
|
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_updateRequestState).call(this, cacheKey, (0, RequestCache_1.createLoadingState)());
|
|
441
448
|
// Set resource-level loading state (only on cache miss). Ref-count so concurrent
|
|
@@ -484,14 +491,17 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
484
491
|
}
|
|
485
492
|
// Clear resource-level loading state only when no requests for this resource remain
|
|
486
493
|
if (resourceType && !abortController.signal.aborted) {
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
494
|
+
const currentGeneration = __classPrivateFieldGet(this, _RampsController_pendingResourceGeneration, "f").get(resourceType) ?? 0;
|
|
495
|
+
if (currentGeneration === resourceGeneration) {
|
|
496
|
+
const count = __classPrivateFieldGet(this, _RampsController_pendingResourceCount, "f").get(resourceType) ?? 0;
|
|
497
|
+
const next = Math.max(0, count - 1);
|
|
498
|
+
if (next === 0) {
|
|
499
|
+
__classPrivateFieldGet(this, _RampsController_pendingResourceCount, "f").delete(resourceType);
|
|
500
|
+
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_setResourceLoading).call(this, resourceType, false);
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
__classPrivateFieldGet(this, _RampsController_pendingResourceCount, "f").set(resourceType, next);
|
|
504
|
+
}
|
|
495
505
|
}
|
|
496
506
|
}
|
|
497
507
|
}
|
|
@@ -549,12 +559,14 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
549
559
|
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_cleanupState).call(this);
|
|
550
560
|
throw new Error(`Region "${normalizedRegion}" not found in countries data. Cannot set user region without valid country information.`);
|
|
551
561
|
}
|
|
552
|
-
const regionChanged =
|
|
553
|
-
|
|
554
|
-
!this.state.tokens.data ||
|
|
555
|
-
this.state.providers.data.length === 0;
|
|
562
|
+
const regionChanged = Boolean(options?.forceRefresh) ||
|
|
563
|
+
normalizedRegion !== this.state.userRegion?.regionCode;
|
|
556
564
|
if (regionChanged) {
|
|
557
|
-
|
|
565
|
+
// Note: we intentionally do NOT abort in-flight requests here.
|
|
566
|
+
// Aborting causes data loss during rapid region switching (e.g.
|
|
567
|
+
// user taps France → Finland → France quickly). Instead we let
|
|
568
|
+
// old requests complete naturally; isResultCurrent guards in
|
|
569
|
+
// getProviders/getPaymentMethods discard stale results.
|
|
558
570
|
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_clearPendingResourceCountForDependentResources).call(this);
|
|
559
571
|
}
|
|
560
572
|
this.update((state) => {
|
|
@@ -563,18 +575,6 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
563
575
|
}
|
|
564
576
|
state.userRegion = userRegion;
|
|
565
577
|
});
|
|
566
|
-
if (needsRefetch) {
|
|
567
|
-
const refetchPromises = [];
|
|
568
|
-
if (regionChanged || !this.state.tokens.data) {
|
|
569
|
-
refetchPromises.push(this.getTokens(userRegion.regionCode, 'buy', options));
|
|
570
|
-
}
|
|
571
|
-
if (regionChanged || this.state.providers.data.length === 0) {
|
|
572
|
-
refetchPromises.push(this.getProviders(userRegion.regionCode, options));
|
|
573
|
-
}
|
|
574
|
-
if (refetchPromises.length > 0) {
|
|
575
|
-
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_fireAndForget).call(this, Promise.all(refetchPromises));
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
578
|
return userRegion;
|
|
579
579
|
}
|
|
580
580
|
catch (error) {
|
|
@@ -583,50 +583,44 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
583
583
|
}
|
|
584
584
|
}
|
|
585
585
|
/**
|
|
586
|
-
* Sets the user's selected provider
|
|
587
|
-
* Looks up the provider from the current providers in state and automatically
|
|
588
|
-
* fetches payment methods for that provider.
|
|
586
|
+
* Sets the user's selected provider.
|
|
589
587
|
*
|
|
590
|
-
*
|
|
588
|
+
* Accepts either a Provider object (stored directly) or a provider ID
|
|
589
|
+
* string (looked up from state). The object form is preferred when the
|
|
590
|
+
* caller already has the full data (e.g. from React Query cache).
|
|
591
|
+
*
|
|
592
|
+
* @param providerOrId - A Provider object, a provider ID string (e.g., "/providers/moonpay"), or null to clear.
|
|
591
593
|
* @param options - Optional settings for the selection.
|
|
592
594
|
* @param options.autoSelected - When true, marks the provider as system-guessed
|
|
593
595
|
* (soft selection). The UI will silently auto-switch on token conflict instead
|
|
594
596
|
* of showing the "Token Not Available" modal. Defaults to false.
|
|
595
|
-
* @throws If region is not set, providers are not loaded, or provider is not found.
|
|
596
597
|
*/
|
|
597
|
-
setSelectedProvider(
|
|
598
|
-
if (
|
|
598
|
+
setSelectedProvider(providerOrId, options) {
|
|
599
|
+
if (providerOrId === null) {
|
|
599
600
|
this.update((state) => {
|
|
600
601
|
state.providers.selected = null;
|
|
601
602
|
state.providerAutoSelected = false;
|
|
602
|
-
resetResource(state, 'paymentMethods');
|
|
603
603
|
});
|
|
604
604
|
return;
|
|
605
605
|
}
|
|
606
|
-
|
|
606
|
+
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_requireRegion).call(this);
|
|
607
|
+
// If a full Provider object is passed, store it directly (avoids
|
|
608
|
+
// depending on state.providers.data being populated).
|
|
609
|
+
if (typeof providerOrId !== 'string') {
|
|
610
|
+
this.update((state) => {
|
|
611
|
+
state.providers.selected = providerOrId;
|
|
612
|
+
state.providerAutoSelected = options?.autoSelected ?? false;
|
|
613
|
+
});
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
// ID string: look up from state
|
|
607
617
|
const providers = this.state.providers.data;
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
}
|
|
615
|
-
const selectedToken = this.state.tokens.selected;
|
|
616
|
-
const supportedCryptos = provider.supportedCryptoCurrencies;
|
|
617
|
-
// Only fetch payment methods if the selected token is supported by the new
|
|
618
|
-
// provider. If it isn't, the payment methods request would fail or return
|
|
619
|
-
// empty for the wrong reason; the UI will show the Token Not Available modal
|
|
620
|
-
// so the user can change token or pick a different provider.
|
|
621
|
-
const assetId = selectedToken?.assetId;
|
|
622
|
-
const tokenSupportedByProvider = !(assetId && supportedCryptos?.[assetId] === false);
|
|
623
|
-
this.update((state) => {
|
|
624
|
-
state.providers.selected = provider;
|
|
625
|
-
state.providerAutoSelected = options?.autoSelected ?? false;
|
|
626
|
-
resetResource(state, 'paymentMethods');
|
|
627
|
-
});
|
|
628
|
-
if (tokenSupportedByProvider) {
|
|
629
|
-
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_fireAndForget).call(this, this.getPaymentMethods(regionCode, { provider: provider.id }));
|
|
618
|
+
const provider = providers?.find((prov) => prov.id === providerOrId);
|
|
619
|
+
if (provider) {
|
|
620
|
+
this.update((state) => {
|
|
621
|
+
state.providers.selected = provider;
|
|
622
|
+
state.providerAutoSelected = options?.autoSelected ?? false;
|
|
623
|
+
});
|
|
630
624
|
}
|
|
631
625
|
}
|
|
632
626
|
/**
|
|
@@ -721,11 +715,10 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
721
715
|
if (!assetId) {
|
|
722
716
|
this.update((state) => {
|
|
723
717
|
state.tokens.selected = null;
|
|
724
|
-
resetResource(state, 'paymentMethods');
|
|
725
718
|
});
|
|
726
719
|
return;
|
|
727
720
|
}
|
|
728
|
-
|
|
721
|
+
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_requireRegion).call(this);
|
|
729
722
|
const tokens = this.state.tokens.data;
|
|
730
723
|
if (!tokens) {
|
|
731
724
|
throw new Error('Tokens not loaded. Cannot set selected token before tokens are fetched.');
|
|
@@ -737,9 +730,7 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
737
730
|
}
|
|
738
731
|
this.update((state) => {
|
|
739
732
|
state.tokens.selected = token;
|
|
740
|
-
resetResource(state, 'paymentMethods');
|
|
741
733
|
});
|
|
742
|
-
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_fireAndForget).call(this, this.getPaymentMethods(regionCode, { assetId: token.assetId }));
|
|
743
734
|
}
|
|
744
735
|
/**
|
|
745
736
|
* Fetches the list of providers for a given region.
|
|
@@ -847,29 +838,35 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
847
838
|
return response;
|
|
848
839
|
}
|
|
849
840
|
/**
|
|
850
|
-
* Sets the user's selected payment method
|
|
851
|
-
* Looks up the payment method from the current payment methods in state.
|
|
841
|
+
* Sets the user's selected payment method.
|
|
852
842
|
*
|
|
853
|
-
*
|
|
854
|
-
*
|
|
843
|
+
* Accepts either a payment method ID (looked up from state) or a full
|
|
844
|
+
* PaymentMethod object (stored directly). The object form is preferred
|
|
845
|
+
* when the caller already has the full data (e.g. from React Query cache),
|
|
846
|
+
* as it avoids depending on controller state being populated.
|
|
847
|
+
*
|
|
848
|
+
* @param paymentMethodOrId - A PaymentMethod object, a payment method ID string, or undefined/null to clear.
|
|
855
849
|
*/
|
|
856
|
-
setSelectedPaymentMethod(
|
|
857
|
-
if (!
|
|
850
|
+
setSelectedPaymentMethod(paymentMethodOrId) {
|
|
851
|
+
if (!paymentMethodOrId) {
|
|
858
852
|
this.update((state) => {
|
|
859
853
|
state.paymentMethods.selected = null;
|
|
860
854
|
});
|
|
861
855
|
return;
|
|
862
856
|
}
|
|
863
|
-
|
|
864
|
-
if (
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
throw new Error(`Payment method with ID "${paymentMethodId}" not found in available payment methods.`);
|
|
857
|
+
// If a full object is passed, store it directly
|
|
858
|
+
if (typeof paymentMethodOrId !== 'string') {
|
|
859
|
+
this.update((state) => {
|
|
860
|
+
state.paymentMethods.selected = paymentMethodOrId;
|
|
861
|
+
});
|
|
862
|
+
return;
|
|
870
863
|
}
|
|
864
|
+
// ID string: look up from state
|
|
865
|
+
const paymentMethodId = paymentMethodOrId;
|
|
866
|
+
const paymentMethods = this.state.paymentMethods.data;
|
|
867
|
+
const paymentMethod = paymentMethods?.find((pm) => pm.id === paymentMethodId);
|
|
871
868
|
this.update((state) => {
|
|
872
|
-
state.paymentMethods.selected = paymentMethod;
|
|
869
|
+
state.paymentMethods.selected = paymentMethod ?? null;
|
|
873
870
|
});
|
|
874
871
|
}
|
|
875
872
|
/**
|
|
@@ -1527,9 +1524,11 @@ class RampsController extends base_controller_1.BaseController {
|
|
|
1527
1524
|
}
|
|
1528
1525
|
}
|
|
1529
1526
|
exports.RampsController = RampsController;
|
|
1530
|
-
_RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheMaxSize = new WeakMap(), _RampsController_pendingRequests = new WeakMap(), _RampsController_pendingResourceCount = 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() {
|
|
1527
|
+
_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() {
|
|
1531
1528
|
for (const resourceType of DEPENDENT_RESOURCE_KEYS) {
|
|
1532
1529
|
__classPrivateFieldGet(this, _RampsController_pendingResourceCount, "f").delete(resourceType);
|
|
1530
|
+
const generation = __classPrivateFieldGet(this, _RampsController_pendingResourceGeneration, "f").get(resourceType) ?? 0;
|
|
1531
|
+
__classPrivateFieldGet(this, _RampsController_pendingResourceGeneration, "f").set(resourceType, generation + 1);
|
|
1533
1532
|
}
|
|
1534
1533
|
}, _RampsController_abortDependentRequests = function _RampsController_abortDependentRequests() {
|
|
1535
1534
|
for (const [cacheKey, pending] of __classPrivateFieldGet(this, _RampsController_pendingRequests, "f").entries()) {
|
|
@@ -1553,8 +1552,6 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
|
|
|
1553
1552
|
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_abortDependentRequests).call(this);
|
|
1554
1553
|
__classPrivateFieldGet(this, _RampsController_instances, "m", _RampsController_clearPendingResourceCountForDependentResources).call(this);
|
|
1555
1554
|
this.update((state) => resetDependentResources(state, { clearUserRegionData: true }));
|
|
1556
|
-
}, _RampsController_fireAndForget = function _RampsController_fireAndForget(promise) {
|
|
1557
|
-
promise.catch((_error) => undefined);
|
|
1558
1555
|
}, _RampsController_requireRegion = function _RampsController_requireRegion() {
|
|
1559
1556
|
const regionCode = this.state.userRegion?.regionCode;
|
|
1560
1557
|
if (!regionCode) {
|
|
@@ -1616,14 +1613,11 @@ _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheM
|
|
|
1616
1613
|
if (forceRefresh || !hasCountries) {
|
|
1617
1614
|
await this.getCountries(options);
|
|
1618
1615
|
}
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
regionCode = this.state.userRegion?.regionCode;
|
|
1625
|
-
regionCode ?? (regionCode = await this.messenger.call('RampsService:getGeolocation'));
|
|
1626
|
-
}
|
|
1616
|
+
// Always prefer the user's persisted region. Geolocation is only used to
|
|
1617
|
+
// seed the initial value; once the user (or a prior init) has set a region
|
|
1618
|
+
// we must respect that choice — even on forceRefresh.
|
|
1619
|
+
let regionCode = this.state.userRegion?.regionCode;
|
|
1620
|
+
regionCode ?? (regionCode = await this.messenger.call('RampsService:getGeolocation'));
|
|
1627
1621
|
if (!regionCode) {
|
|
1628
1622
|
throw new Error('Failed to fetch geolocation. Cannot initialize controller without valid region information.');
|
|
1629
1623
|
}
|