@chemmangat/msal-next 5.2.0 → 5.2.1

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/CHANGELOG.md CHANGED
@@ -2,7 +2,32 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [5.2.0] - 2026-04-07
5
+ ## [5.2.1] - 2026-04-07
6
+
7
+ ### 🐛 Bug Fix
8
+
9
+ #### `createAuthMiddleware` now importable from `@chemmangat/msal-next/middleware`
10
+
11
+ `createAuthMiddleware` was previously bundled inside `dist/index.mjs` which carries a `"use client"` directive. Importing it in `middleware.ts` caused Next.js to throw:
12
+
13
+ > "Attempted to call createAuthMiddleware() from the server but createAuthMiddleware is on the client."
14
+
15
+ It now has its own edge-compatible entry point with no React, no `@azure/msal-browser`, and no `"use client"` — only `next/server`.
16
+
17
+ **Migration** (update your import):
18
+ ```ts
19
+ // Before
20
+ import { createAuthMiddleware } from '@chemmangat/msal-next';
21
+
22
+ // After
23
+ import { createAuthMiddleware } from '@chemmangat/msal-next/middleware';
24
+ ```
25
+
26
+ Also fixed `tenantValidator.ts` to use `import type` for its `@azure/msal-browser` and `types.ts` imports, ensuring those never get bundled into the middleware output.
27
+
28
+ ---
29
+
30
+
6
31
 
7
32
  ### 🔧 Compatibility
8
33
 
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { Configuration, LogLevel, IPublicClientApplication, PublicClientApplication, AccountInfo } from '@azure/msal-browser';
3
3
  export { AccountInfo } from '@azure/msal-browser';
4
4
  import { ReactNode, CSSProperties, Component, ErrorInfo, ComponentType } from 'react';
5
- import { NextRequest, NextResponse } from 'next/server';
5
+ import { NextRequest } from 'next/server';
6
6
  export { useAccount, useIsAuthenticated, useMsal } from '@azure/msal-react';
7
7
 
8
8
  /**
@@ -1865,6 +1865,26 @@ declare function withPageAuth<P extends object>(Component: ComponentType<P>, aut
1865
1865
  displayName: string;
1866
1866
  };
1867
1867
 
1868
+ interface ServerSession {
1869
+ /**
1870
+ * Whether user is authenticated
1871
+ */
1872
+ isAuthenticated: boolean;
1873
+ /**
1874
+ * User's account ID from MSAL cache
1875
+ */
1876
+ accountId?: string;
1877
+ /**
1878
+ * User's username/email
1879
+ */
1880
+ username?: string;
1881
+ /**
1882
+ * Access token (if available in cookie)
1883
+ * @deprecated Storing tokens in cookies is not recommended for security reasons
1884
+ */
1885
+ accessToken?: string;
1886
+ }
1887
+
1868
1888
  interface AuthMiddlewareConfig {
1869
1889
  /**
1870
1890
  * Routes that require authentication
@@ -1911,45 +1931,5 @@ interface AuthMiddlewareConfig {
1911
1931
  */
1912
1932
  debug?: boolean;
1913
1933
  }
1914
- /**
1915
- * Creates authentication middleware for Next.js App Router
1916
- *
1917
- * @example
1918
- * ```tsx
1919
- * // middleware.ts
1920
- * import { createAuthMiddleware } from '@chemmangat/msal-next';
1921
- *
1922
- * export const middleware = createAuthMiddleware({
1923
- * protectedRoutes: ['/dashboard', '/profile'],
1924
- * publicOnlyRoutes: ['/login'],
1925
- * loginPath: '/login',
1926
- * });
1927
- *
1928
- * export const config = {
1929
- * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
1930
- * };
1931
- * ```
1932
- */
1933
- declare function createAuthMiddleware(config?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
1934
-
1935
- interface ServerSession {
1936
- /**
1937
- * Whether user is authenticated
1938
- */
1939
- isAuthenticated: boolean;
1940
- /**
1941
- * User's account ID from MSAL cache
1942
- */
1943
- accountId?: string;
1944
- /**
1945
- * User's username/email
1946
- */
1947
- username?: string;
1948
- /**
1949
- * Access token (if available in cookie)
1950
- * @deprecated Storing tokens in cookies is not recommended for security reasons
1951
- */
1952
- accessToken?: string;
1953
- }
1954
1934
 
1955
- export { AccountList, type AccountListProps, AccountSwitcher, type AccountSwitcherProps, AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, MsalError, type MultiTenantConfig, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type TenantAuthConfig, type TenantInfo, type UseGraphApiReturn, type UseMsalAuthReturn, type UseMultiAccountReturn, type UseRolesReturn, type UseTenantReturn, type UseTokenRefreshOptions, type UseTokenRefreshReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type ValidationError, type ValidationResult, type ValidationWarning, type WithAuthOptions, createAuthMiddleware, createMissingEnvVarError, createMsalConfig, createRetryWrapper, createScopedLogger, displayValidationResults, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useMultiAccount, useRoles, useTenant, useTenantConfig, useTokenRefresh, useUserProfile, validateConfig, validateScopes, withAuth, withPageAuth, wrapMsalError };
1935
+ export { AccountList, type AccountListProps, AccountSwitcher, type AccountSwitcherProps, AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, MsalError, type MultiTenantConfig, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type TenantAuthConfig, type TenantInfo, type UseGraphApiReturn, type UseMsalAuthReturn, type UseMultiAccountReturn, type UseRolesReturn, type UseTenantReturn, type UseTokenRefreshOptions, type UseTokenRefreshReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type ValidationError, type ValidationResult, type ValidationWarning, type WithAuthOptions, createMissingEnvVarError, createMsalConfig, createRetryWrapper, createScopedLogger, displayValidationResults, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useMultiAccount, useRoles, useTenant, useTenantConfig, useTokenRefresh, useUserProfile, validateConfig, validateScopes, withAuth, withPageAuth, wrapMsalError };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { Configuration, LogLevel, IPublicClientApplication, PublicClientApplication, AccountInfo } from '@azure/msal-browser';
3
3
  export { AccountInfo } from '@azure/msal-browser';
4
4
  import { ReactNode, CSSProperties, Component, ErrorInfo, ComponentType } from 'react';
5
- import { NextRequest, NextResponse } from 'next/server';
5
+ import { NextRequest } from 'next/server';
6
6
  export { useAccount, useIsAuthenticated, useMsal } from '@azure/msal-react';
7
7
 
8
8
  /**
@@ -1865,6 +1865,26 @@ declare function withPageAuth<P extends object>(Component: ComponentType<P>, aut
1865
1865
  displayName: string;
1866
1866
  };
1867
1867
 
1868
+ interface ServerSession {
1869
+ /**
1870
+ * Whether user is authenticated
1871
+ */
1872
+ isAuthenticated: boolean;
1873
+ /**
1874
+ * User's account ID from MSAL cache
1875
+ */
1876
+ accountId?: string;
1877
+ /**
1878
+ * User's username/email
1879
+ */
1880
+ username?: string;
1881
+ /**
1882
+ * Access token (if available in cookie)
1883
+ * @deprecated Storing tokens in cookies is not recommended for security reasons
1884
+ */
1885
+ accessToken?: string;
1886
+ }
1887
+
1868
1888
  interface AuthMiddlewareConfig {
1869
1889
  /**
1870
1890
  * Routes that require authentication
@@ -1911,45 +1931,5 @@ interface AuthMiddlewareConfig {
1911
1931
  */
1912
1932
  debug?: boolean;
1913
1933
  }
1914
- /**
1915
- * Creates authentication middleware for Next.js App Router
1916
- *
1917
- * @example
1918
- * ```tsx
1919
- * // middleware.ts
1920
- * import { createAuthMiddleware } from '@chemmangat/msal-next';
1921
- *
1922
- * export const middleware = createAuthMiddleware({
1923
- * protectedRoutes: ['/dashboard', '/profile'],
1924
- * publicOnlyRoutes: ['/login'],
1925
- * loginPath: '/login',
1926
- * });
1927
- *
1928
- * export const config = {
1929
- * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
1930
- * };
1931
- * ```
1932
- */
1933
- declare function createAuthMiddleware(config?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
1934
-
1935
- interface ServerSession {
1936
- /**
1937
- * Whether user is authenticated
1938
- */
1939
- isAuthenticated: boolean;
1940
- /**
1941
- * User's account ID from MSAL cache
1942
- */
1943
- accountId?: string;
1944
- /**
1945
- * User's username/email
1946
- */
1947
- username?: string;
1948
- /**
1949
- * Access token (if available in cookie)
1950
- * @deprecated Storing tokens in cookies is not recommended for security reasons
1951
- */
1952
- accessToken?: string;
1953
- }
1954
1934
 
1955
- export { AccountList, type AccountListProps, AccountSwitcher, type AccountSwitcherProps, AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, MsalError, type MultiTenantConfig, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type TenantAuthConfig, type TenantInfo, type UseGraphApiReturn, type UseMsalAuthReturn, type UseMultiAccountReturn, type UseRolesReturn, type UseTenantReturn, type UseTokenRefreshOptions, type UseTokenRefreshReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type ValidationError, type ValidationResult, type ValidationWarning, type WithAuthOptions, createAuthMiddleware, createMissingEnvVarError, createMsalConfig, createRetryWrapper, createScopedLogger, displayValidationResults, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useMultiAccount, useRoles, useTenant, useTenantConfig, useTokenRefresh, useUserProfile, validateConfig, validateScopes, withAuth, withPageAuth, wrapMsalError };
1935
+ export { AccountList, type AccountListProps, AccountSwitcher, type AccountSwitcherProps, AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, type AuthProtectionConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, MsalError, type MultiTenantConfig, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type TenantAuthConfig, type TenantInfo, type UseGraphApiReturn, type UseMsalAuthReturn, type UseMultiAccountReturn, type UseRolesReturn, type UseTenantReturn, type UseTokenRefreshOptions, type UseTokenRefreshReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type ValidationError, type ValidationResult, type ValidationWarning, type WithAuthOptions, createMissingEnvVarError, createMsalConfig, createRetryWrapper, createScopedLogger, displayValidationResults, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useMultiAccount, useRoles, useTenant, useTenantConfig, useTokenRefresh, useUserProfile, validateConfig, validateScopes, withAuth, withPageAuth, wrapMsalError };
package/dist/index.js CHANGED
@@ -33,7 +33,6 @@ __export(client_exports, {
33
33
  ProtectedPage: () => ProtectedPage,
34
34
  SignOutButton: () => SignOutButton,
35
35
  UserAvatar: () => UserAvatar,
36
- createAuthMiddleware: () => createAuthMiddleware,
37
36
  createMissingEnvVarError: () => createMissingEnvVarError,
38
37
  createMsalConfig: () => createMsalConfig,
39
38
  createRetryWrapper: () => createRetryWrapper,
@@ -3166,105 +3165,6 @@ function withPageAuth(Component2, authConfig, globalConfig) {
3166
3165
  return WrappedComponent;
3167
3166
  }
3168
3167
 
3169
- // src/middleware/createAuthMiddleware.ts
3170
- var import_server = require("next/server");
3171
- function createAuthMiddleware(config = {}) {
3172
- const {
3173
- protectedRoutes = [],
3174
- publicOnlyRoutes = [],
3175
- loginPath = "/login",
3176
- redirectAfterLogin = "/",
3177
- sessionCookie = "msal.account",
3178
- isAuthenticated: customAuthCheck,
3179
- tenantConfig,
3180
- tenantDeniedPath = "/unauthorized",
3181
- debug = false
3182
- } = config;
3183
- return async function authMiddleware(request) {
3184
- const { pathname } = request.nextUrl;
3185
- if (debug) {
3186
- console.log("[AuthMiddleware] Processing:", pathname);
3187
- }
3188
- let authenticated = false;
3189
- if (customAuthCheck) {
3190
- authenticated = await customAuthCheck(request);
3191
- } else {
3192
- const sessionData = request.cookies.get(sessionCookie);
3193
- authenticated = !!sessionData?.value;
3194
- }
3195
- if (debug) {
3196
- console.log("[AuthMiddleware] Authenticated:", authenticated);
3197
- }
3198
- const isProtectedRoute = protectedRoutes.some(
3199
- (route) => pathname.startsWith(route)
3200
- );
3201
- const isPublicOnlyRoute = publicOnlyRoutes.some(
3202
- (route) => pathname.startsWith(route)
3203
- );
3204
- if (isProtectedRoute && !authenticated) {
3205
- if (debug) {
3206
- console.log("[AuthMiddleware] Redirecting to login");
3207
- }
3208
- const url = request.nextUrl.clone();
3209
- url.pathname = loginPath;
3210
- url.searchParams.set("returnUrl", pathname);
3211
- return import_server.NextResponse.redirect(url);
3212
- }
3213
- if (isProtectedRoute && authenticated && tenantConfig) {
3214
- try {
3215
- const sessionData = request.cookies.get(sessionCookie);
3216
- if (sessionData?.value) {
3217
- const account = safeJsonParse(sessionData.value, isValidAccountData);
3218
- if (account) {
3219
- const tenantResult = validateTenantAccess(account, tenantConfig);
3220
- if (!tenantResult.allowed) {
3221
- if (debug) {
3222
- console.log("[AuthMiddleware] Tenant access denied:", tenantResult.reason);
3223
- }
3224
- const url = request.nextUrl.clone();
3225
- url.pathname = tenantDeniedPath;
3226
- url.searchParams.set("reason", tenantResult.reason || "access_denied");
3227
- return import_server.NextResponse.redirect(url);
3228
- }
3229
- }
3230
- }
3231
- } catch (error) {
3232
- if (debug) {
3233
- console.warn("[AuthMiddleware] Tenant validation error:", error);
3234
- }
3235
- }
3236
- }
3237
- if (isPublicOnlyRoute && authenticated) {
3238
- if (debug) {
3239
- console.log("[AuthMiddleware] Redirecting to home");
3240
- }
3241
- const returnUrl = request.nextUrl.searchParams.get("returnUrl");
3242
- const url = request.nextUrl.clone();
3243
- url.pathname = returnUrl || redirectAfterLogin;
3244
- url.searchParams.delete("returnUrl");
3245
- return import_server.NextResponse.redirect(url);
3246
- }
3247
- const response = import_server.NextResponse.next();
3248
- if (authenticated) {
3249
- response.headers.set("x-msal-authenticated", "true");
3250
- try {
3251
- const sessionData = request.cookies.get(sessionCookie);
3252
- if (sessionData?.value) {
3253
- const account = safeJsonParse(sessionData.value, isValidAccountData);
3254
- if (account?.username) {
3255
- response.headers.set("x-msal-username", account.username);
3256
- }
3257
- }
3258
- } catch (error) {
3259
- if (debug) {
3260
- console.warn("[AuthMiddleware] Failed to parse session data");
3261
- }
3262
- }
3263
- }
3264
- return response;
3265
- };
3266
- }
3267
-
3268
3168
  // src/client.ts
3269
3169
  var import_msal_react4 = require("@azure/msal-react");
3270
3170
  // Annotate the CommonJS export names for ESM import in node:
@@ -3281,7 +3181,6 @@ var import_msal_react4 = require("@azure/msal-react");
3281
3181
  ProtectedPage,
3282
3182
  SignOutButton,
3283
3183
  UserAvatar,
3284
- createAuthMiddleware,
3285
3184
  createMissingEnvVarError,
3286
3185
  createMsalConfig,
3287
3186
  createRetryWrapper,
package/dist/index.mjs CHANGED
@@ -3106,105 +3106,6 @@ function withPageAuth(Component2, authConfig, globalConfig) {
3106
3106
  return WrappedComponent;
3107
3107
  }
3108
3108
 
3109
- // src/middleware/createAuthMiddleware.ts
3110
- import { NextResponse } from "next/server";
3111
- function createAuthMiddleware(config = {}) {
3112
- const {
3113
- protectedRoutes = [],
3114
- publicOnlyRoutes = [],
3115
- loginPath = "/login",
3116
- redirectAfterLogin = "/",
3117
- sessionCookie = "msal.account",
3118
- isAuthenticated: customAuthCheck,
3119
- tenantConfig,
3120
- tenantDeniedPath = "/unauthorized",
3121
- debug = false
3122
- } = config;
3123
- return async function authMiddleware(request) {
3124
- const { pathname } = request.nextUrl;
3125
- if (debug) {
3126
- console.log("[AuthMiddleware] Processing:", pathname);
3127
- }
3128
- let authenticated = false;
3129
- if (customAuthCheck) {
3130
- authenticated = await customAuthCheck(request);
3131
- } else {
3132
- const sessionData = request.cookies.get(sessionCookie);
3133
- authenticated = !!sessionData?.value;
3134
- }
3135
- if (debug) {
3136
- console.log("[AuthMiddleware] Authenticated:", authenticated);
3137
- }
3138
- const isProtectedRoute = protectedRoutes.some(
3139
- (route) => pathname.startsWith(route)
3140
- );
3141
- const isPublicOnlyRoute = publicOnlyRoutes.some(
3142
- (route) => pathname.startsWith(route)
3143
- );
3144
- if (isProtectedRoute && !authenticated) {
3145
- if (debug) {
3146
- console.log("[AuthMiddleware] Redirecting to login");
3147
- }
3148
- const url = request.nextUrl.clone();
3149
- url.pathname = loginPath;
3150
- url.searchParams.set("returnUrl", pathname);
3151
- return NextResponse.redirect(url);
3152
- }
3153
- if (isProtectedRoute && authenticated && tenantConfig) {
3154
- try {
3155
- const sessionData = request.cookies.get(sessionCookie);
3156
- if (sessionData?.value) {
3157
- const account = safeJsonParse(sessionData.value, isValidAccountData);
3158
- if (account) {
3159
- const tenantResult = validateTenantAccess(account, tenantConfig);
3160
- if (!tenantResult.allowed) {
3161
- if (debug) {
3162
- console.log("[AuthMiddleware] Tenant access denied:", tenantResult.reason);
3163
- }
3164
- const url = request.nextUrl.clone();
3165
- url.pathname = tenantDeniedPath;
3166
- url.searchParams.set("reason", tenantResult.reason || "access_denied");
3167
- return NextResponse.redirect(url);
3168
- }
3169
- }
3170
- }
3171
- } catch (error) {
3172
- if (debug) {
3173
- console.warn("[AuthMiddleware] Tenant validation error:", error);
3174
- }
3175
- }
3176
- }
3177
- if (isPublicOnlyRoute && authenticated) {
3178
- if (debug) {
3179
- console.log("[AuthMiddleware] Redirecting to home");
3180
- }
3181
- const returnUrl = request.nextUrl.searchParams.get("returnUrl");
3182
- const url = request.nextUrl.clone();
3183
- url.pathname = returnUrl || redirectAfterLogin;
3184
- url.searchParams.delete("returnUrl");
3185
- return NextResponse.redirect(url);
3186
- }
3187
- const response = NextResponse.next();
3188
- if (authenticated) {
3189
- response.headers.set("x-msal-authenticated", "true");
3190
- try {
3191
- const sessionData = request.cookies.get(sessionCookie);
3192
- if (sessionData?.value) {
3193
- const account = safeJsonParse(sessionData.value, isValidAccountData);
3194
- if (account?.username) {
3195
- response.headers.set("x-msal-username", account.username);
3196
- }
3197
- }
3198
- } catch (error) {
3199
- if (debug) {
3200
- console.warn("[AuthMiddleware] Failed to parse session data");
3201
- }
3202
- }
3203
- }
3204
- return response;
3205
- };
3206
- }
3207
-
3208
3109
  // src/client.ts
3209
3110
  import { useMsal as useMsal3, useIsAuthenticated, useAccount as useAccount2 } from "@azure/msal-react";
3210
3111
  export {
@@ -3220,7 +3121,6 @@ export {
3220
3121
  ProtectedPage,
3221
3122
  SignOutButton,
3222
3123
  UserAvatar,
3223
- createAuthMiddleware,
3224
3124
  createMissingEnvVarError,
3225
3125
  createMsalConfig,
3226
3126
  createRetryWrapper,
@@ -0,0 +1,115 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+
3
+ /**
4
+ * Type definitions for @chemmangat/msal-next
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ /**
10
+ * Multi-tenant configuration for v5.1.0
11
+ */
12
+ interface MultiTenantConfig {
13
+ /**
14
+ * Tenant mode
15
+ * - 'single' — only your own tenant (maps to authorityType 'tenant')
16
+ * - 'multi' — any Azure AD tenant (maps to authorityType 'common')
17
+ * - 'organizations' — any organisational tenant, no personal accounts
18
+ * - 'consumers' — Microsoft personal accounts only
19
+ * - 'common' — alias for 'multi'
20
+ *
21
+ * @defaultValue 'common'
22
+ */
23
+ type?: 'single' | 'multi' | 'organizations' | 'consumers' | 'common';
24
+ /**
25
+ * Tenant allow-list — only users from these tenant IDs or domains are permitted.
26
+ * Checked after authentication; users from other tenants are shown an error.
27
+ *
28
+ * @example ['contoso.com', '72f988bf-86f1-41af-91ab-2d7cd011db47']
29
+ */
30
+ allowList?: string[];
31
+ /**
32
+ * Tenant block-list — users from these tenant IDs or domains are denied.
33
+ * Takes precedence over allowList.
34
+ */
35
+ blockList?: string[];
36
+ /**
37
+ * Require a specific tenant type ('Member' | 'Guest').
38
+ * Useful to block B2B guests or to allow only guests.
39
+ */
40
+ requireType?: 'Member' | 'Guest';
41
+ /**
42
+ * Require MFA claim in the token (amr claim must contain 'mfa').
43
+ * @defaultValue false
44
+ */
45
+ requireMFA?: boolean;
46
+ }
47
+
48
+ interface AuthMiddlewareConfig {
49
+ /**
50
+ * Routes that require authentication
51
+ * @example ['/dashboard', '/profile', '/api/protected']
52
+ */
53
+ protectedRoutes?: string[];
54
+ /**
55
+ * Routes that should be accessible only when NOT authenticated
56
+ * @example ['/login', '/signup']
57
+ */
58
+ publicOnlyRoutes?: string[];
59
+ /**
60
+ * Login page path
61
+ * @default '/login'
62
+ */
63
+ loginPath?: string;
64
+ /**
65
+ * Redirect path after login
66
+ * @default '/'
67
+ */
68
+ redirectAfterLogin?: string;
69
+ /**
70
+ * Cookie name for session
71
+ * @default 'msal.account'
72
+ */
73
+ sessionCookie?: string;
74
+ /**
75
+ * Custom authentication check function
76
+ */
77
+ isAuthenticated?: (request: NextRequest) => boolean | Promise<boolean>;
78
+ /**
79
+ * Tenant access configuration (v5.1.0).
80
+ * Validated against the account stored in the session cookie.
81
+ */
82
+ tenantConfig?: MultiTenantConfig;
83
+ /**
84
+ * Path to redirect to when tenant access is denied (v5.1.0).
85
+ * @default '/unauthorized'
86
+ */
87
+ tenantDeniedPath?: string;
88
+ /**
89
+ * Enable debug logging
90
+ * @default false
91
+ */
92
+ debug?: boolean;
93
+ }
94
+ /**
95
+ * Creates authentication middleware for Next.js App Router
96
+ *
97
+ * @example
98
+ * ```tsx
99
+ * // middleware.ts
100
+ * import { createAuthMiddleware } from '@chemmangat/msal-next';
101
+ *
102
+ * export const middleware = createAuthMiddleware({
103
+ * protectedRoutes: ['/dashboard', '/profile'],
104
+ * publicOnlyRoutes: ['/login'],
105
+ * loginPath: '/login',
106
+ * });
107
+ *
108
+ * export const config = {
109
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
110
+ * };
111
+ * ```
112
+ */
113
+ declare function createAuthMiddleware(config?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
114
+
115
+ export { type AuthMiddlewareConfig, createAuthMiddleware };
@@ -0,0 +1,115 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+
3
+ /**
4
+ * Type definitions for @chemmangat/msal-next
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ /**
10
+ * Multi-tenant configuration for v5.1.0
11
+ */
12
+ interface MultiTenantConfig {
13
+ /**
14
+ * Tenant mode
15
+ * - 'single' — only your own tenant (maps to authorityType 'tenant')
16
+ * - 'multi' — any Azure AD tenant (maps to authorityType 'common')
17
+ * - 'organizations' — any organisational tenant, no personal accounts
18
+ * - 'consumers' — Microsoft personal accounts only
19
+ * - 'common' — alias for 'multi'
20
+ *
21
+ * @defaultValue 'common'
22
+ */
23
+ type?: 'single' | 'multi' | 'organizations' | 'consumers' | 'common';
24
+ /**
25
+ * Tenant allow-list — only users from these tenant IDs or domains are permitted.
26
+ * Checked after authentication; users from other tenants are shown an error.
27
+ *
28
+ * @example ['contoso.com', '72f988bf-86f1-41af-91ab-2d7cd011db47']
29
+ */
30
+ allowList?: string[];
31
+ /**
32
+ * Tenant block-list — users from these tenant IDs or domains are denied.
33
+ * Takes precedence over allowList.
34
+ */
35
+ blockList?: string[];
36
+ /**
37
+ * Require a specific tenant type ('Member' | 'Guest').
38
+ * Useful to block B2B guests or to allow only guests.
39
+ */
40
+ requireType?: 'Member' | 'Guest';
41
+ /**
42
+ * Require MFA claim in the token (amr claim must contain 'mfa').
43
+ * @defaultValue false
44
+ */
45
+ requireMFA?: boolean;
46
+ }
47
+
48
+ interface AuthMiddlewareConfig {
49
+ /**
50
+ * Routes that require authentication
51
+ * @example ['/dashboard', '/profile', '/api/protected']
52
+ */
53
+ protectedRoutes?: string[];
54
+ /**
55
+ * Routes that should be accessible only when NOT authenticated
56
+ * @example ['/login', '/signup']
57
+ */
58
+ publicOnlyRoutes?: string[];
59
+ /**
60
+ * Login page path
61
+ * @default '/login'
62
+ */
63
+ loginPath?: string;
64
+ /**
65
+ * Redirect path after login
66
+ * @default '/'
67
+ */
68
+ redirectAfterLogin?: string;
69
+ /**
70
+ * Cookie name for session
71
+ * @default 'msal.account'
72
+ */
73
+ sessionCookie?: string;
74
+ /**
75
+ * Custom authentication check function
76
+ */
77
+ isAuthenticated?: (request: NextRequest) => boolean | Promise<boolean>;
78
+ /**
79
+ * Tenant access configuration (v5.1.0).
80
+ * Validated against the account stored in the session cookie.
81
+ */
82
+ tenantConfig?: MultiTenantConfig;
83
+ /**
84
+ * Path to redirect to when tenant access is denied (v5.1.0).
85
+ * @default '/unauthorized'
86
+ */
87
+ tenantDeniedPath?: string;
88
+ /**
89
+ * Enable debug logging
90
+ * @default false
91
+ */
92
+ debug?: boolean;
93
+ }
94
+ /**
95
+ * Creates authentication middleware for Next.js App Router
96
+ *
97
+ * @example
98
+ * ```tsx
99
+ * // middleware.ts
100
+ * import { createAuthMiddleware } from '@chemmangat/msal-next';
101
+ *
102
+ * export const middleware = createAuthMiddleware({
103
+ * protectedRoutes: ['/dashboard', '/profile'],
104
+ * publicOnlyRoutes: ['/login'],
105
+ * loginPath: '/login',
106
+ * });
107
+ *
108
+ * export const config = {
109
+ * matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
110
+ * };
111
+ * ```
112
+ */
113
+ declare function createAuthMiddleware(config?: AuthMiddlewareConfig): (request: NextRequest) => Promise<NextResponse<unknown>>;
114
+
115
+ export { type AuthMiddlewareConfig, createAuthMiddleware };
@@ -0,0 +1,203 @@
1
+ 'use strict';
2
+
3
+ var server = require('next/server');
4
+
5
+ // src/middleware/createAuthMiddleware.ts
6
+
7
+ // src/utils/validation.ts
8
+ function safeJsonParse(jsonString, validator) {
9
+ try {
10
+ const parsed = JSON.parse(jsonString);
11
+ if (validator(parsed)) {
12
+ return parsed;
13
+ }
14
+ console.warn("[Validation] JSON validation failed");
15
+ return null;
16
+ } catch (error) {
17
+ console.error("[Validation] JSON parse error:", error);
18
+ return null;
19
+ }
20
+ }
21
+ function isValidAccountData(data) {
22
+ return typeof data === "object" && data !== null && typeof data.homeAccountId === "string" && data.homeAccountId.length > 0 && typeof data.username === "string" && data.username.length > 0 && (data.name === void 0 || typeof data.name === "string");
23
+ }
24
+
25
+ // src/utils/tenantValidator.ts
26
+ function getTenantDomain(account) {
27
+ const upn = account.username || account.idTokenClaims?.preferred_username || account.idTokenClaims?.upn || "";
28
+ return upn.includes("@") ? upn.split("@")[1].toLowerCase() : null;
29
+ }
30
+ function getTenantId(account) {
31
+ return account.tenantId || account.idTokenClaims?.tid || null;
32
+ }
33
+ function matchesTenant(value, tenantId, tenantDomain) {
34
+ const v = value.toLowerCase();
35
+ if (tenantId && v === tenantId.toLowerCase()) return true;
36
+ if (tenantDomain && v === tenantDomain.toLowerCase()) return true;
37
+ return false;
38
+ }
39
+ function isGuestAccount(account) {
40
+ const claims = account.idTokenClaims ?? {};
41
+ const resourceTenantId = account.tenantId || claims["tid"] || null;
42
+ const issuer = claims["iss"] || null;
43
+ if (!issuer || !resourceTenantId) return false;
44
+ const match = issuer.match(
45
+ /https:\/\/login\.microsoftonline\.com\/([^/]+)(?:\/|$)/i
46
+ );
47
+ if (!match) return false;
48
+ const homeTenantId = match[1];
49
+ return homeTenantId.toLowerCase() !== resourceTenantId.toLowerCase();
50
+ }
51
+ function validateTenantAccess(account, config) {
52
+ const tenantId = getTenantId(account);
53
+ const tenantDomain = getTenantDomain(account);
54
+ const claims = account.idTokenClaims ?? {};
55
+ if (config.blockList && config.blockList.length > 0) {
56
+ const blocked = config.blockList.some(
57
+ (entry) => matchesTenant(entry, tenantId, tenantDomain)
58
+ );
59
+ if (blocked) {
60
+ return {
61
+ allowed: false,
62
+ reason: `Tenant "${tenantDomain || tenantId}" is blocked from accessing this application.`
63
+ };
64
+ }
65
+ }
66
+ if (config.allowList && config.allowList.length > 0) {
67
+ const allowed = config.allowList.some(
68
+ (entry) => matchesTenant(entry, tenantId, tenantDomain)
69
+ );
70
+ if (!allowed) {
71
+ return {
72
+ allowed: false,
73
+ reason: `Tenant "${tenantDomain || tenantId}" is not in the allowed list for this application.`
74
+ };
75
+ }
76
+ }
77
+ if (config.requireType) {
78
+ const isGuest = isGuestAccount(account);
79
+ if (config.requireType === "Member" && isGuest) {
80
+ return {
81
+ allowed: false,
82
+ reason: "Only member accounts are allowed. Guest (B2B) accounts are not permitted."
83
+ };
84
+ }
85
+ if (config.requireType === "Guest" && !isGuest) {
86
+ return {
87
+ allowed: false,
88
+ reason: "Only guest (B2B) accounts are allowed."
89
+ };
90
+ }
91
+ }
92
+ if (config.requireMFA) {
93
+ const amr = claims["amr"] || [];
94
+ const hasMfa = amr.includes("mfa") || amr.includes("ngcmfa") || amr.includes("hwk") || amr.includes("swk");
95
+ if (!hasMfa) {
96
+ return {
97
+ allowed: false,
98
+ reason: "Multi-factor authentication (MFA) is required to access this application."
99
+ };
100
+ }
101
+ }
102
+ return { allowed: true };
103
+ }
104
+
105
+ // src/middleware/createAuthMiddleware.ts
106
+ function createAuthMiddleware(config = {}) {
107
+ const {
108
+ protectedRoutes = [],
109
+ publicOnlyRoutes = [],
110
+ loginPath = "/login",
111
+ redirectAfterLogin = "/",
112
+ sessionCookie = "msal.account",
113
+ isAuthenticated: customAuthCheck,
114
+ tenantConfig,
115
+ tenantDeniedPath = "/unauthorized",
116
+ debug = false
117
+ } = config;
118
+ return async function authMiddleware(request) {
119
+ const { pathname } = request.nextUrl;
120
+ if (debug) {
121
+ console.log("[AuthMiddleware] Processing:", pathname);
122
+ }
123
+ let authenticated = false;
124
+ if (customAuthCheck) {
125
+ authenticated = await customAuthCheck(request);
126
+ } else {
127
+ const sessionData = request.cookies.get(sessionCookie);
128
+ authenticated = !!sessionData?.value;
129
+ }
130
+ if (debug) {
131
+ console.log("[AuthMiddleware] Authenticated:", authenticated);
132
+ }
133
+ const isProtectedRoute = protectedRoutes.some(
134
+ (route) => pathname.startsWith(route)
135
+ );
136
+ const isPublicOnlyRoute = publicOnlyRoutes.some(
137
+ (route) => pathname.startsWith(route)
138
+ );
139
+ if (isProtectedRoute && !authenticated) {
140
+ if (debug) {
141
+ console.log("[AuthMiddleware] Redirecting to login");
142
+ }
143
+ const url = request.nextUrl.clone();
144
+ url.pathname = loginPath;
145
+ url.searchParams.set("returnUrl", pathname);
146
+ return server.NextResponse.redirect(url);
147
+ }
148
+ if (isProtectedRoute && authenticated && tenantConfig) {
149
+ try {
150
+ const sessionData = request.cookies.get(sessionCookie);
151
+ if (sessionData?.value) {
152
+ const account = safeJsonParse(sessionData.value, isValidAccountData);
153
+ if (account) {
154
+ const tenantResult = validateTenantAccess(account, tenantConfig);
155
+ if (!tenantResult.allowed) {
156
+ if (debug) {
157
+ console.log("[AuthMiddleware] Tenant access denied:", tenantResult.reason);
158
+ }
159
+ const url = request.nextUrl.clone();
160
+ url.pathname = tenantDeniedPath;
161
+ url.searchParams.set("reason", tenantResult.reason || "access_denied");
162
+ return server.NextResponse.redirect(url);
163
+ }
164
+ }
165
+ }
166
+ } catch (error) {
167
+ if (debug) {
168
+ console.warn("[AuthMiddleware] Tenant validation error:", error);
169
+ }
170
+ }
171
+ }
172
+ if (isPublicOnlyRoute && authenticated) {
173
+ if (debug) {
174
+ console.log("[AuthMiddleware] Redirecting to home");
175
+ }
176
+ const returnUrl = request.nextUrl.searchParams.get("returnUrl");
177
+ const url = request.nextUrl.clone();
178
+ url.pathname = returnUrl || redirectAfterLogin;
179
+ url.searchParams.delete("returnUrl");
180
+ return server.NextResponse.redirect(url);
181
+ }
182
+ const response = server.NextResponse.next();
183
+ if (authenticated) {
184
+ response.headers.set("x-msal-authenticated", "true");
185
+ try {
186
+ const sessionData = request.cookies.get(sessionCookie);
187
+ if (sessionData?.value) {
188
+ const account = safeJsonParse(sessionData.value, isValidAccountData);
189
+ if (account?.username) {
190
+ response.headers.set("x-msal-username", account.username);
191
+ }
192
+ }
193
+ } catch (error) {
194
+ if (debug) {
195
+ console.warn("[AuthMiddleware] Failed to parse session data");
196
+ }
197
+ }
198
+ }
199
+ return response;
200
+ };
201
+ }
202
+
203
+ exports.createAuthMiddleware = createAuthMiddleware;
@@ -0,0 +1,201 @@
1
+ import { NextResponse } from 'next/server';
2
+
3
+ // src/middleware/createAuthMiddleware.ts
4
+
5
+ // src/utils/validation.ts
6
+ function safeJsonParse(jsonString, validator) {
7
+ try {
8
+ const parsed = JSON.parse(jsonString);
9
+ if (validator(parsed)) {
10
+ return parsed;
11
+ }
12
+ console.warn("[Validation] JSON validation failed");
13
+ return null;
14
+ } catch (error) {
15
+ console.error("[Validation] JSON parse error:", error);
16
+ return null;
17
+ }
18
+ }
19
+ function isValidAccountData(data) {
20
+ return typeof data === "object" && data !== null && typeof data.homeAccountId === "string" && data.homeAccountId.length > 0 && typeof data.username === "string" && data.username.length > 0 && (data.name === void 0 || typeof data.name === "string");
21
+ }
22
+
23
+ // src/utils/tenantValidator.ts
24
+ function getTenantDomain(account) {
25
+ const upn = account.username || account.idTokenClaims?.preferred_username || account.idTokenClaims?.upn || "";
26
+ return upn.includes("@") ? upn.split("@")[1].toLowerCase() : null;
27
+ }
28
+ function getTenantId(account) {
29
+ return account.tenantId || account.idTokenClaims?.tid || null;
30
+ }
31
+ function matchesTenant(value, tenantId, tenantDomain) {
32
+ const v = value.toLowerCase();
33
+ if (tenantId && v === tenantId.toLowerCase()) return true;
34
+ if (tenantDomain && v === tenantDomain.toLowerCase()) return true;
35
+ return false;
36
+ }
37
+ function isGuestAccount(account) {
38
+ const claims = account.idTokenClaims ?? {};
39
+ const resourceTenantId = account.tenantId || claims["tid"] || null;
40
+ const issuer = claims["iss"] || null;
41
+ if (!issuer || !resourceTenantId) return false;
42
+ const match = issuer.match(
43
+ /https:\/\/login\.microsoftonline\.com\/([^/]+)(?:\/|$)/i
44
+ );
45
+ if (!match) return false;
46
+ const homeTenantId = match[1];
47
+ return homeTenantId.toLowerCase() !== resourceTenantId.toLowerCase();
48
+ }
49
+ function validateTenantAccess(account, config) {
50
+ const tenantId = getTenantId(account);
51
+ const tenantDomain = getTenantDomain(account);
52
+ const claims = account.idTokenClaims ?? {};
53
+ if (config.blockList && config.blockList.length > 0) {
54
+ const blocked = config.blockList.some(
55
+ (entry) => matchesTenant(entry, tenantId, tenantDomain)
56
+ );
57
+ if (blocked) {
58
+ return {
59
+ allowed: false,
60
+ reason: `Tenant "${tenantDomain || tenantId}" is blocked from accessing this application.`
61
+ };
62
+ }
63
+ }
64
+ if (config.allowList && config.allowList.length > 0) {
65
+ const allowed = config.allowList.some(
66
+ (entry) => matchesTenant(entry, tenantId, tenantDomain)
67
+ );
68
+ if (!allowed) {
69
+ return {
70
+ allowed: false,
71
+ reason: `Tenant "${tenantDomain || tenantId}" is not in the allowed list for this application.`
72
+ };
73
+ }
74
+ }
75
+ if (config.requireType) {
76
+ const isGuest = isGuestAccount(account);
77
+ if (config.requireType === "Member" && isGuest) {
78
+ return {
79
+ allowed: false,
80
+ reason: "Only member accounts are allowed. Guest (B2B) accounts are not permitted."
81
+ };
82
+ }
83
+ if (config.requireType === "Guest" && !isGuest) {
84
+ return {
85
+ allowed: false,
86
+ reason: "Only guest (B2B) accounts are allowed."
87
+ };
88
+ }
89
+ }
90
+ if (config.requireMFA) {
91
+ const amr = claims["amr"] || [];
92
+ const hasMfa = amr.includes("mfa") || amr.includes("ngcmfa") || amr.includes("hwk") || amr.includes("swk");
93
+ if (!hasMfa) {
94
+ return {
95
+ allowed: false,
96
+ reason: "Multi-factor authentication (MFA) is required to access this application."
97
+ };
98
+ }
99
+ }
100
+ return { allowed: true };
101
+ }
102
+
103
+ // src/middleware/createAuthMiddleware.ts
104
+ function createAuthMiddleware(config = {}) {
105
+ const {
106
+ protectedRoutes = [],
107
+ publicOnlyRoutes = [],
108
+ loginPath = "/login",
109
+ redirectAfterLogin = "/",
110
+ sessionCookie = "msal.account",
111
+ isAuthenticated: customAuthCheck,
112
+ tenantConfig,
113
+ tenantDeniedPath = "/unauthorized",
114
+ debug = false
115
+ } = config;
116
+ return async function authMiddleware(request) {
117
+ const { pathname } = request.nextUrl;
118
+ if (debug) {
119
+ console.log("[AuthMiddleware] Processing:", pathname);
120
+ }
121
+ let authenticated = false;
122
+ if (customAuthCheck) {
123
+ authenticated = await customAuthCheck(request);
124
+ } else {
125
+ const sessionData = request.cookies.get(sessionCookie);
126
+ authenticated = !!sessionData?.value;
127
+ }
128
+ if (debug) {
129
+ console.log("[AuthMiddleware] Authenticated:", authenticated);
130
+ }
131
+ const isProtectedRoute = protectedRoutes.some(
132
+ (route) => pathname.startsWith(route)
133
+ );
134
+ const isPublicOnlyRoute = publicOnlyRoutes.some(
135
+ (route) => pathname.startsWith(route)
136
+ );
137
+ if (isProtectedRoute && !authenticated) {
138
+ if (debug) {
139
+ console.log("[AuthMiddleware] Redirecting to login");
140
+ }
141
+ const url = request.nextUrl.clone();
142
+ url.pathname = loginPath;
143
+ url.searchParams.set("returnUrl", pathname);
144
+ return NextResponse.redirect(url);
145
+ }
146
+ if (isProtectedRoute && authenticated && tenantConfig) {
147
+ try {
148
+ const sessionData = request.cookies.get(sessionCookie);
149
+ if (sessionData?.value) {
150
+ const account = safeJsonParse(sessionData.value, isValidAccountData);
151
+ if (account) {
152
+ const tenantResult = validateTenantAccess(account, tenantConfig);
153
+ if (!tenantResult.allowed) {
154
+ if (debug) {
155
+ console.log("[AuthMiddleware] Tenant access denied:", tenantResult.reason);
156
+ }
157
+ const url = request.nextUrl.clone();
158
+ url.pathname = tenantDeniedPath;
159
+ url.searchParams.set("reason", tenantResult.reason || "access_denied");
160
+ return NextResponse.redirect(url);
161
+ }
162
+ }
163
+ }
164
+ } catch (error) {
165
+ if (debug) {
166
+ console.warn("[AuthMiddleware] Tenant validation error:", error);
167
+ }
168
+ }
169
+ }
170
+ if (isPublicOnlyRoute && authenticated) {
171
+ if (debug) {
172
+ console.log("[AuthMiddleware] Redirecting to home");
173
+ }
174
+ const returnUrl = request.nextUrl.searchParams.get("returnUrl");
175
+ const url = request.nextUrl.clone();
176
+ url.pathname = returnUrl || redirectAfterLogin;
177
+ url.searchParams.delete("returnUrl");
178
+ return NextResponse.redirect(url);
179
+ }
180
+ const response = NextResponse.next();
181
+ if (authenticated) {
182
+ response.headers.set("x-msal-authenticated", "true");
183
+ try {
184
+ const sessionData = request.cookies.get(sessionCookie);
185
+ if (sessionData?.value) {
186
+ const account = safeJsonParse(sessionData.value, isValidAccountData);
187
+ if (account?.username) {
188
+ response.headers.set("x-msal-username", account.username);
189
+ }
190
+ }
191
+ } catch (error) {
192
+ if (debug) {
193
+ console.warn("[AuthMiddleware] Failed to parse session data");
194
+ }
195
+ }
196
+ }
197
+ return response;
198
+ };
199
+ }
200
+
201
+ export { createAuthMiddleware };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chemmangat/msal-next",
3
- "version": "5.2.0",
3
+ "version": "5.2.1",
4
4
  "description": "Production-ready Microsoft/Azure AD authentication for Next.js App Router. Zero-config setup, TypeScript-first, multi-account support, auto token refresh. The easiest way to add Microsoft login to your Next.js app.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -15,6 +15,11 @@
15
15
  "types": "./dist/server.d.ts",
16
16
  "import": "./dist/server.mjs",
17
17
  "require": "./dist/server.js"
18
+ },
19
+ "./middleware": {
20
+ "types": "./dist/middleware.d.ts",
21
+ "import": "./dist/middleware.mjs",
22
+ "require": "./dist/middleware.js"
18
23
  }
19
24
  },
20
25
  "files": [