@jaak.ai/stamps 2.1.0-dev.7 → 2.1.0-dev.8

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 (27) hide show
  1. package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
  2. package/dist/cjs/jaak-stamps.cjs.entry.js +364 -11
  3. package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
  4. package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/collection/components/my-component/my-component.js +254 -6
  7. package/dist/collection/components/my-component/my-component.js.map +1 -1
  8. package/dist/collection/services/DetectionService.js +146 -7
  9. package/dist/collection/services/DetectionService.js.map +1 -1
  10. package/dist/collection/services/interfaces/IDetectionService.js.map +1 -1
  11. package/dist/components/jaak-stamps.js +367 -12
  12. package/dist/components/jaak-stamps.js.map +1 -1
  13. package/dist/esm/jaak-stamps-webcomponent.js +1 -1
  14. package/dist/esm/jaak-stamps.entry.js +364 -11
  15. package/dist/esm/jaak-stamps.entry.js.map +1 -1
  16. package/dist/esm/loader.js +1 -1
  17. package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
  18. package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
  19. package/dist/jaak-stamps-webcomponent/p-8e25497e.entry.js +2 -0
  20. package/dist/jaak-stamps-webcomponent/p-8e25497e.entry.js.map +1 -0
  21. package/dist/types/components/my-component/my-component.d.ts +27 -0
  22. package/dist/types/components.d.ts +3 -1
  23. package/dist/types/services/DetectionService.d.ts +9 -1
  24. package/dist/types/services/interfaces/IDetectionService.d.ts +6 -0
  25. package/package.json +1 -1
  26. package/dist/jaak-stamps-webcomponent/p-be6b6ca3.entry.js +0 -2
  27. package/dist/jaak-stamps-webcomponent/p-be6b6ca3.entry.js.map +0 -1
@@ -5,7 +5,7 @@ var index = require('./index-BfhtOB0D.js');
5
5
  const defineCustomElements = async (win, options) => {
6
6
  if (typeof window === 'undefined') return undefined;
7
7
  await index.globalScripts();
8
- return index.bootstrapLazy([["jaak-stamps.cjs",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"maskSize":[2,"mask-size"],"cropMargin":[2,"crop-margin"],"useDocumentClassification":[4,"use-document-classification"],"useDocumentDetector":[4,"use-document-detector"],"preferredCamera":[1,"preferred-camera"],"captureDelay":[2,"capture-delay"],"enableBackDocumentTimer":[4,"enable-back-document-timer"],"backDocumentTimerDuration":[2,"back-document-timer-duration"],"detectionBoxes":[32],"sideAlignment":[32],"isMaskReady":[32],"shouldMirrorVideo":[32],"showCameraSelector":[32],"isSwitchingCamera":[32],"hasDocumentDetected":[32],"cameraInfoWithAutofocus":[32],"currentStatus":[32],"performanceData":[32],"backDocumentTimerRemaining":[32],"showManualCaptureButton":[32],"performanceDegradedMode":[32],"showPerformanceMessage":[32],"captureStateVersion":[32],"processingButton":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"skipBackCapture":[64],"getStatus":[64],"preloadModel":[64],"getCameraInfo":[64],"setPreferredCamera":[64],"setCaptureDelay":[64],"getCaptureDelay":[64]}]]]], options);
8
+ return index.bootstrapLazy([["jaak-stamps.cjs",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"maskSize":[2,"mask-size"],"cropMargin":[2,"crop-margin"],"useDocumentClassification":[4,"use-document-classification"],"useDocumentDetector":[4,"use-document-detector"],"preferredCamera":[1,"preferred-camera"],"captureDelay":[2,"capture-delay"],"enableBackDocumentTimer":[4,"enable-back-document-timer"],"backDocumentTimerDuration":[2,"back-document-timer-duration"],"detectionBoxes":[32],"sideAlignment":[32],"isMaskReady":[32],"shouldMirrorVideo":[32],"showCameraSelector":[32],"isSwitchingCamera":[32],"hasDocumentDetected":[32],"cameraInfoWithAutofocus":[32],"currentStatus":[32],"performanceData":[32],"backDocumentTimerRemaining":[32],"showManualCaptureButton":[32],"performanceDegradedMode":[32],"showPerformanceMessage":[32],"captureStateVersion":[32],"processingButton":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"skipBackCapture":[64],"getStatus":[64],"preloadModel":[64],"getCameraInfo":[64],"setPreferredCamera":[64],"setCaptureDelay":[64],"getCaptureDelay":[64],"getResourceReport":[64],"forceResourceCleanup":[64]}]]]], options);
9
9
  };
10
10
 
11
11
  exports.setNonce = index.setNonce;
@@ -411,7 +411,13 @@ export class JaakStamps {
411
411
  }
412
412
  try {
413
413
  this.exitSession();
414
- return { success: true };
414
+ // Aggressive cleanup when stopping capture
415
+ const cleanupResult = await this.aggressiveResourceCleanup();
416
+ return {
417
+ success: true,
418
+ resourcesFreed: cleanupResult.freed,
419
+ cleanupErrors: cleanupResult.errors
420
+ };
415
421
  }
416
422
  catch (error) {
417
423
  return { success: false, error: error.message };
@@ -636,6 +642,29 @@ export class JaakStamps {
636
642
  // Always allow getting capture delay, even during initialization
637
643
  return this.captureDelay;
638
644
  }
645
+ async getResourceReport() {
646
+ // Public method to get resource usage report
647
+ return this.getResourceReportInternal();
648
+ }
649
+ async forceResourceCleanup() {
650
+ // Public method to force aggressive resource cleanup
651
+ const readyCheck = this.isComponentReady();
652
+ if (!readyCheck.ready) {
653
+ return { success: false, error: readyCheck.message };
654
+ }
655
+ try {
656
+ const cleanupResult = await this.aggressiveResourceCleanup();
657
+ return {
658
+ success: true,
659
+ resourcesFreed: cleanupResult.freed,
660
+ errors: cleanupResult.errors,
661
+ timestamp: new Date().toISOString()
662
+ };
663
+ }
664
+ catch (error) {
665
+ return { success: false, error: error.message };
666
+ }
667
+ }
639
668
  // Memory and device capability detection
640
669
  checkDeviceCapabilities() {
641
670
  const deviceMemory = navigator.deviceMemory;
@@ -971,11 +1000,182 @@ export class JaakStamps {
971
1000
  }
972
1001
  // Clear canvas pool
973
1002
  this.canvasPool = [];
1003
+ // Clean DOM references and memory leaks
1004
+ this.cleanupDOMReferences();
974
1005
  this.detectionBoxes = [];
975
1006
  this.alignmentStartTime = undefined;
976
1007
  this.hasDocumentDetected = false;
977
1008
  this.serviceContainer?.cleanup();
978
1009
  }
1010
+ // AGGRESSIVE RESOURCE CLEANUP METHODS
1011
+ // Clean DOM references and memory leaks
1012
+ cleanupDOMReferences() {
1013
+ // Remove event listeners that could maintain references
1014
+ if (this.videoRef) {
1015
+ // Remove common event listeners (if any were added)
1016
+ this.videoRef.srcObject = null;
1017
+ this.videoRef = undefined;
1018
+ }
1019
+ // Clean detection container
1020
+ if (this.detectionContainer) {
1021
+ this.detectionContainer = undefined;
1022
+ }
1023
+ // Clean references to images in the DOM and revoke blob URLs
1024
+ const images = this.el.shadowRoot?.querySelectorAll('img');
1025
+ images?.forEach(img => {
1026
+ if (img.src.startsWith('blob:')) {
1027
+ URL.revokeObjectURL(img.src);
1028
+ }
1029
+ img.src = '';
1030
+ });
1031
+ }
1032
+ // Clear browser cache and storage
1033
+ async clearBrowserCache() {
1034
+ try {
1035
+ // 1. Clear Service Worker cache if exists
1036
+ if ('serviceWorker' in navigator) {
1037
+ const registrations = await navigator.serviceWorker.getRegistrations();
1038
+ await Promise.all(registrations.map(registration => registration.unregister()));
1039
+ }
1040
+ // 2. Clear Cache API specific to the component
1041
+ const cacheNames = await caches.keys();
1042
+ const componentCaches = cacheNames.filter(name => name.includes('jaak') || name.includes('stamps'));
1043
+ await Promise.all(componentCaches.map(cacheName => caches.delete(cacheName)));
1044
+ // 3. Force garbage collection if available (only in dev)
1045
+ if (this.debug && window.gc) {
1046
+ window.gc();
1047
+ }
1048
+ }
1049
+ catch (error) {
1050
+ console.warn('Error clearing browser cache:', error);
1051
+ }
1052
+ }
1053
+ // Clear local storage specific to the component
1054
+ async clearLocalStorage() {
1055
+ try {
1056
+ // Clear localStorage specific to the component
1057
+ const keysToRemove = [];
1058
+ for (let i = 0; i < localStorage.length; i++) {
1059
+ const key = localStorage.key(i);
1060
+ if (key && (key.includes('jaak') || key.includes('onnx') || key.includes('stamps'))) {
1061
+ keysToRemove.push(key);
1062
+ }
1063
+ }
1064
+ keysToRemove.forEach(key => localStorage.removeItem(key));
1065
+ // Clear sessionStorage
1066
+ const sessionKeysToRemove = [];
1067
+ for (let i = 0; i < sessionStorage.length; i++) {
1068
+ const key = sessionStorage.key(i);
1069
+ if (key && (key.includes('jaak') || key.includes('onnx'))) {
1070
+ sessionKeysToRemove.push(key);
1071
+ }
1072
+ }
1073
+ sessionKeysToRemove.forEach(key => sessionStorage.removeItem(key));
1074
+ }
1075
+ catch (error) {
1076
+ console.warn('Error clearing local storage:', error);
1077
+ }
1078
+ }
1079
+ // Aggressive resource cleanup combining all strategies
1080
+ async aggressiveResourceCleanup() {
1081
+ const freed = [];
1082
+ const errors = [];
1083
+ try {
1084
+ // 1. Release ONNX resources
1085
+ this.releaseOnnxResources();
1086
+ freed.push('ONNX models');
1087
+ // 2. Clear model cache in detection service
1088
+ if (this.detectionService) {
1089
+ await this.detectionService.clearModelCache();
1090
+ freed.push('Model cache');
1091
+ }
1092
+ // 3. Clear browser cache
1093
+ await this.clearBrowserCache();
1094
+ freed.push('Browser cache');
1095
+ // 4. Clear local storage
1096
+ await this.clearLocalStorage();
1097
+ freed.push('Local storage');
1098
+ // 5. Clean DOM references
1099
+ this.cleanupDOMReferences();
1100
+ freed.push('DOM references');
1101
+ // 6. Optimize canvas pools
1102
+ if (this.detectionService) {
1103
+ this.detectionService.optimizeCanvasPool(0);
1104
+ freed.push('Canvas pools');
1105
+ }
1106
+ // 7. Clear component canvas pool
1107
+ this.canvasPool = [];
1108
+ freed.push('Component canvas pool');
1109
+ // 8. Force garbage collection (if available)
1110
+ if (this.debug && window.gc) {
1111
+ window.gc();
1112
+ freed.push('Garbage collection');
1113
+ }
1114
+ }
1115
+ catch (error) {
1116
+ errors.push(error.message);
1117
+ }
1118
+ return { freed, errors };
1119
+ }
1120
+ // Progressive resource release after front capture
1121
+ async onFrontCaptureComplete() {
1122
+ try {
1123
+ // Release classification model if not needed for back
1124
+ if (this.detectionService && !this.useDocumentClassification) {
1125
+ await this.detectionService.releaseMobileNetResources();
1126
+ }
1127
+ // Optimize canvas pool to minimum needed for back capture
1128
+ if (this.detectionService) {
1129
+ this.detectionService.optimizeCanvasPool(1);
1130
+ }
1131
+ // Reduce component canvas pool
1132
+ while (this.canvasPool.length > 1) {
1133
+ const canvas = this.canvasPool.pop();
1134
+ if (canvas) {
1135
+ const ctx = canvas.getContext('2d');
1136
+ if (ctx) {
1137
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1138
+ }
1139
+ }
1140
+ }
1141
+ if (this.debug) {
1142
+ console.log('🧹 Progressive cleanup after front capture completed');
1143
+ }
1144
+ }
1145
+ catch (error) {
1146
+ console.warn('Error in progressive cleanup:', error);
1147
+ }
1148
+ }
1149
+ // Resource reporting for debugging
1150
+ getResourceReportInternal() {
1151
+ const report = {
1152
+ timestamp: new Date().toISOString(),
1153
+ component: {
1154
+ hasVideoStream: !!this.videoStream,
1155
+ hasAnimationFrame: !!this.animationId,
1156
+ canvasPoolSize: this.canvasPool.length,
1157
+ detectionBoxesCount: this.detectionBoxes.length,
1158
+ performanceMonitorActive: !!this.performanceUpdateInterval
1159
+ }
1160
+ };
1161
+ // Add detection service stats if available
1162
+ if (this.detectionService) {
1163
+ report.detectionService = {
1164
+ isModelLoaded: this.detectionService.isModelLoaded(),
1165
+ canvasPoolStats: this.detectionService.getPoolStats()
1166
+ };
1167
+ }
1168
+ // Add memory info if available
1169
+ if ('memory' in performance) {
1170
+ const memInfo = performance.memory;
1171
+ report.memory = {
1172
+ usedJSHeapSize: Math.round(memInfo.usedJSHeapSize / 1048576), // MB
1173
+ totalJSHeapSize: Math.round(memInfo.totalJSHeapSize / 1048576), // MB
1174
+ jsHeapSizeLimit: Math.round(memInfo.jsHeapSizeLimit / 1048576) // MB
1175
+ };
1176
+ }
1177
+ return report;
1178
+ }
979
1179
  render() {
980
1180
  const captureState = this.stateManager?.getCaptureState() || {
981
1181
  isVideoActive: false,
@@ -986,7 +1186,7 @@ export class JaakStamps {
986
1186
  isCapturing: false
987
1187
  };
988
1188
  const cameraInfo = this.cameraInfoWithAutofocus;
989
- return (h("div", { key: '51cc6d0f873691852f938940b131732252b970c1', class: "detector-container" }, h("div", { key: '009480499c0a2833bf9f6bd28003142ca3dd3750', class: "video-container" }, h("video", { key: '88a99a1a90c8d817e40549a255324b2da342797f', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '7ede15ccd6f67b3081d907777de7b0d1a1b4cfd6', 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: {
1189
+ return (h("div", { key: 'ca44b9eacbde9f688f2c41aa21ad35a2b882002b', class: "detector-container" }, h("div", { key: '86c7b5d31ed69276b62fa43e01c92b0c0b9f298d', class: "video-container" }, h("video", { key: 'bb310544c17ae734d8b42ed2617748c2f69743ff', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '078a79a0c6386ca6c040e629acbf4f52f12d8e29', 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: {
990
1190
  position: 'absolute',
991
1191
  left: `${box.x}px`,
992
1192
  top: `${box.y}px`,
@@ -995,9 +1195,9 @@ export class JaakStamps {
995
1195
  border: '2px solid #32406C',
996
1196
  pointerEvents: 'none',
997
1197
  boxSizing: 'border-box'
998
- } })))), this.isMaskReady && (h("div", { key: '63beb4330ab171a5e63237b1d83dcace61422018', class: "overlay-mask" }, h("div", { key: '93cfac6898de6ece6c7dd8f02ba2b79ce6591755', class: "card-outline" }, h("div", { key: '3087d3c51f42ea8d720cea4170dcb68e8bb385e1', class: "side side-top" }), h("div", { key: '992e311b895da161d3b5c49dde346ae378139641', class: "side side-right" }), h("div", { key: '5fb3d7b704f08177b2b9c6e4fbaf685f251a3e53', class: "side side-bottom" }), h("div", { key: '76f6e2cb856632c58809ccdabdf3f7d9a588c9da', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '142dfc187e07100278e16b19018e4b5fb96d964a', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'bba078ce4c9585631b6a8154f878464b1f779c8b', class: "back-capture-section" }, h("div", { key: 'ec94c9ba2cb373a539f0e6cc3eb356294cebf3ea', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode) && (h("button", { key: '30561e1fc88090c6bb4d0cd7909a33a9525b0ac2', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: '4b3e3356507c7f654705425e201d0303d727db72', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: '1abfada41312658eab4966d8fcdb711a6c4762e6', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '3cab3ce751cb38174b6d061170a66ac654a90a38', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
1198
+ } })))), this.isMaskReady && (h("div", { key: '990015ff5b2ded89405dd2b891c027aad8788f3e', class: "overlay-mask" }, h("div", { key: 'dd9145140987addb1b6e4cc2119b8e9f89003726', class: "card-outline" }, h("div", { key: 'e8f4ec692a8b80c7a98075e4f708b79a272db67b', class: "side side-top" }), h("div", { key: '2577253b40425ecdcb3dd51b2f4a43c15c83ca79', class: "side side-right" }), h("div", { key: '30f4454020c00cf4fb92308af5ecf1843ec24005', class: "side side-bottom" }), h("div", { key: '3459f634987b8396106fff23fa1c99b295ee7d0a', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '84f4d70947e211a9c6b296531d53420223d2ca34', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '7c28e86e8de6c33bf7d7baab3083c5f6a0ab060f', class: "back-capture-section" }, h("div", { key: '27bdcf9cfe9790c4bbad484423f6f4c353ccf0b3', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode) && (h("button", { key: 'ed0320b1df412bf53cbe4e4119f6d769926eb2c5', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: '0bba706c8ebda59c33faca8e97b7536146462d21', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: 'b072c46b25d16a04c5e0a8f3975d8aa8d24576d5', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: 'efd0827d0f19c9072d49d1b3c0046ef6c95a842c', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
999
1199
  ? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
1000
- : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'b773fe579cc039fd90ff5e61976752bcf631d16e', class: "camera-controls" }, h("button", { key: '8535463b13cc02e0030d14c1d57390e560572b4f', 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: 'c4b159cf28c24ba2ec0a658bf6f1296c6aba47e3', class: "camera-selector-dropdown" }, h("div", { key: '033273241b77cedc414dee00b70926c3a659910a', class: "camera-selector-header" }, h("span", { key: '83fb4c7ae2387b85134a3ca0c5a156beaf73e481' }, "Seleccionar C\u00E1mara"), h("button", { key: 'f65b6e994603e616af8d69df198c3d8471125695', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'fd90d4c4db1e910c5d05b9ce19a252967c71ad1f', 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: '49faa944b3c0c052e18f48e9dda2758cd2c0ae6b', class: "device-info" }, h("small", { key: '15e95207aef60a78b2912a6c00a1b61ab760b72d' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'a67a3795837adcd307fa3666c338376cecae16d0', class: "manual-capture-section" }, h("button", { key: '7f21ccd9b622d97bfce80962038de8be7cd6e33d', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: 'a4b5e865f373cc0e7787098eedd2d4df413d310f', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '0b02e81963136dfda62a8980bc5a1f5662509fb8', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '5eb16e12a7ce16720ca7bdd11aefd902ba772e24', class: "flip-animation" }, h("div", { key: '4c6f3ed33c5080e9e18d17c4594cf394250c3517', class: "id-card-icon" }), h("div", { key: 'd848d7a98540988a8f491bcf8f6f6ad9c5dccfd4', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '94863e6d0c404188d548db428af918274d882652', class: "success-animation" }, h("div", { key: 'a90b777e7b7eb533fabec2c15f79a4bd18778f0b', class: "check-icon" }), h("div", { key: '2152e5a3756f58f996c520b58cb1b6cca1763e94', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: 'ae18e06bf291429a74d1b6c8a0c4d37d473f7b30', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'b6b03ed285868d7d3350a2a73e59cb1d65a47401', class: "status-spinner" })), h("div", { key: 'dc85b49dd1cfcddf7300fb3f327d2e1de8ab9bff', class: "status-content" }, h("div", { key: '82461ed0c6d70a0c95ae6b7144ff1d8b8371c6fc', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '24aa77ec92ca5a48d1bed4cf98ae591bdbff74f0', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '3b56a0b305ca07407c09a73624a4040cf6625b56', class: "performance-monitor" }, h("div", { key: '52f975da1502f6b08a0b2c828bfd0be8d10e36f8', class: "performance-expanded" }, h("div", { key: 'ea2f444255add0415c7f88cdea2733e1244b17bd', class: "metrics-row" }, h("div", { key: 'e3c2370f1a900594940cb321d5b1661690018025', class: "metric-compact" }, h("span", { key: '25c2f402c9b69f21736c494420e7a396673e9893', class: "metric-label" }, "FPS"), h("span", { key: '505de593f7927544cd874332127e84c72131da72', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '5cb1ff4bc1ac33988404e59dac3d01d5a55893b9', class: "metric-compact" }, h("span", { key: 'ce701538abbfe797b288520ab4c277bf7a1d6a05', class: "metric-label" }, "MEM"), h("span", { key: 'efc383e993ad72c20cbfc630e20b2bf9a617a02d', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'b6b6b832740c44d4f78cddf99ba1d139dc3d4739', class: "metrics-row" }, h("div", { key: '3a8903a05aed8adb1626f93bee6ba258fbea9a7d', class: "metric-compact" }, h("span", { key: 'aabc56057156217b3be771ab3b1e92590fa886c5', class: "metric-label" }, "INF"), h("span", { key: '1080df34860cc891cda94c5aacc754cbde18a138', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: 'ac152093d4c0cc25862aac638fc4693dd0c51a69', class: "metric-compact" }, h("span", { key: 'b23712dbc0b9b8e9cb6e2c659e5af3844ec0ebe7', class: "metric-label" }, "FRAME"), h("span", { key: '461f88519b339fbad6444f009312f72efbc6e450', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '8f99afe2c94f37fd3a6feb082cc9aa96f54fc5e1', class: "metrics-row" }, h("div", { key: 'da7ac0fd842f38bbdcac01550764f9fe1bd666a2', class: "metric-compact" }, h("span", { key: 'a5dcd9c8753ba42038f869efa50ae9602cdf6256', class: "metric-label" }, "DET"), h("span", { key: 'e98b91ea98a41637baea1fcfda0bb590cf5d24a0', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '3ac54161a712d305a098eae0a3b5d21a731c6019', class: "metric-compact" }, h("span", { key: '3c8cc465433be3b490887457a6c3967dbbda6a7d', class: "metric-label" }, "RATE"), h("span", { key: 'f2e083118fe107c7dc2a675e3f661466cea6d479', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '10b6c32b0460e194d680c63b30a078c51a26e9c9', class: "watermark" }, h("img", { key: 'f5954a0ba3f90a642e0d5c6c14d5b549cd193018', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1200
+ : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'bd0303e8ce85211e4c68fc3cd79545db7c74288b', class: "camera-controls" }, h("button", { key: 'e4327d260b988b67e0de3654c72f24455cd3bbbd', 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: '35da16baf4c62466c2a66650209a1daf842c0db2', class: "camera-selector-dropdown" }, h("div", { key: '7035dd0e22f614cf239a015c6d59531b68fa74a9', class: "camera-selector-header" }, h("span", { key: 'ae026f31931f52ea0daf72391a9de4ff9e4b88f1' }, "Seleccionar C\u00E1mara"), h("button", { key: '40f2ba0770bafea71fedbf849938010e743be776', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: '6f26927094a724a35ebb07ef701caf14f296a837', 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: '082236981c369f8fd487f036439b16e6560514be', class: "device-info" }, h("small", { key: 'ccbbfa0bca96395f574bda71103338ae9226f709' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '6baa487409503777e90453b39fd30649941cbbe4', class: "manual-capture-section" }, h("button", { key: '893f4715ca3315613f779603f178459955f686f0', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: '7c30b680fe84f4c8227beba45d8416f1edb8348f', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: 'd8ef052cf67d7bda4b3534febf96efa2cdcc6bf7', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '3dae7634e770dda2655b1042ec8fb997b3cb2220', class: "flip-animation" }, h("div", { key: 'a977fc5e889369121bacc06cf5213dfee39d858d', class: "id-card-icon" }), h("div", { key: '4f052cdc8c7b493cddce90e108e976325c9bab8e', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '5117cd6e63e1e0763c1503f6f60f3c7ef60dd665', class: "success-animation" }, h("div", { key: 'd11128c45c7118915cc0dd9c25845bb55b4b3eb2', class: "check-icon" }), h("div", { key: '693e197bf8a4c91ac7ddedb457d15aa3aa46a5d5', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '89caaa9d78eb522e0fadfd1c0e844e05d29b8286', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: '3f41d40b05b71e13e7e1d0c0e980b48308cba9d6', class: "status-spinner" })), h("div", { key: '8674480928f4f4a77099c0600ed84f0e27903379', class: "status-content" }, h("div", { key: 'e88f4044ab8115a6a5cbb78cc4030975eef9149a', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: 'ad581e42c30c304b837711549148c11b801dee5e', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '1b371c1b47f3ba699885db00fef52eb448f9e245', class: "performance-monitor" }, h("div", { key: '8b9ac60449a15e9fb966c329b2e6c9285c0228c0', class: "performance-expanded" }, h("div", { key: '760c11a3ed28e248a144d53a92fd8adee6822ff2', class: "metrics-row" }, h("div", { key: '858ab8b106f1d12210e4e15c423ab3bab11bdb60', class: "metric-compact" }, h("span", { key: '65fe2479c3822d99452e7e5faa93c25a80765024', class: "metric-label" }, "FPS"), h("span", { key: '9faf7763d1284a6f3c1e15fb0f3c99f1d45bb4dc', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: 'c95ed8fa8101f42bfba5cc8ca7debbad028caf42', class: "metric-compact" }, h("span", { key: '3555b3778cb71e959d132d6aa563f58f757915d8', class: "metric-label" }, "MEM"), h("span", { key: 'd72b0491147a6f80dcf33f5d72dd8dae5898f44a', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'cd4dc81f28f9e59a36a0295dde7bfee89f50d3e2', class: "metrics-row" }, h("div", { key: 'c43d8624c5da256ce3e97f67b022bdd98fb04e07', class: "metric-compact" }, h("span", { key: 'adb402d83809a90580b81544f31b5331bdff59dd', class: "metric-label" }, "INF"), h("span", { key: 'e48c9814c08acbe321460a29e42cb49b0eab38ff', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '71517f9279e9a6aa0d5b02e2169db868ca3fb676', class: "metric-compact" }, h("span", { key: '3ddbcc56b137aea702a40f900178e8e16efd146e', class: "metric-label" }, "FRAME"), h("span", { key: 'd3a70afb511d3f72b485b3a1cb922876faa62b11', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: 'a3b62cdbe830b1024ab96f7fb726825df24fecdc', class: "metrics-row" }, h("div", { key: '95471e5cdde748d1ce6bdee3540740dd3aa66865', class: "metric-compact" }, h("span", { key: 'c93e01c0bdc67621c3a666357d2477b7a5275d52', class: "metric-label" }, "DET"), h("span", { key: 'ef33c86a83101b0989b14c7f1ab0ce0b331b397f', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: 'e14d56128bf96337e4c3859f8e4003e001e8e953', class: "metric-compact" }, h("span", { key: '8aa828632f0a977a27ed377f103bb8d5e7e0ed1a', class: "metric-label" }, "RATE"), h("span", { key: '59035c473b5a747a27f774e2554322a084b6d19f', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '4d0c2de00954416faac30ab622fb21f36c932aca', class: "watermark" }, h("img", { key: 'd8f775428ebb3ba86a943ca73b074db2180d0c29', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1001
1201
  }
1002
1202
  // Utility methods
1003
1203
  updateDetectionBoxes(boxes) {
@@ -1221,6 +1421,8 @@ export class JaakStamps {
1221
1421
  showFlipAnimation: true
1222
1422
  });
1223
1423
  this.triggerRerender();
1424
+ // Progressive resource cleanup after front capture
1425
+ await this.onFrontCaptureComplete();
1224
1426
  setTimeout(() => {
1225
1427
  this.stateManager.updateCaptureState({
1226
1428
  showFlipAnimation: false,
@@ -1296,6 +1498,8 @@ export class JaakStamps {
1296
1498
  isDetectionPaused: true,
1297
1499
  showFlipAnimation: true
1298
1500
  });
1501
+ // Progressive resource cleanup after front capture
1502
+ await this.onFrontCaptureComplete();
1299
1503
  setTimeout(() => {
1300
1504
  this.stateManager.updateCaptureState({
1301
1505
  showFlipAnimation: false,
@@ -1473,6 +1677,16 @@ export class JaakStamps {
1473
1677
  setTimeout(() => {
1474
1678
  this.stateManager.updateCaptureState({ showSuccessAnimation: false });
1475
1679
  }, 3000);
1680
+ // Aggressive cleanup after process completion with delay
1681
+ setTimeout(async () => {
1682
+ const cleanupResult = await this.aggressiveResourceCleanup();
1683
+ if (this.debug) {
1684
+ console.log('🧹 Post-completion cleanup:', cleanupResult.freed);
1685
+ if (cleanupResult.errors.length > 0) {
1686
+ console.warn('⚠️ Cleanup errors:', cleanupResult.errors);
1687
+ }
1688
+ }
1689
+ }, 1000); // Wait 1 second after completion
1476
1690
  }
1477
1691
  stopDetection() {
1478
1692
  if (this.animationId) {
@@ -2054,7 +2268,7 @@ export class JaakStamps {
2054
2268
  },
2055
2269
  "stopCapture": {
2056
2270
  "complexType": {
2057
- "signature": "() => Promise<{ success: boolean; error?: undefined; } | { success: boolean; error: any; }>",
2271
+ "signature": "() => Promise<{ success: boolean; resourcesFreed: string[]; cleanupErrors: string[]; error?: undefined; } | { success: boolean; error: any; resourcesFreed?: undefined; cleanupErrors?: undefined; }>",
2058
2272
  "parameters": [],
2059
2273
  "references": {
2060
2274
  "Promise": {
@@ -2062,7 +2276,7 @@ export class JaakStamps {
2062
2276
  "id": "global::Promise"
2063
2277
  }
2064
2278
  },
2065
- "return": "Promise<{ success: boolean; error?: undefined; } | { success: boolean; error: any; }>"
2279
+ "return": "Promise<{ success: boolean; resourcesFreed: string[]; cleanupErrors: string[]; error?: undefined; } | { success: boolean; error: any; resourcesFreed?: undefined; cleanupErrors?: undefined; }>"
2066
2280
  },
2067
2281
  "docs": {
2068
2282
  "text": "",
@@ -2222,6 +2436,40 @@ export class JaakStamps {
2222
2436
  "text": "",
2223
2437
  "tags": []
2224
2438
  }
2439
+ },
2440
+ "getResourceReport": {
2441
+ "complexType": {
2442
+ "signature": "() => Promise<any>",
2443
+ "parameters": [],
2444
+ "references": {
2445
+ "Promise": {
2446
+ "location": "global",
2447
+ "id": "global::Promise"
2448
+ }
2449
+ },
2450
+ "return": "Promise<any>"
2451
+ },
2452
+ "docs": {
2453
+ "text": "",
2454
+ "tags": []
2455
+ }
2456
+ },
2457
+ "forceResourceCleanup": {
2458
+ "complexType": {
2459
+ "signature": "() => Promise<{ success: boolean; resourcesFreed: string[]; errors: string[]; timestamp: string; error?: undefined; } | { success: boolean; error: any; resourcesFreed?: undefined; errors?: undefined; timestamp?: undefined; }>",
2460
+ "parameters": [],
2461
+ "references": {
2462
+ "Promise": {
2463
+ "location": "global",
2464
+ "id": "global::Promise"
2465
+ }
2466
+ },
2467
+ "return": "Promise<{ success: boolean; resourcesFreed: string[]; errors: string[]; timestamp: string; error?: undefined; } | { success: boolean; error: any; resourcesFreed?: undefined; errors?: undefined; timestamp?: undefined; }>"
2468
+ },
2469
+ "docs": {
2470
+ "text": "",
2471
+ "tags": []
2472
+ }
2225
2473
  }
2226
2474
  };
2227
2475
  }