@jaak.ai/stamps 2.5.2 → 2.5.4-dev.1

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.
@@ -18779,6 +18779,18 @@ const JaakStamps = class {
18779
18779
  processedFramesCount = 0; // Contador total de frames procesados
18780
18780
  hasAutoSwitchedToManual = false;
18781
18781
  _manualModeLoggedOnce = false;
18782
+ VIDEO_DIAGNOSTIC_EVENTS = [
18783
+ 'loadstart',
18784
+ 'loadedmetadata',
18785
+ 'loadeddata',
18786
+ 'canplay',
18787
+ 'playing',
18788
+ 'pause',
18789
+ 'stalled',
18790
+ 'suspend',
18791
+ 'abort',
18792
+ 'emptied',
18793
+ ];
18782
18794
  // Canvas pool for optimized screenshot capture
18783
18795
  canvasPool = [];
18784
18796
  MAX_CANVAS_POOL_SIZE = 3;
@@ -19507,6 +19519,130 @@ const JaakStamps = class {
19507
19519
  memoryMB: deviceMemory ? deviceMemory * 1024 : null
19508
19520
  };
19509
19521
  }
19522
+ debugLog(message, details) {
19523
+ if (!this.debug) {
19524
+ return;
19525
+ }
19526
+ if (typeof details === 'undefined') {
19527
+ console.log(`[jaak-stamps][diag] ${message}`);
19528
+ return;
19529
+ }
19530
+ console.log(`[jaak-stamps][diag] ${message}`, details);
19531
+ }
19532
+ debugWarn(message, details) {
19533
+ if (!this.debug) {
19534
+ return;
19535
+ }
19536
+ if (typeof details === 'undefined') {
19537
+ console.warn(`[jaak-stamps][diag] ${message}`);
19538
+ return;
19539
+ }
19540
+ console.warn(`[jaak-stamps][diag] ${message}`, details);
19541
+ }
19542
+ summarizeId(id) {
19543
+ if (!id) {
19544
+ return null;
19545
+ }
19546
+ return id.length <= 8 ? id : `${id.slice(0, 8)}...`;
19547
+ }
19548
+ getCameraDevicesSnapshot() {
19549
+ return this.cameraService.getAvailableCameras().map(camera => ({
19550
+ label: camera.label || '(sin label)',
19551
+ deviceId: this.summarizeId(camera.deviceId),
19552
+ groupId: this.summarizeId(camera.groupId),
19553
+ kind: camera.kind,
19554
+ }));
19555
+ }
19556
+ sanitizeTrackSettings(settings) {
19557
+ if (!settings) {
19558
+ return null;
19559
+ }
19560
+ return {
19561
+ ...settings,
19562
+ deviceId: this.summarizeId(settings.deviceId),
19563
+ groupId: this.summarizeId(settings.groupId),
19564
+ };
19565
+ }
19566
+ sanitizeTrackConstraints(track) {
19567
+ if (!track) {
19568
+ return null;
19569
+ }
19570
+ const constraints = track.getConstraints ? track.getConstraints() : {};
19571
+ const sanitizedConstraints = { ...constraints };
19572
+ if (typeof sanitizedConstraints.deviceId === 'string') {
19573
+ sanitizedConstraints.deviceId = this.summarizeId(sanitizedConstraints.deviceId);
19574
+ }
19575
+ return sanitizedConstraints;
19576
+ }
19577
+ getStreamSnapshot(stream) {
19578
+ if (!stream) {
19579
+ return { hasStream: false };
19580
+ }
19581
+ const videoTrack = stream.getVideoTracks()[0];
19582
+ if (!videoTrack) {
19583
+ return {
19584
+ hasStream: true,
19585
+ streamActive: stream.active,
19586
+ trackCount: stream.getTracks().length,
19587
+ hasVideoTrack: false,
19588
+ };
19589
+ }
19590
+ return {
19591
+ hasStream: true,
19592
+ streamActive: stream.active,
19593
+ trackCount: stream.getTracks().length,
19594
+ trackLabel: videoTrack.label || '(sin label)',
19595
+ trackEnabled: videoTrack.enabled,
19596
+ trackMuted: videoTrack.muted,
19597
+ trackReadyState: videoTrack.readyState,
19598
+ settings: this.sanitizeTrackSettings(videoTrack.getSettings ? videoTrack.getSettings() : undefined),
19599
+ constraints: this.sanitizeTrackConstraints(videoTrack),
19600
+ };
19601
+ }
19602
+ getVideoElementSnapshot() {
19603
+ if (!this.videoRef) {
19604
+ return { hasVideoRef: false };
19605
+ }
19606
+ const computedStyle = this.el.ownerDocument?.defaultView?.getComputedStyle(this.videoRef);
19607
+ return {
19608
+ hasVideoRef: true,
19609
+ isConnected: this.videoRef.isConnected,
19610
+ readyState: this.videoRef.readyState,
19611
+ networkState: this.videoRef.networkState,
19612
+ paused: this.videoRef.paused,
19613
+ muted: this.videoRef.muted,
19614
+ autoplay: this.videoRef.autoplay,
19615
+ playsInline: this.videoRef.playsInline,
19616
+ currentTime: Number.isFinite(this.videoRef.currentTime)
19617
+ ? Number(this.videoRef.currentTime.toFixed(3))
19618
+ : this.videoRef.currentTime,
19619
+ videoWidth: this.videoRef.videoWidth,
19620
+ videoHeight: this.videoRef.videoHeight,
19621
+ clientWidth: this.videoRef.clientWidth,
19622
+ clientHeight: this.videoRef.clientHeight,
19623
+ hasSrcObject: !!this.videoRef.srcObject,
19624
+ display: computedStyle?.display ?? 'unknown',
19625
+ visibility: computedStyle?.visibility ?? 'unknown',
19626
+ };
19627
+ }
19628
+ attachVideoDiagnosticListeners() {
19629
+ if (!this.debug || !this.videoRef) {
19630
+ return () => undefined;
19631
+ }
19632
+ const video = this.videoRef;
19633
+ const listeners = this.VIDEO_DIAGNOSTIC_EVENTS.map(eventName => {
19634
+ const handler = () => {
19635
+ this.debugLog(`video event "${eventName}"`, this.getVideoElementSnapshot());
19636
+ };
19637
+ video.addEventListener(eventName, handler);
19638
+ return { eventName, handler };
19639
+ });
19640
+ return () => {
19641
+ listeners.forEach(({ eventName, handler }) => {
19642
+ video.removeEventListener(eventName, handler);
19643
+ });
19644
+ };
19645
+ }
19510
19646
  // DETECTION METHODS
19511
19647
  async startDetection() {
19512
19648
  try {
@@ -19593,12 +19729,19 @@ const JaakStamps = class {
19593
19729
  this.updateStatus('Configurando cámara...', 'Buscando dispositivos disponibles', 'loading');
19594
19730
  try {
19595
19731
  await this.cameraService.enumerateDevices();
19732
+ this.debugLog('step 2/5 enumerateDevices()', {
19733
+ cameras: this.getCameraDevicesSnapshot(),
19734
+ selectedCameraId: this.summarizeId(this.cameraService.getSelectedCameraId() || undefined),
19735
+ });
19596
19736
  }
19597
19737
  catch (enumerateError) {
19598
19738
  throw new Error(`Error al enumerar dispositivos: ${enumerateError.message}`);
19599
19739
  }
19600
19740
  try {
19601
19741
  await this.updateCameraInfoWithAutofocus();
19742
+ this.debugLog('step 2/5 updateCameraInfoWithAutofocus()', {
19743
+ cameraInfo: this.cameraInfoWithAutofocus,
19744
+ });
19602
19745
  }
19603
19746
  catch (cameraInfoError) {
19604
19747
  throw new Error(`Error al actualizar información de cámara: ${cameraInfoError.message}`);
@@ -19608,6 +19751,10 @@ const JaakStamps = class {
19608
19751
  let stream;
19609
19752
  try {
19610
19753
  stream = await this.cameraService.setupCamera();
19754
+ this.debugLog('step 3/5 setupCamera() resolved', {
19755
+ stream: this.getStreamSnapshot(stream),
19756
+ videoRef: this.getVideoElementSnapshot(),
19757
+ });
19611
19758
  }
19612
19759
  catch (setupError) {
19613
19760
  throw new Error(`Error al configurar cámara: ${setupError.message}`);
@@ -19620,7 +19767,15 @@ const JaakStamps = class {
19620
19767
  this.updateStatus('Captura activa', 'Posicione su documento y use el botón para capturar', 'active');
19621
19768
  }
19622
19769
  try {
19770
+ this.debugLog('step 4/5 initializeVideoStream() start', {
19771
+ stream: this.getStreamSnapshot(stream),
19772
+ videoRef: this.getVideoElementSnapshot(),
19773
+ });
19623
19774
  await this.initializeVideoStream(stream);
19775
+ this.debugLog('step 4/5 initializeVideoStream() completed', {
19776
+ stream: this.getStreamSnapshot(stream),
19777
+ videoRef: this.getVideoElementSnapshot(),
19778
+ });
19624
19779
  }
19625
19780
  catch (videoError) {
19626
19781
  throw new Error(`Error al inicializar video: ${videoError.message}`);
@@ -19638,37 +19793,199 @@ const JaakStamps = class {
19638
19793
  if (!this.useDocumentDetector) {
19639
19794
  this.showManualCaptureButton = true;
19640
19795
  }
19796
+ this.debugLog('step 5/5 capture loop ready', {
19797
+ videoRef: this.getVideoElementSnapshot(),
19798
+ stream: this.getStreamSnapshot(this.videoStream),
19799
+ useDocumentDetector: this.useDocumentDetector,
19800
+ });
19641
19801
  this.detectFrame();
19642
19802
  }
19643
19803
  catch (err) {
19804
+ this.debugWarn('startDetection() failed', {
19805
+ error: err instanceof Error ? err.message : String(err),
19806
+ videoRef: this.getVideoElementSnapshot(),
19807
+ stream: this.getStreamSnapshot(this.videoStream),
19808
+ });
19644
19809
  console.error('[jaak-stamps] Error al preparar captura:', err);
19645
19810
  this.updateStatus('Error al iniciar', 'No se pudo preparar la captura', 'error');
19646
19811
  this.stateManager.updateCaptureState({ isLoading: false });
19647
19812
  }
19648
19813
  }
19649
19814
  async initializeVideoStream(stream) {
19650
- if (this.videoRef) {
19651
- this.videoRef.srcObject = stream;
19652
- this.videoStream = stream;
19653
- const isRear = this.cameraService.isRearCamera(stream);
19654
- this.shouldMirrorVideo = !isRear;
19655
- return new Promise((resolve) => {
19656
- this.videoRef.onloadedmetadata = async () => {
19657
- await this.videoRef.play();
19658
- this.stateManager.updateCaptureState({ isVideoActive: true });
19659
- // Recalculate mask dimensions when new camera stream loads
19660
- if (this.detectionContainer) {
19661
- const container = this.detectionContainer.parentElement;
19662
- const rect = container.getBoundingClientRect();
19663
- this.updateMaskDimensions(rect);
19664
- }
19665
- resolve();
19666
- };
19667
- });
19668
- }
19669
- else {
19815
+ if (!this.videoRef) {
19670
19816
  throw new Error('Video element not available');
19671
19817
  }
19818
+ const detachVideoDiagnosticListeners = this.attachVideoDiagnosticListeners();
19819
+ this.debugLog('initializeVideoStream() pre-assign', {
19820
+ stream: this.getStreamSnapshot(stream),
19821
+ videoRef: this.getVideoElementSnapshot(),
19822
+ });
19823
+ this.videoRef.srcObject = stream;
19824
+ this.videoStream = stream;
19825
+ this.debugLog('initializeVideoStream() post-srcObject assignment', {
19826
+ stream: this.getStreamSnapshot(stream),
19827
+ videoRef: this.getVideoElementSnapshot(),
19828
+ });
19829
+ const isRear = this.cameraService.isRearCamera(stream);
19830
+ this.shouldMirrorVideo = !isRear;
19831
+ const LOAD_METADATA_TIMEOUT_MS = 10000;
19832
+ // Diagnostic instrumentation: when the timeout fires we need enough
19833
+ // context to distinguish between "OS muted the track", "permission
19834
+ // revoked mid-flight", "device never produced frames" and other modes
19835
+ // that all surface as the same generic timeout error.
19836
+ const track = stream.getVideoTracks()[0];
19837
+ const waitStart = performance.now();
19838
+ const trackEvents = [];
19839
+ const recordTrackEvent = (event) => {
19840
+ trackEvents.push({
19841
+ at: Math.round(performance.now() - waitStart),
19842
+ event,
19843
+ state: track?.readyState,
19844
+ });
19845
+ };
19846
+ const onTrackMute = () => recordTrackEvent('mute');
19847
+ const onTrackUnmute = () => recordTrackEvent('unmute');
19848
+ const onTrackEnded = () => recordTrackEvent('ended');
19849
+ if (track) {
19850
+ track.addEventListener('mute', onTrackMute);
19851
+ track.addEventListener('unmute', onTrackUnmute);
19852
+ track.addEventListener('ended', onTrackEnded);
19853
+ }
19854
+ const cleanupTrackListeners = () => {
19855
+ if (!track)
19856
+ return;
19857
+ track.removeEventListener('mute', onTrackMute);
19858
+ track.removeEventListener('unmute', onTrackUnmute);
19859
+ track.removeEventListener('ended', onTrackEnded);
19860
+ };
19861
+ const captureDiagnostics = () => {
19862
+ const settings = track?.getSettings?.();
19863
+ const computed = this.videoRef ? getComputedStyle(this.videoRef) : null;
19864
+ return {
19865
+ reason: 'VIDEO_METADATA_TIMEOUT',
19866
+ waitedMs: Math.round(performance.now() - waitStart),
19867
+ stream: {
19868
+ videoTrackCount: stream.getVideoTracks().length,
19869
+ audioTrackCount: stream.getAudioTracks().length,
19870
+ },
19871
+ track: track ? {
19872
+ readyState: track.readyState,
19873
+ muted: track.muted,
19874
+ enabled: track.enabled,
19875
+ label: track.label,
19876
+ kind: track.kind,
19877
+ settings: settings ? {
19878
+ width: settings.width,
19879
+ height: settings.height,
19880
+ frameRate: settings.frameRate,
19881
+ deviceId: settings.deviceId,
19882
+ facingMode: settings.facingMode,
19883
+ } : null,
19884
+ } : null,
19885
+ video: this.videoRef ? {
19886
+ readyState: this.videoRef.readyState,
19887
+ networkState: this.videoRef.networkState,
19888
+ error: this.videoRef.error ? { code: this.videoRef.error.code, message: this.videoRef.error.message } : null,
19889
+ paused: this.videoRef.paused,
19890
+ offsetWidth: this.videoRef.offsetWidth,
19891
+ offsetHeight: this.videoRef.offsetHeight,
19892
+ videoWidth: this.videoRef.videoWidth,
19893
+ videoHeight: this.videoRef.videoHeight,
19894
+ display: computed?.display,
19895
+ visibility: computed?.visibility,
19896
+ } : null,
19897
+ document: {
19898
+ visibilityState: document.visibilityState,
19899
+ hasFocus: document.hasFocus(),
19900
+ },
19901
+ trackEvents,
19902
+ userAgent: navigator.userAgent,
19903
+ };
19904
+ };
19905
+ const finalizeStreamInitialization = async () => {
19906
+ try {
19907
+ await this.videoRef.play();
19908
+ }
19909
+ catch (playError) {
19910
+ console.error('[jaak-stamps] video.play() failed (likely autoplay policy):', playError);
19911
+ throw playError;
19912
+ }
19913
+ this.stateManager.updateCaptureState({ isVideoActive: true });
19914
+ if (this.detectionContainer) {
19915
+ const container = this.detectionContainer.parentElement;
19916
+ const rect = container.getBoundingClientRect();
19917
+ this.updateMaskDimensions(rect);
19918
+ }
19919
+ this.debugLog('initializeVideoStream() finalized after play()', {
19920
+ stream: this.getStreamSnapshot(stream),
19921
+ videoRef: this.getVideoElementSnapshot(),
19922
+ });
19923
+ };
19924
+ // If metadata is already available (readyState >= HAVE_METADATA = 1),
19925
+ // the 'loadedmetadata' event will not fire again. Handle both cases.
19926
+ if (this.videoRef.readyState >= 1) {
19927
+ this.debugLog('video metadata already available, skipping event wait', this.getVideoElementSnapshot());
19928
+ cleanupTrackListeners();
19929
+ await finalizeStreamInitialization();
19930
+ detachVideoDiagnosticListeners();
19931
+ return;
19932
+ }
19933
+ return new Promise((resolve, reject) => {
19934
+ let settled = false;
19935
+ const cleanup = () => {
19936
+ this.videoRef.onloadedmetadata = null;
19937
+ this.videoRef.onerror = null;
19938
+ detachVideoDiagnosticListeners();
19939
+ };
19940
+ const timeoutId = setTimeout(() => {
19941
+ if (settled)
19942
+ return;
19943
+ settled = true;
19944
+ const diagnostics = captureDiagnostics();
19945
+ this.debugWarn(`initializeVideoStream() timeout after ${LOAD_METADATA_TIMEOUT_MS}ms`, {
19946
+ videoRef: this.getVideoElementSnapshot(),
19947
+ stream: this.getStreamSnapshot(stream),
19948
+ });
19949
+ console.error('[jaak-stamps] Video metadata timeout diagnostics (json):', JSON.stringify(diagnostics));
19950
+ cleanup();
19951
+ cleanupTrackListeners();
19952
+ reject(new Error(`Video metadata load timeout after ${LOAD_METADATA_TIMEOUT_MS}ms`));
19953
+ }, LOAD_METADATA_TIMEOUT_MS);
19954
+ this.videoRef.onloadedmetadata = async () => {
19955
+ if (settled)
19956
+ return;
19957
+ settled = true;
19958
+ clearTimeout(timeoutId);
19959
+ this.debugLog('initializeVideoStream() onloadedmetadata fired', {
19960
+ videoRef: this.getVideoElementSnapshot(),
19961
+ stream: this.getStreamSnapshot(stream),
19962
+ });
19963
+ cleanupTrackListeners();
19964
+ try {
19965
+ await finalizeStreamInitialization();
19966
+ cleanup();
19967
+ resolve();
19968
+ }
19969
+ catch (err) {
19970
+ cleanup();
19971
+ reject(err);
19972
+ }
19973
+ };
19974
+ this.videoRef.onerror = (event) => {
19975
+ if (settled)
19976
+ return;
19977
+ settled = true;
19978
+ clearTimeout(timeoutId);
19979
+ this.debugWarn('initializeVideoStream() video element emitted error', {
19980
+ event,
19981
+ videoRef: this.getVideoElementSnapshot(),
19982
+ stream: this.getStreamSnapshot(stream),
19983
+ });
19984
+ cleanup();
19985
+ cleanupTrackListeners();
19986
+ reject(new Error(`Video element error: ${event}`));
19987
+ };
19988
+ });
19672
19989
  }
19673
19990
  async detectFrame() {
19674
19991
  try {
@@ -19890,7 +20207,16 @@ const JaakStamps = class {
19890
20207
  isCapturing: false
19891
20208
  };
19892
20209
  const cameraInfo = this.cameraInfoWithAutofocus;
19893
- return (h("div", { key: '688ceafa324ab0d67de00440e6381710f3785f5a', class: "detector-container" }, !this.licenseValid && this.licenseError && (h("div", { key: 'f4eb75c9da36ce781535c477be56b16d7270dcf6', class: "license-error-container" }, h("div", { key: '712e3b2e048f22d62890ad8ca6db458a8400f87b', class: "license-error-card" }, h("svg", { key: 'e1e86cc112c183729b537e8b94b9f9409c4f7969', 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: '4f8376df61e8ad8105d84b767c663c24fcfb47af', 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: '45ca99e068518901a5d332cfdcb25b774b8e4159', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), h("circle", { key: '5f9561c5b3b1ca6bf8a9c0daeb92594f25e144ba', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), h("h2", { key: 'da86ee4ac849d76c4bbe19f135e5f8e0793a22f6', class: "license-error-title" }, "Licencia Requerida"), h("p", { key: 'ca3bc193e7145e2b68c82b56d92f6a07a4986469', class: "license-error-message" }, this.licenseError), h("p", { key: 'd802523e06804557a8df11c78de70317056db746', class: "license-error-help" }, "Contacte a soporte: ", h("a", { key: '9ace3ca5c198b95899a3128af4da3a46a7038421', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), h("div", { key: '07f7de4b3c21a0c30f39126e8afd73da323c42e5', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (h("div", { key: '2ef7e0747e644563b358667a328b0859e969ced2', class: "video-container" }, h("video", { key: 'fd4c30c9faa0029b145453a54dd1e4e72c99decc', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '08ae5cc6d6a643a33251cd03bb16e2e298ff8ea2', 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: {
20210
+ return (h("div", { key: '958fb0a94dcab5e15b2da9b2f6e1219d85e1f03a', class: "detector-container" }, !this.licenseValid && this.licenseError && (h("div", { key: 'b455ba5f14b5415d2b49c8ace3ead469cd2a7acc', class: "license-error-container" }, h("div", { key: '4c1e7f980319cf125b5186e26158c37a7a97842c', class: "license-error-card" }, h("svg", { key: '4c411ef193d03c543fe9298bc3aa077dcaf6b7ea', 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: '24f0eb292901ee9cef24afdc2161bc69f6a51cd0', 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: 'e5e61abf14d9422633d1c3de9efb7d1a909c941c', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), h("circle", { key: 'f5612a5748a26d33fbfa9a60ea084614f53197f9', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), h("h2", { key: '5ba51ab22b3dc341a5a59661a5f4f87d6dcc4f96', class: "license-error-title" }, "Licencia Requerida"), h("p", { key: 'd162830f9b888ff9d179abd4d532287c3edd2b44', class: "license-error-message" }, this.licenseError), h("p", { key: '8ac80117990849f03c4cac091a9642160b49c109', class: "license-error-help" }, "Contacte a soporte: ", h("a", { key: 'df4b871006f2d4e5f95be43b4a2c3699288d3773', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), h("div", { key: 'aa1aacb0dc56c76cce5d6bdac373f2e64d7b3f18', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (h("div", { key: '0a5a3ad11c511d0d8f1b33a4a2fff32aede47277', class: "video-container" }, h("video", { key: 'db9c667c035c27aec76625385bb7b1ec0624736e', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: {
20211
+ // Keep the element rendered (display: block) so the browser
20212
+ // loads stream metadata and fires 'loadedmetadata'. Hiding it
20213
+ // with display:none prevents metadata loading in Chrome and
20214
+ // causes initializeVideoStream to hang waiting for the event.
20215
+ // Use opacity + visibility to hide visually while keeping the
20216
+ // render context alive.
20217
+ opacity: captureState.isVideoActive ? '1' : '0',
20218
+ visibility: captureState.isVideoActive ? 'visible' : 'hidden',
20219
+ } }), h("div", { key: '424765f58b596d8459ae903245ee8e0717eaf14a', 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: {
19894
20220
  position: 'absolute',
19895
20221
  left: `${box.x}px`,
19896
20222
  top: `${box.y}px`,
@@ -19899,9 +20225,9 @@ const JaakStamps = class {
19899
20225
  border: '2px solid #32406C',
19900
20226
  pointerEvents: 'none',
19901
20227
  boxSizing: 'border-box'
19902
- } })))), this.isMaskReady && (h("div", { key: '8aed3362a1cba7d4f013221d0f03b74dcf481c9f', class: "overlay-mask" }, h("div", { key: 'f0436ced815a8a5bf640d3b475c6b3214af042ec', class: "card-outline" }, h("div", { key: 'e72e65b5824d791fcc129af00d00f0c11a4ef547', class: "side side-top" }), h("div", { key: '0f6a64d0b63d528b71268d5f8a0d7b462441c3b9', class: "side side-right" }), h("div", { key: 'a855aaeb78ed7b493390f04583fca9fd3f70e26e', class: "side side-bottom" }), h("div", { key: '6b1e6ac88329a096cf22c4f28e61db8cd06e9bbc', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'b3e66d548cb1ab9d602105f72d8e1bcfec54d33e', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'b27c8a1c3e4d3639d27a64e931f436ec8b67063b', class: "back-capture-section" }, h("div", { key: 'a16554331fc9eee781839b959a4c3b8835896b93', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: '32d16a0f2d01dc62566af7996d222f3427002af5', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: 'c58a90f250a0106774383fd7fdf64f3c2bddc31b', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: '4e71900b8792f7ea4f46964b1effa59e8c7c4a1e', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '3fc8bfaf8434457c004fa3176fc8d8d51f12ca2d', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
20228
+ } })))), this.isMaskReady && (h("div", { key: '26b11d2375ac441dbd8b5eaec4f5976df4d1f0aa', class: "overlay-mask" }, h("div", { key: '51d95dab401719ed84533a76e58ce00c12d4f72a', class: "card-outline" }, h("div", { key: 'd2b87cb68858e74340611a46ea7e3efc1691f46e', class: "side side-top" }), h("div", { key: '55ff7658fcc123535c9710133ef4d8973bca1d2e', class: "side side-right" }), h("div", { key: '0dfa4f296ff756afa2003eb4fb368d208128c47e', class: "side side-bottom" }), h("div", { key: '9aefe3fef283ee27cbe412d27a1a873cd871eb1a', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'ae93e17580fe8d6efa460857011ebf36d4b162b6', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'a9835585d26c8819ffb12e5a278d19c89d17ec6a', class: "back-capture-section" }, h("div", { key: '7563c10750eb649c337379bcd1966ebbe4c0a7be', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: '0c44faf4123197765b0bad30f5674ce7b1cc4f00', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: 'efed4645446e3ac5189dcc909998bda49771e61d', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: '7f21e533d151507cb8aefeb232e2e6924ec4a935', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '2634e6953b71e30b658dc632d853124f5ce5bb91', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
19903
20229
  ? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
19904
- : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: '9d2bd5f8e2d20758d9ff87b230639a67d8fdae41', class: "camera-controls" }, h("button", { key: '487ff8e5151bde715dd00bd7688b31ba623b4c7f', 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: 'eeee411b06c3715613cbb6cf0e93d255fcac1ea6', class: "camera-selector-dropdown" }, h("div", { key: '5a4995c2b7951a19575735c8e768b283798f8280', class: "camera-selector-header" }, h("span", { key: '4b6d72d4b56671ce8c3936ccb15a6aaa27ce220c' }, "Seleccionar C\u00E1mara"), h("button", { key: 'a7caae51ff55e5494cc55bacf5d261a8282a550b', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'c59e0105c938c60106c2764bb2793633115fdfe5', 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: '1b421328878d79031cf5565f2189e72ef5969fb7', class: "device-info" }, h("small", { key: '8eff3bcd2295ee817b164a53f9142d301c0b04f6' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'b655bc09a9054682f7a7d7b1bd169a11efac3c45', class: "manual-capture-section" }, h("button", { key: '73650786a96abb2e3883eb411d95aef4fb00821d', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: '9af39330393a1dc56dc7adf66d8d2000820ccc3d', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '619bdc1df901e2321842e9f51765e5f74939d043', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: 'f91616b49f53df94e19c440b04d9334111d059bb', class: "flip-animation" }, h("div", { key: 'da522b17c21022a12f8af69f82aac44d52bbaa71', class: "id-card-icon" }), h("div", { key: '29440e74bf938c11e2f743badf7f2144a986fd8a', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '181817d898e4c2430338884b71f7ab96356972ae', class: "success-animation" }, h("div", { key: '6cb28526b5b9f5aac12d8328552c96233eeb4a0c', class: "check-icon" }), h("div", { key: '20c9a81338d6752448e4bca4c608faa3070fb64a', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '549a6374d9491e212fd2d9fa4d240c6a348652ad', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: '7b077a21197447095a349fd625ca08eca2a9094c', class: "status-spinner" })), h("div", { key: 'fcff47edbac15b6cb5323efc946b7fa177b65658', class: "status-content" }, h("div", { key: 'a3dcdd467791c078cda33b8c75577c4cf7bb6468', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '4d7dd231afeeffb4dbab8a2833fdf79726326ff3', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '854702ca658986c6600abf612a687ad83488f6a0', class: "performance-monitor" }, h("div", { key: '19bd29ac89585dafa0dde90699099b6111e6bb3b', class: "performance-expanded" }, h("div", { key: '08760ca40d44165994ca40b077bef0b1becec629', class: "metrics-row" }, h("div", { key: '5d7cc885bfd45e2d9e48f89e94faad5716870a93', class: "metric-compact" }, h("span", { key: '4a0040ebb932f3d9b4b167b7e91abac925644815', class: "metric-label" }, "FPS"), h("span", { key: '31335bb6758ffb49a267d6eea55f3dab74d3fb20', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: 'c5ddca6673a720ccef6e1ffd431916840eb66f48', class: "metric-compact" }, h("span", { key: 'badf1f2858dfbf1faa4da3f575a7ba7aed19c190', class: "metric-label" }, "MEM"), h("span", { key: '206bf0afefeb7e4f8aec02667c8bb3b91eca2fd6', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: '0e12d3c961f7d4a24b860775702c735b046dfbb9', class: "metrics-row" }, h("div", { key: '23c16b7d5b55e2657aeef65d09968ab3279a7866', class: "metric-compact" }, h("span", { key: 'ad5f68534e549bf368e8da8857bb3eda707badcd', class: "metric-label" }, "INF"), h("span", { key: 'f53ed6bd2454f98b4a765f1af65e696ce82eea03', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: 'bbc9ac7dbe4bb335547cc1a9ee5101c27ab80e71', class: "metric-compact" }, h("span", { key: '8392c0a514a4dc25b60a5843ce9563031a9245d0', class: "metric-label" }, "FRAME"), h("span", { key: 'd3aaca5da2db9e31f5f58d09ef9460eca5cc331c', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: 'f294351ea0a26d7309441f68eca0c6fcc048d30e', class: "metrics-row" }, h("div", { key: '97c2f2854b2b799e47ace3449130c7e3952bb673', class: "metric-compact" }, h("span", { key: '17a9e44716640663162a7eafb3bd6471adb62d37', class: "metric-label" }, "DET"), h("span", { key: 'd301a6decf7c25e43aaea9828be7864866fd6cae', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '51d3ca5308396f8e712204c366ea0c4622122dad', class: "metric-compact" }, h("span", { key: '064c7fe006d64de181d9fd707c74ebee11b78519', class: "metric-label" }, "RATE"), h("span", { key: '467e9a5b59051d172134ceab926b69c172338826', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: 'ca4f45de99c4e305f872368b1a26983f4e22a368', class: "watermark" }, h("img", { key: 'b3854686a8b5eb959b5516100d4c792d2899db91', src: "https://static.jaak.ai/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
20230
+ : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'ed8cf74950d02b58d4c8628663ec692d964757f0', class: "camera-controls" }, h("button", { key: 'd309850ed774ac08e63e1eb1ea0019f7c80d3db6', 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: '4a70996d233bffbeac7badc52537d94453db30d3', class: "camera-selector-dropdown" }, h("div", { key: '7f893af0afeff55fe63e4971d0afc24516d2b6a6', class: "camera-selector-header" }, h("span", { key: 'd20382742b5ee5d90f678988d0d2c1c964f615d6' }, "Seleccionar C\u00E1mara"), h("button", { key: '1542d189db50740dd10e2ea843f7c5dccc5e24f2', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'e7907a23b4c7571c455f906333ccbd8e4172d3c9', 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: '8615ca9b81f57bbf5d52d40fd827b79a637f5e4f', class: "device-info" }, h("small", { key: '6f07c1bfb1a2b3824ccdfae4ebca11b0fa0297fe' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'c1c18723517003f2bcb9f68c527a13c4e6f30095', class: "manual-capture-section" }, h("button", { key: '94d21c348697cd28ecb44a5144e1e105f10e377c', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: '74333b317328ad70da763e5d127635f3b6dc13d1', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '6761b16e393c5d496c5fde729b6b36580cfede0c', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '7556dddec2de2c134f9b09fbd38569366c35da48', class: "flip-animation" }, h("div", { key: 'baa3cd8993ef761ebfb94ccda6d66896959f32ee', class: "id-card-icon" }), h("div", { key: '3c5027ada509290b9abbf599849dbd19e50113af', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '1826a908ea94637428d9e800668d9ee02f0f03de', class: "success-animation" }, h("div", { key: '60d8e894ceed0c5198edb67a1e3e0fa24b9aaa3b', class: "check-icon" }), h("div", { key: '106d6ccec79f64b94273baeb8984f23e71987076', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '804e4fe62de056dca22964283282e32336f8eb00', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: '108d6cab9eb7826cbe396806652a6b096ce0736d', class: "status-spinner" })), h("div", { key: '4abe0717c6b66b2bf44eb2da513fb6c22af31725', class: "status-content" }, h("div", { key: '77fb79d89df1f9e25c3c4962235b0605c7b6237f', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '2b24b09eabbbbbedd1270ebbf72f32f19ee063cb', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '7c6bf594cdb26334bfe62ee09d860b19399b4fd2', class: "performance-monitor" }, h("div", { key: '06f2b94e8a08e8afe94a2947d928a4c3c1ec260f', class: "performance-expanded" }, h("div", { key: 'c9302538e10e53e81a5685226c89a293ffd1608b', class: "metrics-row" }, h("div", { key: '7499bee1d362bf9910b401c2f85961847facc9f8', class: "metric-compact" }, h("span", { key: 'f005aab118350af46520ece3615544976b5d533f', class: "metric-label" }, "FPS"), h("span", { key: '69102a7df1fdc559883f807a8d26ae9268e56b01', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '0a63031beb60eeeb19cd50637f506661cdb1da16', class: "metric-compact" }, h("span", { key: '0231014ed6f077d780252c3b822a269148675d2f', class: "metric-label" }, "MEM"), h("span", { key: '859eda6914fdab077635f983fd4ca01daaf47ce7', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: '102218bc7cf2d29c3c8ef7f91febf924ecb418a3', class: "metrics-row" }, h("div", { key: '205e50b3dbc43c541b76c21ef8e19a3defe065ce', class: "metric-compact" }, h("span", { key: '42eace007731c4642040e33f3e20462d7e150494', class: "metric-label" }, "INF"), h("span", { key: 'ff2d169c660011b24fa3340479d91befc9c2d06c', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: 'ec3ec57e442b3aefb38acf774873b0b181731523', class: "metric-compact" }, h("span", { key: '27d6d74dcdffbdafb4382c40b60f032b20dc5ade', class: "metric-label" }, "FRAME"), h("span", { key: 'e55795508f97a27c0b03736de2e5960560970378', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '60e80821ed57f1a724409e26a232fa2792886011', class: "metrics-row" }, h("div", { key: '7deb1504fb3705affaab105782ed7107d6e1a501', class: "metric-compact" }, h("span", { key: '0658ce3204ce120557caa248505def48a8a205dd', class: "metric-label" }, "DET"), h("span", { key: '6b14fafc3903912380edda27e5024e1221917db7', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: 'ec602c3b4d7d8ab0ffbf165d98e8b2e7d7d0b0ec', class: "metric-compact" }, h("span", { key: '9615ae1d383d383f116d2953f05ddb252336f7be', class: "metric-label" }, "RATE"), h("span", { key: 'eca7277e9185b9ff4232e556e707a3f1ce80365f', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '3b6b9368797965d5795c9752d2b4a08a9934b441', class: "watermark" }, h("img", { key: 'b40ffaeb6f88d1a744bffeb64ac11d4f19be6220', src: "https://static.jaak.ai/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
19905
20231
  }
19906
20232
  // Utility methods
19907
20233
  updateDetectionBoxes(boxes) {