@todesktop/plugin-recall 1.0.2 → 1.0.4

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/src/main.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * ToDesktop Recall Desktop SDK Plugin - Main Process
3
- *
3
+ *
4
4
  * This file runs in Electron's main process and handles:
5
5
  * - Recall Desktop SDK integration and lifecycle management
6
6
  * - IPC communication with renderer processes
@@ -8,11 +8,11 @@
8
8
  * - Event forwarding from SDK to frontend
9
9
  */
10
10
 
11
- import { ipcMain, BrowserWindow } from 'electron';
12
- import {
13
- IPC_CHANNELS,
14
- ApiResponse,
15
- PluginStatus,
11
+ import { ipcMain } from "electron";
12
+ import {
13
+ IPC_CHANNELS,
14
+ ApiResponse,
15
+ PluginStatus,
16
16
  RecallSdkError,
17
17
  StartRecordingRequest,
18
18
  StopRecordingRequest,
@@ -23,235 +23,143 @@ import {
23
23
  SdkInitOptions,
24
24
  PrepareDesktopAudioResponse,
25
25
  RecallSdkConfig,
26
- RecallSdkEventType
27
- } from './shared';
28
- import { recallSdkStore } from './store';
29
-
30
- // Import Recall SDK, with a dev-friendly fallback mock if the package isn't installed
31
- type RecallAiSdk = {
32
- init(options: any): Promise<null> | void;
33
- shutdown(): Promise<null> | void;
34
- startRecording(config: { windowId: string; uploadToken: string }): Promise<null> | void;
35
- stopRecording(config: { windowId: string }): Promise<null> | void;
36
- pauseRecording(config: { windowId: string }): Promise<null> | void;
37
- resumeRecording(config: { windowId: string }): Promise<null> | void;
38
- uploadRecording(config: { windowId: string }): Promise<null> | void;
39
- prepareDesktopAudioRecording(): Promise<string>;
40
- requestPermission(permission: PermissionType): Promise<null> | void;
41
- addEventListener<T extends RecallSdkEventType>(type: T, callback: (event: any) => void): void;
42
- };
43
-
44
- let RecallAiSdk: RecallAiSdk;
45
- try {
46
- // eslint-disable-next-line @typescript-eslint/no-var-requires
47
- const mod = require('@recallai/desktop-sdk');
48
- RecallAiSdk = (mod && mod.default) ? mod.default : mod;
49
- } catch {
50
- RecallAiSdk = {
51
- init: async (config: any) => { console.log('RecallAiSdk.init called with:', config); return null; },
52
- shutdown: async () => { console.log('RecallAiSdk.shutdown called'); return null; },
53
- startRecording: async (params: any) => { console.log('RecallAiSdk.startRecording called with:', params); return null; },
54
- stopRecording: async (params: any) => { console.log('RecallAiSdk.stopRecording called with:', params); return null; },
55
- pauseRecording: async (params: any) => { console.log('RecallAiSdk.pauseRecording called with:', params); return null; },
56
- resumeRecording: async (params: any) => { console.log('RecallAiSdk.resumeRecording called with:', params); return null; },
57
- uploadRecording: async (params: any) => { console.log('RecallAiSdk.uploadRecording called with:', params); return null; },
58
- prepareDesktopAudioRecording: async () => { console.log('RecallAiSdk.prepareDesktopAudioRecording called'); return 'mock-window-id'; },
59
- requestPermission: async (permission: PermissionType) => { console.log(`RecallAiSdk.requestPermission called for: ${permission}`); return null; },
60
- addEventListener: (_eventType: string) => { /* no-op in mock */ },
61
- } as RecallAiSdk;
62
- }
26
+ RecallSdkEventType,
27
+ PluginContext,
28
+ } from "./shared";
29
+ import { recallSdkStore, setPluginContext } from "./store";
30
+ import RecallAiSdk from "@recallai/desktop-sdk";
63
31
 
64
32
  class RecallDesktopMain {
65
- private version = '1.0.0';
33
+ private version = "1.0.0";
66
34
  private isInitialized = false;
67
- private subscriptions: Map<RecallSdkEventType, Map<number, number>> = new Map();
35
+ private subscriptions: Map<RecallSdkEventType, Map<number, number>> =
36
+ new Map();
68
37
  private trackedWebContents = new Map<number, Electron.WebContents>();
38
+ private sdkEventHandlers = new Map<RecallSdkEventType, (evt: any) => void>();
39
+ private readonly eventSideEffects: Partial<
40
+ Record<RecallSdkEventType, (evt: any) => void>
41
+ > = {
42
+ shutdown: () => {
43
+ recallSdkStore.clearState();
44
+ },
45
+ };
69
46
 
70
47
  async initialize(): Promise<void> {
48
+ if (this.isInitialized) {
49
+ return;
50
+ }
51
+
52
+ if (!recallSdkStore.isEnabled()) {
53
+ console.log("RecallDesktopMain: Plugin is disabled");
54
+ return;
55
+ }
56
+
71
57
  try {
72
58
  // Initialize plugin store
73
59
  await recallSdkStore.initialize();
74
60
 
75
- // Load configuration from ToDesktop preferences
76
- // In a real implementation, this would integrate with ToDesktop's preference system
77
- this.loadPreferences();
78
-
79
61
  // Register IPC handlers
80
62
  this.registerIpcHandlers();
81
63
 
82
- // Initialize SDK if plugin is enabled
83
- if (recallSdkStore.isEnabled()) {
84
- await this.initializeSdk();
85
- }
64
+ // SDK will now be initialized on-demand via IPC
86
65
 
87
66
  this.isInitialized = true;
88
- console.log('RecallDesktopMain: Main process initialized');
67
+ console.log("RecallDesktopMain: Main process initialized");
89
68
  } catch (error) {
90
- console.error('RecallDesktopMain: Failed to initialize main process:', error);
69
+ console.error(
70
+ "RecallDesktopMain: Failed to initialize main process:",
71
+ error
72
+ );
91
73
  throw error;
92
74
  }
93
75
  }
94
76
 
95
- private loadPreferences(): void {
96
- // In a real implementation, this would load from ToDesktop's preference system
97
- // For now, we'll use defaults
98
- const preferences = {
99
- enabled: true,
100
- apiUrl: 'https://us-east-1.recall.ai',
101
- requestPermissionsOnStartup: true,
102
- };
103
-
104
- recallSdkStore.loadFromPreferences(preferences);
105
- }
106
-
107
77
  private async initializeSdk(): Promise<void> {
108
78
  try {
109
79
  const config = recallSdkStore.getConfig();
110
-
80
+
111
81
  const sdkOptions: SdkInitOptions = {
112
82
  apiUrl: config.apiUrl,
113
83
  acquirePermissionsOnStartup: config.requestPermissionsOnStartup
114
- ? ['accessibility', 'screen-capture', 'microphone', 'system-audio']
84
+ ? ["accessibility", "screen-capture", "microphone", "system-audio"]
115
85
  : undefined,
116
86
  restartOnError: true,
117
87
  };
118
88
 
119
- // Initialize the Recall SDK
120
- await (RecallAiSdk.init as any)(sdkOptions);
89
+ console.log("RecallDesktopMain: SDK options:", sdkOptions);
121
90
 
122
- // Set up event listeners
123
- this.setupSdkEventListeners();
91
+ // Initialize the Recall SDK
92
+ await RecallAiSdk.init(sdkOptions);
124
93
 
125
94
  recallSdkStore.setSdkInitialized(true);
126
- console.log('RecallDesktopMain: SDK initialized successfully');
95
+ console.log("RecallDesktopMain: SDK initialized successfully");
127
96
  } catch (error) {
128
- console.error('RecallDesktopMain: Failed to initialize SDK:', error);
129
- throw new RecallSdkError('SDK initialization failed', 'SDK_INIT_ERROR');
97
+ console.error("RecallDesktopMain: Failed to initialize SDK:", error);
98
+ throw new RecallSdkError("SDK initialization failed", "SDK_INIT_ERROR");
130
99
  }
131
100
  }
132
101
 
133
- private setupSdkEventListeners(): void {
134
- const broadcast = (type: RecallSdkEventType, data: any) => {
135
- const channel = `recall-desktop:event:${type}`;
136
- const subs = this.subscriptions.get(type);
137
- if (!subs) return;
138
- subs.forEach((_count, wcId) => {
139
- const wc = this.trackedWebContents.get(wcId);
140
- if (!wc) return;
141
- try {
142
- wc.send(channel, data);
143
- } catch (err) {
144
- console.error('RecallDesktopMain: Failed to send event to webContents', wcId, err);
145
- }
146
- });
147
- };
148
-
149
- // Permissions granted
150
- RecallAiSdk.addEventListener('permissions-granted', (evt) => {
151
- console.log('RecallDesktopMain: Permissions granted');
152
- const type: RecallSdkEventType = 'permissions-granted';
153
- recallSdkStore.emitEvent({ type, data: evt });
154
- broadcast(type, evt);
155
- });
156
-
157
- // Meeting detected
158
- RecallAiSdk.addEventListener('meeting-detected', (evt) => {
159
- console.log('RecallDesktopMain: Meeting detected:', evt);
160
- const meeting = evt.window;
161
- recallSdkStore.addMeeting(meeting);
162
- const type: RecallSdkEventType = 'meeting-detected';
163
- recallSdkStore.emitEvent({ type, data: evt });
164
- broadcast(type, evt);
165
- });
166
-
167
- // SDK state change
168
- RecallAiSdk.addEventListener('sdk-state-change', (evt) => {
169
- console.log('RecallDesktopMain: SDK state change:', evt);
170
- const state = evt.sdk.state.code;
171
- recallSdkStore.setSdkState(state);
172
- const type: RecallSdkEventType = 'sdk-state-change';
173
- recallSdkStore.emitEvent({ type, data: evt });
174
- broadcast(type, evt);
175
- });
176
-
177
- // Recording started
178
- RecallAiSdk.addEventListener('recording-started', (evt) => {
179
- console.log('RecallDesktopMain: Recording started:', evt);
180
- const type: RecallSdkEventType = 'recording-started';
181
- recallSdkStore.emitEvent({ type, data: evt });
182
- broadcast(type, evt);
183
- });
184
-
185
- // Recording ended
186
- RecallAiSdk.addEventListener('recording-ended', (evt) => {
187
- console.log('RecallDesktopMain: Recording ended:', evt);
188
- recallSdkStore.stopRecording(evt.window.id);
189
- const type: RecallSdkEventType = 'recording-ended';
190
- recallSdkStore.emitEvent({ type, data: evt });
191
- broadcast(type, evt);
102
+ private broadcastEvent(type: RecallSdkEventType, data: any): void {
103
+ const channel = `recall-desktop:event:${type}`;
104
+ const subs = this.subscriptions.get(type);
105
+ if (!subs) return;
106
+ subs.forEach((_count, wcId) => {
107
+ const wc = this.trackedWebContents.get(wcId);
108
+ if (!wc) return;
109
+ try {
110
+ wc.send(channel, data);
111
+ } catch (err) {
112
+ console.error(
113
+ "RecallDesktopMain: Failed to send event to webContents",
114
+ wcId,
115
+ err
116
+ );
117
+ }
192
118
  });
119
+ }
193
120
 
194
- // Meeting closed
195
- RecallAiSdk.addEventListener('meeting-closed', (evt) => {
196
- console.log('RecallDesktopMain: Meeting closed:', evt);
197
- recallSdkStore.removeMeeting(evt.window.id);
198
- const type: RecallSdkEventType = 'meeting-closed';
199
- recallSdkStore.emitEvent({ type, data: evt });
200
- broadcast(type, evt);
201
- });
121
+ private ensureSdkListener(eventType: RecallSdkEventType): void {
122
+ if (this.sdkEventHandlers.has(eventType)) {
123
+ return;
124
+ }
202
125
 
203
- // Upload progress
204
- RecallAiSdk.addEventListener('upload-progress', (evt) => {
205
- console.log(`RecallDesktopMain: Upload progress: ${evt.progress}%`);
206
- const type: RecallSdkEventType = 'upload-progress';
207
- recallSdkStore.emitEvent({ type, data: evt });
208
- broadcast(type, evt);
209
- });
126
+ const handler = (evt: any) => {
127
+ this.handleSdkEvent(eventType, evt);
128
+ };
210
129
 
211
- // Other events
212
- (['realtime-event', 'meeting-updated', 'media-capture-status', 'participant-capture-status'] as RecallSdkEventType[])
213
- .forEach(eventType => {
214
- RecallAiSdk.addEventListener(eventType, (evt) => {
215
- console.log(`RecallDesktopMain: ${eventType}:`, evt);
216
- recallSdkStore.emitEvent({ type: eventType, data: evt });
217
- broadcast(eventType, evt);
218
- });
219
- });
130
+ this.sdkEventHandlers.set(eventType, handler);
131
+ RecallAiSdk.addEventListener(eventType as any, handler);
132
+ }
220
133
 
221
- // Permission status
222
- RecallAiSdk.addEventListener('permission-status', (evt) => {
223
- console.log('RecallDesktopMain: Permission status:', evt);
224
- recallSdkStore.setPermissionStatus(evt.permission, evt.status);
225
- const type: RecallSdkEventType = 'permission-status';
226
- recallSdkStore.emitEvent({ type, data: evt });
227
- broadcast(type, evt);
228
- });
134
+ private handleSdkEvent(eventType: RecallSdkEventType, evt: any): void {
135
+ if (eventType === "error") {
136
+ console.error("RecallDesktopMain: SDK error:", evt);
137
+ } else {
138
+ console.log(`RecallDesktopMain: ${eventType}`, evt);
139
+ }
229
140
 
230
- // Error handling
231
- RecallAiSdk.addEventListener('error', (evt) => {
232
- console.error('RecallDesktopMain: SDK error:', evt);
233
- const type: RecallSdkEventType = 'error';
234
- recallSdkStore.emitEvent({ type, data: evt });
235
- broadcast(type, evt);
236
- });
141
+ const sideEffect = this.eventSideEffects[eventType];
142
+ if (sideEffect) {
143
+ try {
144
+ sideEffect(evt);
145
+ } catch (error) {
146
+ console.error(
147
+ "RecallDesktopMain: Side effect failed for",
148
+ eventType,
149
+ error
150
+ );
151
+ }
152
+ }
237
153
 
238
- // Shutdown
239
- RecallAiSdk.addEventListener('shutdown', (evt) => {
240
- console.log('RecallDesktopMain: SDK shutdown:', evt);
241
- recallSdkStore.setSdkInitialized(false);
242
- const type: RecallSdkEventType = 'shutdown';
243
- recallSdkStore.emitEvent({ type, data: evt });
244
- broadcast(type, evt);
245
- });
154
+ this.broadcastEvent(eventType, evt);
246
155
  }
247
156
 
248
-
249
157
  private registerIpcHandlers(): void {
250
158
  const addDestroyedCleanup = (wc: Electron.WebContents) => {
251
159
  const id = wc.id;
252
160
  if (this.trackedWebContents.has(id)) return;
253
161
  this.trackedWebContents.set(id, wc);
254
- wc.once('destroyed', () => {
162
+ wc.once("destroyed", () => {
255
163
  // Remove this wc from all subscriptions
256
164
  this.subscriptions.forEach((map) => {
257
165
  map.delete(id);
@@ -261,75 +169,91 @@ class RecallDesktopMain {
261
169
  };
262
170
 
263
171
  // Subscribe to events
264
- ipcMain.handle(IPC_CHANNELS.SUBSCRIBE_EVENTS, async (event, eventType: RecallSdkEventType): Promise<ApiResponse> => {
265
- try {
266
- const wc = event.sender;
267
- addDestroyedCleanup(wc);
268
- let map = this.subscriptions.get(eventType);
269
- if (!map) {
270
- map = new Map();
271
- this.subscriptions.set(eventType, map);
172
+ ipcMain.handle(
173
+ IPC_CHANNELS.SUBSCRIBE_EVENTS,
174
+ async (event, eventType: RecallSdkEventType): Promise<ApiResponse> => {
175
+ try {
176
+ const wc = event.sender;
177
+ addDestroyedCleanup(wc);
178
+ let map = this.subscriptions.get(eventType);
179
+ if (!map) {
180
+ map = new Map();
181
+ this.subscriptions.set(eventType, map);
182
+ }
183
+ const id = wc.id;
184
+ const prev = map.get(id) || 0;
185
+ map.set(id, prev + 1);
186
+ this.ensureSdkListener(eventType);
187
+ return { success: true, message: `Subscribed to ${eventType}` };
188
+ } catch (error) {
189
+ console.error("RecallDesktopMain: subscribe-events failed", error);
190
+ return { success: false, message: "Failed to subscribe to events" };
272
191
  }
273
- const id = wc.id;
274
- const prev = map.get(id) || 0;
275
- map.set(id, prev + 1);
276
- return { success: true, message: `Subscribed to ${eventType}` };
277
- } catch (error) {
278
- console.error('RecallDesktopMain: subscribe-events failed', error);
279
- return { success: false, message: 'Failed to subscribe to events' };
280
192
  }
281
- });
193
+ );
282
194
 
283
195
  // Unsubscribe from events
284
- ipcMain.handle(IPC_CHANNELS.UNSUBSCRIBE_EVENTS, async (event, eventType: RecallSdkEventType): Promise<ApiResponse> => {
285
- try {
286
- const wc = event.sender;
287
- const map = this.subscriptions.get(eventType);
288
- if (map) {
289
- const id = wc.id;
290
- const prev = map.get(id) || 0;
291
- if (prev <= 1) map.delete(id);
292
- else map.set(id, prev - 1);
196
+ ipcMain.handle(
197
+ IPC_CHANNELS.UNSUBSCRIBE_EVENTS,
198
+ async (event, eventType: RecallSdkEventType): Promise<ApiResponse> => {
199
+ try {
200
+ const wc = event.sender;
201
+ const map = this.subscriptions.get(eventType);
202
+ if (map) {
203
+ const id = wc.id;
204
+ const prev = map.get(id) || 0;
205
+ if (prev <= 1) map.delete(id);
206
+ else map.set(id, prev - 1);
207
+ }
208
+ return { success: true, message: `Unsubscribed from ${eventType}` };
209
+ } catch (error) {
210
+ console.error("RecallDesktopMain: unsubscribe-events failed", error);
211
+ return {
212
+ success: false,
213
+ message: "Failed to unsubscribe from events",
214
+ };
293
215
  }
294
- return { success: true, message: `Unsubscribed from ${eventType}` };
295
- } catch (error) {
296
- console.error('RecallDesktopMain: unsubscribe-events failed', error);
297
- return { success: false, message: 'Failed to unsubscribe from events' };
298
216
  }
299
- });
217
+ );
300
218
  // Initialize SDK
301
219
  ipcMain.handle(IPC_CHANNELS.INIT_SDK, async (): Promise<ApiResponse> => {
302
220
  try {
303
221
  if (!recallSdkStore.isEnabled()) {
304
- throw new RecallSdkError('Plugin is disabled', 'PLUGIN_DISABLED');
222
+ throw new RecallSdkError("Plugin is disabled", "PLUGIN_DISABLED");
305
223
  }
306
224
 
307
225
  if (recallSdkStore.isSdkInitialized()) {
308
- return { success: true, message: 'SDK already initialized' };
226
+ return { success: true, message: "SDK already initialized" };
309
227
  }
310
228
 
311
229
  await this.initializeSdk();
312
- return { success: true, message: 'SDK initialized successfully' };
230
+ return { success: true, message: "SDK initialized successfully" };
313
231
  } catch (error) {
314
- console.error('RecallDesktopMain: SDK initialization failed:', error);
232
+ console.error("RecallDesktopMain: SDK initialization failed:", error);
315
233
  return {
316
234
  success: false,
317
- message: error instanceof RecallSdkError ? error.message : 'SDK initialization failed'
235
+ message:
236
+ error instanceof RecallSdkError
237
+ ? error.message
238
+ : "SDK initialization failed",
318
239
  };
319
240
  }
320
241
  });
321
242
 
322
243
  // Shutdown SDK
323
- ipcMain.handle(IPC_CHANNELS.SHUTDOWN_SDK, async (): Promise<ApiResponse> => {
324
- try {
325
- await (RecallAiSdk.shutdown as any)();
326
- recallSdkStore.clearState();
327
- return { success: true, message: 'SDK shutdown successfully' };
328
- } catch (error) {
329
- console.error('RecallDesktopMain: SDK shutdown failed:', error);
330
- return { success: false, message: 'SDK shutdown failed' };
244
+ ipcMain.handle(
245
+ IPC_CHANNELS.SHUTDOWN_SDK,
246
+ async (): Promise<ApiResponse> => {
247
+ try {
248
+ await (RecallAiSdk.shutdown as any)();
249
+ recallSdkStore.clearState();
250
+ return { success: true, message: "SDK shutdown successfully" };
251
+ } catch (error) {
252
+ console.error("RecallDesktopMain: SDK shutdown failed:", error);
253
+ return { success: false, message: "SDK shutdown failed" };
254
+ }
331
255
  }
332
- });
256
+ );
333
257
 
334
258
  // Get plugin status
335
259
  ipcMain.handle(IPC_CHANNELS.GET_STATUS, async (): Promise<PluginStatus> => {
@@ -338,137 +262,200 @@ class RecallDesktopMain {
338
262
  sdkInitialized: recallSdkStore.isSdkInitialized(),
339
263
  version: this.version,
340
264
  config: recallSdkStore.getConfig(),
341
- sdkState: recallSdkStore.getSdkState(),
342
- permissions: recallSdkStore.getPermissions()
343
265
  };
344
266
  });
345
267
 
346
268
  // Start recording
347
- ipcMain.handle(IPC_CHANNELS.START_RECORDING, async (event, request: StartRecordingRequest): Promise<ApiResponse> => {
348
- try {
349
- if (!recallSdkStore.isSdkInitialized()) {
350
- throw new RecallSdkError('SDK not initialized', 'SDK_NOT_INITIALIZED');
269
+ ipcMain.handle(
270
+ IPC_CHANNELS.START_RECORDING,
271
+ async (event, request: StartRecordingRequest): Promise<ApiResponse> => {
272
+ try {
273
+ if (!recallSdkStore.isSdkInitialized()) {
274
+ throw new RecallSdkError(
275
+ "SDK not initialized",
276
+ "SDK_NOT_INITIALIZED"
277
+ );
278
+ }
279
+
280
+ await (RecallAiSdk.startRecording as any)({
281
+ windowId: request.windowId,
282
+ uploadToken: request.uploadToken,
283
+ });
284
+ return { success: true, message: "Recording started successfully" };
285
+ } catch (error) {
286
+ console.error("RecallDesktopMain: Start recording failed:", error);
287
+ return {
288
+ success: false,
289
+ message:
290
+ error instanceof RecallSdkError
291
+ ? error.message
292
+ : "Failed to start recording",
293
+ };
351
294
  }
352
-
353
- await (RecallAiSdk.startRecording as any)({
354
- windowId: request.windowId,
355
- uploadToken: request.uploadToken
356
- });
357
-
358
- recallSdkStore.startRecording(request.windowId, request.uploadToken);
359
- return { success: true, message: 'Recording started successfully' };
360
- } catch (error) {
361
- console.error('RecallDesktopMain: Start recording failed:', error);
362
- return {
363
- success: false,
364
- message: error instanceof RecallSdkError ? error.message : 'Failed to start recording'
365
- };
366
295
  }
367
- });
296
+ );
368
297
 
369
298
  // Stop recording
370
- ipcMain.handle(IPC_CHANNELS.STOP_RECORDING, async (event, request: StopRecordingRequest): Promise<ApiResponse> => {
371
- try {
372
- await (RecallAiSdk.stopRecording as any)({ windowId: request.windowId });
373
- recallSdkStore.stopRecording(request.windowId);
374
- return { success: true, message: 'Recording stopped successfully' };
375
- } catch (error) {
376
- console.error('RecallDesktopMain: Stop recording failed:', error);
377
- return { success: false, message: 'Failed to stop recording' };
299
+ ipcMain.handle(
300
+ IPC_CHANNELS.STOP_RECORDING,
301
+ async (event, request: StopRecordingRequest): Promise<ApiResponse> => {
302
+ try {
303
+ await (RecallAiSdk.stopRecording as any)({
304
+ windowId: request.windowId,
305
+ });
306
+ return { success: true, message: "Recording stopped successfully" };
307
+ } catch (error) {
308
+ console.error("RecallDesktopMain: Stop recording failed:", error);
309
+ return { success: false, message: "Failed to stop recording" };
310
+ }
378
311
  }
379
- });
312
+ );
380
313
 
381
314
  // Pause recording
382
- ipcMain.handle(IPC_CHANNELS.PAUSE_RECORDING, async (event, request: PauseRecordingRequest): Promise<ApiResponse> => {
383
- try {
384
- await (RecallAiSdk.pauseRecording as any)({ windowId: request.windowId });
385
- return { success: true, message: 'Recording paused successfully' };
386
- } catch (error) {
387
- console.error('RecallDesktopMain: Pause recording failed:', error);
388
- return { success: false, message: 'Failed to pause recording' };
315
+ ipcMain.handle(
316
+ IPC_CHANNELS.PAUSE_RECORDING,
317
+ async (event, request: PauseRecordingRequest): Promise<ApiResponse> => {
318
+ try {
319
+ await (RecallAiSdk.pauseRecording as any)({
320
+ windowId: request.windowId,
321
+ });
322
+ return { success: true, message: "Recording paused successfully" };
323
+ } catch (error) {
324
+ console.error("RecallDesktopMain: Pause recording failed:", error);
325
+ return { success: false, message: "Failed to pause recording" };
326
+ }
389
327
  }
390
- });
328
+ );
391
329
 
392
330
  // Resume recording
393
- ipcMain.handle(IPC_CHANNELS.RESUME_RECORDING, async (event, request: ResumeRecordingRequest): Promise<ApiResponse> => {
394
- try {
395
- await (RecallAiSdk.resumeRecording as any)({ windowId: request.windowId });
396
- return { success: true, message: 'Recording resumed successfully' };
397
- } catch (error) {
398
- console.error('RecallDesktopMain: Resume recording failed:', error);
399
- return { success: false, message: 'Failed to resume recording' };
331
+ ipcMain.handle(
332
+ IPC_CHANNELS.RESUME_RECORDING,
333
+ async (event, request: ResumeRecordingRequest): Promise<ApiResponse> => {
334
+ try {
335
+ await (RecallAiSdk.resumeRecording as any)({
336
+ windowId: request.windowId,
337
+ });
338
+ return { success: true, message: "Recording resumed successfully" };
339
+ } catch (error) {
340
+ console.error("RecallDesktopMain: Resume recording failed:", error);
341
+ return { success: false, message: "Failed to resume recording" };
342
+ }
400
343
  }
401
- });
344
+ );
402
345
 
403
346
  // Upload recording
404
- ipcMain.handle(IPC_CHANNELS.UPLOAD_RECORDING, async (event, request: UploadRecordingRequest): Promise<ApiResponse> => {
405
- try {
406
- await (RecallAiSdk.uploadRecording as any)({ windowId: request.windowId });
407
- return { success: true, message: 'Recording upload started successfully' };
408
- } catch (error) {
409
- console.error('RecallDesktopMain: Upload recording failed:', error);
410
- return { success: false, message: 'Failed to upload recording' };
347
+ ipcMain.handle(
348
+ IPC_CHANNELS.UPLOAD_RECORDING,
349
+ async (event, request: UploadRecordingRequest): Promise<ApiResponse> => {
350
+ try {
351
+ await (RecallAiSdk.uploadRecording as any)({
352
+ windowId: request.windowId,
353
+ });
354
+ return {
355
+ success: true,
356
+ message: "Recording upload started successfully",
357
+ };
358
+ } catch (error) {
359
+ console.error("RecallDesktopMain: Upload recording failed:", error);
360
+ return { success: false, message: "Failed to upload recording" };
361
+ }
411
362
  }
412
- });
363
+ );
413
364
 
414
365
  // Prepare desktop audio recording
415
- ipcMain.handle(IPC_CHANNELS.PREPARE_DESKTOP_AUDIO, async (): Promise<ApiResponse<PrepareDesktopAudioResponse>> => {
416
- try {
417
- const windowId = await (RecallAiSdk.prepareDesktopAudioRecording as any)();
418
- return {
419
- success: true,
420
- message: 'Desktop audio recording prepared successfully',
421
- data: { windowId }
422
- };
423
- } catch (error) {
424
- console.error('RecallDesktopMain: Prepare desktop audio failed:', error);
425
- return { success: false, message: 'Failed to prepare desktop audio recording' };
366
+ ipcMain.handle(
367
+ IPC_CHANNELS.PREPARE_DESKTOP_AUDIO,
368
+ async (): Promise<ApiResponse<PrepareDesktopAudioResponse>> => {
369
+ try {
370
+ const windowId = await (
371
+ RecallAiSdk.prepareDesktopAudioRecording as any
372
+ )();
373
+ return {
374
+ success: true,
375
+ message: "Desktop audio recording prepared successfully",
376
+ data: { windowId },
377
+ };
378
+ } catch (error) {
379
+ console.error(
380
+ "RecallDesktopMain: Prepare desktop audio failed:",
381
+ error
382
+ );
383
+ return {
384
+ success: false,
385
+ message: "Failed to prepare desktop audio recording",
386
+ };
387
+ }
426
388
  }
427
- });
389
+ );
428
390
 
429
391
  // Request permission
430
- ipcMain.handle(IPC_CHANNELS.REQUEST_PERMISSION, async (event, permission: PermissionType): Promise<ApiResponse> => {
431
- try {
432
- await (RecallAiSdk.requestPermission as any)(permission);
433
- return { success: true, message: `Permission request sent for ${permission}` };
434
- } catch (error) {
435
- console.error('RecallDesktopMain: Request permission failed:', error);
436
- return { success: false, message: 'Failed to request permission' };
392
+ ipcMain.handle(
393
+ IPC_CHANNELS.REQUEST_PERMISSION,
394
+ async (event, permission: PermissionType): Promise<ApiResponse> => {
395
+ try {
396
+ await (RecallAiSdk.requestPermission as any)(permission);
397
+ return {
398
+ success: true,
399
+ message: `Permission request sent for ${permission}`,
400
+ };
401
+ } catch (error) {
402
+ console.error("RecallDesktopMain: Request permission failed:", error);
403
+ return { success: false, message: "Failed to request permission" };
404
+ }
437
405
  }
438
- });
406
+ );
439
407
 
440
408
  // Set configuration
441
- ipcMain.handle(IPC_CHANNELS.SET_CONFIG, async (event, config: Partial<RecallSdkConfig>): Promise<ApiResponse> => {
442
- try {
443
- recallSdkStore.setConfig(config);
444
-
445
- // If SDK settings changed and SDK is initialized, reinitialize
446
- if (recallSdkStore.isSdkInitialized() && (config.apiUrl || config.requestPermissionsOnStartup !== undefined)) {
447
- console.log('RecallDesktopMain: Reinitializing SDK due to configuration change');
448
- await (RecallAiSdk.shutdown as any)();
449
- await this.initializeSdk();
409
+ ipcMain.handle(
410
+ IPC_CHANNELS.SET_CONFIG,
411
+ async (event, config: Partial<RecallSdkConfig>): Promise<ApiResponse> => {
412
+ try {
413
+ recallSdkStore.setConfig(config);
414
+
415
+ // If SDK settings changed and SDK is initialized, reinitialize
416
+ if (
417
+ recallSdkStore.isSdkInitialized() &&
418
+ (config.apiUrl || config.requestPermissionsOnStartup !== undefined)
419
+ ) {
420
+ console.log(
421
+ "RecallDesktopMain: Reinitializing SDK due to configuration change"
422
+ );
423
+ await (RecallAiSdk.shutdown as any)();
424
+ await this.initializeSdk();
425
+ }
426
+
427
+ return {
428
+ success: true,
429
+ message: "Configuration updated successfully",
430
+ };
431
+ } catch (error) {
432
+ console.error(
433
+ "RecallDesktopMain: Failed to set configuration:",
434
+ error
435
+ );
436
+ return { success: false, message: "Failed to update configuration" };
450
437
  }
451
-
452
- return { success: true, message: 'Configuration updated successfully' };
453
- } catch (error) {
454
- console.error('RecallDesktopMain: Failed to set configuration:', error);
455
- return { success: false, message: 'Failed to update configuration' };
456
438
  }
457
- });
439
+ );
458
440
 
459
441
  // Get configuration
460
- ipcMain.handle(IPC_CHANNELS.GET_CONFIG, async (): Promise<ApiResponse<RecallSdkConfig>> => {
461
- return {
462
- success: true,
463
- message: 'Configuration retrieved successfully',
464
- data: recallSdkStore.getConfig()
465
- };
466
- });
442
+ ipcMain.handle(
443
+ IPC_CHANNELS.GET_CONFIG,
444
+ async (): Promise<ApiResponse<RecallSdkConfig>> => {
445
+ return {
446
+ success: true,
447
+ message: "Configuration retrieved successfully",
448
+ data: recallSdkStore.getConfig(),
449
+ };
450
+ }
451
+ );
467
452
  }
468
453
  }
469
454
 
470
455
  // Initialize plugin
471
- const recallDesktopMain = new RecallDesktopMain();
472
- recallDesktopMain.initialize().catch(console.error);
456
+ export const recallDesktopMain = new RecallDesktopMain();
473
457
 
474
- export default recallDesktopMain;
458
+ export default (context: PluginContext): void => {
459
+ setPluginContext(context);
460
+ recallDesktopMain.initialize().catch(() => undefined);
461
+ };