@riligar/auth-react 1.2.0 → 1.4.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
- */
482
-
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
- }
293
+ const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
582
294
 
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,103 @@ 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
 
675
+ const isIterable = (obj) => Symbol.iterator in obj;
676
+ const hasIterableEntries = (value) => (
677
+ // HACK: avoid checking entries type
678
+ "entries" in value
679
+ );
680
+ const compareEntries = (valueA, valueB) => {
681
+ const mapA = valueA instanceof Map ? valueA : new Map(valueA.entries());
682
+ const mapB = valueB instanceof Map ? valueB : new Map(valueB.entries());
683
+ if (mapA.size !== mapB.size) {
684
+ return false;
685
+ }
686
+ for (const [key, value] of mapA) {
687
+ if (!mapB.has(key) || !Object.is(value, mapB.get(key))) {
688
+ return false;
689
+ }
690
+ }
691
+ return true;
692
+ };
693
+ const compareIterables = (valueA, valueB) => {
694
+ const iteratorA = valueA[Symbol.iterator]();
695
+ const iteratorB = valueB[Symbol.iterator]();
696
+ let nextA = iteratorA.next();
697
+ let nextB = iteratorB.next();
698
+ while (!nextA.done && !nextB.done) {
699
+ if (!Object.is(nextA.value, nextB.value)) {
700
+ return false;
701
+ }
702
+ nextA = iteratorA.next();
703
+ nextB = iteratorB.next();
704
+ }
705
+ return !!nextA.done && !!nextB.done;
706
+ };
707
+ function shallow(valueA, valueB) {
708
+ if (Object.is(valueA, valueB)) {
709
+ return true;
710
+ }
711
+ if (typeof valueA !== "object" || valueA === null || typeof valueB !== "object" || valueB === null) {
712
+ return false;
713
+ }
714
+ if (Object.getPrototypeOf(valueA) !== Object.getPrototypeOf(valueB)) {
715
+ return false;
716
+ }
717
+ if (isIterable(valueA) && isIterable(valueB)) {
718
+ if (hasIterableEntries(valueA) && hasIterableEntries(valueB)) {
719
+ return compareEntries(valueA, valueB);
720
+ }
721
+ return compareIterables(valueA, valueB);
722
+ }
723
+ return compareEntries(
724
+ { entries: () => Object.entries(valueA) },
725
+ { entries: () => Object.entries(valueB) }
726
+ );
727
+ }
728
+
729
+ function useShallow(selector) {
730
+ const prev = React$1.useRef(void 0);
731
+ return (state) => {
732
+ const next = selector(state);
733
+ return shallow(prev.current, next) ? prev.current : prev.current = next;
734
+ };
735
+ }
736
+
756
737
  const AuthContext = /*#__PURE__*/createContext(); // só para ter o Provider em JSX
757
738
 
758
739
  function AuthProvider({
759
- children
740
+ children,
741
+ apiUrl,
742
+ // URL base da API (OBRIGATÓRIA)
743
+ apiKey,
744
+ // API Key para header X-API-Key (OBRIGATÓRIA)
745
+ onError // Callback de erro global
760
746
  }) {
747
+ // Validação de props obrigatórias
748
+ if (!apiKey) {
749
+ throw new Error('[@riligar/auth-react] apiKey é obrigatória no AuthProvider. ' + 'Obtenha sua API Key no dashboard em https://dashboard.myauth.click');
750
+ }
751
+ if (!apiUrl) {
752
+ throw new Error('[@riligar/auth-react] apiUrl é obrigatória no AuthProvider. ' + 'Use a URL do seu servidor de autenticação.');
753
+ }
761
754
  const init = useAuthStore(s => s.init);
762
755
  const startRefresh = useAuthStore(s => s.startRefresh);
763
756
  const checkTokenValidity = useAuthStore(s => s.checkTokenValidity);
757
+
758
+ // Configura SDK com apiUrl e apiKey
759
+ useEffect(() => {
760
+ configure({
761
+ apiUrl,
762
+ apiKey
763
+ });
764
+ }, [apiUrl, apiKey]);
764
765
  useEffect(() => {
765
766
  init();
766
767
  startRefresh();
@@ -791,23 +792,66 @@ function AuthProvider({
791
792
 
792
793
  return () => clearInterval(interval);
793
794
  }, [checkTokenValidity]);
795
+
796
+ // Contexto com onError callback
797
+ const contextValue = useMemo(() => ({
798
+ onError
799
+ }), [onError]);
794
800
  return /*#__PURE__*/React.createElement(AuthContext.Provider, {
795
- value: null /* valor irrelevante */
801
+ value: contextValue
796
802
  }, children);
797
803
  }
798
804
 
799
805
  /* Hooks "facade" que a app vai usar */
800
- const useAuth = () => useAuthStore(s => ({
806
+ const useAuth = () => useAuthStore(useShallow(s => ({
801
807
  user: s.user,
802
808
  loading: s.loading,
803
809
  error: s.error,
804
810
  isAuthenticated: s.user !== null
805
- }));
811
+ })));
812
+
813
+ // Auth Actions
806
814
  const useSignIn = () => useAuthStore(s => s.signIn);
807
815
  const useSignUp = () => useAuthStore(s => s.signUp);
808
816
  const useSignOut = () => useAuthStore(s => s.signOut);
809
817
  const useCheckToken = () => useAuthStore(s => s.checkTokenValidity);
810
818
 
819
+ // Magic Link Hook
820
+ const useMagicLink = () => useAuthStore(useShallow(s => ({
821
+ sendMagicLink: s.sendMagicLink,
822
+ verifyMagicLink: s.verifyMagicLink,
823
+ loading: s.loadingStates.magicLink,
824
+ verifying: s.loadingStates.verifyMagicLink,
825
+ error: s.error
826
+ })));
827
+
828
+ // Password Reset Hook
829
+ const usePasswordReset = () => useAuthStore(useShallow(s => ({
830
+ forgotPassword: s.forgotPassword,
831
+ resetPassword: s.resetPassword,
832
+ loading: s.loadingStates.resetPassword,
833
+ error: s.error
834
+ })));
835
+
836
+ // Email Verification Hook
837
+ const useEmailVerification = () => useAuthStore(useShallow(s => ({
838
+ verifyEmail: s.verifyEmail,
839
+ resendVerification: s.resendVerification,
840
+ loading: s.loadingStates.verifyEmail,
841
+ resending: s.loadingStates.resendVerification,
842
+ error: s.error
843
+ })));
844
+
845
+ // Session Hook
846
+ const useSession = () => useAuthStore(useShallow(s => ({
847
+ getSession: s.getSession,
848
+ user: s.user,
849
+ setUser: s.setUser
850
+ })));
851
+
852
+ // Loading States Hook
853
+ const useAuthLoading = () => useAuthStore(s => s.loadingStates);
854
+
811
855
  function ProtectedRoute({
812
856
  fallback = /*#__PURE__*/React.createElement("p", null, "\u231B Carregando..."),
813
857
  redirectTo = "/login"
@@ -824,5 +868,787 @@ function ProtectedRoute({
824
868
  return /*#__PURE__*/React.createElement(Outlet, null);
825
869
  }
826
870
 
827
- export { AuthProvider, ProtectedRoute, getCurrentUser, isAuthenticated, refreshToken, signIn, signOut, signUp, socialRedirect, useAuth, useAuthStore, useCheckToken, useSignIn, useSignOut, useSignUp };
871
+ function _extends() {
872
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
873
+ for (var e = 1; e < arguments.length; e++) {
874
+ var t = arguments[e];
875
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
876
+ }
877
+ return n;
878
+ }, _extends.apply(null, arguments);
879
+ }
880
+
881
+ /**
882
+ * Container wrapper para componentes de autenticação
883
+ * Usa Mantine Paper com estilo consistente
884
+ */
885
+ function AuthCard({
886
+ children,
887
+ title,
888
+ subtitle,
889
+ logo,
890
+ logoHeight = 32,
891
+ width = 350,
892
+ ...props
893
+ }) {
894
+ return /*#__PURE__*/React.createElement(Paper, _extends({
895
+ withBorder: true,
896
+ shadow: "md",
897
+ p: 24,
898
+ w: width,
899
+ radius: "md"
900
+ }, props), /*#__PURE__*/React.createElement(Stack, {
901
+ gap: "sm"
902
+ }, (logo || title || subtitle) && /*#__PURE__*/React.createElement(Stack, {
903
+ gap: "xs"
904
+ }, logo && /*#__PURE__*/React.createElement(Image, {
905
+ src: logo,
906
+ alt: "Auth",
907
+ h: logoHeight,
908
+ fit: "contain"
909
+ }), title && /*#__PURE__*/React.createElement(Title, {
910
+ order: 3
911
+ }, title), subtitle && /*#__PURE__*/React.createElement(Text, {
912
+ size: "sm",
913
+ c: "dimmed"
914
+ }, subtitle)), children));
915
+ }
916
+
917
+ var img = "data:image/webp;base64,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";
918
+
919
+ /**
920
+ * Formulário de Sign In completo com Mantine
921
+ * Suporta email/password, magic link, social login
922
+ */
923
+ function SignInForm({
924
+ // Configuração
925
+ logo = img,
926
+ title = 'Entrar',
927
+ subtitle = 'Acesse sua conta para continuar',
928
+ // Features
929
+ showMagicLink = true,
930
+ showForgotPassword = true,
931
+ showSocialLogin = false,
932
+ showSignUpLink = true,
933
+ // Links
934
+ signUpUrl = '/auth/signup',
935
+ // Callbacks
936
+ onSuccess,
937
+ onError,
938
+ onMagicLinkSent,
939
+ onForgotPasswordSent,
940
+ onSocialLogin,
941
+ // Custom labels
942
+ labels = {},
943
+ ...cardProps
944
+ }) {
945
+ const signIn = useAuthStore(s => s.signIn);
946
+ const sendMagicLink = useAuthStore(s => s.sendMagicLink);
947
+ const forgotPassword = useAuthStore(s => s.forgotPassword);
948
+ const loadingSignIn = useAuthStore(s => s.loadingStates.signIn);
949
+ const loadingMagicLink = useAuthStore(s => s.loadingStates.magicLink);
950
+ const loadingResetPassword = useAuthStore(s => s.loadingStates.resetPassword);
951
+ const form = useForm({
952
+ initialValues: {
953
+ email: '',
954
+ password: ''
955
+ },
956
+ validate: {
957
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido',
958
+ password: value => value.length < 6 ? labels.passwordTooShort || 'A senha deve ter pelo menos 6 caracteres' : null
959
+ }
960
+ });
961
+ const handleSubmit = async values => {
962
+ try {
963
+ const result = await signIn(values.email, values.password);
964
+ onSuccess?.(result);
965
+ } catch (error) {
966
+ onError?.(error);
967
+ }
968
+ };
969
+ const handleMagicLink = async () => {
970
+ if (!form.values.email) {
971
+ form.setFieldError('email', labels.emailRequired || 'Email obrigatório');
972
+ return;
973
+ }
974
+ try {
975
+ await sendMagicLink(form.values.email);
976
+ onMagicLinkSent?.(form.values.email);
977
+ } catch (error) {
978
+ onError?.(error);
979
+ }
980
+ };
981
+ const handleForgotPassword = async () => {
982
+ if (!form.values.email) {
983
+ form.setFieldError('email', labels.emailRequired || 'Email obrigatório');
984
+ return;
985
+ }
986
+ try {
987
+ await forgotPassword(form.values.email);
988
+ onForgotPasswordSent?.(form.values.email);
989
+ } catch (error) {
990
+ onError?.(error);
991
+ }
992
+ };
993
+ const isLoading = loadingSignIn || loadingMagicLink || loadingResetPassword;
994
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
995
+ logo: logo,
996
+ title: title,
997
+ subtitle: subtitle
998
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
999
+ onSubmit: form.onSubmit(handleSubmit)
1000
+ }, /*#__PURE__*/React.createElement(Stack, {
1001
+ gap: "sm"
1002
+ }, /*#__PURE__*/React.createElement(TextInput, _extends({
1003
+ label: labels.email || 'Email',
1004
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
1005
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1006
+ size: 16
1007
+ })
1008
+ }, form.getInputProps('email'), {
1009
+ disabled: isLoading
1010
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
1011
+ label: labels.password || 'Senha',
1012
+ placeholder: labels.passwordPlaceholder || 'Sua senha',
1013
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1014
+ size: 16
1015
+ })
1016
+ }, form.getInputProps('password'), {
1017
+ disabled: isLoading
1018
+ })), showForgotPassword && /*#__PURE__*/React.createElement(Anchor, {
1019
+ size: "sm",
1020
+ ta: "right",
1021
+ onClick: handleForgotPassword,
1022
+ style: {
1023
+ cursor: 'pointer'
1024
+ },
1025
+ c: loadingResetPassword ? 'dimmed' : 'blue'
1026
+ }, loadingResetPassword ? labels.sendingReset || 'Enviando...' : labels.forgotPassword || 'Esqueceu a senha?'), /*#__PURE__*/React.createElement(Button, {
1027
+ type: "submit",
1028
+ fullWidth: true,
1029
+ loading: loadingSignIn,
1030
+ rightSection: /*#__PURE__*/React.createElement(IconArrowRight, {
1031
+ size: 16
1032
+ })
1033
+ }, labels.signInButton || 'Entrar'))), showMagicLink && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, {
1034
+ label: labels.orContinueWith || 'Ou continue com'
1035
+ }), /*#__PURE__*/React.createElement(Button, {
1036
+ variant: "light",
1037
+ fullWidth: true,
1038
+ loading: loadingMagicLink,
1039
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1040
+ size: 16
1041
+ }),
1042
+ onClick: handleMagicLink,
1043
+ disabled: isLoading || !form.values.email
1044
+ }, labels.magicLinkButton || 'Enviar Link Mágico')), showSocialLogin && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, null), /*#__PURE__*/React.createElement(Group, {
1045
+ grow: true
1046
+ }, /*#__PURE__*/React.createElement(Button, {
1047
+ variant: "light",
1048
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGoogle, {
1049
+ size: 16
1050
+ }),
1051
+ onClick: () => onSocialLogin?.('google'),
1052
+ disabled: isLoading
1053
+ }, "Google"), /*#__PURE__*/React.createElement(Button, {
1054
+ variant: "light",
1055
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGithub, {
1056
+ size: 16
1057
+ }),
1058
+ onClick: () => onSocialLogin?.('github'),
1059
+ disabled: isLoading
1060
+ }, "GitHub"))), showSignUpLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1061
+ size: "sm",
1062
+ c: "dimmed"
1063
+ }, labels.noAccount || 'Não tem uma conta?', " ", /*#__PURE__*/React.createElement(Anchor, {
1064
+ href: signUpUrl
1065
+ }, labels.createAccount || 'Criar conta'))));
1066
+ }
1067
+
1068
+ /**
1069
+ * Formulário de Sign Up com Mantine
1070
+ */
1071
+ function SignUpForm({
1072
+ // Configuração
1073
+ logo = img,
1074
+ title = 'Criar Conta',
1075
+ subtitle = 'Preencha os dados para se cadastrar',
1076
+ // Features
1077
+ requireName = true,
1078
+ showSignInLink = true,
1079
+ showSocialLogin = false,
1080
+ // Links
1081
+ signInUrl = '/auth/signin',
1082
+ // Callbacks
1083
+ onSuccess,
1084
+ onError,
1085
+ onSocialLogin,
1086
+ // Custom labels
1087
+ labels = {},
1088
+ ...cardProps
1089
+ }) {
1090
+ const signUp = useAuthStore(s => s.signUp);
1091
+ const loading = useAuthStore(s => s.loadingStates.signUp);
1092
+ const form = useForm({
1093
+ initialValues: {
1094
+ name: '',
1095
+ email: '',
1096
+ password: '',
1097
+ confirmPassword: ''
1098
+ },
1099
+ validate: {
1100
+ name: value => requireName && !value ? labels.nameRequired || 'Nome obrigatório' : null,
1101
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido',
1102
+ password: value => value.length < 6 ? labels.passwordTooShort || 'A senha deve ter pelo menos 6 caracteres' : null,
1103
+ confirmPassword: (value, values) => value !== values.password ? labels.passwordMismatch || 'As senhas não coincidem' : null
1104
+ }
1105
+ });
1106
+ const handleSubmit = async values => {
1107
+ try {
1108
+ const result = await signUp(values.email, values.password, values.name);
1109
+ onSuccess?.(result);
1110
+ } catch (error) {
1111
+ onError?.(error);
1112
+ }
1113
+ };
1114
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1115
+ logo: logo,
1116
+ title: title,
1117
+ subtitle: subtitle
1118
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1119
+ onSubmit: form.onSubmit(handleSubmit)
1120
+ }, /*#__PURE__*/React.createElement(Stack, {
1121
+ gap: "sm"
1122
+ }, requireName && /*#__PURE__*/React.createElement(TextInput, _extends({
1123
+ label: labels.name || 'Nome',
1124
+ placeholder: labels.namePlaceholder || 'Seu nome',
1125
+ leftSection: /*#__PURE__*/React.createElement(IconUser, {
1126
+ size: 16
1127
+ })
1128
+ }, form.getInputProps('name'), {
1129
+ disabled: loading
1130
+ })), /*#__PURE__*/React.createElement(TextInput, _extends({
1131
+ label: labels.email || 'Email',
1132
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
1133
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1134
+ size: 16
1135
+ })
1136
+ }, form.getInputProps('email'), {
1137
+ disabled: loading
1138
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
1139
+ label: labels.password || 'Senha',
1140
+ placeholder: labels.passwordPlaceholder || 'Crie uma senha',
1141
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1142
+ size: 16
1143
+ })
1144
+ }, form.getInputProps('password'), {
1145
+ disabled: loading
1146
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
1147
+ label: labels.confirmPassword || 'Confirmar Senha',
1148
+ placeholder: labels.confirmPasswordPlaceholder || 'Repita a senha',
1149
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1150
+ size: 16
1151
+ })
1152
+ }, form.getInputProps('confirmPassword'), {
1153
+ disabled: loading
1154
+ })), /*#__PURE__*/React.createElement(Button, {
1155
+ type: "submit",
1156
+ fullWidth: true,
1157
+ loading: loading,
1158
+ rightSection: /*#__PURE__*/React.createElement(IconArrowRight, {
1159
+ size: 16
1160
+ })
1161
+ }, labels.signUpButton || 'Criar Conta'))), showSocialLogin && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Divider, {
1162
+ label: labels.orContinueWith || 'Ou continue com'
1163
+ }), /*#__PURE__*/React.createElement(Group, {
1164
+ grow: true
1165
+ }, /*#__PURE__*/React.createElement(Button, {
1166
+ variant: "light",
1167
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGoogle, {
1168
+ size: 16
1169
+ }),
1170
+ onClick: () => onSocialLogin?.('google'),
1171
+ disabled: loading
1172
+ }, "Google"), /*#__PURE__*/React.createElement(Button, {
1173
+ variant: "light",
1174
+ leftSection: /*#__PURE__*/React.createElement(IconBrandGithub, {
1175
+ size: 16
1176
+ }),
1177
+ onClick: () => onSocialLogin?.('github'),
1178
+ disabled: loading
1179
+ }, "GitHub"))), showSignInLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1180
+ size: "sm",
1181
+ c: "dimmed"
1182
+ }, labels.hasAccount || 'Já tem uma conta?', " ", /*#__PURE__*/React.createElement(Anchor, {
1183
+ href: signInUrl
1184
+ }, labels.signIn || 'Entrar'))));
1185
+ }
1186
+
1187
+ /**
1188
+ * Formulário para envio de Magic Link
1189
+ */
1190
+ function MagicLinkForm({
1191
+ // Configuração
1192
+ logo = img,
1193
+ title = 'Login sem Senha',
1194
+ subtitle = 'Receba um link de acesso no seu email',
1195
+ // Features
1196
+ showSignInLink = true,
1197
+ // Links
1198
+ signInUrl = '/auth/signin',
1199
+ // Callbacks
1200
+ onSent,
1201
+ onError,
1202
+ // Custom labels
1203
+ labels = {},
1204
+ ...cardProps
1205
+ }) {
1206
+ const sendMagicLink = useAuthStore(s => s.sendMagicLink);
1207
+ const loading = useAuthStore(s => s.loadingStates.magicLink);
1208
+ const form = useForm({
1209
+ initialValues: {
1210
+ email: ''
1211
+ },
1212
+ validate: {
1213
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido'
1214
+ }
1215
+ });
1216
+ const handleSubmit = async values => {
1217
+ try {
1218
+ await sendMagicLink(values.email);
1219
+ onSent?.(values.email);
1220
+ } catch (error) {
1221
+ onError?.(error);
1222
+ }
1223
+ };
1224
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1225
+ logo: logo,
1226
+ title: title,
1227
+ subtitle: subtitle
1228
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1229
+ onSubmit: form.onSubmit(handleSubmit)
1230
+ }, /*#__PURE__*/React.createElement(Stack, {
1231
+ gap: "sm"
1232
+ }, /*#__PURE__*/React.createElement(TextInput, _extends({
1233
+ label: labels.email || 'Email',
1234
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
1235
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1236
+ size: 16
1237
+ })
1238
+ }, form.getInputProps('email'), {
1239
+ disabled: loading
1240
+ })), /*#__PURE__*/React.createElement(Button, {
1241
+ type: "submit",
1242
+ fullWidth: true,
1243
+ loading: loading,
1244
+ leftSection: /*#__PURE__*/React.createElement(IconSend, {
1245
+ size: 16
1246
+ })
1247
+ }, labels.sendButton || 'Enviar Link Mágico'))), showSignInLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1248
+ size: "sm",
1249
+ c: "dimmed"
1250
+ }, labels.backTo || 'Voltar para', " ", /*#__PURE__*/React.createElement(Anchor, {
1251
+ href: signInUrl
1252
+ }, labels.signIn || 'login com senha'))));
1253
+ }
1254
+
1255
+ /**
1256
+ * Componente de verificação de Magic Link
1257
+ * Extrai token da URL e verifica automaticamente
1258
+ */
1259
+ function MagicLinkVerify({
1260
+ // Configuração
1261
+ logo = img,
1262
+ // Token pode ser passado diretamente ou extraído da URL
1263
+ token: propToken,
1264
+ // Callbacks
1265
+ onSuccess,
1266
+ onError,
1267
+ // Redirect após sucesso/erro
1268
+ redirectTo,
1269
+ redirectDelay = 2000,
1270
+ // Custom labels
1271
+ labels = {},
1272
+ ...cardProps
1273
+ }) {
1274
+ const [status, setStatus] = useState('verifying'); // verifying, success, error
1275
+ const [errorMessage, setErrorMessage] = useState('');
1276
+ const verifyMagicLink = useAuthStore(s => s.verifyMagicLink);
1277
+ useEffect(() => {
1278
+ const verify = async () => {
1279
+ // Pega token da prop ou da URL
1280
+ let token = propToken;
1281
+ if (!token && typeof window !== 'undefined') {
1282
+ const urlParams = new URLSearchParams(window.location.search);
1283
+ token = urlParams.get('token');
1284
+ }
1285
+ if (!token) {
1286
+ setStatus('error');
1287
+ setErrorMessage(labels.noToken || 'Token não encontrado na URL');
1288
+ onError?.(new Error('No token'));
1289
+ return;
1290
+ }
1291
+ try {
1292
+ const result = await verifyMagicLink(token);
1293
+ setStatus('success');
1294
+ onSuccess?.(result);
1295
+ if (redirectTo) {
1296
+ setTimeout(() => {
1297
+ window.location.href = redirectTo;
1298
+ }, redirectDelay);
1299
+ }
1300
+ } catch (error) {
1301
+ setStatus('error');
1302
+ setErrorMessage(error.message || labels.verificationFailed || 'Verificação falhou');
1303
+ onError?.(error);
1304
+ }
1305
+ };
1306
+ verify();
1307
+ }, [propToken, verifyMagicLink, onSuccess, onError, redirectTo, redirectDelay, labels]);
1308
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1309
+ logo: logo
1310
+ }, cardProps), status === 'verifying' && /*#__PURE__*/React.createElement(Stack, {
1311
+ align: "center",
1312
+ gap: "sm"
1313
+ }, /*#__PURE__*/React.createElement(Loader, {
1314
+ size: "lg"
1315
+ }), /*#__PURE__*/React.createElement(Title, {
1316
+ order: 4
1317
+ }, labels.verifying || 'Verificando Link Mágico'), /*#__PURE__*/React.createElement(Text, {
1318
+ size: "sm",
1319
+ c: "dimmed",
1320
+ ta: "center"
1321
+ }, labels.pleaseWait || 'Aguarde enquanto autenticamos você...')), status === 'success' && /*#__PURE__*/React.createElement(Stack, {
1322
+ align: "center",
1323
+ gap: "sm"
1324
+ }, /*#__PURE__*/React.createElement(IconCheck, {
1325
+ size: 48,
1326
+ color: "var(--mantine-color-green-6)"
1327
+ }), /*#__PURE__*/React.createElement(Title, {
1328
+ order: 4
1329
+ }, labels.success || 'Autenticado com Sucesso!'), /*#__PURE__*/React.createElement(Text, {
1330
+ size: "sm",
1331
+ c: "dimmed",
1332
+ ta: "center"
1333
+ }, redirectTo ? labels.redirecting || 'Redirecionando...' : labels.authenticated || 'Você está autenticado.')), status === 'error' && /*#__PURE__*/React.createElement(Stack, {
1334
+ align: "center",
1335
+ gap: "sm"
1336
+ }, /*#__PURE__*/React.createElement(IconX, {
1337
+ size: 48,
1338
+ color: "var(--mantine-color-red-6)"
1339
+ }), /*#__PURE__*/React.createElement(Title, {
1340
+ order: 4
1341
+ }, labels.failed || 'Falha na Autenticação'), /*#__PURE__*/React.createElement(Text, {
1342
+ size: "sm",
1343
+ c: "dimmed",
1344
+ ta: "center"
1345
+ }, errorMessage || labels.invalidLink || 'O link é inválido ou expirou.')));
1346
+ }
1347
+
1348
+ /**
1349
+ * Formulário para solicitar reset de senha
1350
+ */
1351
+ function ForgotPasswordForm({
1352
+ // Configuração
1353
+ logo = img,
1354
+ title = 'Recuperar Senha',
1355
+ subtitle = 'Enviaremos um link para redefinir sua senha',
1356
+ // Features
1357
+ showSignInLink = true,
1358
+ // Links
1359
+ signInUrl = '/auth/signin',
1360
+ // Callbacks
1361
+ onSent,
1362
+ onError,
1363
+ // Custom labels
1364
+ labels = {},
1365
+ ...cardProps
1366
+ }) {
1367
+ const forgotPassword = useAuthStore(s => s.forgotPassword);
1368
+ const loading = useAuthStore(s => s.loadingStates.resetPassword);
1369
+ const form = useForm({
1370
+ initialValues: {
1371
+ email: ''
1372
+ },
1373
+ validate: {
1374
+ email: value => /^\S+@\S+$/.test(value) ? null : labels.invalidEmail || 'Email inválido'
1375
+ }
1376
+ });
1377
+ const handleSubmit = async values => {
1378
+ try {
1379
+ await forgotPassword(values.email);
1380
+ onSent?.(values.email);
1381
+ } catch (error) {
1382
+ onError?.(error);
1383
+ }
1384
+ };
1385
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1386
+ logo: logo,
1387
+ title: title,
1388
+ subtitle: subtitle
1389
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1390
+ onSubmit: form.onSubmit(handleSubmit)
1391
+ }, /*#__PURE__*/React.createElement(Stack, {
1392
+ gap: "sm"
1393
+ }, /*#__PURE__*/React.createElement(TextInput, _extends({
1394
+ label: labels.email || 'Email',
1395
+ placeholder: labels.emailPlaceholder || 'seu@email.com',
1396
+ leftSection: /*#__PURE__*/React.createElement(IconMail, {
1397
+ size: 16
1398
+ })
1399
+ }, form.getInputProps('email'), {
1400
+ disabled: loading
1401
+ })), /*#__PURE__*/React.createElement(Button, {
1402
+ type: "submit",
1403
+ fullWidth: true,
1404
+ loading: loading,
1405
+ leftSection: /*#__PURE__*/React.createElement(IconSend, {
1406
+ size: 16
1407
+ })
1408
+ }, labels.sendButton || 'Enviar Link de Recuperação'))), showSignInLink && /*#__PURE__*/React.createElement(Center, null, /*#__PURE__*/React.createElement(Text, {
1409
+ size: "sm",
1410
+ c: "dimmed"
1411
+ }, labels.rememberedPassword || 'Lembrou a senha?', " ", /*#__PURE__*/React.createElement(Anchor, {
1412
+ href: signInUrl
1413
+ }, labels.signIn || 'Entrar'))));
1414
+ }
1415
+
1416
+ /**
1417
+ * Formulário para redefinir senha com token
1418
+ */
1419
+ function ResetPasswordForm({
1420
+ // Configuração
1421
+ logo = img,
1422
+ title = 'Nova Senha',
1423
+ subtitle = 'Crie uma nova senha para sua conta',
1424
+ // Token pode ser passado diretamente ou extraído da URL
1425
+ token: propToken,
1426
+ // Callbacks
1427
+ onSuccess,
1428
+ onError,
1429
+ // Redirect após sucesso
1430
+ signInUrl = '/auth/signin',
1431
+ // Custom labels
1432
+ labels = {},
1433
+ ...cardProps
1434
+ }) {
1435
+ const [token, setToken] = useState(propToken || '');
1436
+ const [success, setSuccess] = useState(false);
1437
+ const resetPassword = useAuthStore(s => s.resetPassword);
1438
+ const loading = useAuthStore(s => s.loadingStates.resetPassword);
1439
+
1440
+ // Extrai token da URL se não foi passado como prop
1441
+ useEffect(() => {
1442
+ if (!propToken && typeof window !== 'undefined') {
1443
+ const urlParams = new URLSearchParams(window.location.search);
1444
+ const urlToken = urlParams.get('token');
1445
+ if (urlToken) setToken(urlToken);
1446
+ }
1447
+ }, [propToken]);
1448
+ const form = useForm({
1449
+ initialValues: {
1450
+ password: '',
1451
+ confirmPassword: ''
1452
+ },
1453
+ validate: {
1454
+ password: value => value.length < 6 ? labels.passwordTooShort || 'A senha deve ter pelo menos 6 caracteres' : null,
1455
+ confirmPassword: (value, values) => value !== values.password ? labels.passwordMismatch || 'As senhas não coincidem' : null
1456
+ }
1457
+ });
1458
+ const handleSubmit = async values => {
1459
+ if (!token) {
1460
+ onError?.(new Error('Token não encontrado'));
1461
+ return;
1462
+ }
1463
+ try {
1464
+ await resetPassword(token, values.password);
1465
+ setSuccess(true);
1466
+ onSuccess?.();
1467
+ } catch (error) {
1468
+ onError?.(error);
1469
+ }
1470
+ };
1471
+ if (success) {
1472
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1473
+ logo: logo
1474
+ }, cardProps), /*#__PURE__*/React.createElement(Stack, {
1475
+ align: "center",
1476
+ gap: "sm"
1477
+ }, /*#__PURE__*/React.createElement(IconCheck, {
1478
+ size: 48,
1479
+ color: "var(--mantine-color-green-6)"
1480
+ }), /*#__PURE__*/React.createElement(Title, {
1481
+ order: 4
1482
+ }, labels.successTitle || 'Senha Redefinida!'), /*#__PURE__*/React.createElement(Text, {
1483
+ size: "sm",
1484
+ c: "dimmed",
1485
+ ta: "center"
1486
+ }, labels.successMessage || 'Sua senha foi alterada com sucesso.'), /*#__PURE__*/React.createElement(Button, {
1487
+ component: "a",
1488
+ href: signInUrl,
1489
+ fullWidth: true
1490
+ }, labels.goToSignIn || 'Ir para Login')));
1491
+ }
1492
+ if (!token) {
1493
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1494
+ logo: logo
1495
+ }, cardProps), /*#__PURE__*/React.createElement(Stack, {
1496
+ align: "center",
1497
+ gap: "sm"
1498
+ }, /*#__PURE__*/React.createElement(Text, {
1499
+ c: "red"
1500
+ }, labels.noToken || 'Token não encontrado na URL'), /*#__PURE__*/React.createElement(Button, {
1501
+ component: "a",
1502
+ href: signInUrl,
1503
+ variant: "light",
1504
+ fullWidth: true
1505
+ }, labels.goToSignIn || 'Voltar para Login')));
1506
+ }
1507
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1508
+ logo: logo,
1509
+ title: title,
1510
+ subtitle: subtitle
1511
+ }, cardProps), /*#__PURE__*/React.createElement("form", {
1512
+ onSubmit: form.onSubmit(handleSubmit)
1513
+ }, /*#__PURE__*/React.createElement(Stack, {
1514
+ gap: "sm"
1515
+ }, /*#__PURE__*/React.createElement(PasswordInput, _extends({
1516
+ label: labels.newPassword || 'Nova Senha',
1517
+ placeholder: labels.newPasswordPlaceholder || 'Crie uma nova senha',
1518
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1519
+ size: 16
1520
+ })
1521
+ }, form.getInputProps('password'), {
1522
+ disabled: loading
1523
+ })), /*#__PURE__*/React.createElement(PasswordInput, _extends({
1524
+ label: labels.confirmPassword || 'Confirmar Senha',
1525
+ placeholder: labels.confirmPasswordPlaceholder || 'Repita a nova senha',
1526
+ leftSection: /*#__PURE__*/React.createElement(IconLock, {
1527
+ size: 16
1528
+ })
1529
+ }, form.getInputProps('confirmPassword'), {
1530
+ disabled: loading
1531
+ })), /*#__PURE__*/React.createElement(Button, {
1532
+ type: "submit",
1533
+ fullWidth: true,
1534
+ loading: loading
1535
+ }, labels.resetButton || 'Redefinir Senha'))));
1536
+ }
1537
+
1538
+ /**
1539
+ * Card de verificação de email
1540
+ * Verifica token automaticamente e permite reenvio
1541
+ */
1542
+ function VerifyEmailCard({
1543
+ // Configuração
1544
+ logo = img,
1545
+ // Token pode ser passado diretamente ou extraído da URL
1546
+ token: propToken,
1547
+ // Email para reenvio (opcional)
1548
+ email,
1549
+ // Callbacks
1550
+ onSuccess,
1551
+ onError,
1552
+ onResent,
1553
+ // Redirect após sucesso
1554
+ redirectTo,
1555
+ redirectDelay = 2000,
1556
+ // Custom labels
1557
+ labels = {},
1558
+ ...cardProps
1559
+ }) {
1560
+ const [status, setStatus] = useState('verifying'); // verifying, success, error
1561
+ const [errorMessage, setErrorMessage] = useState('');
1562
+ const verifyEmail = useAuthStore(s => s.verifyEmail);
1563
+ const resendVerification = useAuthStore(s => s.resendVerification);
1564
+ const loadingResend = useAuthStore(s => s.loadingStates.resendVerification);
1565
+ useEffect(() => {
1566
+ const verify = async () => {
1567
+ // Pega token da prop ou da URL
1568
+ let token = propToken;
1569
+ if (!token && typeof window !== 'undefined') {
1570
+ const urlParams = new URLSearchParams(window.location.search);
1571
+ token = urlParams.get('token');
1572
+ }
1573
+ if (!token) {
1574
+ setStatus('error');
1575
+ setErrorMessage(labels.noToken || 'Token não encontrado na URL');
1576
+ onError?.(new Error('No token'));
1577
+ return;
1578
+ }
1579
+ try {
1580
+ const result = await verifyEmail(token);
1581
+ setStatus('success');
1582
+ onSuccess?.(result);
1583
+ if (redirectTo) {
1584
+ setTimeout(() => {
1585
+ window.location.href = redirectTo;
1586
+ }, redirectDelay);
1587
+ }
1588
+ } catch (error) {
1589
+ setStatus('error');
1590
+ setErrorMessage(error.message || labels.verificationFailed || 'Verificação falhou');
1591
+ onError?.(error);
1592
+ }
1593
+ };
1594
+ verify();
1595
+ }, [propToken, verifyEmail, onSuccess, onError, redirectTo, redirectDelay, labels]);
1596
+ const handleResend = async () => {
1597
+ if (!email) return;
1598
+ try {
1599
+ await resendVerification(email);
1600
+ onResent?.(email);
1601
+ } catch (error) {
1602
+ onError?.(error);
1603
+ }
1604
+ };
1605
+ return /*#__PURE__*/React.createElement(AuthCard, _extends({
1606
+ logo: logo
1607
+ }, cardProps), status === 'verifying' && /*#__PURE__*/React.createElement(Stack, {
1608
+ align: "center",
1609
+ gap: "sm"
1610
+ }, /*#__PURE__*/React.createElement(Loader, {
1611
+ size: "lg"
1612
+ }), /*#__PURE__*/React.createElement(Title, {
1613
+ order: 4
1614
+ }, labels.verifying || 'Verificando Email'), /*#__PURE__*/React.createElement(Text, {
1615
+ size: "sm",
1616
+ c: "dimmed",
1617
+ ta: "center"
1618
+ }, labels.pleaseWait || 'Aguarde enquanto verificamos seu email...')), status === 'success' && /*#__PURE__*/React.createElement(Stack, {
1619
+ align: "center",
1620
+ gap: "sm"
1621
+ }, /*#__PURE__*/React.createElement(IconCheck, {
1622
+ size: 48,
1623
+ color: "var(--mantine-color-green-6)"
1624
+ }), /*#__PURE__*/React.createElement(Title, {
1625
+ order: 4
1626
+ }, labels.success || 'Email Verificado!'), /*#__PURE__*/React.createElement(Text, {
1627
+ size: "sm",
1628
+ c: "dimmed",
1629
+ ta: "center"
1630
+ }, redirectTo ? labels.redirecting || 'Redirecionando...' : labels.verified || 'Seu email foi verificado com sucesso.')), status === 'error' && /*#__PURE__*/React.createElement(Stack, {
1631
+ align: "center",
1632
+ gap: "sm"
1633
+ }, /*#__PURE__*/React.createElement(IconX, {
1634
+ size: 48,
1635
+ color: "var(--mantine-color-red-6)"
1636
+ }), /*#__PURE__*/React.createElement(Title, {
1637
+ order: 4
1638
+ }, labels.failed || 'Verificação Falhou'), /*#__PURE__*/React.createElement(Text, {
1639
+ size: "sm",
1640
+ c: "dimmed",
1641
+ ta: "center"
1642
+ }, errorMessage || labels.invalidToken || 'O link é inválido ou expirou.'), email && /*#__PURE__*/React.createElement(Button, {
1643
+ variant: "light",
1644
+ leftSection: /*#__PURE__*/React.createElement(IconRefresh, {
1645
+ size: 16
1646
+ }),
1647
+ onClick: handleResend,
1648
+ loading: loadingResend,
1649
+ fullWidth: true
1650
+ }, labels.resend || 'Reenviar Email de Verificação')));
1651
+ }
1652
+
1653
+ 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
1654
  //# sourceMappingURL=index.esm.js.map