{"version":3,"file":"ExecutionService.cjs","sourceRoot":"","sources":["../../src/services/ExecutionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { asV2Middleware } from '@metamask/json-rpc-engine';\nimport { JsonRpcEngineV2 as JsonRpcEngine } from '@metamask/json-rpc-engine/v2';\nimport { createStreamMiddleware } from '@metamask/json-rpc-middleware-stream';\nimport type { Messenger } from '@metamask/messenger';\nimport type ObjectMultiplex from '@metamask/object-multiplex';\nimport type { BasePostMessageStream } from '@metamask/post-message-stream';\nimport type { SnapRpcHookArgs } from '@metamask/snaps-utils';\nimport { SNAP_STREAM_NAMES, logError, logWarning } from '@metamask/snaps-utils';\nimport type {\n  Json,\n  JsonRpcNotification,\n  JsonRpcRequest,\n} from '@metamask/utils';\nimport {\n  Duration,\n  assertIsJsonRpcRequest,\n  hasProperty,\n  inMilliseconds,\n} from '@metamask/utils';\nimport { nanoid } from 'nanoid';\nimport { pipeline } from 'readable-stream';\nimport type { Duplex } from 'readable-stream';\n\nimport type { ExecutionServiceMethodActions } from './ExecutionService-method-action-types';\nimport { setupMultiplex } from './multiplex';\nimport { log } from '../logging';\nimport { Timer } from '../snaps/Timer';\nimport { hasTimedOut, withTimeout } from '../utils';\n\nconst serviceName = 'ExecutionService';\n\nexport type SetupSnapProvider = (snapId: string, stream: Duplex) => void;\n\nexport type ExecutionServiceArgs = {\n  setupSnapProvider: SetupSnapProvider;\n  messenger: ExecutionServiceMessenger;\n  initTimeout?: number;\n  pingTimeout?: number;\n  terminationTimeout?: number;\n  usePing?: boolean;\n};\n\ntype JobStreams = {\n  command: Duplex;\n  rpc: Duplex;\n  connection: BasePostMessageStream;\n  mux: ObjectMultiplex;\n};\n\nexport type Job<WorkerType> = {\n  id: string;\n  streams: JobStreams;\n  rpcEngine: JsonRpcEngine<JsonRpcRequest>;\n  worker: WorkerType;\n};\n\nexport type TerminateJobArgs<WorkerType> = Partial<Job<WorkerType>> &\n  Pick<Job<WorkerType>, 'id'>;\n\n/**\n Statuses used for diagnostic purposes\n - created: The initial state, no initialization has started\n - initializing: Snap execution environment is initializing\n - initialized: Snap execution environment has initialized\n - executing: Snap source code is being executed\n - running: Snap executed and ready for RPC requests\n */\ntype ExecutionStatus =\n  | 'created'\n  | 'initializing'\n  | 'initialized'\n  | 'executing'\n  | 'running';\n\nconst MESSENGER_EXPOSED_METHODS = [\n  'terminateSnap',\n  'terminateAllSnaps',\n  'executeSnap',\n  'handleRpcRequest',\n] as const;\n\nexport type SnapExecutionData = {\n  snapId: string;\n  sourceCode: string;\n  endowments: Json;\n};\n\nexport type SnapErrorJson = {\n  message: string;\n  code: number;\n  data?: Json;\n};\n\nexport type ExecutionServiceUnhandledErrorEvent = {\n  type: 'ExecutionService:unhandledError';\n  payload: [string, SnapErrorJson];\n};\n\nexport type ExecutionServiceOutboundRequestEvent = {\n  type: 'ExecutionService:outboundRequest';\n  payload: [string];\n};\n\nexport type ExecutionServiceOutboundResponseEvent = {\n  type: 'ExecutionService:outboundResponse';\n  payload: [string];\n};\n\nexport type ExecutionServiceEvents =\n  | ExecutionServiceUnhandledErrorEvent\n  | ExecutionServiceOutboundRequestEvent\n  | ExecutionServiceOutboundResponseEvent;\n\nexport type ExecutionServiceActions = ExecutionServiceMethodActions;\n\nexport type ExecutionServiceMessenger = Messenger<\n  'ExecutionService',\n  ExecutionServiceActions,\n  ExecutionServiceEvents\n>;\n\nexport abstract class ExecutionService<WorkerType = unknown> {\n  name: typeof serviceName = serviceName;\n\n  state = null;\n\n  readonly #jobs: Map<string, Job<WorkerType>>;\n\n  readonly #status: Map<string, ExecutionStatus>;\n\n  readonly #setupSnapProvider: SetupSnapProvider;\n\n  readonly #messenger: ExecutionServiceMessenger;\n\n  readonly #initTimeout: number;\n\n  readonly #pingTimeout: number;\n\n  readonly #terminationTimeout: number;\n\n  readonly #usePing: boolean;\n\n  constructor({\n    setupSnapProvider,\n    messenger,\n    initTimeout = inMilliseconds(60, Duration.Second),\n    pingTimeout = inMilliseconds(10, Duration.Second),\n    terminationTimeout = inMilliseconds(1, Duration.Second),\n    usePing = true,\n  }: ExecutionServiceArgs) {\n    this.#jobs = new Map();\n    this.#status = new Map();\n    this.#setupSnapProvider = setupSnapProvider;\n    this.#messenger = messenger;\n    this.#initTimeout = initTimeout;\n    this.#pingTimeout = pingTimeout;\n    this.#terminationTimeout = terminationTimeout;\n    this.#usePing = usePing;\n\n    this.#messenger.registerMethodActionHandlers(\n      this,\n      MESSENGER_EXPOSED_METHODS,\n    );\n  }\n\n  /**\n   * Performs additional necessary work during job termination. **MUST** be\n   * implemented by concrete implementations. See\n   * {@link AbstractExecutionService.terminate} for details.\n   *\n   * @param job - The object corresponding to the job to be terminated.\n   */\n  protected abstract terminateJob(\n    job: TerminateJobArgs<WorkerType>,\n  ): Promise<void>;\n\n  /**\n   * Terminates the Snap with the specified ID and deletes all its associated\n   * data. Any subsequent messages targeting the Snap will fail with an error.\n   * Throws an error if termination fails unexpectedly.\n   *\n   * @param snapId - The id of the Snap to be terminated.\n   */\n  public async terminateSnap(snapId: string): Promise<void> {\n    const job = this.#jobs.get(snapId);\n    if (!job) {\n      return;\n    }\n\n    try {\n      // Ping worker and tell it to run teardown, continue with termination if it takes too long\n      const result = await withTimeout(\n        this.#command(snapId, {\n          jsonrpc: '2.0',\n          method: 'terminate',\n          id: nanoid(),\n        }),\n        this.#terminationTimeout,\n      );\n\n      if (result === hasTimedOut || result !== 'OK') {\n        logWarning(`Snap \"${snapId}\" failed to terminate gracefully.`);\n      }\n    } catch {\n      // Ignore\n    }\n\n    Object.values(job.streams).forEach((stream) => {\n      try {\n        if (!stream.destroyed) {\n          stream.destroy();\n        }\n      } catch (error) {\n        logError('Error while destroying stream', error);\n      }\n    });\n\n    await this.terminateJob(job);\n\n    this.#jobs.delete(snapId);\n    this.#status.delete(snapId);\n    log(`Snap \"${snapId}\" terminated.`);\n  }\n\n  /**\n   * Initiates a job for a Snap.\n   *\n   * @param snapId - The ID of the Snap to initiate a job for.\n   * @param timer - The timer to use for timeouts.\n   * @returns Information regarding the created job.\n   * @throws If the execution service returns an error or execution times out.\n   */\n  async #initJob(snapId: string, timer: Timer): Promise<Job<WorkerType>> {\n    const { streams, worker } = await this.#initStreams(snapId, timer);\n\n    const jsonRpcConnection = createStreamMiddleware();\n\n    pipeline(\n      jsonRpcConnection.stream,\n      streams.command,\n      jsonRpcConnection.stream,\n      (error) => {\n        if (error && !error.message?.match('Premature close')) {\n          logError(`Command stream failure.`, error);\n        }\n      },\n    );\n\n    const rpcEngine = JsonRpcEngine.create({\n      middleware: [asV2Middleware(jsonRpcConnection.middleware)],\n    });\n\n    const envMetadata = {\n      id: snapId,\n      streams,\n      rpcEngine,\n      worker,\n    };\n    this.#jobs.set(snapId, envMetadata);\n\n    return envMetadata;\n  }\n\n  /**\n   * Sets up the streams for an initiated job.\n   *\n   * @param snapId - The Snap ID.\n   * @param timer - The timer to use for timeouts.\n   * @returns The streams to communicate with the worker and the worker itself.\n   * @throws If the execution service returns an error or execution times out.\n   */\n  async #initStreams(\n    snapId: string,\n    timer: Timer,\n  ): Promise<{ streams: JobStreams; worker: WorkerType }> {\n    const result = await withTimeout(this.initEnvStream(snapId), timer);\n\n    if (result === hasTimedOut) {\n      // For certain environments, such as the iframe we may have already created the worker and wish to terminate it.\n      await this.terminateJob({ id: snapId });\n\n      const status = this.#status.get(snapId);\n      if (status === 'created') {\n        // Currently this error can only be thrown by OffscreenExecutionService.\n        throw new Error(\n          `The executor for \"${snapId}\" couldn't start initialization. The offscreen document may not exist.`,\n        );\n      }\n      throw new Error(\n        `The executor for \"${snapId}\" failed to initialize. The iframe/webview/worker failed to load.`,\n      );\n    }\n\n    const { worker, stream: envStream } = result;\n    const mux = setupMultiplex(envStream, `Snap: \"${snapId}\"`);\n    const commandStream = mux.createStream(SNAP_STREAM_NAMES.COMMAND);\n\n    // Handle out-of-band errors, i.e. errors thrown from the Snap outside of the req/res cycle.\n    // Also keep track of outbound request/responses\n    const notificationHandler = (\n      message:\n        | JsonRpcRequest\n        | JsonRpcNotification<Json[] | Record<string, Json>>,\n    ) => {\n      if (hasProperty(message, 'id')) {\n        return;\n      }\n\n      if (message.method === 'OutboundRequest') {\n        this.#messenger.publish('ExecutionService:outboundRequest', snapId);\n      } else if (message.method === 'OutboundResponse') {\n        this.#messenger.publish('ExecutionService:outboundResponse', snapId);\n      } else if (message.method === 'UnhandledError') {\n        this.#messenger.publish(\n          'ExecutionService:unhandledError',\n          snapId,\n          (message.params as { error: SnapErrorJson }).error,\n        );\n        commandStream.removeListener('data', notificationHandler);\n      } else {\n        logError(\n          new Error(\n            `Received unexpected command stream notification \"${message.method}\".`,\n          ),\n        );\n      }\n    };\n\n    commandStream.on('data', notificationHandler);\n\n    const rpcStream = mux\n      .createStream(SNAP_STREAM_NAMES.JSON_RPC)\n      .setMaxListeners(20);\n\n    rpcStream.on('data', (chunk) => {\n      if (chunk?.data && hasProperty(chunk?.data, 'id')) {\n        this.#messenger.publish('ExecutionService:outboundRequest', snapId);\n      }\n    });\n\n    // An error handler is not attached to the RPC stream until `setupSnapProvider` is called.\n    // We must set it up here to prevent errors from bubbling up if the stream is destroyed before then.\n    rpcStream.on('error', (error) => {\n      if (error && !error.message?.match('Premature close')) {\n        logError(`Snap: \"${snapId}\" - RPC stream failure:`, error);\n      }\n    });\n\n    const originalWrite = rpcStream.write.bind(rpcStream);\n\n    // @ts-expect-error Hack to inspect the messages being written to the stream.\n    rpcStream.write = (chunk, encoding, callback) => {\n      // Ignore chain switching notifications as it doesn't matter for the SnapProvider.\n      if (chunk?.data?.method === 'metamask_chainChanged') {\n        return true;\n      }\n\n      if (chunk?.data && hasProperty(chunk?.data, 'id')) {\n        this.#messenger.publish('ExecutionService:outboundResponse', snapId);\n      }\n\n      return originalWrite(chunk, encoding, callback);\n    };\n\n    return {\n      streams: {\n        command: commandStream,\n        rpc: rpcStream,\n        connection: envStream,\n        mux,\n      },\n      worker,\n    };\n  }\n\n  /**\n   * Abstract function implemented by implementing class that spins up a new worker for a job.\n   *\n   * Depending on the execution environment, this may run forever if the Snap fails to start up properly, therefore any call to this function should be wrapped in a timeout.\n   */\n  protected abstract initEnvStream(snapId: string): Promise<{\n    worker: WorkerType;\n    stream: BasePostMessageStream;\n  }>;\n\n  /**\n   * Set the execution status of the Snap.\n   *\n   * @param snapId - The Snap ID.\n   * @param status - The current execution status.\n   */\n  protected setSnapStatus(snapId: string, status: ExecutionStatus) {\n    this.#status.set(snapId, status);\n  }\n\n  async terminateAllSnaps() {\n    await Promise.all(\n      [...this.#jobs.keys()].map(async (snapId) => this.terminateSnap(snapId)),\n    );\n  }\n\n  /**\n   * Initializes and executes a Snap, setting up the communication channels to the Snap etc.\n   *\n   * @param snapData - Data needed for Snap execution.\n   * @param snapData.snapId - The ID of the Snap to execute.\n   * @param snapData.sourceCode - The source code of the Snap to execute.\n   * @param snapData.endowments - The endowments available to the executing Snap.\n   * @returns A string `OK` if execution succeeded.\n   * @throws If the execution service returns an error or execution times out.\n   */\n  async executeSnap({\n    snapId,\n    sourceCode,\n    endowments,\n  }: SnapExecutionData): Promise<string> {\n    if (this.#jobs.has(snapId)) {\n      throw new Error(`\"${snapId}\" is already running.`);\n    }\n\n    this.setSnapStatus(snapId, 'created');\n\n    const timer = new Timer(this.#initTimeout);\n\n    // This may resolve even if the environment has failed to start up fully\n    const job = await this.#initJob(snapId, timer);\n\n    // Certain environments use ping as part of their initialization and thus can skip it here\n    if (this.#usePing) {\n      // Ping the worker to ensure that it started up\n      const pingResult = await withTimeout(\n        this.#command(job.id, {\n          jsonrpc: '2.0',\n          method: 'ping',\n          id: nanoid(),\n        }),\n        this.#pingTimeout,\n      );\n\n      if (pingResult === hasTimedOut) {\n        throw new Error(\n          `The executor for \"${snapId}\" was unreachable. The executor did not respond in time.`,\n        );\n      }\n    }\n\n    const rpcStream = job.streams.rpc;\n\n    this.#setupSnapProvider(snapId, rpcStream);\n\n    // Use the remaining time as the timer, but ensure that the\n    // Snap gets at least half the init timeout.\n    const remainingTime = Math.max(timer.remaining, this.#initTimeout / 2);\n\n    this.setSnapStatus(snapId, 'initialized');\n\n    const request = {\n      jsonrpc: '2.0',\n      method: 'executeSnap',\n      params: { snapId, sourceCode, endowments },\n      id: nanoid(),\n    };\n\n    assertIsJsonRpcRequest(request);\n\n    this.setSnapStatus(snapId, 'executing');\n\n    const result = await withTimeout(\n      this.#command(job.id, request),\n      remainingTime,\n    );\n\n    if (result === hasTimedOut) {\n      throw new Error(`${snapId} failed to start.`);\n    }\n\n    if (result === 'OK') {\n      this.setSnapStatus(snapId, 'running');\n    }\n\n    return result as string;\n  }\n\n  async #command(\n    snapId: string,\n    message: JsonRpcRequest,\n  ): Promise<Json | undefined> {\n    const job = this.#jobs.get(snapId);\n    if (!job) {\n      throw new Error(`\"${snapId}\" is not currently running.`);\n    }\n\n    log('Parent: Sending Command', message);\n    return await job.rpcEngine.handle(message);\n  }\n\n  /**\n   * Handle RPC request.\n   *\n   * @param snapId - The ID of the recipient Snap.\n   * @param options - Bag of options to pass to the RPC handler.\n   * @returns Promise that can handle the request.\n   */\n  public async handleRpcRequest(\n    snapId: string,\n    options: SnapRpcHookArgs,\n  ): Promise<unknown> {\n    const { handler, request, origin } = options;\n\n    return await this.#command(snapId, {\n      id: nanoid(),\n      jsonrpc: '2.0',\n      method: 'snapRpc',\n      params: {\n        snapId,\n        origin,\n        handler,\n        request: request as JsonRpcRequest,\n      },\n    });\n  }\n}\n"]}