{"version":3,"file":"MultichainAccountGroup.mjs","sourceRoot":"","sources":["../src/MultichainAccountGroup.ts"],"names":[],"mappings":"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","sourcesContent":["import { AccountGroupType, select, selectOne } from '@metamask/account-api';\nimport {\n  toMultichainAccountGroupId,\n  type MultichainAccountGroupId,\n  type MultichainAccountGroup as MultichainAccountGroupDefinition,\n} from '@metamask/account-api';\nimport type { Bip44Account } from '@metamask/account-api';\nimport type { AccountSelector } from '@metamask/account-api';\nimport type { AccountProvider } from '@metamask/account-api';\nimport { type KeyringAccount } from '@metamask/keyring-api';\n\nimport type { MultichainAccountWallet } from './MultichainAccountWallet';\n\n/**\n * A multichain account group that holds multiple accounts.\n */\nexport class MultichainAccountGroup<\n  Account extends Bip44Account<KeyringAccount>,\n> implements MultichainAccountGroupDefinition<Account>\n{\n  readonly #id: MultichainAccountGroupId;\n\n  readonly #wallet: MultichainAccountWallet<Account>;\n\n  readonly #groupIndex: number;\n\n  readonly #providers: AccountProvider<Account>[];\n\n  readonly #providerToAccounts: Map<AccountProvider<Account>, Account['id'][]>;\n\n  readonly #accountToProvider: Map<Account['id'], AccountProvider<Account>>;\n\n  constructor({\n    groupIndex,\n    wallet,\n    providers,\n  }: {\n    groupIndex: number;\n    wallet: MultichainAccountWallet<Account>;\n    providers: AccountProvider<Account>[];\n  }) {\n    this.#id = toMultichainAccountGroupId(wallet.id, groupIndex);\n    this.#groupIndex = groupIndex;\n    this.#wallet = wallet;\n    this.#providers = providers;\n    this.#providerToAccounts = new Map();\n    this.#accountToProvider = new Map();\n\n    this.sync();\n  }\n\n  /**\n   * Force multichain account synchronization.\n   *\n   * This can be used if account providers got new accounts that the multichain\n   * account doesn't know about.\n   */\n  sync(): void {\n    // Clear reverse mapping and re-construct it entirely based on the refreshed\n    // list of accounts from each providers.\n    this.#accountToProvider.clear();\n\n    for (const provider of this.#providers) {\n      // Filter account only for that index.\n      const accounts = [];\n      for (const account of provider.getAccounts()) {\n        if (\n          account.options.entropy.id === this.wallet.entropySource &&\n          account.options.entropy.groupIndex === this.groupIndex\n        ) {\n          // We only use IDs to always fetch the latest version of accounts.\n          accounts.push(account.id);\n        }\n      }\n      this.#providerToAccounts.set(provider, accounts);\n\n      // Reverse-mapping for fast indexing.\n      for (const id of accounts) {\n        this.#accountToProvider.set(id, provider);\n      }\n    }\n  }\n\n  /**\n   * Gets the multichain account group ID.\n   *\n   * @returns The multichain account group ID.\n   */\n  get id(): MultichainAccountGroupId {\n    return this.#id;\n  }\n\n  /**\n   * Gets the multichain account group type.\n   *\n   * @returns The multichain account type.\n   */\n  get type(): AccountGroupType.MultichainAccount {\n    return AccountGroupType.MultichainAccount;\n  }\n\n  /**\n   * Gets the multichain account's wallet reference (parent).\n   *\n   * @returns The multichain account's wallet.\n   */\n  get wallet(): MultichainAccountWallet<Account> {\n    return this.#wallet;\n  }\n\n  /**\n   * Gets the multichain account group index.\n   *\n   * @returns The multichain account group index.\n   */\n  get groupIndex(): number {\n    return this.#groupIndex;\n  }\n\n  /**\n   * Checks if there's any underlying accounts for this multichain accounts.\n   *\n   * @returns True if there's any underlying accounts, false otherwise.\n   */\n  hasAccounts(): boolean {\n    // If there's anything in the reverse-map, it means we have some accounts.\n    return this.#accountToProvider.size > 0;\n  }\n\n  /**\n   * Gets the accounts for this multichain account.\n   *\n   * @returns The accounts.\n   */\n  getAccounts(): Account[] {\n    const allAccounts: Account[] = [];\n\n    for (const [provider, accounts] of this.#providerToAccounts.entries()) {\n      for (const id of accounts) {\n        const account = provider.getAccount(id);\n\n        if (account) {\n          // If for some reason we cannot get this account from the provider, it\n          // might means it has been deleted or something, so we just filter it\n          // out.\n          allAccounts.push(account);\n        }\n      }\n    }\n\n    return allAccounts;\n  }\n\n  /**\n   * Gets the account for a given account ID.\n   *\n   * @param id - Account ID.\n   * @returns The account or undefined if not found.\n   */\n  getAccount(id: Account['id']): Account | undefined {\n    const provider = this.#accountToProvider.get(id);\n\n    // If there's nothing in the map, it means we tried to get an account\n    // that does not belong to this multichain account.\n    if (!provider) {\n      return undefined;\n    }\n    return provider.getAccount(id);\n  }\n\n  /**\n   * Query an account matching the selector.\n   *\n   * @param selector - Query selector.\n   * @returns The account matching the selector or undefined if not matching.\n   * @throws If multiple accounts match the selector.\n   */\n  get(selector: AccountSelector<Account>): Account | undefined {\n    return selectOne(this.getAccounts(), selector);\n  }\n\n  /**\n   * Query accounts matching the selector.\n   *\n   * @param selector - Query selector.\n   * @returns The accounts matching the selector.\n   */\n  select(selector: AccountSelector<Account>): Account[] {\n    return select(this.getAccounts(), selector);\n  }\n\n  /**\n   * Align the multichain account group.\n   *\n   * This will create accounts for providers that don't have any accounts yet.\n   */\n  async align(): Promise<void> {\n    const results = await Promise.allSettled(\n      this.#providers.map((provider) => {\n        const accounts = this.#providerToAccounts.get(provider);\n        if (!accounts || accounts.length === 0) {\n          return provider.createAccounts({\n            entropySource: this.wallet.entropySource,\n            groupIndex: this.groupIndex,\n          });\n        }\n        return Promise.resolve();\n      }),\n    );\n\n    if (results.some((result) => result.status === 'rejected')) {\n      console.warn(\n        `Failed to fully align multichain account group for entropy ID: ${this.wallet.entropySource} and group index: ${this.groupIndex}, some accounts might be missing`,\n      );\n    }\n  }\n}\n"]}