@metamask-previews/ramps-controller 3.0.0-preview-a4747b2b → 4.0.0-preview-4a66b658

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.
@@ -35,6 +35,12 @@ const rampsControllerMetadata = {
35
35
  includeInStateLogs: true,
36
36
  usedInUi: true,
37
37
  },
38
+ providers: {
39
+ persist: true,
40
+ includeInDebugSnapshot: true,
41
+ includeInStateLogs: true,
42
+ usedInUi: true,
43
+ },
38
44
  tokens: {
39
45
  persist: true,
40
46
  includeInDebugSnapshot: true,
@@ -60,6 +66,7 @@ export function getDefaultRampsControllerState() {
60
66
  return {
61
67
  userRegion: null,
62
68
  preferredProvider: null,
69
+ providers: [],
63
70
  tokens: null,
64
71
  requests: {},
65
72
  };
@@ -264,11 +271,12 @@ export class RampsController extends BaseController {
264
271
  if (this.state.userRegion && !options?.forceRefresh) {
265
272
  return this.state.userRegion;
266
273
  }
267
- // When forceRefresh is true, clear the existing region and tokens before fetching
274
+ // When forceRefresh is true, clear the existing region, tokens, and providers before fetching
268
275
  if (options?.forceRefresh) {
269
276
  this.update((state) => {
270
277
  state.userRegion = null;
271
278
  state.tokens = null;
279
+ state.providers = [];
272
280
  });
273
281
  }
274
282
  const cacheKey = createCacheKey('updateUserRegion', []);
@@ -280,6 +288,7 @@ export class RampsController extends BaseController {
280
288
  this.update((state) => {
281
289
  state.userRegion = null;
282
290
  state.tokens = null;
291
+ state.providers = [];
283
292
  });
284
293
  return null;
285
294
  }
@@ -291,17 +300,28 @@ export class RampsController extends BaseController {
291
300
  this.update((state) => {
292
301
  const regionChanged = state.userRegion?.regionCode !== userRegion.regionCode;
293
302
  state.userRegion = userRegion;
294
- // Clear tokens when region changes
303
+ // Clear tokens and providers when region changes
295
304
  if (regionChanged) {
296
305
  state.tokens = null;
306
+ state.providers = [];
297
307
  }
298
308
  });
309
+ // Fetch providers for the new region
310
+ if (userRegion.regionCode) {
311
+ try {
312
+ await this.getProviders(userRegion.regionCode, options);
313
+ }
314
+ catch {
315
+ // Provider fetch failed - error state will be available via selectors
316
+ }
317
+ }
299
318
  return userRegion;
300
319
  }
301
320
  // Region not found in countries data
302
321
  this.update((state) => {
303
322
  state.userRegion = null;
304
323
  state.tokens = null;
324
+ state.providers = [];
305
325
  });
306
326
  return null;
307
327
  }
@@ -311,6 +331,7 @@ export class RampsController extends BaseController {
311
331
  this.update((state) => {
312
332
  state.userRegion = null;
313
333
  state.tokens = null;
334
+ state.providers = [];
314
335
  });
315
336
  return null;
316
337
  }
@@ -332,13 +353,22 @@ export class RampsController extends BaseController {
332
353
  this.update((state) => {
333
354
  state.userRegion = userRegion;
334
355
  state.tokens = null;
356
+ state.providers = [];
335
357
  });
358
+ // Fetch providers for the new region
359
+ try {
360
+ await this.getProviders(userRegion.regionCode, options);
361
+ }
362
+ catch {
363
+ // Provider fetch failed - error state will be available via selectors
364
+ }
336
365
  return userRegion;
337
366
  }
338
367
  // Region not found in countries data
339
368
  this.update((state) => {
340
369
  state.userRegion = null;
341
370
  state.tokens = null;
371
+ state.providers = [];
342
372
  });
343
373
  throw new Error(`Region "${normalizedRegion}" not found in countries data. Cannot set user region without valid country information.`);
344
374
  }
@@ -352,6 +382,7 @@ export class RampsController extends BaseController {
352
382
  this.update((state) => {
353
383
  state.userRegion = null;
354
384
  state.tokens = null;
385
+ state.providers = [];
355
386
  });
356
387
  throw new Error('Failed to fetch countries data. Cannot set user region without valid country information.');
357
388
  }
@@ -390,6 +421,12 @@ export class RampsController extends BaseController {
390
421
  catch {
391
422
  // Token fetch failed - error state will be available via selectors
392
423
  }
424
+ try {
425
+ await this.getProviders(userRegion.regionCode, options);
426
+ }
427
+ catch {
428
+ // Provider fetch failed - error state will be available via selectors
429
+ }
393
430
  }
394
431
  }
395
432
  /**
@@ -432,6 +469,47 @@ export class RampsController extends BaseController {
432
469
  });
433
470
  return tokens;
434
471
  }
472
+ /**
473
+ * Fetches the list of providers for a given region.
474
+ * The providers are saved in the controller state once fetched.
475
+ *
476
+ * @param region - The region code (e.g., "us", "fr", "us-ny"). If not provided, uses the user's region from controller state.
477
+ * @param options - Options for cache behavior and query filters.
478
+ * @param options.provider - Provider ID(s) to filter by.
479
+ * @param options.crypto - Crypto currency ID(s) to filter by.
480
+ * @param options.fiat - Fiat currency ID(s) to filter by.
481
+ * @param options.payments - Payment method ID(s) to filter by.
482
+ * @returns The providers response containing providers array.
483
+ */
484
+ async getProviders(region, options) {
485
+ const regionToUse = region ?? this.state.userRegion?.regionCode;
486
+ if (!regionToUse) {
487
+ throw new Error('Region is required. Either provide a region parameter or ensure userRegion is set in controller state.');
488
+ }
489
+ const normalizedRegion = regionToUse.toLowerCase().trim();
490
+ const cacheKey = createCacheKey('getProviders', [
491
+ normalizedRegion,
492
+ options?.provider,
493
+ options?.crypto,
494
+ options?.fiat,
495
+ options?.payments,
496
+ ]);
497
+ const { providers } = await this.executeRequest(cacheKey, async () => {
498
+ return this.messenger.call('RampsService:getProviders', normalizedRegion, {
499
+ provider: options?.provider,
500
+ crypto: options?.crypto,
501
+ fiat: options?.fiat,
502
+ payments: options?.payments,
503
+ });
504
+ }, options);
505
+ this.update((state) => {
506
+ const userRegionCode = state.userRegion?.regionCode;
507
+ if (userRegionCode === undefined || userRegionCode === normalizedRegion) {
508
+ state.providers = providers;
509
+ }
510
+ });
511
+ return { providers };
512
+ }
435
513
  }
436
514
  _RampsController_requestCacheTTL = new WeakMap(), _RampsController_requestCacheMaxSize = new WeakMap(), _RampsController_pendingRequests = new WeakMap(), _RampsController_instances = new WeakSet(), _RampsController_removeRequestState = function _RampsController_removeRequestState(cacheKey) {
437
515
  this.update((state) => {
@@ -1 +1 @@
1
- {"version":3,"file":"RampsController.mjs","sourceRoot":"","sources":["../src/RampsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\n\nimport type { Country, TokensResponse, Provider, State } from './RampsService';\nimport type {\n RampsServiceGetGeolocationAction,\n RampsServiceGetCountriesAction,\n RampsServiceGetTokensAction,\n} from './RampsService-method-action-types';\nimport type {\n RequestCache as RequestCacheType,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n} from './RequestCache';\nimport {\n DEFAULT_REQUEST_CACHE_TTL,\n DEFAULT_REQUEST_CACHE_MAX_SIZE,\n createCacheKey,\n isCacheExpired,\n createLoadingState,\n createSuccessState,\n createErrorState,\n} from './RequestCache';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link RampsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'RampsController';\n\n// === STATE ===\n\n/**\n * Represents the user's selected region with full country and state objects.\n */\nexport type UserRegion = {\n /**\n * The country object for the selected region.\n */\n country: Country;\n /**\n * The state object if a state was selected, null if only country was selected.\n */\n state: State | null;\n /**\n * The region code string (e.g., \"us-ut\" or \"fr\") used for API calls.\n */\n regionCode: string;\n};\n\n/**\n * Describes the shape of the state object for {@link RampsController}.\n */\nexport type RampsControllerState = {\n /**\n * The user's selected region with full country and state objects.\n * Initially set via geolocation fetch, but can be manually changed by the user.\n * Once set (either via geolocation or manual selection), it will not be overwritten\n * by subsequent geolocation fetches.\n */\n userRegion: UserRegion | null;\n /**\n * The user's preferred provider.\n * Can be manually set by the user.\n */\n preferredProvider: Provider | null;\n /**\n * Tokens fetched for the current region and action.\n * Contains topTokens and allTokens arrays.\n */\n tokens: TokensResponse | null;\n /**\n * Cache of request states, keyed by cache key.\n * This stores loading, success, and error states for API requests.\n */\n requests: RequestCacheType;\n};\n\n/**\n * The metadata for each property in {@link RampsControllerState}.\n */\nconst rampsControllerMetadata = {\n userRegion: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n preferredProvider: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n tokens: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n requests: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: false,\n usedInUi: true,\n },\n} satisfies StateMetadata<RampsControllerState>;\n\n/**\n * Constructs the default {@link RampsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link RampsController} state.\n */\nexport function getDefaultRampsControllerState(): RampsControllerState {\n return {\n userRegion: null,\n preferredProvider: null,\n tokens: null,\n requests: {},\n };\n}\n\n// === MESSENGER ===\n\n/**\n * Retrieves the state of the {@link RampsController}.\n */\nexport type RampsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Actions that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerActions = RampsControllerGetStateAction;\n\n/**\n * Actions from other messengers that {@link RampsController} calls.\n */\ntype AllowedActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction;\n\n/**\n * Published when the state of {@link RampsController} changes.\n */\nexport type RampsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Events that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerEvents = RampsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link RampsController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link RampsController}.\n */\nexport type RampsControllerMessenger = Messenger<\n typeof controllerName,\n RampsControllerActions | AllowedActions,\n RampsControllerEvents | AllowedEvents\n>;\n\n/**\n * Configuration options for the RampsController.\n */\nexport type RampsControllerOptions = {\n /** The messenger suited for this controller. */\n messenger: RampsControllerMessenger;\n /** The desired state with which to initialize this controller. */\n state?: Partial<RampsControllerState>;\n /** Time to live for cached requests in milliseconds. Defaults to 15 minutes. */\n requestCacheTTL?: number;\n /** Maximum number of entries in the request cache. Defaults to 250. */\n requestCacheMaxSize?: number;\n};\n\n// === HELPER FUNCTIONS ===\n\n/**\n * Finds a country and state from a region code string.\n *\n * @param regionCode - The region code (e.g., \"us-ca\" or \"us\").\n * @param countries - Array of countries to search.\n * @returns UserRegion object with country and state, or null if not found.\n */\nfunction findRegionFromCode(\n regionCode: string,\n countries: Country[],\n): UserRegion | null {\n const normalizedCode = regionCode.toLowerCase().trim();\n const parts = normalizedCode.split('-');\n const countryCode = parts[0];\n const stateCode = parts[1];\n\n const country = countries.find((countryItem) => {\n if (countryItem.isoCode?.toLowerCase() === countryCode) {\n return true;\n }\n if (countryItem.id) {\n const id = countryItem.id.toLowerCase();\n if (id.startsWith('/regions/')) {\n const extractedCode = id.replace('/regions/', '').split('/')[0];\n return extractedCode === countryCode;\n }\n return id === countryCode || id.endsWith(`/${countryCode}`);\n }\n return false;\n });\n\n if (!country) {\n return null;\n }\n\n let state: State | null = null;\n if (stateCode && country.states) {\n state =\n country.states.find((stateItem) => {\n if (stateItem.stateId?.toLowerCase() === stateCode) {\n return true;\n }\n if (stateItem.id) {\n const stateId = stateItem.id.toLowerCase();\n if (\n stateId.includes(`-${stateCode}`) ||\n stateId.endsWith(`/${stateCode}`)\n ) {\n return true;\n }\n }\n return false;\n }) ?? null;\n }\n\n return {\n country,\n state,\n regionCode: normalizedCode,\n };\n}\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * Manages cryptocurrency on/off ramps functionality.\n */\nexport class RampsController extends BaseController<\n typeof controllerName,\n RampsControllerState,\n RampsControllerMessenger\n> {\n /**\n * Default TTL for cached requests.\n */\n readonly #requestCacheTTL: number;\n\n /**\n * Maximum number of entries in the request cache.\n */\n readonly #requestCacheMaxSize: number;\n\n /**\n * Map of pending requests for deduplication.\n * Key is the cache key, value is the pending request with abort controller.\n */\n readonly #pendingRequests: Map<string, PendingRequest> = new Map();\n\n /**\n * Constructs a new {@link RampsController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to initialize this\n * controller. Missing properties will be filled in with defaults.\n * @param args.requestCacheTTL - Time to live for cached requests in milliseconds.\n * @param args.requestCacheMaxSize - Maximum number of entries in the request cache.\n */\n constructor({\n messenger,\n state = {},\n requestCacheTTL = DEFAULT_REQUEST_CACHE_TTL,\n requestCacheMaxSize = DEFAULT_REQUEST_CACHE_MAX_SIZE,\n }: RampsControllerOptions) {\n super({\n messenger,\n metadata: rampsControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultRampsControllerState(),\n ...state,\n // Always reset requests cache on initialization (non-persisted)\n requests: {},\n },\n });\n\n this.#requestCacheTTL = requestCacheTTL;\n this.#requestCacheMaxSize = requestCacheMaxSize;\n }\n\n /**\n * Executes a request with caching and deduplication.\n *\n * If a request with the same cache key is already in flight, returns the\n * existing promise. If valid cached data exists, returns it without making\n * a new request.\n *\n * @param cacheKey - Unique identifier for this request.\n * @param fetcher - Function that performs the actual fetch. Receives an AbortSignal.\n * @param options - Options for cache behavior.\n * @returns The result of the request.\n */\n async executeRequest<TResult>(\n cacheKey: string,\n fetcher: (signal: AbortSignal) => Promise<TResult>,\n options?: ExecuteRequestOptions,\n ): Promise<TResult> {\n const ttl = options?.ttl ?? this.#requestCacheTTL;\n\n // Check for existing pending request - join it instead of making a duplicate\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n return pending.promise as Promise<TResult>;\n }\n\n // Check cache validity (unless force refresh)\n if (!options?.forceRefresh) {\n const cached = this.state.requests[cacheKey];\n if (cached && !isCacheExpired(cached, ttl)) {\n return cached.data as TResult;\n }\n }\n\n // Create abort controller for this request\n const abortController = new AbortController();\n const lastFetchedAt = Date.now();\n\n // Update state to loading\n this.#updateRequestState(cacheKey, createLoadingState());\n\n // Create the fetch promise\n const promise = (async (): Promise<TResult> => {\n try {\n const data = await fetcher(abortController.signal);\n\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw new Error('Request was aborted');\n }\n\n this.#updateRequestState(\n cacheKey,\n createSuccessState(data as Json, lastFetchedAt),\n );\n return data;\n } catch (error) {\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw error;\n }\n\n const errorMessage = (error as Error)?.message;\n\n this.#updateRequestState(\n cacheKey,\n createErrorState(errorMessage ?? 'Unknown error', lastFetchedAt),\n );\n throw error;\n } finally {\n // Only delete if this is still our entry (not replaced by a new request)\n const currentPending = this.#pendingRequests.get(cacheKey);\n if (currentPending?.abortController === abortController) {\n this.#pendingRequests.delete(cacheKey);\n }\n }\n })();\n\n // Store pending request for deduplication\n this.#pendingRequests.set(cacheKey, { promise, abortController });\n\n return promise;\n }\n\n /**\n * Aborts a pending request if one exists.\n *\n * @param cacheKey - The cache key of the request to abort.\n * @returns True if a request was aborted.\n */\n abortRequest(cacheKey: string): boolean {\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n pending.abortController.abort();\n this.#pendingRequests.delete(cacheKey);\n this.#removeRequestState(cacheKey);\n return true;\n }\n return false;\n }\n\n /**\n * Removes a request state from the cache.\n *\n * @param cacheKey - The cache key to remove.\n */\n #removeRequestState(cacheKey: string): void {\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n delete requests[cacheKey];\n });\n }\n\n /**\n * Gets the state of a specific cached request.\n *\n * @param cacheKey - The cache key to look up.\n * @returns The request state, or undefined if not cached.\n */\n getRequestState(cacheKey: string): RequestState | undefined {\n return this.state.requests[cacheKey];\n }\n\n /**\n * Updates the state for a specific request.\n *\n * @param cacheKey - The cache key.\n * @param requestState - The new state for the request.\n */\n #updateRequestState(cacheKey: string, requestState: RequestState): void {\n const maxSize = this.#requestCacheMaxSize;\n\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n requests[cacheKey] = requestState;\n\n // Evict oldest entries if cache exceeds max size\n const keys = Object.keys(requests);\n\n if (keys.length > maxSize) {\n // Sort by timestamp (oldest first)\n const sortedKeys = keys.sort((a, b) => {\n const aTime = requests[a]?.timestamp ?? 0;\n const bTime = requests[b]?.timestamp ?? 0;\n return aTime - bTime;\n });\n\n // Remove oldest entries until we're under the limit\n const entriesToRemove = keys.length - maxSize;\n for (let i = 0; i < entriesToRemove; i++) {\n const keyToRemove = sortedKeys[i];\n if (keyToRemove) {\n delete requests[keyToRemove];\n }\n }\n }\n });\n }\n\n /**\n * Updates the user's region by fetching geolocation.\n * This method calls the RampsService to get the geolocation.\n *\n * @param options - Options for cache behavior.\n * @returns The user region object.\n */\n async updateUserRegion(\n options?: ExecuteRequestOptions,\n ): Promise<UserRegion | null> {\n // If a userRegion already exists and forceRefresh is not requested,\n // return it immediately without fetching geolocation.\n // This ensures that once a region is set (either via geolocation or manual selection),\n // it will not be overwritten by subsequent geolocation fetches.\n if (this.state.userRegion && !options?.forceRefresh) {\n return this.state.userRegion;\n }\n\n // When forceRefresh is true, clear the existing region and tokens before fetching\n if (options?.forceRefresh) {\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n });\n }\n\n const cacheKey = createCacheKey('updateUserRegion', []);\n\n const regionCode = await this.executeRequest(\n cacheKey,\n async () => {\n const result = await this.messenger.call('RampsService:getGeolocation');\n return result;\n },\n options,\n );\n\n if (!regionCode) {\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n });\n return null;\n }\n\n const normalizedRegion = regionCode.toLowerCase().trim();\n\n try {\n const countries = await this.getCountries('buy', options);\n const userRegion = findRegionFromCode(normalizedRegion, countries);\n\n if (userRegion) {\n this.update((state) => {\n const regionChanged =\n state.userRegion?.regionCode !== userRegion.regionCode;\n state.userRegion = userRegion;\n // Clear tokens when region changes\n if (regionChanged) {\n state.tokens = null;\n }\n });\n\n return userRegion;\n }\n\n // Region not found in countries data\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n });\n\n return null;\n } catch {\n // If countries fetch fails, we can't create a valid UserRegion\n // Return null to indicate we don't have valid country data\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n });\n\n return null;\n }\n }\n\n /**\n * Sets the user's region manually (without fetching geolocation).\n * This allows users to override the detected region.\n *\n * @param region - The region code to set (e.g., \"US-CA\").\n * @param options - Options for cache behavior.\n * @returns The user region object.\n */\n async setUserRegion(\n region: string,\n options?: ExecuteRequestOptions,\n ): Promise<UserRegion> {\n const normalizedRegion = region.toLowerCase().trim();\n\n try {\n const countries = await this.getCountries('buy', options);\n const userRegion = findRegionFromCode(normalizedRegion, countries);\n\n if (userRegion) {\n this.update((state) => {\n state.userRegion = userRegion;\n state.tokens = null;\n });\n return userRegion;\n }\n\n // Region not found in countries data\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n });\n throw new Error(\n `Region \"${normalizedRegion}\" not found in countries data. Cannot set user region without valid country information.`,\n );\n } catch (error) {\n // If the error is \"not found\", re-throw it\n // Otherwise, it's from countries fetch failure\n if (error instanceof Error && error.message.includes('not found')) {\n throw error;\n }\n // Countries fetch failed\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n });\n throw new Error(\n 'Failed to fetch countries data. Cannot set user region without valid country information.',\n );\n }\n }\n\n /**\n * Sets the user's preferred provider.\n * This allows users to set their preferred ramp provider.\n *\n * @param provider - The provider object to set.\n */\n setPreferredProvider(provider: Provider | null): void {\n this.update((state) => {\n state.preferredProvider = provider;\n });\n }\n\n /**\n * Initializes the controller by fetching the user's region from geolocation.\n * This should be called once at app startup to set up the initial region.\n * After the region is set, tokens are fetched and saved to state.\n *\n * If a userRegion already exists (from persistence or manual selection),\n * this method will skip geolocation fetch and only fetch tokens if needed.\n *\n * @param options - Options for cache behavior.\n * @returns Promise that resolves when initialization is complete.\n */\n async init(options?: ExecuteRequestOptions): Promise<void> {\n const userRegion = await this.updateUserRegion(options).catch(() => {\n // User region fetch failed - error state will be available via selectors\n return null;\n });\n\n if (userRegion) {\n try {\n await this.getTokens(userRegion.regionCode, 'buy', options);\n } catch {\n // Token fetch failed - error state will be available via selectors\n }\n }\n }\n\n /**\n * Fetches the list of supported countries for a given ramp action.\n *\n * @param action - The ramp action type ('buy' or 'sell').\n * @param options - Options for cache behavior.\n * @returns An array of countries.\n */\n async getCountries(\n action: 'buy' | 'sell' = 'buy',\n options?: ExecuteRequestOptions,\n ): Promise<Country[]> {\n const cacheKey = createCacheKey('getCountries', [action]);\n\n return this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getCountries', action);\n },\n options,\n );\n }\n\n /**\n * Fetches the list of available tokens for a given region and action.\n * The tokens are saved in the controller state once fetched.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\"). If not provided, uses the user's region from controller state.\n * @param action - The ramp action type ('buy' or 'sell').\n * @param options - Options for cache behavior.\n * @returns The tokens response containing topTokens and allTokens.\n */\n async getTokens(\n region?: string,\n action: 'buy' | 'sell' = 'buy',\n options?: ExecuteRequestOptions,\n ): Promise<TokensResponse> {\n const regionToUse = region ?? this.state.userRegion?.regionCode;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getTokens', [normalizedRegion, action]);\n\n const tokens = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call(\n 'RampsService:getTokens',\n normalizedRegion,\n action,\n );\n },\n options,\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.tokens = tokens;\n }\n });\n\n return tokens;\n }\n}\n"]}
1
+ {"version":3,"file":"RampsController.mjs","sourceRoot":"","sources":["../src/RampsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\n\nimport type { Country, TokensResponse, Provider, State } from './RampsService';\nimport type {\n RampsServiceGetGeolocationAction,\n RampsServiceGetCountriesAction,\n RampsServiceGetTokensAction,\n RampsServiceGetProvidersAction,\n} from './RampsService-method-action-types';\nimport type {\n RequestCache as RequestCacheType,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n} from './RequestCache';\nimport {\n DEFAULT_REQUEST_CACHE_TTL,\n DEFAULT_REQUEST_CACHE_MAX_SIZE,\n createCacheKey,\n isCacheExpired,\n createLoadingState,\n createSuccessState,\n createErrorState,\n} from './RequestCache';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link RampsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'RampsController';\n\n// === STATE ===\n\n/**\n * Represents the user's selected region with full country and state objects.\n */\nexport type UserRegion = {\n /**\n * The country object for the selected region.\n */\n country: Country;\n /**\n * The state object if a state was selected, null if only country was selected.\n */\n state: State | null;\n /**\n * The region code string (e.g., \"us-ut\" or \"fr\") used for API calls.\n */\n regionCode: string;\n};\n\n/**\n * Describes the shape of the state object for {@link RampsController}.\n */\nexport type RampsControllerState = {\n /**\n * The user's selected region with full country and state objects.\n * Initially set via geolocation fetch, but can be manually changed by the user.\n * Once set (either via geolocation or manual selection), it will not be overwritten\n * by subsequent geolocation fetches.\n */\n userRegion: UserRegion | null;\n /**\n * The user's preferred provider.\n * Can be manually set by the user.\n */\n preferredProvider: Provider | null;\n /**\n * List of providers available for the current region.\n */\n providers: Provider[];\n /**\n * Tokens fetched for the current region and action.\n * Contains topTokens and allTokens arrays.\n */\n tokens: TokensResponse | null;\n /**\n * Cache of request states, keyed by cache key.\n * This stores loading, success, and error states for API requests.\n */\n requests: RequestCacheType;\n};\n\n/**\n * The metadata for each property in {@link RampsControllerState}.\n */\nconst rampsControllerMetadata = {\n userRegion: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n preferredProvider: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n providers: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n tokens: {\n persist: true,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n requests: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: false,\n usedInUi: true,\n },\n} satisfies StateMetadata<RampsControllerState>;\n\n/**\n * Constructs the default {@link RampsController} state. This allows\n * consumers to provide a partial state object when initializing the controller\n * and also helps in constructing complete state objects for this controller in\n * tests.\n *\n * @returns The default {@link RampsController} state.\n */\nexport function getDefaultRampsControllerState(): RampsControllerState {\n return {\n userRegion: null,\n preferredProvider: null,\n providers: [],\n tokens: null,\n requests: {},\n };\n}\n\n// === MESSENGER ===\n\n/**\n * Retrieves the state of the {@link RampsController}.\n */\nexport type RampsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Actions that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerActions = RampsControllerGetStateAction;\n\n/**\n * Actions from other messengers that {@link RampsController} calls.\n */\ntype AllowedActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction\n | RampsServiceGetProvidersAction;\n\n/**\n * Published when the state of {@link RampsController} changes.\n */\nexport type RampsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n RampsControllerState\n>;\n\n/**\n * Events that {@link RampsControllerMessenger} exposes to other consumers.\n */\nexport type RampsControllerEvents = RampsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link RampsController} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link RampsController}.\n */\nexport type RampsControllerMessenger = Messenger<\n typeof controllerName,\n RampsControllerActions | AllowedActions,\n RampsControllerEvents | AllowedEvents\n>;\n\n/**\n * Configuration options for the RampsController.\n */\nexport type RampsControllerOptions = {\n /** The messenger suited for this controller. */\n messenger: RampsControllerMessenger;\n /** The desired state with which to initialize this controller. */\n state?: Partial<RampsControllerState>;\n /** Time to live for cached requests in milliseconds. Defaults to 15 minutes. */\n requestCacheTTL?: number;\n /** Maximum number of entries in the request cache. Defaults to 250. */\n requestCacheMaxSize?: number;\n};\n\n// === HELPER FUNCTIONS ===\n\n/**\n * Finds a country and state from a region code string.\n *\n * @param regionCode - The region code (e.g., \"us-ca\" or \"us\").\n * @param countries - Array of countries to search.\n * @returns UserRegion object with country and state, or null if not found.\n */\nfunction findRegionFromCode(\n regionCode: string,\n countries: Country[],\n): UserRegion | null {\n const normalizedCode = regionCode.toLowerCase().trim();\n const parts = normalizedCode.split('-');\n const countryCode = parts[0];\n const stateCode = parts[1];\n\n const country = countries.find((countryItem) => {\n if (countryItem.isoCode?.toLowerCase() === countryCode) {\n return true;\n }\n if (countryItem.id) {\n const id = countryItem.id.toLowerCase();\n if (id.startsWith('/regions/')) {\n const extractedCode = id.replace('/regions/', '').split('/')[0];\n return extractedCode === countryCode;\n }\n return id === countryCode || id.endsWith(`/${countryCode}`);\n }\n return false;\n });\n\n if (!country) {\n return null;\n }\n\n let state: State | null = null;\n if (stateCode && country.states) {\n state =\n country.states.find((stateItem) => {\n if (stateItem.stateId?.toLowerCase() === stateCode) {\n return true;\n }\n if (stateItem.id) {\n const stateId = stateItem.id.toLowerCase();\n if (\n stateId.includes(`-${stateCode}`) ||\n stateId.endsWith(`/${stateCode}`)\n ) {\n return true;\n }\n }\n return false;\n }) ?? null;\n }\n\n return {\n country,\n state,\n regionCode: normalizedCode,\n };\n}\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * Manages cryptocurrency on/off ramps functionality.\n */\nexport class RampsController extends BaseController<\n typeof controllerName,\n RampsControllerState,\n RampsControllerMessenger\n> {\n /**\n * Default TTL for cached requests.\n */\n readonly #requestCacheTTL: number;\n\n /**\n * Maximum number of entries in the request cache.\n */\n readonly #requestCacheMaxSize: number;\n\n /**\n * Map of pending requests for deduplication.\n * Key is the cache key, value is the pending request with abort controller.\n */\n readonly #pendingRequests: Map<string, PendingRequest> = new Map();\n\n /**\n * Constructs a new {@link RampsController}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this controller.\n * @param args.state - The desired state with which to initialize this\n * controller. Missing properties will be filled in with defaults.\n * @param args.requestCacheTTL - Time to live for cached requests in milliseconds.\n * @param args.requestCacheMaxSize - Maximum number of entries in the request cache.\n */\n constructor({\n messenger,\n state = {},\n requestCacheTTL = DEFAULT_REQUEST_CACHE_TTL,\n requestCacheMaxSize = DEFAULT_REQUEST_CACHE_MAX_SIZE,\n }: RampsControllerOptions) {\n super({\n messenger,\n metadata: rampsControllerMetadata,\n name: controllerName,\n state: {\n ...getDefaultRampsControllerState(),\n ...state,\n // Always reset requests cache on initialization (non-persisted)\n requests: {},\n },\n });\n\n this.#requestCacheTTL = requestCacheTTL;\n this.#requestCacheMaxSize = requestCacheMaxSize;\n }\n\n /**\n * Executes a request with caching and deduplication.\n *\n * If a request with the same cache key is already in flight, returns the\n * existing promise. If valid cached data exists, returns it without making\n * a new request.\n *\n * @param cacheKey - Unique identifier for this request.\n * @param fetcher - Function that performs the actual fetch. Receives an AbortSignal.\n * @param options - Options for cache behavior.\n * @returns The result of the request.\n */\n async executeRequest<TResult>(\n cacheKey: string,\n fetcher: (signal: AbortSignal) => Promise<TResult>,\n options?: ExecuteRequestOptions,\n ): Promise<TResult> {\n const ttl = options?.ttl ?? this.#requestCacheTTL;\n\n // Check for existing pending request - join it instead of making a duplicate\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n return pending.promise as Promise<TResult>;\n }\n\n // Check cache validity (unless force refresh)\n if (!options?.forceRefresh) {\n const cached = this.state.requests[cacheKey];\n if (cached && !isCacheExpired(cached, ttl)) {\n return cached.data as TResult;\n }\n }\n\n // Create abort controller for this request\n const abortController = new AbortController();\n const lastFetchedAt = Date.now();\n\n // Update state to loading\n this.#updateRequestState(cacheKey, createLoadingState());\n\n // Create the fetch promise\n const promise = (async (): Promise<TResult> => {\n try {\n const data = await fetcher(abortController.signal);\n\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw new Error('Request was aborted');\n }\n\n this.#updateRequestState(\n cacheKey,\n createSuccessState(data as Json, lastFetchedAt),\n );\n return data;\n } catch (error) {\n // Don't update state if aborted\n if (abortController.signal.aborted) {\n throw error;\n }\n\n const errorMessage = (error as Error)?.message;\n\n this.#updateRequestState(\n cacheKey,\n createErrorState(errorMessage ?? 'Unknown error', lastFetchedAt),\n );\n throw error;\n } finally {\n // Only delete if this is still our entry (not replaced by a new request)\n const currentPending = this.#pendingRequests.get(cacheKey);\n if (currentPending?.abortController === abortController) {\n this.#pendingRequests.delete(cacheKey);\n }\n }\n })();\n\n // Store pending request for deduplication\n this.#pendingRequests.set(cacheKey, { promise, abortController });\n\n return promise;\n }\n\n /**\n * Aborts a pending request if one exists.\n *\n * @param cacheKey - The cache key of the request to abort.\n * @returns True if a request was aborted.\n */\n abortRequest(cacheKey: string): boolean {\n const pending = this.#pendingRequests.get(cacheKey);\n if (pending) {\n pending.abortController.abort();\n this.#pendingRequests.delete(cacheKey);\n this.#removeRequestState(cacheKey);\n return true;\n }\n return false;\n }\n\n /**\n * Removes a request state from the cache.\n *\n * @param cacheKey - The cache key to remove.\n */\n #removeRequestState(cacheKey: string): void {\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n delete requests[cacheKey];\n });\n }\n\n /**\n * Gets the state of a specific cached request.\n *\n * @param cacheKey - The cache key to look up.\n * @returns The request state, or undefined if not cached.\n */\n getRequestState(cacheKey: string): RequestState | undefined {\n return this.state.requests[cacheKey];\n }\n\n /**\n * Updates the state for a specific request.\n *\n * @param cacheKey - The cache key.\n * @param requestState - The new state for the request.\n */\n #updateRequestState(cacheKey: string, requestState: RequestState): void {\n const maxSize = this.#requestCacheMaxSize;\n\n this.update((state) => {\n const requests = state.requests as unknown as Record<\n string,\n RequestState | undefined\n >;\n requests[cacheKey] = requestState;\n\n // Evict oldest entries if cache exceeds max size\n const keys = Object.keys(requests);\n\n if (keys.length > maxSize) {\n // Sort by timestamp (oldest first)\n const sortedKeys = keys.sort((a, b) => {\n const aTime = requests[a]?.timestamp ?? 0;\n const bTime = requests[b]?.timestamp ?? 0;\n return aTime - bTime;\n });\n\n // Remove oldest entries until we're under the limit\n const entriesToRemove = keys.length - maxSize;\n for (let i = 0; i < entriesToRemove; i++) {\n const keyToRemove = sortedKeys[i];\n if (keyToRemove) {\n delete requests[keyToRemove];\n }\n }\n }\n });\n }\n\n /**\n * Updates the user's region by fetching geolocation.\n * This method calls the RampsService to get the geolocation.\n *\n * @param options - Options for cache behavior.\n * @returns The user region object.\n */\n async updateUserRegion(\n options?: ExecuteRequestOptions,\n ): Promise<UserRegion | null> {\n // If a userRegion already exists and forceRefresh is not requested,\n // return it immediately without fetching geolocation.\n // This ensures that once a region is set (either via geolocation or manual selection),\n // it will not be overwritten by subsequent geolocation fetches.\n if (this.state.userRegion && !options?.forceRefresh) {\n return this.state.userRegion;\n }\n\n // When forceRefresh is true, clear the existing region, tokens, and providers before fetching\n if (options?.forceRefresh) {\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n state.providers = [];\n });\n }\n\n const cacheKey = createCacheKey('updateUserRegion', []);\n\n const regionCode = await this.executeRequest(\n cacheKey,\n async () => {\n const result = await this.messenger.call('RampsService:getGeolocation');\n return result;\n },\n options,\n );\n\n if (!regionCode) {\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n state.providers = [];\n });\n return null;\n }\n\n const normalizedRegion = regionCode.toLowerCase().trim();\n\n try {\n const countries = await this.getCountries('buy', options);\n const userRegion = findRegionFromCode(normalizedRegion, countries);\n\n if (userRegion) {\n this.update((state) => {\n const regionChanged =\n state.userRegion?.regionCode !== userRegion.regionCode;\n state.userRegion = userRegion;\n // Clear tokens and providers when region changes\n if (regionChanged) {\n state.tokens = null;\n state.providers = [];\n }\n });\n\n // Fetch providers for the new region\n if (userRegion.regionCode) {\n try {\n await this.getProviders(userRegion.regionCode, options);\n } catch {\n // Provider fetch failed - error state will be available via selectors\n }\n }\n\n return userRegion;\n }\n\n // Region not found in countries data\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n state.providers = [];\n });\n\n return null;\n } catch {\n // If countries fetch fails, we can't create a valid UserRegion\n // Return null to indicate we don't have valid country data\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n state.providers = [];\n });\n\n return null;\n }\n }\n\n /**\n * Sets the user's region manually (without fetching geolocation).\n * This allows users to override the detected region.\n *\n * @param region - The region code to set (e.g., \"US-CA\").\n * @param options - Options for cache behavior.\n * @returns The user region object.\n */\n async setUserRegion(\n region: string,\n options?: ExecuteRequestOptions,\n ): Promise<UserRegion> {\n const normalizedRegion = region.toLowerCase().trim();\n\n try {\n const countries = await this.getCountries('buy', options);\n const userRegion = findRegionFromCode(normalizedRegion, countries);\n\n if (userRegion) {\n this.update((state) => {\n state.userRegion = userRegion;\n state.tokens = null;\n state.providers = [];\n });\n\n // Fetch providers for the new region\n try {\n await this.getProviders(userRegion.regionCode, options);\n } catch {\n // Provider fetch failed - error state will be available via selectors\n }\n\n return userRegion;\n }\n\n // Region not found in countries data\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n state.providers = [];\n });\n throw new Error(\n `Region \"${normalizedRegion}\" not found in countries data. Cannot set user region without valid country information.`,\n );\n } catch (error) {\n // If the error is \"not found\", re-throw it\n // Otherwise, it's from countries fetch failure\n if (error instanceof Error && error.message.includes('not found')) {\n throw error;\n }\n // Countries fetch failed\n this.update((state) => {\n state.userRegion = null;\n state.tokens = null;\n state.providers = [];\n });\n throw new Error(\n 'Failed to fetch countries data. Cannot set user region without valid country information.',\n );\n }\n }\n\n /**\n * Sets the user's preferred provider.\n * This allows users to set their preferred ramp provider.\n *\n * @param provider - The provider object to set.\n */\n setPreferredProvider(provider: Provider | null): void {\n this.update((state) => {\n state.preferredProvider = provider;\n });\n }\n\n /**\n * Initializes the controller by fetching the user's region from geolocation.\n * This should be called once at app startup to set up the initial region.\n * After the region is set, tokens are fetched and saved to state.\n *\n * If a userRegion already exists (from persistence or manual selection),\n * this method will skip geolocation fetch and only fetch tokens if needed.\n *\n * @param options - Options for cache behavior.\n * @returns Promise that resolves when initialization is complete.\n */\n async init(options?: ExecuteRequestOptions): Promise<void> {\n const userRegion = await this.updateUserRegion(options).catch(() => {\n // User region fetch failed - error state will be available via selectors\n return null;\n });\n\n if (userRegion) {\n try {\n await this.getTokens(userRegion.regionCode, 'buy', options);\n } catch {\n // Token fetch failed - error state will be available via selectors\n }\n\n try {\n await this.getProviders(userRegion.regionCode, options);\n } catch {\n // Provider fetch failed - error state will be available via selectors\n }\n }\n }\n\n /**\n * Fetches the list of supported countries for a given ramp action.\n *\n * @param action - The ramp action type ('buy' or 'sell').\n * @param options - Options for cache behavior.\n * @returns An array of countries.\n */\n async getCountries(\n action: 'buy' | 'sell' = 'buy',\n options?: ExecuteRequestOptions,\n ): Promise<Country[]> {\n const cacheKey = createCacheKey('getCountries', [action]);\n\n return this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call('RampsService:getCountries', action);\n },\n options,\n );\n }\n\n /**\n * Fetches the list of available tokens for a given region and action.\n * The tokens are saved in the controller state once fetched.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\"). If not provided, uses the user's region from controller state.\n * @param action - The ramp action type ('buy' or 'sell').\n * @param options - Options for cache behavior.\n * @returns The tokens response containing topTokens and allTokens.\n */\n async getTokens(\n region?: string,\n action: 'buy' | 'sell' = 'buy',\n options?: ExecuteRequestOptions,\n ): Promise<TokensResponse> {\n const regionToUse = region ?? this.state.userRegion?.regionCode;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getTokens', [normalizedRegion, action]);\n\n const tokens = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call(\n 'RampsService:getTokens',\n normalizedRegion,\n action,\n );\n },\n options,\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.tokens = tokens;\n }\n });\n\n return tokens;\n }\n\n /**\n * Fetches the list of providers for a given region.\n * The providers are saved in the controller state once fetched.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\"). If not provided, uses the user's region from controller state.\n * @param options - Options for cache behavior and query filters.\n * @param options.provider - Provider ID(s) to filter by.\n * @param options.crypto - Crypto currency ID(s) to filter by.\n * @param options.fiat - Fiat currency ID(s) to filter by.\n * @param options.payments - Payment method ID(s) to filter by.\n * @returns The providers response containing providers array.\n */\n async getProviders(\n region?: string,\n options?: ExecuteRequestOptions & {\n provider?: string | string[];\n crypto?: string | string[];\n fiat?: string | string[];\n payments?: string | string[];\n },\n ): Promise<{ providers: Provider[] }> {\n const regionToUse = region ?? this.state.userRegion?.regionCode;\n\n if (!regionToUse) {\n throw new Error(\n 'Region is required. Either provide a region parameter or ensure userRegion is set in controller state.',\n );\n }\n\n const normalizedRegion = regionToUse.toLowerCase().trim();\n const cacheKey = createCacheKey('getProviders', [\n normalizedRegion,\n options?.provider,\n options?.crypto,\n options?.fiat,\n options?.payments,\n ]);\n\n const { providers } = await this.executeRequest(\n cacheKey,\n async () => {\n return this.messenger.call(\n 'RampsService:getProviders',\n normalizedRegion,\n {\n provider: options?.provider,\n crypto: options?.crypto,\n fiat: options?.fiat,\n payments: options?.payments,\n },\n );\n },\n options,\n );\n\n this.update((state) => {\n const userRegionCode = state.userRegion?.regionCode;\n\n if (userRegionCode === undefined || userRegionCode === normalizedRegion) {\n state.providers = providers;\n }\n });\n\n return { providers };\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"RampsService-method-action-types.cjs","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { RampsService } from './RampsService';\n\n/**\n * Makes a request to the API in order to retrieve the user's geolocation\n * based on their IP address.\n *\n * @returns The user's country/region code (e.g., \"US-UT\" for Utah, USA).\n */\nexport type RampsServiceGetGeolocationAction = {\n type: `RampsService:getGeolocation`;\n handler: RampsService['getGeolocation'];\n};\n\n/**\n * Makes a request to the cached API to retrieve the list of supported countries.\n * Filters countries based on aggregator support (preserves OnRampSDK logic).\n *\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns An array of countries filtered by aggregator support.\n */\nexport type RampsServiceGetCountriesAction = {\n type: `RampsService:getCountries`;\n handler: RampsService['getCountries'];\n};\n\n/**\n * Fetches the list of available tokens for a given region and action.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\").\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns The tokens response containing topTokens and allTokens.\n */\nexport type RampsServiceGetTokensAction = {\n type: `RampsService:getTokens`;\n handler: RampsService['getTokens'];\n};\n\n/**\n * Union of all RampsService action types.\n */\nexport type RampsServiceMethodActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction;\n"]}
1
+ {"version":3,"file":"RampsService-method-action-types.cjs","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { RampsService } from './RampsService';\n\n/**\n * Makes a request to the API in order to retrieve the user's geolocation\n * based on their IP address.\n *\n * @returns The user's country/region code (e.g., \"US-UT\" for Utah, USA).\n */\nexport type RampsServiceGetGeolocationAction = {\n type: `RampsService:getGeolocation`;\n handler: RampsService['getGeolocation'];\n};\n\n/**\n * Makes a request to the cached API to retrieve the list of supported countries.\n * Filters countries based on aggregator support (preserves OnRampSDK logic).\n *\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns An array of countries filtered by aggregator support.\n */\nexport type RampsServiceGetCountriesAction = {\n type: `RampsService:getCountries`;\n handler: RampsService['getCountries'];\n};\n\n/**\n * Fetches the list of available tokens for a given region and action.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\").\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns The tokens response containing topTokens and allTokens.\n */\nexport type RampsServiceGetTokensAction = {\n type: `RampsService:getTokens`;\n handler: RampsService['getTokens'];\n};\n\n/**\n * Fetches the list of providers for a given region.\n * Supports optional query filters: provider, crypto, fiat, payments.\n *\n * @param regionCode - The region code (e.g., \"us\", \"fr\", \"us-ny\").\n * @param options - Optional query parameters for filtering providers.\n * @param options.provider - Provider ID(s) to filter by.\n * @param options.crypto - Crypto currency ID(s) to filter by.\n * @param options.fiat - Fiat currency ID(s) to filter by.\n * @param options.payments - Payment method ID(s) to filter by.\n * @returns The providers response containing providers array.\n */\nexport type RampsServiceGetProvidersAction = {\n type: `RampsService:getProviders`;\n handler: RampsService['getProviders'];\n};\n\n/**\n * Union of all RampsService action types.\n */\nexport type RampsServiceMethodActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction\n | RampsServiceGetProvidersAction;\n"]}
@@ -35,8 +35,24 @@ export type RampsServiceGetTokensAction = {
35
35
  type: `RampsService:getTokens`;
36
36
  handler: RampsService['getTokens'];
37
37
  };
38
+ /**
39
+ * Fetches the list of providers for a given region.
40
+ * Supports optional query filters: provider, crypto, fiat, payments.
41
+ *
42
+ * @param regionCode - The region code (e.g., "us", "fr", "us-ny").
43
+ * @param options - Optional query parameters for filtering providers.
44
+ * @param options.provider - Provider ID(s) to filter by.
45
+ * @param options.crypto - Crypto currency ID(s) to filter by.
46
+ * @param options.fiat - Fiat currency ID(s) to filter by.
47
+ * @param options.payments - Payment method ID(s) to filter by.
48
+ * @returns The providers response containing providers array.
49
+ */
50
+ export type RampsServiceGetProvidersAction = {
51
+ type: `RampsService:getProviders`;
52
+ handler: RampsService['getProviders'];
53
+ };
38
54
  /**
39
55
  * Union of all RampsService action types.
40
56
  */
41
- export type RampsServiceMethodActions = RampsServiceGetGeolocationAction | RampsServiceGetCountriesAction | RampsServiceGetTokensAction;
57
+ export type RampsServiceMethodActions = RampsServiceGetGeolocationAction | RampsServiceGetCountriesAction | RampsServiceGetTokensAction | RampsServiceGetProvidersAction;
42
58
  //# sourceMappingURL=RampsService-method-action-types.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RampsService-method-action-types.d.cts","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,2BAAuB;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,6BAA6B,CAAC;IACpC,OAAO,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,yBAAyB,GACjC,gCAAgC,GAChC,8BAA8B,GAC9B,2BAA2B,CAAC"}
1
+ {"version":3,"file":"RampsService-method-action-types.d.cts","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,2BAAuB;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,6BAA6B,CAAC;IACpC,OAAO,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;CACvC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,yBAAyB,GACjC,gCAAgC,GAChC,8BAA8B,GAC9B,2BAA2B,GAC3B,8BAA8B,CAAC"}
@@ -35,8 +35,24 @@ export type RampsServiceGetTokensAction = {
35
35
  type: `RampsService:getTokens`;
36
36
  handler: RampsService['getTokens'];
37
37
  };
38
+ /**
39
+ * Fetches the list of providers for a given region.
40
+ * Supports optional query filters: provider, crypto, fiat, payments.
41
+ *
42
+ * @param regionCode - The region code (e.g., "us", "fr", "us-ny").
43
+ * @param options - Optional query parameters for filtering providers.
44
+ * @param options.provider - Provider ID(s) to filter by.
45
+ * @param options.crypto - Crypto currency ID(s) to filter by.
46
+ * @param options.fiat - Fiat currency ID(s) to filter by.
47
+ * @param options.payments - Payment method ID(s) to filter by.
48
+ * @returns The providers response containing providers array.
49
+ */
50
+ export type RampsServiceGetProvidersAction = {
51
+ type: `RampsService:getProviders`;
52
+ handler: RampsService['getProviders'];
53
+ };
38
54
  /**
39
55
  * Union of all RampsService action types.
40
56
  */
41
- export type RampsServiceMethodActions = RampsServiceGetGeolocationAction | RampsServiceGetCountriesAction | RampsServiceGetTokensAction;
57
+ export type RampsServiceMethodActions = RampsServiceGetGeolocationAction | RampsServiceGetCountriesAction | RampsServiceGetTokensAction | RampsServiceGetProvidersAction;
42
58
  //# sourceMappingURL=RampsService-method-action-types.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RampsService-method-action-types.d.mts","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,2BAAuB;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,6BAA6B,CAAC;IACpC,OAAO,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,yBAAyB,GACjC,gCAAgC,GAChC,8BAA8B,GAC9B,2BAA2B,CAAC"}
1
+ {"version":3,"file":"RampsService-method-action-types.d.mts","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,2BAAuB;AAEnD;;;;;GAKG;AACH,MAAM,MAAM,gCAAgC,GAAG;IAC7C,IAAI,EAAE,6BAA6B,CAAC;IACpC,OAAO,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;CACzC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,OAAO,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;CACvC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,yBAAyB,GACjC,gCAAgC,GAChC,8BAA8B,GAC9B,2BAA2B,GAC3B,8BAA8B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"RampsService-method-action-types.mjs","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { RampsService } from './RampsService';\n\n/**\n * Makes a request to the API in order to retrieve the user's geolocation\n * based on their IP address.\n *\n * @returns The user's country/region code (e.g., \"US-UT\" for Utah, USA).\n */\nexport type RampsServiceGetGeolocationAction = {\n type: `RampsService:getGeolocation`;\n handler: RampsService['getGeolocation'];\n};\n\n/**\n * Makes a request to the cached API to retrieve the list of supported countries.\n * Filters countries based on aggregator support (preserves OnRampSDK logic).\n *\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns An array of countries filtered by aggregator support.\n */\nexport type RampsServiceGetCountriesAction = {\n type: `RampsService:getCountries`;\n handler: RampsService['getCountries'];\n};\n\n/**\n * Fetches the list of available tokens for a given region and action.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\").\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns The tokens response containing topTokens and allTokens.\n */\nexport type RampsServiceGetTokensAction = {\n type: `RampsService:getTokens`;\n handler: RampsService['getTokens'];\n};\n\n/**\n * Union of all RampsService action types.\n */\nexport type RampsServiceMethodActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction;\n"]}
1
+ {"version":3,"file":"RampsService-method-action-types.mjs","sourceRoot":"","sources":["../src/RampsService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated by `scripts/generate-method-action-types.ts`.\n * Do not edit manually.\n */\n\nimport type { RampsService } from './RampsService';\n\n/**\n * Makes a request to the API in order to retrieve the user's geolocation\n * based on their IP address.\n *\n * @returns The user's country/region code (e.g., \"US-UT\" for Utah, USA).\n */\nexport type RampsServiceGetGeolocationAction = {\n type: `RampsService:getGeolocation`;\n handler: RampsService['getGeolocation'];\n};\n\n/**\n * Makes a request to the cached API to retrieve the list of supported countries.\n * Filters countries based on aggregator support (preserves OnRampSDK logic).\n *\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns An array of countries filtered by aggregator support.\n */\nexport type RampsServiceGetCountriesAction = {\n type: `RampsService:getCountries`;\n handler: RampsService['getCountries'];\n};\n\n/**\n * Fetches the list of available tokens for a given region and action.\n *\n * @param region - The region code (e.g., \"us\", \"fr\", \"us-ny\").\n * @param action - The ramp action type ('buy' or 'sell').\n * @returns The tokens response containing topTokens and allTokens.\n */\nexport type RampsServiceGetTokensAction = {\n type: `RampsService:getTokens`;\n handler: RampsService['getTokens'];\n};\n\n/**\n * Fetches the list of providers for a given region.\n * Supports optional query filters: provider, crypto, fiat, payments.\n *\n * @param regionCode - The region code (e.g., \"us\", \"fr\", \"us-ny\").\n * @param options - Optional query parameters for filtering providers.\n * @param options.provider - Provider ID(s) to filter by.\n * @param options.crypto - Crypto currency ID(s) to filter by.\n * @param options.fiat - Fiat currency ID(s) to filter by.\n * @param options.payments - Payment method ID(s) to filter by.\n * @returns The providers response containing providers array.\n */\nexport type RampsServiceGetProvidersAction = {\n type: `RampsService:getProviders`;\n handler: RampsService['getProviders'];\n};\n\n/**\n * Union of all RampsService action types.\n */\nexport type RampsServiceMethodActions =\n | RampsServiceGetGeolocationAction\n | RampsServiceGetCountriesAction\n | RampsServiceGetTokensAction\n | RampsServiceGetProvidersAction;\n"]}
@@ -51,6 +51,7 @@ const MESSENGER_EXPOSED_METHODS = [
51
51
  'getGeolocation',
52
52
  'getCountries',
53
53
  'getTokens',
54
+ 'getProviders',
54
55
  ];
55
56
  // === SERVICE DEFINITION ===
56
57
  /**
@@ -270,6 +271,61 @@ class RampsService {
270
271
  }
271
272
  return response;
272
273
  }
274
+ /**
275
+ * Fetches the list of providers for a given region.
276
+ * Supports optional query filters: provider, crypto, fiat, payments.
277
+ *
278
+ * @param regionCode - The region code (e.g., "us", "fr", "us-ny").
279
+ * @param options - Optional query parameters for filtering providers.
280
+ * @param options.provider - Provider ID(s) to filter by.
281
+ * @param options.crypto - Crypto currency ID(s) to filter by.
282
+ * @param options.fiat - Fiat currency ID(s) to filter by.
283
+ * @param options.payments - Payment method ID(s) to filter by.
284
+ * @returns The providers response containing providers array.
285
+ */
286
+ async getProviders(regionCode, options) {
287
+ const normalizedRegion = regionCode.toLowerCase().trim();
288
+ const url = new URL(getApiPath(`regions/${normalizedRegion}/providers`), getBaseUrl(__classPrivateFieldGet(this, _RampsService_environment, "f"), RampsApiService.Regions));
289
+ __classPrivateFieldGet(this, _RampsService_instances, "m", _RampsService_addCommonParams).call(this, url);
290
+ if (options?.provider) {
291
+ const providerIds = Array.isArray(options.provider)
292
+ ? options.provider
293
+ : [options.provider];
294
+ providerIds.forEach((id) => url.searchParams.append('provider', id));
295
+ }
296
+ if (options?.crypto) {
297
+ const cryptoIds = Array.isArray(options.crypto)
298
+ ? options.crypto
299
+ : [options.crypto];
300
+ cryptoIds.forEach((id) => url.searchParams.append('crypto', id));
301
+ }
302
+ if (options?.fiat) {
303
+ const fiatIds = Array.isArray(options.fiat)
304
+ ? options.fiat
305
+ : [options.fiat];
306
+ fiatIds.forEach((id) => url.searchParams.append('fiat', id));
307
+ }
308
+ if (options?.payments) {
309
+ const paymentIds = Array.isArray(options.payments)
310
+ ? options.payments
311
+ : [options.payments];
312
+ paymentIds.forEach((id) => url.searchParams.append('payments', id));
313
+ }
314
+ const response = await __classPrivateFieldGet(this, _RampsService_policy, "f").execute(async () => {
315
+ const fetchResponse = await __classPrivateFieldGet(this, _RampsService_fetch, "f").call(this, url);
316
+ if (!fetchResponse.ok) {
317
+ throw new controller_utils_1.HttpError(fetchResponse.status, `Fetching '${url.toString()}' failed with status '${fetchResponse.status}'`);
318
+ }
319
+ return fetchResponse.json();
320
+ });
321
+ if (!response || typeof response !== 'object') {
322
+ throw new Error('Malformed response received from providers API');
323
+ }
324
+ if (!Array.isArray(response.providers)) {
325
+ throw new Error('Malformed response received from providers API');
326
+ }
327
+ return response;
328
+ }
273
329
  }
274
330
  exports.RampsService = RampsService;
275
331
  _a = RampsService, _RampsService_messenger = new WeakMap(), _RampsService_fetch = new WeakMap(), _RampsService_policy = new WeakMap(), _RampsService_environment = new WeakMap(), _RampsService_context = new WeakMap(), _RampsService_instances = new WeakSet(), _RampsService_addCommonParams = function _RampsService_addCommonParams(url, action) {