@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.
- package/dist/cjs/jaak-stamps.cjs.entry.js +349 -23
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/collection/components/my-component/my-component.js +349 -23
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/components/jaak-stamps.js +349 -23
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps.entry.js +349 -23
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/{p-49ed15ce.entry.js → p-0f4d77b3.entry.js} +3 -3
- package/dist/jaak-stamps-webcomponent/p-0f4d77b3.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +10 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-49ed15ce.entry.js.map +0 -1
|
@@ -18781,6 +18781,18 @@ const JaakStamps = class {
|
|
|
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 = class {
|
|
|
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 = class {
|
|
|
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 = class {
|
|
|
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 = class {
|
|
|
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,37 +19795,199 @@ const JaakStamps = class {
|
|
|
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 });
|
|
19649
19814
|
}
|
|
19650
19815
|
}
|
|
19651
19816
|
async initializeVideoStream(stream) {
|
|
19652
|
-
if (this.videoRef) {
|
|
19653
|
-
this.videoRef.srcObject = stream;
|
|
19654
|
-
this.videoStream = stream;
|
|
19655
|
-
const isRear = this.cameraService.isRearCamera(stream);
|
|
19656
|
-
this.shouldMirrorVideo = !isRear;
|
|
19657
|
-
return new Promise((resolve) => {
|
|
19658
|
-
this.videoRef.onloadedmetadata = async () => {
|
|
19659
|
-
await this.videoRef.play();
|
|
19660
|
-
this.stateManager.updateCaptureState({ isVideoActive: true });
|
|
19661
|
-
// Recalculate mask dimensions when new camera stream loads
|
|
19662
|
-
if (this.detectionContainer) {
|
|
19663
|
-
const container = this.detectionContainer.parentElement;
|
|
19664
|
-
const rect = container.getBoundingClientRect();
|
|
19665
|
-
this.updateMaskDimensions(rect);
|
|
19666
|
-
}
|
|
19667
|
-
resolve();
|
|
19668
|
-
};
|
|
19669
|
-
});
|
|
19670
|
-
}
|
|
19671
|
-
else {
|
|
19817
|
+
if (!this.videoRef) {
|
|
19672
19818
|
throw new Error('Video element not available');
|
|
19673
19819
|
}
|
|
19820
|
+
const detachVideoDiagnosticListeners = this.attachVideoDiagnosticListeners();
|
|
19821
|
+
this.debugLog('initializeVideoStream() pre-assign', {
|
|
19822
|
+
stream: this.getStreamSnapshot(stream),
|
|
19823
|
+
videoRef: this.getVideoElementSnapshot(),
|
|
19824
|
+
});
|
|
19825
|
+
this.videoRef.srcObject = stream;
|
|
19826
|
+
this.videoStream = stream;
|
|
19827
|
+
this.debugLog('initializeVideoStream() post-srcObject assignment', {
|
|
19828
|
+
stream: this.getStreamSnapshot(stream),
|
|
19829
|
+
videoRef: this.getVideoElementSnapshot(),
|
|
19830
|
+
});
|
|
19831
|
+
const isRear = this.cameraService.isRearCamera(stream);
|
|
19832
|
+
this.shouldMirrorVideo = !isRear;
|
|
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
|
+
};
|
|
19907
|
+
const finalizeStreamInitialization = async () => {
|
|
19908
|
+
try {
|
|
19909
|
+
await this.videoRef.play();
|
|
19910
|
+
}
|
|
19911
|
+
catch (playError) {
|
|
19912
|
+
console.error('[jaak-stamps] video.play() failed (likely autoplay policy):', playError);
|
|
19913
|
+
throw playError;
|
|
19914
|
+
}
|
|
19915
|
+
this.stateManager.updateCaptureState({ isVideoActive: true });
|
|
19916
|
+
if (this.detectionContainer) {
|
|
19917
|
+
const container = this.detectionContainer.parentElement;
|
|
19918
|
+
const rect = container.getBoundingClientRect();
|
|
19919
|
+
this.updateMaskDimensions(rect);
|
|
19920
|
+
}
|
|
19921
|
+
this.debugLog('initializeVideoStream() finalized after play()', {
|
|
19922
|
+
stream: this.getStreamSnapshot(stream),
|
|
19923
|
+
videoRef: this.getVideoElementSnapshot(),
|
|
19924
|
+
});
|
|
19925
|
+
};
|
|
19926
|
+
// If metadata is already available (readyState >= HAVE_METADATA = 1),
|
|
19927
|
+
// the 'loadedmetadata' event will not fire again. Handle both cases.
|
|
19928
|
+
if (this.videoRef.readyState >= 1) {
|
|
19929
|
+
this.debugLog('video metadata already available, skipping event wait', this.getVideoElementSnapshot());
|
|
19930
|
+
cleanupTrackListeners();
|
|
19931
|
+
await finalizeStreamInitialization();
|
|
19932
|
+
detachVideoDiagnosticListeners();
|
|
19933
|
+
return;
|
|
19934
|
+
}
|
|
19935
|
+
return new Promise((resolve, reject) => {
|
|
19936
|
+
let settled = false;
|
|
19937
|
+
const cleanup = () => {
|
|
19938
|
+
this.videoRef.onloadedmetadata = null;
|
|
19939
|
+
this.videoRef.onerror = null;
|
|
19940
|
+
detachVideoDiagnosticListeners();
|
|
19941
|
+
};
|
|
19942
|
+
const timeoutId = setTimeout(() => {
|
|
19943
|
+
if (settled)
|
|
19944
|
+
return;
|
|
19945
|
+
settled = true;
|
|
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();
|
|
19954
|
+
reject(new Error(`Video metadata load timeout after ${LOAD_METADATA_TIMEOUT_MS}ms`));
|
|
19955
|
+
}, LOAD_METADATA_TIMEOUT_MS);
|
|
19956
|
+
this.videoRef.onloadedmetadata = async () => {
|
|
19957
|
+
if (settled)
|
|
19958
|
+
return;
|
|
19959
|
+
settled = true;
|
|
19960
|
+
clearTimeout(timeoutId);
|
|
19961
|
+
this.debugLog('initializeVideoStream() onloadedmetadata fired', {
|
|
19962
|
+
videoRef: this.getVideoElementSnapshot(),
|
|
19963
|
+
stream: this.getStreamSnapshot(stream),
|
|
19964
|
+
});
|
|
19965
|
+
cleanupTrackListeners();
|
|
19966
|
+
try {
|
|
19967
|
+
await finalizeStreamInitialization();
|
|
19968
|
+
cleanup();
|
|
19969
|
+
resolve();
|
|
19970
|
+
}
|
|
19971
|
+
catch (err) {
|
|
19972
|
+
cleanup();
|
|
19973
|
+
reject(err);
|
|
19974
|
+
}
|
|
19975
|
+
};
|
|
19976
|
+
this.videoRef.onerror = (event) => {
|
|
19977
|
+
if (settled)
|
|
19978
|
+
return;
|
|
19979
|
+
settled = true;
|
|
19980
|
+
clearTimeout(timeoutId);
|
|
19981
|
+
this.debugWarn('initializeVideoStream() video element emitted error', {
|
|
19982
|
+
event,
|
|
19983
|
+
videoRef: this.getVideoElementSnapshot(),
|
|
19984
|
+
stream: this.getStreamSnapshot(stream),
|
|
19985
|
+
});
|
|
19986
|
+
cleanup();
|
|
19987
|
+
cleanupTrackListeners();
|
|
19988
|
+
reject(new Error(`Video element error: ${event}`));
|
|
19989
|
+
};
|
|
19990
|
+
});
|
|
19674
19991
|
}
|
|
19675
19992
|
async detectFrame() {
|
|
19676
19993
|
try {
|
|
@@ -19892,7 +20209,16 @@ const JaakStamps = class {
|
|
|
19892
20209
|
isCapturing: false
|
|
19893
20210
|
};
|
|
19894
20211
|
const cameraInfo = this.cameraInfoWithAutofocus;
|
|
19895
|
-
return (index.h("div", { key: '
|
|
20212
|
+
return (index.h("div", { key: '958fb0a94dcab5e15b2da9b2f6e1219d85e1f03a', class: "detector-container" }, !this.licenseValid && this.licenseError && (index.h("div", { key: 'b455ba5f14b5415d2b49c8ace3ead469cd2a7acc', class: "license-error-container" }, index.h("div", { key: '4c1e7f980319cf125b5186e26158c37a7a97842c', class: "license-error-card" }, index.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" }, index.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" }), index.h("path", { key: 'e5e61abf14d9422633d1c3de9efb7d1a909c941c', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), index.h("circle", { key: 'f5612a5748a26d33fbfa9a60ea084614f53197f9', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), index.h("h2", { key: '5ba51ab22b3dc341a5a59661a5f4f87d6dcc4f96', class: "license-error-title" }, "Licencia Requerida"), index.h("p", { key: 'd162830f9b888ff9d179abd4d532287c3edd2b44', class: "license-error-message" }, this.licenseError), index.h("p", { key: '8ac80117990849f03c4cac091a9642160b49c109', class: "license-error-help" }, "Contacte a soporte: ", index.h("a", { key: 'df4b871006f2d4e5f95be43b4a2c3699288d3773', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), index.h("div", { key: 'aa1aacb0dc56c76cce5d6bdac373f2e64d7b3f18', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (index.h("div", { key: '0a5a3ad11c511d0d8f1b33a4a2fff32aede47277', class: "video-container" }, index.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
|
+
} }), index.h("div", { key: '424765f58b596d8459ae903245ee8e0717eaf14a', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index$1) => (index.h("div", { key: index$1, class: "detection-box", style: {
|
|
19896
20222
|
position: 'absolute',
|
|
19897
20223
|
left: `${box.x}px`,
|
|
19898
20224
|
top: `${box.y}px`,
|
|
@@ -19901,9 +20227,9 @@ const JaakStamps = class {
|
|
|
19901
20227
|
border: '2px solid #32406C',
|
|
19902
20228
|
pointerEvents: 'none',
|
|
19903
20229
|
boxSizing: 'border-box'
|
|
19904
|
-
} })))), this.isMaskReady && (index.h("div", { key: '
|
|
20230
|
+
} })))), this.isMaskReady && (index.h("div", { key: '26b11d2375ac441dbd8b5eaec4f5976df4d1f0aa', class: "overlay-mask" }, index.h("div", { key: '51d95dab401719ed84533a76e58ce00c12d4f72a', class: "card-outline" }, index.h("div", { key: 'd2b87cb68858e74340611a46ea7e3efc1691f46e', class: "side side-top" }), index.h("div", { key: '55ff7658fcc123535c9710133ef4d8973bca1d2e', class: "side side-right" }), index.h("div", { key: '0dfa4f296ff756afa2003eb4fb368d208128c47e', class: "side side-bottom" }), index.h("div", { key: '9aefe3fef283ee27cbe412d27a1a873cd871eb1a', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: 'ae93e17580fe8d6efa460857011ebf36d4b162b6', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: 'a9835585d26c8819ffb12e5a278d19c89d17ec6a', class: "back-capture-section" }, index.h("div", { key: '7563c10750eb649c337379bcd1966ebbe4c0a7be', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (index.h("button", { key: '0c44faf4123197765b0bad30f5674ce7b1cc4f00', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (index.h("span", { key: 'efed4645446e3ac5189dcc909998bda49771e61d', class: "button-spinner" })), "Capturar Reverso")), index.h("button", { key: '7f21e533d151507cb8aefeb232e2e6924ec4a935', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (index.h("span", { key: '2634e6953b71e30b658dc632d853124f5ce5bb91', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
|
|
19905
20231
|
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
19906
|
-
: 'Saltar reverso')))), captureState.isVideoActive && (index.h("div", { key: '
|
|
20232
|
+
: 'Saltar reverso')))), captureState.isVideoActive && (index.h("div", { key: 'ed8cf74950d02b58d4c8628663ec692d964757f0', class: "camera-controls" }, index.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 ? (index.h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (index.h("div", { key: '4a70996d233bffbeac7badc52537d94453db30d3', class: "camera-selector-dropdown" }, index.h("div", { key: '7f893af0afeff55fe63e4971d0afc24516d2b6a6', class: "camera-selector-header" }, index.h("span", { key: 'd20382742b5ee5d90f678988d0d2c1c964f615d6' }, "Seleccionar C\u00E1mara"), index.h("button", { key: '1542d189db50740dd10e2ea843f7c5dccc5e24f2', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), index.h("div", { key: 'e7907a23b4c7571c455f906333ccbd8e4172d3c9', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (index.h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, index.h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (index.h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (index.h("span", { class: "selected-indicator" }, "\u2713")))))), index.h("div", { key: '8615ca9b81f57bbf5d52d40fd827b79a637f5e4f', class: "device-info" }, index.h("small", { key: '6f07c1bfb1a2b3824ccdfae4ebca11b0fa0297fe' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: 'c1c18723517003f2bcb9f68c527a13c4e6f30095', class: "manual-capture-section" }, index.h("button", { key: '94d21c348697cd28ecb44a5144e1e105f10e377c', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (index.h("span", { key: '74333b317328ad70da763e5d127635f3b6dc13d1', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (index.h("div", { key: '6761b16e393c5d496c5fde729b6b36580cfede0c', class: "capture-animation" })), captureState.showFlipAnimation && (index.h("div", { key: '7556dddec2de2c134f9b09fbd38569366c35da48', class: "flip-animation" }, index.h("div", { key: 'baa3cd8993ef761ebfb94ccda6d66896959f32ee', class: "id-card-icon" }), index.h("div", { key: '3c5027ada509290b9abbf599849dbd19e50113af', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (index.h("div", { key: '1826a908ea94637428d9e800668d9ee02f0f03de', class: "success-animation" }, index.h("div", { key: '60d8e894ceed0c5198edb67a1e3e0fa24b9aaa3b', class: "check-icon" }), index.h("div", { key: '106d6ccec79f64b94273baeb8984f23e71987076', class: "success-text" }, "\u00A1Proceso completado!"))), index.h("div", { key: '804e4fe62de056dca22964283282e32336f8eb00', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (index.h("div", { key: '108d6cab9eb7826cbe396806652a6b096ce0736d', class: "status-spinner" })), index.h("div", { key: '4abe0717c6b66b2bf44eb2da513fb6c22af31725', class: "status-content" }, index.h("div", { key: '77fb79d89df1f9e25c3c4962235b0605c7b6237f', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (index.h("div", { key: '2b24b09eabbbbbedd1270ebbf72f32f19ee063cb', class: "status-description" }, this.currentStatus.description)))), this.debug && (index.h("div", { key: '7c6bf594cdb26334bfe62ee09d860b19399b4fd2', class: "performance-monitor" }, index.h("div", { key: '06f2b94e8a08e8afe94a2947d928a4c3c1ec260f', class: "performance-expanded" }, index.h("div", { key: 'c9302538e10e53e81a5685226c89a293ffd1608b', class: "metrics-row" }, index.h("div", { key: '7499bee1d362bf9910b401c2f85961847facc9f8', class: "metric-compact" }, index.h("span", { key: 'f005aab118350af46520ece3615544976b5d533f', class: "metric-label" }, "FPS"), index.h("span", { key: '69102a7df1fdc559883f807a8d26ae9268e56b01', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), index.h("div", { key: '0a63031beb60eeeb19cd50637f506661cdb1da16', class: "metric-compact" }, index.h("span", { key: '0231014ed6f077d780252c3b822a269148675d2f', class: "metric-label" }, "MEM"), index.h("span", { key: '859eda6914fdab077635f983fd4ca01daaf47ce7', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), index.h("div", { key: '102218bc7cf2d29c3c8ef7f91febf924ecb418a3', class: "metrics-row" }, index.h("div", { key: '205e50b3dbc43c541b76c21ef8e19a3defe065ce', class: "metric-compact" }, index.h("span", { key: '42eace007731c4642040e33f3e20462d7e150494', class: "metric-label" }, "INF"), index.h("span", { key: 'ff2d169c660011b24fa3340479d91befc9c2d06c', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), index.h("div", { key: 'ec3ec57e442b3aefb38acf774873b0b181731523', class: "metric-compact" }, index.h("span", { key: '27d6d74dcdffbdafb4382c40b60f032b20dc5ade', class: "metric-label" }, "FRAME"), index.h("span", { key: 'e55795508f97a27c0b03736de2e5960560970378', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), index.h("div", { key: '60e80821ed57f1a724409e26a232fa2792886011', class: "metrics-row" }, index.h("div", { key: '7deb1504fb3705affaab105782ed7107d6e1a501', class: "metric-compact" }, index.h("span", { key: '0658ce3204ce120557caa248505def48a8a205dd', class: "metric-label" }, "DET"), index.h("span", { key: '6b14fafc3903912380edda27e5024e1221917db7', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), index.h("div", { key: 'ec602c3b4d7d8ab0ffbf165d98e8b2e7d7d0b0ec', class: "metric-compact" }, index.h("span", { key: '9615ae1d383d383f116d2953f05ddb252336f7be', class: "metric-label" }, "RATE"), index.h("span", { key: 'eca7277e9185b9ff4232e556e707a3f1ce80365f', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), index.h("div", { key: '3b6b9368797965d5795c9752d2b4a08a9934b441', class: "watermark" }, index.h("img", { key: 'b40ffaeb6f88d1a744bffeb64ac11d4f19be6220', src: "https://static.jaak.ai/commons/powered-by-jaak.png", alt: "Powered by Jaak" }))))));
|
|
19907
20233
|
}
|
|
19908
20234
|
// Utility methods
|
|
19909
20235
|
updateDetectionBoxes(boxes) {
|