Procházet zdrojové kódy

✨ feat(dependencies): 添加阿里云RTC和视频点播SDK依赖

- 添加aliyun-rtc-sdk@7.1.1用于实时音视频通信功能
- 添加vod-js-sdk-v6@1.7.1-beta.1用于视频点播功能

✨ feat(classroom): 实现基础课堂功能架构

- 创建Classroom页面路由配置
- 添加IM类型定义文件alivc-im.iife.d.ts
- 实现useClassroom钩子函数基础结构
- 引入阿里云IM SDK脚本

✨ feat(api): 添加阿里云服务端API支持

- 创建阿里云IM和RTC Token生成接口
- 实现IM和RTC签名算法
- 添加用户认证中间件支持

♻️ refactor(auth): 导出User类型供其他模块使用

- 从AuthProvider中导出User类型定义
- 调整相关导入路径以使用共享User类型
yourname před 5 měsíci
rodič
revize
a1b991b80c

+ 3 - 1
package.json

@@ -20,6 +20,7 @@
     "@tanstack/react-query": "^5.77.2",
     "@types/bcrypt": "^5.0.2",
     "@types/jsonwebtoken": "^9.0.9",
+    "aliyun-rtc-sdk": "^7.1.1",
     "antd": "^5.26.0",
     "axios": "^1.9.0",
     "bcrypt": "^6.0.0",
@@ -42,7 +43,8 @@
     "react-router-dom": "^7.6.1",
     "react-toastify": "^11.0.5",
     "reflect-metadata": "^0.2.2",
-    "typeorm": "^0.3.24"
+    "typeorm": "^0.3.24",
+    "vod-js-sdk-v6": "1.7.1-beta.1"
   },
   "devDependencies": {
     "@types/debug": "^4.1.12",

+ 501 - 4
pnpm-lock.yaml

@@ -44,6 +44,9 @@ importers:
       '@types/jsonwebtoken':
         specifier: ^9.0.9
         version: 9.0.9
+      aliyun-rtc-sdk:
+        specifier: ^7.1.1
+        version: 7.1.1(@tensorflow/tfjs-core@4.22.0)(debug@4.4.1)(seedrandom@3.0.5)
       antd:
         specifier: ^5.26.0
         version: 5.26.0(moment@2.30.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -94,7 +97,7 @@ importers:
         version: 7.57.0(react@19.1.0)
       react-i18next:
         specifier: ^15.5.2
-        version: 15.5.2(i18next@25.2.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
+        version: 15.5.2(i18next@25.2.1(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
       react-json-view:
         specifier: ^1.21.3
         version: 1.21.3(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -113,6 +116,9 @@ importers:
       typeorm:
         specifier: ^0.3.24
         version: 0.3.24(babel-plugin-macros@3.1.0)(ioredis@5.6.1)(mysql2@3.14.1)(reflect-metadata@0.2.2)
+      vod-js-sdk-v6:
+        specifier: 1.7.1-beta.1
+        version: 1.7.1-beta.1(debug@4.4.1)
     devDependencies:
       '@types/debug':
         specifier: ^4.1.12
@@ -147,6 +153,33 @@ importers:
 
 packages:
 
+  '@aliyun-sls/web-base@0.2.9':
+    resolution: {integrity: sha512-ywCyyx7hqtAhOmuOjXu/gVQw6rPiig8HxshnUmT2VYkD9WAE7y4LeG8Yh6Lzh+5KA8ep+IzPa46WhOGiOFwDjw==}
+
+  '@aliyun-sls/web-base@0.3.9':
+    resolution: {integrity: sha512-UmRgTRzRyCqJywsjdFjMU+P/s3BGSc8laPsBo3YZ1fNAE8e3n2x5u2X7RGVwT9sHy+J+iUgaRHXqSXks+fxo7w==}
+
+  '@aliyun-sls/web-sts-plugin@0.3.9':
+    resolution: {integrity: sha512-khL3ctMlh2FCxkm/0ZJQnxmIBd7G1hIsZcCuEMTnz6sGUX1bFuEv2b8jcTbs9kh39wUSqIOQE+Tuc37BqVdGXQ==}
+
+  '@aliyun-sls/web-track-base@0.2.9':
+    resolution: {integrity: sha512-iEMpU60HoLiAA0Ihgl+t6WWjMTJ9Z7NsRGDhijaJmv/9N5Iwmpcc/A85XmqBG3QzfkF1HjTbzQwmE8x7QsFMlQ==}
+
+  '@aliyun-sls/web-track-base@0.3.9':
+    resolution: {integrity: sha512-kL1Qox9WIIr3IOHtcPuwWWzlWx6fWfs1Y7UhQBv6fwfk2NToqEVUFl68DAfZtiIY39w7Mu5epwk2bnhSiV3gpw==}
+
+  '@aliyun-sls/web-track-browser@0.2.9':
+    resolution: {integrity: sha512-XyyFXCaGvcyHFwHCM07X+KN8tfK3tOvdVqgA29bf0l0yysnhX5rgtwZF7v/tHMKLk+LVk2r0wGkSOMcF+ZVFIQ==}
+
+  '@aliyun-sls/web-track-browser@0.3.9':
+    resolution: {integrity: sha512-Gy8hm3ZmYDTZBwJgiata4/0/cPozxCLp8MEHdbipvHiEnzhCEKrkmLUmmqAr6fpKvmySHB06bska+1+MSOg7UQ==}
+
+  '@aliyun-sls/web-types@0.2.9':
+    resolution: {integrity: sha512-QtOG+AHc+e8gdhjObHceGrrWs+k94zQpKZtHYSimG78c6yyZCJMa8nwVpwB2C+Dem4Ca/Y1Rpat8VSvh2uWx5Q==}
+
+  '@aliyun-sls/web-types@0.3.9':
+    resolution: {integrity: sha512-RbyUwW5XeFkdsP3NozepmUPQFQFtB6JvAob20O/NMwf0HEGDBNeNk8NKWshwQVOwyS9cdxCwC5uyRdKFiVP/Pg==}
+
   '@ampproject/remapping@2.3.0':
     resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
     engines: {node: '>=6.0.0'}
@@ -1250,6 +1283,47 @@ packages:
     peerDependencies:
       react: ^18 || ^19
 
+  '@tensorflow/tfjs-backend-cpu@4.22.0':
+    resolution: {integrity: sha512-1u0FmuLGuRAi8D2c3cocHTASGXOmHc/4OvoVDENJayjYkS119fcTcQf4iHrtLthWyDIPy3JiPhRrZQC9EwnhLw==}
+    engines: {yarn: '>= 1.3.2'}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs-backend-webgl@4.22.0':
+    resolution: {integrity: sha512-H535XtZWnWgNwSzv538czjVlbJebDl5QTMOth4RXr2p/kJ1qSIXE0vZvEtO+5EC9b00SvhplECny2yDewQb/Yg==}
+    engines: {yarn: '>= 1.3.2'}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs-backend-webgpu@4.22.0':
+    resolution: {integrity: sha512-lvIc7Af4Tl2BCdYp43iQmSCRq3asaKT0q2xaErphXiUZ+jqeB0bQa0ZvQys1Xatvto0U4/c90DVsHPfvkn5ftg==}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs-converter@4.22.0':
+    resolution: {integrity: sha512-PT43MGlnzIo+YfbsjM79Lxk9lOq6uUwZuCc8rrp0hfpLjF6Jv8jS84u2jFb+WpUeuF4K33ZDNx8CjiYrGQ2trQ==}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs-core@4.22.0':
+    resolution: {integrity: sha512-LEkOyzbknKFoWUwfkr59vSB68DMJ4cjwwHgicXN0DUi3a0Vh1Er3JQqCI1Hl86GGZQvY8ezVrtDIvqR1ZFW55A==}
+    engines: {yarn: '>= 1.3.2'}
+
+  '@tensorflow/tfjs-data@4.22.0':
+    resolution: {integrity: sha512-dYmF3LihQIGvtgJrt382hSRH4S0QuAp2w1hXJI2+kOaEqo5HnUPG0k5KA6va+S1yUhx7UBToUKCBHeLHFQRV4w==}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+      seedrandom: ^3.0.5
+
+  '@tensorflow/tfjs-layers@4.22.0':
+    resolution: {integrity: sha512-lybPj4ZNj9iIAPUj7a8ZW1hg8KQGfqWLlCZDi9eM/oNKCCAgchiyzx8OrYoWmRrB+AM6VNEeIT+2gZKg5ReihA==}
+    peerDependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs@4.22.0':
+    resolution: {integrity: sha512-0TrIrXs6/b7FLhLVNmfh8Sah6JgjBPH4mZ8JGb7NU6WW+cx00qK5BcAZxw7NCzxj6N8MRAIfHq+oNbPUNG5VAg==}
+    hasBin: true
+
   '@tweenjs/tween.js@23.1.3':
     resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==}
 
@@ -1271,21 +1345,42 @@ packages:
   '@types/debug@4.1.12':
     resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
 
+  '@types/dom-mediacapture-transform@0.1.11':
+    resolution: {integrity: sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==}
+
+  '@types/dom-webcodecs@0.1.15':
+    resolution: {integrity: sha512-omOlCPvTWyPm4ZE5bZUhlSvnHM2ZWM2U+1cPiYFL/e8aV5O9MouELp+L4dMKNTON0nTeHqEg+KWDfFQMY5Wkaw==}
+
   '@types/estree@1.0.7':
     resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
 
   '@types/jsonwebtoken@9.0.9':
     resolution: {integrity: sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==}
 
+  '@types/long@4.0.2':
+    resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==}
+
   '@types/ms@2.1.0':
     resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
 
   '@types/node-cron@3.0.11':
     resolution: {integrity: sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==}
 
+  '@types/node-fetch@2.6.12':
+    resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==}
+
+  '@types/node@14.18.63':
+    resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==}
+
   '@types/node@22.15.31':
     resolution: {integrity: sha512-jnVe5ULKl6tijxUhvQeNbQG/84fHfg+yMak02cT8QVhBx/F05rAVxCGBYYTh2EKz22D6JF5ktXuNwdx7b9iEGw==}
 
+  '@types/offscreencanvas@2019.3.0':
+    resolution: {integrity: sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==}
+
+  '@types/offscreencanvas@2019.7.3':
+    resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==}
+
   '@types/parse-json@4.0.2':
     resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
 
@@ -1297,6 +1392,9 @@ packages:
   '@types/react@19.1.8':
     resolution: {integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==}
 
+  '@types/seedrandom@2.4.34':
+    resolution: {integrity: sha512-ytDiArvrn/3Xk6/vtylys5tlY6eo7Ane0hvcx++TKo6RxQXuVfW0AF/oeWqAj9dN29SyhtawuXstgmPlwNcv/A==}
+
   '@types/stats.js@0.17.4':
     resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==}
 
@@ -1312,6 +1410,9 @@ packages:
     peerDependencies:
       vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0
 
+  '@webgpu/types@0.1.38':
+    resolution: {integrity: sha512-7LrhVKz2PRh+DD7+S+PVaFd5HxaWQvoMqBbsV9fNJO1pjUs1P8bM2vQVNfk+3URTqbuTI7gkXi0rfsN0IadoBA==}
+
   '@webgpu/types@0.1.62':
     resolution: {integrity: sha512-eS+Go7OnNIILkrrh/w450XfzdyCfnJPmfAgJlNKIn1sR31Jhi9dbsIjFvP98z2U+AgtgNRfCk2lBQdczHCaOGQ==}
 
@@ -1335,6 +1436,18 @@ packages:
     engines: {node: '>=0.4.0'}
     hasBin: true
 
+  aliyun-peerconnection-core@0.6.3:
+    resolution: {integrity: sha512-CUmm1TfZ+Saj44s9Jpw5ACaxpPL/Gcqlva+8+E65ijiwN+X8nzjTtZJo5U+3EExQk6dSlKSdiAKQsH37qtry4A==}
+
+  aliyun-queen-engine@6.3.14:
+    resolution: {integrity: sha512-VtDSRsLEQ3/nRJtGSbuj+92Sew6D/x75nMEWv/YX/9VW/Cyhg5Vf55hrJ9hXq7Utf5bOKiqmks6/egYPs7LLvg==}
+
+  aliyun-rtc-sdk@7.1.1:
+    resolution: {integrity: sha512-UlISc356+uCgzgOldMfbvqK/hL5EGVkhax/nVR9U8Ob0vmMtjVCCGueGCgmrjAzt+5jHf9W5qreuimBJuezuag==}
+
+  aliyun-rts-sdk@2.12.5:
+    resolution: {integrity: sha512-Ax0UWpCYOWfTAKX49ZUx6pjHYvi+Xi7JEvLvzTVOfi0qe/2D/2DhA8VsQJYgd/LrFvPsASOqEIjFMZyjJn0Jig==}
+
   ansi-regex@5.0.1:
     resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
     engines: {node: '>=8'}
@@ -1365,6 +1478,9 @@ packages:
     resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==}
     engines: {node: '>= 6.0.0'}
 
+  argparse@1.0.10:
+    resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+
   as-table@1.0.55:
     resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==}
 
@@ -1385,6 +1501,9 @@ packages:
     resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
     engines: {node: '>= 6.0.0'}
 
+  axios@0.21.4:
+    resolution: {integrity: sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==}
+
   axios@1.10.0:
     resolution: {integrity: sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==}
 
@@ -1459,6 +1578,10 @@ packages:
   caniuse-lite@1.0.30001723:
     resolution: {integrity: sha512-1R/elMjtehrFejxwmexeXAtae5UO9iSyFn6G/I806CYC/BLyyBk1EPhrKBkWhy6wM6Xnm47dSJQec+tLJ39WHw==}
 
+  chalk@4.1.2:
+    resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+    engines: {node: '>=10'}
+
   chownr@3.0.0:
     resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==}
     engines: {node: '>=18'}
@@ -1466,6 +1589,9 @@ packages:
   classnames@2.5.1:
     resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==}
 
+  cliui@7.0.4:
+    resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+
   cliui@8.0.1:
     resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
     engines: {node: '>=12'}
@@ -1516,6 +1642,9 @@ packages:
   copy-to-clipboard@3.3.3:
     resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==}
 
+  core-js@3.29.1:
+    resolution: {integrity: sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==}
+
   cosmiconfig@7.1.0:
     resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
     engines: {node: '>=10'}
@@ -1527,6 +1656,9 @@ packages:
     resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
     engines: {node: '>= 8'}
 
+  crypto-js@4.2.0:
+    resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
+
   csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
@@ -1537,6 +1669,10 @@ packages:
     resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
     engines: {node: '>= 12'}
 
+  dateformat@5.0.3:
+    resolution: {integrity: sha512-Kvr6HmPXUMerlLcLF+Pwq3K7apHpYmGDVqrxcDasBg86UcKeTSNWbEzU8bwdXnxnR44FtMhJAxI4Bov6Y/KUfA==}
+    engines: {node: '>=12.20'}
+
   dayjs@1.11.13:
     resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
 
@@ -1644,6 +1780,9 @@ packages:
     resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
     engines: {node: '>=10'}
 
+  eventemitter3@4.0.7:
+    resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+
   eventemitter3@5.0.1:
     resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==}
 
@@ -1781,6 +1920,10 @@ packages:
   graceful-fs@4.2.11:
     resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
 
+  has-flag@4.0.0:
+    resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+    engines: {node: '>=8'}
+
   has-property-descriptors@1.0.2:
     resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==}
 
@@ -1887,6 +2030,9 @@ packages:
     resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==}
     hasBin: true
 
+  js-sha1@0.6.0:
+    resolution: {integrity: sha512-01gwBFreYydzmU9BmZxpVk6svJJHrVxEN3IOiGl6VO93bVKYETJ0sIth6DASI6mIFdt7NmfX9UiByRzsYHGU9w==}
+
   js-tokens@4.0.0:
     resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
 
@@ -2023,6 +2169,9 @@ packages:
   lodash@4.17.21:
     resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
 
+  long@4.0.0:
+    resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==}
+
   long@5.3.2:
     resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
 
@@ -2051,6 +2200,9 @@ packages:
     resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
     engines: {node: '>= 0.4'}
 
+  media-device@1.4.0:
+    resolution: {integrity: sha512-gCO7l0kI2wnCl+a7ckPhhVFOLfhlq0F11Y/lMM7oVQ5c+pMMgwko7dcalC0X5fbWH59zW4juGhVIp6O2271axA==}
+
   meshoptimizer@0.18.1:
     resolution: {integrity: sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==}
 
@@ -2137,6 +2289,15 @@ packages:
   node-fetch-native@1.6.6:
     resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==}
 
+  node-fetch@2.6.13:
+    resolution: {integrity: sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==}
+    engines: {node: 4.x || >=6.0.0}
+    peerDependencies:
+      encoding: ^0.1.0
+    peerDependenciesMeta:
+      encoding:
+        optional: true
+
   node-fetch@2.7.0:
     resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
     engines: {node: 4.x || >=6.0.0}
@@ -2555,6 +2716,9 @@ packages:
   reflect-metadata@0.2.2:
     resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
 
+  regenerator-runtime@0.13.11:
+    resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
+
   require-directory@2.1.1:
     resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
     engines: {node: '>=0.10.0'}
@@ -2576,6 +2740,10 @@ packages:
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
     hasBin: true
 
+  rtcpeerconnection-shim@1.2.15:
+    resolution: {integrity: sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==}
+    engines: {node: '>=6.0.0', npm: '>=3.10.0'}
+
   safe-buffer@5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
 
@@ -2595,6 +2763,16 @@ packages:
   scroll-into-view-if-needed@3.1.0:
     resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==}
 
+  sdp-transform@2.15.0:
+    resolution: {integrity: sha512-KrOH82c/W+GYQ0LHqtr3caRpM3ITglq3ljGUIb8LTki7ByacJZ9z+piSGiwZDsRyhQbYBOBJgr2k6X4BZXi3Kw==}
+    hasBin: true
+
+  sdp@2.12.0:
+    resolution: {integrity: sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==}
+
+  seedrandom@3.0.5:
+    resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==}
+
   semver@6.3.1:
     resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
     hasBin: true
@@ -2656,6 +2834,9 @@ packages:
     resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==}
     engines: {node: '>=6'}
 
+  sprintf-js@1.0.3:
+    resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
+
   sql-highlight@6.1.0:
     resolution: {integrity: sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA==}
     engines: {node: '>=14'}
@@ -2719,6 +2900,10 @@ packages:
   stylis@4.3.6:
     resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==}
 
+  supports-color@7.2.0:
+    resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+    engines: {node: '>=8'}
+
   supports-preserve-symlinks-flag@1.0.0:
     resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
     engines: {node: '>= 0.4'}
@@ -2813,6 +2998,11 @@ packages:
       typeorm-aurora-data-api-driver:
         optional: true
 
+  typescript@5.8.3:
+    resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==}
+    engines: {node: '>=14.17'}
+    hasBin: true
+
   ua-parser-js@1.0.40:
     resolution: {integrity: sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==}
     hasBin: true
@@ -2839,6 +3029,9 @@ packages:
     peerDependencies:
       browserslist: '>= 4.21.0'
 
+  url-search-params-polyfill@8.2.5:
+    resolution: {integrity: sha512-FOEojW4XReTmtZOB7xqSHmJZhrNTmClhBriwLTmle4iA7bwuCo6ldSfbtsFSb8bTf3E0a3XpfonAdaur9vqq8A==}
+
   urlpattern-polyfill@10.1.0:
     resolution: {integrity: sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==}
 
@@ -2869,16 +3062,28 @@ packages:
       '@types/react':
         optional: true
 
+  useragent-utils@1.3.1:
+    resolution: {integrity: sha512-TfdaK9uNA+XJvNZyfWLl2NGwIkJoIbk2j4a9FzGN88TeCUdtsFUH42vbJhAVmk86Qqzb6/T+MtI63TuA+CmCyA==}
+
   util-deprecate@1.0.2:
     resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
 
   util@0.12.5:
     resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
 
+  uuid@10.0.0:
+    resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
+    hasBin: true
+
   uuid@11.1.0:
     resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==}
     hasBin: true
 
+  uuid@3.4.0:
+    resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
+    deprecated: Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.
+    hasBin: true
+
   vite-plugin-ssr-hot-reload@0.4.2:
     resolution: {integrity: sha512-KhuXZxYXSlzEo6S3leOj806RI6XGdspDYPwqUYFGJajlsB4MffQ5My6rW+YO9uYkc2eM2Q+7OcCUnPrHaa3Upw==}
     engines: {node: '>=18.0.0'}
@@ -2923,6 +3128,9 @@ packages:
       yaml:
         optional: true
 
+  vod-js-sdk-v6@1.7.1-beta.1:
+    resolution: {integrity: sha512-YZljTVwogoCcx7VtlAhem9w3AP7RCnDlqKsxaU3bv7sylwTsC5/jE9QlvpCKEorkOHRBsbu37m3mYXUkelwBaw==}
+
   void-elements@3.1.0:
     resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
     engines: {node: '>=0.10.0'}
@@ -2937,6 +3145,10 @@ packages:
   webidl-conversions@3.0.1:
     resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
 
+  webrtc-adapter@7.7.1:
+    resolution: {integrity: sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A==}
+    engines: {node: '>=6.0.0', npm: '>=3.10.0'}
+
   whatwg-url@5.0.0:
     resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
 
@@ -3017,10 +3229,18 @@ packages:
     engines: {node: '>= 14.6'}
     hasBin: true
 
+  yargs-parser@20.2.9:
+    resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
+    engines: {node: '>=10'}
+
   yargs-parser@21.1.1:
     resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
     engines: {node: '>=12'}
 
+  yargs@16.2.0:
+    resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
+    engines: {node: '>=10'}
+
   yargs@17.7.2:
     resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
     engines: {node: '>=12'}
@@ -3036,6 +3256,44 @@ packages:
 
 snapshots:
 
+  '@aliyun-sls/web-base@0.2.9':
+    dependencies:
+      '@aliyun-sls/web-types': 0.2.9
+
+  '@aliyun-sls/web-base@0.3.9':
+    dependencies:
+      '@aliyun-sls/web-types': 0.3.9
+
+  '@aliyun-sls/web-sts-plugin@0.3.9':
+    dependencies:
+      '@aliyun-sls/web-base': 0.3.9
+      '@aliyun-sls/web-types': 0.3.9
+      crypto-js: 4.2.0
+
+  '@aliyun-sls/web-track-base@0.2.9':
+    dependencies:
+      '@aliyun-sls/web-types': 0.2.9
+
+  '@aliyun-sls/web-track-base@0.3.9':
+    dependencies:
+      '@aliyun-sls/web-types': 0.3.9
+
+  '@aliyun-sls/web-track-browser@0.2.9':
+    dependencies:
+      '@aliyun-sls/web-base': 0.2.9
+      '@aliyun-sls/web-track-base': 0.2.9
+      '@aliyun-sls/web-types': 0.2.9
+
+  '@aliyun-sls/web-track-browser@0.3.9':
+    dependencies:
+      '@aliyun-sls/web-base': 0.3.9
+      '@aliyun-sls/web-track-base': 0.3.9
+      '@aliyun-sls/web-types': 0.3.9
+
+  '@aliyun-sls/web-types@0.2.9': {}
+
+  '@aliyun-sls/web-types@0.3.9': {}
+
   '@ampproject/remapping@2.3.0':
     dependencies:
       '@jridgewell/gen-mapping': 0.3.8
@@ -3922,6 +4180,72 @@ snapshots:
       '@tanstack/query-core': 5.80.7
       react: 19.1.0
 
+  '@tensorflow/tfjs-backend-cpu@4.22.0(@tensorflow/tfjs-core@4.22.0)':
+    dependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+      '@types/seedrandom': 2.4.34
+      seedrandom: 3.0.5
+
+  '@tensorflow/tfjs-backend-webgl@4.22.0(@tensorflow/tfjs-core@4.22.0)':
+    dependencies:
+      '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      '@tensorflow/tfjs-core': 4.22.0
+      '@types/offscreencanvas': 2019.3.0
+      '@types/seedrandom': 2.4.34
+      seedrandom: 3.0.5
+
+  '@tensorflow/tfjs-backend-webgpu@4.22.0(@tensorflow/tfjs-core@4.22.0)':
+    dependencies:
+      '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs-converter@4.22.0(@tensorflow/tfjs-core@4.22.0)':
+    dependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs-core@4.22.0':
+    dependencies:
+      '@types/long': 4.0.2
+      '@types/offscreencanvas': 2019.7.3
+      '@types/seedrandom': 2.4.34
+      '@webgpu/types': 0.1.38
+      long: 4.0.0
+      node-fetch: 2.6.13
+      seedrandom: 3.0.5
+    transitivePeerDependencies:
+      - encoding
+
+  '@tensorflow/tfjs-data@4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5)':
+    dependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+      '@types/node-fetch': 2.6.12
+      node-fetch: 2.6.13
+      seedrandom: 3.0.5
+      string_decoder: 1.3.0
+    transitivePeerDependencies:
+      - encoding
+
+  '@tensorflow/tfjs-layers@4.22.0(@tensorflow/tfjs-core@4.22.0)':
+    dependencies:
+      '@tensorflow/tfjs-core': 4.22.0
+
+  '@tensorflow/tfjs@4.22.0(seedrandom@3.0.5)':
+    dependencies:
+      '@tensorflow/tfjs-backend-cpu': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      '@tensorflow/tfjs-backend-webgl': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      '@tensorflow/tfjs-converter': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      '@tensorflow/tfjs-core': 4.22.0
+      '@tensorflow/tfjs-data': 4.22.0(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5)
+      '@tensorflow/tfjs-layers': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      argparse: 1.0.10
+      chalk: 4.1.2
+      core-js: 3.29.1
+      regenerator-runtime: 0.13.11
+      yargs: 16.2.0
+    transitivePeerDependencies:
+      - encoding
+      - seedrandom
+
   '@tweenjs/tween.js@23.1.3': {}
 
   '@types/babel__core@7.20.5':
@@ -3953,6 +4277,12 @@ snapshots:
     dependencies:
       '@types/ms': 2.1.0
 
+  '@types/dom-mediacapture-transform@0.1.11':
+    dependencies:
+      '@types/dom-webcodecs': 0.1.15
+
+  '@types/dom-webcodecs@0.1.15': {}
+
   '@types/estree@1.0.7': {}
 
   '@types/jsonwebtoken@9.0.9':
@@ -3960,14 +4290,27 @@ snapshots:
       '@types/ms': 2.1.0
       '@types/node': 22.15.31
 
+  '@types/long@4.0.2': {}
+
   '@types/ms@2.1.0': {}
 
   '@types/node-cron@3.0.11': {}
 
+  '@types/node-fetch@2.6.12':
+    dependencies:
+      '@types/node': 22.15.31
+      form-data: 4.0.3
+
+  '@types/node@14.18.63': {}
+
   '@types/node@22.15.31':
     dependencies:
       undici-types: 6.21.0
 
+  '@types/offscreencanvas@2019.3.0': {}
+
+  '@types/offscreencanvas@2019.7.3': {}
+
   '@types/parse-json@4.0.2': {}
 
   '@types/react-dom@19.1.6(@types/react@19.1.8)':
@@ -3978,6 +4321,8 @@ snapshots:
     dependencies:
       csstype: 3.1.3
 
+  '@types/seedrandom@2.4.34': {}
+
   '@types/stats.js@0.17.4': {}
 
   '@types/three@0.177.0':
@@ -4004,6 +4349,8 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@webgpu/types@0.1.38': {}
+
   '@webgpu/types@0.1.62': {}
 
   '@whatwg-node/fetch@0.9.23':
@@ -4025,6 +4372,51 @@ snapshots:
 
   acorn@8.14.0: {}
 
+  aliyun-peerconnection-core@0.6.3:
+    dependencies:
+      sdp-transform: 2.15.0
+
+  aliyun-queen-engine@6.3.14(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5):
+    dependencies:
+      '@tensorflow/tfjs': 4.22.0(seedrandom@3.0.5)
+      '@tensorflow/tfjs-backend-webgl': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      '@tensorflow/tfjs-backend-webgpu': 4.22.0(@tensorflow/tfjs-core@4.22.0)
+      '@types/dom-mediacapture-transform': 0.1.11
+      '@types/dom-webcodecs': 0.1.15
+    transitivePeerDependencies:
+      - '@tensorflow/tfjs-core'
+      - encoding
+      - seedrandom
+
+  aliyun-rtc-sdk@7.1.1(@tensorflow/tfjs-core@4.22.0)(debug@4.4.1)(seedrandom@3.0.5):
+    dependencies:
+      '@aliyun-sls/web-sts-plugin': 0.3.9
+      '@aliyun-sls/web-track-browser': 0.3.9
+      aliyun-queen-engine: 6.3.14(@tensorflow/tfjs-core@4.22.0)(seedrandom@3.0.5)
+      aliyun-rts-sdk: 2.12.5(debug@4.4.1)
+      crypto-js: 4.2.0
+      dateformat: 5.0.3
+      eventemitter3: 5.0.1
+      ua-parser-js: 1.0.40
+      uuid: 10.0.0
+    transitivePeerDependencies:
+      - '@tensorflow/tfjs-core'
+      - debug
+      - encoding
+      - seedrandom
+
+  aliyun-rts-sdk@2.12.5(debug@4.4.1):
+    dependencies:
+      '@aliyun-sls/web-track-browser': 0.2.9
+      aliyun-peerconnection-core: 0.6.3
+      axios: 0.21.4(debug@4.4.1)
+      media-device: 1.4.0
+      url-search-params-polyfill: 8.2.5
+      useragent-utils: 1.3.1
+      webrtc-adapter: 7.7.1
+    transitivePeerDependencies:
+      - debug
+
   ansi-regex@5.0.1: {}
 
   ansi-regex@6.1.0: {}
@@ -4097,6 +4489,10 @@ snapshots:
 
   app-root-path@3.1.0: {}
 
+  argparse@1.0.10:
+    dependencies:
+      sprintf-js: 1.0.3
+
   as-table@1.0.55:
     dependencies:
       printable-characters: 1.0.42
@@ -4113,6 +4509,12 @@ snapshots:
 
   aws-ssl-profiles@1.1.2: {}
 
+  axios@0.21.4(debug@4.4.1):
+    dependencies:
+      follow-redirects: 1.15.9(debug@4.4.1)
+    transitivePeerDependencies:
+      - debug
+
   axios@1.10.0(debug@4.4.1):
     dependencies:
       follow-redirects: 1.15.9(debug@4.4.1)
@@ -4193,10 +4595,21 @@ snapshots:
 
   caniuse-lite@1.0.30001723: {}
 
+  chalk@4.1.2:
+    dependencies:
+      ansi-styles: 4.3.0
+      supports-color: 7.2.0
+
   chownr@3.0.0: {}
 
   classnames@2.5.1: {}
 
+  cliui@7.0.4:
+    dependencies:
+      string-width: 4.2.3
+      strip-ansi: 6.0.1
+      wrap-ansi: 7.0.0
+
   cliui@8.0.1:
     dependencies:
       string-width: 4.2.3
@@ -4241,6 +4654,8 @@ snapshots:
     dependencies:
       toggle-selection: 1.0.6
 
+  core-js@3.29.1: {}
+
   cosmiconfig@7.1.0:
     dependencies:
       '@types/parse-json': 4.0.2
@@ -4261,12 +4676,16 @@ snapshots:
       shebang-command: 2.0.0
       which: 2.0.2
 
+  crypto-js@4.2.0: {}
+
   csstype@3.1.3: {}
 
   data-uri-to-buffer@2.0.2: {}
 
   data-uri-to-buffer@4.0.1: {}
 
+  dateformat@5.0.3: {}
+
   dayjs@1.11.13: {}
 
   debug@4.4.1:
@@ -4397,6 +4816,8 @@ snapshots:
 
   escape-string-regexp@4.0.0: {}
 
+  eventemitter3@4.0.7: {}
+
   eventemitter3@5.0.1: {}
 
   exit-hook@2.2.1: {}
@@ -4538,6 +4959,8 @@ snapshots:
 
   graceful-fs@4.2.11: {}
 
+  has-flag@4.0.0: {}
+
   has-property-descriptors@1.0.2:
     dependencies:
       es-define-property: 1.0.1
@@ -4580,9 +5003,11 @@ snapshots:
     dependencies:
       void-elements: 3.1.0
 
-  i18next@25.2.1:
+  i18next@25.2.1(typescript@5.8.3):
     dependencies:
       '@babel/runtime': 7.27.6
+    optionalDependencies:
+      typescript: 5.8.3
 
   iconv-lite@0.6.3:
     dependencies:
@@ -4660,6 +5085,8 @@ snapshots:
 
   jiti@2.4.2: {}
 
+  js-sha1@0.6.0: {}
+
   js-tokens@4.0.0: {}
 
   jsesc@3.1.0: {}
@@ -4767,6 +5194,8 @@ snapshots:
 
   lodash@4.17.21: {}
 
+  long@4.0.0: {}
+
   long@5.3.2: {}
 
   loose-envify@1.4.0:
@@ -4789,6 +5218,11 @@ snapshots:
 
   math-intrinsics@1.1.0: {}
 
+  media-device@1.4.0:
+    dependencies:
+      '@types/node': 14.18.63
+      lodash: 4.17.21
+
   meshoptimizer@0.18.1: {}
 
   mime-db@1.52.0: {}
@@ -4896,6 +5330,10 @@ snapshots:
 
   node-fetch-native@1.6.6: {}
 
+  node-fetch@2.6.13:
+    dependencies:
+      whatwg-url: 5.0.0
+
   node-fetch@2.7.0:
     dependencies:
       whatwg-url: 5.0.0
@@ -5311,14 +5749,15 @@ snapshots:
     dependencies:
       react: 19.1.0
 
-  react-i18next@15.5.2(i18next@25.2.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
+  react-i18next@15.5.2(i18next@25.2.1(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3):
     dependencies:
       '@babel/runtime': 7.27.6
       html-parse-stringify: 3.0.1
-      i18next: 25.2.1
+      i18next: 25.2.1(typescript@5.8.3)
       react: 19.1.0
     optionalDependencies:
       react-dom: 19.1.0(react@19.1.0)
+      typescript: 5.8.3
 
   react-is@16.13.1: {}
 
@@ -5385,6 +5824,8 @@ snapshots:
 
   reflect-metadata@0.2.2: {}
 
+  regenerator-runtime@0.13.11: {}
+
   require-directory@2.1.1: {}
 
   resize-observer-polyfill@1.5.1: {}
@@ -5423,6 +5864,10 @@ snapshots:
       '@rollup/rollup-win32-x64-msvc': 4.43.0
       fsevents: 2.3.3
 
+  rtcpeerconnection-shim@1.2.15:
+    dependencies:
+      sdp: 2.12.0
+
   safe-buffer@5.2.1: {}
 
   safe-regex-test@1.1.0:
@@ -5441,6 +5886,12 @@ snapshots:
     dependencies:
       compute-scroll-into-view: 3.1.1
 
+  sdp-transform@2.15.0: {}
+
+  sdp@2.12.0: {}
+
+  seedrandom@3.0.5: {}
+
   semver@6.3.1: {}
 
   semver@7.7.2: {}
@@ -5511,6 +5962,8 @@ snapshots:
 
   split-on-first@1.1.0: {}
 
+  sprintf-js@1.0.3: {}
+
   sql-highlight@6.1.0: {}
 
   sqlstring@2.3.3: {}
@@ -5566,6 +6019,10 @@ snapshots:
 
   stylis@4.3.6: {}
 
+  supports-color@7.2.0:
+    dependencies:
+      has-flag: 4.0.0
+
   supports-preserve-symlinks-flag@1.0.0: {}
 
   tailwindcss@4.1.10: {}
@@ -5622,6 +6079,8 @@ snapshots:
       - babel-plugin-macros
       - supports-color
 
+  typescript@5.8.3: {}
+
   ua-parser-js@1.0.40: {}
 
   ufo@1.6.1: {}
@@ -5654,6 +6113,8 @@ snapshots:
       escalade: 3.2.0
       picocolors: 1.1.1
 
+  url-search-params-polyfill@8.2.5: {}
+
   urlpattern-polyfill@10.1.0: {}
 
   use-composed-ref@1.4.0(@types/react@19.1.8)(react@19.1.0):
@@ -5675,6 +6136,11 @@ snapshots:
     optionalDependencies:
       '@types/react': 19.1.8
 
+  useragent-utils@1.3.1:
+    dependencies:
+      '@types/node': 14.18.63
+      lodash: 4.17.21
+
   util-deprecate@1.0.2: {}
 
   util@0.12.5:
@@ -5685,8 +6151,12 @@ snapshots:
       is-typed-array: 1.1.15
       which-typed-array: 1.1.19
 
+  uuid@10.0.0: {}
+
   uuid@11.1.0: {}
 
+  uuid@3.4.0: {}
+
   vite-plugin-ssr-hot-reload@0.4.2:
     dependencies:
       picomatch: 4.0.2
@@ -5706,6 +6176,16 @@ snapshots:
       lightningcss: 1.30.1
       yaml: 2.8.0
 
+  vod-js-sdk-v6@1.7.1-beta.1(debug@4.4.1):
+    dependencies:
+      axios: 0.21.4(debug@4.4.1)
+      eventemitter3: 4.0.7
+      js-sha1: 0.6.0
+      typescript: 5.8.3
+      uuid: 3.4.0
+    transitivePeerDependencies:
+      - debug
+
   void-elements@3.1.0: {}
 
   web-encoding@1.1.5:
@@ -5718,6 +6198,11 @@ snapshots:
 
   webidl-conversions@3.0.1: {}
 
+  webrtc-adapter@7.7.1:
+    dependencies:
+      rtcpeerconnection-shim: 1.2.15
+      sdp: 2.12.0
+
   whatwg-url@5.0.0:
     dependencies:
       tr46: 0.0.3
@@ -5800,8 +6285,20 @@ snapshots:
 
   yaml@2.8.0: {}
 
+  yargs-parser@20.2.9: {}
+
   yargs-parser@21.1.1: {}
 
+  yargs@16.2.0:
+    dependencies:
+      cliui: 7.0.4
+      escalade: 3.2.0
+      get-caller-file: 2.0.5
+      require-directory: 2.1.1
+      string-width: 4.2.3
+      y18n: 5.0.8
+      yargs-parser: 20.2.9
+
   yargs@17.7.2:
     dependencies:
       cliui: 8.0.1

+ 1515 - 0
src/client/mobile/components/Classroom/alivc-im.iife.d.ts

@@ -0,0 +1,1515 @@
+declare namespace AliVCInteraction {
+  class AliVCIMAttachmentManager {
+    private static instance;
+    private wasmIns;
+    private attachmentManager;
+    private uploader;
+    constructor(wasmIns: any, wasmInterface: any);
+    static getInstance(wasmIns: any, wasmInterface: any): AliVCIMAttachmentManager;
+    getAttachmentReq(attachmentReq: ImAttachmentReq): Promise<any>;
+    /**
+     * 上传附件
+     * @param {string} reqId
+     * @param {ImAttachmentReq} attachmentReq
+     * @returns {ImAttachmentRes}
+     */
+    uploadAttachment(reqId: string, attachmentReq: ImAttachmentReq): Promise<ImAttachmentRes>;
+    /**
+     * 取消上传附件
+     * @param {string} reqId
+     * @returns
+     */
+    cancelAttachmentUpload(reqId: string): Promise<void>;
+    /**
+     * 删除已上传附件
+     * @param {ImAttachmentRes} attachment
+     * @returns
+     */
+    deleteAttachment(attachment: ImAttachmentRes): Promise<void>;
+    destroy(): void;
+}
+
+class AliVCIMGroupManager extends EventEmitter<ImGroupListener> {
+    private wasmIns;
+    private wasmGroupManager;
+    private groupListener;
+    constructor(wasmIns: any, wasmInterface: any);
+    addGroupListener(): void;
+    removeGroupListener(): void;
+    destroy(): void;
+    /**
+     * 创建群组,限管理员才能操作
+     * @param {ImCreateGroupReq} req
+     * @returns {Promise<ImCreateGroupRsp>}
+     */
+    createGroup(req: ImCreateGroupReq): Promise<ImCreateGroupRsp>;
+    /**
+     * 查询群组信息
+     * @param {string | ImQueryGroupReq} groupIdOrReq
+     * @returns {Promise<ImGroupInfo>}
+     */
+    queryGroup(groupIdOrReq: string | ImQueryGroupReq): Promise<ImGroupInfo>;
+    /**
+     * 关闭群组,限管理员才能操作
+     * @param {string | ImCloseGroupReq} groupIdOrReq
+     * @returns {Promise<void>}
+     */
+    closeGroup(groupIdOrReq: string | ImCloseGroupReq): Promise<void>;
+    /**
+     * 加入群组
+     * @param {string | ImJoinGroupReq} groupIdOrReq
+     * @returns {Promise<ImGroupInfo>}
+     */
+    joinGroup(groupIdOrReq: string | ImJoinGroupReq): Promise<ImGroupInfo>;
+    /**
+     * 离开群组
+     * @param {string | ImLeaveGroupReq} groupIdOrReq
+     * @returns {Promise<void>}
+     */
+    leaveGroup(groupIdOrReq: string | ImLeaveGroupReq): Promise<void>;
+    /**
+     * 修改群组信息
+     * @param {ImModifyGroupReq} req
+     * @returns {Promise<void>}
+     */
+    modifyGroup(req: ImModifyGroupReq): Promise<void>;
+    /**
+     * 查询最近组成员
+     * @param {string | ImListRecentGroupUserReq} groupIdOrReq
+     * @returns {Promise<ImListRecentGroupUserRsp>}
+     */
+    listRecentGroupUser(groupIdOrReq: string | ImListRecentGroupUserReq): Promise<ImListRecentGroupUserRsp>;
+    /**
+     * 查询群组成员,限管理员才能操作
+     * @param {string | ImListGroupUserReq} groupIdOrReq
+     * @returns {Promise<ImListGroupUserRsp>}
+     */
+    listGroupUser(groupIdOrReq: string | ImListGroupUserReq): Promise<ImListGroupUserRsp>;
+    /**
+     * 全体禁言,限管理员才能操作
+     * @param {string | ImMuteAllReq} groupIdOrReq
+     * @returns {Promise<void>}
+     */
+    muteAll(groupIdOrReq: string | ImMuteAllReq): Promise<void>;
+    /**
+     * 取消全体禁言,限管理员才能操作
+     * @param {string | ImCancelMuteAllReq} groupIdOrReq
+     * @returns {Promise<void>}
+     */
+    cancelMuteAll(groupIdOrReq: string | ImCancelMuteAllReq): Promise<void>;
+    /**
+     * 禁言指定用户,限管理员才能操作
+     * @param {ImMuteUserReq} req
+     * @returns {Promise<void>}
+     */
+    muteUser(req: ImMuteUserReq): Promise<void>;
+    /**
+     * 取消禁言指定用户,限管理员才能操作
+     * @param {ImCancelMuteUserReq} req
+     * @returns {Promise<void>}
+     */
+    cancelMuteUser(req: ImCancelMuteUserReq): Promise<void>;
+    /**
+     * 查询禁言用户列表,限管理员才能操作
+     * @param {string | ImListMuteUsersReq} groupIdOrReq
+     * @returns {Promise<ImListMuteUsersRsp>}
+     */
+    listMuteUsers(groupIdOrReq: string | ImListMuteUsersReq): Promise<ImListMuteUsersRsp>;
+}
+
+class AliVCIMMessageManager extends EventEmitter<ImMessageListener> {
+    private wasmIns;
+    private wasmMessageManager;
+    private messageListener;
+    private streamMessageManager;
+    constructor(wasmIns: any, wasmInterface: any);
+    addMessageListener(): void;
+    removeMessageListener(): void;
+    destroy(): void;
+    /**
+     * 发送单聊普通消息
+     * @param {ImSendMessageToUserReq} req
+     * @returns {string} messageId
+     */
+    sendC2cMessage(req: ImSendMessageToUserReq): Promise<string>;
+    /**
+     * 发送群聊普通消息
+     * @param {ImSendMessageToGroupReq} req
+     * @returns {string} messageId
+     */
+    sendGroupMessage(req: ImSendMessageToGroupReq): Promise<string>;
+    /**
+     * 查询消息列表
+     * @param {ImListMessageReq} req
+     * @returns {ImListMessageRsp}
+     */
+    listMessage(req: ImListMessageReq): Promise<ImListMessageRsp>;
+    /**
+     * 查询最近消息
+     * @param {string |ImListRecentMessageReq} groupIdOrReq
+     * @returns {ImListRecentMessageRsp}
+     */
+    listRecentMessage(groupIdOrReq: string | ImListRecentMessageReq): Promise<ImListRecentMessageRsp>;
+    /**
+     * 查询历史消息,该接口主要用户直播结束后的历史消息回放,用户无需进入群组可查询,比较耗时,在直播过程中不建议使用,另外该接口后续可能会收费。
+     * @param {ImListHistoryMessageReq} req
+     * @returns {ImListHistoryMessageRsp}
+     */
+    listHistoryMessage(req: ImListHistoryMessageReq): Promise<ImListHistoryMessageRsp>;
+    /**
+     * 删除/撤回群消息
+     */
+    deleteMessage(req: ImDeleteMessageReq): Promise<void>;
+    /**
+     * 创建流式消息
+     */
+    createStreamMessage(req: ImCreateStreamMessageReq): Promise<ImStreamMessageSender>;
+    /**
+     * 拒收流式消息
+     */
+    rejectStreamMessage(req: ImRejectStreamMessageReq): Promise<void>;
+    /**
+     * 自定义流式消息转发
+     */
+    forwardCustomMessage(req: ImForwardCustomMessageReq): Promise<ImForwardCustomMessageRsp>;
+}
+
+/**
+ * Minimal `EventEmitter` interface that is molded against the Node.js
+ * `EventEmitter` interface.
+ */
+class EventEmitter<
+EventTypes extends EventEmitter.ValidEventTypes = string | symbol,
+Context extends any = any
+> {
+    static prefixed: string | boolean;
+
+    /**
+     * Return an array listing the events for which the emitter has registered
+     * listeners.
+     */
+    eventNames(): Array<EventEmitter.EventNames<EventTypes>>;
+
+    /**
+     * Return the listeners registered for a given event.
+     */
+    listeners<T extends EventEmitter.EventNames<EventTypes>>(
+    event: T
+    ): Array<EventEmitter.EventListener<EventTypes, T>>;
+
+    /**
+     * Return the number of listeners listening to a given event.
+     */
+    listenerCount(event: EventEmitter.EventNames<EventTypes>): number;
+
+    /**
+     * Calls each of the listeners registered for a given event.
+     */
+    emit<T extends EventEmitter.EventNames<EventTypes>>(
+    event: T,
+    ...args: EventEmitter.EventArgs<EventTypes, T>
+    ): boolean;
+
+    /**
+     * Add a listener for a given event.
+     */
+    on<T extends EventEmitter.EventNames<EventTypes>>(
+    event: T,
+    fn: EventEmitter.EventListener<EventTypes, T>,
+    context?: Context
+    ): this;
+    addListener<T extends EventEmitter.EventNames<EventTypes>>(
+    event: T,
+    fn: EventEmitter.EventListener<EventTypes, T>,
+    context?: Context
+    ): this;
+
+    /**
+     * Add a one-time listener for a given event.
+     */
+    once<T extends EventEmitter.EventNames<EventTypes>>(
+    event: T,
+    fn: EventEmitter.EventListener<EventTypes, T>,
+    context?: Context
+    ): this;
+
+    /**
+     * Remove the listeners of a given event.
+     */
+    removeListener<T extends EventEmitter.EventNames<EventTypes>>(
+    event: T,
+    fn?: EventEmitter.EventListener<EventTypes, T>,
+    context?: Context,
+    once?: boolean
+    ): this;
+    off<T extends EventEmitter.EventNames<EventTypes>>(
+    event: T,
+    fn?: EventEmitter.EventListener<EventTypes, T>,
+    context?: Context,
+    once?: boolean
+    ): this;
+
+    /**
+     * Remove all listeners, or those of the specified event.
+     */
+    removeAllListeners(event?: EventEmitter.EventNames<EventTypes>): this;
+}
+
+namespace EventEmitter {
+    interface ListenerFn<Args extends any[] = any[]> {
+        (...args: Args): void;
+    }
+
+    interface EventEmitterStatic {
+        new <
+        EventTypes extends ValidEventTypes = string | symbol,
+        Context = any
+        >(): EventEmitter<EventTypes, Context>;
+    }
+
+    /**
+     * `object` should be in either of the following forms:
+     * ```
+     * interface EventTypes {
+     *   'event-with-parameters': any[]
+     *   'event-with-example-handler': (...args: any[]) => void
+     * }
+     * ```
+     */
+    type ValidEventTypes = string | symbol | object;
+
+    type EventNames<T extends ValidEventTypes> = T extends string | symbol
+    ? T
+    : keyof T;
+
+    type ArgumentMap<T extends object> = {
+        [K in keyof T]: T[K] extends (...args: any[]) => void
+        ? Parameters<T[K]>
+        : T[K] extends any[]
+        ? T[K]
+        : any[];
+    };
+
+    type EventListener<
+    T extends ValidEventTypes,
+    K extends EventNames<T>
+    > = T extends string | symbol
+    ? (...args: any[]) => void
+    : (
+    ...args: ArgumentMap<Exclude<T, string | symbol>>[Extract<K, keyof T>]
+    ) => void;
+
+    type EventArgs<
+    T extends ValidEventTypes,
+    K extends EventNames<T>
+    > = Parameters<EventListener<T, K>>;
+
+    const EventEmitter: EventEmitterStatic;
+}
+
+interface ImAttachmentProgress {
+    progress: number;
+    totalSize: number;
+    currentSize: number;
+}
+
+interface ImAttachmentReq {
+    id: string;
+    fileType: ImAttachmentType;
+    fileName: string;
+    file?: File | Blob;
+    filePath?: string;
+    extra?: string;
+    onProgress?: (res: ImAttachmentProgress) => void;
+}
+
+interface ImAttachmentRes {
+    id: string;
+    fileType: ImAttachmentType;
+    fileSize: number;
+    fileName: string;
+    accessKey: string;
+    fileDuration: number;
+    extra: string;
+}
+
+enum ImAttachmentType {
+    IMAGE = 1,
+    AUDIO = 2,
+    VIDEO = 3,
+    OTHER = 4
+}
+
+interface ImAuth {
+    /**
+     * 随机数,格式:"AK-随机串", 最长64字节, 仅限A-Z,a-z,0-9及"_",可为空
+     */
+    nonce: string;
+    /**
+     * 过期时间:从1970到过期时间的秒数
+     */
+    timestamp: number;
+    /**
+     * 角色,为admin时,表示该用户可以调用管控接口,可为空,如果要给当前用户admin权限,应该传admin
+     */
+    role?: string;
+    /**
+     * token
+     */
+    token: string;
+}
+
+interface ImCancelMuteAllReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImCancelMuteUserReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param userList 被取消禁言的用户列表
+     */
+    userList: string[];
+}
+
+interface ImCloseGroupReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImCreateGroupReq {
+    /**
+     * @param groupId 群组id,【可选】id为空的话,会由sdk内部生成
+     */
+    groupId?: string;
+    /**
+     * @param groupName 群组名称
+     */
+    groupName: string;
+    /**
+     * @param extension 业务扩展字段
+     */
+    groupMeta?: string;
+}
+
+interface ImCreateGroupRsp {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param alreadyExist 是否已经创建过
+     */
+    alreadyExist: boolean;
+}
+
+interface ImCreateStreamMessageReq {
+    /**
+     * 数据类型
+     */
+    dataType: ImStreamMessageDataType;
+    /**
+     * 数据接收类型
+     */
+    receiverType: ImStreamMessageReceiverType;
+    /**
+     * 数据接收者ID
+     */
+    receiverId: string;
+}
+
+interface ImDeleteMessageReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param messageId 消息id
+     */
+    messageId: string;
+}
+
+let ImEngine: typeof ImEngine_2;
+
+class ImEngine_2 extends EventEmitter<ImSdkListener> {
+    private wasmIns;
+    private wasmEngine;
+    private wasmInterface;
+    private transport?;
+    private appEventManager?;
+    private eventListener;
+    private messageManager?;
+    private groupManager?;
+    private attachmentManager?;
+    private pluginProvider?;
+    private uploader;
+    private supportsWebRtc;
+    private supportWASM;
+    private initFlag;
+    constructor();
+    static engine: ImEngine_2;
+    /**
+     * @brief 获取 SDK 引擎实例(单例)
+     * @returns ImEngine
+     */
+    static createEngine(): ImEngine_2;
+    /**
+     * 当前 SDK 是否支持,支持 WASM 或者 ASM
+     * @returns
+     */
+    static isSupport(): boolean;
+    static getSdkVersion(): string;
+    private initTransport;
+    private initAppEvent;
+    private loadWasm;
+    private preloadUploader;
+    private initNativePlugin;
+    /**
+     * @brief 初始化
+     * @param config SDK配置信息
+     */
+    init(config: ImSdkConfig): Promise<0 | ImErrors.ERROR_CLIENT_REPEATED_INIT>;
+    /**
+     * 添加 Engine 事件监听
+     */
+    private addEventListener;
+    private removeEventListener;
+    private destroy;
+    /**
+     * @brief 销毁
+     */
+    unInit(): boolean;
+    /**
+     * @brief 登录
+     * @param req 登录请求数据
+     */
+    login(loginReq: ImLoginReq): Promise<void>;
+    /**
+     * @brief 登出
+     */
+    logout(): Promise<void>;
+    /**
+     * 强制重连
+     */
+    reconnect(): void;
+    /**
+     * @brief 获取当前登录用户 ID
+     */
+    getCurrentUserId(): string;
+    /**
+     * @brief 是否登录
+     */
+    isLogin(): boolean;
+    /**
+     * @brief 是否已退出登录
+     */
+    isLogout(): boolean;
+    /**
+     * @brief 获取消息管理器 {AliVCIMMessageInterface}
+     * @return 返回消息管理器实例
+     */
+    getMessageManager(): AliVCIMMessageManager | undefined;
+    /**
+     * @brief 获取群组管理器 {AliVCIMGroupInterface}
+     * @return 返回群组管理器实例
+     */
+    getGroupManager(): AliVCIMGroupManager | undefined;
+    /**
+     * @brief 获取附件管理器 {AliVCIMAttachmentInterface}
+     * @return 返回附件管理器实例
+     */
+    getAttachmentManager(): AliVCIMAttachmentManager | undefined;
+}
+
+enum ImErrors {
+    /**
+     * 已经登录
+     */
+    ERROR_HAS_LOGIN = 304,
+    /**
+     * 参数错误;参数无法解析
+     */
+    ERROR_INVALID_PARAM = 400,
+    /**
+     * 错误码(subcode)	说明
+     * 403	操作无权限; 或登录时鉴权失败
+     */
+    ERROR_NO_PERMISSION = 403,
+    /**
+     * no session,可能因为客户网络变化等原因导致的连接变化,服务器在新连接上收到消息无法正常处理,需要reconnect 信令。
+     */
+    ERROR_NO_SESSION = 404,
+    /**
+     * 审核不通过
+     */
+    ERROR_AUDIT_FAIL = 406,
+    /**
+     * 繁忙,发送太快,稍候重试
+     * 服务端同学确认不需要区分这两个错误
+     */
+    ERROR_INTERNAL_BUSY = 412,
+    ERROR_INTERNAL_BUSY2 = 413,
+    /**
+     * 发送 c2c 消息对方用户不在线
+     */
+    ERROR_USER_OFFLINE = 424,
+    /**
+     * 未加入群组
+     */
+    ERROR_GROUP_NOT_JOINED = 425,
+    /**
+     * 操作过快,短时间内,发起过多请求。如同一个用户,1秒内发起2次登录。
+     */
+    ERROR_INTERNAL_BUSY3 = 429,
+    /**
+     * 群组不存在
+     */
+    ERROR_GROUP_NOT_EXIST = 440,
+    /**
+     * 群组已删除
+     */
+    ERROR_GROUP_DELETED = 441,
+    /**
+     * 无法在该群组中发送消息,被禁言
+     */
+    ERROR_SEND_GROUP_MSG_FAIL = 442,
+    /**
+     * 进了太多的群组, 列表人数超大等
+     */
+    ERROR_REACH_MAX = 443,
+    /**
+     * 无法加入该群,被禁止加入(暂无需求未实现)预留
+     */
+    ERROR_JOIN_GROUP_FAIL = 450,
+    /**
+     * ots 查询错误
+     */
+    ERROR_OTS_FAIL = 480,
+    /**
+     * 系统临时错误,稍候重试
+     */
+    ERROR_INTERNALE_RROR = 500,
+    /**
+     * 底层重复初始化
+     */
+    ERROR_CLIENT_REPEATED_INIT = -1,
+    /**
+     * 初始化配置信息有误
+     */
+    ERROR_CLIENT_INIT_INVALID_PARAM = -2,
+    /**
+     * 未初始化
+     */
+    ERROR_CLIENT_NOT_INIT = 1,
+    /**
+     * 参数异常
+     */
+    ERROR_CLIENT_INVALID_PARAM = 2,
+    /**
+     * 状态有误
+     */
+    ERROR_CLIENT_INVALID_STATE = 3,
+    /**
+     * 建连失败
+     */
+    ERROR_CLIENT_CONNECT_ERROR = 4,
+    /**
+     * 建连超时
+     */
+    ERROR_CLIENT_CONNECT_TIMEOUT = 5,
+    /**
+     * 发送失败
+     */
+    ERROR_CLIENT_SEND_FAILED = 6,
+    /**
+     * 发送取消
+     */
+    ERROR_CLIENT_SEND_CANCEL = 7,
+    /**
+     * 发送超时
+     */
+    ERROR_CLIENT_SEND_TIMEOUT = 8,
+    /**
+     * 订阅失败
+     */
+    ERROR_CLIENT_SUB_ERROR = 9,
+    /**
+     * 订阅通道断连
+     */
+    ERROR_CLIENT_SUB_DISCONNECT = 10,
+    /**
+     * 订阅超时
+     */
+    ERROR_CLIENT_SUB_TIMEOUT = 11,
+    /**
+     * 压缩失败
+     */
+    ERROR_CLIENT_COMPRESS_ERROR = 12,
+    /**
+     * 解压失败
+     */
+    ERROR_CLIENT_DECOMPRESS_ERROR = 13,
+    /**
+     * 加密失败
+     */
+    ERROR_CLIENT_ENCRYPT_ERROR = 14,
+    /**
+     * 解密失败
+     */
+    ERROR_CLIENT_DECRYPT_ERROR = 15,
+    /**
+     * 消息体封装失败
+     */
+    ERROR_CLIENT_CONVERTER_ERROR = 16,
+    /**
+     * 消息体解析失败
+     */
+    ERROR_CLIENT_PARSE_ERROR = 17,
+    /**
+     * 数据为空
+     */
+    ERROR_CLIENT_DATA_EMPTY = 18,
+    /**
+     * 数据错误
+     */
+    ERROR_CLIENT_DATA_ERROR = 19,
+    /**
+     * 地址出错(可能是AppSign有误,如头部带了空格、内容被截断等)
+     */
+    ERROR_CLIENT_URL_ERROR = 20,
+    /**
+     * 建连取消
+     */
+    CONNECT_CANCEL = 21,
+    /**
+     * 重试超过次数限制
+     */
+    RETRY_OVER_TIME = 22,
+    /**
+     * 状态错误
+     */
+    ERROR_INVALID_STATE = 601,
+    /**
+     * 未登录
+     */
+    ERROR_NOT_LOGIN = 602,
+    /**
+     * 收到上次session的消息
+     */
+    ERROR_RECEIVE_LAST_SESSION = 603,
+    /**
+     * Parse Data Error
+     */
+    ERROR_PARSE_DATA_ERROR = 604
+}
+
+interface ImForwardCustomMessageReq {
+    /**
+     * 数据接收者ID
+     */
+    receiverId: string;
+    /**
+     * 数据,若需要传对象,需要序列化
+     */
+    data: string;
+}
+
+interface ImForwardCustomMessageRsp {
+    /**
+     * 流式消息ID
+     */
+    messageId: string;
+    /**
+     * 数据,若返回的是对象,需要反序列化
+     */
+    data: string;
+}
+
+interface ImGroupInfo {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param groupName 群组名称
+     */
+    groupName: string;
+    /**
+     * @param groupMeta 群组透传信息
+     */
+    groupMeta: string;
+    /**
+     * @param createTime 创建时间
+     */
+    createTime: number;
+    /**
+     * @param creator 创建者id
+     */
+    creator: string;
+    /**
+     * @param admins 管理员列表
+     */
+    admins: string[];
+    /**
+     * @param statistics 群组统计
+     */
+    statistics: ImGroupStatistics;
+    /**
+     * @param muteStatus 群禁言信息
+     */
+    muteStatus: ImGroupMuteStatus;
+}
+
+interface ImGroupInfoStatus {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param groupMeta 群组扩展信息
+     */
+    groupMeta: string;
+    /**
+     * @param adminList 管理员列表
+     */
+    adminList: string[];
+}
+
+interface ImGroupListener {
+    /**
+     * @deprecated 1.4.1 后请使用 memberdatachange 事件
+     *
+     * 群组成员变化
+     * @param groupId  群组ID
+     * @param memberCount 当前群组人数
+     * @param joinUsers 加入的用户
+     * @param leaveUsers 离开的用户
+     */
+    memberchange: (groupId: string, memberCount: number, joinUsers: ImUser[], leaveUsers: ImUser[]) => void;
+    /**
+     * 1.4.1 版本新增新的群组成员变化,返回的是一个对象
+     * @param data 群组成员变化数据对象
+     * @param data.groupId  群组ID
+     * @param data.onlineCount 当前群组在线人数
+     * @param data.pv  加入群组累积pv数
+     * @param data.isBigGroup 是否是大群组
+     * @param data.joinUsers 加入的用户
+     * @param data.leaveUsers 离开的用户
+     */
+    memberdatachange: (data: ImMemberChangeData) => void;
+    /**
+     * 退出群组
+     * @param groupId  群组ID
+     * @param reason 退出原因 1: 群被解散, 2:被踢出来了
+     */
+    exit: (groupId: string, reason: number) => void;
+    /**
+     * 群组静音状态变化
+     * @param groupId  群组ID
+     * @param status 静音状态
+     */
+    mutechange: (groupId: string, status: ImGroupMuteStatus) => void;
+    /**
+     * 群组信息变化
+     * @param groupId  群组ID
+     * @param info 群组信息
+     */
+    infochange: (groupId: string, info: ImGroupInfoStatus) => void;
+}
+
+interface ImGroupMuteStatus {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param muteAll 是否全员禁言
+     */
+    muteAll: boolean;
+    /**
+     * @param muteUserList 禁言用户ID列表
+     */
+    muteUserList: string[];
+    /**
+     * @param whiteUserList 白名单用户ID列表
+     */
+    whiteUserList: string[];
+}
+
+interface ImGroupStatistics {
+    /**
+     * @param pv PV
+     */
+    pv: number;
+    /**
+     * @param onlineCount 在线人数
+     */
+    onlineCount: number;
+    /**
+     * @param msgAmount 消息数量
+     */
+    msgAmount: {
+        [key: string]: number;
+    };
+}
+
+interface ImJoinGroupReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImLeaveGroupReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImListGroupUserReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param sortType 排序方式,ASC-先加入优先,DESC-后加入优先
+     */
+    sortType?: ImSortType;
+    /**
+     * @param nextPageToken 默认表示第一页,遍历时服务端会返回,客户端获取下一页时,应带上
+     */
+    nextPageToken?: number;
+    /**
+     * @deprecated 请使用 nextPageToken
+     */
+    nextpagetoken?: number;
+    /**
+     * @param pageSize 最大不超过50
+     */
+    pageSize?: number;
+}
+
+interface ImListGroupUserRsp {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param nextPageToken 下一页的token
+     */
+    nextPageToken: number;
+    /**
+     * @deprecated 请使用 nextPageToken
+     */
+    nextpagetoken?: number;
+    /**
+     * @param hasMore 是否还有下一页
+     */
+    hasMore: boolean;
+    /**
+     * @param userList 返回的群组的在线成员列表
+     */
+    userList: ImUser[];
+}
+
+interface ImListHistoryMessageReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param type 消息类型
+     */
+    type: number;
+    /**
+     * @param nextPageToken 不传时表示第一页,遍历时服务端会返回,客户端获取下一页时,应带上
+     */
+    nextPageToken?: number;
+    /**
+     * @param sortType 排序类型,默认为时间递增
+     */
+    sortType?: ImSortType;
+    /**
+     * @param pageSize 取值范围 10~30
+     */
+    pageSize?: number;
+    /**
+     * @param begintime 按时间范围遍历,开始时间,不传时表示最早时间,单位:秒
+     */
+    beginTime?: number;
+    /**
+     * @param endtime 按时间范围遍历,结束时间,不传时表示最晚时间,单位:秒
+     */
+    endTime?: number;
+}
+
+interface ImListHistoryMessageRsp {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param nextPageToken 不传时表示第一页,遍历时服务端会返回,客户端获取下一页时,应带上
+     */
+    nextPageToken?: number;
+    /**
+     *@param hasMore 是否有更多数据
+     */
+    hasMore: boolean;
+    /**
+     *@param messageList 返回消息列表
+     **/
+    messageList: ImMessage[];
+}
+
+interface ImListMessageReq {
+    /**
+     * @param groupId 话题id,聊天插件实例id
+     */
+    groupId: string;
+    /**
+     * @param type 消息类型
+     */
+    type: number;
+    /**
+     * @param nextPageToken 不传时表示第一页,遍历时服务端会返回,客户端获取下一页时应带上
+     */
+    nextPageToken?: number;
+    /**
+     * @deprecated 请使用nextPageToken
+     */
+    nextpagetoken?: number;
+    /**
+     * @param sortType 排序类型,默认为时间递增
+     */
+    sortType?: ImSortType;
+    /**
+     * @param pageSize 分页拉取的大小,默认10条,最大30条
+     */
+    pageSize?: number;
+    /**
+     * @param begintime 按时间范围遍历,开始时间,不传时表示最早时间,单位:秒
+     */
+    beginTime?: number;
+    /**
+     * @param endtime 按时间范围遍历,结束时间,不传时表示最晚时间,单位:秒
+     */
+    endTime?: number;
+}
+
+interface ImListMessageRsp {
+    /**
+     ** @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     *@param nextpagetoken 客户端获取下一页时,应带上
+     */
+    nextPageToken: number;
+    /**
+     * @deprecated 请使用 nextPageToken
+     */
+    nextpagetoken?: number;
+    /**
+     *@param hasmore 是否有更多数据
+     */
+    hasMore: boolean;
+    /**
+     *@param messageList 返回消息列表
+     **/
+    messageList: ImMessage[];
+}
+
+interface ImListMuteUsersReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImListMuteUsersRsp {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param muteAll 是否全员禁言
+     */
+    muteAll: boolean;
+    /**
+     * @param muteUserList 禁言用户ID列表
+     */
+    muteUserList: string[];
+    /**
+     * @param whiteUserList 白名单用户ID列表
+     */
+    whiteUserList: string[];
+}
+
+interface ImListRecentGroupUserReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImListRecentGroupUserRsp {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param total 群组成员总数
+     */
+    total: number;
+    /**
+     * @param userList 返回的群组的在线成员列表
+     */
+    userList: ImUser[];
+}
+
+interface ImListRecentMessageReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param seqnum 消息序列号
+     */
+    seqnum?: number;
+    /**
+     * @param pageSize 分页拉取的大小,默认50条
+     */
+    pageSize?: number;
+}
+
+interface ImListRecentMessageRsp {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param messageList 返回消息列表
+     */
+    messageList: ImMessage[];
+}
+
+interface ImLoginReq {
+    user: ImUser;
+    /**
+     * 用户鉴权信息
+     */
+    userAuth: ImAuth;
+}
+
+enum ImLogLevel {
+    NONE = 0,
+    DBUG = 1,
+    INFO = 2,
+    WARN = 3,
+    ERROR = 4
+}
+
+interface ImMemberChangeData {
+    groupId: string;
+    onlineCount: number;
+    pv: number;
+    isBigGroup: boolean;
+    joinUsers: ImUser[];
+    leaveUsers: ImUser[];
+}
+
+interface ImMessage {
+    /**
+     * @param groupId 话题id,聊天插件实例id
+     */
+    groupId?: string;
+    /**
+     * @param messageId 消息id
+     */
+    messageId: string;
+    /**
+     *@param type 消息类型。系统消息小于10000
+     */
+    type: number;
+    /**
+     *@param sender 发送者
+     */
+    sender?: ImUser;
+    /**
+     **@param data 消息内容
+     */
+    data: string;
+    /**
+     *@param seqnum 消息顺序号
+     */
+    seqnum: number;
+    /**
+     *@param timestamp 消息发送时间
+     */
+    timestamp: number;
+    /**
+     *@param level 消息分级
+     **/
+    level: ImMessageLevel;
+    /**
+     * @param repeatCount 消息统计数量增长值,默认1,主要用于聚合同类型消息。
+     */
+    repeatCount: number;
+    /**
+     * @param totalMsgs 同类型的消息数量
+     */
+    totalMsgs: number;
+}
+
+enum ImMessageLevel {
+    NORMAL = 0,
+    HIGH = 1
+}
+
+interface ImMessageListener {
+    /**
+     * 接收到c2c消息
+     * @param msg 消息
+     */
+    recvc2cmessage: (msg: ImMessage) => void;
+    /**
+     * 接收到群消息
+     * @param msg 消息
+     * @param groupId 群id
+     */
+    recvgroupmessage: (msg: ImMessage, groupId: string) => void;
+    /**
+     * 删除群消息
+     * @param msgId 消息id
+     * @param groupId 群id
+     */
+    deletegroupmessage: (msgId: string, groupId: string) => void;
+    /**
+     * 流消息结束通知
+     * @param {string} messageId 消息ID
+     * @param {number} endCode 结束原因:0正常处理结束,1主动取消,2与智能体服务连接异常断开,3连接超时断开,4收到新的开始切片,5包请求异常
+     * @param {number} [subCode] 详情码
+     * @param {string} [subMsg]  详情信息
+     */
+    streammessageend: (messageId: string, endCode: number, subCode?: number, subMsg?: string) => void;
+    /**
+     * 接收到流消息
+     * @param message 流消息
+     */
+    recvstreammessage: (message: ImStreamMessage) => void;
+}
+
+interface ImModifyGroupReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param forceUpdateGroupMeta 为true表示强制刷新groupMeta信息,若groupMeta为空则表示清空;
+     *                             为false,则只有groupMeta不空才更新groupMeta信息
+     */
+    forceUpdateGroupMeta?: boolean;
+    /**
+     * @param groupMeta 群信息扩展字段
+     */
+    groupMeta?: string;
+    /**
+     * @param forceUpdateAdmins 为true表示强制刷新admins信息,若admins为空则表示清空;
+     *                          为false,则只有admins不空才更新admins信息
+     */
+    forceUpdateAdmins?: boolean;
+    /**
+     * @param admins 群管理员ID列表,最多设置3个管理员
+     */
+    admins?: string[];
+}
+
+interface ImMuteAllReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImMuteUserReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+    /**
+     * @param userList 需要禁言的用户列表
+     */
+    userList: string[];
+}
+
+interface ImQueryGroupReq {
+    /**
+     * @param groupId 群组id
+     */
+    groupId: string;
+}
+
+interface ImRejectStreamMessageReq {
+    /**
+     * 流式消息ID
+     */
+    messageId: string;
+    /**
+     * 数据接收类型
+     */
+    receiverType: ImStreamMessageReceiverType;
+    /**
+     * 错误码
+     */
+    code: number;
+    /**
+     * 错误信息
+     */
+    msg: string;
+}
+
+interface ImSdkConfig {
+    /**
+     * 设备唯一标识
+     */
+    deviceId?: string;
+    /**
+     * 应用ID
+     */
+    appId: string;
+    /**
+     * 应用签名
+     */
+    appSign: string;
+    /**
+     * 日志级别
+     */
+    logLevel?: ImLogLevel;
+    /**
+     * 来源
+     */
+    source?: string;
+    /**
+     * 心跳超时时间,单位是秒,默认 99s,允许 [15-120]s
+     */
+    heartbeatTimeout?: number;
+    /**
+     * @param extra 用户自定义参数
+     */
+    extra?: {
+        [key: string]: string;
+    };
+    /**
+     * @param uploader 附件上传器参数
+     */
+    uploader?: {
+        /**
+         * 是否提前加载,默认 false
+         */
+        preload?: boolean;
+        /**
+         * 指定sdk文件地址
+         */
+        sdkUrl?: string;
+    };
+}
+
+interface ImSdkListener {
+    /**
+     * 连接中
+     */
+    connecting: () => void;
+    /**
+     * 连接成功
+     */
+    connectsuccess: () => void;
+    /**
+     * 连接失败
+     */
+    connectfailed: (error: Error) => void;
+    /**
+     * 连接断开
+     * @param code 断开原因 1:主动退出, 2:被踢出 3:超时等其他原因 4:在其他端上登录
+     */
+    disconnect: (code: number) => void;
+    /**
+     * 连接状态变化
+     * state 状态 0:未连接 1:连接中 2:已连接 3:已断联
+     */
+    linkstate: (data: {
+        previousState: number;
+        currentState: number;
+    }) => void;
+    /**
+     * token过期
+     * @param callback 更新 Token 的回调
+     */
+    tokenexpired: (callback: TokenCallback) => void;
+    /**
+     * 重连成功
+     */
+    reconnectsuccess: (groupInfos: ImGroupInfo[]) => void;
+}
+
+interface ImSendMessageToGroupReq {
+    /**
+     * @param groupId 话题id,聊天插件实例id
+     */
+    groupId: string;
+    /**
+     * @param type 消息类型,小于等于10000位系统消息,大于10000位自定义消息
+     */
+    type: number;
+    /**
+     * @param data 消息体
+     */
+    data: string;
+    /**
+     * @param skipMuteCheck 跳过禁言检测,true:忽略被禁言用户,还可发消息;false:当被禁言时,消息无法发送,默认为false,即为不跳过禁言检测。
+     */
+    skipMuteCheck?: boolean;
+    /**
+     * @param skipAudit 跳过安全审核,true:发送的消息不经过阿里云安全审核服务审核;false:发送的消息经过阿里云安全审核服务审核,审核失败则不发送;
+     */
+    skipAudit?: boolean;
+    /**
+     * @param level 消息分级
+     */
+    level?: ImMessageLevel;
+    /**
+     * @param noStorage 为true时,表示该消息不需要存储,也无法拉取查询
+     */
+    noStorage?: boolean;
+    /**
+     * @param repeatCount 消息统计数量增长值,默认1,主要用于聚合同类型消息,只发送一次请求,例如点赞场景
+     */
+    repeatCount?: number;
+}
+
+interface ImSendMessageToUserReq {
+    /**
+     * 消息类型。系统消息小于10000
+     */
+    type: number;
+    /**
+     * 消息体
+     */
+    data: string;
+    /**
+     * 接收者用户
+     */
+    receiverId: string;
+    /**
+     * 跳过安全审核,true:发送的消息不经过阿里云安全审核服务审核;false:发送的消息经过阿里云安全审核服务审核,审核失败则不发送;
+     */
+    skipAudit?: boolean;
+    /**
+     * 消息分级
+     */
+    level?: ImMessageLevel;
+}
+
+enum ImSortType {
+    ASC = 0,
+    DESC = 1
+}
+
+interface ImStreamData {
+    seqNum: number;
+    byteData: ArrayBuffer;
+}
+
+interface ImStreamMessage {
+    /**
+     * 流式消息ID
+     */
+    messageId: string;
+    /**
+     * 发送用户
+     */
+    sender: ImUser;
+    /**
+     * 流式消息帧数据
+     */
+    data: ImStreamData;
+}
+
+enum ImStreamMessageDataType {
+    TEXT = 1,// 文本
+    BINARY_FILE = 2
+}
+
+enum ImStreamMessageReceiverType {
+    SERVER = 0
+}
+
+class ImStreamMessageSender extends EventEmitter<ImStreamMessageSenderListener> {
+    private wasmIns;
+    private sender;
+    constructor(wasmIns: any);
+    setSender(sender: any): void;
+    getMessageId(): string;
+    /**
+     * 发送字节数据
+     * @param {Uint8Array} byteData 字节数据
+     * @param {boolean} isLast 是否结束流
+     * @param {ImAttachmentRes[]} [attachments] 附件列表
+     */
+    sendByteData(byteData: Uint8Array, isLast: boolean, attachments?: ImAttachmentRes[]): void;
+    /**
+     * 取消发送
+     * @param {number} [code] 取消码
+     * @param {string} [msg] 取消原因
+     */
+    cancel(code?: number, msg?: string): void;
+    destroy(): void;
+}
+
+interface ImStreamMessageSenderListener {
+    /**
+     * 流消息结束通知
+     * @param {string} messageId 消息ID
+     * @param {number} endCode 结束原因:0正常处理结束,1主动取消,2与智能体服务连接异常断开,3连接超时断开,4收到新的开始切片,5包请求异常
+     * @param {number} [subCode] 详情码
+     * @param {string} [subMsg]  详情信息
+     */
+    streammessageend: (messageId: string, endCode: number, subCode?: number, subMsg?: string) => void;
+}
+
+enum ImStreamMessageStatus {
+    CONTINUE = 0,// 中间帧
+    START = 1,// 开始帧
+    END = 2,// 结束帧
+    ALL = 3,// 一次性传输
+    CANCEL = 4
+}
+
+enum ImStreamMessageType {
+    NORMAL = 0
+}
+
+interface ImUser {
+    /**
+     * @param user_id 用户id
+     */
+    userId: string;
+    /**
+     * @param user_extension 用户扩展信息
+     */
+    userExtension?: string;
+}
+
+type TokenCallback = (error: {
+    code?: number;
+    msg: string;
+} | null, auth?: ImAuth) => void;
+}

+ 5 - 3
src/client/mobile/components/Classroom/useClassroom.ts

@@ -1,11 +1,13 @@
 import { useState, useEffect, useRef } from 'react';
 import { useParams } from 'react-router';
-import { User } from '../../../share/types.ts';
-import { ClassroomAPI } from '../../api/index.ts';
+// import { ClassroomAPI } from '../../api/index.ts';
 // @ts-types="../../../share/aliyun-rtc-sdk.d.ts"
+// @ts-types="./alivc-im.iife.d.ts"
 import AliRtcEngine, { AliRtcSubscribeState, AliRtcVideoTrack } from 'aliyun-rtc-sdk';
 import { toast } from 'react-toastify';
-
+import { User } from '../../hooks/AuthProvider';
+import { classroomDataClient } from '@/client/api';
+import "https://g.alicdn.com/apsara-media-box/imp-interaction/1.6.1/alivc-im.iife.js"
 export enum Role {
   Teacher = 'admin',
   Student = 'student'

+ 1 - 1
src/client/mobile/hooks/AuthProvider.tsx

@@ -12,7 +12,7 @@ import type {
 import { authClient } from '@/client/api';
 import type { InferResponseType, InferRequestType } from 'hono/client';
 
-type User = InferResponseType<typeof authClient.me.$get, 200>;
+export type User = InferResponseType<typeof authClient.me.$get, 200>;
 
 
 // 创建认证上下文

+ 6 - 6
src/client/mobile/routes.tsx

@@ -4,7 +4,7 @@ import { ProtectedRoute } from './components/ProtectedRoute';
 import { ErrorPage } from './components/ErrorPage';
 import { NotFoundPage } from './components/NotFoundPage';
 // import { MainLayout } from './layouts/MainLayout';
-// import { ClassroomDataPage } from './pages/ClassroomDataPage';
+import { ClassroomPage } from './pages/ClassroomPage';
 // import { SubmissionRecordsPage } from './pages/SubmissionRecordsPage';
 // import { StockDataPage } from './pages/StockDataPage';
 // import { StockXunlianCodesPage } from './pages/StockXunlianCodesPage';
@@ -29,11 +29,11 @@ export const router = createBrowserRouter([
       </ProtectedRoute>
     ),
     children: [
-      // {
-      //   path: 'classroom-data',
-      //   element: <ClassroomDataPage />,
-      //   errorElement: <ErrorPage />
-      // },
+      {
+        path: 'classroom',
+        element: <ClassroomPage />,
+        errorElement: <ErrorPage />
+      },
       // {
       //   path: 'submission-records',
       //   element: <SubmissionRecordsPage />,

+ 119 - 0
src/server/api/aliyun/index.ts

@@ -0,0 +1,119 @@
+import { Hono } from 'hono'
+import type { Variables , WithAuth } from './middlewares.ts'
+
+// 配置信息
+const IM_APP_ID = Deno.env.get('IM_APP_ID');
+const IM_APP_KEY = Deno.env.get('IM_APP_KEY');
+const IM_APP_SIGN = Deno.env.get('IM_APP_SIGN');
+const RTC_APP_ID = Deno.env.get('RTC_APP_ID')
+const RTC_APP_KEY = Deno.env.get('RTC_APP_KEY')
+
+const hex = (buffer: ArrayBuffer): string => {
+  const hexCodes = [];
+  const view = new DataView(buffer);
+  for (let i = 0; i < view.byteLength; i += 4) {
+    const value = view.getUint32(i);
+    const stringValue = value.toString(16);
+    const padding = '00000000';
+    const paddedValue = (padding + stringValue).slice(-padding.length);
+    hexCodes.push(paddedValue);
+  }
+  return hexCodes.join('');
+};
+
+const generateRTCToken = async (
+  channelId: string,
+  userId: string
+): Promise<{
+  token: string;
+  timestamp: number;
+}> => {
+  const timestamp = Math.floor(Date.now() / 1000) + 3600 * 3;
+  const encoder = new TextEncoder();
+  const data = encoder.encode(`${RTC_APP_ID}${RTC_APP_KEY}${channelId}${userId}${timestamp}`);
+  const hash = await crypto.subtle.digest('SHA-256', data);
+  const token = hex(hash);
+  return {
+    token,
+    timestamp
+  }
+};
+
+const generateImToken = async (userId: string, role: string): Promise<{
+  nonce: string;
+  token: string;
+  timestamp: number;
+}> => {
+  const nonce = 'AK_4';
+  const timestamp = Math.floor(Date.now() / 1000) + 3600 * 3;
+  const pendingShaStr = `${IM_APP_ID}${IM_APP_KEY}${userId}${nonce}${timestamp}${role}`;
+  const encoder = new TextEncoder();
+  const data = encoder.encode(pendingShaStr);
+  const hash = await crypto.subtle.digest('SHA-256', data);
+  const token = hex(hash);
+  return {
+    nonce,
+    token,
+    timestamp
+  }
+};
+
+export function createClassRoomRoutes(withAuth: WithAuth) {
+  const tokenRoutes = new Hono<{ Variables: Variables }>()
+
+  // 生成IM Token
+  tokenRoutes.post('/im_token', withAuth, async (c) => {
+    try {
+      const { role } = await c.req.json()
+      const user = c.get('user')
+      if (!user || typeof user !== 'object' || !('id' in user)) {
+        return c.json({ error: '用户信息无效' }, 401)
+      }
+      
+
+      // 生成Token
+      const { nonce, token , timestamp } = await generateImToken(user.id.toString(), role);
+
+      return c.json({
+        nonce, 
+        token,
+        timestamp,
+        appId: IM_APP_ID,
+        appSign: IM_APP_SIGN,
+      })
+    } catch (error) {
+      console.error('生成IM Token失败:', error)
+      return c.json({ error: '生成IM Token失败' }, 500)
+    }
+  })
+
+  // 生成RTC Token
+  tokenRoutes.post('/rtc_token', withAuth, async (c) => {
+    try {
+      const { channelId } = await c.req.json()
+      const user = c.get('user')
+      
+      if (!user || typeof user !== 'object' || !('id' in user)) {
+        return c.json({ error: '用户信息无效' }, 401)
+      }
+      
+      if (!RTC_APP_ID || !RTC_APP_KEY) {
+        return c.json({ error: '服务配置不完整' }, 500)
+      }
+
+      // 生成Token
+      const { token , timestamp } = await generateRTCToken(channelId, user.id.toString());
+
+      return c.json({
+        token,
+        timestamp,
+        appId: RTC_APP_ID,
+      })
+    } catch (error) {
+      console.error('生成RTC Token失败:', error)
+      return c.json({ error: '生成RTC Token失败' }, 500)
+    }
+  })
+
+  return tokenRoutes
+}