@jaak.ai/stamps 2.5.3 → 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.
@@ -18781,6 +18781,18 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
18781
18781
  processedFramesCount = 0; // Contador total de frames procesados
18782
18782
  hasAutoSwitchedToManual = false;
18783
18783
  _manualModeLoggedOnce = false;
18784
+ VIDEO_DIAGNOSTIC_EVENTS = [
18785
+ 'loadstart',
18786
+ 'loadedmetadata',
18787
+ 'loadeddata',
18788
+ 'canplay',
18789
+ 'playing',
18790
+ 'pause',
18791
+ 'stalled',
18792
+ 'suspend',
18793
+ 'abort',
18794
+ 'emptied',
18795
+ ];
18784
18796
  // Canvas pool for optimized screenshot capture
18785
18797
  canvasPool = [];
18786
18798
  MAX_CANVAS_POOL_SIZE = 3;
@@ -19509,6 +19521,130 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19509
19521
  memoryMB: deviceMemory ? deviceMemory * 1024 : null
19510
19522
  };
19511
19523
  }
19524
+ debugLog(message, details) {
19525
+ if (!this.debug) {
19526
+ return;
19527
+ }
19528
+ if (typeof details === 'undefined') {
19529
+ console.log(`[jaak-stamps][diag] ${message}`);
19530
+ return;
19531
+ }
19532
+ console.log(`[jaak-stamps][diag] ${message}`, details);
19533
+ }
19534
+ debugWarn(message, details) {
19535
+ if (!this.debug) {
19536
+ return;
19537
+ }
19538
+ if (typeof details === 'undefined') {
19539
+ console.warn(`[jaak-stamps][diag] ${message}`);
19540
+ return;
19541
+ }
19542
+ console.warn(`[jaak-stamps][diag] ${message}`, details);
19543
+ }
19544
+ summarizeId(id) {
19545
+ if (!id) {
19546
+ return null;
19547
+ }
19548
+ return id.length <= 8 ? id : `${id.slice(0, 8)}...`;
19549
+ }
19550
+ getCameraDevicesSnapshot() {
19551
+ return this.cameraService.getAvailableCameras().map(camera => ({
19552
+ label: camera.label || '(sin label)',
19553
+ deviceId: this.summarizeId(camera.deviceId),
19554
+ groupId: this.summarizeId(camera.groupId),
19555
+ kind: camera.kind,
19556
+ }));
19557
+ }
19558
+ sanitizeTrackSettings(settings) {
19559
+ if (!settings) {
19560
+ return null;
19561
+ }
19562
+ return {
19563
+ ...settings,
19564
+ deviceId: this.summarizeId(settings.deviceId),
19565
+ groupId: this.summarizeId(settings.groupId),
19566
+ };
19567
+ }
19568
+ sanitizeTrackConstraints(track) {
19569
+ if (!track) {
19570
+ return null;
19571
+ }
19572
+ const constraints = track.getConstraints ? track.getConstraints() : {};
19573
+ const sanitizedConstraints = { ...constraints };
19574
+ if (typeof sanitizedConstraints.deviceId === 'string') {
19575
+ sanitizedConstraints.deviceId = this.summarizeId(sanitizedConstraints.deviceId);
19576
+ }
19577
+ return sanitizedConstraints;
19578
+ }
19579
+ getStreamSnapshot(stream) {
19580
+ if (!stream) {
19581
+ return { hasStream: false };
19582
+ }
19583
+ const videoTrack = stream.getVideoTracks()[0];
19584
+ if (!videoTrack) {
19585
+ return {
19586
+ hasStream: true,
19587
+ streamActive: stream.active,
19588
+ trackCount: stream.getTracks().length,
19589
+ hasVideoTrack: false,
19590
+ };
19591
+ }
19592
+ return {
19593
+ hasStream: true,
19594
+ streamActive: stream.active,
19595
+ trackCount: stream.getTracks().length,
19596
+ trackLabel: videoTrack.label || '(sin label)',
19597
+ trackEnabled: videoTrack.enabled,
19598
+ trackMuted: videoTrack.muted,
19599
+ trackReadyState: videoTrack.readyState,
19600
+ settings: this.sanitizeTrackSettings(videoTrack.getSettings ? videoTrack.getSettings() : undefined),
19601
+ constraints: this.sanitizeTrackConstraints(videoTrack),
19602
+ };
19603
+ }
19604
+ getVideoElementSnapshot() {
19605
+ if (!this.videoRef) {
19606
+ return { hasVideoRef: false };
19607
+ }
19608
+ const computedStyle = this.el.ownerDocument?.defaultView?.getComputedStyle(this.videoRef);
19609
+ return {
19610
+ hasVideoRef: true,
19611
+ isConnected: this.videoRef.isConnected,
19612
+ readyState: this.videoRef.readyState,
19613
+ networkState: this.videoRef.networkState,
19614
+ paused: this.videoRef.paused,
19615
+ muted: this.videoRef.muted,
19616
+ autoplay: this.videoRef.autoplay,
19617
+ playsInline: this.videoRef.playsInline,
19618
+ currentTime: Number.isFinite(this.videoRef.currentTime)
19619
+ ? Number(this.videoRef.currentTime.toFixed(3))
19620
+ : this.videoRef.currentTime,
19621
+ videoWidth: this.videoRef.videoWidth,
19622
+ videoHeight: this.videoRef.videoHeight,
19623
+ clientWidth: this.videoRef.clientWidth,
19624
+ clientHeight: this.videoRef.clientHeight,
19625
+ hasSrcObject: !!this.videoRef.srcObject,
19626
+ display: computedStyle?.display ?? 'unknown',
19627
+ visibility: computedStyle?.visibility ?? 'unknown',
19628
+ };
19629
+ }
19630
+ attachVideoDiagnosticListeners() {
19631
+ if (!this.debug || !this.videoRef) {
19632
+ return () => undefined;
19633
+ }
19634
+ const video = this.videoRef;
19635
+ const listeners = this.VIDEO_DIAGNOSTIC_EVENTS.map(eventName => {
19636
+ const handler = () => {
19637
+ this.debugLog(`video event "${eventName}"`, this.getVideoElementSnapshot());
19638
+ };
19639
+ video.addEventListener(eventName, handler);
19640
+ return { eventName, handler };
19641
+ });
19642
+ return () => {
19643
+ listeners.forEach(({ eventName, handler }) => {
19644
+ video.removeEventListener(eventName, handler);
19645
+ });
19646
+ };
19647
+ }
19512
19648
  // DETECTION METHODS
19513
19649
  async startDetection() {
19514
19650
  try {
@@ -19595,12 +19731,19 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19595
19731
  this.updateStatus('Configurando cámara...', 'Buscando dispositivos disponibles', 'loading');
19596
19732
  try {
19597
19733
  await this.cameraService.enumerateDevices();
19734
+ this.debugLog('step 2/5 enumerateDevices()', {
19735
+ cameras: this.getCameraDevicesSnapshot(),
19736
+ selectedCameraId: this.summarizeId(this.cameraService.getSelectedCameraId() || undefined),
19737
+ });
19598
19738
  }
19599
19739
  catch (enumerateError) {
19600
19740
  throw new Error(`Error al enumerar dispositivos: ${enumerateError.message}`);
19601
19741
  }
19602
19742
  try {
19603
19743
  await this.updateCameraInfoWithAutofocus();
19744
+ this.debugLog('step 2/5 updateCameraInfoWithAutofocus()', {
19745
+ cameraInfo: this.cameraInfoWithAutofocus,
19746
+ });
19604
19747
  }
19605
19748
  catch (cameraInfoError) {
19606
19749
  throw new Error(`Error al actualizar información de cámara: ${cameraInfoError.message}`);
@@ -19610,6 +19753,10 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19610
19753
  let stream;
19611
19754
  try {
19612
19755
  stream = await this.cameraService.setupCamera();
19756
+ this.debugLog('step 3/5 setupCamera() resolved', {
19757
+ stream: this.getStreamSnapshot(stream),
19758
+ videoRef: this.getVideoElementSnapshot(),
19759
+ });
19613
19760
  }
19614
19761
  catch (setupError) {
19615
19762
  throw new Error(`Error al configurar cámara: ${setupError.message}`);
@@ -19622,7 +19769,15 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19622
19769
  this.updateStatus('Captura activa', 'Posicione su documento y use el botón para capturar', 'active');
19623
19770
  }
19624
19771
  try {
19772
+ this.debugLog('step 4/5 initializeVideoStream() start', {
19773
+ stream: this.getStreamSnapshot(stream),
19774
+ videoRef: this.getVideoElementSnapshot(),
19775
+ });
19625
19776
  await this.initializeVideoStream(stream);
19777
+ this.debugLog('step 4/5 initializeVideoStream() completed', {
19778
+ stream: this.getStreamSnapshot(stream),
19779
+ videoRef: this.getVideoElementSnapshot(),
19780
+ });
19626
19781
  }
19627
19782
  catch (videoError) {
19628
19783
  throw new Error(`Error al inicializar video: ${videoError.message}`);
@@ -19640,9 +19795,19 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19640
19795
  if (!this.useDocumentDetector) {
19641
19796
  this.showManualCaptureButton = true;
19642
19797
  }
19798
+ this.debugLog('step 5/5 capture loop ready', {
19799
+ videoRef: this.getVideoElementSnapshot(),
19800
+ stream: this.getStreamSnapshot(this.videoStream),
19801
+ useDocumentDetector: this.useDocumentDetector,
19802
+ });
19643
19803
  this.detectFrame();
19644
19804
  }
19645
19805
  catch (err) {
19806
+ this.debugWarn('startDetection() failed', {
19807
+ error: err instanceof Error ? err.message : String(err),
19808
+ videoRef: this.getVideoElementSnapshot(),
19809
+ stream: this.getStreamSnapshot(this.videoStream),
19810
+ });
19646
19811
  console.error('[jaak-stamps] Error al preparar captura:', err);
19647
19812
  this.updateStatus('Error al iniciar', 'No se pudo preparar la captura', 'error');
19648
19813
  this.stateManager.updateCaptureState({ isLoading: false });
@@ -19652,11 +19817,93 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19652
19817
  if (!this.videoRef) {
19653
19818
  throw new Error('Video element not available');
19654
19819
  }
19820
+ const detachVideoDiagnosticListeners = this.attachVideoDiagnosticListeners();
19821
+ this.debugLog('initializeVideoStream() pre-assign', {
19822
+ stream: this.getStreamSnapshot(stream),
19823
+ videoRef: this.getVideoElementSnapshot(),
19824
+ });
19655
19825
  this.videoRef.srcObject = stream;
19656
19826
  this.videoStream = stream;
19827
+ this.debugLog('initializeVideoStream() post-srcObject assignment', {
19828
+ stream: this.getStreamSnapshot(stream),
19829
+ videoRef: this.getVideoElementSnapshot(),
19830
+ });
19657
19831
  const isRear = this.cameraService.isRearCamera(stream);
19658
19832
  this.shouldMirrorVideo = !isRear;
19659
19833
  const LOAD_METADATA_TIMEOUT_MS = 10000;
19834
+ // Diagnostic instrumentation: when the timeout fires we need enough
19835
+ // context to distinguish between "OS muted the track", "permission
19836
+ // revoked mid-flight", "device never produced frames" and other modes
19837
+ // that all surface as the same generic timeout error.
19838
+ const track = stream.getVideoTracks()[0];
19839
+ const waitStart = performance.now();
19840
+ const trackEvents = [];
19841
+ const recordTrackEvent = (event) => {
19842
+ trackEvents.push({
19843
+ at: Math.round(performance.now() - waitStart),
19844
+ event,
19845
+ state: track?.readyState,
19846
+ });
19847
+ };
19848
+ const onTrackMute = () => recordTrackEvent('mute');
19849
+ const onTrackUnmute = () => recordTrackEvent('unmute');
19850
+ const onTrackEnded = () => recordTrackEvent('ended');
19851
+ if (track) {
19852
+ track.addEventListener('mute', onTrackMute);
19853
+ track.addEventListener('unmute', onTrackUnmute);
19854
+ track.addEventListener('ended', onTrackEnded);
19855
+ }
19856
+ const cleanupTrackListeners = () => {
19857
+ if (!track)
19858
+ return;
19859
+ track.removeEventListener('mute', onTrackMute);
19860
+ track.removeEventListener('unmute', onTrackUnmute);
19861
+ track.removeEventListener('ended', onTrackEnded);
19862
+ };
19863
+ const captureDiagnostics = () => {
19864
+ const settings = track?.getSettings?.();
19865
+ const computed = this.videoRef ? getComputedStyle(this.videoRef) : null;
19866
+ return {
19867
+ reason: 'VIDEO_METADATA_TIMEOUT',
19868
+ waitedMs: Math.round(performance.now() - waitStart),
19869
+ stream: {
19870
+ videoTrackCount: stream.getVideoTracks().length,
19871
+ audioTrackCount: stream.getAudioTracks().length,
19872
+ },
19873
+ track: track ? {
19874
+ readyState: track.readyState,
19875
+ muted: track.muted,
19876
+ enabled: track.enabled,
19877
+ label: track.label,
19878
+ kind: track.kind,
19879
+ settings: settings ? {
19880
+ width: settings.width,
19881
+ height: settings.height,
19882
+ frameRate: settings.frameRate,
19883
+ deviceId: settings.deviceId,
19884
+ facingMode: settings.facingMode,
19885
+ } : null,
19886
+ } : null,
19887
+ video: this.videoRef ? {
19888
+ readyState: this.videoRef.readyState,
19889
+ networkState: this.videoRef.networkState,
19890
+ error: this.videoRef.error ? { code: this.videoRef.error.code, message: this.videoRef.error.message } : null,
19891
+ paused: this.videoRef.paused,
19892
+ offsetWidth: this.videoRef.offsetWidth,
19893
+ offsetHeight: this.videoRef.offsetHeight,
19894
+ videoWidth: this.videoRef.videoWidth,
19895
+ videoHeight: this.videoRef.videoHeight,
19896
+ display: computed?.display,
19897
+ visibility: computed?.visibility,
19898
+ } : null,
19899
+ document: {
19900
+ visibilityState: document.visibilityState,
19901
+ hasFocus: document.hasFocus(),
19902
+ },
19903
+ trackEvents,
19904
+ userAgent: navigator.userAgent,
19905
+ };
19906
+ };
19660
19907
  const finalizeStreamInitialization = async () => {
19661
19908
  try {
19662
19909
  await this.videoRef.play();
@@ -19671,24 +19918,39 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19671
19918
  const rect = container.getBoundingClientRect();
19672
19919
  this.updateMaskDimensions(rect);
19673
19920
  }
19921
+ this.debugLog('initializeVideoStream() finalized after play()', {
19922
+ stream: this.getStreamSnapshot(stream),
19923
+ videoRef: this.getVideoElementSnapshot(),
19924
+ });
19674
19925
  };
19675
19926
  // If metadata is already available (readyState >= HAVE_METADATA = 1),
19676
19927
  // the 'loadedmetadata' event will not fire again. Handle both cases.
19677
19928
  if (this.videoRef.readyState >= 1) {
19678
- if (this.debug) {
19679
- console.log('[JAAK-DEBUG] Video metadata already available (readyState:', this.videoRef.readyState, '), skipping event wait');
19680
- }
19929
+ this.debugLog('video metadata already available, skipping event wait', this.getVideoElementSnapshot());
19930
+ cleanupTrackListeners();
19681
19931
  await finalizeStreamInitialization();
19932
+ detachVideoDiagnosticListeners();
19682
19933
  return;
19683
19934
  }
19684
19935
  return new Promise((resolve, reject) => {
19685
19936
  let settled = false;
19937
+ const cleanup = () => {
19938
+ this.videoRef.onloadedmetadata = null;
19939
+ this.videoRef.onerror = null;
19940
+ detachVideoDiagnosticListeners();
19941
+ };
19686
19942
  const timeoutId = setTimeout(() => {
19687
19943
  if (settled)
19688
19944
  return;
19689
19945
  settled = true;
19690
- this.videoRef.onloadedmetadata = null;
19691
- this.videoRef.onerror = null;
19946
+ const diagnostics = captureDiagnostics();
19947
+ this.debugWarn(`initializeVideoStream() timeout after ${LOAD_METADATA_TIMEOUT_MS}ms`, {
19948
+ videoRef: this.getVideoElementSnapshot(),
19949
+ stream: this.getStreamSnapshot(stream),
19950
+ });
19951
+ console.error('[jaak-stamps] Video metadata timeout diagnostics (json):', JSON.stringify(diagnostics));
19952
+ cleanup();
19953
+ cleanupTrackListeners();
19692
19954
  reject(new Error(`Video metadata load timeout after ${LOAD_METADATA_TIMEOUT_MS}ms`));
19693
19955
  }, LOAD_METADATA_TIMEOUT_MS);
19694
19956
  this.videoRef.onloadedmetadata = async () => {
@@ -19696,13 +19958,18 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19696
19958
  return;
19697
19959
  settled = true;
19698
19960
  clearTimeout(timeoutId);
19699
- this.videoRef.onloadedmetadata = null;
19700
- this.videoRef.onerror = null;
19961
+ this.debugLog('initializeVideoStream() onloadedmetadata fired', {
19962
+ videoRef: this.getVideoElementSnapshot(),
19963
+ stream: this.getStreamSnapshot(stream),
19964
+ });
19965
+ cleanupTrackListeners();
19701
19966
  try {
19702
19967
  await finalizeStreamInitialization();
19968
+ cleanup();
19703
19969
  resolve();
19704
19970
  }
19705
19971
  catch (err) {
19972
+ cleanup();
19706
19973
  reject(err);
19707
19974
  }
19708
19975
  };
@@ -19711,8 +19978,13 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19711
19978
  return;
19712
19979
  settled = true;
19713
19980
  clearTimeout(timeoutId);
19714
- this.videoRef.onloadedmetadata = null;
19715
- this.videoRef.onerror = null;
19981
+ this.debugWarn('initializeVideoStream() video element emitted error', {
19982
+ event,
19983
+ videoRef: this.getVideoElementSnapshot(),
19984
+ stream: this.getStreamSnapshot(stream),
19985
+ });
19986
+ cleanup();
19987
+ cleanupTrackListeners();
19716
19988
  reject(new Error(`Video element error: ${event}`));
19717
19989
  };
19718
19990
  });
@@ -19937,7 +20209,16 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19937
20209
  isCapturing: false
19938
20210
  };
19939
20211
  const cameraInfo = this.cameraInfoWithAutofocus;
19940
- return (h("div", { key: 'd9e8fef8a096429937860396347148e6bdd06340', class: "detector-container" }, !this.licenseValid && this.licenseError && (h("div", { key: '7eb2f885adab60a4b8b1667bf0a362510d537794', class: "license-error-container" }, h("div", { key: 'af1079677131e33d5cc7698d4da03b2ba012c4bf', class: "license-error-card" }, h("svg", { key: 'f968e7c76c710dd8a4b6b407a026346d524740fe', 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: '39f44307ef8a1ef1fb786dc925fb753f647aa94c', 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: '64fe021fadc616f46e69b35a7950ad503f55028a', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), h("circle", { key: 'aa86c48652cce218d24f78f49c0f32f8485184ca', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), h("h2", { key: 'b49877aa248f90ef207cc26a294f3f7f4f5f8e03', class: "license-error-title" }, "Licencia Requerida"), h("p", { key: 'fe929456590ae3ee78804613072df9c873732f99', class: "license-error-message" }, this.licenseError), h("p", { key: '1177a85cdd98a3dfd120043ce58256a33095d720', class: "license-error-help" }, "Contacte a soporte: ", h("a", { key: 'd5fe21ac8932ab88907e59775d459597cbd3b51f', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), h("div", { key: '3b764654f555dae41581f5d855548b8f3382e0f2', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (h("div", { key: '4051657a840db456841fdea943409f75c4c72985', class: "video-container" }, h("video", { key: 'aa7fb4da7f721a511f4e8bbd9d2727ff2a3c350f', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: 'a9f5839bd5f7543f5e3e37701c95c3528d233161', 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: {
20212
+ 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: {
20213
+ // Keep the element rendered (display: block) so the browser
20214
+ // loads stream metadata and fires 'loadedmetadata'. Hiding it
20215
+ // with display:none prevents metadata loading in Chrome and
20216
+ // causes initializeVideoStream to hang waiting for the event.
20217
+ // Use opacity + visibility to hide visually while keeping the
20218
+ // render context alive.
20219
+ opacity: captureState.isVideoActive ? '1' : '0',
20220
+ visibility: captureState.isVideoActive ? 'visible' : 'hidden',
20221
+ } }), 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: {
19941
20222
  position: 'absolute',
19942
20223
  left: `${box.x}px`,
19943
20224
  top: `${box.y}px`,
@@ -19946,9 +20227,9 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
19946
20227
  border: '2px solid #32406C',
19947
20228
  pointerEvents: 'none',
19948
20229
  boxSizing: 'border-box'
19949
- } })))), this.isMaskReady && (h("div", { key: 'ad737b47a608ba2d6e43a8c41aee15ea00012966', class: "overlay-mask" }, h("div", { key: '70c5b2591dd75742eae22e444eab4d4368fc659d', class: "card-outline" }, h("div", { key: '0962f587354f4b300f6f6a1f5b9652441c3aeb5c', class: "side side-top" }), h("div", { key: '955d5346898f560e1e3fc854c4c339074613116c', class: "side side-right" }), h("div", { key: '0388ccc214b045e392c07e6e8fffe2c8d67d3582', class: "side side-bottom" }), h("div", { key: '718600bfad1eff4298628402190ffb34b7988afa', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '70603563d303912248bf60e1d39e06d78b3adbaf', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'a3639b10d52b29da6f0490356f7cdae789d62f88', class: "back-capture-section" }, h("div", { key: 'dd430526d6e096396d10367fd216b1c6568ce19b', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: '04b0afd7e6adc890287749add773910445ff5255', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: '69022991921cbc04ab20dee2148bb95d5dd371f8', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: 'dd698341642e875e8f252746db747ca77b2f37b0', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: 'c33706bf76eeb1ca401ea3df042e858e23d3a929', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
20230
+ } })))), 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
19950
20231
  ? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
19951
- : 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'f9c95646d564518b75d7511ef69049e82760c687', class: "camera-controls" }, h("button", { key: 'ff21667ee09360e13e0b7fa190eb58d4e9ab2955', 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: '1f5d7ced9311037a22402797075862c66b541201', class: "camera-selector-dropdown" }, h("div", { key: '38ccad6dfb46613519efac337a68ad8ed68ca585', class: "camera-selector-header" }, h("span", { key: 'efd67097b98bf82455703888a0294bba18084b58' }, "Seleccionar C\u00E1mara"), h("button", { key: 'efea962578d1ff9f4dc76e40f98b6763ab32fabd', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'dc7fcc35ea20505547b9980f0793aab21635815f', 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: '450b9819604b9490c17759eb53468832abdf239c', class: "device-info" }, h("small", { key: '9423cb4f0f6eb767b9a9bf86412dcc74c40e3c9b' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'fc02b6ac27b7d239d07ea5df46136b5941a09020', class: "manual-capture-section" }, h("button", { key: '0e8bc7d6b2c44b66f62083bb9682880109ce1b50', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: 'd4067363057c004774322ae6ac4c6aac8ac4c1a7', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '79a88a6cf21fb0d8c2883c44fe181dc34773dae6', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '2e8f2d1441ea6ae7e62d6cb22fb8afb25308ae5b', class: "flip-animation" }, h("div", { key: '449282679041e4ad1b1f48e26185b1ab1ab3be60', class: "id-card-icon" }), h("div", { key: 'eac0b9728eefcde854ddb1675811f91ee3161176', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '521094652be1010ebb740ef3278649bc0077fbfa', class: "success-animation" }, h("div", { key: 'e9b425d4c039f7267ecb7e3005506f07706f9054', class: "check-icon" }), h("div", { key: '4859b32d3219e325afa326651f21ce3663d9c0b8', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '8fff23c16b531dda94a087a3ef3fe4ef0b6a51e4', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'e7139e242d3be20012efe25d808990fc9631492f', class: "status-spinner" })), h("div", { key: '935075ef8c1a7321e445578cdf918471e0f6e01c', class: "status-content" }, h("div", { key: '0f4910657f11df16d6cec635fdeb3864888ed55c', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: 'c362a69bed2503ecb4456b183876a5ea0645cc71', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '04d2a4d664742ca110f562fa599b118fa5e7a282', class: "performance-monitor" }, h("div", { key: '30c37005f87500d487e23cb87dd66973ce30bcfa', class: "performance-expanded" }, h("div", { key: '647c87a140f7ea8b39348402e0355b3b15ac9616', class: "metrics-row" }, h("div", { key: '99f886b025473adcd69b42aca61f7aa8158d13cf', class: "metric-compact" }, h("span", { key: '69215c74430c502fa51402e1fcf46d31b89b34f2', class: "metric-label" }, "FPS"), h("span", { key: '27283246a143119a4a8f0e63a8ee335f76868c46', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '6843f5f79d3e54643c6515e509364b4fa3fc032f', class: "metric-compact" }, h("span", { key: '20e83d94bf0a76e89a47b3d682e5c5c27ee94792', class: "metric-label" }, "MEM"), h("span", { key: '68922415fd8ba5ebf797f52026ecd0cf2abf861e', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'be6bb0a65bfc5bd16d6948f347756732918f80d1', class: "metrics-row" }, h("div", { key: 'c07a3723b79743697230a11267a6b2c8a847a86b', class: "metric-compact" }, h("span", { key: '2f2c75418ed31ba22f80112f6c02bdc32a1bc7e3', class: "metric-label" }, "INF"), h("span", { key: '788aa1a4220f0150c5ce77127d75be64104591c1', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '23bdf32e7ee8533c3327b271bd0cec93551f7c8e', class: "metric-compact" }, h("span", { key: '1d63525671ef0e99072d472f6bbe45919694ca98', class: "metric-label" }, "FRAME"), h("span", { key: '834f075061da75860a481142defddcd3973a2641', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '2767844f849c3a8217dce6d44180b5db604284d9', class: "metrics-row" }, h("div", { key: '78e4ae2297c867c7036186bb9871800b57e6cd50', class: "metric-compact" }, h("span", { key: '9fd42d1a4c18ead68ee81bc72dddb98dcd09952c', class: "metric-label" }, "DET"), h("span", { key: '0e3c0bbf718b21c3c20ae2e68c6f1e8f5dea0624', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '41be4df95b8745706e9b98d28cefb758e9e6b65f', class: "metric-compact" }, h("span", { key: '520b7e3d4841c0865c3643c5db33f0a762e550e7', class: "metric-label" }, "RATE"), h("span", { key: 'fe56fdd018002bce4e0efc5059cbc6562edee17f', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '3c7b83cf7bfd1f42198edd1029f03b7c68f7766f', class: "watermark" }, h("img", { key: '5684517b58bafeffdbe6533c4dcc3ef36bec0b6c', src: "https://static.jaak.ai/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
20232
+ : '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" }))))));
19952
20233
  }
19953
20234
  // Utility methods
19954
20235
  updateDetectionBoxes(boxes) {