yv-voice-capture-web 1.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Youverse
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.
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ ![https://yk-website-images.s3.eu-west-1.amazonaws.com/LogoV4_TRANSPARENT.png](https://yk-website-images.s3.eu-west-1.amazonaws.com/LogoV4_TRANSPARENT.png)
2
+
3
+ # Youverse Voice Capture Component
4
+
5
+ [![License](https://img.shields.io/github/license/dev-yoonik/yv-voice-capture-web)](https://github.com/dev-yoonik/yv-voice-capture-web/blob/master/LICENSE)
6
+ [![Version](https://img.shields.io/github/v/release/dev-yoonik/yv-voice-capture-web?display_name=tag)](https://github.com/dev-yoonik/yv-voice-capture-web)
7
+
8
+ A lightweight web component that records voice directly in the browser and outputs WAV audio files.
9
+
10
+ ## Getting Started
11
+
12
+ ```
13
+ npm install yv-voice-capture-web
14
+ ```
15
+
16
+ ## License token (JWT) setup
17
+
18
+ Before using this component, you must obtain a valid license token (JWT) from your backend service.
19
+
20
+ 1. **Send an HTTP GET request** to the authentication endpoint:
21
+ - **Endpoint**: `https://web-sdk.youverse.id/auth-token`
22
+ - **Headers**:
23
+ - `x-api-key`: Your API key (get it from your Youverse dashboard at [https://www.youverse.id/](https://www.youverse.id/))
24
+ - **Parameters**:
25
+ - `customer_bind`: Customer identifier required by the service
26
+
27
+ 2. **Response**: Backend returns authentication payload containing the JWT token.
28
+
29
+ 3. **Use the token** as the `license` attribute:
30
+ ```html
31
+ <youverse-voice-capture license="JWT_TOKEN" ...></youverse-voice-capture>
32
+ ```
33
+
34
+ ## Integration via NPM
35
+
36
+ Install `yv-voice-capture-web`:
37
+
38
+ ```
39
+ npm i yv-voice-capture-web
40
+ ```
41
+
42
+ Import the component module into your `.js` file:
43
+
44
+ ```javascript
45
+ // If you use module bundler
46
+ import 'yv-voice-capture-web';
47
+
48
+ // If you don't use module bundler
49
+ import './node_modules/yv-voice-capture-web/js/dist/youverse-voice-capture.min.js';
50
+ ```
51
+
52
+ Add the component name to the `.html` file.
53
+
54
+ ```html
55
+ <youverse-voice-capture
56
+ license="JWT_TOKEN"
57
+ locale="en"
58
+ max-duration="5"
59
+ ></youverse-voice-capture>
60
+ ```
61
+
62
+ ## Integration via CDN
63
+
64
+ Connect the script in your `.html` file. Here is the CDN link: `https://www.jsdelivr.com/package/npm/:package@:version/:file`
65
+
66
+ For example:
67
+
68
+ ```html
69
+ <script src="https://cdn.jsdelivr.net/npm/yv-voice-capture-web@latest/js/dist/youverse-voice-capture.min.js"></script>
70
+ ```
71
+
72
+ Add the component name to the `.html` file.
73
+
74
+ ```html
75
+ <youverse-voice-capture
76
+ license="JWT_TOKEN"
77
+ locale="en"
78
+ max-duration="5"
79
+ ></youverse-voice-capture>
80
+ ```
81
+
82
+ ## Attributes
83
+
84
+ **Attribute** | **Info** | **Data type** | **Default Value** | **Values**
85
+ ------------------|------------------------------------------------------------------|---------------|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
86
+ **license** | JWT license token required to authorize the component | string | - | string (required)
87
+ **locale** | The language of the component interface | string | en | en, pt, es, ru, de, pl, it, hu, zh, sk, uk, fr, ar, nl, id, vi, ko, ms, ro, el, tr, ja, cs, th, hi, bn, he, fi, sv, da, hr, no
88
+ **max-duration** | Maximum recording duration in seconds | number | 5 | Any positive number
89
+ **title-text** | Text for the component title. Translation based on the language selected | string | Voice verification | string
90
+ **info-text** | Text for the component info. Translation based on the language selected | string | Tap to record your voice | string
91
+
92
+ ## Events
93
+
94
+ You can subscribe to the component events.
95
+
96
+ For example:
97
+
98
+ ```javascript
99
+ document.addEventListener('YV_VOICE_EVENT', (event) => {
100
+ console.log(event.detail);
101
+ // event.detail contains:
102
+ // - audio: Blob (WAV format)
103
+ // - metadata: Object (for attestation)
104
+
105
+ // Example: Download the recorded audio
106
+ const url = URL.createObjectURL(event.detail.audio);
107
+ const a = document.createElement('a');
108
+ a.href = url;
109
+ a.download = 'recording.wav';
110
+ a.click();
111
+ });
112
+ ```
113
+
114
+ ### Type of events:
115
+
116
+ | **Event** | **Description** | **Event Handling** |
117
+ |-------------------|---------------------------------------------|--------------------------------------------------|
118
+ | **YV_VOICE_EVENT**| Event triggered when voice recording stops | Handled by a designated event listener in the application (listener) |
119
+
120
+ ### Event Detail Properties:
121
+
122
+ | **Property** | **Type** | **Description** |
123
+ |--------------|----------|----------------------------------------|
124
+ | **audio** | Blob | The recorded audio in WAV format |
125
+ | **metadata** | Object | Metadata object for attestation |
126
+
127
+ ### Metadata Object Structure:
128
+
129
+ | **Property** | **Type** | **Description** |
130
+ |---------------|----------|--------------------------------------------------|
131
+ | **session** | string | Session identifier |
132
+ | **upload** | Object | Upload metadata (hash, ts, nonce) |
133
+ | **signature** | string | Cryptographic signature for verification |
134
+
135
+ ## Attest payload with your backend service
136
+
137
+ Before validating the payload, you must send the captured data to the attestation endpoint from your backend service.
138
+
139
+ 1. **Send an HTTP POST request** to the attestation endpoint:
140
+ - **Endpoint**: `https://web-sdk.youverse.id/attest`
141
+ - **Payload**:
142
+ - `metadata`: Metadata object generated by the component
143
+ - `audio`: Captured audio data (base64 encoded)
144
+
145
+ 2. **Response**: Backend returns an attestation result indicating whether the payload is valid and trusted.
146
+
147
+ For more information please [contact us](mailto:tech@youverse.id).
package/css/styles.css ADDED
@@ -0,0 +1,5 @@
1
+ @import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap");
2
+
3
+ /*! tailwindcss v2.2.19 | MIT License | https://tailwindcss.com*/
4
+
5
+ /*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */html{-webkit-text-size-adjust:100%;line-height:1.15;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;margin:0}hr{color:inherit;height:0}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,select{text-transform:none}[type=button],button{-webkit-appearance:button}::-moz-focus-inner{border-style:none;padding:0}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}button{background-color:transparent;background-image:none}fieldset,ol,ul{margin:0;padding:0}ol,ul{list-style:none}html{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{font-family:inherit;line-height:inherit}*,:after,:before{border:0 solid;-webkit-box-sizing:border-box;box-sizing:border-box}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#9ca3af;opacity:1}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#9ca3af;opacity:1}input::-ms-input-placeholder,textarea::-ms-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}button{cursor:pointer}table{border-collapse:collapse}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,optgroup,select,textarea{color:inherit;line-height:inherit;padding:0}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}*,:after,:before{--tw-border-opacity:1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.absolute{position:absolute}.relative{position:relative}.inset-0{bottom:0;left:0;right:0;top:0}.z-10{z-index:10}.m-auto{margin:auto}.mx-auto{margin-left:auto;margin-right:auto}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-10{margin-top:2.5rem}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.table{display:table}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-12{height:3rem}.h-24{height:6rem}.h-32{height:8rem}.h-40{height:10rem}.h-64{height:16rem}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-12{width:3rem}.w-24{width:6rem}.w-32{width:8rem}.w-40{width:10rem}.w-64{width:16rem}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.flex-1{-webkit-box-flex:1;-ms-flex:1 1 0%;flex:1 1 0%}@-webkit-keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes ping{75%,to{opacity:0;-webkit-transform:scale(2);transform:scale(2)}}@keyframes ping{75%,to{opacity:0;-webkit-transform:scale(2);transform:scale(2)}}@-webkit-keyframes pulse{50%{opacity:.5}}@-webkit-keyframes bounce{0%,to{-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1);-webkit-transform:translateY(-25%);transform:translateY(-25%)}50%{-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1);-webkit-transform:none;transform:none}}@keyframes bounce{0%,to{-webkit-animation-timing-function:cubic-bezier(.8,0,1,1);animation-timing-function:cubic-bezier(.8,0,1,1);-webkit-transform:translateY(-25%);transform:translateY(-25%)}50%{-webkit-animation-timing-function:cubic-bezier(0,0,.2,1);animation-timing-function:cubic-bezier(0,0,.2,1);-webkit-transform:none;transform:none}}.animate-spin{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}.flex-col{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.gap-2{gap:.5rem}.overflow-hidden{overflow:hidden}.rounded-full{border-radius:9999px}.border-4{border-width:4px}.border-purple-200{--tw-border-opacity:1;border-color:rgba(221,214,254,var(--tw-border-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.hover\:bg-purple-50:hover{--tw-bg-opacity:1;background-color:rgba(245,243,255,var(--tw-bg-opacity))}.p-4{padding:1rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-8{padding-left:2rem;padding-right:2rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.pb-8{padding-bottom:2rem}.text-center{text-align:center}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-5xl{font-size:3rem;line-height:1}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.text-white{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgba(107,114,128,var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgba(75,85,99,var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgba(17,24,39,var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgba(239,68,68,var(--tw-text-opacity))}.text-purple-700{--tw-text-opacity:1;color:rgba(109,40,217,var(--tw-text-opacity))}*,:after,:before{--tw-shadow:0 0 #0000}.shadow-xl{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);-webkit-box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}*,:after,:before{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000}.filter{--tw-blur:var(--tw-empty,/*!*/ /*!*/);--tw-brightness:var(--tw-empty,/*!*/ /*!*/);--tw-contrast:var(--tw-empty,/*!*/ /*!*/);--tw-grayscale:var(--tw-empty,/*!*/ /*!*/);--tw-hue-rotate:var(--tw-empty,/*!*/ /*!*/);--tw-invert:var(--tw-empty,/*!*/ /*!*/);--tw-saturate:var(--tw-empty,/*!*/ /*!*/);--tw-sepia:var(--tw-empty,/*!*/ /*!*/);--tw-drop-shadow:var(--tw-empty,/*!*/ /*!*/);-webkit-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px rgba(0,0,0,.1)) drop-shadow(0 1px 1px rgba(0,0,0,.06))}.transition-colors{-webkit-transition-duration:.15s;transition-duration:.15s;-webkit-transition-property:background-color,border-color,color,fill,stroke;transition-property:background-color,border-color,color,fill,stroke;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{-webkit-transition-duration:.15s;transition-duration:.15s;-webkit-transition-property:-webkit-transform;transition-property:-webkit-transform;transition-property:transform;transition-property:transform,-webkit-transform;-webkit-transition-timing-function:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1)}*{font-family:Roboto,Helvetica,Arial,sans-serif;margin:0;padding:0}.voice-container{margin:0 auto;max-width:100%;min-height:300px;overflow:hidden;position:relative;width:100%}.voice-visualizer{max-width:300px;width:100%}.voice-bar{max-height:60px;min-height:4px;width:8px}.record-btn:active,.stop-btn:active{-webkit-transform:scale(.95);transform:scale(.95)}@-webkit-keyframes fade-in{0%{opacity:0;-webkit-transform:translateY(10px);transform:translateY(10px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes fade-in{0%{opacity:0;-webkit-transform:translateY(10px);transform:translateY(10px)}to{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.animate-fade-in{-webkit-animation:fade-in .3s ease-out;animation:fade-in .3s ease-out}@-webkit-keyframes fade-out{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(10px);transform:translateY(10px)}}@keyframes fade-out{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}to{opacity:0;-webkit-transform:translateY(10px);transform:translateY(10px)}}.animate-fade-out{-webkit-animation:fade-out .5s ease-in forwards;animation:fade-out .5s ease-in forwards}@keyframes pulse{0%,to{opacity:1}50%{opacity:.7}}.animate-pulse{-webkit-animation:pulse 1.5s ease-in-out infinite;animation:pulse 1.5s ease-in-out infinite}.inner-circle{background:#d7ddf1b0;border:1px solid #c9b1de8a}@media (min-width:640px){.sm\:px-8{padding-left:2rem;padding-right:2rem}}
@@ -0,0 +1,41 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>Youverse Voice Capture</title>
8
+ <script src="../js/dist/youverse-voice-capture.min.js"></script>
9
+
10
+ <style>
11
+ body {
12
+ margin: 0;
13
+ }
14
+ </style>
15
+ </head>
16
+
17
+ <body>
18
+ <div>
19
+ <youverse-voice-capture license="Your.Jwt.License" locale="en" />
20
+ </div>
21
+ </body>
22
+
23
+ <script>
24
+ const EVENT_TYPES = {
25
+ YV_VOICE_EVENT: "YV_VOICE_EVENT",
26
+ };
27
+
28
+ document.addEventListener(EVENT_TYPES.YV_VOICE_EVENT, function (event) {
29
+ console.log("YV_VOICE_EVENT", event.detail);
30
+ // event.detail contains: { audio: Blob, metadata: Object }
31
+
32
+ // Example: Download the recorded audio
33
+ /* const url = URL.createObjectURL(event.detail.audio);
34
+ const a = document.createElement('a');
35
+ a.href = url;
36
+ a.download = 'recording.wav';
37
+ a.click(); */
38
+ });
39
+ </script>
40
+
41
+ </html>
package/index.html ADDED
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
6
+ <meta name="viewport" content="width=device-width,initial-scale=1.0" />
7
+ <title>Youverse Voice Capture</title>
8
+ </head>
9
+ <body>
10
+ <div id="app"></div>
11
+ </body>
12
+ </html>