@seams/voiceid 0.55.0 → 0.56.0
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/README.md
CHANGED
|
@@ -10,7 +10,7 @@ and the trusted host API. Existing voice enrollments keep their storage identity
|
|
|
10
10
|
Install matching Wallet and VoiceID versions, then import the descriptor:
|
|
11
11
|
|
|
12
12
|
```sh
|
|
13
|
-
pnpm add @seams/wallet@0.
|
|
13
|
+
pnpm add @seams/wallet@0.56.0 @seams/voiceid@0.56.0
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
```ts
|
|
@@ -78,4 +78,4 @@ import{a as e,i as t,t as n}from"./phrase-CArJ-DH1.js";import{i as r,l as i,n as
|
|
|
78
78
|
color: var(--seams-colors-textPrimary, #eff2f3);
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
-
`,nonce:h}),_.set(n,r)),r.ensureBase(),e.classList.add(`seams-voiceid-unlock`);let i=n.createElement(`div`);i.className=`seams-voiceid-unlock-header`,t.cancel.className=`seams-voiceid-unlock-back`,t.cancel.setAttribute(`aria-label`,`Back`),t.cancel.replaceChildren(),a(f(),t.cancel),i.append(t.cancel),e.prepend(i),this.footer=n.createElement(`div`),this.footer.className=`seams-voiceid-unlock-footer`,a([o(`span`,null,`Secured by`),` `,o(c,{})],this.footer),e.append(this.footer)}succeed(){let e=this.prompt.cancel;return e.animate([{opacity:1},{opacity:0}],{duration:150,easing:`ease-in`,fill:`forwards`}),{top:e.getBoundingClientRect().top,bottom:this.footer.getBoundingClientRect().top}}dispose(){a(null,this.prompt.cancel),a(null,this.footer)}};const y={activation:`Activate VoiceID`,unlock:`Unlock with VoiceID`,export:`Export keys with VoiceID`};var b=class{result;completion=new u;controller=new AbortController;element;activateButton;cancelButton;status;prompt;unlockFrame;autoStartUnlock;unlockSuccess;unmountCapture;measurement;phrase=t(null);state={kind:`preparing`};settlement=`closed`;expiryTimer=null;constructor(e,t,n,r,i){this.unlockSuccess=r;let a=y[t],o=document.getElementById(`root`)??document.body;if(!o)throw Error(`Wallet activation surface has no mount root.`);this.element=document.createElement(`section`),this.element.className=`seams-wallet-ui seams-auth-method-activation-surface seams-voiceid-activation-surface`,this.element.setAttribute(`role`,`dialog`),this.element.setAttribute(`aria-modal`,`true`),this.element.setAttribute(`aria-label`,a);let c=t===`unlock`&&r===`skip`&&i!==void 0;this.prompt=new s(document,a,this.phrase,c?`segments`:`ring`),this.element.append(this.prompt.element),this.unlockFrame=t===`unlock`&&!c?new v(this.element,this.prompt):null,this.autoStartUnlock=t===`unlock`&&i!==void 0,c&&(this.element.classList.add(`seams-voiceid-in-card`),this.prompt.cancel.hidden=!0),this.status=this.prompt.status,this.status.textContent=`Loading VoiceID…`,this.prompt.title.textContent=`VoiceID`,this.element.dataset.preparation=`loading`,this.activateButton=this.prompt.record,this.activateButton.textContent=a,this.activateButton.disabled=!0,this.activateButton.hidden=this.autoStartUnlock,this.activateButton.addEventListener(`click`,this.begin),this.cancelButton=this.prompt.cancel,this.cancelButton.addEventListener(`click`,this.cancel),this.element.addEventListener(`cancel`,this.cancel),this.unmountCapture=i?i(this.element):null,i||o.appendChild(this.element),this.measurement=!i&&n.kind===`wallet_iframe`?m({kind:`request_surface`,element:this.element,requestId:n.requestId,postMeasurement:n.postMeasurement}):null,this.cancelButton.focus(),this.result=this.completion.promise,this.initialize(e)}dispose(){this.measurement?.disconnect(),this.expiryTimer!==null&&clearTimeout(this.expiryTimer),this.element.removeEventListener(`cancel`,this.cancel),this.activateButton.removeEventListener(`click`,this.begin),this.cancelButton.removeEventListener(`click`,this.cancel),this.unlockFrame?.dispose(),this.prompt.dispose(),this.unmountCapture?this.unmountCapture(this.settlement):this.element.remove()}async initialize(e){try{await new Promise(C),this.controller.signal.throwIfAborted();let t=await e(this.controller.signal,{parent:this.element,progress:this.prompt.progress});if(this.state.kind===`closed`)return;if(t.kind===`management`){this.element.setAttribute(`aria-label`,`Manage voice`),this.element.dataset.preparation=`ready`,this.state={kind:`capturing`};let e=await t.action(this.controller.signal);this.controller.signal.throwIfAborted(),this.state={kind:`closed`},this.completion.resolve(e);return}let n=t.expiresAtMs===null?null:t.expiresAtMs-Date.now();if(n!==null&&n<=0)throw Error(`VoiceID challenge expired. Start unlock again.`);this.state={kind:`ready`,capture:t},this.expiryTimer=n===null?null:setTimeout(this.expire,n);for(let e of this.element.querySelectorAll(`.seams-voiceid-model-download`))e.remove();this.element.dataset.preparation=`ready`,this.prompt.title.textContent=`Read aloud`,this.status.textContent=`Read naturally, then pause.`,this.activateButton.disabled=!1,this.autoStartUnlock?this.begin():this.activateButton.focus()}catch(e){if(this.state.kind===`closed`)return;this.state={kind:`closed`},this.completion.reject(g(e))}}begin=()=>{if(this.state.kind!==`ready`)return;let e=this.state.capture;this.state={kind:`capturing`},this.perform(e)};async perform(a){this.activateButton.disabled=!0,this.status.textContent=`Opening microphone…`;try{let e=await a.action(this.controller.signal,this.prompt.capture,this.phrase);if(this.state.kind===`closed`)return;this.unlockFrame&&this.unlockSuccess===`show`&&await this.showUnlocked(this.unlockFrame),this.settlement=`succeeded`,this.state={kind:`closed`},this.completion.resolve(e)}catch(o){if(this.state.kind===`closed`)return;if(o instanceof r||o instanceof n||o instanceof i||o instanceof e){if(a.expiresAtMs!==null&&Date.now()>=a.expiresAtMs){this.expire();return}let e=this.phrase;this.phrase=t(e),this.prompt.setPhrase(this.phrase),this.state={kind:`ready`,capture:a},this.activateButton.hidden=!1,this.activateButton.textContent=`Try again`,this.prompt.ready(o.message),this.activateButton.focus();return}this.state={kind:`closed`},this.completion.reject(g(o))}}async showUnlocked(e){this.state={kind:`succeeding`},this.settlement=`succeeded`,this.expiryTimer!==null&&clearTimeout(this.expiryTimer),this.expiryTimer=null,this.cancelButton.disabled=!0;let t=performance.now(),n=d(`authenticated`);await this.prompt.succeed(n.headline,n.message,e.succeed());let r=Math.max(0,1300-(performance.now()-t));await this.element.animate([{opacity:1},{opacity:1,offset:r/(r+240),easing:`ease-in`},{opacity:0}],{duration:r+240,fill:`forwards`}).finished}cancel=()=>{this.state.kind===`closed`||this.state.kind===`succeeding`||(this.state={kind:`closed`},this.controller.abort(),this.completion.reject(new x))};expire=()=>{this.state.kind===`closed`||this.state.kind===`succeeding`||(this.state={kind:`closed`},this.controller.abort(),this.completion.reject(Error(`VoiceID challenge expired. Start unlock again.`)))}},x=class extends Error{constructor(){super(`VoiceID capture was cancelled.`),this.name=`VoiceIdCaptureCancelledError`}};async function S(e){let t=new b(e.prepare,e.purpose,e.measurement,e.unlockSuccess??`show`,e.mountCapture);try{return await t.result}finally{t.dispose()}}function C(e){requestAnimationFrame(w.bind(null,e))}function w(e){setTimeout(e,0)}const T=9;if(l!==9)throw Error(`VoiceID requires a matching Wallet host API.`);function E(e){return{unlock:A.bind(null,e),activate:M.bind(null,e),confirmOperation:O.bind(null,e),recordPhrase:D}}async function D(e){let t=await import(`./phrase-
|
|
81
|
+
`,nonce:h}),_.set(n,r)),r.ensureBase(),e.classList.add(`seams-voiceid-unlock`);let i=n.createElement(`div`);i.className=`seams-voiceid-unlock-header`,t.cancel.className=`seams-voiceid-unlock-back`,t.cancel.setAttribute(`aria-label`,`Back`),t.cancel.replaceChildren(),a(f(),t.cancel),i.append(t.cancel),e.prepend(i),this.footer=n.createElement(`div`),this.footer.className=`seams-voiceid-unlock-footer`,a([o(`span`,null,`Secured by`),` `,o(c,{})],this.footer),e.append(this.footer)}succeed(){let e=this.prompt.cancel;return e.animate([{opacity:1},{opacity:0}],{duration:150,easing:`ease-in`,fill:`forwards`}),{top:e.getBoundingClientRect().top,bottom:this.footer.getBoundingClientRect().top}}dispose(){a(null,this.prompt.cancel),a(null,this.footer)}};const y={activation:`Activate VoiceID`,unlock:`Unlock with VoiceID`,export:`Export keys with VoiceID`};var b=class{result;completion=new u;controller=new AbortController;element;activateButton;cancelButton;status;prompt;unlockFrame;autoStartUnlock;unlockSuccess;unmountCapture;measurement;phrase=t(null);state={kind:`preparing`};settlement=`closed`;expiryTimer=null;constructor(e,t,n,r,i){this.unlockSuccess=r;let a=y[t],o=document.getElementById(`root`)??document.body;if(!o)throw Error(`Wallet activation surface has no mount root.`);this.element=document.createElement(`section`),this.element.className=`seams-wallet-ui seams-auth-method-activation-surface seams-voiceid-activation-surface`,this.element.setAttribute(`role`,`dialog`),this.element.setAttribute(`aria-modal`,`true`),this.element.setAttribute(`aria-label`,a);let c=t===`unlock`&&r===`skip`&&i!==void 0;this.prompt=new s(document,a,this.phrase,c?`segments`:`ring`),this.element.append(this.prompt.element),this.unlockFrame=t===`unlock`&&!c?new v(this.element,this.prompt):null,this.autoStartUnlock=t===`unlock`&&i!==void 0,c&&(this.element.classList.add(`seams-voiceid-in-card`),this.prompt.cancel.hidden=!0),this.status=this.prompt.status,this.status.textContent=`Loading VoiceID…`,this.prompt.title.textContent=`VoiceID`,this.element.dataset.preparation=`loading`,this.activateButton=this.prompt.record,this.activateButton.textContent=a,this.activateButton.disabled=!0,this.activateButton.hidden=this.autoStartUnlock,this.activateButton.addEventListener(`click`,this.begin),this.cancelButton=this.prompt.cancel,this.cancelButton.addEventListener(`click`,this.cancel),this.element.addEventListener(`cancel`,this.cancel),this.unmountCapture=i?i(this.element):null,i||o.appendChild(this.element),this.measurement=!i&&n.kind===`wallet_iframe`?m({kind:`request_surface`,element:this.element,requestId:n.requestId,postMeasurement:n.postMeasurement}):null,this.cancelButton.focus(),this.result=this.completion.promise,this.initialize(e)}dispose(){this.measurement?.disconnect(),this.expiryTimer!==null&&clearTimeout(this.expiryTimer),this.element.removeEventListener(`cancel`,this.cancel),this.activateButton.removeEventListener(`click`,this.begin),this.cancelButton.removeEventListener(`click`,this.cancel),this.unlockFrame?.dispose(),this.prompt.dispose(),this.unmountCapture?this.unmountCapture(this.settlement):this.element.remove()}async initialize(e){try{await new Promise(C),this.controller.signal.throwIfAborted();let t=await e(this.controller.signal,{parent:this.element,progress:this.prompt.progress});if(this.state.kind===`closed`)return;if(t.kind===`management`){this.element.setAttribute(`aria-label`,`Manage voice`),this.element.dataset.preparation=`ready`,this.state={kind:`capturing`};let e=await t.action(this.controller.signal);this.controller.signal.throwIfAborted(),this.state={kind:`closed`},this.completion.resolve(e);return}let n=t.expiresAtMs===null?null:t.expiresAtMs-Date.now();if(n!==null&&n<=0)throw Error(`VoiceID challenge expired. Start unlock again.`);this.state={kind:`ready`,capture:t},this.expiryTimer=n===null?null:setTimeout(this.expire,n);for(let e of this.element.querySelectorAll(`.seams-voiceid-model-download`))e.remove();this.element.dataset.preparation=`ready`,this.prompt.title.textContent=`Read aloud`,this.status.textContent=`Read naturally, then pause.`,this.activateButton.disabled=!1,this.autoStartUnlock?this.begin():this.activateButton.focus()}catch(e){if(this.state.kind===`closed`)return;this.state={kind:`closed`},this.completion.reject(g(e))}}begin=()=>{if(this.state.kind!==`ready`)return;let e=this.state.capture;this.state={kind:`capturing`},this.perform(e)};async perform(a){this.activateButton.disabled=!0,this.status.textContent=`Opening microphone…`;try{let e=await a.action(this.controller.signal,this.prompt.capture,this.phrase);if(this.state.kind===`closed`)return;this.unlockFrame&&this.unlockSuccess===`show`&&await this.showUnlocked(this.unlockFrame),this.settlement=`succeeded`,this.state={kind:`closed`},this.completion.resolve(e)}catch(o){if(this.state.kind===`closed`)return;if(o instanceof r||o instanceof n||o instanceof i||o instanceof e){if(a.expiresAtMs!==null&&Date.now()>=a.expiresAtMs){this.expire();return}let e=this.phrase;this.phrase=t(e),this.prompt.setPhrase(this.phrase),this.state={kind:`ready`,capture:a},this.activateButton.hidden=!1,this.activateButton.textContent=`Try again`,this.prompt.ready(o.message),this.activateButton.focus();return}this.state={kind:`closed`},this.completion.reject(g(o))}}async showUnlocked(e){this.state={kind:`succeeding`},this.settlement=`succeeded`,this.expiryTimer!==null&&clearTimeout(this.expiryTimer),this.expiryTimer=null,this.cancelButton.disabled=!0;let t=performance.now(),n=d(`authenticated`);await this.prompt.succeed(n.headline,n.message,e.succeed());let r=Math.max(0,1300-(performance.now()-t));await this.element.animate([{opacity:1},{opacity:1,offset:r/(r+240),easing:`ease-in`},{opacity:0}],{duration:r+240,fill:`forwards`}).finished}cancel=()=>{this.state.kind===`closed`||this.state.kind===`succeeding`||(this.state={kind:`closed`},this.controller.abort(),this.completion.reject(new x))};expire=()=>{this.state.kind===`closed`||this.state.kind===`succeeding`||(this.state={kind:`closed`},this.controller.abort(),this.completion.reject(Error(`VoiceID challenge expired. Start unlock again.`)))}},x=class extends Error{constructor(){super(`VoiceID capture was cancelled.`),this.name=`VoiceIdCaptureCancelledError`}};async function S(e){let t=new b(e.prepare,e.purpose,e.measurement,e.unlockSuccess??`show`,e.mountCapture);try{return await t.result}finally{t.dispose()}}function C(e){requestAnimationFrame(w.bind(null,e))}function w(e){setTimeout(e,0)}const T=9;if(l!==9)throw Error(`VoiceID requires a matching Wallet host API.`);function E(e){return{unlock:A.bind(null,e),activate:M.bind(null,e),confirmOperation:O.bind(null,e),recordPhrase:D}}async function D(e){let t=await import(`./phrase-BumWInpD.js`);return e.signal.throwIfAborted(),await t.recordPhrase(e)}function O(e,t){return S({purpose:`export`,measurement:t.surfaceMeasurementBinding,prepare:k.bind(null,e,t)})}async function k(e,t,n,r){let i=await import(`./operation-CObNRH_J.js`);return n.throwIfAborted(),i.prepareOperationSurface(t,n,r.progress,e)}function A(e,t){return S({purpose:`unlock`,unlockSuccess:t.purpose===`step_up`?`skip`:`show`,measurement:t.surfaceMeasurementBinding,mountCapture:t.mountCapture,prepare:j.bind(null,e,t)})}async function j(e,t,n,r){let i=await import(`./unlock-CPiLZCsY.js`);return n.throwIfAborted(),i.prepareUnlockSurface(t,n,r.progress,e)}async function M(e,t){try{return await S({purpose:`activation`,measurement:t.surfaceMeasurementBinding,prepare:N.bind(null,e,t)})}catch(e){if(e instanceof x)return{kind:`cancelled`};throw e}}async function N(e,t,n,r){let i=await import(`./addVoiceId-BzirvbVh.js`);return n.throwIfAborted(),i.prepareActivationSurface(t,n,r.parent,e)}export{E as createVoiceIdHostPlugin,T as hostApiVersion};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,c as t,l as n,p as r,t as i}from"./prompt-BPtSdsWi.js";import{WorkerDeferred as a,createWalletIframeSurfaceMeasurementReporter as o,toError as s}from"../voiceid-host.js";const c=`Say this with your voice`;async function l(e){let t=new u(e.sentence,e.surfaceMeasurementBinding,e.signal);try{return await t.result}finally{t.dispose()}}var u=class{completion=new a;result=this.completion.promise;controller=new AbortController;element;prompt;measurement;recording=!1;settled=!1;constructor(e,t,n){this.outer=n;let a=document.getElementById(`root`)??document.body;this.element=document.createElement(`section`),this.element.className=`seams-wallet-ui seams-auth-method-activation-surface seams-voiceid-activation-surface`,this.element.setAttribute(`role`,`dialog`),this.element.setAttribute(`aria-modal`,`true`),this.element.setAttribute(`aria-label`,c),this.prompt=new i(document,c,r[0]),this.prompt.title.textContent=`Say this sentence`,this.prompt.phrase.textContent=/[.!?]$/.test(e)?e:`${e}.`,delete this.prompt.phrase.dataset.voiceidPhrase,this.prompt.status.textContent=`Read it naturally, then pause.`,this.prompt.record.textContent=`Record`,this.element.append(this.prompt.element),this.prompt.record.addEventListener(`click`,this.record),this.prompt.cancel.addEventListener(`click`,this.cancel),this.element.addEventListener(`cancel`,this.cancel),n.addEventListener(`abort`,this.cancel),a.appendChild(this.element),this.measurement=t.kind===`wallet_iframe`?o({kind:`request_surface`,element:this.element,requestId:t.requestId,postMeasurement:t.postMeasurement}):null,this.prompt.record.focus(),n.aborted&&this.cancel()}dispose(){this.controller.abort(),this.measurement?.disconnect(),this.outer.removeEventListener(`abort`,this.cancel),this.element.removeEventListener(`cancel`,this.cancel),this.prompt.record.removeEventListener(`click`,this.record),this.prompt.cancel.removeEventListener(`click`,this.cancel),this.prompt.dispose(),this.element.remove()}record=()=>{this.recording||this.settled||(this.recording=!0,this.prompt.record.disabled=!0,this.prompt.status.textContent=`Opening microphone…`,this.attempt())};async attempt(){try{let n=await e(this.controller.signal,this.prompt.capture),r=performance.now();if(this.settled){n.samples?.fill(0);return}if(n.kind===`insufficient_audio`){this.retry(t(n.quality));return}this.settle({kind:`recorded`,samples:n.samples,endOfSpeechAt:r})}catch(e){if(this.settled)return;if(e instanceof n){this.retry(e.message);return}this.settled=!0,this.completion.reject(s(e))}}retry(e){this.recording=!1,this.prompt.record.textContent=`Try again`,this.prompt.ready(e),this.prompt.record.focus()}settle(e){this.settled||(this.settled=!0,this.completion.resolve(e))}cancel=()=>{this.controller.abort(),this.settle({kind:`cancelled`})}};export{l as recordPhrase};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seams/voiceid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.56.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Optional browser VoiceID authentication for Seams Wallet",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"voice-glow": "0.2.1"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
|
-
"@seams/wallet": "0.
|
|
53
|
+
"@seams/wallet": "0.56.0",
|
|
54
54
|
"react": ">=19.0.0",
|
|
55
55
|
"react-dom": ">=19.0.0"
|
|
56
56
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e,c as t,l as n,p as r,t as i}from"./prompt-BPtSdsWi.js";import{WorkerDeferred as a,createWalletIframeSurfaceMeasurementReporter as o,toError as s}from"../voiceid-host.js";const c=`Say this with your voice`;async function l(e){let t=new u(e.sentence,e.surfaceMeasurementBinding,e.signal);try{return await t.result}finally{t.dispose()}}var u=class{completion=new a;result=this.completion.promise;controller=new AbortController;element;prompt;measurement;recording=!1;settled=!1;constructor(e,t,n){this.outer=n;let a=document.getElementById(`root`)??document.body;this.element=document.createElement(`section`),this.element.className=`seams-wallet-ui seams-auth-method-activation-surface seams-voiceid-activation-surface`,this.element.setAttribute(`role`,`dialog`),this.element.setAttribute(`aria-modal`,`true`),this.element.setAttribute(`aria-label`,c),this.prompt=new i(document,c,r[0]),this.prompt.title.textContent=`Say this sentence`,this.prompt.phrase.textContent=`${e}.`,delete this.prompt.phrase.dataset.voiceidPhrase,this.prompt.status.textContent=`Read it naturally, then pause.`,this.prompt.record.textContent=`Record`,this.element.append(this.prompt.element),this.prompt.record.addEventListener(`click`,this.record),this.prompt.cancel.addEventListener(`click`,this.cancel),this.element.addEventListener(`cancel`,this.cancel),n.addEventListener(`abort`,this.cancel),a.appendChild(this.element),this.measurement=t.kind===`wallet_iframe`?o({kind:`request_surface`,element:this.element,requestId:t.requestId,postMeasurement:t.postMeasurement}):null,this.prompt.record.focus(),n.aborted&&this.cancel()}dispose(){this.controller.abort(),this.measurement?.disconnect(),this.outer.removeEventListener(`abort`,this.cancel),this.element.removeEventListener(`cancel`,this.cancel),this.prompt.record.removeEventListener(`click`,this.record),this.prompt.cancel.removeEventListener(`click`,this.cancel),this.prompt.dispose(),this.element.remove()}record=()=>{this.recording||this.settled||(this.recording=!0,this.prompt.record.disabled=!0,this.prompt.status.textContent=`Opening microphone…`,this.attempt())};async attempt(){try{let n=await e(this.controller.signal,this.prompt.capture),r=performance.now();if(this.settled){n.samples?.fill(0);return}if(n.kind===`insufficient_audio`){this.retry(t(n.quality));return}this.settle({kind:`recorded`,samples:n.samples,endOfSpeechAt:r})}catch(e){if(this.settled)return;if(e instanceof n){this.retry(e.message);return}this.settled=!0,this.completion.reject(s(e))}}retry(e){this.recording=!1,this.prompt.record.textContent=`Try again`,this.prompt.ready(e),this.prompt.record.focus()}settle(e){this.settled||(this.settled=!0,this.completion.resolve(e))}cancel=()=>{this.controller.abort(),this.settle({kind:`cancelled`})}};export{l as recordPhrase};
|