biometry-sdk 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,25 @@
1
1
  # biometry-sdk
2
2
 
3
3
  ## Overview
4
- The **Biometry Web SDK** is a software development kit (SDK) designed to facilitate the integration of Biometry's API services.
4
+ The **Biometry Web SDK** is a software development kit designed to simplify the integration of Biometry's API services into your web application. Providing tools, UI components, and utilities enables biometric onboarding (face and voice), liveness checks, and user consent.
5
+
5
6
 
6
7
  ## Features
7
- - **Consent management**: Ask a permission to store their biometric data for authentication using Biometry.
8
- - **Voice onboarding**: Onboard voice for Voice Recognition.
8
+ - **Consent Management**:
9
+ - Ask a permission to store their biometric data for authentication using Biometry.
10
+ - Collect user permission to store their biometric data for authentication using Biometry.
11
+ - Important: You must obtain consent before performing any onboarding or video processing.
12
+ - **Voice onboarding**:
13
+ - Enroll a user’s voice, creating a voice model for future authentication.
9
14
  - **Face onboarding**: Onboard face for face recognition.
10
- - Includes a customizable **Face Onboarding UI Component** for streamlined user interactions.
11
- - **Face match**: Compares extracted image from user’s personal document with the frame from the `/process-video.`
12
- - **Process video**: Process the video through Biometry services to check liveness and authorize user.
13
- - (UI Component for this feature coming soon)
15
+ - Onboard a user’s face for facial recognition.
16
+ - **Face Onboarding UI Component:** A ready-to-use, customizable component for capturing and processing face data.
17
+ - **Face match**:
18
+ - Compares an extracted image from a user’s personal document to an image frame captured during onboarding or `/process-video.`
19
+ - **Process video**:
20
+ - Checks user liveness and authorizes users based on video input.
21
+ - **Process Video UI Component:** A ready-to-use, customizable component for capturing and processing video.
22
+
14
23
 
15
24
  ## Installation
16
25
  ```bash
@@ -33,31 +42,30 @@ console.log(response);
33
42
 
34
43
  ## Example
35
44
 
36
- You can find an example in the example/ directory. The example demonstrates how to integrate the SDK into a React app.
37
-
45
+ You can find an example in the example/ directory. The example demonstrates how you might integrate the BiometrySDK in a React component with the state.
38
46
  ## UI Components
39
- The **Biometry Web SDK** includes reusable and customizable web components for key features. These components make it simple to add biometric functionalities to your application.
47
+ The Biometry Web SDK includes reusable, customizable web components for crucial features. These components are easy to embed into your application and handle the most common biometric operations with minimal setup.
40
48
 
41
49
  ### Face Onboarding Component
42
- The `Face Onboarding` component provides an intuitive interface for onboarding users with their camera. It integrates with the `BiometrySDK` to handle backend communication and error states.
50
+ This component provides an intuitive interface for onboarding users with their cameras. It integrates directly with the `BiometrySDK backend`, managing camera capture, consent checks, and error handling.
43
51
 
44
52
  ### Integration
45
53
  Here's how to integrate the `Face Onboarding` component into your application:
46
54
 
47
55
  **Option 1: Using npm (Recommended for full SDK usage)**
48
56
  1. Install the SDK package via **npm**:
49
- ```bash
50
- npm install biometry-sdk
51
- ```
57
+ ```bash
58
+ npm install biometry-sdk
59
+ ```
52
60
  2. Import the component in your **index.js** or equivalent JavaScript file:
53
- ```javascript
54
- // index.js
55
- import './node_modules/biometry-sdk/dist/components/biometry-onboarding.js';
56
- ```
61
+ ```javascript
62
+ // index.js
63
+ import './node_modules/biometry-sdk/dist/components/biometry-onboarding.js';
64
+ ```
57
65
  3. Connect the script to your **HTML file** and use the component:
58
- ```html
59
- <script type="module" src="./index.js"></script>
60
- ```
66
+ ```html
67
+ <script type="module" src="./index.js"></script>
68
+ ```
61
69
 
62
70
 
63
71
  **Option 2: Using CDN (Quick Integration)**
@@ -66,9 +74,14 @@ import './node_modules/biometry-sdk/dist/components/biometry-onboarding.js';
66
74
  ```
67
75
 
68
76
  ### Usage
69
- The `api-key` and `user-fullname` attributes are required for the component to function.
77
+ **Required attributes:**
78
+ - `api-key`: Your Biometry API key.
79
+ - `user-fullname`: The user’s full name (used in data storage and consent).
70
80
 
71
- Custom slots allow you to style and customize UI elements, loading, success, and error states.
81
+ **Slots:**
82
+ - `video`: Your custom <video> element.
83
+ - `button`: Custom capture button.
84
+ - `loading`, `success`, `error-no-face`, `error-multiple-faces`, `error-not-centered`, `error-other`: Custom UI messages for different states.
72
85
 
73
86
  **Basic Usage**
74
87
  ```html
@@ -98,38 +111,31 @@ Custom slots allow you to style and customize UI elements, loading, success, and
98
111
  ```
99
112
 
100
113
  ### Process Video Component
101
- The Process Video component allows developers to record, upload, and process video directly within their applications through Biometry services to check liveness and authorize user.
114
+ The **Process Video** component enables you to record, upload, and process a video within your application. It integrates with Biometry's services to check liveness and authorize the user.
102
115
 
103
116
  ### Integration
104
117
  **Option 1: Install via npm**
105
-
106
118
  1. To include the component in your project, install the biometry-sdk package:
107
- ```bash
108
- npm install biometry-sdk
109
- ```
110
-
119
+ ```bash
120
+ npm install biometry-sdk
121
+ ```
111
122
  2. After installation, import the component into your project:
112
- ```javascript
113
- // index.js
114
- import './node_modules/biometry-sdk/dist/components/process-video.js';
115
- ```
116
-
123
+ ```javascript
124
+ // index.js
125
+ import './node_modules/biometry-sdk/dist/components/process-video.js'
126
+ ```
117
127
  3. Include the component in your HTML:
118
- ```html
119
- <script type="module" src="./index.js"></script>
120
- <process-video ...></process-video>
121
- ```
122
-
123
- **Option 2: Import directly via CDN**
124
-
125
- You can skip the npm installation and include the component directly in your HTML:
128
+ You can skip the npm installation and include the component directly in your HTML:
129
+ ```html
130
+ <script type="module" src="./index.js"></script>
131
+ <process-video ...></process-video>
132
+ ```
133
+ **Option 2: Using CDN (Quick Integration)**
126
134
  ```html
127
135
  <script type="module" src="https://cdn.jsdelivr.net/npm/biometry-sdk/dist/components/process-video.js"></script>
128
136
  <process-video ...></process-video>
129
137
  ```
130
-
131
138
  ### Usage
132
-
133
139
  **Basic Usage**
134
140
  ```html
135
141
  <process-video
@@ -163,16 +169,35 @@ You can skip the npm installation and include the component directly in your HTM
163
169
  <div slot="success">Video submitted successfully!</div>
164
170
  </process-video>
165
171
  ```
166
-
167
- **Notes**
168
- - By default, all elements are functional without customization. Replace slots only if customization is required.
169
-
170
- - To regenerate the video preview or handle custom actions, use JavaScript to interact with the provided slots or the component's public methods.
171
-
172
+ **Note:**
173
+ - All default elements and messages are functional out-of-the-box.
174
+ - Replace slots if you want to customize the UI or functionality.
175
+ - Call giveConsent() before using any biometric methods to ensure compliance with data processing requirements.
176
+
177
+ ## Best Practices
178
+ 1. **Always Acquire Consent**
179
+ - Before performing Face Onboarding or Process Video, you can call:
180
+ ```javascript
181
+ sdk.giveConsent(true, userFullName);
182
+ ```
183
+ - Or directly send a request to the `/consent` in the [official documentation](https://developer.biometrysolutions.com/overview/).
184
+
185
+ This ensures legal compliance and user awareness when storing and processing biometric data.
186
+ 3. **Handle Errors Gracefully**
187
+ - The SDK methods throw errors if something goes wrong (e.g., network, permission, or detection errors). Use try/catch or .catch() to handle them.
188
+ 4. **Security**
189
+ - Protect your API key. Avoid exposing it in public repositories or client-side code if possible.
190
+
172
191
  ## License
173
192
 
174
193
  This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
175
194
 
176
195
  ## More Information
177
-
178
- For more detailed documentation on the Biometry API, visit the [official documentation](https://developer.biometrysolutions.com/overview/).
196
+ For more detailed information on Biometry’s API endpoints, parameters, and responses, visit the official [Biometry API Documentation](https://developer.biometrysolutions.com/overview/). If you have questions or need help, please reach out to our support team or create a GitHub issue.
197
+
198
+ ## Quick Reference
199
+ - Install: `npm install biometry-sdk`
200
+ - Consent: `sdk.giveConsent(true, userFullName)` (Required before onboarding/processing)
201
+ - Voice Onboarding: `sdk.enrollVoice(file, userFullName)`
202
+ - Face Onboarding: `sdk.enrollFace(file, userFullName)`
203
+ - Process Video: `sdk.processVideo(file, phrase, userFullName)`
package/dist/sdk.js CHANGED
@@ -42,7 +42,7 @@ export class BiometrySDK {
42
42
  is_consent_given: isConsentGiven,
43
43
  user_fullname: userFullName,
44
44
  };
45
- const response = await this.request('/consent', 'POST', body);
45
+ const response = await this.request('/api-consent/consent', 'POST', body);
46
46
  return {
47
47
  is_consent_given: response.is_consent_given,
48
48
  user_fullname: response.user_fullname,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "biometry-sdk",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -1,51 +0,0 @@
1
- export declare class ProcessVideoComponent extends HTMLElement {
2
- private sdk;
3
- private apiKey;
4
- private phrase;
5
- private previewStream;
6
- private recordedChunks;
7
- private mediaRecorder;
8
- private videoFile;
9
- private timerInterval;
10
- private recordingTimeout;
11
- private videoElement;
12
- private fileInput;
13
- private recordButton;
14
- private stopButton;
15
- private submitButton;
16
- private errorState;
17
- private timeLimit;
18
- constructor();
19
- private initializeSDK;
20
- connectedCallback(): void;
21
- disconnectedCallback(): void;
22
- attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
23
- private generateDefaultPhrase;
24
- initializeUI(): void;
25
- private attachSlotListeners;
26
- private getSlotElement;
27
- replaceSlotContent(slotName: string, content: string | HTMLElement): void;
28
- removeSlotListener(slotName: string, event: string, callback: EventListener): void;
29
- private toggleState;
30
- private convertPhraseToWords;
31
- private setupPreview;
32
- private startTimer;
33
- private stopTimer;
34
- startRecording(): Promise<void>;
35
- stopRecording(): void;
36
- private handleFileUpload;
37
- handleSubmit(): Promise<void>;
38
- static get observedAttributes(): string[];
39
- get userFullname(): string | null;
40
- set userFullname(value: string | null);
41
- get isRecording(): boolean;
42
- get currentPhrase(): string;
43
- get videoDuration(): number | null;
44
- get currentFile(): File | null;
45
- get currentStream(): MediaStream | null;
46
- set sdkInstance(newSdk: any);
47
- get videoElementRef(): HTMLVideoElement;
48
- get fileInputRef(): HTMLInputElement;
49
- get recordingTimeLimit(): number;
50
- set recordingTimeLimit(value: number);
51
- }
@@ -1,452 +0,0 @@
1
- import { BiometrySDK } from "../sdk.js";
2
- export class ProcessVideoComponent extends HTMLElement {
3
- constructor() {
4
- super();
5
- this.apiKey = null;
6
- this.previewStream = null;
7
- this.recordedChunks = [];
8
- this.mediaRecorder = null;
9
- this.videoFile = null;
10
- this.timerInterval = null;
11
- this.recordingTimeout = null;
12
- this.errorState = null;
13
- this.timeLimit = 30;
14
- this.phrase = this.generateDefaultPhrase();
15
- // Attach shadow DOM and initialize UI
16
- this.attachShadow({ mode: 'open' });
17
- this.apiKey = this.getAttribute('api-key');
18
- this.initializeSDK();
19
- this.initializeUI();
20
- }
21
- initializeSDK() {
22
- if (this.apiKey) {
23
- this.sdk = new BiometrySDK(this.apiKey);
24
- }
25
- else {
26
- this.toggleState('error');
27
- console.error('API key is required to initialize the SDK.');
28
- }
29
- }
30
- connectedCallback() {
31
- if (this.apiKey) {
32
- this.initializeSDK();
33
- }
34
- else {
35
- console.error('API key is required.');
36
- }
37
- }
38
- disconnectedCallback() {
39
- this.stopRecording();
40
- if (this.previewStream) {
41
- this.previewStream.getTracks().forEach(track => track.stop());
42
- }
43
- }
44
- attributeChangedCallback(name, oldValue, newValue) {
45
- if (name === 'api-key' && newValue !== oldValue) {
46
- this.apiKey = newValue;
47
- this.initializeSDK();
48
- }
49
- }
50
- generateDefaultPhrase() {
51
- return Math.random().toString().slice(2, 10); // 8-digit random phrase
52
- }
53
- initializeUI() {
54
- const phraseDisplay = this.phrase
55
- .split("")
56
- .map((digit) => `<span class="digit">${digit}</span>`)
57
- .join(" ");
58
- this.shadowRoot.innerHTML = `
59
- <style>
60
- :host {
61
- display: block;
62
- font-family: Arial, sans-serif;
63
- --primary-color: #007bff;
64
- --secondary-color: #6c757d;
65
- --button-bg: var(--primary-color);
66
- --button-text-color: #fff;
67
- --input-border-color: var(--secondary-color);
68
- --input-focus-border-color: var(--primary-color);
69
- --spacing: 16px;
70
- --button-padding: 10px 20px;
71
- --border-radius: 4px;
72
- }
73
-
74
- .container {
75
- display: flex;
76
- flex-direction: column;
77
- align-items: center;
78
- justify-content: center;
79
- gap: var(--spacing);
80
- padding: var(--spacing);
81
- max-width: 500px;
82
- margin: 0 auto;
83
- text-align: center;
84
- }
85
-
86
- .video-wrapper {
87
- position: relative;
88
- display: inline-block;
89
- }
90
-
91
- #timer-overlay {
92
- position: absolute;
93
- top: 10px;
94
- left: 10px;
95
- background-color: rgba(0, 0, 0, 0.7);
96
- color: white;
97
- padding: 5px 10px;
98
- border-radius: 4px;
99
- font-family: Arial, sans-serif;
100
- font-size: 14px;
101
- }
102
-
103
- video {
104
- max-width: 100%;
105
- border-radius: var(--border-radius);
106
- }
107
-
108
- input[type="text"], input[type="file"] {
109
- padding: var(--button-padding);
110
- border: 1px solid var(--input-border-color);
111
- border-radius: var(--border-radius);
112
- width: 100%;
113
- max-width: 100%;
114
- }
115
-
116
- input[type="text"]:focus, input[type="file"]:focus {
117
- outline: none;
118
- border-color: var(--input-focus-border-color);
119
- }
120
-
121
- .hidden {
122
- display: none;
123
- }
124
-
125
- .phrase-display {
126
- font-size: 24px;
127
- font-weight: bold;
128
- display: flex;
129
- gap: 8px;
130
- justify-content: center;
131
- }
132
- .digit {
133
- padding: 4px;
134
- border: 1px solid #ccc;
135
- border-radius: 4px;
136
- text-align: center;
137
- width: 24px;
138
- }
139
-
140
- </style>
141
- <div class="container">
142
- <slot name="video">
143
- <div class="video-wrapper">
144
- <video id="video-preview" muted autoplay></video>
145
- <div id="timer-overlay" class="hidden">00:00</div>
146
- </div>
147
- </slot>
148
- <slot name="phrase-display">
149
- <div class="phrase-display">
150
- ${phraseDisplay}
151
- </div>
152
- </slot>
153
- <slot name="record-button">
154
- <button id="record-button">Start Recording</button>
155
- </slot>
156
- <slot name="stop-button">
157
- <button id="stop-button" disabled>Stop Recording</button>
158
- </slot>
159
- <slot name="file-input">
160
- <input type="file" accept="video/*" id="file-input" />
161
- </slot>
162
- <slot name="submit-button">
163
- <button id="submit-button">Submit Video</button>
164
- </slot>
165
- <slot name="loading">
166
- <div class="message">Loading...</div>
167
- </slot>
168
- <slot name="error">
169
- <div class="message error">An error occurred</div>
170
- </slot>
171
- <slot name="success">
172
- <div class="message success">Video submitted successfully!</div>
173
- </slot>
174
- </div>
175
- `;
176
- this.attachSlotListeners();
177
- this.setupPreview();
178
- this.toggleState(null);
179
- }
180
- attachSlotListeners() {
181
- const videoSlot = this.shadowRoot.querySelector('slot[name="video"]');
182
- const recordButtonSlot = this.shadowRoot.querySelector('slot[name="record-button"]');
183
- const stopButtonSlot = this.shadowRoot.querySelector('slot[name="stop-button"]');
184
- const fileInputSlot = this.shadowRoot.querySelector('slot[name="file-input"]');
185
- const submitButtonSlot = this.shadowRoot.querySelector('slot[name="submit-button"]');
186
- this.videoElement = this.getSlotElement(videoSlot, '#video-preview', HTMLVideoElement);
187
- this.recordButton = this.getSlotElement(recordButtonSlot, '#record-button', HTMLButtonElement);
188
- this.stopButton = this.getSlotElement(stopButtonSlot, '#stop-button', HTMLButtonElement);
189
- this.fileInput = this.getSlotElement(fileInputSlot, '#file-input', HTMLInputElement);
190
- this.submitButton = this.getSlotElement(submitButtonSlot, '#submit-button', HTMLButtonElement);
191
- if (this.fileInput) {
192
- this.fileInput.addEventListener('change', (e) => this.handleFileUpload(e));
193
- }
194
- if (this.recordButton) {
195
- this.recordButton.addEventListener("click", () => this.startRecording());
196
- }
197
- if (this.stopButton) {
198
- this.stopButton.addEventListener("click", () => this.stopRecording());
199
- }
200
- if (this.submitButton) {
201
- this.submitButton.addEventListener("click", () => this.handleSubmit());
202
- }
203
- }
204
- getSlotElement(slot, fallbackSelector, elementType) {
205
- const assignedElements = slot.assignedElements();
206
- return (assignedElements.length > 0 ? assignedElements[0] : null) || this.shadowRoot.querySelector(fallbackSelector);
207
- }
208
- replaceSlotContent(slotName, content) {
209
- const slot = this.shadowRoot.querySelector(`slot[name="${slotName}"]`);
210
- if (slot) {
211
- if (typeof content === 'string') {
212
- slot.innerHTML = content;
213
- }
214
- else if (content instanceof HTMLElement) {
215
- slot.innerHTML = '';
216
- slot.appendChild(content);
217
- }
218
- }
219
- }
220
- removeSlotListener(slotName, event, callback) {
221
- const slot = this.shadowRoot.querySelector(`slot[name="${slotName}"]`);
222
- if (slot) {
223
- const assignedNodes = slot.assignedElements();
224
- assignedNodes.forEach((node) => {
225
- node.removeEventListener(event, callback);
226
- });
227
- }
228
- }
229
- toggleState(state) {
230
- const states = ['loading', 'success', 'error'];
231
- states.forEach((slotName) => {
232
- const slot = this.shadowRoot.querySelector(`slot[name="${slotName}"]`);
233
- if (slot) {
234
- slot.style.display = slotName === state ? 'block' : 'none';
235
- }
236
- });
237
- }
238
- convertPhraseToWords(phrase) {
239
- const digitWords = [
240
- "zero", "one", "two", "three", "four",
241
- "five", "six", "seven", "eight", "nine"
242
- ];
243
- return phrase
244
- .split("")
245
- .map((digit) => digitWords[parseInt(digit, 10)])
246
- .join(" ");
247
- }
248
- async setupPreview() {
249
- try {
250
- const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
251
- this.previewStream = stream;
252
- this.videoElement.srcObject = stream;
253
- this.videoElement.controls = false;
254
- this.videoElement.play();
255
- }
256
- catch (error) {
257
- this.toggleState('error');
258
- console.error('Error setting up video preview:', error);
259
- }
260
- }
261
- async startTimer() {
262
- const timerOverlay = this.shadowRoot.querySelector('#timer-overlay');
263
- timerOverlay.textContent = '00:00';
264
- timerOverlay.classList.remove('hidden');
265
- let seconds = 0;
266
- this.timerInterval = setInterval(() => {
267
- seconds++;
268
- const minutes = Math.floor(seconds / 60);
269
- const remainingSeconds = seconds % 60;
270
- timerOverlay.textContent = `${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;
271
- }, 1000);
272
- this.recordingTimeout = setTimeout(() => {
273
- this.stopRecording();
274
- }, this.timeLimit * 1000);
275
- }
276
- async stopTimer() {
277
- if (this.recordingTimeout) {
278
- clearTimeout(this.recordingTimeout);
279
- }
280
- if (this.timerInterval) {
281
- clearInterval(this.timerInterval);
282
- this.timerInterval = null;
283
- }
284
- const timerOverlay = this.shadowRoot.querySelector('#timer-overlay');
285
- timerOverlay.classList.add('hidden');
286
- }
287
- async startRecording() {
288
- if (!window.MediaRecorder) {
289
- console.error('MediaRecorder API is not supported in this browser');
290
- return;
291
- }
292
- try {
293
- if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') {
294
- console.log('Recording already in progress.');
295
- return;
296
- }
297
- if (!this.previewStream) {
298
- console.log('Initializing preview stream...');
299
- this.previewStream = await navigator.mediaDevices.getUserMedia({
300
- video: true,
301
- audio: true,
302
- });
303
- }
304
- this.videoElement.muted = true;
305
- this.videoElement.srcObject = this.previewStream;
306
- this.videoElement.currentTime = 0;
307
- await this.videoElement.play();
308
- this.mediaRecorder = new MediaRecorder(this.previewStream);
309
- this.recordedChunks = [];
310
- this.mediaRecorder.ondataavailable = (event) => {
311
- if (event.data.size > 0) {
312
- this.recordedChunks.push(event.data);
313
- }
314
- };
315
- this.mediaRecorder.onstop = () => {
316
- const blob = new Blob(this.recordedChunks, { type: 'video/webm' });
317
- const videoURL = URL.createObjectURL(blob);
318
- this.videoFile = new File([blob], 'recorded_video.webm', { type: 'video/webm' });
319
- this.videoElement.src = videoURL;
320
- this.videoElement.controls = true;
321
- this.videoElement.play();
322
- this.videoElement.muted = false;
323
- this.stopTimer();
324
- };
325
- this.mediaRecorder.start();
326
- this.startTimer();
327
- this.recordButton.disabled = true;
328
- this.stopButton.disabled = false;
329
- this.videoElement.controls = false;
330
- }
331
- catch (error) {
332
- console.error('Error starting video recording:', error);
333
- }
334
- }
335
- stopRecording() {
336
- try {
337
- if (!this.mediaRecorder || this.mediaRecorder.state === 'inactive') {
338
- console.log('No recording in progress.');
339
- return;
340
- }
341
- this.mediaRecorder.stop();
342
- if (this.previewStream) {
343
- this.previewStream.getTracks().forEach(track => track.stop());
344
- }
345
- this.videoElement.srcObject = null;
346
- this.videoElement.src = '';
347
- this.videoElement.controls = false;
348
- this.recordButton.disabled = false;
349
- this.stopButton.disabled = true;
350
- this.mediaRecorder = null;
351
- this.recordedChunks = [];
352
- this.previewStream = null;
353
- }
354
- catch (error) {
355
- console.error('Error stopping video recording:', error);
356
- }
357
- }
358
- handleFileUpload(event) {
359
- var _a, _b;
360
- const file = (_a = event.target.files) === null || _a === void 0 ? void 0 : _a[0];
361
- if ((_b = file === null || file === void 0 ? void 0 : file.type) === null || _b === void 0 ? void 0 : _b.startsWith('video/')) {
362
- if (file.size > 100 * 1024 * 1024) { // 100MB limit
363
- this.toggleState('error');
364
- console.error('File size exceeds limit of 100MB');
365
- return;
366
- }
367
- this.videoFile = file;
368
- this.videoElement.src = URL.createObjectURL(file);
369
- this.videoElement.play();
370
- }
371
- else {
372
- this.toggleState('error');
373
- console.error('Please select a valid video file.');
374
- }
375
- }
376
- async handleSubmit() {
377
- if (!this.videoFile) {
378
- this.toggleState('error');
379
- console.error('No video file to submit.');
380
- return;
381
- }
382
- if (!this.apiKey || !this.userFullname) {
383
- this.toggleState('error');
384
- console.error('API key and user fullname must be provided.');
385
- return;
386
- }
387
- this.toggleState('loading');
388
- try {
389
- const phraseInWords = this.convertPhraseToWords(this.phrase);
390
- const result = await this.sdk.processVideo(this.videoFile, phraseInWords, this.userFullname);
391
- console.log('Response from processVideo:', result);
392
- this.toggleState('success');
393
- }
394
- catch (error) {
395
- this.toggleState('error');
396
- console.error('Error submitting video:', error);
397
- }
398
- }
399
- static get observedAttributes() {
400
- return ['api-key', 'user-fullname'];
401
- }
402
- get userFullname() {
403
- return this.getAttribute('user-fullname');
404
- }
405
- set userFullname(value) {
406
- if (value) {
407
- this.setAttribute('user-fullname', value);
408
- }
409
- else {
410
- this.removeAttribute('user-fullname');
411
- }
412
- }
413
- get isRecording() {
414
- var _a;
415
- return ((_a = this.mediaRecorder) === null || _a === void 0 ? void 0 : _a.state) === 'recording';
416
- }
417
- get currentPhrase() {
418
- return this.phrase;
419
- }
420
- get videoDuration() {
421
- var _a;
422
- return ((_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.duration) || null;
423
- }
424
- get currentFile() {
425
- return this.videoFile;
426
- }
427
- get currentStream() {
428
- return this.previewStream;
429
- }
430
- set sdkInstance(newSdk) {
431
- this.sdk = newSdk;
432
- }
433
- get videoElementRef() {
434
- return this.videoElement;
435
- }
436
- get fileInputRef() {
437
- return this.fileInput;
438
- }
439
- get recordingTimeLimit() {
440
- return this.timeLimit;
441
- }
442
- set recordingTimeLimit(value) {
443
- this.timeLimit = value;
444
- if (this.mediaRecorder && this.mediaRecorder.state === 'recording') {
445
- if (this.recordingTimeout) {
446
- clearTimeout(this.recordingTimeout);
447
- }
448
- this.recordingTimeout = setTimeout(() => this.stopRecording(), this.timeLimit * 1000);
449
- }
450
- }
451
- }
452
- customElements.define('process-video', ProcessVideoComponent);