@recallai/desktop-sdk 2.0.37 → 2.0.38

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ### 2.0.38 [patch] (MacOS+Windows) - 2026-10-14
2
+ - Add telemetryMode field to init method
3
+ - Fix for compliance messaging failing to send for Zoom Desktop on macOS
4
+ - Fix for focus issue with compliance messaging for Zoom Desktop on macOS
5
+ - Fix for meeting detection for Teams Desktop v26246+ on macOS
6
+ - Fix for title extraction for Zoom Desktop on macOS
7
+
1
8
  ### 2.0.37 [patch] (MacOS+Windows) - 2026-10-08
2
9
  - Fix Arc meeting detection
3
10
  - Add anonymizeLogging field to init method
package/index.d.ts CHANGED
@@ -111,12 +111,7 @@ export interface RecallAiSdkConfig {
111
111
  * Ignored on Windows, where these permission flows are unnecessary.
112
112
  */
113
113
  acquirePermissionsOnStartup?: Exclude<Permission, 'teams-automation' | 'browser-automation'>[];
114
- /**
115
- * Anonymizes debug logging when enabled. (Default: false).
116
- *
117
- * This will make debugging issues harder, so please keep that in mind before enabling.
118
- * This setting may be required for data privacy.
119
- */
114
+ telemetryMode?: 'full' | 'limited' | 'off';
120
115
  anonymizeLogging?: boolean;
121
116
  [key: string]: any;
122
117
  }
package/index.js CHANGED
@@ -78,6 +78,7 @@ const listeners = [];
78
78
  const lastErrorOut = [];
79
79
  const pendingCommands = {};
80
80
  let lastOptions;
81
+ let telemetryMode = 'off';
81
82
  let remainingAutomaticRestarts = 10;
82
83
  let unexpectedShutdown = false;
83
84
  let exiting = false;
@@ -111,12 +112,17 @@ function getPackageVersion() {
111
112
  process.on("exit", () => {
112
113
  exiting = true;
113
114
  if (proc && !proc.killed) {
114
- console.warn("Desktop SDK received exit signal and is still running, killing the process.");
115
+ if (telemetryMode !== 'off') {
116
+ console.warn("Desktop SDK received exit signal and is still running, killing the process.");
117
+ }
115
118
  proc.kill();
116
119
  proc = null;
117
120
  }
118
121
  });
119
122
  function appendError(error) {
123
+ if (telemetryMode !== 'full') {
124
+ return;
125
+ }
120
126
  lastErrorOut.push(error);
121
127
  if (lastErrorOut.length > 100) {
122
128
  lastErrorOut.shift();
@@ -131,7 +137,7 @@ function flushLogBuffer() {
131
137
  // and know that Nick and Tucker spent at least 10 minutes debating this
132
138
  for (const idx in buf) {
133
139
  const { level, log, echo } = buf[idx];
134
- doLog(level, [log], echo);
140
+ doLog(level, { full: () => [log] }, echo);
135
141
  }
136
142
  }
137
143
  function isPlainObject(value) {
@@ -175,8 +181,16 @@ function sortedStringify(value, replacer, space) {
175
181
  }
176
182
  return JSON.stringify(normalize(value), replacer, space);
177
183
  }
178
- async function doLog(level, log, echo = true) {
184
+ async function doLog(level, messages, echo = true) {
185
+ if (telemetryMode === 'off') {
186
+ return;
187
+ }
188
+ const render = telemetryMode === 'limited' && messages.limited !== true ? messages.limited : messages.full;
189
+ if (!render) {
190
+ return;
191
+ }
179
192
  try {
193
+ const log = render();
180
194
  const levelMap = {
181
195
  "info": "log",
182
196
  "warning": "warn",
@@ -186,6 +200,9 @@ async function doLog(level, log, echo = true) {
186
200
  const consoleMethod = console[levelMap[level] ?? "log"];
187
201
  consoleMethod(...log);
188
202
  }
203
+ if (telemetryMode === 'limited') {
204
+ return;
205
+ }
189
206
  const logPayload = {
190
207
  log: log.join(" "),
191
208
  level: level,
@@ -201,25 +218,27 @@ async function doLog(level, log, echo = true) {
201
218
  delete logBuffer[idx];
202
219
  }
203
220
  }
204
- catch (e) {
221
+ catch {
205
222
  if (proc?.exitCode === 0 || exiting) {
206
223
  return;
207
224
  }
208
- console.error("Failed to send log to Desktop SDK", e.stack, e.message);
225
+ if (telemetryMode === 'full' || telemetryMode === 'limited') {
226
+ console.error("Failed to send log to Desktop SDK");
227
+ }
209
228
  }
210
229
  }
211
230
  function log(...log) {
212
- doLog("info", log);
231
+ doLog("info", { full: () => log });
213
232
  }
214
233
  function logWarning(...log) {
215
- doLog("warning", log);
234
+ doLog("warning", { full: () => log });
216
235
  }
217
236
  function logError(...log) {
218
- doLog("error", log);
237
+ doLog("error", { full: () => log });
219
238
  }
220
239
  function emitEvent(type, payload) {
221
240
  if (type !== "upload-progress" && type !== "realtime-event" && type !== "log") {
222
- doLog("info", ["Receiving event: " + type + " | " + sortedStringify(payload)], false);
241
+ doLog("info", { full: () => ["Receiving event: " + type + " | " + sortedStringify(payload)] }, false);
223
242
  }
224
243
  for (const listener of listeners) {
225
244
  if (listener.type === type) {
@@ -315,7 +334,7 @@ function flushPendingStdinWrites() {
315
334
  activeDrainWriteSequence = null;
316
335
  waitingForStdinDrain = false;
317
336
  flushingPendingStdinWrites = false;
318
- if (drainStartMs !== null && drainStartIso) {
337
+ if (telemetryMode === 'full' && drainStartMs !== null && drainStartIso) {
319
338
  const drainStopIso = new Date(drainStopMs).toISOString();
320
339
  const durationMs = drainStopMs - drainStartMs;
321
340
  void enqueueCommand("log", {
@@ -326,10 +345,18 @@ function flushPendingStdinWrites() {
326
345
  if (proc?.exitCode === 0 || exiting) {
327
346
  return;
328
347
  }
329
- console.error("Failed to enqueue stdin drain log", error.stack, error.message);
348
+ if (telemetryMode === 'full') {
349
+ console.error("Failed to enqueue stdin drain log", error.stack, error.message);
350
+ }
330
351
  });
331
352
  return;
332
353
  }
354
+ if (telemetryMode === 'limited' && drainStartMs !== null) {
355
+ void doLog("info", {
356
+ full: () => [],
357
+ limited: () => [`stdin drain completed | durationMs=${drainStopMs - drainStartMs} | blockedWriteSequence=${drainWriteSequence ?? "unknown"}`]
358
+ });
359
+ }
333
360
  flushPendingStdinWrites();
334
361
  });
335
362
  return;
@@ -383,7 +410,7 @@ function enqueueCommand(command, params = {}, options = {}) {
383
410
  const payloadStr = JSON.stringify(payload);
384
411
  enqueueStdinWrite({ command, commandId, data: payloadStr + "\n", writeSequence }, options.front ?? false);
385
412
  if (!options.suppressSendLog && command !== "log") {
386
- doLog("info", [`Sending command [${writeSequence}]: ` + payloadStr], false);
413
+ doLog("info", { full: () => [`Sending command [${writeSequence}]: ` + payloadStr] }, false);
387
414
  }
388
415
  });
389
416
  }
@@ -394,7 +421,10 @@ function startProcess() {
394
421
  }
395
422
  const exe_path = exe_paths.find(fs.existsSync);
396
423
  if (!exe_path) {
397
- logError(`Desktop SDK: Couldn't launch! This is likely an issue with the build tool you're using.`);
424
+ void doLog("error", {
425
+ full: () => ["Desktop SDK: Couldn't launch! This is likely an issue with the build tool you're using."],
426
+ limited: true
427
+ });
398
428
  for (const exe_path of exe_paths) {
399
429
  logError("Tried:", exe_path);
400
430
  }
@@ -442,7 +472,7 @@ function startProcess() {
442
472
  fs.mkdirSync(gst_dump_dir);
443
473
  }
444
474
  catch (e) {
445
- logError("Failed to create gst dump dir:", String(e));
475
+ void doLog("error", { full: () => ["Failed to create gst dump dir:", String(e)] });
446
476
  }
447
477
  }
448
478
  // The diarization debug dashboard parses smart_annotator's per-word
@@ -465,6 +495,13 @@ function startProcess() {
465
495
  // MallocStackLogging: "1",
466
496
  // MallocStackLoggingNoCompact: "1",
467
497
  ...envExtra,
498
+ RECALL_DSDK_TELEMETRY_MODE: telemetryMode,
499
+ ...(telemetryMode !== 'full' ? {
500
+ GST_DEBUG: "0",
501
+ GST_RECALL_DEBUG: "0",
502
+ GST_DEBUG_DUMP_DOT_DIR: undefined,
503
+ RUST_BACKTRACE: "0",
504
+ } : {}),
468
505
  }
469
506
  });
470
507
  const currentProc = proc;
@@ -473,7 +510,12 @@ function startProcess() {
473
510
  return;
474
511
  }
475
512
  // Do not use logError here: it sends a command through this same stdin.
476
- console.error(`Desktop SDK: stdin stream error: ${error.stack ?? error.message}`);
513
+ if (telemetryMode === 'full') {
514
+ console.error(`Desktop SDK: stdin stream error: ${error.stack ?? error.message}`);
515
+ }
516
+ else if (telemetryMode === 'limited') {
517
+ console.error("Desktop SDK: stdin stream error");
518
+ }
477
519
  resetPendingStdinWrites();
478
520
  flushPendingCommands(new Error(`Desktop SDK stdin error: ${error.message}`));
479
521
  if (currentProc.exitCode === null && !currentProc.killed) {
@@ -515,11 +557,14 @@ function startProcess() {
515
557
  }
516
558
  }
517
559
  catch (err) {
518
- logError("Desktop SDK: Failed to parse incoming data:", String(err));
560
+ void doLog("error", {
561
+ full: () => ["Desktop SDK: Failed to parse incoming data:", String(err)],
562
+ limited: () => ["Desktop SDK: Failed to parse incoming data"]
563
+ });
519
564
  }
520
565
  }
521
566
  else {
522
- if (process.env.RECALLAI_DESKTOP_SDK_DEV) {
567
+ if (telemetryMode === 'full' && process.env.RECALLAI_DESKTOP_SDK_DEV) {
523
568
  console.log(line);
524
569
  }
525
570
  }
@@ -528,7 +573,7 @@ function startProcess() {
528
573
  rlStdout.on('line', onLine);
529
574
  rlStderr.on('line', (line) => {
530
575
  appendError(line);
531
- if (process.env.RECALLAI_DESKTOP_SDK_DEV) {
576
+ if (telemetryMode === 'full' && process.env.RECALLAI_DESKTOP_SDK_DEV) {
532
577
  console.error(line);
533
578
  }
534
579
  });
@@ -549,7 +594,10 @@ function startProcess() {
549
594
  type: 'process',
550
595
  message: `The Desktop SDK server process has failed to start or exited improperly.`
551
596
  });
552
- logError(`Desktop SDK: Process error: ${error.message}`);
597
+ void doLog("error", {
598
+ full: () => [`Desktop SDK: Process error: ${error.message}`],
599
+ limited: () => ["Desktop SDK: Process error"]
600
+ });
553
601
  });
554
602
  proc.on('close', async (code, signal) => {
555
603
  if (proc !== currentProc) {
@@ -566,10 +614,12 @@ function startProcess() {
566
614
  rlStdout = null;
567
615
  rlStderr = null;
568
616
  if (code === 0 || signal === 'SIGINT' || signal === 'SIGTERM' || exiting) {
569
- log(`Desktop SDK: Process closed with code ${code}, signal ${signal}, exiting ${exiting}`);
617
+ const message = `Desktop SDK: Process closed with code ${code}, signal ${signal}, exiting ${exiting}`;
618
+ void doLog("info", { full: () => [message], limited: true });
570
619
  return;
571
620
  }
572
- logError(`Desktop SDK: Process exited with code ${code}, signal ${signal}, exiting ${exiting}`);
621
+ const message = `Desktop SDK: Process exited with code ${code}, signal ${signal}, exiting ${exiting}`;
622
+ void doLog("error", { full: () => [message], limited: true });
573
623
  emitEvent('error', {
574
624
  type: 'process',
575
625
  message: "The Desktop SDK server process exited unexpectedly."
@@ -577,10 +627,16 @@ function startProcess() {
577
627
  unexpectedShutdown = true;
578
628
  if (lastOptions.restartOnError && remainingAutomaticRestarts > 0) {
579
629
  remainingAutomaticRestarts--;
580
- logError(`Automatically restarting Desktop SDK due to unexpected exit! Automatic restarts left: ${remainingAutomaticRestarts}`);
581
- logError(`Last error output from Desktop SDK:\n${lastErrorOut.join("\n")}`);
630
+ const restartMessage = `Automatically restarting Desktop SDK due to unexpected exit! Automatic restarts left: ${remainingAutomaticRestarts}`;
631
+ void doLog("error", { full: () => [restartMessage], limited: true });
632
+ void doLog("error", { full: () => [`Last error output from Desktop SDK:\n${lastErrorOut.join("\n")}`] });
582
633
  lastErrorOut.length = 0;
583
- doInit(lastOptions);
634
+ void doInit(lastOptions).catch((error) => {
635
+ void doLog("error", {
636
+ full: () => ["Desktop SDK: Automatic restart failed:", String(error)],
637
+ limited: () => ["Desktop SDK: Automatic restart failed"]
638
+ });
639
+ });
584
640
  }
585
641
  });
586
642
  }
@@ -590,7 +646,10 @@ function sendCommand(command, params = {}) {
590
646
  async function doInit(options) {
591
647
  startProcess();
592
648
  if (unexpectedShutdown) {
593
- logError("Desktop SDK: Recovered from unexpected shutdown");
649
+ void doLog("error", {
650
+ full: () => ["Desktop SDK: Recovered from unexpected shutdown"],
651
+ limited: true
652
+ });
594
653
  unexpectedShutdown = false;
595
654
  }
596
655
  await sendCommand("init", { config: JSON.stringify(options) });
@@ -610,13 +669,30 @@ async function doInit(options) {
610
669
  * @see https://docs.recall.ai/docs/dsdk-supported-platforms
611
670
  */
612
671
  async function init(options) {
672
+ if (options.telemetryMode !== undefined && !['full', 'limited', 'off'].includes(options.telemetryMode)) {
673
+ throw new Error("telemetryMode must be full, limited, or off");
674
+ }
675
+ if (options.anonymizeLogging !== undefined && typeof options.anonymizeLogging !== 'boolean') {
676
+ throw new Error("anonymizeLogging must be a boolean");
677
+ }
678
+ if (proc && proc.exitCode === null) {
679
+ throw new Error("The Desktop SDK is already started; call shutdown before initializing again");
680
+ }
681
+ telemetryMode = options.anonymizeLogging === true ? 'off' : options.telemetryMode ?? 'full';
682
+ if (telemetryMode !== 'full') {
683
+ logBuffer = [];
684
+ logIndex = 0;
685
+ lastErrorOut.length = 0;
686
+ }
613
687
  if (process.platform !== "darwin" && process.platform !== "win32") {
614
688
  throw new Error(`Platform ${process.platform} is not supported by Desktop SDK`);
615
689
  }
616
690
  const { api_url, apiUrl, dev } = options;
617
691
  options.api_url = api_url ?? apiUrl ?? "https://api.recall.ai";
618
692
  if (!dev && (!options.api_url || !options.api_url.startsWith("https"))) {
619
- throw new Error(`apiUrl must be an https url, got: ${options.api_url}`);
693
+ throw new Error(telemetryMode === 'full'
694
+ ? `apiUrl must be an https url, got: ${options.api_url}`
695
+ : "apiUrl must be an https url");
620
696
  }
621
697
  if (options.restartOnError === undefined) {
622
698
  options.restartOnError = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recallai/desktop-sdk",
3
- "version": "2.0.37",
3
+ "version": "2.0.38",
4
4
  "description": "Recall Desktop SDK",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -20,5 +20,5 @@
20
20
  "@types/node": "^24.2.0",
21
21
  "typescript": "^5.3.3"
22
22
  },
23
- "commit_sha": "67dbe93b4680eaf1332182daaed9a59fa6c7eafa"
23
+ "commit_sha": "82799f1ae5ad0c08f58c6605a6a73992325588ce"
24
24
  }