@riligar/auth-react 1.2.0 → 1.3.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.
package/dist/index.esm.js CHANGED
@@ -1,14 +1,44 @@
1
- import require$$0, { useEffect, createContext } from 'react';
1
+ import React$1, { useEffect, useMemo, createContext, useState } from 'react';
2
2
  import { Navigate, Outlet } from 'react-router-dom';
3
+ import { Paper, Stack, Image, Title, Text, TextInput, PasswordInput, Anchor, Button, Divider, Group, Center, Loader } from '@mantine/core';
4
+ import { useForm } from '@mantine/form';
5
+ import { IconArrowRight, IconMail, IconBrandGoogle, IconBrandGithub, IconLock, IconUser, IconSend, IconCheck, IconX, IconRefresh } from '@tabler/icons-react';
3
6
 
4
- // Ajuste se o back-end estiver em outro domínio/porta
5
- const API_BASE = typeof window !== 'undefined' && window?.location ? import.meta?.env?.VITE_API_BASE ?? "http://localhost:3000" : "http://localhost:3000";
7
+ // Config - pode ser sobrescrita pelo AuthProvider
8
+ // Tenta detectar ambiente Vite, mas falha graciosamente se não existir
9
+ const getEnvVar = key => {
10
+ try {
11
+ if (typeof import.meta !== 'undefined' && import.meta.env && import.meta.env[key]) {
12
+ return import.meta.env[key];
13
+ }
14
+ } catch (e) {
15
+ // ignore
16
+ }
17
+ return null;
18
+ };
19
+ let API_BASE = (typeof window !== 'undefined' && window?.location ? getEnvVar('VITE_API_BASE') : null) || 'http://localhost:3000';
20
+ let API_KEY = null;
21
+
22
+ // Permite configurar a API base e key externamente (chamado pelo AuthProvider)
23
+ function configure({
24
+ apiUrl,
25
+ apiKey
26
+ }) {
27
+ if (apiUrl) API_BASE = apiUrl.replace(/\/$/, ''); // Remove trailing slash
28
+ if (apiKey) API_KEY = apiKey;
29
+ }
6
30
 
7
31
  // helper fetch pré-configurado
8
32
  async function api(route, opts = {}) {
33
+ // Garante que a rota comece com /
34
+ const cleanRoute = route.startsWith('/') ? route : `/${route}`;
35
+
36
+ // Constrói URL completa (API_BASE já teve trailing slash removido no configure)
37
+ const url = `${API_BASE}${cleanRoute}`;
9
38
  const token = getStoredToken();
10
39
  const headers = {
11
- "Content-Type": "application/json",
40
+ 'Content-Type': 'application/json',
41
+ Accept: 'application/json',
12
42
  ...opts.headers
13
43
  };
14
44
 
@@ -16,7 +46,12 @@ async function api(route, opts = {}) {
16
46
  if (token) {
17
47
  headers.Authorization = `Bearer ${token}`;
18
48
  }
19
- const res = await fetch(`${API_BASE}${route}`, {
49
+
50
+ // Adiciona API Key se configurada
51
+ if (API_KEY) {
52
+ headers['X-API-Key'] = API_KEY;
53
+ }
54
+ const res = await fetch(url, {
20
55
  headers,
21
56
  ...opts
22
57
  });
@@ -43,14 +78,38 @@ function setStoredToken(token) {
43
78
  window.localStorage.removeItem('auth:token');
44
79
  }
45
80
  }
81
+ // Helper para processar resposta de autenticação e salvar token
82
+ function handleAuthResponse(result) {
83
+ // Tenta encontrar o token em vários lugares possíveis
84
+ const token = result.token || result.session?.token || result.session?.sessionToken;
85
+ console.log('[AuthSDK] Handling Auth Response:', {
86
+ hasToken: !!result.token,
87
+ hasSessionToken: !!result.session?.token,
88
+ hasSessionSessionToken: !!result.session?.sessionToken,
89
+ extractedToken: token
90
+ });
91
+ if (token) {
92
+ console.log('[AuthSDK] Saving token to storage');
93
+ setStoredToken(token);
94
+ } else {
95
+ console.warn('[AuthSDK] No token found in response', result);
96
+ }
97
+ return result;
98
+ }
46
99
 
47
100
  // Decodifica JWT (apenas payload, sem verificação de assinatura)
48
101
  function decodeJWT(token) {
49
102
  try {
50
103
  const parts = token.split('.');
51
104
  if (parts.length !== 3) return null;
52
- const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/')));
53
- return payload;
105
+
106
+ // Safe base64 decode
107
+ const base64Url = parts[1];
108
+ const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
109
+
110
+ // Verifica ambiente para decodificar
111
+ const jsonPayload = typeof window !== 'undefined' ? window.atob(base64) : Buffer.from(base64, 'base64').toString();
112
+ return JSON.parse(jsonPayload);
54
113
  } catch {
55
114
  return null;
56
115
  }
@@ -59,14 +118,33 @@ function decodeJWT(token) {
59
118
  // Verifica se o token está expirado
60
119
  function isTokenExpired(token) {
61
120
  const payload = decodeJWT(token);
62
- if (!payload || !payload.exp) return true;
63
- return Date.now() >= payload.exp * 1000;
121
+
122
+ // Se não for um JWT válido (payload null), assumimos que é um token opaco (session token)
123
+ // Nesse caso, deixamos o servidor validar via 401
124
+ if (!payload) return false;
125
+ if (!payload.exp) return false;
126
+ const now = Date.now();
127
+ const exp = payload.exp * 1000;
128
+ const isExpired = now >= exp;
129
+ if (isExpired) {
130
+ console.log('[AuthSDK] Token expired:', {
131
+ now,
132
+ exp,
133
+ diff: exp - now
134
+ });
135
+ }
136
+ return isExpired;
64
137
  }
65
138
 
66
139
  // Verifica se o usuário está autenticado
67
140
  function isAuthenticated() {
68
141
  const token = getStoredToken();
69
- return token && !isTokenExpired(token);
142
+ const valid = token && !isTokenExpired(token);
143
+ console.log('[AuthSDK] isAuthenticated check:', {
144
+ hasToken: !!token,
145
+ valid
146
+ });
147
+ return valid;
70
148
  }
71
149
 
72
150
  // Obtém dados do usuário do token
@@ -82,37 +160,32 @@ function getCurrentUser() {
82
160
  } : null;
83
161
  }
84
162
 
85
- /*--- métodos de autenticação-------------------*/
86
- const signUp = async (email, password) => {
87
- const result = await api("/auth/sign-up", {
88
- method: "POST",
163
+ /*--- métodos de autenticação -------------------*/
164
+ const signUp = async (email, password, name = '') => {
165
+ const result = await api('/auth/sign-up/email', {
166
+ method: 'POST',
89
167
  body: JSON.stringify({
90
168
  email,
91
- password
169
+ password,
170
+ name
92
171
  })
93
172
  });
94
- if (result.token) {
95
- setStoredToken(result.token);
96
- }
97
- return result;
173
+ return handleAuthResponse(result);
98
174
  };
99
175
  const signIn = async (email, password) => {
100
- const result = await api("/auth/sign-in", {
101
- method: "POST",
176
+ const result = await api('/auth/sign-in/email', {
177
+ method: 'POST',
102
178
  body: JSON.stringify({
103
179
  email,
104
180
  password
105
181
  })
106
182
  });
107
- if (result.token) {
108
- setStoredToken(result.token);
109
- }
110
- return result;
183
+ return handleAuthResponse(result);
111
184
  };
112
185
  const signOut = async () => {
113
186
  try {
114
- await api("/auth/sign-out", {
115
- method: "POST"
187
+ await api('/auth/sign-out', {
188
+ method: 'POST'
116
189
  });
117
190
  } catch {
118
191
  // Ignora erros de logout no servidor
@@ -122,23 +195,77 @@ const signOut = async () => {
122
195
  };
123
196
  const refreshToken = async () => {
124
197
  try {
125
- const result = await api("/auth/refresh", {
126
- method: "POST"
198
+ const result = await api('/auth/refresh', {
199
+ method: 'POST'
127
200
  });
128
- if (result.token) {
129
- setStoredToken(result.token);
130
- return result;
131
- }
201
+ return handleAuthResponse(result);
132
202
  } catch (error) {
133
203
  setStoredToken(null);
134
204
  throw error;
135
205
  }
136
206
  };
137
207
 
138
- /* Social login redirect (ex.: Google) ---------*/
208
+ /*--- Magic Link ---------------------------------*/
209
+ const sendMagicLink = async (email, callbackURL) => {
210
+ const callback = callbackURL || (typeof window !== 'undefined' ? `${window.location.origin}/auth/magic-link/verify` : '/auth/magic-link/verify');
211
+ return await api('/auth/sign-in/magic-link', {
212
+ method: 'POST',
213
+ body: JSON.stringify({
214
+ email,
215
+ callbackURL: callback
216
+ })
217
+ });
218
+ };
219
+ const verifyMagicLink = async token => {
220
+ const result = await api(`/auth/magic-link/verify?token=${encodeURIComponent(token)}`);
221
+ return handleAuthResponse(result);
222
+ };
223
+
224
+ /*--- Password Reset -----------------------------*/
225
+ const forgotPassword = async (email, redirectTo) => {
226
+ const redirect = redirectTo || (typeof window !== 'undefined' ? `${window.location.origin}/auth/reset-password` : '/auth/reset-password');
227
+ return await api('/auth/forget-password', {
228
+ method: 'POST',
229
+ body: JSON.stringify({
230
+ email,
231
+ redirectTo: redirect
232
+ })
233
+ });
234
+ };
235
+ const resetPassword = async (token, newPassword) => {
236
+ return await api('/auth/reset-password', {
237
+ method: 'POST',
238
+ body: JSON.stringify({
239
+ token,
240
+ newPassword
241
+ })
242
+ });
243
+ };
244
+
245
+ /*--- Email Verification -------------------------*/
246
+ const verifyEmail = async token => {
247
+ const result = await api(`/auth/verify-email?token=${encodeURIComponent(token)}`);
248
+ return handleAuthResponse(result);
249
+ };
250
+ const resendVerification = async (email, callbackURL) => {
251
+ const callback = callbackURL || (typeof window !== 'undefined' ? `${window.location.origin}/auth/verify-email` : '/auth/verify-email');
252
+ return await api('/auth/send-verification-email', {
253
+ method: 'POST',
254
+ body: JSON.stringify({
255
+ email,
256
+ callbackURL: callback
257
+ })
258
+ });
259
+ };
260
+
261
+ /*--- Session ------------------------------------*/
262
+ const getSession = async () => {
263
+ return await api('/auth/session');
264
+ };
265
+
266
+ /* Social login redirect (ex.: Google) -----------*/
139
267
  function socialRedirect(provider, redirectTo = typeof window !== 'undefined' ? window.location.href : '/') {
140
268
  if (typeof window === 'undefined') return;
141
- // Melhor pegar a URL de redirect dada pelo back-end, mas isso já funciona:
142
269
  window.location = `${API_BASE}/auth/sign-in/${provider}?redirect=${encodeURIComponent(redirectTo)}`;
143
270
  }
144
271
 
@@ -159,479 +286,84 @@ const createStoreImpl = (createState) => {
159
286
  listeners.add(listener);
160
287
  return () => listeners.delete(listener);
161
288
  };
162
- const destroy = () => {
163
- if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") {
164
- console.warn(
165
- "[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."
166
- );
167
- }
168
- listeners.clear();
169
- };
170
- const api = { setState, getState, getInitialState, subscribe, destroy };
289
+ const api = { setState, getState, getInitialState, subscribe };
171
290
  const initialState = state = createState(setState, getState, api);
172
291
  return api;
173
292
  };
174
- const createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
175
-
176
- function getDefaultExportFromCjs (x) {
177
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
178
- }
179
-
180
- var withSelector = {exports: {}};
181
-
182
- var withSelector_production = {};
183
-
184
- var shim = {exports: {}};
185
-
186
- var useSyncExternalStoreShim_production = {};
187
-
188
- /**
189
- * @license React
190
- * use-sync-external-store-shim.production.js
191
- *
192
- * Copyright (c) Meta Platforms, Inc. and affiliates.
193
- *
194
- * This source code is licensed under the MIT license found in the
195
- * LICENSE file in the root directory of this source tree.
196
- */
197
-
198
- var hasRequiredUseSyncExternalStoreShim_production;
199
-
200
- function requireUseSyncExternalStoreShim_production () {
201
- if (hasRequiredUseSyncExternalStoreShim_production) return useSyncExternalStoreShim_production;
202
- hasRequiredUseSyncExternalStoreShim_production = 1;
203
- var React = require$$0;
204
- function is(x, y) {
205
- return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
206
- }
207
- var objectIs = "function" === typeof Object.is ? Object.is : is,
208
- useState = React.useState,
209
- useEffect = React.useEffect,
210
- useLayoutEffect = React.useLayoutEffect,
211
- useDebugValue = React.useDebugValue;
212
- function useSyncExternalStore$2(subscribe, getSnapshot) {
213
- var value = getSnapshot(),
214
- _useState = useState({ inst: { value: value, getSnapshot: getSnapshot } }),
215
- inst = _useState[0].inst,
216
- forceUpdate = _useState[1];
217
- useLayoutEffect(
218
- function () {
219
- inst.value = value;
220
- inst.getSnapshot = getSnapshot;
221
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
222
- },
223
- [subscribe, value, getSnapshot]
224
- );
225
- useEffect(
226
- function () {
227
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
228
- return subscribe(function () {
229
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
230
- });
231
- },
232
- [subscribe]
233
- );
234
- useDebugValue(value);
235
- return value;
236
- }
237
- function checkIfSnapshotChanged(inst) {
238
- var latestGetSnapshot = inst.getSnapshot;
239
- inst = inst.value;
240
- try {
241
- var nextValue = latestGetSnapshot();
242
- return !objectIs(inst, nextValue);
243
- } catch (error) {
244
- return true;
245
- }
246
- }
247
- function useSyncExternalStore$1(subscribe, getSnapshot) {
248
- return getSnapshot();
249
- }
250
- var shim =
251
- "undefined" === typeof window ||
252
- "undefined" === typeof window.document ||
253
- "undefined" === typeof window.document.createElement
254
- ? useSyncExternalStore$1
255
- : useSyncExternalStore$2;
256
- useSyncExternalStoreShim_production.useSyncExternalStore =
257
- void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim;
258
- return useSyncExternalStoreShim_production;
259
- }
260
-
261
- var useSyncExternalStoreShim_development = {};
262
-
263
- /**
264
- * @license React
265
- * use-sync-external-store-shim.development.js
266
- *
267
- * Copyright (c) Meta Platforms, Inc. and affiliates.
268
- *
269
- * This source code is licensed under the MIT license found in the
270
- * LICENSE file in the root directory of this source tree.
271
- */
272
-
273
- var hasRequiredUseSyncExternalStoreShim_development;
274
-
275
- function requireUseSyncExternalStoreShim_development () {
276
- if (hasRequiredUseSyncExternalStoreShim_development) return useSyncExternalStoreShim_development;
277
- hasRequiredUseSyncExternalStoreShim_development = 1;
278
- "production" !== process.env.NODE_ENV &&
279
- (function () {
280
- function is(x, y) {
281
- return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
282
- }
283
- function useSyncExternalStore$2(subscribe, getSnapshot) {
284
- didWarnOld18Alpha ||
285
- void 0 === React.startTransition ||
286
- ((didWarnOld18Alpha = true),
287
- console.error(
288
- "You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."
289
- ));
290
- var value = getSnapshot();
291
- if (!didWarnUncachedGetSnapshot) {
292
- var cachedValue = getSnapshot();
293
- objectIs(value, cachedValue) ||
294
- (console.error(
295
- "The result of getSnapshot should be cached to avoid an infinite loop"
296
- ),
297
- (didWarnUncachedGetSnapshot = true));
298
- }
299
- cachedValue = useState({
300
- inst: { value: value, getSnapshot: getSnapshot }
301
- });
302
- var inst = cachedValue[0].inst,
303
- forceUpdate = cachedValue[1];
304
- useLayoutEffect(
305
- function () {
306
- inst.value = value;
307
- inst.getSnapshot = getSnapshot;
308
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
309
- },
310
- [subscribe, value, getSnapshot]
311
- );
312
- useEffect(
313
- function () {
314
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
315
- return subscribe(function () {
316
- checkIfSnapshotChanged(inst) && forceUpdate({ inst: inst });
317
- });
318
- },
319
- [subscribe]
320
- );
321
- useDebugValue(value);
322
- return value;
323
- }
324
- function checkIfSnapshotChanged(inst) {
325
- var latestGetSnapshot = inst.getSnapshot;
326
- inst = inst.value;
327
- try {
328
- var nextValue = latestGetSnapshot();
329
- return !objectIs(inst, nextValue);
330
- } catch (error) {
331
- return true;
332
- }
333
- }
334
- function useSyncExternalStore$1(subscribe, getSnapshot) {
335
- return getSnapshot();
336
- }
337
- "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
338
- "function" ===
339
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
340
- __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
341
- var React = require$$0,
342
- objectIs = "function" === typeof Object.is ? Object.is : is,
343
- useState = React.useState,
344
- useEffect = React.useEffect,
345
- useLayoutEffect = React.useLayoutEffect,
346
- useDebugValue = React.useDebugValue,
347
- didWarnOld18Alpha = false,
348
- didWarnUncachedGetSnapshot = false,
349
- shim =
350
- "undefined" === typeof window ||
351
- "undefined" === typeof window.document ||
352
- "undefined" === typeof window.document.createElement
353
- ? useSyncExternalStore$1
354
- : useSyncExternalStore$2;
355
- useSyncExternalStoreShim_development.useSyncExternalStore =
356
- void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim;
357
- "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
358
- "function" ===
359
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
360
- __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
361
- })();
362
- return useSyncExternalStoreShim_development;
363
- }
364
-
365
- var hasRequiredShim;
366
-
367
- function requireShim () {
368
- if (hasRequiredShim) return shim.exports;
369
- hasRequiredShim = 1;
370
-
371
- if (process.env.NODE_ENV === 'production') {
372
- shim.exports = requireUseSyncExternalStoreShim_production();
373
- } else {
374
- shim.exports = requireUseSyncExternalStoreShim_development();
375
- }
376
- return shim.exports;
377
- }
378
-
379
- /**
380
- * @license React
381
- * use-sync-external-store-shim/with-selector.production.js
382
- *
383
- * Copyright (c) Meta Platforms, Inc. and affiliates.
384
- *
385
- * This source code is licensed under the MIT license found in the
386
- * LICENSE file in the root directory of this source tree.
387
- */
388
-
389
- var hasRequiredWithSelector_production;
390
-
391
- function requireWithSelector_production () {
392
- if (hasRequiredWithSelector_production) return withSelector_production;
393
- hasRequiredWithSelector_production = 1;
394
- var React = require$$0,
395
- shim = requireShim();
396
- function is(x, y) {
397
- return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
398
- }
399
- var objectIs = "function" === typeof Object.is ? Object.is : is,
400
- useSyncExternalStore = shim.useSyncExternalStore,
401
- useRef = React.useRef,
402
- useEffect = React.useEffect,
403
- useMemo = React.useMemo,
404
- useDebugValue = React.useDebugValue;
405
- withSelector_production.useSyncExternalStoreWithSelector = function (
406
- subscribe,
407
- getSnapshot,
408
- getServerSnapshot,
409
- selector,
410
- isEqual
411
- ) {
412
- var instRef = useRef(null);
413
- if (null === instRef.current) {
414
- var inst = { hasValue: false, value: null };
415
- instRef.current = inst;
416
- } else inst = instRef.current;
417
- instRef = useMemo(
418
- function () {
419
- function memoizedSelector(nextSnapshot) {
420
- if (!hasMemo) {
421
- hasMemo = true;
422
- memoizedSnapshot = nextSnapshot;
423
- nextSnapshot = selector(nextSnapshot);
424
- if (void 0 !== isEqual && inst.hasValue) {
425
- var currentSelection = inst.value;
426
- if (isEqual(currentSelection, nextSnapshot))
427
- return (memoizedSelection = currentSelection);
428
- }
429
- return (memoizedSelection = nextSnapshot);
430
- }
431
- currentSelection = memoizedSelection;
432
- if (objectIs(memoizedSnapshot, nextSnapshot)) return currentSelection;
433
- var nextSelection = selector(nextSnapshot);
434
- if (void 0 !== isEqual && isEqual(currentSelection, nextSelection))
435
- return (memoizedSnapshot = nextSnapshot), currentSelection;
436
- memoizedSnapshot = nextSnapshot;
437
- return (memoizedSelection = nextSelection);
438
- }
439
- var hasMemo = false,
440
- memoizedSnapshot,
441
- memoizedSelection,
442
- maybeGetServerSnapshot =
443
- void 0 === getServerSnapshot ? null : getServerSnapshot;
444
- return [
445
- function () {
446
- return memoizedSelector(getSnapshot());
447
- },
448
- null === maybeGetServerSnapshot
449
- ? void 0
450
- : function () {
451
- return memoizedSelector(maybeGetServerSnapshot());
452
- }
453
- ];
454
- },
455
- [getSnapshot, getServerSnapshot, selector, isEqual]
456
- );
457
- var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);
458
- useEffect(
459
- function () {
460
- inst.hasValue = true;
461
- inst.value = value;
462
- },
463
- [value]
464
- );
465
- useDebugValue(value);
466
- return value;
467
- };
468
- return withSelector_production;
469
- }
470
-
471
- var withSelector_development = {};
472
-
473
- /**
474
- * @license React
475
- * use-sync-external-store-shim/with-selector.development.js
476
- *
477
- * Copyright (c) Meta Platforms, Inc. and affiliates.
478
- *
479
- * This source code is licensed under the MIT license found in the
480
- * LICENSE file in the root directory of this source tree.
481
- */
293
+ const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
482
294
 
483
- var hasRequiredWithSelector_development;
484
-
485
- function requireWithSelector_development () {
486
- if (hasRequiredWithSelector_development) return withSelector_development;
487
- hasRequiredWithSelector_development = 1;
488
- "production" !== process.env.NODE_ENV &&
489
- (function () {
490
- function is(x, y) {
491
- return (x === y && (0 !== x || 1 / x === 1 / y)) || (x !== x && y !== y);
492
- }
493
- "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
494
- "function" ===
495
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
496
- __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
497
- var React = require$$0,
498
- shim = requireShim(),
499
- objectIs = "function" === typeof Object.is ? Object.is : is,
500
- useSyncExternalStore = shim.useSyncExternalStore,
501
- useRef = React.useRef,
502
- useEffect = React.useEffect,
503
- useMemo = React.useMemo,
504
- useDebugValue = React.useDebugValue;
505
- withSelector_development.useSyncExternalStoreWithSelector = function (
506
- subscribe,
507
- getSnapshot,
508
- getServerSnapshot,
509
- selector,
510
- isEqual
511
- ) {
512
- var instRef = useRef(null);
513
- if (null === instRef.current) {
514
- var inst = { hasValue: false, value: null };
515
- instRef.current = inst;
516
- } else inst = instRef.current;
517
- instRef = useMemo(
518
- function () {
519
- function memoizedSelector(nextSnapshot) {
520
- if (!hasMemo) {
521
- hasMemo = true;
522
- memoizedSnapshot = nextSnapshot;
523
- nextSnapshot = selector(nextSnapshot);
524
- if (void 0 !== isEqual && inst.hasValue) {
525
- var currentSelection = inst.value;
526
- if (isEqual(currentSelection, nextSnapshot))
527
- return (memoizedSelection = currentSelection);
528
- }
529
- return (memoizedSelection = nextSnapshot);
530
- }
531
- currentSelection = memoizedSelection;
532
- if (objectIs(memoizedSnapshot, nextSnapshot))
533
- return currentSelection;
534
- var nextSelection = selector(nextSnapshot);
535
- if (void 0 !== isEqual && isEqual(currentSelection, nextSelection))
536
- return (memoizedSnapshot = nextSnapshot), currentSelection;
537
- memoizedSnapshot = nextSnapshot;
538
- return (memoizedSelection = nextSelection);
539
- }
540
- var hasMemo = false,
541
- memoizedSnapshot,
542
- memoizedSelection,
543
- maybeGetServerSnapshot =
544
- void 0 === getServerSnapshot ? null : getServerSnapshot;
545
- return [
546
- function () {
547
- return memoizedSelector(getSnapshot());
548
- },
549
- null === maybeGetServerSnapshot
550
- ? void 0
551
- : function () {
552
- return memoizedSelector(maybeGetServerSnapshot());
553
- }
554
- ];
555
- },
556
- [getSnapshot, getServerSnapshot, selector, isEqual]
557
- );
558
- var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);
559
- useEffect(
560
- function () {
561
- inst.hasValue = true;
562
- inst.value = value;
563
- },
564
- [value]
565
- );
566
- useDebugValue(value);
567
- return value;
568
- };
569
- "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
570
- "function" ===
571
- typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
572
- __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
573
- })();
574
- return withSelector_development;
575
- }
576
-
577
- if (process.env.NODE_ENV === 'production') {
578
- withSelector.exports = requireWithSelector_production();
579
- } else {
580
- withSelector.exports = requireWithSelector_development();
581
- }
582
-
583
- var withSelectorExports = withSelector.exports;
584
- var useSyncExternalStoreExports = /*@__PURE__*/getDefaultExportFromCjs(withSelectorExports);
585
-
586
- const { useDebugValue } = require$$0;
587
- const { useSyncExternalStoreWithSelector } = useSyncExternalStoreExports;
588
- let didWarnAboutEqualityFn = false;
589
295
  const identity = (arg) => arg;
590
- function useStore(api, selector = identity, equalityFn) {
591
- if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && equalityFn && !didWarnAboutEqualityFn) {
592
- console.warn(
593
- "[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"
594
- );
595
- didWarnAboutEqualityFn = true;
596
- }
597
- const slice = useSyncExternalStoreWithSelector(
296
+ function useStore(api, selector = identity) {
297
+ const slice = React$1.useSyncExternalStore(
598
298
  api.subscribe,
599
- api.getState,
600
- api.getServerState || api.getInitialState,
601
- selector,
602
- equalityFn
299
+ React$1.useCallback(() => selector(api.getState()), [api, selector]),
300
+ React$1.useCallback(() => selector(api.getInitialState()), [api, selector])
603
301
  );
604
- useDebugValue(slice);
302
+ React$1.useDebugValue(slice);
605
303
  return slice;
606
304
  }
607
305
  const createImpl = (createState) => {
608
- if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && typeof createState !== "function") {
609
- console.warn(
610
- "[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`."
611
- );
612
- }
613
- const api = typeof createState === "function" ? createStore(createState) : createState;
614
- const useBoundStore = (selector, equalityFn) => useStore(api, selector, equalityFn);
306
+ const api = createStore(createState);
307
+ const useBoundStore = (selector) => useStore(api, selector);
615
308
  Object.assign(useBoundStore, api);
616
309
  return useBoundStore;
617
310
  };
618
- const create = (createState) => createState ? createImpl(createState) : createImpl;
311
+ const create = ((createState) => createState ? createImpl(createState) : createImpl);
619
312
 
620
313
  // Estado: { user, loading, error }
621
314
  const useAuthStore = create((set, get) => ({
622
315
  user: null,
623
316
  loading: true,
624
317
  error: null,
318
+ // Loading states granulares
319
+ loadingStates: {
320
+ signIn: false,
321
+ signUp: false,
322
+ signOut: false,
323
+ magicLink: false,
324
+ verifyMagicLink: false,
325
+ resetPassword: false,
326
+ verifyEmail: false,
327
+ resendVerification: false
328
+ },
329
+ // Helper para atualizar loading states
330
+ setLoading: (key, value) => set(state => ({
331
+ loadingStates: {
332
+ ...state.loadingStates,
333
+ [key]: value
334
+ }
335
+ })),
625
336
  /* Init ao montar o Provider */
626
337
  init: async () => {
627
338
  try {
628
- // Verifica se há um token válido e obtém dados do usuário
339
+ // Verifica se há um token válido
629
340
  if (isAuthenticated()) {
630
- const user = getCurrentUser();
631
- set({
632
- user,
633
- loading: false
634
- });
341
+ // Tenta extrair usuário do token (JWT)
342
+ let user = getCurrentUser();
343
+
344
+ // Se o token for opaco (não-JWT), getCurrentUser retorna null.
345
+ // Precisamos buscar a sessão no servidor.
346
+ if (!user) {
347
+ try {
348
+ const session = await getSession();
349
+ if (session?.user) {
350
+ user = session.user;
351
+ }
352
+ } catch (sessionError) {
353
+ console.warn('[AuthStore] Failed to fetch session:', sessionError);
354
+ }
355
+ }
356
+ if (user) {
357
+ set({
358
+ user,
359
+ loading: false
360
+ });
361
+ } else {
362
+ set({
363
+ user: null,
364
+ loading: false
365
+ });
366
+ }
635
367
  } else {
636
368
  set({
637
369
  user: null,
@@ -646,57 +378,237 @@ const useAuthStore = create((set, get) => ({
646
378
  });
647
379
  }
648
380
  },
649
- /* Ações */
650
- signUp: async (email, password) => {
381
+ /* Ações de Autenticação */
382
+ signUp: async (email, password, name) => {
383
+ const {
384
+ setLoading
385
+ } = get();
386
+ setLoading('signUp', true);
651
387
  set({
652
- loading: true,
653
388
  error: null
654
389
  });
655
390
  try {
656
- const result = await signUp(email, password);
391
+ const result = await signUp(email, password, name);
657
392
  const user = getCurrentUser();
658
393
  set({
659
394
  user,
660
395
  loading: false
661
396
  });
397
+ setLoading('signUp', false);
662
398
  return result;
663
399
  } catch (err) {
664
400
  set({
665
- error: err,
666
- loading: false
401
+ error: err
667
402
  });
403
+ setLoading('signUp', false);
668
404
  throw err;
669
405
  }
670
406
  },
671
407
  signIn: async (email, password) => {
408
+ const {
409
+ setLoading
410
+ } = get();
411
+ setLoading('signIn', true);
672
412
  set({
673
- loading: true,
674
413
  error: null
675
414
  });
676
415
  try {
677
416
  const result = await signIn(email, password);
678
- const user = getCurrentUser();
417
+
418
+ // Tenta obter usuário do token (se JWT)
419
+ let user = getCurrentUser();
420
+
421
+ // Se não encontrou no token (sessão opaca), busca do servidor
422
+ if (!user) {
423
+ const session = await getSession();
424
+ if (session?.user) user = session.user;
425
+ }
679
426
  set({
680
427
  user,
681
428
  loading: false
682
429
  });
430
+ setLoading('signIn', false);
683
431
  return result;
684
432
  } catch (err) {
685
433
  set({
686
- error: err,
687
- loading: false
434
+ error: err
688
435
  });
436
+ setLoading('signIn', false);
689
437
  throw err;
690
438
  }
691
439
  },
692
440
  signOut: async () => {
693
- await signOut();
441
+ const {
442
+ setLoading
443
+ } = get();
444
+ setLoading('signOut', true);
445
+ try {
446
+ await signOut();
447
+ set({
448
+ user: null
449
+ });
450
+ // Sincronizar logout entre abas
451
+ if (typeof window !== 'undefined') {
452
+ window.localStorage.setItem('auth:logout', Date.now());
453
+ }
454
+ } finally {
455
+ setLoading('signOut', false);
456
+ }
457
+ },
458
+ /* Magic Link */
459
+ sendMagicLink: async (email, callbackURL) => {
460
+ const {
461
+ setLoading
462
+ } = get();
463
+ setLoading('magicLink', true);
694
464
  set({
695
- user: null
465
+ error: null
696
466
  });
697
- // Sincronizar logout entre abas
698
- if (typeof window !== 'undefined') {
699
- window.localStorage.setItem("auth:logout", Date.now());
467
+ try {
468
+ const result = await sendMagicLink(email, callbackURL);
469
+ setLoading('magicLink', false);
470
+ return result;
471
+ } catch (err) {
472
+ set({
473
+ error: err
474
+ });
475
+ setLoading('magicLink', false);
476
+ throw err;
477
+ }
478
+ },
479
+ verifyMagicLink: async token => {
480
+ const {
481
+ setLoading
482
+ } = get();
483
+ setLoading('verifyMagicLink', true);
484
+ set({
485
+ error: null
486
+ });
487
+ try {
488
+ const result = await verifyMagicLink(token);
489
+ let user = result.user;
490
+
491
+ // Se não veio no resultado, tenta pegar do token ou do servidor
492
+ if (!user) {
493
+ user = getCurrentUser();
494
+ if (!user) {
495
+ const session = await getSession();
496
+ if (session?.user) user = session.user;
497
+ }
498
+ }
499
+ if (user) {
500
+ set({
501
+ user,
502
+ loading: false
503
+ });
504
+ }
505
+ setLoading('verifyMagicLink', false);
506
+ return result;
507
+ } catch (err) {
508
+ set({
509
+ error: err
510
+ });
511
+ setLoading('verifyMagicLink', false);
512
+ throw err;
513
+ }
514
+ },
515
+ /* Password Reset */
516
+ forgotPassword: async (email, redirectTo) => {
517
+ const {
518
+ setLoading
519
+ } = get();
520
+ setLoading('resetPassword', true);
521
+ set({
522
+ error: null
523
+ });
524
+ try {
525
+ const result = await forgotPassword(email, redirectTo);
526
+ setLoading('resetPassword', false);
527
+ return result;
528
+ } catch (err) {
529
+ set({
530
+ error: err
531
+ });
532
+ setLoading('resetPassword', false);
533
+ throw err;
534
+ }
535
+ },
536
+ resetPassword: async (token, newPassword) => {
537
+ const {
538
+ setLoading
539
+ } = get();
540
+ setLoading('resetPassword', true);
541
+ set({
542
+ error: null
543
+ });
544
+ try {
545
+ const result = await resetPassword(token, newPassword);
546
+ setLoading('resetPassword', false);
547
+ return result;
548
+ } catch (err) {
549
+ set({
550
+ error: err
551
+ });
552
+ setLoading('resetPassword', false);
553
+ throw err;
554
+ }
555
+ },
556
+ /* Email Verification */
557
+ verifyEmail: async token => {
558
+ const {
559
+ setLoading
560
+ } = get();
561
+ setLoading('verifyEmail', true);
562
+ set({
563
+ error: null
564
+ });
565
+ try {
566
+ const result = await verifyEmail(token);
567
+ if (result.user) {
568
+ set({
569
+ user: result.user,
570
+ loading: false
571
+ });
572
+ }
573
+ setLoading('verifyEmail', false);
574
+ return result;
575
+ } catch (err) {
576
+ set({
577
+ error: err
578
+ });
579
+ setLoading('verifyEmail', false);
580
+ throw err;
581
+ }
582
+ },
583
+ resendVerification: async (email, callbackURL) => {
584
+ const {
585
+ setLoading
586
+ } = get();
587
+ setLoading('resendVerification', true);
588
+ set({
589
+ error: null
590
+ });
591
+ try {
592
+ const result = await resendVerification(email, callbackURL);
593
+ setLoading('resendVerification', false);
594
+ return result;
595
+ } catch (err) {
596
+ set({
597
+ error: err
598
+ });
599
+ setLoading('resendVerification', false);
600
+ throw err;
601
+ }
602
+ },
603
+ /* Session */
604
+ getSession: async () => {
605
+ try {
606
+ return await getSession();
607
+ } catch (err) {
608
+ set({
609
+ error: err
610
+ });
611
+ throw err;
700
612
  }
701
613
  },
702
614
  /* Refresh do token em background */
@@ -709,7 +621,10 @@ const useAuthStore = create((set, get) => ({
709
621
  const token = window.localStorage.getItem('auth:token');
710
622
  if (token) {
711
623
  // Decodifica o token para verificar tempo de expiração
712
- const payload = JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
624
+ const base64Url = token.split('.')[1];
625
+ const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
626
+ const jsonPayload = window.atob(base64);
627
+ const payload = JSON.parse(jsonPayload);
713
628
  const now = Date.now() / 1000;
714
629
  const timeUntilExpiry = payload.exp - now;
715
630
 
@@ -750,17 +665,41 @@ const useAuthStore = create((set, get) => ({
750
665
  return false;
751
666
  }
752
667
  return true;
753
- }
668
+ },
669
+ /* Atualizar usuário manualmente */
670
+ setUser: user => set({
671
+ user
672
+ })
754
673
  }));
755
674
 
756
675
  const AuthContext = /*#__PURE__*/createContext(); // só para ter o Provider em JSX
757
676
 
758
677
  function AuthProvider({
759
- children
678
+ children,
679
+ apiUrl,
680
+ // URL base da API (OBRIGATÓRIA)
681
+ apiKey,
682
+ // API Key para header X-API-Key (OBRIGATÓRIA)
683
+ onError // Callback de erro global
760
684
  }) {
685
+ // Validação de props obrigatórias
686
+ if (!apiKey) {
687
+ throw new Error('[@riligar/auth-react] apiKey é obrigatória no AuthProvider. ' + 'Obtenha sua API Key no dashboard em https://dashboard.myauth.click');
688
+ }
689
+ if (!apiUrl) {
690
+ throw new Error('[@riligar/auth-react] apiUrl é obrigatória no AuthProvider. ' + 'Use a URL do seu servidor de autenticação.');
691
+ }
761
692
  const init = useAuthStore(s => s.init);
762
693
  const startRefresh = useAuthStore(s => s.startRefresh);
763
694
  const checkTokenValidity = useAuthStore(s => s.checkTokenValidity);
695
+
696
+ // Configura SDK com apiUrl e apiKey
697
+ useEffect(() => {
698
+ configure({
699
+ apiUrl,
700
+ apiKey
701
+ });
702
+ }, [apiUrl, apiKey]);
764
703
  useEffect(() => {
765
704
  init();
766
705
  startRefresh();
@@ -791,8 +730,13 @@ function AuthProvider({
791
730
 
792
731
  return () => clearInterval(interval);
793
732
  }, [checkTokenValidity]);
733
+
734
+ // Contexto com onError callback
735
+ const contextValue = useMemo(() => ({
736
+ onError
737
+ }), [onError]);
794
738
  return /*#__PURE__*/React.createElement(AuthContext.Provider, {
795
- value: null /* valor irrelevante */
739
+ value: contextValue
796
740
  }, children);
797
741
  }
798
742
 
@@ -803,11 +747,74 @@ const useAuth = () => useAuthStore(s => ({
803
747
  error: s.error,
804
748
  isAuthenticated: s.user !== null
805
749
  }));
750
+
751
+ // Auth Actions
806
752
  const useSignIn = () => useAuthStore(s => s.signIn);
807
753
  const useSignUp = () => useAuthStore(s => s.signUp);
808
754
  const useSignOut = () => useAuthStore(s => s.signOut);
809
755
  const useCheckToken = () => useAuthStore(s => s.checkTokenValidity);
810
756
 
757
+ // Magic Link Hook
758
+ const useMagicLink = () => {
759
+ const sendMagicLink = useAuthStore(s => s.sendMagicLink);
760
+ const verifyMagicLink = useAuthStore(s => s.verifyMagicLink);
761
+ const loading = useAuthStore(s => s.loadingStates.magicLink);
762
+ const verifying = useAuthStore(s => s.loadingStates.verifyMagicLink);
763
+ const error = useAuthStore(s => s.error);
764
+ return {
765
+ sendMagicLink,
766
+ verifyMagicLink,
767
+ loading,
768
+ verifying,
769
+ error
770
+ };
771
+ };
772
+
773
+ // Password Reset Hook
774
+ const usePasswordReset = () => {
775
+ const forgotPassword = useAuthStore(s => s.forgotPassword);
776
+ const resetPassword = useAuthStore(s => s.resetPassword);
777
+ const loading = useAuthStore(s => s.loadingStates.resetPassword);
778
+ const error = useAuthStore(s => s.error);
779
+ return {
780
+ forgotPassword,
781
+ resetPassword,
782
+ loading,
783
+ error
784
+ };
785
+ };
786
+
787
+ // Email Verification Hook
788
+ const useEmailVerification = () => {
789
+ const verifyEmail = useAuthStore(s => s.verifyEmail);
790
+ const resendVerification = useAuthStore(s => s.resendVerification);
791
+ const loading = useAuthStore(s => s.loadingStates.verifyEmail);
792
+ const resending = useAuthStore(s => s.loadingStates.resendVerification);
793
+ const error = useAuthStore(s => s.error);
794
+ return {
795
+ verifyEmail,
796
+ resendVerification,
797
+ loading,
798
+ resending,
799
+ error
800
+ };
801
+ };
802
+
803
+ // Session Hook
804
+ const useSession = () => {
805
+ const getSession = useAuthStore(s => s.getSession);
806
+ const user = useAuthStore(s => s.user);
807
+ const setUser = useAuthStore(s => s.setUser);
808
+ return {
809
+ getSession,
810
+ user,
811
+ setUser
812
+ };
813
+ };
814
+
815
+ // Loading States Hook
816
+ const useAuthLoading = () => useAuthStore(s => s.loadingStates);
817
+
811
818
  function ProtectedRoute({
812
819
  fallback = /*#__PURE__*/React.createElement("p", null, "\u231B Carregando..."),
813
820
  redirectTo = "/login"
@@ -824,5 +831,787 @@ function ProtectedRoute({
824
831
  return /*#__PURE__*/React.createElement(Outlet, null);
825
832
  }
826
833
 
827
- export { AuthProvider, ProtectedRoute, getCurrentUser, isAuthenticated, refreshToken, signIn, signOut, signUp, socialRedirect, useAuth, useAuthStore, useCheckToken, useSignIn, useSignOut, useSignUp };
834
+ function _extends() {
835
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
836
+ for (var e = 1; e < arguments.length; e++) {
837
+ var t = arguments[e];
838
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
839
+ }
840
+ return n;
841
+ }, _extends.apply(null, arguments);
842
+ }
843
+
844
+ /**
845
+ * Container wrapper para componentes de autenticação
846
+ * Usa Mantine Paper com estilo consistente
847
+ */
848
+ function AuthCard({
849
+ children,
850
+ title,
851
+ subtitle,
852
+ logo,
853
+ logoHeight = 32,
854
+ width = 350,
855
+ ...props
856
+ }) {
857
+ return /*#__PURE__*/React.createElement(Paper, _extends({
858
+ withBorder: true,
859
+ shadow: "md",
860
+ p: 24,
861
+ w: width,
862
+ radius: "md"
863
+ }, props), /*#__PURE__*/React.createElement(Stack, {
864
+ gap: "sm"
865
+ }, (logo || title || subtitle) && /*#__PURE__*/React.createElement(Stack, {
866
+ gap: "xs"
867
+ }, logo && /*#__PURE__*/React.createElement(Image, {
868
+ src: logo,
869
+ alt: "Auth",
870
+ h: logoHeight,
871
+ fit: "contain"
872
+ }), title && /*#__PURE__*/React.createElement(Title, {
873
+ order: 3
874
+ }, title), subtitle && /*#__PURE__*/React.createElement(Text, {
875
+ size: "sm",
876
+ c: "dimmed"
877
+ }, subtitle)), children));
878
+ }
879
+
880
+ var img = "data:image/webp;base64,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";
881
+
882
+ /**
883
+ * Formulário de Sign In completo com Mantine
884
+ * Suporta email/password, magic link, social login
885
+ */
886
+ function SignInForm({
887
+ // Configuração
888
+ logo = img,
889
+ title = 'Entrar',
890
+ subtitle = 'Acesse sua conta para continuar',
891
+ // Features
892
+ showMagicLink = true,
893
+ showForgotPassword = true,
894
+ showSocialLogin = false,
895
+ showSignUpLink = true,
896
+ // Links
897
+ signUpUrl = '/auth/signup',
898
+ // Callbacks
899
+ onSuccess,
900
+ onError,
901
+ onMagicLinkSent,
902
+ onForgotPasswordSent,
903
+ onSocialLogin,
904
+ // Custom labels
905
+ labels = {},
906
+ ...cardProps
907
+ }) {
908
+ const signIn = useAuthStore(s => s.signIn);
909
+ const sendMagicLink = useAuthStore(s => s.sendMagicLink);
910
+ const forgotPassword = useAuthStore(s => s.forgotPassword);
911
+ const loadingSignIn = useAuthStore(s => s.loadingStates.signIn);
912
+ const loadingMagicLink = useAuthStore(s => s.loadingStates.magicLink);
913
+ const loadingResetPassword = useAuthStore(s => s.loadingStates.resetPassword);
914
+ const form = useForm({
915
+ initialValues: {
916
+ email: '',
917
+ password: ''
918
+ },
919
+ validate: {
920
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido',
921
+ password: value => value.length < 6 ? labels.passwordTooShort || 'A senha deve ter pelo menos 6 caracteres' : null
922
+ }
923
+ });
924
+ const handleSubmit = async values => {
925
+ try {
926
+ const result = await signIn(values.email, values.password);
927
+ onSuccess?.(result);
928
+ } catch (error) {
929
+ onError?.(error);
930
+ }
931
+ };
932
+ const handleMagicLink = async () => {
933
+ if (!form.values.email) {
934
+ form.setFieldError('email', labels.emailRequired || 'Email obrigatório');
935
+ return;
936
+ }
937
+ try {
938
+ await sendMagicLink(form.values.email);
939
+ onMagicLinkSent?.(form.values.email);
940
+ } catch (error) {
941
+ onError?.(error);
942
+ }
943
+ };
944
+ const handleForgotPassword = async () => {
945
+ if (!form.values.email) {
946
+ form.setFieldError('email', labels.emailRequired || 'Email obrigatório');
947
+ return;
948
+ }
949
+ try {
950
+ await forgotPassword(form.values.email);
951
+ onForgotPasswordSent?.(form.values.email);
952
+ } catch (error) {
953
+ onError?.(error);
954
+ }
955
+ };
956
+ const isLoading = loadingSignIn || loadingMagicLink || loadingResetPassword;
957
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
958
+ logo: logo,
959
+ title: title,
960
+ subtitle: subtitle
961
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
962
+ onSubmit: form.onSubmit(handleSubmit)
963
+ }, /*#__PURE__*/React.createElement(Stack, {
964
+ gap: "sm"
965
+ }, /*#__PURE__*/React.createElement(TextInput, _extends({
966
+ label: labels.email || 'Email',
967
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
968
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
969
+ size: 16
970
+ })
971
+ }, form.getInputProps('email'), {
972
+ disabled: isLoading
973
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
974
+ label: labels.password || 'Senha',
975
+ placeholder: labels.passwordPlaceholder || 'Sua senha',
976
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
977
+ size: 16
978
+ })
979
+ }, form.getInputProps('password'), {
980
+ disabled: isLoading
981
+ })), showForgotPassword && /*#__PURE__*/React.createElement(Anchor, {
982
+ size: "sm",
983
+ ta: "right",
984
+ onClick: handleForgotPassword,
985
+ style: {
986
+ cursor: 'pointer'
987
+ },
988
+ c: loadingResetPassword ? 'dimmed' : 'blue'
989
+ }, loadingResetPassword ? labels.sendingReset || 'Enviando...' : labels.forgotPassword || 'Esqueceu a senha?'), /*#__PURE__*/React.createElement(Button, {
990
+ type: "submit",
991
+ fullWidth: true,
992
+ loading: loadingSignIn,
993
+ rightSection: /*#__PURE__*/React.createElement(IconArrowRight, {
994
+ size: 16
995
+ })
996
+ }, labels.signInButton || 'Entrar'))), showMagicLink && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, {
997
+ label: labels.orContinueWith || 'Ou continue com'
998
+ }), /*#__PURE__*/React.createElement(Button, {
999
+ variant: "light",
1000
+ fullWidth: true,
1001
+ loading: loadingMagicLink,
1002
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1003
+ size: 16
1004
+ }),
1005
+ onClick: handleMagicLink,
1006
+ disabled: isLoading || !form.values.email
1007
+ }, labels.magicLinkButton || 'Enviar Link Mágico')), showSocialLogin && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Group, {
1008
+ grow: true
1009
+ }, /*#__PURE__*/React.createElement(Button, {
1010
+ variant: "light",
1011
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGoogle, {
1012
+ size: 16
1013
+ }),
1014
+ onClick: () => onSocialLogin?.('google'),
1015
+ disabled: isLoading
1016
+ }, "Google"), /*#__PURE__*/React.createElement(Button, {
1017
+ variant: "light",
1018
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGithub, {
1019
+ size: 16
1020
+ }),
1021
+ onClick: () => onSocialLogin?.('github'),
1022
+ disabled: isLoading
1023
+ }, "GitHub"))), showSignUpLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1024
+ size: "sm",
1025
+ c: "dimmed"
1026
+ }, labels.noAccount || 'Não tem uma conta?', " ", /*#__PURE__*/React.createElement(Anchor, {
1027
+ href: signUpUrl
1028
+ }, labels.createAccount || 'Criar conta'))));
1029
+ }
1030
+
1031
+ /**
1032
+ * Formulário de Sign Up com Mantine
1033
+ */
1034
+ function SignUpForm({
1035
+ // Configuração
1036
+ logo = img,
1037
+ title = 'Criar Conta',
1038
+ subtitle = 'Preencha os dados para se cadastrar',
1039
+ // Features
1040
+ requireName = true,
1041
+ showSignInLink = true,
1042
+ showSocialLogin = false,
1043
+ // Links
1044
+ signInUrl = '/auth/signin',
1045
+ // Callbacks
1046
+ onSuccess,
1047
+ onError,
1048
+ onSocialLogin,
1049
+ // Custom labels
1050
+ labels = {},
1051
+ ...cardProps
1052
+ }) {
1053
+ const signUp = useAuthStore(s => s.signUp);
1054
+ const loading = useAuthStore(s => s.loadingStates.signUp);
1055
+ const form = useForm({
1056
+ initialValues: {
1057
+ name: '',
1058
+ email: '',
1059
+ password: '',
1060
+ confirmPassword: ''
1061
+ },
1062
+ validate: {
1063
+ name: value => requireName && !value ? labels.nameRequired || 'Nome obrigatório' : null,
1064
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido',
1065
+ password: value => value.length < 6 ? labels.passwordTooShort || 'A senha deve ter pelo menos 6 caracteres' : null,
1066
+ confirmPassword: (value, values) => value !== values.password ? labels.passwordMismatch || 'As senhas não coincidem' : null
1067
+ }
1068
+ });
1069
+ const handleSubmit = async values => {
1070
+ try {
1071
+ const result = await signUp(values.email, values.password, values.name);
1072
+ onSuccess?.(result);
1073
+ } catch (error) {
1074
+ onError?.(error);
1075
+ }
1076
+ };
1077
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1078
+ logo: logo,
1079
+ title: title,
1080
+ subtitle: subtitle
1081
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1082
+ onSubmit: form.onSubmit(handleSubmit)
1083
+ }, /*#__PURE__*/React.createElement(Stack, {
1084
+ gap: "sm"
1085
+ }, requireName && /*#__PURE__*/React.createElement(TextInput, _extends({
1086
+ label: labels.name || 'Nome',
1087
+ placeholder: labels.namePlaceholder || 'Seu nome',
1088
+ leftSection: /*#__PURE__*/React.createElement(IconUser, {
1089
+ size: 16
1090
+ })
1091
+ }, form.getInputProps('name'), {
1092
+ disabled: loading
1093
+ })), /*#__PURE__*/React.createElement(TextInput, _extends({
1094
+ label: labels.email || 'Email',
1095
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
1096
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1097
+ size: 16
1098
+ })
1099
+ }, form.getInputProps('email'), {
1100
+ disabled: loading
1101
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
1102
+ label: labels.password || 'Senha',
1103
+ placeholder: labels.passwordPlaceholder || 'Crie uma senha',
1104
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1105
+ size: 16
1106
+ })
1107
+ }, form.getInputProps('password'), {
1108
+ disabled: loading
1109
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
1110
+ label: labels.confirmPassword || 'Confirmar Senha',
1111
+ placeholder: labels.confirmPasswordPlaceholder || 'Repita a senha',
1112
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1113
+ size: 16
1114
+ })
1115
+ }, form.getInputProps('confirmPassword'), {
1116
+ disabled: loading
1117
+ })), /*#__PURE__*/React.createElement(Button, {
1118
+ type: "submit",
1119
+ fullWidth: true,
1120
+ loading: loading,
1121
+ rightSection: /*#__PURE__*/React.createElement(IconArrowRight, {
1122
+ size: 16
1123
+ })
1124
+ }, labels.signUpButton || 'Criar Conta'))), showSocialLogin && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, {
1125
+ label: labels.orContinueWith || 'Ou continue com'
1126
+ }), /*#__PURE__*/React.createElement(Group, {
1127
+ grow: true
1128
+ }, /*#__PURE__*/React.createElement(Button, {
1129
+ variant: "light",
1130
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGoogle, {
1131
+ size: 16
1132
+ }),
1133
+ onClick: () => onSocialLogin?.('google'),
1134
+ disabled: loading
1135
+ }, "Google"), /*#__PURE__*/React.createElement(Button, {
1136
+ variant: "light",
1137
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGithub, {
1138
+ size: 16
1139
+ }),
1140
+ onClick: () => onSocialLogin?.('github'),
1141
+ disabled: loading
1142
+ }, "GitHub"))), showSignInLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1143
+ size: "sm",
1144
+ c: "dimmed"
1145
+ }, labels.hasAccount || 'Já tem uma conta?', " ", /*#__PURE__*/React.createElement(Anchor, {
1146
+ href: signInUrl
1147
+ }, labels.signIn || 'Entrar'))));
1148
+ }
1149
+
1150
+ /**
1151
+ * Formulário para envio de Magic Link
1152
+ */
1153
+ function MagicLinkForm({
1154
+ // Configuração
1155
+ logo = img,
1156
+ title = 'Login sem Senha',
1157
+ subtitle = 'Receba um link de acesso no seu email',
1158
+ // Features
1159
+ showSignInLink = true,
1160
+ // Links
1161
+ signInUrl = '/auth/signin',
1162
+ // Callbacks
1163
+ onSent,
1164
+ onError,
1165
+ // Custom labels
1166
+ labels = {},
1167
+ ...cardProps
1168
+ }) {
1169
+ const sendMagicLink = useAuthStore(s => s.sendMagicLink);
1170
+ const loading = useAuthStore(s => s.loadingStates.magicLink);
1171
+ const form = useForm({
1172
+ initialValues: {
1173
+ email: ''
1174
+ },
1175
+ validate: {
1176
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido'
1177
+ }
1178
+ });
1179
+ const handleSubmit = async values => {
1180
+ try {
1181
+ await sendMagicLink(values.email);
1182
+ onSent?.(values.email);
1183
+ } catch (error) {
1184
+ onError?.(error);
1185
+ }
1186
+ };
1187
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1188
+ logo: logo,
1189
+ title: title,
1190
+ subtitle: subtitle
1191
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1192
+ onSubmit: form.onSubmit(handleSubmit)
1193
+ }, /*#__PURE__*/React.createElement(Stack, {
1194
+ gap: "sm"
1195
+ }, /*#__PURE__*/React.createElement(TextInput, _extends({
1196
+ label: labels.email || 'Email',
1197
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
1198
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1199
+ size: 16
1200
+ })
1201
+ }, form.getInputProps('email'), {
1202
+ disabled: loading
1203
+ })), /*#__PURE__*/React.createElement(Button, {
1204
+ type: "submit",
1205
+ fullWidth: true,
1206
+ loading: loading,
1207
+ leftSection: /*#__PURE__*/React.createElement(IconSend, {
1208
+ size: 16
1209
+ })
1210
+ }, labels.sendButton || 'Enviar Link Mágico'))), showSignInLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1211
+ size: "sm",
1212
+ c: "dimmed"
1213
+ }, labels.backTo || 'Voltar para', " ", /*#__PURE__*/React.createElement(Anchor, {
1214
+ href: signInUrl
1215
+ }, labels.signIn || 'login com senha'))));
1216
+ }
1217
+
1218
+ /**
1219
+ * Componente de verificação de Magic Link
1220
+ * Extrai token da URL e verifica automaticamente
1221
+ */
1222
+ function MagicLinkVerify({
1223
+ // Configuração
1224
+ logo = img,
1225
+ // Token pode ser passado diretamente ou extraído da URL
1226
+ token: propToken,
1227
+ // Callbacks
1228
+ onSuccess,
1229
+ onError,
1230
+ // Redirect após sucesso/erro
1231
+ redirectTo,
1232
+ redirectDelay = 2000,
1233
+ // Custom labels
1234
+ labels = {},
1235
+ ...cardProps
1236
+ }) {
1237
+ const [status, setStatus] = useState('verifying'); // verifying, success, error
1238
+ const [errorMessage, setErrorMessage] = useState('');
1239
+ const verifyMagicLink = useAuthStore(s => s.verifyMagicLink);
1240
+ useEffect(() => {
1241
+ const verify = async () => {
1242
+ // Pega token da prop ou da URL
1243
+ let token = propToken;
1244
+ if (!token && typeof window !== 'undefined') {
1245
+ const urlParams = new URLSearchParams(window.location.search);
1246
+ token = urlParams.get('token');
1247
+ }
1248
+ if (!token) {
1249
+ setStatus('error');
1250
+ setErrorMessage(labels.noToken || 'Token não encontrado na URL');
1251
+ onError?.(new Error('No token'));
1252
+ return;
1253
+ }
1254
+ try {
1255
+ const result = await verifyMagicLink(token);
1256
+ setStatus('success');
1257
+ onSuccess?.(result);
1258
+ if (redirectTo) {
1259
+ setTimeout(() => {
1260
+ window.location.href = redirectTo;
1261
+ }, redirectDelay);
1262
+ }
1263
+ } catch (error) {
1264
+ setStatus('error');
1265
+ setErrorMessage(error.message || labels.verificationFailed || 'Verificação falhou');
1266
+ onError?.(error);
1267
+ }
1268
+ };
1269
+ verify();
1270
+ }, [propToken, verifyMagicLink, onSuccess, onError, redirectTo, redirectDelay, labels]);
1271
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1272
+ logo: logo
1273
+ }, cardProps), status === 'verifying' && /*#__PURE__*/React.createElement(Stack, {
1274
+ align: "center",
1275
+ gap: "sm"
1276
+ }, /*#__PURE__*/React.createElement(Loader, {
1277
+ size: "lg"
1278
+ }), /*#__PURE__*/React.createElement(Title, {
1279
+ order: 4
1280
+ }, labels.verifying || 'Verificando Link Mágico'), /*#__PURE__*/React.createElement(Text, {
1281
+ size: "sm",
1282
+ c: "dimmed",
1283
+ ta: "center"
1284
+ }, labels.pleaseWait || 'Aguarde enquanto autenticamos você...')), status === 'success' && /*#__PURE__*/React.createElement(Stack, {
1285
+ align: "center",
1286
+ gap: "sm"
1287
+ }, /*#__PURE__*/React.createElement(IconCheck, {
1288
+ size: 48,
1289
+ color: "var(--mantine-color-green-6)"
1290
+ }), /*#__PURE__*/React.createElement(Title, {
1291
+ order: 4
1292
+ }, labels.success || 'Autenticado com Sucesso!'), /*#__PURE__*/React.createElement(Text, {
1293
+ size: "sm",
1294
+ c: "dimmed",
1295
+ ta: "center"
1296
+ }, redirectTo ? labels.redirecting || 'Redirecionando...' : labels.authenticated || 'Você está autenticado.')), status === 'error' && /*#__PURE__*/React.createElement(Stack, {
1297
+ align: "center",
1298
+ gap: "sm"
1299
+ }, /*#__PURE__*/React.createElement(IconX, {
1300
+ size: 48,
1301
+ color: "var(--mantine-color-red-6)"
1302
+ }), /*#__PURE__*/React.createElement(Title, {
1303
+ order: 4
1304
+ }, labels.failed || 'Falha na Autenticação'), /*#__PURE__*/React.createElement(Text, {
1305
+ size: "sm",
1306
+ c: "dimmed",
1307
+ ta: "center"
1308
+ }, errorMessage || labels.invalidLink || 'O link é inválido ou expirou.')));
1309
+ }
1310
+
1311
+ /**
1312
+ * Formulário para solicitar reset de senha
1313
+ */
1314
+ function ForgotPasswordForm({
1315
+ // Configuração
1316
+ logo = img,
1317
+ title = 'Recuperar Senha',
1318
+ subtitle = 'Enviaremos um link para redefinir sua senha',
1319
+ // Features
1320
+ showSignInLink = true,
1321
+ // Links
1322
+ signInUrl = '/auth/signin',
1323
+ // Callbacks
1324
+ onSent,
1325
+ onError,
1326
+ // Custom labels
1327
+ labels = {},
1328
+ ...cardProps
1329
+ }) {
1330
+ const forgotPassword = useAuthStore(s => s.forgotPassword);
1331
+ const loading = useAuthStore(s => s.loadingStates.resetPassword);
1332
+ const form = useForm({
1333
+ initialValues: {
1334
+ email: ''
1335
+ },
1336
+ validate: {
1337
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido'
1338
+ }
1339
+ });
1340
+ const handleSubmit = async values => {
1341
+ try {
1342
+ await forgotPassword(values.email);
1343
+ onSent?.(values.email);
1344
+ } catch (error) {
1345
+ onError?.(error);
1346
+ }
1347
+ };
1348
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1349
+ logo: logo,
1350
+ title: title,
1351
+ subtitle: subtitle
1352
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1353
+ onSubmit: form.onSubmit(handleSubmit)
1354
+ }, /*#__PURE__*/React.createElement(Stack, {
1355
+ gap: "sm"
1356
+ }, /*#__PURE__*/React.createElement(TextInput, _extends({
1357
+ label: labels.email || 'Email',
1358
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
1359
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1360
+ size: 16
1361
+ })
1362
+ }, form.getInputProps('email'), {
1363
+ disabled: loading
1364
+ })), /*#__PURE__*/React.createElement(Button, {
1365
+ type: "submit",
1366
+ fullWidth: true,
1367
+ loading: loading,
1368
+ leftSection: /*#__PURE__*/React.createElement(IconSend, {
1369
+ size: 16
1370
+ })
1371
+ }, labels.sendButton || 'Enviar Link de Recuperação'))), showSignInLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1372
+ size: "sm",
1373
+ c: "dimmed"
1374
+ }, labels.rememberedPassword || 'Lembrou a senha?', " ", /*#__PURE__*/React.createElement(Anchor, {
1375
+ href: signInUrl
1376
+ }, labels.signIn || 'Entrar'))));
1377
+ }
1378
+
1379
+ /**
1380
+ * Formulário para redefinir senha com token
1381
+ */
1382
+ function ResetPasswordForm({
1383
+ // Configuração
1384
+ logo = img,
1385
+ title = 'Nova Senha',
1386
+ subtitle = 'Crie uma nova senha para sua conta',
1387
+ // Token pode ser passado diretamente ou extraído da URL
1388
+ token: propToken,
1389
+ // Callbacks
1390
+ onSuccess,
1391
+ onError,
1392
+ // Redirect após sucesso
1393
+ signInUrl = '/auth/signin',
1394
+ // Custom labels
1395
+ labels = {},
1396
+ ...cardProps
1397
+ }) {
1398
+ const [token, setToken] = useState(propToken || '');
1399
+ const [success, setSuccess] = useState(false);
1400
+ const resetPassword = useAuthStore(s => s.resetPassword);
1401
+ const loading = useAuthStore(s => s.loadingStates.resetPassword);
1402
+
1403
+ // Extrai token da URL se não foi passado como prop
1404
+ useEffect(() => {
1405
+ if (!propToken && typeof window !== 'undefined') {
1406
+ const urlParams = new URLSearchParams(window.location.search);
1407
+ const urlToken = urlParams.get('token');
1408
+ if (urlToken) setToken(urlToken);
1409
+ }
1410
+ }, [propToken]);
1411
+ const form = useForm({
1412
+ initialValues: {
1413
+ password: '',
1414
+ confirmPassword: ''
1415
+ },
1416
+ validate: {
1417
+ password: value => value.length < 6 ? labels.passwordTooShort || 'A senha deve ter pelo menos 6 caracteres' : null,
1418
+ confirmPassword: (value, values) => value !== values.password ? labels.passwordMismatch || 'As senhas não coincidem' : null
1419
+ }
1420
+ });
1421
+ const handleSubmit = async values => {
1422
+ if (!token) {
1423
+ onError?.(new Error('Token não encontrado'));
1424
+ return;
1425
+ }
1426
+ try {
1427
+ await resetPassword(token, values.password);
1428
+ setSuccess(true);
1429
+ onSuccess?.();
1430
+ } catch (error) {
1431
+ onError?.(error);
1432
+ }
1433
+ };
1434
+ if (success) {
1435
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1436
+ logo: logo
1437
+ }, cardProps), /*#__PURE__*/React.createElement(Stack, {
1438
+ align: "center",
1439
+ gap: "sm"
1440
+ }, /*#__PURE__*/React.createElement(IconCheck, {
1441
+ size: 48,
1442
+ color: "var(--mantine-color-green-6)"
1443
+ }), /*#__PURE__*/React.createElement(Title, {
1444
+ order: 4
1445
+ }, labels.successTitle || 'Senha Redefinida!'), /*#__PURE__*/React.createElement(Text, {
1446
+ size: "sm",
1447
+ c: "dimmed",
1448
+ ta: "center"
1449
+ }, labels.successMessage || 'Sua senha foi alterada com sucesso.'), /*#__PURE__*/React.createElement(Button, {
1450
+ component: "a",
1451
+ href: signInUrl,
1452
+ fullWidth: true
1453
+ }, labels.goToSignIn || 'Ir para Login')));
1454
+ }
1455
+ if (!token) {
1456
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1457
+ logo: logo
1458
+ }, cardProps), /*#__PURE__*/React.createElement(Stack, {
1459
+ align: "center",
1460
+ gap: "sm"
1461
+ }, /*#__PURE__*/React.createElement(Text, {
1462
+ c: "red"
1463
+ }, labels.noToken || 'Token não encontrado na URL'), /*#__PURE__*/React.createElement(Button, {
1464
+ component: "a",
1465
+ href: signInUrl,
1466
+ variant: "light",
1467
+ fullWidth: true
1468
+ }, labels.goToSignIn || 'Voltar para Login')));
1469
+ }
1470
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1471
+ logo: logo,
1472
+ title: title,
1473
+ subtitle: subtitle
1474
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1475
+ onSubmit: form.onSubmit(handleSubmit)
1476
+ }, /*#__PURE__*/React.createElement(Stack, {
1477
+ gap: "sm"
1478
+ }, /*#__PURE__*/React.createElement(PasswordInput, _extends({
1479
+ label: labels.newPassword || 'Nova Senha',
1480
+ placeholder: labels.newPasswordPlaceholder || 'Crie uma nova senha',
1481
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1482
+ size: 16
1483
+ })
1484
+ }, form.getInputProps('password'), {
1485
+ disabled: loading
1486
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
1487
+ label: labels.confirmPassword || 'Confirmar Senha',
1488
+ placeholder: labels.confirmPasswordPlaceholder || 'Repita a nova senha',
1489
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1490
+ size: 16
1491
+ })
1492
+ }, form.getInputProps('confirmPassword'), {
1493
+ disabled: loading
1494
+ })), /*#__PURE__*/React.createElement(Button, {
1495
+ type: "submit",
1496
+ fullWidth: true,
1497
+ loading: loading
1498
+ }, labels.resetButton || 'Redefinir Senha'))));
1499
+ }
1500
+
1501
+ /**
1502
+ * Card de verificação de email
1503
+ * Verifica token automaticamente e permite reenvio
1504
+ */
1505
+ function VerifyEmailCard({
1506
+ // Configuração
1507
+ logo = img,
1508
+ // Token pode ser passado diretamente ou extraído da URL
1509
+ token: propToken,
1510
+ // Email para reenvio (opcional)
1511
+ email,
1512
+ // Callbacks
1513
+ onSuccess,
1514
+ onError,
1515
+ onResent,
1516
+ // Redirect após sucesso
1517
+ redirectTo,
1518
+ redirectDelay = 2000,
1519
+ // Custom labels
1520
+ labels = {},
1521
+ ...cardProps
1522
+ }) {
1523
+ const [status, setStatus] = useState('verifying'); // verifying, success, error
1524
+ const [errorMessage, setErrorMessage] = useState('');
1525
+ const verifyEmail = useAuthStore(s => s.verifyEmail);
1526
+ const resendVerification = useAuthStore(s => s.resendVerification);
1527
+ const loadingResend = useAuthStore(s => s.loadingStates.resendVerification);
1528
+ useEffect(() => {
1529
+ const verify = async () => {
1530
+ // Pega token da prop ou da URL
1531
+ let token = propToken;
1532
+ if (!token && typeof window !== 'undefined') {
1533
+ const urlParams = new URLSearchParams(window.location.search);
1534
+ token = urlParams.get('token');
1535
+ }
1536
+ if (!token) {
1537
+ setStatus('error');
1538
+ setErrorMessage(labels.noToken || 'Token não encontrado na URL');
1539
+ onError?.(new Error('No token'));
1540
+ return;
1541
+ }
1542
+ try {
1543
+ const result = await verifyEmail(token);
1544
+ setStatus('success');
1545
+ onSuccess?.(result);
1546
+ if (redirectTo) {
1547
+ setTimeout(() => {
1548
+ window.location.href = redirectTo;
1549
+ }, redirectDelay);
1550
+ }
1551
+ } catch (error) {
1552
+ setStatus('error');
1553
+ setErrorMessage(error.message || labels.verificationFailed || 'Verificação falhou');
1554
+ onError?.(error);
1555
+ }
1556
+ };
1557
+ verify();
1558
+ }, [propToken, verifyEmail, onSuccess, onError, redirectTo, redirectDelay, labels]);
1559
+ const handleResend = async () => {
1560
+ if (!email) return;
1561
+ try {
1562
+ await resendVerification(email);
1563
+ onResent?.(email);
1564
+ } catch (error) {
1565
+ onError?.(error);
1566
+ }
1567
+ };
1568
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1569
+ logo: logo
1570
+ }, cardProps), status === 'verifying' && /*#__PURE__*/React.createElement(Stack, {
1571
+ align: "center",
1572
+ gap: "sm"
1573
+ }, /*#__PURE__*/React.createElement(Loader, {
1574
+ size: "lg"
1575
+ }), /*#__PURE__*/React.createElement(Title, {
1576
+ order: 4
1577
+ }, labels.verifying || 'Verificando Email'), /*#__PURE__*/React.createElement(Text, {
1578
+ size: "sm",
1579
+ c: "dimmed",
1580
+ ta: "center"
1581
+ }, labels.pleaseWait || 'Aguarde enquanto verificamos seu email...')), status === 'success' && /*#__PURE__*/React.createElement(Stack, {
1582
+ align: "center",
1583
+ gap: "sm"
1584
+ }, /*#__PURE__*/React.createElement(IconCheck, {
1585
+ size: 48,
1586
+ color: "var(--mantine-color-green-6)"
1587
+ }), /*#__PURE__*/React.createElement(Title, {
1588
+ order: 4
1589
+ }, labels.success || 'Email Verificado!'), /*#__PURE__*/React.createElement(Text, {
1590
+ size: "sm",
1591
+ c: "dimmed",
1592
+ ta: "center"
1593
+ }, redirectTo ? labels.redirecting || 'Redirecionando...' : labels.verified || 'Seu email foi verificado com sucesso.')), status === 'error' && /*#__PURE__*/React.createElement(Stack, {
1594
+ align: "center",
1595
+ gap: "sm"
1596
+ }, /*#__PURE__*/React.createElement(IconX, {
1597
+ size: 48,
1598
+ color: "var(--mantine-color-red-6)"
1599
+ }), /*#__PURE__*/React.createElement(Title, {
1600
+ order: 4
1601
+ }, labels.failed || 'Verificação Falhou'), /*#__PURE__*/React.createElement(Text, {
1602
+ size: "sm",
1603
+ c: "dimmed",
1604
+ ta: "center"
1605
+ }, errorMessage || labels.invalidToken || 'O link é inválido ou expirou.'), email && /*#__PURE__*/React.createElement(Button, {
1606
+ variant: "light",
1607
+ leftSection: /*#__PURE__*/React.createElement(IconRefresh, {
1608
+ size: 16
1609
+ }),
1610
+ onClick: handleResend,
1611
+ loading: loadingResend,
1612
+ fullWidth: true
1613
+ }, labels.resend || 'Reenviar Email de Verificação')));
1614
+ }
1615
+
1616
+ export { AuthCard, AuthProvider, ForgotPasswordForm, MagicLinkForm, MagicLinkVerify, ProtectedRoute, ResetPasswordForm, SignInForm, SignUpForm, VerifyEmailCard, configure, forgotPassword, getCurrentUser, getSession, isAuthenticated, refreshToken, resendVerification, resetPassword, sendMagicLink, signIn, signOut, signUp, socialRedirect, useAuth, useAuthLoading, useAuthStore, useCheckToken, useEmailVerification, useMagicLink, usePasswordReset, useSession, useSignIn, useSignOut, useSignUp, verifyEmail, verifyMagicLink };
828
1617
  //# sourceMappingURL=index.esm.js.map