mailsentry-auth 0.1.1 → 0.1.3

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.d.mts CHANGED
@@ -516,22 +516,22 @@ type AuthEvent = {
516
516
  sourcePageType?: PageType;
517
517
  };
518
518
  declare enum PageType {
519
- LOGIN = "/login",
520
- DASHBOARD = "/dashboard",
519
+ LOGIN = "login",
520
+ DASHBOARD = "dashboard",
521
521
  HOME = "/"
522
522
  }
523
523
  declare enum NavigationAction {
524
524
  NONE = "none",
525
525
  REDIRECT = "redirect",
526
- MODAL = "modal"
526
+ MODAL = "modal",
527
+ CURRENT = "current"
527
528
  }
528
529
  declare const PageTypePatterns: {
529
- readonly "/login": PageType.LOGIN;
530
- readonly "/dashboard": PageType.DASHBOARD;
531
- readonly "/": PageType.HOME;
530
+ readonly login: PageType.LOGIN;
531
+ readonly dashboard: PageType.DASHBOARD;
532
532
  };
533
533
  declare const CrossTabBehaviorConfig: {
534
- readonly "/login": {
534
+ readonly login: {
535
535
  readonly "auth.logged_in": {
536
536
  readonly action: NavigationAction.REDIRECT;
537
537
  readonly target: PageType.DASHBOARD;
@@ -546,31 +546,29 @@ declare const CrossTabBehaviorConfig: {
546
546
  readonly action: NavigationAction.NONE;
547
547
  };
548
548
  };
549
- readonly "/dashboard": {
549
+ readonly dashboard: {
550
550
  readonly "auth.logged_in": {
551
- readonly action: NavigationAction.MODAL;
551
+ readonly action: NavigationAction.CURRENT;
552
552
  };
553
553
  readonly "auth.logged_out": {
554
- readonly action: NavigationAction.REDIRECT;
555
- readonly target: PageType.DASHBOARD;
554
+ readonly action: NavigationAction.CURRENT;
556
555
  };
557
556
  readonly "auth.email_verified": {
558
- readonly action: NavigationAction.MODAL;
557
+ readonly action: NavigationAction.CURRENT;
559
558
  };
560
559
  readonly "auth.signin_required_modal": {
561
- readonly action: NavigationAction.NONE;
560
+ readonly action: NavigationAction.CURRENT;
562
561
  };
563
562
  };
564
563
  readonly "/": {
565
564
  readonly "auth.logged_in": {
566
- readonly action: NavigationAction.MODAL;
565
+ readonly action: NavigationAction.NONE;
567
566
  };
568
567
  readonly "auth.logged_out": {
569
- readonly action: NavigationAction.REDIRECT;
570
- readonly target: PageType.HOME;
568
+ readonly action: NavigationAction.NONE;
571
569
  };
572
570
  readonly "auth.email_verified": {
573
- readonly action: NavigationAction.MODAL;
571
+ readonly action: NavigationAction.NONE;
574
572
  };
575
573
  readonly "auth.signin_required_modal": {
576
574
  readonly action: NavigationAction.NONE;
@@ -588,6 +586,7 @@ interface MiddlewareContext {
588
586
  searchParams: URLSearchParams;
589
587
  cookies: NextRequest['cookies'];
590
588
  nextUrl: URL;
589
+ hostname: string;
591
590
  }
592
591
  /**
593
592
  * Base interface for middleware handlers
@@ -629,38 +628,49 @@ declare const getPasswordField: (isLogin: boolean, disabled?: boolean, options?:
629
628
  declare const getVerificationField: (codeLength?: number, options?: InputProps) => BaseFormField;
630
629
 
631
630
  /**
632
- * Middleware configuration constants
631
+ * Middleware configuration constants for subdomain-based routing
633
632
  */
634
633
  declare class MiddlewareConfig {
635
- static readonly PROTECTED_ROUTES: {
636
- readonly DASHBOARD: "/";
634
+ static readonly SUBDOMAINS: {
635
+ readonly DASHBOARD: "dashboard";
637
636
  };
638
- static readonly AUTH_ROUTES: {
637
+ static readonly ROUTES: {
638
+ readonly ROOT: "/";
639
639
  readonly LOGIN: "/login";
640
640
  };
641
641
  static readonly ALLOWED_METHODS: readonly ["GET", "HEAD"];
642
642
  static readonly QUERY_PARAMS: {
643
643
  readonly LOGIN_REQUIRED: "sign_in_required";
644
644
  readonly AUTH_CHECKED: "auth_checked";
645
+ readonly REDIRECT_URL: "redirect_url";
645
646
  };
646
647
  static readonly QUERY_VALUES: {
647
648
  readonly LOGIN_REQUIRED: "true";
648
649
  readonly AUTH_CHECKED: "1";
649
650
  };
651
+ /**
652
+ * Get the base domain from environment or use default
653
+ */
654
+ static getBaseDomain(): string;
655
+ /**
656
+ * Get the protocol based on environment
657
+ */
658
+ static getProtocol(): string;
659
+ /**
660
+ * Get the dashboard subdomain URL
661
+ */
662
+ static getDashboardUrl(path?: string): string;
650
663
  }
651
664
  /**
652
- * Middleware matcher patterns - exported separately for static analysis
653
- * Pattern includes:
654
- * - / (home route and all other routes for authentication protection)
655
- * - /login route (for authenticated user redirection)
656
- * Excludes: API routes, Next.js internals, static assets, and file extensions
665
+ * Middleware matcher patterns
666
+ * Matches all routes except API routes, Next.js internals, and static assets
657
667
  */
658
- declare const middlewareMatcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)", "/login"];
668
+ declare const middlewareMatcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"];
659
669
  /**
660
- * Middleware configuration - runs on all routes (including home) and login page
670
+ * Middleware configuration
661
671
  */
662
672
  declare const config: {
663
- matcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)", "/login"];
673
+ matcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"];
664
674
  };
665
675
 
666
676
  /**
@@ -793,11 +803,11 @@ declare class BroadcastChannelEventBus<TEvent> {
793
803
  /**
794
804
  * Cross-Tab Behavior Handler
795
805
  * Determines cross-tab behavior based on authentication events and current page context
796
- * Uses lookup patterns instead of conditional statements
806
+ * Uses object lookup pattern for page type detection
797
807
  */
798
808
  declare class CrossTabBehaviorHandler {
799
809
  /**
800
- * Get current page type based on pathname using pattern matching
810
+ * Get current page type using object lookup pattern
801
811
  */
802
812
  static getCurrentPageType(): PageType;
803
813
  /**
@@ -813,32 +823,43 @@ declare class CrossTabBehaviorHandler {
813
823
  } | {
814
824
  readonly action: NavigationAction.NONE;
815
825
  } | {
816
- readonly action: NavigationAction.MODAL;
826
+ readonly action: NavigationAction.CURRENT;
817
827
  } | {
818
- readonly action: NavigationAction.REDIRECT;
819
- readonly target: PageType.DASHBOARD;
828
+ readonly action: NavigationAction.CURRENT;
820
829
  } | {
821
- readonly action: NavigationAction.MODAL;
830
+ readonly action: NavigationAction.CURRENT;
822
831
  } | {
823
- readonly action: NavigationAction.NONE;
832
+ readonly action: NavigationAction.CURRENT;
824
833
  } | {
825
- readonly action: NavigationAction.MODAL;
834
+ readonly action: NavigationAction.NONE;
826
835
  } | {
827
- readonly action: NavigationAction.REDIRECT;
828
- readonly target: PageType.HOME;
836
+ readonly action: NavigationAction.NONE;
829
837
  } | {
830
- readonly action: NavigationAction.MODAL;
838
+ readonly action: NavigationAction.NONE;
831
839
  } | {
832
840
  readonly action: NavigationAction.NONE;
833
841
  };
834
842
  /**
835
843
  * Check if current route requires redirect for given event
844
+ * Returns PageType to redirect to, or null if no redirect needed
836
845
  */
837
846
  static shouldRedirect(currentPageType: PageType, eventType: AuthEventType): PageType | null;
847
+ }
848
+
849
+ /**
850
+ * URL utility functions
851
+ */
852
+ declare class UrlUtils {
853
+ /**
854
+ * Extract subdomain from hostname or URL
855
+ * Example: "dashboard.cutly.io" -> "dashboard"
856
+ * Example: "dashboard.localhost" -> "dashboard"
857
+ */
858
+ static getSubdomain(url: string): string | null;
838
859
  /**
839
- * Check if current route should show modal for given event
860
+ * Check if URL has auth-related query parameters
840
861
  */
841
- static shouldShowModal(currentPageType: PageType, eventType: AuthEventType): boolean;
862
+ static hasAuthParams(url: string): boolean;
842
863
  }
843
864
 
844
865
  /**
@@ -1489,4 +1510,4 @@ declare const useAuthFlowModal: () => {
1489
1510
  openModal: () => void;
1490
1511
  };
1491
1512
 
1492
- export { AUTH_ENDPOINTS, AlertDisplay, type AlertDisplayProps, type AnyStepProps, type ApiErrorResponse, type ApiKeyConfig, type AuthActionCallbacks, type AuthActionOptions, type AuthActionResult, type AuthActionResultFailure, type AuthActionResultSuccess, type AuthActionState, type AuthEvent, AuthEventType, AuthFlowContainer, AuthFlowModal, AuthFlowStep, AuthInitializer, AuthOrchestrator, AuthOrchestratorFactory, AuthResultFactory, AuthService, type AuthState, AuthenticatedState, type AuthenticatedStateProps, AuthenticationStatusContext, type BaseComponentProps, BaseErrorHandler, BaseEventBus, BaseForm, type BaseFormField, type BaseFormProps, type BaseResponse, BaseService, type BaseStepProps, BroadcastChannelEventBus, Channel, CookieUtils, CrossTabBehaviorConfig, CrossTabBehaviorHandler, CrossTabDemo, DevelopmentLogger, EMAIL_SUBMISSION_NAVIGATION, type EmailCheckResult, type EmailExistResponse, EmailStep, type EmailStepProps, EndpointBuilder, type EventBus, ExistingUserLoginStrategy, FormFields, type FormFieldsProps, FormHeader, type FormHeaderProps, GenericErrorHandler, HttpClient, type HttpClientConfig, type HttpError, HttpMethod, type HttpRequestOptions, type HttpResponse, type IAuthOrchestrator, type IAuthService, type IAuthStatusState, type IErrorHandler, type ILogger, type ILoginFlowStrategy, type ITokenManager, LocalStorageUtils, LoggerFactory, type LoginData, LoginFlowStrategyFactory, type LoginRequest, type LoginResponse, MiddlewareConfig, type MiddlewareContext, type MiddlewareHandler, NavigationAction, NetworkErrorHandler, NextAction, PASSWORD_SUBMISSION_NAVIGATION, PageType, PageTypePatterns, PasswordStep, type PasswordStepProps, ProductionLogger, ProfileStateRenderer, ProfileUIState, type PropsFactory, RoleType, SignupFlowStrategy, type Step, type StepComponent, type StepComponentRetriever, type StepConfig, type StepPropsFactoryRegistry, type StepRegistry, type StepRegistryBaseProps, type StepRegistryConfigs, type StepRegistryHandlers, type StepRegistryParams, type StepRegistryState, type StepperActions, type StepperState$1 as StepperState, type Subscription, TokenManager, UnauthenticatedState, type UseAuthActionHandler, type UseAuthEventBusProps, type UseFormSubmissionProps, type UseStepRegistryParams, type UseStepperReturn, type UserProfile, type UserProfileResponse, type UserSession, type UserState, UserStorageManager, type UserStoreState, VERIFICATION_SUBMISSION_NAVIGATION, ValidationErrorHandler, VerificationStep, type VerificationStepProps, type VerifyEmailRequest, type VerifyEmailResponse, config, createAuthSteps, createPropsFactoryRegistry, createStepRegistry, getAuthPageStepMessage, getEmailField, getEmailStepComponent, getPasswordField, getPasswordStepComponent, getStepForEmailSubmission, getStepForPasswordSubmission, getStepForVerificationSubmission, getStepProgressMessage, getVerificationField, getVerificationStepComponent, middlewareMatcher, useAuth, useAuthActionHandler, useAuthEventBus, useAuthFlowModal, useAuthInitializer, useIsAuthenticated, useLogout, useRefreshUser, useSharedEventBus, useSignInRequiredParams, useStepRegistry, useStepRenderer, useStepper, useUser, useUserActions, useUserData, useUserError, useUserLoading, useUserProfile, useUserStore, userSelectors };
1513
+ export { AUTH_ENDPOINTS, AlertDisplay, type AlertDisplayProps, type AnyStepProps, type ApiErrorResponse, type ApiKeyConfig, type AuthActionCallbacks, type AuthActionOptions, type AuthActionResult, type AuthActionResultFailure, type AuthActionResultSuccess, type AuthActionState, type AuthEvent, AuthEventType, AuthFlowContainer, AuthFlowModal, AuthFlowStep, AuthInitializer, AuthOrchestrator, AuthOrchestratorFactory, AuthResultFactory, AuthService, type AuthState, AuthenticatedState, type AuthenticatedStateProps, AuthenticationStatusContext, type BaseComponentProps, BaseErrorHandler, BaseEventBus, BaseForm, type BaseFormField, type BaseFormProps, type BaseResponse, BaseService, type BaseStepProps, BroadcastChannelEventBus, Channel, CookieUtils, CrossTabBehaviorConfig, CrossTabBehaviorHandler, CrossTabDemo, DevelopmentLogger, EMAIL_SUBMISSION_NAVIGATION, type EmailCheckResult, type EmailExistResponse, EmailStep, type EmailStepProps, EndpointBuilder, type EventBus, ExistingUserLoginStrategy, FormFields, type FormFieldsProps, FormHeader, type FormHeaderProps, GenericErrorHandler, HttpClient, type HttpClientConfig, type HttpError, HttpMethod, type HttpRequestOptions, type HttpResponse, type IAuthOrchestrator, type IAuthService, type IAuthStatusState, type IErrorHandler, type ILogger, type ILoginFlowStrategy, type ITokenManager, LocalStorageUtils, LoggerFactory, type LoginData, LoginFlowStrategyFactory, type LoginRequest, type LoginResponse, MiddlewareConfig, type MiddlewareContext, type MiddlewareHandler, NavigationAction, NetworkErrorHandler, NextAction, PASSWORD_SUBMISSION_NAVIGATION, PageType, PageTypePatterns, PasswordStep, type PasswordStepProps, ProductionLogger, ProfileStateRenderer, ProfileUIState, type PropsFactory, RoleType, SignupFlowStrategy, type Step, type StepComponent, type StepComponentRetriever, type StepConfig, type StepPropsFactoryRegistry, type StepRegistry, type StepRegistryBaseProps, type StepRegistryConfigs, type StepRegistryHandlers, type StepRegistryParams, type StepRegistryState, type StepperActions, type StepperState$1 as StepperState, type Subscription, TokenManager, UnauthenticatedState, UrlUtils, type UseAuthActionHandler, type UseAuthEventBusProps, type UseFormSubmissionProps, type UseStepRegistryParams, type UseStepperReturn, type UserProfile, type UserProfileResponse, type UserSession, type UserState, UserStorageManager, type UserStoreState, VERIFICATION_SUBMISSION_NAVIGATION, ValidationErrorHandler, VerificationStep, type VerificationStepProps, type VerifyEmailRequest, type VerifyEmailResponse, config, createAuthSteps, createPropsFactoryRegistry, createStepRegistry, getAuthPageStepMessage, getEmailField, getEmailStepComponent, getPasswordField, getPasswordStepComponent, getStepForEmailSubmission, getStepForPasswordSubmission, getStepForVerificationSubmission, getStepProgressMessage, getVerificationField, getVerificationStepComponent, middlewareMatcher, useAuth, useAuthActionHandler, useAuthEventBus, useAuthFlowModal, useAuthInitializer, useIsAuthenticated, useLogout, useRefreshUser, useSharedEventBus, useSignInRequiredParams, useStepRegistry, useStepRenderer, useStepper, useUser, useUserActions, useUserData, useUserError, useUserLoading, useUserProfile, useUserStore, userSelectors };
package/dist/index.d.ts CHANGED
@@ -516,22 +516,22 @@ type AuthEvent = {
516
516
  sourcePageType?: PageType;
517
517
  };
518
518
  declare enum PageType {
519
- LOGIN = "/login",
520
- DASHBOARD = "/dashboard",
519
+ LOGIN = "login",
520
+ DASHBOARD = "dashboard",
521
521
  HOME = "/"
522
522
  }
523
523
  declare enum NavigationAction {
524
524
  NONE = "none",
525
525
  REDIRECT = "redirect",
526
- MODAL = "modal"
526
+ MODAL = "modal",
527
+ CURRENT = "current"
527
528
  }
528
529
  declare const PageTypePatterns: {
529
- readonly "/login": PageType.LOGIN;
530
- readonly "/dashboard": PageType.DASHBOARD;
531
- readonly "/": PageType.HOME;
530
+ readonly login: PageType.LOGIN;
531
+ readonly dashboard: PageType.DASHBOARD;
532
532
  };
533
533
  declare const CrossTabBehaviorConfig: {
534
- readonly "/login": {
534
+ readonly login: {
535
535
  readonly "auth.logged_in": {
536
536
  readonly action: NavigationAction.REDIRECT;
537
537
  readonly target: PageType.DASHBOARD;
@@ -546,31 +546,29 @@ declare const CrossTabBehaviorConfig: {
546
546
  readonly action: NavigationAction.NONE;
547
547
  };
548
548
  };
549
- readonly "/dashboard": {
549
+ readonly dashboard: {
550
550
  readonly "auth.logged_in": {
551
- readonly action: NavigationAction.MODAL;
551
+ readonly action: NavigationAction.CURRENT;
552
552
  };
553
553
  readonly "auth.logged_out": {
554
- readonly action: NavigationAction.REDIRECT;
555
- readonly target: PageType.DASHBOARD;
554
+ readonly action: NavigationAction.CURRENT;
556
555
  };
557
556
  readonly "auth.email_verified": {
558
- readonly action: NavigationAction.MODAL;
557
+ readonly action: NavigationAction.CURRENT;
559
558
  };
560
559
  readonly "auth.signin_required_modal": {
561
- readonly action: NavigationAction.NONE;
560
+ readonly action: NavigationAction.CURRENT;
562
561
  };
563
562
  };
564
563
  readonly "/": {
565
564
  readonly "auth.logged_in": {
566
- readonly action: NavigationAction.MODAL;
565
+ readonly action: NavigationAction.NONE;
567
566
  };
568
567
  readonly "auth.logged_out": {
569
- readonly action: NavigationAction.REDIRECT;
570
- readonly target: PageType.HOME;
568
+ readonly action: NavigationAction.NONE;
571
569
  };
572
570
  readonly "auth.email_verified": {
573
- readonly action: NavigationAction.MODAL;
571
+ readonly action: NavigationAction.NONE;
574
572
  };
575
573
  readonly "auth.signin_required_modal": {
576
574
  readonly action: NavigationAction.NONE;
@@ -588,6 +586,7 @@ interface MiddlewareContext {
588
586
  searchParams: URLSearchParams;
589
587
  cookies: NextRequest['cookies'];
590
588
  nextUrl: URL;
589
+ hostname: string;
591
590
  }
592
591
  /**
593
592
  * Base interface for middleware handlers
@@ -629,38 +628,49 @@ declare const getPasswordField: (isLogin: boolean, disabled?: boolean, options?:
629
628
  declare const getVerificationField: (codeLength?: number, options?: InputProps) => BaseFormField;
630
629
 
631
630
  /**
632
- * Middleware configuration constants
631
+ * Middleware configuration constants for subdomain-based routing
633
632
  */
634
633
  declare class MiddlewareConfig {
635
- static readonly PROTECTED_ROUTES: {
636
- readonly DASHBOARD: "/";
634
+ static readonly SUBDOMAINS: {
635
+ readonly DASHBOARD: "dashboard";
637
636
  };
638
- static readonly AUTH_ROUTES: {
637
+ static readonly ROUTES: {
638
+ readonly ROOT: "/";
639
639
  readonly LOGIN: "/login";
640
640
  };
641
641
  static readonly ALLOWED_METHODS: readonly ["GET", "HEAD"];
642
642
  static readonly QUERY_PARAMS: {
643
643
  readonly LOGIN_REQUIRED: "sign_in_required";
644
644
  readonly AUTH_CHECKED: "auth_checked";
645
+ readonly REDIRECT_URL: "redirect_url";
645
646
  };
646
647
  static readonly QUERY_VALUES: {
647
648
  readonly LOGIN_REQUIRED: "true";
648
649
  readonly AUTH_CHECKED: "1";
649
650
  };
651
+ /**
652
+ * Get the base domain from environment or use default
653
+ */
654
+ static getBaseDomain(): string;
655
+ /**
656
+ * Get the protocol based on environment
657
+ */
658
+ static getProtocol(): string;
659
+ /**
660
+ * Get the dashboard subdomain URL
661
+ */
662
+ static getDashboardUrl(path?: string): string;
650
663
  }
651
664
  /**
652
- * Middleware matcher patterns - exported separately for static analysis
653
- * Pattern includes:
654
- * - / (home route and all other routes for authentication protection)
655
- * - /login route (for authenticated user redirection)
656
- * Excludes: API routes, Next.js internals, static assets, and file extensions
665
+ * Middleware matcher patterns
666
+ * Matches all routes except API routes, Next.js internals, and static assets
657
667
  */
658
- declare const middlewareMatcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)", "/login"];
668
+ declare const middlewareMatcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"];
659
669
  /**
660
- * Middleware configuration - runs on all routes (including home) and login page
670
+ * Middleware configuration
661
671
  */
662
672
  declare const config: {
663
- matcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)", "/login"];
673
+ matcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"];
664
674
  };
665
675
 
666
676
  /**
@@ -793,11 +803,11 @@ declare class BroadcastChannelEventBus<TEvent> {
793
803
  /**
794
804
  * Cross-Tab Behavior Handler
795
805
  * Determines cross-tab behavior based on authentication events and current page context
796
- * Uses lookup patterns instead of conditional statements
806
+ * Uses object lookup pattern for page type detection
797
807
  */
798
808
  declare class CrossTabBehaviorHandler {
799
809
  /**
800
- * Get current page type based on pathname using pattern matching
810
+ * Get current page type using object lookup pattern
801
811
  */
802
812
  static getCurrentPageType(): PageType;
803
813
  /**
@@ -813,32 +823,43 @@ declare class CrossTabBehaviorHandler {
813
823
  } | {
814
824
  readonly action: NavigationAction.NONE;
815
825
  } | {
816
- readonly action: NavigationAction.MODAL;
826
+ readonly action: NavigationAction.CURRENT;
817
827
  } | {
818
- readonly action: NavigationAction.REDIRECT;
819
- readonly target: PageType.DASHBOARD;
828
+ readonly action: NavigationAction.CURRENT;
820
829
  } | {
821
- readonly action: NavigationAction.MODAL;
830
+ readonly action: NavigationAction.CURRENT;
822
831
  } | {
823
- readonly action: NavigationAction.NONE;
832
+ readonly action: NavigationAction.CURRENT;
824
833
  } | {
825
- readonly action: NavigationAction.MODAL;
834
+ readonly action: NavigationAction.NONE;
826
835
  } | {
827
- readonly action: NavigationAction.REDIRECT;
828
- readonly target: PageType.HOME;
836
+ readonly action: NavigationAction.NONE;
829
837
  } | {
830
- readonly action: NavigationAction.MODAL;
838
+ readonly action: NavigationAction.NONE;
831
839
  } | {
832
840
  readonly action: NavigationAction.NONE;
833
841
  };
834
842
  /**
835
843
  * Check if current route requires redirect for given event
844
+ * Returns PageType to redirect to, or null if no redirect needed
836
845
  */
837
846
  static shouldRedirect(currentPageType: PageType, eventType: AuthEventType): PageType | null;
847
+ }
848
+
849
+ /**
850
+ * URL utility functions
851
+ */
852
+ declare class UrlUtils {
853
+ /**
854
+ * Extract subdomain from hostname or URL
855
+ * Example: "dashboard.cutly.io" -> "dashboard"
856
+ * Example: "dashboard.localhost" -> "dashboard"
857
+ */
858
+ static getSubdomain(url: string): string | null;
838
859
  /**
839
- * Check if current route should show modal for given event
860
+ * Check if URL has auth-related query parameters
840
861
  */
841
- static shouldShowModal(currentPageType: PageType, eventType: AuthEventType): boolean;
862
+ static hasAuthParams(url: string): boolean;
842
863
  }
843
864
 
844
865
  /**
@@ -1489,4 +1510,4 @@ declare const useAuthFlowModal: () => {
1489
1510
  openModal: () => void;
1490
1511
  };
1491
1512
 
1492
- export { AUTH_ENDPOINTS, AlertDisplay, type AlertDisplayProps, type AnyStepProps, type ApiErrorResponse, type ApiKeyConfig, type AuthActionCallbacks, type AuthActionOptions, type AuthActionResult, type AuthActionResultFailure, type AuthActionResultSuccess, type AuthActionState, type AuthEvent, AuthEventType, AuthFlowContainer, AuthFlowModal, AuthFlowStep, AuthInitializer, AuthOrchestrator, AuthOrchestratorFactory, AuthResultFactory, AuthService, type AuthState, AuthenticatedState, type AuthenticatedStateProps, AuthenticationStatusContext, type BaseComponentProps, BaseErrorHandler, BaseEventBus, BaseForm, type BaseFormField, type BaseFormProps, type BaseResponse, BaseService, type BaseStepProps, BroadcastChannelEventBus, Channel, CookieUtils, CrossTabBehaviorConfig, CrossTabBehaviorHandler, CrossTabDemo, DevelopmentLogger, EMAIL_SUBMISSION_NAVIGATION, type EmailCheckResult, type EmailExistResponse, EmailStep, type EmailStepProps, EndpointBuilder, type EventBus, ExistingUserLoginStrategy, FormFields, type FormFieldsProps, FormHeader, type FormHeaderProps, GenericErrorHandler, HttpClient, type HttpClientConfig, type HttpError, HttpMethod, type HttpRequestOptions, type HttpResponse, type IAuthOrchestrator, type IAuthService, type IAuthStatusState, type IErrorHandler, type ILogger, type ILoginFlowStrategy, type ITokenManager, LocalStorageUtils, LoggerFactory, type LoginData, LoginFlowStrategyFactory, type LoginRequest, type LoginResponse, MiddlewareConfig, type MiddlewareContext, type MiddlewareHandler, NavigationAction, NetworkErrorHandler, NextAction, PASSWORD_SUBMISSION_NAVIGATION, PageType, PageTypePatterns, PasswordStep, type PasswordStepProps, ProductionLogger, ProfileStateRenderer, ProfileUIState, type PropsFactory, RoleType, SignupFlowStrategy, type Step, type StepComponent, type StepComponentRetriever, type StepConfig, type StepPropsFactoryRegistry, type StepRegistry, type StepRegistryBaseProps, type StepRegistryConfigs, type StepRegistryHandlers, type StepRegistryParams, type StepRegistryState, type StepperActions, type StepperState$1 as StepperState, type Subscription, TokenManager, UnauthenticatedState, type UseAuthActionHandler, type UseAuthEventBusProps, type UseFormSubmissionProps, type UseStepRegistryParams, type UseStepperReturn, type UserProfile, type UserProfileResponse, type UserSession, type UserState, UserStorageManager, type UserStoreState, VERIFICATION_SUBMISSION_NAVIGATION, ValidationErrorHandler, VerificationStep, type VerificationStepProps, type VerifyEmailRequest, type VerifyEmailResponse, config, createAuthSteps, createPropsFactoryRegistry, createStepRegistry, getAuthPageStepMessage, getEmailField, getEmailStepComponent, getPasswordField, getPasswordStepComponent, getStepForEmailSubmission, getStepForPasswordSubmission, getStepForVerificationSubmission, getStepProgressMessage, getVerificationField, getVerificationStepComponent, middlewareMatcher, useAuth, useAuthActionHandler, useAuthEventBus, useAuthFlowModal, useAuthInitializer, useIsAuthenticated, useLogout, useRefreshUser, useSharedEventBus, useSignInRequiredParams, useStepRegistry, useStepRenderer, useStepper, useUser, useUserActions, useUserData, useUserError, useUserLoading, useUserProfile, useUserStore, userSelectors };
1513
+ export { AUTH_ENDPOINTS, AlertDisplay, type AlertDisplayProps, type AnyStepProps, type ApiErrorResponse, type ApiKeyConfig, type AuthActionCallbacks, type AuthActionOptions, type AuthActionResult, type AuthActionResultFailure, type AuthActionResultSuccess, type AuthActionState, type AuthEvent, AuthEventType, AuthFlowContainer, AuthFlowModal, AuthFlowStep, AuthInitializer, AuthOrchestrator, AuthOrchestratorFactory, AuthResultFactory, AuthService, type AuthState, AuthenticatedState, type AuthenticatedStateProps, AuthenticationStatusContext, type BaseComponentProps, BaseErrorHandler, BaseEventBus, BaseForm, type BaseFormField, type BaseFormProps, type BaseResponse, BaseService, type BaseStepProps, BroadcastChannelEventBus, Channel, CookieUtils, CrossTabBehaviorConfig, CrossTabBehaviorHandler, CrossTabDemo, DevelopmentLogger, EMAIL_SUBMISSION_NAVIGATION, type EmailCheckResult, type EmailExistResponse, EmailStep, type EmailStepProps, EndpointBuilder, type EventBus, ExistingUserLoginStrategy, FormFields, type FormFieldsProps, FormHeader, type FormHeaderProps, GenericErrorHandler, HttpClient, type HttpClientConfig, type HttpError, HttpMethod, type HttpRequestOptions, type HttpResponse, type IAuthOrchestrator, type IAuthService, type IAuthStatusState, type IErrorHandler, type ILogger, type ILoginFlowStrategy, type ITokenManager, LocalStorageUtils, LoggerFactory, type LoginData, LoginFlowStrategyFactory, type LoginRequest, type LoginResponse, MiddlewareConfig, type MiddlewareContext, type MiddlewareHandler, NavigationAction, NetworkErrorHandler, NextAction, PASSWORD_SUBMISSION_NAVIGATION, PageType, PageTypePatterns, PasswordStep, type PasswordStepProps, ProductionLogger, ProfileStateRenderer, ProfileUIState, type PropsFactory, RoleType, SignupFlowStrategy, type Step, type StepComponent, type StepComponentRetriever, type StepConfig, type StepPropsFactoryRegistry, type StepRegistry, type StepRegistryBaseProps, type StepRegistryConfigs, type StepRegistryHandlers, type StepRegistryParams, type StepRegistryState, type StepperActions, type StepperState$1 as StepperState, type Subscription, TokenManager, UnauthenticatedState, UrlUtils, type UseAuthActionHandler, type UseAuthEventBusProps, type UseFormSubmissionProps, type UseStepRegistryParams, type UseStepperReturn, type UserProfile, type UserProfileResponse, type UserSession, type UserState, UserStorageManager, type UserStoreState, VERIFICATION_SUBMISSION_NAVIGATION, ValidationErrorHandler, VerificationStep, type VerificationStepProps, type VerifyEmailRequest, type VerifyEmailResponse, config, createAuthSteps, createPropsFactoryRegistry, createStepRegistry, getAuthPageStepMessage, getEmailField, getEmailStepComponent, getPasswordField, getPasswordStepComponent, getStepForEmailSubmission, getStepForPasswordSubmission, getStepForVerificationSubmission, getStepProgressMessage, getVerificationField, getVerificationStepComponent, middlewareMatcher, useAuth, useAuthActionHandler, useAuthEventBus, useAuthFlowModal, useAuthInitializer, useIsAuthenticated, useLogout, useRefreshUser, useSharedEventBus, useSignInRequiredParams, useStepRegistry, useStepRenderer, useStepper, useUser, useUserActions, useUserData, useUserError, useUserLoading, useUserProfile, useUserStore, userSelectors };
package/dist/index.js CHANGED
@@ -83,8 +83,8 @@ var AuthEventType = /* @__PURE__ */ ((AuthEventType3) => {
83
83
  return AuthEventType3;
84
84
  })(AuthEventType || {});
85
85
  var PageType = /* @__PURE__ */ ((PageType3) => {
86
- PageType3["LOGIN"] = "/login";
87
- PageType3["DASHBOARD"] = "/dashboard";
86
+ PageType3["LOGIN"] = "login";
87
+ PageType3["DASHBOARD"] = "dashboard";
88
88
  PageType3["HOME"] = "/";
89
89
  return PageType3;
90
90
  })(PageType || {});
@@ -92,30 +92,30 @@ var NavigationAction = /* @__PURE__ */ ((NavigationAction2) => {
92
92
  NavigationAction2["NONE"] = "none";
93
93
  NavigationAction2["REDIRECT"] = "redirect";
94
94
  NavigationAction2["MODAL"] = "modal";
95
+ NavigationAction2["CURRENT"] = "current";
95
96
  return NavigationAction2;
96
97
  })(NavigationAction || {});
97
98
  var PageTypePatterns = {
98
- ["/login" /* LOGIN */]: "/login" /* LOGIN */,
99
- ["/dashboard" /* DASHBOARD */]: "/dashboard" /* DASHBOARD */,
100
- ["/" /* HOME */]: "/" /* HOME */
99
+ ["login" /* LOGIN */]: "login" /* LOGIN */,
100
+ ["dashboard" /* DASHBOARD */]: "dashboard" /* DASHBOARD */
101
101
  };
102
102
  var CrossTabBehaviorConfig = {
103
- ["/login" /* LOGIN */]: {
104
- ["auth.logged_in" /* LoggedIn */]: { action: "redirect" /* REDIRECT */, target: "/dashboard" /* DASHBOARD */ },
103
+ ["login" /* LOGIN */]: {
104
+ ["auth.logged_in" /* LoggedIn */]: { action: "redirect" /* REDIRECT */, target: "dashboard" /* DASHBOARD */ },
105
105
  ["auth.logged_out" /* LoggedOut */]: { action: "none" /* NONE */ },
106
106
  ["auth.email_verified" /* EmailVerified */]: { action: "none" /* NONE */ },
107
107
  ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
108
108
  },
109
- ["/dashboard" /* DASHBOARD */]: {
110
- ["auth.logged_in" /* LoggedIn */]: { action: "modal" /* MODAL */ },
111
- ["auth.logged_out" /* LoggedOut */]: { action: "redirect" /* REDIRECT */, target: "/dashboard" /* DASHBOARD */ },
112
- ["auth.email_verified" /* EmailVerified */]: { action: "modal" /* MODAL */ },
113
- ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
109
+ ["dashboard" /* DASHBOARD */]: {
110
+ ["auth.logged_in" /* LoggedIn */]: { action: "current" /* CURRENT */ },
111
+ ["auth.logged_out" /* LoggedOut */]: { action: "current" /* CURRENT */ },
112
+ ["auth.email_verified" /* EmailVerified */]: { action: "current" /* CURRENT */ },
113
+ ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "current" /* CURRENT */ }
114
114
  },
115
115
  ["/" /* HOME */]: {
116
- ["auth.logged_in" /* LoggedIn */]: { action: "modal" /* MODAL */ },
117
- ["auth.logged_out" /* LoggedOut */]: { action: "redirect" /* REDIRECT */, target: "/" /* HOME */ },
118
- ["auth.email_verified" /* EmailVerified */]: { action: "modal" /* MODAL */ },
116
+ ["auth.logged_in" /* LoggedIn */]: { action: "none" /* NONE */ },
117
+ ["auth.logged_out" /* LoggedOut */]: { action: "none" /* NONE */ },
118
+ ["auth.email_verified" /* EmailVerified */]: { action: "none" /* NONE */ },
119
119
  ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
120
120
  }
121
121
  };
@@ -254,13 +254,32 @@ var getVerificationField = (codeLength = 5, options = {}) => ({
254
254
 
255
255
  // src/config/middleware.ts
256
256
  var MiddlewareConfig = class {
257
+ /**
258
+ * Get the base domain from environment or use default
259
+ */
260
+ static getBaseDomain() {
261
+ return process.env.NEXT_PUBLIC_BASE_DOMAIN || "cutly.io";
262
+ }
263
+ /**
264
+ * Get the protocol based on environment
265
+ */
266
+ static getProtocol() {
267
+ return process.env.NODE_ENV === "production" ? "https" : "http";
268
+ }
269
+ /**
270
+ * Get the dashboard subdomain URL
271
+ */
272
+ static getDashboardUrl(path = "") {
273
+ return `${this.getProtocol()}://${this.SUBDOMAINS.DASHBOARD}.${this.getBaseDomain()}${path}`;
274
+ }
257
275
  };
258
- // Protected routes
259
- MiddlewareConfig.PROTECTED_ROUTES = {
260
- DASHBOARD: "/"
276
+ // Subdomain configuration
277
+ MiddlewareConfig.SUBDOMAINS = {
278
+ DASHBOARD: "dashboard"
261
279
  };
262
- // Auth routes
263
- MiddlewareConfig.AUTH_ROUTES = {
280
+ // Routes
281
+ MiddlewareConfig.ROUTES = {
282
+ ROOT: "/",
264
283
  LOGIN: "/login"
265
284
  };
266
285
  // HTTP methods to process
@@ -268,7 +287,8 @@ MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
268
287
  // Query parameters
269
288
  MiddlewareConfig.QUERY_PARAMS = {
270
289
  LOGIN_REQUIRED: "sign_in_required",
271
- AUTH_CHECKED: "auth_checked"
290
+ AUTH_CHECKED: "auth_checked",
291
+ REDIRECT_URL: "redirect_url"
272
292
  };
273
293
  // Query parameter values
274
294
  MiddlewareConfig.QUERY_VALUES = {
@@ -276,8 +296,7 @@ MiddlewareConfig.QUERY_VALUES = {
276
296
  AUTH_CHECKED: "1"
277
297
  };
278
298
  var middlewareMatcher = [
279
- "/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)",
280
- "/login"
299
+ "/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"
281
300
  ];
282
301
  var config = {
283
302
  matcher: middlewareMatcher
@@ -744,18 +763,53 @@ var BroadcastChannelEventBus = class _BroadcastChannelEventBus {
744
763
  }
745
764
  };
746
765
 
766
+ // src/services/utils/url-utils.ts
767
+ var UrlUtils = class {
768
+ /**
769
+ * Extract subdomain from hostname or URL
770
+ * Example: "dashboard.cutly.io" -> "dashboard"
771
+ * Example: "dashboard.localhost" -> "dashboard"
772
+ */
773
+ static getSubdomain(url) {
774
+ try {
775
+ const domain = new URL(`http://${url}`).hostname;
776
+ const parts = domain.split(".");
777
+ if (parts.length < 2 || domain === "localhost" || /^\d{1,3}(\.\d{1,3}){3}/.test(domain) || domain.startsWith(MiddlewareConfig.getBaseDomain())) {
778
+ return null;
779
+ }
780
+ return parts[0] || null;
781
+ } catch (e) {
782
+ return null;
783
+ }
784
+ }
785
+ /**
786
+ * Check if URL has auth-related query parameters
787
+ */
788
+ static hasAuthParams(url) {
789
+ return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
790
+ }
791
+ };
792
+
747
793
  // src/services/utils/cross-tab-behavior-handler.ts
748
794
  var CrossTabBehaviorHandler = class {
749
795
  /**
750
- * Get current page type based on pathname using pattern matching
796
+ * Get current page type using object lookup pattern
751
797
  */
752
798
  static getCurrentPageType() {
753
- var _a, _b;
799
+ var _a;
754
800
  if (typeof window === "undefined") return "/" /* HOME */;
755
- const pathname = window.location.pathname;
756
- return (_b = (_a = Object.entries(PageTypePatterns).find(
757
- ([pattern]) => pathname.includes(pattern)
758
- )) == null ? void 0 : _a[1]) != null ? _b : "/" /* HOME */;
801
+ try {
802
+ const pathname = window.location.pathname;
803
+ const subdomain = UrlUtils.getSubdomain(window.location.hostname);
804
+ const pageTypeMatchers = {
805
+ ["login" /* LOGIN */]: pathname === MiddlewareConfig.ROUTES.LOGIN,
806
+ ["dashboard" /* DASHBOARD */]: subdomain === MiddlewareConfig.SUBDOMAINS.DASHBOARD
807
+ };
808
+ const matchedPageType = (_a = Object.entries(pageTypeMatchers).find(([, matches]) => matches)) == null ? void 0 : _a[0];
809
+ return matchedPageType != null ? matchedPageType : "dashboard" /* DASHBOARD */;
810
+ } catch (e) {
811
+ return "dashboard" /* DASHBOARD */;
812
+ }
759
813
  }
760
814
  /**
761
815
  * Get the action configuration for current route and event
@@ -766,18 +820,12 @@ var CrossTabBehaviorHandler = class {
766
820
  }
767
821
  /**
768
822
  * Check if current route requires redirect for given event
823
+ * Returns PageType to redirect to, or null if no redirect needed
769
824
  */
770
825
  static shouldRedirect(currentPageType, eventType) {
771
826
  const action = this.getAction(currentPageType, eventType);
772
827
  return action.action === "redirect" /* REDIRECT */ ? action.target : null;
773
828
  }
774
- /**
775
- * Check if current route should show modal for given event
776
- */
777
- static shouldShowModal(currentPageType, eventType) {
778
- const action = this.getAction(currentPageType, eventType);
779
- return action.action === "modal" /* MODAL */;
780
- }
781
829
  };
782
830
 
783
831
  // src/services/auth/manager/token-manager.ts
@@ -2315,6 +2363,13 @@ var useAuthEventBus = ({ onLoggedOut, onLoggedIn } = {}) => {
2315
2363
  window.location.replace(target);
2316
2364
  }
2317
2365
  },
2366
+ ["current" /* CURRENT */]: () => {
2367
+ const isAuthAction = e.type === "auth.logged_in" /* LoggedIn */ || e.type === "auth.logged_out" /* LoggedOut */;
2368
+ const hasParams = UrlUtils.hasAuthParams(window.location.href);
2369
+ if (isAuthAction || !hasParams) {
2370
+ window.location.reload();
2371
+ }
2372
+ },
2318
2373
  ["modal" /* MODAL */]: () => {
2319
2374
  if (e.type === "auth.logged_in" /* LoggedIn */) {
2320
2375
  window.location.replace(window.location.href);
@@ -2988,7 +3043,8 @@ var CrossTabDemo = () => {
2988
3043
 
2989
3044
 
2990
3045
 
2991
- exports.AUTH_ENDPOINTS = AUTH_ENDPOINTS; exports.AlertDisplay = AlertDisplay; exports.AuthEventType = AuthEventType; exports.AuthFlowContainer = AuthFlowContainer; exports.AuthFlowModal = AuthFlowModal; exports.AuthFlowStep = AuthFlowStep; exports.AuthInitializer = AuthInitializer; exports.AuthOrchestrator = AuthOrchestrator; exports.AuthOrchestratorFactory = AuthOrchestratorFactory; exports.AuthResultFactory = AuthResultFactory; exports.AuthService = AuthService; exports.AuthenticatedState = AuthenticatedState; exports.AuthenticationStatusContext = AuthenticationStatusContext; exports.BaseErrorHandler = BaseErrorHandler; exports.BaseEventBus = BaseEventBus; exports.BaseForm = BaseForm; exports.BaseService = BaseService; exports.BroadcastChannelEventBus = BroadcastChannelEventBus; exports.Channel = Channel; exports.CookieUtils = CookieUtils; exports.CrossTabBehaviorConfig = CrossTabBehaviorConfig; exports.CrossTabBehaviorHandler = CrossTabBehaviorHandler; exports.CrossTabDemo = CrossTabDemo; exports.DevelopmentLogger = DevelopmentLogger; exports.EMAIL_SUBMISSION_NAVIGATION = EMAIL_SUBMISSION_NAVIGATION; exports.EmailStep = EmailStep; exports.EndpointBuilder = EndpointBuilder; exports.ExistingUserLoginStrategy = ExistingUserLoginStrategy; exports.FormFields = FormFields; exports.FormHeader = FormHeader; exports.GenericErrorHandler = GenericErrorHandler; exports.HttpClient = HttpClient; exports.HttpMethod = HttpMethod; exports.LocalStorageUtils = LocalStorageUtils; exports.LoggerFactory = LoggerFactory; exports.LoginFlowStrategyFactory = LoginFlowStrategyFactory; exports.MiddlewareConfig = MiddlewareConfig; exports.NavigationAction = NavigationAction; exports.NetworkErrorHandler = NetworkErrorHandler; exports.NextAction = NextAction; exports.PASSWORD_SUBMISSION_NAVIGATION = PASSWORD_SUBMISSION_NAVIGATION; exports.PageType = PageType; exports.PageTypePatterns = PageTypePatterns; exports.PasswordStep = PasswordStep; exports.ProductionLogger = ProductionLogger; exports.ProfileStateRenderer = ProfileStateRenderer; exports.ProfileUIState = ProfileUIState; exports.RoleType = RoleType; exports.SignupFlowStrategy = SignupFlowStrategy; exports.TokenManager = TokenManager; exports.UnauthenticatedState = UnauthenticatedState; exports.UserStorageManager = UserStorageManager; exports.VERIFICATION_SUBMISSION_NAVIGATION = VERIFICATION_SUBMISSION_NAVIGATION; exports.ValidationErrorHandler = ValidationErrorHandler; exports.VerificationStep = VerificationStep; exports.config = config; exports.createAuthSteps = createAuthSteps; exports.createPropsFactoryRegistry = createPropsFactoryRegistry; exports.createStepRegistry = createStepRegistry; exports.getAuthPageStepMessage = getAuthPageStepMessage; exports.getEmailField = getEmailField; exports.getEmailStepComponent = getEmailStepComponent; exports.getPasswordField = getPasswordField; exports.getPasswordStepComponent = getPasswordStepComponent; exports.getStepForEmailSubmission = getStepForEmailSubmission; exports.getStepForPasswordSubmission = getStepForPasswordSubmission; exports.getStepForVerificationSubmission = getStepForVerificationSubmission; exports.getStepProgressMessage = getStepProgressMessage; exports.getVerificationField = getVerificationField; exports.getVerificationStepComponent = getVerificationStepComponent; exports.middlewareMatcher = middlewareMatcher; exports.useAuth = useAuth; exports.useAuthActionHandler = useAuthActionHandler; exports.useAuthEventBus = useAuthEventBus; exports.useAuthFlowModal = useAuthFlowModal; exports.useAuthInitializer = useAuthInitializer; exports.useIsAuthenticated = useIsAuthenticated; exports.useLogout = useLogout; exports.useRefreshUser = useRefreshUser; exports.useSharedEventBus = useSharedEventBus; exports.useSignInRequiredParams = useSignInRequiredParams; exports.useStepRegistry = useStepRegistry; exports.useStepRenderer = useStepRenderer; exports.useStepper = useStepper; exports.useUser = useUser; exports.useUserActions = useUserActions; exports.useUserData = useUserData; exports.useUserError = useUserError; exports.useUserLoading = useUserLoading; exports.useUserProfile = useUserProfile; exports.useUserStore = useUserStore; exports.userSelectors = userSelectors;
3046
+
3047
+ exports.AUTH_ENDPOINTS = AUTH_ENDPOINTS; exports.AlertDisplay = AlertDisplay; exports.AuthEventType = AuthEventType; exports.AuthFlowContainer = AuthFlowContainer; exports.AuthFlowModal = AuthFlowModal; exports.AuthFlowStep = AuthFlowStep; exports.AuthInitializer = AuthInitializer; exports.AuthOrchestrator = AuthOrchestrator; exports.AuthOrchestratorFactory = AuthOrchestratorFactory; exports.AuthResultFactory = AuthResultFactory; exports.AuthService = AuthService; exports.AuthenticatedState = AuthenticatedState; exports.AuthenticationStatusContext = AuthenticationStatusContext; exports.BaseErrorHandler = BaseErrorHandler; exports.BaseEventBus = BaseEventBus; exports.BaseForm = BaseForm; exports.BaseService = BaseService; exports.BroadcastChannelEventBus = BroadcastChannelEventBus; exports.Channel = Channel; exports.CookieUtils = CookieUtils; exports.CrossTabBehaviorConfig = CrossTabBehaviorConfig; exports.CrossTabBehaviorHandler = CrossTabBehaviorHandler; exports.CrossTabDemo = CrossTabDemo; exports.DevelopmentLogger = DevelopmentLogger; exports.EMAIL_SUBMISSION_NAVIGATION = EMAIL_SUBMISSION_NAVIGATION; exports.EmailStep = EmailStep; exports.EndpointBuilder = EndpointBuilder; exports.ExistingUserLoginStrategy = ExistingUserLoginStrategy; exports.FormFields = FormFields; exports.FormHeader = FormHeader; exports.GenericErrorHandler = GenericErrorHandler; exports.HttpClient = HttpClient; exports.HttpMethod = HttpMethod; exports.LocalStorageUtils = LocalStorageUtils; exports.LoggerFactory = LoggerFactory; exports.LoginFlowStrategyFactory = LoginFlowStrategyFactory; exports.MiddlewareConfig = MiddlewareConfig; exports.NavigationAction = NavigationAction; exports.NetworkErrorHandler = NetworkErrorHandler; exports.NextAction = NextAction; exports.PASSWORD_SUBMISSION_NAVIGATION = PASSWORD_SUBMISSION_NAVIGATION; exports.PageType = PageType; exports.PageTypePatterns = PageTypePatterns; exports.PasswordStep = PasswordStep; exports.ProductionLogger = ProductionLogger; exports.ProfileStateRenderer = ProfileStateRenderer; exports.ProfileUIState = ProfileUIState; exports.RoleType = RoleType; exports.SignupFlowStrategy = SignupFlowStrategy; exports.TokenManager = TokenManager; exports.UnauthenticatedState = UnauthenticatedState; exports.UrlUtils = UrlUtils; exports.UserStorageManager = UserStorageManager; exports.VERIFICATION_SUBMISSION_NAVIGATION = VERIFICATION_SUBMISSION_NAVIGATION; exports.ValidationErrorHandler = ValidationErrorHandler; exports.VerificationStep = VerificationStep; exports.config = config; exports.createAuthSteps = createAuthSteps; exports.createPropsFactoryRegistry = createPropsFactoryRegistry; exports.createStepRegistry = createStepRegistry; exports.getAuthPageStepMessage = getAuthPageStepMessage; exports.getEmailField = getEmailField; exports.getEmailStepComponent = getEmailStepComponent; exports.getPasswordField = getPasswordField; exports.getPasswordStepComponent = getPasswordStepComponent; exports.getStepForEmailSubmission = getStepForEmailSubmission; exports.getStepForPasswordSubmission = getStepForPasswordSubmission; exports.getStepForVerificationSubmission = getStepForVerificationSubmission; exports.getStepProgressMessage = getStepProgressMessage; exports.getVerificationField = getVerificationField; exports.getVerificationStepComponent = getVerificationStepComponent; exports.middlewareMatcher = middlewareMatcher; exports.useAuth = useAuth; exports.useAuthActionHandler = useAuthActionHandler; exports.useAuthEventBus = useAuthEventBus; exports.useAuthFlowModal = useAuthFlowModal; exports.useAuthInitializer = useAuthInitializer; exports.useIsAuthenticated = useIsAuthenticated; exports.useLogout = useLogout; exports.useRefreshUser = useRefreshUser; exports.useSharedEventBus = useSharedEventBus; exports.useSignInRequiredParams = useSignInRequiredParams; exports.useStepRegistry = useStepRegistry; exports.useStepRenderer = useStepRenderer; exports.useStepper = useStepper; exports.useUser = useUser; exports.useUserActions = useUserActions; exports.useUserData = useUserData; exports.useUserError = useUserError; exports.useUserLoading = useUserLoading; exports.useUserProfile = useUserProfile; exports.useUserStore = useUserStore; exports.userSelectors = userSelectors;
2992
3048
  /*! Bundled license information:
2993
3049
 
2994
3050
  js-cookie/dist/js.cookie.mjs:
package/dist/index.mjs CHANGED
@@ -83,8 +83,8 @@ var AuthEventType = /* @__PURE__ */ ((AuthEventType3) => {
83
83
  return AuthEventType3;
84
84
  })(AuthEventType || {});
85
85
  var PageType = /* @__PURE__ */ ((PageType3) => {
86
- PageType3["LOGIN"] = "/login";
87
- PageType3["DASHBOARD"] = "/dashboard";
86
+ PageType3["LOGIN"] = "login";
87
+ PageType3["DASHBOARD"] = "dashboard";
88
88
  PageType3["HOME"] = "/";
89
89
  return PageType3;
90
90
  })(PageType || {});
@@ -92,30 +92,30 @@ var NavigationAction = /* @__PURE__ */ ((NavigationAction2) => {
92
92
  NavigationAction2["NONE"] = "none";
93
93
  NavigationAction2["REDIRECT"] = "redirect";
94
94
  NavigationAction2["MODAL"] = "modal";
95
+ NavigationAction2["CURRENT"] = "current";
95
96
  return NavigationAction2;
96
97
  })(NavigationAction || {});
97
98
  var PageTypePatterns = {
98
- ["/login" /* LOGIN */]: "/login" /* LOGIN */,
99
- ["/dashboard" /* DASHBOARD */]: "/dashboard" /* DASHBOARD */,
100
- ["/" /* HOME */]: "/" /* HOME */
99
+ ["login" /* LOGIN */]: "login" /* LOGIN */,
100
+ ["dashboard" /* DASHBOARD */]: "dashboard" /* DASHBOARD */
101
101
  };
102
102
  var CrossTabBehaviorConfig = {
103
- ["/login" /* LOGIN */]: {
104
- ["auth.logged_in" /* LoggedIn */]: { action: "redirect" /* REDIRECT */, target: "/dashboard" /* DASHBOARD */ },
103
+ ["login" /* LOGIN */]: {
104
+ ["auth.logged_in" /* LoggedIn */]: { action: "redirect" /* REDIRECT */, target: "dashboard" /* DASHBOARD */ },
105
105
  ["auth.logged_out" /* LoggedOut */]: { action: "none" /* NONE */ },
106
106
  ["auth.email_verified" /* EmailVerified */]: { action: "none" /* NONE */ },
107
107
  ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
108
108
  },
109
- ["/dashboard" /* DASHBOARD */]: {
110
- ["auth.logged_in" /* LoggedIn */]: { action: "modal" /* MODAL */ },
111
- ["auth.logged_out" /* LoggedOut */]: { action: "redirect" /* REDIRECT */, target: "/dashboard" /* DASHBOARD */ },
112
- ["auth.email_verified" /* EmailVerified */]: { action: "modal" /* MODAL */ },
113
- ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
109
+ ["dashboard" /* DASHBOARD */]: {
110
+ ["auth.logged_in" /* LoggedIn */]: { action: "current" /* CURRENT */ },
111
+ ["auth.logged_out" /* LoggedOut */]: { action: "current" /* CURRENT */ },
112
+ ["auth.email_verified" /* EmailVerified */]: { action: "current" /* CURRENT */ },
113
+ ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "current" /* CURRENT */ }
114
114
  },
115
115
  ["/" /* HOME */]: {
116
- ["auth.logged_in" /* LoggedIn */]: { action: "modal" /* MODAL */ },
117
- ["auth.logged_out" /* LoggedOut */]: { action: "redirect" /* REDIRECT */, target: "/" /* HOME */ },
118
- ["auth.email_verified" /* EmailVerified */]: { action: "modal" /* MODAL */ },
116
+ ["auth.logged_in" /* LoggedIn */]: { action: "none" /* NONE */ },
117
+ ["auth.logged_out" /* LoggedOut */]: { action: "none" /* NONE */ },
118
+ ["auth.email_verified" /* EmailVerified */]: { action: "none" /* NONE */ },
119
119
  ["auth.signin_required_modal" /* SignInRequiredModal */]: { action: "none" /* NONE */ }
120
120
  }
121
121
  };
@@ -254,13 +254,32 @@ var getVerificationField = (codeLength = 5, options = {}) => ({
254
254
 
255
255
  // src/config/middleware.ts
256
256
  var MiddlewareConfig = class {
257
+ /**
258
+ * Get the base domain from environment or use default
259
+ */
260
+ static getBaseDomain() {
261
+ return process.env.NEXT_PUBLIC_BASE_DOMAIN || "cutly.io";
262
+ }
263
+ /**
264
+ * Get the protocol based on environment
265
+ */
266
+ static getProtocol() {
267
+ return process.env.NODE_ENV === "production" ? "https" : "http";
268
+ }
269
+ /**
270
+ * Get the dashboard subdomain URL
271
+ */
272
+ static getDashboardUrl(path = "") {
273
+ return `${this.getProtocol()}://${this.SUBDOMAINS.DASHBOARD}.${this.getBaseDomain()}${path}`;
274
+ }
257
275
  };
258
- // Protected routes
259
- MiddlewareConfig.PROTECTED_ROUTES = {
260
- DASHBOARD: "/"
276
+ // Subdomain configuration
277
+ MiddlewareConfig.SUBDOMAINS = {
278
+ DASHBOARD: "dashboard"
261
279
  };
262
- // Auth routes
263
- MiddlewareConfig.AUTH_ROUTES = {
280
+ // Routes
281
+ MiddlewareConfig.ROUTES = {
282
+ ROOT: "/",
264
283
  LOGIN: "/login"
265
284
  };
266
285
  // HTTP methods to process
@@ -268,7 +287,8 @@ MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
268
287
  // Query parameters
269
288
  MiddlewareConfig.QUERY_PARAMS = {
270
289
  LOGIN_REQUIRED: "sign_in_required",
271
- AUTH_CHECKED: "auth_checked"
290
+ AUTH_CHECKED: "auth_checked",
291
+ REDIRECT_URL: "redirect_url"
272
292
  };
273
293
  // Query parameter values
274
294
  MiddlewareConfig.QUERY_VALUES = {
@@ -276,8 +296,7 @@ MiddlewareConfig.QUERY_VALUES = {
276
296
  AUTH_CHECKED: "1"
277
297
  };
278
298
  var middlewareMatcher = [
279
- "/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)",
280
- "/login"
299
+ "/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"
281
300
  ];
282
301
  var config = {
283
302
  matcher: middlewareMatcher
@@ -744,18 +763,53 @@ var BroadcastChannelEventBus = class _BroadcastChannelEventBus {
744
763
  }
745
764
  };
746
765
 
766
+ // src/services/utils/url-utils.ts
767
+ var UrlUtils = class {
768
+ /**
769
+ * Extract subdomain from hostname or URL
770
+ * Example: "dashboard.cutly.io" -> "dashboard"
771
+ * Example: "dashboard.localhost" -> "dashboard"
772
+ */
773
+ static getSubdomain(url) {
774
+ try {
775
+ const domain = new URL(`http://${url}`).hostname;
776
+ const parts = domain.split(".");
777
+ if (parts.length < 2 || domain === "localhost" || /^\d{1,3}(\.\d{1,3}){3}/.test(domain) || domain.startsWith(MiddlewareConfig.getBaseDomain())) {
778
+ return null;
779
+ }
780
+ return parts[0] || null;
781
+ } catch (e) {
782
+ return null;
783
+ }
784
+ }
785
+ /**
786
+ * Check if URL has auth-related query parameters
787
+ */
788
+ static hasAuthParams(url) {
789
+ return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
790
+ }
791
+ };
792
+
747
793
  // src/services/utils/cross-tab-behavior-handler.ts
748
794
  var CrossTabBehaviorHandler = class {
749
795
  /**
750
- * Get current page type based on pathname using pattern matching
796
+ * Get current page type using object lookup pattern
751
797
  */
752
798
  static getCurrentPageType() {
753
- var _a, _b;
799
+ var _a;
754
800
  if (typeof window === "undefined") return "/" /* HOME */;
755
- const pathname = window.location.pathname;
756
- return (_b = (_a = Object.entries(PageTypePatterns).find(
757
- ([pattern]) => pathname.includes(pattern)
758
- )) == null ? void 0 : _a[1]) != null ? _b : "/" /* HOME */;
801
+ try {
802
+ const pathname = window.location.pathname;
803
+ const subdomain = UrlUtils.getSubdomain(window.location.hostname);
804
+ const pageTypeMatchers = {
805
+ ["login" /* LOGIN */]: pathname === MiddlewareConfig.ROUTES.LOGIN,
806
+ ["dashboard" /* DASHBOARD */]: subdomain === MiddlewareConfig.SUBDOMAINS.DASHBOARD
807
+ };
808
+ const matchedPageType = (_a = Object.entries(pageTypeMatchers).find(([, matches]) => matches)) == null ? void 0 : _a[0];
809
+ return matchedPageType != null ? matchedPageType : "dashboard" /* DASHBOARD */;
810
+ } catch (e) {
811
+ return "dashboard" /* DASHBOARD */;
812
+ }
759
813
  }
760
814
  /**
761
815
  * Get the action configuration for current route and event
@@ -766,18 +820,12 @@ var CrossTabBehaviorHandler = class {
766
820
  }
767
821
  /**
768
822
  * Check if current route requires redirect for given event
823
+ * Returns PageType to redirect to, or null if no redirect needed
769
824
  */
770
825
  static shouldRedirect(currentPageType, eventType) {
771
826
  const action = this.getAction(currentPageType, eventType);
772
827
  return action.action === "redirect" /* REDIRECT */ ? action.target : null;
773
828
  }
774
- /**
775
- * Check if current route should show modal for given event
776
- */
777
- static shouldShowModal(currentPageType, eventType) {
778
- const action = this.getAction(currentPageType, eventType);
779
- return action.action === "modal" /* MODAL */;
780
- }
781
829
  };
782
830
 
783
831
  // src/services/auth/manager/token-manager.ts
@@ -2315,6 +2363,13 @@ var useAuthEventBus = ({ onLoggedOut, onLoggedIn } = {}) => {
2315
2363
  window.location.replace(target);
2316
2364
  }
2317
2365
  },
2366
+ ["current" /* CURRENT */]: () => {
2367
+ const isAuthAction = e.type === "auth.logged_in" /* LoggedIn */ || e.type === "auth.logged_out" /* LoggedOut */;
2368
+ const hasParams = UrlUtils.hasAuthParams(window.location.href);
2369
+ if (isAuthAction || !hasParams) {
2370
+ window.location.reload();
2371
+ }
2372
+ },
2318
2373
  ["modal" /* MODAL */]: () => {
2319
2374
  if (e.type === "auth.logged_in" /* LoggedIn */) {
2320
2375
  window.location.replace(window.location.href);
@@ -2947,6 +3002,7 @@ export {
2947
3002
  SignupFlowStrategy,
2948
3003
  TokenManager,
2949
3004
  UnauthenticatedState,
3005
+ UrlUtils,
2950
3006
  UserStorageManager,
2951
3007
  VERIFICATION_SUBMISSION_NAVIGATION,
2952
3008
  ValidationErrorHandler,
@@ -1,27 +1,22 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
 
3
3
  /**
4
- * Middleware matcher patterns - exported separately for static analysis
5
- * Pattern includes:
6
- * - / (home route and all other routes for authentication protection)
7
- * - /login route (for authenticated user redirection)
8
- * Excludes: API routes, Next.js internals, static assets, and file extensions
4
+ * Middleware matcher patterns
5
+ * Matches all routes except API routes, Next.js internals, and static assets
9
6
  */
10
- declare const middlewareMatcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)", "/login"];
7
+ declare const middlewareMatcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"];
11
8
  /**
12
- * Middleware configuration - runs on all routes (including home) and login page
9
+ * Middleware configuration
13
10
  */
14
11
  declare const config: {
15
- matcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)", "/login"];
12
+ matcher: readonly ["/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"];
16
13
  };
17
14
 
18
15
  /**
19
- * Authentication middleware entry point
16
+ * Authentication middleware for subdomain-based routing
20
17
  * Chain order:
21
18
  * 1. MethodFilterHandler - filters HTTP methods (GET/HEAD only)
22
- * 2. RouteProtectionHandler - identifies protected routes
23
- * 3. LoginRedirectHandler - redirects authenticated users away from login
24
- * 4. AuthenticationHandler - validates JWT and handles query parameter cleanup
19
+ * 2. AuthenticationHandler - validates JWT and adds login params if needed
25
20
  */
26
21
  declare function middleware(req: NextRequest): Promise<NextResponse>;
27
22
 
@@ -23,13 +23,32 @@ import { NextResponse } from "next/server";
23
23
 
24
24
  // src/config/middleware.ts
25
25
  var MiddlewareConfig = class {
26
+ /**
27
+ * Get the base domain from environment or use default
28
+ */
29
+ static getBaseDomain() {
30
+ return process.env.NEXT_PUBLIC_BASE_DOMAIN || "cutly.io";
31
+ }
32
+ /**
33
+ * Get the protocol based on environment
34
+ */
35
+ static getProtocol() {
36
+ return process.env.NODE_ENV === "production" ? "https" : "http";
37
+ }
38
+ /**
39
+ * Get the dashboard subdomain URL
40
+ */
41
+ static getDashboardUrl(path = "") {
42
+ return `${this.getProtocol()}://${this.SUBDOMAINS.DASHBOARD}.${this.getBaseDomain()}${path}`;
43
+ }
26
44
  };
27
- // Protected routes
28
- MiddlewareConfig.PROTECTED_ROUTES = {
29
- DASHBOARD: "/"
45
+ // Subdomain configuration
46
+ MiddlewareConfig.SUBDOMAINS = {
47
+ DASHBOARD: "dashboard"
30
48
  };
31
- // Auth routes
32
- MiddlewareConfig.AUTH_ROUTES = {
49
+ // Routes
50
+ MiddlewareConfig.ROUTES = {
51
+ ROOT: "/",
33
52
  LOGIN: "/login"
34
53
  };
35
54
  // HTTP methods to process
@@ -37,7 +56,8 @@ MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
37
56
  // Query parameters
38
57
  MiddlewareConfig.QUERY_PARAMS = {
39
58
  LOGIN_REQUIRED: "sign_in_required",
40
- AUTH_CHECKED: "auth_checked"
59
+ AUTH_CHECKED: "auth_checked",
60
+ REDIRECT_URL: "redirect_url"
41
61
  };
42
62
  // Query parameter values
43
63
  MiddlewareConfig.QUERY_VALUES = {
@@ -45,8 +65,7 @@ MiddlewareConfig.QUERY_VALUES = {
45
65
  AUTH_CHECKED: "1"
46
66
  };
47
67
  var middlewareMatcher = [
48
- "/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)",
49
- "/login"
68
+ "/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"
50
69
  ];
51
70
  var config = {
52
71
  matcher: middlewareMatcher
@@ -356,6 +375,33 @@ LocalStorageUtils.USER_PROFILE_STORAGE_KEY = "user_profile_data";
356
375
  LocalStorageUtils.USER_PROFILE_TIMESTAMP_KEY = "user_profile_timestamp";
357
376
  LocalStorageUtils.DEFAULT_CACHE_DURATION = 5 * 60 * 1e3;
358
377
 
378
+ // src/services/utils/url-utils.ts
379
+ var UrlUtils = class {
380
+ /**
381
+ * Extract subdomain from hostname or URL
382
+ * Example: "dashboard.cutly.io" -> "dashboard"
383
+ * Example: "dashboard.localhost" -> "dashboard"
384
+ */
385
+ static getSubdomain(url) {
386
+ try {
387
+ const domain = new URL(`http://${url}`).hostname;
388
+ const parts = domain.split(".");
389
+ if (parts.length < 2 || domain === "localhost" || /^\d{1,3}(\.\d{1,3}){3}/.test(domain) || domain.startsWith(MiddlewareConfig.getBaseDomain())) {
390
+ return null;
391
+ }
392
+ return parts[0] || null;
393
+ } catch (e) {
394
+ return null;
395
+ }
396
+ }
397
+ /**
398
+ * Check if URL has auth-related query parameters
399
+ */
400
+ static hasAuthParams(url) {
401
+ return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
402
+ }
403
+ };
404
+
359
405
  // src/services/api/endpoints.ts
360
406
  var AUTH_ENDPOINTS = {
361
407
  // Email existence check
@@ -567,6 +613,12 @@ AuthenticationStatusContext.states = /* @__PURE__ */ new Map([
567
613
 
568
614
  // src/middlewares/handlers/base-middleware-handler.ts
569
615
  var BaseMiddlewareHandler = class {
616
+ /**
617
+ * Check if current request is on dashboard subdomain
618
+ */
619
+ isDashboardSubdomain(hostname) {
620
+ return UrlUtils.getSubdomain(hostname) === MiddlewareConfig.SUBDOMAINS.DASHBOARD;
621
+ }
570
622
  /**
571
623
  * Check if user has both access and refresh tokens
572
624
  */
@@ -575,7 +627,7 @@ var BaseMiddlewareHandler = class {
575
627
  return cookies.has(accessTokenKey) && cookies.has(refreshTokenKey);
576
628
  }
577
629
  /**
578
- * Get authentication cookie keys from environment variables with fallbacks
630
+ * Get authentication cookie keys from environment variables
579
631
  */
580
632
  getAuthCookieKeys() {
581
633
  return {
@@ -584,49 +636,18 @@ var BaseMiddlewareHandler = class {
584
636
  };
585
637
  }
586
638
  /**
587
- * Create a redirect response to the dashboard
639
+ * Add login modal parameters to current URL
640
+ * Redirects to same page with sign_in_required parameter to trigger modal
588
641
  */
589
- redirectToDashboard(context) {
590
- const dashboardUrl = new URL(MiddlewareConfig.PROTECTED_ROUTES.DASHBOARD, context.request.url);
591
- return NextResponse.redirect(dashboardUrl);
592
- }
593
- /**
594
- * Create a redirect response to login with authentication parameters
595
- * Includes loop prevention - won't redirect if already has auth_checked parameter
596
- */
597
- redirectToLoginWithParams(context) {
598
- const loginUrl = new URL(MiddlewareConfig.AUTH_ROUTES.LOGIN, context.request.url);
599
- if (context.searchParams.get(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED) === MiddlewareConfig.QUERY_VALUES.AUTH_CHECKED) {
642
+ addLoginModalParams(context) {
643
+ if (this.hasAuthCheckedParam(context.searchParams)) {
600
644
  return NextResponse.next();
601
645
  }
602
- loginUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED, MiddlewareConfig.QUERY_VALUES.LOGIN_REQUIRED);
603
- loginUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED, MiddlewareConfig.QUERY_VALUES.AUTH_CHECKED);
604
- return NextResponse.redirect(loginUrl);
605
- }
606
- /**
607
- * Create a redirect response with custom URL and auth parameters
608
- * Includes loop prevention - won't redirect if target already has auth_checked parameter
609
- */
610
- redirectWithAuthParams(targetUrl) {
611
- const url = new URL(targetUrl.toString());
612
- if (url.searchParams.get(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED) === MiddlewareConfig.QUERY_VALUES.AUTH_CHECKED) {
613
- return NextResponse.next();
614
- }
615
- url.searchParams.set(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED, MiddlewareConfig.QUERY_VALUES.LOGIN_REQUIRED);
616
- url.searchParams.set(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED, MiddlewareConfig.QUERY_VALUES.AUTH_CHECKED);
617
- return NextResponse.redirect(url);
618
- }
619
- /**
620
- * Check if the current path is a dashboard route
621
- */
622
- isDashboardRoute(pathname) {
623
- return pathname.startsWith(MiddlewareConfig.PROTECTED_ROUTES.DASHBOARD);
624
- }
625
- /**
626
- * Check if the current path is the login page
627
- */
628
- isLoginRoute(pathname) {
629
- return pathname === MiddlewareConfig.AUTH_ROUTES.LOGIN;
646
+ const currentUrl = new URL(context.request.url);
647
+ currentUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED, MiddlewareConfig.QUERY_VALUES.LOGIN_REQUIRED);
648
+ currentUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED, MiddlewareConfig.QUERY_VALUES.AUTH_CHECKED);
649
+ currentUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.REDIRECT_URL, context.pathname);
650
+ return NextResponse.redirect(currentUrl);
630
651
  }
631
652
  /**
632
653
  * Check if request method is allowed
@@ -653,24 +674,25 @@ var BaseMiddlewareHandler = class {
653
674
  return NextResponse.next();
654
675
  }
655
676
  /**
656
- * Create a redirect response with cleaned URL (removes auth-related query parameters)
677
+ * Remove auth-related query parameters and redirect to clean URL
657
678
  */
658
- redirectWithCleanUrl(context) {
679
+ removeAuthParams(context) {
659
680
  const cleanUrl = new URL(context.nextUrl.toString());
660
681
  cleanUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED);
661
682
  cleanUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
683
+ cleanUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.REDIRECT_URL);
662
684
  return NextResponse.redirect(cleanUrl);
663
685
  }
664
686
  /**
665
687
  * Check if URL has auth-related query parameters that need cleanup
666
688
  */
667
689
  hasAuthQueryParams(searchParams) {
668
- return searchParams.has(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED) || searchParams.has(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
690
+ return searchParams.has(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED) || searchParams.has(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED) || searchParams.has(MiddlewareConfig.QUERY_PARAMS.REDIRECT_URL);
669
691
  }
670
692
  /**
671
- * Make an authenticated GET API call to getUserProfile endpoint
693
+ * Validate user authentication by calling getUserProfile API
672
694
  */
673
- async makeAuthenticatedApiCall(cookies) {
695
+ async validateUserAuth(cookies) {
674
696
  var _a;
675
697
  const { accessTokenKey } = this.getAuthCookieKeys();
676
698
  const accessToken = (_a = cookies.get(accessTokenKey)) == null ? void 0 : _a.value;
@@ -705,60 +727,30 @@ var MethodFilterHandler = class extends BaseMiddlewareHandler {
705
727
  }
706
728
  };
707
729
 
708
- // src/middlewares/handlers/route-protection-handler.ts
709
- var RouteProtectionHandler = class extends BaseMiddlewareHandler {
710
- handle(context) {
711
- const { pathname } = context;
712
- if (!this.isDashboardRoute(pathname)) {
713
- return this.continue();
714
- }
715
- return this.continue();
716
- }
717
- };
718
-
719
730
  // src/middlewares/handlers/authentication-handler.ts
720
731
  var AuthenticationHandler = class extends BaseMiddlewareHandler {
721
732
  async handle(context) {
722
- const { cookies, nextUrl, pathname } = context;
723
- const hasAuthCookies = this.hasAuthenticationCookies(cookies);
724
- if (!hasAuthCookies) {
725
- if (this.isDashboardRoute(pathname)) {
726
- return this.redirectWithAuthParams(nextUrl);
727
- }
733
+ const { cookies, hostname } = context;
734
+ if (!this.isDashboardSubdomain(hostname)) {
728
735
  return this.continue();
729
736
  }
737
+ if (!this.hasAuthenticationCookies(cookies)) {
738
+ return this.addLoginModalParams(context);
739
+ }
730
740
  try {
731
- const response = await this.makeAuthenticatedApiCall(cookies);
741
+ const response = await this.validateUserAuth(cookies);
732
742
  if (!response.ok) {
733
743
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
734
744
  }
735
745
  await response.json();
736
746
  if (this.hasAuthQueryParams(context.searchParams)) {
737
- return this.redirectWithCleanUrl(context);
747
+ return this.removeAuthParams(context);
738
748
  }
739
749
  return this.allow();
740
750
  } catch (error) {
741
751
  console.log("JWT validation failed:", error instanceof Error ? error.message : "Unknown error");
742
- if (this.isDashboardRoute(pathname)) {
743
- return this.redirectWithAuthParams(nextUrl);
744
- }
745
- return this.continue();
746
- }
747
- }
748
- };
749
-
750
- // src/middlewares/handlers/login-redirect-handler.ts
751
- var LoginRedirectHandler = class extends BaseMiddlewareHandler {
752
- handle(context) {
753
- const { pathname, cookies } = context;
754
- if (!this.isLoginRoute(pathname)) {
755
- return this.continue();
756
- }
757
- const isAuthenticated = this.hasAuthenticationCookies(cookies);
758
- if (isAuthenticated) {
759
- return this.redirectToDashboard(context);
752
+ return this.addLoginModalParams(context);
760
753
  }
761
- return this.continue();
762
754
  }
763
755
  };
764
756
 
@@ -785,15 +777,17 @@ var MiddlewareChain = class {
785
777
 
786
778
  // src/middleware.ts
787
779
  async function middleware(req) {
780
+ const hostname = req.headers.get("host") || req.nextUrl.hostname;
788
781
  const context = {
789
782
  request: req,
790
783
  method: req.method,
791
784
  pathname: req.nextUrl.pathname,
792
785
  searchParams: req.nextUrl.searchParams,
793
786
  cookies: req.cookies,
794
- nextUrl: req.nextUrl
787
+ nextUrl: req.nextUrl,
788
+ hostname
795
789
  };
796
- const chain = new MiddlewareChain().addHandler(new MethodFilterHandler()).addHandler(new RouteProtectionHandler()).addHandler(new LoginRedirectHandler()).addHandler(new AuthenticationHandler());
790
+ const chain = new MiddlewareChain().addHandler(new MethodFilterHandler()).addHandler(new AuthenticationHandler());
797
791
  return await chain.process(context);
798
792
  }
799
793
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mailsentry-auth",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Next.js 15 authentication package with multi-step auth flow, cross-tab sync, and Zustand state management",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",