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

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.
@@ -76,34 +76,65 @@ const JaakStamps = class {
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
  }
@@ -979,6 +1030,12 @@ const JaakStamps = class {
979
1030
  };
980
1031
  }
981
1032
  async startDetection() {
1033
+ this.logger.state('INICIANDO_DETECCION', {
1034
+ sessionExists: !!this.session,
1035
+ modelPreloaded: this.isModelPreloaded,
1036
+ videoActive: this.isVideoActive,
1037
+ captureStep: this.captureStep
1038
+ });
982
1039
  try {
983
1040
  // Check if model is already preloaded
984
1041
  if (!this.session) {
@@ -992,14 +1049,14 @@ const JaakStamps = class {
992
1049
  this.statusColor = "#007bff";
993
1050
  }
994
1051
  const modelPath = this.MODEL_PATH;
995
- this.debugLog('🤖 Loading detection model:', modelPath);
1052
+ this.logger.state('CARGANDO_MODELO_DETECCION', { modelPath });
996
1053
  const sessionOptions = this.getSessionOptions();
997
1054
  try {
998
1055
  this.session = await window.ort.InferenceSession.create(modelPath, sessionOptions);
999
1056
  }
1000
1057
  catch (error) {
1001
1058
  if (error.message.includes('failed to allocate a buffer')) {
1002
- this.debugLog(' Buffer allocation failed, trying with minimal settings');
1059
+ this.logger.warn('Fallo en asignación de buffer, intentando con configuración mínima');
1003
1060
  const fallbackOptions = {
1004
1061
  executionProviders: ['wasm'],
1005
1062
  graphOptimizationLevel: 'disabled',
@@ -1030,7 +1087,7 @@ const JaakStamps = class {
1030
1087
  this.emitReadyEvent();
1031
1088
  }
1032
1089
  else {
1033
- this.debugLog('🚀 Using preloaded models');
1090
+ this.logger.state('USANDO_MODELOS_PRECARGADOS', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
1034
1091
  if (this.debug) {
1035
1092
  this.statusMessage = "Usando modelos precargados...";
1036
1093
  this.statusColor = "#007bff";
@@ -1049,7 +1106,7 @@ const JaakStamps = class {
1049
1106
  this.detectFrame();
1050
1107
  }
1051
1108
  catch (err) {
1052
- this.debugLog("Error al inicializar:", err);
1109
+ this.logger.error('Error al inicializar detección:', err);
1053
1110
  this.statusMessage = "Error al inicializar el detector";
1054
1111
  this.statusColor = "#ff6b6b";
1055
1112
  this.isLoading = false;
@@ -1131,7 +1188,7 @@ const JaakStamps = class {
1131
1188
  }
1132
1189
  }
1133
1190
  catch (e) {
1134
- this.debugLog("Error en inferencia:", e);
1191
+ this.logger.error('Error en inferencia de modelo:', e);
1135
1192
  // Solo continuar si no hemos completado el proceso
1136
1193
  if (this.captureStep !== 'completed') {
1137
1194
  // On error, wait longer before retrying
@@ -1259,7 +1316,7 @@ const JaakStamps = class {
1259
1316
  if (!this.hasScreenshotTaken) {
1260
1317
  this.lastDetectedBox = bestBox;
1261
1318
  this.takeScreenshot().catch(error => {
1262
- this.debugLog('Error taking screenshot:', error);
1319
+ this.logger.error('Error al tomar captura de pantalla:', error);
1263
1320
  });
1264
1321
  this.hasScreenshotTaken = true;
1265
1322
  // Reset para permitir segunda captura
@@ -1277,6 +1334,7 @@ const JaakStamps = class {
1277
1334
  if (boxes.length === 0) {
1278
1335
  this.statusMessage = "Posicione la identificación dentro del marco";
1279
1336
  this.statusColor = "#ff6b6b";
1337
+ this.logger.debug('Sin detección de documento en el frame');
1280
1338
  }
1281
1339
  else {
1282
1340
  const bestBox = boxes.reduce((best, current) => current.score > best.score ? current : best);
@@ -1286,6 +1344,11 @@ const JaakStamps = class {
1286
1344
  if (allSidesAligned) {
1287
1345
  this.statusMessage = "Identificación perfectamente alineada. Mantenga inmóvil";
1288
1346
  this.statusColor = "#00ff00";
1347
+ this.logger.state('DOCUMENTO_PERFECTAMENTE_ALINEADO', {
1348
+ score: bestBox.score,
1349
+ boxDimensions: { width: bestBox.w, height: bestBox.h },
1350
+ alignedSides: 4
1351
+ });
1289
1352
  }
1290
1353
  else if (alignedSides > 0) {
1291
1354
  this.statusMessage = `Alinee los lados restantes (${alignedSides}/4 lados correctos)`;
@@ -1346,6 +1409,14 @@ const JaakStamps = class {
1346
1409
  async takeScreenshot() {
1347
1410
  if (!this.videoRef || !this.lastDetectedBox)
1348
1411
  return;
1412
+ this.logger.state('INICIANDO_CAPTURA', {
1413
+ captureStep: this.captureStep,
1414
+ detectedBox: this.lastDetectedBox,
1415
+ videoResolution: {
1416
+ width: this.videoRef.videoWidth,
1417
+ height: this.videoRef.videoHeight
1418
+ }
1419
+ });
1349
1420
  // Activar animación
1350
1421
  this.triggerCaptureAnimation();
1351
1422
  // OPTIMIZATION: Reuse capture canvas for full frame
@@ -1385,7 +1456,7 @@ const JaakStamps = class {
1385
1456
  await this.loadMobileNetModel();
1386
1457
  }
1387
1458
  catch (error) {
1388
- this.debugLog('⚠️ Failed to load classification model, continuing without classification:', error);
1459
+ this.logger.warn('Fallo al cargar modelo de clasificación, continuando sin clasificación:', error);
1389
1460
  }
1390
1461
  }
1391
1462
  // Classify the cropped document if model is available
@@ -1393,7 +1464,7 @@ const JaakStamps = class {
1393
1464
  const classification = await this.classifyDocument(croppedCanvas);
1394
1465
  if (classification && classification.class === 'passport') {
1395
1466
  // If it's a passport, skip back capture since passports don't have a back side
1396
- this.debugLog('📄 Passport detected - skipping back capture');
1467
+ this.logger.state('PASAPORTE_DETECTADO_SALTANDO_REVERSO', { classification: classification?.class });
1397
1468
  this.completeProcess(true);
1398
1469
  return;
1399
1470
  }
@@ -1414,14 +1485,23 @@ const JaakStamps = class {
1414
1485
  this.isDetectionPaused = false;
1415
1486
  }, 3000);
1416
1487
  }, 800);
1417
- this.debugLog('📸 FRENTE capturado. Esperando trasera...');
1488
+ this.logger.state('CAPTURA_FRENTE_COMPLETADA', {
1489
+ captureStep: this.captureStep,
1490
+ hasFullFrame: !!this.capturedFullFrame,
1491
+ hasCroppedId: !!this.capturedCroppedId
1492
+ });
1418
1493
  }
1419
1494
  else if (this.captureStep === 'back') {
1420
1495
  // Captura de la trasera usando canvas reutilizado
1421
1496
  this.capturedBackFullFrame = this.captureCanvas.toDataURL('image/png');
1422
1497
  this.capturedBackCroppedId = croppedCanvas.toDataURL('image/png');
1423
1498
  this.completeProcess(false);
1424
- this.debugLog('📸 TRASERA capturada. Proceso completado. Detector detenido. Imágenes emitidas.');
1499
+ this.logger.state('CAPTURA_TRASERA_COMPLETADA', {
1500
+ captureStep: this.captureStep,
1501
+ hasBackFullFrame: !!this.capturedBackFullFrame,
1502
+ hasBackCroppedId: !!this.capturedBackCroppedId,
1503
+ processCompleted: true
1504
+ });
1425
1505
  }
1426
1506
  }
1427
1507
  triggerCaptureAnimation() {
@@ -1445,7 +1525,7 @@ const JaakStamps = class {
1445
1525
  const ctx = this.canvasRef.getContext("2d");
1446
1526
  ctx.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
1447
1527
  }
1448
- this.debugLog('🛑 Detector de identificación detenido');
1528
+ this.logger.state('DETECTOR_DETENIDO', { timestamp: Date.now() });
1449
1529
  }
1450
1530
  resetDetection() {
1451
1531
  this.bestScore = 0;
@@ -1484,6 +1564,13 @@ const JaakStamps = class {
1484
1564
  "Proceso completado (solo frente capturado)" :
1485
1565
  "Proceso de captura completado exitosamente";
1486
1566
  this.statusColor = "#28a745";
1567
+ this.logger.state('PROCESO_COMPLETADO', {
1568
+ skippedBack,
1569
+ hasFrontImages: !!(this.capturedFullFrame && this.capturedCroppedId),
1570
+ hasBackImages: !!(this.capturedBackFullFrame && this.capturedBackCroppedId),
1571
+ totalImages: skippedBack ? 2 : 4,
1572
+ timestamp: new Date().toISOString()
1573
+ });
1487
1574
  // Detener el detector
1488
1575
  this.stopDetection();
1489
1576
  // Emitir evento con las imágenes capturadas
@@ -1535,7 +1622,7 @@ const JaakStamps = class {
1535
1622
  this.cleanup();
1536
1623
  }
1537
1624
  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: {
1625
+ return (h("div", { key: '87e2e2065012b5792b52b18349490492b5bdc80c', class: "detector-container" }, h("div", { key: '04b8bba38297d39c84ddc01f5a9bf72c65b9bef4', class: "video-container" }, h("video", { key: '905b99e1670fccb2ff5555818f91d0b0241fa29d', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: this.isVideoActive ? 'block' : 'none' } }), h("canvas", { key: '3f219b649b8d4f961b15256b8586451c2a737eb8', ref: el => this.canvasRef = el, class: this.shouldMirrorVideo ? 'mirror' : '' }), this.isMaskReady && (h("div", { key: 'f8d6742689d4446897ca48c2407cb3d3fab643e9', class: "overlay-mask" }, h("div", { key: '630a06c530f168cc0b71286adbf48fd922eb710d', class: "card-outline" }, h("div", { key: 'ce8c043ad41d5574cd0c4d737dec08b9f7fee927', class: "side side-top" }), h("div", { key: 'e90ead592f84e5df98143bc88714e70f32684204', class: "side side-right" }), h("div", { key: '31d6778c5036e42a3addb26c732149abc5a18ef7', class: "side side-bottom" }), h("div", { key: 'f85c31e77f024f9070c706b06b91d62a7fdbc357', class: "side side-left" }), h("div", { key: '27b362711bc53019483c0d36742d97e10ae9b9ce', class: "corner corner-tl" }), h("div", { key: '03b55893610684d690987c2eacf3c4e5d0c3bbe5', class: "corner corner-tr" }), h("div", { key: 'b6bf31327925c45a7fa8e1fd5ab2f25b824a03a2', class: "corner corner-bl" }), h("div", { key: '0737e0c82f8ad9703ce2546f3e594db6d50cafde', class: "corner corner-br" }), !this.showFlipAnimation && !this.showSuccessAnimation && (h("div", { key: '145f8383c496e151bd6ef4f5841292adeba083c4', class: "guide-text" }, this.statusMessage))), this.captureStep === 'back' && !this.showFlipAnimation && !this.showSuccessAnimation && (h("button", { key: 'fcdedebc31eddd21b978dd63e93c348d324b47da', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")), this.isVideoActive && (h("div", { key: 'dc9157bf7bed3b6439db742055201e2c4eddec84', class: "camera-controls" }, this.isMultipleCamerasAvailable && (h("button", { key: '6b052562ccb203dbf3cc8b627f31ed2435559f80', class: "flip-camera-button", onClick: () => this.flipCamera(), type: "button", title: "Cambiar c\u00E1mara" }, "Girar c\u00E1mara")), h("button", { key: 'f9fad1757d01f0cb45f65bb2088bd1f0bc0e4e8d', class: "camera-selector-button", onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara" }, "C\u00E1maras"), this.debug && (h("div", { key: '5362fb33508c7f903b09f65fdb449b608804260d', style: {
1539
1626
  position: 'absolute',
1540
1627
  top: '50px',
1541
1628
  right: '0',
@@ -1545,10 +1632,10 @@ const JaakStamps = class {
1545
1632
  fontSize: '10px',
1546
1633
  borderRadius: '4px',
1547
1634
  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: () => {
1635
+ } }, "C\u00E1maras: ", this.availableCameras.length, h("br", { key: '5ead451a54a59c885f62740d0a0ce43ba8b674e4' }), "M\u00FAltiples: ", this.isMultipleCamerasAvailable ? 'Sí' : 'No', h("br", { key: '9a92514d07576ed7052eaa3a418c00013ef7c479' }), "Selector: ", this.showCameraSelector ? 'Visible' : 'Oculto', h("br", { key: 'd06abebad3b2e3c19aa22e511e0c4cfd4425b8b2' }), "Video: ", this.isVideoActive ? 'Activo' : 'Inactivo')))), this.showCameraSelector && this.availableCameras.length > 0 && (h("div", { key: '93a09ce3bb108175b55944a71c21e86e58de55be', class: "camera-selector-dropdown" }, h("div", { key: '7ceb4c8826945ab2a9da106a88a44cbb5490e92a', class: "camera-selector-header" }, h("span", { key: 'fa98621700584d8021ff57eca6f804b6eb792c5b' }, "Seleccionar C\u00E1mara"), h("button", { key: 'ce6477a1494f58fb5974dd7c9e62bd7d041572c5', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'eff226b006c95fafce2566947155e13ee68f9a02', class: "camera-list" }, this.availableCameras.map((camera) => (h("button", { key: camera.deviceId, class: `camera-option ${this.selectedCameraId === camera.deviceId ? 'selected' : ''}`, onClick: () => {
1549
1636
  this.switchCamera(camera.deviceId);
1550
1637
  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" })))));
1638
+ }, 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: '617d33caa5d3b3e6dca56d479b27c0ac7ed19c2c', class: "device-info" }, h("small", { key: 'fba56ac1238c33864f8dba1d8bd9a5661e11d770' }, "Dispositivo: ", this.deviceType)))))), this.isCapturing && (h("div", { key: 'b46982a0b949ee9d50d0a819c59b24dceec9d7b2', class: "capture-animation" })), this.showFlipAnimation && (h("div", { key: 'c82773fffca8ec53949197a105e1e11bf0f9b294', class: "flip-animation" }, h("div", { key: 'ad52c9ec91132bf5ed94e36f621489a66b0bf680', class: "id-card-icon" }), h("div", { key: '2be407ee84beddc5ce968a9a94d9014f416cde54', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), this.showSuccessAnimation && (h("div", { key: 'f20b6be925178a123de99e535e893b7c09391dee', class: "success-animation" }, h("div", { key: 'd3ae65d40943f73bc92e9529764ded454adc5dbf', class: "check-icon" }), h("div", { key: 'f2b03082a106c69f09d384ba3b1cb4a636d3a189', class: "success-text" }, "\u00A1Proceso completado!"))), this.isLoading && (h("div", { key: '65736e303d9eb1c3f6f2dccb5cc0d27c571ac9c8', class: "loading-overlay" }, h("div", { key: '5863d855d1caea9202a9f3d0a29919985ddbb926', class: "loading-spinner" }), h("div", { key: 'aa5a16c96ac6bfa43846ba06346fad6dce39dfbb', class: "loading-text" }, this.statusMessage))), this.debug && (h("div", { key: '308c664b07d2c2427c38f766fc9eb78d27843f67', class: "status-bar" }, h("div", { key: '3884b311710d7f373a508eb492771e503e68f648', class: "status-message", style: { 'color': this.statusColor } }, this.statusMessage))), h("div", { key: '3125cfecda03d3ab9e80e0d9d5674f1cc167e2f8', class: "watermark" }, h("img", { key: '5ef43a18aea74f570db0d61f4fd86c3becf1d23e', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1552
1639
  }
1553
1640
  };
1554
1641
  JaakStamps.style = myComponentCss;