@neofaceid/web-sdk 1.15.2 → 1.17.0
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.
|
@@ -1623,7 +1623,7 @@ const loginWithBiometric = async (image, applicationToken) => {
|
|
|
1623
1623
|
}
|
|
1624
1624
|
return {
|
|
1625
1625
|
success: true,
|
|
1626
|
-
accessToken: data.accessToken,
|
|
1626
|
+
accessToken: data.accessToken || data.access_token || "",
|
|
1627
1627
|
alias: data.alias,
|
|
1628
1628
|
user: {
|
|
1629
1629
|
id: ((_a = data.user) == null ? void 0 : _a.id) || "",
|
|
@@ -1633,6 +1633,7 @@ const loginWithBiometric = async (image, applicationToken) => {
|
|
|
1633
1633
|
active: ((_e = data.user) == null ? void 0 : _e.active) || false
|
|
1634
1634
|
},
|
|
1635
1635
|
person: data.person ? {
|
|
1636
|
+
id: data.person.id || "",
|
|
1636
1637
|
name: data.person.name || "",
|
|
1637
1638
|
birth_date: data.person.birth_date || ""
|
|
1638
1639
|
} : void 0,
|
|
@@ -1838,7 +1839,8 @@ const registerPersonWithoutFace = async (personData, applicationToken, options)
|
|
|
1838
1839
|
cpf: personData.cpf,
|
|
1839
1840
|
email: personData.email,
|
|
1840
1841
|
password: personData.password,
|
|
1841
|
-
password_confirm: personData.password
|
|
1842
|
+
password_confirm: personData.password,
|
|
1843
|
+
is_pep: personData.is_pep ?? false
|
|
1842
1844
|
};
|
|
1843
1845
|
if (documentFrontBase64) {
|
|
1844
1846
|
body.document_images = [
|
|
@@ -1879,6 +1881,43 @@ const registerPersonWithoutFace = async (personData, applicationToken, options)
|
|
|
1879
1881
|
throw new NeoFaceError("Unknown error occurred", ErrorType.NETWORK);
|
|
1880
1882
|
}
|
|
1881
1883
|
};
|
|
1884
|
+
const checkUserExistence = async (params) => {
|
|
1885
|
+
const controller = createTimeoutController();
|
|
1886
|
+
const queryParams = new URLSearchParams();
|
|
1887
|
+
if (params.email) queryParams.append("email", params.email);
|
|
1888
|
+
if (params.cpf) queryParams.append("cpf", params.cpf);
|
|
1889
|
+
try {
|
|
1890
|
+
const response = await fetch(
|
|
1891
|
+
`${getApiBaseUrl()}/api/v1/verify/user/?${queryParams.toString()}`,
|
|
1892
|
+
{
|
|
1893
|
+
method: "GET",
|
|
1894
|
+
headers: {
|
|
1895
|
+
"Content-Type": "application/json"
|
|
1896
|
+
},
|
|
1897
|
+
signal: controller.signal
|
|
1898
|
+
}
|
|
1899
|
+
);
|
|
1900
|
+
if (!response.ok) {
|
|
1901
|
+
const errorData = await response.json().catch(() => ({}));
|
|
1902
|
+
throw new NeoFaceError(
|
|
1903
|
+
errorData.message || `Server returned status ${response.status}`,
|
|
1904
|
+
ErrorType.NETWORK
|
|
1905
|
+
);
|
|
1906
|
+
}
|
|
1907
|
+
return await response.json();
|
|
1908
|
+
} catch (error) {
|
|
1909
|
+
if (error instanceof Error) {
|
|
1910
|
+
if (error.name === "AbortError") {
|
|
1911
|
+
throw new NeoFaceError("Request timed out", ErrorType.NETWORK);
|
|
1912
|
+
}
|
|
1913
|
+
if (error instanceof NeoFaceError) {
|
|
1914
|
+
throw error;
|
|
1915
|
+
}
|
|
1916
|
+
throw new NeoFaceError(error.message, ErrorType.NETWORK);
|
|
1917
|
+
}
|
|
1918
|
+
throw new NeoFaceError("Unknown error occurred", ErrorType.NETWORK);
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1882
1921
|
const registerPersonWithBiometric = async (personData, facePhotos, applicationToken, options) => {
|
|
1883
1922
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1884
1923
|
ensureSecureContext();
|
|
@@ -1934,7 +1973,8 @@ const registerPersonWithBiometric = async (personData, facePhotos, applicationTo
|
|
|
1934
1973
|
email: personData.email,
|
|
1935
1974
|
password: personData.password,
|
|
1936
1975
|
password_confirm: personData.password,
|
|
1937
|
-
face_photos: facePhotosBase64
|
|
1976
|
+
face_photos: facePhotosBase64,
|
|
1977
|
+
is_pep: personData.is_pep ?? false
|
|
1938
1978
|
};
|
|
1939
1979
|
if (documentFrontBase64) {
|
|
1940
1980
|
body.document_images = [
|
|
@@ -2028,7 +2068,6 @@ const registerPersonWithBiometric = async (personData, facePhotos, applicationTo
|
|
|
2028
2068
|
}
|
|
2029
2069
|
};
|
|
2030
2070
|
const loginWithEmail = async (email, password, applicationToken) => {
|
|
2031
|
-
ensureSecureContext();
|
|
2032
2071
|
const controller = createTimeoutController();
|
|
2033
2072
|
try {
|
|
2034
2073
|
const response = await fetch(`${getApiBaseUrl()}/api/v1/auth/login/`, {
|
|
@@ -2074,10 +2113,10 @@ const loginWithEmail = async (email, password, applicationToken) => {
|
|
|
2074
2113
|
}
|
|
2075
2114
|
};
|
|
2076
2115
|
const identifyPerson = async (image, applicationToken) => {
|
|
2077
|
-
var _a, _b;
|
|
2116
|
+
var _a, _b, _c, _d;
|
|
2078
2117
|
ensureSecureContext();
|
|
2079
2118
|
const controller = createTimeoutController();
|
|
2080
|
-
const compressedImage = await
|
|
2119
|
+
const compressedImage = await compressDocumentImage(image);
|
|
2081
2120
|
const base64Image = await new Promise((resolve, reject) => {
|
|
2082
2121
|
const reader = new FileReader();
|
|
2083
2122
|
reader.onload = () => {
|
|
@@ -2088,7 +2127,7 @@ const identifyPerson = async (image, applicationToken) => {
|
|
|
2088
2127
|
reader.readAsDataURL(compressedImage);
|
|
2089
2128
|
});
|
|
2090
2129
|
try {
|
|
2091
|
-
const response = await fetch(`${getApiBaseUrl()}/api/v1/
|
|
2130
|
+
const response = await fetch(`${getApiBaseUrl()}/api/v1/auth/recognition/face/external/`, {
|
|
2092
2131
|
method: "POST",
|
|
2093
2132
|
headers: {
|
|
2094
2133
|
"Content-Type": "application/json",
|
|
@@ -2107,30 +2146,26 @@ const identifyPerson = async (image, applicationToken) => {
|
|
|
2107
2146
|
throw new NeoFaceError(`Server returned status ${response.status}`, ErrorType.NETWORK);
|
|
2108
2147
|
}
|
|
2109
2148
|
const data = await response.json();
|
|
2149
|
+
if (response.status === 202 || data.data && data.data.task_id) {
|
|
2150
|
+
return {
|
|
2151
|
+
success: true,
|
|
2152
|
+
taskId: ((_a = data.data) == null ? void 0 : _a.task_id) || data.task_id,
|
|
2153
|
+
status: ((_b = data.data) == null ? void 0 : _b.status) || "processing",
|
|
2154
|
+
message: data.message || "Identification scheduled"
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2110
2157
|
if (!data.success) {
|
|
2111
2158
|
throw new NeoFaceError(
|
|
2112
2159
|
data.message || "Person identification failed",
|
|
2113
2160
|
ErrorType.RECOGNITION_FAILED
|
|
2114
2161
|
);
|
|
2115
2162
|
}
|
|
2116
|
-
const personName = ((_a = data.person) == null ? void 0 : _a.name) || "";
|
|
2117
|
-
const birthDateStr = (_b = data.person) == null ? void 0 : _b.birth_date;
|
|
2118
|
-
if (!personName) {
|
|
2119
|
-
throw new NeoFaceError("Person name not found in response", ErrorType.PERSON_NOT_FOUND);
|
|
2120
|
-
}
|
|
2121
|
-
if (!birthDateStr) {
|
|
2122
|
-
throw new NeoFaceError("Birth date not found in response", ErrorType.PERSON_NOT_FOUND);
|
|
2123
|
-
}
|
|
2124
|
-
const birthDate = new Date(birthDateStr);
|
|
2125
|
-
const today = /* @__PURE__ */ new Date();
|
|
2126
|
-
let age = today.getFullYear() - birthDate.getFullYear();
|
|
2127
|
-
const monthDiff = today.getMonth() - birthDate.getMonth();
|
|
2128
|
-
if (monthDiff < 0 || monthDiff === 0 && today.getDate() < birthDate.getDate()) {
|
|
2129
|
-
age--;
|
|
2130
|
-
}
|
|
2131
2163
|
return {
|
|
2132
|
-
|
|
2133
|
-
|
|
2164
|
+
success: true,
|
|
2165
|
+
person: {
|
|
2166
|
+
name: ((_c = data.person) == null ? void 0 : _c.name) || "",
|
|
2167
|
+
birth_date: ((_d = data.person) == null ? void 0 : _d.birth_date) || ""
|
|
2168
|
+
}
|
|
2134
2169
|
};
|
|
2135
2170
|
} catch (error) {
|
|
2136
2171
|
if (error instanceof Error) {
|
|
@@ -2564,6 +2599,135 @@ const registerDocumentByImage = async (personId, jwtToken, images) => {
|
|
|
2564
2599
|
throw new NeoFaceError("Unknown error occurred", ErrorType.NETWORK_ERROR);
|
|
2565
2600
|
}
|
|
2566
2601
|
};
|
|
2602
|
+
const getTaskStatus = async (taskId) => {
|
|
2603
|
+
const controller = createTimeoutController();
|
|
2604
|
+
try {
|
|
2605
|
+
const response = await fetch(`${getApiBaseUrl()}/api/v1/tasks/status/?task_id=${taskId}`, {
|
|
2606
|
+
method: "GET",
|
|
2607
|
+
headers: {
|
|
2608
|
+
"Content-Type": "application/json"
|
|
2609
|
+
},
|
|
2610
|
+
signal: controller.signal
|
|
2611
|
+
});
|
|
2612
|
+
const data = await response.json();
|
|
2613
|
+
if (!response.ok) {
|
|
2614
|
+
throw new NeoFaceError(
|
|
2615
|
+
(data == null ? void 0 : data.message) || `API Error ${response.status}`,
|
|
2616
|
+
ErrorType.NETWORK_ERROR
|
|
2617
|
+
);
|
|
2618
|
+
}
|
|
2619
|
+
return {
|
|
2620
|
+
success: data.success,
|
|
2621
|
+
status: data.data.status,
|
|
2622
|
+
result: data.data.result,
|
|
2623
|
+
error: data.data.error
|
|
2624
|
+
};
|
|
2625
|
+
} catch (error) {
|
|
2626
|
+
if (error instanceof NeoFaceError) throw error;
|
|
2627
|
+
throw new NeoFaceError("Failed to fetch task status", ErrorType.NETWORK_ERROR);
|
|
2628
|
+
}
|
|
2629
|
+
};
|
|
2630
|
+
const identifyPersonAsync = async (image, applicationToken, options = {}) => {
|
|
2631
|
+
var _a, _b;
|
|
2632
|
+
const { maxRetries = 30, interval = 2e3 } = options;
|
|
2633
|
+
const initialResponse = await identifyPerson(image, applicationToken);
|
|
2634
|
+
if (initialResponse.person) {
|
|
2635
|
+
return {
|
|
2636
|
+
personFound: true,
|
|
2637
|
+
person: initialResponse.person
|
|
2638
|
+
};
|
|
2639
|
+
}
|
|
2640
|
+
const taskId = initialResponse.taskId;
|
|
2641
|
+
if (!taskId) {
|
|
2642
|
+
return { personFound: false };
|
|
2643
|
+
}
|
|
2644
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
2645
|
+
const status = await getTaskStatus(taskId);
|
|
2646
|
+
if (status.status === "success") {
|
|
2647
|
+
if (status.result && status.result.success) {
|
|
2648
|
+
return {
|
|
2649
|
+
personFound: true,
|
|
2650
|
+
person: {
|
|
2651
|
+
name: ((_a = status.result.person) == null ? void 0 : _a.name) || "Pessoa identificada",
|
|
2652
|
+
birth_date: ((_b = status.result.person) == null ? void 0 : _b.birth_date) || ""
|
|
2653
|
+
}
|
|
2654
|
+
};
|
|
2655
|
+
}
|
|
2656
|
+
return { personFound: false };
|
|
2657
|
+
}
|
|
2658
|
+
if (status.status === "failure") {
|
|
2659
|
+
return { personFound: false };
|
|
2660
|
+
}
|
|
2661
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
2662
|
+
}
|
|
2663
|
+
throw new NeoFaceError("Timed out waiting for identification", ErrorType.NETWORK_ERROR);
|
|
2664
|
+
};
|
|
2665
|
+
async function requestPasswordReset(email, applicationToken) {
|
|
2666
|
+
const baseUrl = getBaseUrl();
|
|
2667
|
+
const response = await fetch(`${baseUrl}/api/v1/user/password/reset/request/`, {
|
|
2668
|
+
method: "POST",
|
|
2669
|
+
headers: {
|
|
2670
|
+
"Content-Type": "application/json",
|
|
2671
|
+
"X-App-Token": applicationToken
|
|
2672
|
+
},
|
|
2673
|
+
body: JSON.stringify({ email })
|
|
2674
|
+
});
|
|
2675
|
+
if (!response.ok) {
|
|
2676
|
+
const errorData = await response.json();
|
|
2677
|
+
throw new NeoFaceError(
|
|
2678
|
+
errorData.message || "Erro ao solicitar recuperação de senha",
|
|
2679
|
+
ErrorType.API_ERROR
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
return response.json();
|
|
2683
|
+
}
|
|
2684
|
+
async function confirmPasswordReset(token, new_password) {
|
|
2685
|
+
const baseUrl = getBaseUrl();
|
|
2686
|
+
const response = await fetch(`${baseUrl}/api/v1/user/password/reset/confirm/`, {
|
|
2687
|
+
method: "POST",
|
|
2688
|
+
headers: {
|
|
2689
|
+
"Content-Type": "application/json"
|
|
2690
|
+
},
|
|
2691
|
+
body: JSON.stringify({ token, new_password })
|
|
2692
|
+
});
|
|
2693
|
+
if (!response.ok) {
|
|
2694
|
+
const errorData = await response.json();
|
|
2695
|
+
throw new NeoFaceError(
|
|
2696
|
+
errorData.error || errorData.message || "Erro ao redefinir senha",
|
|
2697
|
+
ErrorType.API_ERROR
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
return response.json();
|
|
2701
|
+
}
|
|
2702
|
+
const api = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
2703
|
+
__proto__: null,
|
|
2704
|
+
checkUserExistence,
|
|
2705
|
+
completeOnboarding,
|
|
2706
|
+
completeOnboardingWithData,
|
|
2707
|
+
confirmPasswordReset,
|
|
2708
|
+
getOnboardingDetails,
|
|
2709
|
+
getTaskStatus,
|
|
2710
|
+
identifyPerson,
|
|
2711
|
+
identifyPersonAsync,
|
|
2712
|
+
loginWithBiometric,
|
|
2713
|
+
loginWithEmail,
|
|
2714
|
+
pollTaskStatus,
|
|
2715
|
+
recognize,
|
|
2716
|
+
recognizeBiometric,
|
|
2717
|
+
recognizeByPurpose,
|
|
2718
|
+
recordFaceVideo,
|
|
2719
|
+
registerApplication,
|
|
2720
|
+
registerBiometric,
|
|
2721
|
+
registerDocumentByImage,
|
|
2722
|
+
registerPersonWithBiometric,
|
|
2723
|
+
registerPersonWithoutFace,
|
|
2724
|
+
requestPasswordReset,
|
|
2725
|
+
simpleIdentification,
|
|
2726
|
+
startProofOfLife,
|
|
2727
|
+
validateOnboardingToken,
|
|
2728
|
+
validateToken,
|
|
2729
|
+
videoToBase64
|
|
2730
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
2567
2731
|
const modalReducer$1 = (state, action) => {
|
|
2568
2732
|
switch (action.type) {
|
|
2569
2733
|
case "PERMISSION_GRANTED":
|
|
@@ -2857,6 +3021,336 @@ function FaceCaptureModal({ accessToken, onClose, onSuccess }) {
|
|
|
2857
3021
|
] })
|
|
2858
3022
|
] });
|
|
2859
3023
|
}
|
|
3024
|
+
class ForgotPasswordModal {
|
|
3025
|
+
constructor(applicationToken) {
|
|
3026
|
+
__publicField(this, "applicationToken");
|
|
3027
|
+
__publicField(this, "modalElement", null);
|
|
3028
|
+
this.applicationToken = applicationToken;
|
|
3029
|
+
}
|
|
3030
|
+
open() {
|
|
3031
|
+
if (this.modalElement) return;
|
|
3032
|
+
this.addStyles();
|
|
3033
|
+
this.modalElement = document.createElement("div");
|
|
3034
|
+
this.modalElement.className = "neoface-forgot-modal";
|
|
3035
|
+
this.renderEmailForm();
|
|
3036
|
+
document.body.appendChild(this.modalElement);
|
|
3037
|
+
}
|
|
3038
|
+
close() {
|
|
3039
|
+
if (this.modalElement && document.body.contains(this.modalElement)) {
|
|
3040
|
+
document.body.removeChild(this.modalElement);
|
|
3041
|
+
this.modalElement = null;
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
renderEmailForm() {
|
|
3045
|
+
if (!this.modalElement) return;
|
|
3046
|
+
this.modalElement.innerHTML = `
|
|
3047
|
+
<div class="neoface-forgot-overlay">
|
|
3048
|
+
<div class="neoface-forgot-content">
|
|
3049
|
+
<div class="neoface-forgot-icon">
|
|
3050
|
+
<svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3051
|
+
<circle cx="32" cy="32" r="28" stroke="#7c3aed" stroke-width="3" fill="none"/>
|
|
3052
|
+
<rect x="22" y="28" width="20" height="16" rx="3" stroke="#7c3aed" stroke-width="2.5" fill="none"/>
|
|
3053
|
+
<path d="M26 28v-4a6 6 0 0 1 12 0v4" stroke="#7c3aed" stroke-width="2.5" stroke-linecap="round"/>
|
|
3054
|
+
<circle cx="32" cy="36" r="2" fill="#7c3aed"/>
|
|
3055
|
+
</svg>
|
|
3056
|
+
</div>
|
|
3057
|
+
|
|
3058
|
+
<h2 class="neoface-forgot-title">Recuperar senha</h2>
|
|
3059
|
+
<p class="neoface-forgot-subtitle">Informe seu email e enviaremos um link para redefinir sua senha.</p>
|
|
3060
|
+
|
|
3061
|
+
<div id="neoface-forgot-error" class="neoface-forgot-error" style="display:none"></div>
|
|
3062
|
+
|
|
3063
|
+
<form id="neoface-forgot-form">
|
|
3064
|
+
<input
|
|
3065
|
+
type="email"
|
|
3066
|
+
id="neoface-forgot-email"
|
|
3067
|
+
class="neoface-forgot-input"
|
|
3068
|
+
placeholder="seu@email.com"
|
|
3069
|
+
autocomplete="email"
|
|
3070
|
+
required
|
|
3071
|
+
/>
|
|
3072
|
+
<button type="submit" class="neoface-forgot-btn-primary">
|
|
3073
|
+
Enviar link
|
|
3074
|
+
</button>
|
|
3075
|
+
</form>
|
|
3076
|
+
|
|
3077
|
+
<button class="neoface-forgot-btn-ghost neoface-forgot-back">
|
|
3078
|
+
Voltar
|
|
3079
|
+
</button>
|
|
3080
|
+
|
|
3081
|
+
<div class="neoface-forgot-branding">
|
|
3082
|
+
<img src="/logo-icone-no-background.png" alt="NeoFaceId" class="neoface-forgot-brand-logo" onerror="this.style.display='none'" />
|
|
3083
|
+
<span>NeoFaceId by</span>
|
|
3084
|
+
<span class="neoface-forgot-brand-name">OCTA</span>
|
|
3085
|
+
</div>
|
|
3086
|
+
</div>
|
|
3087
|
+
</div>
|
|
3088
|
+
`;
|
|
3089
|
+
const form = this.modalElement.querySelector("#neoface-forgot-form");
|
|
3090
|
+
form.addEventListener("submit", this.handleSubmit.bind(this));
|
|
3091
|
+
const backBtn = this.modalElement.querySelector(".neoface-forgot-back");
|
|
3092
|
+
backBtn.addEventListener("click", this.close.bind(this));
|
|
3093
|
+
}
|
|
3094
|
+
renderSuccess() {
|
|
3095
|
+
if (!this.modalElement) return;
|
|
3096
|
+
const content = this.modalElement.querySelector(".neoface-forgot-content");
|
|
3097
|
+
content.innerHTML = `
|
|
3098
|
+
<div class="neoface-forgot-success-icon">
|
|
3099
|
+
<svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3100
|
+
<circle cx="32" cy="32" r="28" stroke="#10b981" stroke-width="3" fill="none"/>
|
|
3101
|
+
<path d="M20 32 L28 40 L44 24" stroke="#10b981" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3102
|
+
</svg>
|
|
3103
|
+
</div>
|
|
3104
|
+
|
|
3105
|
+
<h2 class="neoface-forgot-title">Email enviado!</h2>
|
|
3106
|
+
<p class="neoface-forgot-subtitle">
|
|
3107
|
+
Verifique sua caixa de entrada e siga as instruções para redefinir sua senha.
|
|
3108
|
+
<br/><br/>
|
|
3109
|
+
<span style="color: rgba(255,255,255,0.5); font-size: 13px;">Não recebeu? Verifique também sua pasta de spam.</span>
|
|
3110
|
+
</p>
|
|
3111
|
+
|
|
3112
|
+
<button class="neoface-forgot-btn-primary neoface-forgot-close-success" style="margin-top: 8px;">
|
|
3113
|
+
Fechar
|
|
3114
|
+
</button>
|
|
3115
|
+
|
|
3116
|
+
<div class="neoface-forgot-branding">
|
|
3117
|
+
<img src="/logo-icone-no-background.png" alt="NeoFaceId" class="neoface-forgot-brand-logo" onerror="this.style.display='none'" />
|
|
3118
|
+
<span>NeoFaceId by</span>
|
|
3119
|
+
<span class="neoface-forgot-brand-name">OCTA</span>
|
|
3120
|
+
</div>
|
|
3121
|
+
`;
|
|
3122
|
+
const closeBtn = content.querySelector(".neoface-forgot-close-success");
|
|
3123
|
+
closeBtn.addEventListener("click", this.close.bind(this));
|
|
3124
|
+
}
|
|
3125
|
+
async handleSubmit(e) {
|
|
3126
|
+
var _a, _b, _c, _d;
|
|
3127
|
+
e.preventDefault();
|
|
3128
|
+
const emailInput = (_a = this.modalElement) == null ? void 0 : _a.querySelector(
|
|
3129
|
+
"#neoface-forgot-email"
|
|
3130
|
+
);
|
|
3131
|
+
const submitBtn = (_b = this.modalElement) == null ? void 0 : _b.querySelector(
|
|
3132
|
+
".neoface-forgot-btn-primary"
|
|
3133
|
+
);
|
|
3134
|
+
const errorEl = (_c = this.modalElement) == null ? void 0 : _c.querySelector("#neoface-forgot-error");
|
|
3135
|
+
const email = (_d = emailInput == null ? void 0 : emailInput.value) == null ? void 0 : _d.trim();
|
|
3136
|
+
if (!email) return;
|
|
3137
|
+
submitBtn.disabled = true;
|
|
3138
|
+
submitBtn.textContent = "Enviando...";
|
|
3139
|
+
errorEl.style.display = "none";
|
|
3140
|
+
try {
|
|
3141
|
+
await requestPasswordReset(email, this.applicationToken);
|
|
3142
|
+
this.renderSuccess();
|
|
3143
|
+
} catch (error) {
|
|
3144
|
+
submitBtn.disabled = false;
|
|
3145
|
+
submitBtn.textContent = "Enviar link";
|
|
3146
|
+
errorEl.style.display = "block";
|
|
3147
|
+
errorEl.textContent = error instanceof NeoFaceError ? error.message : "Erro ao enviar email. Tente novamente.";
|
|
3148
|
+
}
|
|
3149
|
+
}
|
|
3150
|
+
addStyles() {
|
|
3151
|
+
const styleId = "neoface-forgot-password-modal-styles";
|
|
3152
|
+
if (document.getElementById(styleId)) return;
|
|
3153
|
+
const style = document.createElement("style");
|
|
3154
|
+
style.id = styleId;
|
|
3155
|
+
style.textContent = `
|
|
3156
|
+
.neoface-forgot-modal {
|
|
3157
|
+
position: fixed;
|
|
3158
|
+
top: 0;
|
|
3159
|
+
left: 0;
|
|
3160
|
+
width: 100%;
|
|
3161
|
+
height: 100%;
|
|
3162
|
+
z-index: 10003;
|
|
3163
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
3164
|
+
}
|
|
3165
|
+
|
|
3166
|
+
.neoface-forgot-overlay {
|
|
3167
|
+
position: absolute;
|
|
3168
|
+
inset: 0;
|
|
3169
|
+
background: rgba(0, 0, 0, 0.65);
|
|
3170
|
+
backdrop-filter: blur(8px);
|
|
3171
|
+
display: flex;
|
|
3172
|
+
align-items: center;
|
|
3173
|
+
justify-content: center;
|
|
3174
|
+
padding: 20px;
|
|
3175
|
+
animation: neoface-forgot-fadeIn 0.3s ease-out;
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
@keyframes neoface-forgot-fadeIn {
|
|
3179
|
+
from { opacity: 0; }
|
|
3180
|
+
to { opacity: 1; }
|
|
3181
|
+
}
|
|
3182
|
+
|
|
3183
|
+
@keyframes neoface-forgot-slideUp {
|
|
3184
|
+
from { opacity: 0; transform: translateY(20px); }
|
|
3185
|
+
to { opacity: 1; transform: translateY(0); }
|
|
3186
|
+
}
|
|
3187
|
+
|
|
3188
|
+
.neoface-forgot-content {
|
|
3189
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
3190
|
+
border-radius: 20px;
|
|
3191
|
+
padding: 32px;
|
|
3192
|
+
max-width: 400px;
|
|
3193
|
+
width: 100%;
|
|
3194
|
+
box-shadow: 0 24px 48px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.1);
|
|
3195
|
+
animation: neoface-forgot-slideUp 0.4s ease-out;
|
|
3196
|
+
text-align: center;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
.neoface-forgot-icon {
|
|
3200
|
+
width: 64px;
|
|
3201
|
+
height: 64px;
|
|
3202
|
+
margin: 0 auto 20px;
|
|
3203
|
+
}
|
|
3204
|
+
|
|
3205
|
+
.neoface-forgot-success-icon {
|
|
3206
|
+
width: 64px;
|
|
3207
|
+
height: 64px;
|
|
3208
|
+
margin: 0 auto 20px;
|
|
3209
|
+
animation: neoface-forgot-scaleIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
@keyframes neoface-forgot-scaleIn {
|
|
3213
|
+
0% { transform: scale(0); opacity: 0; }
|
|
3214
|
+
50% { transform: scale(1.1); }
|
|
3215
|
+
100% { transform: scale(1); opacity: 1; }
|
|
3216
|
+
}
|
|
3217
|
+
|
|
3218
|
+
.neoface-forgot-title {
|
|
3219
|
+
font-size: 22px;
|
|
3220
|
+
font-weight: 700;
|
|
3221
|
+
color: white;
|
|
3222
|
+
margin: 0 0 10px 0;
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
.neoface-forgot-subtitle {
|
|
3226
|
+
font-size: 15px;
|
|
3227
|
+
color: rgba(255, 255, 255, 0.7);
|
|
3228
|
+
margin: 0 0 24px 0;
|
|
3229
|
+
line-height: 1.5;
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
.neoface-forgot-error {
|
|
3233
|
+
background: rgba(239, 68, 68, 0.15);
|
|
3234
|
+
border: 1px solid rgba(239, 68, 68, 0.4);
|
|
3235
|
+
color: #fca5a5;
|
|
3236
|
+
border-radius: 10px;
|
|
3237
|
+
padding: 10px 14px;
|
|
3238
|
+
font-size: 14px;
|
|
3239
|
+
margin-bottom: 16px;
|
|
3240
|
+
text-align: left;
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
#neoface-forgot-form {
|
|
3244
|
+
display: flex;
|
|
3245
|
+
flex-direction: column;
|
|
3246
|
+
gap: 14px;
|
|
3247
|
+
margin-bottom: 12px;
|
|
3248
|
+
}
|
|
3249
|
+
|
|
3250
|
+
.neoface-forgot-input {
|
|
3251
|
+
width: 100%;
|
|
3252
|
+
padding: 14px 16px;
|
|
3253
|
+
border: 2px solid rgba(255, 255, 255, 0.2);
|
|
3254
|
+
border-radius: 12px;
|
|
3255
|
+
font-size: 15px;
|
|
3256
|
+
background: rgba(255, 255, 255, 0.08);
|
|
3257
|
+
color: white;
|
|
3258
|
+
font-family: inherit;
|
|
3259
|
+
transition: all 0.2s;
|
|
3260
|
+
box-sizing: border-box;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
.neoface-forgot-input::placeholder {
|
|
3264
|
+
color: rgba(255, 255, 255, 0.4);
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
.neoface-forgot-input:focus {
|
|
3268
|
+
outline: none;
|
|
3269
|
+
border-color: #7c3aed;
|
|
3270
|
+
box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.2);
|
|
3271
|
+
background: rgba(255, 255, 255, 0.12);
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3274
|
+
.neoface-forgot-btn-primary {
|
|
3275
|
+
width: 100%;
|
|
3276
|
+
padding: 14px 24px;
|
|
3277
|
+
border-radius: 12px;
|
|
3278
|
+
border: none;
|
|
3279
|
+
background: linear-gradient(135deg, #7c3aed 0%, #6d28d9 100%);
|
|
3280
|
+
color: white;
|
|
3281
|
+
font-size: 16px;
|
|
3282
|
+
font-weight: 600;
|
|
3283
|
+
cursor: pointer;
|
|
3284
|
+
transition: all 0.2s;
|
|
3285
|
+
box-shadow: 0 4px 16px rgba(124, 58, 237, 0.3);
|
|
3286
|
+
font-family: inherit;
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
.neoface-forgot-btn-primary:hover:not(:disabled) {
|
|
3290
|
+
transform: translateY(-2px);
|
|
3291
|
+
box-shadow: 0 8px 24px rgba(124, 58, 237, 0.4);
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
.neoface-forgot-btn-primary:disabled {
|
|
3295
|
+
opacity: 0.6;
|
|
3296
|
+
cursor: not-allowed;
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
.neoface-forgot-btn-ghost {
|
|
3300
|
+
background: transparent;
|
|
3301
|
+
border: none;
|
|
3302
|
+
color: rgba(255, 255, 255, 0.5);
|
|
3303
|
+
font-size: 14px;
|
|
3304
|
+
font-weight: 500;
|
|
3305
|
+
cursor: pointer;
|
|
3306
|
+
padding: 10px 16px;
|
|
3307
|
+
border-radius: 8px;
|
|
3308
|
+
transition: all 0.2s;
|
|
3309
|
+
font-family: inherit;
|
|
3310
|
+
width: 100%;
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
.neoface-forgot-btn-ghost:hover {
|
|
3314
|
+
color: white;
|
|
3315
|
+
background: rgba(255, 255, 255, 0.05);
|
|
3316
|
+
}
|
|
3317
|
+
|
|
3318
|
+
.neoface-forgot-branding {
|
|
3319
|
+
display: flex;
|
|
3320
|
+
align-items: center;
|
|
3321
|
+
justify-content: center;
|
|
3322
|
+
gap: 6px;
|
|
3323
|
+
margin-top: 20px;
|
|
3324
|
+
color: rgba(255, 255, 255, 0.3);
|
|
3325
|
+
font-size: 12px;
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3328
|
+
.neoface-forgot-brand-logo {
|
|
3329
|
+
width: 18px;
|
|
3330
|
+
height: 18px;
|
|
3331
|
+
object-fit: contain;
|
|
3332
|
+
opacity: 0.5;
|
|
3333
|
+
}
|
|
3334
|
+
|
|
3335
|
+
.neoface-forgot-brand-name {
|
|
3336
|
+
font-weight: 700;
|
|
3337
|
+
letter-spacing: 0.05em;
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
@media (max-width: 640px) {
|
|
3341
|
+
.neoface-forgot-content {
|
|
3342
|
+
padding: 24px;
|
|
3343
|
+
border-radius: 16px;
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3346
|
+
.neoface-forgot-title {
|
|
3347
|
+
font-size: 20px;
|
|
3348
|
+
}
|
|
3349
|
+
}
|
|
3350
|
+
`;
|
|
3351
|
+
document.head.appendChild(style);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
2860
3354
|
const modalReducer = (state, action) => {
|
|
2861
3355
|
switch (action.type) {
|
|
2862
3356
|
case "START_LIVENESS":
|
|
@@ -2891,10 +3385,10 @@ const modalReducer = (state, action) => {
|
|
|
2891
3385
|
return state;
|
|
2892
3386
|
case "CAMERA_LOADING":
|
|
2893
3387
|
return { status: "camera-loading" };
|
|
2894
|
-
case "START_PROCESSING":
|
|
2895
|
-
return { status: "processing" };
|
|
2896
3388
|
case "SUCCESS":
|
|
2897
3389
|
return { status: "success" };
|
|
3390
|
+
case "DUPLICATE":
|
|
3391
|
+
return { status: "duplicate", personName: action.personName };
|
|
2898
3392
|
case "ERROR":
|
|
2899
3393
|
return { status: "error", message: action.message, retryable: action.retryable ?? true };
|
|
2900
3394
|
case "RESET":
|
|
@@ -3364,7 +3858,24 @@ function BiometricRegistrationModal({
|
|
|
3364
3858
|
);
|
|
3365
3859
|
};
|
|
3366
3860
|
const processRegistration = async (photos) => {
|
|
3861
|
+
var _a;
|
|
3367
3862
|
try {
|
|
3863
|
+
dispatch({ type: "START_PROCESSING" });
|
|
3864
|
+
if (applicationToken && photos.length > 0) {
|
|
3865
|
+
try {
|
|
3866
|
+
const { identifyPersonAsync: identifyPersonAsync2 } = await Promise.resolve().then(() => api);
|
|
3867
|
+
const result2 = await identifyPersonAsync2(photos[0], applicationToken);
|
|
3868
|
+
if (result2.personFound) {
|
|
3869
|
+
dispatch({
|
|
3870
|
+
type: "DUPLICATE",
|
|
3871
|
+
personName: ((_a = result2.person) == null ? void 0 : _a.name) || "Pessoa identificada"
|
|
3872
|
+
});
|
|
3873
|
+
return;
|
|
3874
|
+
}
|
|
3875
|
+
} catch (idError) {
|
|
3876
|
+
console.warn("Erro silencioso na identificação preventiva:", idError);
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3368
3879
|
if (onPhotosCaptured) {
|
|
3369
3880
|
dispatch({ type: "SUCCESS" });
|
|
3370
3881
|
onPhotosCaptured(photos);
|
|
@@ -3520,6 +4031,75 @@ function BiometricRegistrationModal({
|
|
|
3520
4031
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: onPhotosCaptured ? "Suas capturas faciais foram realizadas" : "Sua biometria foi registrada com sucesso" }),
|
|
3521
4032
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "primary-button", onClick: onClose, children: "Continuar" })
|
|
3522
4033
|
] });
|
|
4034
|
+
const renderDuplicate = () => {
|
|
4035
|
+
if (state.status !== "duplicate") return null;
|
|
4036
|
+
const greeting = state.personName && state.personName !== "Pessoa identificada" ? `Olá, ${state.personName.split(" ")[0]}!` : "Olá!";
|
|
4037
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "result-container duplicate scale-in", children: [
|
|
4038
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { style: { marginTop: "0px" }, children: greeting }),
|
|
4039
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { style: { marginBottom: "32px", fontSize: "15px" }, children: "Identificamos seu cadastro biométrico em nossa rede. Você já faz parte da NeoFaceId!" }),
|
|
4040
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "button-group-vertical", children: [
|
|
4041
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4042
|
+
"button",
|
|
4043
|
+
{
|
|
4044
|
+
className: "primary-button",
|
|
4045
|
+
onClick: () => {
|
|
4046
|
+
onClose();
|
|
4047
|
+
window.location.href = "/";
|
|
4048
|
+
},
|
|
4049
|
+
children: "Ir para o Login"
|
|
4050
|
+
}
|
|
4051
|
+
),
|
|
4052
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4053
|
+
"button",
|
|
4054
|
+
{
|
|
4055
|
+
className: "secondary-button",
|
|
4056
|
+
style: { marginTop: "12px" },
|
|
4057
|
+
onClick: () => {
|
|
4058
|
+
onClose();
|
|
4059
|
+
new ForgotPasswordModal(applicationToken ?? "").open();
|
|
4060
|
+
},
|
|
4061
|
+
children: "Esqueci minha senha"
|
|
4062
|
+
}
|
|
4063
|
+
),
|
|
4064
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "support-section", children: [
|
|
4065
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Não reconhece esta conta?" }),
|
|
4066
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4067
|
+
"button",
|
|
4068
|
+
{
|
|
4069
|
+
className: "ghost-button",
|
|
4070
|
+
onClick: () => window.open("https://support.neofaceid.com", "_blank"),
|
|
4071
|
+
children: "Falar com Suporte"
|
|
4072
|
+
}
|
|
4073
|
+
)
|
|
4074
|
+
] })
|
|
4075
|
+
] }),
|
|
4076
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
4077
|
+
"div",
|
|
4078
|
+
{
|
|
4079
|
+
className: "branding",
|
|
4080
|
+
style: {
|
|
4081
|
+
marginTop: "32px",
|
|
4082
|
+
paddingTop: "20px",
|
|
4083
|
+
borderTop: "1px solid rgba(255, 255, 255, 0.08)",
|
|
4084
|
+
width: "100%"
|
|
4085
|
+
},
|
|
4086
|
+
children: [
|
|
4087
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
4088
|
+
"img",
|
|
4089
|
+
{
|
|
4090
|
+
src: "/logo-icone.png",
|
|
4091
|
+
alt: "NeoFaceId",
|
|
4092
|
+
className: "brand-logo",
|
|
4093
|
+
style: { height: "18px" }
|
|
4094
|
+
}
|
|
4095
|
+
),
|
|
4096
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "NeoFaceId by" }),
|
|
4097
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "brand-name", children: "OCTA" })
|
|
4098
|
+
]
|
|
4099
|
+
}
|
|
4100
|
+
)
|
|
4101
|
+
] });
|
|
4102
|
+
};
|
|
3523
4103
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
3524
4104
|
/* @__PURE__ */ jsxRuntimeExports.jsx("style", { children: `
|
|
3525
4105
|
@keyframes fadeIn {
|
|
@@ -4049,6 +4629,61 @@ function BiometricRegistrationModal({
|
|
|
4049
4629
|
background: rgba(255, 255, 255, 0.05);
|
|
4050
4630
|
}
|
|
4051
4631
|
|
|
4632
|
+
/* Duplicate Screen Styles */
|
|
4633
|
+
.profile-icon-wrapper {
|
|
4634
|
+
position: relative;
|
|
4635
|
+
display: inline-block;
|
|
4636
|
+
margin-bottom: 24px;
|
|
4637
|
+
}
|
|
4638
|
+
|
|
4639
|
+
.profile-main-icon {
|
|
4640
|
+
background: rgba(124, 58, 237, 0.1);
|
|
4641
|
+
color: #7c3aed;
|
|
4642
|
+
padding: 20px;
|
|
4643
|
+
border-radius: 50%;
|
|
4644
|
+
border: 2px solid rgba(124, 58, 237, 0.2);
|
|
4645
|
+
box-shadow: 0 0 30px rgba(124, 58, 237, 0.2);
|
|
4646
|
+
}
|
|
4647
|
+
|
|
4648
|
+
.profile-main-icon svg {
|
|
4649
|
+
width: 48px;
|
|
4650
|
+
height: 48px;
|
|
4651
|
+
}
|
|
4652
|
+
|
|
4653
|
+
.verified-badge {
|
|
4654
|
+
position: absolute;
|
|
4655
|
+
bottom: -4px;
|
|
4656
|
+
right: -4px;
|
|
4657
|
+
background: #10b981;
|
|
4658
|
+
border-radius: 50%;
|
|
4659
|
+
padding: 4px;
|
|
4660
|
+
border: 3px solid #16213e;
|
|
4661
|
+
width: 24px;
|
|
4662
|
+
height: 24px;
|
|
4663
|
+
display: flex;
|
|
4664
|
+
align-items: center;
|
|
4665
|
+
justify-content: center;
|
|
4666
|
+
}
|
|
4667
|
+
|
|
4668
|
+
.button-group-vertical {
|
|
4669
|
+
display: flex;
|
|
4670
|
+
flex-direction: column;
|
|
4671
|
+
width: 100%;
|
|
4672
|
+
gap: 8px;
|
|
4673
|
+
}
|
|
4674
|
+
|
|
4675
|
+
.support-section {
|
|
4676
|
+
margin-top: 24px;
|
|
4677
|
+
padding-top: 16px;
|
|
4678
|
+
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
|
4679
|
+
}
|
|
4680
|
+
|
|
4681
|
+
.support-section p {
|
|
4682
|
+
font-size: 13px;
|
|
4683
|
+
color: rgba(255, 255, 255, 0.4);
|
|
4684
|
+
margin-bottom: 8px;
|
|
4685
|
+
}
|
|
4686
|
+
|
|
4052
4687
|
/* Canvas */
|
|
4053
4688
|
canvas {
|
|
4054
4689
|
display: none;
|
|
@@ -4086,7 +4721,8 @@ function BiometricRegistrationModal({
|
|
|
4086
4721
|
state.status === "camera-loading" && renderCameraLoading(),
|
|
4087
4722
|
state.status === "processing" && renderProcessing(),
|
|
4088
4723
|
state.status === "error" && renderError(),
|
|
4089
|
-
state.status === "success" && renderSuccess()
|
|
4724
|
+
state.status === "success" && renderSuccess(),
|
|
4725
|
+
state.status === "duplicate" && renderDuplicate()
|
|
4090
4726
|
] }) }),
|
|
4091
4727
|
/* @__PURE__ */ jsxRuntimeExports.jsx("canvas", { ref: canvasRef })
|
|
4092
4728
|
] });
|
|
@@ -4674,6 +5310,7 @@ class BiometricStatusOverlay {
|
|
|
4674
5310
|
/* Cores por estado */
|
|
4675
5311
|
.neofaceid-state-preparing .neofaceid-logo { filter: drop-shadow(0 0 15px rgba(124, 58, 237, 0.4)); }
|
|
4676
5312
|
.neofaceid-state-detecting .neofaceid-logo { filter: hue-rotate(180deg) drop-shadow(0 0 15px rgba(59, 130, 246, 0.6)); }
|
|
5313
|
+
.neofaceid-state-waiting-for-face .neofaceid-logo { filter: hue-rotate(30deg) drop-shadow(0 0 15px rgba(251, 146, 60, 0.6)); }
|
|
4677
5314
|
.neofaceid-state-capturing .neofaceid-logo { filter: hue-rotate(45deg) drop-shadow(0 0 15px rgba(245, 158, 11, 0.6)); }
|
|
4678
5315
|
.neofaceid-state-verifying .neofaceid-logo { filter: hue-rotate(90deg) drop-shadow(0 0 15px rgba(34, 197, 94, 0.6)); }
|
|
4679
5316
|
|
|
@@ -4747,6 +5384,8 @@ class BiometricStatusOverlay {
|
|
|
4747
5384
|
return "Iniciando câmera";
|
|
4748
5385
|
case "detecting":
|
|
4749
5386
|
return "Posicione seu rosto";
|
|
5387
|
+
case "waiting-for-face":
|
|
5388
|
+
return "Aguardando rosto";
|
|
4750
5389
|
case "capturing":
|
|
4751
5390
|
return "Capturando";
|
|
4752
5391
|
case "verifying":
|
|
@@ -4760,12 +5399,18 @@ class BiometricStatusOverlay {
|
|
|
4760
5399
|
}
|
|
4761
5400
|
}
|
|
4762
5401
|
renderContent() {
|
|
4763
|
-
const isPulsing = ["detecting", "verifying"].includes(this.currentStatus);
|
|
5402
|
+
const isPulsing = ["detecting", "waiting-for-face", "verifying"].includes(this.currentStatus);
|
|
4764
5403
|
const showLogo = !["success", "error"].includes(this.currentStatus);
|
|
4765
5404
|
const showSuccess = this.currentStatus === "success";
|
|
4766
5405
|
const showError = this.currentStatus === "error";
|
|
4767
5406
|
const statusText = this.getStatusText();
|
|
4768
|
-
const showDots = [
|
|
5407
|
+
const showDots = [
|
|
5408
|
+
"preparing",
|
|
5409
|
+
"detecting",
|
|
5410
|
+
"waiting-for-face",
|
|
5411
|
+
"capturing",
|
|
5412
|
+
"verifying"
|
|
5413
|
+
].includes(this.currentStatus);
|
|
4769
5414
|
return `
|
|
4770
5415
|
<style>${this.getStyles()}</style>
|
|
4771
5416
|
<div class="neofaceid-overlay-container neofaceid-state-${this.currentStatus}">
|
|
@@ -4850,8 +5495,13 @@ function FallbackPromptComponent({
|
|
|
4850
5495
|
error,
|
|
4851
5496
|
onRetry,
|
|
4852
5497
|
onCredentials,
|
|
4853
|
-
onCancel
|
|
5498
|
+
onCancel,
|
|
5499
|
+
applicationToken
|
|
4854
5500
|
}) {
|
|
5501
|
+
const handleForgotPassword = () => {
|
|
5502
|
+
const modal = new ForgotPasswordModal(applicationToken);
|
|
5503
|
+
modal.open();
|
|
5504
|
+
};
|
|
4855
5505
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
4856
5506
|
/* @__PURE__ */ jsxRuntimeExports.jsx("style", { children: `
|
|
4857
5507
|
@keyframes slideUp {
|
|
@@ -5029,6 +5679,15 @@ function FallbackPromptComponent({
|
|
|
5029
5679
|
children: "Entrar com Email e Senha"
|
|
5030
5680
|
}
|
|
5031
5681
|
),
|
|
5682
|
+
applicationToken && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5683
|
+
"button",
|
|
5684
|
+
{
|
|
5685
|
+
type: "button",
|
|
5686
|
+
className: "neofaceid-fallback-button neofaceid-fallback-button-ghost",
|
|
5687
|
+
onClick: handleForgotPassword,
|
|
5688
|
+
children: "Esqueceu sua senha?"
|
|
5689
|
+
}
|
|
5690
|
+
),
|
|
5032
5691
|
onCancel && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
5033
5692
|
"button",
|
|
5034
5693
|
{
|
|
@@ -5050,7 +5709,7 @@ class FallbackPrompt {
|
|
|
5050
5709
|
/**
|
|
5051
5710
|
* Exibe o prompt de fallback
|
|
5052
5711
|
*/
|
|
5053
|
-
show(error, onRetry, onCredentials, onCancel) {
|
|
5712
|
+
show(error, onRetry, onCredentials, onCancel, applicationToken) {
|
|
5054
5713
|
if (this.container) {
|
|
5055
5714
|
return;
|
|
5056
5715
|
}
|
|
@@ -5058,7 +5717,7 @@ class FallbackPrompt {
|
|
|
5058
5717
|
this.container.id = "neofaceid-fallback-prompt";
|
|
5059
5718
|
document.body.appendChild(this.container);
|
|
5060
5719
|
this.root = clientExports.createRoot(this.container);
|
|
5061
|
-
this.render(error, onRetry, onCredentials, onCancel);
|
|
5720
|
+
this.render(error, onRetry, onCredentials, onCancel, applicationToken);
|
|
5062
5721
|
}
|
|
5063
5722
|
/**
|
|
5064
5723
|
* Fecha o prompt
|
|
@@ -5076,7 +5735,7 @@ class FallbackPrompt {
|
|
|
5076
5735
|
/**
|
|
5077
5736
|
* Renderiza o componente
|
|
5078
5737
|
*/
|
|
5079
|
-
render(error, onRetry, onCredentials, onCancel) {
|
|
5738
|
+
render(error, onRetry, onCredentials, onCancel, applicationToken) {
|
|
5080
5739
|
if (!this.root || !this.container) return;
|
|
5081
5740
|
this.root.render(
|
|
5082
5741
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -5091,6 +5750,7 @@ class FallbackPrompt {
|
|
|
5091
5750
|
this.close();
|
|
5092
5751
|
onCredentials();
|
|
5093
5752
|
},
|
|
5753
|
+
applicationToken: applicationToken ?? "",
|
|
5094
5754
|
onCancel: () => {
|
|
5095
5755
|
this.close();
|
|
5096
5756
|
onCancel == null ? void 0 : onCancel();
|
|
@@ -5565,12 +6225,14 @@ async function captureFaceSilently() {
|
|
|
5565
6225
|
});
|
|
5566
6226
|
});
|
|
5567
6227
|
}
|
|
5568
|
-
async function detectFaceQuickly(video, maxTime = FACE_DETECTION_TIME, interval = DETECTION_INTERVAL) {
|
|
6228
|
+
async function detectFaceQuickly(video, maxTime = FACE_DETECTION_TIME, interval = DETECTION_INTERVAL, overlay) {
|
|
5569
6229
|
return new Promise((resolve) => {
|
|
5570
6230
|
let attempts = 0;
|
|
5571
6231
|
const maxAttempts = Math.ceil(maxTime / interval);
|
|
5572
6232
|
let timeoutId = null;
|
|
5573
6233
|
let isResolved = false;
|
|
6234
|
+
let overlayShowingWaiting = false;
|
|
6235
|
+
const ATTEMPTS_BEFORE_WAITING = Math.ceil(3e3 / interval);
|
|
5574
6236
|
const finish = (success) => {
|
|
5575
6237
|
if (isResolved) return;
|
|
5576
6238
|
isResolved = true;
|
|
@@ -5581,7 +6243,16 @@ async function detectFaceQuickly(video, maxTime = FACE_DETECTION_TIME, interval
|
|
|
5581
6243
|
if (isResolved) return;
|
|
5582
6244
|
attempts++;
|
|
5583
6245
|
if (!modelsLoaded) {
|
|
5584
|
-
|
|
6246
|
+
if (overlay && !overlayShowingWaiting && attempts >= ATTEMPTS_BEFORE_WAITING) {
|
|
6247
|
+
overlay.updateStatus("waiting-for-face");
|
|
6248
|
+
overlayShowingWaiting = true;
|
|
6249
|
+
console.log("⏳ Models not loaded - waiting for face...");
|
|
6250
|
+
}
|
|
6251
|
+
if (attempts >= maxAttempts) {
|
|
6252
|
+
finish(false);
|
|
6253
|
+
return;
|
|
6254
|
+
}
|
|
6255
|
+
timeoutId = window.setTimeout(checkFace, interval);
|
|
5585
6256
|
return;
|
|
5586
6257
|
}
|
|
5587
6258
|
try {
|
|
@@ -5590,21 +6261,43 @@ async function detectFaceQuickly(video, maxTime = FACE_DETECTION_TIME, interval
|
|
|
5590
6261
|
new faceapi.TinyFaceDetectorOptions({ inputSize: 160, scoreThreshold: 0.3 })
|
|
5591
6262
|
);
|
|
5592
6263
|
if (detection) {
|
|
6264
|
+
if (overlay && overlayShowingWaiting) {
|
|
6265
|
+
overlay.updateStatus("detecting");
|
|
6266
|
+
overlayShowingWaiting = false;
|
|
6267
|
+
console.log("👤 Face appeared");
|
|
6268
|
+
}
|
|
6269
|
+
console.log("✅ Face detected!");
|
|
5593
6270
|
finish(true);
|
|
5594
6271
|
return;
|
|
5595
6272
|
}
|
|
6273
|
+
if (overlay && !overlayShowingWaiting && attempts >= ATTEMPTS_BEFORE_WAITING) {
|
|
6274
|
+
overlay.updateStatus("waiting-for-face");
|
|
6275
|
+
overlayShowingWaiting = true;
|
|
6276
|
+
console.log("⏳ Waiting for face...");
|
|
6277
|
+
}
|
|
5596
6278
|
if (attempts >= maxAttempts) {
|
|
6279
|
+
console.warn("⏱️ Face detection timeout - no face found");
|
|
5597
6280
|
finish(false);
|
|
5598
6281
|
return;
|
|
5599
6282
|
}
|
|
5600
6283
|
timeoutId = window.setTimeout(checkFace, interval);
|
|
5601
6284
|
} catch (error) {
|
|
5602
|
-
|
|
6285
|
+
console.error("❌ Face detection error:", error);
|
|
6286
|
+
if (overlay && !overlayShowingWaiting && attempts >= ATTEMPTS_BEFORE_WAITING) {
|
|
6287
|
+
overlay.updateStatus("waiting-for-face");
|
|
6288
|
+
overlayShowingWaiting = true;
|
|
6289
|
+
}
|
|
6290
|
+
if (attempts >= maxAttempts) {
|
|
6291
|
+
finish(false);
|
|
6292
|
+
return;
|
|
6293
|
+
}
|
|
6294
|
+
timeoutId = window.setTimeout(checkFace, interval);
|
|
5603
6295
|
}
|
|
5604
6296
|
};
|
|
5605
6297
|
window.setTimeout(() => {
|
|
5606
6298
|
if (!isResolved) {
|
|
5607
|
-
|
|
6299
|
+
console.warn("⏱️ Face detection safety timeout reached");
|
|
6300
|
+
finish(false);
|
|
5608
6301
|
}
|
|
5609
6302
|
}, maxTime + 500);
|
|
5610
6303
|
checkFace();
|
|
@@ -5678,7 +6371,12 @@ async function attemptLogin(applicationToken, overlay, fastMode = false, isRetry
|
|
|
5678
6371
|
await new Promise((resolve) => setTimeout(resolve, CAMERA_STABILITY_DELAY));
|
|
5679
6372
|
let faceDetected = true;
|
|
5680
6373
|
if (!fastMode) {
|
|
5681
|
-
faceDetected = await detectFaceQuickly(
|
|
6374
|
+
faceDetected = await detectFaceQuickly(
|
|
6375
|
+
video,
|
|
6376
|
+
FACE_DETECTION_TIME,
|
|
6377
|
+
DETECTION_INTERVAL,
|
|
6378
|
+
overlay
|
|
6379
|
+
);
|
|
5682
6380
|
}
|
|
5683
6381
|
if (!faceDetected) {
|
|
5684
6382
|
if (stream) {
|
|
@@ -5688,7 +6386,7 @@ async function attemptLogin(applicationToken, overlay, fastMode = false, isRetry
|
|
|
5688
6386
|
video.parentElement.removeChild(video);
|
|
5689
6387
|
}
|
|
5690
6388
|
throw new NeoFaceError(
|
|
5691
|
-
"
|
|
6389
|
+
"Nenhum rosto detectado. Por favor, posicione seu rosto na frente da câmera e tente novamente.",
|
|
5692
6390
|
ErrorType.VALIDATION_ERROR
|
|
5693
6391
|
);
|
|
5694
6392
|
}
|
|
@@ -5808,7 +6506,8 @@ async function executeBiometricLoginFlow(options) {
|
|
|
5808
6506
|
);
|
|
5809
6507
|
}
|
|
5810
6508
|
},
|
|
5811
|
-
onCancel
|
|
6509
|
+
onCancel,
|
|
6510
|
+
applicationToken
|
|
5812
6511
|
);
|
|
5813
6512
|
}, 500);
|
|
5814
6513
|
}
|
|
@@ -6136,8 +6835,8 @@ const biometricDetection = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.
|
|
|
6136
6835
|
initializeBiometricDetection,
|
|
6137
6836
|
isAdvancedDetectionAvailable
|
|
6138
6837
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
6139
|
-
const VERSION = "1.
|
|
6140
|
-
const RELEASE_DATE = "2026-03-
|
|
6838
|
+
const VERSION = "1.17.0";
|
|
6839
|
+
const RELEASE_DATE = "2026-03-13";
|
|
6141
6840
|
class OnboardingCaptureModal {
|
|
6142
6841
|
constructor(options) {
|
|
6143
6842
|
__publicField(this, "overlay", null);
|
|
@@ -6822,11 +7521,11 @@ const authorizeOperation = async (applicationToken, cpf, options) => {
|
|
|
6822
7521
|
};
|
|
6823
7522
|
const DOCUMENT_INFO = {
|
|
6824
7523
|
RG: {
|
|
6825
|
-
name: "RG /
|
|
7524
|
+
name: "Documento de Identidade (RG / CIN / CPF)",
|
|
6826
7525
|
icon: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="16" rx="2"/><circle cx="9" cy="10" r="2"/><path d="M15 8h2M15 12h2M7 16h10"/></svg>',
|
|
6827
7526
|
hasBack: true,
|
|
6828
|
-
frontLabel: "Frente do
|
|
6829
|
-
backLabel: "Verso do
|
|
7527
|
+
frontLabel: "Frente do Documento",
|
|
7528
|
+
backLabel: "Verso do Documento"
|
|
6830
7529
|
},
|
|
6831
7530
|
CNH: {
|
|
6832
7531
|
name: "CNH / Carteira de Motorista",
|
|
@@ -6836,7 +7535,7 @@ const DOCUMENT_INFO = {
|
|
|
6836
7535
|
backLabel: "Verso da CNH"
|
|
6837
7536
|
},
|
|
6838
7537
|
CPF: {
|
|
6839
|
-
name: "CPF",
|
|
7538
|
+
name: "Cartão CPF (Apenas Frente)",
|
|
6840
7539
|
icon: '<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"/></svg>',
|
|
6841
7540
|
hasBack: false,
|
|
6842
7541
|
frontLabel: "Cartão CPF"
|
|
@@ -6930,7 +7629,7 @@ class DocumentCaptureModal {
|
|
|
6930
7629
|
|
|
6931
7630
|
<div class="neoface-doc-body">
|
|
6932
7631
|
<div class="neoface-doc-select-grid">
|
|
6933
|
-
${Object.entries(DOCUMENT_INFO).map(([type, info]) => `
|
|
7632
|
+
${Object.entries(DOCUMENT_INFO).filter(([type]) => type !== "CPF").map(([type, info]) => `
|
|
6934
7633
|
<button class="neoface-doc-select-option" data-type="${type}">
|
|
6935
7634
|
<span class="neoface-doc-select-icon">${info.icon}</span>
|
|
6936
7635
|
<span class="neoface-doc-select-name">${info.name}</span>
|
|
@@ -7936,6 +8635,7 @@ export {
|
|
|
7936
8635
|
ErrorType,
|
|
7937
8636
|
FaceCaptureModal,
|
|
7938
8637
|
FallbackPrompt,
|
|
8638
|
+
ForgotPasswordModal,
|
|
7939
8639
|
NeoFaceError,
|
|
7940
8640
|
NeoFaceID,
|
|
7941
8641
|
RELEASE_DATE,
|
|
@@ -7943,14 +8643,17 @@ export {
|
|
|
7943
8643
|
authorizeOperation,
|
|
7944
8644
|
biometricLogin,
|
|
7945
8645
|
biometricLoginWithFallback,
|
|
8646
|
+
checkUserExistence,
|
|
7946
8647
|
completeOnboarding,
|
|
7947
8648
|
completeOnboardingWithData,
|
|
8649
|
+
confirmPasswordReset,
|
|
7948
8650
|
detectBiometricType,
|
|
7949
8651
|
getApplicationToken,
|
|
7950
8652
|
getBaseUrl,
|
|
7951
8653
|
getConfig,
|
|
7952
8654
|
getEnvironment,
|
|
7953
8655
|
identifyPerson,
|
|
8656
|
+
identifyPersonAsync,
|
|
7954
8657
|
init,
|
|
7955
8658
|
initializeBiometricDetection,
|
|
7956
8659
|
isAdvancedDetectionAvailable,
|
|
@@ -7964,6 +8667,7 @@ export {
|
|
|
7964
8667
|
registerBiometric,
|
|
7965
8668
|
registerPersonWithBiometric,
|
|
7966
8669
|
registerPersonWithoutFace,
|
|
8670
|
+
requestPasswordReset,
|
|
7967
8671
|
simpleIdentification,
|
|
7968
8672
|
start,
|
|
7969
8673
|
startAutoLogin,
|