diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 360764abba6..09f86241476 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -156,6 +156,7 @@ /packages/wallet/src/initialization/instances/remote-feature-flag-controller/ @MetaMask/extension-platform @MetaMask/mobile-platform @MetaMask/core-platform /packages/wallet/src/initialization/instances/seedless-onboarding-controller/ @MetaMask/web3auth /packages/wallet/src/initialization/instances/storage-service/ @MetaMask/extension-platform @MetaMask/mobile-platform @MetaMask/core-platform +/packages/wallet/src/initialization/instances/subscription-controller/ @MetaMask/web3auth /packages/wallet/src/initialization/instances/transaction-controller/ @MetaMask/confirmations ## Package Release related diff --git a/README.md b/README.md index e03df83f857..8eea8b0e7d4 100644 --- a/README.md +++ b/README.md @@ -657,6 +657,7 @@ linkStyle default opacity:0.5 wallet --> remote_feature_flag_controller; wallet --> seedless_onboarding_controller; wallet --> storage_service; + wallet --> subscription_controller; wallet --> transaction_controller; wallet_cli --> base_controller; wallet_cli --> remote_feature_flag_controller; diff --git a/codeowners.ts b/codeowners.ts index 2a864d499ba..8cbf7e00fe1 100644 --- a/codeowners.ts +++ b/codeowners.ts @@ -347,6 +347,7 @@ const PACKAGES: Record = { }, 'subscription-controller': { teams: ['@MetaMask/web3auth'], + initializationPath: 'subscription-controller', }, 'transaction-controller': { teams: ['@MetaMask/confirmations'], diff --git a/packages/wallet-cli/CHANGELOG.md b/packages/wallet-cli/CHANGELOG.md index e70a1ee28fa..3038a75231a 100644 --- a/packages/wallet-cli/CHANGELOG.md +++ b/packages/wallet-cli/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Wire the `subscriptionController` slot in the daemon wallet's instance options (`SubscriptionEnv.PRD` and `globalThis.fetch`), so the daemon initializes `SubscriptionController` with the wallet's required configuration ([#9598](https://github.com/MetaMask/core/pull/9598)) - Wire the `transactionController` slot in the daemon wallet's instance options, so the daemon runs the `TransactionController` with an explicit CLI-appropriate configuration (swaps processing disabled, no client hooks) rather than relying on the controller's implicit defaults ([#9509](https://github.com/MetaMask/core/pull/9509)) - Wire the `gasFeeController` slot in the daemon wallet's instance options, passing `clientId: 'cli'` so the CLI identifies itself to the gas estimation API, now that `@metamask/wallet` requires this option ([#9527](https://github.com/MetaMask/core/pull/9527)) - Add the `mm wallet unlock` command, which dispatches `KeyringController:submitPassword` over the daemon socket, allowing the keyring to be unlocked after a daemon start with no password or after a `mm daemon call KeyringController:setLocked` ([#8821](https://github.com/MetaMask/core/pull/8821)) diff --git a/packages/wallet-cli/src/daemon/wallet-factory.test.ts b/packages/wallet-cli/src/daemon/wallet-factory.test.ts index d50a2b4fd78..fc87b91b18f 100644 --- a/packages/wallet-cli/src/daemon/wallet-factory.test.ts +++ b/packages/wallet-cli/src/daemon/wallet-factory.test.ts @@ -3,6 +3,7 @@ import { InMemoryStorageAdapter } from '@metamask/storage-service'; import { AlwaysOnlineAdapter, importSecretRecoveryPhrase, + SubscriptionEnv, Wallet, } from '@metamask/wallet'; import { rmSync } from 'node:fs'; @@ -119,6 +120,10 @@ describe('createWallet', () => { expect(instanceOptions.storageService.storage).toBeInstanceOf( InMemoryStorageAdapter, ); + expect(instanceOptions.subscriptionController).toStrictEqual({ + env: SubscriptionEnv.PRD, + fetchFunction: globalThis.fetch, + }); expect(instanceOptions.transactionController?.disableSwaps).toBe(true); expect(instanceOptions.transactionController?.hooks).toStrictEqual({}); expect(ClientConfigApiService).toHaveBeenCalled(); diff --git a/packages/wallet-cli/src/daemon/wallet-factory.ts b/packages/wallet-cli/src/daemon/wallet-factory.ts index 832c16a155a..19bf254facf 100644 --- a/packages/wallet-cli/src/daemon/wallet-factory.ts +++ b/packages/wallet-cli/src/daemon/wallet-factory.ts @@ -9,6 +9,7 @@ import type { Json } from '@metamask/utils'; import { AlwaysOnlineAdapter, importSecretRecoveryPhrase, + SubscriptionEnv, Wallet, } from '@metamask/wallet'; import type { WalletOptions } from '@metamask/wallet'; @@ -65,6 +66,9 @@ export type CreateWalletResult = { * - `transactionController` — swaps processing disabled and no client hooks; * see the slot's inline comment for why the daemon relies on the * controller's defaults for everything else. + * - `subscriptionController` — production subscription API environment and + * platform `fetch`; authenticated calls require host `AuthenticationController` + * wiring on the wallet root messenger (not configured in the CLI). * * The optional `keyringController` slot is intentionally omitted so the * controller's built-in defaults (e.g. the PBKDF2 encryptor) apply. @@ -108,6 +112,10 @@ function buildInstanceOptions( storageService: { storage: new InMemoryStorageAdapter(), }, + subscriptionController: { + env: SubscriptionEnv.PRD, + fetchFunction: globalThis.fetch, + }, transactionController: { // The CLI exposes no swaps surface, so skip the swaps-specific // post-processing a full wallet client runs (mobile makes the same diff --git a/packages/wallet/CHANGELOG.md b/packages/wallet/CHANGELOG.md index 9eaa012500c..69a4899e610 100644 --- a/packages/wallet/CHANGELOG.md +++ b/packages/wallet/CHANGELOG.md @@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- **BREAKING** Wire `SubscriptionController` into the default wallet initialization ([#9598](https://github.com/MetaMask/core/pull/9598)) + - Adds a required `subscriptionController` slot to `instanceOptions` (`env`, `fetchFunction`; optional `subscriptionService`, `getAccessToken`, `captureException`, `pollingInterval`). + - Hosts must register `AuthenticationController` on the wallet root messenger for authenticated subscription API calls. + - Re-exports `Env` from `@metamask/subscription-controller` as `SubscriptionEnv` for `instanceOptions.subscriptionController.env`. + ## [8.0.0] ### Added diff --git a/packages/wallet/package.json b/packages/wallet/package.json index e9ebc5e43ae..4885e28d880 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -71,6 +71,7 @@ "@metamask/scure-bip39": "^2.1.1", "@metamask/seedless-onboarding-controller": "^10.1.0", "@metamask/storage-service": "^1.0.2", + "@metamask/subscription-controller": "^6.2.1", "@metamask/transaction-controller": "^69.2.1", "@metamask/utils": "^11.11.0" }, diff --git a/packages/wallet/src/Wallet.test.ts b/packages/wallet/src/Wallet.test.ts index e370c699aa0..82797300d37 100644 --- a/packages/wallet/src/Wallet.test.ts +++ b/packages/wallet/src/Wallet.test.ts @@ -2,6 +2,10 @@ import { getDefaultAddressBookControllerState } from '@metamask/address-book-con import { CONNECTIVITY_STATUSES } from '@metamask/connectivity-controller'; import { Messenger } from '@metamask/messenger'; import { InMemoryStorageAdapter } from '@metamask/storage-service'; +import { + Env, + getDefaultSubscriptionControllerState, +} from '@metamask/subscription-controller'; import { Json } from '@metamask/utils'; import { webcrypto } from 'crypto'; @@ -23,6 +27,11 @@ const REMOTE_FEATURE_FLAG_OPTIONS = { }, }; +const SUBSCRIPTION_CONTROLLER_OPTIONS = { + env: Env.DEV, + fetchFunction: globalThis.fetch, +}; + async function setupWallet(): Promise { const wallet = new Wallet({ instanceOptions: { @@ -39,6 +48,7 @@ async function setupWallet(): Promise { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); @@ -105,6 +115,7 @@ describe('Wallet', () => { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); @@ -157,6 +168,7 @@ describe('Wallet', () => { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); const { state } = wallet; @@ -203,6 +215,7 @@ describe('Wallet', () => { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); @@ -316,6 +329,7 @@ describe('Wallet', () => { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); @@ -351,6 +365,7 @@ describe('Wallet', () => { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); @@ -394,6 +409,7 @@ describe('Wallet', () => { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); @@ -454,6 +470,17 @@ describe('Wallet', () => { }); }); + describe('SubscriptionController', () => { + it('is wired and exposes its state on the wallet messenger', async () => { + const wallet = await setupWallet(); + + expect( + wallet.messenger.call('SubscriptionController:getState'), + ).toStrictEqual(getDefaultSubscriptionControllerState()); + expect(wallet.getInstance('SubscriptionController')).toBeDefined(); + }); + }); + describe('RemoteFeatureFlagController', () => { it('is wired and exposes its state on the wallet messenger', async () => { const wallet = await setupWallet(); @@ -494,6 +521,7 @@ describe('Wallet', () => { }), }, }, + subscriptionController: SUBSCRIPTION_CONTROLLER_OPTIONS, }, }); const { messenger } = wallet; diff --git a/packages/wallet/src/index.ts b/packages/wallet/src/index.ts index 50e9b004160..ef78fd60e5b 100644 --- a/packages/wallet/src/index.ts +++ b/packages/wallet/src/index.ts @@ -1,6 +1,7 @@ export { Wallet } from './Wallet.js'; export { AlwaysOnlineAdapter } from './initialization/instances/connectivity-controller/always-online-adapter.js'; export { importSecretRecoveryPhrase } from './utilities.js'; +export { Env as SubscriptionEnv } from '@metamask/subscription-controller'; export type { WalletOptions } from './types.js'; export type { DefaultActions, diff --git a/packages/wallet/src/initialization/instances/index.ts b/packages/wallet/src/initialization/instances/index.ts index d45bb0917b2..ac27041b6a1 100644 --- a/packages/wallet/src/initialization/instances/index.ts +++ b/packages/wallet/src/initialization/instances/index.ts @@ -9,4 +9,5 @@ export { passkeyController } from './passkey-controller/passkey-controller.js'; export { remoteFeatureFlagController } from './remote-feature-flag-controller/remote-feature-flag-controller.js'; export { seedlessOnboardingController } from './seedless-onboarding-controller/seedless-onboarding-controller.js'; export { storageService } from './storage-service/storage-service.js'; +export { subscriptionController } from './subscription-controller/subscription-controller.js'; export { transactionController } from './transaction-controller/transaction-controller.js'; diff --git a/packages/wallet/src/initialization/instances/subscription-controller/subscription-controller.test.ts b/packages/wallet/src/initialization/instances/subscription-controller/subscription-controller.test.ts new file mode 100644 index 00000000000..3f82d1a9f92 --- /dev/null +++ b/packages/wallet/src/initialization/instances/subscription-controller/subscription-controller.test.ts @@ -0,0 +1,249 @@ +import { Messenger } from '@metamask/messenger'; +import { + Env, + getDefaultSubscriptionControllerState, + SubscriptionController, +} from '@metamask/subscription-controller'; +import type { ISubscriptionService } from '@metamask/subscription-controller'; + +import { defaultConfigurations } from '../../defaults.js'; +import type { + DefaultActions, + DefaultEvents, + RootMessenger, +} from '../../defaults.js'; +import { subscriptionController } from './subscription-controller.js'; + +type ActionHandler = (...args: unknown[]) => unknown; + +type AnyMessenger = Messenger; + +function getRootMessenger(): RootMessenger { + return new Messenger({ namespace: 'Root' }); +} + +function registerActionHandler( + parent: RootMessenger, + namespace: string, + actionType: string, + handler: ActionHandler, +): void { + const messenger = new Messenger({ + namespace, + parent: parent as unknown as AnyMessenger, + }); + + ( + messenger as unknown as { + registerActionHandler(type: string, handler: ActionHandler): void; + } + ).registerActionHandler(actionType, handler); +} + +function createMockSubscriptionService(): jest.Mocked { + return { + getSubscriptions: jest.fn(), + getPricing: jest.fn(), + cancelSubscription: jest.fn(), + unCancelSubscription: jest.fn(), + startSubscriptionWithCard: jest.fn(), + startSubscriptionWithCrypto: jest.fn(), + getBillingPortalUrl: jest.fn(), + updatePaymentMethodCard: jest.fn(), + updatePaymentMethodCrypto: jest.fn(), + getSubscriptionsEligibilities: jest.fn(), + submitSponsorshipIntents: jest.fn(), + submitUserEvent: jest.fn(), + assignUserToCohort: jest.fn(), + linkRewards: jest.fn(), + }; +} + +describe('subscriptionController', () => { + it('is registered as a default initialization configuration', () => { + expect(Object.values(defaultConfigurations)).toContain( + subscriptionController, + ); + }); + + it('initializes a SubscriptionController with default state', () => { + const messenger = subscriptionController.getMessenger(getRootMessenger()); + + const instance = subscriptionController.init({ + state: undefined, + messenger, + options: { + env: Env.DEV, + fetchFunction: globalThis.fetch, + }, + }); + + expect(instance).toBeInstanceOf(SubscriptionController); + expect(instance.state).toStrictEqual( + getDefaultSubscriptionControllerState(), + ); + }); + + it('forwards the provided state to the controller', () => { + const messenger = subscriptionController.getMessenger(getRootMessenger()); + + const instance = subscriptionController.init({ + state: { + subscriptions: [], + customerId: 'cus_test', + trialedProducts: [], + }, + messenger, + options: { + env: Env.DEV, + fetchFunction: globalThis.fetch, + }, + }); + + expect(instance.state.customerId).toBe('cus_test'); + }); + + it('constructs a default SubscriptionService from options', () => { + const messenger = subscriptionController.getMessenger(getRootMessenger()); + + const instance = subscriptionController.init({ + state: undefined, + messenger, + options: { + env: Env.DEV, + fetchFunction: globalThis.fetch, + }, + }); + + expect(instance).toBeInstanceOf(SubscriptionController); + }); + + it('uses a provided subscriptionService override', () => { + const messenger = subscriptionController.getMessenger(getRootMessenger()); + const mockService = createMockSubscriptionService(); + + const instance = subscriptionController.init({ + state: undefined, + messenger, + options: { + subscriptionService: mockService, + env: Env.DEV, + fetchFunction: globalThis.fetch, + }, + }); + + expect(instance).toBeInstanceOf(SubscriptionController); + }); + + it('forwards pollingInterval to the controller', () => { + const messenger = subscriptionController.getMessenger(getRootMessenger()); + const pollingInterval = 60_000; + + const instance = subscriptionController.init({ + state: undefined, + messenger, + options: { + env: Env.DEV, + fetchFunction: globalThis.fetch, + pollingInterval, + }, + }); + + expect(instance.getIntervalLength()).toBe(pollingInterval); + }); + + it('defaults pollingInterval to five minutes', () => { + const messenger = subscriptionController.getMessenger(getRootMessenger()); + + const instance = subscriptionController.init({ + state: undefined, + messenger, + options: { + env: Env.DEV, + fetchFunction: globalThis.fetch, + }, + }); + + expect(instance.getIntervalLength()).toBe(5 * 60 * 1_000); + }); + + it('wires default getAccessToken to AuthenticationController:getBearerToken', async () => { + const rootMessenger = getRootMessenger(); + registerActionHandler( + rootMessenger, + 'AuthenticationController', + 'AuthenticationController:getBearerToken', + async () => 'test-bearer-token', + ); + registerActionHandler( + rootMessenger, + 'AuthenticationController', + 'AuthenticationController:performSignOut', + jest.fn(), + ); + const messenger = subscriptionController.getMessenger(rootMessenger); + const fetchFunction = jest.fn( + async () => + new globalThis.Response( + JSON.stringify({ + customerId: 'cus_1', + subscriptions: [], + trialedProducts: [], + }), + { status: 200 }, + ), + ); + + subscriptionController.init({ + state: undefined, + messenger, + options: { + env: Env.DEV, + fetchFunction, + }, + }); + + await rootMessenger.call('SubscriptionController:getSubscriptions'); + + expect(fetchFunction).toHaveBeenCalled(); + const [, requestInit] = fetchFunction.mock.calls[0] as [ + string, + RequestInit, + ]; + const headers = new globalThis.Headers(requestInit.headers); + expect(headers.get('Authorization')).toBe('Bearer test-bearer-token'); + }); + + it('delegates AuthenticationController actions and events', () => { + const parent = getRootMessenger(); + const delegateSpy = jest.spyOn(parent, 'delegate'); + const messenger = subscriptionController.getMessenger(parent); + + expect(delegateSpy).toHaveBeenCalledWith({ + messenger, + actions: [ + 'AuthenticationController:getBearerToken', + 'AuthenticationController:performSignOut', + ], + events: ['AuthenticationController:stateChange'], + }); + }); + + it('exposes its actions through the root messenger', () => { + const rootMessenger = getRootMessenger(); + const messenger = subscriptionController.getMessenger(rootMessenger); + + subscriptionController.init({ + state: undefined, + messenger, + options: { + env: Env.DEV, + fetchFunction: globalThis.fetch, + }, + }); + + expect(rootMessenger.call('SubscriptionController:getState')).toStrictEqual( + getDefaultSubscriptionControllerState(), + ); + }); +}); diff --git a/packages/wallet/src/initialization/instances/subscription-controller/subscription-controller.ts b/packages/wallet/src/initialization/instances/subscription-controller/subscription-controller.ts new file mode 100644 index 00000000000..0d52e586a4f --- /dev/null +++ b/packages/wallet/src/initialization/instances/subscription-controller/subscription-controller.ts @@ -0,0 +1,86 @@ +import { Messenger } from '@metamask/messenger'; +import type { + ISubscriptionService, + SubscriptionControllerMessenger, + SubscriptionControllerState, +} from '@metamask/subscription-controller'; +import { + SubscriptionController, + SubscriptionService, +} from '@metamask/subscription-controller'; + +import type { InitializationConfiguration } from '../../types.js'; +import type { SubscriptionControllerInstanceOptions } from './types.js'; + +export type { SubscriptionControllerInstanceOptions } from './types.js'; + +function resolveSubscriptionService( + messenger: SubscriptionControllerMessenger, + options: SubscriptionControllerInstanceOptions, +): ISubscriptionService { + if (options.subscriptionService) { + return options.subscriptionService; + } + + const getAccessToken = + options.getAccessToken ?? + ((): Promise => + messenger.call('AuthenticationController:getBearerToken')); + + return new SubscriptionService({ + env: options.env, + auth: { getAccessToken }, + fetchFunction: options.fetchFunction, + captureException: options.captureException, + }); +} + +export const subscriptionController: InitializationConfiguration< + SubscriptionController, + SubscriptionControllerMessenger +> = { + name: 'SubscriptionController', + init: ({ + state, + messenger, + options, + }: { + state: Partial | undefined; + messenger: SubscriptionControllerMessenger; + options: SubscriptionControllerInstanceOptions; + }) => { + const { pollingInterval, ...serviceOptions } = options; + + return new SubscriptionController({ + messenger, + state, + subscriptionService: resolveSubscriptionService( + messenger, + serviceOptions, + ), + pollingInterval, + }); + }, + getMessenger: (parent) => { + const messenger: SubscriptionControllerMessenger = new Messenger({ + namespace: 'SubscriptionController', + parent, + }); + + parent.delegate({ + messenger, + actions: [ + 'AuthenticationController:getBearerToken', + 'AuthenticationController:performSignOut', + ], + events: [ + // SubscriptionController subscribes to :stateChange internally; the + // delegation must match until that package migrates to :stateChanged. + // eslint-disable-next-line no-restricted-syntax + 'AuthenticationController:stateChange', + ], + }); + + return messenger; + }, +}; diff --git a/packages/wallet/src/initialization/instances/subscription-controller/types.ts b/packages/wallet/src/initialization/instances/subscription-controller/types.ts new file mode 100644 index 00000000000..392b8e8fde9 --- /dev/null +++ b/packages/wallet/src/initialization/instances/subscription-controller/types.ts @@ -0,0 +1,18 @@ +import type { + Env, + ISubscriptionService, +} from '@metamask/subscription-controller'; + +export type SubscriptionControllerInstanceOptions = { + /** + * When set, used as-is; `env`, `fetchFunction`, `getAccessToken`, and + * `captureException` are ignored for service construction. + */ + subscriptionService?: ISubscriptionService; + /** Required when building the default `SubscriptionService`. */ + env: Env; + fetchFunction: typeof fetch; + getAccessToken?: () => Promise; + captureException?: (error: Error) => void; + pollingInterval?: number; +}; diff --git a/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts b/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts index a3831f1b973..4835c322a19 100644 --- a/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts +++ b/packages/wallet/src/initialization/instances/transaction-controller/transaction-controller.test.ts @@ -1,5 +1,6 @@ import { Messenger } from '@metamask/messenger'; import { InMemoryStorageAdapter } from '@metamask/storage-service'; +import { Env } from '@metamask/subscription-controller'; import { TransactionController } from '@metamask/transaction-controller'; import type { WalletOptions } from '../../../types.js'; @@ -125,6 +126,10 @@ function getInstanceOptions(): WalletOptions['instanceOptions'] { storage: new InMemoryStorageAdapter(), }, remoteFeatureFlagController: REMOTE_FEATURE_FLAG_OPTIONS, + subscriptionController: { + env: Env.DEV, + fetchFunction: globalThis.fetch, + }, }; } diff --git a/packages/wallet/src/types.ts b/packages/wallet/src/types.ts index 978bf1b1afd..73459ee9614 100644 --- a/packages/wallet/src/types.ts +++ b/packages/wallet/src/types.ts @@ -14,6 +14,7 @@ import type { PasskeyControllerInstanceOptions } from './initialization/instance import type { RemoteFeatureFlagControllerInstanceOptions } from './initialization/instances/remote-feature-flag-controller/types.js'; import type { SeedlessOnboardingControllerInstanceOptions } from './initialization/instances/seedless-onboarding-controller/types.js'; import type { StorageServiceInstanceOptions } from './initialization/instances/storage-service/types.js'; +import type { SubscriptionControllerInstanceOptions } from './initialization/instances/subscription-controller/types.js'; import type { TransactionControllerInstanceOptions } from './initialization/instances/transaction-controller/types.js'; import type { InitializationConfiguration } from './initialization/types.js'; @@ -35,6 +36,7 @@ export type InstanceSpecificOptions = { networkController: NetworkControllerInstanceOptions; remoteFeatureFlagController: RemoteFeatureFlagControllerInstanceOptions; storageService: StorageServiceInstanceOptions; + subscriptionController: SubscriptionControllerInstanceOptions; transactionController?: TransactionControllerInstanceOptions; passkeyController?: PasskeyControllerInstanceOptions; seedlessOnboardingController?: SeedlessOnboardingControllerInstanceOptions; diff --git a/packages/wallet/tsconfig.build.json b/packages/wallet/tsconfig.build.json index dae6d88285a..435fe7872f1 100644 --- a/packages/wallet/tsconfig.build.json +++ b/packages/wallet/tsconfig.build.json @@ -20,6 +20,7 @@ { "path": "../remote-feature-flag-controller/tsconfig.build.json" }, { "path": "../seedless-onboarding-controller/tsconfig.build.json" }, { "path": "../storage-service/tsconfig.build.json" }, + { "path": "../subscription-controller/tsconfig.build.json" }, { "path": "../transaction-controller/tsconfig.build.json" } ], "include": ["../../types", "./src"] diff --git a/packages/wallet/tsconfig.json b/packages/wallet/tsconfig.json index 10221177468..a6db377460a 100644 --- a/packages/wallet/tsconfig.json +++ b/packages/wallet/tsconfig.json @@ -46,6 +46,9 @@ { "path": "../storage-service" }, + { + "path": "../subscription-controller" + }, { "path": "../transaction-controller" } diff --git a/yarn.lock b/yarn.lock index 97d8dc6c6d9..5aa35f64d1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8962,7 +8962,7 @@ __metadata: languageName: unknown linkType: soft -"@metamask/subscription-controller@workspace:packages/subscription-controller": +"@metamask/subscription-controller@npm:^6.2.1, @metamask/subscription-controller@workspace:packages/subscription-controller": version: 0.0.0-use.local resolution: "@metamask/subscription-controller@workspace:packages/subscription-controller" dependencies: @@ -9271,6 +9271,7 @@ __metadata: "@metamask/scure-bip39": "npm:^2.1.1" "@metamask/seedless-onboarding-controller": "npm:^10.1.0" "@metamask/storage-service": "npm:^1.0.2" + "@metamask/subscription-controller": "npm:^6.2.1" "@metamask/transaction-controller": "npm:^69.2.1" "@metamask/utils": "npm:^11.11.0" "@ts-bridge/cli": "npm:^0.6.4"