@jaak.ai/stamps 2.5.7 → 2.5.8-dev.2
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/{index-D6NBn_qu.js → index-BcFBOmM6.js} +30 -4
- package/dist/cjs/index-BcFBOmM6.js.map +1 -0
- package/dist/cjs/jaak-stamps-webcomponent.cjs.js +2 -2
- package/dist/cjs/jaak-stamps.cjs.entry.js +264 -75
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/collection/collection-manifest.json +1 -1
- package/dist/collection/components/{my-component/my-component.js → jaak-stamps/jaak-stamps.js} +209 -37
- package/dist/collection/components/jaak-stamps/jaak-stamps.js.map +1 -0
- package/dist/collection/components/jaak-stamps/watermark-fallback.js.map +1 -0
- package/dist/collection/services/DetectionService.js +60 -38
- package/dist/collection/services/DetectionService.js.map +1 -1
- package/dist/components/index.js +20 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/jaak-stamps.js +266 -74
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/{index-BCfAsrzL.js → index-Cb0ILUvS.js} +30 -4
- package/dist/esm/index-Cb0ILUvS.js.map +1 -0
- package/dist/esm/jaak-stamps-webcomponent.js +3 -3
- package/dist/esm/jaak-stamps.entry.js +264 -75
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/esm/loader.js +3 -3
- 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-Cb0ILUvS.js +3 -0
- package/dist/jaak-stamps-webcomponent/p-Cb0ILUvS.js.map +1 -0
- package/dist/jaak-stamps-webcomponent/{p-63c2c085.entry.js → p-b4834625.entry.js} +3 -3
- package/dist/jaak-stamps-webcomponent/p-b4834625.entry.js.map +1 -0
- package/dist/types/components/{my-component/my-component.d.ts → jaak-stamps/jaak-stamps.d.ts} +12 -0
- package/dist/types/services/DetectionService.d.ts +5 -4
- package/package.json +4 -4
- package/dist/cjs/index-D6NBn_qu.js.map +0 -1
- package/dist/collection/components/my-component/my-component.js.map +0 -1
- package/dist/collection/components/my-component/watermark-fallback.js.map +0 -1
- package/dist/collection/utils/utils.js +0 -4
- package/dist/collection/utils/utils.js.map +0 -1
- package/dist/esm/index-BCfAsrzL.js.map +0 -1
- package/dist/jaak-stamps-webcomponent/p-63c2c085.entry.js.map +0 -1
- package/dist/jaak-stamps-webcomponent/p-BCfAsrzL.js +0 -3
- package/dist/jaak-stamps-webcomponent/p-BCfAsrzL.js.map +0 -1
- package/dist/types/utils/utils.d.ts +0 -1
- /package/dist/collection/components/{my-component/my-component.css → jaak-stamps/jaak-stamps.css} +0 -0
- /package/dist/collection/components/{my-component → jaak-stamps}/watermark-fallback.js +0 -0
- /package/dist/types/components/{my-component → jaak-stamps}/watermark-fallback.d.ts +0 -0
|
@@ -796,15 +796,6 @@ class DetectionService {
|
|
|
796
796
|
INPUT_SIZE = 320;
|
|
797
797
|
CONFIDENCE_THRESHOLD = 0.6;
|
|
798
798
|
useFloat16 = true;
|
|
799
|
-
// Hoisted views for float32->float16 bit-twiddling. A fresh ArrayBuffer
|
|
800
|
-
// per call was costing ~614K allocations per frame.
|
|
801
|
-
_f32View = new Float32Array(1);
|
|
802
|
-
_u32View = new Uint32Array(this._f32View.buffer);
|
|
803
|
-
// Pre-allocated tensor buffers reused across frames. Same shape every time
|
|
804
|
-
// (3 * INPUT_SIZE * INPUT_SIZE), and runInference is awaited before the next
|
|
805
|
-
// preprocess runs, so reuse is safe.
|
|
806
|
-
_tensorF32 = new Float32Array(3 * 320 * 320);
|
|
807
|
-
_tensorF16 = new Uint16Array(3 * 320 * 320);
|
|
808
799
|
// Canvas pool for optimization
|
|
809
800
|
preprocessCanvas;
|
|
810
801
|
preprocessCtx;
|
|
@@ -831,7 +822,7 @@ class DetectionService {
|
|
|
831
822
|
try {
|
|
832
823
|
const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
|
|
833
824
|
try {
|
|
834
|
-
this.session = await
|
|
825
|
+
this.session = await this.createSession(this.MODEL_PATH, sessionOptions);
|
|
835
826
|
this.detectFloat16Support();
|
|
836
827
|
}
|
|
837
828
|
catch (error) {
|
|
@@ -846,7 +837,7 @@ class DetectionService {
|
|
|
846
837
|
if (isFloat16Error) {
|
|
847
838
|
this.useFloat16 = false;
|
|
848
839
|
try {
|
|
849
|
-
this.session = await
|
|
840
|
+
this.session = await this.createSession(this.MODEL_PATH_FP32, sessionOptions);
|
|
850
841
|
}
|
|
851
842
|
catch (fp32Error) {
|
|
852
843
|
// Intentar con opciones minimas de WASM
|
|
@@ -855,7 +846,7 @@ class DetectionService {
|
|
|
855
846
|
graphOptimizationLevel: 'all',
|
|
856
847
|
logSeverityLevel: this.debug ? 2 : 4,
|
|
857
848
|
};
|
|
858
|
-
this.session = await
|
|
849
|
+
this.session = await this.createSession(this.MODEL_PATH_FP32, wasmOptions);
|
|
859
850
|
}
|
|
860
851
|
}
|
|
861
852
|
else if (isMemoryError) {
|
|
@@ -874,7 +865,7 @@ class DetectionService {
|
|
|
874
865
|
};
|
|
875
866
|
this.useFloat16 = false;
|
|
876
867
|
try {
|
|
877
|
-
this.session = await
|
|
868
|
+
this.session = await this.createSession(this.MODEL_PATH_FP32, fallbackOptions);
|
|
878
869
|
}
|
|
879
870
|
catch (fallbackError) {
|
|
880
871
|
throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);
|
|
@@ -915,7 +906,7 @@ class DetectionService {
|
|
|
915
906
|
// Load model
|
|
916
907
|
const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
|
|
917
908
|
try {
|
|
918
|
-
this.mobileNetSession = await
|
|
909
|
+
this.mobileNetSession = await this.createSession(this.MOBILENET_MODEL_PATH, sessionOptions);
|
|
919
910
|
}
|
|
920
911
|
catch (error) {
|
|
921
912
|
// Múltiples tipos de errores de memoria que pueden ocurrir
|
|
@@ -939,7 +930,7 @@ class DetectionService {
|
|
|
939
930
|
sessionLogVerbosityLevel: 0,
|
|
940
931
|
};
|
|
941
932
|
try {
|
|
942
|
-
this.mobileNetSession = await
|
|
933
|
+
this.mobileNetSession = await this.createSession(this.MOBILENET_MODEL_PATH, fallbackOptions);
|
|
943
934
|
}
|
|
944
935
|
catch (fallbackError) {
|
|
945
936
|
throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);
|
|
@@ -965,31 +956,25 @@ class DetectionService {
|
|
|
965
956
|
if (!this.preprocessCanvas || !this.preprocessCtx) {
|
|
966
957
|
this.initializeCanvasPool();
|
|
967
958
|
}
|
|
968
|
-
|
|
969
|
-
this.preprocessCtx.
|
|
970
|
-
this.preprocessCtx.
|
|
971
|
-
const
|
|
959
|
+
this.preprocessCtx.clearRect(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);
|
|
960
|
+
this.preprocessCtx.drawImage(video, 0, 0, this.INPUT_SIZE, this.INPUT_SIZE);
|
|
961
|
+
const imageData = this.preprocessCtx.getImageData(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);
|
|
962
|
+
const [R, G, B] = [[], [], []];
|
|
972
963
|
const { data } = imageData;
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
964
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
965
|
+
R.push(data[i] / 255);
|
|
966
|
+
G.push(data[i + 1] / 255);
|
|
967
|
+
B.push(data[i + 2] / 255);
|
|
968
|
+
}
|
|
969
|
+
const transposedData = new Float32Array(R.concat(G, B));
|
|
977
970
|
if (this.useFloat16) {
|
|
978
|
-
const
|
|
979
|
-
for (let i = 0
|
|
980
|
-
|
|
981
|
-
out[gOffset + p] = this.float32ToFloat16(data[i + 1] * inv255);
|
|
982
|
-
out[bOffset + p] = this.float32ToFloat16(data[i + 2] * inv255);
|
|
971
|
+
const float16Data = new Uint16Array(transposedData.length);
|
|
972
|
+
for (let i = 0; i < transposedData.length; i++) {
|
|
973
|
+
float16Data[i] = this.float32ToFloat16(transposedData[i]);
|
|
983
974
|
}
|
|
984
|
-
return new window.ort.Tensor("float16",
|
|
985
|
-
}
|
|
986
|
-
const out = this._tensorF32;
|
|
987
|
-
for (let i = 0, p = 0; i < data.length; i += 4, p++) {
|
|
988
|
-
out[p] = data[i] * inv255;
|
|
989
|
-
out[gOffset + p] = data[i + 1] * inv255;
|
|
990
|
-
out[bOffset + p] = data[i + 2] * inv255;
|
|
975
|
+
return new window.ort.Tensor("float16", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);
|
|
991
976
|
}
|
|
992
|
-
return new window.ort.Tensor("float32",
|
|
977
|
+
return new window.ort.Tensor("float32", transposedData, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);
|
|
993
978
|
}
|
|
994
979
|
async runInference(inputTensor) {
|
|
995
980
|
if (!this.useDocumentDetector) {
|
|
@@ -1137,6 +1122,41 @@ class DetectionService {
|
|
|
1137
1122
|
areAllSidesAligned(alignment) {
|
|
1138
1123
|
return alignment.top && alignment.right && alignment.bottom && alignment.left;
|
|
1139
1124
|
}
|
|
1125
|
+
// Reference counter so concurrent sessions share one filter and the last
|
|
1126
|
+
// one to finish restores the original console.warn.
|
|
1127
|
+
static _ortWarnActiveCount = 0;
|
|
1128
|
+
static _originalWarn = null;
|
|
1129
|
+
static _acquireWarnFilter() {
|
|
1130
|
+
if (DetectionService._ortWarnActiveCount === 0) {
|
|
1131
|
+
DetectionService._originalWarn = console.warn;
|
|
1132
|
+
console.warn = (...args) => {
|
|
1133
|
+
const msg = typeof args[0] === 'string' ? args[0] : '';
|
|
1134
|
+
if (!msg.includes('removing requested execution provider')) {
|
|
1135
|
+
DetectionService._originalWarn.apply(console, args);
|
|
1136
|
+
}
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
DetectionService._ortWarnActiveCount++;
|
|
1140
|
+
}
|
|
1141
|
+
static _releaseWarnFilter() {
|
|
1142
|
+
DetectionService._ortWarnActiveCount--;
|
|
1143
|
+
if (DetectionService._ortWarnActiveCount === 0 && DetectionService._originalWarn) {
|
|
1144
|
+
console.warn = DetectionService._originalWarn;
|
|
1145
|
+
DetectionService._originalWarn = null;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
async createSession(modelPath, options) {
|
|
1149
|
+
// Keep the filter active for the full await: ORT may emit
|
|
1150
|
+
// "removing requested execution provider" during async resolution,
|
|
1151
|
+
// not only in the synchronous preamble of create().
|
|
1152
|
+
DetectionService._acquireWarnFilter();
|
|
1153
|
+
try {
|
|
1154
|
+
return await window.ort.InferenceSession.create(modelPath, options);
|
|
1155
|
+
}
|
|
1156
|
+
finally {
|
|
1157
|
+
DetectionService._releaseWarnFilter();
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1140
1160
|
cleanup() {
|
|
1141
1161
|
this.cleanupCanvasPool();
|
|
1142
1162
|
if (this.session) {
|
|
@@ -1181,8 +1201,10 @@ class DetectionService {
|
|
|
1181
1201
|
}
|
|
1182
1202
|
}
|
|
1183
1203
|
float32ToFloat16(value) {
|
|
1184
|
-
|
|
1185
|
-
const
|
|
1204
|
+
const buffer = new ArrayBuffer(4);
|
|
1205
|
+
const view = new DataView(buffer);
|
|
1206
|
+
view.setFloat32(0, value, true);
|
|
1207
|
+
const f = view.getUint32(0, true);
|
|
1186
1208
|
const sign = (f >> 31) & 0x1;
|
|
1187
1209
|
const exp = (f >> 23) & 0xFF;
|
|
1188
1210
|
const frac = f & 0x7FFFFF;
|
|
@@ -18645,7 +18667,7 @@ class LicenseValidationService {
|
|
|
18645
18667
|
}
|
|
18646
18668
|
}
|
|
18647
18669
|
|
|
18648
|
-
const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background-color:#000;border:none;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}video::-webkit-media-controls{display:none !important}video::-webkit-media-controls-panel{display:none !important}video::-webkit-media-controls-play-button{display:none !important}video::-webkit-media-controls-start-playback-button{display:none !important}video::-webkit-media-controls-enclosure{display:none !important}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled,.capture-button.primary-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}.capture-button:disabled,.capture-button.primary-button:disabled,.skip-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.skip-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(0, 0, 0, 0.2);border-top:2px solid #333333;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-right:8px;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}.manual-capture-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.license-error-container{display:flex;align-items:center;justify-content:center;padding:40px 20px;height:100%;width:100%;background:#f5f7fa;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif}.license-error-card{background:#ffffff;border-radius:8px;box-shadow:0 2px 12px rgba(0, 0, 0, 0.1);max-width:480px;width:100%;padding:48px 32px;text-align:center}.license-error-icon{color:#dc3545;margin-bottom:24px}.license-error-title{color:#2c3e50;font-size:24px;font-weight:600;margin:0 0 16px 0}.license-error-message{color:#495057;font-size:16px;line-height:1.6;margin:0 0 24px 0}.license-error-help{color:#6c757d;font-size:14px;margin:0 0 32px 0}.license-error-help a{color:#007bff;text-decoration:none;font-weight:500}.license-error-help a:hover{text-decoration:underline}.license-error-footer{color:#adb5bd;font-size:12px;font-weight:500;padding-top:24px;border-top:1px solid #e9ecef}@media (max-width: 640px){.license-error-card{padding:32px 24px}.license-error-title{font-size:20px}.license-error-message{font-size:14px}}";
|
|
18670
|
+
const jaakStampsCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background-color:#000;border:none;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}video::-webkit-media-controls{display:none !important}video::-webkit-media-controls-panel{display:none !important}video::-webkit-media-controls-play-button{display:none !important}video::-webkit-media-controls-start-playback-button{display:none !important}video::-webkit-media-controls-enclosure{display:none !important}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled,.capture-button.primary-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}.capture-button:disabled,.capture-button.primary-button:disabled,.skip-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.skip-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(0, 0, 0, 0.2);border-top:2px solid #333333;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-right:8px;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}.manual-capture-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.license-error-container{display:flex;align-items:center;justify-content:center;padding:40px 20px;height:100%;width:100%;background:#f5f7fa;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif}.license-error-card{background:#ffffff;border-radius:8px;box-shadow:0 2px 12px rgba(0, 0, 0, 0.1);max-width:480px;width:100%;padding:48px 32px;text-align:center}.license-error-icon{color:#dc3545;margin-bottom:24px}.license-error-title{color:#2c3e50;font-size:24px;font-weight:600;margin:0 0 16px 0}.license-error-message{color:#495057;font-size:16px;line-height:1.6;margin:0 0 24px 0}.license-error-help{color:#6c757d;font-size:14px;margin:0 0 32px 0}.license-error-help a{color:#007bff;text-decoration:none;font-weight:500}.license-error-help a:hover{text-decoration:underline}.license-error-footer{color:#adb5bd;font-size:12px;font-weight:500;padding-top:24px;border-top:1px solid #e9ecef}@media (max-width: 640px){.license-error-card{padding:32px 24px}.license-error-title{font-size:20px}.license-error-message{font-size:14px}}";
|
|
18649
18671
|
|
|
18650
18672
|
const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H {
|
|
18651
18673
|
constructor() {
|
|
@@ -18677,7 +18699,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
18677
18699
|
propagateTraceHeaderCorsUrls; // Comma-separated URLs or regex patterns
|
|
18678
18700
|
metricsExportIntervalMillis = 60000; // Export metrics every 60 seconds
|
|
18679
18701
|
license; // License key for validation
|
|
18680
|
-
licenseEnvironment = 'prod';
|
|
18702
|
+
licenseEnvironment = 'prod';
|
|
18681
18703
|
traceId; // Optional trace ID for tracking
|
|
18682
18704
|
appId = 'jaak-stamps-web'; // Application ID for license validation
|
|
18683
18705
|
captureCompleted;
|
|
@@ -18725,6 +18747,10 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
18725
18747
|
licenseValid = true; // License validation status
|
|
18726
18748
|
licenseError = null; // License validation error message
|
|
18727
18749
|
classificationDisabled = false; // Classification disabled at runtime due to errors
|
|
18750
|
+
_initialized = false;
|
|
18751
|
+
_initializing = false;
|
|
18752
|
+
_pendingEnvironmentRetry = false;
|
|
18753
|
+
_pendingInit = null;
|
|
18728
18754
|
// Services
|
|
18729
18755
|
licenseValidationService = null;
|
|
18730
18756
|
serviceContainer;
|
|
@@ -18793,46 +18819,124 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
18793
18819
|
// Canvas pool for optimized screenshot capture
|
|
18794
18820
|
canvasPool = [];
|
|
18795
18821
|
MAX_CANVAS_POOL_SIZE = 3;
|
|
18822
|
+
// Readiness gate for startCapture(). The host may call startCapture() before the
|
|
18823
|
+
// component finishes loading its resources (ONNX Runtime + WASM/models from the CDN).
|
|
18824
|
+
// On slow devices/networks this race made startCapture() abort with "El componente
|
|
18825
|
+
// está cargando recursos", leaving the screen black (TO-807). Instead of aborting we
|
|
18826
|
+
// wait for initialization to settle and retry. `initializationSettled` flips once
|
|
18827
|
+
// finalizeInitialization() has run; pending waiters are released via these callbacks.
|
|
18828
|
+
initializationSettled = false;
|
|
18829
|
+
initializationWaiters = [];
|
|
18830
|
+
// Max time startCapture() waits for a still-initializing component before giving up.
|
|
18831
|
+
// Sized for slow Android/network asset downloads; if resources never load (CDN down,
|
|
18832
|
+
// 404, CORS) the timeout fires and startCapture() returns the original error.
|
|
18833
|
+
START_CAPTURE_READY_TIMEOUT_MS = 15000;
|
|
18796
18834
|
async componentWillLoad() {
|
|
18835
|
+
// @Watch handlers fire synchronously when Angular sets properties, which happens
|
|
18836
|
+
// BEFORE componentWillLoad (Stencil schedules componentWillLoad as a microtask after
|
|
18837
|
+
// connectedCallback, while Angular sets props synchronously in that same call stack).
|
|
18838
|
+
// @Watch('license') defers init to a macrotask so @Watch('licenseEnvironment') fires
|
|
18839
|
+
// first. By the time we resume here, init may already be in progress.
|
|
18840
|
+
await new Promise(resolve => setTimeout(resolve, 50));
|
|
18797
18841
|
if (this.debug) {
|
|
18798
|
-
console.log('[JAAK-DEBUG] componentWillLoad() - Props
|
|
18842
|
+
console.log('[JAAK-DEBUG] componentWillLoad() - Props after yield:');
|
|
18843
|
+
console.log('[JAAK-DEBUG] license:', this.license ? this.license.substring(0, 8) + '...' : 'EMPTY');
|
|
18844
|
+
console.log('[JAAK-DEBUG] licenseEnvironment:', this.licenseEnvironment);
|
|
18845
|
+
console.log('[JAAK-DEBUG] _initializing:', this._initializing);
|
|
18846
|
+
console.log('[JAAK-DEBUG] _initialized:', this._initialized);
|
|
18799
18847
|
console.log('[JAAK-DEBUG] useDocumentDetector:', this.useDocumentDetector, '(type:', typeof this.useDocumentDetector, ')');
|
|
18800
18848
|
console.log('[JAAK-DEBUG] useDocumentClassification:', this.useDocumentClassification);
|
|
18801
18849
|
console.log('[JAAK-DEBUG] debug:', this.debug);
|
|
18802
|
-
console.log('[JAAK-DEBUG] license:', this.license ? this.license.substring(0, 8) + '...' : 'EMPTY');
|
|
18803
|
-
console.log('[JAAK-DEBUG] licenseEnvironment:', this.licenseEnvironment);
|
|
18804
18850
|
console.log('[JAAK-DEBUG] alignmentTolerance:', this.alignmentTolerance);
|
|
18805
18851
|
console.log('[JAAK-DEBUG] maskSize:', this.maskSize);
|
|
18806
18852
|
console.log('[JAAK-DEBUG] captureDelay:', this.captureDelay);
|
|
18807
18853
|
console.log('[JAAK-DEBUG] preferredCamera:', this.preferredCamera);
|
|
18808
18854
|
console.log('[JAAK-DEBUG] appId:', this.appId);
|
|
18809
18855
|
}
|
|
18810
|
-
|
|
18811
|
-
|
|
18812
|
-
|
|
18813
|
-
|
|
18814
|
-
|
|
18815
|
-
|
|
18816
|
-
}
|
|
18817
|
-
this.updateStatus('Validando licencia...', 'Verificando autorización de uso', 'initializing');
|
|
18818
|
-
await this.validateLicense();
|
|
18819
|
-
// If license validation failed, stop initialization
|
|
18820
|
-
if (!this.licenseValid) {
|
|
18821
|
-
if (this.debug) {
|
|
18822
|
-
console.error('[JAAK-DEBUG] License validation FAILED. Stopping initialization.');
|
|
18856
|
+
if (!this.license) {
|
|
18857
|
+
if (!this._initialized && !this._initializing) {
|
|
18858
|
+
// No license and init not started — show blocking error UI
|
|
18859
|
+
this.licenseValid = false;
|
|
18860
|
+
this.licenseError = 'Se requiere una licencia para continuar. Por favor, proporcione una licencia usando el atributo "license".';
|
|
18861
|
+
this.updateStatus('Licencia requerida', 'Proporcione una licencia para continuar', 'error');
|
|
18823
18862
|
}
|
|
18824
|
-
return;
|
|
18825
18863
|
}
|
|
18826
|
-
if (this.
|
|
18827
|
-
|
|
18864
|
+
else if (!this._initialized && !this._initializing) {
|
|
18865
|
+
// License present but init hasn't started yet (no @Watch fired) — set initial status
|
|
18866
|
+
// so the first render already shows it without a redundant state change in componentDidLoad
|
|
18867
|
+
this.updateStatus('Validando licencia...', 'Verificando autorización de uso', 'initializing');
|
|
18828
18868
|
}
|
|
18869
|
+
// Heavy initialization is deferred to componentDidLoad so the first render is not blocked
|
|
18829
18870
|
}
|
|
18830
18871
|
async componentDidLoad() {
|
|
18872
|
+
// If @Watch('license') already scheduled or started init, let it proceed
|
|
18873
|
+
if (!this.license || this._initialized || this._initializing || this._pendingInit !== null) {
|
|
18874
|
+
return;
|
|
18875
|
+
}
|
|
18876
|
+
await this.validateAndInitialize();
|
|
18877
|
+
}
|
|
18878
|
+
onLicenseChanged(newLicense) {
|
|
18879
|
+
if (!newLicense || this._initialized || this._initializing) {
|
|
18880
|
+
return;
|
|
18881
|
+
}
|
|
18882
|
+
// Defer init by one macrotask (setTimeout 0) so @Watch('licenseEnvironment') fires
|
|
18883
|
+
// first. Angular applies [license] before [licenseEnvironment] in template order,
|
|
18884
|
+
// meaning a synchronous start here would use the Stencil default "prod" for the env.
|
|
18885
|
+
if (this._pendingInit !== null)
|
|
18886
|
+
clearTimeout(this._pendingInit);
|
|
18887
|
+
this._pendingInit = setTimeout(async () => {
|
|
18888
|
+
this._pendingInit = null;
|
|
18889
|
+
if (!this._initialized && !this._initializing && this.license) {
|
|
18890
|
+
this.updateStatus('Validando licencia...', 'Verificando autorización de uso', 'initializing');
|
|
18891
|
+
await this.validateAndInitialize();
|
|
18892
|
+
}
|
|
18893
|
+
}, 0);
|
|
18894
|
+
}
|
|
18895
|
+
async onLicenseEnvironmentChanged() {
|
|
18896
|
+
// Always recreate the service so the correct environment URL is ready.
|
|
18897
|
+
this.licenseValidationService = new LicenseValidationService(this.licenseEnvironment);
|
|
18898
|
+
if (this._initializing) {
|
|
18899
|
+
// Validation is already in-flight with the wrong environment.
|
|
18900
|
+
// Flag a retry so validateAndInitialize restarts once the current attempt ends.
|
|
18901
|
+
this._pendingEnvironmentRetry = true;
|
|
18902
|
+
return;
|
|
18903
|
+
}
|
|
18904
|
+
// If @Watch('license') already scheduled a deferred init, that init will read
|
|
18905
|
+
// this.licenseEnvironment at fire time (after this handler returns), so the
|
|
18906
|
+
// correct URL will be used — no need to trigger a second init here.
|
|
18907
|
+
if (this._pendingInit !== null) {
|
|
18908
|
+
return;
|
|
18909
|
+
}
|
|
18910
|
+
if (this._initialized) {
|
|
18911
|
+
// Component was fully initialized with the wrong env URL (e.g. Ionic animation
|
|
18912
|
+
// delayed Angular's CD past the initial validateAndInitialize() cycle).
|
|
18913
|
+
// Re-validate the license only — services and camera are already running.
|
|
18914
|
+
await this.validateLicense();
|
|
18915
|
+
return;
|
|
18916
|
+
}
|
|
18917
|
+
if (this.license) {
|
|
18918
|
+
this.updateStatus('Validando licencia...', 'Verificando autorización de uso', 'initializing');
|
|
18919
|
+
await this.validateAndInitialize();
|
|
18920
|
+
}
|
|
18921
|
+
}
|
|
18922
|
+
async validateAndInitialize() {
|
|
18923
|
+
if (this._initialized || this._initializing) {
|
|
18924
|
+
return;
|
|
18925
|
+
}
|
|
18926
|
+
this._initializing = true;
|
|
18831
18927
|
try {
|
|
18832
|
-
//
|
|
18928
|
+
// Status was already set synchronously by the caller (componentWillLoad or @Watch)
|
|
18929
|
+
// to avoid a state change inside componentDidLoad that Stencil warns about.
|
|
18930
|
+
await this.validateLicense();
|
|
18833
18931
|
if (!this.licenseValid) {
|
|
18932
|
+
if (this.debug) {
|
|
18933
|
+
console.error('[JAAK-DEBUG] License validation FAILED. Stopping initialization.');
|
|
18934
|
+
}
|
|
18834
18935
|
return;
|
|
18835
18936
|
}
|
|
18937
|
+
if (this.debug) {
|
|
18938
|
+
console.log('[JAAK-DEBUG] License validation OK');
|
|
18939
|
+
}
|
|
18836
18940
|
this.updateStatus('Preparando capturador...', 'Configurando herramientas de captura', 'initializing');
|
|
18837
18941
|
await this.initializeServices();
|
|
18838
18942
|
this.updateStatus('Preparando funciones...', 'Configurando herramientas de trabajo', 'initializing');
|
|
@@ -18842,9 +18946,37 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
18842
18946
|
if (this.debug) {
|
|
18843
18947
|
this.initializePerformanceMonitor();
|
|
18844
18948
|
}
|
|
18949
|
+
this._initialized = true;
|
|
18845
18950
|
}
|
|
18846
18951
|
catch (error) {
|
|
18847
|
-
|
|
18952
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
18953
|
+
this.updateStatus('Error de inicialización', errorMessage, 'error');
|
|
18954
|
+
}
|
|
18955
|
+
finally {
|
|
18956
|
+
this._initializing = false;
|
|
18957
|
+
if (this._pendingEnvironmentRetry && this.license) {
|
|
18958
|
+
this._pendingEnvironmentRetry = false;
|
|
18959
|
+
if (this._initialized) {
|
|
18960
|
+
// Already fully initialized with wrong env URL — re-validate only the license.
|
|
18961
|
+
// Services and camera are already running and don't depend on the env URL.
|
|
18962
|
+
await this.validateLicense();
|
|
18963
|
+
}
|
|
18964
|
+
else {
|
|
18965
|
+
// Not yet initialized — full retry with the correct environment.
|
|
18966
|
+
this.updateStatus('Validando licencia...', 'Verificando autorización de uso', 'initializing');
|
|
18967
|
+
await this.validateAndInitialize();
|
|
18968
|
+
}
|
|
18969
|
+
}
|
|
18970
|
+
else {
|
|
18971
|
+
this._pendingEnvironmentRetry = false;
|
|
18972
|
+
}
|
|
18973
|
+
// Release any startCapture() calls waiting on readiness. On success this is a
|
|
18974
|
+
// no-op (finalizeInitialization already settled); on a terminal failure (invalid
|
|
18975
|
+
// license / init error) it lets startCapture() return its error without waiting
|
|
18976
|
+
// out the full timeout. Idempotent, so a completed retry above stays settled.
|
|
18977
|
+
if (!this._initializing) {
|
|
18978
|
+
this.settleInitialization();
|
|
18979
|
+
}
|
|
18848
18980
|
}
|
|
18849
18981
|
}
|
|
18850
18982
|
async initializeServices() {
|
|
@@ -18894,14 +19026,14 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
18894
19026
|
}
|
|
18895
19027
|
async validateLicense() {
|
|
18896
19028
|
if (!this.license) {
|
|
18897
|
-
console.error('❌ No license provided for JAAK Stamps component');
|
|
18898
19029
|
this.licenseError = 'Este componente requiere una licencia válida. Por favor, proporcione una licencia usando el atributo "license".';
|
|
18899
19030
|
this.licenseValid = false;
|
|
18900
19031
|
this.updateStatus('Error de licencia', 'Licencia no proporcionada', 'error');
|
|
18901
19032
|
return;
|
|
18902
19033
|
}
|
|
18903
19034
|
try {
|
|
18904
|
-
|
|
19035
|
+
if (this.debug)
|
|
19036
|
+
console.log('[jaak-stamps] validating license...');
|
|
18905
19037
|
// Initialize license validation service
|
|
18906
19038
|
this.licenseValidationService = new LicenseValidationService(this.licenseEnvironment);
|
|
18907
19039
|
// Validate the license, passing traceId and appId if provided
|
|
@@ -18909,18 +19041,21 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
18909
19041
|
if (response && response.access_token) {
|
|
18910
19042
|
this.licenseValid = true;
|
|
18911
19043
|
this.licenseError = null;
|
|
18912
|
-
|
|
19044
|
+
if (this.debug)
|
|
19045
|
+
console.log('[jaak-stamps] license validated successfully');
|
|
18913
19046
|
// Emit the traceId (either provided or generated)
|
|
18914
19047
|
if (response.traceId) {
|
|
18915
19048
|
this.traceIdGenerated.emit({ traceId: response.traceId });
|
|
18916
|
-
|
|
19049
|
+
if (this.debug)
|
|
19050
|
+
console.log('[jaak-stamps] traceId:', response.traceId);
|
|
18917
19051
|
}
|
|
18918
19052
|
}
|
|
18919
19053
|
else {
|
|
18920
19054
|
this.licenseValid = false;
|
|
18921
19055
|
this.licenseError = 'La licencia proporcionada no es válida. Por favor, verifique su licencia e intente nuevamente.';
|
|
18922
19056
|
this.updateStatus('Error de licencia', 'Licencia inválida', 'error');
|
|
18923
|
-
|
|
19057
|
+
if (this.debug)
|
|
19058
|
+
console.error('[jaak-stamps] invalid license');
|
|
18924
19059
|
}
|
|
18925
19060
|
}
|
|
18926
19061
|
catch (error) {
|
|
@@ -18928,7 +19063,8 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
18928
19063
|
const licenseError = error;
|
|
18929
19064
|
this.licenseError = licenseError.error_description || 'Error al validar la licencia. Por favor, verifique su conexión e intente nuevamente.';
|
|
18930
19065
|
this.updateStatus('Error de licencia', 'Fallo en la validación', 'error');
|
|
18931
|
-
|
|
19066
|
+
if (this.debug)
|
|
19067
|
+
console.error('[jaak-stamps] license validation failed:', error);
|
|
18932
19068
|
}
|
|
18933
19069
|
}
|
|
18934
19070
|
async setupEventListeners() {
|
|
@@ -19031,6 +19167,42 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
19031
19167
|
};
|
|
19032
19168
|
}
|
|
19033
19169
|
this.emitReadyEvent();
|
|
19170
|
+
this.settleInitialization();
|
|
19171
|
+
}
|
|
19172
|
+
// Releases any startCapture() calls that arrived while the component was still
|
|
19173
|
+
// initializing. Idempotent: safe to call more than once.
|
|
19174
|
+
settleInitialization() {
|
|
19175
|
+
if (this.initializationSettled) {
|
|
19176
|
+
return;
|
|
19177
|
+
}
|
|
19178
|
+
this.initializationSettled = true;
|
|
19179
|
+
const waiters = this.initializationWaiters;
|
|
19180
|
+
this.initializationWaiters = [];
|
|
19181
|
+
waiters.forEach(resolve => resolve());
|
|
19182
|
+
}
|
|
19183
|
+
// Waits until initialization settles (finalizeInitialization ran) or the timeout
|
|
19184
|
+
// elapses, whichever comes first. Resolves regardless of outcome; the caller
|
|
19185
|
+
// re-checks isComponentReady() afterwards to decide success/failure.
|
|
19186
|
+
waitForInitialization(timeoutMs) {
|
|
19187
|
+
if (this.initializationSettled) {
|
|
19188
|
+
return Promise.resolve();
|
|
19189
|
+
}
|
|
19190
|
+
return new Promise(resolve => {
|
|
19191
|
+
let settled = false;
|
|
19192
|
+
const done = () => {
|
|
19193
|
+
if (settled) {
|
|
19194
|
+
return;
|
|
19195
|
+
}
|
|
19196
|
+
settled = true;
|
|
19197
|
+
clearTimeout(timer);
|
|
19198
|
+
resolve();
|
|
19199
|
+
};
|
|
19200
|
+
const timer = setTimeout(() => {
|
|
19201
|
+
this.initializationWaiters = this.initializationWaiters.filter(w => w !== done);
|
|
19202
|
+
done();
|
|
19203
|
+
}, timeoutMs);
|
|
19204
|
+
this.initializationWaiters.push(done);
|
|
19205
|
+
});
|
|
19034
19206
|
}
|
|
19035
19207
|
updateStatus(message, description, type = 'loading') {
|
|
19036
19208
|
this.currentStatus = {
|
|
@@ -19222,7 +19394,20 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
19222
19394
|
}
|
|
19223
19395
|
async startCapture() {
|
|
19224
19396
|
const span = this.tracingService?.startSpan('capture.start');
|
|
19225
|
-
|
|
19397
|
+
let readyCheck = this.isComponentReady();
|
|
19398
|
+
// TO-807: absorb the start-before-ready race instead of aborting. When the
|
|
19399
|
+
// component is still loading its resources (transient initializing/loading
|
|
19400
|
+
// state) we wait for initialization to settle and re-check, rather than
|
|
19401
|
+
// returning an error immediately (which left the host with a black screen).
|
|
19402
|
+
// A terminal state ('error' / missing services) is not waited on.
|
|
19403
|
+
if (!readyCheck.ready && (readyCheck.status === 'initializing' || readyCheck.status === 'loading')) {
|
|
19404
|
+
this.updateStatus('El componente está cargando recursos', 'Espere a que termine la inicialización', 'loading');
|
|
19405
|
+
if (span) {
|
|
19406
|
+
this.tracingService?.setSpanAttribute(span, 'startCapture.waitedForReady', true);
|
|
19407
|
+
}
|
|
19408
|
+
await this.waitForInitialization(this.START_CAPTURE_READY_TIMEOUT_MS);
|
|
19409
|
+
readyCheck = this.isComponentReady();
|
|
19410
|
+
}
|
|
19226
19411
|
if (!readyCheck.ready) {
|
|
19227
19412
|
this.updateStatus(readyCheck.message, 'Espere a que termine la inicialización', readyCheck.status);
|
|
19228
19413
|
if (span) {
|
|
@@ -20214,7 +20399,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
20214
20399
|
isCapturing: false
|
|
20215
20400
|
};
|
|
20216
20401
|
const cameraInfo = this.cameraInfoWithAutofocus;
|
|
20217
|
-
return (h("div", { key: '
|
|
20402
|
+
return (h("div", { key: 'ed400c7cc247fb12e5915e270207d3fa916362fd', class: "detector-container" }, !this.licenseValid && this.licenseError && (h("div", { key: 'd2f7507026d01d2fd381d365c9954067eb37c3f4', class: "license-error-container" }, h("div", { key: 'fc4ae7ae434a038a3730057a99a7d96d851dba43', class: "license-error-card" }, h("svg", { key: '7361da72e3fda0147044873bc770460098a4b4f1', 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: '57a3dce14d47d4b91af6ff84ab39cde58814f573', 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: '8c96a1638602eface0ae8c7377cdda04dffde5c7', d: "M12 8V12", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round" }), h("circle", { key: '7455af58b1827570713d778a4ef01bb0ffcfb553', cx: "12", cy: "16", r: "0.5", fill: "currentColor", stroke: "currentColor", "stroke-width": "1" })), h("h2", { key: '5779f8a2c4468ea185df620edecb3f79b7ae8bfb', class: "license-error-title" }, "Licencia Requerida"), h("p", { key: '8180147597c077798ff4ea4eb9309a3bec69c77f', class: "license-error-message" }, this.licenseError), h("p", { key: '2103af42045a8ee8385de273da8f98e23395469b', class: "license-error-help" }, "Contacte a soporte: ", h("a", { key: '8a7fe987b24600b123216c952c5b69f2c2afc0a0', href: "mailto:support@jaak.ai" }, "support@jaak.ai")), h("div", { key: 'fd00ef42e259669b7b7cc512478c9c925bd03415', class: "license-error-footer" }, "JAAK Stamps")))), this.licenseValid && (h("div", { key: '44a92ba0a4cc066bb4497f4f548fce0bd5dbc121', class: "video-container" }, h("video", { key: '9ef40fb28c0fea1b59657ae50134b4dc3df4cf24', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: {
|
|
20218
20403
|
// Keep the element rendered (display: block) so the browser
|
|
20219
20404
|
// loads stream metadata and fires 'loadedmetadata'. Hiding it
|
|
20220
20405
|
// with display:none prevents metadata loading in Chrome and
|
|
@@ -20223,7 +20408,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
20223
20408
|
// render context alive.
|
|
20224
20409
|
opacity: captureState.isVideoActive ? '1' : '0',
|
|
20225
20410
|
visibility: captureState.isVideoActive ? 'visible' : 'hidden',
|
|
20226
|
-
} }), h("div", { key: '
|
|
20411
|
+
} }), h("div", { key: 'f3d6e544bb8b13214894f71216badf092d2516dd', 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: {
|
|
20227
20412
|
position: 'absolute',
|
|
20228
20413
|
left: `${box.x}px`,
|
|
20229
20414
|
top: `${box.y}px`,
|
|
@@ -20232,9 +20417,9 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
20232
20417
|
border: '2px solid #32406C',
|
|
20233
20418
|
pointerEvents: 'none',
|
|
20234
20419
|
boxSizing: 'border-box'
|
|
20235
|
-
} })))), this.isMaskReady && (h("div", { key: '
|
|
20420
|
+
} })))), this.isMaskReady && (h("div", { key: '312b9d7733e550a444e84d699c0e14834fc41057', class: "overlay-mask" }, h("div", { key: '2af1c83efb4d360ecada3301f4479bbf8845f032', class: "card-outline" }, h("div", { key: 'b6f57f153953e059056fae6d9f8a8220bfff4357', class: "side side-top" }), h("div", { key: 'e465f72b8834a04174dc88897b813517afa372fb', class: "side side-right" }), h("div", { key: '32e2785c7570f2002b6bc68b491007925d9fcad5', class: "side side-bottom" }), h("div", { key: 'bf2133811df7f516d9e3b37ae6019c90c0a68d0b', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'de00829ac42fe7f3645cb515fb46cfabe415190b', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'ae09d9c23635d87d31110781dc0ab3acb8ec4667', class: "back-capture-section" }, h("div", { key: 'a30a50ee0272140d16e32f582dd93f8de87d2a44', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode || this.showManualCaptureButton) && (h("button", { key: 'fb104cf6feaeca2f9542a2d5933bbf4f15c6771f', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: '7a1bff56bae244c5b8d1d4c3fd523e7a20b4b5ce', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: '59125b29ad55122e5ee9e8c2aaf9689a1fef588e', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '4d0b8184b4eb82824d5d864fb1b196f22302506d', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
|
|
20236
20421
|
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
20237
|
-
: 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: '
|
|
20422
|
+
: 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: '1febf678f87e32916d3990677b41345ce034db4e', class: "camera-controls" }, h("button", { key: '79f00bac9d56347de1fc08b2e06be1c0e996a855', 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: '4f6d101ce789b7fff227a6a2ce2479cb6255fd58', class: "camera-selector-dropdown" }, h("div", { key: 'f82222bb25162d2717d84c098c2a6540caa821f3', class: "camera-selector-header" }, h("span", { key: '0b1648857467c5749fe5d1d846d1786fa2e394c3' }, "Seleccionar C\u00E1mara"), h("button", { key: 'f406f08ad9dc2dcaced7e95aed013665c5fcfb4e', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'a051beeab1c8447730d41e963cd3b95027922cab', 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: 'c9c0702a57c105b02062f325cd413b531c7f802c', class: "device-info" }, h("small", { key: '584f4c1ce525b8ab03107329c92797737d5afad5' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'e3e2a270d3c4e7accdd9bc8b37861af4fceaad5d', class: "manual-capture-section" }, h("button", { key: '1283629ce59fc82d7b3fc08d5573bc69238f7aab', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: '5de009e4d2ff0de43355e95e1d69f12d7f2e65f8', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '975142144bb104d3ed532ac80fca19a7f237bb2b', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '5d54b9130ed4d1e13b95cfeee8f9d694b5de68d3', class: "flip-animation" }, h("div", { key: 'c8b955180065d2b99f8e5f405b1ff92bc050af77', class: "id-card-icon" }), h("div", { key: 'f103b1871266886455d5bba094a0e119aa484595', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '5845c045d37099cf906f7c56d3c91568dd198bdf', class: "success-animation" }, h("div", { key: '430496db95f10834a43842e9ac97bdf0f025eb3b', class: "check-icon" }), h("div", { key: '0815cf6feffe8bd4ba84712c14d8f29c1a945577', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: 'f8a8a529850fc93e93f12810b7928e4700bac880', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: '929ab612be046e97bb02ebe366b531864b90cc7a', class: "status-spinner" })), h("div", { key: 'defaf70aa54f2ccc222ddbe392cc47f7c143fc06', class: "status-content" }, h("div", { key: '685cca31f70e26d062f2d01b9ffd8c5a4a6b6f86', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '21bce9f6de9e5a50763ef83a25787225319dc5bf', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '6e43560821e469e397b78ab44d1679a3ff8e330f', class: "performance-monitor" }, h("div", { key: 'afcde6083be4a1b4a76d5523e0a239926b76ff9a', class: "performance-expanded" }, h("div", { key: '0706e93c06bcaf2e573c0c2ac414c3ca7d3605ba', class: "metrics-row" }, h("div", { key: '32b755f0f81ae758d9ab0b2e75dd9d55ef52eef0', class: "metric-compact" }, h("span", { key: 'b1d8e773fdd1e333cd55bb5bbed2878a7e106474', class: "metric-label" }, "FPS"), h("span", { key: 'a6c53d389e7424f6696b6279bef267b28e112201', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: 'a8c4157b696ae53e8ae5cee14f9e8b37be34a0a6', class: "metric-compact" }, h("span", { key: '0fa82dd84f6e0a9c16c1894021932e8ba355991a', class: "metric-label" }, "MEM"), h("span", { key: 'fc7f19be4e3fbbc82da538703ef9049e26571496', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: '84bd7b6da8e91004ef6c554264b97b89fa6123e1', class: "metrics-row" }, h("div", { key: 'a2bc7af57fe87f5ef53ee00f76aa27675736c404', class: "metric-compact" }, h("span", { key: '59e9114f50cf4d69bfc447162001e8ab3214906a', class: "metric-label" }, "INF"), h("span", { key: 'c92e1f7e92127d85e0cdd647af44f1da4c46da57', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '5751e9dee9d55ddc559d1c60e68c4be7da2eb7a2', class: "metric-compact" }, h("span", { key: 'a34e394ab188e74a39eb77af4cf0108c8a2be1c3', class: "metric-label" }, "FRAME"), h("span", { key: '19165e851fc7f348e6cee93deccff0159c3bb982', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: 'dde9e547b8c9e200624e525d15baaa4a18a27417', class: "metrics-row" }, h("div", { key: '770301e51025a446e29638d38e8e8a8dfb911882', class: "metric-compact" }, h("span", { key: '96750b7a455ef1f3353b870467afdff402fa605b', class: "metric-label" }, "DET"), h("span", { key: 'a7951b69998e1d13beee40b6677d55091a413a4c', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: 'a82589fbccc749ef904a68933c6b850c3b69018c', class: "metric-compact" }, h("span", { key: 'ced7d42d2ebf2c4f20671c696b845263f4de4f4a', class: "metric-label" }, "RATE"), h("span", { key: '693c9735796ec276ca1d7e559aea250dafb0e5cf', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '3ff1698eae36352f9268839b86cef29144de297c', class: "watermark" }, h("img", { key: 'efa9735216e7caafdb67e10a5fc9363b503307b5', src: "https://static.jaak.ai/commons/powered-by-jaak.png", alt: "Powered by Jaak", onError: (e) => {
|
|
20238
20423
|
const img = e.target;
|
|
20239
20424
|
img.onerror = null;
|
|
20240
20425
|
img.src = POWERED_BY_JAAK_FALLBACK;
|
|
@@ -20782,7 +20967,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
20782
20967
|
await this.tracingService.flush();
|
|
20783
20968
|
}
|
|
20784
20969
|
catch (error) {
|
|
20785
|
-
console.error('[
|
|
20970
|
+
console.error('[jaak-stamps] Failed to flush traces:', error);
|
|
20786
20971
|
}
|
|
20787
20972
|
}
|
|
20788
20973
|
this.captureCompleted.emit(finalImages);
|
|
@@ -21055,7 +21240,11 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
21055
21240
|
// If pool is full, let the canvas be garbage collected
|
|
21056
21241
|
}
|
|
21057
21242
|
static get assetsDirs() { return ["../../assets"]; }
|
|
21058
|
-
static get
|
|
21243
|
+
static get watchers() { return {
|
|
21244
|
+
"license": ["onLicenseChanged"],
|
|
21245
|
+
"licenseEnvironment": ["onLicenseEnvironmentChanged"]
|
|
21246
|
+
}; }
|
|
21247
|
+
static get style() { return jaakStampsCss; }
|
|
21059
21248
|
}, [257, "jaak-stamps", {
|
|
21060
21249
|
"debug": [4],
|
|
21061
21250
|
"alignmentTolerance": [2, "alignment-tolerance"],
|
|
@@ -21111,6 +21300,9 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
|
|
|
21111
21300
|
"setPreferredCamera": [64],
|
|
21112
21301
|
"setCaptureDelay": [64],
|
|
21113
21302
|
"getCaptureDelay": [64]
|
|
21303
|
+
}, undefined, {
|
|
21304
|
+
"license": ["onLicenseChanged"],
|
|
21305
|
+
"licenseEnvironment": ["onLicenseEnvironmentChanged"]
|
|
21114
21306
|
}]);
|
|
21115
21307
|
function defineCustomElement$1() {
|
|
21116
21308
|
if (typeof customElements === "undefined") {
|