@untemps/vocal 1.3.1 → 1.3.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,12 @@
1
+ ## [1.3.3](https://github.com/untemps/vocal/compare/v1.3.2...v1.3.3) (2026-05-15)
2
+
3
+ ## [1.3.2](https://github.com/untemps/vocal/compare/v1.3.1...v1.3.2) (2026-05-15)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * Expose all RESULT alternatives as third callback argument ([#35](https://github.com/untemps/vocal/issues/35)) ([87760ea](https://github.com/untemps/vocal/commit/87760eac36f05083de8d84a9bb606ec47dd395e8))
9
+
1
10
  ## [1.3.1](https://github.com/untemps/vocal/compare/v1.3.0...v1.3.1) (2026-05-15)
2
11
 
3
12
  # [1.3.0](https://github.com/untemps/vocal/compare/v1.2.1...v1.3.0) (2021-05-24)
package/README.md CHANGED
@@ -20,9 +20,8 @@ Import `Vocal` to a file.
20
20
  import { Vocal } from '@untemps/vocal'
21
21
 
22
22
  // Check whether SpeechRecognition, Permissions and MediaDevices interfaces are supported
23
- if (!Vocal.isSupported()) {
24
- throw "Vocal is not supported"
25
- return;
23
+ if (!Vocal.isSupported) {
24
+ throw new Error('Vocal is not supported')
26
25
  }
27
26
 
28
27
  // Create a Vocal instance (see below for all available option properties)
@@ -34,8 +33,8 @@ const vocal = new Vocal(options)
34
33
  // Subscribe to Vocal instance events (see below for all available events)
35
34
  vocal.addEventListener('speechstart', (event) => console.log('Vocal starts recording'))
36
35
  vocal.addEventListener('speechend', (event) => console.log('Vocal stops recording'))
37
- vocal.addEventListener('result', (event, result) => console.log('Vocal catches a result'))
38
- vocal.addEventListener('error', (error) => throw error)
36
+ vocal.addEventListener('result', (event, transcript, alternatives) => console.log('Vocal catches a result:', transcript, alternatives))
37
+ vocal.addEventListener('error', (error) => { throw error })
39
38
 
40
39
  // Start recording
41
40
  vocal.start()
@@ -53,7 +52,7 @@ vocal.cleanup()
53
52
  ## Options
54
53
 
55
54
  Options described below are those from the `SpeechRecognition` Web API.
56
- Please this [this section](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#properties) for more information.
55
+ Please refer to [this section](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#properties) for more information.
57
56
 
58
57
  | Option | Type | Default | Description |
59
58
  | ---------------- | ----------------- | ---------- | ----------------------------------------------------------------------------------------------------------------- |
@@ -67,7 +66,7 @@ Please this [this section](https://developer.mozilla.org/en-US/docs/Web/API/Spee
67
66
  ## Events
68
67
 
69
68
  Events described below are those from the `SpeechRecognition` Web API.
70
- Please this [this section](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#events) for more information.
69
+ Please refer to [this section](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#events) for more information.
71
70
 
72
71
  | Event | Description |
73
72
  | ----------- | ----------------------------------------------------------------------------------------- |
@@ -76,7 +75,7 @@ Please this [this section](https://developer.mozilla.org/en-US/docs/Web/API/Spee
76
75
  | end | Fired when the recognition service has disconnected |
77
76
  | error | Fired when a recognition error occurs |
78
77
  | nomatch | Fired when the recognition service returns a final result with no significant recognition |
79
- | result | Fired when the recognition service returns a result |
78
+ | result | Fired when the recognition service returns a result — callback receives `(event, transcript: string, alternatives: string[])` where `transcript === alternatives[0]` |
80
79
  | soundend | Fired when any sound — recognisable or not — has stopped being detected |
81
80
  | soundstart | Fired when any sound — recognisable or not — has been detected |
82
81
  | speechend | Fired when speech recognized by the recognition service has stopped being detected |
@@ -0,0 +1,2 @@
1
+ export { default as Vocal } from './Vocal';
2
+ export type { VocalOptions, EventType } from './Vocal';
package/dist/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getUserMediaStream as e, isNavigatorMediaDevicesSupported as t, isNavigatorPermissionsSupported as n } from "@untemps/user-permissions-utils";
2
- //#region src/Vocal.js
2
+ //#region src/Vocal.ts
3
3
  var r = class r {
4
4
  static defaultOptions = {
5
5
  grammars: null,
@@ -33,16 +33,16 @@ var r = class r {
33
33
  constructor(e) {
34
34
  let t = r._resolveSpeechRecognition();
35
35
  if (!t) throw new DOMException("SpeechRecognition not supported", "NOT_SUPPORTED_ERR");
36
- this._instance = new t(), this._listeners = {}, Object.entries({
36
+ this._instance = new t(), this._listeners = {};
37
+ let { grammars: n, ...i } = {
37
38
  ...r.defaultOptions,
38
- ...e || {}
39
- }).forEach(([e, t]) => {
40
- if (e === "grammars" && !t) {
41
- let e = r._resolveSpeechGrammarList();
42
- e && (t = new e());
43
- }
44
- this._instance[e] = t;
45
- });
39
+ ...e ?? {}
40
+ }, a = this._instance;
41
+ if (Object.assign(a, i), n) a.grammars = n;
42
+ else {
43
+ let e = r._resolveSpeechGrammarList();
44
+ a.grammars = e ? new e() : null;
45
+ }
46
46
  }
47
47
  get instance() {
48
48
  return this._instance;
@@ -55,7 +55,7 @@ var r = class r {
55
55
  if (!await e("microphone", { audio: !0 })) throw Error("Unable to retrieve the stream from media device");
56
56
  this._instance.start();
57
57
  } catch (e) {
58
- let t = this._listeners.error;
58
+ let t = this._listeners?.error;
59
59
  t && t(e);
60
60
  }
61
61
  return this;
@@ -67,31 +67,41 @@ var r = class r {
67
67
  return this._instance && this._instance.abort(), this;
68
68
  }
69
69
  addEventListener(e, t) {
70
- if (this._instance && this._includesEventType(e)) {
70
+ if (this._instance && this._listeners && this._includesEventType(e)) {
71
71
  this._listeners[e] && this.removeEventListener(e);
72
72
  let n = (n) => {
73
73
  let i = [];
74
- e === r.eventTypes.RESULT && n.results && n.results.length > 0 && i.push(n.results[0][0].transcript), t && t.apply(this, [n, ...i]);
74
+ if (e === r.eventTypes.RESULT) {
75
+ let e = n;
76
+ if (e.results?.length > 0) {
77
+ let t = Array.from(e.results[0], (e) => e.transcript);
78
+ i.push(t[0], t);
79
+ }
80
+ }
81
+ t.apply(this, [n, ...i]);
75
82
  };
76
83
  this._instance.addEventListener(e, n), this._listeners[e] = n;
77
84
  }
78
85
  return this;
79
86
  }
80
87
  removeEventListener(e) {
81
- let t = this._listeners[e];
82
- return this._instance.removeEventListener(e, t), delete this._listeners[e], this;
88
+ if (this._instance && this._listeners) {
89
+ let t = this._listeners[e];
90
+ this._instance.removeEventListener(e, t), delete this._listeners[e];
91
+ }
92
+ return this;
83
93
  }
84
94
  cleanup() {
85
95
  return this.stop(), Object.keys(this._listeners).forEach((e) => this.removeEventListener(e)), this._instance = null, this;
86
96
  }
87
97
  _includesEventType(e) {
88
- return !!Object.values(r.eventTypes).find((t) => t === e);
98
+ return Object.values(r.eventTypes).includes(e);
89
99
  }
90
100
  static _resolveSpeechRecognition() {
91
- return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition;
101
+ return window.SpeechRecognition ?? window.webkitSpeechRecognition ?? window.mozSpeechRecognition ?? window.msSpeechRecognition;
92
102
  }
93
103
  static _resolveSpeechGrammarList() {
94
- return window.SpeechGrammarList || window.webkitSpeechGrammarList || window.mozSpeechGrammarList || window.msSpeechGrammarList;
104
+ return window.SpeechGrammarList ?? window.webkitSpeechGrammarList ?? window.mozSpeechGrammarList ?? window.msSpeechGrammarList;
95
105
  }
96
106
  };
97
107
  //#endregion
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,serviceURI:null};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={},Object.entries({...t.defaultOptions,...e||{}}).forEach(([e,n])=>{if(e===`grammars`&&!n){let e=t._resolveSpeechGrammarList();e&&(n=new e)}this._instance[e]=n})}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._includesEventType(e)){this._listeners[e]&&this.removeEventListener(e);let r=r=>{let i=[];e===t.eventTypes.RESULT&&r.results&&r.results.length>0&&i.push(r.results[0][0].transcript),n&&n.apply(this,[r,...i])};this._instance.addEventListener(e,r),this._listeners[e]=r}return this}removeEventListener(e){let t=this._listeners[e];return this._instance.removeEventListener(e,t),delete this._listeners[e],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).find(t=>t===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,serviceURI:null};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;
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,serviceURI:null};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={},Object.entries({...e.defaultOptions,...t||{}}).forEach(([t,n])=>{if(t===`grammars`&&!n){let t=e._resolveSpeechGrammarList();t&&(n=new t)}this._instance[t]=n})}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._includesEventType(t)){this._listeners[t]&&this.removeEventListener(t);let r=r=>{let i=[];t===e.eventTypes.RESULT&&r.results&&r.results.length>0&&i.push(r.results[0][0].transcript),n&&n.apply(this,[r,...i])};this._instance.addEventListener(t,r),this._listeners[t]=r}return this}removeEventListener(e){let t=this._listeners[e];return this._instance.removeEventListener(e,t),delete this._listeners[e],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).find(e=>e===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,serviceURI:null};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}}});
2
2
  //# sourceMappingURL=index.umd.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@untemps/vocal",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Class wrapped around the SpeechRecognition Web API",
5
5
  "repository": "git@github.com:untemps/vocal.git",
6
6
  "keywords": [
@@ -23,10 +23,20 @@
23
23
  "dist/index.js",
24
24
  "dist/index.es.js",
25
25
  "dist/index.umd.js",
26
+ "dist/index.d.ts",
26
27
  "CHANGELOG.md"
27
28
  ],
28
29
  "main": "dist/index.js",
29
30
  "module": "dist/index.es.js",
31
+ "types": "dist/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.es.js",
36
+ "require": "./dist/index.js",
37
+ "default": "./dist/index.es.js"
38
+ }
39
+ },
30
40
  "devDependencies": {
31
41
  "@commitlint/cli": "^21.0.1",
32
42
  "@commitlint/config-conventional": "^21.0.1",
@@ -39,7 +49,9 @@
39
49
  "jsdom": "^29.1.1",
40
50
  "prettier": "^3.8.3",
41
51
  "semantic-release": "^25.0.3",
52
+ "typescript": "^6.0.3",
42
53
  "vite": "^8.0.13",
54
+ "vite-plugin-dts": "^5.0.0",
43
55
  "vitest": "^4.1.5"
44
56
  },
45
57
  "dependencies": {
@@ -94,6 +106,7 @@
94
106
  "test": "vitest",
95
107
  "test:ci": "vitest run --coverage",
96
108
  "build": "vite build",
109
+ "typecheck": "tsc --noEmit",
97
110
  "prepare": "husky",
98
111
  "prettier": "prettier \"*/**/*.js\" --ignore-path ./.prettierignore --write"
99
112
  }