@recallai/desktop-sdk 1.1.0 → 1.2.0

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,17 @@
1
+ ### 1.2.0 [minor] (MacOS+Windows) - 2025-09-26
2
+
3
+ - Initial support for Google Meet on Windows
4
+ - Fixed issues with participant mapping on Windows
5
+ - Mixed audio mp3 support for Windows
6
+ - Zoom, Teams, Google Meet url scraping for Windows
7
+ - Gladia streaming support for transcription
8
+ - Fixed an issue where Zoom video capture would be affected when chat is open
9
+ - Improved acoustic audio cancellation
10
+ - Added the ability to get URL from Zoom and Teams meetings
11
+ - Various improvements for Google Meet support on macOS
12
+ - Speeded up starting a recording
13
+ - Caused recording to stop when the laptop lid is closed
14
+
1
15
  ### 1.1.0 [minor] (MacOS+Windows) - 2025-08-29
2
16
 
3
17
  - Reduce idle power consumption by 80%
package/index.d.ts CHANGED
@@ -105,6 +105,7 @@ export interface ShutdownEvent {
105
105
  }
106
106
  export declare function init(options: RecallAiSdkConfig): Promise<null>;
107
107
  export declare function shutdown(): Promise<null>;
108
+ export declare function dumpAXTree(procName: string): Promise<any>;
108
109
  export declare function startRecording(config: StartRecordingConfig): Promise<null>;
109
110
  export declare function stopRecording({ windowId }: StopRecordingConfig): Promise<null>;
110
111
  export declare function pauseRecording({ windowId }: PauseRecordingConfig): Promise<null>;
package/index.js CHANGED
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.init = init;
37
37
  exports.shutdown = shutdown;
38
+ exports.dumpAXTree = dumpAXTree;
38
39
  exports.startRecording = startRecording;
39
40
  exports.stopRecording = stopRecording;
40
41
  exports.pauseRecording = pauseRecording;
@@ -46,6 +47,7 @@ exports.addEventListener = addEventListener;
46
47
  const path = __importStar(require("path"));
47
48
  const child_process_1 = require("child_process");
48
49
  const readline = __importStar(require("node:readline"));
50
+ const node_stream_1 = require("node:stream");
49
51
  const fs = __importStar(require("node:fs"));
50
52
  const os = __importStar(require("node:os"));
51
53
  const uuid_1 = require("uuid");
@@ -62,6 +64,9 @@ else if (process.platform === "win32") {
62
64
  exe_paths.push(path.join(__dirname, "agent-windows.exe"));
63
65
  }
64
66
  let proc;
67
+ let rlData;
68
+ let rlStdout;
69
+ let rlStderr;
65
70
  const listeners = [];
66
71
  const pendingCommands = {};
67
72
  let lastOptions;
@@ -81,6 +86,47 @@ function flushLogBuffer() {
81
86
  doLog(level, [log], echo);
82
87
  }
83
88
  }
89
+ function isPlainObject(value) {
90
+ return (value !== null &&
91
+ typeof value === "object" &&
92
+ Object.getPrototypeOf(value) === Object.prototype);
93
+ }
94
+ /**
95
+ * JSON.stringify with alphabetically sorted object keys (deep).
96
+ * - Preserves array order
97
+ * - Leaves non-plain objects (Date, Map, Set, class instances with toJSON, etc.) intact
98
+ * - Detects circular references like JSON.stringify and throws
99
+ */
100
+ function sortedStringify(value, replacer, space) {
101
+ const seen = new WeakSet();
102
+ function normalize(v) {
103
+ if (v === null || typeof v !== "object")
104
+ return v;
105
+ const obj = v;
106
+ if (seen.has(obj)) {
107
+ throw new TypeError("Converting circular structure to JSON");
108
+ }
109
+ seen.add(obj);
110
+ if (Array.isArray(v)) {
111
+ const out = v.map(normalize);
112
+ seen.delete(obj);
113
+ return out;
114
+ }
115
+ if (isPlainObject(v)) {
116
+ const src = v;
117
+ const out = {};
118
+ for (const key of Object.keys(src).sort()) {
119
+ out[key] = normalize(src[key]);
120
+ }
121
+ seen.delete(obj);
122
+ return out;
123
+ }
124
+ // Non-plain object: keep as-is so built-in toJSON/serialization applies.
125
+ seen.delete(obj);
126
+ return v;
127
+ }
128
+ return JSON.stringify(normalize(value), replacer, space);
129
+ }
84
130
  async function doLog(level, log, echo = true) {
85
131
  try {
86
132
  const levelMap = {
@@ -119,7 +165,7 @@ function logError(...log) {
119
165
  }
120
166
  function emitEvent(type, payload) {
121
167
  if (type !== "upload-progress" && type !== "realtime-event") {
122
- doLog("info", ["Receiving event: " + type + " | " + JSON.stringify(payload)], false);
168
+ doLog("info", ["Receiving event: " + type + " | " + sortedStringify(payload)], false);
123
169
  }
124
170
  for (const listener of listeners) {
125
171
  if (listener.type === type) {
@@ -160,7 +206,7 @@ function startProcess() {
160
206
  }
161
207
  }
162
208
  proc = (0, child_process_1.spawn)(exe_path, {
163
- stdio: "pipe",
209
+ stdio: (process.platform === "darwin" ? ["pipe", "pipe", "pipe", "pipe"] : "pipe"),
164
210
  env: {
165
211
  GST_DEBUG: "2",
166
212
  GST_DEBUG_DUMP_DOT_DIR: gst_dump_dir,
@@ -171,10 +217,16 @@ function startProcess() {
171
217
  ...envExtra,
172
218
  }
173
219
  });
174
- const rlStdout = readline.createInterface({ input: proc.stdout, crlfDelay: Infinity });
175
- const rlStderr = readline.createInterface({ input: proc.stderr, crlfDelay: Infinity });
176
- rlStdout.on('line', (line) => {
177
- if (line.startsWith("recall_ai_command|")) {
220
+ if (process.platform === "darwin") {
221
+ const fd3 = proc.stdio[3];
222
+ if (fd3 && fd3 instanceof node_stream_1.Readable) {
223
+ rlData = readline.createInterface({ input: fd3, crlfDelay: Infinity });
224
+ }
225
+ }
226
+ rlStdout = readline.createInterface({ input: proc.stdout, crlfDelay: Infinity });
227
+ rlStderr = readline.createInterface({ input: proc.stderr, crlfDelay: Infinity });
228
+ let onLine = (line) => {
229
+ if (line?.startsWith("recall_ai_command|")) {
178
230
  try {
179
231
  const data = JSON.parse(line.substring(18));
180
232
  switch (data.type) {
@@ -207,7 +259,9 @@ function startProcess() {
207
259
  console.log(line);
208
260
  }
209
261
  }
210
- });
262
+ };
263
+ rlData?.on('line', onLine);
264
+ rlStdout.on('line', onLine);
211
265
  rlStderr.on('line', (line) => {
212
266
  if (process.env.RECALLAI_DESKTOP_SDK_DEV) {
213
267
  console.error(line);
@@ -224,6 +278,10 @@ function startProcess() {
224
278
  proc.on('close', async (code, signal) => {
225
279
  flushPendingCommands(new Error(`Process exited with code ${code}, signal ${signal}.`));
226
280
  emitEvent('shutdown', { code: code ?? 0, signal: signal ?? '' });
281
+ rlStdout?.close();
282
+ rlStderr?.close();
283
+ rlStdout = null;
284
+ rlStderr = null;
227
285
  if (code === 0 || signal === 'SIGINT') {
228
286
  return;
229
287
  }
@@ -298,6 +356,9 @@ async function shutdown() {
298
356
  }
299
357
  return result;
300
358
  }
359
+ function dumpAXTree(procName) {
360
+ return sendCommand("dumpAXTree", { procName });
361
+ }
301
362
  function startRecording(config) {
302
363
  return sendCommand("startRecording", { config: JSON.stringify(config) });
303
364
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recallai/desktop-sdk",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Recall Desktop SDK",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -13,12 +13,12 @@
13
13
  },
14
14
  "scripts": {
15
15
  "install": "node ./setup.js",
16
- "validate-types": "tsc --noEmit index.d.ts",
16
+ "validate-types": "tsc --noEmit",
17
17
  "build": "tsc -p tsconfig.build.json"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/node": "^24.2.0",
21
21
  "typescript": "^5.3.3"
22
22
  },
23
- "commit_sha": "6b2ffc56b52550ef46336f4ed9646d20f0e4b722"
23
+ "commit_sha": "f1c3fbbb113f8f5a51d801dd9fe240b371125539"
24
24
  }