@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/shared.ts
CHANGED
|
@@ -5,30 +5,30 @@
|
|
|
5
5
|
// IPC channel names - use unique namespace to avoid conflicts
|
|
6
6
|
export const IPC_CHANNELS = {
|
|
7
7
|
// SDK lifecycle
|
|
8
|
-
INIT_SDK:
|
|
9
|
-
SHUTDOWN_SDK:
|
|
10
|
-
GET_STATUS:
|
|
11
|
-
|
|
8
|
+
INIT_SDK: "recall-desktop:init-sdk",
|
|
9
|
+
SHUTDOWN_SDK: "recall-desktop:shutdown-sdk",
|
|
10
|
+
GET_STATUS: "recall-desktop:get-status",
|
|
11
|
+
|
|
12
12
|
// Recording management
|
|
13
|
-
START_RECORDING:
|
|
14
|
-
STOP_RECORDING:
|
|
15
|
-
PAUSE_RECORDING:
|
|
16
|
-
RESUME_RECORDING:
|
|
17
|
-
UPLOAD_RECORDING:
|
|
18
|
-
|
|
13
|
+
START_RECORDING: "recall-desktop:start-recording",
|
|
14
|
+
STOP_RECORDING: "recall-desktop:stop-recording",
|
|
15
|
+
PAUSE_RECORDING: "recall-desktop:pause-recording",
|
|
16
|
+
RESUME_RECORDING: "recall-desktop:resume-recording",
|
|
17
|
+
UPLOAD_RECORDING: "recall-desktop:upload-recording",
|
|
18
|
+
|
|
19
19
|
// Desktop audio recording
|
|
20
|
-
PREPARE_DESKTOP_AUDIO:
|
|
21
|
-
|
|
20
|
+
PREPARE_DESKTOP_AUDIO: "recall-desktop:prepare-desktop-audio",
|
|
21
|
+
|
|
22
22
|
// Permission management
|
|
23
|
-
REQUEST_PERMISSION:
|
|
24
|
-
|
|
23
|
+
REQUEST_PERMISSION: "recall-desktop:request-permission",
|
|
24
|
+
|
|
25
25
|
// Configuration
|
|
26
|
-
SET_CONFIG:
|
|
27
|
-
GET_CONFIG:
|
|
28
|
-
|
|
26
|
+
SET_CONFIG: "recall-desktop:set-config",
|
|
27
|
+
GET_CONFIG: "recall-desktop:get-config",
|
|
28
|
+
|
|
29
29
|
// Event subscription
|
|
30
|
-
SUBSCRIBE_EVENTS:
|
|
31
|
-
UNSUBSCRIBE_EVENTS:
|
|
30
|
+
SUBSCRIBE_EVENTS: "recall-desktop:subscribe-events",
|
|
31
|
+
UNSUBSCRIBE_EVENTS: "recall-desktop:unsubscribe-events",
|
|
32
32
|
} as const;
|
|
33
33
|
|
|
34
34
|
// Recall SDK Configuration (mirrors RecallAiSdkConfig where applicable)
|
|
@@ -38,6 +38,37 @@ export interface RecallSdkConfig {
|
|
|
38
38
|
requestPermissionsOnStartup: boolean;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// ToDesktop plugin context (subset relevant to this plugin)
|
|
42
|
+
export interface PluginContext {
|
|
43
|
+
plugin: {
|
|
44
|
+
todesktop: {
|
|
45
|
+
preferences: [
|
|
46
|
+
{
|
|
47
|
+
id: "enabled";
|
|
48
|
+
name: string;
|
|
49
|
+
description: string;
|
|
50
|
+
type: "checkbox";
|
|
51
|
+
spec: { value?: boolean };
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "apiUrl";
|
|
55
|
+
name: string;
|
|
56
|
+
description: string;
|
|
57
|
+
type: "text";
|
|
58
|
+
spec: { value?: string };
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "requestPermissionsOnStartup";
|
|
62
|
+
name: string;
|
|
63
|
+
description: string;
|
|
64
|
+
type: "checkbox";
|
|
65
|
+
spec: { value?: boolean };
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
41
72
|
// Meeting window information from SDK
|
|
42
73
|
export interface MeetingWindow {
|
|
43
74
|
id: string;
|
|
@@ -70,20 +101,20 @@ export interface UploadRecordingRequest {
|
|
|
70
101
|
|
|
71
102
|
// SDK Events from Recall SDK (mirror upstream)
|
|
72
103
|
export type RecallSdkEventType =
|
|
73
|
-
|
|
|
74
|
-
|
|
|
75
|
-
|
|
|
76
|
-
|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
|
104
|
+
| "recording-started"
|
|
105
|
+
| "recording-ended"
|
|
106
|
+
| "upload-progress"
|
|
107
|
+
| "meeting-detected"
|
|
108
|
+
| "meeting-updated"
|
|
109
|
+
| "meeting-closed"
|
|
110
|
+
| "sdk-state-change"
|
|
111
|
+
| "error"
|
|
112
|
+
| "media-capture-status"
|
|
113
|
+
| "participant-capture-status"
|
|
114
|
+
| "permissions-granted"
|
|
115
|
+
| "permission-status"
|
|
116
|
+
| "realtime-event"
|
|
117
|
+
| "shutdown";
|
|
87
118
|
|
|
88
119
|
export interface RecallSdkEvent {
|
|
89
120
|
type: RecallSdkEventType;
|
|
@@ -98,7 +129,7 @@ export interface MeetingDetectedEvent {
|
|
|
98
129
|
export interface SdkStateChangeEvent {
|
|
99
130
|
sdk: {
|
|
100
131
|
state: {
|
|
101
|
-
code:
|
|
132
|
+
code: "recording" | "idle" | "paused";
|
|
102
133
|
};
|
|
103
134
|
};
|
|
104
135
|
}
|
|
@@ -126,13 +157,13 @@ export interface MeetingUpdatedEvent {
|
|
|
126
157
|
|
|
127
158
|
export interface MediaCaptureStatusEvent {
|
|
128
159
|
window: MeetingWindow;
|
|
129
|
-
type:
|
|
160
|
+
type: "video" | "audio";
|
|
130
161
|
capturing: boolean;
|
|
131
162
|
}
|
|
132
163
|
|
|
133
164
|
export interface ParticipantCaptureStatusEvent {
|
|
134
165
|
window: MeetingWindow;
|
|
135
|
-
type:
|
|
166
|
+
type: "video" | "audio" | "screenshare";
|
|
136
167
|
capturing: boolean;
|
|
137
168
|
}
|
|
138
169
|
|
|
@@ -159,7 +190,11 @@ export interface ShutdownEvent {
|
|
|
159
190
|
}
|
|
160
191
|
|
|
161
192
|
// Permission types (mirror upstream)
|
|
162
|
-
export type PermissionType =
|
|
193
|
+
export type PermissionType =
|
|
194
|
+
| "accessibility"
|
|
195
|
+
| "screen-capture"
|
|
196
|
+
| "microphone"
|
|
197
|
+
| "system-audio";
|
|
163
198
|
|
|
164
199
|
// API Response types
|
|
165
200
|
export interface ApiResponse<T = any> {
|
|
@@ -174,7 +209,7 @@ export interface PluginStatus {
|
|
|
174
209
|
sdkInitialized: boolean;
|
|
175
210
|
version: string;
|
|
176
211
|
config: RecallSdkConfig;
|
|
177
|
-
sdkState?:
|
|
212
|
+
sdkState?: "recording" | "idle" | "paused";
|
|
178
213
|
permissions?: {
|
|
179
214
|
accessibility: boolean;
|
|
180
215
|
screenCapture: boolean;
|
|
@@ -187,7 +222,7 @@ export interface PluginStatus {
|
|
|
187
222
|
export class RecallSdkError extends Error {
|
|
188
223
|
constructor(message: string, public code?: string) {
|
|
189
224
|
super(message);
|
|
190
|
-
this.name =
|
|
225
|
+
this.name = "RecallSdkError";
|
|
191
226
|
}
|
|
192
227
|
}
|
|
193
228
|
|
package/src/store.ts
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* Recall Desktop SDK plugin state management and storage
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { PluginContext, RecallSdkConfig } from './shared';
|
|
6
|
+
|
|
7
|
+
let pluginContext: PluginContext | undefined;
|
|
6
8
|
|
|
7
9
|
class RecallSdkStore {
|
|
8
10
|
private config: RecallSdkConfig = {
|
|
@@ -13,22 +15,6 @@ class RecallSdkStore {
|
|
|
13
15
|
|
|
14
16
|
private initialized = false;
|
|
15
17
|
private sdkInitialized = false;
|
|
16
|
-
private currentSdkState: 'recording' | 'idle' | 'paused' = 'idle';
|
|
17
|
-
|
|
18
|
-
// Active meetings and recordings
|
|
19
|
-
private activeMeetings = new Map<string, MeetingWindow>();
|
|
20
|
-
private activeRecordings = new Map<string, { window: MeetingWindow; uploadToken: string }>();
|
|
21
|
-
|
|
22
|
-
// Permission status
|
|
23
|
-
private permissions = {
|
|
24
|
-
accessibility: false,
|
|
25
|
-
screenCapture: false,
|
|
26
|
-
microphone: false,
|
|
27
|
-
systemAudio: false,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// Event listeners for SDK events
|
|
31
|
-
private eventListeners = new Set<(event: any) => void>();
|
|
32
18
|
|
|
33
19
|
/**
|
|
34
20
|
* Initialize the plugin store
|
|
@@ -64,7 +50,7 @@ class RecallSdkStore {
|
|
|
64
50
|
/**
|
|
65
51
|
* Load configuration from ToDesktop preferences
|
|
66
52
|
*/
|
|
67
|
-
loadFromPreferences(preferences:
|
|
53
|
+
loadFromPreferences(preferences: Partial<RecallSdkConfig>): void {
|
|
68
54
|
if (preferences.enabled !== undefined) {
|
|
69
55
|
this.config.enabled = preferences.enabled;
|
|
70
56
|
}
|
|
@@ -106,161 +92,50 @@ class RecallSdkStore {
|
|
|
106
92
|
return this.sdkInitialized;
|
|
107
93
|
}
|
|
108
94
|
|
|
109
|
-
/**
|
|
110
|
-
* Set current SDK state
|
|
111
|
-
*/
|
|
112
|
-
setSdkState(state: 'recording' | 'idle' | 'paused'): void {
|
|
113
|
-
this.currentSdkState = state;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Get current SDK state
|
|
118
|
-
*/
|
|
119
|
-
getSdkState(): 'recording' | 'idle' | 'paused' {
|
|
120
|
-
return this.currentSdkState;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Add an active meeting
|
|
125
|
-
*/
|
|
126
|
-
addMeeting(meeting: MeetingWindow): void {
|
|
127
|
-
this.activeMeetings.set(meeting.id, meeting);
|
|
128
|
-
console.log(`RecallSdkStore: Added meeting ${meeting.id}:`, meeting);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Remove a meeting
|
|
133
|
-
*/
|
|
134
|
-
removeMeeting(windowId: string): void {
|
|
135
|
-
this.activeMeetings.delete(windowId);
|
|
136
|
-
console.log(`RecallSdkStore: Removed meeting ${windowId}`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Get active meeting by window ID
|
|
141
|
-
*/
|
|
142
|
-
getMeeting(windowId: string): MeetingWindow | undefined {
|
|
143
|
-
return this.activeMeetings.get(windowId);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Get all active meetings
|
|
148
|
-
*/
|
|
149
|
-
getAllMeetings(): MeetingWindow[] {
|
|
150
|
-
return Array.from(this.activeMeetings.values());
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Start a recording
|
|
155
|
-
*/
|
|
156
|
-
startRecording(windowId: string, uploadToken: string): void {
|
|
157
|
-
const window = this.activeMeetings.get(windowId);
|
|
158
|
-
if (window) {
|
|
159
|
-
this.activeRecordings.set(windowId, { window, uploadToken });
|
|
160
|
-
console.log(`RecallSdkStore: Started recording for ${windowId}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Stop a recording
|
|
166
|
-
*/
|
|
167
|
-
stopRecording(windowId: string): void {
|
|
168
|
-
this.activeRecordings.delete(windowId);
|
|
169
|
-
console.log(`RecallSdkStore: Stopped recording for ${windowId}`);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Get active recording by window ID
|
|
174
|
-
*/
|
|
175
|
-
getRecording(windowId: string): { window: MeetingWindow; uploadToken: string } | undefined {
|
|
176
|
-
return this.activeRecordings.get(windowId);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Get all active recordings
|
|
181
|
-
*/
|
|
182
|
-
getAllRecordings(): { window: MeetingWindow; uploadToken: string }[] {
|
|
183
|
-
return Array.from(this.activeRecordings.values());
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Update permission status
|
|
188
|
-
*/
|
|
189
|
-
setPermissionStatus(permission: PermissionType, status: string): void {
|
|
190
|
-
const granted = status === 'granted' || status === 'authorized' || status === 'ALLOWED';
|
|
191
|
-
if (permission === 'screen-capture') {
|
|
192
|
-
this.permissions.screenCapture = granted;
|
|
193
|
-
} else if (permission === 'system-audio') {
|
|
194
|
-
this.permissions.systemAudio = granted;
|
|
195
|
-
} else {
|
|
196
|
-
// permission is 'accessibility' | 'microphone'
|
|
197
|
-
// @ts-ignore - index by key
|
|
198
|
-
this.permissions[permission] = granted;
|
|
199
|
-
}
|
|
200
|
-
console.log(`RecallSdkStore: Permission ${permission} status: ${status}`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Get permission status
|
|
205
|
-
*/
|
|
206
|
-
getPermissions(): { accessibility: boolean; screenCapture: boolean; microphone: boolean; systemAudio: boolean } {
|
|
207
|
-
return { ...this.permissions };
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Check if all required permissions are granted
|
|
212
|
-
*/
|
|
213
|
-
arePermissionsGranted(): boolean {
|
|
214
|
-
return (
|
|
215
|
-
this.permissions.accessibility &&
|
|
216
|
-
this.permissions.screenCapture &&
|
|
217
|
-
this.permissions.microphone
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Add event listener for SDK events
|
|
223
|
-
*/
|
|
224
|
-
addEventListener(listener: (event: any) => void): void {
|
|
225
|
-
this.eventListeners.add(listener);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Remove event listener
|
|
230
|
-
*/
|
|
231
|
-
removeEventListener(listener: (event: any) => void): void {
|
|
232
|
-
this.eventListeners.delete(listener);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Emit event to all listeners
|
|
237
|
-
*/
|
|
238
|
-
emitEvent(event: any): void {
|
|
239
|
-
this.eventListeners.forEach(listener => {
|
|
240
|
-
try {
|
|
241
|
-
listener(event);
|
|
242
|
-
} catch (error) {
|
|
243
|
-
console.error('RecallSdkStore: Error in event listener:', error);
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
|
|
248
95
|
/**
|
|
249
96
|
* Clear all state (useful for shutdown/reset)
|
|
250
97
|
*/
|
|
251
98
|
clearState(): void {
|
|
252
|
-
this.activeMeetings.clear();
|
|
253
|
-
this.activeRecordings.clear();
|
|
254
99
|
this.setSdkInitialized(false);
|
|
255
|
-
this.setSdkState('idle');
|
|
256
|
-
this.permissions = {
|
|
257
|
-
accessibility: false,
|
|
258
|
-
screenCapture: false,
|
|
259
|
-
microphone: false,
|
|
260
|
-
systemAudio: false,
|
|
261
|
-
};
|
|
262
100
|
console.log('RecallSdkStore: Cleared all state');
|
|
263
101
|
}
|
|
264
102
|
}
|
|
265
103
|
|
|
266
104
|
export const recallSdkStore = new RecallSdkStore();
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Persist the ToDesktop plugin context and hydrate the store configuration.
|
|
108
|
+
*/
|
|
109
|
+
export const setPluginContext = (input: PluginContext): void => {
|
|
110
|
+
pluginContext = input;
|
|
111
|
+
|
|
112
|
+
const [enabledPref, apiUrlPref, requestPref] =
|
|
113
|
+
input.plugin?.todesktop?.preferences ?? [];
|
|
114
|
+
|
|
115
|
+
const preferences: Partial<RecallSdkConfig> = {
|
|
116
|
+
enabled:
|
|
117
|
+
typeof enabledPref?.spec?.value === 'boolean'
|
|
118
|
+
? enabledPref.spec.value
|
|
119
|
+
: undefined,
|
|
120
|
+
apiUrl:
|
|
121
|
+
typeof apiUrlPref?.spec?.value === 'string' && apiUrlPref.spec.value.trim()
|
|
122
|
+
? apiUrlPref.spec.value
|
|
123
|
+
: undefined,
|
|
124
|
+
requestPermissionsOnStartup:
|
|
125
|
+
typeof requestPref?.spec?.value === 'boolean'
|
|
126
|
+
? requestPref.spec.value
|
|
127
|
+
: undefined,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
recallSdkStore.loadFromPreferences(preferences);
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Accessor for the stored plugin context.
|
|
135
|
+
*/
|
|
136
|
+
export const getPluginContext = (): PluginContext => {
|
|
137
|
+
if (!pluginContext) {
|
|
138
|
+
throw new Error('Plugin context has not been set');
|
|
139
|
+
}
|
|
140
|
+
return pluginContext;
|
|
141
|
+
};
|