@metamask-previews/ramps-controller 2.0.0-preview-1d3aa020 → 2.0.0-preview-67bc4e39

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 CHANGED
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  ### Added
11
11
 
12
+ - Add `createRequestSelector` utility function for creating memoized selectors for RampsController request states ([#7554](https://github.com/MetaMask/core/pull/7554))
13
+
12
14
  - Add request caching infrastructure with TTL, deduplication, and abort support ([#7536](https://github.com/MetaMask/core/pull/7536))
13
15
 
14
16
  ### Changed
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createErrorState = exports.createSuccessState = exports.createLoadingState = exports.isCacheExpired = exports.createCacheKey = exports.DEFAULT_REQUEST_CACHE_MAX_SIZE = exports.DEFAULT_REQUEST_CACHE_TTL = exports.RequestStatus = exports.RampsEnvironment = exports.RampsService = exports.getDefaultRampsControllerState = exports.RampsController = void 0;
3
+ exports.createRequestSelector = exports.createErrorState = exports.createSuccessState = exports.createLoadingState = exports.isCacheExpired = exports.createCacheKey = exports.DEFAULT_REQUEST_CACHE_MAX_SIZE = exports.DEFAULT_REQUEST_CACHE_TTL = exports.RequestStatus = exports.RampsEnvironment = exports.RampsService = exports.getDefaultRampsControllerState = exports.RampsController = void 0;
4
4
  var RampsController_1 = require("./RampsController.cjs");
5
5
  Object.defineProperty(exports, "RampsController", { enumerable: true, get: function () { return RampsController_1.RampsController; } });
6
6
  Object.defineProperty(exports, "getDefaultRampsControllerState", { enumerable: true, get: function () { return RampsController_1.getDefaultRampsControllerState; } });
@@ -16,4 +16,6 @@ Object.defineProperty(exports, "isCacheExpired", { enumerable: true, get: functi
16
16
  Object.defineProperty(exports, "createLoadingState", { enumerable: true, get: function () { return RequestCache_1.createLoadingState; } });
17
17
  Object.defineProperty(exports, "createSuccessState", { enumerable: true, get: function () { return RequestCache_1.createSuccessState; } });
18
18
  Object.defineProperty(exports, "createErrorState", { enumerable: true, get: function () { return RequestCache_1.createErrorState; } });
19
+ var selectors_1 = require("./selectors.cjs");
20
+ Object.defineProperty(exports, "createRequestSelector", { enumerable: true, get: function () { return selectors_1.createRequestSelector; } });
19
21
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AASA,yDAG2B;AAFzB,kHAAA,eAAe,OAAA;AACf,iIAAA,8BAA8B,OAAA;AAOhC,mDAAgE;AAAvD,4GAAA,YAAY,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AAQvC,mDASwB;AARtB,6GAAA,aAAa,OAAA;AACb,yHAAA,yBAAyB,OAAA;AACzB,8HAAA,8BAA8B,OAAA;AAC9B,8GAAA,cAAc,OAAA;AACd,8GAAA,cAAc,OAAA;AACd,kHAAA,kBAAkB,OAAA;AAClB,kHAAA,kBAAkB,OAAA;AAClB,gHAAA,gBAAgB,OAAA","sourcesContent":["export type {\n RampsControllerActions,\n RampsControllerEvents,\n RampsControllerGetStateAction,\n RampsControllerMessenger,\n RampsControllerState,\n RampsControllerStateChangeEvent,\n RampsControllerOptions,\n} from './RampsController';\nexport {\n RampsController,\n getDefaultRampsControllerState,\n} from './RampsController';\nexport type {\n RampsServiceActions,\n RampsServiceEvents,\n RampsServiceMessenger,\n} from './RampsService';\nexport { RampsService, RampsEnvironment } from './RampsService';\nexport type { RampsServiceGetGeolocationAction } from './RampsService-method-action-types';\nexport type {\n RequestCache,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n} from './RequestCache';\nexport {\n RequestStatus,\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"]}
1
+ {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AASA,yDAG2B;AAFzB,kHAAA,eAAe,OAAA;AACf,iIAAA,8BAA8B,OAAA;AAOhC,mDAAgE;AAAvD,4GAAA,YAAY,OAAA;AAAE,gHAAA,gBAAgB,OAAA;AAQvC,mDASwB;AARtB,6GAAA,aAAa,OAAA;AACb,yHAAA,yBAAyB,OAAA;AACzB,8HAAA,8BAA8B,OAAA;AAC9B,8GAAA,cAAc,OAAA;AACd,8GAAA,cAAc,OAAA;AACd,kHAAA,kBAAkB,OAAA;AAClB,kHAAA,kBAAkB,OAAA;AAClB,gHAAA,gBAAgB,OAAA;AAGlB,6CAAoD;AAA3C,kHAAA,qBAAqB,OAAA","sourcesContent":["export type {\n RampsControllerActions,\n RampsControllerEvents,\n RampsControllerGetStateAction,\n RampsControllerMessenger,\n RampsControllerState,\n RampsControllerStateChangeEvent,\n RampsControllerOptions,\n} from './RampsController';\nexport {\n RampsController,\n getDefaultRampsControllerState,\n} from './RampsController';\nexport type {\n RampsServiceActions,\n RampsServiceEvents,\n RampsServiceMessenger,\n} from './RampsService';\nexport { RampsService, RampsEnvironment } from './RampsService';\nexport type { RampsServiceGetGeolocationAction } from './RampsService-method-action-types';\nexport type {\n RequestCache,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n} from './RequestCache';\nexport {\n RequestStatus,\n DEFAULT_REQUEST_CACHE_TTL,\n DEFAULT_REQUEST_CACHE_MAX_SIZE,\n createCacheKey,\n isCacheExpired,\n createLoadingState,\n createSuccessState,\n createErrorState,\n} from './RequestCache';\nexport type { RequestSelectorResult } from './selectors';\nexport { createRequestSelector } from './selectors';\n"]}
package/dist/index.d.cts CHANGED
@@ -5,4 +5,6 @@ export { RampsService, RampsEnvironment } from "./RampsService.cjs";
5
5
  export type { RampsServiceGetGeolocationAction } from "./RampsService-method-action-types.cjs";
6
6
  export type { RequestCache, RequestState, ExecuteRequestOptions, PendingRequest, } from "./RequestCache.cjs";
7
7
  export { RequestStatus, DEFAULT_REQUEST_CACHE_TTL, DEFAULT_REQUEST_CACHE_MAX_SIZE, createCacheKey, isCacheExpired, createLoadingState, createSuccessState, createErrorState, } from "./RequestCache.cjs";
8
+ export type { RequestSelectorResult } from "./selectors.cjs";
9
+ export { createRequestSelector } from "./selectors.cjs";
8
10
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,oBAAoB,EACpB,+BAA+B,EAC/B,sBAAsB,GACvB,8BAA0B;AAC3B,OAAO,EACL,eAAe,EACf,8BAA8B,GAC/B,8BAA0B;AAC3B,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,2BAAuB;AACxB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAAuB;AAChE,YAAY,EAAE,gCAAgC,EAAE,+CAA2C;AAC3F,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,GACf,2BAAuB;AACxB,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,GACjB,2BAAuB"}
1
+ {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,oBAAoB,EACpB,+BAA+B,EAC/B,sBAAsB,GACvB,8BAA0B;AAC3B,OAAO,EACL,eAAe,EACf,8BAA8B,GAC/B,8BAA0B;AAC3B,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,2BAAuB;AACxB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAAuB;AAChE,YAAY,EAAE,gCAAgC,EAAE,+CAA2C;AAC3F,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,GACf,2BAAuB;AACxB,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,GACjB,2BAAuB;AACxB,YAAY,EAAE,qBAAqB,EAAE,wBAAoB;AACzD,OAAO,EAAE,qBAAqB,EAAE,wBAAoB"}
package/dist/index.d.mts CHANGED
@@ -5,4 +5,6 @@ export { RampsService, RampsEnvironment } from "./RampsService.mjs";
5
5
  export type { RampsServiceGetGeolocationAction } from "./RampsService-method-action-types.mjs";
6
6
  export type { RequestCache, RequestState, ExecuteRequestOptions, PendingRequest, } from "./RequestCache.mjs";
7
7
  export { RequestStatus, DEFAULT_REQUEST_CACHE_TTL, DEFAULT_REQUEST_CACHE_MAX_SIZE, createCacheKey, isCacheExpired, createLoadingState, createSuccessState, createErrorState, } from "./RequestCache.mjs";
8
+ export type { RequestSelectorResult } from "./selectors.mjs";
9
+ export { createRequestSelector } from "./selectors.mjs";
8
10
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,oBAAoB,EACpB,+BAA+B,EAC/B,sBAAsB,GACvB,8BAA0B;AAC3B,OAAO,EACL,eAAe,EACf,8BAA8B,GAC/B,8BAA0B;AAC3B,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,2BAAuB;AACxB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAAuB;AAChE,YAAY,EAAE,gCAAgC,EAAE,+CAA2C;AAC3F,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,GACf,2BAAuB;AACxB,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,GACjB,2BAAuB"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,sBAAsB,EACtB,qBAAqB,EACrB,6BAA6B,EAC7B,wBAAwB,EACxB,oBAAoB,EACpB,+BAA+B,EAC/B,sBAAsB,GACvB,8BAA0B;AAC3B,OAAO,EACL,eAAe,EACf,8BAA8B,GAC/B,8BAA0B;AAC3B,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,GACtB,2BAAuB;AACxB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAAuB;AAChE,YAAY,EAAE,gCAAgC,EAAE,+CAA2C;AAC3F,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACrB,cAAc,GACf,2BAAuB;AACxB,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,GACjB,2BAAuB;AACxB,YAAY,EAAE,qBAAqB,EAAE,wBAAoB;AACzD,OAAO,EAAE,qBAAqB,EAAE,wBAAoB"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  export { RampsController, getDefaultRampsControllerState } from "./RampsController.mjs";
2
2
  export { RampsService, RampsEnvironment } from "./RampsService.mjs";
3
3
  export { RequestStatus, DEFAULT_REQUEST_CACHE_TTL, DEFAULT_REQUEST_CACHE_MAX_SIZE, createCacheKey, isCacheExpired, createLoadingState, createSuccessState, createErrorState } from "./RequestCache.mjs";
4
+ export { createRequestSelector } from "./selectors.mjs";
4
5
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,eAAe,EACf,8BAA8B,EAC/B,8BAA0B;AAM3B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAAuB;AAQhE,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EACjB,2BAAuB","sourcesContent":["export type {\n RampsControllerActions,\n RampsControllerEvents,\n RampsControllerGetStateAction,\n RampsControllerMessenger,\n RampsControllerState,\n RampsControllerStateChangeEvent,\n RampsControllerOptions,\n} from './RampsController';\nexport {\n RampsController,\n getDefaultRampsControllerState,\n} from './RampsController';\nexport type {\n RampsServiceActions,\n RampsServiceEvents,\n RampsServiceMessenger,\n} from './RampsService';\nexport { RampsService, RampsEnvironment } from './RampsService';\nexport type { RampsServiceGetGeolocationAction } from './RampsService-method-action-types';\nexport type {\n RequestCache,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n} from './RequestCache';\nexport {\n RequestStatus,\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"]}
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EACL,eAAe,EACf,8BAA8B,EAC/B,8BAA0B;AAM3B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,2BAAuB;AAQhE,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,8BAA8B,EAC9B,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EACjB,2BAAuB;AAExB,OAAO,EAAE,qBAAqB,EAAE,wBAAoB","sourcesContent":["export type {\n RampsControllerActions,\n RampsControllerEvents,\n RampsControllerGetStateAction,\n RampsControllerMessenger,\n RampsControllerState,\n RampsControllerStateChangeEvent,\n RampsControllerOptions,\n} from './RampsController';\nexport {\n RampsController,\n getDefaultRampsControllerState,\n} from './RampsController';\nexport type {\n RampsServiceActions,\n RampsServiceEvents,\n RampsServiceMessenger,\n} from './RampsService';\nexport { RampsService, RampsEnvironment } from './RampsService';\nexport type { RampsServiceGetGeolocationAction } from './RampsService-method-action-types';\nexport type {\n RequestCache,\n RequestState,\n ExecuteRequestOptions,\n PendingRequest,\n} from './RequestCache';\nexport {\n RequestStatus,\n DEFAULT_REQUEST_CACHE_TTL,\n DEFAULT_REQUEST_CACHE_MAX_SIZE,\n createCacheKey,\n isCacheExpired,\n createLoadingState,\n createSuccessState,\n createErrorState,\n} from './RequestCache';\nexport type { RequestSelectorResult } from './selectors';\nexport { createRequestSelector } from './selectors';\n"]}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createRequestSelector = void 0;
4
+ const RequestCache_1 = require("./RequestCache.cjs");
5
+ /**
6
+ * Creates a memoized selector for a controller method's request state.
7
+ *
8
+ * This selector tracks the loading, error, and data state for a specific
9
+ * controller method call. It's optimized for use with React Redux's `useSelector`
10
+ * hook - the selector returns the same object reference when the underlying
11
+ * request state hasn't changed, so no `shallowEqual` is needed.
12
+ *
13
+ * The selector uses reference equality on the request object itself, so it
14
+ * works correctly with arrays and objects without expensive deep equality checks.
15
+ *
16
+ * @param getState - Function that extracts RampsControllerState from the root state.
17
+ * Typically a reselect selector like `selectRampsControllerState`.
18
+ * @param method - The controller method name (e.g., 'updateGeolocation').
19
+ * @param params - The parameters passed to the method, used to generate the cache key.
20
+ * Must match the params used when calling the controller method.
21
+ * @returns A selector function that returns `{ data, isFetching, error }`.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * // In selectors file - create once at module level
26
+ * import { createRequestSelector } from '@metamask/ramps-controller';
27
+ * import { createSelector } from 'reselect';
28
+ *
29
+ * const selectRampsControllerState = createSelector(
30
+ * (state: RootState) => state.engine.backgroundState.RampsController,
31
+ * (rampsControllerState) => rampsControllerState,
32
+ * );
33
+ *
34
+ * export const selectGeolocationRequest = createRequestSelector<
35
+ * RootState,
36
+ * string
37
+ * >(selectRampsControllerState, 'updateGeolocation', []);
38
+ *
39
+ * // In hook - use directly with useSelector, no shallowEqual needed
40
+ * export function useRampsGeolocation() {
41
+ * const { isFetching, error } = useSelector(selectGeolocationRequest);
42
+ * // ... rest of hook
43
+ * }
44
+ * ```
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * // For methods with parameters
49
+ * export const selectCryptoCurrenciesRequest = (region: string) =>
50
+ * createRequestSelector<RootState, CryptoCurrency[]>(
51
+ * selectRampsControllerState,
52
+ * 'getCryptoCurrencies',
53
+ * [region],
54
+ * );
55
+ *
56
+ * // In component
57
+ * const { data, isFetching, error } = useSelector(
58
+ * selectCryptoCurrenciesRequest('US')
59
+ * );
60
+ * ```
61
+ */
62
+ function createRequestSelector(getState, method, params) {
63
+ const cacheKey = (0, RequestCache_1.createCacheKey)(method, params);
64
+ let lastRequest;
65
+ let lastResult = null;
66
+ return (state) => {
67
+ const request = getState(state)?.requests?.[cacheKey];
68
+ if (request === lastRequest && lastResult !== null) {
69
+ return lastResult;
70
+ }
71
+ lastRequest = request;
72
+ lastResult = {
73
+ data: request?.data ?? null,
74
+ isFetching: request?.status === RequestCache_1.RequestStatus.LOADING,
75
+ error: request?.error ?? null,
76
+ };
77
+ return lastResult;
78
+ };
79
+ }
80
+ exports.createRequestSelector = createRequestSelector;
81
+ //# sourceMappingURL=selectors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.cjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":";;;AAEA,qDAA+D;AAkB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,SAAgB,qBAAqB,CACnC,QAAqE,EACrE,MAAc,EACd,MAAiB;IAEjB,MAAM,QAAQ,GAAG,IAAA,6BAAc,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD,IAAI,WAAqC,CAAC;IAC1C,IAAI,UAAU,GAAwC,IAAI,CAAC;IAE3D,OAAO,CAAC,KAAiB,EAAgC,EAAE;QACzD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;QAEtD,IAAI,OAAO,KAAK,WAAW,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACnD,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,WAAW,GAAG,OAAO,CAAC;QACtB,UAAU,GAAG;YACX,IAAI,EAAG,OAAO,EAAE,IAAc,IAAI,IAAI;YACtC,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,4BAAa,CAAC,OAAO;YACrD,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI;SAC9B,CAAC;QAEF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AA1BD,sDA0BC","sourcesContent":["import type { RampsControllerState } from './RampsController';\nimport type { RequestState } from './RequestCache';\nimport { RequestStatus, createCacheKey } from './RequestCache';\n\n/**\n * Result shape returned by request selectors.\n *\n * This object is memoized - the same reference is returned when the underlying\n * request state hasn't changed, making it safe to use with React Redux's\n * `useSelector` without `shallowEqual`.\n */\nexport type RequestSelectorResult<TData> = {\n /** The data returned by the request, or null if not yet loaded or on error. */\n data: TData | null;\n /** Whether the request is currently in progress. */\n isFetching: boolean;\n /** Error message if the request failed, or null if successful or not yet attempted. */\n error: string | null;\n};\n\n/**\n * Creates a memoized selector for a controller method's request state.\n *\n * This selector tracks the loading, error, and data state for a specific\n * controller method call. It's optimized for use with React Redux's `useSelector`\n * hook - the selector returns the same object reference when the underlying\n * request state hasn't changed, so no `shallowEqual` is needed.\n *\n * The selector uses reference equality on the request object itself, so it\n * works correctly with arrays and objects without expensive deep equality checks.\n *\n * @param getState - Function that extracts RampsControllerState from the root state.\n * Typically a reselect selector like `selectRampsControllerState`.\n * @param method - The controller method name (e.g., 'updateGeolocation').\n * @param params - The parameters passed to the method, used to generate the cache key.\n * Must match the params used when calling the controller method.\n * @returns A selector function that returns `{ data, isFetching, error }`.\n *\n * @example\n * ```ts\n * // In selectors file - create once at module level\n * import { createRequestSelector } from '@metamask/ramps-controller';\n * import { createSelector } from 'reselect';\n *\n * const selectRampsControllerState = createSelector(\n * (state: RootState) => state.engine.backgroundState.RampsController,\n * (rampsControllerState) => rampsControllerState,\n * );\n *\n * export const selectGeolocationRequest = createRequestSelector<\n * RootState,\n * string\n * >(selectRampsControllerState, 'updateGeolocation', []);\n *\n * // In hook - use directly with useSelector, no shallowEqual needed\n * export function useRampsGeolocation() {\n * const { isFetching, error } = useSelector(selectGeolocationRequest);\n * // ... rest of hook\n * }\n * ```\n *\n * @example\n * ```ts\n * // For methods with parameters\n * export const selectCryptoCurrenciesRequest = (region: string) =>\n * createRequestSelector<RootState, CryptoCurrency[]>(\n * selectRampsControllerState,\n * 'getCryptoCurrencies',\n * [region],\n * );\n *\n * // In component\n * const { data, isFetching, error } = useSelector(\n * selectCryptoCurrenciesRequest('US')\n * );\n * ```\n */\nexport function createRequestSelector<TRootState, TData>(\n getState: (rootState: TRootState) => RampsControllerState | undefined,\n method: string,\n params: unknown[],\n): (state: TRootState) => RequestSelectorResult<TData> {\n const cacheKey = createCacheKey(method, params);\n\n let lastRequest: RequestState | undefined;\n let lastResult: RequestSelectorResult<TData> | null = null;\n\n return (state: TRootState): RequestSelectorResult<TData> => {\n const request = getState(state)?.requests?.[cacheKey];\n\n if (request === lastRequest && lastResult !== null) {\n return lastResult;\n }\n\n lastRequest = request;\n lastResult = {\n data: (request?.data as TData) ?? null,\n isFetching: request?.status === RequestStatus.LOADING,\n error: request?.error ?? null,\n };\n\n return lastResult;\n };\n}\n"]}
@@ -0,0 +1,75 @@
1
+ import type { RampsControllerState } from "./RampsController.cjs";
2
+ /**
3
+ * Result shape returned by request selectors.
4
+ *
5
+ * This object is memoized - the same reference is returned when the underlying
6
+ * request state hasn't changed, making it safe to use with React Redux's
7
+ * `useSelector` without `shallowEqual`.
8
+ */
9
+ export type RequestSelectorResult<TData> = {
10
+ /** The data returned by the request, or null if not yet loaded or on error. */
11
+ data: TData | null;
12
+ /** Whether the request is currently in progress. */
13
+ isFetching: boolean;
14
+ /** Error message if the request failed, or null if successful or not yet attempted. */
15
+ error: string | null;
16
+ };
17
+ /**
18
+ * Creates a memoized selector for a controller method's request state.
19
+ *
20
+ * This selector tracks the loading, error, and data state for a specific
21
+ * controller method call. It's optimized for use with React Redux's `useSelector`
22
+ * hook - the selector returns the same object reference when the underlying
23
+ * request state hasn't changed, so no `shallowEqual` is needed.
24
+ *
25
+ * The selector uses reference equality on the request object itself, so it
26
+ * works correctly with arrays and objects without expensive deep equality checks.
27
+ *
28
+ * @param getState - Function that extracts RampsControllerState from the root state.
29
+ * Typically a reselect selector like `selectRampsControllerState`.
30
+ * @param method - The controller method name (e.g., 'updateGeolocation').
31
+ * @param params - The parameters passed to the method, used to generate the cache key.
32
+ * Must match the params used when calling the controller method.
33
+ * @returns A selector function that returns `{ data, isFetching, error }`.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * // In selectors file - create once at module level
38
+ * import { createRequestSelector } from '@metamask/ramps-controller';
39
+ * import { createSelector } from 'reselect';
40
+ *
41
+ * const selectRampsControllerState = createSelector(
42
+ * (state: RootState) => state.engine.backgroundState.RampsController,
43
+ * (rampsControllerState) => rampsControllerState,
44
+ * );
45
+ *
46
+ * export const selectGeolocationRequest = createRequestSelector<
47
+ * RootState,
48
+ * string
49
+ * >(selectRampsControllerState, 'updateGeolocation', []);
50
+ *
51
+ * // In hook - use directly with useSelector, no shallowEqual needed
52
+ * export function useRampsGeolocation() {
53
+ * const { isFetching, error } = useSelector(selectGeolocationRequest);
54
+ * // ... rest of hook
55
+ * }
56
+ * ```
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * // For methods with parameters
61
+ * export const selectCryptoCurrenciesRequest = (region: string) =>
62
+ * createRequestSelector<RootState, CryptoCurrency[]>(
63
+ * selectRampsControllerState,
64
+ * 'getCryptoCurrencies',
65
+ * [region],
66
+ * );
67
+ *
68
+ * // In component
69
+ * const { data, isFetching, error } = useSelector(
70
+ * selectCryptoCurrenciesRequest('US')
71
+ * );
72
+ * ```
73
+ */
74
+ export declare function createRequestSelector<TRootState, TData>(getState: (rootState: TRootState) => RampsControllerState | undefined, method: string, params: unknown[]): (state: TRootState) => RequestSelectorResult<TData>;
75
+ //# sourceMappingURL=selectors.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.cts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,8BAA0B;AAI9D;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,CAAC,KAAK,IAAI;IACzC,+EAA+E;IAC/E,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC;IACnB,oDAAoD;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,uFAAuF;IACvF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,KAAK,EACrD,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,oBAAoB,GAAG,SAAS,EACrE,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EAAE,GAChB,CAAC,KAAK,EAAE,UAAU,KAAK,qBAAqB,CAAC,KAAK,CAAC,CAsBrD"}
@@ -0,0 +1,75 @@
1
+ import type { RampsControllerState } from "./RampsController.mjs";
2
+ /**
3
+ * Result shape returned by request selectors.
4
+ *
5
+ * This object is memoized - the same reference is returned when the underlying
6
+ * request state hasn't changed, making it safe to use with React Redux's
7
+ * `useSelector` without `shallowEqual`.
8
+ */
9
+ export type RequestSelectorResult<TData> = {
10
+ /** The data returned by the request, or null if not yet loaded or on error. */
11
+ data: TData | null;
12
+ /** Whether the request is currently in progress. */
13
+ isFetching: boolean;
14
+ /** Error message if the request failed, or null if successful or not yet attempted. */
15
+ error: string | null;
16
+ };
17
+ /**
18
+ * Creates a memoized selector for a controller method's request state.
19
+ *
20
+ * This selector tracks the loading, error, and data state for a specific
21
+ * controller method call. It's optimized for use with React Redux's `useSelector`
22
+ * hook - the selector returns the same object reference when the underlying
23
+ * request state hasn't changed, so no `shallowEqual` is needed.
24
+ *
25
+ * The selector uses reference equality on the request object itself, so it
26
+ * works correctly with arrays and objects without expensive deep equality checks.
27
+ *
28
+ * @param getState - Function that extracts RampsControllerState from the root state.
29
+ * Typically a reselect selector like `selectRampsControllerState`.
30
+ * @param method - The controller method name (e.g., 'updateGeolocation').
31
+ * @param params - The parameters passed to the method, used to generate the cache key.
32
+ * Must match the params used when calling the controller method.
33
+ * @returns A selector function that returns `{ data, isFetching, error }`.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * // In selectors file - create once at module level
38
+ * import { createRequestSelector } from '@metamask/ramps-controller';
39
+ * import { createSelector } from 'reselect';
40
+ *
41
+ * const selectRampsControllerState = createSelector(
42
+ * (state: RootState) => state.engine.backgroundState.RampsController,
43
+ * (rampsControllerState) => rampsControllerState,
44
+ * );
45
+ *
46
+ * export const selectGeolocationRequest = createRequestSelector<
47
+ * RootState,
48
+ * string
49
+ * >(selectRampsControllerState, 'updateGeolocation', []);
50
+ *
51
+ * // In hook - use directly with useSelector, no shallowEqual needed
52
+ * export function useRampsGeolocation() {
53
+ * const { isFetching, error } = useSelector(selectGeolocationRequest);
54
+ * // ... rest of hook
55
+ * }
56
+ * ```
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * // For methods with parameters
61
+ * export const selectCryptoCurrenciesRequest = (region: string) =>
62
+ * createRequestSelector<RootState, CryptoCurrency[]>(
63
+ * selectRampsControllerState,
64
+ * 'getCryptoCurrencies',
65
+ * [region],
66
+ * );
67
+ *
68
+ * // In component
69
+ * const { data, isFetching, error } = useSelector(
70
+ * selectCryptoCurrenciesRequest('US')
71
+ * );
72
+ * ```
73
+ */
74
+ export declare function createRequestSelector<TRootState, TData>(getState: (rootState: TRootState) => RampsControllerState | undefined, method: string, params: unknown[]): (state: TRootState) => RequestSelectorResult<TData>;
75
+ //# sourceMappingURL=selectors.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.mts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,8BAA0B;AAI9D;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,CAAC,KAAK,IAAI;IACzC,+EAA+E;IAC/E,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC;IACnB,oDAAoD;IACpD,UAAU,EAAE,OAAO,CAAC;IACpB,uFAAuF;IACvF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,KAAK,EACrD,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,KAAK,oBAAoB,GAAG,SAAS,EACrE,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EAAE,GAChB,CAAC,KAAK,EAAE,UAAU,KAAK,qBAAqB,CAAC,KAAK,CAAC,CAsBrD"}
@@ -0,0 +1,77 @@
1
+ import { RequestStatus, createCacheKey } from "./RequestCache.mjs";
2
+ /**
3
+ * Creates a memoized selector for a controller method's request state.
4
+ *
5
+ * This selector tracks the loading, error, and data state for a specific
6
+ * controller method call. It's optimized for use with React Redux's `useSelector`
7
+ * hook - the selector returns the same object reference when the underlying
8
+ * request state hasn't changed, so no `shallowEqual` is needed.
9
+ *
10
+ * The selector uses reference equality on the request object itself, so it
11
+ * works correctly with arrays and objects without expensive deep equality checks.
12
+ *
13
+ * @param getState - Function that extracts RampsControllerState from the root state.
14
+ * Typically a reselect selector like `selectRampsControllerState`.
15
+ * @param method - The controller method name (e.g., 'updateGeolocation').
16
+ * @param params - The parameters passed to the method, used to generate the cache key.
17
+ * Must match the params used when calling the controller method.
18
+ * @returns A selector function that returns `{ data, isFetching, error }`.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // In selectors file - create once at module level
23
+ * import { createRequestSelector } from '@metamask/ramps-controller';
24
+ * import { createSelector } from 'reselect';
25
+ *
26
+ * const selectRampsControllerState = createSelector(
27
+ * (state: RootState) => state.engine.backgroundState.RampsController,
28
+ * (rampsControllerState) => rampsControllerState,
29
+ * );
30
+ *
31
+ * export const selectGeolocationRequest = createRequestSelector<
32
+ * RootState,
33
+ * string
34
+ * >(selectRampsControllerState, 'updateGeolocation', []);
35
+ *
36
+ * // In hook - use directly with useSelector, no shallowEqual needed
37
+ * export function useRampsGeolocation() {
38
+ * const { isFetching, error } = useSelector(selectGeolocationRequest);
39
+ * // ... rest of hook
40
+ * }
41
+ * ```
42
+ *
43
+ * @example
44
+ * ```ts
45
+ * // For methods with parameters
46
+ * export const selectCryptoCurrenciesRequest = (region: string) =>
47
+ * createRequestSelector<RootState, CryptoCurrency[]>(
48
+ * selectRampsControllerState,
49
+ * 'getCryptoCurrencies',
50
+ * [region],
51
+ * );
52
+ *
53
+ * // In component
54
+ * const { data, isFetching, error } = useSelector(
55
+ * selectCryptoCurrenciesRequest('US')
56
+ * );
57
+ * ```
58
+ */
59
+ export function createRequestSelector(getState, method, params) {
60
+ const cacheKey = createCacheKey(method, params);
61
+ let lastRequest;
62
+ let lastResult = null;
63
+ return (state) => {
64
+ const request = getState(state)?.requests?.[cacheKey];
65
+ if (request === lastRequest && lastResult !== null) {
66
+ return lastResult;
67
+ }
68
+ lastRequest = request;
69
+ lastResult = {
70
+ data: request?.data ?? null,
71
+ isFetching: request?.status === RequestStatus.LOADING,
72
+ error: request?.error ?? null,
73
+ };
74
+ return lastResult;
75
+ };
76
+ }
77
+ //# sourceMappingURL=selectors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.mjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,2BAAuB;AAkB/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAqE,EACrE,MAAc,EACd,MAAiB;IAEjB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD,IAAI,WAAqC,CAAC;IAC1C,IAAI,UAAU,GAAwC,IAAI,CAAC;IAE3D,OAAO,CAAC,KAAiB,EAAgC,EAAE;QACzD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC;QAEtD,IAAI,OAAO,KAAK,WAAW,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACnD,OAAO,UAAU,CAAC;QACpB,CAAC;QAED,WAAW,GAAG,OAAO,CAAC;QACtB,UAAU,GAAG;YACX,IAAI,EAAG,OAAO,EAAE,IAAc,IAAI,IAAI;YACtC,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,aAAa,CAAC,OAAO;YACrD,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,IAAI;SAC9B,CAAC;QAEF,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { RampsControllerState } from './RampsController';\nimport type { RequestState } from './RequestCache';\nimport { RequestStatus, createCacheKey } from './RequestCache';\n\n/**\n * Result shape returned by request selectors.\n *\n * This object is memoized - the same reference is returned when the underlying\n * request state hasn't changed, making it safe to use with React Redux's\n * `useSelector` without `shallowEqual`.\n */\nexport type RequestSelectorResult<TData> = {\n /** The data returned by the request, or null if not yet loaded or on error. */\n data: TData | null;\n /** Whether the request is currently in progress. */\n isFetching: boolean;\n /** Error message if the request failed, or null if successful or not yet attempted. */\n error: string | null;\n};\n\n/**\n * Creates a memoized selector for a controller method's request state.\n *\n * This selector tracks the loading, error, and data state for a specific\n * controller method call. It's optimized for use with React Redux's `useSelector`\n * hook - the selector returns the same object reference when the underlying\n * request state hasn't changed, so no `shallowEqual` is needed.\n *\n * The selector uses reference equality on the request object itself, so it\n * works correctly with arrays and objects without expensive deep equality checks.\n *\n * @param getState - Function that extracts RampsControllerState from the root state.\n * Typically a reselect selector like `selectRampsControllerState`.\n * @param method - The controller method name (e.g., 'updateGeolocation').\n * @param params - The parameters passed to the method, used to generate the cache key.\n * Must match the params used when calling the controller method.\n * @returns A selector function that returns `{ data, isFetching, error }`.\n *\n * @example\n * ```ts\n * // In selectors file - create once at module level\n * import { createRequestSelector } from '@metamask/ramps-controller';\n * import { createSelector } from 'reselect';\n *\n * const selectRampsControllerState = createSelector(\n * (state: RootState) => state.engine.backgroundState.RampsController,\n * (rampsControllerState) => rampsControllerState,\n * );\n *\n * export const selectGeolocationRequest = createRequestSelector<\n * RootState,\n * string\n * >(selectRampsControllerState, 'updateGeolocation', []);\n *\n * // In hook - use directly with useSelector, no shallowEqual needed\n * export function useRampsGeolocation() {\n * const { isFetching, error } = useSelector(selectGeolocationRequest);\n * // ... rest of hook\n * }\n * ```\n *\n * @example\n * ```ts\n * // For methods with parameters\n * export const selectCryptoCurrenciesRequest = (region: string) =>\n * createRequestSelector<RootState, CryptoCurrency[]>(\n * selectRampsControllerState,\n * 'getCryptoCurrencies',\n * [region],\n * );\n *\n * // In component\n * const { data, isFetching, error } = useSelector(\n * selectCryptoCurrenciesRequest('US')\n * );\n * ```\n */\nexport function createRequestSelector<TRootState, TData>(\n getState: (rootState: TRootState) => RampsControllerState | undefined,\n method: string,\n params: unknown[],\n): (state: TRootState) => RequestSelectorResult<TData> {\n const cacheKey = createCacheKey(method, params);\n\n let lastRequest: RequestState | undefined;\n let lastResult: RequestSelectorResult<TData> | null = null;\n\n return (state: TRootState): RequestSelectorResult<TData> => {\n const request = getState(state)?.requests?.[cacheKey];\n\n if (request === lastRequest && lastResult !== null) {\n return lastResult;\n }\n\n lastRequest = request;\n lastResult = {\n data: (request?.data as TData) ?? null,\n isFetching: request?.status === RequestStatus.LOADING,\n error: request?.error ?? null,\n };\n\n return lastResult;\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/ramps-controller",
3
- "version": "2.0.0-preview-1d3aa020",
3
+ "version": "2.0.0-preview-67bc4e39",
4
4
  "description": "A controller for managing cryptocurrency on/off ramps functionality",
5
5
  "keywords": [
6
6
  "MetaMask",