@@ -10,15 +10,15 @@ import { log } from "./log.js";
1010 * - Web/Mobile: Sends web push notifications to subscribed clients
1111 */
1212export class NotificationService {
13- private isDesktop : boolean ;
13+ private readonly isDesktop : boolean ;
1414 private vapidKeys : VapidKeys | null = null ;
1515 private subscriptions = new Map < string , PushSubscription [ ] > ( ) ; // workspaceId -> subscriptions
16- private vapidKeysPath : string ;
16+ private readonly vapidKeysPath : string ;
1717
1818 constructor ( configDir : string , isDesktop : boolean ) {
1919 this . isDesktop = isDesktop ;
2020 this . vapidKeysPath = path . join ( configDir , "vapid.json" ) ;
21-
21+
2222 // Load or generate VAPID keys for web push
2323 if ( ! isDesktop ) {
2424 this . initializeVapidKeys ( ) ;
@@ -28,11 +28,15 @@ export class NotificationService {
2828 /**
2929 * Initialize VAPID keys for web push authentication
3030 * Generates new keys if they don't exist, otherwise loads from disk
31+ * Note: Uses sync fs methods during startup initialization (before async operations start)
3132 */
3233 private initializeVapidKeys ( ) : void {
3334 try {
35+ // eslint-disable-next-line local/no-sync-fs-methods -- Startup initialization needs sync
3436 if ( fs . existsSync ( this . vapidKeysPath ) ) {
37+ // eslint-disable-next-line local/no-sync-fs-methods -- Startup initialization needs sync
3538 const keysJson = fs . readFileSync ( this . vapidKeysPath , "utf-8" ) ;
39+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- JSON parse is safe for VAPID keys
3640 this . vapidKeys = JSON . parse ( keysJson ) ;
3741 log . info ( "Loaded existing VAPID keys" ) ;
3842 } else {
@@ -41,6 +45,7 @@ export class NotificationService {
4145 publicKey : keys . publicKey ,
4246 privateKey : keys . privateKey ,
4347 } ;
48+ // eslint-disable-next-line local/no-sync-fs-methods -- Startup initialization needs sync
4449 fs . writeFileSync ( this . vapidKeysPath , JSON . stringify ( this . vapidKeys , null , 2 ) ) ;
4550 log . info ( "Generated and saved new VAPID keys" ) ;
4651 }
@@ -70,9 +75,9 @@ export class NotificationService {
7075 */
7176 subscribePush ( workspaceId : string , subscription : PushSubscription ) : void {
7277 const existing = this . subscriptions . get ( workspaceId ) ?? [ ] ;
73-
78+
7479 // Check if subscription already exists (by endpoint)
75- const isDuplicate = existing . some ( sub => sub . endpoint === subscription . endpoint ) ;
80+ const isDuplicate = existing . some ( ( sub ) => sub . endpoint === subscription . endpoint ) ;
7681 if ( isDuplicate ) {
7782 log . debug ( `Subscription already exists for workspace ${ workspaceId } ` ) ;
7883 return ;
@@ -88,8 +93,8 @@ export class NotificationService {
8893 */
8994 unsubscribePush ( workspaceId : string , endpoint : string ) : void {
9095 const existing = this . subscriptions . get ( workspaceId ) ?? [ ] ;
91- const filtered = existing . filter ( sub => sub . endpoint !== endpoint ) ;
92-
96+ const filtered = existing . filter ( ( sub ) => sub . endpoint !== endpoint ) ;
97+
9398 if ( filtered . length < existing . length ) {
9499 this . subscriptions . set ( workspaceId , filtered ) ;
95100 log . info ( `Removed push subscription for workspace ${ workspaceId } ` ) ;
@@ -135,16 +140,16 @@ export class NotificationService {
135140 } ) ;
136141
137142 const results = await Promise . allSettled ( sendPromises ) ;
138-
143+
139144 // Remove failed subscriptions
140145 const validSubscriptions = results
141- . filter ( ( result , index ) => {
146+ . filter ( ( result ) => {
142147 if ( result . status === "fulfilled" && result . value . success ) {
143148 return true ;
144149 }
145150 return false ;
146151 } )
147- . map ( ( result , index ) => subscriptions [ index ] ) ;
152+ . map ( ( _result , index ) => subscriptions [ index ] ) ;
148153
149154 this . subscriptions . set ( workspaceId , validSubscriptions ) ;
150155 }
0 commit comments