{"version":3,"file":"socket.mjs","names":[],"sources":["../src/macros/env.ts","../src/std/socket/socket_define.ts","../src/std/socket/mina_socket.ts","../src/std/socket/web_socket.ts","../src/std/socket/mod.ts"],"sourcesContent":["/**\n * @internal\n * 小游戏环境宏模块。\n */\n\n/**\n * 小游戏环境宏。\n *\n * 可通过打包工具在 build 时修改，如 esbuild webpack vite 等。\n */\ndeclare const __MINIGAME_STD_MINA__: boolean;\n\n/**\n * 如果在小游戏环境中返回 true，否则返回 false。\n */\nexport const IS_MINA = __MINIGAME_STD_MINA__;\n","import type { AsyncVoidIOResult } from 'happy-rusty';\nimport type { DataSource } from '../defines.ts';\n\n/**\n * WebSocket 连接状态，小游戏环境可用。\n * @since 1.6.0\n * @example\n * ```ts\n * import { SocketReadyState, connectSocket } from 'minigame-std';\n *\n * const socket = connectSocket('wss://example.com');\n * if (socket.readyState === SocketReadyState.OPEN) {\n *     console.log('连接已打开');\n * }\n * ```\n */\nexport const SocketReadyState = {\n    /**\n     * WebSocket.CONNECTING\n     */\n    CONNECTING: 0,\n    /**\n     * WebSocket.OPEN\n     */\n    OPEN: 1,\n    /**\n     * WebSocket.CLOSING\n     */\n    CLOSING: 2,\n    /**\n     * WebSocket.CLOSED\n     */\n    CLOSED: 3,\n} as const;\n\n/**\n * WebSocket 事件监听器映射接口，定义了与 WebSocket 事件对应的回调函数类型。\n * @since 1.0.0\n * @example\n * ```ts\n * import type { SocketListenerMap } from 'minigame-std';\n *\n * const onMessage: SocketListenerMap['message'] = (data) => {\n *     console.log('收到消息:', data);\n * };\n * ```\n */\nexport interface SocketListenerMap {\n    /**\n     * 当 WebSocket 连接成功打开时触发。\n     */\n    open(): void;\n\n    /**\n     * 当 WebSocket 连接关闭时触发。\n     * @param code - 表示关闭连接的状态码。\n     * @param reason - 表示关闭连接的原因。\n     */\n    close(code: number, reason: string): void;\n\n    /**\n     * 当 WebSocket 接收到消息时触发。\n     * @param data - 接收到的消息数据，可以是字符串或者 ArrayBuffer。\n     */\n    message(data: string | ArrayBuffer): void;\n\n    /**\n     * 当 WebSocket 连接发生错误时触发。\n     * @param err - 发生的错误对象。\n     */\n    error(err: Error): void;\n}\n\n/**\n * WebSocket 接口定义，描述了 WebSocket 的基本操作方法。\n * @since 1.0.0\n * @example\n * ```ts\n * import type { ISocket } from 'minigame-std';\n *\n * function handleSocket(socket: ISocket) {\n *     socket.addEventListener('message', (data) => {\n *         console.log('收到:', data);\n *     });\n *     socket.send('Hello');\n * }\n * ```\n */\nexport interface ISocket {\n    /**\n     * WebSocket 的连接状态。\n     */\n    readonly readyState: number;\n\n    /**\n     * 添加事件监听器到 WebSocket 对象。\n     * @typeParam K - 限定为 WebSocketEventMap 的键类型。\n     * @param type - 事件类型，如 'open', 'close', 'message', 'error'。\n     * @param listener - 对应事件的监听器回调函数。\n     * @returns 返回对应的`removeEventListener代理函数`。\n     */\n    addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: SocketListenerMap[K]): () => void;\n\n    /**\n     * 发送数据到 WebSocket 服务器。\n     * @param data - 要发送的数据，可以是字符串、ArrayBuffer 或 ArrayBufferView。\n     * @returns 返回一个 Promise，其解析为发送结果，成功时返回 true，失败时返回 Error。\n     */\n    send(data: DataSource): AsyncVoidIOResult;\n\n    /**\n     * 关闭 WebSocket 连接。\n     * @param code - 可选的状态码，表示关闭连接的原因。\n     * @param reason - 可选的字符串，解释为什么要关闭连接。\n     */\n    close(code?: number, reason?: string): void;\n}\n\n/**\n * 创建Socket的可选参数。\n * @since 1.0.0\n * @example\n * ```ts\n * import { connectSocket, type SocketOptions } from 'minigame-std';\n *\n * const options: SocketOptions = {\n *     protocols: ['protocol1', 'protocol2'],\n *     headers: { 'Authorization': 'Bearer token' },\n * };\n * const socket = connectSocket('wss://example.com', options);\n * ```\n */\nexport interface SocketOptions extends Omit<WechatMinigame.ConnectSocketOption, 'url' | 'header' | 'complete' | 'success' | 'fail'> {\n    headers?: Record<string, string>;\n}","/**\n * @internal\n * 小游戏平台的 WebSocket 实现。\n */\n\nimport { RESULT_VOID, tryResult, type AsyncVoidIOResult } from 'happy-rusty';\nimport type { DataSource } from '../defines.ts';\nimport { bufferSourceToAb, miniGameFailureToError } from '../internal/mod.ts';\nimport { asyncIOResultify } from '../utils/mod.ts';\nimport { type ISocket, type SocketListenerMap, type SocketOptions } from './socket_define.ts';\n\n/**\n * 创建并返回一个 WebSocket 连接。\n * @param url - WebSocket 服务器的 URL。\n * @param options - 透传给`wx.connectSocket`。\n * @returns 返回一个实现了 ISocket 接口的 WebSocket 对象。\n */\nexport function connectSocket(url: string, options?: SocketOptions): ISocket {\n    const { headers, ...rest } = options ?? {};\n    const socket = wx.connectSocket({\n        ...rest,\n        url,\n        header: headers,\n    });\n\n    return {\n        get readyState(): number {\n            // 小游戏 SocketTask 实际已支持 readyState，但 api typings 尚未更新\n            return (socket as typeof socket & { readyState: number; }).readyState;\n        },\n\n        addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: SocketListenerMap[K]): () => void {\n            switch (type) {\n                case 'open': {\n                    socket.onOpen(() => {\n                        (listener as SocketListenerMap['open'])();\n                    });\n\n                    return (): void => {\n                        // 小游戏没有实现移除监听\n                    };\n                }\n                case 'close': {\n                    socket.onClose((res) => {\n                        (listener as SocketListenerMap['close'])(res.code, res.reason);\n                    });\n\n\n                    return (): void => {\n                        // 小游戏没有实现移除监听\n                    };\n                }\n                case 'message': {\n                    socket.onMessage((res) => {\n                        (listener as SocketListenerMap['message'])(res.data);\n                    });\n\n                    return (): void => {\n                        // 小游戏没有实现移除监听\n                    };\n                }\n                case 'error': {\n                    socket.onError((err) => {\n                        (listener as SocketListenerMap['error'])(miniGameFailureToError(err));\n                    });\n\n                    return (): void => {\n                        // 小游戏没有实现移除监听\n                    };\n                }\n                default: {\n                    throw new TypeError(`Invalid socket event type: ${type}`);\n                }\n            }\n        },\n\n        async send(data: DataSource): AsyncVoidIOResult {\n            const sendDataRes = tryResult(() => typeof data === 'string'\n                ? data\n                : bufferSourceToAb(data));\n            if (sendDataRes.isErr()) return sendDataRes.asErr();\n\n            const result = await asyncIOResultify(socket.send)({\n                data: sendDataRes.unwrap(),\n            });\n\n            return result.and(RESULT_VOID);\n        },\n\n        close(code?: number, reason?: string): void {\n            socket.close({\n                code,\n                reason,\n            });\n        },\n    };\n}","/**\n * Web 平台的 WebSocket 实现。\n *\n * @internal\n */\n\nimport { tryAsyncResult, type AsyncVoidIOResult } from 'happy-rusty';\nimport type { DataSource } from '../defines.ts';\nimport type { ISocket, SocketListenerMap } from './socket_define.ts';\n\n/**\n * 创建并返回一个 WebSocket 连接。\n * @param url - WebSocket 服务器的 URL。\n * @param protocols - 子协议数组。\n * @returns 返回一个实现了 ISocket 接口的 WebSocket 对象。\n */\nexport function connectSocket(url: string, protocols?: string | string[]): ISocket {\n    const socket = new WebSocket(url, protocols);\n    // 考虑到小游戏只支持string和arraybuffer，二进制强制使用arraybuffer通信\n    socket.binaryType = 'arraybuffer';\n\n    return {\n        get readyState(): number {\n            return socket.readyState;\n        },\n\n        addEventListener<K extends keyof WebSocketEventMap>(type: K, listener: SocketListenerMap[K]): () => void {\n            switch (type) {\n                case 'open': {\n                    const socketListener = listener as SocketListenerMap['open'];\n\n                    socket.addEventListener('open', socketListener);\n\n                    return (): void => {\n                        socket.removeEventListener('open', socketListener);\n                    };\n                }\n                case 'close': {\n                    const socketListener = (ev: CloseEvent) => {\n                        (listener as SocketListenerMap['close'])(ev.code, ev.reason);\n                    };\n\n                    socket.addEventListener('close', socketListener);\n\n                    return (): void => {\n                        socket.removeEventListener('close', socketListener);\n                    };\n                }\n                case 'message': {\n                    const socketListener = (ev: MessageEvent<string | ArrayBuffer>) => {\n                        (listener as SocketListenerMap['message'])(ev.data);\n                    };\n\n                    socket.addEventListener('message', socketListener);\n\n                    return (): void => {\n                        socket.removeEventListener('message', socketListener);\n                    };\n                }\n                case 'error': {\n                    const socketListener = () => {\n                        (listener as SocketListenerMap['error'])(new Error('WebSocket error'));\n                    };\n\n                    socket.addEventListener('error', socketListener);\n\n                    return (): void => {\n                        socket.removeEventListener('error', socketListener);\n                    };\n                }\n                default: {\n                    throw new TypeError(`Invalid socket event type: ${type}`);\n                }\n            }\n        },\n\n        send(data: DataSource): AsyncVoidIOResult {\n            return tryAsyncResult(() => {\n                socket.send(data);\n            });\n        },\n\n        close: socket.close.bind(socket),\n    };\n}","/**\n * WebSocket 模块，提供创建和管理 WebSocket 连接的功能。\n * @module socket\n */\nimport { Ok, type IOResult } from 'happy-rusty';\nimport { IS_MINA } from '../../macros/env.ts';\nimport { validateSafeSocketUrl } from '../internal/validations.ts';\nimport { connectSocket as minaConnectSocket } from './mina_socket.ts';\nimport type { ISocket, SocketOptions } from './socket_define.ts';\nimport { connectSocket as webConnectSocket } from './web_socket.ts';\n\nexport * from './socket_define.ts';\n\n/**\n * 创建并返回一个 WebSocket 连接。\n * @param url - WebSocket 服务器的 URL。\n * @param options - 可选的参数。\n * @returns 返回一个实现了 ISocket 接口的 WebSocket 对象。\n * @since 1.0.0\n * @example\n * ```ts\n * const socket = connectSocket('wss://echo.websocket.org');\n *\n * socket.addEventListener('open', () => {\n *     console.log('连接已建立');\n *     socket.send('Hello, Server!');\n * });\n *\n * socket.addEventListener('message', (data) => {\n *     console.log('收到消息:', data);\n * });\n *\n * socket.addEventListener('close', (code, reason) => {\n *     console.log('连接已关闭:', code, reason);\n * });\n *\n * socket.addEventListener('error', (error) => {\n *     console.error('连接错误:', error);\n * });\n *\n * // 关闭连接\n * socket.close();\n * ```\n */\nexport function connectSocket(url: string, options?: SocketOptions): IOResult<ISocket> {\n    const urlRes = validateSafeSocketUrl(url);\n    if (urlRes.isErr()) return urlRes.asErr();\n\n    return Ok(IS_MINA\n        ? minaConnectSocket(url, options)\n        : webConnectSocket(url, options?.protocols));\n}"],"mappings":"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"}