mailsentry-auth 0.2.6 → 0.2.8

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.
@@ -4,18 +4,54 @@ import Cookies from 'js-cookie';
4
4
  // src/middlewares/handlers/base-middleware-handler.ts
5
5
 
6
6
  // src/config/middleware.ts
7
- var _MiddlewareConfig = class _MiddlewareConfig {
8
- // Route Protection Configuration
9
- // PATTERNS_TO_PROTECT: Routes that require authentication (whitelist approach recommended for security)
10
- // PATTERNS_TO_EXCLUDE: Routes to explicitly exclude from protection (e.g., login page, public assets)
7
+ var MiddlewareConfig = class {
11
8
  /**
12
- * Get public routes whitelist from environment variable
13
- * Expected format: comma-separated paths like "/public,/links/new,/about"
9
+ * Get dynamic protection rules from environment variable
10
+ * Format: "host:path" or "path"
14
11
  */
15
- static getPublicRoutesWhitelist() {
16
- const envWhitelist = process.env.NEXT_PUBLIC_AUTH_WHITELIST_ROUTES || "";
17
- const customRoutes = envWhitelist.split(",").map((route) => route.trim()).filter((route) => route.length > 0);
18
- return customRoutes;
12
+ static getProtectedRules() {
13
+ return this.parseRules(process.env.NEXT_PUBLIC_PROTECTED_ROUTES, [
14
+ { hostPattern: this.CONSTANTS.DASHBOARD_SUBDOMAIN, pathPattern: "*" }
15
+ ]);
16
+ }
17
+ /**
18
+ * Get public routes whitelist (Exclusions)
19
+ * Format: "host:path" or "path"
20
+ */
21
+ static getWhitelistRules() {
22
+ return this.parseRules(process.env.NEXT_PUBLIC_AUTH_WHITELIST_ROUTES, [
23
+ { hostPattern: null, pathPattern: this.CONSTANTS.LOGIN_PATH }
24
+ ]);
25
+ }
26
+ /**
27
+ * Get guest-only routes (redirects authenticated users away)
28
+ * Format: "host:path" or "path"
29
+ */
30
+ static getGuestOnlyRules() {
31
+ return this.parseRules(process.env.NEXT_PUBLIC_GUEST_ONLY_ROUTES, [
32
+ { hostPattern: null, pathPattern: this.CONSTANTS.LOGIN_PATH }
33
+ ]);
34
+ }
35
+ /**
36
+ * Generic parser for environment variables containing rule lists
37
+ */
38
+ static parseRules(envVar, defaults) {
39
+ if (envVar === void 0) return defaults;
40
+ return envVar.split(",").map((rule) => this.parseSingleRule(rule)).filter((r) => r.pathPattern.length > 0);
41
+ }
42
+ /**
43
+ * Parse a single rule string into a ProtectionRule object
44
+ */
45
+ static parseSingleRule(ruleString) {
46
+ const trimmed = ruleString.trim();
47
+ const separatorIndex = trimmed.indexOf(":");
48
+ if (separatorIndex === -1) {
49
+ return { hostPattern: null, pathPattern: trimmed };
50
+ }
51
+ return {
52
+ hostPattern: trimmed.substring(0, separatorIndex).trim(),
53
+ pathPattern: trimmed.substring(separatorIndex + 1).trim()
54
+ };
19
55
  }
20
56
  /**
21
57
  * Get the base domain from environment or use default
@@ -31,41 +67,23 @@ var _MiddlewareConfig = class _MiddlewareConfig {
31
67
  }
32
68
  };
33
69
  // Common constants
34
- _MiddlewareConfig.CONSTANTS = {
70
+ MiddlewareConfig.CONSTANTS = {
35
71
  LOGIN_PATH: "/login",
36
- DASHBOARD_SUBDOMAIN: "dashboard",
37
- PUBLIC_PATH: "/public",
38
- PUBLIC_API_PATH: "/api/public"
39
- };
40
- _MiddlewareConfig.PROTECTED_ROUTES = {
41
- // Routes that MUST be protected
42
- INCLUDE: [
43
- "/"
44
- // Protect everything by default (since dashboard.cutly.io/ is the root)
45
- ],
46
- // Routes that should NEVER be protected (public)
47
- EXCLUDE: [
48
- _MiddlewareConfig.CONSTANTS.LOGIN_PATH,
49
- _MiddlewareConfig.CONSTANTS.PUBLIC_PATH,
50
- _MiddlewareConfig.CONSTANTS.PUBLIC_API_PATH,
51
- ..._MiddlewareConfig.getPublicRoutesWhitelist()
52
- // Add custom whitelist from env
53
- ]
72
+ DASHBOARD_SUBDOMAIN: "dashboard"
54
73
  };
55
74
  // HTTP methods to process
56
- _MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
75
+ MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
57
76
  // Query parameters
58
- _MiddlewareConfig.QUERY_PARAMS = {
77
+ MiddlewareConfig.QUERY_PARAMS = {
59
78
  LOGIN_REQUIRED: "sign_in_required",
60
79
  AUTH_CHECKED: "auth_checked",
61
80
  REDIRECT_URL: "redirect_url"
62
81
  };
63
82
  // Query parameter values
64
- _MiddlewareConfig.QUERY_VALUES = {
83
+ MiddlewareConfig.QUERY_VALUES = {
65
84
  LOGIN_REQUIRED: "true",
66
85
  AUTH_CHECKED: "1"
67
86
  };
68
- var MiddlewareConfig = _MiddlewareConfig;
69
87
  var middlewareMatcher = [
70
88
  "/((?!api|_next/static|_next/image|_next/webpack-hmr|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico|css|js)$).*)"
71
89
  ];
@@ -350,23 +368,83 @@ var _CookieUtils = class _CookieUtils {
350
368
  _CookieUtils.COOKIE_DOMAIN = _CookieUtils.getRootDomain();
351
369
  var CookieUtils = _CookieUtils;
352
370
 
371
+ // src/middlewares/utils/email-validator.ts
372
+ var isPublicUserEmail = (email) => {
373
+ if (!email || typeof email !== "string") return false;
374
+ const parts = email.split("@");
375
+ if (parts.length !== 2) return false;
376
+ const localPart = parts[0];
377
+ const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
378
+ const match = localPart.match(ipv4Pattern);
379
+ if (!match) return false;
380
+ for (let i = 1; i <= 4; i++) {
381
+ const octet = parseInt(match[i], 10);
382
+ if (octet < 0 || octet > 255) return false;
383
+ }
384
+ return true;
385
+ };
386
+
353
387
  // src/middlewares/handlers/base-middleware-handler.ts
354
388
  var BaseMiddlewareHandler = class {
355
389
  /**
356
390
  * Check if current route requires authentication
357
- * Uses inclusive (PROTECTED_ROUTES.INCLUDE) and exclusive (PROTECTED_ROUTES.EXCLUDE) lists
358
391
  */
359
- requiresAuthentication(pathname) {
360
- const isExcluded = MiddlewareConfig.PROTECTED_ROUTES.EXCLUDE.some(
361
- (route) => pathname.startsWith(route) || pathname === route
362
- );
363
- if (isExcluded) {
392
+ requiresAuthentication(pathname, hostname) {
393
+ if (this.isExcludedRoute(pathname, hostname)) {
364
394
  return false;
365
395
  }
366
- return MiddlewareConfig.PROTECTED_ROUTES.INCLUDE.some(
367
- (route) => pathname.startsWith(route) || pathname === route
396
+ return MiddlewareConfig.getProtectedRules().some(
397
+ (rule) => this.isRuleMatch(rule, pathname, hostname)
368
398
  );
369
399
  }
400
+ /**
401
+ * Check if current route is guest-only (authenticated users should be redirected away)
402
+ */
403
+ isGuestOnlyRoute(pathname, hostname) {
404
+ return MiddlewareConfig.getGuestOnlyRules().some(
405
+ (rule) => this.isRuleMatch(rule, pathname, hostname)
406
+ );
407
+ }
408
+ /**
409
+ * Check if the route is explicitly excluded from authentication
410
+ */
411
+ isExcludedRoute(pathname, hostname) {
412
+ return MiddlewareConfig.getWhitelistRules().some(
413
+ (rule) => this.isRuleMatch(rule, pathname, hostname)
414
+ );
415
+ }
416
+ /**
417
+ * Check if a single protection rule matches the current request
418
+ */
419
+ isRuleMatch(rule, pathname, hostname) {
420
+ if (rule.hostPattern && (!hostname || !hostname.startsWith(`${rule.hostPattern}.`) && hostname !== rule.hostPattern)) {
421
+ return false;
422
+ }
423
+ return rule.pathPattern === "*" || pathname === rule.pathPattern || pathname.startsWith(rule.pathPattern);
424
+ }
425
+ /**
426
+ * Validates authentication and returns user info if valid
427
+ * Used by both AuthenticationHandler and GuestOnlyHandler to avoid duplication
428
+ */
429
+ async getAuthenticatedUser(cookies) {
430
+ var _a, _b;
431
+ if (!this.hasAuthenticationCookies(cookies)) {
432
+ return null;
433
+ }
434
+ try {
435
+ const authResponse = await this.validateUserAuth(cookies);
436
+ if (!authResponse.ok) {
437
+ return null;
438
+ }
439
+ const data = await authResponse.json();
440
+ const userEmail = ((_b = (_a = data == null ? void 0 : data.data) == null ? void 0 : _a.user) == null ? void 0 : _b.email) || "";
441
+ const isPublic = isPublicUserEmail(userEmail);
442
+ return { email: userEmail, isPublic };
443
+ } catch (error) {
444
+ console.log("Auth validation error:", error instanceof Error ? error.message : "Unknown error");
445
+ return null;
446
+ }
447
+ }
370
448
  /**
371
449
  * Check if user has both access and refresh tokens
372
450
  */
@@ -478,26 +556,27 @@ var MethodFilterHandler = class extends BaseMiddlewareHandler {
478
556
  return this.continue();
479
557
  }
480
558
  };
481
-
482
- // src/middlewares/handlers/authentication-handler.ts
483
559
  var AuthenticationHandler = class extends BaseMiddlewareHandler {
484
560
  async handle(context) {
485
- var _a, _b;
486
- const { cookies, pathname } = context;
487
- if (!this.requiresAuthentication(pathname)) {
488
- return this.continue();
489
- }
490
- const hasAuthCookies = this.hasAuthenticationCookies(cookies);
491
- if (!hasAuthCookies) {
492
- return this.addLoginModalParams(context);
493
- }
561
+ const { cookies, pathname, hostname } = context;
494
562
  try {
495
- const authResponse = await this.validateUserAuth(cookies);
496
- if (authResponse.ok) {
497
- const data = await authResponse.json();
498
- const userEmail = ((_b = (_a = data == null ? void 0 : data.data) == null ? void 0 : _a.user) == null ? void 0 : _b.email) || "";
499
- const isPublicUserFlag = isPublicUserEmail(userEmail);
500
- if (isPublicUserFlag) {
563
+ const isGuestOnly = this.isGuestOnlyRoute(pathname, hostname);
564
+ const isProtected = this.requiresAuthentication(pathname, hostname);
565
+ if (!isGuestOnly && !isProtected) {
566
+ return this.continue();
567
+ }
568
+ const user = this.hasAuthenticationCookies(cookies) ? await this.getAuthenticatedUser(cookies) : null;
569
+ if (isGuestOnly) {
570
+ if (user && !user.isPublic) {
571
+ return NextResponse.redirect(new URL("/", context.request.url));
572
+ }
573
+ return this.continue();
574
+ }
575
+ if (isProtected) {
576
+ if (!user) {
577
+ return this.addLoginModalParams(context);
578
+ }
579
+ if (user.isPublic) {
501
580
  console.log("Public session user detected (IP-based email) - requiring authentication");
502
581
  return this.addLoginModalParams(context);
503
582
  }
@@ -506,10 +585,9 @@ var AuthenticationHandler = class extends BaseMiddlewareHandler {
506
585
  }
507
586
  return this.allow();
508
587
  }
509
- console.log("Authentication failed - requiring login for protected route");
510
- return this.addLoginModalParams(context);
588
+ return this.continue();
511
589
  } catch (error) {
512
- console.log("Authentication validation failed:", error instanceof Error ? error.message : "Unknown error");
590
+ console.error("AuthenticationHandler error:", error);
513
591
  return this.addLoginModalParams(context);
514
592
  }
515
593
  }
@@ -533,22 +611,6 @@ var MiddlewareChain = class {
533
611
  }
534
612
  };
535
613
 
536
- // src/middlewares/utils/email-validator.ts
537
- var isPublicUserEmail = (email) => {
538
- if (!email || typeof email !== "string") return false;
539
- const parts = email.split("@");
540
- if (parts.length !== 2) return false;
541
- const localPart = parts[0];
542
- const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
543
- const match = localPart.match(ipv4Pattern);
544
- if (!match) return false;
545
- for (let i = 1; i <= 4; i++) {
546
- const octet = parseInt(match[i], 10);
547
- if (octet < 0 || octet > 255) return false;
548
- }
549
- return true;
550
- };
551
-
552
614
  // src/middleware.ts
553
615
  async function middleware(req) {
554
616
  const hostname = req.headers.get("host") || req.nextUrl.hostname;
@@ -2,18 +2,54 @@
2
2
  var _jscookie = require('js-cookie'); var _jscookie2 = _interopRequireDefault(_jscookie);
3
3
 
4
4
  // src/config/middleware.ts
5
- var _MiddlewareConfig = class _MiddlewareConfig {
6
- // Route Protection Configuration
7
- // PATTERNS_TO_PROTECT: Routes that require authentication (whitelist approach recommended for security)
8
- // PATTERNS_TO_EXCLUDE: Routes to explicitly exclude from protection (e.g., login page, public assets)
5
+ var MiddlewareConfig = class {
9
6
  /**
10
- * Get public routes whitelist from environment variable
11
- * Expected format: comma-separated paths like "/public,/links/new,/about"
7
+ * Get dynamic protection rules from environment variable
8
+ * Format: "host:path" or "path"
12
9
  */
13
- static getPublicRoutesWhitelist() {
14
- const envWhitelist = process.env.NEXT_PUBLIC_AUTH_WHITELIST_ROUTES || "";
15
- const customRoutes = envWhitelist.split(",").map((route) => route.trim()).filter((route) => route.length > 0);
16
- return customRoutes;
10
+ static getProtectedRules() {
11
+ return this.parseRules(process.env.NEXT_PUBLIC_PROTECTED_ROUTES, [
12
+ { hostPattern: this.CONSTANTS.DASHBOARD_SUBDOMAIN, pathPattern: "*" }
13
+ ]);
14
+ }
15
+ /**
16
+ * Get public routes whitelist (Exclusions)
17
+ * Format: "host:path" or "path"
18
+ */
19
+ static getWhitelistRules() {
20
+ return this.parseRules(process.env.NEXT_PUBLIC_AUTH_WHITELIST_ROUTES, [
21
+ { hostPattern: null, pathPattern: this.CONSTANTS.LOGIN_PATH }
22
+ ]);
23
+ }
24
+ /**
25
+ * Get guest-only routes (redirects authenticated users away)
26
+ * Format: "host:path" or "path"
27
+ */
28
+ static getGuestOnlyRules() {
29
+ return this.parseRules(process.env.NEXT_PUBLIC_GUEST_ONLY_ROUTES, [
30
+ { hostPattern: null, pathPattern: this.CONSTANTS.LOGIN_PATH }
31
+ ]);
32
+ }
33
+ /**
34
+ * Generic parser for environment variables containing rule lists
35
+ */
36
+ static parseRules(envVar, defaults) {
37
+ if (envVar === void 0) return defaults;
38
+ return envVar.split(",").map((rule) => this.parseSingleRule(rule)).filter((r) => r.pathPattern.length > 0);
39
+ }
40
+ /**
41
+ * Parse a single rule string into a ProtectionRule object
42
+ */
43
+ static parseSingleRule(ruleString) {
44
+ const trimmed = ruleString.trim();
45
+ const separatorIndex = trimmed.indexOf(":");
46
+ if (separatorIndex === -1) {
47
+ return { hostPattern: null, pathPattern: trimmed };
48
+ }
49
+ return {
50
+ hostPattern: trimmed.substring(0, separatorIndex).trim(),
51
+ pathPattern: trimmed.substring(separatorIndex + 1).trim()
52
+ };
17
53
  }
18
54
  /**
19
55
  * Get the base domain from environment or use default
@@ -29,41 +65,23 @@ var _MiddlewareConfig = class _MiddlewareConfig {
29
65
  }
30
66
  };
31
67
  // Common constants
32
- _MiddlewareConfig.CONSTANTS = {
68
+ MiddlewareConfig.CONSTANTS = {
33
69
  LOGIN_PATH: "/login",
34
- DASHBOARD_SUBDOMAIN: "dashboard",
35
- PUBLIC_PATH: "/public",
36
- PUBLIC_API_PATH: "/api/public"
37
- };
38
- _MiddlewareConfig.PROTECTED_ROUTES = {
39
- // Routes that MUST be protected
40
- INCLUDE: [
41
- "/"
42
- // Protect everything by default (since dashboard.cutly.io/ is the root)
43
- ],
44
- // Routes that should NEVER be protected (public)
45
- EXCLUDE: [
46
- _MiddlewareConfig.CONSTANTS.LOGIN_PATH,
47
- _MiddlewareConfig.CONSTANTS.PUBLIC_PATH,
48
- _MiddlewareConfig.CONSTANTS.PUBLIC_API_PATH,
49
- ..._MiddlewareConfig.getPublicRoutesWhitelist()
50
- // Add custom whitelist from env
51
- ]
70
+ DASHBOARD_SUBDOMAIN: "dashboard"
52
71
  };
53
72
  // HTTP methods to process
54
- _MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
73
+ MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
55
74
  // Query parameters
56
- _MiddlewareConfig.QUERY_PARAMS = {
75
+ MiddlewareConfig.QUERY_PARAMS = {
57
76
  LOGIN_REQUIRED: "sign_in_required",
58
77
  AUTH_CHECKED: "auth_checked",
59
78
  REDIRECT_URL: "redirect_url"
60
79
  };
61
80
  // Query parameter values
62
- _MiddlewareConfig.QUERY_VALUES = {
81
+ MiddlewareConfig.QUERY_VALUES = {
63
82
  LOGIN_REQUIRED: "true",
64
83
  AUTH_CHECKED: "1"
65
84
  };
66
- var MiddlewareConfig = _MiddlewareConfig;
67
85
 
68
86
  // src/services/utils/url-utils.ts
69
87
  var UrlUtils = class {
@@ -2,18 +2,54 @@
2
2
  import Cookies from "js-cookie";
3
3
 
4
4
  // src/config/middleware.ts
5
- var _MiddlewareConfig = class _MiddlewareConfig {
6
- // Route Protection Configuration
7
- // PATTERNS_TO_PROTECT: Routes that require authentication (whitelist approach recommended for security)
8
- // PATTERNS_TO_EXCLUDE: Routes to explicitly exclude from protection (e.g., login page, public assets)
5
+ var MiddlewareConfig = class {
9
6
  /**
10
- * Get public routes whitelist from environment variable
11
- * Expected format: comma-separated paths like "/public,/links/new,/about"
7
+ * Get dynamic protection rules from environment variable
8
+ * Format: "host:path" or "path"
12
9
  */
13
- static getPublicRoutesWhitelist() {
14
- const envWhitelist = process.env.NEXT_PUBLIC_AUTH_WHITELIST_ROUTES || "";
15
- const customRoutes = envWhitelist.split(",").map((route) => route.trim()).filter((route) => route.length > 0);
16
- return customRoutes;
10
+ static getProtectedRules() {
11
+ return this.parseRules(process.env.NEXT_PUBLIC_PROTECTED_ROUTES, [
12
+ { hostPattern: this.CONSTANTS.DASHBOARD_SUBDOMAIN, pathPattern: "*" }
13
+ ]);
14
+ }
15
+ /**
16
+ * Get public routes whitelist (Exclusions)
17
+ * Format: "host:path" or "path"
18
+ */
19
+ static getWhitelistRules() {
20
+ return this.parseRules(process.env.NEXT_PUBLIC_AUTH_WHITELIST_ROUTES, [
21
+ { hostPattern: null, pathPattern: this.CONSTANTS.LOGIN_PATH }
22
+ ]);
23
+ }
24
+ /**
25
+ * Get guest-only routes (redirects authenticated users away)
26
+ * Format: "host:path" or "path"
27
+ */
28
+ static getGuestOnlyRules() {
29
+ return this.parseRules(process.env.NEXT_PUBLIC_GUEST_ONLY_ROUTES, [
30
+ { hostPattern: null, pathPattern: this.CONSTANTS.LOGIN_PATH }
31
+ ]);
32
+ }
33
+ /**
34
+ * Generic parser for environment variables containing rule lists
35
+ */
36
+ static parseRules(envVar, defaults) {
37
+ if (envVar === void 0) return defaults;
38
+ return envVar.split(",").map((rule) => this.parseSingleRule(rule)).filter((r) => r.pathPattern.length > 0);
39
+ }
40
+ /**
41
+ * Parse a single rule string into a ProtectionRule object
42
+ */
43
+ static parseSingleRule(ruleString) {
44
+ const trimmed = ruleString.trim();
45
+ const separatorIndex = trimmed.indexOf(":");
46
+ if (separatorIndex === -1) {
47
+ return { hostPattern: null, pathPattern: trimmed };
48
+ }
49
+ return {
50
+ hostPattern: trimmed.substring(0, separatorIndex).trim(),
51
+ pathPattern: trimmed.substring(separatorIndex + 1).trim()
52
+ };
17
53
  }
18
54
  /**
19
55
  * Get the base domain from environment or use default
@@ -29,41 +65,23 @@ var _MiddlewareConfig = class _MiddlewareConfig {
29
65
  }
30
66
  };
31
67
  // Common constants
32
- _MiddlewareConfig.CONSTANTS = {
68
+ MiddlewareConfig.CONSTANTS = {
33
69
  LOGIN_PATH: "/login",
34
- DASHBOARD_SUBDOMAIN: "dashboard",
35
- PUBLIC_PATH: "/public",
36
- PUBLIC_API_PATH: "/api/public"
37
- };
38
- _MiddlewareConfig.PROTECTED_ROUTES = {
39
- // Routes that MUST be protected
40
- INCLUDE: [
41
- "/"
42
- // Protect everything by default (since dashboard.cutly.io/ is the root)
43
- ],
44
- // Routes that should NEVER be protected (public)
45
- EXCLUDE: [
46
- _MiddlewareConfig.CONSTANTS.LOGIN_PATH,
47
- _MiddlewareConfig.CONSTANTS.PUBLIC_PATH,
48
- _MiddlewareConfig.CONSTANTS.PUBLIC_API_PATH,
49
- ..._MiddlewareConfig.getPublicRoutesWhitelist()
50
- // Add custom whitelist from env
51
- ]
70
+ DASHBOARD_SUBDOMAIN: "dashboard"
52
71
  };
53
72
  // HTTP methods to process
54
- _MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
73
+ MiddlewareConfig.ALLOWED_METHODS = ["GET", "HEAD"];
55
74
  // Query parameters
56
- _MiddlewareConfig.QUERY_PARAMS = {
75
+ MiddlewareConfig.QUERY_PARAMS = {
57
76
  LOGIN_REQUIRED: "sign_in_required",
58
77
  AUTH_CHECKED: "auth_checked",
59
78
  REDIRECT_URL: "redirect_url"
60
79
  };
61
80
  // Query parameter values
62
- _MiddlewareConfig.QUERY_VALUES = {
81
+ MiddlewareConfig.QUERY_VALUES = {
63
82
  LOGIN_REQUIRED: "true",
64
83
  AUTH_CHECKED: "1"
65
84
  };
66
- var MiddlewareConfig = _MiddlewareConfig;
67
85
 
68
86
  // src/services/utils/url-utils.ts
69
87
  var UrlUtils = class {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mailsentry-auth",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
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",