@greatapps/common 1.1.51 → 1.1.52

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.mjs CHANGED
@@ -7,7 +7,7 @@ export * from "./providers/auth.provider";
7
7
  export * from "./providers/whitelabel.provider";
8
8
  import { useListProjectUsers, LIST_PROJECT_USERS_QUERY_KEY, LIST_PROJECT_USERS_BASE_KEY } from "./modules/projects/hooks/list-project-users.hook";
9
9
  import { useListAvailableUsers, LIST_AVAILABLE_USERS_QUERY_KEY, LIST_AVAILABLE_USERS_BASE_KEY } from "./modules/projects/hooks/list-available-users.hook";
10
- import { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from "./modules/auth/hooks/useUserQuery";
10
+ import { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, useTwoFactorVerify, useTwoFactorPending, USER_QUERY_KEY } from "./modules/auth/hooks/useUserQuery";
11
11
  import { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from "./modules/subscriptions/hooks/list-subscriptions.hook";
12
12
  import { useActiveSubscription } from "./modules/subscriptions/hooks/find-active-subscription.hook";
13
13
  import { useIaCredits } from "./modules/ia-credits/hooks/ia-credits.hook";
@@ -294,6 +294,8 @@ export {
294
294
  default5 as usePasswordVisibility,
295
295
  useSetUserData,
296
296
  useSubscriptions,
297
+ useTwoFactorPending,
298
+ useTwoFactorVerify,
297
299
  useUpdateAccount,
298
300
  useUpdateAccountUser,
299
301
  useUpdateAccountUserById,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useListProjectUsers, LIST_PROJECT_USERS_QUERY_KEY, LIST_PROJECT_USERS_BASE_KEY } from './modules/projects/hooks/list-project-users.hook';\nexport { useListAvailableUsers, LIST_AVAILABLE_USERS_QUERY_KEY, LIST_AVAILABLE_USERS_BASE_KEY } from './modules/projects/hooks/list-available-users.hook';\nexport type { ProjectUser, AccountUser, AddRemoveProjectUsersParams, ListUsersParams, UsersPage } from './modules/projects/types';\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\nexport { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from './modules/subscriptions/hooks/list-subscriptions.hook';\nexport { useActiveSubscription } from './modules/subscriptions/hooks/find-active-subscription.hook';\nexport { useIaCredits } from './modules/ia-credits/hooks/ia-credits.hook';\nexport type { IaCreditsSummary, IaCreditOperation } from './modules/ia-credits/types';\nexport type { Subscription, SubscriptionItem, FindSubscriptionsParams } from './modules/subscriptions/types';\nexport { SubscriptionSchema, SubscriptionItemSchema } from './modules/subscriptions/types';\nexport { ADDON_IDS } from './modules/subscriptions/constants/addons.constants';\nexport type { AddonKindEnum } from './modules/subscriptions/constants/addons.constants';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\nexport { parseSchema, parseResult } from './infra/utils/parser';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { AppNavBar } from './components/layouts/AppNavBar';\nexport type { AppNavBarProps } from './components/layouts/AppNavBar';\nexport { AppMobileNavBar } from './components/layouts/AppMobileNavBar';\nexport type { AppMobileNavBarProps } from './components/layouts/AppMobileNavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\nexport { NotificationsPopover } from './components/layouts/NotificationsPopover';\nexport type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';\nexport { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';\nexport type { UsersSelectorPopoverProps } from './components/layouts/UsersSelectorPopover';\nexport { ProfilePopover } from './components/layouts/ProfilePopover';\nexport type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';\nexport { NavBarItem } from './components/layouts/NavBarItem';\nexport type { NavBarItemProps } from './components/layouts/NavBarItem';\n\n// UI - Buttons\nexport { Button, buttonVariants } from './components/ui/buttons/Button';\nexport { CopyButton } from './components/ui/buttons/CopyButton';\nexport { default as CancelButton } from './components/ui/buttons/CancelButton';\n\n// UI - Data Display\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';\nexport { Badge, badgeVariants } from './components/ui/data-display/Badge';\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';\nexport { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';\nexport { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';\nexport { Separator } from './components/ui/data-display/Separator';\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';\nexport { UserAvatar } from './components/ui/data-display/UserAvatar';\nexport type { UserAvatarProps } from './components/ui/data-display/UserAvatar';\n\n// UI - Feedback\nexport { default as CircularProgress } from './components/ui/feedback/CircularProgress';\nexport { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';\nexport { Progress } from './components/ui/feedback/Progress';\nexport { LoadingOverlay } from './components/ui/feedback/LoadingOverlay';\nexport { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';\nexport type { ToastProps } from './components/ui/feedback/Toast';\n\n// UI - Form\nexport { Calendar, CalendarDayButton } from './components/ui/form/Calendar';\nexport { Checkbox } from './components/ui/form/Checkbox';\nexport { DatePicker } from './components/ui/form/DatePicker';\nexport { DateRangePicker } from './components/ui/form/DateRangePicker';\nexport { Input } from './components/ui/form/Input';\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';\nexport { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';\nexport { Switch } from './components/ui/form/Switch';\nexport { Textarea } from './components/ui/form/Textarea';\n\n// UI - Overlay\nexport { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\nexport { useModalManager } from './store/useModalManager';\nexport type { ModalData } from './store/useModalManager';\n\n// Enums\nexport { AccountSectionType } from './enums/AccountSectionType';\n\n// Hooks\nexport { default as usePasswordVisibility } from './hooks/usePasswordVisibility';\nexport { default as useCountdownTimer } from './hooks/useCountdownTimer';\nexport { default as useIsMobile } from './hooks/useIsMobile';\n\n// Utils\nexport { formatPhone, formatTimer, formatFullName, formatCPF, formatCardNumber } from './utils/format/masks';\nexport { timezoneService } from './modules/accounts/services/timezone.service';\nexport type { TimezoneOption } from './modules/accounts/services/timezone.service';\nexport { buildLocaleOptions, LANGUAGE_OPTIONS as LOCALE_LANGUAGE_OPTIONS } from './utils/intl/locales';\nexport type { LocaleOption } from './utils/intl/locales';\nexport { copyToClipboard, readFromClipboard } from './utils/browser/clipboard';\n\n// UI - Form (new widgets)\nexport { FormField } from './components/ui/form/FormField';\nexport { SelectField } from './components/ui/form/SelectField';\nexport { ComboboxField } from './components/ui/form/ComboboxField';\nexport type { ComboboxOption } from './components/ui/form/ComboboxField';\nexport { default as PhoneInput } from './components/ui/form/PhoneInput';\nexport { default as SwitchOptionFieldWithIcon } from './components/ui/form/SwitchOptionFieldWithIcon';\nexport { TextAreaField } from './components/ui/form/TextAreaField';\n\n// Account Module - Hooks\nexport {\n useUpdateAccount,\n useUpdateAccountUser,\n useUpdateAccountUserById,\n useDeleteAccountUser,\n useDeleteAccount,\n} from './modules/accounts/hooks/useAccountManagement';\n\n// Account Types\nexport type {\n UpdateAccountRequest,\n UpdateAccountUserRequest,\n ChangePasswordRequest,\n DeleteAccountActionResult,\n DeleteUserActionResult,\n UpdateAccountActionResult,\n UpdateUserActionResult,\n TwoFactorGenerateResult,\n TwoFactorActionResult,\n ContactResetResult,\n} from './modules/accounts/types';\n\nexport { default as AccountModals } from './components/account/AccountModals';\nexport { useAccountModals } from './store/useAccountModals';\nexport type { AccountModalsConfig } from './store/useAccountModals';\n\nexport { ModalManager } from './components/modals/ModalManager';\nexport { Modals } from './components/modals/Modals';\n\nexport { default as TwoFactorAuthModal } from './components/account/TwoFactorAuthModal';\nexport { default as DisableTwoFactorAuthModal } from './components/account/DisableTwoFactorAuthModal';\nexport { default as ConfirmGlobalPreferencesModal } from './components/account/ConfirmGlobalPreferencesModal';\nexport { MyProfileSection } from './components/account/sections/MyProfileSection';\nexport { PreferencesSection } from './components/account/sections/PreferencesSection';\nexport { SecuritySection } from './components/account/sections/SecuritySection';\nexport { ChangePasswordSection } from './components/account/sections/ChangePasswordSection';\nexport { ChangeEmailModal } from './components/account/sections/ChangeEmailModal';\nexport { ChangePhoneModal } from './components/account/sections/ChangePhoneModal';\n\n// Account Constants\nexport {\n GENDER_OPTIONS,\n CURRENCY_OPTIONS,\n TIME_FORMAT_OPTIONS,\n NOTIFICATION_TYPES,\n LANGUAGE_OPTIONS,\n} from './components/account/constants';\n"],"mappings":"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","names":["default","LANGUAGE_OPTIONS"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["// Types\nexport * from './modules/auth/schema';\nexport * from './modules/users/schema';\nexport * from './modules/whitelabel/schema';\nexport * from './infra/api/types';\n\n// Contexts\nexport * from './providers/query.provider';\nexport * from './providers/auth.provider';\nexport * from './providers/whitelabel.provider';\n\n// Hooks\nexport { useListProjectUsers, LIST_PROJECT_USERS_QUERY_KEY, LIST_PROJECT_USERS_BASE_KEY } from './modules/projects/hooks/list-project-users.hook';\nexport { useListAvailableUsers, LIST_AVAILABLE_USERS_QUERY_KEY, LIST_AVAILABLE_USERS_BASE_KEY } from './modules/projects/hooks/list-available-users.hook';\nexport type { ProjectUser, AccountUser, AddRemoveProjectUsersParams, ListUsersParams, UsersPage } from './modules/projects/types';\nexport { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, useTwoFactorVerify, useTwoFactorPending, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';\nexport { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from './modules/subscriptions/hooks/list-subscriptions.hook';\nexport { useActiveSubscription } from './modules/subscriptions/hooks/find-active-subscription.hook';\nexport { useIaCredits } from './modules/ia-credits/hooks/ia-credits.hook';\nexport type { IaCreditsSummary, IaCreditOperation } from './modules/ia-credits/types';\nexport type { Subscription, SubscriptionItem, FindSubscriptionsParams } from './modules/subscriptions/types';\nexport { SubscriptionSchema, SubscriptionItemSchema } from './modules/subscriptions/types';\nexport { ADDON_IDS } from './modules/subscriptions/constants/addons.constants';\nexport type { AddonKindEnum } from './modules/subscriptions/constants/addons.constants';\n\n// Providers\nexport { QueryProvider } from './providers/query.provider';\n\n// Middleware\nexport { createAuthMiddleware } from './middlewares/create-auth-middleware';\nexport { createMiddlewareChain } from './middlewares/chain';\nexport { continueChain, stopChain } from './middlewares/types';\nexport type { MiddlewareFunction, MiddlewareConfig, MiddlewareResult } from './middlewares/types';\n\n// Utils\nexport { cn } from './infra/utils/clsx';\nexport { buildQueryParams } from './infra/utils/params';\nexport { parseSchema, parseResult } from './infra/utils/parser';\n\n// Layout\nexport { MainLayout, MainLayoutContent, MainLayoutSpacer, MainLayoutMain } from './components/layouts/MainLayout';\nexport { NavBar } from './components/layouts/NavBar';\nexport type { NavBarProps } from './components/layouts/NavBar';\nexport { AppNavBar } from './components/layouts/AppNavBar';\nexport type { AppNavBarProps } from './components/layouts/AppNavBar';\nexport { AppMobileNavBar } from './components/layouts/AppMobileNavBar';\nexport type { AppMobileNavBarProps } from './components/layouts/AppMobileNavBar';\nexport { SideBarNavigation } from './components/layouts/SideBarNavigation';\nexport { MdSideBarNavigation } from './components/layouts/MdSideBarNavigation';\nexport { NotificationItem } from './components/layouts/NotificationItem';\nexport type { NotificationItemProps } from './components/layouts/NotificationItem';\nexport { NotificationsPopover } from './components/layouts/NotificationsPopover';\nexport type { NotificationsPopoverProps, NotificationData } from './components/layouts/NotificationsPopover';\nexport { UsersSelectorPopover } from './components/layouts/UsersSelectorPopover';\nexport type { UsersSelectorPopoverProps } from './components/layouts/UsersSelectorPopover';\nexport { ProfilePopover } from './components/layouts/ProfilePopover';\nexport type { ProfilePopoverProps, ProfileMenuItem } from './components/layouts/ProfilePopover';\nexport { NavBarItem } from './components/layouts/NavBarItem';\nexport type { NavBarItemProps } from './components/layouts/NavBarItem';\n\n// UI - Buttons\nexport { Button, buttonVariants } from './components/ui/buttons/Button';\nexport { CopyButton } from './components/ui/buttons/CopyButton';\nexport { default as CancelButton } from './components/ui/buttons/CancelButton';\n\n// UI - Data Display\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from './components/ui/data-display/Accordion';\nexport { Badge, badgeVariants } from './components/ui/data-display/Badge';\nexport { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent } from './components/ui/data-display/Card';\nexport { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis } from './components/ui/data-display/Pagination';\nexport { ScrollArea, ScrollBar } from './components/ui/data-display/ScrollArea';\nexport { Separator } from './components/ui/data-display/Separator';\nexport { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } from './components/ui/data-display/Table';\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/ui/data-display/Tabs';\nexport { UserAvatar } from './components/ui/data-display/UserAvatar';\nexport type { UserAvatarProps } from './components/ui/data-display/UserAvatar';\n\n// UI - Feedback\nexport { default as CircularProgress } from './components/ui/feedback/CircularProgress';\nexport { default as DefaultCircularProgress } from './components/ui/feedback/DefaultCircularProgress';\nexport { Progress } from './components/ui/feedback/Progress';\nexport { LoadingOverlay } from './components/ui/feedback/LoadingOverlay';\nexport { Toast, toastVariants, toastIconContainerVariants } from './components/ui/feedback/Toast';\nexport type { ToastProps } from './components/ui/feedback/Toast';\n\n// UI - Form\nexport { Calendar, CalendarDayButton } from './components/ui/form/Calendar';\nexport { Checkbox } from './components/ui/form/Checkbox';\nexport { DatePicker } from './components/ui/form/DatePicker';\nexport { DateRangePicker } from './components/ui/form/DateRangePicker';\nexport { Input } from './components/ui/form/Input';\nexport { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } from './components/ui/form/InputOtp';\nexport { RadioGroup, RadioGroupItem } from './components/ui/form/RadioGroup';\nexport { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from './components/ui/form/Select';\nexport { Switch } from './components/ui/form/Switch';\nexport { Textarea } from './components/ui/form/Textarea';\n\n// UI - Overlay\nexport { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from './components/ui/overlay/Command';\nexport { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger } from './components/ui/overlay/Dialog';\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } from './components/ui/overlay/Popover';\nexport { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from './components/ui/overlay/Sheet';\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from './components/ui/overlay/Tooltip';\n\n// Store\nexport { useMdSidebarStore } from './store/useMdSidebarStore';\nexport { useModalManager } from './store/useModalManager';\nexport type { ModalData } from './store/useModalManager';\n\n// Enums\nexport { AccountSectionType } from './enums/AccountSectionType';\n\n// Hooks\nexport { default as usePasswordVisibility } from './hooks/usePasswordVisibility';\nexport { default as useCountdownTimer } from './hooks/useCountdownTimer';\nexport { default as useIsMobile } from './hooks/useIsMobile';\n\n// Utils\nexport { formatPhone, formatTimer, formatFullName, formatCPF, formatCardNumber } from './utils/format/masks';\nexport { timezoneService } from './modules/accounts/services/timezone.service';\nexport type { TimezoneOption } from './modules/accounts/services/timezone.service';\nexport { buildLocaleOptions, LANGUAGE_OPTIONS as LOCALE_LANGUAGE_OPTIONS } from './utils/intl/locales';\nexport type { LocaleOption } from './utils/intl/locales';\nexport { copyToClipboard, readFromClipboard } from './utils/browser/clipboard';\n\n// UI - Form (new widgets)\nexport { FormField } from './components/ui/form/FormField';\nexport { SelectField } from './components/ui/form/SelectField';\nexport { ComboboxField } from './components/ui/form/ComboboxField';\nexport type { ComboboxOption } from './components/ui/form/ComboboxField';\nexport { default as PhoneInput } from './components/ui/form/PhoneInput';\nexport { default as SwitchOptionFieldWithIcon } from './components/ui/form/SwitchOptionFieldWithIcon';\nexport { TextAreaField } from './components/ui/form/TextAreaField';\n\n// Account Module - Hooks\nexport {\n useUpdateAccount,\n useUpdateAccountUser,\n useUpdateAccountUserById,\n useDeleteAccountUser,\n useDeleteAccount,\n} from './modules/accounts/hooks/useAccountManagement';\n\n// Account Types\nexport type {\n UpdateAccountRequest,\n UpdateAccountUserRequest,\n ChangePasswordRequest,\n DeleteAccountActionResult,\n DeleteUserActionResult,\n UpdateAccountActionResult,\n UpdateUserActionResult,\n TwoFactorGenerateResult,\n TwoFactorActionResult,\n ContactResetResult,\n} from './modules/accounts/types';\n\nexport { default as AccountModals } from './components/account/AccountModals';\nexport { useAccountModals } from './store/useAccountModals';\nexport type { AccountModalsConfig } from './store/useAccountModals';\n\nexport { ModalManager } from './components/modals/ModalManager';\nexport { Modals } from './components/modals/Modals';\n\nexport { default as TwoFactorAuthModal } from './components/account/TwoFactorAuthModal';\nexport { default as DisableTwoFactorAuthModal } from './components/account/DisableTwoFactorAuthModal';\nexport { default as ConfirmGlobalPreferencesModal } from './components/account/ConfirmGlobalPreferencesModal';\nexport { MyProfileSection } from './components/account/sections/MyProfileSection';\nexport { PreferencesSection } from './components/account/sections/PreferencesSection';\nexport { SecuritySection } from './components/account/sections/SecuritySection';\nexport { ChangePasswordSection } from './components/account/sections/ChangePasswordSection';\nexport { ChangeEmailModal } from './components/account/sections/ChangeEmailModal';\nexport { ChangePhoneModal } from './components/account/sections/ChangePhoneModal';\n\n// Account Constants\nexport {\n GENDER_OPTIONS,\n CURRENCY_OPTIONS,\n TIME_FORMAT_OPTIONS,\n NOTIFICATION_TYPES,\n LANGUAGE_OPTIONS,\n} from './components/account/constants';\n"],"mappings":"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","names":["default","LANGUAGE_OPTIONS"]}
@@ -0,0 +1,9 @@
1
+ "use server";
2
+ import { authService } from "../services/auth.service";
3
+ async function isTwoFactorPendingAction() {
4
+ return authService.isTwoFactorPending();
5
+ }
6
+ export {
7
+ isTwoFactorPendingAction
8
+ };
9
+ //# sourceMappingURL=is-two-factor-pending.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/auth/actions/is-two-factor-pending.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { authService } from '../services/auth.service';\r\n\r\nexport async function isTwoFactorPendingAction(): Promise<boolean> {\r\n return authService.isTwoFactorPending();\r\n}\r\n"],"mappings":";AAEA,SAAS,mBAAmB;AAE5B,eAAsB,2BAA6C;AACjE,SAAO,YAAY,mBAAmB;AACxC;","names":[]}
@@ -0,0 +1,16 @@
1
+ "use server";
2
+ import { authService } from "../services/auth.service";
3
+ import { ApiError } from "../../../infra/api/types";
4
+ import { getClientInfoFromRequest } from "../../../infra/utils/client-info";
5
+ async function verifyTwoFactorAction(code) {
6
+ if (!Number.isInteger(code) || code < 0 || code > 999999) {
7
+ throw new ApiError("C\xF3digo inv\xE1lido", "INVALID_CODE", 400);
8
+ }
9
+ const clientInfo = await getClientInfoFromRequest();
10
+ await authService.verifyTwoFactor(code, clientInfo);
11
+ return { success: true };
12
+ }
13
+ export {
14
+ verifyTwoFactorAction
15
+ };
16
+ //# sourceMappingURL=verify-two-factor.action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/modules/auth/actions/verify-two-factor.action.ts"],"sourcesContent":["'use server';\r\n\r\nimport { authService } from '../services/auth.service';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { getClientInfoFromRequest } from '../../../infra/utils/client-info';\r\n\r\nexport async function verifyTwoFactorAction(code: number): Promise<{ success: boolean }> {\r\n if (!Number.isInteger(code) || code < 0 || code > 999999) {\r\n throw new ApiError('Código inválido', 'INVALID_CODE', 400);\r\n }\r\n\r\n const clientInfo = await getClientInfoFromRequest();\r\n await authService.verifyTwoFactor(code, clientInfo);\r\n return { success: true };\r\n}\r\n"],"mappings":";AAEA,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,gCAAgC;AAEzC,eAAsB,sBAAsB,MAA6C;AACvF,MAAI,CAAC,OAAO,UAAU,IAAI,KAAK,OAAO,KAAK,OAAO,QAAQ;AACxD,UAAM,IAAI,SAAS,yBAAmB,gBAAgB,GAAG;AAAA,EAC3D;AAEA,QAAM,aAAa,MAAM,yBAAyB;AAClD,QAAM,YAAY,gBAAgB,MAAM,UAAU;AAClD,SAAO,EAAE,SAAS,KAAK;AACzB;","names":[]}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useQuery, useQueryClient } from "@tanstack/react-query";
2
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  const USER_QUERY_KEY = ["user"];
4
4
  async function fetchUser() {
5
5
  const { findUserById: getUserDataAction } = await import("../../users/action/find-user-by-id.action");
@@ -30,6 +30,30 @@ function useUserValidateSession(options) {
30
30
  refetchOnWindowFocus: true
31
31
  });
32
32
  }
33
+ function useTwoFactorVerify() {
34
+ const queryClient = useQueryClient();
35
+ return useMutation({
36
+ mutationFn: async (code) => {
37
+ const { verifyTwoFactorAction } = await import("../actions/verify-two-factor.action");
38
+ return verifyTwoFactorAction(code);
39
+ },
40
+ onSuccess: () => {
41
+ queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
42
+ queryClient.invalidateQueries({ queryKey: ["two-factor-pending"] });
43
+ }
44
+ });
45
+ }
46
+ function useTwoFactorPending() {
47
+ return useQuery({
48
+ queryKey: ["two-factor-pending"],
49
+ queryFn: async () => {
50
+ const { isTwoFactorPendingAction } = await import("../actions/is-two-factor-pending.action");
51
+ return isTwoFactorPendingAction();
52
+ },
53
+ staleTime: 10 * 1e3,
54
+ retry: false
55
+ });
56
+ }
33
57
  function useInvalidateUser() {
34
58
  const queryClient = useQueryClient();
35
59
  return () => queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
@@ -42,6 +66,8 @@ export {
42
66
  USER_QUERY_KEY,
43
67
  useInvalidateUser,
44
68
  useSetUserData,
69
+ useTwoFactorPending,
70
+ useTwoFactorVerify,
45
71
  useUserQuery,
46
72
  useUserValidateSession
47
73
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/auth/hooks/useUserQuery.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';\r\nimport { User } from '../../users/schema';\r\n\r\nexport const USER_QUERY_KEY = ['user'];\r\n\r\nasync function fetchUser(): Promise<User | null> {\r\n const { findUserById: getUserDataAction } = await import('../../users/action/find-user-by-id.action');\r\n const result = await getUserDataAction();\r\n return result.success && result.data ? result.data : null;\r\n}\r\n\r\nasync function validateUserSession(): Promise<boolean> {\r\n const { validateSessionAction } = await import('../actions/validate-session.action');\r\n return await validateSessionAction();\r\n}\r\n\r\nexport function useUserQuery() {\r\n return useQuery({\r\n queryKey: USER_QUERY_KEY,\r\n queryFn: fetchUser,\r\n staleTime: 5 * 60 * 1000,\r\n gcTime: 10 * 60 * 1000,\r\n retry: false,\r\n });\r\n}\r\n\r\nexport function useUserValidateSession(options?: UseQueryOptions) {\r\n return useQuery({\r\n queryKey: ['user-validate-session'],\r\n queryFn: validateUserSession,\r\n retry: false,\r\n staleTime: 5 * 60 * 1000,\r\n ...options,\r\n refetchOnMount: 'always',\r\n refetchOnWindowFocus: true,\r\n });\r\n}\r\n\r\nexport function useInvalidateUser() {\r\n const queryClient = useQueryClient();\r\n return () => queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });\r\n}\r\n\r\nexport function useSetUserData() {\r\n const queryClient = useQueryClient();\r\n return (user: User | null) => queryClient.setQueryData(USER_QUERY_KEY, user);\r\n}\r\n"],"mappings":";AAEA,SAAS,UAAU,sBAAuC;AAGnD,MAAM,iBAAiB,CAAC,MAAM;AAErC,eAAe,YAAkC;AAC/C,QAAM,EAAE,cAAc,kBAAkB,IAAI,MAAM,OAAO,2CAA2C;AACpG,QAAM,SAAS,MAAM,kBAAkB;AACvC,SAAO,OAAO,WAAW,OAAO,OAAO,OAAO,OAAO;AACvD;AAEA,eAAe,sBAAwC;AACrD,QAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,oCAAoC;AACnF,SAAO,MAAM,sBAAsB;AACrC;AAEO,SAAS,eAAe;AAC7B,SAAO,SAAS;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,WAAW,IAAI,KAAK;AAAA,IACpB,QAAQ,KAAK,KAAK;AAAA,IAClB,OAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,uBAAuB,SAA2B;AAChE,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,uBAAuB;AAAA,IAClC,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,IAAI,KAAK;AAAA,IACpB,GAAG;AAAA,IACH,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EACxB,CAAC;AACH;AAEO,SAAS,oBAAoB;AAClC,QAAM,cAAc,eAAe;AACnC,SAAO,MAAM,YAAY,kBAAkB,EAAE,UAAU,eAAe,CAAC;AACzE;AAEO,SAAS,iBAAiB;AAC/B,QAAM,cAAc,eAAe;AACnC,SAAO,CAAC,SAAsB,YAAY,aAAa,gBAAgB,IAAI;AAC7E;","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/auth/hooks/useUserQuery.ts"],"sourcesContent":["'use client';\r\n\r\nimport { useMutation, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';\r\nimport { User } from '../../users/schema';\r\n\r\nexport const USER_QUERY_KEY = ['user'];\r\n\r\nasync function fetchUser(): Promise<User | null> {\r\n const { findUserById: getUserDataAction } = await import('../../users/action/find-user-by-id.action');\r\n const result = await getUserDataAction();\r\n return result.success && result.data ? result.data : null;\r\n}\r\n\r\nasync function validateUserSession(): Promise<boolean> {\r\n const { validateSessionAction } = await import('../actions/validate-session.action');\r\n return await validateSessionAction();\r\n}\r\n\r\nexport function useUserQuery() {\r\n return useQuery({\r\n queryKey: USER_QUERY_KEY,\r\n queryFn: fetchUser,\r\n staleTime: 5 * 60 * 1000,\r\n gcTime: 10 * 60 * 1000,\r\n retry: false,\r\n });\r\n}\r\n\r\nexport function useUserValidateSession(options?: UseQueryOptions) {\r\n return useQuery({\r\n queryKey: ['user-validate-session'],\r\n queryFn: validateUserSession,\r\n retry: false,\r\n staleTime: 5 * 60 * 1000,\r\n ...options,\r\n refetchOnMount: 'always',\r\n refetchOnWindowFocus: true,\r\n });\r\n}\r\n\r\nexport function useTwoFactorVerify() {\r\n const queryClient = useQueryClient();\r\n\r\n return useMutation({\r\n mutationFn: async (code: number) => {\r\n const { verifyTwoFactorAction } = await import('../actions/verify-two-factor.action');\r\n return verifyTwoFactorAction(code);\r\n },\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });\r\n queryClient.invalidateQueries({ queryKey: ['two-factor-pending'] });\r\n },\r\n });\r\n}\r\n\r\nexport function useTwoFactorPending() {\r\n return useQuery({\r\n queryKey: ['two-factor-pending'],\r\n queryFn: async () => {\r\n const { isTwoFactorPendingAction } = await import('../actions/is-two-factor-pending.action');\r\n return isTwoFactorPendingAction();\r\n },\r\n staleTime: 10 * 1000,\r\n retry: false,\r\n });\r\n}\r\n\r\nexport function useInvalidateUser() {\r\n const queryClient = useQueryClient();\r\n return () => queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });\r\n}\r\n\r\nexport function useSetUserData() {\r\n const queryClient = useQueryClient();\r\n return (user: User | null) => queryClient.setQueryData(USER_QUERY_KEY, user);\r\n}\r\n"],"mappings":";AAEA,SAAS,aAAa,UAAU,sBAAuC;AAGhE,MAAM,iBAAiB,CAAC,MAAM;AAErC,eAAe,YAAkC;AAC/C,QAAM,EAAE,cAAc,kBAAkB,IAAI,MAAM,OAAO,2CAA2C;AACpG,QAAM,SAAS,MAAM,kBAAkB;AACvC,SAAO,OAAO,WAAW,OAAO,OAAO,OAAO,OAAO;AACvD;AAEA,eAAe,sBAAwC;AACrD,QAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,oCAAoC;AACnF,SAAO,MAAM,sBAAsB;AACrC;AAEO,SAAS,eAAe;AAC7B,SAAO,SAAS;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,WAAW,IAAI,KAAK;AAAA,IACpB,QAAQ,KAAK,KAAK;AAAA,IAClB,OAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,uBAAuB,SAA2B;AAChE,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,uBAAuB;AAAA,IAClC,SAAS;AAAA,IACT,OAAO;AAAA,IACP,WAAW,IAAI,KAAK;AAAA,IACpB,GAAG;AAAA,IACH,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,EACxB,CAAC;AACH;AAEO,SAAS,qBAAqB;AACnC,QAAM,cAAc,eAAe;AAEnC,SAAO,YAAY;AAAA,IACjB,YAAY,OAAO,SAAiB;AAClC,YAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,qCAAqC;AACpF,aAAO,sBAAsB,IAAI;AAAA,IACnC;AAAA,IACA,WAAW,MAAM;AACf,kBAAY,kBAAkB,EAAE,UAAU,eAAe,CAAC;AAC1D,kBAAY,kBAAkB,EAAE,UAAU,CAAC,oBAAoB,EAAE,CAAC;AAAA,IACpE;AAAA,EACF,CAAC;AACH;AAEO,SAAS,sBAAsB;AACpC,SAAO,SAAS;AAAA,IACd,UAAU,CAAC,oBAAoB;AAAA,IAC/B,SAAS,YAAY;AACnB,YAAM,EAAE,yBAAyB,IAAI,MAAM,OAAO,yCAAyC;AAC3F,aAAO,yBAAyB;AAAA,IAClC;AAAA,IACA,WAAW,KAAK;AAAA,IAChB,OAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,oBAAoB;AAClC,QAAM,cAAc,eAAe;AACnC,SAAO,MAAM,YAAY,kBAAkB,EAAE,UAAU,eAAe,CAAC;AACzE;AAEO,SAAS,iBAAiB;AAC/B,QAAM,cAAc,eAAe;AACnC,SAAO,CAAC,SAAsB,YAAY,aAAa,gBAAgB,IAAI;AAC7E;","names":[]}
@@ -2,33 +2,41 @@ import { cookies } from "next/headers";
2
2
  import { apiClient } from "../../../infra/api/client";
3
3
  import { ApiError } from "../../../infra/api/types";
4
4
  const AUTH_COOKIE_NAME = "greatapps";
5
+ const PENDING_2FA_COOKIE_NAME = "greatapps_2fa_pending";
5
6
  const COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
7
+ const PENDING_2FA_MAX_AGE = 60 * 10;
8
+ const COOKIE_OPTIONS = {
9
+ httpOnly: true,
10
+ secure: process.env.NODE_ENV === "production",
11
+ sameSite: "lax",
12
+ path: "/",
13
+ domain: process.env.DOMAIN_COOKIE
14
+ };
6
15
  async function setAuthCookie(token) {
7
16
  const cookieStore = await cookies();
8
- cookieStore.set(AUTH_COOKIE_NAME, token, {
9
- httpOnly: true,
10
- secure: process.env.NODE_ENV === "production",
11
- sameSite: "lax",
12
- maxAge: COOKIE_MAX_AGE,
13
- path: "/",
14
- domain: process.env.DOMAIN_COOKIE
15
- });
17
+ cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });
16
18
  }
17
19
  async function removeAuthCookie() {
18
20
  const cookieStore = await cookies();
19
- cookieStore.delete({
20
- name: AUTH_COOKIE_NAME,
21
- path: "/",
22
- secure: process.env.NODE_ENV === "production",
23
- sameSite: "lax",
24
- domain: process.env.DOMAIN_COOKIE
25
- });
21
+ cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });
26
22
  }
27
23
  async function getAuthCookie() {
28
24
  if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;
29
25
  const cookieStore = await cookies();
30
26
  return cookieStore.get(AUTH_COOKIE_NAME)?.value;
31
27
  }
28
+ async function setPending2FACookie(token) {
29
+ const cookieStore = await cookies();
30
+ cookieStore.set(PENDING_2FA_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: PENDING_2FA_MAX_AGE });
31
+ }
32
+ async function removePending2FACookie() {
33
+ const cookieStore = await cookies();
34
+ cookieStore.delete({ name: PENDING_2FA_COOKIE_NAME, ...COOKIE_OPTIONS });
35
+ }
36
+ async function getPending2FACookie() {
37
+ const cookieStore = await cookies();
38
+ return cookieStore.get(PENDING_2FA_COOKIE_NAME)?.value;
39
+ }
32
40
  class AuthService {
33
41
  async login(credentials, clientInfo) {
34
42
  const response = await apiClient.post("/auth/login", {
@@ -45,15 +53,45 @@ class AuthService {
45
53
  if (!response.cookie) {
46
54
  throw new ApiError("Resposta de autentica\xE7\xE3o inv\xE1lida", "INVALID_RESPONSE", 500);
47
55
  }
56
+ if (response.two_factor_authentication) {
57
+ await setPending2FACookie(response.cookie);
58
+ return { twoFactorRequired: true };
59
+ }
48
60
  await setAuthCookie(response.cookie);
49
61
  return {
50
62
  user: {},
51
- // Placeholder, será preenchido pelo AuthProvider
52
63
  accessToken: response.cookie,
53
64
  refreshToken: "",
54
65
  expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1e3).toISOString()
55
66
  };
56
67
  }
68
+ async verifyTwoFactor(code, clientInfo) {
69
+ const pendingCookie = await getPending2FACookie();
70
+ if (!pendingCookie) {
71
+ throw new ApiError("Nenhuma autentica\xE7\xE3o 2FA pendente", "NO_PENDING_2FA", 400);
72
+ }
73
+ const payload = {
74
+ location: clientInfo.location,
75
+ ip: clientInfo.ip,
76
+ timezone: clientInfo.timezone,
77
+ agent: clientInfo.agent,
78
+ cookie: pendingCookie,
79
+ code
80
+ };
81
+ const response = await apiClient.post("/auth/code", payload);
82
+ if (response.status === 0) {
83
+ throw new ApiError(response.message || "C\xF3digo 2FA inv\xE1lido", "TWO_FACTOR_FAILED", 401);
84
+ }
85
+ if (!response.cookie) {
86
+ throw new ApiError("Resposta de autentica\xE7\xE3o inv\xE1lida ap\xF3s 2FA", "INVALID_RESPONSE", 500);
87
+ }
88
+ await Promise.all([setAuthCookie(response.cookie), removePending2FACookie()]);
89
+ return { success: true };
90
+ }
91
+ async isTwoFactorPending() {
92
+ const pending = await getPending2FACookie();
93
+ return !!pending;
94
+ }
57
95
  async register(data) {
58
96
  const today = /* @__PURE__ */ new Date();
59
97
  const trialEndDate = new Date(today);
@@ -120,8 +158,7 @@ class AuthService {
120
158
  throw new ApiError(response.message || "Erro ao realizar logout", "LOGOUT_FAILED", 400);
121
159
  }
122
160
  } finally {
123
- console.log("[AuthService] Logout - removendo cookie localmente");
124
- await removeAuthCookie();
161
+ await Promise.all([removeAuthCookie(), removePending2FACookie()]);
125
162
  }
126
163
  return {
127
164
  success: true
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { apiClient } from '../../../infra/api/client';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { User } from '../../users/schema';\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from '../schema';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\n\r\nasync function setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'lax',\r\n maxAge: COOKIE_MAX_AGE,\r\n path: '/',\r\n domain: process.env.DOMAIN_COOKIE\r\n });\r\n}\r\n\r\nasync function removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({\r\n name: AUTH_COOKIE_NAME,\r\n path: \"/\",\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'lax',\r\n domain: process.env.DOMAIN_COOKIE,\r\n });\r\n}\r\n\r\nasync function getAuthCookie(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n}\r\n\r\nclass AuthService {\r\n async login(credentials: LoginRequest, clientInfo: ClientInfo): Promise<LoginResponse> {\r\n const response = await apiClient.post<LoginApiResponse>('/auth/login', {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'E-mail ou senha incorretos', 'LOGIN_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n await setAuthCookie(response.cookie);\r\n\r\n // O usuário completo será carregado pelo AuthProvider via getUserDataAction\r\n return {\r\n user: {} as User, // Placeholder, será preenchido pelo AuthProvider\r\n accessToken: response.cookie,\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async register(data: RegisterRequest): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: 'pt-br',\r\n timezone: 'America/Sao_Paulo',\r\n currency: 'BRL',\r\n user: {\r\n id_api: '',\r\n name: data.name,\r\n last_name: data.lastName || '',\r\n rg: data.rg || '',\r\n cpf: data.cpf || '',\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: 'owner',\r\n language: 'pt-br',\r\n },\r\n subscription: {\r\n type: 'trial',\r\n id_cupom: '',\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split('T')[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await apiClient.post<RegisterApiResponse>('/accounts', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao criar conta', 'REGISTER_FAILED', 400);\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError('Resposta de registro inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n // Retornar sem token pois o registro não retorna cookie diretamente\r\n // O usuário precisará fazer login após o registro\r\n // O usuário completo será carregado após o login\r\n return {\r\n user: {} as User, // Placeholder, será preenchido após login\r\n accessToken: '',\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED', 401);\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await apiClient.post<LogoutApiResponse>('/auth/logout', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao realizar logout', 'LOGOUT_FAILED', 400);\r\n }\r\n } finally {\r\n console.log('[AuthService] Logout - removendo cookie localmente');\r\n await removeAuthCookie();\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(_data: ForgotPasswordRequest): Promise<ForgotPasswordResponse> {\r\n throw new ApiError('Recuperação de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resetPassword(_data: ResetPasswordRequest): Promise<ResetPasswordResponse> {\r\n throw new ApiError('Redefinição de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError('Verificação de email não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resendVerification(_data: ResendVerificationRequest): Promise<ResendVerificationResponse> {\r\n throw new ApiError('Reenvio de verificação não implementado', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await apiClient.post<SessionKeepResponse>('/auth/keep', payload);\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error('[AuthService] validateSession error', error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await getAuthCookie();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n return getAuthCookie();\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/modules/auth/services/auth.service.ts"],"sourcesContent":["\r\nimport { cookies } from 'next/headers';\r\n\r\nimport { apiClient } from '../../../infra/api/client';\r\nimport { ApiError } from '../../../infra/api/types';\r\nimport { User } from '../../users/schema';\r\nimport {\r\n ClientInfo,\r\n ForgotPasswordRequest,\r\n ForgotPasswordResponse,\r\n GeoLocation,\r\n LoginApiResponse,\r\n LoginRequest,\r\n LoginResponse,\r\n LogoutApiResponse,\r\n LogoutRequest,\r\n LogoutResponse,\r\n RegisterApiRequest,\r\n RegisterApiResponse,\r\n RegisterRequest,\r\n RegisterResponse,\r\n ResendVerificationRequest,\r\n ResendVerificationResponse,\r\n ResetPasswordRequest,\r\n ResetPasswordResponse,\r\n SessionKeepRequest,\r\n SessionKeepResponse,\r\n TwoFactorApiResponse,\r\n TwoFactorRequest,\r\n TwoFactorResponse,\r\n VerifyEmailRequest,\r\n VerifyEmailResponse,\r\n} from '../schema';\r\n\r\nconst AUTH_COOKIE_NAME = 'greatapps';\r\nconst PENDING_2FA_COOKIE_NAME = 'greatapps_2fa_pending';\r\nconst COOKIE_MAX_AGE = 60 * 60 * 24 * 30;\r\nconst PENDING_2FA_MAX_AGE = 60 * 10; // 10 minutos para completar o 2FA\r\n\r\nconst COOKIE_OPTIONS = {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'lax' as const,\r\n path: '/',\r\n domain: process.env.DOMAIN_COOKIE,\r\n};\r\n\r\nasync function setAuthCookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });\r\n}\r\n\r\nasync function removeAuthCookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });\r\n}\r\n\r\nasync function getAuthCookie(): Promise<string | undefined> {\r\n if (process.env.DUMMY_AUTH_TOKEN) return process.env.DUMMY_AUTH_TOKEN;\r\n const cookieStore = await cookies();\r\n return cookieStore.get(AUTH_COOKIE_NAME)?.value;\r\n}\r\n\r\nasync function setPending2FACookie(token: string): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.set(PENDING_2FA_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: PENDING_2FA_MAX_AGE });\r\n}\r\n\r\nasync function removePending2FACookie(): Promise<void> {\r\n const cookieStore = await cookies();\r\n cookieStore.delete({ name: PENDING_2FA_COOKIE_NAME, ...COOKIE_OPTIONS });\r\n}\r\n\r\nasync function getPending2FACookie(): Promise<string | undefined> {\r\n const cookieStore = await cookies();\r\n return cookieStore.get(PENDING_2FA_COOKIE_NAME)?.value;\r\n}\r\n\r\nclass AuthService {\r\n async login(credentials: LoginRequest, clientInfo: ClientInfo): Promise<LoginResponse> {\r\n const response = await apiClient.post<LoginApiResponse>('/auth/login', {\r\n email: credentials.email,\r\n password: credentials.password,\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n });\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'E-mail ou senha incorretos', 'LOGIN_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n if (response.two_factor_authentication) {\r\n // Armazena o cookie temporariamente até o 2FA ser concluído.\r\n // O cookie principal NÃO é setado aqui para evitar falso positivo em isAuthenticated().\r\n await setPending2FACookie(response.cookie);\r\n return { twoFactorRequired: true };\r\n }\r\n\r\n await setAuthCookie(response.cookie);\r\n\r\n return {\r\n user: {} as User,\r\n accessToken: response.cookie,\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n };\r\n }\r\n\r\n async verifyTwoFactor(code: number, clientInfo: ClientInfo): Promise<TwoFactorResponse> {\r\n const pendingCookie = await getPending2FACookie();\r\n\r\n if (!pendingCookie) {\r\n throw new ApiError('Nenhuma autenticação 2FA pendente', 'NO_PENDING_2FA', 400);\r\n }\r\n\r\n const payload: TwoFactorRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie: pendingCookie,\r\n code,\r\n };\r\n\r\n const response = await apiClient.post<TwoFactorApiResponse>('/auth/code', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Código 2FA inválido', 'TWO_FACTOR_FAILED', 401);\r\n }\r\n\r\n if (!response.cookie) {\r\n throw new ApiError('Resposta de autenticação inválida após 2FA', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n await Promise.all([setAuthCookie(response.cookie), removePending2FACookie()]);\r\n\r\n return { success: true };\r\n }\r\n\r\n async isTwoFactorPending(): Promise<boolean> {\r\n const pending = await getPending2FACookie();\r\n return !!pending;\r\n }\r\n\r\n async register(data: RegisterRequest): Promise<RegisterResponse> {\r\n const today = new Date();\r\n const trialEndDate = new Date(today);\r\n trialEndDate.setDate(today.getDate() + 7); // 7 dias de trial\r\n\r\n const payload: RegisterApiRequest = {\r\n name: data.accountName,\r\n bussiness_type: data.businessType,\r\n language: 'pt-br',\r\n timezone: 'America/Sao_Paulo',\r\n currency: 'BRL',\r\n user: {\r\n id_api: '',\r\n name: data.name,\r\n last_name: data.lastName || '',\r\n rg: data.rg || '',\r\n cpf: data.cpf || '',\r\n gender: data.gender,\r\n email: data.email,\r\n phone: data.phone,\r\n password: data.password,\r\n profile: 'owner',\r\n language: 'pt-br',\r\n },\r\n subscription: {\r\n type: 'trial',\r\n id_cupom: '',\r\n id_plan: 1,\r\n due_date: trialEndDate.toISOString().split('T')[0],\r\n id_product: 1,\r\n },\r\n };\r\n\r\n const response = await apiClient.post<RegisterApiResponse>('/accounts', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao criar conta', 'REGISTER_FAILED', 400);\r\n }\r\n\r\n if (!response.data || response.data.length === 0) {\r\n throw new ApiError('Resposta de registro inválida', 'INVALID_RESPONSE', 500);\r\n }\r\n\r\n const accountData = response.data[0];\r\n\r\n // Retornar sem token pois o registro não retorna cookie diretamente\r\n // O usuário precisará fazer login após o registro\r\n // O usuário completo será carregado após o login\r\n return {\r\n user: {} as User, // Placeholder, será preenchido após login\r\n accessToken: '',\r\n refreshToken: '',\r\n expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),\r\n requiresEmailVerification: !accountData.verified,\r\n };\r\n }\r\n\r\n async logout(clientInfo: ClientInfo): Promise<LogoutResponse> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n throw new ApiError('Usuário não autenticado', 'NOT_AUTHENTICATED', 401);\r\n }\r\n\r\n const payload: LogoutRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n try {\r\n const response = await apiClient.post<LogoutApiResponse>('/auth/logout', payload);\r\n\r\n if (response.status === 0) {\r\n throw new ApiError(response.message || 'Erro ao realizar logout', 'LOGOUT_FAILED', 400);\r\n }\r\n } finally {\r\n await Promise.all([removeAuthCookie(), removePending2FACookie()]);\r\n }\r\n\r\n return {\r\n success: true,\r\n };\r\n }\r\n\r\n async forgotPassword(_data: ForgotPasswordRequest): Promise<ForgotPasswordResponse> {\r\n throw new ApiError('Recuperação de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resetPassword(_data: ResetPasswordRequest): Promise<ResetPasswordResponse> {\r\n throw new ApiError('Redefinição de senha não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async verifyEmail(_data: VerifyEmailRequest): Promise<VerifyEmailResponse> {\r\n throw new ApiError('Verificação de email não implementada', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async resendVerification(_data: ResendVerificationRequest): Promise<ResendVerificationResponse> {\r\n throw new ApiError('Reenvio de verificação não implementado', 'NOT_IMPLEMENTED', 501);\r\n }\r\n\r\n async validateSession(clientInfo: ClientInfo): Promise<boolean> {\r\n const cookie = await getAuthCookie();\r\n\r\n if (!cookie) {\r\n return false;\r\n }\r\n\r\n try {\r\n const payload: SessionKeepRequest = {\r\n location: clientInfo.location,\r\n ip: clientInfo.ip,\r\n timezone: clientInfo.timezone,\r\n agent: clientInfo.agent,\r\n cookie,\r\n };\r\n\r\n const response = await apiClient.post<SessionKeepResponse>('/auth/keep', payload);\r\n\r\n return response.status === 1;\r\n } catch (error) {\r\n console.error('[AuthService] validateSession error', error);\r\n return false;\r\n }\r\n }\r\n\r\n async isAuthenticated(): Promise<boolean> {\r\n const token = await getAuthCookie();\r\n return !!token;\r\n }\r\n\r\n async getToken(): Promise<string | undefined> {\r\n return getAuthCookie();\r\n }\r\n}\r\n\r\nexport const authService = new AuthService();\r\n\r\nexport type { ClientInfo, GeoLocation };\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/common",
3
- "version": "1.1.51",
3
+ "version": "1.1.52",
4
4
  "description": "Shared library for GreatApps frontend applications",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./src/index.ts",
package/src/index.ts CHANGED
@@ -13,7 +13,7 @@ export * from './providers/whitelabel.provider';
13
13
  export { useListProjectUsers, LIST_PROJECT_USERS_QUERY_KEY, LIST_PROJECT_USERS_BASE_KEY } from './modules/projects/hooks/list-project-users.hook';
14
14
  export { useListAvailableUsers, LIST_AVAILABLE_USERS_QUERY_KEY, LIST_AVAILABLE_USERS_BASE_KEY } from './modules/projects/hooks/list-available-users.hook';
15
15
  export type { ProjectUser, AccountUser, AddRemoveProjectUsersParams, ListUsersParams, UsersPage } from './modules/projects/types';
16
- export { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';
16
+ export { useUserQuery, useUserValidateSession, useInvalidateUser, useSetUserData, useTwoFactorVerify, useTwoFactorPending, USER_QUERY_KEY } from './modules/auth/hooks/useUserQuery';
17
17
  export { useSubscriptions, SUBSCRIPTIONS_QUERY_KEY } from './modules/subscriptions/hooks/list-subscriptions.hook';
18
18
  export { useActiveSubscription } from './modules/subscriptions/hooks/find-active-subscription.hook';
19
19
  export { useIaCredits } from './modules/ia-credits/hooks/ia-credits.hook';
@@ -0,0 +1,7 @@
1
+ 'use server';
2
+
3
+ import { authService } from '../services/auth.service';
4
+
5
+ export async function isTwoFactorPendingAction(): Promise<boolean> {
6
+ return authService.isTwoFactorPending();
7
+ }
@@ -0,0 +1,15 @@
1
+ 'use server';
2
+
3
+ import { authService } from '../services/auth.service';
4
+ import { ApiError } from '../../../infra/api/types';
5
+ import { getClientInfoFromRequest } from '../../../infra/utils/client-info';
6
+
7
+ export async function verifyTwoFactorAction(code: number): Promise<{ success: boolean }> {
8
+ if (!Number.isInteger(code) || code < 0 || code > 999999) {
9
+ throw new ApiError('Código inválido', 'INVALID_CODE', 400);
10
+ }
11
+
12
+ const clientInfo = await getClientInfoFromRequest();
13
+ await authService.verifyTwoFactor(code, clientInfo);
14
+ return { success: true };
15
+ }
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
3
+ import { useMutation, useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query';
4
4
  import { User } from '../../users/schema';
5
5
 
6
6
  export const USER_QUERY_KEY = ['user'];
@@ -38,6 +38,33 @@ export function useUserValidateSession(options?: UseQueryOptions) {
38
38
  });
39
39
  }
40
40
 
41
+ export function useTwoFactorVerify() {
42
+ const queryClient = useQueryClient();
43
+
44
+ return useMutation({
45
+ mutationFn: async (code: number) => {
46
+ const { verifyTwoFactorAction } = await import('../actions/verify-two-factor.action');
47
+ return verifyTwoFactorAction(code);
48
+ },
49
+ onSuccess: () => {
50
+ queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
51
+ queryClient.invalidateQueries({ queryKey: ['two-factor-pending'] });
52
+ },
53
+ });
54
+ }
55
+
56
+ export function useTwoFactorPending() {
57
+ return useQuery({
58
+ queryKey: ['two-factor-pending'],
59
+ queryFn: async () => {
60
+ const { isTwoFactorPendingAction } = await import('../actions/is-two-factor-pending.action');
61
+ return isTwoFactorPendingAction();
62
+ },
63
+ staleTime: 10 * 1000,
64
+ retry: false,
65
+ });
66
+ }
67
+
41
68
  export function useInvalidateUser() {
42
69
  const queryClient = useQueryClient();
43
70
  return () => queryClient.invalidateQueries({ queryKey: USER_QUERY_KEY });
@@ -15,6 +15,29 @@ export interface LoginApiResponse {
15
15
  two_factor_authentication?: boolean;
16
16
  }
17
17
 
18
+ export type LoginResponse =
19
+ | { twoFactorRequired: true }
20
+ | { twoFactorRequired?: false; user: User; accessToken: string; refreshToken: string; expiresAt: string };
21
+
22
+ export interface TwoFactorRequest {
23
+ location: GeoLocation;
24
+ ip: string;
25
+ timezone: string;
26
+ agent: string;
27
+ cookie: string;
28
+ code: number;
29
+ }
30
+
31
+ export interface TwoFactorApiResponse {
32
+ status: 0 | 1;
33
+ message: string;
34
+ cookie?: string;
35
+ }
36
+
37
+ export interface TwoFactorResponse {
38
+ success: boolean;
39
+ }
40
+
18
41
  export interface GeoLocation {
19
42
  continent: string;
20
43
  country: string;
@@ -37,13 +60,6 @@ export interface LoginRequest {
37
60
  rememberMe?: boolean;
38
61
  }
39
62
 
40
- export interface LoginResponse {
41
- user: User;
42
- accessToken: string;
43
- refreshToken: string;
44
- expiresAt: string;
45
- }
46
-
47
63
  export interface RegisterRequest {
48
64
  accountName: string;
49
65
  businessType: number;
@@ -25,34 +25,34 @@ import {
25
25
  ResetPasswordResponse,
26
26
  SessionKeepRequest,
27
27
  SessionKeepResponse,
28
+ TwoFactorApiResponse,
29
+ TwoFactorRequest,
30
+ TwoFactorResponse,
28
31
  VerifyEmailRequest,
29
32
  VerifyEmailResponse,
30
33
  } from '../schema';
31
34
 
32
35
  const AUTH_COOKIE_NAME = 'greatapps';
36
+ const PENDING_2FA_COOKIE_NAME = 'greatapps_2fa_pending';
33
37
  const COOKIE_MAX_AGE = 60 * 60 * 24 * 30;
38
+ const PENDING_2FA_MAX_AGE = 60 * 10; // 10 minutos para completar o 2FA
39
+
40
+ const COOKIE_OPTIONS = {
41
+ httpOnly: true,
42
+ secure: process.env.NODE_ENV === 'production',
43
+ sameSite: 'lax' as const,
44
+ path: '/',
45
+ domain: process.env.DOMAIN_COOKIE,
46
+ };
34
47
 
35
48
  async function setAuthCookie(token: string): Promise<void> {
36
49
  const cookieStore = await cookies();
37
- cookieStore.set(AUTH_COOKIE_NAME, token, {
38
- httpOnly: true,
39
- secure: process.env.NODE_ENV === 'production',
40
- sameSite: 'lax',
41
- maxAge: COOKIE_MAX_AGE,
42
- path: '/',
43
- domain: process.env.DOMAIN_COOKIE
44
- });
50
+ cookieStore.set(AUTH_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: COOKIE_MAX_AGE });
45
51
  }
46
52
 
47
53
  async function removeAuthCookie(): Promise<void> {
48
54
  const cookieStore = await cookies();
49
- cookieStore.delete({
50
- name: AUTH_COOKIE_NAME,
51
- path: "/",
52
- secure: process.env.NODE_ENV === 'production',
53
- sameSite: 'lax',
54
- domain: process.env.DOMAIN_COOKIE,
55
- });
55
+ cookieStore.delete({ name: AUTH_COOKIE_NAME, ...COOKIE_OPTIONS });
56
56
  }
57
57
 
58
58
  async function getAuthCookie(): Promise<string | undefined> {
@@ -61,6 +61,21 @@ async function getAuthCookie(): Promise<string | undefined> {
61
61
  return cookieStore.get(AUTH_COOKIE_NAME)?.value;
62
62
  }
63
63
 
64
+ async function setPending2FACookie(token: string): Promise<void> {
65
+ const cookieStore = await cookies();
66
+ cookieStore.set(PENDING_2FA_COOKIE_NAME, token, { ...COOKIE_OPTIONS, maxAge: PENDING_2FA_MAX_AGE });
67
+ }
68
+
69
+ async function removePending2FACookie(): Promise<void> {
70
+ const cookieStore = await cookies();
71
+ cookieStore.delete({ name: PENDING_2FA_COOKIE_NAME, ...COOKIE_OPTIONS });
72
+ }
73
+
74
+ async function getPending2FACookie(): Promise<string | undefined> {
75
+ const cookieStore = await cookies();
76
+ return cookieStore.get(PENDING_2FA_COOKIE_NAME)?.value;
77
+ }
78
+
64
79
  class AuthService {
65
80
  async login(credentials: LoginRequest, clientInfo: ClientInfo): Promise<LoginResponse> {
66
81
  const response = await apiClient.post<LoginApiResponse>('/auth/login', {
@@ -80,17 +95,59 @@ class AuthService {
80
95
  throw new ApiError('Resposta de autenticação inválida', 'INVALID_RESPONSE', 500);
81
96
  }
82
97
 
98
+ if (response.two_factor_authentication) {
99
+ // Armazena o cookie temporariamente até o 2FA ser concluído.
100
+ // O cookie principal NÃO é setado aqui para evitar falso positivo em isAuthenticated().
101
+ await setPending2FACookie(response.cookie);
102
+ return { twoFactorRequired: true };
103
+ }
104
+
83
105
  await setAuthCookie(response.cookie);
84
106
 
85
- // O usuário completo será carregado pelo AuthProvider via getUserDataAction
86
107
  return {
87
- user: {} as User, // Placeholder, será preenchido pelo AuthProvider
108
+ user: {} as User,
88
109
  accessToken: response.cookie,
89
110
  refreshToken: '',
90
111
  expiresAt: new Date(Date.now() + COOKIE_MAX_AGE * 1000).toISOString(),
91
112
  };
92
113
  }
93
114
 
115
+ async verifyTwoFactor(code: number, clientInfo: ClientInfo): Promise<TwoFactorResponse> {
116
+ const pendingCookie = await getPending2FACookie();
117
+
118
+ if (!pendingCookie) {
119
+ throw new ApiError('Nenhuma autenticação 2FA pendente', 'NO_PENDING_2FA', 400);
120
+ }
121
+
122
+ const payload: TwoFactorRequest = {
123
+ location: clientInfo.location,
124
+ ip: clientInfo.ip,
125
+ timezone: clientInfo.timezone,
126
+ agent: clientInfo.agent,
127
+ cookie: pendingCookie,
128
+ code,
129
+ };
130
+
131
+ const response = await apiClient.post<TwoFactorApiResponse>('/auth/code', payload);
132
+
133
+ if (response.status === 0) {
134
+ throw new ApiError(response.message || 'Código 2FA inválido', 'TWO_FACTOR_FAILED', 401);
135
+ }
136
+
137
+ if (!response.cookie) {
138
+ throw new ApiError('Resposta de autenticação inválida após 2FA', 'INVALID_RESPONSE', 500);
139
+ }
140
+
141
+ await Promise.all([setAuthCookie(response.cookie), removePending2FACookie()]);
142
+
143
+ return { success: true };
144
+ }
145
+
146
+ async isTwoFactorPending(): Promise<boolean> {
147
+ const pending = await getPending2FACookie();
148
+ return !!pending;
149
+ }
150
+
94
151
  async register(data: RegisterRequest): Promise<RegisterResponse> {
95
152
  const today = new Date();
96
153
  const trialEndDate = new Date(today);
@@ -170,8 +227,7 @@ class AuthService {
170
227
  throw new ApiError(response.message || 'Erro ao realizar logout', 'LOGOUT_FAILED', 400);
171
228
  }
172
229
  } finally {
173
- console.log('[AuthService] Logout - removendo cookie localmente');
174
- await removeAuthCookie();
230
+ await Promise.all([removeAuthCookie(), removePending2FACookie()]);
175
231
  }
176
232
 
177
233
  return {