mailsentry-auth 0.1.1 → 0.1.4

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.
@@ -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
@@ -67,12 +86,18 @@ var _CookieUtils = class _CookieUtils {
67
86
  static getRefreshTokenKey() {
68
87
  return process.env.AUTH_REFRESH_TOKEN_KEY || "auth_refresh_token";
69
88
  }
70
- // Use current domain in development
71
89
  /**
72
90
  * Get root domain for subdomain support
91
+ * Must match the domain used by backend when setting cookies
73
92
  */
74
93
  static getRootDomain() {
75
- if (typeof window === "undefined") return void 0;
94
+ if (typeof window === "undefined") {
95
+ const baseDomain = process.env.NEXT_PUBLIC_BASE_DOMAIN;
96
+ if (baseDomain && process.env.NODE_ENV === "production") {
97
+ return `.${baseDomain}`;
98
+ }
99
+ return void 0;
100
+ }
76
101
  const hostname = window.location.hostname;
77
102
  if (hostname === "localhost" || hostname === "127.0.0.1") {
78
103
  return void 0;
@@ -86,13 +111,15 @@ var _CookieUtils = class _CookieUtils {
86
111
  }
87
112
  return void 0;
88
113
  }
114
+ // Use current domain in development
89
115
  /**
90
116
  * Get common cookie options
91
117
  */
92
118
  static getCookieOptions() {
93
119
  return {
94
120
  path: "/",
95
- sameSite: "strict",
121
+ sameSite: "lax",
122
+ // Changed from 'strict' to 'lax' for cross-subdomain
96
123
  secure: process.env.NODE_ENV === "production",
97
124
  // Only secure in production
98
125
  domain: this.COOKIE_DOMAIN
@@ -182,18 +209,26 @@ var _CookieUtils = class _CookieUtils {
182
209
  }
183
210
  /**
184
211
  * Clear all authentication cookies (client-side only)
212
+ * Clears cookies from both current domain and root domain
185
213
  */
186
214
  static clearAuthCookies() {
187
215
  if (this.isServerSide()) {
188
216
  console.warn("clearAuthCookies called on server side - use server actions instead");
189
217
  return;
190
218
  }
191
- const removeOptions = {
219
+ const accessKey = this.getAccessTokenKey();
220
+ const refreshKey = this.getRefreshTokenKey();
221
+ const rootDomainOptions = {
192
222
  path: "/",
193
223
  domain: this.COOKIE_DOMAIN
194
224
  };
195
- Cookies.remove(this.getAccessTokenKey(), removeOptions);
196
- Cookies.remove(this.getRefreshTokenKey(), removeOptions);
225
+ Cookies.remove(accessKey, rootDomainOptions);
226
+ Cookies.remove(refreshKey, rootDomainOptions);
227
+ const currentDomainOptions = {
228
+ path: "/"
229
+ };
230
+ Cookies.remove(accessKey, currentDomainOptions);
231
+ Cookies.remove(refreshKey, currentDomainOptions);
197
232
  }
198
233
  /**
199
234
  * Check if cookies are supported/enabled (client-side only)
@@ -260,18 +295,21 @@ var _CookieUtils = class _CookieUtils {
260
295
  return {
261
296
  error: "Server-side rendering - no domain info available",
262
297
  environment: process.env.NODE_ENV || "unknown",
298
+ cookieDomain: this.COOKIE_DOMAIN || "undefined",
299
+ baseDomain: process.env.NEXT_PUBLIC_BASE_DOMAIN || "undefined",
263
300
  recommendation: "Use server actions for server-side cookie access"
264
301
  };
265
302
  }
266
303
  return {
267
304
  hostname: window.location.hostname,
268
- domain: this.COOKIE_DOMAIN || "current domain",
305
+ cookieDomain: this.COOKIE_DOMAIN || "current domain",
269
306
  environment: process.env.NODE_ENV || "unknown",
270
- protocol: window.location.protocol
307
+ protocol: window.location.protocol,
308
+ sameSite: "lax"
271
309
  };
272
310
  }
273
311
  };
274
- // Domain configuration
312
+ // Domain configuration - computed once
275
313
  _CookieUtils.COOKIE_DOMAIN = process.env.NODE_ENV === "production" ? _CookieUtils.getRootDomain() : void 0;
276
314
  var CookieUtils = _CookieUtils;
277
315
 
@@ -356,6 +394,33 @@ LocalStorageUtils.USER_PROFILE_STORAGE_KEY = "user_profile_data";
356
394
  LocalStorageUtils.USER_PROFILE_TIMESTAMP_KEY = "user_profile_timestamp";
357
395
  LocalStorageUtils.DEFAULT_CACHE_DURATION = 5 * 60 * 1e3;
358
396
 
397
+ // src/services/utils/url-utils.ts
398
+ var UrlUtils = class {
399
+ /**
400
+ * Extract subdomain from hostname or URL
401
+ * Example: "dashboard.cutly.io" -> "dashboard"
402
+ * Example: "dashboard.localhost" -> "dashboard"
403
+ */
404
+ static getSubdomain(url) {
405
+ try {
406
+ const domain = new URL(`http://${url}`).hostname;
407
+ const parts = domain.split(".");
408
+ if (parts.length < 2 || domain === "localhost" || /^\d{1,3}(\.\d{1,3}){3}/.test(domain) || domain.startsWith(MiddlewareConfig.getBaseDomain())) {
409
+ return null;
410
+ }
411
+ return parts[0] || null;
412
+ } catch (e) {
413
+ return null;
414
+ }
415
+ }
416
+ /**
417
+ * Check if URL has auth-related query parameters
418
+ */
419
+ static hasAuthParams(url) {
420
+ return url.includes(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
421
+ }
422
+ };
423
+
359
424
  // src/services/api/endpoints.ts
360
425
  var AUTH_ENDPOINTS = {
361
426
  // Email existence check
@@ -567,6 +632,12 @@ AuthenticationStatusContext.states = /* @__PURE__ */ new Map([
567
632
 
568
633
  // src/middlewares/handlers/base-middleware-handler.ts
569
634
  var BaseMiddlewareHandler = class {
635
+ /**
636
+ * Check if current request is on dashboard subdomain
637
+ */
638
+ isDashboardSubdomain(hostname) {
639
+ return UrlUtils.getSubdomain(hostname) === MiddlewareConfig.SUBDOMAINS.DASHBOARD;
640
+ }
570
641
  /**
571
642
  * Check if user has both access and refresh tokens
572
643
  */
@@ -575,7 +646,7 @@ var BaseMiddlewareHandler = class {
575
646
  return cookies.has(accessTokenKey) && cookies.has(refreshTokenKey);
576
647
  }
577
648
  /**
578
- * Get authentication cookie keys from environment variables with fallbacks
649
+ * Get authentication cookie keys from environment variables
579
650
  */
580
651
  getAuthCookieKeys() {
581
652
  return {
@@ -584,49 +655,21 @@ var BaseMiddlewareHandler = class {
584
655
  };
585
656
  }
586
657
  /**
587
- * Create a redirect response to the dashboard
658
+ * Add login modal parameters to current URL
659
+ * Redirects to same page with sign_in_required parameter to trigger modal
588
660
  */
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) {
661
+ addLoginModalParams(context) {
662
+ if (this.hasAuthCheckedParam(context.searchParams)) {
600
663
  return NextResponse.next();
601
664
  }
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;
665
+ const currentUrl = new URL(context.request.url);
666
+ currentUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED);
667
+ currentUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
668
+ currentUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.REDIRECT_URL);
669
+ currentUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED, MiddlewareConfig.QUERY_VALUES.LOGIN_REQUIRED);
670
+ currentUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED, MiddlewareConfig.QUERY_VALUES.AUTH_CHECKED);
671
+ currentUrl.searchParams.set(MiddlewareConfig.QUERY_PARAMS.REDIRECT_URL, context.pathname);
672
+ return NextResponse.redirect(currentUrl);
630
673
  }
631
674
  /**
632
675
  * Check if request method is allowed
@@ -653,24 +696,25 @@ var BaseMiddlewareHandler = class {
653
696
  return NextResponse.next();
654
697
  }
655
698
  /**
656
- * Create a redirect response with cleaned URL (removes auth-related query parameters)
699
+ * Remove auth-related query parameters and redirect to clean URL
657
700
  */
658
- redirectWithCleanUrl(context) {
701
+ removeAuthParams(context) {
659
702
  const cleanUrl = new URL(context.nextUrl.toString());
660
703
  cleanUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED);
661
704
  cleanUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
662
- return NextResponse.redirect(cleanUrl);
705
+ cleanUrl.searchParams.delete(MiddlewareConfig.QUERY_PARAMS.REDIRECT_URL);
706
+ return NextResponse.redirect(cleanUrl, { status: 302 });
663
707
  }
664
708
  /**
665
709
  * Check if URL has auth-related query parameters that need cleanup
666
710
  */
667
711
  hasAuthQueryParams(searchParams) {
668
- return searchParams.has(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED) || searchParams.has(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED);
712
+ return searchParams.has(MiddlewareConfig.QUERY_PARAMS.LOGIN_REQUIRED) || searchParams.has(MiddlewareConfig.QUERY_PARAMS.AUTH_CHECKED) || searchParams.has(MiddlewareConfig.QUERY_PARAMS.REDIRECT_URL);
669
713
  }
670
714
  /**
671
- * Make an authenticated GET API call to getUserProfile endpoint
715
+ * Validate user authentication by calling getUserProfile API
672
716
  */
673
- async makeAuthenticatedApiCall(cookies) {
717
+ async validateUserAuth(cookies) {
674
718
  var _a;
675
719
  const { accessTokenKey } = this.getAuthCookieKeys();
676
720
  const accessToken = (_a = cookies.get(accessTokenKey)) == null ? void 0 : _a.value;
@@ -705,63 +749,34 @@ var MethodFilterHandler = class extends BaseMiddlewareHandler {
705
749
  }
706
750
  };
707
751
 
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
752
  // src/middlewares/handlers/authentication-handler.ts
720
753
  var AuthenticationHandler = class extends BaseMiddlewareHandler {
721
754
  async handle(context) {
722
- const { cookies, nextUrl, pathname } = context;
755
+ const { cookies, hostname } = context;
756
+ if (!this.isDashboardSubdomain(hostname)) {
757
+ return this.continue();
758
+ }
723
759
  const hasAuthCookies = this.hasAuthenticationCookies(cookies);
724
760
  if (!hasAuthCookies) {
725
- if (this.isDashboardRoute(pathname)) {
726
- return this.redirectWithAuthParams(nextUrl);
727
- }
728
- return this.continue();
761
+ return this.addLoginModalParams(context);
729
762
  }
730
763
  try {
731
- const response = await this.makeAuthenticatedApiCall(cookies);
764
+ const response = await this.validateUserAuth(cookies);
732
765
  if (!response.ok) {
733
766
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
734
767
  }
735
768
  await response.json();
736
769
  if (this.hasAuthQueryParams(context.searchParams)) {
737
- return this.redirectWithCleanUrl(context);
770
+ return this.removeAuthParams(context);
738
771
  }
739
772
  return this.allow();
740
773
  } catch (error) {
741
774
  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();
775
+ return this.addLoginModalParams(context);
746
776
  }
747
777
  }
748
778
  };
749
779
 
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);
760
- }
761
- return this.continue();
762
- }
763
- };
764
-
765
780
  // src/middlewares/handlers/middleware-chain.ts
766
781
  import { NextResponse as NextResponse2 } from "next/server";
767
782
  var MiddlewareChain = class {
@@ -785,15 +800,17 @@ var MiddlewareChain = class {
785
800
 
786
801
  // src/middleware.ts
787
802
  async function middleware(req) {
803
+ const hostname = req.headers.get("host") || req.nextUrl.hostname;
788
804
  const context = {
789
805
  request: req,
790
806
  method: req.method,
791
807
  pathname: req.nextUrl.pathname,
792
808
  searchParams: req.nextUrl.searchParams,
793
809
  cookies: req.cookies,
794
- nextUrl: req.nextUrl
810
+ nextUrl: req.nextUrl,
811
+ hostname
795
812
  };
796
- const chain = new MiddlewareChain().addHandler(new MethodFilterHandler()).addHandler(new RouteProtectionHandler()).addHandler(new LoginRedirectHandler()).addHandler(new AuthenticationHandler());
813
+ const chain = new MiddlewareChain().addHandler(new MethodFilterHandler()).addHandler(new AuthenticationHandler());
797
814
  return await chain.process(context);
798
815
  }
799
816
  export {
@@ -13,12 +13,18 @@ var _CookieUtils = class _CookieUtils {
13
13
  static getRefreshTokenKey() {
14
14
  return process.env.AUTH_REFRESH_TOKEN_KEY || "auth_refresh_token";
15
15
  }
16
- // Use current domain in development
17
16
  /**
18
17
  * Get root domain for subdomain support
18
+ * Must match the domain used by backend when setting cookies
19
19
  */
20
20
  static getRootDomain() {
21
- if (typeof window === "undefined") return void 0;
21
+ if (typeof window === "undefined") {
22
+ const baseDomain = process.env.NEXT_PUBLIC_BASE_DOMAIN;
23
+ if (baseDomain && process.env.NODE_ENV === "production") {
24
+ return `.${baseDomain}`;
25
+ }
26
+ return void 0;
27
+ }
22
28
  const hostname = window.location.hostname;
23
29
  if (hostname === "localhost" || hostname === "127.0.0.1") {
24
30
  return void 0;
@@ -32,13 +38,15 @@ var _CookieUtils = class _CookieUtils {
32
38
  }
33
39
  return void 0;
34
40
  }
41
+ // Use current domain in development
35
42
  /**
36
43
  * Get common cookie options
37
44
  */
38
45
  static getCookieOptions() {
39
46
  return {
40
47
  path: "/",
41
- sameSite: "strict",
48
+ sameSite: "lax",
49
+ // Changed from 'strict' to 'lax' for cross-subdomain
42
50
  secure: process.env.NODE_ENV === "production",
43
51
  // Only secure in production
44
52
  domain: this.COOKIE_DOMAIN
@@ -128,18 +136,26 @@ var _CookieUtils = class _CookieUtils {
128
136
  }
129
137
  /**
130
138
  * Clear all authentication cookies (client-side only)
139
+ * Clears cookies from both current domain and root domain
131
140
  */
132
141
  static clearAuthCookies() {
133
142
  if (this.isServerSide()) {
134
143
  console.warn("clearAuthCookies called on server side - use server actions instead");
135
144
  return;
136
145
  }
137
- const removeOptions = {
146
+ const accessKey = this.getAccessTokenKey();
147
+ const refreshKey = this.getRefreshTokenKey();
148
+ const rootDomainOptions = {
138
149
  path: "/",
139
150
  domain: this.COOKIE_DOMAIN
140
151
  };
141
- _jscookie2.default.remove(this.getAccessTokenKey(), removeOptions);
142
- _jscookie2.default.remove(this.getRefreshTokenKey(), removeOptions);
152
+ _jscookie2.default.remove(accessKey, rootDomainOptions);
153
+ _jscookie2.default.remove(refreshKey, rootDomainOptions);
154
+ const currentDomainOptions = {
155
+ path: "/"
156
+ };
157
+ _jscookie2.default.remove(accessKey, currentDomainOptions);
158
+ _jscookie2.default.remove(refreshKey, currentDomainOptions);
143
159
  }
144
160
  /**
145
161
  * Check if cookies are supported/enabled (client-side only)
@@ -206,18 +222,21 @@ var _CookieUtils = class _CookieUtils {
206
222
  return {
207
223
  error: "Server-side rendering - no domain info available",
208
224
  environment: process.env.NODE_ENV || "unknown",
225
+ cookieDomain: this.COOKIE_DOMAIN || "undefined",
226
+ baseDomain: process.env.NEXT_PUBLIC_BASE_DOMAIN || "undefined",
209
227
  recommendation: "Use server actions for server-side cookie access"
210
228
  };
211
229
  }
212
230
  return {
213
231
  hostname: window.location.hostname,
214
- domain: this.COOKIE_DOMAIN || "current domain",
232
+ cookieDomain: this.COOKIE_DOMAIN || "current domain",
215
233
  environment: process.env.NODE_ENV || "unknown",
216
- protocol: window.location.protocol
234
+ protocol: window.location.protocol,
235
+ sameSite: "lax"
217
236
  };
218
237
  }
219
238
  };
220
- // Domain configuration
239
+ // Domain configuration - computed once
221
240
  _CookieUtils.COOKIE_DOMAIN = process.env.NODE_ENV === "production" ? _CookieUtils.getRootDomain() : void 0;
222
241
  var CookieUtils = _CookieUtils;
223
242
 
@@ -13,12 +13,18 @@ var _CookieUtils = class _CookieUtils {
13
13
  static getRefreshTokenKey() {
14
14
  return process.env.AUTH_REFRESH_TOKEN_KEY || "auth_refresh_token";
15
15
  }
16
- // Use current domain in development
17
16
  /**
18
17
  * Get root domain for subdomain support
18
+ * Must match the domain used by backend when setting cookies
19
19
  */
20
20
  static getRootDomain() {
21
- if (typeof window === "undefined") return void 0;
21
+ if (typeof window === "undefined") {
22
+ const baseDomain = process.env.NEXT_PUBLIC_BASE_DOMAIN;
23
+ if (baseDomain && process.env.NODE_ENV === "production") {
24
+ return `.${baseDomain}`;
25
+ }
26
+ return void 0;
27
+ }
22
28
  const hostname = window.location.hostname;
23
29
  if (hostname === "localhost" || hostname === "127.0.0.1") {
24
30
  return void 0;
@@ -32,13 +38,15 @@ var _CookieUtils = class _CookieUtils {
32
38
  }
33
39
  return void 0;
34
40
  }
41
+ // Use current domain in development
35
42
  /**
36
43
  * Get common cookie options
37
44
  */
38
45
  static getCookieOptions() {
39
46
  return {
40
47
  path: "/",
41
- sameSite: "strict",
48
+ sameSite: "lax",
49
+ // Changed from 'strict' to 'lax' for cross-subdomain
42
50
  secure: process.env.NODE_ENV === "production",
43
51
  // Only secure in production
44
52
  domain: this.COOKIE_DOMAIN
@@ -128,18 +136,26 @@ var _CookieUtils = class _CookieUtils {
128
136
  }
129
137
  /**
130
138
  * Clear all authentication cookies (client-side only)
139
+ * Clears cookies from both current domain and root domain
131
140
  */
132
141
  static clearAuthCookies() {
133
142
  if (this.isServerSide()) {
134
143
  console.warn("clearAuthCookies called on server side - use server actions instead");
135
144
  return;
136
145
  }
137
- const removeOptions = {
146
+ const accessKey = this.getAccessTokenKey();
147
+ const refreshKey = this.getRefreshTokenKey();
148
+ const rootDomainOptions = {
138
149
  path: "/",
139
150
  domain: this.COOKIE_DOMAIN
140
151
  };
141
- Cookies.remove(this.getAccessTokenKey(), removeOptions);
142
- Cookies.remove(this.getRefreshTokenKey(), removeOptions);
152
+ Cookies.remove(accessKey, rootDomainOptions);
153
+ Cookies.remove(refreshKey, rootDomainOptions);
154
+ const currentDomainOptions = {
155
+ path: "/"
156
+ };
157
+ Cookies.remove(accessKey, currentDomainOptions);
158
+ Cookies.remove(refreshKey, currentDomainOptions);
143
159
  }
144
160
  /**
145
161
  * Check if cookies are supported/enabled (client-side only)
@@ -206,18 +222,21 @@ var _CookieUtils = class _CookieUtils {
206
222
  return {
207
223
  error: "Server-side rendering - no domain info available",
208
224
  environment: process.env.NODE_ENV || "unknown",
225
+ cookieDomain: this.COOKIE_DOMAIN || "undefined",
226
+ baseDomain: process.env.NEXT_PUBLIC_BASE_DOMAIN || "undefined",
209
227
  recommendation: "Use server actions for server-side cookie access"
210
228
  };
211
229
  }
212
230
  return {
213
231
  hostname: window.location.hostname,
214
- domain: this.COOKIE_DOMAIN || "current domain",
232
+ cookieDomain: this.COOKIE_DOMAIN || "current domain",
215
233
  environment: process.env.NODE_ENV || "unknown",
216
- protocol: window.location.protocol
234
+ protocol: window.location.protocol,
235
+ sameSite: "lax"
217
236
  };
218
237
  }
219
238
  };
220
- // Domain configuration
239
+ // Domain configuration - computed once
221
240
  _CookieUtils.COOKIE_DOMAIN = process.env.NODE_ENV === "production" ? _CookieUtils.getRootDomain() : void 0;
222
241
  var CookieUtils = _CookieUtils;
223
242
  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.4",
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",
@@ -38,21 +38,6 @@
38
38
  "README.md",
39
39
  "ZUSTAND_MIGRATION.md"
40
40
  ],
41
- "scripts": {
42
- "dev": "next dev --turbopack",
43
- "build": "next build",
44
- "build:package": "tsup",
45
- "build:package:watch": "tsup --watch",
46
- "build:link": "npm run build:package && npm link",
47
- "link:sample": "cd ../nextjs-sample && npm link mailsentry-auth",
48
- "build:link:sample": "npm run build:link && npm run link:sample",
49
- "link:cutly": "cd ../cutly && pnpm link ../auth-nextjs",
50
- "build:link:cutly": "pnpm run build:package && pnpm run link:cutly",
51
- "start": "next start",
52
- "lint": "next lint",
53
- "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,scss}\"",
54
- "prepublishOnly": "npm run build:package"
55
- },
56
41
  "peerDependencies": {
57
42
  "next": ">=15.0.0",
58
43
  "react": ">=18.0.0 || >=19.0.0",
@@ -99,5 +84,22 @@
99
84
  "url": "https://github.com/danielaei/mailsentry-auth.git"
100
85
  },
101
86
  "author": "danielaei",
102
- "license": "MIT"
103
- }
87
+ "license": "MIT",
88
+ "scripts": {
89
+ "dev": "next dev --turbopack",
90
+ "build": "next build",
91
+ "build:package": "tsup",
92
+ "build:package:watch": "tsup --watch",
93
+ "build:link": "npm run build:package && npm link",
94
+ "link:sample": "cd ../nextjs-sample && npm link mailsentry-auth",
95
+ "build:link:sample": "npm run build:link && npm run link:sample",
96
+ "link:cutly": "cd ../cutly && pnpm link ../auth-nextjs",
97
+ "build:link:cutly": "pnpm run build:package && pnpm run link:cutly",
98
+ "start": "next start",
99
+ "lint": "next lint",
100
+ "format": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,css,scss}\"",
101
+ "publish:patch": "bash scripts/publish-package.sh patch",
102
+ "publish:minor": "bash scripts/publish-package.sh minor",
103
+ "publish:major": "bash scripts/publish-package.sh major"
104
+ }
105
+ }