@untemps/vocal 2.0.0-beta.1 → 2.0.0-beta.3

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [2.0.0-beta.3](https://github.com/untemps/vocal/compare/v2.0.0-beta.2...v2.0.0-beta.3) (2026-05-15)
2
+
3
+
4
+ ### Features
5
+
6
+ * Expose AbortSignal support in start() ([#42](https://github.com/untemps/vocal/issues/42)) ([a7f638b](https://github.com/untemps/vocal/commit/a7f638b541347a4377bce1f43a47aa5290ea2852))
7
+
8
+ # [2.0.0-beta.2](https://github.com/untemps/vocal/compare/v2.0.0-beta.1...v2.0.0-beta.2) (2026-05-15)
9
+
10
+
11
+ ### Features
12
+
13
+ * Add isRecording getter to track recognition state ([#41](https://github.com/untemps/vocal/issues/41)) ([7abcc56](https://github.com/untemps/vocal/commit/7abcc566f40aa95af88078d2a7632ef8633cad5a))
14
+
1
15
  # [2.0.0-beta.1](https://github.com/untemps/vocal/compare/v1.3.4-beta.1...v2.0.0-beta.1) (2026-05-15)
2
16
 
3
17
 
package/README.md CHANGED
@@ -78,4 +78,29 @@ Please refer to [this section](https://developer.mozilla.org/en-US/docs/Web/API/
78
78
  | soundstart | Fired when any sound — recognisable or not — has been detected |
79
79
  | speechend | Fired when speech recognized by the recognition service has stopped being detected |
80
80
  | speechstart | Fired when sound recognized by the recognition service as speech has been detected |
81
- | start | fired when the recognition service has begun listening to incoming audio |
81
+ | start | fired when the recognition service has begun listening to incoming audio |
82
+
83
+ ## Getters
84
+
85
+ | Getter | Type | Description |
86
+ | ----------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------- |
87
+ | isSupported | boolean | Whether the current environment supports the SpeechRecognition Web API (static) |
88
+ | instance | SpeechRecognition \| null | The underlying SpeechRecognition instance |
89
+ | isRecording | boolean | Whether recognition is currently active — `true` after `start()`, `false` after `stop()`, `abort()`, or `end` event |
90
+
91
+ ## Methods
92
+
93
+ ### `start({ signal? })`
94
+
95
+ | Parameter | Type | Default | Description |
96
+ | --------- | ------------- | ----------- | ----------------------------------------------------------------------------- |
97
+ | signal | AbortSignal | `undefined` | Cancels the in-flight microphone permission request when the signal is aborted |
98
+
99
+ ```js
100
+ const controller = new AbortController()
101
+ vocal.start({ signal: controller.signal })
102
+
103
+ // Cancel the permission request at any later point
104
+ controller.abort()
105
+ ```
106
+
package/dist/index.es.js CHANGED
@@ -29,6 +29,7 @@ var r = class r {
29
29
  }
30
30
  _instance = null;
31
31
  _listeners = null;
32
+ _isRecording = !1;
32
33
  constructor(e) {
33
34
  let t = r._resolveSpeechRecognition();
34
35
  if (!t) throw new DOMException("SpeechRecognition not supported", "NOT_SUPPORTED_ERR");
@@ -42,6 +43,9 @@ var r = class r {
42
43
  let e = r._resolveSpeechGrammarList();
43
44
  a.grammars = e ? new e() : null;
44
45
  }
46
+ this._instance.addEventListener("end", () => {
47
+ this._isRecording = !1;
48
+ });
45
49
  }
46
50
  get instance() {
47
51
  return this._instance;
@@ -49,21 +53,28 @@ var r = class r {
49
53
  set instance(e) {
50
54
  throw Error("You cannot set instance directly.");
51
55
  }
52
- async start() {
56
+ get isRecording() {
57
+ return this._isRecording;
58
+ }
59
+ set isRecording(e) {
60
+ throw Error("You cannot set isRecording directly.");
61
+ }
62
+ async start({ signal: t } = {}) {
53
63
  if (this._instance) try {
54
- if (!await e("microphone", { audio: !0 })) throw Error("Unable to retrieve the stream from media device");
55
- this._instance.start();
64
+ if (!await e("microphone", { audio: !0 }, { signal: t })) throw Error("Unable to retrieve the stream from media device");
65
+ this._instance.start(), this._isRecording = !0;
56
66
  } catch (e) {
67
+ if (e instanceof Error && e.name === "AbortError") return this;
57
68
  let t = this._listeners?.error;
58
69
  t && t(e);
59
70
  }
60
71
  return this;
61
72
  }
62
73
  stop() {
63
- return this._instance && this._instance.stop(), this;
74
+ return this._instance && (this._instance.stop(), this._isRecording = !1), this;
64
75
  }
65
76
  abort() {
66
- return this._instance && this._instance.abort(), this;
77
+ return this._instance && (this._instance.abort(), this._isRecording = !1), this;
67
78
  }
68
79
  addEventListener(e, t) {
69
80
  if (this._instance && this._listeners && this._includesEventType(e)) {
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@untemps/user-permissions-utils`);var t=class t{static defaultOptions={grammars:null,lang:`en-US`,continuous:!1,interimResults:!1,maxAlternatives:1};static eventTypes={AUDIO_END:`audioend`,AUDIO_START:`audiostart`,END:`end`,ERROR:`error`,NO_MATCH:`nomatch`,RESULT:`result`,SOUND_END:`soundend`,SOUND_START:`soundstart`,SPEECH_END:`speechend`,SPEECH_START:`speechstart`,START:`start`};static get isSupported(){return!!t._resolveSpeechRecognition()&&!!(0,e.isNavigatorPermissionsSupported)()&&!!(0,e.isNavigatorMediaDevicesSupported)()}static set isSupported(e){throw Error(`You cannot set isSupported directly.`)}_instance=null;_listeners=null;constructor(e){let n=t._resolveSpeechRecognition();if(!n)throw new DOMException(`SpeechRecognition not supported`,`NOT_SUPPORTED_ERR`);this._instance=new n,this._listeners={};let{grammars:r,...i}={...t.defaultOptions,...e??{}},a=this._instance;if(Object.assign(a,i),r)a.grammars=r;else{let e=t._resolveSpeechGrammarList();a.grammars=e?new e:null}}get instance(){return this._instance}set instance(e){throw Error(`You cannot set instance directly.`)}async start(){if(this._instance)try{if(!await(0,e.getUserMediaStream)(`microphone`,{audio:!0}))throw Error(`Unable to retrieve the stream from media device`);this._instance.start()}catch(e){let t=this._listeners?.error;t&&t(e)}return this}stop(){return this._instance&&this._instance.stop(),this}abort(){return this._instance&&this._instance.abort(),this}addEventListener(e,n){if(this._instance&&this._listeners&&this._includesEventType(e)){this._listeners[e]&&this.removeEventListener(e);let r=r=>{let i=[];if(e===t.eventTypes.RESULT){let e=r;if(e.results?.length>0){let t=Array.from(e.results[0],e=>e.transcript);i.push(t[0],t)}}n.apply(this,[r,...i])};this._instance.addEventListener(e,r),this._listeners[e]=r}return this}removeEventListener(e){if(this._instance&&this._listeners){let t=this._listeners[e];this._instance.removeEventListener(e,t),delete this._listeners[e]}return this}cleanup(){return this.stop(),Object.keys(this._listeners).forEach(e=>this.removeEventListener(e)),this._instance=null,this}_includesEventType(e){return Object.values(t.eventTypes).includes(e)}static _resolveSpeechRecognition(){return window.SpeechRecognition??window.webkitSpeechRecognition??window.mozSpeechRecognition??window.msSpeechRecognition}static _resolveSpeechGrammarList(){return window.SpeechGrammarList??window.webkitSpeechGrammarList??window.mozSpeechGrammarList??window.msSpeechGrammarList}};exports.Vocal=t;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@untemps/user-permissions-utils`);var t=class t{static defaultOptions={grammars:null,lang:`en-US`,continuous:!1,interimResults:!1,maxAlternatives:1};static eventTypes={AUDIO_END:`audioend`,AUDIO_START:`audiostart`,END:`end`,ERROR:`error`,NO_MATCH:`nomatch`,RESULT:`result`,SOUND_END:`soundend`,SOUND_START:`soundstart`,SPEECH_END:`speechend`,SPEECH_START:`speechstart`,START:`start`};static get isSupported(){return!!t._resolveSpeechRecognition()&&!!(0,e.isNavigatorPermissionsSupported)()&&!!(0,e.isNavigatorMediaDevicesSupported)()}static set isSupported(e){throw Error(`You cannot set isSupported directly.`)}_instance=null;_listeners=null;_isRecording=!1;constructor(e){let n=t._resolveSpeechRecognition();if(!n)throw new DOMException(`SpeechRecognition not supported`,`NOT_SUPPORTED_ERR`);this._instance=new n,this._listeners={};let{grammars:r,...i}={...t.defaultOptions,...e??{}},a=this._instance;if(Object.assign(a,i),r)a.grammars=r;else{let e=t._resolveSpeechGrammarList();a.grammars=e?new e:null}this._instance.addEventListener(`end`,()=>{this._isRecording=!1})}get instance(){return this._instance}set instance(e){throw Error(`You cannot set instance directly.`)}get isRecording(){return this._isRecording}set isRecording(e){throw Error(`You cannot set isRecording directly.`)}async start({signal:t}={}){if(this._instance)try{if(!await(0,e.getUserMediaStream)(`microphone`,{audio:!0},{signal:t}))throw Error(`Unable to retrieve the stream from media device`);this._instance.start(),this._isRecording=!0}catch(e){if(e instanceof Error&&e.name===`AbortError`)return this;let t=this._listeners?.error;t&&t(e)}return this}stop(){return this._instance&&(this._instance.stop(),this._isRecording=!1),this}abort(){return this._instance&&(this._instance.abort(),this._isRecording=!1),this}addEventListener(e,n){if(this._instance&&this._listeners&&this._includesEventType(e)){this._listeners[e]&&this.removeEventListener(e);let r=r=>{let i=[];if(e===t.eventTypes.RESULT){let e=r;if(e.results?.length>0){let t=Array.from(e.results[0],e=>e.transcript);i.push(t[0],t)}}n.apply(this,[r,...i])};this._instance.addEventListener(e,r),this._listeners[e]=r}return this}removeEventListener(e){if(this._instance&&this._listeners){let t=this._listeners[e];this._instance.removeEventListener(e,t),delete this._listeners[e]}return this}cleanup(){return this.stop(),Object.keys(this._listeners).forEach(e=>this.removeEventListener(e)),this._instance=null,this}_includesEventType(e){return Object.values(t.eventTypes).includes(e)}static _resolveSpeechRecognition(){return window.SpeechRecognition??window.webkitSpeechRecognition??window.mozSpeechRecognition??window.msSpeechRecognition}static _resolveSpeechGrammarList(){return window.SpeechGrammarList??window.webkitSpeechGrammarList??window.mozSpeechGrammarList??window.msSpeechGrammarList}};exports.Vocal=t;
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.umd.js CHANGED
@@ -1,2 +1,2 @@
1
- (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`@untemps/user-permissions-utils`)):typeof define==`function`&&define.amd?define([`exports`,`@untemps/user-permissions-utils`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.Vocal={},e.UserPermissionsUtils))})(this,function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}),e.Vocal=class e{static defaultOptions={grammars:null,lang:`en-US`,continuous:!1,interimResults:!1,maxAlternatives:1};static eventTypes={AUDIO_END:`audioend`,AUDIO_START:`audiostart`,END:`end`,ERROR:`error`,NO_MATCH:`nomatch`,RESULT:`result`,SOUND_END:`soundend`,SOUND_START:`soundstart`,SPEECH_END:`speechend`,SPEECH_START:`speechstart`,START:`start`};static get isSupported(){return!!e._resolveSpeechRecognition()&&!!(0,t.isNavigatorPermissionsSupported)()&&!!(0,t.isNavigatorMediaDevicesSupported)()}static set isSupported(e){throw Error(`You cannot set isSupported directly.`)}_instance=null;_listeners=null;constructor(t){let n=e._resolveSpeechRecognition();if(!n)throw new DOMException(`SpeechRecognition not supported`,`NOT_SUPPORTED_ERR`);this._instance=new n,this._listeners={};let{grammars:r,...i}={...e.defaultOptions,...t??{}},a=this._instance;if(Object.assign(a,i),r)a.grammars=r;else{let t=e._resolveSpeechGrammarList();a.grammars=t?new t:null}}get instance(){return this._instance}set instance(e){throw Error(`You cannot set instance directly.`)}async start(){if(this._instance)try{if(!await(0,t.getUserMediaStream)(`microphone`,{audio:!0}))throw Error(`Unable to retrieve the stream from media device`);this._instance.start()}catch(e){let t=this._listeners?.error;t&&t(e)}return this}stop(){return this._instance&&this._instance.stop(),this}abort(){return this._instance&&this._instance.abort(),this}addEventListener(t,n){if(this._instance&&this._listeners&&this._includesEventType(t)){this._listeners[t]&&this.removeEventListener(t);let r=r=>{let i=[];if(t===e.eventTypes.RESULT){let e=r;if(e.results?.length>0){let t=Array.from(e.results[0],e=>e.transcript);i.push(t[0],t)}}n.apply(this,[r,...i])};this._instance.addEventListener(t,r),this._listeners[t]=r}return this}removeEventListener(e){if(this._instance&&this._listeners){let t=this._listeners[e];this._instance.removeEventListener(e,t),delete this._listeners[e]}return this}cleanup(){return this.stop(),Object.keys(this._listeners).forEach(e=>this.removeEventListener(e)),this._instance=null,this}_includesEventType(t){return Object.values(e.eventTypes).includes(t)}static _resolveSpeechRecognition(){return window.SpeechRecognition??window.webkitSpeechRecognition??window.mozSpeechRecognition??window.msSpeechRecognition}static _resolveSpeechGrammarList(){return window.SpeechGrammarList??window.webkitSpeechGrammarList??window.mozSpeechGrammarList??window.msSpeechGrammarList}}});
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require(`@untemps/user-permissions-utils`)):typeof define==`function`&&define.amd?define([`exports`,`@untemps/user-permissions-utils`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.Vocal={},e.UserPermissionsUtils))})(this,function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`}),e.Vocal=class e{static defaultOptions={grammars:null,lang:`en-US`,continuous:!1,interimResults:!1,maxAlternatives:1};static eventTypes={AUDIO_END:`audioend`,AUDIO_START:`audiostart`,END:`end`,ERROR:`error`,NO_MATCH:`nomatch`,RESULT:`result`,SOUND_END:`soundend`,SOUND_START:`soundstart`,SPEECH_END:`speechend`,SPEECH_START:`speechstart`,START:`start`};static get isSupported(){return!!e._resolveSpeechRecognition()&&!!(0,t.isNavigatorPermissionsSupported)()&&!!(0,t.isNavigatorMediaDevicesSupported)()}static set isSupported(e){throw Error(`You cannot set isSupported directly.`)}_instance=null;_listeners=null;_isRecording=!1;constructor(t){let n=e._resolveSpeechRecognition();if(!n)throw new DOMException(`SpeechRecognition not supported`,`NOT_SUPPORTED_ERR`);this._instance=new n,this._listeners={};let{grammars:r,...i}={...e.defaultOptions,...t??{}},a=this._instance;if(Object.assign(a,i),r)a.grammars=r;else{let t=e._resolveSpeechGrammarList();a.grammars=t?new t:null}this._instance.addEventListener(`end`,()=>{this._isRecording=!1})}get instance(){return this._instance}set instance(e){throw Error(`You cannot set instance directly.`)}get isRecording(){return this._isRecording}set isRecording(e){throw Error(`You cannot set isRecording directly.`)}async start({signal:e}={}){if(this._instance)try{if(!await(0,t.getUserMediaStream)(`microphone`,{audio:!0},{signal:e}))throw Error(`Unable to retrieve the stream from media device`);this._instance.start(),this._isRecording=!0}catch(e){if(e instanceof Error&&e.name===`AbortError`)return this;let t=this._listeners?.error;t&&t(e)}return this}stop(){return this._instance&&(this._instance.stop(),this._isRecording=!1),this}abort(){return this._instance&&(this._instance.abort(),this._isRecording=!1),this}addEventListener(t,n){if(this._instance&&this._listeners&&this._includesEventType(t)){this._listeners[t]&&this.removeEventListener(t);let r=r=>{let i=[];if(t===e.eventTypes.RESULT){let e=r;if(e.results?.length>0){let t=Array.from(e.results[0],e=>e.transcript);i.push(t[0],t)}}n.apply(this,[r,...i])};this._instance.addEventListener(t,r),this._listeners[t]=r}return this}removeEventListener(e){if(this._instance&&this._listeners){let t=this._listeners[e];this._instance.removeEventListener(e,t),delete this._listeners[e]}return this}cleanup(){return this.stop(),Object.keys(this._listeners).forEach(e=>this.removeEventListener(e)),this._instance=null,this}_includesEventType(t){return Object.values(e.eventTypes).includes(t)}static _resolveSpeechRecognition(){return window.SpeechRecognition??window.webkitSpeechRecognition??window.mozSpeechRecognition??window.msSpeechRecognition}static _resolveSpeechGrammarList(){return window.SpeechGrammarList??window.webkitSpeechGrammarList??window.mozSpeechGrammarList??window.msSpeechGrammarList}}});
2
2
  //# sourceMappingURL=index.umd.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@untemps/vocal",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.3",
4
4
  "description": "Class wrapped around the SpeechRecognition Web API",
5
5
  "repository": "git@github.com:untemps/vocal.git",
6
6
  "keywords": [