@todesktop/plugin-recall 1.0.3 → 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/dist/main.d.ts +9 -4
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +183 -364
- package/dist/main.js.map +1 -1
- package/dist/preload.js +14 -14
- package/dist/shared.d.ts +41 -6
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js.map +1 -1
- package/dist/store.d.ts +10 -82
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +14 -7
- package/dist/store.js.map +1 -1
- package/package.json +1 -1
- package/src/main.ts +314 -327
- package/src/shared.ts +74 -39
- package/src/store.ts +41 -166
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
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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 =
|
|
33
|
+
private version = "1.0.0";
|
|
66
34
|
private isInitialized = false;
|
|
67
|
-
private subscriptions: Map<RecallSdkEventType, Map<number, number>> =
|
|
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
|
-
//
|
|
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(
|
|
67
|
+
console.log("RecallDesktopMain: Main process initialized");
|
|
89
68
|
} catch (error) {
|
|
90
|
-
console.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
|
-
? [
|
|
84
|
+
? ["accessibility", "screen-capture", "microphone", "system-audio"]
|
|
115
85
|
: undefined,
|
|
116
86
|
restartOnError: true,
|
|
117
87
|
};
|
|
118
88
|
|
|
119
|
-
|
|
120
|
-
await (RecallAiSdk.init as any)(sdkOptions);
|
|
89
|
+
console.log("RecallDesktopMain: SDK options:", sdkOptions);
|
|
121
90
|
|
|
122
|
-
//
|
|
123
|
-
|
|
91
|
+
// Initialize the Recall SDK
|
|
92
|
+
await RecallAiSdk.init(sdkOptions);
|
|
124
93
|
|
|
125
94
|
recallSdkStore.setSdkInitialized(true);
|
|
126
|
-
console.log(
|
|
95
|
+
console.log("RecallDesktopMain: SDK initialized successfully");
|
|
127
96
|
} catch (error) {
|
|
128
|
-
console.error(
|
|
129
|
-
throw new RecallSdkError(
|
|
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
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
212
|
-
(
|
|
213
|
-
|
|
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
|
-
|
|
222
|
-
|
|
223
|
-
console.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
map =
|
|
271
|
-
|
|
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(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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(
|
|
222
|
+
throw new RecallSdkError("Plugin is disabled", "PLUGIN_DISABLED");
|
|
305
223
|
}
|
|
306
224
|
|
|
307
225
|
if (recallSdkStore.isSdkInitialized()) {
|
|
308
|
-
return { success: true, message:
|
|
226
|
+
return { success: true, message: "SDK already initialized" };
|
|
309
227
|
}
|
|
310
228
|
|
|
311
229
|
await this.initializeSdk();
|
|
312
|
-
return { success: true, message:
|
|
230
|
+
return { success: true, message: "SDK initialized successfully" };
|
|
313
231
|
} catch (error) {
|
|
314
|
-
console.error(
|
|
232
|
+
console.error("RecallDesktopMain: SDK initialization failed:", error);
|
|
315
233
|
return {
|
|
316
234
|
success: false,
|
|
317
|
-
message:
|
|
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(
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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(
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
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(
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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(
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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(
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
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(
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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(
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
|
458
|
+
export default (context: PluginContext): void => {
|
|
459
|
+
setPluginContext(context);
|
|
460
|
+
recallDesktopMain.initialize().catch(() => undefined);
|
|
461
|
+
};
|