@chemmangat/msal-next 3.1.9 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -285,6 +285,112 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
285
285
  declare function getMsalInstance(): PublicClientApplication | null;
286
286
  declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
287
287
 
288
+ /**
289
+ * Zero-Config Protected Routes - Type Definitions
290
+ * v4.0.0 Killer Feature
291
+ */
292
+
293
+ /**
294
+ * Page-level auth configuration
295
+ * Export this from your page to enable protection
296
+ *
297
+ * @example
298
+ * ```tsx
299
+ * // app/dashboard/page.tsx
300
+ * export const auth = { required: true };
301
+ *
302
+ * export default function Dashboard() {
303
+ * return <div>Protected content</div>;
304
+ * }
305
+ * ```
306
+ */
307
+ interface PageAuthConfig {
308
+ /**
309
+ * Whether authentication is required for this page
310
+ * @default false
311
+ */
312
+ required?: boolean;
313
+ /**
314
+ * Required roles for access (checks account.idTokenClaims.roles)
315
+ * User must have at least one of these roles
316
+ *
317
+ * @example
318
+ * ```tsx
319
+ * export const auth = {
320
+ * required: true,
321
+ * roles: ['admin', 'editor']
322
+ * };
323
+ * ```
324
+ */
325
+ roles?: string[];
326
+ /**
327
+ * Custom redirect path when auth fails
328
+ * @default '/login'
329
+ */
330
+ redirectTo?: string;
331
+ /**
332
+ * Custom loading component while checking auth
333
+ */
334
+ loading?: ReactNode;
335
+ /**
336
+ * Custom unauthorized component (shown instead of redirect)
337
+ */
338
+ unauthorized?: ReactNode;
339
+ /**
340
+ * Custom validation function
341
+ * Return true to allow access, false to deny
342
+ *
343
+ * @example
344
+ * ```tsx
345
+ * export const auth = {
346
+ * required: true,
347
+ * validate: (account) => account.username.endsWith('@company.com')
348
+ * };
349
+ * ```
350
+ */
351
+ validate?: (account: any) => boolean | Promise<boolean>;
352
+ }
353
+ /**
354
+ * Global auth configuration for the provider
355
+ */
356
+ interface AuthProtectionConfig {
357
+ /**
358
+ * Default redirect path for unauthenticated users
359
+ * @default '/login'
360
+ */
361
+ defaultRedirectTo?: string;
362
+ /**
363
+ * Default loading component
364
+ */
365
+ defaultLoading?: ReactNode;
366
+ /**
367
+ * Default unauthorized component
368
+ */
369
+ defaultUnauthorized?: ReactNode;
370
+ /**
371
+ * Enable debug logging
372
+ * @default false
373
+ */
374
+ debug?: boolean;
375
+ }
376
+
377
+ interface MSALProviderProps extends MsalAuthProviderProps {
378
+ /**
379
+ * Zero-Config Protected Routes configuration (v4.0.0)
380
+ * @example
381
+ * ```tsx
382
+ * <MSALProvider
383
+ * clientId="..."
384
+ * protection={{
385
+ * defaultRedirectTo: '/login',
386
+ * defaultLoading: <Spinner />,
387
+ * debug: true
388
+ * }}
389
+ * >
390
+ * ```
391
+ */
392
+ protection?: AuthProtectionConfig;
393
+ }
288
394
  /**
289
395
  * Pre-configured MSALProvider component for Next.js App Router layouts.
290
396
  * This component is already marked as 'use client', so you can use it directly
@@ -311,7 +417,7 @@ declare function MsalAuthProvider({ children, loadingComponent, onInitialized, .
311
417
  * }
312
418
  * ```
313
419
  */
314
- declare function MSALProvider({ children, ...props }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
420
+ declare function MSALProvider({ children, protection, ...props }: MSALProviderProps): react_jsx_runtime.JSX.Element;
315
421
 
316
422
  interface MicrosoftSignInButtonProps {
317
423
  /**
@@ -1008,6 +1114,39 @@ declare function isValidScope(scope: string): boolean;
1008
1114
  */
1009
1115
  declare function validateScopes(scopes: string[]): boolean;
1010
1116
 
1117
+ interface ProtectedPageProps {
1118
+ children: ReactNode;
1119
+ config: PageAuthConfig;
1120
+ defaultRedirectTo?: string;
1121
+ defaultLoading?: ReactNode;
1122
+ defaultUnauthorized?: ReactNode;
1123
+ debug?: boolean;
1124
+ }
1125
+ /**
1126
+ * Internal component that wraps pages with auth protection
1127
+ * This is automatically used when you export `auth` from your page
1128
+ */
1129
+ declare function ProtectedPage({ children, config, defaultRedirectTo, defaultLoading, defaultUnauthorized, debug }: ProtectedPageProps): react_jsx_runtime.JSX.Element;
1130
+
1131
+ /**
1132
+ * Higher-order component that adds auth protection to a page
1133
+ *
1134
+ * @example
1135
+ * ```tsx
1136
+ * // Automatic usage (recommended):
1137
+ * export const auth = { required: true };
1138
+ * export default function Dashboard() { ... }
1139
+ *
1140
+ * // Manual usage:
1141
+ * const ProtectedDashboard = withPageAuth(Dashboard, { required: true });
1142
+ * export default ProtectedDashboard;
1143
+ * ```
1144
+ */
1145
+ declare function withPageAuth<P extends object>(Component: ComponentType<P>, authConfig: PageAuthConfig, globalConfig?: AuthProtectionConfig): {
1146
+ (props: P): react_jsx_runtime.JSX.Element;
1147
+ displayName: string;
1148
+ };
1149
+
1011
1150
  interface AuthMiddlewareConfig {
1012
1151
  /**
1013
1152
  * Routes that require authentication
@@ -1085,4 +1224,4 @@ interface ServerSession {
1085
1224
  accessToken?: string;
1086
1225
  }
1087
1226
 
1088
- export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth };
1227
+ export { 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, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth, withPageAuth };
package/dist/index.d.ts CHANGED
@@ -285,6 +285,112 @@ interface MsalAuthProviderProps extends MsalAuthConfig {
285
285
  declare function getMsalInstance(): PublicClientApplication | null;
286
286
  declare function MsalAuthProvider({ children, loadingComponent, onInitialized, ...config }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
287
287
 
288
+ /**
289
+ * Zero-Config Protected Routes - Type Definitions
290
+ * v4.0.0 Killer Feature
291
+ */
292
+
293
+ /**
294
+ * Page-level auth configuration
295
+ * Export this from your page to enable protection
296
+ *
297
+ * @example
298
+ * ```tsx
299
+ * // app/dashboard/page.tsx
300
+ * export const auth = { required: true };
301
+ *
302
+ * export default function Dashboard() {
303
+ * return <div>Protected content</div>;
304
+ * }
305
+ * ```
306
+ */
307
+ interface PageAuthConfig {
308
+ /**
309
+ * Whether authentication is required for this page
310
+ * @default false
311
+ */
312
+ required?: boolean;
313
+ /**
314
+ * Required roles for access (checks account.idTokenClaims.roles)
315
+ * User must have at least one of these roles
316
+ *
317
+ * @example
318
+ * ```tsx
319
+ * export const auth = {
320
+ * required: true,
321
+ * roles: ['admin', 'editor']
322
+ * };
323
+ * ```
324
+ */
325
+ roles?: string[];
326
+ /**
327
+ * Custom redirect path when auth fails
328
+ * @default '/login'
329
+ */
330
+ redirectTo?: string;
331
+ /**
332
+ * Custom loading component while checking auth
333
+ */
334
+ loading?: ReactNode;
335
+ /**
336
+ * Custom unauthorized component (shown instead of redirect)
337
+ */
338
+ unauthorized?: ReactNode;
339
+ /**
340
+ * Custom validation function
341
+ * Return true to allow access, false to deny
342
+ *
343
+ * @example
344
+ * ```tsx
345
+ * export const auth = {
346
+ * required: true,
347
+ * validate: (account) => account.username.endsWith('@company.com')
348
+ * };
349
+ * ```
350
+ */
351
+ validate?: (account: any) => boolean | Promise<boolean>;
352
+ }
353
+ /**
354
+ * Global auth configuration for the provider
355
+ */
356
+ interface AuthProtectionConfig {
357
+ /**
358
+ * Default redirect path for unauthenticated users
359
+ * @default '/login'
360
+ */
361
+ defaultRedirectTo?: string;
362
+ /**
363
+ * Default loading component
364
+ */
365
+ defaultLoading?: ReactNode;
366
+ /**
367
+ * Default unauthorized component
368
+ */
369
+ defaultUnauthorized?: ReactNode;
370
+ /**
371
+ * Enable debug logging
372
+ * @default false
373
+ */
374
+ debug?: boolean;
375
+ }
376
+
377
+ interface MSALProviderProps extends MsalAuthProviderProps {
378
+ /**
379
+ * Zero-Config Protected Routes configuration (v4.0.0)
380
+ * @example
381
+ * ```tsx
382
+ * <MSALProvider
383
+ * clientId="..."
384
+ * protection={{
385
+ * defaultRedirectTo: '/login',
386
+ * defaultLoading: <Spinner />,
387
+ * debug: true
388
+ * }}
389
+ * >
390
+ * ```
391
+ */
392
+ protection?: AuthProtectionConfig;
393
+ }
288
394
  /**
289
395
  * Pre-configured MSALProvider component for Next.js App Router layouts.
290
396
  * This component is already marked as 'use client', so you can use it directly
@@ -311,7 +417,7 @@ declare function MsalAuthProvider({ children, loadingComponent, onInitialized, .
311
417
  * }
312
418
  * ```
313
419
  */
314
- declare function MSALProvider({ children, ...props }: MsalAuthProviderProps): react_jsx_runtime.JSX.Element;
420
+ declare function MSALProvider({ children, protection, ...props }: MSALProviderProps): react_jsx_runtime.JSX.Element;
315
421
 
316
422
  interface MicrosoftSignInButtonProps {
317
423
  /**
@@ -1008,6 +1114,39 @@ declare function isValidScope(scope: string): boolean;
1008
1114
  */
1009
1115
  declare function validateScopes(scopes: string[]): boolean;
1010
1116
 
1117
+ interface ProtectedPageProps {
1118
+ children: ReactNode;
1119
+ config: PageAuthConfig;
1120
+ defaultRedirectTo?: string;
1121
+ defaultLoading?: ReactNode;
1122
+ defaultUnauthorized?: ReactNode;
1123
+ debug?: boolean;
1124
+ }
1125
+ /**
1126
+ * Internal component that wraps pages with auth protection
1127
+ * This is automatically used when you export `auth` from your page
1128
+ */
1129
+ declare function ProtectedPage({ children, config, defaultRedirectTo, defaultLoading, defaultUnauthorized, debug }: ProtectedPageProps): react_jsx_runtime.JSX.Element;
1130
+
1131
+ /**
1132
+ * Higher-order component that adds auth protection to a page
1133
+ *
1134
+ * @example
1135
+ * ```tsx
1136
+ * // Automatic usage (recommended):
1137
+ * export const auth = { required: true };
1138
+ * export default function Dashboard() { ... }
1139
+ *
1140
+ * // Manual usage:
1141
+ * const ProtectedDashboard = withPageAuth(Dashboard, { required: true });
1142
+ * export default ProtectedDashboard;
1143
+ * ```
1144
+ */
1145
+ declare function withPageAuth<P extends object>(Component: ComponentType<P>, authConfig: PageAuthConfig, globalConfig?: AuthProtectionConfig): {
1146
+ (props: P): react_jsx_runtime.JSX.Element;
1147
+ displayName: string;
1148
+ };
1149
+
1011
1150
  interface AuthMiddlewareConfig {
1012
1151
  /**
1013
1152
  * Routes that require authentication
@@ -1085,4 +1224,4 @@ interface ServerSession {
1085
1224
  accessToken?: string;
1086
1225
  }
1087
1226
 
1088
- export { AuthGuard, type AuthGuardProps, type AuthMiddlewareConfig, AuthStatus, type AuthStatusProps, type CustomTokenClaims, type DebugLoggerConfig, ErrorBoundary, type ErrorBoundaryProps, type GraphApiOptions, MSALProvider, MicrosoftSignInButton, type MicrosoftSignInButtonProps, type MsalAuthConfig, MsalAuthProvider, type MsalAuthProviderProps, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth };
1227
+ export { 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, type PageAuthConfig, ProtectedPage, type RetryConfig, type ServerSession, SignOutButton, type SignOutButtonProps, type UseGraphApiReturn, type UseMsalAuthReturn, type UseRolesReturn, type UseUserProfileReturn, UserAvatar, type UserAvatarProps, type UserProfile, type ValidatedAccountData, type WithAuthOptions, createAuthMiddleware, createMsalConfig, createRetryWrapper, createScopedLogger, getDebugLogger, getMsalInstance, isValidAccountData, isValidRedirectUri, isValidScope, retryWithBackoff, safeJsonParse, sanitizeError, useGraphApi, useMsalAuth, useRoles, useUserProfile, validateScopes, withAuth, withPageAuth };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var msalReact=require('@azure/msal-react'),msalBrowser=require('@azure/msal-browser'),react=require('react'),jsxRuntime=require('react/jsx-runtime'),server=require('next/server');function q(r,e){try{let t=JSON.parse(r);return e(t)?t:(console.warn("[Validation] JSON validation failed"),null)}catch(t){return console.error("[Validation] JSON parse error:",t),null}}function _(r){return typeof r=="object"&&r!==null&&typeof r.homeAccountId=="string"&&r.homeAccountId.length>0&&typeof r.username=="string"&&r.username.length>0&&(r.name===void 0||typeof r.name=="string")}function v(r){return r instanceof Error?r.message.replace(/[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g,"[TOKEN_REDACTED]").replace(/[a-f0-9]{32,}/gi,"[SECRET_REDACTED]").replace(/Bearer\s+[^\s]+/gi,"Bearer [REDACTED]"):"An unexpected error occurred"}function G(r,e){try{let t=new URL(r);return e.some(o=>{let i=new URL(o);return t.origin===i.origin})}catch{return false}}function ne(r){return /^[a-zA-Z0-9._-]+$/.test(r)}function Ae(r){return Array.isArray(r)&&r.every(ne)}function H(r){if(r.msalConfig)return r.msalConfig;let{clientId:e,tenantId:t,authorityType:o="common",redirectUri:i,postLogoutRedirectUri:a,cacheLocation:p="sessionStorage",storeAuthStateInCookie:u=false,navigateToLoginRequestUrl:c=false,enableLogging:n=false,loggerCallback:h,allowedRedirectUris:g}=r;if(!e)throw new Error("@chemmangat/msal-next: clientId is required");let l=()=>{if(o==="tenant"){if(!t)throw new Error('@chemmangat/msal-next: tenantId is required when authorityType is "tenant"');return `https://login.microsoftonline.com/${t}`}return `https://login.microsoftonline.com/${o}`},s=typeof window<"u"?window.location.origin:"http://localhost:3000",m=i||s;if(g&&g.length>0){if(!G(m,g))throw new Error(`@chemmangat/msal-next: redirectUri "${m}" is not in the allowed list`);let d=a||m;if(!G(d,g))throw new Error(`@chemmangat/msal-next: postLogoutRedirectUri "${d}" is not in the allowed list`)}return {auth:{clientId:e,authority:l(),redirectUri:m,postLogoutRedirectUri:a||m,navigateToLoginRequestUrl:c},cache:{cacheLocation:p,storeAuthStateInCookie:u},system:{loggerOptions:{loggerCallback:h||((d,y,R)=>{if(!(R||!n))switch(d){case msalBrowser.LogLevel.Error:console.error("[MSAL]",y);break;case msalBrowser.LogLevel.Warning:console.warn("[MSAL]",y);break;case msalBrowser.LogLevel.Info:console.info("[MSAL]",y);break;case msalBrowser.LogLevel.Verbose:console.debug("[MSAL]",y);break}}),logLevel:n?msalBrowser.LogLevel.Verbose:msalBrowser.LogLevel.Error}}}}var se=null;function Pe(){return se}function V({children:r,loadingComponent:e,onInitialized:t,...o}){let[i,a]=react.useState(null),p=react.useRef(null);return react.useEffect(()=>{if(typeof window>"u"||p.current)return;(async()=>{try{let c=H(o),n=new msalBrowser.PublicClientApplication(c);await n.initialize();try{let l=await n.handleRedirectPromise();l&&(o.enableLogging&&console.log("[MSAL] Redirect authentication successful"),l.account&&n.setActiveAccount(l.account),window.location.hash&&window.history.replaceState(null,"",window.location.pathname+window.location.search));}catch(l){l?.errorCode==="no_token_request_cache_error"?o.enableLogging&&console.log("[MSAL] No pending redirect found (this is normal)"):l?.errorCode==="user_cancelled"?o.enableLogging&&console.log("[MSAL] User cancelled authentication"):console.error("[MSAL] Redirect handling error:",l),window.location.hash&&(window.location.hash.includes("code=")||window.location.hash.includes("error="))&&window.history.replaceState(null,"",window.location.pathname+window.location.search);}let h=n.getAllAccounts();h.length>0&&!n.getActiveAccount()&&n.setActiveAccount(h[0]);let g=o.enableLogging||!1;n.addEventCallback(l=>{if(l.eventType===msalBrowser.EventType.LOGIN_SUCCESS){let s=l.payload;s?.account&&n.setActiveAccount(s.account),g&&console.log("[MSAL] Login successful:",s.account?.username);}if(l.eventType===msalBrowser.EventType.LOGIN_FAILURE&&console.error("[MSAL] Login failed:",l.error),l.eventType===msalBrowser.EventType.LOGOUT_SUCCESS&&(n.setActiveAccount(null),g&&console.log("[MSAL] Logout successful")),l.eventType===msalBrowser.EventType.ACQUIRE_TOKEN_SUCCESS){let s=l.payload;s?.account&&!n.getActiveAccount()&&n.setActiveAccount(s.account);}l.eventType===msalBrowser.EventType.ACQUIRE_TOKEN_FAILURE&&g&&console.error("[MSAL] Token acquisition failed:",l.error);}),p.current=n,se=n,a(n),t&&t(n);}catch(c){throw console.error("[MSAL] Initialization failed:",c),c}})();},[]),typeof window>"u"?jsxRuntime.jsx(jsxRuntime.Fragment,{children:e||jsxRuntime.jsx("div",{children:"Loading authentication..."})}):i?jsxRuntime.jsx(msalReact.MsalProvider,{instance:i,children:r}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:e||jsxRuntime.jsx("div",{children:"Loading authentication..."})})}function Se({children:r,...e}){return jsxRuntime.jsx(V,{...e,children:r})}var W=new Map;function A(r=["User.Read"]){let{instance:e,accounts:t,inProgress:o}=msalReact.useMsal(),i=msalReact.useAccount(t[0]||null),a=react.useMemo(()=>t.length>0,[t]),p=react.useCallback(async(l=r)=>{if(o!==msalBrowser.InteractionStatus.None){console.warn("[MSAL] Interaction already in progress");return}try{let s={scopes:l,prompt:"select_account"};await e.loginRedirect(s);}catch(s){if(s?.errorCode==="user_cancelled"){console.log("[MSAL] User cancelled login");return}throw console.error("[MSAL] Login redirect failed:",s),s}},[e,r,o]),u=react.useCallback(async()=>{try{await e.logoutRedirect({account:i||void 0});}catch(l){throw console.error("[MSAL] Logout redirect failed:",l),l}},[e,i]),c=react.useCallback(async(l=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:l,account:i,forceRefresh:!1};return (await e.acquireTokenSilent(s)).accessToken}catch(s){throw console.error("[MSAL] Silent token acquisition failed:",s),s}},[e,i,r]),n=react.useCallback(async(l=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:l,account:i};await e.acquireTokenRedirect(s);}catch(s){throw console.error("[MSAL] Token redirect acquisition failed:",s),s}},[e,i,r]),h=react.useCallback(async(l=r)=>{let s=`${i?.homeAccountId||"anonymous"}-${l.sort().join(",")}`,m=W.get(s);if(m)return m;let f=(async()=>{try{return await c(l)}catch{throw console.warn("[MSAL] Silent token acquisition failed, falling back to redirect"),await n(l),new Error("[MSAL] Redirecting for token acquisition")}finally{W.delete(s);}})();return W.set(s,f),f},[c,n,r,i]),g=react.useCallback(async()=>{e.setActiveAccount(null),await e.clearCache();},[e]);return {account:i,accounts:t,isAuthenticated:a,inProgress:o!==msalBrowser.InteractionStatus.None,loginRedirect:p,logoutRedirect:u,acquireToken:h,acquireTokenSilent:c,acquireTokenRedirect:n,clearSession:g}}function Ue({text:r="Sign in with Microsoft",variant:e="dark",size:t="medium",scopes:o,className:i="",style:a,onSuccess:p,onError:u}){let{loginRedirect:c,inProgress:n}=A(),[h,g]=react.useState(false),l=async()=>{g(true);try{await c(o),p?.();}catch(y){u?.(y);}finally{setTimeout(()=>g(false),500);}},s={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},m={dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}},f=n||h,d={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:f?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:f?.6:1,...m[e],...s[t],...a};return jsxRuntime.jsxs("button",{onClick:l,disabled:f,className:i,style:d,"aria-label":r,children:[jsxRuntime.jsx(ke,{}),jsxRuntime.jsx("span",{children:r})]})}function ke(){return jsxRuntime.jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsxRuntime.jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsxRuntime.jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsxRuntime.jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsxRuntime.jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function Fe({text:r="Sign out",variant:e="dark",size:t="medium",className:o="",style:i,onSuccess:a,onError:p}){let{logoutRedirect:u,inProgress:c}=A(),n=async()=>{try{await u(),a?.();}catch(s){p?.(s);}},h={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},l={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:c?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:c?.6:1,...{dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}}[e],...h[t],...i};return jsxRuntime.jsxs("button",{onClick:n,disabled:c,className:o,style:l,"aria-label":r,children:[jsxRuntime.jsx(Ne,{}),jsxRuntime.jsx("span",{children:r})]})}function Ne(){return jsxRuntime.jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsxRuntime.jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsxRuntime.jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsxRuntime.jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsxRuntime.jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function k(){let{acquireToken:r}=A(),e=react.useCallback(async(u,c={})=>{let{scopes:n=["User.Read"],version:h="v1.0",debug:g=false,...l}=c;try{let s=await r(n),m=`https://graph.microsoft.com/${h}`,f=u.startsWith("http")?u:`${m}${u.startsWith("/")?u:`/${u}`}`;g&&console.log("[GraphAPI] Request:",{url:f,method:l.method||"GET"});let d=await fetch(f,{...l,headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json",...l.headers}});if(!d.ok){let R=await d.text(),L=`Graph API error (${d.status}): ${R}`;throw new Error(L)}if(d.status===204||d.headers.get("content-length")==="0")return null;let y=await d.json();return g&&console.log("[GraphAPI] Response:",y),y}catch(s){let m=v(s);throw console.error("[GraphAPI] Request failed:",m),new Error(m)}},[r]),t=react.useCallback((u,c={})=>e(u,{...c,method:"GET"}),[e]),o=react.useCallback((u,c,n={})=>e(u,{...n,method:"POST",body:c?JSON.stringify(c):void 0}),[e]),i=react.useCallback((u,c,n={})=>e(u,{...n,method:"PUT",body:c?JSON.stringify(c):void 0}),[e]),a=react.useCallback((u,c,n={})=>e(u,{...n,method:"PATCH",body:c?JSON.stringify(c):void 0}),[e]),p=react.useCallback((u,c={})=>e(u,{...c,method:"DELETE"}),[e]);return {get:t,post:o,put:i,patch:a,delete:p,request:e}}var x=new Map,Ie=300*1e3,pe=100;function Oe(){if(x.size>pe){let r=Array.from(x.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,x.size-pe).forEach(([t])=>{let o=x.get(t);o?.data.photo&&URL.revokeObjectURL(o.data.photo),x.delete(t);});}}function J(){let{isAuthenticated:r,account:e}=A(),t=k(),[o,i]=react.useState(null),[a,p]=react.useState(false),[u,c]=react.useState(null),n=react.useCallback(async()=>{if(!r||!e){i(null);return}let g=e.homeAccountId,l=x.get(g);if(l&&Date.now()-l.timestamp<Ie){i(l.data);return}p(true),c(null);try{let s=await t.get("/me",{scopes:["User.Read"]}),m;try{let d=await t.get("/me/photo/$value",{scopes:["User.Read"],headers:{"Content-Type":"image/jpeg"}});d&&(m=URL.createObjectURL(d));}catch{console.debug("[UserProfile] Photo not available");}let f={id:s.id,displayName:s.displayName,givenName:s.givenName,surname:s.surname,userPrincipalName:s.userPrincipalName,mail:s.mail,jobTitle:s.jobTitle,officeLocation:s.officeLocation,mobilePhone:s.mobilePhone,businessPhones:s.businessPhones,photo:m};x.set(g,{data:f,timestamp:Date.now()}),Oe(),i(f);}catch(s){let f=v(s),d=new Error(f);c(d),console.error("[UserProfile] Failed to fetch profile:",f);}finally{p(false);}},[r,e,t]),h=react.useCallback(()=>{if(e){let g=x.get(e.homeAccountId);g?.data.photo&&URL.revokeObjectURL(g.data.photo),x.delete(e.homeAccountId);}o?.photo&&URL.revokeObjectURL(o.photo),i(null);},[e,o]);return react.useEffect(()=>(n(),()=>{o?.photo&&URL.revokeObjectURL(o.photo);}),[n]),react.useEffect(()=>()=>{o?.photo&&URL.revokeObjectURL(o.photo);},[o?.photo]),{profile:o,loading:a,error:u,refetch:n,clearCache:h}}function Ge({size:r=40,className:e="",style:t,showTooltip:o=true,fallbackImage:i}){let{profile:a,loading:p}=J(),[u,c]=react.useState(null),[n,h]=react.useState(false);react.useEffect(()=>{a?.photo&&c(a.photo);},[a?.photo]);let g=()=>{if(!a)return "?";let{givenName:m,surname:f,displayName:d}=a;if(m&&f)return `${m[0]}${f[0]}`.toUpperCase();if(d){let y=d.split(" ");return y.length>=2?`${y[0][0]}${y[y.length-1][0]}`.toUpperCase():d.substring(0,2).toUpperCase()}return "?"},l={width:`${r}px`,height:`${r}px`,borderRadius:"50%",display:"inline-flex",alignItems:"center",justifyContent:"center",fontSize:`${r*.4}px`,fontWeight:600,fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',backgroundColor:"#0078D4",color:"#FFFFFF",overflow:"hidden",userSelect:"none",...t},s=a?.displayName||"User";return p?jsxRuntime.jsx("div",{className:e,style:{...l,backgroundColor:"#E1E1E1"},"aria-label":"Loading user avatar",children:jsxRuntime.jsx("span",{style:{fontSize:`${r*.3}px`},children:"..."})}):u&&!n?jsxRuntime.jsx("div",{className:e,style:l,title:o?s:void 0,"aria-label":`${s} avatar`,children:jsxRuntime.jsx("img",{src:u,alt:s,style:{width:"100%",height:"100%",objectFit:"cover"},onError:()=>{h(true),i&&c(i);}})}):jsxRuntime.jsx("div",{className:e,style:l,title:o?s:void 0,"aria-label":`${s} avatar`,children:g()})}function $e({className:r="",style:e,showDetails:t=false,renderLoading:o,renderAuthenticated:i,renderUnauthenticated:a}){let{isAuthenticated:p,inProgress:u,account:c}=A(),n={display:"inline-flex",alignItems:"center",gap:"8px",padding:"8px 12px",borderRadius:"4px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontSize:"14px",fontWeight:500,...e};if(u)return o?jsxRuntime.jsx(jsxRuntime.Fragment,{children:o()}):jsxRuntime.jsxs("div",{className:r,style:{...n,backgroundColor:"#FFF4CE",color:"#8A6D3B"},role:"status","aria-live":"polite",children:[jsxRuntime.jsx(K,{color:"#FFA500"}),jsxRuntime.jsx("span",{children:"Loading..."})]});if(p){let h=c?.username||c?.name||"User";return i?jsxRuntime.jsx(jsxRuntime.Fragment,{children:i(h)}):jsxRuntime.jsxs("div",{className:r,style:{...n,backgroundColor:"#D4EDDA",color:"#155724"},role:"status","aria-live":"polite",children:[jsxRuntime.jsx(K,{color:"#28A745"}),jsxRuntime.jsx("span",{children:t?`Authenticated as ${h}`:"Authenticated"})]})}return a?jsxRuntime.jsx(jsxRuntime.Fragment,{children:a()}):jsxRuntime.jsxs("div",{className:r,style:{...n,backgroundColor:"#F8D7DA",color:"#721C24"},role:"status","aria-live":"polite",children:[jsxRuntime.jsx(K,{color:"#DC3545"}),jsxRuntime.jsx("span",{children:"Not authenticated"})]})}function K({color:r}){return jsxRuntime.jsx("svg",{width:"8",height:"8",viewBox:"0 0 8 8",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsxRuntime.jsx("circle",{cx:"4",cy:"4",r:"4",fill:r})})}function Y({children:r,loadingComponent:e,fallbackComponent:t,scopes:o,onAuthRequired:i}){let{isAuthenticated:a,inProgress:p,loginRedirect:u}=A();return react.useEffect(()=>{!a&&!p&&(i?.(),(async()=>{try{await u(o);}catch(n){console.error("[AuthGuard] Authentication failed:",n);}})());},[a,p,o,u,i]),p?jsxRuntime.jsx(jsxRuntime.Fragment,{children:e||jsxRuntime.jsx("div",{children:"Authenticating..."})}):a?jsxRuntime.jsx(jsxRuntime.Fragment,{children:r}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:t||jsxRuntime.jsx("div",{children:"Redirecting to login..."})})}var re=class extends react.Component{constructor(t){super(t);this.reset=()=>{this.setState({hasError:false,error:null});};this.state={hasError:false,error:null};}static getDerivedStateFromError(t){return {hasError:true,error:t}}componentDidCatch(t,o){let{onError:i,debug:a}=this.props;a&&(console.error("[ErrorBoundary] Caught error:",t),console.error("[ErrorBoundary] Error info:",o)),i?.(t,o);}render(){let{hasError:t,error:o}=this.state,{children:i,fallback:a}=this.props;return t&&o?a?a(o,this.reset):jsxRuntime.jsxs("div",{style:{padding:"20px",margin:"20px",border:"1px solid #DC3545",borderRadius:"4px",backgroundColor:"#F8D7DA",color:"#721C24",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif'},children:[jsxRuntime.jsx("h2",{style:{margin:"0 0 10px 0",fontSize:"18px"},children:"Authentication Error"}),jsxRuntime.jsx("p",{style:{margin:"0 0 10px 0"},children:o.message}),jsxRuntime.jsx("button",{onClick:this.reset,style:{padding:"8px 16px",backgroundColor:"#DC3545",color:"#FFFFFF",border:"none",borderRadius:"4px",cursor:"pointer",fontSize:"14px",fontWeight:600},children:"Try Again"})]}):i}};var w=new Map,He=300*1e3,fe=100;function Ve(r){r?w.delete(r):w.clear();}function We(){if(w.size>fe){let r=Array.from(w.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,w.size-fe).forEach(([t])=>w.delete(t));}}function je(){let{isAuthenticated:r,account:e}=A(),t=k(),[o,i]=react.useState([]),[a,p]=react.useState([]),[u,c]=react.useState(false),[n,h]=react.useState(null),g=react.useCallback(async()=>{if(!r||!e){i([]),p([]);return}let d=e.homeAccountId,y=w.get(d);if(y&&Date.now()-y.timestamp<He){i(y.roles),p(y.groups);return}c(true),h(null);try{let L=e.idTokenClaims?.roles||[],D=(await t.get("/me/memberOf",{scopes:["User.Read","Directory.Read.All"]})).value.map(oe=>oe.id);w.set(d,{roles:L,groups:D,timestamp:Date.now()}),We(),i(L),p(D);}catch(R){let B=v(R),D=new Error(B);h(D),console.error("[Roles] Failed to fetch roles/groups:",B);let ye=e.idTokenClaims?.roles||[];i(ye);}finally{c(false);}},[r,e,t]),l=react.useCallback(d=>o.includes(d),[o]),s=react.useCallback(d=>a.includes(d),[a]),m=react.useCallback(d=>d.some(y=>o.includes(y)),[o]),f=react.useCallback(d=>d.every(y=>o.includes(y)),[o]);return react.useEffect(()=>(g(),()=>{e&&Ve(e.homeAccountId);}),[g,e]),{roles:o,groups:a,loading:u,error:n,hasRole:l,hasGroup:s,hasAnyRole:m,hasAllRoles:f,refetch:g}}function Je(r,e={}){let{displayName:t,...o}=e,i=a=>jsxRuntime.jsx(Y,{...o,children:jsxRuntime.jsx(r,{...a})});return i.displayName=t||`withAuth(${r.displayName||r.name||"Component"})`,i}async function me(r,e={}){let{maxRetries:t=3,initialDelay:o=1e3,maxDelay:i=1e4,backoffMultiplier:a=2,debug:p=false}=e,u,c=o;for(let n=0;n<=t;n++)try{return p&&n>0&&console.log(`[TokenRetry] Attempt ${n+1}/${t+1}`),await r()}catch(h){if(u=h,n===t){p&&console.error("[TokenRetry] All retry attempts failed");break}if(!Ke(h))throw p&&console.log("[TokenRetry] Non-retryable error, aborting"),h;p&&console.warn(`[TokenRetry] Attempt ${n+1} failed, retrying in ${c}ms...`),await Ze(c),c=Math.min(c*a,i);}throw u}function Ke(r){let e=r.message.toLowerCase();return !!(e.includes("network")||e.includes("timeout")||e.includes("fetch")||e.includes("connection")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("429")||e.includes("rate limit")||e.includes("token")&&e.includes("expired"))}function Ze(r){return new Promise(e=>setTimeout(e,r))}function Qe(r,e={}){return (...t)=>me(()=>r(...t),e)}var z=class{constructor(e={}){this.logHistory=[];this.performanceTimings=new Map;this.config={enabled:e.enabled??false,prefix:e.prefix??"[MSAL-Next]",showTimestamp:e.showTimestamp??true,level:e.level??"info",enablePerformance:e.enablePerformance??false,enableNetworkLogs:e.enableNetworkLogs??false,maxHistorySize:e.maxHistorySize??100};}shouldLog(e){if(!this.config.enabled)return false;let t=["error","warn","info","debug"],o=t.indexOf(this.config.level);return t.indexOf(e)<=o}formatMessage(e,t,o){let i=this.config.showTimestamp?`[${new Date().toISOString()}]`:"",a=this.config.prefix,p=`[${e.toUpperCase()}]`,u=`${i} ${a} ${p} ${t}`;return o!==void 0&&(u+=`
2
- `+JSON.stringify(o,null,2)),u}addToHistory(e,t,o){this.logHistory.length>=this.config.maxHistorySize&&this.logHistory.shift(),this.logHistory.push({timestamp:Date.now(),level:e,message:t,data:o});}error(e,t){this.shouldLog("error")&&(console.error(this.formatMessage("error",e,t)),this.addToHistory("error",e,t));}warn(e,t){this.shouldLog("warn")&&(console.warn(this.formatMessage("warn",e,t)),this.addToHistory("warn",e,t));}info(e,t){this.shouldLog("info")&&(console.info(this.formatMessage("info",e,t)),this.addToHistory("info",e,t));}debug(e,t){this.shouldLog("debug")&&(console.debug(this.formatMessage("debug",e,t)),this.addToHistory("debug",e,t));}group(e){this.config.enabled&&console.group(`${this.config.prefix} ${e}`);}groupEnd(){this.config.enabled&&console.groupEnd();}startTiming(e){this.config.enablePerformance&&(this.performanceTimings.set(e,{operation:e,startTime:performance.now()}),this.debug(`\u23F1\uFE0F Started: ${e}`));}endTiming(e){if(this.config.enablePerformance){let t=this.performanceTimings.get(e);if(t)return t.endTime=performance.now(),t.duration=t.endTime-t.startTime,this.info(`\u23F1\uFE0F Completed: ${e} (${t.duration.toFixed(2)}ms)`),t.duration}}logRequest(e,t,o){this.config.enableNetworkLogs&&this.debug(`\u{1F310} ${e} ${t}`,o);}logResponse(e,t,o,i){if(this.config.enableNetworkLogs){let a=o>=200&&o<300?"\u2705":"\u274C";this.debug(`${a} ${e} ${t} - ${o}`,i);}}getHistory(){return [...this.logHistory]}getPerformanceTimings(){return Array.from(this.performanceTimings.values())}clearHistory(){this.logHistory=[];}clearTimings(){this.performanceTimings.clear();}exportLogs(){return JSON.stringify({config:this.config,history:this.logHistory,performanceTimings:Array.from(this.performanceTimings.values()),exportedAt:new Date().toISOString()},null,2)}downloadLogs(e="msal-next-debug-logs.json"){if(typeof window>"u")return;let t=this.exportLogs(),o=new Blob([t],{type:"application/json"}),i=URL.createObjectURL(o),a=document.createElement("a");a.href=i,a.download=e,a.click(),URL.revokeObjectURL(i);}setEnabled(e){this.config.enabled=e;}setLevel(e){e&&(this.config.level=e);}},O=null;function Xe(r){return O?r&&(r.enabled!==void 0&&O.setEnabled(r.enabled),r.level&&O.setLevel(r.level)):O=new z(r),O}function Ye(r,e){return new z({...e,prefix:`[MSAL-Next:${r}]`})}function er(r={}){let{protectedRoutes:e=[],publicOnlyRoutes:t=[],loginPath:o="/login",redirectAfterLogin:i="/",sessionCookie:a="msal.account",isAuthenticated:p,debug:u=false}=r;return async function(n){let{pathname:h}=n.nextUrl;u&&console.log("[AuthMiddleware] Processing:",h);let g=false;p?g=await p(n):g=!!n.cookies.get(a)?.value,u&&console.log("[AuthMiddleware] Authenticated:",g);let l=e.some(f=>h.startsWith(f)),s=t.some(f=>h.startsWith(f));if(l&&!g){u&&console.log("[AuthMiddleware] Redirecting to login");let f=n.nextUrl.clone();return f.pathname=o,f.searchParams.set("returnUrl",h),server.NextResponse.redirect(f)}if(s&&g){u&&console.log("[AuthMiddleware] Redirecting to home");let f=n.nextUrl.searchParams.get("returnUrl"),d=n.nextUrl.clone();return d.pathname=f||i,d.searchParams.delete("returnUrl"),server.NextResponse.redirect(d)}let m=server.NextResponse.next();if(g){m.headers.set("x-msal-authenticated","true");try{let f=n.cookies.get(a);if(f?.value){let d=q(f.value,_);d?.username&&m.headers.set("x-msal-username",d.username);}}catch{u&&console.warn("[AuthMiddleware] Failed to parse session data");}}return m}}Object.defineProperty(exports,"useAccount",{enumerable:true,get:function(){return msalReact.useAccount}});Object.defineProperty(exports,"useIsAuthenticated",{enumerable:true,get:function(){return msalReact.useIsAuthenticated}});Object.defineProperty(exports,"useMsal",{enumerable:true,get:function(){return msalReact.useMsal}});exports.AuthGuard=Y;exports.AuthStatus=$e;exports.ErrorBoundary=re;exports.MSALProvider=Se;exports.MicrosoftSignInButton=Ue;exports.MsalAuthProvider=V;exports.SignOutButton=Fe;exports.UserAvatar=Ge;exports.createAuthMiddleware=er;exports.createMsalConfig=H;exports.createRetryWrapper=Qe;exports.createScopedLogger=Ye;exports.getDebugLogger=Xe;exports.getMsalInstance=Pe;exports.isValidAccountData=_;exports.isValidRedirectUri=G;exports.isValidScope=ne;exports.retryWithBackoff=me;exports.safeJsonParse=q;exports.sanitizeError=v;exports.useGraphApi=k;exports.useMsalAuth=A;exports.useRoles=je;exports.useUserProfile=J;exports.validateScopes=Ae;exports.withAuth=Je;
1
+ 'use strict';var msalReact=require('@azure/msal-react'),msalBrowser=require('@azure/msal-browser'),react=require('react'),jsxRuntime=require('react/jsx-runtime'),navigation=require('next/navigation'),server=require('next/server');function H(r,e){try{let t=JSON.parse(r);return e(t)?t:(console.warn("[Validation] JSON validation failed"),null)}catch(t){return console.error("[Validation] JSON parse error:",t),null}}function W(r){return typeof r=="object"&&r!==null&&typeof r.homeAccountId=="string"&&r.homeAccountId.length>0&&typeof r.username=="string"&&r.username.length>0&&(r.name===void 0||typeof r.name=="string")}function w(r){return r instanceof Error?r.message.replace(/[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g,"[TOKEN_REDACTED]").replace(/[a-f0-9]{32,}/gi,"[SECRET_REDACTED]").replace(/Bearer\s+[^\s]+/gi,"Bearer [REDACTED]"):"An unexpected error occurred"}function z(r,e){try{let t=new URL(r);return e.some(o=>{let i=new URL(o);return t.origin===i.origin})}catch{return false}}function ae(r){return /^[a-zA-Z0-9._-]+$/.test(r)}function Ce(r){return Array.isArray(r)&&r.every(ae)}function j(r){if(r.msalConfig)return r.msalConfig;let{clientId:e,tenantId:t,authorityType:o="common",redirectUri:i,postLogoutRedirectUri:a,cacheLocation:g="sessionStorage",storeAuthStateInCookie:u=false,navigateToLoginRequestUrl:l=false,enableLogging:n=false,loggerCallback:h,allowedRedirectUris:f}=r;if(!e)throw new Error("@chemmangat/msal-next: clientId is required");let c=()=>{if(o==="tenant"){if(!t)throw new Error('@chemmangat/msal-next: tenantId is required when authorityType is "tenant"');return `https://login.microsoftonline.com/${t}`}return `https://login.microsoftonline.com/${o}`},s=typeof window<"u"?window.location.origin:"http://localhost:3000",m=i||s;if(f&&f.length>0){if(!z(m,f))throw new Error(`@chemmangat/msal-next: redirectUri "${m}" is not in the allowed list`);let d=a||m;if(!z(d,f))throw new Error(`@chemmangat/msal-next: postLogoutRedirectUri "${d}" is not in the allowed list`)}return {auth:{clientId:e,authority:c(),redirectUri:m,postLogoutRedirectUri:a||m,navigateToLoginRequestUrl:l},cache:{cacheLocation:g,storeAuthStateInCookie:u},system:{loggerOptions:{loggerCallback:h||((d,y,R)=>{if(!(R||!n))switch(d){case msalBrowser.LogLevel.Error:console.error("[MSAL]",y);break;case msalBrowser.LogLevel.Warning:console.warn("[MSAL]",y);break;case msalBrowser.LogLevel.Info:console.info("[MSAL]",y);break;case msalBrowser.LogLevel.Verbose:console.debug("[MSAL]",y);break}}),logLevel:n?msalBrowser.LogLevel.Verbose:msalBrowser.LogLevel.Error}}}}var ce=null;function Ue(){return ce}function J({children:r,loadingComponent:e,onInitialized:t,...o}){let[i,a]=react.useState(null),g=react.useRef(null);return react.useEffect(()=>{if(typeof window>"u"||g.current)return;(async()=>{try{let l=j(o),n=new msalBrowser.PublicClientApplication(l);await n.initialize();try{let c=await n.handleRedirectPromise();c&&(o.enableLogging&&console.log("[MSAL] Redirect authentication successful"),c.account&&n.setActiveAccount(c.account),window.location.hash&&window.history.replaceState(null,"",window.location.pathname+window.location.search));}catch(c){c?.errorCode==="no_token_request_cache_error"?o.enableLogging&&console.log("[MSAL] No pending redirect found (this is normal)"):c?.errorCode==="user_cancelled"?o.enableLogging&&console.log("[MSAL] User cancelled authentication"):console.error("[MSAL] Redirect handling error:",c),window.location.hash&&(window.location.hash.includes("code=")||window.location.hash.includes("error="))&&window.history.replaceState(null,"",window.location.pathname+window.location.search);}let h=n.getAllAccounts();h.length>0&&!n.getActiveAccount()&&n.setActiveAccount(h[0]);let f=o.enableLogging||!1;n.addEventCallback(c=>{if(c.eventType===msalBrowser.EventType.LOGIN_SUCCESS){let s=c.payload;s?.account&&n.setActiveAccount(s.account),f&&console.log("[MSAL] Login successful:",s.account?.username);}if(c.eventType===msalBrowser.EventType.LOGIN_FAILURE&&console.error("[MSAL] Login failed:",c.error),c.eventType===msalBrowser.EventType.LOGOUT_SUCCESS&&(n.setActiveAccount(null),f&&console.log("[MSAL] Logout successful")),c.eventType===msalBrowser.EventType.ACQUIRE_TOKEN_SUCCESS){let s=c.payload;s?.account&&!n.getActiveAccount()&&n.setActiveAccount(s.account);}c.eventType===msalBrowser.EventType.ACQUIRE_TOKEN_FAILURE&&f&&console.error("[MSAL] Token acquisition failed:",c.error);}),g.current=n,ce=n,a(n),t&&t(n);}catch(l){throw console.error("[MSAL] Initialization failed:",l),l}})();},[]),typeof window>"u"?jsxRuntime.jsx(jsxRuntime.Fragment,{children:e||jsxRuntime.jsx("div",{children:"Loading authentication..."})}):i?jsxRuntime.jsx(msalReact.MsalProvider,{instance:i,children:r}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:e||jsxRuntime.jsx("div",{children:"Loading authentication..."})})}var Ne=react.createContext(void 0);function Fe({children:r,protection:e,...t}){return jsxRuntime.jsx(Ne.Provider,{value:e,children:jsxRuntime.jsx(J,{...t,children:r})})}var K=new Map;function A(r=["User.Read"]){let{instance:e,accounts:t,inProgress:o}=msalReact.useMsal(),i=msalReact.useAccount(t[0]||null),a=react.useMemo(()=>t.length>0,[t]),g=react.useCallback(async(c=r)=>{if(o!==msalBrowser.InteractionStatus.None){console.warn("[MSAL] Interaction already in progress");return}try{let s={scopes:c,prompt:"select_account"};await e.loginRedirect(s);}catch(s){if(s?.errorCode==="user_cancelled"){console.log("[MSAL] User cancelled login");return}throw console.error("[MSAL] Login redirect failed:",s),s}},[e,r,o]),u=react.useCallback(async()=>{try{await e.logoutRedirect({account:i||void 0});}catch(c){throw console.error("[MSAL] Logout redirect failed:",c),c}},[e,i]),l=react.useCallback(async(c=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:c,account:i,forceRefresh:!1};return (await e.acquireTokenSilent(s)).accessToken}catch(s){throw console.error("[MSAL] Silent token acquisition failed:",s),s}},[e,i,r]),n=react.useCallback(async(c=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:c,account:i};await e.acquireTokenRedirect(s);}catch(s){throw console.error("[MSAL] Token redirect acquisition failed:",s),s}},[e,i,r]),h=react.useCallback(async(c=r)=>{let s=`${i?.homeAccountId||"anonymous"}-${c.sort().join(",")}`,m=K.get(s);if(m)return m;let p=(async()=>{try{return await l(c)}catch{throw console.warn("[MSAL] Silent token acquisition failed, falling back to redirect"),await n(c),new Error("[MSAL] Redirecting for token acquisition")}finally{K.delete(s);}})();return K.set(s,p),p},[l,n,r,i]),f=react.useCallback(async()=>{e.setActiveAccount(null),await e.clearCache();},[e]);return {account:i,accounts:t,isAuthenticated:a,inProgress:o!==msalBrowser.InteractionStatus.None,loginRedirect:g,logoutRedirect:u,acquireToken:h,acquireTokenSilent:l,acquireTokenRedirect:n,clearSession:f}}function $e({text:r="Sign in with Microsoft",variant:e="dark",size:t="medium",scopes:o,className:i="",style:a,onSuccess:g,onError:u}){let{loginRedirect:l,inProgress:n}=A(),[h,f]=react.useState(false),c=async()=>{f(true);try{await l(o),g?.();}catch(y){u?.(y);}finally{setTimeout(()=>f(false),500);}},s={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},m={dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}},p=n||h,d={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:p?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:p?.6:1,...m[e],...s[t],...a};return jsxRuntime.jsxs("button",{onClick:c,disabled:p,className:i,style:d,"aria-label":r,children:[jsxRuntime.jsx(ze,{}),jsxRuntime.jsx("span",{children:r})]})}function ze(){return jsxRuntime.jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsxRuntime.jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsxRuntime.jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsxRuntime.jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsxRuntime.jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function qe({text:r="Sign out",variant:e="dark",size:t="medium",className:o="",style:i,onSuccess:a,onError:g}){let{logoutRedirect:u,inProgress:l}=A(),n=async()=>{try{await u(),a?.();}catch(s){g?.(s);}},h={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},c={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:l?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:l?.6:1,...{dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}}[e],...h[t],...i};return jsxRuntime.jsxs("button",{onClick:n,disabled:l,className:o,style:c,"aria-label":r,children:[jsxRuntime.jsx(Be,{}),jsxRuntime.jsx("span",{children:r})]})}function Be(){return jsxRuntime.jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsxRuntime.jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsxRuntime.jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsxRuntime.jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsxRuntime.jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function N(){let{acquireToken:r}=A(),e=react.useCallback(async(u,l={})=>{let{scopes:n=["User.Read"],version:h="v1.0",debug:f=false,...c}=l;try{let s=await r(n),m=`https://graph.microsoft.com/${h}`,p=u.startsWith("http")?u:`${m}${u.startsWith("/")?u:`/${u}`}`;f&&console.log("[GraphAPI] Request:",{url:p,method:c.method||"GET"});let d=await fetch(p,{...c,headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json",...c.headers}});if(!d.ok){let R=await d.text(),M=`Graph API error (${d.status}): ${R}`;throw new Error(M)}if(d.status===204||d.headers.get("content-length")==="0")return null;let y=await d.json();return f&&console.log("[GraphAPI] Response:",y),y}catch(s){let m=w(s);throw console.error("[GraphAPI] Request failed:",m),new Error(m)}},[r]),t=react.useCallback((u,l={})=>e(u,{...l,method:"GET"}),[e]),o=react.useCallback((u,l,n={})=>e(u,{...n,method:"POST",body:l?JSON.stringify(l):void 0}),[e]),i=react.useCallback((u,l,n={})=>e(u,{...n,method:"PUT",body:l?JSON.stringify(l):void 0}),[e]),a=react.useCallback((u,l,n={})=>e(u,{...n,method:"PATCH",body:l?JSON.stringify(l):void 0}),[e]),g=react.useCallback((u,l={})=>e(u,{...l,method:"DELETE"}),[e]);return {get:t,post:o,put:i,patch:a,delete:g,request:e}}var x=new Map,_e=300*1e3,me=100;function Ve(){if(x.size>me){let r=Array.from(x.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,x.size-me).forEach(([t])=>{let o=x.get(t);o?.data.photo&&URL.revokeObjectURL(o.data.photo),x.delete(t);});}}function Q(){let{isAuthenticated:r,account:e}=A(),t=N(),[o,i]=react.useState(null),[a,g]=react.useState(false),[u,l]=react.useState(null),n=react.useCallback(async()=>{if(!r||!e){i(null);return}let f=e.homeAccountId,c=x.get(f);if(c&&Date.now()-c.timestamp<_e){i(c.data);return}g(true),l(null);try{let s=await t.get("/me",{scopes:["User.Read"]}),m;try{let d=await t.get("/me/photo/$value",{scopes:["User.Read"],headers:{"Content-Type":"image/jpeg"}});d&&(m=URL.createObjectURL(d));}catch{console.debug("[UserProfile] Photo not available");}let p={id:s.id,displayName:s.displayName,givenName:s.givenName,surname:s.surname,userPrincipalName:s.userPrincipalName,mail:s.mail,jobTitle:s.jobTitle,officeLocation:s.officeLocation,mobilePhone:s.mobilePhone,businessPhones:s.businessPhones,photo:m};x.set(f,{data:p,timestamp:Date.now()}),Ve(),i(p);}catch(s){let p=w(s),d=new Error(p);l(d),console.error("[UserProfile] Failed to fetch profile:",p);}finally{g(false);}},[r,e,t]),h=react.useCallback(()=>{if(e){let f=x.get(e.homeAccountId);f?.data.photo&&URL.revokeObjectURL(f.data.photo),x.delete(e.homeAccountId);}o?.photo&&URL.revokeObjectURL(o.photo),i(null);},[e,o]);return react.useEffect(()=>(n(),()=>{o?.photo&&URL.revokeObjectURL(o.photo);}),[n]),react.useEffect(()=>()=>{o?.photo&&URL.revokeObjectURL(o.photo);},[o?.photo]),{profile:o,loading:a,error:u,refetch:n,clearCache:h}}function We({size:r=40,className:e="",style:t,showTooltip:o=true,fallbackImage:i}){let{profile:a,loading:g}=Q(),[u,l]=react.useState(null),[n,h]=react.useState(false);react.useEffect(()=>{a?.photo&&l(a.photo);},[a?.photo]);let f=()=>{if(!a)return "?";let{givenName:m,surname:p,displayName:d}=a;if(m&&p)return `${m[0]}${p[0]}`.toUpperCase();if(d){let y=d.split(" ");return y.length>=2?`${y[0][0]}${y[y.length-1][0]}`.toUpperCase():d.substring(0,2).toUpperCase()}return "?"},c={width:`${r}px`,height:`${r}px`,borderRadius:"50%",display:"inline-flex",alignItems:"center",justifyContent:"center",fontSize:`${r*.4}px`,fontWeight:600,fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',backgroundColor:"#0078D4",color:"#FFFFFF",overflow:"hidden",userSelect:"none",...t},s=a?.displayName||"User";return g?jsxRuntime.jsx("div",{className:e,style:{...c,backgroundColor:"#E1E1E1"},"aria-label":"Loading user avatar",children:jsxRuntime.jsx("span",{style:{fontSize:`${r*.3}px`},children:"..."})}):u&&!n?jsxRuntime.jsx("div",{className:e,style:c,title:o?s:void 0,"aria-label":`${s} avatar`,children:jsxRuntime.jsx("img",{src:u,alt:s,style:{width:"100%",height:"100%",objectFit:"cover"},onError:()=>{h(true),i&&l(i);}})}):jsxRuntime.jsx("div",{className:e,style:c,title:o?s:void 0,"aria-label":`${s} avatar`,children:f()})}function je({className:r="",style:e,showDetails:t=false,renderLoading:o,renderAuthenticated:i,renderUnauthenticated:a}){let{isAuthenticated:g,inProgress:u,account:l}=A(),n={display:"inline-flex",alignItems:"center",gap:"8px",padding:"8px 12px",borderRadius:"4px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontSize:"14px",fontWeight:500,...e};if(u)return o?jsxRuntime.jsx(jsxRuntime.Fragment,{children:o()}):jsxRuntime.jsxs("div",{className:r,style:{...n,backgroundColor:"#FFF4CE",color:"#8A6D3B"},role:"status","aria-live":"polite",children:[jsxRuntime.jsx(X,{color:"#FFA500"}),jsxRuntime.jsx("span",{children:"Loading..."})]});if(g){let h=l?.username||l?.name||"User";return i?jsxRuntime.jsx(jsxRuntime.Fragment,{children:i(h)}):jsxRuntime.jsxs("div",{className:r,style:{...n,backgroundColor:"#D4EDDA",color:"#155724"},role:"status","aria-live":"polite",children:[jsxRuntime.jsx(X,{color:"#28A745"}),jsxRuntime.jsx("span",{children:t?`Authenticated as ${h}`:"Authenticated"})]})}return a?jsxRuntime.jsx(jsxRuntime.Fragment,{children:a()}):jsxRuntime.jsxs("div",{className:r,style:{...n,backgroundColor:"#F8D7DA",color:"#721C24"},role:"status","aria-live":"polite",children:[jsxRuntime.jsx(X,{color:"#DC3545"}),jsxRuntime.jsx("span",{children:"Not authenticated"})]})}function X({color:r}){return jsxRuntime.jsx("svg",{width:"8",height:"8",viewBox:"0 0 8 8",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsxRuntime.jsx("circle",{cx:"4",cy:"4",r:"4",fill:r})})}function re({children:r,loadingComponent:e,fallbackComponent:t,scopes:o,onAuthRequired:i}){let{isAuthenticated:a,inProgress:g,loginRedirect:u}=A();return react.useEffect(()=>{!a&&!g&&(i?.(),(async()=>{try{await u(o);}catch(n){console.error("[AuthGuard] Authentication failed:",n);}})());},[a,g,o,u,i]),g?jsxRuntime.jsx(jsxRuntime.Fragment,{children:e||jsxRuntime.jsx("div",{children:"Authenticating..."})}):a?jsxRuntime.jsx(jsxRuntime.Fragment,{children:r}):jsxRuntime.jsx(jsxRuntime.Fragment,{children:t||jsxRuntime.jsx("div",{children:"Redirecting to login..."})})}var ne=class extends react.Component{constructor(t){super(t);this.reset=()=>{this.setState({hasError:false,error:null});};this.state={hasError:false,error:null};}static getDerivedStateFromError(t){return {hasError:true,error:t}}componentDidCatch(t,o){let{onError:i,debug:a}=this.props;a&&(console.error("[ErrorBoundary] Caught error:",t),console.error("[ErrorBoundary] Error info:",o)),i?.(t,o);}render(){let{hasError:t,error:o}=this.state,{children:i,fallback:a}=this.props;return t&&o?a?a(o,this.reset):jsxRuntime.jsxs("div",{style:{padding:"20px",margin:"20px",border:"1px solid #DC3545",borderRadius:"4px",backgroundColor:"#F8D7DA",color:"#721C24",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif'},children:[jsxRuntime.jsx("h2",{style:{margin:"0 0 10px 0",fontSize:"18px"},children:"Authentication Error"}),jsxRuntime.jsx("p",{style:{margin:"0 0 10px 0"},children:o.message}),jsxRuntime.jsx("button",{onClick:this.reset,style:{padding:"8px 16px",backgroundColor:"#DC3545",color:"#FFFFFF",border:"none",borderRadius:"4px",cursor:"pointer",fontSize:"14px",fontWeight:600},children:"Try Again"})]}):i}};var v=new Map,Xe=300*1e3,Ae=100;function Ye(r){r?v.delete(r):v.clear();}function et(){if(v.size>Ae){let r=Array.from(v.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,v.size-Ae).forEach(([t])=>v.delete(t));}}function tt(){let{isAuthenticated:r,account:e}=A(),t=N(),[o,i]=react.useState([]),[a,g]=react.useState([]),[u,l]=react.useState(false),[n,h]=react.useState(null),f=react.useCallback(async()=>{if(!r||!e){i([]),g([]);return}let d=e.homeAccountId,y=v.get(d);if(y&&Date.now()-y.timestamp<Xe){i(y.roles),g(y.groups);return}l(true),h(null);try{let M=e.idTokenClaims?.roles||[],$=(await t.get("/me/memberOf",{scopes:["User.Read","Directory.Read.All"]})).value.map(se=>se.id);v.set(d,{roles:M,groups:$,timestamp:Date.now()}),et(),i(M),g($);}catch(R){let V=w(R),$=new Error(V);h($),console.error("[Roles] Failed to fetch roles/groups:",V);let Re=e.idTokenClaims?.roles||[];i(Re);}finally{l(false);}},[r,e,t]),c=react.useCallback(d=>o.includes(d),[o]),s=react.useCallback(d=>a.includes(d),[a]),m=react.useCallback(d=>d.some(y=>o.includes(y)),[o]),p=react.useCallback(d=>d.every(y=>o.includes(y)),[o]);return react.useEffect(()=>(f(),()=>{e&&Ye(e.homeAccountId);}),[f,e]),{roles:o,groups:a,loading:u,error:n,hasRole:c,hasGroup:s,hasAnyRole:m,hasAllRoles:p,refetch:f}}function rt(r,e={}){let{displayName:t,...o}=e,i=a=>jsxRuntime.jsx(re,{...o,children:jsxRuntime.jsx(r,{...a})});return i.displayName=t||`withAuth(${r.displayName||r.name||"Component"})`,i}async function Pe(r,e={}){let{maxRetries:t=3,initialDelay:o=1e3,maxDelay:i=1e4,backoffMultiplier:a=2,debug:g=false}=e,u,l=o;for(let n=0;n<=t;n++)try{return g&&n>0&&console.log(`[TokenRetry] Attempt ${n+1}/${t+1}`),await r()}catch(h){if(u=h,n===t){g&&console.error("[TokenRetry] All retry attempts failed");break}if(!ot(h))throw g&&console.log("[TokenRetry] Non-retryable error, aborting"),h;g&&console.warn(`[TokenRetry] Attempt ${n+1} failed, retrying in ${l}ms...`),await nt(l),l=Math.min(l*a,i);}throw u}function ot(r){let e=r.message.toLowerCase();return !!(e.includes("network")||e.includes("timeout")||e.includes("fetch")||e.includes("connection")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("429")||e.includes("rate limit")||e.includes("token")&&e.includes("expired"))}function nt(r){return new Promise(e=>setTimeout(e,r))}function it(r,e={}){return (...t)=>Pe(()=>r(...t),e)}var B=class{constructor(e={}){this.logHistory=[];this.performanceTimings=new Map;this.config={enabled:e.enabled??false,prefix:e.prefix??"[MSAL-Next]",showTimestamp:e.showTimestamp??true,level:e.level??"info",enablePerformance:e.enablePerformance??false,enableNetworkLogs:e.enableNetworkLogs??false,maxHistorySize:e.maxHistorySize??100};}shouldLog(e){if(!this.config.enabled)return false;let t=["error","warn","info","debug"],o=t.indexOf(this.config.level);return t.indexOf(e)<=o}formatMessage(e,t,o){let i=this.config.showTimestamp?`[${new Date().toISOString()}]`:"",a=this.config.prefix,g=`[${e.toUpperCase()}]`,u=`${i} ${a} ${g} ${t}`;return o!==void 0&&(u+=`
2
+ `+JSON.stringify(o,null,2)),u}addToHistory(e,t,o){this.logHistory.length>=this.config.maxHistorySize&&this.logHistory.shift(),this.logHistory.push({timestamp:Date.now(),level:e,message:t,data:o});}error(e,t){this.shouldLog("error")&&(console.error(this.formatMessage("error",e,t)),this.addToHistory("error",e,t));}warn(e,t){this.shouldLog("warn")&&(console.warn(this.formatMessage("warn",e,t)),this.addToHistory("warn",e,t));}info(e,t){this.shouldLog("info")&&(console.info(this.formatMessage("info",e,t)),this.addToHistory("info",e,t));}debug(e,t){this.shouldLog("debug")&&(console.debug(this.formatMessage("debug",e,t)),this.addToHistory("debug",e,t));}group(e){this.config.enabled&&console.group(`${this.config.prefix} ${e}`);}groupEnd(){this.config.enabled&&console.groupEnd();}startTiming(e){this.config.enablePerformance&&(this.performanceTimings.set(e,{operation:e,startTime:performance.now()}),this.debug(`\u23F1\uFE0F Started: ${e}`));}endTiming(e){if(this.config.enablePerformance){let t=this.performanceTimings.get(e);if(t)return t.endTime=performance.now(),t.duration=t.endTime-t.startTime,this.info(`\u23F1\uFE0F Completed: ${e} (${t.duration.toFixed(2)}ms)`),t.duration}}logRequest(e,t,o){this.config.enableNetworkLogs&&this.debug(`\u{1F310} ${e} ${t}`,o);}logResponse(e,t,o,i){if(this.config.enableNetworkLogs){let a=o>=200&&o<300?"\u2705":"\u274C";this.debug(`${a} ${e} ${t} - ${o}`,i);}}getHistory(){return [...this.logHistory]}getPerformanceTimings(){return Array.from(this.performanceTimings.values())}clearHistory(){this.logHistory=[];}clearTimings(){this.performanceTimings.clear();}exportLogs(){return JSON.stringify({config:this.config,history:this.logHistory,performanceTimings:Array.from(this.performanceTimings.values()),exportedAt:new Date().toISOString()},null,2)}downloadLogs(e="msal-next-debug-logs.json"){if(typeof window>"u")return;let t=this.exportLogs(),o=new Blob([t],{type:"application/json"}),i=URL.createObjectURL(o),a=document.createElement("a");a.href=i,a.download=e,a.click(),URL.revokeObjectURL(i);}setEnabled(e){this.config.enabled=e;}setLevel(e){e&&(this.config.level=e);}},O=null;function st(r){return O?r&&(r.enabled!==void 0&&O.setEnabled(r.enabled),r.level&&O.setLevel(r.level)):O=new B(r),O}function at(r,e){return new B({...e,prefix:`[MSAL-Next:${r}]`})}function _({children:r,config:e,defaultRedirectTo:t="/login",defaultLoading:o,defaultUnauthorized:i,debug:a=false}){let g=navigation.useRouter(),{isAuthenticated:u,account:l,inProgress:n}=A(),[h,f]=react.useState(true),[c,s]=react.useState(false);return react.useEffect(()=>{async function m(){if(a&&console.log("[ProtectedPage] Checking auth...",{isAuthenticated:u,inProgress:n,config:e}),!n){if(!e.required){s(true),f(false);return}if(!u||!l){a&&console.log("[ProtectedPage] Not authenticated, redirecting...");let p=e.redirectTo||t,d=encodeURIComponent(window.location.pathname+window.location.search);g.push(`${p}?returnUrl=${d}`);return}if(e.roles&&e.roles.length>0){let p=l.idTokenClaims?.roles||[];if(!e.roles.some(y=>p.includes(y))){a&&console.log("[ProtectedPage] Missing required role",{required:e.roles,user:p}),s(false),f(false);return}}if(e.validate)try{if(!await e.validate(l)){a&&console.log("[ProtectedPage] Custom validation failed"),s(!1),f(!1);return}}catch(p){console.error("[ProtectedPage] Validation error:",p),s(false),f(false);return}a&&console.log("[ProtectedPage] Authorization successful"),s(true),f(false);}}m();},[u,l,n,e,g,t,a]),h||n?e.loading?jsxRuntime.jsx(jsxRuntime.Fragment,{children:e.loading}):o?jsxRuntime.jsx(jsxRuntime.Fragment,{children:o}):jsxRuntime.jsx("div",{className:"flex items-center justify-center min-h-screen",children:jsxRuntime.jsx("div",{className:"animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"})}):c?jsxRuntime.jsx(jsxRuntime.Fragment,{children:r}):e.unauthorized?jsxRuntime.jsx(jsxRuntime.Fragment,{children:e.unauthorized}):i?jsxRuntime.jsx(jsxRuntime.Fragment,{children:i}):jsxRuntime.jsx("div",{className:"flex items-center justify-center min-h-screen",children:jsxRuntime.jsxs("div",{className:"text-center",children:[jsxRuntime.jsx("h1",{className:"text-2xl font-bold text-gray-900 mb-2",children:"Access Denied"}),jsxRuntime.jsx("p",{className:"text-gray-600",children:"You don't have permission to access this page."})]})})}function we(r,e,t){let o=i=>jsxRuntime.jsx(_,{config:e,defaultRedirectTo:t?.defaultRedirectTo,defaultLoading:t?.defaultLoading,defaultUnauthorized:t?.defaultUnauthorized,debug:t?.debug,children:jsxRuntime.jsx(r,{...i})});return o.displayName=`withPageAuth(${r.displayName||r.name||"Component"})`,o}function dt(r={}){let{protectedRoutes:e=[],publicOnlyRoutes:t=[],loginPath:o="/login",redirectAfterLogin:i="/",sessionCookie:a="msal.account",isAuthenticated:g,debug:u=false}=r;return async function(n){let{pathname:h}=n.nextUrl;u&&console.log("[AuthMiddleware] Processing:",h);let f=false;g?f=await g(n):f=!!n.cookies.get(a)?.value,u&&console.log("[AuthMiddleware] Authenticated:",f);let c=e.some(p=>h.startsWith(p)),s=t.some(p=>h.startsWith(p));if(c&&!f){u&&console.log("[AuthMiddleware] Redirecting to login");let p=n.nextUrl.clone();return p.pathname=o,p.searchParams.set("returnUrl",h),server.NextResponse.redirect(p)}if(s&&f){u&&console.log("[AuthMiddleware] Redirecting to home");let p=n.nextUrl.searchParams.get("returnUrl"),d=n.nextUrl.clone();return d.pathname=p||i,d.searchParams.delete("returnUrl"),server.NextResponse.redirect(d)}let m=server.NextResponse.next();if(f){m.headers.set("x-msal-authenticated","true");try{let p=n.cookies.get(a);if(p?.value){let d=H(p.value,W);d?.username&&m.headers.set("x-msal-username",d.username);}}catch{u&&console.warn("[AuthMiddleware] Failed to parse session data");}}return m}}Object.defineProperty(exports,"useAccount",{enumerable:true,get:function(){return msalReact.useAccount}});Object.defineProperty(exports,"useIsAuthenticated",{enumerable:true,get:function(){return msalReact.useIsAuthenticated}});Object.defineProperty(exports,"useMsal",{enumerable:true,get:function(){return msalReact.useMsal}});exports.AuthGuard=re;exports.AuthStatus=je;exports.ErrorBoundary=ne;exports.MSALProvider=Fe;exports.MicrosoftSignInButton=$e;exports.MsalAuthProvider=J;exports.ProtectedPage=_;exports.SignOutButton=qe;exports.UserAvatar=We;exports.createAuthMiddleware=dt;exports.createMsalConfig=j;exports.createRetryWrapper=it;exports.createScopedLogger=at;exports.getDebugLogger=st;exports.getMsalInstance=Ue;exports.isValidAccountData=W;exports.isValidRedirectUri=z;exports.isValidScope=ae;exports.retryWithBackoff=Pe;exports.safeJsonParse=H;exports.sanitizeError=w;exports.useGraphApi=N;exports.useMsalAuth=A;exports.useRoles=tt;exports.useUserProfile=Q;exports.validateScopes=Ce;exports.withAuth=rt;exports.withPageAuth=we;
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import {MsalProvider,useMsal,useAccount}from'@azure/msal-react';export{useAccount,useIsAuthenticated,useMsal}from'@azure/msal-react';import {LogLevel,PublicClientApplication,EventType,InteractionStatus}from'@azure/msal-browser';import {useState,useRef,useEffect,useMemo,useCallback,Component}from'react';import {jsx,Fragment,jsxs}from'react/jsx-runtime';import {NextResponse}from'next/server';function q(r,e){try{let t=JSON.parse(r);return e(t)?t:(console.warn("[Validation] JSON validation failed"),null)}catch(t){return console.error("[Validation] JSON parse error:",t),null}}function _(r){return typeof r=="object"&&r!==null&&typeof r.homeAccountId=="string"&&r.homeAccountId.length>0&&typeof r.username=="string"&&r.username.length>0&&(r.name===void 0||typeof r.name=="string")}function v(r){return r instanceof Error?r.message.replace(/[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g,"[TOKEN_REDACTED]").replace(/[a-f0-9]{32,}/gi,"[SECRET_REDACTED]").replace(/Bearer\s+[^\s]+/gi,"Bearer [REDACTED]"):"An unexpected error occurred"}function G(r,e){try{let t=new URL(r);return e.some(o=>{let i=new URL(o);return t.origin===i.origin})}catch{return false}}function ne(r){return /^[a-zA-Z0-9._-]+$/.test(r)}function Ae(r){return Array.isArray(r)&&r.every(ne)}function H(r){if(r.msalConfig)return r.msalConfig;let{clientId:e,tenantId:t,authorityType:o="common",redirectUri:i,postLogoutRedirectUri:a,cacheLocation:p="sessionStorage",storeAuthStateInCookie:u=false,navigateToLoginRequestUrl:c=false,enableLogging:n=false,loggerCallback:h,allowedRedirectUris:g}=r;if(!e)throw new Error("@chemmangat/msal-next: clientId is required");let l=()=>{if(o==="tenant"){if(!t)throw new Error('@chemmangat/msal-next: tenantId is required when authorityType is "tenant"');return `https://login.microsoftonline.com/${t}`}return `https://login.microsoftonline.com/${o}`},s=typeof window<"u"?window.location.origin:"http://localhost:3000",m=i||s;if(g&&g.length>0){if(!G(m,g))throw new Error(`@chemmangat/msal-next: redirectUri "${m}" is not in the allowed list`);let d=a||m;if(!G(d,g))throw new Error(`@chemmangat/msal-next: postLogoutRedirectUri "${d}" is not in the allowed list`)}return {auth:{clientId:e,authority:l(),redirectUri:m,postLogoutRedirectUri:a||m,navigateToLoginRequestUrl:c},cache:{cacheLocation:p,storeAuthStateInCookie:u},system:{loggerOptions:{loggerCallback:h||((d,y,R)=>{if(!(R||!n))switch(d){case LogLevel.Error:console.error("[MSAL]",y);break;case LogLevel.Warning:console.warn("[MSAL]",y);break;case LogLevel.Info:console.info("[MSAL]",y);break;case LogLevel.Verbose:console.debug("[MSAL]",y);break}}),logLevel:n?LogLevel.Verbose:LogLevel.Error}}}}var se=null;function Pe(){return se}function V({children:r,loadingComponent:e,onInitialized:t,...o}){let[i,a]=useState(null),p=useRef(null);return useEffect(()=>{if(typeof window>"u"||p.current)return;(async()=>{try{let c=H(o),n=new PublicClientApplication(c);await n.initialize();try{let l=await n.handleRedirectPromise();l&&(o.enableLogging&&console.log("[MSAL] Redirect authentication successful"),l.account&&n.setActiveAccount(l.account),window.location.hash&&window.history.replaceState(null,"",window.location.pathname+window.location.search));}catch(l){l?.errorCode==="no_token_request_cache_error"?o.enableLogging&&console.log("[MSAL] No pending redirect found (this is normal)"):l?.errorCode==="user_cancelled"?o.enableLogging&&console.log("[MSAL] User cancelled authentication"):console.error("[MSAL] Redirect handling error:",l),window.location.hash&&(window.location.hash.includes("code=")||window.location.hash.includes("error="))&&window.history.replaceState(null,"",window.location.pathname+window.location.search);}let h=n.getAllAccounts();h.length>0&&!n.getActiveAccount()&&n.setActiveAccount(h[0]);let g=o.enableLogging||!1;n.addEventCallback(l=>{if(l.eventType===EventType.LOGIN_SUCCESS){let s=l.payload;s?.account&&n.setActiveAccount(s.account),g&&console.log("[MSAL] Login successful:",s.account?.username);}if(l.eventType===EventType.LOGIN_FAILURE&&console.error("[MSAL] Login failed:",l.error),l.eventType===EventType.LOGOUT_SUCCESS&&(n.setActiveAccount(null),g&&console.log("[MSAL] Logout successful")),l.eventType===EventType.ACQUIRE_TOKEN_SUCCESS){let s=l.payload;s?.account&&!n.getActiveAccount()&&n.setActiveAccount(s.account);}l.eventType===EventType.ACQUIRE_TOKEN_FAILURE&&g&&console.error("[MSAL] Token acquisition failed:",l.error);}),p.current=n,se=n,a(n),t&&t(n);}catch(c){throw console.error("[MSAL] Initialization failed:",c),c}})();},[]),typeof window>"u"?jsx(Fragment,{children:e||jsx("div",{children:"Loading authentication..."})}):i?jsx(MsalProvider,{instance:i,children:r}):jsx(Fragment,{children:e||jsx("div",{children:"Loading authentication..."})})}function Se({children:r,...e}){return jsx(V,{...e,children:r})}var W=new Map;function A(r=["User.Read"]){let{instance:e,accounts:t,inProgress:o}=useMsal(),i=useAccount(t[0]||null),a=useMemo(()=>t.length>0,[t]),p=useCallback(async(l=r)=>{if(o!==InteractionStatus.None){console.warn("[MSAL] Interaction already in progress");return}try{let s={scopes:l,prompt:"select_account"};await e.loginRedirect(s);}catch(s){if(s?.errorCode==="user_cancelled"){console.log("[MSAL] User cancelled login");return}throw console.error("[MSAL] Login redirect failed:",s),s}},[e,r,o]),u=useCallback(async()=>{try{await e.logoutRedirect({account:i||void 0});}catch(l){throw console.error("[MSAL] Logout redirect failed:",l),l}},[e,i]),c=useCallback(async(l=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:l,account:i,forceRefresh:!1};return (await e.acquireTokenSilent(s)).accessToken}catch(s){throw console.error("[MSAL] Silent token acquisition failed:",s),s}},[e,i,r]),n=useCallback(async(l=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:l,account:i};await e.acquireTokenRedirect(s);}catch(s){throw console.error("[MSAL] Token redirect acquisition failed:",s),s}},[e,i,r]),h=useCallback(async(l=r)=>{let s=`${i?.homeAccountId||"anonymous"}-${l.sort().join(",")}`,m=W.get(s);if(m)return m;let f=(async()=>{try{return await c(l)}catch{throw console.warn("[MSAL] Silent token acquisition failed, falling back to redirect"),await n(l),new Error("[MSAL] Redirecting for token acquisition")}finally{W.delete(s);}})();return W.set(s,f),f},[c,n,r,i]),g=useCallback(async()=>{e.setActiveAccount(null),await e.clearCache();},[e]);return {account:i,accounts:t,isAuthenticated:a,inProgress:o!==InteractionStatus.None,loginRedirect:p,logoutRedirect:u,acquireToken:h,acquireTokenSilent:c,acquireTokenRedirect:n,clearSession:g}}function Ue({text:r="Sign in with Microsoft",variant:e="dark",size:t="medium",scopes:o,className:i="",style:a,onSuccess:p,onError:u}){let{loginRedirect:c,inProgress:n}=A(),[h,g]=useState(false),l=async()=>{g(true);try{await c(o),p?.();}catch(y){u?.(y);}finally{setTimeout(()=>g(false),500);}},s={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},m={dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}},f=n||h,d={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:f?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:f?.6:1,...m[e],...s[t],...a};return jsxs("button",{onClick:l,disabled:f,className:i,style:d,"aria-label":r,children:[jsx(ke,{}),jsx("span",{children:r})]})}function ke(){return jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function Fe({text:r="Sign out",variant:e="dark",size:t="medium",className:o="",style:i,onSuccess:a,onError:p}){let{logoutRedirect:u,inProgress:c}=A(),n=async()=>{try{await u(),a?.();}catch(s){p?.(s);}},h={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},l={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:c?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:c?.6:1,...{dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}}[e],...h[t],...i};return jsxs("button",{onClick:n,disabled:c,className:o,style:l,"aria-label":r,children:[jsx(Ne,{}),jsx("span",{children:r})]})}function Ne(){return jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function k(){let{acquireToken:r}=A(),e=useCallback(async(u,c={})=>{let{scopes:n=["User.Read"],version:h="v1.0",debug:g=false,...l}=c;try{let s=await r(n),m=`https://graph.microsoft.com/${h}`,f=u.startsWith("http")?u:`${m}${u.startsWith("/")?u:`/${u}`}`;g&&console.log("[GraphAPI] Request:",{url:f,method:l.method||"GET"});let d=await fetch(f,{...l,headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json",...l.headers}});if(!d.ok){let R=await d.text(),L=`Graph API error (${d.status}): ${R}`;throw new Error(L)}if(d.status===204||d.headers.get("content-length")==="0")return null;let y=await d.json();return g&&console.log("[GraphAPI] Response:",y),y}catch(s){let m=v(s);throw console.error("[GraphAPI] Request failed:",m),new Error(m)}},[r]),t=useCallback((u,c={})=>e(u,{...c,method:"GET"}),[e]),o=useCallback((u,c,n={})=>e(u,{...n,method:"POST",body:c?JSON.stringify(c):void 0}),[e]),i=useCallback((u,c,n={})=>e(u,{...n,method:"PUT",body:c?JSON.stringify(c):void 0}),[e]),a=useCallback((u,c,n={})=>e(u,{...n,method:"PATCH",body:c?JSON.stringify(c):void 0}),[e]),p=useCallback((u,c={})=>e(u,{...c,method:"DELETE"}),[e]);return {get:t,post:o,put:i,patch:a,delete:p,request:e}}var x=new Map,Ie=300*1e3,pe=100;function Oe(){if(x.size>pe){let r=Array.from(x.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,x.size-pe).forEach(([t])=>{let o=x.get(t);o?.data.photo&&URL.revokeObjectURL(o.data.photo),x.delete(t);});}}function J(){let{isAuthenticated:r,account:e}=A(),t=k(),[o,i]=useState(null),[a,p]=useState(false),[u,c]=useState(null),n=useCallback(async()=>{if(!r||!e){i(null);return}let g=e.homeAccountId,l=x.get(g);if(l&&Date.now()-l.timestamp<Ie){i(l.data);return}p(true),c(null);try{let s=await t.get("/me",{scopes:["User.Read"]}),m;try{let d=await t.get("/me/photo/$value",{scopes:["User.Read"],headers:{"Content-Type":"image/jpeg"}});d&&(m=URL.createObjectURL(d));}catch{console.debug("[UserProfile] Photo not available");}let f={id:s.id,displayName:s.displayName,givenName:s.givenName,surname:s.surname,userPrincipalName:s.userPrincipalName,mail:s.mail,jobTitle:s.jobTitle,officeLocation:s.officeLocation,mobilePhone:s.mobilePhone,businessPhones:s.businessPhones,photo:m};x.set(g,{data:f,timestamp:Date.now()}),Oe(),i(f);}catch(s){let f=v(s),d=new Error(f);c(d),console.error("[UserProfile] Failed to fetch profile:",f);}finally{p(false);}},[r,e,t]),h=useCallback(()=>{if(e){let g=x.get(e.homeAccountId);g?.data.photo&&URL.revokeObjectURL(g.data.photo),x.delete(e.homeAccountId);}o?.photo&&URL.revokeObjectURL(o.photo),i(null);},[e,o]);return useEffect(()=>(n(),()=>{o?.photo&&URL.revokeObjectURL(o.photo);}),[n]),useEffect(()=>()=>{o?.photo&&URL.revokeObjectURL(o.photo);},[o?.photo]),{profile:o,loading:a,error:u,refetch:n,clearCache:h}}function Ge({size:r=40,className:e="",style:t,showTooltip:o=true,fallbackImage:i}){let{profile:a,loading:p}=J(),[u,c]=useState(null),[n,h]=useState(false);useEffect(()=>{a?.photo&&c(a.photo);},[a?.photo]);let g=()=>{if(!a)return "?";let{givenName:m,surname:f,displayName:d}=a;if(m&&f)return `${m[0]}${f[0]}`.toUpperCase();if(d){let y=d.split(" ");return y.length>=2?`${y[0][0]}${y[y.length-1][0]}`.toUpperCase():d.substring(0,2).toUpperCase()}return "?"},l={width:`${r}px`,height:`${r}px`,borderRadius:"50%",display:"inline-flex",alignItems:"center",justifyContent:"center",fontSize:`${r*.4}px`,fontWeight:600,fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',backgroundColor:"#0078D4",color:"#FFFFFF",overflow:"hidden",userSelect:"none",...t},s=a?.displayName||"User";return p?jsx("div",{className:e,style:{...l,backgroundColor:"#E1E1E1"},"aria-label":"Loading user avatar",children:jsx("span",{style:{fontSize:`${r*.3}px`},children:"..."})}):u&&!n?jsx("div",{className:e,style:l,title:o?s:void 0,"aria-label":`${s} avatar`,children:jsx("img",{src:u,alt:s,style:{width:"100%",height:"100%",objectFit:"cover"},onError:()=>{h(true),i&&c(i);}})}):jsx("div",{className:e,style:l,title:o?s:void 0,"aria-label":`${s} avatar`,children:g()})}function $e({className:r="",style:e,showDetails:t=false,renderLoading:o,renderAuthenticated:i,renderUnauthenticated:a}){let{isAuthenticated:p,inProgress:u,account:c}=A(),n={display:"inline-flex",alignItems:"center",gap:"8px",padding:"8px 12px",borderRadius:"4px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontSize:"14px",fontWeight:500,...e};if(u)return o?jsx(Fragment,{children:o()}):jsxs("div",{className:r,style:{...n,backgroundColor:"#FFF4CE",color:"#8A6D3B"},role:"status","aria-live":"polite",children:[jsx(K,{color:"#FFA500"}),jsx("span",{children:"Loading..."})]});if(p){let h=c?.username||c?.name||"User";return i?jsx(Fragment,{children:i(h)}):jsxs("div",{className:r,style:{...n,backgroundColor:"#D4EDDA",color:"#155724"},role:"status","aria-live":"polite",children:[jsx(K,{color:"#28A745"}),jsx("span",{children:t?`Authenticated as ${h}`:"Authenticated"})]})}return a?jsx(Fragment,{children:a()}):jsxs("div",{className:r,style:{...n,backgroundColor:"#F8D7DA",color:"#721C24"},role:"status","aria-live":"polite",children:[jsx(K,{color:"#DC3545"}),jsx("span",{children:"Not authenticated"})]})}function K({color:r}){return jsx("svg",{width:"8",height:"8",viewBox:"0 0 8 8",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsx("circle",{cx:"4",cy:"4",r:"4",fill:r})})}function Y({children:r,loadingComponent:e,fallbackComponent:t,scopes:o,onAuthRequired:i}){let{isAuthenticated:a,inProgress:p,loginRedirect:u}=A();return useEffect(()=>{!a&&!p&&(i?.(),(async()=>{try{await u(o);}catch(n){console.error("[AuthGuard] Authentication failed:",n);}})());},[a,p,o,u,i]),p?jsx(Fragment,{children:e||jsx("div",{children:"Authenticating..."})}):a?jsx(Fragment,{children:r}):jsx(Fragment,{children:t||jsx("div",{children:"Redirecting to login..."})})}var re=class extends Component{constructor(t){super(t);this.reset=()=>{this.setState({hasError:false,error:null});};this.state={hasError:false,error:null};}static getDerivedStateFromError(t){return {hasError:true,error:t}}componentDidCatch(t,o){let{onError:i,debug:a}=this.props;a&&(console.error("[ErrorBoundary] Caught error:",t),console.error("[ErrorBoundary] Error info:",o)),i?.(t,o);}render(){let{hasError:t,error:o}=this.state,{children:i,fallback:a}=this.props;return t&&o?a?a(o,this.reset):jsxs("div",{style:{padding:"20px",margin:"20px",border:"1px solid #DC3545",borderRadius:"4px",backgroundColor:"#F8D7DA",color:"#721C24",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif'},children:[jsx("h2",{style:{margin:"0 0 10px 0",fontSize:"18px"},children:"Authentication Error"}),jsx("p",{style:{margin:"0 0 10px 0"},children:o.message}),jsx("button",{onClick:this.reset,style:{padding:"8px 16px",backgroundColor:"#DC3545",color:"#FFFFFF",border:"none",borderRadius:"4px",cursor:"pointer",fontSize:"14px",fontWeight:600},children:"Try Again"})]}):i}};var w=new Map,He=300*1e3,fe=100;function Ve(r){r?w.delete(r):w.clear();}function We(){if(w.size>fe){let r=Array.from(w.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,w.size-fe).forEach(([t])=>w.delete(t));}}function je(){let{isAuthenticated:r,account:e}=A(),t=k(),[o,i]=useState([]),[a,p]=useState([]),[u,c]=useState(false),[n,h]=useState(null),g=useCallback(async()=>{if(!r||!e){i([]),p([]);return}let d=e.homeAccountId,y=w.get(d);if(y&&Date.now()-y.timestamp<He){i(y.roles),p(y.groups);return}c(true),h(null);try{let L=e.idTokenClaims?.roles||[],D=(await t.get("/me/memberOf",{scopes:["User.Read","Directory.Read.All"]})).value.map(oe=>oe.id);w.set(d,{roles:L,groups:D,timestamp:Date.now()}),We(),i(L),p(D);}catch(R){let B=v(R),D=new Error(B);h(D),console.error("[Roles] Failed to fetch roles/groups:",B);let ye=e.idTokenClaims?.roles||[];i(ye);}finally{c(false);}},[r,e,t]),l=useCallback(d=>o.includes(d),[o]),s=useCallback(d=>a.includes(d),[a]),m=useCallback(d=>d.some(y=>o.includes(y)),[o]),f=useCallback(d=>d.every(y=>o.includes(y)),[o]);return useEffect(()=>(g(),()=>{e&&Ve(e.homeAccountId);}),[g,e]),{roles:o,groups:a,loading:u,error:n,hasRole:l,hasGroup:s,hasAnyRole:m,hasAllRoles:f,refetch:g}}function Je(r,e={}){let{displayName:t,...o}=e,i=a=>jsx(Y,{...o,children:jsx(r,{...a})});return i.displayName=t||`withAuth(${r.displayName||r.name||"Component"})`,i}async function me(r,e={}){let{maxRetries:t=3,initialDelay:o=1e3,maxDelay:i=1e4,backoffMultiplier:a=2,debug:p=false}=e,u,c=o;for(let n=0;n<=t;n++)try{return p&&n>0&&console.log(`[TokenRetry] Attempt ${n+1}/${t+1}`),await r()}catch(h){if(u=h,n===t){p&&console.error("[TokenRetry] All retry attempts failed");break}if(!Ke(h))throw p&&console.log("[TokenRetry] Non-retryable error, aborting"),h;p&&console.warn(`[TokenRetry] Attempt ${n+1} failed, retrying in ${c}ms...`),await Ze(c),c=Math.min(c*a,i);}throw u}function Ke(r){let e=r.message.toLowerCase();return !!(e.includes("network")||e.includes("timeout")||e.includes("fetch")||e.includes("connection")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("429")||e.includes("rate limit")||e.includes("token")&&e.includes("expired"))}function Ze(r){return new Promise(e=>setTimeout(e,r))}function Qe(r,e={}){return (...t)=>me(()=>r(...t),e)}var z=class{constructor(e={}){this.logHistory=[];this.performanceTimings=new Map;this.config={enabled:e.enabled??false,prefix:e.prefix??"[MSAL-Next]",showTimestamp:e.showTimestamp??true,level:e.level??"info",enablePerformance:e.enablePerformance??false,enableNetworkLogs:e.enableNetworkLogs??false,maxHistorySize:e.maxHistorySize??100};}shouldLog(e){if(!this.config.enabled)return false;let t=["error","warn","info","debug"],o=t.indexOf(this.config.level);return t.indexOf(e)<=o}formatMessage(e,t,o){let i=this.config.showTimestamp?`[${new Date().toISOString()}]`:"",a=this.config.prefix,p=`[${e.toUpperCase()}]`,u=`${i} ${a} ${p} ${t}`;return o!==void 0&&(u+=`
2
- `+JSON.stringify(o,null,2)),u}addToHistory(e,t,o){this.logHistory.length>=this.config.maxHistorySize&&this.logHistory.shift(),this.logHistory.push({timestamp:Date.now(),level:e,message:t,data:o});}error(e,t){this.shouldLog("error")&&(console.error(this.formatMessage("error",e,t)),this.addToHistory("error",e,t));}warn(e,t){this.shouldLog("warn")&&(console.warn(this.formatMessage("warn",e,t)),this.addToHistory("warn",e,t));}info(e,t){this.shouldLog("info")&&(console.info(this.formatMessage("info",e,t)),this.addToHistory("info",e,t));}debug(e,t){this.shouldLog("debug")&&(console.debug(this.formatMessage("debug",e,t)),this.addToHistory("debug",e,t));}group(e){this.config.enabled&&console.group(`${this.config.prefix} ${e}`);}groupEnd(){this.config.enabled&&console.groupEnd();}startTiming(e){this.config.enablePerformance&&(this.performanceTimings.set(e,{operation:e,startTime:performance.now()}),this.debug(`\u23F1\uFE0F Started: ${e}`));}endTiming(e){if(this.config.enablePerformance){let t=this.performanceTimings.get(e);if(t)return t.endTime=performance.now(),t.duration=t.endTime-t.startTime,this.info(`\u23F1\uFE0F Completed: ${e} (${t.duration.toFixed(2)}ms)`),t.duration}}logRequest(e,t,o){this.config.enableNetworkLogs&&this.debug(`\u{1F310} ${e} ${t}`,o);}logResponse(e,t,o,i){if(this.config.enableNetworkLogs){let a=o>=200&&o<300?"\u2705":"\u274C";this.debug(`${a} ${e} ${t} - ${o}`,i);}}getHistory(){return [...this.logHistory]}getPerformanceTimings(){return Array.from(this.performanceTimings.values())}clearHistory(){this.logHistory=[];}clearTimings(){this.performanceTimings.clear();}exportLogs(){return JSON.stringify({config:this.config,history:this.logHistory,performanceTimings:Array.from(this.performanceTimings.values()),exportedAt:new Date().toISOString()},null,2)}downloadLogs(e="msal-next-debug-logs.json"){if(typeof window>"u")return;let t=this.exportLogs(),o=new Blob([t],{type:"application/json"}),i=URL.createObjectURL(o),a=document.createElement("a");a.href=i,a.download=e,a.click(),URL.revokeObjectURL(i);}setEnabled(e){this.config.enabled=e;}setLevel(e){e&&(this.config.level=e);}},O=null;function Xe(r){return O?r&&(r.enabled!==void 0&&O.setEnabled(r.enabled),r.level&&O.setLevel(r.level)):O=new z(r),O}function Ye(r,e){return new z({...e,prefix:`[MSAL-Next:${r}]`})}function er(r={}){let{protectedRoutes:e=[],publicOnlyRoutes:t=[],loginPath:o="/login",redirectAfterLogin:i="/",sessionCookie:a="msal.account",isAuthenticated:p,debug:u=false}=r;return async function(n){let{pathname:h}=n.nextUrl;u&&console.log("[AuthMiddleware] Processing:",h);let g=false;p?g=await p(n):g=!!n.cookies.get(a)?.value,u&&console.log("[AuthMiddleware] Authenticated:",g);let l=e.some(f=>h.startsWith(f)),s=t.some(f=>h.startsWith(f));if(l&&!g){u&&console.log("[AuthMiddleware] Redirecting to login");let f=n.nextUrl.clone();return f.pathname=o,f.searchParams.set("returnUrl",h),NextResponse.redirect(f)}if(s&&g){u&&console.log("[AuthMiddleware] Redirecting to home");let f=n.nextUrl.searchParams.get("returnUrl"),d=n.nextUrl.clone();return d.pathname=f||i,d.searchParams.delete("returnUrl"),NextResponse.redirect(d)}let m=NextResponse.next();if(g){m.headers.set("x-msal-authenticated","true");try{let f=n.cookies.get(a);if(f?.value){let d=q(f.value,_);d?.username&&m.headers.set("x-msal-username",d.username);}}catch{u&&console.warn("[AuthMiddleware] Failed to parse session data");}}return m}}export{Y as AuthGuard,$e as AuthStatus,re as ErrorBoundary,Se as MSALProvider,Ue as MicrosoftSignInButton,V as MsalAuthProvider,Fe as SignOutButton,Ge as UserAvatar,er as createAuthMiddleware,H as createMsalConfig,Qe as createRetryWrapper,Ye as createScopedLogger,Xe as getDebugLogger,Pe as getMsalInstance,_ as isValidAccountData,G as isValidRedirectUri,ne as isValidScope,me as retryWithBackoff,q as safeJsonParse,v as sanitizeError,k as useGraphApi,A as useMsalAuth,je as useRoles,J as useUserProfile,Ae as validateScopes,Je as withAuth};
1
+ import {MsalProvider,useMsal,useAccount}from'@azure/msal-react';export{useAccount,useIsAuthenticated,useMsal}from'@azure/msal-react';import {LogLevel,PublicClientApplication,EventType,InteractionStatus}from'@azure/msal-browser';import {createContext,useState,useRef,useEffect,useMemo,useCallback,Component}from'react';import {jsx,Fragment,jsxs}from'react/jsx-runtime';import {useRouter}from'next/navigation';import {NextResponse}from'next/server';function H(r,e){try{let t=JSON.parse(r);return e(t)?t:(console.warn("[Validation] JSON validation failed"),null)}catch(t){return console.error("[Validation] JSON parse error:",t),null}}function W(r){return typeof r=="object"&&r!==null&&typeof r.homeAccountId=="string"&&r.homeAccountId.length>0&&typeof r.username=="string"&&r.username.length>0&&(r.name===void 0||typeof r.name=="string")}function w(r){return r instanceof Error?r.message.replace(/[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g,"[TOKEN_REDACTED]").replace(/[a-f0-9]{32,}/gi,"[SECRET_REDACTED]").replace(/Bearer\s+[^\s]+/gi,"Bearer [REDACTED]"):"An unexpected error occurred"}function z(r,e){try{let t=new URL(r);return e.some(o=>{let i=new URL(o);return t.origin===i.origin})}catch{return false}}function ae(r){return /^[a-zA-Z0-9._-]+$/.test(r)}function Ce(r){return Array.isArray(r)&&r.every(ae)}function j(r){if(r.msalConfig)return r.msalConfig;let{clientId:e,tenantId:t,authorityType:o="common",redirectUri:i,postLogoutRedirectUri:a,cacheLocation:g="sessionStorage",storeAuthStateInCookie:u=false,navigateToLoginRequestUrl:l=false,enableLogging:n=false,loggerCallback:h,allowedRedirectUris:f}=r;if(!e)throw new Error("@chemmangat/msal-next: clientId is required");let c=()=>{if(o==="tenant"){if(!t)throw new Error('@chemmangat/msal-next: tenantId is required when authorityType is "tenant"');return `https://login.microsoftonline.com/${t}`}return `https://login.microsoftonline.com/${o}`},s=typeof window<"u"?window.location.origin:"http://localhost:3000",m=i||s;if(f&&f.length>0){if(!z(m,f))throw new Error(`@chemmangat/msal-next: redirectUri "${m}" is not in the allowed list`);let d=a||m;if(!z(d,f))throw new Error(`@chemmangat/msal-next: postLogoutRedirectUri "${d}" is not in the allowed list`)}return {auth:{clientId:e,authority:c(),redirectUri:m,postLogoutRedirectUri:a||m,navigateToLoginRequestUrl:l},cache:{cacheLocation:g,storeAuthStateInCookie:u},system:{loggerOptions:{loggerCallback:h||((d,y,R)=>{if(!(R||!n))switch(d){case LogLevel.Error:console.error("[MSAL]",y);break;case LogLevel.Warning:console.warn("[MSAL]",y);break;case LogLevel.Info:console.info("[MSAL]",y);break;case LogLevel.Verbose:console.debug("[MSAL]",y);break}}),logLevel:n?LogLevel.Verbose:LogLevel.Error}}}}var ce=null;function Ue(){return ce}function J({children:r,loadingComponent:e,onInitialized:t,...o}){let[i,a]=useState(null),g=useRef(null);return useEffect(()=>{if(typeof window>"u"||g.current)return;(async()=>{try{let l=j(o),n=new PublicClientApplication(l);await n.initialize();try{let c=await n.handleRedirectPromise();c&&(o.enableLogging&&console.log("[MSAL] Redirect authentication successful"),c.account&&n.setActiveAccount(c.account),window.location.hash&&window.history.replaceState(null,"",window.location.pathname+window.location.search));}catch(c){c?.errorCode==="no_token_request_cache_error"?o.enableLogging&&console.log("[MSAL] No pending redirect found (this is normal)"):c?.errorCode==="user_cancelled"?o.enableLogging&&console.log("[MSAL] User cancelled authentication"):console.error("[MSAL] Redirect handling error:",c),window.location.hash&&(window.location.hash.includes("code=")||window.location.hash.includes("error="))&&window.history.replaceState(null,"",window.location.pathname+window.location.search);}let h=n.getAllAccounts();h.length>0&&!n.getActiveAccount()&&n.setActiveAccount(h[0]);let f=o.enableLogging||!1;n.addEventCallback(c=>{if(c.eventType===EventType.LOGIN_SUCCESS){let s=c.payload;s?.account&&n.setActiveAccount(s.account),f&&console.log("[MSAL] Login successful:",s.account?.username);}if(c.eventType===EventType.LOGIN_FAILURE&&console.error("[MSAL] Login failed:",c.error),c.eventType===EventType.LOGOUT_SUCCESS&&(n.setActiveAccount(null),f&&console.log("[MSAL] Logout successful")),c.eventType===EventType.ACQUIRE_TOKEN_SUCCESS){let s=c.payload;s?.account&&!n.getActiveAccount()&&n.setActiveAccount(s.account);}c.eventType===EventType.ACQUIRE_TOKEN_FAILURE&&f&&console.error("[MSAL] Token acquisition failed:",c.error);}),g.current=n,ce=n,a(n),t&&t(n);}catch(l){throw console.error("[MSAL] Initialization failed:",l),l}})();},[]),typeof window>"u"?jsx(Fragment,{children:e||jsx("div",{children:"Loading authentication..."})}):i?jsx(MsalProvider,{instance:i,children:r}):jsx(Fragment,{children:e||jsx("div",{children:"Loading authentication..."})})}var Ne=createContext(void 0);function Fe({children:r,protection:e,...t}){return jsx(Ne.Provider,{value:e,children:jsx(J,{...t,children:r})})}var K=new Map;function A(r=["User.Read"]){let{instance:e,accounts:t,inProgress:o}=useMsal(),i=useAccount(t[0]||null),a=useMemo(()=>t.length>0,[t]),g=useCallback(async(c=r)=>{if(o!==InteractionStatus.None){console.warn("[MSAL] Interaction already in progress");return}try{let s={scopes:c,prompt:"select_account"};await e.loginRedirect(s);}catch(s){if(s?.errorCode==="user_cancelled"){console.log("[MSAL] User cancelled login");return}throw console.error("[MSAL] Login redirect failed:",s),s}},[e,r,o]),u=useCallback(async()=>{try{await e.logoutRedirect({account:i||void 0});}catch(c){throw console.error("[MSAL] Logout redirect failed:",c),c}},[e,i]),l=useCallback(async(c=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:c,account:i,forceRefresh:!1};return (await e.acquireTokenSilent(s)).accessToken}catch(s){throw console.error("[MSAL] Silent token acquisition failed:",s),s}},[e,i,r]),n=useCallback(async(c=r)=>{if(!i)throw new Error("[MSAL] No active account. Please login first.");try{let s={scopes:c,account:i};await e.acquireTokenRedirect(s);}catch(s){throw console.error("[MSAL] Token redirect acquisition failed:",s),s}},[e,i,r]),h=useCallback(async(c=r)=>{let s=`${i?.homeAccountId||"anonymous"}-${c.sort().join(",")}`,m=K.get(s);if(m)return m;let p=(async()=>{try{return await l(c)}catch{throw console.warn("[MSAL] Silent token acquisition failed, falling back to redirect"),await n(c),new Error("[MSAL] Redirecting for token acquisition")}finally{K.delete(s);}})();return K.set(s,p),p},[l,n,r,i]),f=useCallback(async()=>{e.setActiveAccount(null),await e.clearCache();},[e]);return {account:i,accounts:t,isAuthenticated:a,inProgress:o!==InteractionStatus.None,loginRedirect:g,logoutRedirect:u,acquireToken:h,acquireTokenSilent:l,acquireTokenRedirect:n,clearSession:f}}function $e({text:r="Sign in with Microsoft",variant:e="dark",size:t="medium",scopes:o,className:i="",style:a,onSuccess:g,onError:u}){let{loginRedirect:l,inProgress:n}=A(),[h,f]=useState(false),c=async()=>{f(true);try{await l(o),g?.();}catch(y){u?.(y);}finally{setTimeout(()=>f(false),500);}},s={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},m={dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}},p=n||h,d={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:p?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:p?.6:1,...m[e],...s[t],...a};return jsxs("button",{onClick:c,disabled:p,className:i,style:d,"aria-label":r,children:[jsx(ze,{}),jsx("span",{children:r})]})}function ze(){return jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function qe({text:r="Sign out",variant:e="dark",size:t="medium",className:o="",style:i,onSuccess:a,onError:g}){let{logoutRedirect:u,inProgress:l}=A(),n=async()=>{try{await u(),a?.();}catch(s){g?.(s);}},h={small:{padding:"8px 16px",fontSize:"14px",height:"36px"},medium:{padding:"10px 20px",fontSize:"15px",height:"41px"},large:{padding:"12px 24px",fontSize:"16px",height:"48px"}},c={display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"12px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontWeight:600,borderRadius:"2px",cursor:l?"not-allowed":"pointer",transition:"all 0.2s ease",opacity:l?.6:1,...{dark:{backgroundColor:"#2F2F2F",color:"#FFFFFF",border:"1px solid #8C8C8C"},light:{backgroundColor:"#FFFFFF",color:"#5E5E5E",border:"1px solid #8C8C8C"}}[e],...h[t],...i};return jsxs("button",{onClick:n,disabled:l,className:o,style:c,"aria-label":r,children:[jsx(Be,{}),jsx("span",{children:r})]})}function Be(){return jsxs("svg",{width:"21",height:"21",viewBox:"0 0 21 21",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[jsx("rect",{width:"10",height:"10",fill:"#F25022"}),jsx("rect",{x:"11",width:"10",height:"10",fill:"#7FBA00"}),jsx("rect",{y:"11",width:"10",height:"10",fill:"#00A4EF"}),jsx("rect",{x:"11",y:"11",width:"10",height:"10",fill:"#FFB900"})]})}function N(){let{acquireToken:r}=A(),e=useCallback(async(u,l={})=>{let{scopes:n=["User.Read"],version:h="v1.0",debug:f=false,...c}=l;try{let s=await r(n),m=`https://graph.microsoft.com/${h}`,p=u.startsWith("http")?u:`${m}${u.startsWith("/")?u:`/${u}`}`;f&&console.log("[GraphAPI] Request:",{url:p,method:c.method||"GET"});let d=await fetch(p,{...c,headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json",...c.headers}});if(!d.ok){let R=await d.text(),M=`Graph API error (${d.status}): ${R}`;throw new Error(M)}if(d.status===204||d.headers.get("content-length")==="0")return null;let y=await d.json();return f&&console.log("[GraphAPI] Response:",y),y}catch(s){let m=w(s);throw console.error("[GraphAPI] Request failed:",m),new Error(m)}},[r]),t=useCallback((u,l={})=>e(u,{...l,method:"GET"}),[e]),o=useCallback((u,l,n={})=>e(u,{...n,method:"POST",body:l?JSON.stringify(l):void 0}),[e]),i=useCallback((u,l,n={})=>e(u,{...n,method:"PUT",body:l?JSON.stringify(l):void 0}),[e]),a=useCallback((u,l,n={})=>e(u,{...n,method:"PATCH",body:l?JSON.stringify(l):void 0}),[e]),g=useCallback((u,l={})=>e(u,{...l,method:"DELETE"}),[e]);return {get:t,post:o,put:i,patch:a,delete:g,request:e}}var x=new Map,_e=300*1e3,me=100;function Ve(){if(x.size>me){let r=Array.from(x.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,x.size-me).forEach(([t])=>{let o=x.get(t);o?.data.photo&&URL.revokeObjectURL(o.data.photo),x.delete(t);});}}function Q(){let{isAuthenticated:r,account:e}=A(),t=N(),[o,i]=useState(null),[a,g]=useState(false),[u,l]=useState(null),n=useCallback(async()=>{if(!r||!e){i(null);return}let f=e.homeAccountId,c=x.get(f);if(c&&Date.now()-c.timestamp<_e){i(c.data);return}g(true),l(null);try{let s=await t.get("/me",{scopes:["User.Read"]}),m;try{let d=await t.get("/me/photo/$value",{scopes:["User.Read"],headers:{"Content-Type":"image/jpeg"}});d&&(m=URL.createObjectURL(d));}catch{console.debug("[UserProfile] Photo not available");}let p={id:s.id,displayName:s.displayName,givenName:s.givenName,surname:s.surname,userPrincipalName:s.userPrincipalName,mail:s.mail,jobTitle:s.jobTitle,officeLocation:s.officeLocation,mobilePhone:s.mobilePhone,businessPhones:s.businessPhones,photo:m};x.set(f,{data:p,timestamp:Date.now()}),Ve(),i(p);}catch(s){let p=w(s),d=new Error(p);l(d),console.error("[UserProfile] Failed to fetch profile:",p);}finally{g(false);}},[r,e,t]),h=useCallback(()=>{if(e){let f=x.get(e.homeAccountId);f?.data.photo&&URL.revokeObjectURL(f.data.photo),x.delete(e.homeAccountId);}o?.photo&&URL.revokeObjectURL(o.photo),i(null);},[e,o]);return useEffect(()=>(n(),()=>{o?.photo&&URL.revokeObjectURL(o.photo);}),[n]),useEffect(()=>()=>{o?.photo&&URL.revokeObjectURL(o.photo);},[o?.photo]),{profile:o,loading:a,error:u,refetch:n,clearCache:h}}function We({size:r=40,className:e="",style:t,showTooltip:o=true,fallbackImage:i}){let{profile:a,loading:g}=Q(),[u,l]=useState(null),[n,h]=useState(false);useEffect(()=>{a?.photo&&l(a.photo);},[a?.photo]);let f=()=>{if(!a)return "?";let{givenName:m,surname:p,displayName:d}=a;if(m&&p)return `${m[0]}${p[0]}`.toUpperCase();if(d){let y=d.split(" ");return y.length>=2?`${y[0][0]}${y[y.length-1][0]}`.toUpperCase():d.substring(0,2).toUpperCase()}return "?"},c={width:`${r}px`,height:`${r}px`,borderRadius:"50%",display:"inline-flex",alignItems:"center",justifyContent:"center",fontSize:`${r*.4}px`,fontWeight:600,fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',backgroundColor:"#0078D4",color:"#FFFFFF",overflow:"hidden",userSelect:"none",...t},s=a?.displayName||"User";return g?jsx("div",{className:e,style:{...c,backgroundColor:"#E1E1E1"},"aria-label":"Loading user avatar",children:jsx("span",{style:{fontSize:`${r*.3}px`},children:"..."})}):u&&!n?jsx("div",{className:e,style:c,title:o?s:void 0,"aria-label":`${s} avatar`,children:jsx("img",{src:u,alt:s,style:{width:"100%",height:"100%",objectFit:"cover"},onError:()=>{h(true),i&&l(i);}})}):jsx("div",{className:e,style:c,title:o?s:void 0,"aria-label":`${s} avatar`,children:f()})}function je({className:r="",style:e,showDetails:t=false,renderLoading:o,renderAuthenticated:i,renderUnauthenticated:a}){let{isAuthenticated:g,inProgress:u,account:l}=A(),n={display:"inline-flex",alignItems:"center",gap:"8px",padding:"8px 12px",borderRadius:"4px",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',fontSize:"14px",fontWeight:500,...e};if(u)return o?jsx(Fragment,{children:o()}):jsxs("div",{className:r,style:{...n,backgroundColor:"#FFF4CE",color:"#8A6D3B"},role:"status","aria-live":"polite",children:[jsx(X,{color:"#FFA500"}),jsx("span",{children:"Loading..."})]});if(g){let h=l?.username||l?.name||"User";return i?jsx(Fragment,{children:i(h)}):jsxs("div",{className:r,style:{...n,backgroundColor:"#D4EDDA",color:"#155724"},role:"status","aria-live":"polite",children:[jsx(X,{color:"#28A745"}),jsx("span",{children:t?`Authenticated as ${h}`:"Authenticated"})]})}return a?jsx(Fragment,{children:a()}):jsxs("div",{className:r,style:{...n,backgroundColor:"#F8D7DA",color:"#721C24"},role:"status","aria-live":"polite",children:[jsx(X,{color:"#DC3545"}),jsx("span",{children:"Not authenticated"})]})}function X({color:r}){return jsx("svg",{width:"8",height:"8",viewBox:"0 0 8 8",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:jsx("circle",{cx:"4",cy:"4",r:"4",fill:r})})}function re({children:r,loadingComponent:e,fallbackComponent:t,scopes:o,onAuthRequired:i}){let{isAuthenticated:a,inProgress:g,loginRedirect:u}=A();return useEffect(()=>{!a&&!g&&(i?.(),(async()=>{try{await u(o);}catch(n){console.error("[AuthGuard] Authentication failed:",n);}})());},[a,g,o,u,i]),g?jsx(Fragment,{children:e||jsx("div",{children:"Authenticating..."})}):a?jsx(Fragment,{children:r}):jsx(Fragment,{children:t||jsx("div",{children:"Redirecting to login..."})})}var ne=class extends Component{constructor(t){super(t);this.reset=()=>{this.setState({hasError:false,error:null});};this.state={hasError:false,error:null};}static getDerivedStateFromError(t){return {hasError:true,error:t}}componentDidCatch(t,o){let{onError:i,debug:a}=this.props;a&&(console.error("[ErrorBoundary] Caught error:",t),console.error("[ErrorBoundary] Error info:",o)),i?.(t,o);}render(){let{hasError:t,error:o}=this.state,{children:i,fallback:a}=this.props;return t&&o?a?a(o,this.reset):jsxs("div",{style:{padding:"20px",margin:"20px",border:"1px solid #DC3545",borderRadius:"4px",backgroundColor:"#F8D7DA",color:"#721C24",fontFamily:'"Segoe UI", Tahoma, Geneva, Verdana, sans-serif'},children:[jsx("h2",{style:{margin:"0 0 10px 0",fontSize:"18px"},children:"Authentication Error"}),jsx("p",{style:{margin:"0 0 10px 0"},children:o.message}),jsx("button",{onClick:this.reset,style:{padding:"8px 16px",backgroundColor:"#DC3545",color:"#FFFFFF",border:"none",borderRadius:"4px",cursor:"pointer",fontSize:"14px",fontWeight:600},children:"Try Again"})]}):i}};var v=new Map,Xe=300*1e3,Ae=100;function Ye(r){r?v.delete(r):v.clear();}function et(){if(v.size>Ae){let r=Array.from(v.entries());r.sort((t,o)=>t[1].timestamp-o[1].timestamp),r.slice(0,v.size-Ae).forEach(([t])=>v.delete(t));}}function tt(){let{isAuthenticated:r,account:e}=A(),t=N(),[o,i]=useState([]),[a,g]=useState([]),[u,l]=useState(false),[n,h]=useState(null),f=useCallback(async()=>{if(!r||!e){i([]),g([]);return}let d=e.homeAccountId,y=v.get(d);if(y&&Date.now()-y.timestamp<Xe){i(y.roles),g(y.groups);return}l(true),h(null);try{let M=e.idTokenClaims?.roles||[],$=(await t.get("/me/memberOf",{scopes:["User.Read","Directory.Read.All"]})).value.map(se=>se.id);v.set(d,{roles:M,groups:$,timestamp:Date.now()}),et(),i(M),g($);}catch(R){let V=w(R),$=new Error(V);h($),console.error("[Roles] Failed to fetch roles/groups:",V);let Re=e.idTokenClaims?.roles||[];i(Re);}finally{l(false);}},[r,e,t]),c=useCallback(d=>o.includes(d),[o]),s=useCallback(d=>a.includes(d),[a]),m=useCallback(d=>d.some(y=>o.includes(y)),[o]),p=useCallback(d=>d.every(y=>o.includes(y)),[o]);return useEffect(()=>(f(),()=>{e&&Ye(e.homeAccountId);}),[f,e]),{roles:o,groups:a,loading:u,error:n,hasRole:c,hasGroup:s,hasAnyRole:m,hasAllRoles:p,refetch:f}}function rt(r,e={}){let{displayName:t,...o}=e,i=a=>jsx(re,{...o,children:jsx(r,{...a})});return i.displayName=t||`withAuth(${r.displayName||r.name||"Component"})`,i}async function Pe(r,e={}){let{maxRetries:t=3,initialDelay:o=1e3,maxDelay:i=1e4,backoffMultiplier:a=2,debug:g=false}=e,u,l=o;for(let n=0;n<=t;n++)try{return g&&n>0&&console.log(`[TokenRetry] Attempt ${n+1}/${t+1}`),await r()}catch(h){if(u=h,n===t){g&&console.error("[TokenRetry] All retry attempts failed");break}if(!ot(h))throw g&&console.log("[TokenRetry] Non-retryable error, aborting"),h;g&&console.warn(`[TokenRetry] Attempt ${n+1} failed, retrying in ${l}ms...`),await nt(l),l=Math.min(l*a,i);}throw u}function ot(r){let e=r.message.toLowerCase();return !!(e.includes("network")||e.includes("timeout")||e.includes("fetch")||e.includes("connection")||e.includes("500")||e.includes("502")||e.includes("503")||e.includes("429")||e.includes("rate limit")||e.includes("token")&&e.includes("expired"))}function nt(r){return new Promise(e=>setTimeout(e,r))}function it(r,e={}){return (...t)=>Pe(()=>r(...t),e)}var B=class{constructor(e={}){this.logHistory=[];this.performanceTimings=new Map;this.config={enabled:e.enabled??false,prefix:e.prefix??"[MSAL-Next]",showTimestamp:e.showTimestamp??true,level:e.level??"info",enablePerformance:e.enablePerformance??false,enableNetworkLogs:e.enableNetworkLogs??false,maxHistorySize:e.maxHistorySize??100};}shouldLog(e){if(!this.config.enabled)return false;let t=["error","warn","info","debug"],o=t.indexOf(this.config.level);return t.indexOf(e)<=o}formatMessage(e,t,o){let i=this.config.showTimestamp?`[${new Date().toISOString()}]`:"",a=this.config.prefix,g=`[${e.toUpperCase()}]`,u=`${i} ${a} ${g} ${t}`;return o!==void 0&&(u+=`
2
+ `+JSON.stringify(o,null,2)),u}addToHistory(e,t,o){this.logHistory.length>=this.config.maxHistorySize&&this.logHistory.shift(),this.logHistory.push({timestamp:Date.now(),level:e,message:t,data:o});}error(e,t){this.shouldLog("error")&&(console.error(this.formatMessage("error",e,t)),this.addToHistory("error",e,t));}warn(e,t){this.shouldLog("warn")&&(console.warn(this.formatMessage("warn",e,t)),this.addToHistory("warn",e,t));}info(e,t){this.shouldLog("info")&&(console.info(this.formatMessage("info",e,t)),this.addToHistory("info",e,t));}debug(e,t){this.shouldLog("debug")&&(console.debug(this.formatMessage("debug",e,t)),this.addToHistory("debug",e,t));}group(e){this.config.enabled&&console.group(`${this.config.prefix} ${e}`);}groupEnd(){this.config.enabled&&console.groupEnd();}startTiming(e){this.config.enablePerformance&&(this.performanceTimings.set(e,{operation:e,startTime:performance.now()}),this.debug(`\u23F1\uFE0F Started: ${e}`));}endTiming(e){if(this.config.enablePerformance){let t=this.performanceTimings.get(e);if(t)return t.endTime=performance.now(),t.duration=t.endTime-t.startTime,this.info(`\u23F1\uFE0F Completed: ${e} (${t.duration.toFixed(2)}ms)`),t.duration}}logRequest(e,t,o){this.config.enableNetworkLogs&&this.debug(`\u{1F310} ${e} ${t}`,o);}logResponse(e,t,o,i){if(this.config.enableNetworkLogs){let a=o>=200&&o<300?"\u2705":"\u274C";this.debug(`${a} ${e} ${t} - ${o}`,i);}}getHistory(){return [...this.logHistory]}getPerformanceTimings(){return Array.from(this.performanceTimings.values())}clearHistory(){this.logHistory=[];}clearTimings(){this.performanceTimings.clear();}exportLogs(){return JSON.stringify({config:this.config,history:this.logHistory,performanceTimings:Array.from(this.performanceTimings.values()),exportedAt:new Date().toISOString()},null,2)}downloadLogs(e="msal-next-debug-logs.json"){if(typeof window>"u")return;let t=this.exportLogs(),o=new Blob([t],{type:"application/json"}),i=URL.createObjectURL(o),a=document.createElement("a");a.href=i,a.download=e,a.click(),URL.revokeObjectURL(i);}setEnabled(e){this.config.enabled=e;}setLevel(e){e&&(this.config.level=e);}},O=null;function st(r){return O?r&&(r.enabled!==void 0&&O.setEnabled(r.enabled),r.level&&O.setLevel(r.level)):O=new B(r),O}function at(r,e){return new B({...e,prefix:`[MSAL-Next:${r}]`})}function _({children:r,config:e,defaultRedirectTo:t="/login",defaultLoading:o,defaultUnauthorized:i,debug:a=false}){let g=useRouter(),{isAuthenticated:u,account:l,inProgress:n}=A(),[h,f]=useState(true),[c,s]=useState(false);return useEffect(()=>{async function m(){if(a&&console.log("[ProtectedPage] Checking auth...",{isAuthenticated:u,inProgress:n,config:e}),!n){if(!e.required){s(true),f(false);return}if(!u||!l){a&&console.log("[ProtectedPage] Not authenticated, redirecting...");let p=e.redirectTo||t,d=encodeURIComponent(window.location.pathname+window.location.search);g.push(`${p}?returnUrl=${d}`);return}if(e.roles&&e.roles.length>0){let p=l.idTokenClaims?.roles||[];if(!e.roles.some(y=>p.includes(y))){a&&console.log("[ProtectedPage] Missing required role",{required:e.roles,user:p}),s(false),f(false);return}}if(e.validate)try{if(!await e.validate(l)){a&&console.log("[ProtectedPage] Custom validation failed"),s(!1),f(!1);return}}catch(p){console.error("[ProtectedPage] Validation error:",p),s(false),f(false);return}a&&console.log("[ProtectedPage] Authorization successful"),s(true),f(false);}}m();},[u,l,n,e,g,t,a]),h||n?e.loading?jsx(Fragment,{children:e.loading}):o?jsx(Fragment,{children:o}):jsx("div",{className:"flex items-center justify-center min-h-screen",children:jsx("div",{className:"animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"})}):c?jsx(Fragment,{children:r}):e.unauthorized?jsx(Fragment,{children:e.unauthorized}):i?jsx(Fragment,{children:i}):jsx("div",{className:"flex items-center justify-center min-h-screen",children:jsxs("div",{className:"text-center",children:[jsx("h1",{className:"text-2xl font-bold text-gray-900 mb-2",children:"Access Denied"}),jsx("p",{className:"text-gray-600",children:"You don't have permission to access this page."})]})})}function we(r,e,t){let o=i=>jsx(_,{config:e,defaultRedirectTo:t?.defaultRedirectTo,defaultLoading:t?.defaultLoading,defaultUnauthorized:t?.defaultUnauthorized,debug:t?.debug,children:jsx(r,{...i})});return o.displayName=`withPageAuth(${r.displayName||r.name||"Component"})`,o}function dt(r={}){let{protectedRoutes:e=[],publicOnlyRoutes:t=[],loginPath:o="/login",redirectAfterLogin:i="/",sessionCookie:a="msal.account",isAuthenticated:g,debug:u=false}=r;return async function(n){let{pathname:h}=n.nextUrl;u&&console.log("[AuthMiddleware] Processing:",h);let f=false;g?f=await g(n):f=!!n.cookies.get(a)?.value,u&&console.log("[AuthMiddleware] Authenticated:",f);let c=e.some(p=>h.startsWith(p)),s=t.some(p=>h.startsWith(p));if(c&&!f){u&&console.log("[AuthMiddleware] Redirecting to login");let p=n.nextUrl.clone();return p.pathname=o,p.searchParams.set("returnUrl",h),NextResponse.redirect(p)}if(s&&f){u&&console.log("[AuthMiddleware] Redirecting to home");let p=n.nextUrl.searchParams.get("returnUrl"),d=n.nextUrl.clone();return d.pathname=p||i,d.searchParams.delete("returnUrl"),NextResponse.redirect(d)}let m=NextResponse.next();if(f){m.headers.set("x-msal-authenticated","true");try{let p=n.cookies.get(a);if(p?.value){let d=H(p.value,W);d?.username&&m.headers.set("x-msal-username",d.username);}}catch{u&&console.warn("[AuthMiddleware] Failed to parse session data");}}return m}}export{re as AuthGuard,je as AuthStatus,ne as ErrorBoundary,Fe as MSALProvider,$e as MicrosoftSignInButton,J as MsalAuthProvider,_ as ProtectedPage,qe as SignOutButton,We as UserAvatar,dt as createAuthMiddleware,j as createMsalConfig,it as createRetryWrapper,at as createScopedLogger,st as getDebugLogger,Ue as getMsalInstance,W as isValidAccountData,z as isValidRedirectUri,ae as isValidScope,Pe as retryWithBackoff,H as safeJsonParse,w as sanitizeError,N as useGraphApi,A as useMsalAuth,tt as useRoles,Q as useUserProfile,Ce as validateScopes,rt as withAuth,we as withPageAuth};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chemmangat/msal-next",
3
- "version": "3.1.9",
3
+ "version": "4.0.0",
4
4
  "description": "Production-grade MSAL authentication package for Next.js App Router with minimal boilerplate",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",