@seams/voiceid 0.27.0 → 0.29.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 +23 -3
- package/dist/esm/descriptor.js +5 -2
- package/dist/public/sdk/voiceid/CITRINET_LICENSE.txt +395 -0
- package/dist/public/sdk/voiceid/NOTICE.txt +19 -2
- package/dist/public/sdk/voiceid/addVoiceId-Dbd-PwWG.js +1 -0
- package/dist/public/sdk/voiceid/approval-C4KlEQYu.js +1 -0
- package/dist/public/sdk/voiceid/citrinet-int8.onnx +0 -0
- package/dist/public/sdk/voiceid/{deviceBridge-L6ZKqifG.js → deviceBridge-DQLPNdC8.js} +1 -1
- package/dist/public/sdk/voiceid/enrollment-DPOYb36Z.js +1 -0
- package/dist/public/sdk/voiceid/host.js +2 -2
- package/dist/public/sdk/voiceid/prompt-vztg41jG.js +614 -0
- package/dist/public/sdk/voiceid/unlock-Da49yYxd.js +1 -0
- package/dist/types/activation/addVoiceId.d.ts +2 -1
- package/dist/types/activation/manageEnrollment.d.ts +2 -1
- package/dist/types/browser/enrollment.d.ts +3 -2
- package/dist/types/browser/model.d.ts +1 -1
- package/dist/types/browser/phrase.d.ts +5 -2
- package/dist/types/browser/phraseTokens.d.ts +2 -0
- package/dist/types/browser/phraseVocabulary.d.ts +3 -3
- package/dist/types/browser/progress.d.ts +2 -1
- package/dist/types/capture/approval.d.ts +4 -2
- package/dist/types/capture/bridge.d.ts +2 -1
- package/dist/types/capture/deviceBridge.d.ts +7 -4
- package/dist/types/descriptor.d.ts +5 -2
- package/dist/types/host.d.ts +3 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/session/activation.d.ts +2 -2
- package/dist/types/session/unlock.d.ts +2 -1
- package/dist/types/session/unlockFromDevice.d.ts +2 -2
- package/package.json +2 -2
- package/src/README.md +26 -16
- package/dist/public/sdk/voiceid/addVoiceId-DOpYRrar.js +0 -1
- package/dist/public/sdk/voiceid/approval-DNlI4I0d.js +0 -1
- package/dist/public/sdk/voiceid/enrollment-Cs7Tzcho.js +0 -1
- package/dist/public/sdk/voiceid/prompt-g_wE9gYv.js +0 -614
- package/dist/public/sdk/voiceid/unlock-B9WYZcqy.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{_ as e,a as t,c as n,d as r,f as i,g as a,h as o,p as s,s as c,t as l,u,v as d}from"./prompt-vztg41jG.js";import{IndexedDBManager as f,SEAMS_WALLET_STORES as p,WorkerDeferred as m,availabilityKey as h,base64UrlDecode as g,base64UrlEncode as ee,buildDelegatedWalletAuthorityV1 as _,buildFullOwnerPermissionsV1 as v,isFiniteNumber as y,isPlainObject as b,parseStoredAuthMethodAvailability as x,parseVoiceIdDevicePublicKeyB64u as S,parseWalletAuthMethodV2StorageRow as C,parseWalletAuthorityStorageRow as te,parseWalletSelectionStorageRow as ne,requireRecord as w,sameDelegatedWalletAuthorityV1 as T,sha256DigestB64u as E,toError as D}from"../voiceid-host.js";const O=`e04dd7a6a1e23fc7b89e47682ea9d0a3946cf7bc59d07922c3db3efc52ae4269`,k=`redimnet-b1:${O}`,A=new a({path:`/sdk/voiceid/redimnet-b1.onnx`,sha256:O,bytes:8859593,label:`Speaker verification`});async function j(e){let t=await A.prepare(),n=new(await(import(`./ort.wasm.bundle.min-7y-hlRN8.js`))).Tensor(`float32`,e,[1,e.length]);try{let e=await t.run({samples:n});try{let t=e.embedding;if(!t||!(t.data instanceof Float32Array))throw Error(`VoiceID model returned an invalid embedding.`);return M(Array.from(t.data))}finally{for(let t of Object.values(e))t.dispose()}}finally{n.dispose()}}function M(e){if(e.length!==192)throw Error(`VoiceID template dimensions are invalid.`);let t=0;for(let n of e){if(!Number.isFinite(n))throw Error(`VoiceID template is invalid.`);t+=n*n}if(t<1e-12)throw Error(`VoiceID template contains no signal.`);let n=Math.sqrt(t),r=[];for(let t of e)r.push(t/n);return r}function N(e,t){if(e.length!==192||t.length!==192)throw Error(`VoiceID templates are incompatible.`);let n=0;for(let r=0;r<e.length;r+=1)n+=e[r]*t[r];return n}function re(e){return e.asset}function ie(e,t){return e+t.size}var ae=class{element=document.createElement(`section`);status=document.createElement(`p`);meter=document.createElement(`progress`);retryButton=document.createElement(`button`);retry=null;cancelled=new m;reveal;received=new Map;models;assets;total;constructor(e,t,n){this.parent=e,this.signal=t,this.models=[A,s(n),u],this.assets=[d,...this.models.map(re)],this.total=this.assets.reduce(ie,0),this.element.className=`seams-voiceid-model-download`,this.status.setAttribute(`role`,`status`),this.status.setAttribute(`aria-live`,`polite`),this.meter.setAttribute(`aria-label`,`VoiceID download`),this.meter.style.width=`100%`,this.retryButton.type=`button`,this.retryButton.className=`seams-voiceid-primary`,this.retryButton.textContent=`Retry loading`,this.retryButton.hidden=!0,this.retryButton.addEventListener(`click`,this.retryLoading),this.element.append(this.status,this.meter,this.retryButton),this.status.textContent=`Loading saved VoiceID…`,this.reveal=setTimeout(e.append.bind(e,this.element),300),t.addEventListener(`abort`,this.abort,{once:!0})}settle=()=>{clearTimeout(this.reveal),this.signal.removeEventListener(`abort`,this.abort),this.retryButton.removeEventListener(`click`,this.retryLoading)};abort=()=>{let e=new DOMException(`VoiceID preparation was cancelled.`,`AbortError`);this.cancelled.reject(e),this.retry?.reject(e)};retryLoading=()=>{this.retry?.resolve(),this.retry=null};async prepare(){this.signal.throwIfAborted(),await Promise.race([this.prepareUntilReady(),this.cancelled.promise])}async prepareUntilReady(){for(;;){this.signal.throwIfAborted(),this.retryButton.hidden=!0,this.meter.hidden=!1;try{for(let e of this.assets)await e.download(this.update.bind(this,e)),this.signal.throwIfAborted();this.preparing();for(let e of this.models)await e.prepare(),this.signal.throwIfAborted();this.ready();return}catch(t){if(this.signal.throwIfAborted(),!(t instanceof e))throw t;clearTimeout(this.reveal),this.parent.append(this.element),this.element.dataset.state=`failed`,this.meter.hidden=!0,this.status.textContent=t.message,this.retry=new m,this.retryButton.hidden=!1,this.retryButton.focus(),await this.retry.promise}}}update=(e,t)=>{switch(t.kind){case`checking_cache`:return;case`downloading`:this.received.set(e,t.received),this.element.dataset.state=`downloading`;break;case`ready`:this.received.set(e,e.size);break;default:}if(this.element.dataset.state!==`downloading`)return;let n=0;for(let e of this.received.values())n+=e;this.meter.max=this.total,this.meter.value=n,this.status.textContent=`Downloading VoiceID: ${(n/1e6).toFixed(1)} of ${(this.total/1e6).toFixed(1)} MB · ${Math.floor(n/this.total*100)}%`};preparing(){this.element.dataset.state=`preparing`,this.meter.removeAttribute(`value`),this.status.textContent=`Preparing VoiceID…`}ready(){this.element.dataset.state=`ready`,this.meter.hidden=!0,this.status.textContent=`VoiceID is ready.`}};async function P(e,t,n){let r=new ae(e,t,n);try{await r.prepare()}finally{r.settle()}}function F(e,t){return`voiceid-browser-device-v1:${encodeURIComponent(e)}:${encodeURIComponent(t)}`}function I(e,t,n){return new TextEncoder().encode(JSON.stringify([`seams-voiceid-browser-factor-v1`,location.origin,e,t,n]))}async function L(e,t){let n=await f.getAppState(F(e,t));if(n===void 0)return null;let r=w(n,`VoiceID device record`);if(r.kind!==`browser_voiceid_device_v1`||r.walletId!==e||r.walletAuthMethodId!==t)throw Error(`VoiceID device belongs to another wallet method.`);let{privateKey:i,wrappingKey:a,nonce:o,ciphertext:s}=r;if(!(i instanceof CryptoKey)||i.type!==`private`||i.extractable||i.algorithm.name!==`Ed25519`||!i.usages.includes(`sign`)||!(a instanceof CryptoKey)||a.type!==`secret`||a.extractable||a.algorithm.name!==`AES-GCM`||!a.usages.includes(`decrypt`)||!(o instanceof Uint8Array)||o.length!==12||!(s instanceof ArrayBuffer)||s.byteLength!==48)throw Error(`VoiceID device storage is invalid.`);let c=S(r.publicKeyB64u),l=await E(g(c));if(r.deviceKeyId!==l)throw Error(`VoiceID device key binding is invalid.`);return{kind:`browser_voiceid_device_v1`,walletId:e,walletAuthMethodId:t,privateKey:i,wrappingKey:a,nonce:new Uint8Array(o),ciphertext:s,publicKeyB64u:c,deviceKeyId:l}}async function oe(e,t){return await navigator.locks.request(F(e,t),se.bind(null,e,t))}async function se(e,t){let n=await L(e,t);if(n)return n;let r=await crypto.subtle.generateKey({name:`Ed25519`},!1,[`sign`,`verify`]),i=S(ee(new Uint8Array(await crypto.subtle.exportKey(`raw`,r.publicKey)))),a=await E(g(i)),o=await crypto.subtle.generateKey({name:`AES-GCM`,length:256},!1,[`encrypt`,`decrypt`]),s=crypto.getRandomValues(new Uint8Array(32)),c=crypto.getRandomValues(new Uint8Array(12));try{let n=await crypto.subtle.encrypt({name:`AES-GCM`,iv:c,additionalData:I(e,t,a)},o,s),l={kind:`browser_voiceid_device_v1`,walletId:e,walletAuthMethodId:t,privateKey:r.privateKey,publicKeyB64u:i,deviceKeyId:a,wrappingKey:o,nonce:c,ciphertext:n};return await f.setAppState(F(e,t),l),l}finally{s.fill(0)}}async function ce(e){let t=await crypto.subtle.decrypt({name:`AES-GCM`,iv:e.nonce,additionalData:I(e.walletId,e.walletAuthMethodId,e.deviceKeyId)},e.wrappingKey,e.ciphertext);return new Uint8Array(t)}const R=`voiceid-browser-enrollment-v1`,z=.2,B=[p.appState,p.walletSelections,p.walletAuthMethods,p.walletAuthorities];function V(e,t){return{walletId:e.walletId,walletAuthMethodId:e.walletAuthMethodId,deviceKeyId:e.deviceKeyId,authorityId:t}}async function H(e,t){let n=await f.getWalletAuthMethodV2(t),r=await L(e,t);if(!n||n.kind!==`voiceid`||n.status!==`active`||n.walletId!==e||!r||n.deviceKeyId!==r.deviceKeyId)throw Error(`VoiceID is unavailable for this wallet method.`);return V(r,n.walletAuthorityId)}function U(e){return`voiceid-browser-enrollment-v2:${[e.walletId,e.authorityId,e.walletAuthMethodId,e.deviceKeyId].map(encodeURIComponent).join(`:`)}`}function W(e){if(!Array.isArray(e)||!e.every(y))throw Error(`VoiceID template is invalid.`);let t=M(e);for(let n=0;n<e.length;n+=1)if(Math.abs(e[n]-t[n])>1e-6)throw Error(`VoiceID template is not normalized.`);return e.slice()}function G(e,t){if(e===void 0)return null;let n=w(e,`VoiceID enrollment`),r=w(n.scope,`VoiceID enrollment scope`);if(n.kind!==`browser_voiceid_enrollment_v2`||r.walletId!==t.walletId||r.authorityId!==t.authorityId||r.walletAuthMethodId!==t.walletAuthMethodId||r.deviceKeyId!==t.deviceKeyId||typeof n.generation!=`string`||!n.generation||typeof n.revision!=`number`||!Number.isSafeInteger(n.revision)||n.revision<0)throw Error(`VoiceID enrollment identity is invalid.`);if(n.model!==k)return null;let i=W(n.baseline),a={kind:`baseline`};try{let e=w(n.adaptation,`VoiceID improvements`);if(e.kind===`adapted`&&Array.isArray(e.samples)&&e.samples.length===3){let t=e.samples.map(W);q(i,t),a={kind:`adapted`,samples:t}}}catch{a={kind:`baseline`}}return{kind:`browser_voiceid_enrollment_v2`,scope:t,model:k,generation:n.generation,revision:n.revision,baseline:i,adaptation:a}}function K(e,t){let n=Array(192).fill(0);for(let e of t)for(let r=0;r<n.length;r+=1)n[r]+=e[r]/t.length;let r=M(n);for(let t=0;t<n.length;t+=1)n[t]=(1-z)*e[t]+z*r[t];return M(n)}function q(e,t){if(t.length!==3)throw Error(`Record three samples before saving voice improvements.`);for(let n of t)if(N(e,n)<.45)throw Error(`This sample differs from your original voice. Try again or re-record your enrollment.`);if(N(e,K(e,t))<.98)throw Error(`These samples differ too much from your original voice. Re-record your enrollment instead.`)}async function le(e){let t=(await f.seamsWalletDB.getDB()).transaction(p.appState,`readwrite`);try{let n=await t.store.get(U(e)),r=G(n?.value,e);return r&&JSON.stringify(n?.value?.adaptation)!==JSON.stringify(r.adaptation)&&(r=Z(r,r.adaptation),await t.store.put({key:U(e),value:r})),await t.done,r}catch(e){try{t.abort()}catch{}throw await t.done.catch(X),e}}async function ue(){let e=await f.getAppState(R);if(e===void 0)return null;let t=w(e,`Previous VoiceID enrollment`);return t.kind!==`browser_voiceid_enrollment_v1`||t.model!==k?null:W(t.template)}async function J(e,t,n){let r=ne(await e.objectStore(p.walletSelections).get(t.walletId)),i=te(await e.objectStore(p.walletAuthorities).get(t.authorityId)),a=await e.objectStore(p.walletAuthMethods).get(t.walletAuthMethodId),o=C(a);if(a!==void 0&&!o)throw Error(`VoiceID method storage is invalid.`);if(!i||i.record.state!==`active`||i.record.walletId!==t.walletId)throw Error(`VoiceID authority changed. Start again.`);if(o&&(o.record.kind!==`voiceid`||o.record.status!==`active`||o.record.walletId!==t.walletId||o.record.walletAuthorityId!==t.authorityId||o.record.deviceKeyId!==t.deviceKeyId)||(n===null||n.target===`enrolled`)&&!o)throw Error(`VoiceID method is unavailable.`);if((await e.objectStore(p.appState).get(F(t.walletId,t.walletAuthMethodId)))?.value?.deviceKeyId!==t.deviceKeyId)throw Error(`VoiceID device changed. Start again.`);let s=x((await e.objectStore(p.appState).get(h(t.walletId,t.walletAuthMethodId)))?.value);if(!s.enabled)throw Error(`VoiceID is turned off.`);if(n){if(!T(_({permissions:i.record.permissions}),_({permissions:v()})))throw Error(`Full owner authority is required to change VoiceID enrollment.`);let a=C(await e.objectStore(p.walletAuthMethods).get(n.sessionMethodId));if(n.expiresAtMs<=Date.now()||s.revision!==n.availabilityRevision||!r||r.record.lockState!==`unlocked`||r.record.lockGeneration!==n.lockGeneration||r.record.walletAuthMethodId!==n.sessionMethodId||!a||a.record.status!==`active`||n.target===`activating`&&a.record.kind===`voiceid`||a.record.walletId!==t.walletId||a.record.walletAuthorityId!==t.authorityId)throw Error(`The owner session changed or expired. Start again.`);if(n.target===`enrolled`){let r=C(await e.objectStore(p.walletAuthMethods).get(n.confirmationMethodId));if(!r||r.record.kind!==`passkey`||r.record.status!==`active`||r.record.walletId!==t.walletId||r.record.walletAuthorityId!==t.authorityId)throw Error(`The confirming passkey changed or was removed. Start again.`)}}}async function Y(e,t){let n=(await f.seamsWalletDB.getDB()).transaction(B,`readwrite`);try{await J(n,e,t),await n.done}catch(e){throw $(n),await n.done.catch(X),e}}function X(){}async function de(e,t){let n=e.scope,r=e.kind===`activation`?e.owner:null;if(r&&r.target!==`activating`)throw Error(`VoiceID activation requires its owner scope.`);let i=(await f.seamsWalletDB.getDB()).transaction(B,`readwrite`);try{await J(i,n,r);let e=i.objectStore(p.appState),a=await e.get(U(n)),o=G(a?.value,n);if(!o)throw Error(`Unlock with a passkey, then open Manage voice to import or record your enrollment.`);t.throwIfAborted();let s=o.adaptation,c=s.kind===`adapted`?K(o.baseline,s.samples):[...o.baseline];return JSON.stringify(a?.value?.adaptation)!==JSON.stringify(s)&&await e.put({key:U(n),value:Z(o,s)}),await i.done,t.throwIfAborted(),{template:c,baseline:[...o.baseline],kind:s.kind}}catch(e){try{i.abort()}catch{}throw await i.done.catch(X),e}}function Z(e,t){return{kind:`browser_voiceid_enrollment_v2`,scope:e.scope,model:e.model,generation:e.generation,revision:e.revision+1,baseline:e.baseline,adaptation:t}}async function Q(e,t,n,r,i){let a;if(r.kind===`activate`){if(t.target!==`activating`||n.kind!==`missing`)throw Error(`VoiceID activation cannot replace an enrollment.`)}else{if(t.target!==`enrolled`)throw Error(`VoiceID changes require a confirmation guard.`);await r.confirmation.consume(e,t,n,r.kind,i)}if(r.kind===`import`&&(t.target!==`enrolled`||n.kind!==`missing`))throw Error(`Import requires an existing method without a scoped enrollment.`);if(r.kind===`replace`||r.kind===`activate`||r.kind===`import`)a={kind:`browser_voiceid_enrollment_v2`,scope:e,model:k,generation:crypto.randomUUID(),revision:0,baseline:W(r.baseline),adaptation:{kind:`baseline`}};else{if(n.kind!==`present`)throw Error(`Record or import your original voice first.`);r.kind===`improve`?(q(n.enrollment.baseline,r.samples),a=Z(n.enrollment,{kind:`adapted`,samples:r.samples})):a=Z(n.enrollment,{kind:`baseline`})}if(new TextEncoder().encode(JSON.stringify(a)).length>32768)throw Error(`VoiceID enrollment exceeds its storage limit.`);let o=await f.seamsWalletDB.getDB();i.throwIfAborted();let s=o.transaction(B,`readwrite`),c=$.bind(null,s);i.addEventListener(`abort`,c,{once:!0});try{await J(s,e,t);let o=s.objectStore(p.appState),c=G((await o.get(U(e)))?.value,e);if(n.kind===`missing`?c!==null:!c||c.generation!==n.enrollment.generation||c.revision!==n.enrollment.revision)throw Error(`VoiceID enrollment changed in another operation. Start again.`);i.throwIfAborted(),await o.put({key:U(e),value:a}),r.kind===`import`&&await fe(s),await s.done}catch(e){throw c(),await s.done.catch(X),e}finally{i.removeEventListener(`abort`,c)}}function $(e){try{e.abort()}catch{}}async function fe(e){let t=e.objectStore(p.appState),n=await e.objectStore(p.walletAuthMethods).getAll();for(let e of n){if(!b(e)||e.kind!==`voiceid`)continue;let n=C(e);if(!n)return;let r=n.record;if(r.kind!==`voiceid`||r.status!==`active`)continue;let i={walletId:r.walletId,authorityId:r.walletAuthorityId,walletAuthMethodId:r.walletAuthMethodId,deviceKeyId:r.deviceKeyId};try{if(!G((await t.get(U(i)))?.value,i))return}catch{return}}await t.delete(R)}async function pe(e,t,n){let r=document.querySelector(`.seams-voiceid-activation-surface`);if(!(r instanceof HTMLElement))throw Error(`Open VoiceID activation in the Wallet.`);await P(r,t,n),t.throwIfAborted();let i=new me(r,e,t,n);try{await i.result}finally{i.dispose()}}var me=class{completion=new m;result=this.completion.promise;status;prompt;phrase=o(null);record;cancel;samples=[];phase=`ready`;get closed(){return this.phase===`closed`}controller=new AbortController;guardTimer;checkingGuard=!1;constructor(e,t,n,r){this.plan=t,this.signal=n,this.model=r,this.prompt=new l(document,`Enroll your voice in this browser`,this.phrase),this.prompt.title.textContent=`Read aloud · 0 of 3 accepted`,this.status=this.prompt.status,this.record=this.prompt.record,this.cancel=this.prompt.cancel,this.record.textContent=`Record sample 1`,this.record.addEventListener(`click`,this.capture),this.cancel.setAttribute(`aria-label`,`Cancel enrollment`),this.cancel.addEventListener(`click`,this.cancelled),this.prompt.ready(t.kind===`improve`?`Read naturally. Your original enrollment stays unchanged.`:`Read the full phrase at your normal pace.`),e.replaceChildren(this.prompt.element),n.addEventListener(`abort`,this.cancelled,{once:!0}),this.guardTimer=setInterval(this.checkGuard,250),n.aborted?this.cancelled():this.record.focus()}capture=()=>{this.collect()};async collect(){if(this.phase!==`ready`)return;let e=this.samples.length+1;try{c(),this.phase=`recording`,this.record.disabled=!0,this.status.textContent=`Opening microphone…`;let e=await t(this.controller.signal,this.prompt.capture);if(this.signal.aborted||this.closed){e.kind===`captured`&&e.samples.fill(0);return}if(e.kind===`insufficient_audio`){this.status.textContent=n(e.quality);return}if(this.plan.kind===`improve`&&e.quality.noise!==`normal`){e.samples.fill(0),this.status.textContent=`Use a quiet place to improve your voice enrollment.`;return}let a;try{if(await Y(this.plan.scope,this.plan.guard),this.status.textContent=`Checking your voice…`,(await i(e.samples,this.phrase,this.model)).kind===`mismatch`)throw new r;a=await j(e.samples)}finally{e.samples.fill(0)}if(this.signal.aborted||this.closed){a.fill(0);return}if(this.plan.kind===`improve`&&N(this.plan.snapshot.enrollment.baseline,a)<.45)throw a.fill(0),Error(`Your voice did not match the original enrollment. To replace it, return to Manage voice and choose Record voice again.`);let o=1;for(let e of this.samples)o=Math.min(o,N(e,a));this.status.dataset.voiceCapture=JSON.stringify({attemptId:e.quality.attemptId,capturedAtMs:e.quality.capturedAtMs,sample:this.samples.length+1,durationMs:e.quality.durationMs,recordingMs:e.quality.recordingMs,endedBy:e.quality.endedBy,voicedMs:e.quality.voicedMs,microphone:e.quality.microphone,microphoneSelection:e.quality.microphoneSelection,processing:e.quality.processing,backgroundRms:e.quality.backgroundRms,speechToBackgroundDb:e.quality.speechToBackgroundDb,noise:e.quality.noise,minimumSimilarity:o});for(let e of this.samples)if(N(e,a)<.45)throw a.fill(0),Error(`This sample differs from the earlier samples. Use the same microphone and try again.`);if(this.samples.push(a),this.samples.length<3){this.prompt.accepted(),this.status.textContent=`Sample ${this.samples.length} accepted. Record the next sample.`,this.record.textContent=`Record sample ${this.samples.length+1}`;return}let s=Array(192).fill(0);for(let e of this.samples)for(let t=0;t<s.length;t+=1)s[t]+=e[t]/3;this.phase=`committing`,this.prompt.title.textContent=`3 of 3 accepted`,this.status.textContent=`Saving voice enrollment…`;let l=this.plan;switch(l.kind){case`activate`:await Q(l.scope,l.guard,l.snapshot,{kind:`activate`,baseline:M(s)},this.controller.signal);break;case`replace`:await Q(l.scope,l.guard,l.snapshot,{kind:`replace`,baseline:M(s),confirmation:l.confirmation},this.controller.signal);break;case`improve`:await Q(l.scope,l.guard,l.snapshot,{kind:`improve`,samples:this.samples,confirmation:l.confirmation},this.controller.signal);break}if(this.signal.aborted||this.closed)return;this.phase=`closed`,this.prompt.accepted(),this.status.textContent=`Voice enrollment saved.`,this.completion.resolve()}catch(e){if(!this.closed&&this.phase===`committing`){this.phase=`closed`,this.controller.abort(),this.completion.reject(D(e));return}!this.closed&&this.samples.length===3&&this.samples.pop()?.fill(0),this.closed||(this.status.textContent=e instanceof Error?e.message:`VoiceID enrollment failed.`)}finally{this.closed||(this.samples.length<e&&(this.record.textContent=`Retry sample ${e}`,this.status.textContent=`Sample ${e} was not accepted. ${this.status.textContent??``}`),this.phrase=o(this.phrase),this.prompt.setPhrase(this.phrase),this.prompt.title.textContent=`Read aloud · ${this.samples.length} of 3 accepted`,this.prompt.ready(this.status.textContent??``),this.phase=`ready`,this.record.disabled=!1)}}cancelled=()=>{this.closed||(this.phase=`closed`,this.controller.abort(),this.completion.reject(Error(`VoiceID enrollment was cancelled.`)))};checkGuard=()=>{this.closed||this.checkingGuard||(this.checkingGuard=!0,this.validateGuard())};async validateGuard(){try{await Y(this.plan.scope,this.plan.guard)}catch(e){this.closed||(this.phase=`closed`,this.controller.abort(),this.completion.reject(D(e)))}finally{this.checkingGuard=!1}}dispose(){this.phase=`closed`,this.controller.abort(),clearInterval(this.guardTimer),this.signal.removeEventListener(`abort`,this.cancelled),this.prompt.dispose(),this.record.removeEventListener(`click`,this.capture),this.cancel.removeEventListener(`click`,this.cancelled);for(let e of this.samples)e.fill(0)}};async function he(e,n,r,a,o){delete document.body.dataset.voiceVerification;let s=await t(n,r);if(s.kind===`insufficient_audio`)return n.throwIfAborted(),s;try{n.throwIfAborted();let t=await i(s.samples,a,o),r=t.kind===`matched`,c=s.samples.length/16,l=await j(s.samples),u,d,f;try{n.throwIfAborted();let t=await de(e,n);try{u=N(l,t.template),d=N(l,t.baseline),f=t.kind}finally{t.template.fill(0),t.baseline.fill(0)}}finally{l.fill(0)}return document.body.dataset.voiceVerification=JSON.stringify({attemptId:s.quality.attemptId,capturedAtMs:s.quality.capturedAtMs,durationMs:s.quality.durationMs,recordingMs:s.quality.recordingMs,endedBy:s.quality.endedBy,voicedMs:s.quality.voicedMs,microphone:s.quality.microphone,microphoneSelection:s.quality.microphoneSelection,processing:s.quality.processing,backgroundRms:s.quality.backgroundRms,speechToBackgroundDb:s.quality.speechToBackgroundDb,noise:s.quality.noise,similarity:u,baselineSimilarity:d,referenceKind:f,modelInputMs:c,threshold:.45,phraseMatched:r,phraseRecognition:t.recognition,expectedPhrase:a}),u<.45?{kind:`mismatch`,quality:s.quality}:t.kind===`matched`?{kind:`matched`}:{kind:`phrase_mismatch`}}finally{s.samples.fill(0)}}export{ue as a,V as c,L as d,P as f,Q as i,oe as l,he as n,le as o,Y as r,H as s,pe as t,ce as u};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{d as e,
|
|
1
|
+
import{d as e,h as t,i as n,l as r,n as i,r as a,t as o,y as s}from"./prompt-vztg41jG.js";import{SeamsWordmark as c,VOICE_ID_HOST_API_VERSION as l,WorkerDeferred as u,authMenuSuccessCopy as d,backIcon as f,createCspStylesheetManager as p,createWalletIframeSurfaceMeasurementReporter as m,getDefaultCspNonce as h,toError as g}from"../voiceid-host.js";const _=new WeakMap;var v=class{footer;constructor(e,t){this.prompt=t;let n=e.ownerDocument,r=_.get(n);r||(r=p({doc:n,baseCss:`
|
|
2
2
|
.seams-voiceid-activation-surface.seams-voiceid-unlock {
|
|
3
3
|
box-sizing: border-box;
|
|
4
4
|
overflow: hidden;
|
|
@@ -77,4 +77,4 @@ import{d as e,i as t,l as n,m as r,n as i,r as a,t as o,y as s}from"./prompt-g_w
|
|
|
77
77
|
color: var(--seams-colors-textPrimary, #eff2f3);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
`,nonce:h}),_.set(n,r)),r.ensureBase(),e.classList.add(`seams-voiceid-unlock`);let o=n.createElement(`div`);o.className=`seams-voiceid-unlock-header`,t.cancel.className=`seams-voiceid-unlock-back`,t.cancel.setAttribute(`aria-label`,`Back`),t.cancel.replaceChildren(),i(f(),t.cancel),o.append(t.cancel),e.prepend(o),this.footer=n.createElement(`div`),this.footer.className=`seams-voiceid-unlock-footer`,i([a(`span`,null,`Secured by`),` `,a(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(){i(null,this.prompt.cancel),i(null,this.footer)}},y=class{result;completion=new u;controller=new AbortController;element;activateButton;cancelButton;status;prompt;unlockFrame;unmountCapture;measurement;phrase=
|
|
80
|
+
`,nonce:h}),_.set(n,r)),r.ensureBase(),e.classList.add(`seams-voiceid-unlock`);let o=n.createElement(`div`);o.className=`seams-voiceid-unlock-header`,t.cancel.className=`seams-voiceid-unlock-back`,t.cancel.setAttribute(`aria-label`,`Back`),t.cancel.replaceChildren(),i(f(),t.cancel),o.append(t.cancel),e.prepend(o),this.footer=n.createElement(`div`),this.footer.className=`seams-voiceid-unlock-footer`,i([a(`span`,null,`Secured by`),` `,a(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(){i(null,this.prompt.cancel),i(null,this.footer)}},y=class{result;completion=new u;controller=new AbortController;element;activateButton;cancelButton;status;prompt;unlockFrame;unmountCapture;measurement;phrase=t(null);state={kind:`preparing`};settlement=`closed`;expiryTimer=null;constructor(e,t,n,r){let i=t===`activation`?`Activate VoiceID`:`Unlock with VoiceID`,a=document.getElementById(`root`)??document.body;if(!a)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`,i),this.prompt=new o(document,i,this.phrase),this.element.append(this.prompt.element),this.unlockFrame=t===`unlock`?new v(this.element,this.prompt):null,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=i,this.activateButton.disabled=!0,this.activateButton.hidden=this.unlockFrame!==null,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=r?r(this.element):null,r||a.appendChild(this.element),this.measurement=!r&&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(S),this.controller.signal.throwIfAborted();let t=await e(this.controller.signal,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.unlockFrame?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(i){this.activateButton.disabled=!0,this.status.textContent=`Opening microphone…`;try{let e=await i.action(this.controller.signal,this.prompt.capture,this.phrase);if(this.state.kind===`closed`)return;this.unlockFrame&&await this.showUnlocked(this.unlockFrame),this.state={kind:`closed`},this.completion.resolve(e)}catch(a){if(this.state.kind===`closed`)return;if(a instanceof n||a instanceof e||a instanceof r||a instanceof s){if(i.expiresAtMs!==null&&Date.now()>=i.expiresAtMs){this.expire();return}let e=this.phrase;this.phrase=t(e),this.prompt.setPhrase(this.phrase),this.state={kind:`ready`,capture:i},this.activateButton.hidden=!1,this.activateButton.textContent=`Try again`,this.prompt.ready(a.message),this.activateButton.focus();return}this.state={kind:`closed`},this.completion.reject(g(a))}}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 b))};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.`)))}},b=class extends Error{constructor(){super(`VoiceID capture was cancelled.`),this.name=`VoiceIdCaptureCancelledError`}};async function x(e){let t=new y(e.prepare,e.purpose,e.measurement,e.mountCapture);try{return await t.result}finally{t.dispose()}}function S(e){requestAnimationFrame(C.bind(null,e))}function C(e){setTimeout(e,0)}const w=3;if(l!==3)throw Error(`VoiceID requires a matching Wallet host API.`);function T(e){return{unlock:E.bind(null,e),activate:O.bind(null,e),review:A.bind(null,e)}}function E(e,t){return x({purpose:`unlock`,measurement:t.surfaceMeasurementBinding,mountCapture:t.mountCapture,prepare:D.bind(null,e,t)})}async function D(e,t,n,r){let i=await import(`./unlock-Da49yYxd.js`);return n.throwIfAborted(),i.prepareUnlockSurface(t,n,r,e)}async function O(e,t){try{return await x({purpose:`activation`,measurement:t.context.signingEngine.getWalletIframeSurfaceMeasurementBinding(),prepare:k.bind(null,e,t)})}catch(e){if(e instanceof b)return{kind:`cancelled`};throw e}}async function k(e,t,n){let r=await import(`./addVoiceId-Dbd-PwWG.js`);return n.throwIfAborted(),r.prepareActivationSurface(t,n,e)}async function A(e,t,n){return(await import(`./approval-C4KlEQYu.js`)).voiceIdPolicyForRequest(t,n,e)}export{T as createVoiceIdHostPlugin,w as hostApiVersion};
|