{"_id":"@akokko/blive-message-listener","name":"@akokko/blive-message-listener","dist-tags":{"latest":"0.5.1"},"versions":{"0.5.1":{"name":"@akokko/blive-message-listener","version":"0.5.1","description":"Bilibili-live danmu listener with type","type":"module","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","homepage":"https://github.com/ddiu8081/blive-message-listener#readme","repository":{"type":"git","url":"git+https://github.com/ddiu8081/blive-message-listener.git"},"author":{"name":"Akokko","email":"admin@akokko.com"},"license":"MIT","scripts":{"dev":"tsdown --watch","build":"tsdown"},"exports":{".":{"types":"./dist/index.d.ts","require":"./dist/index.cjs","import":"./dist/index.js"},"./browser":{"types":"./dist/browser.d.ts","require":"./dist/browser.cjs","import":"./dist/browser.js"}},"keywords":["bilibili","bilibili-live","danmaku","danmu"],"sideEffects":false,"dependencies":{"tiny-bilibili-ws":"^1.0.2"},"devDependencies":{"tsdown":"^0.12.4","typescript":"5.5.4"},"packageManager":"pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531","_id":"@akokko/blive-message-listener@0.5.1","gitHead":"f6d464c3fd8881bd010e9d91b4ef7afe9871c327","bugs":{"url":"https://github.com/ddiu8081/blive-message-listener/issues"},"_nodeVersion":"22.14.0","_npmVersion":"11.4.1","dist":{"integrity":"sha512-xekiHWQh2KnUNHzaJeBmDADtgfpvHQBkKjQRaVspb5yfqGnu+9RQMHx5gMd8yT6DNluM9M9+J4JkckFDuYE/oQ==","shasum":"86fc8616acd8227629988a647a429eb9d961b4f6","tarball":"https://registry.npmjs.org/@akokko/blive-message-listener/-/blive-message-listener-0.5.1.tgz","fileCount":16,"unpackedSize":104307,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGg0JAIrDmOZ/bG7ASCOF3ns/BQXXIiN7YYxAlyoUBl3AiEAoiVpE82aXecM9PQPBOBtGLyjMSwPLZCBGi2xmid9NCE="}]},"_npmUser":{"name":"akokko","email":"admin@akokko.com"},"directories":{},"maintainers":[{"name":"akokko","email":"admin@akokko.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/blive-message-listener_0.5.1_1748435810758_0.23821195098519898"},"_hasShrinkwrap":false}},"time":{"created":"2025-05-28T12:36:50.641Z","0.5.1":"2025-05-28T12:36:50.928Z","modified":"2025-05-28T12:36:51.176Z"},"maintainers":[{"name":"akokko","email":"admin@akokko.com"}],"description":"Bilibili-live danmu listener with type","homepage":"https://github.com/ddiu8081/blive-message-listener#readme","keywords":["bilibili","bilibili-live","danmaku","danmu"],"repository":{"type":"git","url":"git+https://github.com/ddiu8081/blive-message-listener.git"},"author":{"name":"Akokko","email":"admin@akokko.com"},"bugs":{"url":"https://github.com/ddiu8081/blive-message-listener/issues"},"license":"MIT","readme":"# blive-message-listener\n\n[![npm](https://img.shields.io/npm/v/blive-message-listener)](https://www.npmjs.com/package/blive-message-listener)\n\n类型友好的 Bilibili 直播间弹幕监听库。\n\n## Features\n\n- 将 [原始数据](mock) 转为更友好的格式输出\n- Node 环境与浏览器环境支持\n- 支持监听与获取原始消息\n\n## Install\n\n```bash\n\nnpm i blive-message-listener\n\n```\n\n## Usage\n\n```ts\nimport { startListen, type MsgHandler } from 'blive-message-listener'\n// 浏览器环境，从 '/browser' 导入 startListen\n// import { startListen } from 'blive-message-listener/browser'\n\nconst handler: MsgHandler = {\n  onIncomeDanmu: (msg) => {\n    console.log(msg.id, msg.body)\n  },\n  onIncomeSuperChat: (msg) => {\n    console.log(msg.id, msg.body)\n  },\n}\n\nconst instance = startListen(652581, handler)\n\ninstance.close()\n```\n\n> 1. 需传入房间的长id。短id需转为长id才能接收到消息。(https://github.com/ddiu8081/blive-message-listener/issues/19)\n> 2. 2023年7月后需登录后才可展示完整用户名，可参考下一节 Options 配置连接选项 (https://github.com/ddiu8081/blive-message-listener/issues/29)\n\n## Options\n\n你可以向 `startListen` 传入第三个参数 `options` 来手动配置连接选项。\n\n```ts\ninterface MessageListenerOptions {\n  /**\n   * tiny-bilibili-ws 连接选项\n   *\n   * @see https://github.com/starknt/tiny-bilibili-ws\n   */\n  ws?: WSOptions | TCPOptions\n}\n```\n\n```ts\nstartListen(652581, handler, {\n  ws: {\n    headers: {\n      Cookie: 'xxx',\n    },\n    uid: 0,\n  }\n})\n\n// or\nstartListen(652581, handler, {\n  ws: {\n    platform: 'web',\n    uid: 541993,\n    key: '<login_key>',\n    buvid: '<login_buvid>',\n  }\n})\n```\n\n## Handlers & Type Definitions\n\n### Common\n\n```ts\nconst startListen: (roomId: number, handler: MsgHandler) => MessageListener\n\nexport interface MessageListener {\n  /** 直播间房间号 */\n  roomId: number\n  /** 关闭连接 */\n  close: () => void\n  /** 刷新当前直播间热度 */\n  getAttention: () => Promise<number>\n}\n\nexport interface Message<T> {\n  /** 消息id */\n  id: string,\n  /** 接收消息的时间，毫秒时间戳 */\n  timestamp: number,\n  /** 消息类型 */\n  type: string,\n  /** 消息内容 */\n  body: T\n  /** 原始消息内容 */\n  raw: any\n}\n\nexport interface User {\n  /** 用户uid */\n  uid: number\n  /** 用户名 */\n  uname: string\n  /** 用户头像 */\n  face?: string\n  /** 用户牌子·*/\n  badge?: {\n    /** 是否点亮 */\n    active: boolean\n    /** 牌子名称 */\n    name: string\n    /** 牌子等级 */\n    level: number\n    /** 牌子颜色 */\n    color: string\n    /** 渐变色牌子，当用户长时间未消费，则会变为灰色，即 `#c0c0c0` */\n    gradient?: [string, string, string]\n    /** 主播信息 */\n    anchor: {\n      /** 主播uid */\n      uid: number\n      /** 主播用户名 */\n      uname: string\n      /** 主播房间号 */\n      room_id: number\n      /** 是否为本直播间 */\n      is_same_room?: boolean\n    }\n  }\n  /** 用户身份 */\n  identity?: {\n    /** 直播榜单排名 */\n    rank: 0 | 1 | 2 | 3\n    /** 大航海信息 */\n    guard_level: GuardLevel\n    /** 房管 */\n    room_admin: boolean\n  }\n}\n\nexport enum GuardLevel {\n  /** 无 */\n  None = 0,\n  /** 总督 */\n  Zongdu = 1,\n  /** 提督 */\n  Tidu = 2,\n  /** 舰长 */\n  Jianzhang = 3,\n}\n```\n\n### Handler\n\nType definition can be also found in [src/parser](src/parser).\n\n#### 连接基础信息\n\n| Handler | Description |\n| --- | --- |\n| onOpen | 连接成功 |\n| onClose | 连接关闭 |\n| onError | 连接错误 |\n| onStartListen | 开始监听消息 |\n\n<details>\n<summary>Type Definitions</summary>\n  \n##### Handler.onOpen\n\n连接成功\n\n```ts\nexport type Handler = {\n  /** 连接成功 */\n  onOpen: () => void,\n}\n```\n\n##### Handler.onClose\n\n连接关闭\n\n```ts\nexport type Handler = {\n  /** 连接关闭 */\n  onClose: () => void,\n}\n```\n\n##### Handler.onError\n\n连接错误\n\n```ts\nexport type Handler = {\n  /** 连接错误 */\n  onError: (e: Error) => void,\n}\n```\n\n##### Handler.onStartListen\n\n开始监听消息\n\n```ts\nexport type Handler = {\n  /** 开始监听消息 */\n  onStartListen: () => void,\n}\n```\n</details>\n\n#### 直播间基础信息\n\n| Handler | Description |\n| --- | --- |\n| onLiveStart | 直播开始消息 |\n| onLiveEnd | 直播结束消息 |\n| onAttentionChange | 直播间热度变化 |\n| onWatchedChange | 累计看过人数变化 |\n| onLikedChange | 累计点赞人数变化 |\n| onRankCountChange | 高能用户人数变化 |\n| onUserAction | 用户进入、关注、分享、点赞直播间 |\n| onRoomInfoChange | 直播间信息修改 |\n\n<details>\n<summary>Type Definitions</summary>\n\n##### handler.onLiveStart\n\n直播开始消息\n\n```ts\nexport type Handler = {\n  /** 直播开始消息 */\n  onLiveStart: (msg: Message<LiveStartMsg>) => void\n}\n\ntype msgType = 'LIVE'\n\nexport interface LiveStartMsg {\n  /** 开播平台 */\n  live_platform: string\n  /** 房间号 */\n  room_id: number\n}\n```\n\n##### handler.onLiveEnd\n\n直播结束消息\n\n```ts\nexport type Handler = {\n  /** 直播结束消息 */\n  onLiveEnd: (msg: Message<LiveEndMsg>) => void\n}\n\ntype msgType = 'PREPARING'\n\nexport interface LiveEndMsg {\n  /** 房间号 */\n  room_id: number\n}\n```\n\n##### handler.onAttentionChange\n\n直播间热度变化\n\n```ts\nexport type Handler = {\n  /** 直播间热度变化 */\n  onAttentionChange: (msg: Message<AttentionChangeMsg>) => void\n}\n\ntype msgType = 'heartbeat'\n\nexport interface AttentionChangeMsg {\n  /** 直播间热度 */\n  attention: number\n}\n```\n\n##### handler.onWatchedChange\n\n累计看过人数变化\n\n```ts\nexport type Handler = {\n  /** 累计看过人数变化 */\n  onWatchedChange: (msg: Message<WatchedChangeMsg>) => void\n}\n\ntype msgType = 'WATCHED_CHANGE'\n\nexport interface WatchedChangeMsg {\n  /** 累计入场人数 */\n  num: number\n  /** 累计入场人数，格式化输出 */\n  text_small: string\n}\n```\n\n##### handler.onLikedChange\n\n累计点赞人数变化\n\n```ts\nexport type Handler = {\n  /** 累计点赞人数变化 */\n  onLikedChange: (msg: Message<LikedChangeMsg>) => void\n}\n\ntype msgType = 'LIKE_INFO_V3_UPDATE'\n\nexport interface LikedChangeMsg {\n  /** 直播间点赞人数 */\n  count: number\n}\n```\n\n##### handler.onRankCountChange\n\n高能用户人数变化\n\n```ts\nexport type Handler = {\n  /** 高能用户人数变化 */\n  onRankCountChange: (msg: Message<RankCountChangeMsg>) => void\n}\n\ntype msgType = 'ONLINE_RANK_COUNT'\n\nexport interface RankCountChangeMsg {\n  /** 高能用户人数 */\n  count: number\n}\n```\n\n##### handler.onUserAction\n\n用户进入、关注、分享、点赞直播间\n\n- 舰长进入直播间时，有几率会触发两次\n- 舰长进入直播间时，uname 超长可能会省略号截断\n\n```ts\nexport type Handler = {\n  /** 用户进入、关注、分享、点赞直播间 */\n  onUserAction: (msg: Message<UserActionMsg>) => void\n}\n\ntype msgType = 'INTERACT_WORD' | 'ENTRY_EFFECT' | 'LIKE_INFO_V3_CLICK'\n\ntype UserAction = 'enter' | 'follow' | 'share' | 'like' | 'unknown'\n\nexport interface UserActionMsg {\n  user: User\n  /** 事件类型 */\n  action: UserAction\n  /** 事件时间，毫秒时间戳 */\n  timestamp: number\n}\n```\n\n##### handler.onRoomInfoChange\n\n直播间信息修改\n\n```ts\nexport type Handler = {\n  /** 直播间信息修改 */\n  onRoomInfoChange: (msg: Message<RoomInfoChangeMsg>) => void\n}\n\ntype msgType = 'ROOM_CHANGE'\n\nexport interface RoomInfoChangeMsg {\n  /** 直播间标题 */\n  title: string\n  /** 一级分区id */\n  parent_area_id: number\n  /** 一级分区名 */\n  parent_area_name: string\n  /** 二级分区id */\n  area_id: number\n  /** 二级分区名 */\n  area_name: string\n}\n```\n</details>\n\n#### 弹幕相关\n\n| Handler | Description |\n| --- | --- |\n| onIncomeDanmu | 收到普通弹幕消息 |\n| onIncomeSuperChat | 收到醒目留言 |\n\n<details>\n<summary>Type Definitions</summary>\n\n##### handler.onIncomeDanmu\n\n收到普通弹幕消息\n\n```ts\nexport type Handler = {\n  /** 收到普通弹幕消息 */\n  onIncomeDanmu: (msg: Message<DanmuMsg>) => void\n}\n\ntype msgType = 'DANMU_MSG'\n\nexport interface DanmuMsg {\n  user: User\n  /** 弹幕内容 */\n  content: string\n  /** 弹幕类型：1 2 3：普通弹幕；4：底部弹幕；5：顶部弹幕 */\n  type: number\n  /** 弹幕颜色 */\n  content_color: string\n  /** 发送时间，毫秒时间戳 */\n  timestamp: number\n  /** 是否为天选抽奖弹幕 */\n  lottery: boolean\n  /** 表情弹幕内容 */\n  emoticon?: {\n    id: string\n    height: number\n    width: number\n    url: string\n  }\n  /** 弹幕内小表情映射，key为表情文字，如\"[妙]\" */\n  in_message_emoticon?: Record<string, {\n    id: string\n    emoticon_id: number\n    height: number\n    width: number\n    url: string\n    description: string\n  }>\n}\n```\n\n##### handler.onIncomeSuperChat\n\n收到醒目留言\n\n```ts\nexport type Handler = {\n  /** 收到醒目留言 */\n  onIncomeSuperChat: (msg: Message<SuperChatMsg>) => void\n}\n\ntype msgType = 'SUPER_CHAT_MESSAGE'\n\nexport interface SuperChatMsg {\n  /** 消息id */\n  id: number\n  /** 发送用户 */\n  user: User\n  /** 弹幕内容 */\n  content: string\n  /** 弹幕颜色 */\n  content_color: string\n  /** 价格，RMB */\n  price: number\n  /** 持续时间，秒 */\n  time: number\n}\n```\n</details>\n\n#### 礼物相关\n\n| Handler | Description |\n| --- | --- |\n| onGift | 收到礼物 |\n| onGuardBuy | 舰长上舰消息 |\n| onRedPocketStart | 红包抽奖开始 |\n| onRedPocketEnd | 红包抽奖结果 |\n| onAnchorLotteryStart | 主播天选时刻抽奖开启 |\n| onAnchorLotteryEnd | 主播天选时刻抽奖结果 |\n\n<details>\n<summary>Type Definitions</summary>\n\n##### handler.onGift\n\n收到礼物\n\n* 礼物信息的用户牌子可见，但没有牌子对应主播的用户名及房间号，也无法判断 `is_same_room` 是否为本直播间。\n\n```ts\nexport type Handler = {\n  /** 收到礼物 */\n  onGift: (msg: Message<GiftMsg>) => void\n}\n\ntype msgType = 'SEND_GIFT'\n\nexport interface GiftMsg {\n  user: User\n  /** 礼物id */\n  gift_id: number\n  /** 礼物名称 */\n  gift_name: string\n  /** 礼物价格类型 */\n  coin_type: 'silver' | 'gold'\n  /** 礼物价格，除以1000为RMB */\n  price: number\n  /** 礼物数量 */\n  amount: number\n  /** 送礼指向主播信息，多人直播间可指定要送给的主播，单人直播间为空 */\n  send_master?: {\n    uid: number\n    uname: string\n    room_id: number\n  }\n  /** 礼物连击 */\n  combo?: {\n    /** 连击id */\n    batch_id: string\n    /** 当前连击数（礼物总数） */\n    combo_num: number\n    /** 连击礼物总价格，除以1000为RMB */\n    total_price: number\n  }\n}\n```\n\n##### handler.onGuardBuy\n\n舰长上舰消息\n\n```ts\nexport type Handler = {\n  /** 舰长上舰消息 */\n  onGuardBuy: (msg: Message<GuardBuyMsg>) => void\n}\n\ntype msgType = 'GUARD_BUY'\n\nexport interface GuardBuyMsg {\n  user: User\n  /** 礼物id */\n  gift_id: number\n  /** 礼物名称 */\n  gift_name: string\n  /** 大航海信息 */\n  guard_level: GuardLevel\n  /** 价格，RMB */\n  price: number\n  /** 等级生效时间 */\n  start_time: number\n  /** 等级过期时间 */\n  end_time: number\n}\n```\n\n##### handler.onRedPocketStart\n\n红包抽奖开始\n\n```ts\nexport type Handler = {\n  /** 红包抽奖开始 */\n  onRedPocketStart: (msg: Message<RedPocketStartMsg>) => void\n}\n\ntype msgType = 'POPULARITY_RED_POCKET_START'\n\nexport interface RedPocketStartMsg {\n  /** 红包抽奖id */\n  id: number\n  /** 红包发送用户 */\n  user: User\n  /** 开始时间，秒级时间戳 */\n  start_time: number\n  /** 结束时间，秒级时间戳 */\n  end_time: number\n  /** 持续时间，秒 */\n  duration: number\n  /** 口令弹幕内容 */\n  danmu: string\n  /** 红包奖品 */\n  awards: RedPocketStartAward[]\n  /** 奖品总价值，除以1000为RMB */\n  total_price: number\n  /** 剩余等待的红包数 */\n  wait_num: number\n}\n\ninterface RedPocketStartAward {\n  /** 奖品id */\n  gift_id: number\n  /** 奖品名称 */\n  gift_name: string\n  /** 奖品图片 */\n  gift_pic: string\n  /** 奖品数量 */\n  num: number\n}\n```\n\n##### handler.onRedPocketEnd\n\n红包抽奖结果\n\n```ts\nexport type Handler = {\n  /** 红包抽奖结果 */\n  onRedPocketEnd: (msg: Message<RedPocketEndMsg>) => void\n}\n\ntype msgType = 'POPULARITY_RED_POCKET_WINNER_LIST'\n\nexport interface RedPocketEndMsg {\n  /** 红包抽奖id */\n  id: number\n  /** 中奖人数 */\n  total_num: number\n  /** 中奖用户列表 */\n  winner: ({\n    /** 用户uid */\n    uid: number\n    /** 用户昵称 */\n    uname: string\n    /** 奖品id */\n    award_id: number\n  } & RedPocketEndAward)[]\n  /** 红包奖品列表 */\n  awards: Record<string, RedPocketEndAward>\n}\n\ninterface RedPocketEndAward {\n  /** 奖品类型，待补充 */\n  award_type: number\n  /** 奖品名称 */\n  award_name: string\n  /** 奖品图片 */\n  award_pic: string\n  /** 奖品图片大图 */\n  award_big_pic: string\n  /** 奖品价值，除以1000为RMB */\n  award_price: number\n}\n```\n\n##### handler.onAnchorLotteryStart\n\n主播天选时刻抽奖开启\n\n```ts\nexport type Handler = {\n  /** 主播天选时刻抽奖开启 */\n  onAnchorLotteryStart: (msg: Message<AnchorLotteryStartMsg>) => void\n}\n\ntype msgType = 'ANCHOR_LOT_START'\n\nexport interface AnchorLotteryStartMsg {\n  /** 天选抽奖id */\n  id: number\n  /** 开始时间，秒级时间戳 */\n  start_time: number\n  /** 持续时间，秒 */\n  duration: number\n  /** 天选奖品信息 */\n  award: {\n    /** 奖品图片 */\n    image: string\n    /** 奖品名称 */\n    name: string\n    /** 奖品数量 */\n    num: number\n    /** 是否为虚拟礼物奖品 */\n    virtual: boolean\n    /** 虚拟奖品价值描述，实物奖品为空 */\n    price_text: string\n  }\n  /** 抽奖要求 */\n  require: {\n    /** 口令弹幕内容，无需弹幕为空字符串 */\n    danmu: string\n    /** 需送主播礼物，无需送礼为空 */\n    gift: {\n      /** 礼物id */\n      id: string\n      /** 礼物名称 */\n      name: string\n      /** 礼物数量 */\n      num: number\n      /** 单个礼物价值，除以1000为RMB */\n      price: number\n    } | null\n    /** 抽奖参与人群要求，无要求为空 */\n    user: {\n      /** 参与人群限制（关注/粉丝勋章/大航海） */\n      type: 'follow' | 'medal' | 'guard'\n      /** 参与人群限制等级，如粉丝勋章等级 */\n      value: number\n      /** 参与人群限制描述 */\n      text: string\n    } | null\n  }\n}\n```\n\n##### handler.onAnchorLotteryEnd\n\n主播天选时刻抽奖结果\n\n```ts\nexport type Handler = {\n  /** 主播天选时刻抽奖结果 */\n  onAnchorLotteryEnd: (msg: Message<AnchorLotteryEndMsg>) => void\n}\n\ntype msgType = 'ANCHOR_LOT_AWARD'\n\nexport interface AnchorLotteryEndMsg {\n  /** 天选抽奖id */\n  id: number\n  /** 天选奖品信息 */\n  award: {\n    /** 奖品图片 */\n    image: string\n    /** 奖品名称 */\n    name: string\n    /** 是否为虚拟礼物奖品 */\n    virtual: boolean\n  }\n  /** 中奖用户列表 */\n  winner: ({\n    /** 用户uid */\n    uid: number\n    /** 用户昵称 */\n    uname: string\n    /** 用户头像 */\n    face: number\n    /** 用户粉丝勋章等级 */\n    level: number\n    /** 中奖数量 */\n    num: number\n  })[]\n}\n```\n</details>\n\n#### 房间管理相关\n\n| Handler | Description |\n| --- | --- |\n| onRoomWarn | 房间被超管警告、切断 |\n| onRoomSilent | 房间开启、关闭全局禁言 |\n| onRoomAdminSet | 房间设立、撤销房管 |\n\n<details>\n<summary>Type Definitions</summary>\n\n##### handler.onRoomWarn\n\n房间被超管警告、切断\n\n```ts\nexport type Handler = {\n  /** 房间被超管警告、切断 */\n  onRoomWarn: (msg: Message<RoomWarnMsg>) => void\n}\n\ntype msgType = 'WARNING' ｜ 'CUT_OFF'\n\nexport interface RoomWarnMsg {\n  /** 处理类型 */\n  type: 'warning' | 'cut'\n  /** 处理原因 */\n  msg: string\n}\n```\n\n##### handler.onRoomSilent\n\n房间开启、关闭全局禁言\n\n```ts\nexport type Handler = {\n  /** 房间开启、关闭全局禁言 */\n  onRoomSilent: (msg: Message<RoomSilentMsg>) => void\n}\n\ntype msgType = 'ROOM_SILENT_ON' ｜ 'ROOM_SILENT_OFF'\n\nexport interface RoomSilentMsg {\n  /** 禁言类型（按用户等级、勋章等级、全员、关闭） */\n  type: 'level' | 'medal' | 'member' | 'off'\n  /** 禁言等级 */\n  level: number\n  /** 禁言结束时间，秒级时间戳，-1 为无限 */\n  second: number\n}\n```\n\n##### handler.onRoomAdminSet\n\n房间设立、撤销房管\n\n```ts\nexport type Handler = {\n  /** 房间设立、撤销房管 */\n  onRoomAdminSet: (msg: Message<RoomAdminSetMsg>) => void\n}\n\ntype msgType = 'room_admin_entrance' ｜ 'ROOM_ADMIN_REVOKE'\n\nexport interface RoomAdminSetMsg {\n  /** 类型（设立、撤销） */\n  type: 'set' | 'revoke'\n  /** 用户uid */\n  uid: number\n}\n```\n</details>\n\n#### 监听原始消息\n\n```ts\nexport type Handler = {\n  /** 原始消息 */\n  raw: Record<'msg' | string, (msg: any) => void>\n}\n```\n\n可在 `raw` 中监听任意原始消息。\n\nexample:\n\n```ts\nconst handler: MsgHandler = {\n  raw: {\n    'msg': (msg) => {\n      // 监听所有 cmd 消息\n      console.log(msg)\n    },\n    'INTERACT_WORD': (msg) => {\n      // 监听特定的 cmd\n      console.log(msg)\n    },\n  }\n}\n\nstartListen(652581, handler)\n```\n\n## Credits\n\n- Based on [tiny-bilibili-ws](https://github.com/starknt/tiny-bilibili-ws)\n\n## License\n\nMIT\n","readmeFilename":"README.md","_rev":"1-02a6da0a3ba4a0ab015ca92a7bedda55"}