@minto-ai/tools 1.0.56 → 1.0.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * 音频权限管理类
3
+ *
4
+ * 用于处理浏览器中的音频播放和录音权限问题,解决自动播放限制。
5
+ *
6
+ * 平台差异处理:
7
+ * - iOS平台:
8
+ * 必须在用户交互后,通过 navigator.mediaDevices.getUserMedia({ audio: true }) 申请权限,这里会直接audioContext仍然suspended状态,需要 audioContext.resume() 改变状态
9
+ * 当后续 audioPermissionGranted 为true 申请完权限之后,第二次调用申请权限时,仍然需要申请权限,使用 audioContext.resume() 改变AudioContext从suspended变为running
10
+ * - Android平台:(注意点:虽然一开始检测AudioContext状态为running,但是navigator.mediaDevices.getUserMedia会报错,所有并不能一开始就检测AudioContext状态)
11
+ * 必须在用户交互后,通过 navigator.mediaDevices.getUserMedia({ audio: true }) 申请权限,这里会直接audioContext变为为running状态,并不需要 audioContext.resume() 改变状态
12
+ * 当后续 audioPermissionGranted 为true 申请完权限之后,第二次调用申请权限时,不需要再次申请权限,这时 audioContext 会变为running状态,直接返回成功
13
+ * - PC平台:
14
+ * 可以优先检测如果为running则表示权限已可用,就不需要申请权限,如果为suspended则表示权限未可用,需要申请权限
15
+ * 当用户交互后,通过 navigator.mediaDevices.getUserMedia({ audio: true }) 申请权限,这里会直接audioContext变为为running状态,并不需要 audioContext.resume() 改变状态
16
+ * 当后续 audioPermissionGranted 为true 申请完权限之后,第二次调用申请权限时,不需要再次申请权限,这时 audioContext 会变为running状态,直接返回成功
17
+ */
18
+ declare class AudioPermission {
19
+ private userInteracted;
20
+ private audioPermissionGranted;
21
+ constructor();
22
+ /**
23
+ * 初始化音频权限检测流程
24
+ * 根据不同平台采用相应的权限检测策略
25
+ */
26
+ private initAudioPermission;
27
+ /**
28
+ * 监听用户交互事件
29
+ * 监听多种交互事件类型,确保在各种设备上都能正确检测到用户操作
30
+ */
31
+ private waitForUserInteraction;
32
+ /**
33
+ * 请求音频权限(包含录音和播放权限)
34
+ *
35
+ * @returns Promise<boolean> 返回权限获取结果,true表示成功,false表示失败
36
+ */
37
+ requestAudioPermission(): Promise<boolean>;
38
+ }
39
+ /**
40
+ * 创建或获取音频权限管理实例
41
+ *
42
+ * @returns AudioPermission 音频权限管理实例
43
+ */
44
+ declare function createAudioPermission(): AudioPermission;
45
+ export default createAudioPermission;
@@ -1,7 +1,7 @@
1
1
  import { default as copyText } from './copy-text';
2
+ import { default as createAudioPermission } from './create-audio-permission';
2
3
  import { default as isAndroid } from './is-android';
3
4
  import { default as isIos } from './is-ios';
4
5
  import { default as isMobile } from './is-mobile';
5
6
  import { default as isPc } from './is-pc';
6
- import { default as waitForUserInteraction } from './wait-for-user-interaction';
7
- export { copyText, isAndroid, isIos, isMobile, isPc, waitForUserInteraction };
7
+ export { copyText, createAudioPermission, isAndroid, isIos, isMobile, isPc };
package/dist/index.js CHANGED
@@ -13246,52 +13246,164 @@ function isIos() {
13246
13246
  var userAgent2 = navigator.userAgent.toLowerCase();
13247
13247
  return /iphone|ipad|ipod/.test(userAgent2);
13248
13248
  }
13249
- function isMobile() {
13250
- return isAndroid() || isIos();
13251
- }
13252
- function isPc() {
13253
- return !isMobile();
13254
- }
13255
- function waitForUserInteraction() {
13256
- return new Promise(function(resolve2) {
13257
- var audioContext = new (window.AudioContext || window.webkitAudioContext)();
13258
- if (audioContext.state === "running") {
13259
- audioContext.close();
13260
- resolve2(true);
13261
- return;
13262
- }
13263
- var interactionEvents = ["click", "touchstart", "touchend", "keydown", "mousedown", "pointerdown"];
13264
- var timeoutId = null;
13265
- var isResolved = false;
13266
- function handleInteraction() {
13267
- if (isResolved) {
13268
- return;
13269
- }
13270
- isResolved = true;
13271
- if (timeoutId) {
13272
- clearTimeout(timeoutId);
13249
+ var AudioPermission = /* @__PURE__ */ function() {
13250
+ function AudioPermission2() {
13251
+ _classCallCheck(this, AudioPermission2);
13252
+ _defineProperty(this, "userInteracted", false);
13253
+ _defineProperty(this, "audioPermissionGranted", false);
13254
+ this.initAudioPermission();
13255
+ }
13256
+ return _createClass(AudioPermission2, [{
13257
+ key: "initAudioPermission",
13258
+ value: function() {
13259
+ var _initAudioPermission = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee() {
13260
+ var audioContext;
13261
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
13262
+ while (1) switch (_context.prev = _context.next) {
13263
+ case 0:
13264
+ if (isIos() || isAndroid()) {
13265
+ this.waitForUserInteraction();
13266
+ } else {
13267
+ try {
13268
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
13269
+ if (audioContext.state === "running") {
13270
+ this.userInteracted = true;
13271
+ this.audioPermissionGranted = true;
13272
+ audioContext.close();
13273
+ } else {
13274
+ audioContext.close();
13275
+ this.waitForUserInteraction();
13276
+ }
13277
+ } catch (error2) {
13278
+ console.warn("AudioContext创建失败,回退到用户交互模式:", error2);
13279
+ this.waitForUserInteraction();
13280
+ }
13281
+ }
13282
+ case 1:
13283
+ case "end":
13284
+ return _context.stop();
13285
+ }
13286
+ }, _callee, this);
13287
+ }));
13288
+ function initAudioPermission() {
13289
+ return _initAudioPermission.apply(this, arguments);
13273
13290
  }
13291
+ return initAudioPermission;
13292
+ }()
13293
+ }, {
13294
+ key: "waitForUserInteraction",
13295
+ value: function waitForUserInteraction() {
13296
+ var _this = this;
13297
+ var interactionEvents = ["click", "touchstart", "touchend", "keydown", "mousedown", "pointerdown"];
13298
+ var _handleInteraction = function handleInteraction() {
13299
+ _this.userInteracted = true;
13300
+ interactionEvents.forEach(function(eventType) {
13301
+ document.removeEventListener(eventType, _handleInteraction);
13302
+ });
13303
+ };
13274
13304
  interactionEvents.forEach(function(eventType) {
13275
- document.removeEventListener(eventType, handleInteraction);
13305
+ document.addEventListener(eventType, _handleInteraction, {
13306
+ passive: true
13307
+ });
13276
13308
  });
13277
- resolve2(true);
13278
13309
  }
13279
- timeoutId = setTimeout(function() {
13280
- if (isResolved) {
13281
- return;
13310
+ /**
13311
+ * 请求音频权限(包含录音和播放权限)
13312
+ *
13313
+ * @returns Promise<boolean> 返回权限获取结果,true表示成功,false表示失败
13314
+ */
13315
+ }, {
13316
+ key: "requestAudioPermission",
13317
+ value: function() {
13318
+ var _requestAudioPermission = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee2() {
13319
+ var stream, audioContext;
13320
+ return _regeneratorRuntime().wrap(function _callee2$(_context2) {
13321
+ while (1) switch (_context2.prev = _context2.next) {
13322
+ case 0:
13323
+ if (this.userInteracted) {
13324
+ _context2.next = 3;
13325
+ break;
13326
+ }
13327
+ console.warn("用户尚未产生交互,无法获取音频权限");
13328
+ return _context2.abrupt("return", false);
13329
+ case 3:
13330
+ if (!(this.audioPermissionGranted && !isIos())) {
13331
+ _context2.next = 5;
13332
+ break;
13333
+ }
13334
+ return _context2.abrupt("return", true);
13335
+ case 5:
13336
+ _context2.prev = 5;
13337
+ _context2.next = 8;
13338
+ return navigator.mediaDevices.getUserMedia({
13339
+ audio: true
13340
+ });
13341
+ case 8:
13342
+ stream = _context2.sent;
13343
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
13344
+ if (!(isIos() && audioContext.state === "suspended")) {
13345
+ _context2.next = 13;
13346
+ break;
13347
+ }
13348
+ _context2.next = 13;
13349
+ return audioContext.resume();
13350
+ case 13:
13351
+ this.audioPermissionGranted = audioContext.state === "running";
13352
+ stream.getTracks().forEach(function(track2) {
13353
+ return track2.stop();
13354
+ });
13355
+ audioContext.close();
13356
+ return _context2.abrupt("return", this.audioPermissionGranted);
13357
+ case 19:
13358
+ _context2.prev = 19;
13359
+ _context2.t0 = _context2["catch"](5);
13360
+ console.error("音频权限获取失败:", _context2.t0);
13361
+ if (!(_context2.t0 instanceof DOMException)) {
13362
+ _context2.next = 33;
13363
+ break;
13364
+ }
13365
+ _context2.t1 = _context2.t0.name;
13366
+ _context2.next = _context2.t1 === "NotAllowedError" ? 26 : _context2.t1 === "NotFoundError" ? 28 : _context2.t1 === "NotSupportedError" ? 30 : 32;
13367
+ break;
13368
+ case 26:
13369
+ console.warn("用户拒绝了音频权限请求");
13370
+ return _context2.abrupt("break", 33);
13371
+ case 28:
13372
+ console.warn("未找到音频设备");
13373
+ return _context2.abrupt("break", 33);
13374
+ case 30:
13375
+ console.warn("浏览器不支持音频权限请求");
13376
+ return _context2.abrupt("break", 33);
13377
+ case 32:
13378
+ console.warn("未知的权限请求错误:", _context2.t0.message);
13379
+ case 33:
13380
+ this.audioPermissionGranted = false;
13381
+ return _context2.abrupt("return", false);
13382
+ case 35:
13383
+ case "end":
13384
+ return _context2.stop();
13385
+ }
13386
+ }, _callee2, this, [[5, 19]]);
13387
+ }));
13388
+ function requestAudioPermission() {
13389
+ return _requestAudioPermission.apply(this, arguments);
13282
13390
  }
13283
- isResolved = true;
13284
- interactionEvents.forEach(function(eventType) {
13285
- document.removeEventListener(eventType, handleInteraction);
13286
- });
13287
- resolve2(false);
13288
- }, 1e4);
13289
- interactionEvents.forEach(function(eventType) {
13290
- document.addEventListener(eventType, handleInteraction, {
13291
- passive: true
13292
- });
13293
- });
13294
- });
13391
+ return requestAudioPermission;
13392
+ }()
13393
+ }]);
13394
+ }();
13395
+ var audioPermissionInstance = null;
13396
+ function createAudioPermission() {
13397
+ if (!audioPermissionInstance) {
13398
+ audioPermissionInstance = new AudioPermission();
13399
+ }
13400
+ return audioPermissionInstance;
13401
+ }
13402
+ function isMobile() {
13403
+ return isAndroid() || isIos();
13404
+ }
13405
+ function isPc() {
13406
+ return !isMobile();
13295
13407
  }
13296
13408
  function isNumber(value) {
13297
13409
  return typeof value === "number";
@@ -16180,6 +16292,7 @@ export {
16180
16292
  chunkString,
16181
16293
  closeWorker,
16182
16294
  copyText,
16295
+ createAudioPermission,
16183
16296
  createWebSocket,
16184
16297
  createWorker,
16185
16298
  debounce,
@@ -16222,6 +16335,5 @@ export {
16222
16335
  throttle,
16223
16336
  timeDelay,
16224
16337
  updateFilePathQuery,
16225
- useTheme,
16226
- waitForUserInteraction
16338
+ useTheme
16227
16339
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@minto-ai/tools",
3
3
  "type": "module",
4
- "version": "1.0.56",
4
+ "version": "1.0.58",
5
5
  "description": "明途公共工具库",
6
6
  "author": "hcc",
7
7
  "license": "ISC",
@@ -12,6 +12,14 @@
12
12
  "publishConfig": {
13
13
  "access": "public"
14
14
  },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "require": "./dist/index.js"
20
+ }
21
+ },
22
+ "main": "./dist/index.js",
15
23
  "module": "./dist/index.js",
16
24
  "types": "./dist/index.d.ts",
17
25
  "files": [
@@ -1,7 +0,0 @@
1
- /**
2
- * 等待用户交互的Promise函数
3
- * 创建AudioContext检测是否已有用户交互,如果没有则监听多种用户交互事件
4
- * @returns {Promise<boolean>} 返回Promise,用户交互后resolve为true,超时后resolve为false
5
- */
6
- declare function waitForUserInteraction(): Promise<boolean>;
7
- export default waitForUserInteraction;