@untemps/vocal 2.0.0-beta.20 → 2.0.0-beta.22
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 +49 -0
- package/README.md +52 -38
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.es.js +122 -165
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
+
# [2.0.0-beta.22](https://github.com/untemps/vocal/compare/v2.0.0-beta.21...v2.0.0-beta.22) (2026-05-22)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Code Refactoring
|
|
5
|
+
|
|
6
|
+
* Move from class-based to functional API ([#88](https://github.com/untemps/vocal/issues/88)) ([1161ce8](https://github.com/untemps/vocal/commit/1161ce8ce983a7f216b5a11803bbc5ad90a68dc5))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* every public entry point changes shape:
|
|
12
|
+
- `new Vocal(options)` → `createVocal(options)`
|
|
13
|
+
- `Vocal.isSupported` (static getter) → `isSupported()` (function)
|
|
14
|
+
- `Vocal.eventTypes` (static) → `eventTypes` (named export)
|
|
15
|
+
- `vocal.addEventListener(type, cb)` → `vocal.on(type, cb)`
|
|
16
|
+
- `vocal.removeEventListener(type, cb?)` → `vocal.off(type, cb?)`
|
|
17
|
+
- Side-effect methods (`stop`, `abort`, `on`, `off`, `cleanup`) now
|
|
18
|
+
return `void` instead of `this` — chaining is no longer supported.
|
|
19
|
+
- The `Vocal` class is no longer exported; the new `VocalInstance`
|
|
20
|
+
interface describes the object returned by `createVocal()`.
|
|
21
|
+
Migration:
|
|
22
|
+
// before
|
|
23
|
+
import { Vocal } from '@untemps/vocal'
|
|
24
|
+
if (!Vocal.isSupported) throw new Error()
|
|
25
|
+
const vocal = new Vocal({ lang: 'fr-FR' })
|
|
26
|
+
vocal.addEventListener('result', cb)
|
|
27
|
+
// after
|
|
28
|
+
import { createVocal, isSupported } from '@untemps/vocal'
|
|
29
|
+
if (!isSupported()) throw new Error()
|
|
30
|
+
const vocal = createVocal({ lang: 'fr-FR' })
|
|
31
|
+
vocal.on('result', cb)
|
|
32
|
+
|
|
33
|
+
# [2.0.0-beta.21](https://github.com/untemps/vocal/compare/v2.0.0-beta.20...v2.0.0-beta.21) (2026-05-20)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### Code Refactoring
|
|
37
|
+
|
|
38
|
+
* Remove once() method ([#87](https://github.com/untemps/vocal/issues/87)) ([3748768](https://github.com/untemps/vocal/commit/3748768c33f61ba170f4ffd09ccba23063e5c8c5))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### BREAKING CHANGES
|
|
42
|
+
|
|
43
|
+
* vocal.once(eventType, callback) is removed. Consumers relying on it must replace the call with a manual addEventListener + removeEventListener pair:
|
|
44
|
+
const handler = (event, best) => {
|
|
45
|
+
vocal.removeEventListener('result', handler)
|
|
46
|
+
// ...
|
|
47
|
+
}
|
|
48
|
+
vocal.addEventListener('result', handler)
|
|
49
|
+
|
|
1
50
|
# [2.0.0-beta.20](https://github.com/untemps/vocal/compare/v2.0.0-beta.19...v2.0.0-beta.20) (2026-05-20)
|
|
2
51
|
|
|
3
52
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @untemps/vocal
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Functional wrapper around the SpeechRecognition Web API
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|

|
|
@@ -14,27 +14,22 @@ yarn add @untemps/vocal
|
|
|
14
14
|
|
|
15
15
|
## Basic Usage
|
|
16
16
|
|
|
17
|
-
Import `Vocal` to a file.
|
|
18
|
-
|
|
19
17
|
```javascript
|
|
20
|
-
import {
|
|
18
|
+
import { createVocal, isSupported } from '@untemps/vocal'
|
|
21
19
|
|
|
22
20
|
// Check whether SpeechRecognition, Permissions and MediaDevices interfaces are supported
|
|
23
|
-
if (!
|
|
21
|
+
if (!isSupported()) {
|
|
24
22
|
throw new Error('Vocal is not supported')
|
|
25
23
|
}
|
|
26
24
|
|
|
27
25
|
// Create a Vocal instance (see below for all available option properties)
|
|
28
|
-
const
|
|
29
|
-
lang: 'fr-FR',
|
|
30
|
-
}
|
|
31
|
-
const vocal = new Vocal(options)
|
|
26
|
+
const vocal = createVocal({ lang: 'fr-FR' })
|
|
32
27
|
|
|
33
|
-
// Subscribe to
|
|
34
|
-
vocal.
|
|
35
|
-
vocal.
|
|
36
|
-
vocal.
|
|
37
|
-
vocal.
|
|
28
|
+
// Subscribe to instance events (see below for all available events)
|
|
29
|
+
vocal.on('speechstart', (event) => console.log('Vocal starts recording'))
|
|
30
|
+
vocal.on('speechend', (event) => console.log('Vocal stops recording'))
|
|
31
|
+
vocal.on('result', (event, bestAlternative, alternatives) => console.log('Vocal catches a result:', bestAlternative, alternatives))
|
|
32
|
+
vocal.on('error', (event) => console.error(event.error, event.message))
|
|
38
33
|
|
|
39
34
|
// Start recording — rejects on error
|
|
40
35
|
try {
|
|
@@ -49,7 +44,7 @@ vocal.stop()
|
|
|
49
44
|
// Abort recording entirely
|
|
50
45
|
vocal.abort()
|
|
51
46
|
|
|
52
|
-
// Remove all attached listeners and
|
|
47
|
+
// Remove all attached listeners and release the internal SpeechRecognition instance
|
|
53
48
|
vocal.cleanup()
|
|
54
49
|
```
|
|
55
50
|
|
|
@@ -97,17 +92,33 @@ Please refer to [this section](https://developer.mozilla.org/en-US/docs/Web/API/
|
|
|
97
92
|
| speechstart | Fired when sound recognized by the recognition service as speech has been detected |
|
|
98
93
|
| start | fired when the recognition service has begun listening to incoming audio |
|
|
99
94
|
|
|
100
|
-
|
|
95
|
+
For convenience, `eventTypes` is exported as a constant map so consumers can reference type strings symbolically:
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
import { eventTypes } from '@untemps/vocal'
|
|
99
|
+
vocal.on(eventTypes.RESULT, handler)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Top-level exports
|
|
103
|
+
|
|
104
|
+
| Export | Kind | Description |
|
|
105
|
+
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
106
|
+
| `createVocal` | function | Factory that returns a `VocalInstance`. See [Methods](#methods). |
|
|
107
|
+
| `isSupported` | function | Returns `true` if the current environment supports the SpeechRecognition Web API. Call it (it is **not** a getter). |
|
|
108
|
+
| `eventTypes` | const | Map of valid event type strings (e.g. `eventTypes.RESULT === 'result'`). |
|
|
109
|
+
|
|
110
|
+
## Instance getter
|
|
101
111
|
|
|
102
|
-
| Getter | Type
|
|
103
|
-
| ----------- |
|
|
104
|
-
|
|
|
105
|
-
| isRecording | boolean | Whether recognition is currently active — `true` after `start()`, `false` after `stop()`, `abort()`, or `end` event |
|
|
112
|
+
| Getter | Type | Description |
|
|
113
|
+
| ----------- | --------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
114
|
+
| isRecording | boolean | Whether recognition is currently active — `true` after `start()`, `false` after `stop()`, `abort()`, or `end` event |
|
|
106
115
|
|
|
107
116
|
## Methods
|
|
108
117
|
|
|
109
118
|
### `start({ signal? })`
|
|
110
119
|
|
|
120
|
+
Starts recognition. Resolves once the engine is active. Rejects if microphone permission cannot be obtained.
|
|
121
|
+
|
|
111
122
|
| Parameter | Type | Default | Description |
|
|
112
123
|
| --------- | ------------- | ----------- | ----------------------------------------------------------------------------- |
|
|
113
124
|
| signal | AbortSignal | `undefined` | Cancels the in-flight microphone permission request when the signal is aborted |
|
|
@@ -122,13 +133,13 @@ controller.abort()
|
|
|
122
133
|
|
|
123
134
|
### `stop()`
|
|
124
135
|
|
|
125
|
-
Stops recognition gracefully, allowing the current audio to be processed before disconnecting. Sets `isRecording` to `false`.
|
|
136
|
+
Stops recognition gracefully, allowing the current audio to be processed before disconnecting. Sets `isRecording` to `false`. In continuous mode, emits the aggregated `result` event just before `end`.
|
|
126
137
|
|
|
127
138
|
### `abort()`
|
|
128
139
|
|
|
129
|
-
Stops recognition immediately without processing pending audio. Sets `isRecording` to `false`.
|
|
140
|
+
Stops recognition immediately without processing pending audio. Sets `isRecording` to `false`. Discards any aggregated transcript without emitting.
|
|
130
141
|
|
|
131
|
-
### `
|
|
142
|
+
### `on(eventType, callback)`
|
|
132
143
|
|
|
133
144
|
Registers a callback for the given event type. Multiple callbacks can be registered for the same type — they stack and all fire in registration order.
|
|
134
145
|
|
|
@@ -139,7 +150,7 @@ Registers a callback for the given event type. Multiple callbacks can be registe
|
|
|
139
150
|
|
|
140
151
|
Throws if `eventType` is not a valid `EventType`.
|
|
141
152
|
|
|
142
|
-
### `
|
|
153
|
+
### `off(eventType, callback?)`
|
|
143
154
|
|
|
144
155
|
Removes a listener for the given event type.
|
|
145
156
|
|
|
@@ -150,23 +161,26 @@ Removes a listener for the given event type.
|
|
|
150
161
|
|
|
151
162
|
Throws if `eventType` is not a valid `EventType`.
|
|
152
163
|
|
|
153
|
-
### `
|
|
164
|
+
### `cleanup()`
|
|
154
165
|
|
|
155
|
-
|
|
166
|
+
Stops recognition, removes all registered listeners, and releases the internal `SpeechRecognition` instance. The returned `VocalInstance` cannot be reused after `cleanup()`.
|
|
156
167
|
|
|
157
|
-
|
|
158
|
-
| --------- | ------------------------------------------------- | ------------------------------------------ |
|
|
159
|
-
| eventType | `EventType` | One of the valid event type strings |
|
|
160
|
-
| callback | `ResultEventHandler \| ErrorEventHandler \| GenericEventHandler` | Callback invoked once when the event fires |
|
|
168
|
+
## Migration from the class-based API (v1.x)
|
|
161
169
|
|
|
162
170
|
```js
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
})
|
|
171
|
+
// Before
|
|
172
|
+
import { Vocal } from '@untemps/vocal'
|
|
173
|
+
if (!Vocal.isSupported) throw new Error()
|
|
174
|
+
const vocal = new Vocal({ lang: 'fr-FR' })
|
|
175
|
+
vocal.addEventListener('result', cb)
|
|
176
|
+
vocal.removeEventListener('result', cb)
|
|
177
|
+
|
|
178
|
+
// After
|
|
179
|
+
import { createVocal, isSupported } from '@untemps/vocal'
|
|
180
|
+
if (!isSupported()) throw new Error()
|
|
181
|
+
const vocal = createVocal({ lang: 'fr-FR' })
|
|
182
|
+
vocal.on('result', cb)
|
|
183
|
+
vocal.off('result', cb)
|
|
167
184
|
```
|
|
168
185
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Stops recognition, removes all registered listeners, and releases the internal `SpeechRecognition` instance. The `Vocal` object cannot be reused after `cleanup()`.
|
|
172
|
-
|
|
186
|
+
Side-effect methods (`stop`, `abort`, `on`, `off`, `cleanup`) now return `void` — method chaining is no longer supported. `Vocal.eventTypes` is now exported as the top-level `eventTypes` const.
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@untemps/user-permissions-utils`);var t=
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@untemps/user-permissions-utils`);var t={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`},n=1e3,r=new Set([`not-allowed`,`service-not-allowed`,`audio-capture`]),i={grammars:null,lang:`en-US`,continuous:!1,interimResults:!1,maxAlternatives:1},a=()=>{if(!(typeof window>`u`))return window.SpeechRecognition??window.webkitSpeechRecognition??window.mozSpeechRecognition??window.msSpeechRecognition},o=()=>window.SpeechGrammarList??window.webkitSpeechGrammarList??window.mozSpeechGrammarList??window.msSpeechGrammarList,s=e=>e.reduce((e,t)=>(t.confidence??0)>(e.confidence??0)?t:e),c=e=>Object.values(t).includes(e),l=e=>`Unknown event type "${e}". Valid types are: ${Object.values(t).join(`, `)}.`,u=()=>!!a()&&!!(0,e.isNavigatorPermissionsSupported)()&&!!(0,e.isNavigatorMediaDevicesSupported)(),d=u=>{let d=a();if(!d)throw new DOMException(`SpeechRecognition not supported`,`NOT_SUPPORTED_ERR`);let f=new d,p={},m=!1,h=!1,g=0,_=null,v=!1,y=[],b={...i,...u??{}};if(f.lang=b.lang,f.continuous=b.continuous,f.interimResults=b.interimResults,f.maxAlternatives=b.maxAlternatives,b.grammars)f.grammars=b.grammars;else{let e=o();f.grammars=e?new e:null}let x=()=>{_!==null&&(clearTimeout(_),_=null),v=!1},S=()=>!!f&&!h&&f.continuous,C=()=>{_=null;try{f.start(),g=Date.now()}catch{v=!1,m=!1}},w=()=>{let e=y;if(y=[],e.length===0||!p[t.RESULT]?.length)return;let n=e.join(` `).trim(),r=Object.assign([{transcript:n,confidence:1}],{isFinal:!0}),i=Object.assign(new Event(t.RESULT),{resultIndex:0,results:[r]});[...p[t.RESULT]].forEach(({handler:e})=>e(i))},T=[[t.END,e=>{if(S()){let t=Math.max(0,n-(Date.now()-g));v=!0,_=setTimeout(C,t),e.stopImmediatePropagation();return}m=!1}],[t.START,e=>{v&&(e.stopImmediatePropagation(),queueMicrotask(()=>{v=!1}))}],[t.ERROR,e=>{r.has(e.error)&&(h=!0,x(),m=!1)}],[t.RESULT,e=>{let t=e,n=t.results?.[t.resultIndex];n?.isFinal&&y.push(s(Array.from(n)).transcript)}]];T.forEach(([e,t])=>f.addEventListener(e,t));let E=async({signal:t}={})=>{if(f)try{let n=await(0,e.getUserMediaStream)(`microphone`,{audio:!0},{signal:t});if(t?.aborted)return;if(!n)throw Error(`Unable to retrieve the stream from media device`);h=!1,y=[],f.start(),m=!0,g=Date.now()}catch(e){if(e instanceof Error&&e.name===`AbortError`)return;throw e}},D=()=>{f&&(h=!0,x(),w(),f.stop(),m=!1)},O=()=>{f&&(h=!0,x(),f.abort(),m=!1,y=[])},k=(e,n)=>{if(!c(e))throw Error(l(e));if(!f)return;let r=r=>{if(v&&(e===t.END||e===t.START))return;if(e!==t.RESULT){n(r);return}let i=r;if(!(i.results?.length>0)||i.resultIndex>=i.results.length){n(r);return}let a=Array.from(i.results[i.resultIndex]);n(r,s(a).transcript,a.map(e=>e.transcript))};f.addEventListener(e,r),p[e]||(p[e]=[]),p[e].push({callback:n,handler:r})},A=(e,t)=>{if(!c(e))throw Error(l(e));if(!(!f||!p[e]))if(t!==void 0){let n=p[e].findIndex(e=>e.callback===t);n!==-1&&(f.removeEventListener(e,p[e][n].handler),p[e].splice(n,1),p[e].length===0&&delete p[e])}else p[e].forEach(({handler:t})=>f.removeEventListener(e,t)),delete p[e]};return{get isRecording(){return m},start:E,stop:D,abort:O,on:k,off:A,cleanup:()=>{D(),Object.keys(p).forEach(e=>A(e)),T.forEach(([e,t])=>f?.removeEventListener(e,t)),f=null}}};exports.createVocal=d,exports.eventTypes=t,exports.isSupported=u;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type { VocalOptions, EventType, ResultEventHandler, ErrorEventHandler, GenericEventHandler, EventHandlerFor, } from './Vocal';
|
|
1
|
+
export { createVocal, isSupported, eventTypes } from './Vocal';
|
|
2
|
+
export type { VocalOptions, VocalInstance, EventType, ResultEventHandler, ErrorEventHandler, GenericEventHandler, EventHandlerFor, } from './Vocal';
|
package/dist/index.es.js
CHANGED
|
@@ -1,184 +1,141 @@
|
|
|
1
1
|
import { getUserMediaStream as e, isNavigatorMediaDevicesSupported as t, isNavigatorPermissionsSupported as n } from "@untemps/user-permissions-utils";
|
|
2
2
|
//#region src/Vocal.ts
|
|
3
|
-
var r =
|
|
3
|
+
var r = {
|
|
4
|
+
AUDIO_END: "audioend",
|
|
5
|
+
AUDIO_START: "audiostart",
|
|
6
|
+
END: "end",
|
|
7
|
+
ERROR: "error",
|
|
8
|
+
NO_MATCH: "nomatch",
|
|
9
|
+
RESULT: "result",
|
|
10
|
+
SOUND_END: "soundend",
|
|
11
|
+
SOUND_START: "soundstart",
|
|
12
|
+
SPEECH_END: "speechend",
|
|
13
|
+
SPEECH_START: "speechstart",
|
|
14
|
+
START: "start"
|
|
15
|
+
}, i = 1e3, a = new Set([
|
|
4
16
|
"not-allowed",
|
|
5
17
|
"service-not-allowed",
|
|
6
18
|
"audio-capture"
|
|
7
|
-
]),
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
19
|
+
]), o = {
|
|
20
|
+
grammars: null,
|
|
21
|
+
lang: "en-US",
|
|
22
|
+
continuous: !1,
|
|
23
|
+
interimResults: !1,
|
|
24
|
+
maxAlternatives: 1
|
|
25
|
+
}, s = () => {
|
|
26
|
+
if (!(typeof window > "u")) return window.SpeechRecognition ?? window.webkitSpeechRecognition ?? window.mozSpeechRecognition ?? window.msSpeechRecognition;
|
|
27
|
+
}, c = () => window.SpeechGrammarList ?? window.webkitSpeechGrammarList ?? window.mozSpeechGrammarList ?? window.msSpeechGrammarList, l = (e) => e.reduce((e, t) => (t.confidence ?? 0) > (e.confidence ?? 0) ? t : e), u = (e) => Object.values(r).includes(e), d = (e) => `Unknown event type "${e}". Valid types are: ${Object.values(r).join(", ")}.`, f = () => !!s() && !!n() && !!t(), p = (t) => {
|
|
28
|
+
let n = s();
|
|
29
|
+
if (!n) throw new DOMException("SpeechRecognition not supported", "NOT_SUPPORTED_ERR");
|
|
30
|
+
let f = new n(), p = {}, m = !1, h = !1, g = 0, _ = null, v = !1, y = [], b = {
|
|
31
|
+
...o,
|
|
32
|
+
...t ?? {}
|
|
14
33
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
SPEECH_END: "speechend",
|
|
25
|
-
SPEECH_START: "speechstart",
|
|
26
|
-
START: "start"
|
|
27
|
-
};
|
|
28
|
-
static get isSupported() {
|
|
29
|
-
return !!a._resolveSpeechRecognition() && !!n() && !!t();
|
|
30
|
-
}
|
|
31
|
-
static set isSupported(e) {
|
|
32
|
-
throw Error("You cannot set isSupported directly.");
|
|
33
|
-
}
|
|
34
|
-
_instance = null;
|
|
35
|
-
_listeners = {};
|
|
36
|
-
_isRecording = !1;
|
|
37
|
-
_explicitStop = !1;
|
|
38
|
-
_lastStartedAt = 0;
|
|
39
|
-
_restartTimeoutId = null;
|
|
40
|
-
_isRestarting = !1;
|
|
41
|
-
_finalTranscripts = [];
|
|
42
|
-
_onEnd = (e) => {
|
|
43
|
-
if (this._shouldAutoRestart()) {
|
|
44
|
-
let t = Math.max(0, r - (Date.now() - this._lastStartedAt));
|
|
45
|
-
this._isRestarting = !0, this._restartTimeoutId = setTimeout(() => this._restart(), t), e.stopImmediatePropagation();
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
this._isRecording = !1;
|
|
49
|
-
};
|
|
50
|
-
_onStart = (e) => {
|
|
51
|
-
this._isRestarting && (e.stopImmediatePropagation(), queueMicrotask(() => {
|
|
52
|
-
this._isRestarting = !1;
|
|
53
|
-
}));
|
|
54
|
-
};
|
|
55
|
-
_onError = (e) => {
|
|
56
|
-
i.has(e.error) && (this._explicitStop = !0, this._clearRestartTimeout(), this._isRecording = !1);
|
|
57
|
-
};
|
|
58
|
-
_onResult = (e) => {
|
|
59
|
-
let t = e, n = t.results?.[t.resultIndex];
|
|
60
|
-
n?.isFinal && this._finalTranscripts.push(a._pickBestAlternative(Array.from(n)).transcript);
|
|
61
|
-
};
|
|
62
|
-
constructor(e) {
|
|
63
|
-
let t = a._resolveSpeechRecognition();
|
|
64
|
-
if (!t) throw new DOMException("SpeechRecognition not supported", "NOT_SUPPORTED_ERR");
|
|
65
|
-
this._instance = new t();
|
|
66
|
-
let { grammars: n, ...r } = {
|
|
67
|
-
...a.defaultOptions,
|
|
68
|
-
...e ?? {}
|
|
69
|
-
}, i = this._instance;
|
|
70
|
-
if (Object.assign(i, r), n) i.grammars = n;
|
|
71
|
-
else {
|
|
72
|
-
let e = a._resolveSpeechGrammarList();
|
|
73
|
-
i.grammars = e ? new e() : null;
|
|
74
|
-
}
|
|
75
|
-
this._instance.addEventListener(a.eventTypes.END, this._onEnd), this._instance.addEventListener(a.eventTypes.START, this._onStart), this._instance.addEventListener(a.eventTypes.ERROR, this._onError), this._instance.addEventListener(a.eventTypes.RESULT, this._onResult);
|
|
76
|
-
}
|
|
77
|
-
get isRecording() {
|
|
78
|
-
return this._isRecording;
|
|
79
|
-
}
|
|
80
|
-
set isRecording(e) {
|
|
81
|
-
throw Error("You cannot set isRecording directly.");
|
|
82
|
-
}
|
|
83
|
-
async start({ signal: t } = {}) {
|
|
84
|
-
if (this._instance) try {
|
|
85
|
-
if (!await e("microphone", { audio: !0 }, { signal: t })) throw Error("Unable to retrieve the stream from media device");
|
|
86
|
-
this._explicitStop = !1, this._finalTranscripts = [], this._instance.start(), this._isRecording = !0, this._lastStartedAt = Date.now();
|
|
87
|
-
} catch (e) {
|
|
88
|
-
if (e instanceof Error && e.name === "AbortError") return this;
|
|
89
|
-
throw e;
|
|
90
|
-
}
|
|
91
|
-
return this;
|
|
92
|
-
}
|
|
93
|
-
stop() {
|
|
94
|
-
return this._instance && (this._explicitStop = !0, this._clearRestartTimeout(), this._emitAggregatedResult(), this._instance.stop(), this._isRecording = !1), this;
|
|
95
|
-
}
|
|
96
|
-
abort() {
|
|
97
|
-
return this._instance && (this._explicitStop = !0, this._clearRestartTimeout(), this._instance.abort(), this._isRecording = !1, this._finalTranscripts = []), this;
|
|
98
|
-
}
|
|
99
|
-
addEventListener(e, t) {
|
|
100
|
-
if (!this._includesEventType(e)) throw Error(this._unknownEventTypeMessage(e));
|
|
101
|
-
if (this._instance) {
|
|
102
|
-
let n = (n) => {
|
|
103
|
-
if (this._isRestarting && (e === a.eventTypes.END || e === a.eventTypes.START)) return;
|
|
104
|
-
let r = [];
|
|
105
|
-
if (e === a.eventTypes.RESULT) {
|
|
106
|
-
let e = n;
|
|
107
|
-
if (e.results?.length > 0 && e.resultIndex < e.results.length) {
|
|
108
|
-
let t = Array.from(e.results[e.resultIndex]);
|
|
109
|
-
r.push(a._pickBestAlternative(t).transcript, t.map((e) => e.transcript));
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
t.call(this, n, ...r);
|
|
113
|
-
};
|
|
114
|
-
this._instance.addEventListener(e, n), this._listeners[e] || (this._listeners[e] = []), this._listeners[e].push({
|
|
115
|
-
callback: t,
|
|
116
|
-
handler: n
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
return this;
|
|
120
|
-
}
|
|
121
|
-
removeEventListener(e, t) {
|
|
122
|
-
if (!this._includesEventType(e)) throw Error(this._unknownEventTypeMessage(e));
|
|
123
|
-
let n = this._instance;
|
|
124
|
-
if (n && this._listeners[e]) if (t !== void 0) {
|
|
125
|
-
let r = this._listeners[e].findIndex((e) => e.callback === t);
|
|
126
|
-
r !== -1 && (n.removeEventListener(e, this._listeners[e][r].handler), this._listeners[e].splice(r, 1), this._listeners[e].length === 0 && delete this._listeners[e]);
|
|
127
|
-
} else this._listeners[e].forEach(({ handler: t }) => n.removeEventListener(e, t)), delete this._listeners[e];
|
|
128
|
-
return this;
|
|
129
|
-
}
|
|
130
|
-
once(e, t) {
|
|
131
|
-
let n = (...r) => {
|
|
132
|
-
t.call(this, ...r), this.removeEventListener(e, n);
|
|
133
|
-
};
|
|
134
|
-
return this.addEventListener(e, n);
|
|
135
|
-
}
|
|
136
|
-
cleanup() {
|
|
137
|
-
return this.stop(), Object.keys(this._listeners).forEach((e) => this.removeEventListener(e)), this._instance?.removeEventListener(a.eventTypes.END, this._onEnd), this._instance?.removeEventListener(a.eventTypes.START, this._onStart), this._instance?.removeEventListener(a.eventTypes.ERROR, this._onError), this._instance?.removeEventListener(a.eventTypes.RESULT, this._onResult), this._instance = null, this;
|
|
138
|
-
}
|
|
139
|
-
_restart = () => {
|
|
140
|
-
this._restartTimeoutId = null;
|
|
34
|
+
if (f.lang = b.lang, f.continuous = b.continuous, f.interimResults = b.interimResults, f.maxAlternatives = b.maxAlternatives, b.grammars) f.grammars = b.grammars;
|
|
35
|
+
else {
|
|
36
|
+
let e = c();
|
|
37
|
+
f.grammars = e ? new e() : null;
|
|
38
|
+
}
|
|
39
|
+
let x = () => {
|
|
40
|
+
_ !== null && (clearTimeout(_), _ = null), v = !1;
|
|
41
|
+
}, S = () => !!f && !h && f.continuous, C = () => {
|
|
42
|
+
_ = null;
|
|
141
43
|
try {
|
|
142
|
-
|
|
44
|
+
f.start(), g = Date.now();
|
|
143
45
|
} catch {
|
|
144
|
-
|
|
46
|
+
v = !1, m = !1;
|
|
145
47
|
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (this._finalTranscripts = [], e.length === 0) return;
|
|
48
|
+
}, w = () => {
|
|
49
|
+
let e = y;
|
|
50
|
+
if (y = [], e.length === 0 || !p[r.RESULT]?.length) return;
|
|
150
51
|
let t = e.join(" ").trim(), n = Object.assign([{
|
|
151
52
|
transcript: t,
|
|
152
53
|
confidence: 1
|
|
153
|
-
}], { isFinal: !0 }),
|
|
54
|
+
}], { isFinal: !0 }), i = Object.assign(new Event(r.RESULT), {
|
|
154
55
|
resultIndex: 0,
|
|
155
56
|
results: [n]
|
|
156
57
|
});
|
|
157
|
-
[...
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
58
|
+
[...p[r.RESULT]].forEach(({ handler: e }) => e(i));
|
|
59
|
+
}, T = [
|
|
60
|
+
[r.END, (e) => {
|
|
61
|
+
if (S()) {
|
|
62
|
+
let t = Math.max(0, i - (Date.now() - g));
|
|
63
|
+
v = !0, _ = setTimeout(C, t), e.stopImmediatePropagation();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
m = !1;
|
|
67
|
+
}],
|
|
68
|
+
[r.START, (e) => {
|
|
69
|
+
v && (e.stopImmediatePropagation(), queueMicrotask(() => {
|
|
70
|
+
v = !1;
|
|
71
|
+
}));
|
|
72
|
+
}],
|
|
73
|
+
[r.ERROR, (e) => {
|
|
74
|
+
a.has(e.error) && (h = !0, x(), m = !1);
|
|
75
|
+
}],
|
|
76
|
+
[r.RESULT, (e) => {
|
|
77
|
+
let t = e, n = t.results?.[t.resultIndex];
|
|
78
|
+
n?.isFinal && y.push(l(Array.from(n)).transcript);
|
|
79
|
+
}]
|
|
80
|
+
];
|
|
81
|
+
T.forEach(([e, t]) => f.addEventListener(e, t));
|
|
82
|
+
let E = async ({ signal: t } = {}) => {
|
|
83
|
+
if (f) try {
|
|
84
|
+
let n = await e("microphone", { audio: !0 }, { signal: t });
|
|
85
|
+
if (t?.aborted) return;
|
|
86
|
+
if (!n) throw Error("Unable to retrieve the stream from media device");
|
|
87
|
+
h = !1, y = [], f.start(), m = !0, g = Date.now();
|
|
88
|
+
} catch (e) {
|
|
89
|
+
if (e instanceof Error && e.name === "AbortError") return;
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
92
|
+
}, D = () => {
|
|
93
|
+
f && (h = !0, x(), w(), f.stop(), m = !1);
|
|
94
|
+
}, O = () => {
|
|
95
|
+
f && (h = !0, x(), f.abort(), m = !1, y = []);
|
|
96
|
+
}, k = (e, t) => {
|
|
97
|
+
if (!u(e)) throw Error(d(e));
|
|
98
|
+
if (!f) return;
|
|
99
|
+
let n = (n) => {
|
|
100
|
+
if (v && (e === r.END || e === r.START)) return;
|
|
101
|
+
if (e !== r.RESULT) {
|
|
102
|
+
t(n);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
let i = n;
|
|
106
|
+
if (!(i.results?.length > 0) || i.resultIndex >= i.results.length) {
|
|
107
|
+
t(n);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
let a = Array.from(i.results[i.resultIndex]);
|
|
111
|
+
t(n, l(a).transcript, a.map((e) => e.transcript));
|
|
112
|
+
};
|
|
113
|
+
f.addEventListener(e, n), p[e] || (p[e] = []), p[e].push({
|
|
114
|
+
callback: t,
|
|
115
|
+
handler: n
|
|
116
|
+
});
|
|
117
|
+
}, A = (e, t) => {
|
|
118
|
+
if (!u(e)) throw Error(d(e));
|
|
119
|
+
if (!(!f || !p[e])) if (t !== void 0) {
|
|
120
|
+
let n = p[e].findIndex((e) => e.callback === t);
|
|
121
|
+
n !== -1 && (f.removeEventListener(e, p[e][n].handler), p[e].splice(n, 1), p[e].length === 0 && delete p[e]);
|
|
122
|
+
} else p[e].forEach(({ handler: t }) => f.removeEventListener(e, t)), delete p[e];
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
get isRecording() {
|
|
126
|
+
return m;
|
|
127
|
+
},
|
|
128
|
+
start: E,
|
|
129
|
+
stop: D,
|
|
130
|
+
abort: O,
|
|
131
|
+
on: k,
|
|
132
|
+
off: A,
|
|
133
|
+
cleanup: () => {
|
|
134
|
+
D(), Object.keys(p).forEach((e) => A(e)), T.forEach(([e, t]) => f?.removeEventListener(e, t)), f = null;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
180
137
|
};
|
|
181
138
|
//#endregion
|
|
182
|
-
export {
|
|
139
|
+
export { p as createVocal, r as eventTypes, f as isSupported };
|
|
183
140
|
|
|
184
141
|
//# sourceMappingURL=index.es.js.map
|