najm-auth 1.1.36 → 1.1.38

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.
@@ -0,0 +1,47 @@
1
+ import * as next_server from 'next/server';
2
+
3
+ interface AuthMiddlewareConfig {
4
+ /** Routes that require authentication (glob patterns) */
5
+ protectedRoutes?: string[];
6
+ /** Always-public routes (glob patterns) */
7
+ publicRoutes?: string[];
8
+ /** Route to redirect unauthenticated users to */
9
+ loginRoute?: string;
10
+ /** Routes restricted to specific roles: { '/admin/*': ['admin'] } */
11
+ roleRoutes?: Record<string, string[]>;
12
+ /** Refresh token cookie name (default: 'refreshToken') */
13
+ cookieName?: string;
14
+ /** Session cookie name to clear on redirect (default: 'najm.session') */
15
+ sessionCookieName?: string;
16
+ /** URL of the verify endpoint (default: derived from request) */
17
+ verifyURL?: string;
18
+ /**
19
+ * When true, call the verify endpoint on EVERY protected route (not just
20
+ * roleRoutes). Redirects to loginRoute if the session is invalid. Adds one
21
+ * fetch per navigation — trade latency for stronger guarantees.
22
+ */
23
+ verifyAlways?: boolean;
24
+ }
25
+ /**
26
+ * Create a Next.js middleware function that protects routes based on auth state.
27
+ *
28
+ * @example
29
+ * ```ts
30
+ * // middleware.ts
31
+ * import { withAuthMiddleware } from 'najm-auth/client/server';
32
+ *
33
+ * export default withAuthMiddleware({
34
+ * protectedRoutes: ['/dashboard/:path*', '/admin/:path*'],
35
+ * publicRoutes: ['/', '/about', '/login', '/register'],
36
+ * loginRoute: '/login',
37
+ * roleRoutes: { '/admin/:path*': ['admin'] },
38
+ * });
39
+ *
40
+ * export const config = {
41
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
42
+ * };
43
+ * ```
44
+ */
45
+ declare function withAuthMiddleware(config: AuthMiddlewareConfig): (request: Request) => Promise<next_server.NextResponse<unknown>>;
46
+
47
+ export { type AuthMiddlewareConfig, withAuthMiddleware };
@@ -0,0 +1,88 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+
4
+ // src/client/server/withAuthMiddleware.ts
5
+ function withAuthMiddleware(config) {
6
+ const {
7
+ protectedRoutes = [],
8
+ publicRoutes = [],
9
+ loginRoute = "/login",
10
+ roleRoutes = {},
11
+ cookieName = "refreshToken",
12
+ sessionCookieName = "najm.session",
13
+ verifyAlways = false
14
+ } = config;
15
+ return /* @__PURE__ */ __name(async function middleware(request) {
16
+ const { NextResponse } = await import("next/server");
17
+ const redirectToLogin = /* @__PURE__ */ __name((pathname2, clearCookies) => {
18
+ const loginUrl = new URL(loginRoute, request.url);
19
+ loginUrl.searchParams.set("from", pathname2);
20
+ const res = NextResponse.redirect(loginUrl);
21
+ if (clearCookies) {
22
+ res.cookies.delete(cookieName);
23
+ res.cookies.delete(sessionCookieName);
24
+ }
25
+ return res;
26
+ }, "redirectToLogin");
27
+ const url = new URL(request.url);
28
+ const pathname = url.pathname;
29
+ if (matchesAny(pathname, publicRoutes)) {
30
+ return NextResponse.next();
31
+ }
32
+ const isProtected = protectedRoutes.length === 0 || matchesAny(pathname, protectedRoutes);
33
+ if (!isProtected) return NextResponse.next();
34
+ const cookie = request.headers.get("cookie") ?? "";
35
+ const hasToken = cookieRegex(cookieName).test(cookie);
36
+ if (!hasToken) {
37
+ return redirectToLogin(pathname, true);
38
+ }
39
+ const requiredRoles = findMatchingRoles(pathname, roleRoutes);
40
+ const needsVerify = verifyAlways || !!requiredRoles;
41
+ if (needsVerify) {
42
+ const verifyURL = config.verifyURL ?? `${url.origin}/api/auth/me`;
43
+ try {
44
+ const res = await fetch(verifyURL, {
45
+ headers: { "Cookie": cookie, "Accept": "application/json" }
46
+ });
47
+ if (!res.ok) {
48
+ return redirectToLogin(pathname, true);
49
+ }
50
+ if (requiredRoles) {
51
+ const body = await res.json();
52
+ const userRole = body?.data?.role;
53
+ if (!userRole || !requiredRoles.includes(userRole)) {
54
+ return new NextResponse(null, { status: 403 });
55
+ }
56
+ }
57
+ } catch {
58
+ return redirectToLogin(pathname, true);
59
+ }
60
+ }
61
+ return NextResponse.next();
62
+ }, "middleware");
63
+ }
64
+ __name(withAuthMiddleware, "withAuthMiddleware");
65
+ function matchesAny(pathname, patterns) {
66
+ return patterns.some((p) => matchPattern(pathname, p));
67
+ }
68
+ __name(matchesAny, "matchesAny");
69
+ function matchPattern(pathname, pattern) {
70
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
71
+ const regex = escaped.replace(/\/:[^/]+\*/g, "(?:/.*)?").replace(/\/\\\*$/g, "(?:/.*)?").replace(/\\\*/g, "(?:/.*)?").replace(/\//g, "\\/");
72
+ return new RegExp(`^${regex}$`).test(pathname);
73
+ }
74
+ __name(matchPattern, "matchPattern");
75
+ function cookieRegex(name) {
76
+ return new RegExp(`(?:^|;\\s*)${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}=[^;]`);
77
+ }
78
+ __name(cookieRegex, "cookieRegex");
79
+ function findMatchingRoles(pathname, roleRoutes) {
80
+ for (const [pattern, roles] of Object.entries(roleRoutes)) {
81
+ if (matchPattern(pathname, pattern)) return roles;
82
+ }
83
+ return null;
84
+ }
85
+ __name(findMatchingRoles, "findMatchingRoles");
86
+ export {
87
+ withAuthMiddleware
88
+ };
@@ -1,5 +1,6 @@
1
1
  import { e as AuthUser, F as FetchClient, R as RetryConfig, N as NajmAuthClient } from '../../NajmAuthClient-D08--i69.js';
2
- import * as next_server from 'next/server';
2
+ export { withAuthMiddleware } from '../edge.js';
3
+ import 'next/server';
3
4
 
4
5
  interface GetServerSessionOptions {
5
6
  /** The URL of the /auth/me endpoint */
@@ -63,50 +64,6 @@ interface ServerClientConfig {
63
64
  */
64
65
  declare function createServerClient(config: ServerClientConfig): FetchClient;
65
66
 
66
- interface AuthMiddlewareConfig {
67
- /** Routes that require authentication (glob patterns) */
68
- protectedRoutes?: string[];
69
- /** Always-public routes (glob patterns) */
70
- publicRoutes?: string[];
71
- /** Route to redirect unauthenticated users to */
72
- loginRoute?: string;
73
- /** Routes restricted to specific roles: { '/admin/*': ['admin'] } */
74
- roleRoutes?: Record<string, string[]>;
75
- /** Refresh token cookie name (default: 'refreshToken') */
76
- cookieName?: string;
77
- /** Session cookie name to clear on redirect (default: 'najm.session') */
78
- sessionCookieName?: string;
79
- /** URL of the verify endpoint (default: derived from request) */
80
- verifyURL?: string;
81
- /**
82
- * When true, call the verify endpoint on EVERY protected route (not just
83
- * roleRoutes). Redirects to loginRoute if the session is invalid. Adds one
84
- * fetch per navigation — trade latency for stronger guarantees.
85
- */
86
- verifyAlways?: boolean;
87
- }
88
- /**
89
- * Create a Next.js middleware function that protects routes based on auth state.
90
- *
91
- * @example
92
- * ```ts
93
- * // middleware.ts
94
- * import { withAuthMiddleware } from 'najm-auth/client/server';
95
- *
96
- * export default withAuthMiddleware({
97
- * protectedRoutes: ['/dashboard/:path*', '/admin/:path*'],
98
- * publicRoutes: ['/', '/about', '/login', '/register'],
99
- * loginRoute: '/login',
100
- * roleRoutes: { '/admin/:path*': ['admin'] },
101
- * });
102
- *
103
- * export const config = {
104
- * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
105
- * };
106
- * ```
107
- */
108
- declare function withAuthMiddleware(config: AuthMiddlewareConfig): (request: Request) => Promise<next_server.NextResponse<unknown>>;
109
-
110
67
  interface ServerSession {
111
68
  user: AuthUser;
112
69
  roles?: string[];
@@ -279,4 +236,4 @@ interface AuthKit {
279
236
  }
280
237
  declare function defineAuth(authConfig?: DefineAuthConfig): AuthKit;
281
238
 
282
- export { AuthConfigError, type AuthKit, AuthTransportError, type DefineAuthConfig, type GetSessionConfig, NoSessionError, type ServerSession, type WithAuthOptions, type WithAuthProps, createServerClient, defineAuth, getServerSession, getSession, withAuth, withAuthMiddleware };
239
+ export { AuthConfigError, type AuthKit, AuthTransportError, type DefineAuthConfig, type GetSessionConfig, NoSessionError, type ServerSession, type WithAuthOptions, type WithAuthProps, createServerClient, defineAuth, getServerSession, getSession, withAuth };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-auth",
3
- "version": "1.1.36",
3
+ "version": "1.1.38",
4
4
  "description": "Authentication and authorization library for najm framework",
5
5
  "type": "module",
6
6
  "files": [
@@ -19,6 +19,11 @@
19
19
  "import": "./dist/client/index.js",
20
20
  "default": "./dist/client/index.js"
21
21
  },
22
+ "./client/edge": {
23
+ "types": "./dist/client/edge.d.ts",
24
+ "import": "./dist/client/edge.js",
25
+ "default": "./dist/client/edge.js"
26
+ },
22
27
  "./client/react": {
23
28
  "types": "./dist/client/react/index.d.ts",
24
29
  "import": "./dist/client/react/index.js",
@@ -73,15 +78,15 @@
73
78
  },
74
79
  "dependencies": {
75
80
  "bcryptjs": "^3.0.2",
76
- "najm-cookies": "^1.1.10",
77
- "najm-core": "^1.2.8",
78
- "najm-database": "^1.1.12",
79
- "najm-guard": "^1.1.10",
80
- "najm-i18n": "^1.1.10",
81
- "najm-cache": "^1.2.7",
82
- "najm-email": "^1.1.10",
83
- "najm-rate": "^1.1.10",
84
- "najm-validation": "^1.1.11",
81
+ "najm-cookies": "^1.1.12",
82
+ "najm-core": "^1.2.10",
83
+ "najm-database": "^1.1.14",
84
+ "najm-guard": "^1.1.12",
85
+ "najm-i18n": "^1.1.12",
86
+ "najm-cache": "^1.2.9",
87
+ "najm-email": "^1.1.12",
88
+ "najm-rate": "^1.1.12",
89
+ "najm-validation": "^1.1.13",
85
90
  "hono": "^4.0.0",
86
91
  "jsonwebtoken": "^9.0.3",
87
92
  "lodash.isempty": "^4.4.0",