@seams/voiceid 0.0.0-stage → 0.24.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/LICENSE.md +201 -0
- package/README.md +74 -2
- package/THIRD_PARTY_NOTICES.md +504 -0
- package/dist/compose-host.mjs +11 -0
- package/dist/esm/browser/ribbon.js +489 -0
- package/dist/esm/capture/prompt.js +515 -0
- package/dist/esm/capture/visual.js +87 -0
- package/dist/esm/descriptor.js +7 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/react/VoiceAssistantCard.css +313 -0
- package/dist/esm/react/VoiceAssistantCard.js +147 -0
- package/dist/esm/react.js +3 -0
- package/dist/hosting.d.mts +4 -0
- package/dist/hosting.mjs +91 -0
- package/dist/public/sdk/voiceid/AURORA_LICENSE.txt +202 -0
- package/dist/public/sdk/voiceid/NOTICE.txt +54 -0
- package/dist/public/sdk/voiceid/SILERO_LICENSE.txt +21 -0
- package/dist/public/sdk/voiceid/addVoiceId-CeBXVHqs.js +1 -0
- package/dist/public/sdk/voiceid/approval-CCbdLhTv.js +1 -0
- package/dist/public/sdk/voiceid/aurora-int8.onnx +0 -0
- package/dist/public/sdk/voiceid/deviceBridge-wRAbqdap.js +1 -0
- package/dist/public/sdk/voiceid/enrollment-DIRoCkx5.js +1 -0
- package/dist/public/sdk/voiceid/host.js +80 -0
- package/dist/public/sdk/voiceid/ort-wasm-simd-threaded.mjs +59 -0
- package/dist/public/sdk/voiceid/ort-wasm-simd-threaded.wasm +0 -0
- package/dist/public/sdk/voiceid/ort.wasm.bundle.min-7y-hlRN8.js +3 -0
- package/dist/public/sdk/voiceid/prompt-CCrXTRRx.js +606 -0
- package/dist/public/sdk/voiceid/redimnet-b1.onnx +0 -0
- package/dist/public/sdk/voiceid/silero-vad.onnx +0 -0
- package/dist/public/sdk/voiceid/unlock-E7YHqBGT.js +1 -0
- package/dist/public/sdk/voiceid/voice-activity-worklet.js +21 -0
- package/dist/types/activation/addVoiceId.d.ts +11 -0
- package/dist/types/activation/manageEnrollment.d.ts +4 -0
- package/dist/types/activation/ownerConfirmation.d.ts +17 -0
- package/dist/types/browser/deviceStore.d.ts +19 -0
- package/dist/types/browser/enrollment.d.ts +37 -0
- package/dist/types/browser/enrollmentStore.d.ts +91 -0
- package/dist/types/browser/inference.d.ts +39 -0
- package/dist/types/browser/microphone.d.ts +61 -0
- package/dist/types/browser/model.d.ts +8 -0
- package/dist/types/browser/phrase.d.ts +35 -0
- package/dist/types/browser/phraseVocabulary.d.ts +3 -0
- package/dist/types/browser/progress.d.ts +2 -0
- package/dist/types/browser/ribbon.d.ts +63 -0
- package/dist/types/browser/verificationError.d.ts +6 -0
- package/dist/types/browser/voiceActivity.d.ts +15 -0
- package/dist/types/capture/approval.d.ts +36 -0
- package/dist/types/capture/bridge.d.ts +12 -0
- package/dist/types/capture/deviceBridge.d.ts +29 -0
- package/dist/types/capture/prompt.d.ts +41 -0
- package/dist/types/capture/surface.d.ts +27 -0
- package/dist/types/capture/unlockFrame.d.ts +13 -0
- package/dist/types/capture/visual.d.ts +24 -0
- package/dist/types/descriptor.d.ts +4 -0
- package/dist/types/host.d.ts +4 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/react/VoiceAssistantCard.d.ts +37 -0
- package/dist/types/react.d.ts +5 -0
- package/dist/types/session/activation.d.ts +61 -0
- package/dist/types/session/activationStore.d.ts +21 -0
- package/dist/types/session/httpClient.d.ts +39 -0
- package/dist/types/session/unlock.d.ts +4 -0
- package/dist/types/session/unlockFromDevice.d.ts +18 -0
- package/package.json +66 -4
- package/src/README.md +270 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
VoiceID speaker model: ReDimNet B1 (VoxCeleb2, large-margin fine-tuned)
|
|
2
|
+
|
|
3
|
+
Source: https://github.com/IDRnD/redimnet
|
|
4
|
+
Source revision: ce039a624cb99fe127702ceb94c6080090e5032f
|
|
5
|
+
Weights: https://huggingface.co/voice-is-cool/ReDimNet
|
|
6
|
+
Weights revision: 5180983b6895dafa0cd88aa88e8a07296df27834
|
|
7
|
+
Checkpoint: b1-vox2-ft_lm.pt
|
|
8
|
+
Checkpoint SHA-256: 6e634bbbeb0f6afd9bbbb0606da834f93e23e4869b3954177a5717acc20ea36c
|
|
9
|
+
ONNX SHA-256: e04dd7a6a1e23fc7b89e47682ea9d0a3946cf7bc59d07922c3db3efc52ae4269
|
|
10
|
+
|
|
11
|
+
Changes: exported to ONNX with complete 16 kHz mono waveform preprocessing.
|
|
12
|
+
The complex STFT is represented with ONNX STFT and equivalent power reduction.
|
|
13
|
+
The model emits 192-dimensional speaker embeddings. No retraining was performed.
|
|
14
|
+
|
|
15
|
+
MIT License
|
|
16
|
+
|
|
17
|
+
Copyright (c) 2024 ID R&D, Inc.
|
|
18
|
+
|
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
20
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
21
|
+
in the Software without restriction, including without limitation the rights
|
|
22
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
23
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
24
|
+
furnished to do so, subject to the following conditions:
|
|
25
|
+
|
|
26
|
+
The above copyright notice and this permission notice shall be included in all
|
|
27
|
+
copies or substantial portions of the Software.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
30
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
31
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
32
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
33
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
34
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
35
|
+
SOFTWARE.
|
|
36
|
+
|
|
37
|
+
AuroraASR-1M spoken phrase model
|
|
38
|
+
|
|
39
|
+
Source: https://huggingface.co/AuroraAI-Research/AuroraASR-1M
|
|
40
|
+
Revision: cd307b54b4d666d6ad7dc982a7a58a96d6e7f942
|
|
41
|
+
Publisher: AuroraAI Research
|
|
42
|
+
License: Apache-2.0; see AURORA_LICENSE.txt.
|
|
43
|
+
ONNX SHA-256: 83ed6f3856458cd96d49a70d8c5175aeec18ba8c184e5367e089cd424eebefd6
|
|
44
|
+
|
|
45
|
+
Changes: exported the publisher's INT8-weight checkpoint to ONNX, with
|
|
46
|
+
full-waveform log-mel preprocessing. The complex STFT is represented by ONNX
|
|
47
|
+
STFT and power reduction. Constant folding is disabled to retain INT8 weights
|
|
48
|
+
in the downloaded file. Execution dequantizes weights to floating point.
|
|
49
|
+
A 16-phrase token vocabulary is generated from the publisher's SentencePiece
|
|
50
|
+
tokenizer. No retraining or user recordings are included.
|
|
51
|
+
|
|
52
|
+
Silero VAD v5.1.2 (MIT), snakers4/silero-vad, revision 6478567951ae5c9979ad7b234185b5515f4be7a1.
|
|
53
|
+
Model SHA-256: 2623a2953f6ff3d2c1e61740c6cdb7168133479b267dfef114a4a3cc5bdd788f
|
|
54
|
+
See SILERO_LICENSE.txt.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020-present Silero Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./prompt-CCrXTRRx.js";import{a as e,i as t,r as n,t as r}from"./deviceBridge-wRAbqdap.js";import{a as i,d as a,i as o,o as s,s as c,t as l}from"./enrollment-DIRoCkx5.js";import{IndexedDBManager as u,WorkerDeferred as d,allocateWalletAuthMethodId as f,alphabetizeStringify as p,base64UrlDecode as m,buildMethodBoundEnvelopeOwnership as h,buildPasskeyCustodyEnvelopeRecord as g,buildVoiceIdEnvelopeFactor as _,buildWalletCustodySeedBinding as v,custodyEnvelopeBindingJsonV1 as y,fetchWithWalletHomeDiscovery as b,isVoiceIdSeedEnvelope as x,parseDigestB64u as S,parseEnvelopeRevision as C,parsePasskeyCustodyEnvelopeRecord as w,parsePasskeyEnvelopeId as T,parseResealedEnvelopeResult as E,parseVoiceIdDevicePublicKeyB64u as D,parseWalletAuthMethodId as O,parseWalletAuthMethodRecordV2 as k,parseWalletId as A,readUnlockedWalletEd25519ExportRootCapabilityV1 as j,rejectUnknownFields as M,requireRecord as N,secureRandomId as P,sha256DigestB64u as F,toError as I,walletCustodyCeremonyTransportFromWorkerContextV1 as L,walletSessionAuthorizations as R}from"../voiceid-host.js";async function z(e){let t=N(e,`pending VoiceID activation`);if(M(t,[`kind`,`walletId`,`walletAuthMethodId`,`devicePublicKeyB64u`,`deviceKeyId`,`custodyEnvelope`],`pending VoiceID activation`),t.kind!==`pending_voiceid_activation_v1`)throw Error(`Pending VoiceID activation kind is invalid.`);let n=A(t.walletId),r=O(t.walletAuthMethodId);if(!n.ok||!r.ok)throw Error(`Pending VoiceID activation identity is invalid.`);let i=D(t.devicePublicKeyB64u),a=S(t.deviceKeyId),o=w(t.custodyEnvelope);if(!x(o)||o.walletId!==n.value||o.ownership.walletAuthMethodId!==r.value||o.factor.deviceKeyId!==a||Number(o.envelopeRevision)!==1||await F(m(i))!==a)throw Error(`Pending VoiceID activation binding is invalid.`);return{kind:`pending_voiceid_activation_v1`,walletId:n.value,walletAuthMethodId:r.value,devicePublicKeyB64u:i,deviceKeyId:a,custodyEnvelope:o}}function B(e){throw Error(`Unhandled VoiceID activation plan: ${String(e)}`)}function V(e,t){let{capability:n}=e;if(n.walletId!==e.walletId||n.walletSessionId!==t.walletSessionId||n.expiresAtMs<=Date.now())throw Error(`VoiceID activation requires the unlocked owner seed and Wallet Session.`)}async function H(e,t){let n=_({deviceKeyId:t.deviceKeyId}),r=v(),i=h(e.walletAuthMethodId),a=C(1),o=y({walletId:e.walletId,envelopeId:e.envelopeId,factor:n,envelopeRevision:a,binding:r,ownership:i}),s=t.factorSecret32.slice(),c;try{c=E(await e.reseal({capability:e.capability,bindingJson:o,factorSecret:s.buffer}))}finally{s.byteLength>0&&s.fill(0)}if(await F(m(c.sealedCustodySecretB64u))!==c.ciphertextDigestB64u)throw Error(`VoiceID worker returned a mismatched ciphertext digest.`);let l=Date.now(),u=w(g({envelopeId:e.envelopeId,walletId:e.walletId,ownership:i,binding:r,factor:n,envelopeRevision:a,nonceB64u:c.nonceB64u,sealedCustodySecretB64u:c.sealedCustodySecretB64u,ciphertextDigestB64u:c.ciphertextDigestB64u,aadHashB64u:c.aadHashB64u,lifecycle:{state:`active`,activatedAtMs:l},createdAtMs:l,updatedAtMs:l}));if(!x(u))throw Error(`VoiceID worker produced an invalid seed envelope.`);return{kind:`pending_voiceid_activation_v1`,walletId:e.walletId,walletAuthMethodId:e.walletAuthMethodId,devicePublicKeyB64u:t.publicKeyB64u,deviceKeyId:t.deviceKeyId,custodyEnvelope:u}}async function U(e){let t=e.plan;switch(t.kind){case`new`:V(t,e.ownerCredential);break;case`resume`:break;default:return B(t)}let n=t.kind===`new`?t.walletId:t.pending.walletId,r=t.kind===`new`?t.walletAuthMethodId:t.pending.walletAuthMethodId,i=await e.capture({walletId:n,walletAuthMethodId:r,signal:e.signal,onCapture:e.onCapture,phrase:e.phrase}),a;try{switch(t.kind){case`new`:a=await H(t,i),await e.persistPending(a);break;case`resume`:if(t.pending.devicePublicKeyB64u!==i.publicKeyB64u||t.pending.deviceKeyId!==i.deviceKeyId)throw Error(`VoiceID activation retry found a different device key.`);a=t.pending;break;default:return B(t)}}finally{i.factorSecret32.fill(0)}if(e.signal.aborted)throw Error(`VoiceID activation was cancelled.`);let o=await e.http.activate({ownerCredential:e.ownerCredential,walletId:a.walletId,walletAuthMethodId:a.walletAuthMethodId,devicePublicKeyB64u:a.devicePublicKeyB64u,deviceKeyId:a.deviceKeyId,custodyEnvelope:a.custodyEnvelope,signal:e.signal});return await e.persistActive(o,a),{authMethod:o,pending:a}}const W=`voiceid-activation-v1:`;function G(e,t){return`${W}${encodeURIComponent(e)}:${encodeURIComponent(t)}`}function K(e){return`${W}${encodeURIComponent(e)}:`}function q(e,t){return p(e)===p(t)}async function J(e){if(e==null)return null;let t=N(e,`stored VoiceID activation`);switch(t.kind){case`pending`:return M(t,[`kind`,`pending`],`stored VoiceID activation`),{kind:`pending`,pending:await z(t.pending)};case`active`:{M(t,[`kind`,`pending`,`authMethod`],`stored VoiceID activation`);let e=await z(t.pending),n=k(t.authMethod);if(!n||n.kind!==`voiceid`||n.status!==`active`||n.walletId!==e.walletId||n.walletAuthMethodId!==e.walletAuthMethodId||n.deviceKeyId!==e.deviceKeyId||n.devicePublicKeyB64u!==e.devicePublicKeyB64u)throw Error(`Stored VoiceID activation method is invalid.`);return{kind:`active`,pending:e,authMethod:n}}default:throw Error(`Stored VoiceID activation lifecycle is invalid.`)}}var Y=class{constructor(e){this.storage=e}async persistPending(e){let t=G(e.walletId,e.walletAuthMethodId),n=await J(await this.storage.getAppState(t));if(n){if(n.kind===`pending`&&q(n.pending,e))return;throw Error(`A different VoiceID activation already owns this method ID.`)}await this.storage.setAppState(t,{kind:`pending`,pending:e})}async persistActive(e,t){let n=G(t.walletId,t.walletAuthMethodId),r=await J(await this.storage.getAppState(n));if(!r||!q(r.pending,t))throw Error(`VoiceID activation has no matching pending record.`);if(e.walletId!==t.walletId||e.walletAuthMethodId!==t.walletAuthMethodId||e.deviceKeyId!==t.deviceKeyId||e.devicePublicKeyB64u!==t.devicePublicKeyB64u)throw Error(`VoiceID server method does not match pending activation.`);await this.storage.upsertWalletAuthMethodV2(e),await this.storage.setAppState(n,{kind:`active`,pending:t,authMethod:e})}async readPending(e,t){let n=await J(await this.storage.getAppState(G(e,t)));if(!n||n.kind===`active`)return null;if(n.pending.walletId!==e||n.pending.walletAuthMethodId!==t)throw Error(`Stored VoiceID activation key does not match its record.`);return n.pending}async listPending(e){let t=await this.storage.listAppStateEntriesByPrefix(K(e)),n=[];for(let r of t){let t=await J(r.value);if(t){if(t.pending.walletId!==e||G(e,t.pending.walletAuthMethodId)!==r.key)throw Error(`Stored VoiceID activation key does not match its record.`);t.kind===`pending`&&n.push(t.pending)}}return n}};const X=`http://www.w3.org/2000/svg`;async function Z(e,t,n){let r=document.querySelector(`.seams-voiceid-activation-surface`);if(!(r instanceof HTMLElement))throw Error(`Open VoiceID management in the Wallet.`);let i=new Q(r,e,t,n);try{await i.result}finally{i.dispose()}}var Q=class{completion=new d;result=this.completion.promise;element=document.createElement(`div`);enrollment=document.createElement(`div`);enrollmentValue=document.createElement(`span`);startOver=document.createElement(`p`);status=document.createElement(`p`);actions;busy=!1;closed=!1;constructor(e,t,n,r){this.parent=e,this.context=t,this.scope=n,this.signal=r,this.element.className=`seams-voiceid-prompt seams-voiceid-management`;let i=document.createElement(`div`);i.className=`seams-voiceid-management-header`;let a=document.createElement(`button`);a.type=`button`,a.className=`seams-voiceid-management-back`,a.setAttribute(`aria-label`,`Back`),a.append($(`M15 6l-6 6 6 6`,20)),a.addEventListener(`click`,this.cancel);let o=document.createElement(`h2`);o.textContent=`Manage voice`,i.append(a,o);let s=document.createElement(`p`);s.className=`seams-voiceid-management-intro`,s.textContent=`Voice unlock on this device. Each change asks for your passkey.`,this.element.append(i,s,this.enrollmentRow()),this.actions={reset:this.resetAction(),improve:this.action(`improve`,`Improve recognition`,!0),import:this.action(`import`,`Use saved enrollment`,!1),replace:this.startOverAction()},this.status.setAttribute(`role`,`status`),this.element.append(this.status),this.enrollmentValue.textContent=`Checking…`,this.actions.import.button.hidden=!0,this.render(null,!1,!1),this.parent.replaceChildren(this.element),this.signal.addEventListener(`abort`,this.cancel,{once:!0}),this.refresh(),a.focus()}enrollmentRow(){this.enrollment.className=`seams-voiceid-management-enrollment`;let e=document.createElement(`span`);e.textContent=`Enrollment`,this.enrollmentValue.className=`seams-voiceid-management-value`;let t=document.createElement(`span`);return t.className=`seams-voiceid-management-summary`,t.append(this.enrollmentValue),this.enrollment.append(e,t),this.enrollment}resetAction(){let e=document.createElement(`button`);e.type=`button`,e.className=`seams-voiceid-management-reset`,e.textContent=`Reset`,e.setAttribute(`aria-label`,`Reset improvements`),e.addEventListener(`click`,this.begin.bind(this,`reset`));let t=document.createElement(`span`);return t.className=`seams-voiceid-management-enrollment-detail`,this.enrollment.querySelector(`.seams-voiceid-management-summary`)?.append(t),this.enrollment.append(e),{button:e,title:e,detail:t,frame:this.enrollment}}startOverAction(){return this.startOver.className=`seams-voiceid-management-section`,this.startOver.textContent=`Start over`,this.element.append(this.startOver),this.action(`replace`,`Record voice again`,!1)}action(e,t,n){let r=document.createElement(`button`);r.type=`button`,r.className=`seams-voiceid-management-action`;let i=document.createElement(`span`),a=document.createElement(`span`);a.className=`seams-voiceid-management-action-heading`;let o=document.createElement(`span`);o.id=`seams-voiceid-management-${e}-title`,o.textContent=t,a.append(o);let s=[];if(n){let t=document.createElement(`span`);t.id=`seams-voiceid-management-${e}-chip`,t.className=`seams-voiceid-management-chip`,t.textContent=`Experimental`,a.append(t),s.push(t.id)}let c=document.createElement(`span`);return c.id=`seams-voiceid-management-${e}-detail`,c.className=`seams-voiceid-management-action-detail`,s.push(c.id),i.append(a,c),r.append(i,$(`M9 6l6 6-6 6`,16)),r.setAttribute(`aria-labelledby`,o.id),r.setAttribute(`aria-describedby`,s.join(` `)),r.disabled=!0,r.addEventListener(`click`,this.begin.bind(this,e)),this.element.append(r),{button:r,title:o,detail:c,frame:r}}async refresh(){try{let e=await s(this.scope),t=e?null:await i();if(this.closed)return;this.render(e,t!==null,!0)}catch(e){this.completion.reject(I(e))}}render(e,t,n){let r=e?.adaptation??null,{improve:i,reset:a,import:o,replace:s}=this.actions;n&&(this.enrollment.dataset.enrollment=r?.kind??`missing`,this.enrollmentValue.textContent=r===null?`Not on this device`:r.kind===`adapted`?`Improved`:`Original`,i.button.hidden=e===null,o.button.hidden=!t),a.button.hidden=r?.kind!==`adapted`,a.detail.textContent=r?.kind===`adapted`?`Saved on this device`:``,i.title.textContent=r?.kind===`adapted`?`Improve again`:`Improve recognition`,i.detail.textContent=r?.kind===`adapted`?`Replace the added samples. Your original enrollment stays.`:`Add three samples. They stay until you replace or reset them.`,o.detail.textContent=`Import the voice enrollment saved in this browser.`,s.detail.textContent=r?.kind===`adapted`?`Replace your enrollment and remove improvements.`:`Replace your enrollment with three new samples.`,this.startOver.hidden=i.button.hidden&&o.button.hidden;for(let e of Object.values(this.actions))delete e.frame.dataset.state,e.button.disabled=!n;this.status.textContent=``,delete this.status.dataset.placement}show(e,t,n){let r=this.actions[e];if(this.status.textContent=n,r.button.hidden){this.status.dataset.placement=`dialog`;return}r.frame.dataset.state=t,r.detail.textContent=n}begin(e){if(!(this.busy||this.closed)){this.busy=!0;for(let e of Object.values(this.actions))e.button.disabled=!0;this.show(e,`pending`,`Confirm with your passkey to continue.`),this.perform(e)}}async perform(e){try{let r=await t(this.scope,`enrolled`),a=await s(this.scope),c=a?{kind:`present`,enrollment:a}:{kind:`missing`};if(e===`improve`&&c.kind===`missing`)throw Error(`Record or import your original voice first.`);let u=e===`import`?await i():null;if(e===`import`&&(!u||c.kind!==`missing`))throw Error(`The previous enrollment is unavailable.`);let d=await n.request(this.context,this.scope,r,c,e,this.signal);switch(this.signal.throwIfAborted(),e){case`improve`:if(c.kind!==`present`)throw Error(`Original voice enrollment is unavailable.`);await l({kind:`improve`,scope:this.scope,guard:r,snapshot:c,confirmation:d},this.signal);break;case`replace`:await l({kind:`replace`,scope:this.scope,guard:r,snapshot:c,confirmation:d},this.signal);break;case`reset`:await o(this.scope,r,c,{kind:`reset`,confirmation:d},this.signal);break;case`import`:if(!u)throw Error(`Previous voice enrollment is unavailable.`);await o(this.scope,r,c,{kind:`import`,baseline:u,confirmation:d},this.signal);break}this.closed||this.completion.resolve()}catch(t){if(this.closed)return;this.parent.replaceChildren(this.element),await this.refresh(),this.closed||this.show(e,`error`,t instanceof Error?t.message:`VoiceID could not be updated.`)}finally{this.busy=!1}}cancel=()=>{this.closed||(this.closed=!0,this.parent.dispatchEvent(new Event(`cancel`,{bubbles:!0})),this.completion.reject(Error(`VoiceID management was cancelled.`)))};dispose(){this.closed=!0,this.signal.removeEventListener(`abort`,this.cancel),this.element.remove()}};function $(e,t){let n=document.createElementNS(X,`svg`);n.setAttribute(`viewBox`,`0 0 24 24`),n.setAttribute(`width`,String(t)),n.setAttribute(`height`,String(t)),n.setAttribute(`aria-hidden`,`true`);let r=document.createElementNS(X,`path`);return r.setAttribute(`d`,e),r.setAttribute(`fill`,`none`),r.setAttribute(`stroke`,`currentColor`),r.setAttribute(`stroke-width`,`1.75`),r.setAttribute(`stroke-linecap`,`round`),r.setAttribute(`stroke-linejoin`,`round`),n.append(r),n}async function ee(e,t){return await e.requestOperation({kind:`walletCustodyCeremony`,request:{type:`resealWalletCustodyFromUnlockedCapability`,payload:{capability:t.capability,replacementEnvelopeBindingJson:t.bindingJson,replacementFactorSecret:t.factorSecret},transfer:[t.factorSecret]}})}async function te(t,n){let r=await u.resolveSelectedWalletAuthority(n);if(r.kind!==`resolved`||r.selection.lockState!==`unlocked`||r.selection.walletId!==n||r.authMethod.status!==`active`||r.authMethod.walletId!==n||r.authMethod.walletAuthorityId!==r.authority.authorityId||r.authority.state!==`active`||r.authority.walletId!==n)throw Error(`Unlock this wallet with a passkey or Email OTP before activating VoiceID.`);let i=await R.readExactWithOperationCredential({walletId:n,authorityId:r.authority.authorityId,authMethodId:r.authMethod.walletAuthMethodId});if(i.kind!==`found`||i.record.walletId!==n||i.record.authMethodId!==r.authMethod.walletAuthMethodId||i.record.authorityId!==r.authority.authorityId||i.record.expiresAtMs<=Date.now())throw Error(`VoiceID activation requires an active owner Wallet Session.`);let o=await u.listWalletAuthMethodsV2ForWallet(n);for(let e of o){if(e.kind!==`voiceid`||e.status!==`active`||e.walletAuthorityId!==r.authority.authorityId)continue;let i=await a(n,e.walletAuthMethodId);if(i&&i.deviceKeyId===e.deviceKeyId)return{kind:`enroll_existing`,walletId:n,walletAuthMethodId:e.walletAuthMethodId,context:t}}if(r.authMethod.kind===`voiceid`)throw Error(`An existing local VoiceID enrollment is required for management.`);let s=new Y(u),c=await s.listPending(n);if(c.length>1)throw Error(`More than one VoiceID activation is pending for this wallet.`);let l;if(c.length===1)l={kind:`resume`,pending:c[0]};else{let e=j(n);if(!e||e.walletSessionId!==i.operationCredential.walletSessionId)throw Error(`Unlock the wallet again to make its custody seed available for VoiceID.`);let r=T(P(`wallet-custody-envelope`,24));if(!r.ok)throw Error(`VoiceID envelope ID generation failed.`);let a=L(t.signingEngine.getSignerWorkerContext());l={kind:`new`,walletId:n,walletAuthMethodId:f(crypto.randomUUID()),envelopeId:r.value,capability:e,reseal:ee.bind(null,a)}}return{kind:`activate`,ownerCredential:i.operationCredential,plan:l,http:new e(t.configs.network.relayer.url,location.origin,b),store:s}}async function ne(e,t){t.throwIfAborted();let{context:n,walletId:r}=e,i=await te(n,r);return t.throwIfAborted(),i.kind===`enroll_existing`?{kind:`management`,action:re.bind(null,i)}:{kind:`recording`,action:ie.bind(null,i),expiresAtMs:null}}async function re(e,t){let n=await c(e.walletId,e.walletAuthMethodId);return await Z(e.context,n,t),t.throwIfAborted(),{kind:`activated`,walletId:e.walletId,walletAuthMethodId:e.walletAuthMethodId}}async function ie(e,t,n,i){let a=await U({plan:e.plan,ownerCredential:e.ownerCredential,http:e.http,signal:t,onCapture:n,phrase:i,capture:r,persistPending:e.store.persistPending.bind(e.store),persistActive:e.store.persistActive.bind(e.store)});return{kind:`activated`,walletId:a.authMethod.walletId,walletAuthMethodId:a.authMethod.walletAuthMethodId}}export{ne as prepareActivationSurface};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as e,f as t,g as n,t as r,u as i}from"./prompt-CCrXTRRx.js";import{f as a,n as o,s}from"./enrollment-DIRoCkx5.js";import{ActionType as c,IndexedDBManager as l,TransactionReviewError as u,isPlainObject as d,parseTransactionReviewWire as f,resolveNearNetwork as p,walletForHostRequest as m,walletHostExecutionFingerprint as h}from"../voiceid-host.js";function g(e,t){return e.attemptId===t.attemptId&&e.operationHash===t.operationHash&&e.expiresAtMs===t.expiresAtMs}async function _(t,r,a,s,c,l){let u=Math.min(r.expiresAtMs,Date.now()+a);if(s.aborted||u<=Date.now())throw Error(`VoiceID review expired or was cancelled.`);let d=await o({kind:`active`,scope:t},s,c,l);if(s.aborted||u<=Date.now())throw Error(`VoiceID review expired or was cancelled.`);switch(d.kind){case`matched`:return{kind:`approved`};case`insufficient_audio`:return{kind:`retry`,message:e(d.quality)};case`mismatch`:return{kind:`retry`,message:new n(d.quality).message};case`phrase_mismatch`:return{kind:`retry`,message:new i().message};default:return v(d)}}function v(e){throw Error(`Unexpected voice result: ${String(e)}`)}function y(e){throw Error(`Unexpected voice outcome: ${String(e)}`)}function b(e){if(!(!d(e)&&!Array.isArray(e))){for(let t of Object.values(e))b(t);Object.freeze(e)}}async function x(e,t){switch(e.type){case`PM_SIGN_TX_WITH_ACTIONS`:case`PM_SIGN_DELEGATE_ACTION`:case`PM_SIGN_NEP413`:throw T();case`PM_SIGN_TEMPO`:{let n=e.payload;if(!n||n.operationKind!==`evm_transaction`)throw T();let{tx:r}=n.request,i=n.chainTarget;if(!t.config.network.chains.some(S)||i.kind!==`evm`||i.namespace!==`eip155`||i.networkSlug!==`arc-testnet`||i.chainId!==5042002||n.request.chain!==`evm`||n.request.kind!==`eip1559`||n.request.senderSignatureAlgorithm!==`secp256k1`||r.chainId!==i.chainId||typeof r.to!=`string`||!/^0x[0-9a-fA-F]{40}$/.test(r.to)||r.data!==void 0&&r.data!==`0x`||r.accessList!==void 0&&r.accessList.length!==0||r.abi!==void 0)throw T();return await w(e,t)}case`PM_SIGN_AND_SEND_TX`:{if(p(t.config.network.chains)!==`testnet`)throw new u(`review_unsupported_mode`,`This VoiceID prototype requires NEAR testnet.`);let n=e.payload;if(!n||n.transaction.actions.length!==1||n.transaction.actions[0].type!==c.Transfer||!(`transactionReview`in e))throw T();return await w(e,t)}default:return{kind:`disabled`}}}function S(e){return e.network===`arc-testnet`&&e.chainId===5042002}function C(e,t){return typeof t==`bigint`?{bigint:t.toString()}:t}async function w(e,t){let n=f(e.transactionReview);if(n.validity.kind!==`expires_at`)throw new u(`review_invalid_input`,`VoiceID requires a review deadline.`);b(e);let r=new TextEncoder().encode(JSON.stringify({domain:`seams-voiceid-operation-v1`,origin:location.origin,executionFingerprint:h(t.config),request:e},C)),i=await crypto.subtle.digest(`SHA-256`,r),a=``;for(let e of new Uint8Array(i))a+=e.toString(16).padStart(2,`0`);let o=m(e,null);if(!o)throw Error(`VoiceID review requires a wallet identity.`);return{kind:`required`,approval:E.forReview(n,a,o)}}function T(){return new u(`review_unsupported_mode`,`VoiceID requires a reviewed NEAR or Arc testnet transfer.`)}var E=class e{phrase=t(null);prompt;surface;get messages(){return{confirm:`Confirm with VoiceID`,approved:`Voice approved this operation.`}}state={kind:`pending`};constructor(e,t,n){this.reviewExpiresAtMs=e,this.operationHash=t,this.walletId=n,this.prompt=new r(document,`Approve transfer with VoiceID`,this.phrase,`segments`),this.prompt.record.hidden=!0,this.prompt.cancel.hidden=!0,this.surface=this.prompt.element}static forReview(t,n,r){if(t.validity.kind!==`expires_at`||!/^[0-9a-f]{64}$/.test(n))throw new u(`review_invalid_input`,`VoiceID requires a bounded operation.`);return new e(t.validity.atMs,n,r)}async approve(e){if(this.state.kind===`approved`){if(e.aborted||performance.now()>=this.state.deadline||Date.now()>=this.state.binding.expiresAtMs)throw Error(`Voice approval expired or closed.`);return{kind:`approved`}}if(this.state.kind!==`pending`)throw Error(`Voice approval already started.`);if(!navigator.userActivation.isActive||document.visibilityState!==`visible`||!document.hasFocus())throw Error(`Open the Wallet review and select Confirm to start voice capture.`);this.state={kind:`preparing`},this.prompt.status.textContent=`Loading VoiceID…`;try{let n=await l.resolveSelectedWalletAuthority(this.walletId);if(n.kind!==`resolved`||n.authMethod.kind!==`voiceid`||n.selection.lockState!==`unlocked`)throw Error(`Unlock this wallet with VoiceID before voice approval.`);let r=await s(this.walletId,n.authMethod.walletAuthMethodId);await a(this.prompt.progress),this.prompt.progress.replaceChildren();let i=this.beginAttempt(e);for(;;){let{binding:n,deadline:a,remaining:o}=i,s=await _(r,n,o,e,this.prompt.capture,this.phrase);if(this.assertListening(n),e.aborted||performance.now()>=a||Date.now()>=n.expiresAtMs)throw Error(`Voice approval expired or closed.`);switch(s.kind){case`approved`:return this.state={kind:`approved`,binding:n,deadline:a,signal:e},s;case`retry`:this.phrase=t(this.phrase),this.prompt.setPhrase(this.phrase),this.prompt.record.textContent=`Try again`,this.prompt.ready(s.message),await this.waitForRetry(e),i=this.beginAttempt(e);break;default:return y(s)}}}catch(e){throw this.state={kind:`closed`},e}}beginAttempt(e){let t=Math.min(25e3,this.reviewExpiresAtMs-Date.now());if(t<250||e.aborted)throw Error(`This voice review has expired or closed.`);let n=Object.freeze({attemptId:crypto.randomUUID(),operationHash:this.operationHash,expiresAtMs:Date.now()+t}),r=performance.now()+t;return this.prompt.record.hidden=!0,this.prompt.status.textContent=`Opening microphone…`,this.state={kind:`listening`,binding:n,deadline:r,signal:e},{binding:n,deadline:r,remaining:t}}waitForRetry(e){return new Promise((t,n)=>{let r=this.prompt.record,i=i=>{clearTimeout(s),r.removeEventListener(`click`,a),e.removeEventListener(`abort`,o),i?t():n(Error(`This voice review has expired or closed.`))},a=i.bind(null,!0),o=i.bind(null,!1),s=setTimeout(o,Math.max(0,this.reviewExpiresAtMs-Date.now()));r.addEventListener(`click`,a),e.addEventListener(`abort`,o),e.aborted&&o(),r.focus()})}consume(){let e=this.state;if(this.state={kind:`consumed`},e.kind!==`approved`||e.signal.aborted||performance.now()>=e.deadline||Date.now()>=e.binding.expiresAtMs)throw Error(`A current voice approval is required before signing.`)}assertListening(e){if(this.state.kind!==`listening`||!g(e,this.state.binding))throw Error(`This voice attempt has closed.`)}};export{x as voiceIdPolicyForRequest};
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{g as e,i as t,o as n,s as r,u as i}from"./prompt-CCrXTRRx.js";import{c as a,d as o,l as s,n as c,o as l,r as u,s as d,t as f,u as p}from"./enrollment-DIRoCkx5.js";import{IndexedDBManager as m,availabilityKey as h,base64UrlDecode as g,base64UrlEncode as _,buildRelayerJsonPostRequestInit as v,buildWalletSessionAuthorizationHeaders as y,buildWebauthnP256SignatureWasm as b,createRelayerExactWalletSessionStatusPort as x,decodeCoseP256PublicKeyWasm as S,fetchWithWalletHomeDiscovery as C,isVoiceIdSeedEnvelope as w,joinNormalizedUrl as T,mpcMaterialActivationRefsEqual as E,normalizeRelayerBaseUrl as D,parseActiveWalletSessionV1 as O,parseEd25519YaoRecoveryCapabilityV1 as k,parseLinkedDeviceListResultV1 as ee,parsePasskeyCustodyEnvelopeRecord as te,parseStoredAuthMethodAvailability as ne,parseVoiceIdDeviceAssertion as re,parseVoiceIdWalletSessionChallenge as ie,parseWalletAuthMethodRecordV2 as ae,parseWalletSessionOperationCredentialV1 as oe,rejectUnknownFields as A,requireRecord as j,sha256DigestB64u as M,voiceIdWalletSessionChallengeBytes as N,walletSessionAuthorizations as P}from"../voiceid-host.js";async function F(e){let t;try{t=await e.json()}catch{throw Error(`VoiceID server returned an invalid response.`)}let n=j(t,`VoiceID server response`);if(!e.ok||n.ok!==!0)throw Error(`VoiceID server request failed (HTTP ${e.status}).`);return n}var I=class{walletOrigin;constructor(e,t,n){this.relayerUrl=e,this.send=n;let r=new URL(t);if(r.origin!==t||r.protocol!==`https:`&&r.protocol!==`http:`)throw Error(`VoiceID Wallet origin is invalid.`);this.walletOrigin=t}async activate(e){if(e.custodyEnvelope.walletId!==e.walletId||e.custodyEnvelope.ownership.walletAuthMethodId!==e.walletAuthMethodId||e.custodyEnvelope.factor.deviceKeyId!==e.deviceKeyId)throw Error(`VoiceID activation envelope does not match the device method.`);let t=new Request(T(this.relayerUrl,`/wallet/voiceid/activate`),{...v({body:{targetWalletAuthMethodId:e.walletAuthMethodId,devicePublicKeyB64u:e.devicePublicKeyB64u,custodyEnvelope:e.custodyEnvelope},headers:y(e.ownerCredential)}),signal:e.signal}),n=await F(await this.send(t));A(n,[`ok`,`authMethod`],`VoiceID activation response`);let r=ae(n.authMethod);if(!r||r.kind!==`voiceid`||r.status!==`active`||r.walletId!==e.walletId||r.walletAuthMethodId!==e.walletAuthMethodId||r.devicePublicKeyB64u!==e.devicePublicKeyB64u||r.deviceKeyId!==e.deviceKeyId)throw Error(`VoiceID server activated a different device method.`);return r}async challenge(e){let t=new Request(T(this.relayerUrl,`/wallet/voiceid/challenge`),{...v({body:{walletId:e.walletId,walletAuthMethodId:e.walletAuthMethodId}}),signal:e.signal}),n=await F(await this.send(t));A(n,[`ok`,`challenge`],`VoiceID challenge response`);let r=ie(n.challenge);if(r.walletId!==e.walletId||r.walletAuthMethodId!==e.walletAuthMethodId||r.requestOrigin!==this.walletOrigin||r.audience!==this.walletOrigin)throw Error(`VoiceID server challenge belongs to a different Wallet method or origin.`);return r}async verify(e){if(e.assertion.challenge.requestOrigin!==this.walletOrigin||e.assertion.challenge.audience!==this.walletOrigin)throw Error(`VoiceID assertion belongs to a different Wallet origin.`);let t=new Request(T(this.relayerUrl,`/wallet/voiceid/verify`),{...v({body:{assertion:e.assertion}}),signal:e.signal}),n=await F(await this.send(t));A(n,[`ok`,`walletSession`,`operationCredential`,`custodyEnvelope`,`near`],`VoiceID verification response`);let r=O(n.walletSession),i=oe(n.operationCredential),a=te(n.custodyEnvelope),o=e.assertion.challenge;if(!w(a)||r.walletId!==o.walletId||r.authMethodId!==o.walletAuthMethodId||r.authorityId!==o.walletAuthorityId||a.walletId!==o.walletId||a.ownership.walletAuthMethodId!==o.walletAuthMethodId||a.factor.deviceKeyId!==o.deviceKeyId)throw Error(`VoiceID server returned a different Wallet Session or custody envelope.`);let s=L(n.near);if(s.kind===`ready`&&(s.capability.applicationBinding.wallet_id!==r.walletId||!r.capabilitySubjects.some(R.bind(null,s.capability.materialActivation))))throw Error(`VoiceID NEAR capability belongs to another Wallet Session.`);return{walletSession:r,operationCredential:i,custodyEnvelope:a,near:s}}};function L(e){let t=j(e,`NEAR installation`);switch(t.kind){case`unavailable`:return A(t,[`kind`],`NEAR installation`),{kind:`unavailable`};case`ready`:if(A(t,[`kind`,`capability`,`remainingUses`],`NEAR installation`),typeof t.remainingUses!=`number`||!Number.isSafeInteger(t.remainingUses)||t.remainingUses<1)throw Error(`NEAR session budget is invalid.`);return{kind:`ready`,capability:k(t.capability),remainingUses:t.remainingUses};default:throw Error(`NEAR installation state is invalid.`)}}function R(e,t){return t.kind===`sign`&&t.keyFamily===`ed25519`&&E(e,t.materialActivation)}function z(e,t,n){if(t<24)return[t,1];let r=e.byteLength-n-1,i=new DataView(e.buffer,n+1),a,o=0;switch(t){case 24:r>0&&(a=i.getUint8(0),o=2);break;case 25:r>1&&(a=i.getUint16(0,!1),o=3);break;case 26:r>3&&(a=i.getUint32(0,!1),o=5);break;case 27:if(r>7){let e=i.getBigUint64(0,!1);if(e>=24n&&e<=2**53-1)return[Number(e),9]}break}if(a&&a>=24)return[a,o];throw Error(`Length not supported or not well formed`)}var B=class{constructor(e,t){Object.defineProperty(this,`tagId`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),Object.defineProperty(this,`tagValue`,{enumerable:!0,configurable:!0,writable:!0,value:void 0}),this.tagId=e,this.tagValue=t}get tag(){return this.tagId}get value(){return this.tagValue}};function V(e,t,n){return z(e,t,n)}function H(e,t,n){let[r,i]=V(e,t,n);return[-r-1,i]}function U(e,t,n){let[r,i]=z(e,t,n),a=n+i;return[new Uint8Array(e.buffer.slice(a,a+r)),i+r]}const W=new TextDecoder;function G(e,t,n){let[r,i]=U(e,t,n);return[W.decode(r),i]}function se(e,t,n){if(t===0)return[[],1];let[r,i]=z(e,t,n),a=i,o=[];for(let t=0;t<r;t++){if(e.byteLength-n-a<=0)throw Error(`array is not supported or well formed`);let[t,r]=q(e,n+a);o.push(t),a+=r}return[o,a]}const K=`Map is not supported or well formed`;function ce(e,t,n){if(t===0)return[new Map,1];let[r,i]=z(e,t,n),a=i,o=new Map;for(let t=0;t<r;t++){let t=e.byteLength-n-a;if(t<=0)throw Error(K);let[r,i]=q(e,n+a);if(a+=i,t-=i,t<=0||typeof r!=`string`&&typeof r!=`number`||o.has(r))throw Error(K);let[s,c]=q(e,n+a);a+=c,o.set(r,s)}return[o,a]}function le(e,t){if(t+3>e.byteLength)throw Error(`CBOR stream ended before end of Float 16`);let n=e.getUint16(t+1,!1);if(n==31744)return[1/0,3];if(n==32256)return[NaN,3];if(n==64512)return[-1/0,3];throw Error(`Float16 data is unsupported`)}function ue(e,t){if(t+5>e.byteLength)throw Error(`CBOR stream ended before end of Float 32`);return[e.getFloat32(t+1,!1),5]}function de(e,t){if(t+9>e.byteLength)throw Error(`CBOR stream ended before end of Float 64`);return[e.getFloat64(t+1,!1),9]}function fe(e,t,n){let[r,i]=z(e,t,n),[a,o]=q(e,n+i);return[new B(r,a),i+o]}function q(e,t){if(t>=e.byteLength)throw Error(`CBOR stream ended before tag value`);let n=e.getUint8(t),r=n>>5,i=n&31;switch(r){case 0:return V(e,i,t);case 1:return H(e,i,t);case 2:return U(e,i,t);case 3:return G(e,i,t);case 4:return se(e,i,t);case 5:return ce(e,i,t);case 6:return fe(e,i,t);case 7:switch(i){case 20:return[!1,1];case 21:return[!0,1];case 22:return[null,1];case 23:return[void 0,1];case 25:return le(e,t);case 26:return ue(e,t);case 27:return de(e,t)}}throw Error(`Unsupported or not well formed at ${t}`)}new TextEncoder;function pe(e,t){if(e.byteLength===0||e.byteLength<=t||t<0)throw Error(`No data`);return e instanceof Uint8Array?q(new DataView(e.buffer),t):e instanceof ArrayBuffer?q(new DataView(e),t):q(e,t)}function me(e){let[t,n]=pe(e,0);if(n!==e.byteLength)throw Error(`Data was decoded, but the whole stream was not processed ${n} != ${e.byteLength}`);return t}async function J(e,t){let n=await m.resolveSelectedWalletAuthority(e.walletId);if(n.kind!==`resolved`||n.selection.lockState!==`unlocked`||t===`activating`&&n.authMethod.kind===`voiceid`||n.authMethod.status!==`active`||n.authority.authorityId!==e.authorityId)throw Error(`Unlock this wallet with an owner method before managing VoiceID.`);let r=await P.readExactWithOperationCredential({walletId:e.walletId,authorityId:e.authorityId,authMethodId:n.authMethod.walletAuthMethodId});if(r.kind!==`found`||r.record.expiresAtMs<=Date.now())throw Error(`Unlock this wallet again before managing VoiceID.`);let i=ne(await m.getAppState(h(e.walletId,e.walletAuthMethodId))),a;if(t===`activating`)a={target:t,sessionMethodId:n.authMethod.walletAuthMethodId,walletSessionId:r.operationCredential.walletSessionId,lockGeneration:n.selection.lockGeneration,expiresAtMs:Math.min(r.record.expiresAtMs,Date.now()+5*6e4),availabilityRevision:i.revision};else{let o=(await m.listWalletAuthMethodsV2ForWallet(e.walletId)).find(Y.bind(null,e));if(!o)throw Error(`Add a passkey to this authority before changing your voice enrollment.`);a={target:t,sessionMethodId:n.authMethod.walletAuthMethodId,confirmationMethodId:o.walletAuthMethodId,walletSessionId:r.operationCredential.walletSessionId,lockGeneration:n.selection.lockGeneration,expiresAtMs:Math.min(r.record.expiresAtMs,Date.now()+5*6e4),availabilityRevision:i.revision}}return await u(e,a),a}function Y(e,t){return t.kind===`passkey`&&t.status===`active`&&t.walletId===e.walletId&&t.walletAuthorityId===e.authorityId}function he(e,t,n,r){return r.walletId===e.walletId&&r.walletAuthorityId===e.authorityId&&r.credential.kind===`passkey`&&r.credential.walletAuthMethodId===t.confirmationMethodId&&r.credential.credentialIdB64u===n}function X(e,t,n,r){return JSON.stringify([`seams-voiceid-enrollment-change-v1`,location.origin,e.walletId,e.authorityId,e.walletAuthMethodId,e.deviceKeyId,t.sessionMethodId,t.confirmationMethodId,t.walletSessionId,t.lockGeneration,t.availabilityRevision,t.expiresAtMs,r,n.kind===`present`?n.enrollment.generation:null,n.kind===`present`?n.enrollment.revision:null])}var ge=class e{consumed=!1;constructor(e,t,n){this.binding=e,this.expiresAtMs=t,this.assertCurrentOwner=n}static async request(t,n,r,i,a,o){await u(n,r);let s=_e.bind(null,t.configs.network.relayer.url,n,r);await s(o);let c=await m.getWalletAuthMethodV2(r.confirmationMethodId);if(!c||c.kind!==`passkey`||c.status!==`active`||c.walletId!==n.walletId||c.walletAuthorityId!==n.authorityId||c.rpId!==t.signingEngine.getRpId())throw Error(`The confirming passkey is unavailable for this wallet.`);let l=X(n,r,i,a),d=await M(new TextEncoder().encode(JSON.stringify({binding:l,nonce:crypto.randomUUID(),expiresAtMs:r.expiresAtMs})));o.throwIfAborted();let f=await navigator.credentials.get({publicKey:{challenge:g(d),rpId:c.rpId,allowCredentials:[{type:`public-key`,id:g(c.credentialIdB64u)}],userVerification:`required`,timeout:Math.min(6e4,r.expiresAtMs-Date.now())},signal:o});if(!(f instanceof PublicKeyCredential)||!(f.response instanceof AuthenticatorAssertionResponse)||_(new Uint8Array(f.rawId))!==c.credentialIdB64u)throw Error(`The passkey did not confirm this wallet.`);let p=f.response,h=new Uint8Array(p.clientDataJSON),v=j(JSON.parse(new TextDecoder().decode(h)),`Passkey client data`);if(v.type!==`webauthn.get`||v.challenge!==d||v.origin!==location.origin)throw Error(`The passkey confirmation belongs to another operation.`);let y=new Uint8Array(p.authenticatorData),b=new Uint8Array(await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(c.rpId)));if(y.length<37||(y[32]&5)!=5||_(y.slice(0,32))!==_(b))throw Error(`Passkey user verification is required for this Wallet origin.`);if(!await Q({cosePublicKey:g(c.credentialPublicKeyB64u),challenge:g(d),authenticatorData:y,clientBytes:h,signature:new Uint8Array(p.signature),workerCtx:t.signingEngine.getSignerWorkerContext()}))throw Error(`Passkey confirmation signature is invalid.`);return o.throwIfAborted(),await u(n,r),new e(l,r.expiresAtMs,s)}async consume(e,t,n,r,i){if(this.consumed||this.expiresAtMs<=Date.now()||this.binding!==X(e,t,n,r))throw Error(`Passkey confirmation expired or was already used. Start again.`);if(this.consumed=!0,await this.assertCurrentOwner(i),i.throwIfAborted(),this.expiresAtMs<=Date.now())throw Error(`Passkey confirmation expired. Start again.`)}};async function _e(e,t,n,r){let i=await P.readExactWithOperationCredential({walletId:t.walletId,authorityId:t.authorityId,authMethodId:n.sessionMethodId});if(i.kind!==`found`||i.operationCredential.walletSessionId!==n.walletSessionId)throw Error(`The owner session changed. Unlock this wallet and try again.`);r.throwIfAborted();let a=await x({relayerUrl:e,operationCredential:i.operationCredential,fetchImpl:Z.bind(null,r)}).read({walletSessionId:n.walletSessionId,quotaId:i.record.quotaId});if(a.status!==`active`&&a.status!==`exhausted`||a.authorization.walletId!==t.walletId||a.authorization.authorityId!==t.authorityId||a.authorization.authMethodId!==n.sessionMethodId)throw Error(`The owner session is unavailable. Unlock this wallet and try again.`);let o=await m.getWalletAuthMethodV2(n.confirmationMethodId);if(!o||o.kind!==`passkey`||!Y(t,o))throw Error(`The confirming passkey is unavailable.`);let s=new URLSearchParams({walletId:t.walletId,limit:`50`,cursor:``}),c=await Z(r,`${D(e)}/wallet/device-linking/v1/devices?${s}`,{headers:y(i.operationCredential)});if(!c.ok)throw Error(`Could not verify the confirming passkey with the wallet service.`);let{ok:l,...u}=j(await c.json(),`Wallet method inventory`);if(l!==!0)throw Error(`Could not verify the confirming passkey with the wallet service.`);if(!ee(u).ownerDevices.some(he.bind(null,t,n,o.credentialIdB64u)))throw Error(`The confirming passkey was removed or belongs to another authority.`);r.throwIfAborted()}function Z(e,t,n){return C(new Request(t,{...n,signal:AbortSignal.any([e,AbortSignal.timeout(15e3)])}))}async function Q(e){let t=me(e.cosePublicKey);if(!(t instanceof Map))throw Error(`Passkey public key is invalid.`);let n=new Uint8Array(await crypto.subtle.digest(`SHA-256`,new Uint8Array(e.clientBytes))),r=new Uint8Array(e.authenticatorData.length+n.length);if(r.set(e.authenticatorData),r.set(n,e.authenticatorData.length),t.get(1)===3&&t.get(3)===-257){let n=t.get(-1),i=t.get(-2);if(!(n instanceof Uint8Array)||!(i instanceof Uint8Array))throw Error(`RSA passkey public key is invalid.`);let a=await crypto.subtle.importKey(`jwk`,{kty:`RSA`,n:_(n),e:_(i)},{name:`RSASSA-PKCS1-v1_5`,hash:`SHA-256`},!1,[`verify`]);return crypto.subtle.verify(`RSASSA-PKCS1-v1_5`,a,new Uint8Array(e.signature),r)}if(t.get(1)!==2||t.get(3)!==-7)throw Error(`This passkey type cannot confirm VoiceID changes.`);let i=await S({cosePublicKey:e.cosePublicKey,workerCtx:e.workerCtx}),a=(await b({challenge32:e.challenge,authenticatorData:e.authenticatorData,clientDataJSON:e.clientBytes,signatureDer:e.signature,pubKeyX32:i.pubKeyX32,pubKeyY32:i.pubKeyY32,workerCtx:e.workerCtx})).slice(-128,-64),o=await crypto.subtle.importKey(`jwk`,{kty:`EC`,crv:`P-256`,x:_(i.pubKeyX32),y:_(i.pubKeyY32)},{name:`ECDSA`,namedCurve:`P-256`},!1,[`verify`]);return crypto.subtle.verify({name:`ECDSA`,hash:`SHA-256`},o,a,r)}async function ve(e){r();let t=await s(e.walletId,e.walletAuthMethodId),n=await m.resolveSelectedWalletAuthority(e.walletId);if(n.kind!==`resolved`)throw Error(`Select the owner wallet before enrolling VoiceID.`);let i=a(t,n.authority.authorityId);await l(i)?await $({kind:`activation`,scope:i,owner:await J(i,`activating`)},e.signal,e.onCapture,e.phrase):await f({kind:`activate`,scope:i,guard:await J(i,`activating`),snapshot:{kind:`missing`}},e.signal),e.signal.throwIfAborted();let o=await p(t);if(e.signal.aborted)throw o.fill(0),Error(`VoiceID activation was cancelled.`);return{kind:`activated`,publicKeyB64u:t.publicKeyB64u,deviceKeyId:t.deviceKeyId,factorSecret32:o}}async function ye(e){n();let{challenge:t}=e;if(t.requestOrigin!==location.origin||t.expiresAtMs<=Date.now())throw Error(`VoiceID challenge is expired or belongs to another Wallet origin.`);let r=await o(t.walletId,t.walletAuthMethodId);if(!r||r.deviceKeyId!==t.deviceKeyId)throw Error(`VoiceID device key is unavailable in this browser.`);if(await $({kind:`active`,scope:await d(t.walletId,t.walletAuthMethodId)},e.signal,e.onCapture,e.phrase),e.signal.throwIfAborted(),t.expiresAtMs<=Date.now())throw Error(`VoiceID challenge expired. Start unlock again.`);let i=await crypto.subtle.sign(`Ed25519`,r.privateKey,N(t)),a=await p(r);if(e.signal.aborted||t.expiresAtMs<=Date.now())throw a.fill(0),Error(`VoiceID unlock expired or was cancelled.`);return{kind:`unlocked`,assertion:re({kind:`voiceid_device_assertion_v1`,challenge:t,signatureB64u:_(new Uint8Array(i))}),factorSecret32:a}}async function $(n,r,a,o){let s=await c(n,r,a,o);switch(s.kind){case`matched`:return;case`insufficient_audio`:throw new t(s.quality);case`mismatch`:throw new e(s.quality);case`phrase_mismatch`:throw new i;default:return be(s)}}function be(e){throw Error(`Unexpected voice result: ${String(e)}`)}export{I as a,J as i,ye as n,ge as r,ve as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,c as t,d as n,f as r,h as i,l as a,m as o,p as s,s as c,t as l,u}from"./prompt-CCrXTRRx.js";import{IndexedDBManager as d,SEAMS_WALLET_STORES as f,WorkerDeferred as ee,availabilityKey as te,base64UrlDecode as p,base64UrlEncode as m,buildDelegatedWalletAuthorityV1 as h,buildFullOwnerPermissionsV1 as ne,isFiniteNumber as re,isPlainObject as g,parseStoredAuthMethodAvailability as _,parseVoiceIdDevicePublicKeyB64u as v,parseWalletAuthMethodV2StorageRow as y,parseWalletAuthorityStorageRow as ie,parseWalletSelectionStorageRow as ae,requireRecord as b,sameDelegatedWalletAuthorityV1 as oe,sha256DigestB64u as x,toError as S}from"../voiceid-host.js";const C=`e04dd7a6a1e23fc7b89e47682ea9d0a3946cf7bc59d07922c3db3efc52ae4269`,w=`redimnet-b1:${C}`,T=new o({path:`/sdk/voiceid/redimnet-b1.onnx`,sha256:C,bytes:8859593,label:`Speaker verification`});async function E(e){let t=await T.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 D(Array.from(t.data))}finally{for(let t of Object.values(e))t.dispose()}}finally{n.dispose()}}function D(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 O(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}const k=[T,s,a],A=[i,...k.map(se)];function se(e){return e.asset}function j(e,t){return e+t.size}var M=class{element=document.createElement(`section`);status=document.createElement(`p`);meter=document.createElement(`progress`);reveal;received=new Map;total=A.reduce(j,0);constructor(e){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.element.append(this.status,this.meter),this.status.textContent=`Loading saved VoiceID…`,this.reveal=setTimeout(e.append.bind(e,this.element),300)}settle=()=>{clearTimeout(this.reveal)};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 N(e){let t=new M(e);try{for(let e of A)await e.download(t.update.bind(t,e));t.preparing();for(let e of k)await e.prepare();t.ready()}finally{t.settle()}}function P(e,t){return`voiceid-browser-device-v1:${encodeURIComponent(e)}:${encodeURIComponent(t)}`}function F(e,t,n){return new TextEncoder().encode(JSON.stringify([`seams-voiceid-browser-factor-v1`,location.origin,e,t,n]))}async function I(e,t){let n=await d.getAppState(P(e,t));if(n===void 0)return null;let r=b(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=v(r.publicKeyB64u),l=await x(p(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 ce(e,t){return await navigator.locks.request(P(e,t),le.bind(null,e,t))}async function le(e,t){let n=await I(e,t);if(n)return n;let r=await crypto.subtle.generateKey({name:`Ed25519`},!1,[`sign`,`verify`]),i=v(m(new Uint8Array(await crypto.subtle.exportKey(`raw`,r.publicKey)))),a=await x(p(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:F(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 d.setAppState(P(e,t),l),l}finally{s.fill(0)}}async function L(e){let t=await crypto.subtle.decrypt({name:`AES-GCM`,iv:e.nonce,additionalData:F(e.walletId,e.walletAuthMethodId,e.deviceKeyId)},e.wrappingKey,e.ciphertext);return new Uint8Array(t)}const R=`voiceid-browser-enrollment-v1`,z=.2,B=[f.appState,f.walletSelections,f.walletAuthMethods,f.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 d.getWalletAuthMethodV2(t),r=await I(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(re))throw Error(`VoiceID template is invalid.`);let t=D(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=b(e,`VoiceID enrollment`),r=b(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!==w)return null;let i=W(n.baseline),a={kind:`baseline`};try{let e=b(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:w,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=D(n);for(let t=0;t<n.length;t+=1)n[t]=(1-z)*e[t]+z*r[t];return D(n)}function q(e,t){if(t.length!==3)throw Error(`Record three samples before saving voice improvements.`);for(let n of t)if(O(e,n)<.5)throw Error(`This sample differs from your original voice. Try again or re-record your enrollment.`);if(O(e,K(e,t))<.98)throw Error(`These samples differ too much from your original voice. Re-record your enrollment instead.`)}async function ue(e){let t=(await d.seamsWalletDB.getDB()).transaction(f.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 de(){let e=await d.getAppState(R);if(e===void 0)return null;let t=b(e,`Previous VoiceID enrollment`);return t.kind!==`browser_voiceid_enrollment_v1`||t.model!==w?null:W(t.template)}async function J(e,t,n){let r=ae(await e.objectStore(f.walletSelections).get(t.walletId)),i=ie(await e.objectStore(f.walletAuthorities).get(t.authorityId)),a=await e.objectStore(f.walletAuthMethods).get(t.walletAuthMethodId),o=y(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(f.appState).get(P(t.walletId,t.walletAuthMethodId)))?.value?.deviceKeyId!==t.deviceKeyId)throw Error(`VoiceID device changed. Start again.`);let s=_((await e.objectStore(f.appState).get(te(t.walletId,t.walletAuthMethodId)))?.value);if(!s.enabled)throw Error(`VoiceID is turned off.`);if(n){if(!oe(h({permissions:i.record.permissions}),h({permissions:ne()})))throw Error(`Full owner authority is required to change VoiceID enrollment.`);let a=y(await e.objectStore(f.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=y(await e.objectStore(f.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 d.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 fe(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 d.seamsWalletDB.getDB()).transaction(B,`readwrite`);try{await J(i,n,r);let e=i.objectStore(f.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:w,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 d.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(f.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 pe(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 pe(e){let t=e.objectStore(f.appState),n=await e.objectStore(f.walletAuthMethods).getAll();for(let e of n){if(!g(e)||e.kind!==`voiceid`)continue;let n=y(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 me(e,t){let n=document.querySelector(`.seams-voiceid-activation-surface`);if(!(n instanceof HTMLElement))throw Error(`Open VoiceID activation in the Wallet.`);await N(n),t.throwIfAborted();let r=new he(n,e,t);try{await r.result}finally{r.dispose()}}var he=class{completion=new ee;result=this.completion.promise;status;prompt;phrase=r(null);record;cancel;samples=[];phase=`ready`;get closed(){return this.phase===`closed`}controller=new AbortController;guardTimer;checkingGuard=!1;constructor(e,t,n){this.plan=t,this.signal=n,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 i=this.samples.length+1;try{c(),this.phase=`recording`,this.record.disabled=!0,this.status.textContent=`Opening microphone…`;let r=await e(this.controller.signal,this.prompt.capture);if(this.signal.aborted||this.closed){r.kind===`captured`&&r.samples.fill(0);return}if(r.kind===`insufficient_audio`){this.status.textContent=t(r.quality);return}if(this.plan.kind===`improve`&&r.quality.noise!==`normal`){r.samples.fill(0),this.status.textContent=`Use a quiet place to improve your voice enrollment.`;return}let i;try{if(await Y(this.plan.scope,this.plan.guard),this.status.textContent=`Checking your voice…`,(await n(r.samples,this.phrase)).kind===`mismatch`)throw new u;i=await E(r.samples)}finally{r.samples.fill(0)}if(this.signal.aborted||this.closed){i.fill(0);return}if(this.plan.kind===`improve`&&O(this.plan.snapshot.enrollment.baseline,i)<.5)throw i.fill(0),Error(`Your voice did not match the original enrollment. To replace it, return to Manage voice and choose Record voice again.`);let a=1;for(let e of this.samples)a=Math.min(a,O(e,i));this.status.dataset.voiceCapture=JSON.stringify({attemptId:r.quality.attemptId,capturedAtMs:r.quality.capturedAtMs,sample:this.samples.length+1,durationMs:r.quality.durationMs,recordingMs:r.quality.recordingMs,endedBy:r.quality.endedBy,voicedMs:r.quality.voicedMs,microphone:r.quality.microphone,processing:r.quality.processing,backgroundRms:r.quality.backgroundRms,speechToBackgroundDb:r.quality.speechToBackgroundDb,noise:r.quality.noise,minimumSimilarity:a});for(let e of this.samples)if(O(e,i)<.5)throw i.fill(0),Error(`This sample differs from the earlier samples. Use the same microphone and try again.`);if(this.samples.push(i),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 o=Array(192).fill(0);for(let e of this.samples)for(let t=0;t<o.length;t+=1)o[t]+=e[t]/3;this.phase=`committing`,this.prompt.title.textContent=`3 of 3 accepted`,this.status.textContent=`Saving voice enrollment…`;let s=this.plan;switch(s.kind){case`activate`:await Q(s.scope,s.guard,s.snapshot,{kind:`activate`,baseline:D(o)},this.controller.signal);break;case`replace`:await Q(s.scope,s.guard,s.snapshot,{kind:`replace`,baseline:D(o),confirmation:s.confirmation},this.controller.signal);break;case`improve`:await Q(s.scope,s.guard,s.snapshot,{kind:`improve`,samples:this.samples,confirmation:s.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(S(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<i&&(this.record.textContent=`Retry sample ${i}`,this.status.textContent=`Sample ${i} was not accepted. ${this.status.textContent??``}`),this.phrase=r(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(S(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 ge(t,r,i,a){delete document.body.dataset.voiceVerification;let o=await e(r,i);if(o.kind===`insufficient_audio`)return r.throwIfAborted(),o;try{r.throwIfAborted();let e=await n(o.samples,a),i=e.kind===`matched`,s=o.samples.length/16,c=await E(o.samples),l,u,d;try{r.throwIfAborted();let e=await fe(t,r);try{l=O(c,e.template),u=O(c,e.baseline),d=e.kind}finally{e.template.fill(0),e.baseline.fill(0)}}finally{c.fill(0)}return document.body.dataset.voiceVerification=JSON.stringify({attemptId:o.quality.attemptId,capturedAtMs:o.quality.capturedAtMs,durationMs:o.quality.durationMs,recordingMs:o.quality.recordingMs,endedBy:o.quality.endedBy,voicedMs:o.quality.voicedMs,microphone:o.quality.microphone,processing:o.quality.processing,backgroundRms:o.quality.backgroundRms,speechToBackgroundDb:o.quality.speechToBackgroundDb,noise:o.quality.noise,similarity:l,baselineSimilarity:u,referenceKind:d,modelInputMs:s,threshold:.5,phraseMatched:i,phraseRecognition:e.recognition,expectedPhrase:a}),l<.5?{kind:`mismatch`,quality:o.quality}:e.kind===`matched`?{kind:`matched`}:{kind:`phrase_mismatch`}}finally{o.samples.fill(0)}}export{de as a,V as c,I as d,N as f,Q as i,ce as l,ge as n,ue as o,Y as r,H as s,me as t,L as u};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import{f as e,g as t,i as n,n as r,r as i,t as a,u as o}from"./prompt-CCrXTRRx.js";import{SeamsWordmark as s,VOICE_ID_HOST_API_VERSION as c,WorkerDeferred as l,authMenuSuccessCopy as u,backIcon as d,createCspStylesheetManager as f,createWalletIframeSurfaceMeasurementReporter as p,getDefaultCspNonce as m,toError as h}from"../voiceid-host.js";const g=new WeakMap;var _=class{footer;constructor(e,t){this.prompt=t;let n=e.ownerDocument,a=g.get(n);a||(a=f({doc:n,baseCss:`
|
|
2
|
+
.seams-voiceid-activation-surface.seams-voiceid-unlock {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
border: 1px solid var(--seams-colors-borderPrimary, #303b41);
|
|
6
|
+
border-radius: var(--seams-shape-card, 24px);
|
|
7
|
+
background: var(--seams-colors-colorBackground, #192024);
|
|
8
|
+
color: var(--seams-colors-textPrimary, #eff2f3);
|
|
9
|
+
font-family: var(--seams-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
|
|
10
|
+
}
|
|
11
|
+
.seams-voiceid-unlock-header {
|
|
12
|
+
padding: 1rem 1.25rem 0;
|
|
13
|
+
}
|
|
14
|
+
.seams-voiceid-unlock-header .seams-menu-origin {
|
|
15
|
+
display: flex;
|
|
16
|
+
align-items: center;
|
|
17
|
+
gap: 0.5rem;
|
|
18
|
+
margin: 0 0 0.5rem;
|
|
19
|
+
font-size: 0.8125rem;
|
|
20
|
+
color: var(--seams-colors-textSecondary, #9cabb3);
|
|
21
|
+
}
|
|
22
|
+
.seams-voiceid-unlock-header .seams-menu-origin svg {
|
|
23
|
+
width: 14px;
|
|
24
|
+
height: 14px;
|
|
25
|
+
}
|
|
26
|
+
.seams-voiceid-unlock-back {
|
|
27
|
+
display: grid;
|
|
28
|
+
place-items: center;
|
|
29
|
+
width: 44px;
|
|
30
|
+
height: 44px;
|
|
31
|
+
margin-inline-start: -0.5rem;
|
|
32
|
+
padding: 0;
|
|
33
|
+
border: 0;
|
|
34
|
+
border-radius: var(--seams-shape-control, 10px);
|
|
35
|
+
background: transparent;
|
|
36
|
+
color: var(--seams-colors-textSecondary, #9cabb3);
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
}
|
|
39
|
+
.seams-voiceid-unlock-back svg {
|
|
40
|
+
width: 20px;
|
|
41
|
+
height: 20px;
|
|
42
|
+
}
|
|
43
|
+
.seams-voiceid-unlock-back:focus-visible {
|
|
44
|
+
outline: none;
|
|
45
|
+
color: var(--seams-colors-textPrimary, #eff2f3);
|
|
46
|
+
}
|
|
47
|
+
.seams-voiceid-unlock .seams-voiceid-prompt {
|
|
48
|
+
width: 100%;
|
|
49
|
+
border: 0;
|
|
50
|
+
border-radius: 0;
|
|
51
|
+
background: transparent;
|
|
52
|
+
padding: 0.75rem 1.5rem 1.5rem;
|
|
53
|
+
grid-template-rows: auto minmax(6rem, auto) 5rem minmax(3.375rem, auto) auto auto;
|
|
54
|
+
}
|
|
55
|
+
.seams-voiceid-unlock .seams-voiceid-record-slot:has(button[hidden]) {
|
|
56
|
+
display: none;
|
|
57
|
+
}
|
|
58
|
+
.seams-voiceid-unlock-footer {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: baseline;
|
|
61
|
+
justify-content: center;
|
|
62
|
+
gap: 0.375rem;
|
|
63
|
+
padding: 0.625rem 1rem;
|
|
64
|
+
border-top: 1px solid color-mix(in srgb, var(--seams-colors-borderPrimary, #303b41) 60%, transparent);
|
|
65
|
+
color: var(--seams-colors-textSecondary, #9cabb3);
|
|
66
|
+
font-size: 0.6875rem;
|
|
67
|
+
line-height: 1rem;
|
|
68
|
+
letter-spacing: 0.01em;
|
|
69
|
+
}
|
|
70
|
+
.seams-voiceid-unlock-footer .seams-receipt-wordmark {
|
|
71
|
+
flex: none;
|
|
72
|
+
width: 3.125rem;
|
|
73
|
+
height: 0.625rem;
|
|
74
|
+
}
|
|
75
|
+
@media (hover: hover) {
|
|
76
|
+
.seams-voiceid-unlock-back:hover {
|
|
77
|
+
color: var(--seams-colors-textPrimary, #eff2f3);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
`,nonce:m}),g.set(n,a)),a.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(),r(d(),t.cancel),o.append(t.cancel),e.prepend(o),this.footer=n.createElement(`div`),this.footer.className=`seams-voiceid-unlock-footer`,r([i(`span`,null,`Secured by`),` `,i(s,{})],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(){r(null,this.prompt.cancel),r(null,this.footer)}},v=class{result;completion=new l;controller=new AbortController;element;activateButton;cancelButton;status;prompt;unlockFrame;unmountCapture;measurement;phrase=e(null);state={kind:`preparing`};settlement=`closed`;expiryTimer=null;constructor(e,t,n,r){let i=t===`activation`?`Activate VoiceID`:`Unlock with VoiceID`,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`,i),this.prompt=new a(document,i,this.phrase),this.element.append(this.prompt.element),this.unlockFrame=t===`unlock`?new _(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||o.appendChild(this.element),this.measurement=!r&&n.kind===`wallet_iframe`?p({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(x),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(h(e))}}begin=()=>{if(this.state.kind!==`ready`)return;let e=this.state.capture;this.state={kind:`capturing`},this.perform(e)};async perform(r){this.activateButton.disabled=!0,this.status.textContent=`Opening microphone…`;try{let e=await r.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(i){if(this.state.kind===`closed`)return;if(i instanceof n||i instanceof o||i instanceof t){if(r.expiresAtMs!==null&&Date.now()>=r.expiresAtMs){this.expire();return}let t=this.phrase;this.phrase=e(t),this.prompt.setPhrase(this.phrase),this.state={kind:`ready`,capture:r},this.activateButton.hidden=!1,this.activateButton.textContent=`Try again`,this.prompt.ready(i.message),this.activateButton.focus();return}this.state={kind:`closed`},this.completion.reject(h(i))}}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=u(`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 y))};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.`)))}},y=class extends Error{constructor(){super(`VoiceID capture was cancelled.`),this.name=`VoiceIdCaptureCancelledError`}};async function b(e){let t=new v(e.prepare,e.purpose,e.measurement,e.mountCapture);try{return await t.result}finally{t.dispose()}}function x(e){requestAnimationFrame(S.bind(null,e))}function S(e){setTimeout(e,0)}const C=1;if(c!==1)throw Error(`VoiceID requires a matching Wallet host API.`);const w={unlock:T,activate:D,review:k};function T(e){return b({purpose:`unlock`,measurement:e.surfaceMeasurementBinding,mountCapture:e.mountCapture,prepare:E.bind(null,e)})}async function E(e,t,n){let r=await import(`./unlock-E7YHqBGT.js`);return t.throwIfAborted(),r.prepareUnlockSurface(e,t,n)}async function D(e){try{return await b({purpose:`activation`,measurement:e.context.signingEngine.getWalletIframeSurfaceMeasurementBinding(),prepare:O.bind(null,e)})}catch(e){if(e instanceof y)return{kind:`cancelled`};throw e}}async function O(e,t){let n=await import(`./addVoiceId-CeBXVHqs.js`);return t.throwIfAborted(),n.prepareActivationSurface(e,t)}async function k(e,t){return(await import(`./approval-CCbdLhTv.js`)).voiceIdPolicyForRequest(e,t)}export{C as hostApiVersion,w as voiceIdHostPlugin};
|