@metamask-previews/geolocation-controller 0.1.0-preview-8c978cc75 → 0.1.1-preview-ccd74c3b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/dist/GeolocationController-method-action-types.cjs.map +1 -1
  3. package/dist/GeolocationController-method-action-types.d.cts +3 -3
  4. package/dist/GeolocationController-method-action-types.d.mts +3 -3
  5. package/dist/GeolocationController-method-action-types.mjs.map +1 -1
  6. package/dist/GeolocationController.cjs +4 -4
  7. package/dist/GeolocationController.cjs.map +1 -1
  8. package/dist/GeolocationController.d.cts +4 -4
  9. package/dist/GeolocationController.d.cts.map +1 -1
  10. package/dist/GeolocationController.d.mts +4 -4
  11. package/dist/GeolocationController.d.mts.map +1 -1
  12. package/dist/GeolocationController.mjs +4 -4
  13. package/dist/GeolocationController.mjs.map +1 -1
  14. package/dist/geolocation-api-service/geolocation-api-service-method-action-types.cjs.map +1 -1
  15. package/dist/geolocation-api-service/geolocation-api-service-method-action-types.d.cts +4 -4
  16. package/dist/geolocation-api-service/geolocation-api-service-method-action-types.d.mts +4 -4
  17. package/dist/geolocation-api-service/geolocation-api-service-method-action-types.mjs.map +1 -1
  18. package/dist/geolocation-api-service/geolocation-api-service.cjs +11 -8
  19. package/dist/geolocation-api-service/geolocation-api-service.cjs.map +1 -1
  20. package/dist/geolocation-api-service/geolocation-api-service.d.cts +7 -6
  21. package/dist/geolocation-api-service/geolocation-api-service.d.cts.map +1 -1
  22. package/dist/geolocation-api-service/geolocation-api-service.d.mts +7 -6
  23. package/dist/geolocation-api-service/geolocation-api-service.d.mts.map +1 -1
  24. package/dist/geolocation-api-service/geolocation-api-service.mjs +11 -8
  25. package/dist/geolocation-api-service/geolocation-api-service.mjs.map +1 -1
  26. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,11 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.1]
11
+
12
+ ### Fixed
13
+
14
+ - Accept ISO 3166-2 subdivision codes (e.g. `US-NY`, `CA-ON`) from the geolocation API, not just 2-letter country codes ([#8137](https://github.com/MetaMask/core/pull/8137))
15
+
10
16
  ## [0.1.0]
11
17
 
12
18
  ### Added
13
19
 
14
20
  - Initial release ([#8037](https://github.com/MetaMask/core/pull/8037))
15
21
 
16
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/geolocation-controller@0.1.0...HEAD
22
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/geolocation-controller@0.1.1...HEAD
23
+ [0.1.1]: https://github.com/MetaMask/core/compare/@metamask/geolocation-controller@0.1.0...@metamask/geolocation-controller@0.1.1
17
24
  [0.1.0]: https://github.com/MetaMask/core/releases/tag/@metamask/geolocation-controller@0.1.0
@@ -1 +1 @@
1
- {"version":3,"file":"GeolocationController-method-action-types.cjs","sourceRoot":"","sources":["../src/GeolocationController-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 { GeolocationController } from './GeolocationController';\n\n/**\n * Returns the geolocation country code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO country code string.\n */\nexport type GeolocationControllerGetGeolocationAction = {\n type: `GeolocationController:getGeolocation`;\n handler: GeolocationController['getGeolocation'];\n};\n\n/**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO country code string.\n */\nexport type GeolocationControllerRefreshGeolocationAction = {\n type: `GeolocationController:refreshGeolocation`;\n handler: GeolocationController['refreshGeolocation'];\n};\n\n/**\n * Union of all GeolocationController action types.\n */\nexport type GeolocationControllerMethodActions =\n | GeolocationControllerGetGeolocationAction\n | GeolocationControllerRefreshGeolocationAction;\n"]}
1
+ {"version":3,"file":"GeolocationController-method-action-types.cjs","sourceRoot":"","sources":["../src/GeolocationController-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 { GeolocationController } from './GeolocationController';\n\n/**\n * Returns the geolocation code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO 3166-2 location code string.\n */\nexport type GeolocationControllerGetGeolocationAction = {\n type: `GeolocationController:getGeolocation`;\n handler: GeolocationController['getGeolocation'];\n};\n\n/**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO 3166-2 location code string.\n */\nexport type GeolocationControllerRefreshGeolocationAction = {\n type: `GeolocationController:refreshGeolocation`;\n handler: GeolocationController['refreshGeolocation'];\n};\n\n/**\n * Union of all GeolocationController action types.\n */\nexport type GeolocationControllerMethodActions =\n | GeolocationControllerGetGeolocationAction\n | GeolocationControllerRefreshGeolocationAction;\n"]}
@@ -4,11 +4,11 @@
4
4
  */
5
5
  import type { GeolocationController } from "./GeolocationController.cjs";
6
6
  /**
7
- * Returns the geolocation country code. Delegates to the
7
+ * Returns the geolocation code. Delegates to the
8
8
  * {@link GeolocationApiService} for network fetching and caching, then
9
9
  * updates controller state with the result.
10
10
  *
11
- * @returns The ISO country code string.
11
+ * @returns The ISO 3166-2 location code string.
12
12
  */
13
13
  export type GeolocationControllerGetGeolocationAction = {
14
14
  type: `GeolocationController:getGeolocation`;
@@ -17,7 +17,7 @@ export type GeolocationControllerGetGeolocationAction = {
17
17
  /**
18
18
  * Forces a fresh geolocation fetch, bypassing the service's cache.
19
19
  *
20
- * @returns The ISO country code string.
20
+ * @returns The ISO 3166-2 location code string.
21
21
  */
22
22
  export type GeolocationControllerRefreshGeolocationAction = {
23
23
  type: `GeolocationController:refreshGeolocation`;
@@ -4,11 +4,11 @@
4
4
  */
5
5
  import type { GeolocationController } from "./GeolocationController.mjs";
6
6
  /**
7
- * Returns the geolocation country code. Delegates to the
7
+ * Returns the geolocation code. Delegates to the
8
8
  * {@link GeolocationApiService} for network fetching and caching, then
9
9
  * updates controller state with the result.
10
10
  *
11
- * @returns The ISO country code string.
11
+ * @returns The ISO 3166-2 location code string.
12
12
  */
13
13
  export type GeolocationControllerGetGeolocationAction = {
14
14
  type: `GeolocationController:getGeolocation`;
@@ -17,7 +17,7 @@ export type GeolocationControllerGetGeolocationAction = {
17
17
  /**
18
18
  * Forces a fresh geolocation fetch, bypassing the service's cache.
19
19
  *
20
- * @returns The ISO country code string.
20
+ * @returns The ISO 3166-2 location code string.
21
21
  */
22
22
  export type GeolocationControllerRefreshGeolocationAction = {
23
23
  type: `GeolocationController:refreshGeolocation`;
@@ -1 +1 @@
1
- {"version":3,"file":"GeolocationController-method-action-types.mjs","sourceRoot":"","sources":["../src/GeolocationController-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 { GeolocationController } from './GeolocationController';\n\n/**\n * Returns the geolocation country code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO country code string.\n */\nexport type GeolocationControllerGetGeolocationAction = {\n type: `GeolocationController:getGeolocation`;\n handler: GeolocationController['getGeolocation'];\n};\n\n/**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO country code string.\n */\nexport type GeolocationControllerRefreshGeolocationAction = {\n type: `GeolocationController:refreshGeolocation`;\n handler: GeolocationController['refreshGeolocation'];\n};\n\n/**\n * Union of all GeolocationController action types.\n */\nexport type GeolocationControllerMethodActions =\n | GeolocationControllerGetGeolocationAction\n | GeolocationControllerRefreshGeolocationAction;\n"]}
1
+ {"version":3,"file":"GeolocationController-method-action-types.mjs","sourceRoot":"","sources":["../src/GeolocationController-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 { GeolocationController } from './GeolocationController';\n\n/**\n * Returns the geolocation code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO 3166-2 location code string.\n */\nexport type GeolocationControllerGetGeolocationAction = {\n type: `GeolocationController:getGeolocation`;\n handler: GeolocationController['getGeolocation'];\n};\n\n/**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO 3166-2 location code string.\n */\nexport type GeolocationControllerRefreshGeolocationAction = {\n type: `GeolocationController:refreshGeolocation`;\n handler: GeolocationController['refreshGeolocation'];\n};\n\n/**\n * Union of all GeolocationController action types.\n */\nexport type GeolocationControllerMethodActions =\n | GeolocationControllerGetGeolocationAction\n | GeolocationControllerRefreshGeolocationAction;\n"]}
@@ -96,11 +96,11 @@ class GeolocationController extends base_controller_1.BaseController {
96
96
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
97
97
  }
98
98
  /**
99
- * Returns the geolocation country code. Delegates to the
99
+ * Returns the geolocation code. Delegates to the
100
100
  * {@link GeolocationApiService} for network fetching and caching, then
101
101
  * updates controller state with the result.
102
102
  *
103
- * @returns The ISO country code string.
103
+ * @returns The ISO 3166-2 location code string.
104
104
  */
105
105
  async getGeolocation() {
106
106
  return __classPrivateFieldGet(this, _GeolocationController_instances, "m", _GeolocationController_fetchAndUpdate).call(this);
@@ -108,7 +108,7 @@ class GeolocationController extends base_controller_1.BaseController {
108
108
  /**
109
109
  * Forces a fresh geolocation fetch, bypassing the service's cache.
110
110
  *
111
- * @returns The ISO country code string.
111
+ * @returns The ISO 3166-2 location code string.
112
112
  */
113
113
  async refreshGeolocation() {
114
114
  this.update((draft) => {
@@ -125,7 +125,7 @@ _GeolocationController_instances = new WeakSet(), _GeolocationController_fetchAn
125
125
  *
126
126
  * @param options - Options forwarded to the service.
127
127
  * @param options.bypassCache - When true, the service skips its TTL cache.
128
- * @returns The ISO country code string.
128
+ * @returns The ISO 3166-2 location code string.
129
129
  */
130
130
  async function _GeolocationController_fetchAndUpdate(options) {
131
131
  this.update((draft) => {
@@ -1 +1 @@
1
- {"version":3,"file":"GeolocationController.cjs","sourceRoot":"","sources":["../src/GeolocationController.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';\n\nimport { UNKNOWN_LOCATION } from './geolocation-api-service/geolocation-api-service';\nimport type { GeolocationApiServiceFetchGeolocationAction } from './geolocation-api-service/geolocation-api-service-method-action-types';\nimport type { GeolocationControllerMethodActions } from './GeolocationController-method-action-types';\nimport type { GeolocationRequestStatus } from './types';\n\n/**\n * The name of the {@link GeolocationController}, 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 = 'GeolocationController';\n\n/**\n * State for the {@link GeolocationController}.\n */\nexport type GeolocationControllerState = {\n /** ISO 3166-1 alpha-2 country code, or \"UNKNOWN\" if not yet determined. */\n location: string;\n /** Current status of the geolocation fetch lifecycle. */\n status: GeolocationRequestStatus;\n /** Epoch milliseconds of the last successful fetch, or null if never fetched. */\n lastFetchedAt: number | null;\n /** Last error message, or null if no error has occurred. */\n error: string | null;\n};\n\n/**\n * The metadata for each property in {@link GeolocationControllerState}.\n */\nconst geolocationControllerMetadata = {\n location: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n status: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n lastFetchedAt: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n error: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<GeolocationControllerState>;\n\n/**\n * Constructs the default {@link GeolocationController} 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 GeolocationController} state.\n */\nexport function getDefaultGeolocationControllerState(): GeolocationControllerState {\n return {\n location: UNKNOWN_LOCATION,\n status: 'idle',\n lastFetchedAt: null,\n error: null,\n };\n}\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getGeolocation',\n 'refreshGeolocation',\n] as const;\n\n/**\n * Retrieves the state of the {@link GeolocationController}.\n */\nexport type GeolocationControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Actions that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerActions =\n | GeolocationControllerGetStateAction\n | GeolocationControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationControllerMessenger} calls.\n */\ntype AllowedActions = GeolocationApiServiceFetchGeolocationAction;\n\n/**\n * Published when the state of {@link GeolocationController} changes.\n */\nexport type GeolocationControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Events that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerEvents = GeolocationControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link GeolocationControllerMessenger}\n * subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationController}.\n */\nexport type GeolocationControllerMessenger = Messenger<\n typeof controllerName,\n GeolocationControllerActions | AllowedActions,\n GeolocationControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link GeolocationController}.\n */\nexport type GeolocationControllerOptions = {\n /** The messenger for inter-controller communication. */\n messenger: GeolocationControllerMessenger;\n /** Optional partial initial state. */\n state?: Partial<GeolocationControllerState>;\n};\n\n/**\n * GeolocationController manages UI-facing geolocation state by delegating\n * the actual API interaction to {@link GeolocationApiService} via the\n * messenger.\n *\n * The service (registered externally as\n * `GeolocationApiService:fetchGeolocation`) handles HTTP requests, response\n * validation, TTL caching, and promise deduplication. This controller focuses\n * on state lifecycle (`idle` -> `loading` -> `complete` | `error`) and\n * exposes `getGeolocation` / `refreshGeolocation` as messenger actions.\n */\nexport class GeolocationController extends BaseController<\n typeof controllerName,\n GeolocationControllerState,\n GeolocationControllerMessenger\n> {\n /**\n * Constructs a new {@link GeolocationController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller. Must\n * have a `GeolocationApiService:fetchGeolocation` action handler registered.\n * @param args.state - Optional partial initial state.\n */\n constructor({ messenger, state }: GeolocationControllerOptions) {\n super({\n messenger,\n metadata: geolocationControllerMetadata,\n name: controllerName,\n state: { ...getDefaultGeolocationControllerState(), ...state },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Returns the geolocation country code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO country code string.\n */\n async getGeolocation(): Promise<string> {\n return this.#fetchAndUpdate();\n }\n\n /**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO country code string.\n */\n async refreshGeolocation(): Promise<string> {\n this.update((draft) => {\n draft.lastFetchedAt = null;\n });\n return this.#fetchAndUpdate({ bypassCache: true });\n }\n\n /**\n * Calls the geolocation service and updates controller state with the\n * result.\n *\n * @param options - Options forwarded to the service.\n * @param options.bypassCache - When true, the service skips its TTL cache.\n * @returns The ISO country code string.\n */\n async #fetchAndUpdate(options?: { bypassCache?: boolean }): Promise<string> {\n this.update((draft) => {\n draft.status = 'loading';\n draft.error = null;\n });\n\n try {\n const location = await this.messenger.call(\n 'GeolocationApiService:fetchGeolocation',\n options,\n );\n\n this.update((draft) => {\n draft.location = location;\n draft.status = 'complete';\n draft.lastFetchedAt = Date.now();\n draft.error = null;\n });\n\n return location;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n this.update((draft) => {\n draft.status = 'error';\n draft.error = message;\n });\n\n return this.state.location;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"GeolocationController.cjs","sourceRoot":"","sources":["../src/GeolocationController.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';\n\nimport { UNKNOWN_LOCATION } from './geolocation-api-service/geolocation-api-service';\nimport type { GeolocationApiServiceFetchGeolocationAction } from './geolocation-api-service/geolocation-api-service-method-action-types';\nimport type { GeolocationControllerMethodActions } from './GeolocationController-method-action-types';\nimport type { GeolocationRequestStatus } from './types';\n\n/**\n * The name of the {@link GeolocationController}, 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 = 'GeolocationController';\n\n/**\n * State for the {@link GeolocationController}.\n */\nexport type GeolocationControllerState = {\n /** ISO 3166-2 location code (e.g. \"US\", \"US-NY\", \"CA-ON\"), or \"UNKNOWN\" if not yet determined. */\n location: string;\n /** Current status of the geolocation fetch lifecycle. */\n status: GeolocationRequestStatus;\n /** Epoch milliseconds of the last successful fetch, or null if never fetched. */\n lastFetchedAt: number | null;\n /** Last error message, or null if no error has occurred. */\n error: string | null;\n};\n\n/**\n * The metadata for each property in {@link GeolocationControllerState}.\n */\nconst geolocationControllerMetadata = {\n location: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n status: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n lastFetchedAt: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n error: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<GeolocationControllerState>;\n\n/**\n * Constructs the default {@link GeolocationController} 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 GeolocationController} state.\n */\nexport function getDefaultGeolocationControllerState(): GeolocationControllerState {\n return {\n location: UNKNOWN_LOCATION,\n status: 'idle',\n lastFetchedAt: null,\n error: null,\n };\n}\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getGeolocation',\n 'refreshGeolocation',\n] as const;\n\n/**\n * Retrieves the state of the {@link GeolocationController}.\n */\nexport type GeolocationControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Actions that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerActions =\n | GeolocationControllerGetStateAction\n | GeolocationControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationControllerMessenger} calls.\n */\ntype AllowedActions = GeolocationApiServiceFetchGeolocationAction;\n\n/**\n * Published when the state of {@link GeolocationController} changes.\n */\nexport type GeolocationControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Events that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerEvents = GeolocationControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link GeolocationControllerMessenger}\n * subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationController}.\n */\nexport type GeolocationControllerMessenger = Messenger<\n typeof controllerName,\n GeolocationControllerActions | AllowedActions,\n GeolocationControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link GeolocationController}.\n */\nexport type GeolocationControllerOptions = {\n /** The messenger for inter-controller communication. */\n messenger: GeolocationControllerMessenger;\n /** Optional partial initial state. */\n state?: Partial<GeolocationControllerState>;\n};\n\n/**\n * GeolocationController manages UI-facing geolocation state by delegating\n * the actual API interaction to {@link GeolocationApiService} via the\n * messenger.\n *\n * The service (registered externally as\n * `GeolocationApiService:fetchGeolocation`) handles HTTP requests, response\n * validation, TTL caching, and promise deduplication. This controller focuses\n * on state lifecycle (`idle` -> `loading` -> `complete` | `error`) and\n * exposes `getGeolocation` / `refreshGeolocation` as messenger actions.\n */\nexport class GeolocationController extends BaseController<\n typeof controllerName,\n GeolocationControllerState,\n GeolocationControllerMessenger\n> {\n /**\n * Constructs a new {@link GeolocationController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller. Must\n * have a `GeolocationApiService:fetchGeolocation` action handler registered.\n * @param args.state - Optional partial initial state.\n */\n constructor({ messenger, state }: GeolocationControllerOptions) {\n super({\n messenger,\n metadata: geolocationControllerMetadata,\n name: controllerName,\n state: { ...getDefaultGeolocationControllerState(), ...state },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Returns the geolocation code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO 3166-2 location code string.\n */\n async getGeolocation(): Promise<string> {\n return this.#fetchAndUpdate();\n }\n\n /**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO 3166-2 location code string.\n */\n async refreshGeolocation(): Promise<string> {\n this.update((draft) => {\n draft.lastFetchedAt = null;\n });\n return this.#fetchAndUpdate({ bypassCache: true });\n }\n\n /**\n * Calls the geolocation service and updates controller state with the\n * result.\n *\n * @param options - Options forwarded to the service.\n * @param options.bypassCache - When true, the service skips its TTL cache.\n * @returns The ISO 3166-2 location code string.\n */\n async #fetchAndUpdate(options?: { bypassCache?: boolean }): Promise<string> {\n this.update((draft) => {\n draft.status = 'loading';\n draft.error = null;\n });\n\n try {\n const location = await this.messenger.call(\n 'GeolocationApiService:fetchGeolocation',\n options,\n );\n\n this.update((draft) => {\n draft.location = location;\n draft.status = 'complete';\n draft.lastFetchedAt = Date.now();\n draft.error = null;\n });\n\n return location;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n this.update((draft) => {\n draft.status = 'error';\n draft.error = message;\n });\n\n return this.state.location;\n }\n }\n}\n"]}
@@ -14,7 +14,7 @@ export declare const controllerName = "GeolocationController";
14
14
  * State for the {@link GeolocationController}.
15
15
  */
16
16
  export type GeolocationControllerState = {
17
- /** ISO 3166-1 alpha-2 country code, or "UNKNOWN" if not yet determined. */
17
+ /** ISO 3166-2 location code (e.g. "US", "US-NY", "CA-ON"), or "UNKNOWN" if not yet determined. */
18
18
  location: string;
19
19
  /** Current status of the geolocation fetch lifecycle. */
20
20
  status: GeolocationRequestStatus;
@@ -94,17 +94,17 @@ export declare class GeolocationController extends BaseController<typeof control
94
94
  */
95
95
  constructor({ messenger, state }: GeolocationControllerOptions);
96
96
  /**
97
- * Returns the geolocation country code. Delegates to the
97
+ * Returns the geolocation code. Delegates to the
98
98
  * {@link GeolocationApiService} for network fetching and caching, then
99
99
  * updates controller state with the result.
100
100
  *
101
- * @returns The ISO country code string.
101
+ * @returns The ISO 3166-2 location code string.
102
102
  */
103
103
  getGeolocation(): Promise<string>;
104
104
  /**
105
105
  * Forces a fresh geolocation fetch, bypassing the service's cache.
106
106
  *
107
- * @returns The ISO country code string.
107
+ * @returns The ISO 3166-2 location code string.
108
108
  */
109
109
  refreshGeolocation(): Promise<string>;
110
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GeolocationController.d.cts","sourceRoot":"","sources":["../src/GeolocationController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EAAE,2CAA2C,EAAE,kFAA8E;AACzI,OAAO,KAAK,EAAE,kCAAkC,EAAE,wDAAoD;AACtG,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAgB;AAExD;;;;GAIG;AACH,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,MAAM,EAAE,wBAAwB,CAAC;IACjC,iFAAiF;IACjF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,oCAAoC,IAAI,0BAA0B,CAOjF;AAOD;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAAG,wBAAwB,CACxE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GACpC,mCAAmC,GACnC,kCAAkC,CAAC;AAEvC;;GAEG;AACH,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,cAAc,EACrB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,wDAAwD;IACxD,SAAS,EAAE,8BAA8B,CAAC;IAC1C,sCAAsC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CACvD,OAAO,cAAc,EACrB,0BAA0B,EAC1B,8BAA8B,CAC/B;;IACC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,4BAA4B;IAc9D;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvC;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;CA8C5C"}
1
+ {"version":3,"file":"GeolocationController.d.cts","sourceRoot":"","sources":["../src/GeolocationController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EAAE,2CAA2C,EAAE,kFAA8E;AACzI,OAAO,KAAK,EAAE,kCAAkC,EAAE,wDAAoD;AACtG,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAgB;AAExD;;;;GAIG;AACH,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,MAAM,EAAE,wBAAwB,CAAC;IACjC,iFAAiF;IACjF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,oCAAoC,IAAI,0BAA0B,CAOjF;AAOD;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAAG,wBAAwB,CACxE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GACpC,mCAAmC,GACnC,kCAAkC,CAAC;AAEvC;;GAEG;AACH,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,cAAc,EACrB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,wDAAwD;IACxD,SAAS,EAAE,8BAA8B,CAAC;IAC1C,sCAAsC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CACvD,OAAO,cAAc,EACrB,0BAA0B,EAC1B,8BAA8B,CAC/B;;IACC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,4BAA4B;IAc9D;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvC;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;CA8C5C"}
@@ -14,7 +14,7 @@ export declare const controllerName = "GeolocationController";
14
14
  * State for the {@link GeolocationController}.
15
15
  */
16
16
  export type GeolocationControllerState = {
17
- /** ISO 3166-1 alpha-2 country code, or "UNKNOWN" if not yet determined. */
17
+ /** ISO 3166-2 location code (e.g. "US", "US-NY", "CA-ON"), or "UNKNOWN" if not yet determined. */
18
18
  location: string;
19
19
  /** Current status of the geolocation fetch lifecycle. */
20
20
  status: GeolocationRequestStatus;
@@ -94,17 +94,17 @@ export declare class GeolocationController extends BaseController<typeof control
94
94
  */
95
95
  constructor({ messenger, state }: GeolocationControllerOptions);
96
96
  /**
97
- * Returns the geolocation country code. Delegates to the
97
+ * Returns the geolocation code. Delegates to the
98
98
  * {@link GeolocationApiService} for network fetching and caching, then
99
99
  * updates controller state with the result.
100
100
  *
101
- * @returns The ISO country code string.
101
+ * @returns The ISO 3166-2 location code string.
102
102
  */
103
103
  getGeolocation(): Promise<string>;
104
104
  /**
105
105
  * Forces a fresh geolocation fetch, bypassing the service's cache.
106
106
  *
107
- * @returns The ISO country code string.
107
+ * @returns The ISO 3166-2 location code string.
108
108
  */
109
109
  refreshGeolocation(): Promise<string>;
110
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"GeolocationController.d.mts","sourceRoot":"","sources":["../src/GeolocationController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EAAE,2CAA2C,EAAE,kFAA8E;AACzI,OAAO,KAAK,EAAE,kCAAkC,EAAE,wDAAoD;AACtG,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAgB;AAExD;;;;GAIG;AACH,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,MAAM,EAAE,wBAAwB,CAAC;IACjC,iFAAiF;IACjF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,oCAAoC,IAAI,0BAA0B,CAOjF;AAOD;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAAG,wBAAwB,CACxE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GACpC,mCAAmC,GACnC,kCAAkC,CAAC;AAEvC;;GAEG;AACH,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,cAAc,EACrB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,wDAAwD;IACxD,SAAS,EAAE,8BAA8B,CAAC;IAC1C,sCAAsC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CACvD,OAAO,cAAc,EACrB,0BAA0B,EAC1B,8BAA8B,CAC/B;;IACC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,4BAA4B;IAc9D;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvC;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;CA8C5C"}
1
+ {"version":3,"file":"GeolocationController.d.mts","sourceRoot":"","sources":["../src/GeolocationController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAGrD,OAAO,KAAK,EAAE,2CAA2C,EAAE,kFAA8E;AACzI,OAAO,KAAK,EAAE,kCAAkC,EAAE,wDAAoD;AACtG,OAAO,KAAK,EAAE,wBAAwB,EAAE,oBAAgB;AAExD;;;;GAIG;AACH,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,MAAM,EAAE,wBAAwB,CAAC;IACjC,iFAAiF;IACjF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAgCF;;;;;;;GAOG;AACH,wBAAgB,oCAAoC,IAAI,0BAA0B,CAOjF;AAOD;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAAG,wBAAwB,CACxE,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GACpC,mCAAmC,GACnC,kCAAkC,CAAC;AAEvC;;GAEG;AACH,KAAK,cAAc,GAAG,2CAA2C,CAAC;AAElE;;GAEG;AACH,MAAM,MAAM,qCAAqC,GAAG,0BAA0B,CAC5E,OAAO,cAAc,EACrB,0BAA0B,CAC3B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAC;AAEhF;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,cAAc,EACrB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG;IACzC,wDAAwD;IACxD,SAAS,EAAE,8BAA8B,CAAC;IAC1C,sCAAsC;IACtC,KAAK,CAAC,EAAE,OAAO,CAAC,0BAA0B,CAAC,CAAC;CAC7C,CAAC;AAEF;;;;;;;;;;GAUG;AACH,qBAAa,qBAAsB,SAAQ,cAAc,CACvD,OAAO,cAAc,EACrB,0BAA0B,EAC1B,8BAA8B,CAC/B;;IACC;;;;;;;OAOG;gBACS,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,4BAA4B;IAc9D;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAIvC;;;;OAIG;IACG,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC;CA8C5C"}
@@ -92,11 +92,11 @@ export class GeolocationController extends BaseController {
92
92
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
93
93
  }
94
94
  /**
95
- * Returns the geolocation country code. Delegates to the
95
+ * Returns the geolocation code. Delegates to the
96
96
  * {@link GeolocationApiService} for network fetching and caching, then
97
97
  * updates controller state with the result.
98
98
  *
99
- * @returns The ISO country code string.
99
+ * @returns The ISO 3166-2 location code string.
100
100
  */
101
101
  async getGeolocation() {
102
102
  return __classPrivateFieldGet(this, _GeolocationController_instances, "m", _GeolocationController_fetchAndUpdate).call(this);
@@ -104,7 +104,7 @@ export class GeolocationController extends BaseController {
104
104
  /**
105
105
  * Forces a fresh geolocation fetch, bypassing the service's cache.
106
106
  *
107
- * @returns The ISO country code string.
107
+ * @returns The ISO 3166-2 location code string.
108
108
  */
109
109
  async refreshGeolocation() {
110
110
  this.update((draft) => {
@@ -120,7 +120,7 @@ _GeolocationController_instances = new WeakSet(), _GeolocationController_fetchAn
120
120
  *
121
121
  * @param options - Options forwarded to the service.
122
122
  * @param options.bypassCache - When true, the service skips its TTL cache.
123
- * @returns The ISO country code string.
123
+ * @returns The ISO 3166-2 location code string.
124
124
  */
125
125
  async function _GeolocationController_fetchAndUpdate(options) {
126
126
  this.update((draft) => {
@@ -1 +1 @@
1
- {"version":3,"file":"GeolocationController.mjs","sourceRoot":"","sources":["../src/GeolocationController.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';\n\nimport { UNKNOWN_LOCATION } from './geolocation-api-service/geolocation-api-service';\nimport type { GeolocationApiServiceFetchGeolocationAction } from './geolocation-api-service/geolocation-api-service-method-action-types';\nimport type { GeolocationControllerMethodActions } from './GeolocationController-method-action-types';\nimport type { GeolocationRequestStatus } from './types';\n\n/**\n * The name of the {@link GeolocationController}, 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 = 'GeolocationController';\n\n/**\n * State for the {@link GeolocationController}.\n */\nexport type GeolocationControllerState = {\n /** ISO 3166-1 alpha-2 country code, or \"UNKNOWN\" if not yet determined. */\n location: string;\n /** Current status of the geolocation fetch lifecycle. */\n status: GeolocationRequestStatus;\n /** Epoch milliseconds of the last successful fetch, or null if never fetched. */\n lastFetchedAt: number | null;\n /** Last error message, or null if no error has occurred. */\n error: string | null;\n};\n\n/**\n * The metadata for each property in {@link GeolocationControllerState}.\n */\nconst geolocationControllerMetadata = {\n location: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n status: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n lastFetchedAt: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n error: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<GeolocationControllerState>;\n\n/**\n * Constructs the default {@link GeolocationController} 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 GeolocationController} state.\n */\nexport function getDefaultGeolocationControllerState(): GeolocationControllerState {\n return {\n location: UNKNOWN_LOCATION,\n status: 'idle',\n lastFetchedAt: null,\n error: null,\n };\n}\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getGeolocation',\n 'refreshGeolocation',\n] as const;\n\n/**\n * Retrieves the state of the {@link GeolocationController}.\n */\nexport type GeolocationControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Actions that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerActions =\n | GeolocationControllerGetStateAction\n | GeolocationControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationControllerMessenger} calls.\n */\ntype AllowedActions = GeolocationApiServiceFetchGeolocationAction;\n\n/**\n * Published when the state of {@link GeolocationController} changes.\n */\nexport type GeolocationControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Events that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerEvents = GeolocationControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link GeolocationControllerMessenger}\n * subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationController}.\n */\nexport type GeolocationControllerMessenger = Messenger<\n typeof controllerName,\n GeolocationControllerActions | AllowedActions,\n GeolocationControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link GeolocationController}.\n */\nexport type GeolocationControllerOptions = {\n /** The messenger for inter-controller communication. */\n messenger: GeolocationControllerMessenger;\n /** Optional partial initial state. */\n state?: Partial<GeolocationControllerState>;\n};\n\n/**\n * GeolocationController manages UI-facing geolocation state by delegating\n * the actual API interaction to {@link GeolocationApiService} via the\n * messenger.\n *\n * The service (registered externally as\n * `GeolocationApiService:fetchGeolocation`) handles HTTP requests, response\n * validation, TTL caching, and promise deduplication. This controller focuses\n * on state lifecycle (`idle` -> `loading` -> `complete` | `error`) and\n * exposes `getGeolocation` / `refreshGeolocation` as messenger actions.\n */\nexport class GeolocationController extends BaseController<\n typeof controllerName,\n GeolocationControllerState,\n GeolocationControllerMessenger\n> {\n /**\n * Constructs a new {@link GeolocationController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller. Must\n * have a `GeolocationApiService:fetchGeolocation` action handler registered.\n * @param args.state - Optional partial initial state.\n */\n constructor({ messenger, state }: GeolocationControllerOptions) {\n super({\n messenger,\n metadata: geolocationControllerMetadata,\n name: controllerName,\n state: { ...getDefaultGeolocationControllerState(), ...state },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Returns the geolocation country code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO country code string.\n */\n async getGeolocation(): Promise<string> {\n return this.#fetchAndUpdate();\n }\n\n /**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO country code string.\n */\n async refreshGeolocation(): Promise<string> {\n this.update((draft) => {\n draft.lastFetchedAt = null;\n });\n return this.#fetchAndUpdate({ bypassCache: true });\n }\n\n /**\n * Calls the geolocation service and updates controller state with the\n * result.\n *\n * @param options - Options forwarded to the service.\n * @param options.bypassCache - When true, the service skips its TTL cache.\n * @returns The ISO country code string.\n */\n async #fetchAndUpdate(options?: { bypassCache?: boolean }): Promise<string> {\n this.update((draft) => {\n draft.status = 'loading';\n draft.error = null;\n });\n\n try {\n const location = await this.messenger.call(\n 'GeolocationApiService:fetchGeolocation',\n options,\n );\n\n this.update((draft) => {\n draft.location = location;\n draft.status = 'complete';\n draft.lastFetchedAt = Date.now();\n draft.error = null;\n });\n\n return location;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n this.update((draft) => {\n draft.status = 'error';\n draft.error = message;\n });\n\n return this.state.location;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"GeolocationController.mjs","sourceRoot":"","sources":["../src/GeolocationController.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';\n\nimport { UNKNOWN_LOCATION } from './geolocation-api-service/geolocation-api-service';\nimport type { GeolocationApiServiceFetchGeolocationAction } from './geolocation-api-service/geolocation-api-service-method-action-types';\nimport type { GeolocationControllerMethodActions } from './GeolocationController-method-action-types';\nimport type { GeolocationRequestStatus } from './types';\n\n/**\n * The name of the {@link GeolocationController}, 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 = 'GeolocationController';\n\n/**\n * State for the {@link GeolocationController}.\n */\nexport type GeolocationControllerState = {\n /** ISO 3166-2 location code (e.g. \"US\", \"US-NY\", \"CA-ON\"), or \"UNKNOWN\" if not yet determined. */\n location: string;\n /** Current status of the geolocation fetch lifecycle. */\n status: GeolocationRequestStatus;\n /** Epoch milliseconds of the last successful fetch, or null if never fetched. */\n lastFetchedAt: number | null;\n /** Last error message, or null if no error has occurred. */\n error: string | null;\n};\n\n/**\n * The metadata for each property in {@link GeolocationControllerState}.\n */\nconst geolocationControllerMetadata = {\n location: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n status: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: true,\n },\n lastFetchedAt: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n error: {\n persist: false,\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<GeolocationControllerState>;\n\n/**\n * Constructs the default {@link GeolocationController} 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 GeolocationController} state.\n */\nexport function getDefaultGeolocationControllerState(): GeolocationControllerState {\n return {\n location: UNKNOWN_LOCATION,\n status: 'idle',\n lastFetchedAt: null,\n error: null,\n };\n}\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'getGeolocation',\n 'refreshGeolocation',\n] as const;\n\n/**\n * Retrieves the state of the {@link GeolocationController}.\n */\nexport type GeolocationControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Actions that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerActions =\n | GeolocationControllerGetStateAction\n | GeolocationControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationControllerMessenger} calls.\n */\ntype AllowedActions = GeolocationApiServiceFetchGeolocationAction;\n\n/**\n * Published when the state of {@link GeolocationController} changes.\n */\nexport type GeolocationControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n GeolocationControllerState\n>;\n\n/**\n * Events that {@link GeolocationControllerMessenger} exposes to other consumers.\n */\nexport type GeolocationControllerEvents = GeolocationControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link GeolocationControllerMessenger}\n * subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationController}.\n */\nexport type GeolocationControllerMessenger = Messenger<\n typeof controllerName,\n GeolocationControllerActions | AllowedActions,\n GeolocationControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing the {@link GeolocationController}.\n */\nexport type GeolocationControllerOptions = {\n /** The messenger for inter-controller communication. */\n messenger: GeolocationControllerMessenger;\n /** Optional partial initial state. */\n state?: Partial<GeolocationControllerState>;\n};\n\n/**\n * GeolocationController manages UI-facing geolocation state by delegating\n * the actual API interaction to {@link GeolocationApiService} via the\n * messenger.\n *\n * The service (registered externally as\n * `GeolocationApiService:fetchGeolocation`) handles HTTP requests, response\n * validation, TTL caching, and promise deduplication. This controller focuses\n * on state lifecycle (`idle` -> `loading` -> `complete` | `error`) and\n * exposes `getGeolocation` / `refreshGeolocation` as messenger actions.\n */\nexport class GeolocationController extends BaseController<\n typeof controllerName,\n GeolocationControllerState,\n GeolocationControllerMessenger\n> {\n /**\n * Constructs a new {@link GeolocationController}.\n *\n * @param args - The arguments to this controller.\n * @param args.messenger - The messenger suited for this controller. Must\n * have a `GeolocationApiService:fetchGeolocation` action handler registered.\n * @param args.state - Optional partial initial state.\n */\n constructor({ messenger, state }: GeolocationControllerOptions) {\n super({\n messenger,\n metadata: geolocationControllerMetadata,\n name: controllerName,\n state: { ...getDefaultGeolocationControllerState(), ...state },\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Returns the geolocation code. Delegates to the\n * {@link GeolocationApiService} for network fetching and caching, then\n * updates controller state with the result.\n *\n * @returns The ISO 3166-2 location code string.\n */\n async getGeolocation(): Promise<string> {\n return this.#fetchAndUpdate();\n }\n\n /**\n * Forces a fresh geolocation fetch, bypassing the service's cache.\n *\n * @returns The ISO 3166-2 location code string.\n */\n async refreshGeolocation(): Promise<string> {\n this.update((draft) => {\n draft.lastFetchedAt = null;\n });\n return this.#fetchAndUpdate({ bypassCache: true });\n }\n\n /**\n * Calls the geolocation service and updates controller state with the\n * result.\n *\n * @param options - Options forwarded to the service.\n * @param options.bypassCache - When true, the service skips its TTL cache.\n * @returns The ISO 3166-2 location code string.\n */\n async #fetchAndUpdate(options?: { bypassCache?: boolean }): Promise<string> {\n this.update((draft) => {\n draft.status = 'loading';\n draft.error = null;\n });\n\n try {\n const location = await this.messenger.call(\n 'GeolocationApiService:fetchGeolocation',\n options,\n );\n\n this.update((draft) => {\n draft.location = location;\n draft.status = 'complete';\n draft.lastFetchedAt = Date.now();\n draft.error = null;\n });\n\n return location;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n this.update((draft) => {\n draft.status = 'error';\n draft.error = message;\n });\n\n return this.state.location;\n }\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"geolocation-api-service-method-action-types.cjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service-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 { GeolocationApiService } from './geolocation-api-service';\n\n/**\n * Returns the geolocation country code. Serves from cache when the TTL has\n * not expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the cache and forces a\n * fresh network request.\n * @returns The ISO 3166-1 alpha-2 country code, or `UNKNOWN_LOCATION`\n * when the API returns an empty or invalid body.\n */\nexport type GeolocationApiServiceFetchGeolocationAction = {\n type: `GeolocationApiService:fetchGeolocation`;\n handler: GeolocationApiService['fetchGeolocation'];\n};\n\n/**\n * Union of all GeolocationApiService action types.\n */\nexport type GeolocationApiServiceMethodActions =\n GeolocationApiServiceFetchGeolocationAction;\n"]}
1
+ {"version":3,"file":"geolocation-api-service-method-action-types.cjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service-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 { GeolocationApiService } from './geolocation-api-service';\n\n/**\n * Returns the geolocation code. Serves from cache when the TTL has not\n * expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the cache and forces a\n * fresh network request.\n * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or\n * `UNKNOWN_LOCATION` when the API returns an empty or invalid body.\n */\nexport type GeolocationApiServiceFetchGeolocationAction = {\n type: `GeolocationApiService:fetchGeolocation`;\n handler: GeolocationApiService['fetchGeolocation'];\n};\n\n/**\n * Union of all GeolocationApiService action types.\n */\nexport type GeolocationApiServiceMethodActions =\n GeolocationApiServiceFetchGeolocationAction;\n"]}
@@ -4,15 +4,15 @@
4
4
  */
5
5
  import type { GeolocationApiService } from "./geolocation-api-service.cjs";
6
6
  /**
7
- * Returns the geolocation country code. Serves from cache when the TTL has
8
- * not expired, otherwise performs a network fetch. Concurrent callers are
7
+ * Returns the geolocation code. Serves from cache when the TTL has not
8
+ * expired, otherwise performs a network fetch. Concurrent callers are
9
9
  * deduplicated to a single in-flight request.
10
10
  *
11
11
  * @param options - Optional fetch options.
12
12
  * @param options.bypassCache - When true, invalidates the cache and forces a
13
13
  * fresh network request.
14
- * @returns The ISO 3166-1 alpha-2 country code, or `UNKNOWN_LOCATION`
15
- * when the API returns an empty or invalid body.
14
+ * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or
15
+ * `UNKNOWN_LOCATION` when the API returns an empty or invalid body.
16
16
  */
17
17
  export type GeolocationApiServiceFetchGeolocationAction = {
18
18
  type: `GeolocationApiService:fetchGeolocation`;
@@ -4,15 +4,15 @@
4
4
  */
5
5
  import type { GeolocationApiService } from "./geolocation-api-service.mjs";
6
6
  /**
7
- * Returns the geolocation country code. Serves from cache when the TTL has
8
- * not expired, otherwise performs a network fetch. Concurrent callers are
7
+ * Returns the geolocation code. Serves from cache when the TTL has not
8
+ * expired, otherwise performs a network fetch. Concurrent callers are
9
9
  * deduplicated to a single in-flight request.
10
10
  *
11
11
  * @param options - Optional fetch options.
12
12
  * @param options.bypassCache - When true, invalidates the cache and forces a
13
13
  * fresh network request.
14
- * @returns The ISO 3166-1 alpha-2 country code, or `UNKNOWN_LOCATION`
15
- * when the API returns an empty or invalid body.
14
+ * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or
15
+ * `UNKNOWN_LOCATION` when the API returns an empty or invalid body.
16
16
  */
17
17
  export type GeolocationApiServiceFetchGeolocationAction = {
18
18
  type: `GeolocationApiService:fetchGeolocation`;
@@ -1 +1 @@
1
- {"version":3,"file":"geolocation-api-service-method-action-types.mjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service-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 { GeolocationApiService } from './geolocation-api-service';\n\n/**\n * Returns the geolocation country code. Serves from cache when the TTL has\n * not expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the cache and forces a\n * fresh network request.\n * @returns The ISO 3166-1 alpha-2 country code, or `UNKNOWN_LOCATION`\n * when the API returns an empty or invalid body.\n */\nexport type GeolocationApiServiceFetchGeolocationAction = {\n type: `GeolocationApiService:fetchGeolocation`;\n handler: GeolocationApiService['fetchGeolocation'];\n};\n\n/**\n * Union of all GeolocationApiService action types.\n */\nexport type GeolocationApiServiceMethodActions =\n GeolocationApiServiceFetchGeolocationAction;\n"]}
1
+ {"version":3,"file":"geolocation-api-service-method-action-types.mjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service-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 { GeolocationApiService } from './geolocation-api-service';\n\n/**\n * Returns the geolocation code. Serves from cache when the TTL has not\n * expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the cache and forces a\n * fresh network request.\n * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or\n * `UNKNOWN_LOCATION` when the API returns an empty or invalid body.\n */\nexport type GeolocationApiServiceFetchGeolocationAction = {\n type: `GeolocationApiService:fetchGeolocation`;\n handler: GeolocationApiService['fetchGeolocation'];\n};\n\n/**\n * Union of all GeolocationApiService action types.\n */\nexport type GeolocationApiServiceMethodActions =\n GeolocationApiServiceFetchGeolocationAction;\n"]}
@@ -42,11 +42,12 @@ function getGeolocationUrl(env) {
42
42
  return `https://on-ramp.${envPrefix}api.cx.metamask.io${ENDPOINT_PATH}`;
43
43
  }
44
44
  /**
45
- * Low-level data service that fetches a country code from the geolocation API.
45
+ * Low-level data service that fetches a location code from the geolocation API.
46
46
  *
47
47
  * Responsibilities:
48
48
  * - HTTP request to the geolocation endpoint (wrapped in a service policy)
49
- * - ISO 3166-1 alpha-2 response validation
49
+ * - ISO 3166-2 response validation (country code with optional subdivision,
50
+ * e.g. `US`, `US-NY`, `CA-ON`)
50
51
  * - TTL-based in-memory cache
51
52
  * - Promise deduplication (concurrent callers share a single in-flight request)
52
53
  *
@@ -125,16 +126,16 @@ class GeolocationApiService {
125
126
  return __classPrivateFieldGet(this, _GeolocationApiService_policy, "f").onDegraded(listener);
126
127
  }
127
128
  /**
128
- * Returns the geolocation country code. Serves from cache when the TTL has
129
- * not expired, otherwise performs a network fetch. Concurrent callers are
129
+ * Returns the geolocation code. Serves from cache when the TTL has not
130
+ * expired, otherwise performs a network fetch. Concurrent callers are
130
131
  * deduplicated to a single in-flight request.
131
132
  *
132
133
  * @param options - Optional fetch options.
133
134
  * @param options.bypassCache - When true, invalidates the TTL cache. If a
134
135
  * request is already in-flight it will be reused (deduplication always
135
136
  * applies).
136
- * @returns The ISO 3166-1 alpha-2 country code, or {@link UNKNOWN_LOCATION}
137
- * when the API returns an empty or invalid body.
137
+ * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or
138
+ * {@link UNKNOWN_LOCATION} when the API returns an empty or invalid body.
138
139
  */
139
140
  async fetchGeolocation(options) {
140
141
  if (options?.bypassCache) {
@@ -165,7 +166,7 @@ _GeolocationApiService_messenger = new WeakMap(), _GeolocationApiService_fetch =
165
166
  * Performs the actual HTTP fetch, wrapped in the service policy for automatic
166
167
  * retry and circuit-breaking, and validates the response.
167
168
  *
168
- * @returns The ISO country code string.
169
+ * @returns The ISO 3166-2 location code string.
169
170
  */
170
171
  async function _GeolocationApiService_performFetch() {
171
172
  const response = await __classPrivateFieldGet(this, _GeolocationApiService_policy, "f").execute(async () => {
@@ -176,7 +177,9 @@ async function _GeolocationApiService_performFetch() {
176
177
  return localResponse;
177
178
  });
178
179
  const raw = (await response.text()).trim();
179
- const location = /^[A-Z]{2}$/u.test(raw) ? raw : exports.UNKNOWN_LOCATION;
180
+ const location = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/u.test(raw)
181
+ ? raw
182
+ : exports.UNKNOWN_LOCATION;
180
183
  if (location !== exports.UNKNOWN_LOCATION) {
181
184
  __classPrivateFieldSet(this, _GeolocationApiService_cachedLocation, location, "f");
182
185
  __classPrivateFieldSet(this, _GeolocationApiService_lastFetchedAt, Date.now(), "f");
@@ -1 +1 @@
1
- {"version":3,"file":"geolocation-api-service.cjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { GeolocationApiServiceMethodActions } from './geolocation-api-service-method-action-types';\nimport { Env } from '../types';\n\nconst DEFAULT_TTL_MS = 5 * 60 * 1000;\n\nconst ENDPOINT_PATH = '/geolocation';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link GeolocationApiService}, used to namespace the\n * service's actions and events.\n */\nexport const serviceName = 'GeolocationApiService';\n\n/**\n * Sentinel value used when the geolocation has not been determined yet or when\n * the API returns an empty / invalid response.\n */\nexport const UNKNOWN_LOCATION = 'UNKNOWN';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = ['fetchGeolocation'] as const;\n\n/**\n * Actions that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceActions = GeolocationApiServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationApiServiceMessenger}\n * calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceEvents = never;\n\n/**\n * Events from other messengers that {@link GeolocationApiService} subscribes\n * to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationApiService}.\n */\nexport type GeolocationApiServiceMessenger = Messenger<\n typeof serviceName,\n GeolocationApiServiceActions | AllowedActions,\n GeolocationApiServiceEvents | AllowedEvents\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * Returns the base URL for the geolocation API for the given environment.\n *\n * @param env - The environment to get the URL for.\n * @returns The full URL for the geolocation endpoint.\n */\nfunction getGeolocationUrl(env: Env): string {\n const envPrefix = env === Env.PRD ? '' : `${env}-`;\n return `https://on-ramp.${envPrefix}api.cx.metamask.io${ENDPOINT_PATH}`;\n}\n\n/**\n * Options accepted by {@link GeolocationApiService.fetchGeolocation}.\n */\nexport type FetchGeolocationOptions = {\n /** When true, the TTL cache is invalidated so the next request fetches fresh data. */\n bypassCache?: boolean;\n};\n\n/**\n * Low-level data service that fetches a country code from the geolocation API.\n *\n * Responsibilities:\n * - HTTP request to the geolocation endpoint (wrapped in a service policy)\n * - ISO 3166-1 alpha-2 response validation\n * - TTL-based in-memory cache\n * - Promise deduplication (concurrent callers share a single in-flight request)\n *\n * This class is intentionally not a controller: it does not manage UI state.\n * Its {@link fetchGeolocation} method is automatically registered on the\n * messenger so that controllers and other packages can call it directly.\n */\nexport class GeolocationApiService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: GeolocationApiServiceMessenger;\n\n readonly #fetch: typeof globalThis.fetch;\n\n readonly #url: string;\n\n readonly #ttlMs: number;\n\n /**\n * The policy that wraps each HTTP request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n #cachedLocation: string = UNKNOWN_LOCATION;\n\n #lastFetchedAt: number | null = null;\n\n #fetchPromise: Promise<string> | null = null;\n\n /**\n * Constructs a new {@link GeolocationApiService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.env - The environment to determine the correct API endpoint.\n * Defaults to PRD.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * Defaults to the global fetch.\n * @param args.ttlMs - Cache TTL in milliseconds. Defaults to 5 minutes.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n env = Env.PRD,\n fetch: fetchFunction = globalThis.fetch,\n ttlMs,\n policyOptions = {},\n }: {\n messenger: GeolocationApiServiceMessenger;\n env?: Env;\n fetch?: typeof fetch;\n ttlMs?: number;\n policyOptions?: CreateServicePolicyOptions;\n }) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#url = getGeolocationUrl(env);\n this.#fetch = fetchFunction;\n this.#ttlMs = ttlMs ?? DEFAULT_TTL_MS;\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a 5xx\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when requests are consistently\n * failing or when a successful request takes longer than the degraded\n * threshold.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Returns the geolocation country code. Serves from cache when the TTL has\n * not expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the TTL cache. If a\n * request is already in-flight it will be reused (deduplication always\n * applies).\n * @returns The ISO 3166-1 alpha-2 country code, or {@link UNKNOWN_LOCATION}\n * when the API returns an empty or invalid body.\n */\n async fetchGeolocation(options?: FetchGeolocationOptions): Promise<string> {\n if (options?.bypassCache) {\n this.#lastFetchedAt = null;\n }\n\n if (this.#isCacheValid()) {\n return this.#cachedLocation;\n }\n\n if (this.#fetchPromise) {\n return this.#fetchPromise;\n }\n\n const promise = this.#performFetch();\n this.#fetchPromise = promise;\n\n try {\n return await promise;\n } finally {\n this.#fetchPromise = null;\n }\n }\n\n /**\n * Checks whether the cached geolocation is still within the TTL window.\n *\n * @returns True if the cache is valid.\n */\n #isCacheValid(): boolean {\n return (\n this.#lastFetchedAt !== null &&\n Date.now() - this.#lastFetchedAt < this.#ttlMs\n );\n }\n\n /**\n * Performs the actual HTTP fetch, wrapped in the service policy for automatic\n * retry and circuit-breaking, and validates the response.\n *\n * @returns The ISO country code string.\n */\n async #performFetch(): Promise<string> {\n const response = await this.#policy.execute(async () => {\n const localResponse = await this.#fetch(this.#url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Geolocation fetch failed: ${localResponse.status}`,\n );\n }\n return localResponse;\n });\n\n const raw = (await response.text()).trim();\n const location = /^[A-Z]{2}$/u.test(raw) ? raw : UNKNOWN_LOCATION;\n\n if (location !== UNKNOWN_LOCATION) {\n this.#cachedLocation = location;\n this.#lastFetchedAt = Date.now();\n }\n\n return location;\n }\n}\n"]}
1
+ {"version":3,"file":"geolocation-api-service.cjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { GeolocationApiServiceMethodActions } from './geolocation-api-service-method-action-types';\nimport { Env } from '../types';\n\nconst DEFAULT_TTL_MS = 5 * 60 * 1000;\n\nconst ENDPOINT_PATH = '/geolocation';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link GeolocationApiService}, used to namespace the\n * service's actions and events.\n */\nexport const serviceName = 'GeolocationApiService';\n\n/**\n * Sentinel value used when the geolocation has not been determined yet or when\n * the API returns an empty / invalid response.\n */\nexport const UNKNOWN_LOCATION = 'UNKNOWN';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = ['fetchGeolocation'] as const;\n\n/**\n * Actions that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceActions = GeolocationApiServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationApiServiceMessenger}\n * calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceEvents = never;\n\n/**\n * Events from other messengers that {@link GeolocationApiService} subscribes\n * to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationApiService}.\n */\nexport type GeolocationApiServiceMessenger = Messenger<\n typeof serviceName,\n GeolocationApiServiceActions | AllowedActions,\n GeolocationApiServiceEvents | AllowedEvents\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * Returns the base URL for the geolocation API for the given environment.\n *\n * @param env - The environment to get the URL for.\n * @returns The full URL for the geolocation endpoint.\n */\nfunction getGeolocationUrl(env: Env): string {\n const envPrefix = env === Env.PRD ? '' : `${env}-`;\n return `https://on-ramp.${envPrefix}api.cx.metamask.io${ENDPOINT_PATH}`;\n}\n\n/**\n * Options accepted by {@link GeolocationApiService.fetchGeolocation}.\n */\nexport type FetchGeolocationOptions = {\n /** When true, the TTL cache is invalidated so the next request fetches fresh data. */\n bypassCache?: boolean;\n};\n\n/**\n * Low-level data service that fetches a location code from the geolocation API.\n *\n * Responsibilities:\n * - HTTP request to the geolocation endpoint (wrapped in a service policy)\n * - ISO 3166-2 response validation (country code with optional subdivision,\n * e.g. `US`, `US-NY`, `CA-ON`)\n * - TTL-based in-memory cache\n * - Promise deduplication (concurrent callers share a single in-flight request)\n *\n * This class is intentionally not a controller: it does not manage UI state.\n * Its {@link fetchGeolocation} method is automatically registered on the\n * messenger so that controllers and other packages can call it directly.\n */\nexport class GeolocationApiService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: GeolocationApiServiceMessenger;\n\n readonly #fetch: typeof globalThis.fetch;\n\n readonly #url: string;\n\n readonly #ttlMs: number;\n\n /**\n * The policy that wraps each HTTP request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n #cachedLocation: string = UNKNOWN_LOCATION;\n\n #lastFetchedAt: number | null = null;\n\n #fetchPromise: Promise<string> | null = null;\n\n /**\n * Constructs a new {@link GeolocationApiService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.env - The environment to determine the correct API endpoint.\n * Defaults to PRD.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * Defaults to the global fetch.\n * @param args.ttlMs - Cache TTL in milliseconds. Defaults to 5 minutes.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n env = Env.PRD,\n fetch: fetchFunction = globalThis.fetch,\n ttlMs,\n policyOptions = {},\n }: {\n messenger: GeolocationApiServiceMessenger;\n env?: Env;\n fetch?: typeof fetch;\n ttlMs?: number;\n policyOptions?: CreateServicePolicyOptions;\n }) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#url = getGeolocationUrl(env);\n this.#fetch = fetchFunction;\n this.#ttlMs = ttlMs ?? DEFAULT_TTL_MS;\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a 5xx\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when requests are consistently\n * failing or when a successful request takes longer than the degraded\n * threshold.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Returns the geolocation code. Serves from cache when the TTL has not\n * expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the TTL cache. If a\n * request is already in-flight it will be reused (deduplication always\n * applies).\n * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or\n * {@link UNKNOWN_LOCATION} when the API returns an empty or invalid body.\n */\n async fetchGeolocation(options?: FetchGeolocationOptions): Promise<string> {\n if (options?.bypassCache) {\n this.#lastFetchedAt = null;\n }\n\n if (this.#isCacheValid()) {\n return this.#cachedLocation;\n }\n\n if (this.#fetchPromise) {\n return this.#fetchPromise;\n }\n\n const promise = this.#performFetch();\n this.#fetchPromise = promise;\n\n try {\n return await promise;\n } finally {\n this.#fetchPromise = null;\n }\n }\n\n /**\n * Checks whether the cached geolocation is still within the TTL window.\n *\n * @returns True if the cache is valid.\n */\n #isCacheValid(): boolean {\n return (\n this.#lastFetchedAt !== null &&\n Date.now() - this.#lastFetchedAt < this.#ttlMs\n );\n }\n\n /**\n * Performs the actual HTTP fetch, wrapped in the service policy for automatic\n * retry and circuit-breaking, and validates the response.\n *\n * @returns The ISO 3166-2 location code string.\n */\n async #performFetch(): Promise<string> {\n const response = await this.#policy.execute(async () => {\n const localResponse = await this.#fetch(this.#url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Geolocation fetch failed: ${localResponse.status}`,\n );\n }\n return localResponse;\n });\n\n const raw = (await response.text()).trim();\n const location = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/u.test(raw)\n ? raw\n : UNKNOWN_LOCATION;\n\n if (location !== UNKNOWN_LOCATION) {\n this.#cachedLocation = location;\n this.#lastFetchedAt = Date.now();\n }\n\n return location;\n }\n}\n"]}
@@ -44,11 +44,12 @@ export type FetchGeolocationOptions = {
44
44
  bypassCache?: boolean;
45
45
  };
46
46
  /**
47
- * Low-level data service that fetches a country code from the geolocation API.
47
+ * Low-level data service that fetches a location code from the geolocation API.
48
48
  *
49
49
  * Responsibilities:
50
50
  * - HTTP request to the geolocation endpoint (wrapped in a service policy)
51
- * - ISO 3166-1 alpha-2 response validation
51
+ * - ISO 3166-2 response validation (country code with optional subdivision,
52
+ * e.g. `US`, `US-NY`, `CA-ON`)
52
53
  * - TTL-based in-memory cache
53
54
  * - Promise deduplication (concurrent callers share a single in-flight request)
54
55
  *
@@ -110,16 +111,16 @@ export declare class GeolocationApiService {
110
111
  */
111
112
  onDegraded(listener: Parameters<ServicePolicy['onDegraded']>[0]): IDisposable;
112
113
  /**
113
- * Returns the geolocation country code. Serves from cache when the TTL has
114
- * not expired, otherwise performs a network fetch. Concurrent callers are
114
+ * Returns the geolocation code. Serves from cache when the TTL has not
115
+ * expired, otherwise performs a network fetch. Concurrent callers are
115
116
  * deduplicated to a single in-flight request.
116
117
  *
117
118
  * @param options - Optional fetch options.
118
119
  * @param options.bypassCache - When true, invalidates the TTL cache. If a
119
120
  * request is already in-flight it will be reused (deduplication always
120
121
  * applies).
121
- * @returns The ISO 3166-1 alpha-2 country code, or {@link UNKNOWN_LOCATION}
122
- * when the API returns an empty or invalid body.
122
+ * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or
123
+ * {@link UNKNOWN_LOCATION} when the API returns an empty or invalid body.
123
124
  */
124
125
  fetchGeolocation(options?: FetchGeolocationOptions): Promise<string>;
125
126
  }
@@ -1 +1 @@
1
- {"version":3,"file":"geolocation-api-service.d.cts","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,kCAAkC,EAAE,0DAAsD;AACxG,OAAO,EAAE,GAAG,EAAE,qBAAiB;AAQ/B;;;GAGG;AACH,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAM1C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,kCAAkC,CAAC;AAE9E;;;GAGG;AACH,KAAK,cAAc,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEhD;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,WAAW,EAClB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAeF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,sFAAsF;IACtF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAqB;;IAChC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC;IAuBlC;;;;;;;;;;;;OAYG;gBACS,EACV,SAAS,EACT,GAAa,EACb,KAAK,EAAE,aAAgC,EACvC,KAAK,EACL,aAAkB,GACnB,EAAE;QACD,SAAS,EAAE,8BAA8B,CAAC;QAC1C,GAAG,CAAC,EAAE,GAAG,CAAC;QACV,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,0BAA0B,CAAC;KAC5C;IAcD;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACnD,WAAW;IAId;;;;;;;;;;;OAWG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;CA+D3E"}
1
+ {"version":3,"file":"geolocation-api-service.d.cts","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,kCAAkC,EAAE,0DAAsD;AACxG,OAAO,EAAE,GAAG,EAAE,qBAAiB;AAQ/B;;;GAGG;AACH,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAM1C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,kCAAkC,CAAC;AAE9E;;;GAGG;AACH,KAAK,cAAc,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEhD;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,WAAW,EAClB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAeF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,sFAAsF;IACtF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAqB;;IAChC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC;IAuBlC;;;;;;;;;;;;OAYG;gBACS,EACV,SAAS,EACT,GAAa,EACb,KAAK,EAAE,aAAgC,EACvC,KAAK,EACL,aAAkB,GACnB,EAAE;QACD,SAAS,EAAE,8BAA8B,CAAC;QAC1C,GAAG,CAAC,EAAE,GAAG,CAAC;QACV,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,0BAA0B,CAAC;KAC5C;IAcD;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACnD,WAAW;IAId;;;;;;;;;;;OAWG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;CAiE3E"}
@@ -44,11 +44,12 @@ export type FetchGeolocationOptions = {
44
44
  bypassCache?: boolean;
45
45
  };
46
46
  /**
47
- * Low-level data service that fetches a country code from the geolocation API.
47
+ * Low-level data service that fetches a location code from the geolocation API.
48
48
  *
49
49
  * Responsibilities:
50
50
  * - HTTP request to the geolocation endpoint (wrapped in a service policy)
51
- * - ISO 3166-1 alpha-2 response validation
51
+ * - ISO 3166-2 response validation (country code with optional subdivision,
52
+ * e.g. `US`, `US-NY`, `CA-ON`)
52
53
  * - TTL-based in-memory cache
53
54
  * - Promise deduplication (concurrent callers share a single in-flight request)
54
55
  *
@@ -110,16 +111,16 @@ export declare class GeolocationApiService {
110
111
  */
111
112
  onDegraded(listener: Parameters<ServicePolicy['onDegraded']>[0]): IDisposable;
112
113
  /**
113
- * Returns the geolocation country code. Serves from cache when the TTL has
114
- * not expired, otherwise performs a network fetch. Concurrent callers are
114
+ * Returns the geolocation code. Serves from cache when the TTL has not
115
+ * expired, otherwise performs a network fetch. Concurrent callers are
115
116
  * deduplicated to a single in-flight request.
116
117
  *
117
118
  * @param options - Optional fetch options.
118
119
  * @param options.bypassCache - When true, invalidates the TTL cache. If a
119
120
  * request is already in-flight it will be reused (deduplication always
120
121
  * applies).
121
- * @returns The ISO 3166-1 alpha-2 country code, or {@link UNKNOWN_LOCATION}
122
- * when the API returns an empty or invalid body.
122
+ * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or
123
+ * {@link UNKNOWN_LOCATION} when the API returns an empty or invalid body.
123
124
  */
124
125
  fetchGeolocation(options?: FetchGeolocationOptions): Promise<string>;
125
126
  }
@@ -1 +1 @@
1
- {"version":3,"file":"geolocation-api-service.d.mts","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,kCAAkC,EAAE,0DAAsD;AACxG,OAAO,EAAE,GAAG,EAAE,qBAAiB;AAQ/B;;;GAGG;AACH,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAM1C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,kCAAkC,CAAC;AAE9E;;;GAGG;AACH,KAAK,cAAc,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEhD;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,WAAW,EAClB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAeF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,sFAAsF;IACtF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,qBAAa,qBAAqB;;IAChC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC;IAuBlC;;;;;;;;;;;;OAYG;gBACS,EACV,SAAS,EACT,GAAa,EACb,KAAK,EAAE,aAAgC,EACvC,KAAK,EACL,aAAkB,GACnB,EAAE;QACD,SAAS,EAAE,8BAA8B,CAAC;QAC1C,GAAG,CAAC,EAAE,GAAG,CAAC;QACV,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,0BAA0B,CAAC;KAC5C;IAcD;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACnD,WAAW;IAId;;;;;;;;;;;OAWG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;CA+D3E"}
1
+ {"version":3,"file":"geolocation-api-service.d.mts","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,0BAA0B,EAC1B,aAAa,EACd,mCAAmC;AAEpC,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB;AAE7C,OAAO,KAAK,EAAE,kCAAkC,EAAE,0DAAsD;AACxG,OAAO,EAAE,GAAG,EAAE,qBAAiB;AAQ/B;;;GAGG;AACH,eAAO,MAAM,WAAW,0BAA0B,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAM1C;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,kCAAkC,CAAC;AAE9E;;;GAGG;AACH,KAAK,cAAc,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEhD;;;GAGG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,8BAA8B,GAAG,SAAS,CACpD,OAAO,WAAW,EAClB,4BAA4B,GAAG,cAAc,EAC7C,2BAA2B,GAAG,aAAa,CAC5C,CAAC;AAeF;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,sFAAsF;IACtF,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAqB;;IAChC;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,WAAW,CAAC;IAuBlC;;;;;;;;;;;;OAYG;gBACS,EACV,SAAS,EACT,GAAa,EACb,KAAK,EAAE,aAAgC,EACvC,KAAK,EACL,aAAkB,GACnB,EAAE;QACD,SAAS,EAAE,8BAA8B,CAAC;QAC1C,GAAG,CAAC,EAAE,GAAG,CAAC;QACV,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;QACrB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,0BAA0B,CAAC;KAC5C;IAcD;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW;IAIvE;;;;;;;OAOG;IACH,UAAU,CACR,QAAQ,EAAE,UAAU,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,GACnD,WAAW;IAId;;;;;;;;;;;OAWG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;CAiE3E"}
@@ -39,11 +39,12 @@ function getGeolocationUrl(env) {
39
39
  return `https://on-ramp.${envPrefix}api.cx.metamask.io${ENDPOINT_PATH}`;
40
40
  }
41
41
  /**
42
- * Low-level data service that fetches a country code from the geolocation API.
42
+ * Low-level data service that fetches a location code from the geolocation API.
43
43
  *
44
44
  * Responsibilities:
45
45
  * - HTTP request to the geolocation endpoint (wrapped in a service policy)
46
- * - ISO 3166-1 alpha-2 response validation
46
+ * - ISO 3166-2 response validation (country code with optional subdivision,
47
+ * e.g. `US`, `US-NY`, `CA-ON`)
47
48
  * - TTL-based in-memory cache
48
49
  * - Promise deduplication (concurrent callers share a single in-flight request)
49
50
  *
@@ -122,16 +123,16 @@ export class GeolocationApiService {
122
123
  return __classPrivateFieldGet(this, _GeolocationApiService_policy, "f").onDegraded(listener);
123
124
  }
124
125
  /**
125
- * Returns the geolocation country code. Serves from cache when the TTL has
126
- * not expired, otherwise performs a network fetch. Concurrent callers are
126
+ * Returns the geolocation code. Serves from cache when the TTL has not
127
+ * expired, otherwise performs a network fetch. Concurrent callers are
127
128
  * deduplicated to a single in-flight request.
128
129
  *
129
130
  * @param options - Optional fetch options.
130
131
  * @param options.bypassCache - When true, invalidates the TTL cache. If a
131
132
  * request is already in-flight it will be reused (deduplication always
132
133
  * applies).
133
- * @returns The ISO 3166-1 alpha-2 country code, or {@link UNKNOWN_LOCATION}
134
- * when the API returns an empty or invalid body.
134
+ * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or
135
+ * {@link UNKNOWN_LOCATION} when the API returns an empty or invalid body.
135
136
  */
136
137
  async fetchGeolocation(options) {
137
138
  if (options?.bypassCache) {
@@ -161,7 +162,7 @@ _GeolocationApiService_messenger = new WeakMap(), _GeolocationApiService_fetch =
161
162
  * Performs the actual HTTP fetch, wrapped in the service policy for automatic
162
163
  * retry and circuit-breaking, and validates the response.
163
164
  *
164
- * @returns The ISO country code string.
165
+ * @returns The ISO 3166-2 location code string.
165
166
  */
166
167
  async function _GeolocationApiService_performFetch() {
167
168
  const response = await __classPrivateFieldGet(this, _GeolocationApiService_policy, "f").execute(async () => {
@@ -172,7 +173,9 @@ async function _GeolocationApiService_performFetch() {
172
173
  return localResponse;
173
174
  });
174
175
  const raw = (await response.text()).trim();
175
- const location = /^[A-Z]{2}$/u.test(raw) ? raw : UNKNOWN_LOCATION;
176
+ const location = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/u.test(raw)
177
+ ? raw
178
+ : UNKNOWN_LOCATION;
176
179
  if (location !== UNKNOWN_LOCATION) {
177
180
  __classPrivateFieldSet(this, _GeolocationApiService_cachedLocation, location, "f");
178
181
  __classPrivateFieldSet(this, _GeolocationApiService_lastFetchedAt, Date.now(), "f");
@@ -1 +1 @@
1
- {"version":3,"file":"geolocation-api-service.mjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAIA,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,mCAAmC;AAK5E,OAAO,EAAE,GAAG,EAAE,qBAAiB;AAE/B,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAErC,MAAM,aAAa,GAAG,cAAc,CAAC;AAErC,kBAAkB;AAElB;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AAEnD;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC;AAE1C,oBAAoB;AAEpB,MAAM,yBAAyB,GAAG,CAAC,kBAAkB,CAAU,CAAC;AAkChE,6BAA6B;AAE7B;;;;;GAKG;AACH,SAAS,iBAAiB,CAAC,GAAQ;IACjC,MAAM,SAAS,GAAG,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;IACnD,OAAO,mBAAmB,SAAS,qBAAqB,aAAa,EAAE,CAAC;AAC1E,CAAC;AAUD;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,qBAAqB;IA2BhC;;;;;;;;;;;;OAYG;IACH,YAAY,EACV,SAAS,EACT,GAAG,GAAG,GAAG,CAAC,GAAG,EACb,KAAK,EAAE,aAAa,GAAG,UAAU,CAAC,KAAK,EACvC,KAAK,EACL,aAAa,GAAG,EAAE,GAOnB;;QA9CQ,mDAA2C;QAE3C,+CAAgC;QAEhC,6CAAa;QAEb,+CAAe;QAExB;;;;WAIG;QACM,gDAAuB;QAEhC,gDAA0B,gBAAgB,EAAC;QAE3C,+CAAgC,IAAI,EAAC;QAErC,8CAAwC,IAAI,EAAC;QA4B3C,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,uBAAA,IAAI,oCAAc,SAAS,MAAA,CAAC;QAC5B,uBAAA,IAAI,8BAAQ,iBAAiB,CAAC,GAAG,CAAC,MAAA,CAAC;QACnC,uBAAA,IAAI,gCAAU,aAAa,MAAA,CAAC;QAC5B,uBAAA,IAAI,gCAAU,KAAK,IAAI,cAAc,MAAA,CAAC;QACtC,uBAAA,IAAI,iCAAW,mBAAmB,CAAC,aAAa,CAAC,MAAA,CAAC;QAElD,uBAAA,IAAI,wCAAW,CAAC,4BAA4B,CAC1C,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,QAAiD;QACvD,OAAO,uBAAA,IAAI,qCAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,QAAiD;QACvD,OAAO,uBAAA,IAAI,qCAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;;OAOG;IACH,UAAU,CACR,QAAoD;QAEpD,OAAO,uBAAA,IAAI,qCAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,gBAAgB,CAAC,OAAiC;QACtD,IAAI,OAAO,EAAE,WAAW,EAAE,CAAC;YACzB,uBAAA,IAAI,wCAAkB,IAAI,MAAA,CAAC;QAC7B,CAAC;QAED,IAAI,uBAAA,IAAI,6EAAc,MAAlB,IAAI,CAAgB,EAAE,CAAC;YACzB,OAAO,uBAAA,IAAI,6CAAgB,CAAC;QAC9B,CAAC;QAED,IAAI,uBAAA,IAAI,2CAAc,EAAE,CAAC;YACvB,OAAO,uBAAA,IAAI,2CAAc,CAAC;QAC5B,CAAC;QAED,MAAM,OAAO,GAAG,uBAAA,IAAI,6EAAc,MAAlB,IAAI,CAAgB,CAAC;QACrC,uBAAA,IAAI,uCAAiB,OAAO,MAAA,CAAC;QAE7B,IAAI,CAAC;YACH,OAAO,MAAM,OAAO,CAAC;QACvB,CAAC;gBAAS,CAAC;YACT,uBAAA,IAAI,uCAAiB,IAAI,MAAA,CAAC;QAC5B,CAAC;IACH,CAAC;CA0CF;;IAlCG,OAAO,CACL,uBAAA,IAAI,4CAAe,KAAK,IAAI;QAC5B,IAAI,CAAC,GAAG,EAAE,GAAG,uBAAA,IAAI,4CAAe,GAAG,uBAAA,IAAI,oCAAO,CAC/C,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,KAAK;IACH,MAAM,QAAQ,GAAG,MAAM,uBAAA,IAAI,qCAAQ,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE;QACrD,MAAM,aAAa,GAAG,MAAM,uBAAA,IAAI,oCAAO,MAAX,IAAI,EAAQ,uBAAA,IAAI,kCAAK,CAAC,CAAC;QACnD,IAAI,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC;YACtB,MAAM,IAAI,SAAS,CACjB,aAAa,CAAC,MAAM,EACpB,6BAA6B,aAAa,CAAC,MAAM,EAAE,CACpD,CAAC;QACJ,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC;IAElE,IAAI,QAAQ,KAAK,gBAAgB,EAAE,CAAC;QAClC,uBAAA,IAAI,yCAAmB,QAAQ,MAAA,CAAC;QAChC,uBAAA,IAAI,wCAAkB,IAAI,CAAC,GAAG,EAAE,MAAA,CAAC;IACnC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { GeolocationApiServiceMethodActions } from './geolocation-api-service-method-action-types';\nimport { Env } from '../types';\n\nconst DEFAULT_TTL_MS = 5 * 60 * 1000;\n\nconst ENDPOINT_PATH = '/geolocation';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link GeolocationApiService}, used to namespace the\n * service's actions and events.\n */\nexport const serviceName = 'GeolocationApiService';\n\n/**\n * Sentinel value used when the geolocation has not been determined yet or when\n * the API returns an empty / invalid response.\n */\nexport const UNKNOWN_LOCATION = 'UNKNOWN';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = ['fetchGeolocation'] as const;\n\n/**\n * Actions that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceActions = GeolocationApiServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationApiServiceMessenger}\n * calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceEvents = never;\n\n/**\n * Events from other messengers that {@link GeolocationApiService} subscribes\n * to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationApiService}.\n */\nexport type GeolocationApiServiceMessenger = Messenger<\n typeof serviceName,\n GeolocationApiServiceActions | AllowedActions,\n GeolocationApiServiceEvents | AllowedEvents\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * Returns the base URL for the geolocation API for the given environment.\n *\n * @param env - The environment to get the URL for.\n * @returns The full URL for the geolocation endpoint.\n */\nfunction getGeolocationUrl(env: Env): string {\n const envPrefix = env === Env.PRD ? '' : `${env}-`;\n return `https://on-ramp.${envPrefix}api.cx.metamask.io${ENDPOINT_PATH}`;\n}\n\n/**\n * Options accepted by {@link GeolocationApiService.fetchGeolocation}.\n */\nexport type FetchGeolocationOptions = {\n /** When true, the TTL cache is invalidated so the next request fetches fresh data. */\n bypassCache?: boolean;\n};\n\n/**\n * Low-level data service that fetches a country code from the geolocation API.\n *\n * Responsibilities:\n * - HTTP request to the geolocation endpoint (wrapped in a service policy)\n * - ISO 3166-1 alpha-2 response validation\n * - TTL-based in-memory cache\n * - Promise deduplication (concurrent callers share a single in-flight request)\n *\n * This class is intentionally not a controller: it does not manage UI state.\n * Its {@link fetchGeolocation} method is automatically registered on the\n * messenger so that controllers and other packages can call it directly.\n */\nexport class GeolocationApiService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: GeolocationApiServiceMessenger;\n\n readonly #fetch: typeof globalThis.fetch;\n\n readonly #url: string;\n\n readonly #ttlMs: number;\n\n /**\n * The policy that wraps each HTTP request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n #cachedLocation: string = UNKNOWN_LOCATION;\n\n #lastFetchedAt: number | null = null;\n\n #fetchPromise: Promise<string> | null = null;\n\n /**\n * Constructs a new {@link GeolocationApiService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.env - The environment to determine the correct API endpoint.\n * Defaults to PRD.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * Defaults to the global fetch.\n * @param args.ttlMs - Cache TTL in milliseconds. Defaults to 5 minutes.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n env = Env.PRD,\n fetch: fetchFunction = globalThis.fetch,\n ttlMs,\n policyOptions = {},\n }: {\n messenger: GeolocationApiServiceMessenger;\n env?: Env;\n fetch?: typeof fetch;\n ttlMs?: number;\n policyOptions?: CreateServicePolicyOptions;\n }) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#url = getGeolocationUrl(env);\n this.#fetch = fetchFunction;\n this.#ttlMs = ttlMs ?? DEFAULT_TTL_MS;\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a 5xx\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when requests are consistently\n * failing or when a successful request takes longer than the degraded\n * threshold.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Returns the geolocation country code. Serves from cache when the TTL has\n * not expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the TTL cache. If a\n * request is already in-flight it will be reused (deduplication always\n * applies).\n * @returns The ISO 3166-1 alpha-2 country code, or {@link UNKNOWN_LOCATION}\n * when the API returns an empty or invalid body.\n */\n async fetchGeolocation(options?: FetchGeolocationOptions): Promise<string> {\n if (options?.bypassCache) {\n this.#lastFetchedAt = null;\n }\n\n if (this.#isCacheValid()) {\n return this.#cachedLocation;\n }\n\n if (this.#fetchPromise) {\n return this.#fetchPromise;\n }\n\n const promise = this.#performFetch();\n this.#fetchPromise = promise;\n\n try {\n return await promise;\n } finally {\n this.#fetchPromise = null;\n }\n }\n\n /**\n * Checks whether the cached geolocation is still within the TTL window.\n *\n * @returns True if the cache is valid.\n */\n #isCacheValid(): boolean {\n return (\n this.#lastFetchedAt !== null &&\n Date.now() - this.#lastFetchedAt < this.#ttlMs\n );\n }\n\n /**\n * Performs the actual HTTP fetch, wrapped in the service policy for automatic\n * retry and circuit-breaking, and validates the response.\n *\n * @returns The ISO country code string.\n */\n async #performFetch(): Promise<string> {\n const response = await this.#policy.execute(async () => {\n const localResponse = await this.#fetch(this.#url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Geolocation fetch failed: ${localResponse.status}`,\n );\n }\n return localResponse;\n });\n\n const raw = (await response.text()).trim();\n const location = /^[A-Z]{2}$/u.test(raw) ? raw : UNKNOWN_LOCATION;\n\n if (location !== UNKNOWN_LOCATION) {\n this.#cachedLocation = location;\n this.#lastFetchedAt = Date.now();\n }\n\n return location;\n }\n}\n"]}
1
+ {"version":3,"file":"geolocation-api-service.mjs","sourceRoot":"","sources":["../../src/geolocation-api-service/geolocation-api-service.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n CreateServicePolicyOptions,\n ServicePolicy,\n} from '@metamask/controller-utils';\nimport { createServicePolicy, HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport type { IDisposable } from 'cockatiel';\n\nimport type { GeolocationApiServiceMethodActions } from './geolocation-api-service-method-action-types';\nimport { Env } from '../types';\n\nconst DEFAULT_TTL_MS = 5 * 60 * 1000;\n\nconst ENDPOINT_PATH = '/geolocation';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link GeolocationApiService}, used to namespace the\n * service's actions and events.\n */\nexport const serviceName = 'GeolocationApiService';\n\n/**\n * Sentinel value used when the geolocation has not been determined yet or when\n * the API returns an empty / invalid response.\n */\nexport const UNKNOWN_LOCATION = 'UNKNOWN';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = ['fetchGeolocation'] as const;\n\n/**\n * Actions that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceActions = GeolocationApiServiceMethodActions;\n\n/**\n * Actions from other messengers that {@link GeolocationApiServiceMessenger}\n * calls.\n */\ntype AllowedActions = never;\n\n/**\n * Events that {@link GeolocationApiService} exposes to other consumers.\n */\nexport type GeolocationApiServiceEvents = never;\n\n/**\n * Events from other messengers that {@link GeolocationApiService} subscribes\n * to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link GeolocationApiService}.\n */\nexport type GeolocationApiServiceMessenger = Messenger<\n typeof serviceName,\n GeolocationApiServiceActions | AllowedActions,\n GeolocationApiServiceEvents | AllowedEvents\n>;\n\n// === SERVICE DEFINITION ===\n\n/**\n * Returns the base URL for the geolocation API for the given environment.\n *\n * @param env - The environment to get the URL for.\n * @returns The full URL for the geolocation endpoint.\n */\nfunction getGeolocationUrl(env: Env): string {\n const envPrefix = env === Env.PRD ? '' : `${env}-`;\n return `https://on-ramp.${envPrefix}api.cx.metamask.io${ENDPOINT_PATH}`;\n}\n\n/**\n * Options accepted by {@link GeolocationApiService.fetchGeolocation}.\n */\nexport type FetchGeolocationOptions = {\n /** When true, the TTL cache is invalidated so the next request fetches fresh data. */\n bypassCache?: boolean;\n};\n\n/**\n * Low-level data service that fetches a location code from the geolocation API.\n *\n * Responsibilities:\n * - HTTP request to the geolocation endpoint (wrapped in a service policy)\n * - ISO 3166-2 response validation (country code with optional subdivision,\n * e.g. `US`, `US-NY`, `CA-ON`)\n * - TTL-based in-memory cache\n * - Promise deduplication (concurrent callers share a single in-flight request)\n *\n * This class is intentionally not a controller: it does not manage UI state.\n * Its {@link fetchGeolocation} method is automatically registered on the\n * messenger so that controllers and other packages can call it directly.\n */\nexport class GeolocationApiService {\n /**\n * The name of the service.\n */\n readonly name: typeof serviceName;\n\n readonly #messenger: GeolocationApiServiceMessenger;\n\n readonly #fetch: typeof globalThis.fetch;\n\n readonly #url: string;\n\n readonly #ttlMs: number;\n\n /**\n * The policy that wraps each HTTP request.\n *\n * @see {@link createServicePolicy}\n */\n readonly #policy: ServicePolicy;\n\n #cachedLocation: string = UNKNOWN_LOCATION;\n\n #lastFetchedAt: number | null = null;\n\n #fetchPromise: Promise<string> | null = null;\n\n /**\n * Constructs a new {@link GeolocationApiService}.\n *\n * @param args - The constructor arguments.\n * @param args.messenger - The messenger suited for this service.\n * @param args.env - The environment to determine the correct API endpoint.\n * Defaults to PRD.\n * @param args.fetch - A function that can be used to make an HTTP request.\n * Defaults to the global fetch.\n * @param args.ttlMs - Cache TTL in milliseconds. Defaults to 5 minutes.\n * @param args.policyOptions - Options to pass to `createServicePolicy`, which\n * is used to wrap each request. See {@link CreateServicePolicyOptions}.\n */\n constructor({\n messenger,\n env = Env.PRD,\n fetch: fetchFunction = globalThis.fetch,\n ttlMs,\n policyOptions = {},\n }: {\n messenger: GeolocationApiServiceMessenger;\n env?: Env;\n fetch?: typeof fetch;\n ttlMs?: number;\n policyOptions?: CreateServicePolicyOptions;\n }) {\n this.name = serviceName;\n this.#messenger = messenger;\n this.#url = getGeolocationUrl(env);\n this.#fetch = fetchFunction;\n this.#ttlMs = ttlMs ?? DEFAULT_TTL_MS;\n this.#policy = createServicePolicy(policyOptions);\n\n this.#messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Registers a handler that will be called after a request returns a 5xx\n * response, causing a retry.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onRetry(listener: Parameters<ServicePolicy['onRetry']>[0]): IDisposable {\n return this.#policy.onRetry(listener);\n }\n\n /**\n * Registers a handler that will be called after a set number of retry rounds\n * prove that requests to the API endpoint consistently return a 5xx response.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n * @see {@link createServicePolicy}\n */\n onBreak(listener: Parameters<ServicePolicy['onBreak']>[0]): IDisposable {\n return this.#policy.onBreak(listener);\n }\n\n /**\n * Registers a handler that will be called when requests are consistently\n * failing or when a successful request takes longer than the degraded\n * threshold.\n *\n * @param listener - The handler to be called.\n * @returns An object that can be used to unregister the handler.\n */\n onDegraded(\n listener: Parameters<ServicePolicy['onDegraded']>[0],\n ): IDisposable {\n return this.#policy.onDegraded(listener);\n }\n\n /**\n * Returns the geolocation code. Serves from cache when the TTL has not\n * expired, otherwise performs a network fetch. Concurrent callers are\n * deduplicated to a single in-flight request.\n *\n * @param options - Optional fetch options.\n * @param options.bypassCache - When true, invalidates the TTL cache. If a\n * request is already in-flight it will be reused (deduplication always\n * applies).\n * @returns An ISO 3166-2 location code (e.g. `US`, `US-NY`, `CA-ON`), or\n * {@link UNKNOWN_LOCATION} when the API returns an empty or invalid body.\n */\n async fetchGeolocation(options?: FetchGeolocationOptions): Promise<string> {\n if (options?.bypassCache) {\n this.#lastFetchedAt = null;\n }\n\n if (this.#isCacheValid()) {\n return this.#cachedLocation;\n }\n\n if (this.#fetchPromise) {\n return this.#fetchPromise;\n }\n\n const promise = this.#performFetch();\n this.#fetchPromise = promise;\n\n try {\n return await promise;\n } finally {\n this.#fetchPromise = null;\n }\n }\n\n /**\n * Checks whether the cached geolocation is still within the TTL window.\n *\n * @returns True if the cache is valid.\n */\n #isCacheValid(): boolean {\n return (\n this.#lastFetchedAt !== null &&\n Date.now() - this.#lastFetchedAt < this.#ttlMs\n );\n }\n\n /**\n * Performs the actual HTTP fetch, wrapped in the service policy for automatic\n * retry and circuit-breaking, and validates the response.\n *\n * @returns The ISO 3166-2 location code string.\n */\n async #performFetch(): Promise<string> {\n const response = await this.#policy.execute(async () => {\n const localResponse = await this.#fetch(this.#url);\n if (!localResponse.ok) {\n throw new HttpError(\n localResponse.status,\n `Geolocation fetch failed: ${localResponse.status}`,\n );\n }\n return localResponse;\n });\n\n const raw = (await response.text()).trim();\n const location = /^[A-Z]{2}(-[A-Z0-9]{1,3})?$/u.test(raw)\n ? raw\n : UNKNOWN_LOCATION;\n\n if (location !== UNKNOWN_LOCATION) {\n this.#cachedLocation = location;\n this.#lastFetchedAt = Date.now();\n }\n\n return location;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/geolocation-controller",
3
- "version": "0.1.0-preview-8c978cc75",
3
+ "version": "0.1.1-preview-ccd74c3b",
4
4
  "description": "Centralised geolocation controller with TTL caching and request deduplication",
5
5
  "keywords": [
6
6
  "MetaMask",