@todesktop/plugin-recall 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js ADDED
@@ -0,0 +1,694 @@
1
+ 'use strict';
2
+
3
+ var electron = require('electron');
4
+
5
+ /**
6
+ * Shared types and constants for Recall Desktop SDK integration
7
+ */
8
+ // IPC channel names - use unique namespace to avoid conflicts
9
+ const IPC_CHANNELS = {
10
+ // SDK lifecycle
11
+ INIT_SDK: 'recall-desktop:init-sdk',
12
+ SHUTDOWN_SDK: 'recall-desktop:shutdown-sdk',
13
+ GET_STATUS: 'recall-desktop:get-status',
14
+ // Recording management
15
+ START_RECORDING: 'recall-desktop:start-recording',
16
+ STOP_RECORDING: 'recall-desktop:stop-recording',
17
+ PAUSE_RECORDING: 'recall-desktop:pause-recording',
18
+ RESUME_RECORDING: 'recall-desktop:resume-recording',
19
+ UPLOAD_RECORDING: 'recall-desktop:upload-recording',
20
+ // Desktop audio recording
21
+ PREPARE_DESKTOP_AUDIO: 'recall-desktop:prepare-desktop-audio',
22
+ // Permission management
23
+ REQUEST_PERMISSION: 'recall-desktop:request-permission',
24
+ // Configuration
25
+ SET_CONFIG: 'recall-desktop:set-config',
26
+ GET_CONFIG: 'recall-desktop:get-config',
27
+ // Event subscription
28
+ SUBSCRIBE_EVENTS: 'recall-desktop:subscribe-events',
29
+ UNSUBSCRIBE_EVENTS: 'recall-desktop:unsubscribe-events',
30
+ };
31
+ // Error types
32
+ class RecallSdkError extends Error {
33
+ constructor(message, code) {
34
+ super(message);
35
+ this.code = code;
36
+ this.name = 'RecallSdkError';
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Recall Desktop SDK plugin state management and storage
42
+ */
43
+ class RecallSdkStore {
44
+ constructor() {
45
+ this.config = {
46
+ enabled: true,
47
+ apiUrl: 'https://us-east-1.recall.ai',
48
+ requestPermissionsOnStartup: true,
49
+ };
50
+ this.initialized = false;
51
+ this.sdkInitialized = false;
52
+ this.currentSdkState = 'idle';
53
+ // Active meetings and recordings
54
+ this.activeMeetings = new Map();
55
+ this.activeRecordings = new Map();
56
+ // Permission status
57
+ this.permissions = {
58
+ accessibility: false,
59
+ screenCapture: false,
60
+ microphone: false,
61
+ systemAudio: false,
62
+ };
63
+ // Event listeners for SDK events
64
+ this.eventListeners = new Set();
65
+ }
66
+ /**
67
+ * Initialize the plugin store
68
+ */
69
+ async initialize() {
70
+ // Load configuration from ToDesktop preferences
71
+ try {
72
+ // In a real implementation, this would load from ToDesktop's preference system
73
+ // For now, we'll use the defaults
74
+ this.initialized = true;
75
+ console.log('RecallSdkStore: Initialized successfully');
76
+ }
77
+ catch (error) {
78
+ console.error('RecallSdkStore: Failed to initialize:', error);
79
+ throw error;
80
+ }
81
+ }
82
+ /**
83
+ * Get current plugin configuration
84
+ */
85
+ getConfig() {
86
+ return { ...this.config };
87
+ }
88
+ /**
89
+ * Update plugin configuration
90
+ */
91
+ setConfig(updates) {
92
+ this.config = { ...this.config, ...updates };
93
+ console.log('RecallSdkStore: Configuration updated:', this.config);
94
+ }
95
+ /**
96
+ * Load configuration from ToDesktop preferences
97
+ */
98
+ loadFromPreferences(preferences) {
99
+ if (preferences.enabled !== undefined) {
100
+ this.config.enabled = preferences.enabled;
101
+ }
102
+ if (preferences.apiUrl !== undefined) {
103
+ this.config.apiUrl = preferences.apiUrl;
104
+ }
105
+ // autoRecord removed by design
106
+ if (preferences.requestPermissionsOnStartup !== undefined) {
107
+ this.config.requestPermissionsOnStartup = preferences.requestPermissionsOnStartup;
108
+ }
109
+ console.log('RecallSdkStore: Loaded configuration from preferences:', this.config);
110
+ }
111
+ /**
112
+ * Check if plugin is initialized
113
+ */
114
+ isInitialized() {
115
+ return this.initialized;
116
+ }
117
+ /**
118
+ * Check if plugin is enabled
119
+ */
120
+ isEnabled() {
121
+ return this.config.enabled;
122
+ }
123
+ /**
124
+ * Set SDK initialization status
125
+ */
126
+ setSdkInitialized(initialized) {
127
+ this.sdkInitialized = initialized;
128
+ }
129
+ /**
130
+ * Check if SDK is initialized
131
+ */
132
+ isSdkInitialized() {
133
+ return this.sdkInitialized;
134
+ }
135
+ /**
136
+ * Set current SDK state
137
+ */
138
+ setSdkState(state) {
139
+ this.currentSdkState = state;
140
+ }
141
+ /**
142
+ * Get current SDK state
143
+ */
144
+ getSdkState() {
145
+ return this.currentSdkState;
146
+ }
147
+ /**
148
+ * Add an active meeting
149
+ */
150
+ addMeeting(meeting) {
151
+ this.activeMeetings.set(meeting.id, meeting);
152
+ console.log(`RecallSdkStore: Added meeting ${meeting.id}:`, meeting);
153
+ }
154
+ /**
155
+ * Remove a meeting
156
+ */
157
+ removeMeeting(windowId) {
158
+ this.activeMeetings.delete(windowId);
159
+ console.log(`RecallSdkStore: Removed meeting ${windowId}`);
160
+ }
161
+ /**
162
+ * Get active meeting by window ID
163
+ */
164
+ getMeeting(windowId) {
165
+ return this.activeMeetings.get(windowId);
166
+ }
167
+ /**
168
+ * Get all active meetings
169
+ */
170
+ getAllMeetings() {
171
+ return Array.from(this.activeMeetings.values());
172
+ }
173
+ /**
174
+ * Start a recording
175
+ */
176
+ startRecording(windowId, uploadToken) {
177
+ const window = this.activeMeetings.get(windowId);
178
+ if (window) {
179
+ this.activeRecordings.set(windowId, { window, uploadToken });
180
+ console.log(`RecallSdkStore: Started recording for ${windowId}`);
181
+ }
182
+ }
183
+ /**
184
+ * Stop a recording
185
+ */
186
+ stopRecording(windowId) {
187
+ this.activeRecordings.delete(windowId);
188
+ console.log(`RecallSdkStore: Stopped recording for ${windowId}`);
189
+ }
190
+ /**
191
+ * Get active recording by window ID
192
+ */
193
+ getRecording(windowId) {
194
+ return this.activeRecordings.get(windowId);
195
+ }
196
+ /**
197
+ * Get all active recordings
198
+ */
199
+ getAllRecordings() {
200
+ return Array.from(this.activeRecordings.values());
201
+ }
202
+ /**
203
+ * Update permission status
204
+ */
205
+ setPermissionStatus(permission, status) {
206
+ const granted = status === 'granted' || status === 'authorized' || status === 'ALLOWED';
207
+ if (permission === 'screen-capture') {
208
+ this.permissions.screenCapture = granted;
209
+ }
210
+ else if (permission === 'system-audio') {
211
+ this.permissions.systemAudio = granted;
212
+ }
213
+ else {
214
+ // permission is 'accessibility' | 'microphone'
215
+ // @ts-ignore - index by key
216
+ this.permissions[permission] = granted;
217
+ }
218
+ console.log(`RecallSdkStore: Permission ${permission} status: ${status}`);
219
+ }
220
+ /**
221
+ * Get permission status
222
+ */
223
+ getPermissions() {
224
+ return { ...this.permissions };
225
+ }
226
+ /**
227
+ * Check if all required permissions are granted
228
+ */
229
+ arePermissionsGranted() {
230
+ return (this.permissions.accessibility &&
231
+ this.permissions.screenCapture &&
232
+ this.permissions.microphone);
233
+ }
234
+ /**
235
+ * Add event listener for SDK events
236
+ */
237
+ addEventListener(listener) {
238
+ this.eventListeners.add(listener);
239
+ }
240
+ /**
241
+ * Remove event listener
242
+ */
243
+ removeEventListener(listener) {
244
+ this.eventListeners.delete(listener);
245
+ }
246
+ /**
247
+ * Emit event to all listeners
248
+ */
249
+ emitEvent(event) {
250
+ this.eventListeners.forEach(listener => {
251
+ try {
252
+ listener(event);
253
+ }
254
+ catch (error) {
255
+ console.error('RecallSdkStore: Error in event listener:', error);
256
+ }
257
+ });
258
+ }
259
+ /**
260
+ * Clear all state (useful for shutdown/reset)
261
+ */
262
+ clearState() {
263
+ this.activeMeetings.clear();
264
+ this.activeRecordings.clear();
265
+ this.setSdkInitialized(false);
266
+ this.setSdkState('idle');
267
+ this.permissions = {
268
+ accessibility: false,
269
+ screenCapture: false,
270
+ microphone: false,
271
+ systemAudio: false,
272
+ };
273
+ console.log('RecallSdkStore: Cleared all state');
274
+ }
275
+ }
276
+ const recallSdkStore = new RecallSdkStore();
277
+
278
+ /**
279
+ * ToDesktop Recall Desktop SDK Plugin - Main Process
280
+ *
281
+ * This file runs in Electron's main process and handles:
282
+ * - Recall Desktop SDK integration and lifecycle management
283
+ * - IPC communication with renderer processes
284
+ * - Meeting detection and recording management
285
+ * - Event forwarding from SDK to frontend
286
+ */
287
+ let RecallAiSdk;
288
+ try {
289
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
290
+ const mod = require('@recallai/desktop-sdk');
291
+ RecallAiSdk = (mod && mod.default) ? mod.default : mod;
292
+ }
293
+ catch {
294
+ RecallAiSdk = {
295
+ init: async (config) => { console.log('RecallAiSdk.init called with:', config); return null; },
296
+ shutdown: async () => { console.log('RecallAiSdk.shutdown called'); return null; },
297
+ startRecording: async (params) => { console.log('RecallAiSdk.startRecording called with:', params); return null; },
298
+ stopRecording: async (params) => { console.log('RecallAiSdk.stopRecording called with:', params); return null; },
299
+ pauseRecording: async (params) => { console.log('RecallAiSdk.pauseRecording called with:', params); return null; },
300
+ resumeRecording: async (params) => { console.log('RecallAiSdk.resumeRecording called with:', params); return null; },
301
+ uploadRecording: async (params) => { console.log('RecallAiSdk.uploadRecording called with:', params); return null; },
302
+ prepareDesktopAudioRecording: async () => { console.log('RecallAiSdk.prepareDesktopAudioRecording called'); return 'mock-window-id'; },
303
+ requestPermission: async (permission) => { console.log(`RecallAiSdk.requestPermission called for: ${permission}`); return null; },
304
+ addEventListener: (_eventType) => { },
305
+ };
306
+ }
307
+ class RecallDesktopMain {
308
+ constructor() {
309
+ this.version = '1.0.0';
310
+ this.isInitialized = false;
311
+ this.subscriptions = new Map();
312
+ this.trackedWebContents = new Map();
313
+ }
314
+ async initialize() {
315
+ try {
316
+ // Initialize plugin store
317
+ await recallSdkStore.initialize();
318
+ // Load configuration from ToDesktop preferences
319
+ // In a real implementation, this would integrate with ToDesktop's preference system
320
+ this.loadPreferences();
321
+ // Register IPC handlers
322
+ this.registerIpcHandlers();
323
+ // Initialize SDK if plugin is enabled
324
+ if (recallSdkStore.isEnabled()) {
325
+ await this.initializeSdk();
326
+ }
327
+ this.isInitialized = true;
328
+ console.log('RecallDesktopMain: Main process initialized');
329
+ }
330
+ catch (error) {
331
+ console.error('RecallDesktopMain: Failed to initialize main process:', error);
332
+ throw error;
333
+ }
334
+ }
335
+ loadPreferences() {
336
+ // In a real implementation, this would load from ToDesktop's preference system
337
+ // For now, we'll use defaults
338
+ const preferences = {
339
+ enabled: true,
340
+ apiUrl: 'https://us-east-1.recall.ai',
341
+ requestPermissionsOnStartup: true,
342
+ };
343
+ recallSdkStore.loadFromPreferences(preferences);
344
+ }
345
+ async initializeSdk() {
346
+ try {
347
+ const config = recallSdkStore.getConfig();
348
+ const sdkOptions = {
349
+ apiUrl: config.apiUrl,
350
+ acquirePermissionsOnStartup: config.requestPermissionsOnStartup
351
+ ? ['accessibility', 'screen-capture', 'microphone', 'system-audio']
352
+ : undefined,
353
+ restartOnError: true,
354
+ };
355
+ // Initialize the Recall SDK
356
+ await RecallAiSdk.init(sdkOptions);
357
+ // Set up event listeners
358
+ this.setupSdkEventListeners();
359
+ recallSdkStore.setSdkInitialized(true);
360
+ console.log('RecallDesktopMain: SDK initialized successfully');
361
+ }
362
+ catch (error) {
363
+ console.error('RecallDesktopMain: Failed to initialize SDK:', error);
364
+ throw new RecallSdkError('SDK initialization failed', 'SDK_INIT_ERROR');
365
+ }
366
+ }
367
+ setupSdkEventListeners() {
368
+ const broadcast = (type, data) => {
369
+ const channel = `recall-desktop:event:${type}`;
370
+ const subs = this.subscriptions.get(type);
371
+ if (!subs)
372
+ return;
373
+ subs.forEach((_count, wcId) => {
374
+ const wc = this.trackedWebContents.get(wcId);
375
+ if (!wc)
376
+ return;
377
+ try {
378
+ wc.send(channel, data);
379
+ }
380
+ catch (err) {
381
+ console.error('RecallDesktopMain: Failed to send event to webContents', wcId, err);
382
+ }
383
+ });
384
+ };
385
+ // Permissions granted
386
+ RecallAiSdk.addEventListener('permissions-granted', (evt) => {
387
+ console.log('RecallDesktopMain: Permissions granted');
388
+ const type = 'permissions-granted';
389
+ recallSdkStore.emitEvent({ type, data: evt });
390
+ broadcast(type, evt);
391
+ });
392
+ // Meeting detected
393
+ RecallAiSdk.addEventListener('meeting-detected', (evt) => {
394
+ console.log('RecallDesktopMain: Meeting detected:', evt);
395
+ const meeting = evt.window;
396
+ recallSdkStore.addMeeting(meeting);
397
+ const type = 'meeting-detected';
398
+ recallSdkStore.emitEvent({ type, data: evt });
399
+ broadcast(type, evt);
400
+ });
401
+ // SDK state change
402
+ RecallAiSdk.addEventListener('sdk-state-change', (evt) => {
403
+ console.log('RecallDesktopMain: SDK state change:', evt);
404
+ const state = evt.sdk.state.code;
405
+ recallSdkStore.setSdkState(state);
406
+ const type = 'sdk-state-change';
407
+ recallSdkStore.emitEvent({ type, data: evt });
408
+ broadcast(type, evt);
409
+ });
410
+ // Recording started
411
+ RecallAiSdk.addEventListener('recording-started', (evt) => {
412
+ console.log('RecallDesktopMain: Recording started:', evt);
413
+ const type = 'recording-started';
414
+ recallSdkStore.emitEvent({ type, data: evt });
415
+ broadcast(type, evt);
416
+ });
417
+ // Recording ended
418
+ RecallAiSdk.addEventListener('recording-ended', (evt) => {
419
+ console.log('RecallDesktopMain: Recording ended:', evt);
420
+ recallSdkStore.stopRecording(evt.window.id);
421
+ const type = 'recording-ended';
422
+ recallSdkStore.emitEvent({ type, data: evt });
423
+ broadcast(type, evt);
424
+ });
425
+ // Meeting closed
426
+ RecallAiSdk.addEventListener('meeting-closed', (evt) => {
427
+ console.log('RecallDesktopMain: Meeting closed:', evt);
428
+ recallSdkStore.removeMeeting(evt.window.id);
429
+ const type = 'meeting-closed';
430
+ recallSdkStore.emitEvent({ type, data: evt });
431
+ broadcast(type, evt);
432
+ });
433
+ // Upload progress
434
+ RecallAiSdk.addEventListener('upload-progress', (evt) => {
435
+ console.log(`RecallDesktopMain: Upload progress: ${evt.progress}%`);
436
+ const type = 'upload-progress';
437
+ recallSdkStore.emitEvent({ type, data: evt });
438
+ broadcast(type, evt);
439
+ });
440
+ // Other events
441
+ ['realtime-event', 'meeting-updated', 'media-capture-status', 'participant-capture-status']
442
+ .forEach(eventType => {
443
+ RecallAiSdk.addEventListener(eventType, (evt) => {
444
+ console.log(`RecallDesktopMain: ${eventType}:`, evt);
445
+ recallSdkStore.emitEvent({ type: eventType, data: evt });
446
+ broadcast(eventType, evt);
447
+ });
448
+ });
449
+ // Permission status
450
+ RecallAiSdk.addEventListener('permission-status', (evt) => {
451
+ console.log('RecallDesktopMain: Permission status:', evt);
452
+ recallSdkStore.setPermissionStatus(evt.permission, evt.status);
453
+ const type = 'permission-status';
454
+ recallSdkStore.emitEvent({ type, data: evt });
455
+ broadcast(type, evt);
456
+ });
457
+ // Error handling
458
+ RecallAiSdk.addEventListener('error', (evt) => {
459
+ console.error('RecallDesktopMain: SDK error:', evt);
460
+ const type = 'error';
461
+ recallSdkStore.emitEvent({ type, data: evt });
462
+ broadcast(type, evt);
463
+ });
464
+ // Shutdown
465
+ RecallAiSdk.addEventListener('shutdown', (evt) => {
466
+ console.log('RecallDesktopMain: SDK shutdown:', evt);
467
+ recallSdkStore.setSdkInitialized(false);
468
+ const type = 'shutdown';
469
+ recallSdkStore.emitEvent({ type, data: evt });
470
+ broadcast(type, evt);
471
+ });
472
+ }
473
+ registerIpcHandlers() {
474
+ const addDestroyedCleanup = (wc) => {
475
+ const id = wc.id;
476
+ if (this.trackedWebContents.has(id))
477
+ return;
478
+ this.trackedWebContents.set(id, wc);
479
+ wc.once('destroyed', () => {
480
+ // Remove this wc from all subscriptions
481
+ this.subscriptions.forEach((map) => {
482
+ map.delete(id);
483
+ });
484
+ this.trackedWebContents.delete(id);
485
+ });
486
+ };
487
+ // Subscribe to events
488
+ electron.ipcMain.handle(IPC_CHANNELS.SUBSCRIBE_EVENTS, async (event, eventType) => {
489
+ try {
490
+ const wc = event.sender;
491
+ addDestroyedCleanup(wc);
492
+ let map = this.subscriptions.get(eventType);
493
+ if (!map) {
494
+ map = new Map();
495
+ this.subscriptions.set(eventType, map);
496
+ }
497
+ const id = wc.id;
498
+ const prev = map.get(id) || 0;
499
+ map.set(id, prev + 1);
500
+ return { success: true, message: `Subscribed to ${eventType}` };
501
+ }
502
+ catch (error) {
503
+ console.error('RecallDesktopMain: subscribe-events failed', error);
504
+ return { success: false, message: 'Failed to subscribe to events' };
505
+ }
506
+ });
507
+ // Unsubscribe from events
508
+ electron.ipcMain.handle(IPC_CHANNELS.UNSUBSCRIBE_EVENTS, async (event, eventType) => {
509
+ try {
510
+ const wc = event.sender;
511
+ const map = this.subscriptions.get(eventType);
512
+ if (map) {
513
+ const id = wc.id;
514
+ const prev = map.get(id) || 0;
515
+ if (prev <= 1)
516
+ map.delete(id);
517
+ else
518
+ map.set(id, prev - 1);
519
+ }
520
+ return { success: true, message: `Unsubscribed from ${eventType}` };
521
+ }
522
+ catch (error) {
523
+ console.error('RecallDesktopMain: unsubscribe-events failed', error);
524
+ return { success: false, message: 'Failed to unsubscribe from events' };
525
+ }
526
+ });
527
+ // Initialize SDK
528
+ electron.ipcMain.handle(IPC_CHANNELS.INIT_SDK, async () => {
529
+ try {
530
+ if (!recallSdkStore.isEnabled()) {
531
+ throw new RecallSdkError('Plugin is disabled', 'PLUGIN_DISABLED');
532
+ }
533
+ if (recallSdkStore.isSdkInitialized()) {
534
+ return { success: true, message: 'SDK already initialized' };
535
+ }
536
+ await this.initializeSdk();
537
+ return { success: true, message: 'SDK initialized successfully' };
538
+ }
539
+ catch (error) {
540
+ console.error('RecallDesktopMain: SDK initialization failed:', error);
541
+ return {
542
+ success: false,
543
+ message: error instanceof RecallSdkError ? error.message : 'SDK initialization failed'
544
+ };
545
+ }
546
+ });
547
+ // Shutdown SDK
548
+ electron.ipcMain.handle(IPC_CHANNELS.SHUTDOWN_SDK, async () => {
549
+ try {
550
+ await RecallAiSdk.shutdown();
551
+ recallSdkStore.clearState();
552
+ return { success: true, message: 'SDK shutdown successfully' };
553
+ }
554
+ catch (error) {
555
+ console.error('RecallDesktopMain: SDK shutdown failed:', error);
556
+ return { success: false, message: 'SDK shutdown failed' };
557
+ }
558
+ });
559
+ // Get plugin status
560
+ electron.ipcMain.handle(IPC_CHANNELS.GET_STATUS, async () => {
561
+ return {
562
+ initialized: this.isInitialized,
563
+ sdkInitialized: recallSdkStore.isSdkInitialized(),
564
+ version: this.version,
565
+ config: recallSdkStore.getConfig(),
566
+ sdkState: recallSdkStore.getSdkState(),
567
+ permissions: recallSdkStore.getPermissions()
568
+ };
569
+ });
570
+ // Start recording
571
+ electron.ipcMain.handle(IPC_CHANNELS.START_RECORDING, async (event, request) => {
572
+ try {
573
+ if (!recallSdkStore.isSdkInitialized()) {
574
+ throw new RecallSdkError('SDK not initialized', 'SDK_NOT_INITIALIZED');
575
+ }
576
+ await RecallAiSdk.startRecording({
577
+ windowId: request.windowId,
578
+ uploadToken: request.uploadToken
579
+ });
580
+ recallSdkStore.startRecording(request.windowId, request.uploadToken);
581
+ return { success: true, message: 'Recording started successfully' };
582
+ }
583
+ catch (error) {
584
+ console.error('RecallDesktopMain: Start recording failed:', error);
585
+ return {
586
+ success: false,
587
+ message: error instanceof RecallSdkError ? error.message : 'Failed to start recording'
588
+ };
589
+ }
590
+ });
591
+ // Stop recording
592
+ electron.ipcMain.handle(IPC_CHANNELS.STOP_RECORDING, async (event, request) => {
593
+ try {
594
+ await RecallAiSdk.stopRecording({ windowId: request.windowId });
595
+ recallSdkStore.stopRecording(request.windowId);
596
+ return { success: true, message: 'Recording stopped successfully' };
597
+ }
598
+ catch (error) {
599
+ console.error('RecallDesktopMain: Stop recording failed:', error);
600
+ return { success: false, message: 'Failed to stop recording' };
601
+ }
602
+ });
603
+ // Pause recording
604
+ electron.ipcMain.handle(IPC_CHANNELS.PAUSE_RECORDING, async (event, request) => {
605
+ try {
606
+ await RecallAiSdk.pauseRecording({ windowId: request.windowId });
607
+ return { success: true, message: 'Recording paused successfully' };
608
+ }
609
+ catch (error) {
610
+ console.error('RecallDesktopMain: Pause recording failed:', error);
611
+ return { success: false, message: 'Failed to pause recording' };
612
+ }
613
+ });
614
+ // Resume recording
615
+ electron.ipcMain.handle(IPC_CHANNELS.RESUME_RECORDING, async (event, request) => {
616
+ try {
617
+ await RecallAiSdk.resumeRecording({ windowId: request.windowId });
618
+ return { success: true, message: 'Recording resumed successfully' };
619
+ }
620
+ catch (error) {
621
+ console.error('RecallDesktopMain: Resume recording failed:', error);
622
+ return { success: false, message: 'Failed to resume recording' };
623
+ }
624
+ });
625
+ // Upload recording
626
+ electron.ipcMain.handle(IPC_CHANNELS.UPLOAD_RECORDING, async (event, request) => {
627
+ try {
628
+ await RecallAiSdk.uploadRecording({ windowId: request.windowId });
629
+ return { success: true, message: 'Recording upload started successfully' };
630
+ }
631
+ catch (error) {
632
+ console.error('RecallDesktopMain: Upload recording failed:', error);
633
+ return { success: false, message: 'Failed to upload recording' };
634
+ }
635
+ });
636
+ // Prepare desktop audio recording
637
+ electron.ipcMain.handle(IPC_CHANNELS.PREPARE_DESKTOP_AUDIO, async () => {
638
+ try {
639
+ const windowId = await RecallAiSdk.prepareDesktopAudioRecording();
640
+ return {
641
+ success: true,
642
+ message: 'Desktop audio recording prepared successfully',
643
+ data: { windowId }
644
+ };
645
+ }
646
+ catch (error) {
647
+ console.error('RecallDesktopMain: Prepare desktop audio failed:', error);
648
+ return { success: false, message: 'Failed to prepare desktop audio recording' };
649
+ }
650
+ });
651
+ // Request permission
652
+ electron.ipcMain.handle(IPC_CHANNELS.REQUEST_PERMISSION, async (event, permission) => {
653
+ try {
654
+ await RecallAiSdk.requestPermission(permission);
655
+ return { success: true, message: `Permission request sent for ${permission}` };
656
+ }
657
+ catch (error) {
658
+ console.error('RecallDesktopMain: Request permission failed:', error);
659
+ return { success: false, message: 'Failed to request permission' };
660
+ }
661
+ });
662
+ // Set configuration
663
+ electron.ipcMain.handle(IPC_CHANNELS.SET_CONFIG, async (event, config) => {
664
+ try {
665
+ recallSdkStore.setConfig(config);
666
+ // If SDK settings changed and SDK is initialized, reinitialize
667
+ if (recallSdkStore.isSdkInitialized() && (config.apiUrl || config.requestPermissionsOnStartup !== undefined)) {
668
+ console.log('RecallDesktopMain: Reinitializing SDK due to configuration change');
669
+ await RecallAiSdk.shutdown();
670
+ await this.initializeSdk();
671
+ }
672
+ return { success: true, message: 'Configuration updated successfully' };
673
+ }
674
+ catch (error) {
675
+ console.error('RecallDesktopMain: Failed to set configuration:', error);
676
+ return { success: false, message: 'Failed to update configuration' };
677
+ }
678
+ });
679
+ // Get configuration
680
+ electron.ipcMain.handle(IPC_CHANNELS.GET_CONFIG, async () => {
681
+ return {
682
+ success: true,
683
+ message: 'Configuration retrieved successfully',
684
+ data: recallSdkStore.getConfig()
685
+ };
686
+ });
687
+ }
688
+ }
689
+ // Initialize plugin
690
+ const recallDesktopMain = new RecallDesktopMain();
691
+ recallDesktopMain.initialize().catch(console.error);
692
+
693
+ module.exports = recallDesktopMain;
694
+ //# sourceMappingURL=main.js.map