@minto-ai/tools 1.0.58 → 1.0.60

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.
@@ -1,45 +1,180 @@
1
+ declare enum AudioPermissionErrorType {
2
+ NO_USER_INTERACTION_ERROR = "NoUserInteractionError",
3
+ AUTOPLAY_BLOCKED = "AutoplayBlocked",
4
+ AUTOPLAY_UNKNOWN_ERROR = "AutoplayUnknownError",
5
+ SECURE_CONTEXT_ERROR = "SecureContextError",
6
+ PERMISSION_DENIED_PERMANENTLY = "PermissionDeniedPermanently",
7
+ NOT_ALLOWED_ERROR = "NotAllowedError",
8
+ MEDIA_DEVICES_API_UNAVAILABLE = "MediaDevicesApiUnavailable",
9
+ NOT_FOUND_ERROR = "NotFoundError",
10
+ NOT_READABLE_ERROR = "NotReadableError",
11
+ OVERCONSTRAINED_ERROR = "OverconstrainedError",
12
+ SECURITY_ERROR = "SecurityError",
13
+ MICROPHONE_UNKNOWN_ERROR = "MicrophoneUnknownError"
14
+ }
15
+ declare class AudioPermissionError extends Error {
16
+ name: AudioPermissionErrorType;
17
+ private constructor();
18
+ static create(name: AudioPermissionErrorType, message?: string): AudioPermissionError;
19
+ }
20
+ /**
21
+ * 音频播放权限管理类
22
+ *
23
+ * 根据MDN文档,音频播放权限需要满足以下条件之一:
24
+ * 1. 音频被静音或音量为0
25
+ * 2. 用户已与网站产生交互(点击、触摸、按键等)
26
+ * 3. 网站已被加入自动播放白名单
27
+ * 4. 通过Permissions Policy授权
28
+ *
29
+ * 跨平台实现策略:
30
+ * - PC端:预检测AudioContext状态,如果suspended则监听用户交互
31
+ * - iOS Safari:必须在用户交互事件的调用栈中调用resume(),需要50ms延迟确保状态变更
32
+ * - Android:直接在用户交互后检测AudioContext状态
33
+ *
34
+ * 自动播放策略限制:
35
+ * - Chrome 66+:需要用户交互或MEI(Media Engagement Index)足够高
36
+ * - Safari:严格要求用户交互,AudioContext创建时默认为suspended状态
37
+ * - Firefox:相对宽松,但仍会阻止明显的自动播放行为
38
+ *
39
+ *
40
+ *
41
+ * 实现原理:
42
+ * PC:
43
+ * 1.在PC端首先预检测AudioContext状态:
44
+ * 如果状态是 “running” 状态则可以播放音频,
45
+ * 如果状态不是 “running” 状态则需要监听用户交互事件,
46
+ * 2.用户交互事件触发后,再检测AudioContext状态:
47
+ * 如果状态是 “running” 状态则可以播放音频,
48
+ * 如果状态不是 “running” 状态则抛出异常。
49
+ *
50
+ * IOS:
51
+ * 1.用户交互事件触发后,再检测AudioContext状态:
52
+ * 如果状态是 “suspended” 则需要调用 resume 方法,并且需要延迟 50ms,
53
+ * 如果状态不是 “suspended” 状态进行下一步判断,
54
+ * 2.获取AudioContext状态:
55
+ * 如果状态是 “running” 状态则可以播放音频,
56
+ * 如果状态不是 “running” 状态则抛出异常。
57
+ *
58
+ * Android:
59
+ * 1.用户交互事件触发后,再检测AudioContext状态:
60
+ * 如果状态是 “running” 状态则可以播放音频,
61
+ * 如果状态不是 “running” 状态则抛出异常。
62
+ */
63
+ declare class AudioPlaybackPermission {
64
+ private userInteracted;
65
+ constructor();
66
+ /**
67
+ * 初始化播放权限检测
68
+ */
69
+ private initPlaybackPermission;
70
+ /**
71
+ * 检测初始AudioContext状态(仅PC平台)
72
+ */
73
+ private checkInitialAudioContextState;
74
+ /**
75
+ * 设置用户交互监听器
76
+ */
77
+ private setupUserInteractionListeners;
78
+ /**
79
+ * 请求播放权限
80
+ * 根据Web Audio API最佳实践实现
81
+ */
82
+ requestPlaybackPermission(): Promise<void>;
83
+ }
1
84
  /**
2
- * 音频权限管理类
85
+ * 麦克风权限管理类
86
+ *
87
+ * 根据MDN文档,getUserMedia需要满足:
88
+ * 1. 安全上下文(HTTPS)
89
+ * 2. 用户明确授权
90
+ * 3. 顶级文档上下文或通过Permissions Policy授权的iframe
91
+ *
92
+ *
93
+ * 权限状态说明:
94
+ * - granted: 用户已授权,可直接访问麦克风
95
+ * - denied: 用户已拒绝,需要用户手动在浏览器设置中重新开启
96
+ * - prompt: 首次访问,会弹出授权对话框
97
+ *
98
+ *
99
+ * 平台差异:
100
+ * - 桌面端:通过浏览器原生授权对话框处理
101
+ * - iOS Safari:权限被拒绝后,需要用户在系统设置中重新开启
102
+ * - Android Chrome:权限处理与桌面端类似,但某些版本可能有缓存问题
3
103
  *
4
- * 用于处理浏览器中的音频播放和录音权限问题,解决自动播放限制。
5
104
  *
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状态,直接返回成功
105
+ * 注意事项:
106
+ * 1. 浏览器会永久缓存用户的权限决定
107
+ * 2. 在非HTTPS环境下(除localhost外)会直接失败
108
+ * 3. 某些浏览器在隐私模式下可能有不同行为
109
+ * 4. iframe中使用需要正确配置Permissions Policy
110
+ *
111
+ *
112
+ * 实现原理:
13
113
  * - PC平台:
14
- * 可以优先检测如果为running则表示权限已可用,就不需要申请权限,如果为suspended则表示权限未可用,需要申请权限
15
- * 当用户交互后,通过 navigator.mediaDevices.getUserMedia({ audio: true }) 申请权限,这里会直接audioContext变为为running状态,并不需要 audioContext.resume() 改变状态
16
- * 当后续 audioPermissionGranted 为true 申请完权限之后,第二次调用申请权限时,不需要再次申请权限,这时 audioContext 会变为running状态,直接返回成功
114
+ * 1. 通过授权弹框申请权限:
115
+ * 如果用户拒绝了权限,会抛出异常
116
+ * 如果用户点击了允许,会返回成功
117
+ * 2.第二次申请权限,会根据用户第一次申请权限的结果:
118
+ * 如果用户第一次申请权限失败,会抛出异常
119
+ * 如果用户第一次申请权限成功,会返回成功
120
+ * - 移动端:
121
+ * 1. 通过授权弹框申请权限:
122
+ * 如果用户拒绝了权限,会抛出异常
123
+ * 如果用户点击了允许,会返回成功
124
+ * 2.第二次申请权限,会根据用户第一次申请权限的结果:
125
+ * 如果用户第一次申请权限失败,会抛出异常
126
+ * 如果用户第一次申请权限成功,会返回成功
127
+ *
128
+ * iOS平台:
129
+ * 1. 通过授权弹框申请权限:
130
+ * 如果用户拒绝了权限,会抛出异常
131
+ * 如果用户点击了允许,会返回成功
132
+ * 2.第二次申请权限,会根据用户第一次申请权限的结果:
133
+ * 如果用户第一次申请权限失败,会抛出异常
134
+ * 如果用户第一次申请权限成功,会返回成功
135
+ *
136
+ *
137
+ */
138
+ declare class MicrophonePermission {
139
+ private microphonePermissionGranted;
140
+ private permissionDeniedPermanently;
141
+ /**
142
+ * 检查是否在安全上下文中
143
+ */
144
+ private isSecureContext;
145
+ /**
146
+ * 请求麦克风权限
147
+ * 根据MediaDevices.getUserMedia规范实现
148
+ */
149
+ requestMicrophonePermission(): Promise<void>;
150
+ /**
151
+ * 检查麦克风权限状态
152
+ */
153
+ isMicrophonePermissionGranted(): boolean;
154
+ }
155
+ /**
156
+ * 统一的音频权限管理类
17
157
  */
18
158
  declare class AudioPermission {
19
- private userInteracted;
20
- private audioPermissionGranted;
159
+ private playbackPermission;
160
+ private microphonePermission;
21
161
  constructor();
22
162
  /**
23
- * 初始化音频权限检测流程
24
- * 根据不同平台采用相应的权限检测策略
163
+ * 请求音频播放权限
25
164
  */
26
- private initAudioPermission;
165
+ requestPlaybackPermission(): Promise<void>;
27
166
  /**
28
- * 监听用户交互事件
29
- * 监听多种交互事件类型,确保在各种设备上都能正确检测到用户操作
167
+ * 请求麦克风权限
30
168
  */
31
- private waitForUserInteraction;
169
+ requestMicrophonePermission(): Promise<void>;
32
170
  /**
33
- * 请求音频权限(包含录音和播放权限)
34
- *
35
- * @returns Promise<boolean> 返回权限获取结果,true表示成功,false表示失败
171
+ * 检查麦克风权限状态
36
172
  */
37
- requestAudioPermission(): Promise<boolean>;
173
+ isMicrophonePermissionGranted(): boolean;
38
174
  }
39
175
  /**
40
176
  * 创建或获取音频权限管理实例
41
- *
42
- * @returns AudioPermission 音频权限管理实例
43
177
  */
44
178
  declare function createAudioPermission(): AudioPermission;
45
179
  export default createAudioPermission;
180
+ export { AudioPermission, AudioPermissionError, AudioPermissionErrorType, AudioPlaybackPermission, MicrophonePermission };
package/dist/index.js CHANGED
@@ -46,6 +46,13 @@ function _callSuper(t, o, e) {
46
46
  function _classCallCheck(a, n) {
47
47
  if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
48
48
  }
49
+ function _construct(t, e, r) {
50
+ if (_isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
51
+ var o = [null];
52
+ o.push.apply(o, e);
53
+ var p = new (t.bind.apply(t, o))();
54
+ return r && _setPrototypeOf(p, r.prototype), p;
55
+ }
49
56
  function _defineProperties(e, r) {
50
57
  for (var t = 0; t < r.length; t++) {
51
58
  var o = r[t];
@@ -53,7 +60,7 @@ function _defineProperties(e, r) {
53
60
  }
54
61
  }
55
62
  function _createClass(e, r, t) {
56
- return r && _defineProperties(e.prototype, r), Object.defineProperty(e, "prototype", {
63
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
57
64
  writable: false
58
65
  }), e;
59
66
  }
@@ -128,6 +135,13 @@ function _inherits(t, e) {
128
135
  writable: false
129
136
  }), e && _setPrototypeOf(t, e);
130
137
  }
138
+ function _isNativeFunction(t) {
139
+ try {
140
+ return -1 !== Function.toString.call(t).indexOf("[native code]");
141
+ } catch (n) {
142
+ return "function" == typeof t;
143
+ }
144
+ }
131
145
  function _isNativeReflectConstruct() {
132
146
  try {
133
147
  var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {
@@ -488,6 +502,28 @@ function _unsupportedIterableToArray(r, a) {
488
502
  return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
489
503
  }
490
504
  }
505
+ function _wrapNativeSuper(t) {
506
+ var r = "function" == typeof Map ? /* @__PURE__ */ new Map() : void 0;
507
+ return _wrapNativeSuper = function(t2) {
508
+ if (null === t2 || !_isNativeFunction(t2)) return t2;
509
+ if ("function" != typeof t2) throw new TypeError("Super expression must either be null or a function");
510
+ if (void 0 !== r) {
511
+ if (r.has(t2)) return r.get(t2);
512
+ r.set(t2, Wrapper);
513
+ }
514
+ function Wrapper() {
515
+ return _construct(t2, arguments, _getPrototypeOf(this).constructor);
516
+ }
517
+ return Wrapper.prototype = Object.create(t2.prototype, {
518
+ constructor: {
519
+ value: Wrapper,
520
+ enumerable: false,
521
+ writable: true,
522
+ configurable: true
523
+ }
524
+ }), _setPrototypeOf(Wrapper, t2);
525
+ }, _wrapNativeSuper(t);
526
+ }
491
527
  var check = function check2(it) {
492
528
  return it && it.Math === Math && it;
493
529
  };
@@ -13238,158 +13274,371 @@ function copyText(text) {
13238
13274
  }
13239
13275
  });
13240
13276
  }
13241
- function isAndroid() {
13242
- var userAgent2 = navigator.userAgent.toLowerCase();
13243
- return /android/.test(userAgent2);
13244
- }
13245
- function isIos() {
13246
- var userAgent2 = navigator.userAgent.toLowerCase();
13247
- return /iphone|ipad|ipod/.test(userAgent2);
13248
- }
13249
- var AudioPermission = /* @__PURE__ */ function() {
13250
- function AudioPermission2() {
13251
- _classCallCheck(this, AudioPermission2);
13277
+ var AudioPermissionError = /* @__PURE__ */ function(_Error) {
13278
+ function AudioPermissionError2(name, message) {
13279
+ var _this;
13280
+ _classCallCheck(this, AudioPermissionError2);
13281
+ _this = _callSuper(this, AudioPermissionError2, [message]);
13282
+ _defineProperty(_this, "name", void 0);
13283
+ _this.name = name;
13284
+ return _this;
13285
+ }
13286
+ _inherits(AudioPermissionError2, _Error);
13287
+ return _createClass(AudioPermissionError2, null, [{
13288
+ key: "create",
13289
+ value: function create4(name, message) {
13290
+ var _codeMessageMap;
13291
+ var codeMessageMap = (_codeMessageMap = {}, _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_codeMessageMap, "NoUserInteractionError", "需要用户交互才能播放音频"), "AutoplayBlocked", "自动播放被浏览器阻止"), "AutoplayUnknownError", "未知自动播放错误"), "SecureContextError", "麦克风权限需要在安全上下文(HTTPS)中使用"), "PermissionDeniedPermanently", "音频权限已被永久拒绝,需在浏览器设置中开启麦克风权限"), "MediaDevicesApiUnavailable", "MediaDevices API不可用"), "NotAllowedError", "麦克风权限被拒绝"), "NotReadableError", "音频设备被其他应用程序占用"), "NotFoundError", "未找到音频输入设备"), "SecurityError", "安全策略阻止访问麦克风"), _defineProperty(_defineProperty(_codeMessageMap, "OverconstrainedError", "音频设备不满足指定的约束条件"), "MicrophoneUnknownError", "未知麦克风权限错误"));
13292
+ return new AudioPermissionError2(name, message || codeMessageMap[name]);
13293
+ }
13294
+ }]);
13295
+ }(/* @__PURE__ */ _wrapNativeSuper(Error));
13296
+ var AudioPlaybackPermission = /* @__PURE__ */ function() {
13297
+ function AudioPlaybackPermission2() {
13298
+ _classCallCheck(this, AudioPlaybackPermission2);
13252
13299
  _defineProperty(this, "userInteracted", false);
13253
- _defineProperty(this, "audioPermissionGranted", false);
13254
- this.initAudioPermission();
13255
- }
13256
- return _createClass(AudioPermission2, [{
13257
- key: "initAudioPermission",
13300
+ this.initPlaybackPermission();
13301
+ }
13302
+ return _createClass(AudioPlaybackPermission2, [{
13303
+ key: "initPlaybackPermission",
13304
+ value: function initPlaybackPermission() {
13305
+ var _this2 = this;
13306
+ if (!isIos() && !isAndroid()) {
13307
+ this.checkInitialAudioContextState()["catch"](function() {
13308
+ _this2.setupUserInteractionListeners();
13309
+ });
13310
+ } else {
13311
+ this.setupUserInteractionListeners();
13312
+ }
13313
+ }
13314
+ /**
13315
+ * 检测初始AudioContext状态(仅PC平台)
13316
+ */
13317
+ }, {
13318
+ key: "checkInitialAudioContextState",
13258
13319
  value: function() {
13259
- var _initAudioPermission = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee() {
13260
- var audioContext;
13320
+ var _checkInitialAudioContextState = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee() {
13321
+ var testContext;
13261
13322
  return _regeneratorRuntime().wrap(function _callee$(_context) {
13262
13323
  while (1) switch (_context.prev = _context.next) {
13263
13324
  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
- }
13325
+ testContext = new (window.AudioContext || window.webkitAudioContext)();
13326
+ if (testContext.state === "running") {
13327
+ this.userInteracted = true;
13281
13328
  }
13282
- case 1:
13329
+ _context.next = 4;
13330
+ return testContext.close();
13331
+ case 4:
13332
+ if (!this.userInteracted) {
13333
+ _context.next = 8;
13334
+ break;
13335
+ }
13336
+ return _context.abrupt("return", Promise.resolve());
13337
+ case 8:
13338
+ return _context.abrupt("return", Promise.reject());
13339
+ case 9:
13283
13340
  case "end":
13284
13341
  return _context.stop();
13285
13342
  }
13286
13343
  }, _callee, this);
13287
13344
  }));
13288
- function initAudioPermission() {
13289
- return _initAudioPermission.apply(this, arguments);
13345
+ function checkInitialAudioContextState() {
13346
+ return _checkInitialAudioContextState.apply(this, arguments);
13290
13347
  }
13291
- return initAudioPermission;
13348
+ return checkInitialAudioContextState;
13292
13349
  }()
13293
13350
  }, {
13294
- key: "waitForUserInteraction",
13295
- value: function waitForUserInteraction() {
13296
- var _this = this;
13351
+ key: "setupUserInteractionListeners",
13352
+ value: function setupUserInteractionListeners() {
13353
+ var _this3 = this;
13297
13354
  var interactionEvents = ["click", "touchstart", "touchend", "keydown", "mousedown", "pointerdown"];
13298
13355
  var _handleInteraction = function handleInteraction() {
13299
- _this.userInteracted = true;
13356
+ _this3.userInteracted = true;
13300
13357
  interactionEvents.forEach(function(eventType) {
13301
13358
  document.removeEventListener(eventType, _handleInteraction);
13302
13359
  });
13303
13360
  };
13304
13361
  interactionEvents.forEach(function(eventType) {
13305
13362
  document.addEventListener(eventType, _handleInteraction, {
13306
- passive: true
13363
+ passive: true,
13364
+ once: true
13307
13365
  });
13308
13366
  });
13309
13367
  }
13310
13368
  /**
13311
- * 请求音频权限(包含录音和播放权限)
13312
- *
13313
- * @returns Promise<boolean> 返回权限获取结果,true表示成功,false表示失败
13369
+ * 请求播放权限
13370
+ * 根据Web Audio API最佳实践实现
13314
13371
  */
13315
13372
  }, {
13316
- key: "requestAudioPermission",
13373
+ key: "requestPlaybackPermission",
13317
13374
  value: function() {
13318
- var _requestAudioPermission = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee2() {
13319
- var stream, audioContext;
13375
+ var _requestPlaybackPermission = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee2() {
13376
+ var audioContext, unknownError;
13320
13377
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
13321
13378
  while (1) switch (_context2.prev = _context2.next) {
13322
13379
  case 0:
13380
+ audioContext = null;
13381
+ _context2.prev = 1;
13323
13382
  if (this.userInteracted) {
13324
- _context2.next = 3;
13383
+ _context2.next = 4;
13325
13384
  break;
13326
13385
  }
13327
- console.warn("用户尚未产生交互,无法获取音频权限");
13328
- return _context2.abrupt("return", false);
13329
- case 3:
13330
- if (!(this.audioPermissionGranted && !isIos())) {
13331
- _context2.next = 5;
13386
+ throw AudioPermissionError.create(
13387
+ "NoUserInteractionError"
13388
+ /* NO_USER_INTERACTION_ERROR */
13389
+ );
13390
+ case 4:
13391
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
13392
+ if (!(isIos() && audioContext.state === "suspended")) {
13393
+ _context2.next = 10;
13332
13394
  break;
13333
13395
  }
13334
- return _context2.abrupt("return", true);
13335
- case 5:
13336
- _context2.prev = 5;
13337
13396
  _context2.next = 8;
13338
- return navigator.mediaDevices.getUserMedia({
13339
- audio: true
13340
- });
13397
+ return audioContext.resume();
13341
13398
  case 8:
13342
- stream = _context2.sent;
13343
- audioContext = new (window.AudioContext || window.webkitAudioContext)();
13344
- if (!(isIos() && audioContext.state === "suspended")) {
13345
- _context2.next = 13;
13399
+ _context2.next = 10;
13400
+ return new Promise(function(resolve2) {
13401
+ return setTimeout(resolve2, 50);
13402
+ });
13403
+ case 10:
13404
+ if (!(audioContext.state !== "running")) {
13405
+ _context2.next = 12;
13346
13406
  break;
13347
13407
  }
13348
- _context2.next = 13;
13349
- return audioContext.resume();
13350
- case 13:
13351
- this.audioPermissionGranted = audioContext.state === "running";
13408
+ throw AudioPermissionError.create(
13409
+ "AutoplayBlocked"
13410
+ /* AUTOPLAY_BLOCKED */
13411
+ );
13412
+ case 12:
13413
+ return _context2.abrupt("return", Promise.resolve());
13414
+ case 15:
13415
+ _context2.prev = 15;
13416
+ _context2.t0 = _context2["catch"](1);
13417
+ if (!(_context2.t0 instanceof AudioPermissionError)) {
13418
+ _context2.next = 19;
13419
+ break;
13420
+ }
13421
+ return _context2.abrupt("return", Promise.reject(_context2.t0));
13422
+ case 19:
13423
+ unknownError = AudioPermissionError.create("AutoplayUnknownError", _context2.t0 instanceof Error ? _context2.t0.message : void 0);
13424
+ return _context2.abrupt("return", Promise.reject(unknownError));
13425
+ case 21:
13426
+ _context2.prev = 21;
13427
+ if (!(audioContext && audioContext.state !== "closed")) {
13428
+ _context2.next = 30;
13429
+ break;
13430
+ }
13431
+ _context2.prev = 23;
13432
+ _context2.next = 26;
13433
+ return audioContext.close();
13434
+ case 26:
13435
+ _context2.next = 30;
13436
+ break;
13437
+ case 28:
13438
+ _context2.prev = 28;
13439
+ _context2.t1 = _context2["catch"](23);
13440
+ case 30:
13441
+ return _context2.finish(21);
13442
+ case 31:
13443
+ case "end":
13444
+ return _context2.stop();
13445
+ }
13446
+ }, _callee2, this, [[1, 15, 21, 31], [23, 28]]);
13447
+ }));
13448
+ function requestPlaybackPermission() {
13449
+ return _requestPlaybackPermission.apply(this, arguments);
13450
+ }
13451
+ return requestPlaybackPermission;
13452
+ }()
13453
+ }]);
13454
+ }();
13455
+ var MicrophonePermission = /* @__PURE__ */ function() {
13456
+ function MicrophonePermission2() {
13457
+ _classCallCheck(this, MicrophonePermission2);
13458
+ _defineProperty(this, "microphonePermissionGranted", false);
13459
+ _defineProperty(this, "permissionDeniedPermanently", false);
13460
+ }
13461
+ return _createClass(MicrophonePermission2, [{
13462
+ key: "isSecureContext",
13463
+ value: (
13464
+ /**
13465
+ * 检查是否在安全上下文中
13466
+ */
13467
+ function isSecureContext() {
13468
+ return window.isSecureContext || location.protocol === "https:" || location.hostname === "localhost";
13469
+ }
13470
+ )
13471
+ /**
13472
+ * 请求麦克风权限
13473
+ * 根据MediaDevices.getUserMedia规范实现
13474
+ */
13475
+ }, {
13476
+ key: "requestMicrophonePermission",
13477
+ value: function() {
13478
+ var _requestMicrophonePermission = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee3() {
13479
+ var stream, errorType, audioError, unknownError;
13480
+ return _regeneratorRuntime().wrap(function _callee3$(_context3) {
13481
+ while (1) switch (_context3.prev = _context3.next) {
13482
+ case 0:
13483
+ _context3.prev = 0;
13484
+ if (this.isSecureContext()) {
13485
+ _context3.next = 3;
13486
+ break;
13487
+ }
13488
+ throw AudioPermissionError.create(
13489
+ "SecureContextError"
13490
+ /* SECURE_CONTEXT_ERROR */
13491
+ );
13492
+ case 3:
13493
+ if (!this.permissionDeniedPermanently) {
13494
+ _context3.next = 5;
13495
+ break;
13496
+ }
13497
+ throw AudioPermissionError.create(
13498
+ "PermissionDeniedPermanently"
13499
+ /* PERMISSION_DENIED_PERMANENTLY */
13500
+ );
13501
+ case 5:
13502
+ if (!this.microphonePermissionGranted) {
13503
+ _context3.next = 7;
13504
+ break;
13505
+ }
13506
+ return _context3.abrupt("return", Promise.resolve());
13507
+ case 7:
13508
+ if (!(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia)) {
13509
+ _context3.next = 9;
13510
+ break;
13511
+ }
13512
+ throw AudioPermissionError.create(
13513
+ "MediaDevicesApiUnavailable"
13514
+ /* MEDIA_DEVICES_API_UNAVAILABLE */
13515
+ );
13516
+ case 9:
13517
+ _context3.next = 11;
13518
+ return navigator.mediaDevices.getUserMedia({
13519
+ audio: {
13520
+ echoCancellation: true,
13521
+ noiseSuppression: true,
13522
+ autoGainControl: true
13523
+ }
13524
+ });
13525
+ case 11:
13526
+ stream = _context3.sent;
13527
+ this.microphonePermissionGranted = true;
13352
13528
  stream.getTracks().forEach(function(track2) {
13353
- return track2.stop();
13529
+ track2.stop();
13354
13530
  });
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;
13531
+ return _context3.abrupt("return", Promise.resolve());
13532
+ case 17:
13533
+ _context3.prev = 17;
13534
+ _context3.t0 = _context3["catch"](0);
13535
+ this.microphonePermissionGranted = false;
13536
+ if (!(_context3.t0 instanceof AudioPermissionError)) {
13537
+ _context3.next = 22;
13538
+ break;
13539
+ }
13540
+ return _context3.abrupt("return", Promise.reject(_context3.t0));
13541
+ case 22:
13542
+ if (!(_context3.t0 instanceof DOMException)) {
13543
+ _context3.next = 40;
13363
13544
  break;
13364
13545
  }
13365
- _context2.t1 = _context2.t0.name;
13366
- _context2.next = _context2.t1 === "NotAllowedError" ? 26 : _context2.t1 === "NotFoundError" ? 28 : _context2.t1 === "NotSupportedError" ? 30 : 32;
13546
+ _context3.t1 = _context3.t0.name;
13547
+ _context3.next = _context3.t1 === "NotFoundError" ? 26 : _context3.t1 === "NotAllowedError" ? 28 : _context3.t1 === "NotReadableError" ? 31 : _context3.t1 === "OverconstrainedError" ? 33 : _context3.t1 === "SecurityError" ? 35 : 37;
13367
13548
  break;
13368
13549
  case 26:
13369
- console.warn("用户拒绝了音频权限请求");
13370
- return _context2.abrupt("break", 33);
13550
+ errorType = "NotFoundError";
13551
+ return _context3.abrupt("break", 38);
13371
13552
  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);
13553
+ this.permissionDeniedPermanently = true;
13554
+ errorType = "NotAllowedError";
13555
+ return _context3.abrupt("break", 38);
13556
+ case 31:
13557
+ errorType = "NotReadableError";
13558
+ return _context3.abrupt("break", 38);
13379
13559
  case 33:
13380
- this.audioPermissionGranted = false;
13381
- return _context2.abrupt("return", false);
13560
+ errorType = "OverconstrainedError";
13561
+ return _context3.abrupt("break", 38);
13382
13562
  case 35:
13563
+ errorType = "SecurityError";
13564
+ return _context3.abrupt("break", 38);
13565
+ case 37:
13566
+ errorType = "MicrophoneUnknownError";
13567
+ case 38:
13568
+ audioError = AudioPermissionError.create(errorType);
13569
+ return _context3.abrupt("return", Promise.reject(audioError));
13570
+ case 40:
13571
+ unknownError = AudioPermissionError.create("MicrophoneUnknownError", _context3.t0 instanceof Error ? _context3.t0.message : void 0);
13572
+ return _context3.abrupt("return", Promise.reject(unknownError));
13573
+ case 42:
13383
13574
  case "end":
13384
- return _context2.stop();
13575
+ return _context3.stop();
13385
13576
  }
13386
- }, _callee2, this, [[5, 19]]);
13577
+ }, _callee3, this, [[0, 17]]);
13387
13578
  }));
13388
- function requestAudioPermission() {
13389
- return _requestAudioPermission.apply(this, arguments);
13579
+ function requestMicrophonePermission() {
13580
+ return _requestMicrophonePermission.apply(this, arguments);
13390
13581
  }
13391
- return requestAudioPermission;
13582
+ return requestMicrophonePermission;
13392
13583
  }()
13584
+ }, {
13585
+ key: "isMicrophonePermissionGranted",
13586
+ value: function isMicrophonePermissionGranted() {
13587
+ return this.microphonePermissionGranted;
13588
+ }
13589
+ }]);
13590
+ }();
13591
+ var AudioPermission = /* @__PURE__ */ function() {
13592
+ function AudioPermission2() {
13593
+ _classCallCheck(this, AudioPermission2);
13594
+ _defineProperty(this, "playbackPermission", void 0);
13595
+ _defineProperty(this, "microphonePermission", void 0);
13596
+ this.playbackPermission = new AudioPlaybackPermission();
13597
+ this.microphonePermission = new MicrophonePermission();
13598
+ }
13599
+ return _createClass(AudioPermission2, [{
13600
+ key: "requestPlaybackPermission",
13601
+ value: function() {
13602
+ var _requestPlaybackPermission2 = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee4() {
13603
+ return _regeneratorRuntime().wrap(function _callee4$(_context4) {
13604
+ while (1) switch (_context4.prev = _context4.next) {
13605
+ case 0:
13606
+ return _context4.abrupt("return", this.playbackPermission.requestPlaybackPermission());
13607
+ case 1:
13608
+ case "end":
13609
+ return _context4.stop();
13610
+ }
13611
+ }, _callee4, this);
13612
+ }));
13613
+ function requestPlaybackPermission() {
13614
+ return _requestPlaybackPermission2.apply(this, arguments);
13615
+ }
13616
+ return requestPlaybackPermission;
13617
+ }()
13618
+ }, {
13619
+ key: "requestMicrophonePermission",
13620
+ value: function() {
13621
+ var _requestMicrophonePermission2 = _asyncToGenerator(/* @__PURE__ */ _regeneratorRuntime().mark(function _callee5() {
13622
+ return _regeneratorRuntime().wrap(function _callee5$(_context5) {
13623
+ while (1) switch (_context5.prev = _context5.next) {
13624
+ case 0:
13625
+ return _context5.abrupt("return", this.microphonePermission.requestMicrophonePermission());
13626
+ case 1:
13627
+ case "end":
13628
+ return _context5.stop();
13629
+ }
13630
+ }, _callee5, this);
13631
+ }));
13632
+ function requestMicrophonePermission() {
13633
+ return _requestMicrophonePermission2.apply(this, arguments);
13634
+ }
13635
+ return requestMicrophonePermission;
13636
+ }()
13637
+ }, {
13638
+ key: "isMicrophonePermissionGranted",
13639
+ value: function isMicrophonePermissionGranted() {
13640
+ return this.microphonePermission.isMicrophonePermissionGranted();
13641
+ }
13393
13642
  }]);
13394
13643
  }();
13395
13644
  var audioPermissionInstance = null;
@@ -13399,6 +13648,14 @@ function createAudioPermission() {
13399
13648
  }
13400
13649
  return audioPermissionInstance;
13401
13650
  }
13651
+ function isAndroid() {
13652
+ var userAgent2 = navigator.userAgent.toLowerCase();
13653
+ return /android/.test(userAgent2);
13654
+ }
13655
+ function isIos() {
13656
+ var userAgent2 = navigator.userAgent.toLowerCase();
13657
+ return /iphone|ipad|ipod/.test(userAgent2);
13658
+ }
13402
13659
  function isMobile() {
13403
13660
  return isAndroid() || isIos();
13404
13661
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@minto-ai/tools",
3
3
  "type": "module",
4
- "version": "1.0.58",
4
+ "version": "1.0.60",
5
5
  "description": "明途公共工具库",
6
6
  "author": "hcc",
7
7
  "license": "ISC",
@@ -12,14 +12,6 @@
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",
23
15
  "module": "./dist/index.js",
24
16
  "types": "./dist/index.d.ts",
25
17
  "files": [