@jaak.ai/stamps 2.0.0-dev.28 → 2.0.0-dev.30

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.
@@ -69,41 +69,72 @@ const JaakStamps = class {
69
69
  preprocessCtx;
70
70
  captureCanvas;
71
71
  captureCtx;
72
- MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v1.onnx";
72
+ MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx";
73
73
  MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx";
74
74
  MOBILENET_CLASSES_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json";
75
75
  INPUT_SIZE = 320;
76
76
  CONFIDENCE_THRESHOLD = 0.6;
77
77
  // ISO/IEC 7810 ID-1 standard dimensions (85.60mm x 53.98mm)
78
78
  ID1_ASPECT_RATIO = 85.60 / 53.98; // 1.5863320574...
79
- debugLog(...args) {
80
- if (this.debug) {
81
- console.log(...args);
79
+ logger = {
80
+ info: (...args) => {
81
+ if (this.debug) {
82
+ console.log(`[JAAK-STAMPS] [INFO] [${new Date().toLocaleTimeString()}]`, ...args);
83
+ }
84
+ },
85
+ warn: (...args) => {
86
+ if (this.debug) {
87
+ console.warn(`[JAAK-STAMPS] [WARN] [${new Date().toLocaleTimeString()}]`, ...args);
88
+ }
89
+ },
90
+ error: (...args) => {
91
+ if (this.debug) {
92
+ console.error(`[JAAK-STAMPS] [ERROR] [${new Date().toLocaleTimeString()}]`, ...args);
93
+ }
94
+ },
95
+ debug: (...args) => {
96
+ if (this.debug) {
97
+ console.debug(`[JAAK-STAMPS] [DEBUG] [${new Date().toLocaleTimeString()}]`, ...args);
98
+ }
99
+ },
100
+ state: (state, data) => {
101
+ if (this.debug) {
102
+ console.log(`[JAAK-STAMPS] [STATE] [${new Date().toLocaleTimeString()}] ${state}`, data || '');
103
+ }
104
+ },
105
+ performance: (operation, duration) => {
106
+ if (this.debug) {
107
+ console.log(`[JAAK-STAMPS] [PERF] [${new Date().toLocaleTimeString()}] ${operation}: ${duration}ms`);
108
+ }
82
109
  }
83
- }
110
+ };
84
111
  validateMaskSize() {
85
112
  if (this.maskSize < 50 || this.maskSize > 100) {
86
- console.warn(`maskSize debe estar entre 50 y 100. Valor actual: ${this.maskSize}. Usando valor por defecto: 90`);
113
+ this.logger.warn(`Propiedad maskSize inválida. Valor: ${this.maskSize}, esperado: 50-100. Usando valor por defecto: 90`);
87
114
  this.maskSize = 90;
88
115
  }
89
116
  }
90
117
  validateCropMargin() {
91
118
  if (this.cropMargin < 0 || this.cropMargin > 100) {
92
- console.warn(`cropMargin debe estar entre 0 y 100. Valor actual: ${this.cropMargin}. Usando valor por defecto: 0`);
119
+ this.logger.warn(`Propiedad cropMargin inválida. Valor: ${this.cropMargin}, esperado: 0-100. Usando valor por defecto: 0`);
93
120
  this.cropMargin = 0;
94
121
  }
95
122
  }
96
123
  validatePreferredCamera() {
97
124
  const validOptions = ['auto', 'front', 'back'];
98
125
  if (!validOptions.includes(this.preferredCamera)) {
99
- console.warn(`preferredCamera debe ser uno de: ${validOptions.join(', ')}. Valor actual: ${this.preferredCamera}. Usando valor por defecto: 'auto'`);
126
+ this.logger.warn(`Propiedad preferredCamera inválida. Valor: ${this.preferredCamera}, esperado: ${validOptions.join(', ')}. Usando valor por defecto: 'auto'`);
100
127
  this.preferredCamera = 'auto';
101
128
  }
102
129
  }
103
130
  emitReadyEvent() {
104
131
  const isDocumentReady = !!window.ort && this.isModelPreloaded;
105
132
  this.isReady.emit(isDocumentReady);
106
- this.debugLog('🟢 isReady event emitted:', isDocumentReady);
133
+ this.logger.state('COMPONENTE_LISTO', {
134
+ ortLibraryLoaded: !!window.ort,
135
+ modelPreloaded: this.isModelPreloaded,
136
+ isReady: isDocumentReady
137
+ });
107
138
  }
108
139
  isRearCamera(stream) {
109
140
  const videoTrack = stream.getVideoTracks()[0];
@@ -126,7 +157,11 @@ const JaakStamps = class {
126
157
  else {
127
158
  this.deviceType = 'desktop';
128
159
  }
129
- this.debugLog('📱 Device type detected:', this.deviceType);
160
+ this.logger.state('DISPOSITIVO_DETECTADO', {
161
+ deviceType: this.deviceType,
162
+ userAgent: navigator.userAgent,
163
+ screenDimensions: { width: window.innerWidth, height: window.innerHeight }
164
+ });
130
165
  // Enumerate available cameras
131
166
  await this.enumerateAndDetectCameras();
132
167
  // Load user preference
@@ -137,7 +172,7 @@ const JaakStamps = class {
137
172
  // First, check if we have permission to enumerate devices
138
173
  const permissionStatus = await this.checkCameraPermission();
139
174
  if (permissionStatus === 'denied') {
140
- this.debugLog(' Camera permission denied');
175
+ this.logger.error('Permiso de cámara denegado por el usuario');
141
176
  this.statusMessage = "Permiso de cámara denegado";
142
177
  this.statusColor = "#ff6b6b";
143
178
  return;
@@ -151,7 +186,7 @@ const JaakStamps = class {
151
186
  const devices = await navigator.mediaDevices.enumerateDevices();
152
187
  this.availableCameras = devices.filter(device => device.kind === 'videoinput');
153
188
  this.isMultipleCamerasAvailable = this.availableCameras.length > 1;
154
- this.debugLog('📹 Available cameras:', {
189
+ this.logger.state('CAMARAS_DETECTADAS', {
155
190
  count: this.availableCameras.length,
156
191
  isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
157
192
  cameras: this.availableCameras.map(cam => ({
@@ -163,7 +198,7 @@ const JaakStamps = class {
163
198
  this.setInitialCameraPreference();
164
199
  }
165
200
  catch (error) {
166
- this.debugLog('Error enumerating cameras:', error);
201
+ this.logger.error('Error al enumerar cámaras disponibles:', error);
167
202
  this.handleCameraPermissionError(error);
168
203
  }
169
204
  }
@@ -176,7 +211,7 @@ const JaakStamps = class {
176
211
  return permission.state;
177
212
  }
178
213
  catch (error) {
179
- this.debugLog('⚠️ Could not check camera permission:', error);
214
+ this.logger.warn('No se pudo verificar permisos de cámara:', error);
180
215
  return 'prompt';
181
216
  }
182
217
  }
@@ -219,11 +254,11 @@ const JaakStamps = class {
219
254
  !camera.label.toLowerCase().includes('back') && !camera.label.toLowerCase().includes('rear'));
220
255
  if (frontCamera) {
221
256
  this.selectedCameraId = frontCamera.deviceId;
222
- this.debugLog('👤 User selected front camera:', frontCamera.label);
257
+ this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { label: frontCamera.label, deviceId: frontCamera.deviceId });
223
258
  }
224
259
  else {
225
260
  this.selectedCameraId = this.availableCameras[0].deviceId;
226
- this.debugLog('⚠️ Front camera not found, using first available:', this.availableCameras[0].label);
261
+ this.logger.warn('Cámara frontal no encontrada, usando primera disponible:', this.availableCameras[0].label);
227
262
  }
228
263
  }
229
264
  else if (this.preferredCamera === 'back') {
@@ -234,11 +269,11 @@ const JaakStamps = class {
234
269
  camera.label.toLowerCase().includes('environment'));
235
270
  if (backCamera) {
236
271
  this.selectedCameraId = backCamera.deviceId;
237
- this.debugLog('📷 User selected back camera:', backCamera.label);
272
+ this.logger.state('CAMARA_TRASERA_SELECCIONADA', { label: backCamera.label, deviceId: backCamera.deviceId });
238
273
  }
239
274
  else {
240
275
  this.selectedCameraId = this.availableCameras[0].deviceId;
241
- this.debugLog('⚠️ Back camera not found, using first available:', this.availableCameras[0].label);
276
+ this.logger.warn('Cámara trasera no encontrada, usando primera disponible:', this.availableCameras[0].label);
242
277
  }
243
278
  }
244
279
  else {
@@ -251,17 +286,17 @@ const JaakStamps = class {
251
286
  camera.label.toLowerCase().includes('environment'));
252
287
  if (rearCamera) {
253
288
  this.selectedCameraId = rearCamera.deviceId;
254
- this.debugLog('📱 Auto-selected rear camera for mobile:', rearCamera.label);
289
+ this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear', label: rearCamera.label, deviceId: rearCamera.deviceId });
255
290
  }
256
291
  else {
257
292
  this.selectedCameraId = this.availableCameras[0].deviceId;
258
- this.debugLog('📱 Rear camera not found, using first available:', this.availableCameras[0].label);
293
+ this.logger.warn('Cámara trasera no encontrada en mobile, usando primera disponible:', this.availableCameras[0].label);
259
294
  }
260
295
  }
261
296
  else {
262
297
  // For desktop, use first available camera (usually the only one)
263
298
  this.selectedCameraId = this.availableCameras[0].deviceId;
264
- this.debugLog('💻 Auto-selected desktop camera:', this.availableCameras[0].label);
299
+ this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { label: this.availableCameras[0].label, deviceId: this.availableCameras[0].deviceId });
265
300
  }
266
301
  }
267
302
  }
@@ -275,12 +310,12 @@ const JaakStamps = class {
275
310
  if (isStillAvailable) {
276
311
  this.selectedCameraId = preference.cameraId;
277
312
  this.preferredCameraFacing = preference.facing;
278
- this.debugLog('💾 Loaded camera preference:', preference);
313
+ this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);
279
314
  }
280
315
  }
281
316
  }
282
317
  catch (error) {
283
- this.debugLog('⚠️ Error loading camera preference:', error);
318
+ this.logger.warn('Error al cargar preferencia de cámara:', error);
284
319
  }
285
320
  }
286
321
  saveCameraPreference() {
@@ -291,10 +326,10 @@ const JaakStamps = class {
291
326
  timestamp: Date.now()
292
327
  };
293
328
  localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));
294
- this.debugLog('💾 Saved camera preference:', preference);
329
+ this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);
295
330
  }
296
331
  catch (error) {
297
- this.debugLog('⚠️ Error saving camera preference:', error);
332
+ this.logger.warn('Error al guardar preferencia de cámara:', error);
298
333
  }
299
334
  }
300
335
  async switchCamera(cameraId) {
@@ -304,7 +339,7 @@ const JaakStamps = class {
304
339
  // Check if the selected camera is still available
305
340
  const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);
306
341
  if (!selectedCamera) {
307
- this.debugLog(' Selected camera not found, re-enumerating...');
342
+ this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');
308
343
  await this.enumerateAndDetectCameras();
309
344
  return;
310
345
  }
@@ -328,10 +363,10 @@ const JaakStamps = class {
328
363
  this.saveCameraPreference();
329
364
  // Setup new camera with error handling
330
365
  await this.setupCameraWithRetry();
331
- this.debugLog('🔄 Switched to camera:', selectedCamera.label);
366
+ this.logger.state('CAMARA_CAMBIADA', { label: selectedCamera.label, deviceId: selectedCamera.deviceId });
332
367
  }
333
368
  catch (error) {
334
- this.debugLog('Error switching camera:', error);
369
+ this.logger.error('Error al cambiar de cámara:', error);
335
370
  this.handleCameraPermissionError(error);
336
371
  }
337
372
  }
@@ -346,7 +381,7 @@ const JaakStamps = class {
346
381
  return; // Success
347
382
  }
348
383
  catch (error) {
349
- this.debugLog(`❌ Camera setup attempt ${attempt} failed:`, error);
384
+ this.logger.error(`Intento ${attempt} de configuración de cámara fallido:`, error);
350
385
  if (attempt === maxRetries) {
351
386
  // Last attempt failed, handle the error
352
387
  this.statusMessage = "Error al configurar la cámara";
@@ -366,7 +401,7 @@ const JaakStamps = class {
366
401
  }
367
402
  toggleCameraSelector() {
368
403
  this.showCameraSelector = !this.showCameraSelector;
369
- this.debugLog('📹 Camera selector toggled:', {
404
+ this.logger.state('SELECTOR_CAMARA_TOGGLE', {
370
405
  showCameraSelector: this.showCameraSelector,
371
406
  isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
372
407
  availableCameras: this.availableCameras.length,
@@ -382,6 +417,13 @@ const JaakStamps = class {
382
417
  await this.switchCamera(nextCamera.deviceId);
383
418
  }
384
419
  async componentDidLoad() {
420
+ this.logger.state('COMPONENTE_INICIALIZANDO', {
421
+ debug: this.debug,
422
+ maskSize: this.maskSize,
423
+ cropMargin: this.cropMargin,
424
+ useDocumentClassification: this.useDocumentClassification,
425
+ preferredCamera: this.preferredCamera
426
+ });
385
427
  if (this.debug) {
386
428
  // Show detailed initialization loading state only in debug mode
387
429
  this.isLoading = true;
@@ -446,7 +488,7 @@ const JaakStamps = class {
446
488
  this.canvasRef.height = rect.height;
447
489
  // Update mask positioning based on container and video dimensions
448
490
  this.updateMaskDimensions(rect);
449
- this.debugLog('📐 Canvas resized:', { width: rect.width, height: rect.height });
491
+ this.logger.debug('Canvas redimensionado:', { width: rect.width, height: rect.height });
450
492
  }
451
493
  }
452
494
  updateMaskDimensions(containerRect) {
@@ -506,7 +548,7 @@ const JaakStamps = class {
506
548
  this.el.style.setProperty('--mask-center-y', `${videoCenterYPercent}%`);
507
549
  // Mark mask as ready now that dimensions are calculated
508
550
  this.isMaskReady = true;
509
- this.debugLog('🎯 Mask dimensions updated:', {
551
+ this.logger.state('DIMENSIONES_MASCARA_ACTUALIZADAS', {
510
552
  video: { width: videoWidth, height: videoHeight },
511
553
  displayed: { width: displayedVideoWidth, height: displayedVideoHeight },
512
554
  mask: { widthPercent: maskWidthPercent, heightPercent: maskHeightPercent },
@@ -528,7 +570,7 @@ const JaakStamps = class {
528
570
  this.captureCtx = this.captureCanvas.getContext('2d', {
529
571
  alpha: false
530
572
  });
531
- this.debugLog('🎨 Canvas pool initialized for performance');
573
+ this.logger.state('CANVAS_POOL_INICIALIZADO', { preprocessCanvasSize: this.INPUT_SIZE });
532
574
  }
533
575
  disconnectedCallback() {
534
576
  this.cleanup();
@@ -576,7 +618,7 @@ const JaakStamps = class {
576
618
  }
577
619
  async preloadModel() {
578
620
  if (this.isModelPreloaded || this.session) {
579
- this.debugLog('🚀 Model already preloaded or session exists');
621
+ this.logger.state('MODELO_YA_PRECARGADO', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
580
622
  return { success: true, message: 'Model already loaded' };
581
623
  }
582
624
  try {
@@ -584,7 +626,7 @@ const JaakStamps = class {
584
626
  this.statusMessage = "Precargando modelos...";
585
627
  this.statusColor = "#007bff";
586
628
  const modelPath = this.MODEL_PATH;
587
- this.debugLog('🤖 Preloading detection model:', modelPath);
629
+ this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath });
588
630
  // Configure ONNX Runtime with device-specific optimizations
589
631
  const sessionOptions = this.getSessionOptions();
590
632
  const deviceInfo = this.getDeviceMemoryInfo();
@@ -593,7 +635,7 @@ const JaakStamps = class {
593
635
  }
594
636
  catch (error) {
595
637
  if (error.message.includes('failed to allocate a buffer')) {
596
- this.debugLog(' Buffer allocation failed during preload, trying with minimal settings');
638
+ this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');
597
639
  const fallbackOptions = {
598
640
  executionProviders: ['wasm'],
599
641
  graphOptimizationLevel: 'disabled',
@@ -614,7 +656,7 @@ const JaakStamps = class {
614
656
  // For low memory devices, load sequentially to avoid memory pressure
615
657
  if (this.useDocumentClassification) {
616
658
  if (deviceInfo.isLowMemory) {
617
- this.debugLog('🔄 Sequential model loading for low memory device');
659
+ this.logger.state('CARGA_SECUENCIAL_MODELOS', { reason: 'low memory device' });
618
660
  await new Promise(resolve => setTimeout(resolve, 1000));
619
661
  }
620
662
  await this.loadMobileNetModel();
@@ -624,11 +666,15 @@ const JaakStamps = class {
624
666
  this.statusMessage = "Modelos precargados. Listo para comenzar detección";
625
667
  this.statusColor = "#28a745";
626
668
  this.emitReadyEvent();
627
- this.debugLog(' Models preloaded successfully');
669
+ this.logger.state('MODELOS_PRECARGADOS_EXITOSAMENTE', {
670
+ detectionModel: !!this.session,
671
+ classificationModel: !!this.mobileNetSession,
672
+ useClassification: this.useDocumentClassification
673
+ });
628
674
  return { success: true, message: 'Models preloaded successfully' };
629
675
  }
630
676
  catch (error) {
631
- this.debugLog('Error preloading models:', error);
677
+ this.logger.error('Error al precargar modelos:', error);
632
678
  this.isLoading = false;
633
679
  this.statusMessage = "Error al precargar los modelos";
634
680
  this.statusColor = "#ff6b6b";
@@ -656,7 +702,7 @@ const JaakStamps = class {
656
702
  }
657
703
  async setPreferredCamera(camera) {
658
704
  this.preferredCamera = camera;
659
- this.debugLog('🎯 Camera preference changed to:', camera);
705
+ this.logger.state('PREFERENCIA_CAMARA_CAMBIADA', { newPreference: camera });
660
706
  // Re-detect and apply new camera preference
661
707
  await this.enumerateAndDetectCameras();
662
708
  // If video is active, switch to the new preferred camera
@@ -671,14 +717,14 @@ const JaakStamps = class {
671
717
  }
672
718
  async loadMobileNetModel() {
673
719
  try {
674
- this.debugLog('🤖 Loading MobileNet model...');
720
+ this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
675
721
  // Load class map
676
722
  const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
677
723
  if (!classResponse.ok) {
678
724
  throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
679
725
  }
680
726
  this.mobileNetClassMap = await classResponse.json();
681
- this.debugLog('📋 MobileNet classes loaded:', this.mobileNetClassMap);
727
+ this.logger.state('CLASES_MOBILENET_CARGADAS', { classCount: Object.keys(this.mobileNetClassMap).length });
682
728
  // Load model
683
729
  const sessionOptions = this.getSessionOptions();
684
730
  try {
@@ -686,7 +732,7 @@ const JaakStamps = class {
686
732
  }
687
733
  catch (error) {
688
734
  if (error.message.includes('failed to allocate a buffer')) {
689
- this.debugLog(' MobileNet buffer allocation failed, trying with minimal settings');
735
+ this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');
690
736
  const fallbackOptions = {
691
737
  executionProviders: ['wasm'],
692
738
  graphOptimizationLevel: 'disabled',
@@ -703,10 +749,10 @@ const JaakStamps = class {
703
749
  throw error;
704
750
  }
705
751
  }
706
- this.debugLog(' MobileNet model loaded successfully');
752
+ this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.mobileNetSession });
707
753
  }
708
754
  catch (error) {
709
- this.debugLog('Error loading MobileNet model:', error);
755
+ this.logger.error('Error al cargar modelo MobileNet:', error);
710
756
  throw error;
711
757
  }
712
758
  }
@@ -733,11 +779,11 @@ const JaakStamps = class {
733
779
  }
734
780
  async classifyDocument(canvas) {
735
781
  if (!this.mobileNetSession || !this.mobileNetClassMap) {
736
- this.debugLog('⚠️ MobileNet model not loaded');
782
+ this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');
737
783
  return null;
738
784
  }
739
785
  try {
740
- this.debugLog('🔍 Classifying document...');
786
+ this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
741
787
  // Preprocess image for MobileNet
742
788
  const inputTensor = this.preprocessMobileNet(canvas);
743
789
  // Run inference
@@ -748,10 +794,11 @@ const JaakStamps = class {
748
794
  const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
749
795
  const confidence = output[maxIdx];
750
796
  const className = this.mobileNetClassMap[maxIdx.toString()] || "unknown";
751
- this.debugLog('📄 Document classification result:', {
797
+ this.logger.state('DOCUMENTO_CLASIFICADO', {
752
798
  class: className,
753
799
  confidence: confidence.toFixed(3),
754
- classIndex: maxIdx
800
+ classIndex: maxIdx,
801
+ timestamp: Date.now()
755
802
  });
756
803
  return {
757
804
  class: className,
@@ -760,7 +807,7 @@ const JaakStamps = class {
760
807
  };
761
808
  }
762
809
  catch (error) {
763
- this.debugLog('Error classifying document:', error);
810
+ this.logger.error('Error al clasificar documento:', error);
764
811
  return null;
765
812
  }
766
813
  }
@@ -802,7 +849,7 @@ const JaakStamps = class {
802
849
  }
803
850
  this.mobileNetClassMap = undefined;
804
851
  this.isModelPreloaded = false;
805
- this.debugLog('🧹 Canvas pool cleaned up');
852
+ this.logger.state('CANVAS_POOL_LIMPIADO', { timestamp: Date.now() });
806
853
  }
807
854
  async getMaxResolution() {
808
855
  try {
@@ -851,18 +898,19 @@ const JaakStamps = class {
851
898
  constraints.width = { ideal: maxWidth };
852
899
  constraints.height = { ideal: maxHeight };
853
900
  }
854
- this.debugLog('📐 Resolution capabilities:', {
901
+ this.logger.state('CAPACIDADES_RESOLUCION_DETECTADAS', {
855
902
  maxWidth: capabilities.width.max,
856
903
  maxHeight: capabilities.height.max,
857
904
  selectedWidth: constraints.width.ideal,
858
905
  selectedHeight: constraints.height.ideal,
859
- isTablet
906
+ isTablet,
907
+ deviceType: this.deviceType
860
908
  });
861
909
  }
862
910
  return constraints;
863
911
  }
864
912
  catch (err) {
865
- this.debugLog('⚠️ Could not get capabilities, using fallback');
913
+ this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');
866
914
  // Optimized fallback for tablets
867
915
  const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
868
916
  const fallbackConstraints = {
@@ -895,8 +943,11 @@ const JaakStamps = class {
895
943
  // Determine if video should be mirrored
896
944
  const isRear = this.isRearCamera(stream);
897
945
  this.shouldMirrorVideo = !isRear;
898
- this.debugLog('📹 Rear camera:', isRear);
899
- this.debugLog('🪞 Should mirror video:', this.shouldMirrorVideo);
946
+ this.logger.state('CAMARA_CONFIGURADA', {
947
+ isRearCamera: isRear,
948
+ shouldMirrorVideo: this.shouldMirrorVideo,
949
+ videoActive: this.isVideoActive
950
+ });
900
951
  return new Promise((resolve) => {
901
952
  this.videoRef.onloadedmetadata = async () => {
902
953
  await this.videoRef.play();
@@ -913,7 +964,7 @@ const JaakStamps = class {
913
964
  }
914
965
  }
915
966
  catch (err) {
916
- this.debugLog("❌ No se pudo acceder a la cámara:", err);
967
+ this.logger.error('No se pudo acceder a la cámara:', err);
917
968
  this.handleCameraPermissionError(err);
918
969
  }
919
970
  }
@@ -935,7 +986,37 @@ const JaakStamps = class {
935
986
  B.push(data[i + 2] / 255);
936
987
  }
937
988
  const transposedData = new Float32Array(R.concat(G, B));
938
- return new window.ort.Tensor("float32", transposedData, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);
989
+ // Convert to float16 for the lighter model
990
+ const float16Data = new Uint16Array(transposedData.length);
991
+ for (let i = 0; i < transposedData.length; i++) {
992
+ float16Data[i] = this.float32ToFloat16(transposedData[i]);
993
+ }
994
+ return new window.ort.Tensor("float16", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);
995
+ }
996
+ float32ToFloat16(value) {
997
+ // Convert float32 to float16 using IEEE 754 half precision format
998
+ const buffer = new ArrayBuffer(4);
999
+ const view = new DataView(buffer);
1000
+ view.setFloat32(0, value, true);
1001
+ const f = view.getUint32(0, true);
1002
+ const sign = (f >> 31) & 0x1;
1003
+ const exp = (f >> 23) & 0xFF;
1004
+ const frac = f & 0x7FFFFF;
1005
+ let newExp = exp - 127 + 15;
1006
+ if (exp === 0) {
1007
+ newExp = 0;
1008
+ }
1009
+ else if (exp === 0xFF) {
1010
+ newExp = 0x1F;
1011
+ }
1012
+ else if (newExp >= 0x1F) {
1013
+ newExp = 0x1F;
1014
+ return (sign << 15) | (newExp << 10);
1015
+ }
1016
+ else if (newExp <= 0) {
1017
+ return (sign << 15);
1018
+ }
1019
+ return (sign << 15) | (newExp << 10) | (frac >> 13);
939
1020
  }
940
1021
  getDeviceMemoryInfo() {
941
1022
  const nav = navigator;
@@ -979,6 +1060,12 @@ const JaakStamps = class {
979
1060
  };
980
1061
  }
981
1062
  async startDetection() {
1063
+ this.logger.state('INICIANDO_DETECCION', {
1064
+ sessionExists: !!this.session,
1065
+ modelPreloaded: this.isModelPreloaded,
1066
+ videoActive: this.isVideoActive,
1067
+ captureStep: this.captureStep
1068
+ });
982
1069
  try {
983
1070
  // Check if model is already preloaded
984
1071
  if (!this.session) {
@@ -992,14 +1079,14 @@ const JaakStamps = class {
992
1079
  this.statusColor = "#007bff";
993
1080
  }
994
1081
  const modelPath = this.MODEL_PATH;
995
- this.debugLog('🤖 Loading detection model:', modelPath);
1082
+ this.logger.state('CARGANDO_MODELO_DETECCION', { modelPath });
996
1083
  const sessionOptions = this.getSessionOptions();
997
1084
  try {
998
1085
  this.session = await window.ort.InferenceSession.create(modelPath, sessionOptions);
999
1086
  }
1000
1087
  catch (error) {
1001
1088
  if (error.message.includes('failed to allocate a buffer')) {
1002
- this.debugLog(' Buffer allocation failed, trying with minimal settings');
1089
+ this.logger.warn('Fallo en asignación de buffer, intentando con configuración mínima');
1003
1090
  const fallbackOptions = {
1004
1091
  executionProviders: ['wasm'],
1005
1092
  graphOptimizationLevel: 'disabled',
@@ -1030,7 +1117,7 @@ const JaakStamps = class {
1030
1117
  this.emitReadyEvent();
1031
1118
  }
1032
1119
  else {
1033
- this.debugLog('🚀 Using preloaded models');
1120
+ this.logger.state('USANDO_MODELOS_PRECARGADOS', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
1034
1121
  if (this.debug) {
1035
1122
  this.statusMessage = "Usando modelos precargados...";
1036
1123
  this.statusColor = "#007bff";
@@ -1049,7 +1136,7 @@ const JaakStamps = class {
1049
1136
  this.detectFrame();
1050
1137
  }
1051
1138
  catch (err) {
1052
- this.debugLog("Error al inicializar:", err);
1139
+ this.logger.error('Error al inicializar detección:', err);
1053
1140
  this.statusMessage = "Error al inicializar el detector";
1054
1141
  this.statusColor = "#ff6b6b";
1055
1142
  this.isLoading = false;
@@ -1131,7 +1218,7 @@ const JaakStamps = class {
1131
1218
  }
1132
1219
  }
1133
1220
  catch (e) {
1134
- this.debugLog("Error en inferencia:", e);
1221
+ this.logger.error('Error en inferencia de modelo:', e);
1135
1222
  // Solo continuar si no hemos completado el proceso
1136
1223
  if (this.captureStep !== 'completed') {
1137
1224
  // On error, wait longer before retrying
@@ -1259,7 +1346,7 @@ const JaakStamps = class {
1259
1346
  if (!this.hasScreenshotTaken) {
1260
1347
  this.lastDetectedBox = bestBox;
1261
1348
  this.takeScreenshot().catch(error => {
1262
- this.debugLog('Error taking screenshot:', error);
1349
+ this.logger.error('Error al tomar captura de pantalla:', error);
1263
1350
  });
1264
1351
  this.hasScreenshotTaken = true;
1265
1352
  // Reset para permitir segunda captura
@@ -1277,6 +1364,7 @@ const JaakStamps = class {
1277
1364
  if (boxes.length === 0) {
1278
1365
  this.statusMessage = "Posicione la identificación dentro del marco";
1279
1366
  this.statusColor = "#ff6b6b";
1367
+ this.logger.debug('Sin detección de documento en el frame');
1280
1368
  }
1281
1369
  else {
1282
1370
  const bestBox = boxes.reduce((best, current) => current.score > best.score ? current : best);
@@ -1286,6 +1374,11 @@ const JaakStamps = class {
1286
1374
  if (allSidesAligned) {
1287
1375
  this.statusMessage = "Identificación perfectamente alineada. Mantenga inmóvil";
1288
1376
  this.statusColor = "#00ff00";
1377
+ this.logger.state('DOCUMENTO_PERFECTAMENTE_ALINEADO', {
1378
+ score: bestBox.score,
1379
+ boxDimensions: { width: bestBox.w, height: bestBox.h },
1380
+ alignedSides: 4
1381
+ });
1289
1382
  }
1290
1383
  else if (alignedSides > 0) {
1291
1384
  this.statusMessage = `Alinee los lados restantes (${alignedSides}/4 lados correctos)`;
@@ -1346,6 +1439,14 @@ const JaakStamps = class {
1346
1439
  async takeScreenshot() {
1347
1440
  if (!this.videoRef || !this.lastDetectedBox)
1348
1441
  return;
1442
+ this.logger.state('INICIANDO_CAPTURA', {
1443
+ captureStep: this.captureStep,
1444
+ detectedBox: this.lastDetectedBox,
1445
+ videoResolution: {
1446
+ width: this.videoRef.videoWidth,
1447
+ height: this.videoRef.videoHeight
1448
+ }
1449
+ });
1349
1450
  // Activar animación
1350
1451
  this.triggerCaptureAnimation();
1351
1452
  // OPTIMIZATION: Reuse capture canvas for full frame
@@ -1385,7 +1486,7 @@ const JaakStamps = class {
1385
1486
  await this.loadMobileNetModel();
1386
1487
  }
1387
1488
  catch (error) {
1388
- this.debugLog('⚠️ Failed to load classification model, continuing without classification:', error);
1489
+ this.logger.warn('Fallo al cargar modelo de clasificación, continuando sin clasificación:', error);
1389
1490
  }
1390
1491
  }
1391
1492
  // Classify the cropped document if model is available
@@ -1393,7 +1494,7 @@ const JaakStamps = class {
1393
1494
  const classification = await this.classifyDocument(croppedCanvas);
1394
1495
  if (classification && classification.class === 'passport') {
1395
1496
  // If it's a passport, skip back capture since passports don't have a back side
1396
- this.debugLog('📄 Passport detected - skipping back capture');
1497
+ this.logger.state('PASAPORTE_DETECTADO_SALTANDO_REVERSO', { classification: classification?.class });
1397
1498
  this.completeProcess(true);
1398
1499
  return;
1399
1500
  }
@@ -1414,14 +1515,23 @@ const JaakStamps = class {
1414
1515
  this.isDetectionPaused = false;
1415
1516
  }, 3000);
1416
1517
  }, 800);
1417
- this.debugLog('📸 FRENTE capturado. Esperando trasera...');
1518
+ this.logger.state('CAPTURA_FRENTE_COMPLETADA', {
1519
+ captureStep: this.captureStep,
1520
+ hasFullFrame: !!this.capturedFullFrame,
1521
+ hasCroppedId: !!this.capturedCroppedId
1522
+ });
1418
1523
  }
1419
1524
  else if (this.captureStep === 'back') {
1420
1525
  // Captura de la trasera usando canvas reutilizado
1421
1526
  this.capturedBackFullFrame = this.captureCanvas.toDataURL('image/png');
1422
1527
  this.capturedBackCroppedId = croppedCanvas.toDataURL('image/png');
1423
1528
  this.completeProcess(false);
1424
- this.debugLog('📸 TRASERA capturada. Proceso completado. Detector detenido. Imágenes emitidas.');
1529
+ this.logger.state('CAPTURA_TRASERA_COMPLETADA', {
1530
+ captureStep: this.captureStep,
1531
+ hasBackFullFrame: !!this.capturedBackFullFrame,
1532
+ hasBackCroppedId: !!this.capturedBackCroppedId,
1533
+ processCompleted: true
1534
+ });
1425
1535
  }
1426
1536
  }
1427
1537
  triggerCaptureAnimation() {
@@ -1445,7 +1555,7 @@ const JaakStamps = class {
1445
1555
  const ctx = this.canvasRef.getContext("2d");
1446
1556
  ctx.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
1447
1557
  }
1448
- this.debugLog('🛑 Detector de identificación detenido');
1558
+ this.logger.state('DETECTOR_DETENIDO', { timestamp: Date.now() });
1449
1559
  }
1450
1560
  resetDetection() {
1451
1561
  this.bestScore = 0;
@@ -1484,6 +1594,13 @@ const JaakStamps = class {
1484
1594
  "Proceso completado (solo frente capturado)" :
1485
1595
  "Proceso de captura completado exitosamente";
1486
1596
  this.statusColor = "#28a745";
1597
+ this.logger.state('PROCESO_COMPLETADO', {
1598
+ skippedBack,
1599
+ hasFrontImages: !!(this.capturedFullFrame && this.capturedCroppedId),
1600
+ hasBackImages: !!(this.capturedBackFullFrame && this.capturedBackCroppedId),
1601
+ totalImages: skippedBack ? 2 : 4,
1602
+ timestamp: new Date().toISOString()
1603
+ });
1487
1604
  // Detener el detector
1488
1605
  this.stopDetection();
1489
1606
  // Emitir evento con las imágenes capturadas
@@ -1535,7 +1652,7 @@ const JaakStamps = class {
1535
1652
  this.cleanup();
1536
1653
  }
1537
1654
  render() {
1538
- return (h("div", { key: 'bacf8b2ded1c5015d01dd4240dda6a93fbfb629e', class: "detector-container" }, h("div", { key: '235aefbd8916d6b53ab191c654ed00f303ca73b7', class: "video-container" }, h("video", { key: '9b641c7092c5ecfa601b1f80d6bf8c310539c436', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: this.isVideoActive ? 'block' : 'none' } }), h("canvas", { key: '2c3c384436b7dd91084dbdd27a34ac9192fa3f22', ref: el => this.canvasRef = el, class: this.shouldMirrorVideo ? 'mirror' : '' }), this.isMaskReady && (h("div", { key: '9e2ca398482ebae4da984854483af3159d908d2b', class: "overlay-mask" }, h("div", { key: 'ee14fd65d752351644a281fc4cbd7d8cf8765eec', class: "card-outline" }, h("div", { key: 'c5a924145ac54e7f545b0b6571f1d7d259fc1145', class: "side side-top" }), h("div", { key: 'a88e9ab5f1a4f7041edb44008697b619bf52a85b', class: "side side-right" }), h("div", { key: '08fbf94000951ea31d029469d8158b8bd3349bf8', class: "side side-bottom" }), h("div", { key: '3b9ead8e1d2c0f7fea2878a248241681c07bd0f6', class: "side side-left" }), h("div", { key: 'f96b9a5a0f00f016b11486a63ca984b368d18c8b', class: "corner corner-tl" }), h("div", { key: '30210f2ec60913466665dea50a1e8bc6cba34b41', class: "corner corner-tr" }), h("div", { key: 'cc4644c99957a9ddf68901ddd368037e01c56899', class: "corner corner-bl" }), h("div", { key: '95b08e9b36f880dda1d614f929ceb71259f5ec38', class: "corner corner-br" }), !this.showFlipAnimation && !this.showSuccessAnimation && (h("div", { key: '9bb545a793764b258381b0e3d665472c67d65b5b', class: "guide-text" }, this.statusMessage))), this.captureStep === 'back' && !this.showFlipAnimation && !this.showSuccessAnimation && (h("button", { key: '3b78e394067ea610021fd915215fca30ed0d654b', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")), this.isVideoActive && (h("div", { key: '85fbcf97d151fbf1f37a2f6f90bbd93ef77afdba', class: "camera-controls" }, this.isMultipleCamerasAvailable && (h("button", { key: '56bab78e6ea660e42057b5e6bc322f6990116119', class: "flip-camera-button", onClick: () => this.flipCamera(), type: "button", title: "Cambiar c\u00E1mara" }, "Girar c\u00E1mara")), h("button", { key: 'c149303ed671d326efada743393e52b5a3710710', class: "camera-selector-button", onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara" }, "C\u00E1maras"), this.debug && (h("div", { key: 'ce7c0c1dbc2ba267dbd0181dd7268e2d9f7209c0', style: {
1655
+ return (h("div", { key: 'a09694bc3b5f78bc792ea101d470ada1a438a57b', class: "detector-container" }, h("div", { key: 'c673c10d3311a44479d4462f3efbb4b6257ec6a9', class: "video-container" }, h("video", { key: 'c9faf3f111c50f945bce9d566fea2bd6b249fa78', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: this.isVideoActive ? 'block' : 'none' } }), h("canvas", { key: 'bdc04a389f6b956f7ca138d9fe74db38a6c8812c', ref: el => this.canvasRef = el, class: this.shouldMirrorVideo ? 'mirror' : '' }), this.isMaskReady && (h("div", { key: '317156579b40924a7bb96c89dd247713f87f1aa9', class: "overlay-mask" }, h("div", { key: '71cfc3c3bbfdae49f05fd563e14f56181440fafa', class: "card-outline" }, h("div", { key: '3f940eeb59d783f47e2e2651ccf1a7be19f1d8b9', class: "side side-top" }), h("div", { key: 'f07e54e9542811897191e9a9a08f91b9e4785cc6', class: "side side-right" }), h("div", { key: '5b6a323213ddff52071b3469068cba0b31930ea0', class: "side side-bottom" }), h("div", { key: '44cf6567819855ab915fcee51cec7d08cb8654a8', class: "side side-left" }), h("div", { key: '8f866542b2d1a399418d1c8cb58ea856d5f3b9e7', class: "corner corner-tl" }), h("div", { key: 'a6567d410c755553d4be5b77dfc965e63b4ef07f', class: "corner corner-tr" }), h("div", { key: '255636461627f2deb61c9feacda3c9379abaaf29', class: "corner corner-bl" }), h("div", { key: 'dd029757b1ccc49c44bedee12c19b9485ef16545', class: "corner corner-br" }), !this.showFlipAnimation && !this.showSuccessAnimation && (h("div", { key: '37aef58019835eac5883042554c648b89cd305ac', class: "guide-text" }, this.statusMessage))), this.captureStep === 'back' && !this.showFlipAnimation && !this.showSuccessAnimation && (h("button", { key: '541f6d35d0655093f767423fc6851b521a5b43cd', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")), this.isVideoActive && (h("div", { key: '73f2232b7c79f8b935cc78f2e5de1f064e4a3472', class: "camera-controls" }, this.isMultipleCamerasAvailable && (h("button", { key: '3c176f9848dc4bf3b7144e2d68225562ae3780c0', class: "flip-camera-button", onClick: () => this.flipCamera(), type: "button", title: "Cambiar c\u00E1mara" }, "Girar c\u00E1mara")), h("button", { key: '9460ad4c42872324141ab19b516e7fa026afdd37', class: "camera-selector-button", onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara" }, "C\u00E1maras"), this.debug && (h("div", { key: '961d825eaba6077189f32193d527fe98a6d4e1e1', style: {
1539
1656
  position: 'absolute',
1540
1657
  top: '50px',
1541
1658
  right: '0',
@@ -1545,10 +1662,10 @@ const JaakStamps = class {
1545
1662
  fontSize: '10px',
1546
1663
  borderRadius: '4px',
1547
1664
  whiteSpace: 'nowrap'
1548
- } }, "C\u00E1maras: ", this.availableCameras.length, h("br", { key: 'd62a6ddde7160f41075b3b1d00340515019a48ca' }), "M\u00FAltiples: ", this.isMultipleCamerasAvailable ? 'Sí' : 'No', h("br", { key: 'fe8c322421809a58f49150ef877ae0502d34d002' }), "Selector: ", this.showCameraSelector ? 'Visible' : 'Oculto', h("br", { key: '084d8c5c6c0193edcaf3bd7d64d0bce8e0bb6964' }), "Video: ", this.isVideoActive ? 'Activo' : 'Inactivo')))), this.showCameraSelector && this.availableCameras.length > 0 && (h("div", { key: '03b1a66188e65f1843c50aec096db840d60bb703', class: "camera-selector-dropdown" }, h("div", { key: 'fe7e08d25dd394d893a7f6269c80a2aaa4732134', class: "camera-selector-header" }, h("span", { key: '1b8f4892c3eef6dac8c682e152abb35e2331496c' }, "Seleccionar C\u00E1mara"), h("button", { key: '396c78a3753c707619e27ef7e5f3a412ba8480c6', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: '6d56d67efe54719f21978cc6cc44cf2f421469bb', class: "camera-list" }, this.availableCameras.map((camera) => (h("button", { key: camera.deviceId, class: `camera-option ${this.selectedCameraId === camera.deviceId ? 'selected' : ''}`, onClick: () => {
1665
+ } }, "C\u00E1maras: ", this.availableCameras.length, h("br", { key: 'f7e12d21177478d03f6df0490dfc91df12bd1225' }), "M\u00FAltiples: ", this.isMultipleCamerasAvailable ? 'Sí' : 'No', h("br", { key: '1f1cc8cf92e10b9b902fd981875621fa8dbe70f2' }), "Selector: ", this.showCameraSelector ? 'Visible' : 'Oculto', h("br", { key: 'c119c6567b28fc33e99b59f76e53e9359491ab77' }), "Video: ", this.isVideoActive ? 'Activo' : 'Inactivo')))), this.showCameraSelector && this.availableCameras.length > 0 && (h("div", { key: 'c230990e87f3b6133263c42fc1b568c0caf076e2', class: "camera-selector-dropdown" }, h("div", { key: '44c224e93c5832eea498e756a446e12ce8255e61', class: "camera-selector-header" }, h("span", { key: '64d951db4843164378424f2d8d2ed2802eb35170' }, "Seleccionar C\u00E1mara"), h("button", { key: '0575a7d0a9a99d665d42c6a7f7d8ceff53da9bd2', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: '4aceed8bcf821710af343611f1b31efdfe61438e', class: "camera-list" }, this.availableCameras.map((camera) => (h("button", { key: camera.deviceId, class: `camera-option ${this.selectedCameraId === camera.deviceId ? 'selected' : ''}`, onClick: () => {
1549
1666
  this.switchCamera(camera.deviceId);
1550
1667
  this.toggleCameraSelector();
1551
- }, type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${this.availableCameras.indexOf(camera) + 1}`), this.selectedCameraId === camera.deviceId && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '7f5dda6214695d50c08d2ba4ccec236f3bd158cf', class: "device-info" }, h("small", { key: '50d2768f82b9b7f0a9c1729a5167493f731fb4f6' }, "Dispositivo: ", this.deviceType)))))), this.isCapturing && (h("div", { key: '7ed246b862639b2c6df54dbd32ebb883776bfbd7', class: "capture-animation" })), this.showFlipAnimation && (h("div", { key: 'f2d3a97dfcb9fd757b2f39ec184bce3f5dcb3595', class: "flip-animation" }, h("div", { key: '89a98223c60317d2b9449029ba393c75bec154b3', class: "id-card-icon" }), h("div", { key: '507f6f1b7f38082772bbac2fc28046618161c69b', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), this.showSuccessAnimation && (h("div", { key: '9010d5be6684759b5d99c58ee65b0a7ebe82b9cb', class: "success-animation" }, h("div", { key: '454c39a5c0d457418b8abdc6e63b1c8a249a118f', class: "check-icon" }), h("div", { key: '502e55f1496f7d8cde9178c416bd9db4cf0491eb', class: "success-text" }, "\u00A1Proceso completado!"))), this.isLoading && (h("div", { key: 'e4d6b7c5ebc8da42689150195dd837e77e152ea3', class: "loading-overlay" }, h("div", { key: '7cc39dbbe94e0730c47829291b83717476517f7f', class: "loading-spinner" }), h("div", { key: '4c1afe04fc7a627c9a57c2f7b851ce62f9305676', class: "loading-text" }, this.statusMessage))), this.debug && (h("div", { key: '8745c4603b35003bff859657c86c713b7f58e204', class: "status-bar" }, h("div", { key: 'e098f2402d58d1808052e3d213f851e66db69ee4', class: "status-message", style: { 'color': this.statusColor } }, this.statusMessage))), h("div", { key: 'af4e07b405af5b1786009b0e9ecf72551753de28', class: "watermark" }, h("img", { key: '25f4b80f13528617007aad160c855c4fff0c8af5', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1668
+ }, type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${this.availableCameras.indexOf(camera) + 1}`), this.selectedCameraId === camera.deviceId && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: 'd6d691cc499a35f40e348cf61d8f81a380e6fe98', class: "device-info" }, h("small", { key: 'ed38304b9dcac5b99d7b32f5733c59b335433f61' }, "Dispositivo: ", this.deviceType)))))), this.isCapturing && (h("div", { key: 'ad19c6c3a2cb761a67b80e52761b2b9cb14d251d', class: "capture-animation" })), this.showFlipAnimation && (h("div", { key: '480615ac9b8ceb5cfc2d821d5777b213c2e86d83', class: "flip-animation" }, h("div", { key: '45e74e5ef254bce75f51d2d12a5961722fb0af03', class: "id-card-icon" }), h("div", { key: '38b9274a67fa8cf1f83bd4b06a3d4ef3d03cdb14', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), this.showSuccessAnimation && (h("div", { key: 'a6344502e3bbbe298dfb509b41354a54038826aa', class: "success-animation" }, h("div", { key: '579f89d7c8d0ff76e42af611286d96a35d3dbfb9', class: "check-icon" }), h("div", { key: '5bb5c155c70f4bf7a04a62d10142e413763fa1fa', class: "success-text" }, "\u00A1Proceso completado!"))), this.isLoading && (h("div", { key: '664113d7266be3c4171291faede143e736efadf0', class: "loading-overlay" }, h("div", { key: 'b699ad30f1784e1a92657391c080b91e017f7420', class: "loading-spinner" }), h("div", { key: '287f8e13229e4d14de31b0c5ad7d89a202eca5f9', class: "loading-text" }, this.statusMessage))), this.debug && (h("div", { key: 'ba649b0414153cb28b2c6e3c5451b324a990ec63', class: "status-bar" }, h("div", { key: '55b11462af7ef04d293757e2e45344f9206352ac', class: "status-message", style: { 'color': this.statusColor } }, this.statusMessage))), h("div", { key: '3b24a505519d8b483fad2b2f66ef8159d458e1b4', class: "watermark" }, h("img", { key: 'd61f9366631661835e1dd9500500c2b7a7334581', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1552
1669
  }
1553
1670
  };
1554
1671
  JaakStamps.style = myComponentCss;