@jaak.ai/stamps 2.1.0 → 2.2.0-dev.10

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.
Files changed (57) hide show
  1. package/README.md +42 -9
  2. package/dist/cjs/{index-Ga0t6BMe.js → index-D6NBn_qu.js} +30 -5
  3. package/dist/cjs/index-D6NBn_qu.js.map +1 -0
  4. package/dist/cjs/jaak-stamps-webcomponent.cjs.js +2 -2
  5. package/dist/cjs/jaak-stamps.cjs.entry.js +17577 -12
  6. package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
  7. package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
  8. package/dist/cjs/loader.cjs.js +2 -2
  9. package/dist/collection/components/my-component/my-component.css +82 -2
  10. package/dist/collection/components/my-component/my-component.js +489 -10
  11. package/dist/collection/components/my-component/my-component.js.map +1 -1
  12. package/dist/collection/services/LicenseValidationService.js +111 -0
  13. package/dist/collection/services/LicenseValidationService.js.map +1 -0
  14. package/dist/collection/services/MetricsService.js +350 -0
  15. package/dist/collection/services/MetricsService.js.map +1 -0
  16. package/dist/collection/services/ServiceContainer.js +66 -1
  17. package/dist/collection/services/ServiceContainer.js.map +1 -1
  18. package/dist/collection/services/TracingService.js +494 -0
  19. package/dist/collection/services/TracingService.js.map +1 -0
  20. package/dist/collection/services/interfaces/ILicenseValidationService.js +2 -0
  21. package/dist/collection/services/interfaces/ILicenseValidationService.js.map +1 -0
  22. package/dist/collection/services/interfaces/IMetricsService.js +2 -0
  23. package/dist/collection/services/interfaces/IMetricsService.js.map +1 -0
  24. package/dist/collection/services/interfaces/ITracingService.js +2 -0
  25. package/dist/collection/services/interfaces/ITracingService.js.map +1 -0
  26. package/dist/components/index.js +28 -3
  27. package/dist/components/index.js.map +1 -1
  28. package/dist/components/jaak-stamps.js +17591 -11
  29. package/dist/components/jaak-stamps.js.map +1 -1
  30. package/dist/esm/{index-Drbzcuq-.js → index-BCfAsrzL.js} +30 -5
  31. package/dist/esm/index-BCfAsrzL.js.map +1 -0
  32. package/dist/esm/jaak-stamps-webcomponent.js +3 -3
  33. package/dist/esm/jaak-stamps.entry.js +17577 -12
  34. package/dist/esm/jaak-stamps.entry.js.map +1 -1
  35. package/dist/esm/loader.js +3 -3
  36. package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
  37. package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
  38. package/dist/jaak-stamps-webcomponent/p-37281823.entry.js +7 -0
  39. package/dist/jaak-stamps-webcomponent/p-37281823.entry.js.map +1 -0
  40. package/dist/jaak-stamps-webcomponent/p-BCfAsrzL.js +3 -0
  41. package/dist/jaak-stamps-webcomponent/p-BCfAsrzL.js.map +1 -0
  42. package/dist/types/components/my-component/my-component.d.ts +23 -0
  43. package/dist/types/components.d.ts +76 -0
  44. package/dist/types/services/LicenseValidationService.d.ts +59 -0
  45. package/dist/types/services/MetricsService.d.ts +74 -0
  46. package/dist/types/services/ServiceContainer.d.ts +14 -1
  47. package/dist/types/services/TracingService.d.ts +72 -0
  48. package/dist/types/services/interfaces/ILicenseValidationService.d.ts +4 -0
  49. package/dist/types/services/interfaces/IMetricsService.d.ts +70 -0
  50. package/dist/types/services/interfaces/ITracingService.d.ts +64 -0
  51. package/package.json +18 -2
  52. package/dist/cjs/index-Ga0t6BMe.js.map +0 -1
  53. package/dist/esm/index-Drbzcuq-.js.map +0 -1
  54. package/dist/jaak-stamps-webcomponent/p-Drbzcuq-.js +0 -3
  55. package/dist/jaak-stamps-webcomponent/p-Drbzcuq-.js.map +0 -1
  56. package/dist/jaak-stamps-webcomponent/p-c06e5d7b.entry.js +0 -2
  57. package/dist/jaak-stamps-webcomponent/p-c06e5d7b.entry.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { h } from "@stencil/core";
2
2
  import { ServiceContainer } from "../../services/ServiceContainer";
3
+ import { LicenseValidationService } from "../../services/LicenseValidationService";
3
4
  export class JaakStamps {
4
5
  el;
5
6
  debug = false;
@@ -12,8 +13,22 @@ export class JaakStamps {
12
13
  captureDelay = 1500;
13
14
  enableBackDocumentTimer = false;
14
15
  backDocumentTimerDuration = 20;
16
+ telemetryCollectorUrl = 'https://collector.jaak.ai/v1/traces';
17
+ metricsCollectorUrl = 'https://collector.jaak.ai/v1/metrics';
18
+ enableTelemetry = true;
19
+ enableMetrics = true;
20
+ customerId;
21
+ tenantId;
22
+ environment = 'production';
23
+ propagateTraceHeaderCorsUrls; // Comma-separated URLs or regex patterns
24
+ metricsExportIntervalMillis = 60000; // Export metrics every 60 seconds
25
+ license; // License key for validation
26
+ licenseEnvironment = 'prod'; // Environment for license validation
27
+ traceId; // Optional trace ID for tracking
28
+ appId = 'jaak-stamps-web'; // Application ID for license validation
15
29
  captureCompleted;
16
30
  isReady;
31
+ traceIdGenerated;
17
32
  // State derived from services
18
33
  detectionBoxes = [];
19
34
  sideAlignment = {
@@ -53,12 +68,17 @@ export class JaakStamps {
53
68
  showPerformanceMessage = false; // Show performance message temporarily
54
69
  captureStateVersion = 0; // Triggers re-render when StateManager changes
55
70
  processingButton = null; // Track which button is processing
71
+ licenseValid = true; // License validation status
72
+ licenseError = null; // License validation error message
56
73
  // Services
74
+ licenseValidationService = null;
57
75
  serviceContainer;
58
76
  eventBus;
59
77
  stateManager;
60
78
  cameraService;
61
79
  detectionService;
80
+ tracingService;
81
+ metricsService;
62
82
  // UI References
63
83
  videoRef;
64
84
  detectionContainer;
@@ -104,8 +124,23 @@ export class JaakStamps {
104
124
  // Canvas pool for optimized screenshot capture
105
125
  canvasPool = [];
106
126
  MAX_CANVAS_POOL_SIZE = 3;
127
+ async componentWillLoad() {
128
+ // License is required - always validate
129
+ // Wait a bit to ensure props are set from attributes
130
+ await new Promise(resolve => setTimeout(resolve, 50));
131
+ this.updateStatus('Validando licencia...', 'Verificando autorización de uso', 'initializing');
132
+ await this.validateLicense();
133
+ // If license validation failed, stop initialization
134
+ if (!this.licenseValid) {
135
+ return;
136
+ }
137
+ }
107
138
  async componentDidLoad() {
108
139
  try {
140
+ // If license validation failed, stop initialization
141
+ if (!this.licenseValid) {
142
+ return;
143
+ }
109
144
  this.updateStatus('Preparando capturador...', 'Configurando herramientas de captura', 'initializing');
110
145
  await this.initializeServices();
111
146
  this.updateStatus('Preparando funciones...', 'Configurando herramientas de trabajo', 'initializing');
@@ -121,6 +156,10 @@ export class JaakStamps {
121
156
  }
122
157
  }
123
158
  async initializeServices() {
159
+ // Parse propagateTraceHeaderCorsUrls from comma-separated string
160
+ const propagateUrls = this.propagateTraceHeaderCorsUrls
161
+ ? this.propagateTraceHeaderCorsUrls.split(',').map(url => url.trim())
162
+ : [];
124
163
  const config = {
125
164
  debug: this.debug,
126
165
  alignmentTolerance: this.alignmentTolerance,
@@ -129,13 +168,76 @@ export class JaakStamps {
129
168
  useDocumentClassification: this.useDocumentClassification,
130
169
  useDocumentDetector: this.useDocumentDetector,
131
170
  preferredCamera: this.preferredCamera,
132
- captureDelay: this.captureDelay
171
+ captureDelay: this.captureDelay,
172
+ telemetryCollectorUrl: this.telemetryCollectorUrl,
173
+ metricsCollectorUrl: this.metricsCollectorUrl,
174
+ enableTelemetry: this.enableTelemetry,
175
+ enableMetrics: this.enableMetrics,
176
+ customerId: this.customerId,
177
+ tenantId: this.tenantId,
178
+ environment: this.environment,
179
+ propagateTraceHeaderCorsUrls: propagateUrls,
180
+ metricsExportIntervalMillis: this.metricsExportIntervalMillis
133
181
  };
134
182
  this.serviceContainer = new ServiceContainer(config);
135
183
  this.eventBus = this.serviceContainer.getEventBus();
136
184
  this.stateManager = this.serviceContainer.getStateManager();
137
185
  this.cameraService = this.serviceContainer.getCameraService();
138
186
  this.detectionService = this.serviceContainer.getDetectionService();
187
+ this.tracingService = this.serviceContainer.getTracingService();
188
+ this.metricsService = this.serviceContainer.getMetricsService();
189
+ // Set the custom trace ID if provided via prop
190
+ if (this.tracingService && this.traceId) {
191
+ this.tracingService.setSessionTraceId(this.traceId);
192
+ }
193
+ // Record component initialization
194
+ if (this.tracingService) {
195
+ const span = this.tracingService.startSpan('component.initialize', {
196
+ 'component.debug': this.debug,
197
+ 'component.useDocumentDetector': this.useDocumentDetector,
198
+ 'component.useDocumentClassification': this.useDocumentClassification,
199
+ });
200
+ this.tracingService.endSpan(span);
201
+ }
202
+ }
203
+ async validateLicense() {
204
+ if (!this.license) {
205
+ console.error('❌ No license provided for JAAK Stamps component');
206
+ this.licenseError = 'Este componente requiere una licencia válida. Por favor, proporcione una licencia usando el atributo "license".';
207
+ this.licenseValid = false;
208
+ this.updateStatus('Error de licencia', 'Licencia no proporcionada', 'error');
209
+ return;
210
+ }
211
+ try {
212
+ console.log('🔑 Validating license for JAAK Stamps...');
213
+ // Initialize license validation service
214
+ this.licenseValidationService = new LicenseValidationService(this.licenseEnvironment);
215
+ // Validate the license, passing traceId and appId if provided
216
+ const response = await this.licenseValidationService.validateLicense(this.license, this.traceId, this.appId);
217
+ if (response && response.access_token) {
218
+ this.licenseValid = true;
219
+ this.licenseError = null;
220
+ console.log('✅ License validated successfully for JAAK Stamps');
221
+ // Emit the traceId (either provided or generated)
222
+ if (response.traceId) {
223
+ this.traceIdGenerated.emit({ traceId: response.traceId });
224
+ console.log('📋 TraceId:', response.traceId);
225
+ }
226
+ }
227
+ else {
228
+ this.licenseValid = false;
229
+ this.licenseError = 'La licencia proporcionada no es válida. Por favor, verifique su licencia e intente nuevamente.';
230
+ this.updateStatus('Error de licencia', 'Licencia inválida', 'error');
231
+ console.error('❌ Invalid license for JAAK Stamps');
232
+ }
233
+ }
234
+ catch (error) {
235
+ this.licenseValid = false;
236
+ const licenseError = error;
237
+ this.licenseError = licenseError.error_description || 'Error al validar la licencia. Por favor, verifique su conexión e intente nuevamente.';
238
+ this.updateStatus('Error de licencia', 'Fallo en la validación', 'error');
239
+ console.error('❌ License validation failed for JAAK Stamps:', error);
240
+ }
139
241
  }
140
242
  async setupEventListeners() {
141
243
  this.eventBus.on('state-changed', () => {
@@ -403,17 +505,31 @@ export class JaakStamps {
403
505
  return this.stateManager.isProcessCompleted();
404
506
  }
405
507
  async startCapture() {
508
+ const span = this.tracingService?.startSpan('capture.start');
406
509
  const readyCheck = this.isComponentReady();
407
510
  if (!readyCheck.ready) {
408
511
  this.updateStatus(readyCheck.message, 'Espere a que termine la inicialización', readyCheck.status);
512
+ if (span) {
513
+ this.tracingService?.setSpanAttribute(span, 'error', true);
514
+ this.tracingService?.setSpanAttribute(span, 'error.message', readyCheck.message);
515
+ this.tracingService?.endSpan(span);
516
+ }
409
517
  return { success: false, error: readyCheck.message };
410
518
  }
411
519
  try {
412
520
  await this.startDetection();
521
+ if (span) {
522
+ this.tracingService?.setSpanAttribute(span, 'success', true);
523
+ this.tracingService?.endSpan(span);
524
+ }
413
525
  return { success: true };
414
526
  }
415
527
  catch (error) {
416
528
  this.updateStatus('Error al iniciar captura', error.message, 'error');
529
+ if (span) {
530
+ this.tracingService?.recordException(span, error);
531
+ this.tracingService?.endSpan(span);
532
+ }
417
533
  return { success: false, error: error.message };
418
534
  }
419
535
  }
@@ -511,13 +627,22 @@ export class JaakStamps {
511
627
  }
512
628
  }
513
629
  async preloadModel() {
630
+ const span = this.tracingService?.startSpan('model.preload');
514
631
  const readyCheck = this.isComponentReady();
515
632
  if (!readyCheck.ready) {
516
633
  this.updateStatus(readyCheck.message, 'Espere a que termine la inicialización', readyCheck.status);
634
+ if (span) {
635
+ this.tracingService?.setSpanAttribute(span, 'error', true);
636
+ this.tracingService?.endSpan(span);
637
+ }
517
638
  return { success: false, error: readyCheck.message };
518
639
  }
519
640
  if (this.detectionService.isModelLoaded()) {
520
641
  this.updateStatus('Reconocimiento listo', '', 'ready');
642
+ if (span) {
643
+ this.tracingService?.setSpanAttribute(span, 'cached', true);
644
+ this.tracingService?.endSpan(span);
645
+ }
521
646
  return { success: true, message: 'Model already loaded' };
522
647
  }
523
648
  try {
@@ -527,17 +652,31 @@ export class JaakStamps {
527
652
  this.stateManager.updateCaptureState({ isLoading: true });
528
653
  }
529
654
  try {
655
+ const detectionStartTime = performance.now();
656
+ const modelSpan = this.tracingService?.startSpan('model.detection.load');
530
657
  await this.detectionService.loadModel();
658
+ if (modelSpan)
659
+ this.tracingService?.endSpan(modelSpan);
660
+ const detectionLoadTime = performance.now() - detectionStartTime;
661
+ this.metricsService?.recordModelLoad('detection', detectionLoadTime, false);
531
662
  }
532
663
  catch (modelError) {
664
+ this.metricsService?.recordError('model_load_failed', 'detection');
533
665
  this.switchToManualModeWithError('Error al cargar modelo de detección');
534
666
  throw modelError;
535
667
  }
536
668
  this.updateStatus('Optimizando detección...', 'Configurando reconocimiento de documentos', 'loading');
537
669
  try {
670
+ const classificationStartTime = performance.now();
671
+ const classSpan = this.tracingService?.startSpan('model.classification.load');
538
672
  await this.detectionService.loadClassificationModel();
673
+ if (classSpan)
674
+ this.tracingService?.endSpan(classSpan);
675
+ const classificationLoadTime = performance.now() - classificationStartTime;
676
+ this.metricsService?.recordModelLoad('classification', classificationLoadTime, false);
539
677
  }
540
678
  catch (classificationError) {
679
+ this.metricsService?.recordError('model_load_failed', 'classification');
541
680
  this.switchToManualModeWithError('Error al cargar modelo de clasificación');
542
681
  throw classificationError;
543
682
  }
@@ -547,6 +686,9 @@ export class JaakStamps {
547
686
  if (this.debug) {
548
687
  this.recordOnnxPerformance(loadTime, 0);
549
688
  }
689
+ if (span) {
690
+ this.tracingService?.setSpanAttribute(span, 'loadTime', loadTime);
691
+ }
550
692
  this.updateStatus('Finalizando configuración...', 'Preparando herramientas para captura', 'loading');
551
693
  await new Promise(resolve => setTimeout(resolve, 300));
552
694
  this.updateStatus('Reconocimiento preparado', '', 'ready');
@@ -554,6 +696,10 @@ export class JaakStamps {
554
696
  this.stateManager.updateCaptureState({ isLoading: false });
555
697
  }
556
698
  this.emitReadyEvent();
699
+ if (span) {
700
+ this.tracingService?.setSpanAttribute(span, 'success', true);
701
+ this.tracingService?.endSpan(span);
702
+ }
557
703
  return { success: true, message: 'Models preloaded successfully' };
558
704
  }
559
705
  catch (error) {
@@ -561,6 +707,10 @@ export class JaakStamps {
561
707
  if (this.stateManager) {
562
708
  this.stateManager.updateCaptureState({ isLoading: false });
563
709
  }
710
+ if (span) {
711
+ this.tracingService?.recordException(span, error);
712
+ this.tracingService?.endSpan(span);
713
+ }
564
714
  return { success: false, error: error.message };
565
715
  }
566
716
  }
@@ -983,7 +1133,7 @@ export class JaakStamps {
983
1133
  isCapturing: false
984
1134
  };
985
1135
  const cameraInfo = this.cameraInfoWithAutofocus;
986
- return (h("div", { key: 'f9cbca2fd6b8548a29ace7fcb972b53f402f61af', class: "detector-container" }, h("div", { key: '4f3cac734eb6bfd44a8de644eadca17e7893e11a', class: "video-container" }, h("video", { key: '5e15a38c989a72d5274281272d41ba064447ca6f', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '38c8ad8b691db60e9b5a2a8b641fe6febbeacfca', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index) => (h("div", { key: index, class: "detection-box", style: {
1136
+ return (h("div", { key: 'a52b452a7aef6574a5e4b74a88c7bd3f9d45fd15', class: "detector-container" }, !this.licenseValid && this.licenseError && (h("div", { key: '18a99579e0b74ceb2cf1c4c3e21a864d2ec7d944', class: "license-error-container" }, h("div", { key: '3431722f4f47824c172a5b6f3a2ad9bd3bf377f2', class: "license-error-card" }, h("svg", { key: 'bf3854de3ba865a58c5c91cfd7a85d3d725be0df', class: "license-error-icon", width: "64", height: "64", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, h("path", { key: '209e3a2a22333ec90e102a7156eb644b529f47c7', d: "M12 22C12 22 20 18 20 12V5L12 2L4 5V12C4 18 12 22 12 22Z", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { key: '7b0dc1cd29a9055e552885b23f4537c19932556d', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), h("circle", { key: '8ea686ebfb31a5744303f313fd104c03c02a5472', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), h("h2", { key: '7e0ec3ec23b80176cbec9c706999746d62486f3c', class: "license-error-title" }, "Licencia Requerida"), h("p", { key: '261a91e2c20feb09319dc4f319fb79611cc36a46', class: "license-error-message" }, this.licenseError), h("p", { key: '2e3cc8da0f4a8ebfd52db469b0f0900514d1d7f8', class: "license-error-help" }, "Contacte a soporte: ", h("a", { key: '283eea87e2f69dce1ea7376e3a63fed780633499', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), h("div", { key: 'b4227ed25a4fb4d953c753671d27ac8c931a435f', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (h("div", { key: 'cb33431cf6992f6e7466273406f729c42c1cbcdb', class: "video-container" }, h("video", { key: 'b44befd61ad616fd36fe1e98fd089a2443bc65b6', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '8cee95ddab5f771a87d43fa434a3ba0c241d2f3e', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index) => (h("div", { key: index, class: "detection-box", style: {
987
1137
  position: 'absolute',
988
1138
  left: `${box.x}px`,
989
1139
  top: `${box.y}px`,
@@ -992,9 +1142,9 @@ export class JaakStamps {
992
1142
  border: '2px solid #32406C',
993
1143
  pointerEvents: 'none',
994
1144
  boxSizing: 'border-box'
995
- } })))), this.isMaskReady && (h("div", { key: 'c56fde56b7a86a4e8a4cf558745291ea5cde12fd', class: "overlay-mask" }, h("div", { key: '04ed3f01f271dc84eed594cb4b60c2453645bd41', class: "card-outline" }, h("div", { key: '648bd423a5e886d4768115237de5896c7223b30b', class: "side side-top" }), h("div", { key: 'b8878059493ca61961b9b3c82ecc18b50b79ac85', class: "side side-right" }), h("div", { key: '09e5ad64ff33dbd5c112bf52b71e14409ab6aa65', class: "side side-bottom" }), h("div", { key: 'b8ba3d83c9bc1b4a0da859d7ed4b9a15eaddcc2a', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '3279701a240f77ac96e68a34ad95c099340c9a6a', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '2adf96d0a57e482372fd9586229dac2301b64fd4', class: "back-capture-section" }, h("div", { key: '305a147c9cfee854c60ac946a48a1d21b2792725', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: '43270a0647f39307229c540dd5130fb58b1ff4fb', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: 'eb4666603774564eef95a120ac13faeb9e10c8b4', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: 'cac667d9548ae2314ad5a677c5ed90f25184f728', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '0af7aa4106ce189ae2d79bec78ede01abe25b1e7', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
1145
+ } })))), this.isMaskReady && (h("div", { key: '00a749ad234294695d9a292911b41fdacafd219a', class: "overlay-mask" }, h("div", { key: 'e344df8a709fca5225985ccc9f8def75ddbd393c', class: "card-outline" }, h("div", { key: '2dcae9e414f2b7131397d49a3d5ecabfc7cd5eb8', class: "side side-top" }), h("div", { key: '48ac3f06fa4a2c83741df378719911f682811caa', class: "side side-right" }), h("div", { key: '238a3269b2a12d528e8a1889d3109ee319c7fd88', class: "side side-bottom" }), h("div", { key: 'b02eec6c102d7e9fb03ef24dfce7c75e081ff1c4', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '15588129ca8027a6ec1c81d70001142986966826', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'f15fd9bddc20c54afcca7be79c3cf2f9ee2b74f7', class: "back-capture-section" }, h("div", { key: 'e3284e1301840a9555857fa879de9f4ca91dc21b', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: '8508d13e117deb3b223308497b1db976643b86f2', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: '99bd464541d9ee8589bc11e937c5ad6bca9d95c8', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: '3de5f0a142f9dfdfe4578c0fcbe004bb5fe94c56', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '268ce949bf5155b3729298f23eea0d7ec15b3590', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
996
1146
  ? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
997
- : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'de6e5c4fad4d4d996b894457c9af52bc71e533fb', class: "camera-controls" }, h("button", { key: 'cfddcf2420d5f5923a6b02ca446bbe1b8e9fc5e4', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (h("div", { key: '5fb73f958b9a5a6f9242032c4530b0bdab84f6c5', class: "camera-selector-dropdown" }, h("div", { key: '8ee2d26b1001e571e7b6c326e927926fa08287fd', class: "camera-selector-header" }, h("span", { key: '78350b0fb1bd933f7c8c59d8dab0b7122ffbe363' }, "Seleccionar C\u00E1mara"), h("button", { key: 'bb750e0ddd5a1ee5ff96bd57805a7f90b8821e9f', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'd0f6343cf1b7367f3da33ec8cf64891109d923b8', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: 'c9642fbfb0acea766d3f0542f4cc9f17f4af4d7b', class: "device-info" }, h("small", { key: 'b6e9507ff7addf011f339f6c22a88a96b40db68a' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '04ae9262409284782850b90945eb7038673e2097', class: "manual-capture-section" }, h("button", { key: '27c315e503ccba468b89ebd58d6b70f40ddd06ba', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: '8f2dcd2df9a218b37eb0b8204a8724362cfeaa53', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '6fd6fe1d0213b01c8119a67fb8108f73227feee1', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: 'fba3816b48b99ca64510ecbefc0d41431569c9ae', class: "flip-animation" }, h("div", { key: 'beea1c8245b5d81f1008efc6d1b079a61c821e7f', class: "id-card-icon" }), h("div", { key: 'f0fbc34f619a653e2c0ade764ca99e7aa582d157', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: 'e4a0e6d31112e3a50024d1d0430b4ad997049fe7', class: "success-animation" }, h("div", { key: '5dd3f781f55630bc904c81207548ae35bc79b452', class: "check-icon" }), h("div", { key: 'a10ebc557582325091efb0abd12d62b27a43b98c', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '975865955dee1803b5215ecf049701c98b324855', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: '84f6f67202e26ce80f7fc5d5f321e23b5bc55c57', class: "status-spinner" })), h("div", { key: 'a1ae56ed156e8feb279a1bf160f749c5d0b5ce45', class: "status-content" }, h("div", { key: 'd62932554cea257ce19763df26e0ba702e50eeca', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: 'c5506fa12dd0d37d26dc26c9f2381c843330451f', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '2097eda63185f336f7319014fae2ef6db1e41761', class: "performance-monitor" }, h("div", { key: 'd611c494c6b1a5930ef64aebdcba41e5d94c9ee6', class: "performance-expanded" }, h("div", { key: '800d46831e7b9bec260d9c5e67ea1a3eb9c2933e', class: "metrics-row" }, h("div", { key: 'dd0db1faa9050d98e71da4b5cd26a4a484c37c64', class: "metric-compact" }, h("span", { key: 'f0e6ea61a35ddb2ae5c2a6aff8c255a02c5c1219', class: "metric-label" }, "FPS"), h("span", { key: 'cbf4df4d142f6f01e45f566a8ede8fbbf29ad673', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '83861ad31fa46c8199a5583e4b3f8eefd44bacd6', class: "metric-compact" }, h("span", { key: '41b8de4cda47959dfc9df393e95fdadde534dd21', class: "metric-label" }, "MEM"), h("span", { key: 'b268f13cc78066e240ed158f1443113a94827aff', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: '9f9a9d0690906b186492af23b900c5fa0f5cff89', class: "metrics-row" }, h("div", { key: '84fa6e453dc36e4a74e8b573447b17230766229e', class: "metric-compact" }, h("span", { key: 'f17d52899090c89f532d74c552dd8c5338fc2d83', class: "metric-label" }, "INF"), h("span", { key: '2beca0d7ce55ed574f6b01efc086c5846983e024', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '981e300cf076e81bfe946974f6cffd63619eacde', class: "metric-compact" }, h("span", { key: '3dfb0c996a69eb87b0f711322675cad69c471146', class: "metric-label" }, "FRAME"), h("span", { key: '3ae2ac6e90cda77f23e559f3197c3b761f9bdc40', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '2c51216838d87728d9d7764e5ba8a50fa02eb493', class: "metrics-row" }, h("div", { key: 'eda810ffb80ec38ab84583f59b26706f90a50fc9', class: "metric-compact" }, h("span", { key: '978ba9c0c67d6da6b29b3535af33a314bab9276a', class: "metric-label" }, "DET"), h("span", { key: '3e5e169fd4a3906283d8f918b5bbc7c5df6ccd0f', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: 'b4b915c745e35c09470a4dc5edfc112d32cfb8b6', class: "metric-compact" }, h("span", { key: '3e2a7b88a4446813c955efb0dfa9e2958e8e1448', class: "metric-label" }, "RATE"), h("span", { key: 'f4f073f7ee622167a241c6a1c535ef580c13d9ab', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '76c556e92f6d7980539f1a30efe8751f665164fb', class: "watermark" }, h("img", { key: 'af23e115d6b4e92a72e55d6d98fde0e4b1d09e9b', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1147
+ : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'bb5c00ad882c303d8a2b6ddc79c9d5b27ff9824e', class: "camera-controls" }, h("button", { key: '7d231b550b58a8336f125a1a7fe7235c8bb3d7dd', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (h("div", { key: '95d1e0d0937f7ef821ff3ad167cd42e25fd1c87f', class: "camera-selector-dropdown" }, h("div", { key: 'e42219e5895c82f40c559c27c4f80f3145fc0a0e', class: "camera-selector-header" }, h("span", { key: '544a6fb2e08211ab6c44b0bfb281124bee318fae' }, "Seleccionar C\u00E1mara"), h("button", { key: '7c4a71243278491ee7dbcc7ab2564bc7e92f5da3', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'c9d24e0bd906d20370214fdfd24ae91abfda98e1', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '8c2e1d2ed02bc55c84f3f726e5be577686d0f32d', class: "device-info" }, h("small", { key: '142410a86e4f819b96ffc9573816994351588a3e' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '48c33b2d6c8c80d18fba6e5f454faaa24c28fbd9', class: "manual-capture-section" }, h("button", { key: 'e3d5bfe9ef8b8f16bf669b66bce4e7a500113798', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: 'f50640fe4308c765011e6ed175528920228df5e7', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '080ab315293fa1fe5b1d97aa2511a2ffe2b013f4', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: 'b062c546af50b799bb1fb7dda07b3ffa601c4bac', class: "flip-animation" }, h("div", { key: 'f7162dc31673c7db1d8e03a658a722a3d323b28e', class: "id-card-icon" }), h("div", { key: 'd950952b480342d80d37df5c48031d72be4ac01a', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: 'bd576fd28065aa712e42636c5fd0e3566d26cc25', class: "success-animation" }, h("div", { key: '6ca5c24510df790bd1c955c5e2936909c4767560', class: "check-icon" }), h("div", { key: '3420164eacddbe1a9aa0a181528ba0be7683af56', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '8ec2b295b233e7bb8ab0cc1c183adedd4e3c7e04', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: '97c8e7e6219984673ebc631da111c17bf72a83cb', class: "status-spinner" })), h("div", { key: '7ca06c48f295892ff77eceff6245891ef7d9dd5e', class: "status-content" }, h("div", { key: '08056c7ec8fd66d23e0b6714c08aeccc092cf46a', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '1e32ca14de53cc2f105822ed5a58e691918b307b', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: 'c25022d9aadd37ead9ae7d1cf7c7d916cdeb9cc1', class: "performance-monitor" }, h("div", { key: 'f0f99c7e820532432ba64726ef0c2aeabeb3309f', class: "performance-expanded" }, h("div", { key: 'e839e90c9cb0f33068ac3311e41914aa52610149', class: "metrics-row" }, h("div", { key: '9f74f4877a048e63f542f2df54f569f79d6f8bd0', class: "metric-compact" }, h("span", { key: '21ec7255706d6fb2cfec035c4be92295ee0216b6', class: "metric-label" }, "FPS"), h("span", { key: 'c8be17f3dc752304bf6b7fd9746f11783f7ff6ca', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '79187257ea30ead7fb41534a94272a3a855e050b', class: "metric-compact" }, h("span", { key: 'cc53dc282c1fe4234217207c2085fa2be06a5458', class: "metric-label" }, "MEM"), h("span", { key: '032002ff63b3a2349b34833668fed8d6337e2063', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'e628febd5bbfb9f593e029b10827635ddd0344fb', class: "metrics-row" }, h("div", { key: 'b2fe558bab709ff6b6781648b13ebc66238f3298', class: "metric-compact" }, h("span", { key: 'd7d816aff11503657781f8ebe9cb5f0f07c7279e', class: "metric-label" }, "INF"), h("span", { key: '3d735d092b5b39d0e96f4ac59b3bf2acde739fab', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '9a83fd4fe43e8a3760aaea1f134c3101b8757681', class: "metric-compact" }, h("span", { key: '8136ab82b50230537f19cd58ed2da0956d291287', class: "metric-label" }, "FRAME"), h("span", { key: '6221cc10edff8c4b0e4034a3734deb548416a3e6', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: 'a31bad44d5c2c5fd5417ed82589c0f103bba1d32', class: "metrics-row" }, h("div", { key: '1441d11e0d83b3b44dfa963e415c3074691eb4f2', class: "metric-compact" }, h("span", { key: '9fe5643129aa7a842f75644b6f71b1ff80993f1b', class: "metric-label" }, "DET"), h("span", { key: '0604065a3867e71a745bfb4e804c7e96048cb70e', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: 'daff0fede819f2b59a4ddb83560dc53f6151c2c9', class: "metric-compact" }, h("span", { key: '75a55c4a4e36b98af3620866ec6f7842b9ef81f7', class: "metric-label" }, "RATE"), h("span", { key: '61776c3fd4c3200d5e18cc28d917c538b282625a', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '4092c684ee3a148ec40e266fd16a718f2c2f2f52', class: "watermark" }, h("img", { key: 'd7bae6157d22675f8b71dbf1afdf345374398c82', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
998
1148
  }
999
1149
  // Utility methods
1000
1150
  updateDetectionBoxes(boxes) {
@@ -1111,24 +1261,44 @@ export class JaakStamps {
1111
1261
  }
1112
1262
  async takeManualScreenshot() {
1113
1263
  console.log('🔵 Botón clicked: Capturar (Frente/Reverso)');
1264
+ const captureStartTime = performance.now();
1265
+ const span = this.tracingService?.startSpan('capture.screenshot.manual');
1114
1266
  // Set processing state immediately
1115
1267
  const captureState = this.stateManager?.getCaptureState();
1268
+ const side = captureState?.step === 'front' ? 'front' : 'back';
1116
1269
  if (captureState?.step === 'front') {
1117
1270
  this.processingButton = 'capture-front';
1271
+ if (span)
1272
+ this.tracingService?.setSpanAttribute(span, 'side', 'front');
1118
1273
  }
1119
1274
  else if (captureState?.step === 'back') {
1120
1275
  this.processingButton = 'capture-back';
1276
+ if (span)
1277
+ this.tracingService?.setSpanAttribute(span, 'side', 'back');
1121
1278
  }
1279
+ // Record user interaction
1280
+ this.metricsService?.recordUserInteraction('manual_capture_button');
1122
1281
  console.log('🔵 processingButton set to:', this.processingButton);
1123
1282
  // Add small delay to show spinner
1124
1283
  await new Promise(resolve => setTimeout(resolve, 100));
1125
1284
  if (!this.videoRef) {
1126
1285
  this.processingButton = null;
1286
+ if (span) {
1287
+ this.tracingService?.setSpanAttribute(span, 'error', 'no_video_ref');
1288
+ this.tracingService?.endSpan(span);
1289
+ }
1127
1290
  return;
1128
1291
  }
1129
1292
  // When using manual capture, use mask coordinates for cropping
1130
1293
  // Note: processingButton will be cleared inside takeScreenshotWithMaskCoordinates
1131
1294
  await this.takeScreenshotWithMaskCoordinates();
1295
+ // Record metrics
1296
+ const captureDuration = performance.now() - captureStartTime;
1297
+ this.metricsService?.recordCapture(side, 'manual', captureDuration);
1298
+ if (span) {
1299
+ this.tracingService?.setSpanAttribute(span, 'success', true);
1300
+ this.tracingService?.endSpan(span);
1301
+ }
1132
1302
  }
1133
1303
  async takeScreenshotWithMaskCoordinates() {
1134
1304
  if (!this.videoRef || !this.detectionContainer)
@@ -1247,6 +1417,8 @@ export class JaakStamps {
1247
1417
  async takeScreenshot() {
1248
1418
  if (!this.videoRef || !this.lastDetectedBox)
1249
1419
  return;
1420
+ const captureStartTime = performance.now();
1421
+ const span = this.tracingService?.startSpan('capture.screenshot.auto');
1250
1422
  this.stateManager.updateCaptureState({ isCapturing: true });
1251
1423
  this.triggerCaptureAnimation();
1252
1424
  // Use pooled canvas for optimization
@@ -1269,17 +1441,30 @@ export class JaakStamps {
1269
1441
  croppedCtx.drawImage(this.videoRef, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
1270
1442
  const captureState = this.stateManager.getCaptureState();
1271
1443
  if (captureState.step === 'front') {
1444
+ const frontImageData = captureCanvas.toDataURL('image/jpeg');
1445
+ const croppedImageData = croppedCanvas.toDataURL('image/jpeg');
1272
1446
  this.stateManager.setCapturedImages({
1273
1447
  front: {
1274
- fullFrame: captureCanvas.toDataURL('image/jpeg'),
1275
- cropped: croppedCanvas.toDataURL('image/jpeg')
1448
+ fullFrame: frontImageData,
1449
+ cropped: croppedImageData
1276
1450
  }
1277
1451
  });
1452
+ // Record metrics
1453
+ const captureDuration = performance.now() - captureStartTime;
1454
+ this.metricsService?.recordCapture('front', 'auto', captureDuration);
1455
+ this.metricsService?.recordImageSize('front', frontImageData.length);
1456
+ if (span) {
1457
+ this.tracingService?.setSpanAttribute(span, 'side', 'front');
1458
+ }
1278
1459
  // Check if document classification is enabled
1279
1460
  if (this.useDocumentClassification) {
1280
1461
  try {
1281
1462
  const classification = await this.detectionService.classifyDocument(croppedCanvas);
1282
1463
  if (classification && classification.class === 'passport') {
1464
+ if (span) {
1465
+ this.tracingService?.setSpanAttribute(span, 'document.type', 'passport');
1466
+ this.tracingService?.endSpan(span);
1467
+ }
1283
1468
  this.completeProcess(true);
1284
1469
  return;
1285
1470
  }
@@ -1293,6 +1478,9 @@ export class JaakStamps {
1293
1478
  isDetectionPaused: true,
1294
1479
  showFlipAnimation: true
1295
1480
  });
1481
+ if (span) {
1482
+ this.tracingService?.endSpan(span);
1483
+ }
1296
1484
  setTimeout(() => {
1297
1485
  this.stateManager.updateCaptureState({
1298
1486
  showFlipAnimation: false,
@@ -1302,12 +1490,22 @@ export class JaakStamps {
1302
1490
  }, 3000);
1303
1491
  }
1304
1492
  else if (captureState.step === 'back') {
1493
+ const backImageData = captureCanvas.toDataURL('image/jpeg');
1494
+ const croppedBackImageData = croppedCanvas.toDataURL('image/jpeg');
1305
1495
  this.stateManager.setCapturedImages({
1306
1496
  back: {
1307
- fullFrame: captureCanvas.toDataURL('image/jpeg'),
1308
- cropped: croppedCanvas.toDataURL('image/jpeg')
1497
+ fullFrame: backImageData,
1498
+ cropped: croppedBackImageData
1309
1499
  }
1310
1500
  });
1501
+ // Record metrics
1502
+ const captureDuration = performance.now() - captureStartTime;
1503
+ this.metricsService?.recordCapture('back', 'auto', captureDuration);
1504
+ this.metricsService?.recordImageSize('back', backImageData.length);
1505
+ if (span) {
1506
+ this.tracingService?.setSpanAttribute(span, 'side', 'back');
1507
+ this.tracingService?.endSpan(span);
1508
+ }
1311
1509
  this.completeProcess(false);
1312
1510
  }
1313
1511
  // Return canvases to pool after use
@@ -1454,7 +1652,7 @@ export class JaakStamps {
1454
1652
  catch (error) {
1455
1653
  }
1456
1654
  }
1457
- completeProcess(skippedBack = false) {
1655
+ async completeProcess(skippedBack = false) {
1458
1656
  this.stateManager.updateCaptureState({
1459
1657
  step: 'completed',
1460
1658
  showSuccessAnimation: true
@@ -1469,6 +1667,15 @@ export class JaakStamps {
1469
1667
  ...capturedImages,
1470
1668
  timestamp: new Date().toISOString()
1471
1669
  };
1670
+ // Flush all traces to collector before emitting capture completed
1671
+ if (this.tracingService) {
1672
+ try {
1673
+ await this.tracingService.flush();
1674
+ }
1675
+ catch (error) {
1676
+ console.error('[my-component] Failed to flush traces:', error);
1677
+ }
1678
+ }
1472
1679
  this.captureCompleted.emit(finalImages);
1473
1680
  setTimeout(() => {
1474
1681
  this.stateManager.updateCaptureState({ showSuccessAnimation: false });
@@ -1944,6 +2151,261 @@ export class JaakStamps {
1944
2151
  "setter": false,
1945
2152
  "reflect": false,
1946
2153
  "defaultValue": "20"
2154
+ },
2155
+ "telemetryCollectorUrl": {
2156
+ "type": "string",
2157
+ "attribute": "telemetry-collector-url",
2158
+ "mutable": false,
2159
+ "complexType": {
2160
+ "original": "string",
2161
+ "resolved": "string",
2162
+ "references": {}
2163
+ },
2164
+ "required": false,
2165
+ "optional": true,
2166
+ "docs": {
2167
+ "tags": [],
2168
+ "text": ""
2169
+ },
2170
+ "getter": false,
2171
+ "setter": false,
2172
+ "reflect": false,
2173
+ "defaultValue": "'https://collector.jaak.ai/v1/traces'"
2174
+ },
2175
+ "metricsCollectorUrl": {
2176
+ "type": "string",
2177
+ "attribute": "metrics-collector-url",
2178
+ "mutable": false,
2179
+ "complexType": {
2180
+ "original": "string",
2181
+ "resolved": "string",
2182
+ "references": {}
2183
+ },
2184
+ "required": false,
2185
+ "optional": true,
2186
+ "docs": {
2187
+ "tags": [],
2188
+ "text": ""
2189
+ },
2190
+ "getter": false,
2191
+ "setter": false,
2192
+ "reflect": false,
2193
+ "defaultValue": "'https://collector.jaak.ai/v1/metrics'"
2194
+ },
2195
+ "enableTelemetry": {
2196
+ "type": "boolean",
2197
+ "attribute": "enable-telemetry",
2198
+ "mutable": false,
2199
+ "complexType": {
2200
+ "original": "boolean",
2201
+ "resolved": "boolean",
2202
+ "references": {}
2203
+ },
2204
+ "required": false,
2205
+ "optional": false,
2206
+ "docs": {
2207
+ "tags": [],
2208
+ "text": ""
2209
+ },
2210
+ "getter": false,
2211
+ "setter": false,
2212
+ "reflect": false,
2213
+ "defaultValue": "true"
2214
+ },
2215
+ "enableMetrics": {
2216
+ "type": "boolean",
2217
+ "attribute": "enable-metrics",
2218
+ "mutable": false,
2219
+ "complexType": {
2220
+ "original": "boolean",
2221
+ "resolved": "boolean",
2222
+ "references": {}
2223
+ },
2224
+ "required": false,
2225
+ "optional": false,
2226
+ "docs": {
2227
+ "tags": [],
2228
+ "text": ""
2229
+ },
2230
+ "getter": false,
2231
+ "setter": false,
2232
+ "reflect": false,
2233
+ "defaultValue": "true"
2234
+ },
2235
+ "customerId": {
2236
+ "type": "string",
2237
+ "attribute": "customer-id",
2238
+ "mutable": false,
2239
+ "complexType": {
2240
+ "original": "string",
2241
+ "resolved": "string",
2242
+ "references": {}
2243
+ },
2244
+ "required": false,
2245
+ "optional": true,
2246
+ "docs": {
2247
+ "tags": [],
2248
+ "text": ""
2249
+ },
2250
+ "getter": false,
2251
+ "setter": false,
2252
+ "reflect": false
2253
+ },
2254
+ "tenantId": {
2255
+ "type": "string",
2256
+ "attribute": "tenant-id",
2257
+ "mutable": false,
2258
+ "complexType": {
2259
+ "original": "string",
2260
+ "resolved": "string",
2261
+ "references": {}
2262
+ },
2263
+ "required": false,
2264
+ "optional": true,
2265
+ "docs": {
2266
+ "tags": [],
2267
+ "text": ""
2268
+ },
2269
+ "getter": false,
2270
+ "setter": false,
2271
+ "reflect": false
2272
+ },
2273
+ "environment": {
2274
+ "type": "string",
2275
+ "attribute": "environment",
2276
+ "mutable": false,
2277
+ "complexType": {
2278
+ "original": "string",
2279
+ "resolved": "string",
2280
+ "references": {}
2281
+ },
2282
+ "required": false,
2283
+ "optional": true,
2284
+ "docs": {
2285
+ "tags": [],
2286
+ "text": ""
2287
+ },
2288
+ "getter": false,
2289
+ "setter": false,
2290
+ "reflect": false,
2291
+ "defaultValue": "'production'"
2292
+ },
2293
+ "propagateTraceHeaderCorsUrls": {
2294
+ "type": "string",
2295
+ "attribute": "propagate-trace-header-cors-urls",
2296
+ "mutable": false,
2297
+ "complexType": {
2298
+ "original": "string",
2299
+ "resolved": "string",
2300
+ "references": {}
2301
+ },
2302
+ "required": false,
2303
+ "optional": true,
2304
+ "docs": {
2305
+ "tags": [],
2306
+ "text": ""
2307
+ },
2308
+ "getter": false,
2309
+ "setter": false,
2310
+ "reflect": false
2311
+ },
2312
+ "metricsExportIntervalMillis": {
2313
+ "type": "number",
2314
+ "attribute": "metrics-export-interval-millis",
2315
+ "mutable": false,
2316
+ "complexType": {
2317
+ "original": "number",
2318
+ "resolved": "number",
2319
+ "references": {}
2320
+ },
2321
+ "required": false,
2322
+ "optional": true,
2323
+ "docs": {
2324
+ "tags": [],
2325
+ "text": ""
2326
+ },
2327
+ "getter": false,
2328
+ "setter": false,
2329
+ "reflect": false,
2330
+ "defaultValue": "60000"
2331
+ },
2332
+ "license": {
2333
+ "type": "string",
2334
+ "attribute": "license",
2335
+ "mutable": false,
2336
+ "complexType": {
2337
+ "original": "string",
2338
+ "resolved": "string",
2339
+ "references": {}
2340
+ },
2341
+ "required": false,
2342
+ "optional": true,
2343
+ "docs": {
2344
+ "tags": [],
2345
+ "text": ""
2346
+ },
2347
+ "getter": false,
2348
+ "setter": false,
2349
+ "reflect": false
2350
+ },
2351
+ "licenseEnvironment": {
2352
+ "type": "string",
2353
+ "attribute": "license-environment",
2354
+ "mutable": false,
2355
+ "complexType": {
2356
+ "original": "'dev' | 'qa' | 'sandbox' | 'prod'",
2357
+ "resolved": "\"dev\" | \"prod\" | \"qa\" | \"sandbox\"",
2358
+ "references": {}
2359
+ },
2360
+ "required": false,
2361
+ "optional": true,
2362
+ "docs": {
2363
+ "tags": [],
2364
+ "text": ""
2365
+ },
2366
+ "getter": false,
2367
+ "setter": false,
2368
+ "reflect": false,
2369
+ "defaultValue": "'prod'"
2370
+ },
2371
+ "traceId": {
2372
+ "type": "string",
2373
+ "attribute": "trace-id",
2374
+ "mutable": false,
2375
+ "complexType": {
2376
+ "original": "string",
2377
+ "resolved": "string",
2378
+ "references": {}
2379
+ },
2380
+ "required": false,
2381
+ "optional": true,
2382
+ "docs": {
2383
+ "tags": [],
2384
+ "text": ""
2385
+ },
2386
+ "getter": false,
2387
+ "setter": false,
2388
+ "reflect": false
2389
+ },
2390
+ "appId": {
2391
+ "type": "string",
2392
+ "attribute": "app-id",
2393
+ "mutable": false,
2394
+ "complexType": {
2395
+ "original": "string",
2396
+ "resolved": "string",
2397
+ "references": {}
2398
+ },
2399
+ "required": false,
2400
+ "optional": true,
2401
+ "docs": {
2402
+ "tags": [],
2403
+ "text": ""
2404
+ },
2405
+ "getter": false,
2406
+ "setter": false,
2407
+ "reflect": false,
2408
+ "defaultValue": "'jaak-stamps-web'"
1947
2409
  }
1948
2410
  };
1949
2411
  }
@@ -1964,7 +2426,9 @@ export class JaakStamps {
1964
2426
  "performanceDegradedMode": {},
1965
2427
  "showPerformanceMessage": {},
1966
2428
  "captureStateVersion": {},
1967
- "processingButton": {}
2429
+ "processingButton": {},
2430
+ "licenseValid": {},
2431
+ "licenseError": {}
1968
2432
  };
1969
2433
  }
1970
2434
  static get events() {
@@ -1998,6 +2462,21 @@ export class JaakStamps {
1998
2462
  "resolved": "boolean",
1999
2463
  "references": {}
2000
2464
  }
2465
+ }, {
2466
+ "method": "traceIdGenerated",
2467
+ "name": "traceIdGenerated",
2468
+ "bubbles": true,
2469
+ "cancelable": true,
2470
+ "composed": true,
2471
+ "docs": {
2472
+ "tags": [],
2473
+ "text": ""
2474
+ },
2475
+ "complexType": {
2476
+ "original": "{traceId: string}",
2477
+ "resolved": "{ traceId: string; }",
2478
+ "references": {}
2479
+ }
2001
2480
  }];
2002
2481
  }
2003
2482
  static get methods() {