@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/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: 'recall-desktop:init-sdk',
9
- SHUTDOWN_SDK: 'recall-desktop:shutdown-sdk',
10
- GET_STATUS: 'recall-desktop: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: '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
-
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: 'recall-desktop:prepare-desktop-audio',
21
-
20
+ PREPARE_DESKTOP_AUDIO: "recall-desktop:prepare-desktop-audio",
21
+
22
22
  // Permission management
23
- REQUEST_PERMISSION: 'recall-desktop:request-permission',
24
-
23
+ REQUEST_PERMISSION: "recall-desktop:request-permission",
24
+
25
25
  // Configuration
26
- SET_CONFIG: 'recall-desktop:set-config',
27
- GET_CONFIG: 'recall-desktop: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: 'recall-desktop:subscribe-events',
31
- UNSUBSCRIBE_EVENTS: 'recall-desktop: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
- | 'recording-started'
74
- | 'recording-ended'
75
- | 'upload-progress'
76
- | 'meeting-detected'
77
- | 'meeting-updated'
78
- | 'meeting-closed'
79
- | 'sdk-state-change'
80
- | 'error'
81
- | 'media-capture-status'
82
- | 'participant-capture-status'
83
- | 'permissions-granted'
84
- | 'permission-status'
85
- | 'realtime-event'
86
- | 'shutdown';
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: 'recording' | 'idle' | 'paused';
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: 'video' | 'audio';
160
+ type: "video" | "audio";
130
161
  capturing: boolean;
131
162
  }
132
163
 
133
164
  export interface ParticipantCaptureStatusEvent {
134
165
  window: MeetingWindow;
135
- type: 'video' | 'audio' | 'screenshare';
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 = 'accessibility' | 'screen-capture' | 'microphone' | 'system-audio';
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?: 'recording' | 'idle' | 'paused';
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 = 'RecallSdkError';
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 { RecallSdkConfig, MeetingWindow, PermissionType } from './shared';
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: Record<string, any>): void {
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
+ };