@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.
@@ -68,34 +68,65 @@ export class JaakStamps {
68
68
  CONFIDENCE_THRESHOLD = 0.6;
69
69
  // ISO/IEC 7810 ID-1 standard dimensions (85.60mm x 53.98mm)
70
70
  ID1_ASPECT_RATIO = 85.60 / 53.98; // 1.5863320574...
71
- debugLog(...args) {
72
- if (this.debug) {
73
- console.log(...args);
71
+ logger = {
72
+ info: (...args) => {
73
+ if (this.debug) {
74
+ console.log(`[JAAK-STAMPS] [INFO] [${new Date().toLocaleTimeString()}]`, ...args);
75
+ }
76
+ },
77
+ warn: (...args) => {
78
+ if (this.debug) {
79
+ console.warn(`[JAAK-STAMPS] [WARN] [${new Date().toLocaleTimeString()}]`, ...args);
80
+ }
81
+ },
82
+ error: (...args) => {
83
+ if (this.debug) {
84
+ console.error(`[JAAK-STAMPS] [ERROR] [${new Date().toLocaleTimeString()}]`, ...args);
85
+ }
86
+ },
87
+ debug: (...args) => {
88
+ if (this.debug) {
89
+ console.debug(`[JAAK-STAMPS] [DEBUG] [${new Date().toLocaleTimeString()}]`, ...args);
90
+ }
91
+ },
92
+ state: (state, data) => {
93
+ if (this.debug) {
94
+ console.log(`[JAAK-STAMPS] [STATE] [${new Date().toLocaleTimeString()}] ${state}`, data || '');
95
+ }
96
+ },
97
+ performance: (operation, duration) => {
98
+ if (this.debug) {
99
+ console.log(`[JAAK-STAMPS] [PERF] [${new Date().toLocaleTimeString()}] ${operation}: ${duration}ms`);
100
+ }
74
101
  }
75
- }
102
+ };
76
103
  validateMaskSize() {
77
104
  if (this.maskSize < 50 || this.maskSize > 100) {
78
- console.warn(`maskSize debe estar entre 50 y 100. Valor actual: ${this.maskSize}. Usando valor por defecto: 90`);
105
+ this.logger.warn(`Propiedad maskSize inválida. Valor: ${this.maskSize}, esperado: 50-100. Usando valor por defecto: 90`);
79
106
  this.maskSize = 90;
80
107
  }
81
108
  }
82
109
  validateCropMargin() {
83
110
  if (this.cropMargin < 0 || this.cropMargin > 100) {
84
- console.warn(`cropMargin debe estar entre 0 y 100. Valor actual: ${this.cropMargin}. Usando valor por defecto: 0`);
111
+ this.logger.warn(`Propiedad cropMargin inválida. Valor: ${this.cropMargin}, esperado: 0-100. Usando valor por defecto: 0`);
85
112
  this.cropMargin = 0;
86
113
  }
87
114
  }
88
115
  validatePreferredCamera() {
89
116
  const validOptions = ['auto', 'front', 'back'];
90
117
  if (!validOptions.includes(this.preferredCamera)) {
91
- console.warn(`preferredCamera debe ser uno de: ${validOptions.join(', ')}. Valor actual: ${this.preferredCamera}. Usando valor por defecto: 'auto'`);
118
+ this.logger.warn(`Propiedad preferredCamera inválida. Valor: ${this.preferredCamera}, esperado: ${validOptions.join(', ')}. Usando valor por defecto: 'auto'`);
92
119
  this.preferredCamera = 'auto';
93
120
  }
94
121
  }
95
122
  emitReadyEvent() {
96
123
  const isDocumentReady = !!window.ort && this.isModelPreloaded;
97
124
  this.isReady.emit(isDocumentReady);
98
- this.debugLog('🟢 isReady event emitted:', isDocumentReady);
125
+ this.logger.state('COMPONENTE_LISTO', {
126
+ ortLibraryLoaded: !!window.ort,
127
+ modelPreloaded: this.isModelPreloaded,
128
+ isReady: isDocumentReady
129
+ });
99
130
  }
100
131
  isRearCamera(stream) {
101
132
  const videoTrack = stream.getVideoTracks()[0];
@@ -118,7 +149,11 @@ export class JaakStamps {
118
149
  else {
119
150
  this.deviceType = 'desktop';
120
151
  }
121
- this.debugLog('📱 Device type detected:', this.deviceType);
152
+ this.logger.state('DISPOSITIVO_DETECTADO', {
153
+ deviceType: this.deviceType,
154
+ userAgent: navigator.userAgent,
155
+ screenDimensions: { width: window.innerWidth, height: window.innerHeight }
156
+ });
122
157
  // Enumerate available cameras
123
158
  await this.enumerateAndDetectCameras();
124
159
  // Load user preference
@@ -129,7 +164,7 @@ export class JaakStamps {
129
164
  // First, check if we have permission to enumerate devices
130
165
  const permissionStatus = await this.checkCameraPermission();
131
166
  if (permissionStatus === 'denied') {
132
- this.debugLog(' Camera permission denied');
167
+ this.logger.error('Permiso de cámara denegado por el usuario');
133
168
  this.statusMessage = "Permiso de cámara denegado";
134
169
  this.statusColor = "#ff6b6b";
135
170
  return;
@@ -143,7 +178,7 @@ export class JaakStamps {
143
178
  const devices = await navigator.mediaDevices.enumerateDevices();
144
179
  this.availableCameras = devices.filter(device => device.kind === 'videoinput');
145
180
  this.isMultipleCamerasAvailable = this.availableCameras.length > 1;
146
- this.debugLog('📹 Available cameras:', {
181
+ this.logger.state('CAMARAS_DETECTADAS', {
147
182
  count: this.availableCameras.length,
148
183
  isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
149
184
  cameras: this.availableCameras.map(cam => ({
@@ -155,7 +190,7 @@ export class JaakStamps {
155
190
  this.setInitialCameraPreference();
156
191
  }
157
192
  catch (error) {
158
- this.debugLog('Error enumerating cameras:', error);
193
+ this.logger.error('Error al enumerar cámaras disponibles:', error);
159
194
  this.handleCameraPermissionError(error);
160
195
  }
161
196
  }
@@ -168,7 +203,7 @@ export class JaakStamps {
168
203
  return permission.state;
169
204
  }
170
205
  catch (error) {
171
- this.debugLog('⚠️ Could not check camera permission:', error);
206
+ this.logger.warn('No se pudo verificar permisos de cámara:', error);
172
207
  return 'prompt';
173
208
  }
174
209
  }
@@ -211,11 +246,11 @@ export class JaakStamps {
211
246
  !camera.label.toLowerCase().includes('back') && !camera.label.toLowerCase().includes('rear'));
212
247
  if (frontCamera) {
213
248
  this.selectedCameraId = frontCamera.deviceId;
214
- this.debugLog('👤 User selected front camera:', frontCamera.label);
249
+ this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { label: frontCamera.label, deviceId: frontCamera.deviceId });
215
250
  }
216
251
  else {
217
252
  this.selectedCameraId = this.availableCameras[0].deviceId;
218
- this.debugLog('⚠️ Front camera not found, using first available:', this.availableCameras[0].label);
253
+ this.logger.warn('Cámara frontal no encontrada, usando primera disponible:', this.availableCameras[0].label);
219
254
  }
220
255
  }
221
256
  else if (this.preferredCamera === 'back') {
@@ -226,11 +261,11 @@ export class JaakStamps {
226
261
  camera.label.toLowerCase().includes('environment'));
227
262
  if (backCamera) {
228
263
  this.selectedCameraId = backCamera.deviceId;
229
- this.debugLog('📷 User selected back camera:', backCamera.label);
264
+ this.logger.state('CAMARA_TRASERA_SELECCIONADA', { label: backCamera.label, deviceId: backCamera.deviceId });
230
265
  }
231
266
  else {
232
267
  this.selectedCameraId = this.availableCameras[0].deviceId;
233
- this.debugLog('⚠️ Back camera not found, using first available:', this.availableCameras[0].label);
268
+ this.logger.warn('Cámara trasera no encontrada, usando primera disponible:', this.availableCameras[0].label);
234
269
  }
235
270
  }
236
271
  else {
@@ -243,17 +278,17 @@ export class JaakStamps {
243
278
  camera.label.toLowerCase().includes('environment'));
244
279
  if (rearCamera) {
245
280
  this.selectedCameraId = rearCamera.deviceId;
246
- this.debugLog('📱 Auto-selected rear camera for mobile:', rearCamera.label);
281
+ this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear', label: rearCamera.label, deviceId: rearCamera.deviceId });
247
282
  }
248
283
  else {
249
284
  this.selectedCameraId = this.availableCameras[0].deviceId;
250
- this.debugLog('📱 Rear camera not found, using first available:', this.availableCameras[0].label);
285
+ this.logger.warn('Cámara trasera no encontrada en mobile, usando primera disponible:', this.availableCameras[0].label);
251
286
  }
252
287
  }
253
288
  else {
254
289
  // For desktop, use first available camera (usually the only one)
255
290
  this.selectedCameraId = this.availableCameras[0].deviceId;
256
- this.debugLog('💻 Auto-selected desktop camera:', this.availableCameras[0].label);
291
+ this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { label: this.availableCameras[0].label, deviceId: this.availableCameras[0].deviceId });
257
292
  }
258
293
  }
259
294
  }
@@ -267,12 +302,12 @@ export class JaakStamps {
267
302
  if (isStillAvailable) {
268
303
  this.selectedCameraId = preference.cameraId;
269
304
  this.preferredCameraFacing = preference.facing;
270
- this.debugLog('💾 Loaded camera preference:', preference);
305
+ this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);
271
306
  }
272
307
  }
273
308
  }
274
309
  catch (error) {
275
- this.debugLog('⚠️ Error loading camera preference:', error);
310
+ this.logger.warn('Error al cargar preferencia de cámara:', error);
276
311
  }
277
312
  }
278
313
  saveCameraPreference() {
@@ -283,10 +318,10 @@ export class JaakStamps {
283
318
  timestamp: Date.now()
284
319
  };
285
320
  localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));
286
- this.debugLog('💾 Saved camera preference:', preference);
321
+ this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);
287
322
  }
288
323
  catch (error) {
289
- this.debugLog('⚠️ Error saving camera preference:', error);
324
+ this.logger.warn('Error al guardar preferencia de cámara:', error);
290
325
  }
291
326
  }
292
327
  async switchCamera(cameraId) {
@@ -296,7 +331,7 @@ export class JaakStamps {
296
331
  // Check if the selected camera is still available
297
332
  const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);
298
333
  if (!selectedCamera) {
299
- this.debugLog(' Selected camera not found, re-enumerating...');
334
+ this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');
300
335
  await this.enumerateAndDetectCameras();
301
336
  return;
302
337
  }
@@ -320,10 +355,10 @@ export class JaakStamps {
320
355
  this.saveCameraPreference();
321
356
  // Setup new camera with error handling
322
357
  await this.setupCameraWithRetry();
323
- this.debugLog('🔄 Switched to camera:', selectedCamera.label);
358
+ this.logger.state('CAMARA_CAMBIADA', { label: selectedCamera.label, deviceId: selectedCamera.deviceId });
324
359
  }
325
360
  catch (error) {
326
- this.debugLog('Error switching camera:', error);
361
+ this.logger.error('Error al cambiar de cámara:', error);
327
362
  this.handleCameraPermissionError(error);
328
363
  }
329
364
  }
@@ -338,7 +373,7 @@ export class JaakStamps {
338
373
  return; // Success
339
374
  }
340
375
  catch (error) {
341
- this.debugLog(`❌ Camera setup attempt ${attempt} failed:`, error);
376
+ this.logger.error(`Intento ${attempt} de configuración de cámara fallido:`, error);
342
377
  if (attempt === maxRetries) {
343
378
  // Last attempt failed, handle the error
344
379
  this.statusMessage = "Error al configurar la cámara";
@@ -358,7 +393,7 @@ export class JaakStamps {
358
393
  }
359
394
  toggleCameraSelector() {
360
395
  this.showCameraSelector = !this.showCameraSelector;
361
- this.debugLog('📹 Camera selector toggled:', {
396
+ this.logger.state('SELECTOR_CAMARA_TOGGLE', {
362
397
  showCameraSelector: this.showCameraSelector,
363
398
  isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
364
399
  availableCameras: this.availableCameras.length,
@@ -374,6 +409,13 @@ export class JaakStamps {
374
409
  await this.switchCamera(nextCamera.deviceId);
375
410
  }
376
411
  async componentDidLoad() {
412
+ this.logger.state('COMPONENTE_INICIALIZANDO', {
413
+ debug: this.debug,
414
+ maskSize: this.maskSize,
415
+ cropMargin: this.cropMargin,
416
+ useDocumentClassification: this.useDocumentClassification,
417
+ preferredCamera: this.preferredCamera
418
+ });
377
419
  if (this.debug) {
378
420
  // Show detailed initialization loading state only in debug mode
379
421
  this.isLoading = true;
@@ -438,7 +480,7 @@ export class JaakStamps {
438
480
  this.canvasRef.height = rect.height;
439
481
  // Update mask positioning based on container and video dimensions
440
482
  this.updateMaskDimensions(rect);
441
- this.debugLog('📐 Canvas resized:', { width: rect.width, height: rect.height });
483
+ this.logger.debug('Canvas redimensionado:', { width: rect.width, height: rect.height });
442
484
  }
443
485
  }
444
486
  updateMaskDimensions(containerRect) {
@@ -498,7 +540,7 @@ export class JaakStamps {
498
540
  this.el.style.setProperty('--mask-center-y', `${videoCenterYPercent}%`);
499
541
  // Mark mask as ready now that dimensions are calculated
500
542
  this.isMaskReady = true;
501
- this.debugLog('🎯 Mask dimensions updated:', {
543
+ this.logger.state('DIMENSIONES_MASCARA_ACTUALIZADAS', {
502
544
  video: { width: videoWidth, height: videoHeight },
503
545
  displayed: { width: displayedVideoWidth, height: displayedVideoHeight },
504
546
  mask: { widthPercent: maskWidthPercent, heightPercent: maskHeightPercent },
@@ -520,7 +562,7 @@ export class JaakStamps {
520
562
  this.captureCtx = this.captureCanvas.getContext('2d', {
521
563
  alpha: false
522
564
  });
523
- this.debugLog('🎨 Canvas pool initialized for performance');
565
+ this.logger.state('CANVAS_POOL_INICIALIZADO', { preprocessCanvasSize: this.INPUT_SIZE });
524
566
  }
525
567
  disconnectedCallback() {
526
568
  this.cleanup();
@@ -568,7 +610,7 @@ export class JaakStamps {
568
610
  }
569
611
  async preloadModel() {
570
612
  if (this.isModelPreloaded || this.session) {
571
- this.debugLog('🚀 Model already preloaded or session exists');
613
+ this.logger.state('MODELO_YA_PRECARGADO', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
572
614
  return { success: true, message: 'Model already loaded' };
573
615
  }
574
616
  try {
@@ -576,7 +618,7 @@ export class JaakStamps {
576
618
  this.statusMessage = "Precargando modelos...";
577
619
  this.statusColor = "#007bff";
578
620
  const modelPath = this.MODEL_PATH;
579
- this.debugLog('🤖 Preloading detection model:', modelPath);
621
+ this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath });
580
622
  // Configure ONNX Runtime with device-specific optimizations
581
623
  const sessionOptions = this.getSessionOptions();
582
624
  const deviceInfo = this.getDeviceMemoryInfo();
@@ -585,7 +627,7 @@ export class JaakStamps {
585
627
  }
586
628
  catch (error) {
587
629
  if (error.message.includes('failed to allocate a buffer')) {
588
- this.debugLog(' Buffer allocation failed during preload, trying with minimal settings');
630
+ this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');
589
631
  const fallbackOptions = {
590
632
  executionProviders: ['wasm'],
591
633
  graphOptimizationLevel: 'disabled',
@@ -606,7 +648,7 @@ export class JaakStamps {
606
648
  // For low memory devices, load sequentially to avoid memory pressure
607
649
  if (this.useDocumentClassification) {
608
650
  if (deviceInfo.isLowMemory) {
609
- this.debugLog('🔄 Sequential model loading for low memory device');
651
+ this.logger.state('CARGA_SECUENCIAL_MODELOS', { reason: 'low memory device' });
610
652
  await new Promise(resolve => setTimeout(resolve, 1000));
611
653
  }
612
654
  await this.loadMobileNetModel();
@@ -616,11 +658,15 @@ export class JaakStamps {
616
658
  this.statusMessage = "Modelos precargados. Listo para comenzar detección";
617
659
  this.statusColor = "#28a745";
618
660
  this.emitReadyEvent();
619
- this.debugLog(' Models preloaded successfully');
661
+ this.logger.state('MODELOS_PRECARGADOS_EXITOSAMENTE', {
662
+ detectionModel: !!this.session,
663
+ classificationModel: !!this.mobileNetSession,
664
+ useClassification: this.useDocumentClassification
665
+ });
620
666
  return { success: true, message: 'Models preloaded successfully' };
621
667
  }
622
668
  catch (error) {
623
- this.debugLog('Error preloading models:', error);
669
+ this.logger.error('Error al precargar modelos:', error);
624
670
  this.isLoading = false;
625
671
  this.statusMessage = "Error al precargar los modelos";
626
672
  this.statusColor = "#ff6b6b";
@@ -648,7 +694,7 @@ export class JaakStamps {
648
694
  }
649
695
  async setPreferredCamera(camera) {
650
696
  this.preferredCamera = camera;
651
- this.debugLog('🎯 Camera preference changed to:', camera);
697
+ this.logger.state('PREFERENCIA_CAMARA_CAMBIADA', { newPreference: camera });
652
698
  // Re-detect and apply new camera preference
653
699
  await this.enumerateAndDetectCameras();
654
700
  // If video is active, switch to the new preferred camera
@@ -663,14 +709,14 @@ export class JaakStamps {
663
709
  }
664
710
  async loadMobileNetModel() {
665
711
  try {
666
- this.debugLog('🤖 Loading MobileNet model...');
712
+ this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
667
713
  // Load class map
668
714
  const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
669
715
  if (!classResponse.ok) {
670
716
  throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
671
717
  }
672
718
  this.mobileNetClassMap = await classResponse.json();
673
- this.debugLog('📋 MobileNet classes loaded:', this.mobileNetClassMap);
719
+ this.logger.state('CLASES_MOBILENET_CARGADAS', { classCount: Object.keys(this.mobileNetClassMap).length });
674
720
  // Load model
675
721
  const sessionOptions = this.getSessionOptions();
676
722
  try {
@@ -678,7 +724,7 @@ export class JaakStamps {
678
724
  }
679
725
  catch (error) {
680
726
  if (error.message.includes('failed to allocate a buffer')) {
681
- this.debugLog(' MobileNet buffer allocation failed, trying with minimal settings');
727
+ this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');
682
728
  const fallbackOptions = {
683
729
  executionProviders: ['wasm'],
684
730
  graphOptimizationLevel: 'disabled',
@@ -695,10 +741,10 @@ export class JaakStamps {
695
741
  throw error;
696
742
  }
697
743
  }
698
- this.debugLog(' MobileNet model loaded successfully');
744
+ this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.mobileNetSession });
699
745
  }
700
746
  catch (error) {
701
- this.debugLog('Error loading MobileNet model:', error);
747
+ this.logger.error('Error al cargar modelo MobileNet:', error);
702
748
  throw error;
703
749
  }
704
750
  }
@@ -725,11 +771,11 @@ export class JaakStamps {
725
771
  }
726
772
  async classifyDocument(canvas) {
727
773
  if (!this.mobileNetSession || !this.mobileNetClassMap) {
728
- this.debugLog('⚠️ MobileNet model not loaded');
774
+ this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');
729
775
  return null;
730
776
  }
731
777
  try {
732
- this.debugLog('🔍 Classifying document...');
778
+ this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
733
779
  // Preprocess image for MobileNet
734
780
  const inputTensor = this.preprocessMobileNet(canvas);
735
781
  // Run inference
@@ -740,10 +786,11 @@ export class JaakStamps {
740
786
  const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
741
787
  const confidence = output[maxIdx];
742
788
  const className = this.mobileNetClassMap[maxIdx.toString()] || "unknown";
743
- this.debugLog('📄 Document classification result:', {
789
+ this.logger.state('DOCUMENTO_CLASIFICADO', {
744
790
  class: className,
745
791
  confidence: confidence.toFixed(3),
746
- classIndex: maxIdx
792
+ classIndex: maxIdx,
793
+ timestamp: Date.now()
747
794
  });
748
795
  return {
749
796
  class: className,
@@ -752,7 +799,7 @@ export class JaakStamps {
752
799
  };
753
800
  }
754
801
  catch (error) {
755
- this.debugLog('Error classifying document:', error);
802
+ this.logger.error('Error al clasificar documento:', error);
756
803
  return null;
757
804
  }
758
805
  }
@@ -794,7 +841,7 @@ export class JaakStamps {
794
841
  }
795
842
  this.mobileNetClassMap = undefined;
796
843
  this.isModelPreloaded = false;
797
- this.debugLog('🧹 Canvas pool cleaned up');
844
+ this.logger.state('CANVAS_POOL_LIMPIADO', { timestamp: Date.now() });
798
845
  }
799
846
  async getMaxResolution() {
800
847
  try {
@@ -844,18 +891,19 @@ export class JaakStamps {
844
891
  constraints.width = { ideal: maxWidth };
845
892
  constraints.height = { ideal: maxHeight };
846
893
  }
847
- this.debugLog('📐 Resolution capabilities:', {
894
+ this.logger.state('CAPACIDADES_RESOLUCION_DETECTADAS', {
848
895
  maxWidth: capabilities.width.max,
849
896
  maxHeight: capabilities.height.max,
850
897
  selectedWidth: constraints.width.ideal,
851
898
  selectedHeight: constraints.height.ideal,
852
- isTablet
899
+ isTablet,
900
+ deviceType: this.deviceType
853
901
  });
854
902
  }
855
903
  return constraints;
856
904
  }
857
905
  catch (err) {
858
- this.debugLog('⚠️ Could not get capabilities, using fallback');
906
+ this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');
859
907
  // Optimized fallback for tablets
860
908
  const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
861
909
  const fallbackConstraints = {
@@ -888,8 +936,11 @@ export class JaakStamps {
888
936
  // Determine if video should be mirrored
889
937
  const isRear = this.isRearCamera(stream);
890
938
  this.shouldMirrorVideo = !isRear;
891
- this.debugLog('📹 Rear camera:', isRear);
892
- this.debugLog('🪞 Should mirror video:', this.shouldMirrorVideo);
939
+ this.logger.state('CAMARA_CONFIGURADA', {
940
+ isRearCamera: isRear,
941
+ shouldMirrorVideo: this.shouldMirrorVideo,
942
+ videoActive: this.isVideoActive
943
+ });
893
944
  return new Promise((resolve) => {
894
945
  this.videoRef.onloadedmetadata = async () => {
895
946
  await this.videoRef.play();
@@ -906,7 +957,7 @@ export class JaakStamps {
906
957
  }
907
958
  }
908
959
  catch (err) {
909
- this.debugLog("❌ No se pudo acceder a la cámara:", err);
960
+ this.logger.error('No se pudo acceder a la cámara:', err);
910
961
  this.handleCameraPermissionError(err);
911
962
  }
912
963
  }
@@ -972,6 +1023,12 @@ export class JaakStamps {
972
1023
  };
973
1024
  }
974
1025
  async startDetection() {
1026
+ this.logger.state('INICIANDO_DETECCION', {
1027
+ sessionExists: !!this.session,
1028
+ modelPreloaded: this.isModelPreloaded,
1029
+ videoActive: this.isVideoActive,
1030
+ captureStep: this.captureStep
1031
+ });
975
1032
  try {
976
1033
  // Check if model is already preloaded
977
1034
  if (!this.session) {
@@ -985,14 +1042,14 @@ export class JaakStamps {
985
1042
  this.statusColor = "#007bff";
986
1043
  }
987
1044
  const modelPath = this.MODEL_PATH;
988
- this.debugLog('🤖 Loading detection model:', modelPath);
1045
+ this.logger.state('CARGANDO_MODELO_DETECCION', { modelPath });
989
1046
  const sessionOptions = this.getSessionOptions();
990
1047
  try {
991
1048
  this.session = await window.ort.InferenceSession.create(modelPath, sessionOptions);
992
1049
  }
993
1050
  catch (error) {
994
1051
  if (error.message.includes('failed to allocate a buffer')) {
995
- this.debugLog(' Buffer allocation failed, trying with minimal settings');
1052
+ this.logger.warn('Fallo en asignación de buffer, intentando con configuración mínima');
996
1053
  const fallbackOptions = {
997
1054
  executionProviders: ['wasm'],
998
1055
  graphOptimizationLevel: 'disabled',
@@ -1023,7 +1080,7 @@ export class JaakStamps {
1023
1080
  this.emitReadyEvent();
1024
1081
  }
1025
1082
  else {
1026
- this.debugLog('🚀 Using preloaded models');
1083
+ this.logger.state('USANDO_MODELOS_PRECARGADOS', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
1027
1084
  if (this.debug) {
1028
1085
  this.statusMessage = "Usando modelos precargados...";
1029
1086
  this.statusColor = "#007bff";
@@ -1042,7 +1099,7 @@ export class JaakStamps {
1042
1099
  this.detectFrame();
1043
1100
  }
1044
1101
  catch (err) {
1045
- this.debugLog("Error al inicializar:", err);
1102
+ this.logger.error('Error al inicializar detección:', err);
1046
1103
  this.statusMessage = "Error al inicializar el detector";
1047
1104
  this.statusColor = "#ff6b6b";
1048
1105
  this.isLoading = false;
@@ -1124,7 +1181,7 @@ export class JaakStamps {
1124
1181
  }
1125
1182
  }
1126
1183
  catch (e) {
1127
- this.debugLog("Error en inferencia:", e);
1184
+ this.logger.error('Error en inferencia de modelo:', e);
1128
1185
  // Solo continuar si no hemos completado el proceso
1129
1186
  if (this.captureStep !== 'completed') {
1130
1187
  // On error, wait longer before retrying
@@ -1252,7 +1309,7 @@ export class JaakStamps {
1252
1309
  if (!this.hasScreenshotTaken) {
1253
1310
  this.lastDetectedBox = bestBox;
1254
1311
  this.takeScreenshot().catch(error => {
1255
- this.debugLog('Error taking screenshot:', error);
1312
+ this.logger.error('Error al tomar captura de pantalla:', error);
1256
1313
  });
1257
1314
  this.hasScreenshotTaken = true;
1258
1315
  // Reset para permitir segunda captura
@@ -1270,6 +1327,7 @@ export class JaakStamps {
1270
1327
  if (boxes.length === 0) {
1271
1328
  this.statusMessage = "Posicione la identificación dentro del marco";
1272
1329
  this.statusColor = "#ff6b6b";
1330
+ this.logger.debug('Sin detección de documento en el frame');
1273
1331
  }
1274
1332
  else {
1275
1333
  const bestBox = boxes.reduce((best, current) => current.score > best.score ? current : best);
@@ -1279,6 +1337,11 @@ export class JaakStamps {
1279
1337
  if (allSidesAligned) {
1280
1338
  this.statusMessage = "Identificación perfectamente alineada. Mantenga inmóvil";
1281
1339
  this.statusColor = "#00ff00";
1340
+ this.logger.state('DOCUMENTO_PERFECTAMENTE_ALINEADO', {
1341
+ score: bestBox.score,
1342
+ boxDimensions: { width: bestBox.w, height: bestBox.h },
1343
+ alignedSides: 4
1344
+ });
1282
1345
  }
1283
1346
  else if (alignedSides > 0) {
1284
1347
  this.statusMessage = `Alinee los lados restantes (${alignedSides}/4 lados correctos)`;
@@ -1339,6 +1402,14 @@ export class JaakStamps {
1339
1402
  async takeScreenshot() {
1340
1403
  if (!this.videoRef || !this.lastDetectedBox)
1341
1404
  return;
1405
+ this.logger.state('INICIANDO_CAPTURA', {
1406
+ captureStep: this.captureStep,
1407
+ detectedBox: this.lastDetectedBox,
1408
+ videoResolution: {
1409
+ width: this.videoRef.videoWidth,
1410
+ height: this.videoRef.videoHeight
1411
+ }
1412
+ });
1342
1413
  // Activar animación
1343
1414
  this.triggerCaptureAnimation();
1344
1415
  // OPTIMIZATION: Reuse capture canvas for full frame
@@ -1378,7 +1449,7 @@ export class JaakStamps {
1378
1449
  await this.loadMobileNetModel();
1379
1450
  }
1380
1451
  catch (error) {
1381
- this.debugLog('⚠️ Failed to load classification model, continuing without classification:', error);
1452
+ this.logger.warn('Fallo al cargar modelo de clasificación, continuando sin clasificación:', error);
1382
1453
  }
1383
1454
  }
1384
1455
  // Classify the cropped document if model is available
@@ -1386,7 +1457,7 @@ export class JaakStamps {
1386
1457
  const classification = await this.classifyDocument(croppedCanvas);
1387
1458
  if (classification && classification.class === 'passport') {
1388
1459
  // If it's a passport, skip back capture since passports don't have a back side
1389
- this.debugLog('📄 Passport detected - skipping back capture');
1460
+ this.logger.state('PASAPORTE_DETECTADO_SALTANDO_REVERSO', { classification: classification?.class });
1390
1461
  this.completeProcess(true);
1391
1462
  return;
1392
1463
  }
@@ -1407,14 +1478,23 @@ export class JaakStamps {
1407
1478
  this.isDetectionPaused = false;
1408
1479
  }, 3000);
1409
1480
  }, 800);
1410
- this.debugLog('📸 FRENTE capturado. Esperando trasera...');
1481
+ this.logger.state('CAPTURA_FRENTE_COMPLETADA', {
1482
+ captureStep: this.captureStep,
1483
+ hasFullFrame: !!this.capturedFullFrame,
1484
+ hasCroppedId: !!this.capturedCroppedId
1485
+ });
1411
1486
  }
1412
1487
  else if (this.captureStep === 'back') {
1413
1488
  // Captura de la trasera usando canvas reutilizado
1414
1489
  this.capturedBackFullFrame = this.captureCanvas.toDataURL('image/png');
1415
1490
  this.capturedBackCroppedId = croppedCanvas.toDataURL('image/png');
1416
1491
  this.completeProcess(false);
1417
- this.debugLog('📸 TRASERA capturada. Proceso completado. Detector detenido. Imágenes emitidas.');
1492
+ this.logger.state('CAPTURA_TRASERA_COMPLETADA', {
1493
+ captureStep: this.captureStep,
1494
+ hasBackFullFrame: !!this.capturedBackFullFrame,
1495
+ hasBackCroppedId: !!this.capturedBackCroppedId,
1496
+ processCompleted: true
1497
+ });
1418
1498
  }
1419
1499
  }
1420
1500
  triggerCaptureAnimation() {
@@ -1438,7 +1518,7 @@ export class JaakStamps {
1438
1518
  const ctx = this.canvasRef.getContext("2d");
1439
1519
  ctx.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
1440
1520
  }
1441
- this.debugLog('🛑 Detector de identificación detenido');
1521
+ this.logger.state('DETECTOR_DETENIDO', { timestamp: Date.now() });
1442
1522
  }
1443
1523
  resetDetection() {
1444
1524
  this.bestScore = 0;
@@ -1477,6 +1557,13 @@ export class JaakStamps {
1477
1557
  "Proceso completado (solo frente capturado)" :
1478
1558
  "Proceso de captura completado exitosamente";
1479
1559
  this.statusColor = "#28a745";
1560
+ this.logger.state('PROCESO_COMPLETADO', {
1561
+ skippedBack,
1562
+ hasFrontImages: !!(this.capturedFullFrame && this.capturedCroppedId),
1563
+ hasBackImages: !!(this.capturedBackFullFrame && this.capturedBackCroppedId),
1564
+ totalImages: skippedBack ? 2 : 4,
1565
+ timestamp: new Date().toISOString()
1566
+ });
1480
1567
  // Detener el detector
1481
1568
  this.stopDetection();
1482
1569
  // Emitir evento con las imágenes capturadas
@@ -1528,7 +1615,7 @@ export class JaakStamps {
1528
1615
  this.cleanup();
1529
1616
  }
1530
1617
  render() {
1531
- 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: {
1618
+ 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: {
1532
1619
  position: 'absolute',
1533
1620
  top: '50px',
1534
1621
  right: '0',
@@ -1538,10 +1625,10 @@ export class JaakStamps {
1538
1625
  fontSize: '10px',
1539
1626
  borderRadius: '4px',
1540
1627
  whiteSpace: 'nowrap'
1541
- } }, "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: () => {
1628
+ } }, "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: () => {
1542
1629
  this.switchCamera(camera.deviceId);
1543
1630
  this.toggleCameraSelector();
1544
- }, 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" })))));
1631
+ }, 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" })))));
1545
1632
  }
1546
1633
  static get is() { return "jaak-stamps"; }
1547
1634
  static get encapsulation() { return "shadow"; }