{"version":3,"file":"openWebSocket.cjs","sourceRoot":"","sources":["../../src/permitted/openWebSocket.ts"],"names":[],"mappings":";;;AAMA,qDAAiE;AACjE,mDAK6B;AAC7B,uDAAgE;AAChE,uDAO+B;AAG/B,wDAA+C;AAU/C,MAAM,6BAA6B,GAAG,IAAA,oBAAM,EAAC;IAC3C,GAAG,EAAE,IAAA,iBAAG,EAAC,EAAE,QAAQ,EAAE,IAAA,iBAAK,EAAC,CAAC,IAAA,mBAAO,EAAC,MAAM,CAAC,EAAE,IAAA,mBAAO,EAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAChE,SAAS,EAAE,IAAA,sBAAQ,EAAC,IAAA,mBAAK,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACrC,CAAC,CAAC;AAOH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACU,QAAA,oBAAoB,GAAG;IAClC,cAAc,EAAE,2BAA2B;IAC3C,WAAW,EAAE,CAAC,oCAAoC,EAAE,uBAAuB,CAAC;CAO7E,CAAC;AAEF;;;;;;;;;;GAUG;AACH,KAAK,UAAU,2BAA2B,CACxC,GAAsD,EACtD,GAAgD,EAChD,KAAc,EACd,GAA6B,EAC7B,MAAa,EACb,SAAwD;IAExD,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAE/B,IACE,CAAC,SAAS,CAAC,IAAI,CACb,oCAAoC,EACpC,MAAM,EACN,2BAAc,CAAC,aAAa,CAC7B,EACD,CAAC;QACD,OAAO,GAAG,CAAC,2BAAc,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACtD,GAAG,CAAC,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAC/B,uBAAuB,EACvB,MAAM,EACN,GAAG,EACH,SAAS,CACV,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC;IAED,OAAO,GAAG,EAAE,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,MAAe;IACzC,IAAI,CAAC;QACH,OAAO,IAAA,oBAAM,EAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,yBAAW,EAAE,CAAC;YACjC,MAAM,sBAAS,CAAC,aAAa,CAAC;gBAC5B,OAAO,EAAE,mBAAmB,KAAK,CAAC,OAAO,GAAG;aAC7C,CAAC,CAAC;QACL,CAAC;QACD,0BAA0B;QAC1B,MAAM,sBAAS,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC;AACH,CAAC","sourcesContent":["import type {\n  JsonRpcEngineEndCallback,\n  MethodHandler,\n} from '@metamask/json-rpc-engine';\nimport type { Messenger } from '@metamask/messenger';\nimport type { PermissionControllerHasPermissionAction } from '@metamask/permission-controller';\nimport { providerErrors, rpcErrors } from '@metamask/rpc-errors';\nimport {\n  literal,\n  union,\n  type OpenWebSocketParams,\n  type OpenWebSocketResult,\n} from '@metamask/snaps-sdk';\nimport { uri, type InferMatching } from '@metamask/snaps-utils';\nimport {\n  create,\n  object,\n  array,\n  string,\n  optional,\n  StructError,\n} from '@metamask/superstruct';\nimport type { PendingJsonRpcResponse } from '@metamask/utils';\n\nimport { SnapEndowments } from '../endowments';\nimport type {\n  JsonRpcRequestWithOrigin,\n  WebSocketServiceOpenAction,\n} from '../types';\n\nexport type OpenWebSocketMethodActions =\n  | PermissionControllerHasPermissionAction\n  | WebSocketServiceOpenAction;\n\nconst OpenWebSocketParametersStruct = object({\n  url: uri({ protocol: union([literal('wss:'), literal('ws:')]) }),\n  protocols: optional(array(string())),\n});\n\nexport type OpenWebSocketParameters = InferMatching<\n  typeof OpenWebSocketParametersStruct,\n  OpenWebSocketParams\n>;\n\n/**\n * Open a WebSocket connection to the specified URL with optional protocols.\n *\n * Note: This method is only available to snaps that have the\n * [`endowment:network-access`](https://docs.metamask.io/snaps/features/network-access/)\n * permission.\n *\n * @example\n * ```json name=\"Manifest\"\n * {\n *   \"initialPermissions\": {\n *     \"endowment:network-access\": {}\n *   }\n * }\n * ```\n * ```ts name=\"Usage\"\n * // Open a connection to a WebSocket server, e.g., in the JSON-RPC handler of\n * // the Snap:\n * snap.request({\n *   method: 'snap_openWebSocket',\n *   params: {\n *     url: 'wss://example.com/socket',\n *     protocols: ['protocol1', 'protocol2'], // Optional\n *   },\n * });\n *\n * // Listen for events from the WebSocket connection in the `onWebSocketEvent`\n * // handler of the Snap:\n * export const onWebSocketEvent: OnWebSocketEventHandler = async ({ event }) => {\n *   switch (event.type) {\n *     case 'open':\n *       console.log(`WebSocket connection opened with origin ${event.origin}`);\n *       break;\n *     case 'message':\n *       console.log(`WebSocket message received from origin ${event.origin}:`, event.data);\n *       break;\n *     case 'close':\n *       console.log(`WebSocket connection closed with origin ${event.origin}`);\n *       break;\n *     case 'error':\n *       console.error(`WebSocket error from origin ${event.origin}:`, event.error);\n *       break;\n *   }\n * };\n * ```\n */\nexport const openWebSocketHandler = {\n  implementation: openWebSocketImplementation,\n  actionNames: ['PermissionController:hasPermission', 'WebSocketService:open'],\n} satisfies MethodHandler<\n  never,\n  OpenWebSocketMethodActions,\n  OpenWebSocketParams,\n  OpenWebSocketResult,\n  { origin: string }\n>;\n\n/**\n * The `snap_openWebSocket` method implementation.\n *\n * @param req - The JSON-RPC request object.\n * @param res - The JSON-RPC response object.\n * @param _next - The `json-rpc-engine` \"next\" callback. Not used by this function.\n * @param end - The `json-rpc-engine` \"end\" callback.\n * @param _hooks - The RPC method hooks. Not used by this function.\n * @param messenger - The messenger used to call controller actions.\n * @returns Nothing.\n */\nasync function openWebSocketImplementation(\n  req: JsonRpcRequestWithOrigin<OpenWebSocketParameters>,\n  res: PendingJsonRpcResponse<OpenWebSocketResult>,\n  _next: unknown,\n  end: JsonRpcEngineEndCallback,\n  _hooks: never,\n  messenger: Messenger<string, OpenWebSocketMethodActions>,\n): Promise<void> {\n  const { params, origin } = req;\n\n  if (\n    !messenger.call(\n      'PermissionController:hasPermission',\n      origin,\n      SnapEndowments.NetworkAccess,\n    )\n  ) {\n    return end(providerErrors.unauthorized());\n  }\n\n  try {\n    const { url, protocols } = getValidatedParams(params);\n    res.result = await messenger.call(\n      'WebSocketService:open',\n      origin,\n      url,\n      protocols,\n    );\n  } catch (error) {\n    return end(error);\n  }\n\n  return end();\n}\n\n/**\n * Validates the parameters for the snap_openWebSocket method.\n *\n * @param params - Parameters to validate.\n * @returns Validated parameters.\n * @throws Throws RPC error if validation fails.\n */\nfunction getValidatedParams(params: unknown): OpenWebSocketParameters {\n  try {\n    return create(params, OpenWebSocketParametersStruct);\n  } catch (error) {\n    if (error instanceof StructError) {\n      throw rpcErrors.invalidParams({\n        message: `Invalid params: ${error.message}.`,\n      });\n    }\n    /* istanbul ignore next */\n    throw rpcErrors.internal();\n  }\n}\n"]}