exports.id=1890,exports.ids=[1890],exports.modules={12269:(e,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0})},19854:(e,r,t)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var o={};Object.defineProperty(r,"default",{enumerable:!0,get:function(){return i.default}});var n=t(12269);Object.keys(n).forEach(function(e){!("default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(o,e))&&(e in r&&r[e]===n[e]||Object.defineProperty(r,e,{enumerable:!0,get:function(){return n[e]}}))});var i=function(e,r){if(e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=s(r);if(t&&t.has(e))return t.get(e);var o={__proto__:null},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&({}).hasOwnProperty.call(e,i)){var a=n?Object.getOwnPropertyDescriptor(e,i):null;a&&(a.get||a.set)?Object.defineProperty(o,i,a):o[i]=e[i]}return o.default=e,t&&t.set(e,o),o}(t(35426));function s(e){if("function"!=typeof WeakMap)return null;var r=new WeakMap,t=new WeakMap;return(s=function(e){return e?t:r})(e)}Object.keys(i).forEach(function(e){!("default"===e||"__esModule"===e||Object.prototype.hasOwnProperty.call(o,e))&&(e in r&&r[e]===i[e]||Object.defineProperty(r,e,{enumerable:!0,get:function(){return i[e]}}))})},26690:(e,r,t)=>{"use strict";t.d(r,{N:()=>a});var o=t(1926),n=t(10591);function i(e){let r=process.env[e];if(!r)throw Error(`Missing required environment variable: ${e}`);return r}async function s(e){try{let r=await fetch(`${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/token`,{headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({client_id:process.env.KEYCLOAK_CLIENT_ID,client_secret:process.env.KEYCLOAK_CLIENT_SECRET,grant_type:"refresh_token",refresh_token:e.refreshToken||""}),method:"POST"}),t=await r.json();if(!r.ok){if("invalid_grant"===t.error||t.error_description?.includes("Session not active")||t.error_description?.includes("Token is not active"))return console.log("Keycloak session invalidated (likely logged out from iframe), marking token for removal"),{...e,error:"SessionNotActive"};throw t}return{...e,accessToken:t.access_token,refreshToken:t.refresh_token??e.refreshToken,idToken:e.idToken,accessTokenExpires:Date.now()+1e3*t.expires_in}}catch(r){if(console.error("Error refreshing access token:",r),r?.error==="invalid_grant"||r?.error_description?.includes("Session not active")||r?.error_description?.includes("Token is not active"))return{...e,error:"SessionNotActive"};return{...e,error:"RefreshAccessTokenError"}}}let a={providers:[(0,o.A)({clientId:i("KEYCLOAK_CLIENT_ID"),clientSecret:i("KEYCLOAK_CLIENT_SECRET"),issuer:i("KEYCLOAK_ISSUER"),authorization:{params:{scope:"openid profile email roles"}},profile(e){console.log("Keycloak profile callback:",{rawProfile:e,rawRoles:e.roles,realmAccess:e.realm_access,groups:e.groups});let r=e.realm_access?.roles||[];console.log("Profile callback raw roles:",r);let t=r.map(e=>e.replace(/^ROLE_/,"").toLowerCase());return console.log("Profile callback cleaned roles:",t),{id:e.sub,name:e.name??e.preferred_username,email:e.email,first_name:e.given_name??"",last_name:e.family_name??"",username:e.preferred_username??e.email?.split("@")[0]??"",role:t}}})],session:{strategy:"jwt",maxAge:2592e3},callbacks:{async jwt({token:e,account:r,profile:t}){if(r&&t){let o=(t.realm_access?.roles||[]).map(e=>e.replace(/^ROLE_/,"").toLowerCase());e.accessToken=r.access_token??"",e.refreshToken=r.refresh_token??"",e.idToken=r.id_token??"",e.accessTokenExpires=r.expires_at??0,e.sub=t.sub,e.role=o,e.username=t.preferred_username??"",e.first_name=t.given_name??"",e.last_name=t.family_name??""}else if(e.accessToken)try{let r=(0,n.s)(e.accessToken);r.realm_access?.roles&&(e.role=r.realm_access.roles.map(e=>e.replace(/^ROLE_/,"").toLowerCase()))}catch(e){console.error("Error decoding token:",e)}let o=e.accessTokenExpires;if(o&&Date.now(){"use strict";t.d(r,{J:()=>a});var o=t(19854),n=t(26690);class i{constructor(){this.sourceName="leantime",this.apiUrl=process.env.LEANTIME_API_URL||"",this.apiToken=process.env.LEANTIME_TOKEN||"",console.log("[LEANTIME_ADAPTER] Initialized with API URL and token")}async getNotifications(e,r=1,t=20){console.log(`[LEANTIME_ADAPTER] getNotifications called for userId: ${e}, page: ${r}, limit: ${t}`);try{let o=await this.getUserEmail();if(console.log("[LEANTIME_ADAPTER] Retrieved email from session:",o||"null"),!o)return console.error("[LEANTIME_ADAPTER] Could not get user email from session"),[];let n=await this.getLeantimeUserId(o);if(console.log(`[LEANTIME_ADAPTER] Retrieved Leantime userId for email ${o}:`,n||"null"),!n)return console.error("[LEANTIME_ADAPTER] User not found in Leantime:",o),[];console.log("[LEANTIME_ADAPTER] Sending request to get all notifications");let i={jsonrpc:"2.0",method:"leantime.rpc.Notifications.Notifications.getAllNotifications",params:{userId:n,showNewOnly:0,limitStart:(r-1)*t,limitEnd:t,filterOptions:[]},id:1};console.log("[LEANTIME_ADAPTER] Request body:",JSON.stringify(i));let s=await fetch(`${this.apiUrl}/api/jsonrpc`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiToken},body:JSON.stringify(i)});if(console.log("[LEANTIME_ADAPTER] Response status:",s.status),!s.ok){let e=await s.text();return console.error("[LEANTIME_ADAPTER] Failed to fetch Leantime notifications:",{status:s.status,body:e.substring(0,200)+(e.length>200?"...":"")}),[]}let a=await s.text();console.log("[LEANTIME_ADAPTER] Raw response (truncated):",a.substring(0,200)+(a.length>200?"...":""));let l=JSON.parse(a);if(console.log("[LEANTIME_ADAPTER] Parsed response data:",{hasResult:!!l.result,resultIsArray:Array.isArray(l.result),resultLength:Array.isArray(l.result)?l.result.length:"n/a",error:l.error}),!l.result||!Array.isArray(l.result))return l.error?console.error(`[LEANTIME_ADAPTER] API error: ${l.error.message||JSON.stringify(l.error)}`):console.error("[LEANTIME_ADAPTER] Invalid response format from Leantime notifications API"),[];let c=this.transformNotifications(l.result,e);return console.log("[LEANTIME_ADAPTER] Transformed notifications count:",c.length),c}catch(e){return console.error("[LEANTIME_ADAPTER] Error fetching Leantime notifications:",e),[]}}async getNotificationCount(e){console.log(`[LEANTIME_ADAPTER] getNotificationCount called for userId: ${e}`);try{let r=await this.getNotifications(e,1,100),t=r.length,o=r.filter(e=>!e.isRead).length;return console.log("[LEANTIME_ADAPTER] Notification counts:",{total:t,unread:o}),{total:t,unread:o,sources:{leantime:{total:t,unread:o}}}}catch(e){return console.error("[LEANTIME_ADAPTER] Error fetching notification count:",e),{total:0,unread:0,sources:{leantime:{total:0,unread:0}}}}}async markAsRead(e,r){console.log(`[LEANTIME_ADAPTER] markAsRead called for ${r}`);try{let e=r.replace(`${this.sourceName}-`,""),t=await this.getUserEmail();if(!t)return console.error("[LEANTIME_ADAPTER] Could not get user email from session"),!1;let o=await this.getLeantimeUserId(t);if(!o)return console.error("[LEANTIME_ADAPTER] User not found in Leantime:",t),!1;let n={jsonrpc:"2.0",method:"leantime.rpc.Notifications.Notifications.markNotificationAsRead",params:{userId:o,notificationId:parseInt(e)},id:1},i=await fetch(`${this.apiUrl}/api/jsonrpc`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiToken},body:JSON.stringify(n)});if(!i.ok)return console.error(`[LEANTIME_ADAPTER] Failed to mark notification as read: ${i.status}`),!1;let s=await i.json();return!0===s.result||"true"===s.result||!!s.result}catch(e){return console.error("[LEANTIME_ADAPTER] Error marking notification as read:",e),!1}}async markAllAsRead(e){console.log(`[LEANTIME_ADAPTER] markAllAsRead called for ${e}`);try{let e=await this.getUserEmail();if(!e)return console.error("[LEANTIME_ADAPTER] Could not get user email from session"),!1;let r=await this.getLeantimeUserId(e);if(!r)return console.error("[LEANTIME_ADAPTER] User not found in Leantime:",e),!1;let t=await fetch(`${this.apiUrl}/api/jsonrpc`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiToken},body:JSON.stringify({jsonrpc:"2.0",method:"leantime.rpc.Notifications.Notifications.markAllNotificationsAsRead",params:{userId:r},id:1})});if(!t.ok)return console.error(`[LEANTIME_ADAPTER] Failed to mark all notifications as read: ${t.status}`),!1;let o=await t.json();return!0===o.result||"true"===o.result||!!o.result}catch(e){return console.error("[LEANTIME_ADAPTER] Error marking all notifications as read:",e),!1}}async isConfigured(){return!!(this.apiUrl&&this.apiToken)}transformNotifications(e,r){return Array.isArray(e)?e.map(e=>{let t=e.id||e._id||e.notificationId,o=e.message||e.text||e.content||"",n=e.type||"notification",i=e.read||e.isRead||0,s=e.date||e.datetime||e.createdDate||new Date().toISOString(),a=e.url||e.link||"";return{id:`${this.sourceName}-${t}`,source:this.sourceName,sourceId:t.toString(),type:n,title:n,message:o,link:a.startsWith("http")?a:`${this.apiUrl}${a.startsWith("/")?"":"/"}${a}`,isRead:1===i||!0===i,timestamp:new Date(s),priority:"normal",user:{id:r,name:e.username||e.userName||""},metadata:{moduleId:e.moduleId||e.module||"",projectId:e.projectId||""}}}):[]}async getUserEmail(){try{let e=await (0,o.getServerSession)(n.N);if(!e||!e.user?.email)return null;return e.user.email}catch(e){return console.error("[LEANTIME_ADAPTER] Error getting user email from session:",e),null}}async getLeantimeUserId(e){try{if(!this.apiToken)return null;let r=await fetch(`${this.apiUrl}/api/jsonrpc`,{method:"POST",headers:{"Content-Type":"application/json","X-API-Key":this.apiToken},body:JSON.stringify({jsonrpc:"2.0",method:"leantime.rpc.users.getAll",id:1})});if(!r.ok)return null;let t=await r.json();if(!t.result||!Array.isArray(t.result))return null;let o=t.result.find(r=>r.username===e||r.email===e||"string"==typeof r.username&&r.username.toLowerCase()===e.toLowerCase());if(o)return o.id;return null}catch(e){return console.error("[LEANTIME_ADAPTER] Error getting Leantime user ID:",e),null}}}var s=t(36781);class a{static{this.NOTIFICATION_COUNT_CACHE_KEY=e=>`notifications:count:${e}`}static{this.NOTIFICATIONS_LIST_CACHE_KEY=(e,r,t)=>`notifications:list:${e}:${r}:${t}`}static{this.COUNT_CACHE_TTL=30}static{this.LIST_CACHE_TTL=300}static{this.REFRESH_LOCK_KEY=e=>`notifications:refresh:lock:${e}`}static{this.REFRESH_LOCK_TTL=30}constructor(){this.adapters=new Map,console.log("[NOTIFICATION_SERVICE] Initializing notification service"),this.registerAdapter(new i),console.log("[NOTIFICATION_SERVICE] Registered adapters:",Array.from(this.adapters.keys()))}static getInstance(){return a.instance||(console.log("[NOTIFICATION_SERVICE] Creating new notification service instance"),a.instance=new a),a.instance}registerAdapter(e){this.adapters.set(e.sourceName,e),console.log(`[NOTIFICATION_SERVICE] Registered notification adapter: ${e.sourceName}`)}async getNotifications(e,r=1,t=20){console.log(`[NOTIFICATION_SERVICE] getNotifications called for user ${e}, page ${r}, limit ${t}`);let o=(0,s.nr)(),n=a.NOTIFICATIONS_LIST_CACHE_KEY(e,r,t);try{let r=await o.get(n);if(r)return console.log(`[NOTIFICATION_SERVICE] Using cached notifications for user ${e}`),await o.ttl(n)e).join(", ")}`);let c=l.map(async([o,n])=>{console.log(`[NOTIFICATION_SERVICE] Checking if adapter ${o} is configured`);try{let i=await n.isConfigured();if(console.log(`[NOTIFICATION_SERVICE] Adapter ${o} is configured: ${i}`),!i)return console.log(`[NOTIFICATION_SERVICE] Skipping adapter ${o} as it is not configured`),[];{console.log(`[NOTIFICATION_SERVICE] Fetching notifications from ${o} for user ${e}`);let i=await n.getNotifications(e,r,t);return console.log(`[NOTIFICATION_SERVICE] Got ${i.length} notifications from ${o}`),i}}catch(e){return console.error(`[NOTIFICATION_SERVICE] Error fetching notifications from ${o}:`,e),[]}});(await Promise.all(c)).forEach((e,r)=>{let t=l[r][0];console.log(`[NOTIFICATION_SERVICE] Adding ${e.length} notifications from ${t}`),i.push(...e)}),i.sort((e,r)=>r.timestamp.getTime()-e.timestamp.getTime()),console.log(`[NOTIFICATION_SERVICE] Total notifications after sorting: ${i.length}`);try{await o.set(n,JSON.stringify(i),"EX",a.LIST_CACHE_TTL),console.log(`[NOTIFICATION_SERVICE] Cached ${i.length} notifications for user ${e}`)}catch(e){console.error("[NOTIFICATION_SERVICE] Error caching notifications:",e)}return i}async getNotificationCount(e){console.log(`[NOTIFICATION_SERVICE] getNotificationCount called for user ${e}`);let r=(0,s.nr)(),t=a.NOTIFICATION_COUNT_CACHE_KEY(e);try{let o=await r.get(t);if(o)return console.log(`[NOTIFICATION_SERVICE] Using cached notification counts for user ${e}`),await r.ttl(t)e).join(", ")}`);let i=n.map(async([r,t])=>{console.log(`[NOTIFICATION_SERVICE] Checking if adapter ${r} is configured for count`);try{let o=await t.isConfigured();if(console.log(`[NOTIFICATION_SERVICE] Adapter ${r} is configured for count: ${o}`),!o)return console.log(`[NOTIFICATION_SERVICE] Skipping adapter ${r} for count as it is not configured`),null;{console.log(`[NOTIFICATION_SERVICE] Fetching notification count from ${r} for user ${e}`);let o=await t.getNotificationCount(e);return console.log(`[NOTIFICATION_SERVICE] Got count from ${r}:`,o),o}}catch(e){return console.error(`[NOTIFICATION_SERVICE] Error fetching notification count from ${r}:`,e),null}});(await Promise.all(i)).forEach((e,r)=>{if(!e)return;let t=n[r][0];console.log(`[NOTIFICATION_SERVICE] Adding counts from ${t}: total=${e.total}, unread=${e.unread}`),o.total+=e.total,o.unread+=e.unread,Object.entries(e.sources).forEach(([e,r])=>{o.sources[e]=r})}),console.log(`[NOTIFICATION_SERVICE] Aggregated counts for user ${e}:`,o);try{await r.set(t,JSON.stringify(o),"EX",a.COUNT_CACHE_TTL),console.log(`[NOTIFICATION_SERVICE] Cached notification counts for user ${e}`)}catch(e){console.error("[NOTIFICATION_SERVICE] Error caching notification counts:",e)}return o}async markAsRead(e,r){let[t,...o]=r.split("-");if(o.join("-"),!t||!this.adapters.has(t))return!1;let n=this.adapters.get(t),i=await n.markAsRead(e,r);return i&&await this.invalidateCache(e),i}async markAllAsRead(e){let r=Array.from(this.adapters.values()).map(r=>r.isConfigured().then(t=>!t||r.markAllAsRead(e)).catch(e=>(console.error(`Error marking all notifications as read for ${r.sourceName}:`,e),!1))),t=(await Promise.all(r)).every(e=>e);return t&&await this.invalidateCache(e),t}async invalidateCache(e){try{let r=(0,s.nr)(),t=a.NOTIFICATION_COUNT_CACHE_KEY(e),o=`notifications:list:${e}:*`;await r.del(t);let n=await r.keys(o);n.length>0&&await r.del(...n),console.log(`[NOTIFICATION_SERVICE] Invalidated notification caches for user ${e}`)}catch(e){console.error("Error invalidating notification caches:",e)}}async scheduleBackgroundRefresh(e){let r=(0,s.nr)(),t=a.REFRESH_LOCK_KEY(e);await r.set(t,Date.now().toString(),"EX",a.REFRESH_LOCK_TTL,"NX")&&setTimeout(async()=>{try{let t=`notifications:last_refresh:${e}`,o=await r.get(t);if(o){let r=parseInt(o,10);if(Date.now()-r<6e4)return void console.log(`[NOTIFICATION_SERVICE] Skipping background refresh for user ${e} - refreshed recently`)}console.log(`[NOTIFICATION_SERVICE] Background refresh started for user ${e}`),await r.set(t,Date.now().toString(),"EX",120),await this.getNotificationCount(e),await this.getNotifications(e,1,20),console.log(`[NOTIFICATION_SERVICE] Background refresh completed for user ${e}`)}catch(r){console.error(`[NOTIFICATION_SERVICE] Background refresh failed for user ${e}:`,r)}finally{await r.del(t).catch(()=>{})}},0)}}},78335:()=>{},96487:()=>{}};