@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/README.md +271 -0
- package/dist/main.d.ts +23 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +694 -0
- package/dist/main.js.map +1 -0
- package/dist/preload.d.ts +136 -0
- package/dist/preload.d.ts.map +1 -0
- package/dist/preload.js +218 -0
- package/dist/preload.js.map +1 -0
- package/dist/shared.d.ts +139 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +35 -0
- package/dist/shared.js.map +1 -0
- package/dist/store.d.ts +128 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +231 -0
- package/dist/store.js.map +1 -0
- package/package.json +71 -0
- package/src/main.ts +474 -0
- package/src/preload.ts +237 -0
- package/src/shared.ts +204 -0
- package/src/store.ts +266 -0
- package/tsconfig.json +11 -0
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
|