{"version":3,"file":"create-auto-managed-network-client.mjs","sourceRoot":"","sources":["../src/create-auto-managed-network-client.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PollingBlockTrackerOptions } from '@metamask/eth-block-tracker';\nimport { Json } from '@metamask/utils';\nimport type { Logger } from 'loglevel';\n\nimport type { NetworkClient } from './create-network-client';\nimport { createNetworkClient } from './create-network-client';\nimport type {\n  NetworkClientId,\n  NetworkControllerMessenger,\n} from './NetworkController';\nimport type { RpcServiceOptions } from './rpc-service/rpc-service';\nimport type {\n  BlockTracker,\n  NetworkClientConfiguration,\n  Provider,\n} from './types';\n\n/**\n * The name of the method on both the provider and block tracker proxy which can\n * be used to get the underlying provider or block tracker from the network\n * client, when it is initialized.\n */\nconst REFLECTIVE_PROPERTY_NAME = '__target__';\n\n/**\n * Represents a proxy object which wraps a target object. As a proxy, it allows\n * for accessing and setting all of the properties that the target object\n * supports, but also supports an extra propertyName (`__target__`) to access\n * the target itself.\n *\n * @template Type - The type of the target object. It is assumed that this type\n * will be constant even when the target is swapped.\n */\nexport type ProxyWithAccessibleTarget<TargetType> = TargetType & {\n  [REFLECTIVE_PROPERTY_NAME]: TargetType;\n};\n\n/**\n * An object that provides the same interface as a network client but where the\n * network client is not initialized until either the provider or block tracker\n * is first accessed.\n */\nexport type AutoManagedNetworkClient<\n  Configuration extends NetworkClientConfiguration,\n> = {\n  configuration: Configuration;\n  provider: ProxyWithAccessibleTarget<Provider>;\n  blockTracker: ProxyWithAccessibleTarget<BlockTracker>;\n  destroy: () => void;\n  enableRpcFailover: () => void;\n  disableRpcFailover: () => void;\n};\n\n/**\n * By default, the provider and block provider proxies will point to nothing.\n * This is impossible when using the Proxy API, as the target object has to be\n * something, so this object represents that \"something\".\n */\nconst UNINITIALIZED_TARGET = { __UNINITIALIZED__: true };\n\n/**\n * This function creates two proxies, one that wraps a provider and another that\n * wraps a block tracker. These proxies are unique in that both will be \"empty\"\n * at first; that is, neither will point to a functional provider or block\n * tracker. Instead, as soon as a method or event is accessed on either object\n * that requires a network request to function, a network client is created on\n * the fly and the method or event in question is then forwarded to whichever\n * part of the network client is serving as the receiver. The network client is\n * then cached for subsequent usages.\n *\n * @param args - The arguments.\n * @param args.networkClientId - The ID that will be assigned to the new network\n * client in the registry.\n * @param args.networkClientConfiguration - The configuration object that will be\n * used to instantiate the network client when it is needed.\n * @param args.getRpcServiceOptions - Factory for constructing RPC service\n * options. See {@link NetworkControllerOptions.getRpcServiceOptions}.\n * @param args.getBlockTrackerOptions - Factory for constructing block tracker\n * options. See {@link NetworkControllerOptions.getBlockTrackerOptions}.\n * @param args.messenger - The network controller messenger.\n * @param args.isRpcFailoverEnabled - Whether or not requests sent to the\n * primary RPC endpoint for this network should be automatically diverted to\n * provided failover endpoints if the primary is unavailable.\n * @param args.logger - A `loglevel` logger.\n * @returns The auto-managed network client.\n */\nexport function createAutoManagedNetworkClient<\n  Configuration extends NetworkClientConfiguration,\n>({\n  networkClientId,\n  networkClientConfiguration,\n  getRpcServiceOptions,\n  getBlockTrackerOptions = (): Omit<\n    PollingBlockTrackerOptions,\n    'provider'\n  > => ({}),\n  messenger,\n  isRpcFailoverEnabled: givenIsRpcFailoverEnabled,\n  logger,\n}: {\n  networkClientId: NetworkClientId;\n  networkClientConfiguration: Configuration;\n  getRpcServiceOptions: (\n    rpcEndpointUrl: string,\n  ) => Omit<RpcServiceOptions, 'failoverService' | 'endpointUrl'>;\n  getBlockTrackerOptions?: (\n    rpcEndpointUrl: string,\n  ) => Omit<PollingBlockTrackerOptions, 'provider'>;\n  messenger: NetworkControllerMessenger;\n  isRpcFailoverEnabled: boolean;\n  logger?: Logger;\n}): AutoManagedNetworkClient<Configuration> {\n  let isRpcFailoverEnabled = givenIsRpcFailoverEnabled;\n  let networkClient: NetworkClient | undefined;\n\n  const ensureNetworkClientCreated = (): NetworkClient => {\n    networkClient ??= createNetworkClient({\n      id: networkClientId,\n      configuration: networkClientConfiguration,\n      getRpcServiceOptions,\n      getBlockTrackerOptions,\n      messenger,\n      isRpcFailoverEnabled,\n      logger,\n    });\n\n    if (networkClient === undefined) {\n      throw new Error(\n        \"It looks like `createNetworkClient` didn't return anything. Perhaps it's being mocked?\",\n      );\n    }\n\n    return networkClient;\n  };\n\n  const providerProxy = new Proxy(UNINITIALIZED_TARGET, {\n    get(\n      _target: unknown,\n      propertyName: PropertyKey,\n      receiver: unknown,\n    ):\n      | Provider\n      | ((this: unknown, ...args: unknown[]) => Promise<Json> | undefined)\n      | undefined {\n      if (propertyName === REFLECTIVE_PROPERTY_NAME) {\n        return networkClient?.provider;\n      }\n\n      const { provider } = ensureNetworkClientCreated();\n\n      if (propertyName in provider) {\n        // Typecast: We know that `[propertyName]` is a propertyName on\n        // `provider`.\n        const value = provider[propertyName as keyof typeof provider];\n        if (typeof value === 'function') {\n          // Ensure that the method on the provider is called with `this` as\n          // the target, *not* the proxy (which happens by default) —\n          // this allows private properties to be accessed\n          return function (this: unknown, ...args: unknown[]): Promise<Json> {\n            // @ts-expect-error We don't care that `this` may not be compatible\n            // with the signature of the method being called, as technically\n            // it can be anything.\n            return value.apply(this === receiver ? provider : this, args);\n          };\n        }\n        return value;\n      }\n\n      return undefined;\n    },\n\n    // TODO: Replace `any` with type\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    has(_target: any, propertyName: PropertyKey): boolean {\n      if (propertyName === REFLECTIVE_PROPERTY_NAME) {\n        return true;\n      }\n      const { provider } = ensureNetworkClientCreated();\n      return propertyName in provider;\n    },\n  });\n\n  const blockTrackerProxy: ProxyWithAccessibleTarget<BlockTracker> = new Proxy(\n    UNINITIALIZED_TARGET,\n    {\n      get(\n        _target: unknown,\n        propertyName: PropertyKey,\n        receiver: unknown,\n      ):\n        | BlockTracker\n        | ((this: unknown, ...args: unknown[]) => unknown)\n        | undefined {\n        if (propertyName === REFLECTIVE_PROPERTY_NAME) {\n          return networkClient?.blockTracker;\n        }\n\n        const { blockTracker } = ensureNetworkClientCreated();\n\n        if (propertyName in blockTracker) {\n          // Typecast: We know that `[propertyName]` is a propertyName on\n          // `provider`.\n          const value = blockTracker[propertyName as keyof typeof blockTracker];\n          if (typeof value === 'function') {\n            // Ensure that the method on the provider is called with `this` as\n            // the target, *not* the proxy (which happens by default) —\n            // this allows private properties to be accessed\n            return function (this: unknown, ...args: unknown[]) {\n              // @ts-expect-error We don't care that `this` may not be\n              // compatible with the signature of the method being called, as\n              // technically it can be anything.\n              return value.apply(this === receiver ? blockTracker : this, args);\n            };\n          }\n          return value;\n        }\n\n        return undefined;\n      },\n\n      // TODO: Replace `any` with type\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      has(_target: any, propertyName: PropertyKey): boolean {\n        if (propertyName === REFLECTIVE_PROPERTY_NAME) {\n          return true;\n        }\n        const { blockTracker } = ensureNetworkClientCreated();\n        return propertyName in blockTracker;\n      },\n    },\n  );\n\n  const destroy = (): void => {\n    networkClient?.destroy();\n  };\n\n  const enableRpcFailover = (): void => {\n    isRpcFailoverEnabled = true;\n    destroy();\n    networkClient = undefined;\n  };\n\n  const disableRpcFailover = (): void => {\n    isRpcFailoverEnabled = false;\n    destroy();\n    networkClient = undefined;\n  };\n\n  return {\n    configuration: networkClientConfiguration,\n    provider: providerProxy,\n    blockTracker: blockTrackerProxy,\n    destroy,\n    enableRpcFailover,\n    disableRpcFailover,\n  };\n}\n"]}