@nonstrict/recordkit 0.3.0 → 0.3.2
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/License.md +2 -0
- package/Readme.md +16 -0
- package/bin/README.md +1 -0
- package/bin/recordkit-rpc +0 -0
- package/out/IpcRecordKit.js +4 -2
- package/out/IpcRecordKit.js.map +1 -1
- package/out/RecordKit.d.ts +115 -34
- package/out/RecordKit.js +51 -2
- package/out/RecordKit.js.map +1 -1
- package/out/Recorder.d.ts +38 -9
- package/out/Recorder.js +5 -0
- package/out/Recorder.js.map +1 -1
- package/out/index.cjs +60 -4
- package/out/index.cjs.map +1 -1
- package/package.json +6 -5
- package/src/IpcRecordKit.ts +4 -2
- package/src/RecordKit.ts +137 -50
- package/src/Recorder.ts +84 -55
- package/typedoc.json +17 -4
package/License.md
CHANGED
package/Readme.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# RecordKit for Electron
|
|
2
|
+
|
|
3
|
+
RecordKit is a screen recording SDK for macOS apps. Enabling simultaneous recording of the users screen, system audio, camera, microphone, mouse and keyboard. RecordKit is the recording foundation of apps. Generating easy to use video and JSON to build upon.
|
|
4
|
+
|
|
5
|
+
## Useful links
|
|
6
|
+
|
|
7
|
+
- [RecordKit Homepage](https://nonstrict.eu/recordkit)
|
|
8
|
+
- [Getting Started](https://nonstrict.eu/recordkit/try-electron.html)
|
|
9
|
+
- [Full API Reference](https://nonstrict.eu/recordkit/api/electron/)
|
|
10
|
+
- [NPM package](https://www.npmjs.com/package/@nonstrict/recordkit)
|
|
11
|
+
|
|
12
|
+
## License
|
|
13
|
+
|
|
14
|
+
RecordKit is a commercial product that offers a free trial license to evaluate and integrate it into your product. Visit [our website](https://nonstrict.eu/recordkit) to learn more about licensing our solution.
|
|
15
|
+
|
|
16
|
+
Copyright © 2024 Nonstrict B.V.
|
package/bin/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# recordkit-rpc 0.3.2
|
package/bin/recordkit-rpc
CHANGED
|
Binary file
|
package/out/IpcRecordKit.js
CHANGED
|
@@ -13,9 +13,11 @@ export class IpcRecordKit {
|
|
|
13
13
|
}
|
|
14
14
|
this.nsrpc.logMessages = logMessages;
|
|
15
15
|
this.childProcess = await new Promise((resolve, reject) => {
|
|
16
|
-
const childProcess = spawn(recordKitRpcPath);
|
|
17
|
-
childProcess.on('
|
|
16
|
+
const childProcess = spawn(recordKitRpcPath, { stdio: ['pipe', 'pipe', process.stderr] });
|
|
17
|
+
childProcess.on('close', (code, signal) => { console.log(`RecordKit RPC closed with code ${code} and signal ${signal}`); });
|
|
18
18
|
childProcess.on('error', (error) => { reject(error); });
|
|
19
|
+
childProcess.on('exit', (code, signal) => { console.log(`RecordKit RPC exited with code ${code} and signal ${signal}`); });
|
|
20
|
+
childProcess.on('spawn', () => { resolve(childProcess); });
|
|
19
21
|
});
|
|
20
22
|
const { stdout } = this.childProcess;
|
|
21
23
|
if (!stdout) {
|
package/out/IpcRecordKit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IpcRecordKit.js","sourceRoot":"","sources":["../src/IpcRecordKit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,MAAM,OAAO,YAAY;IACf,YAAY,CAAgB;IAC3B,KAAK,CAAQ;IAEtB;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,gBAAwB,EAAE,cAAuB,KAAK;QACrE,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YAAC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;QAAC,CAAC;QAE/F,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,MAAM,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACtE,MAAM,YAAY,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"IpcRecordKit.js","sourceRoot":"","sources":["../src/IpcRecordKit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,MAAM,OAAO,YAAY;IACf,YAAY,CAAgB;IAC3B,KAAK,CAAQ;IAEtB;QACE,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,gBAAwB,EAAE,cAAuB,KAAK;QACrE,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YAAC,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;QAAC,CAAC;QAE/F,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC;QACrC,IAAI,CAAC,YAAY,GAAG,MAAM,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACtE,MAAM,YAAY,GAAG,KAAK,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACzF,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,IAAI,eAAe,MAAM,EAAE,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;YAC1H,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;YACtD,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,kCAAkC,IAAI,eAAe,MAAM,EAAE,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;YACzH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;QAC3D,CAAC,CAAC,CAAA;QAEF,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAA;QACpC,IAAI,CAAC,MAAM,EAAE,CAAC;YAAC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;QAAC,CAAC;QAErF,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,OAAe;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;QAAC,CAAC;QACvE,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAC7B,CAAC;CACF"}
|
package/out/RecordKit.d.ts
CHANGED
|
@@ -1,13 +1,104 @@
|
|
|
1
1
|
import { Recorder, RecorderSchema } from "./Recorder.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Entry point for the RecordKit SDK, an instance is available as `recordkit` that can be imported from the module. Do not instantiate this class directly.
|
|
4
|
+
*
|
|
5
|
+
* @groupDescription Discovery
|
|
6
|
+
* Discover the windows and devices that are available to record.
|
|
7
|
+
*
|
|
8
|
+
* @groupDescription Permissions
|
|
9
|
+
* Check and request the apps permission to access the recording devices.
|
|
10
|
+
*/
|
|
11
|
+
export declare class RecordKit {
|
|
12
|
+
private ipcRecordKit;
|
|
13
|
+
/** @ignore */
|
|
14
|
+
constructor();
|
|
15
|
+
/**
|
|
16
|
+
* Initialize the RecordKit SDK.
|
|
17
|
+
*
|
|
18
|
+
* ⚠️ Must be called before calling any other RecordKit method.
|
|
19
|
+
*
|
|
20
|
+
* @param args
|
|
21
|
+
*/
|
|
22
|
+
initialize(args: {
|
|
23
|
+
/**
|
|
24
|
+
* Path to the `recordkit-rpc` binary, most of the time this should be set to `path.join(process.resourcesPath, 'recordkit-rpc')`.
|
|
25
|
+
*/
|
|
26
|
+
rpcBinaryPath: string;
|
|
27
|
+
/**
|
|
28
|
+
* Whether to fallback to the RPC binary from `node_modules` if the given path does not exist. When enabled an extra check to see if the given path exists is performed. Most of the time this should be set to `!app.isPackaged`.
|
|
29
|
+
*/
|
|
30
|
+
fallbackToNodeModules?: boolean;
|
|
31
|
+
/** @ignore */
|
|
32
|
+
logRpcMessages?: boolean;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* @group Discovery
|
|
36
|
+
*/
|
|
37
|
+
getWindows(): Promise<Window[]>;
|
|
38
|
+
/**
|
|
39
|
+
* @group Discovery
|
|
40
|
+
*/
|
|
41
|
+
getCameras(): Promise<Camera[]>;
|
|
42
|
+
/**
|
|
43
|
+
* @group Discovery
|
|
44
|
+
*/
|
|
45
|
+
getMicrophones(): Promise<Microphone[]>;
|
|
46
|
+
/**
|
|
47
|
+
* @group Discovery
|
|
48
|
+
*/
|
|
49
|
+
getAppleDevices(): Promise<AppleDevice[]>;
|
|
50
|
+
/**
|
|
51
|
+
* @group Permissions
|
|
52
|
+
*/
|
|
53
|
+
getCameraAuthorizationStatus(): Promise<AuthorizationStatus>;
|
|
54
|
+
/**
|
|
55
|
+
* @group Permissions
|
|
56
|
+
*/
|
|
57
|
+
getMicrophoneAuthorizationStatus(): Promise<AuthorizationStatus>;
|
|
58
|
+
/**
|
|
59
|
+
* @group Permissions
|
|
60
|
+
*/
|
|
61
|
+
getScreenRecordingAccess(): Promise<boolean>;
|
|
62
|
+
/**
|
|
63
|
+
* @group Permissions
|
|
64
|
+
*/
|
|
65
|
+
requestCameraAccess(): Promise<boolean>;
|
|
66
|
+
/**
|
|
67
|
+
* @group Permissions
|
|
68
|
+
*/
|
|
69
|
+
requestMicrophoneAccess(): Promise<boolean>;
|
|
70
|
+
/**
|
|
71
|
+
* @group Permissions
|
|
72
|
+
*/
|
|
73
|
+
requestScreenRecordingAccess(): Promise<void>;
|
|
74
|
+
createRecorder(schema: RecorderSchema): Promise<Recorder>;
|
|
75
|
+
}
|
|
76
|
+
/** @ignore */
|
|
77
|
+
export declare let recordkit: RecordKit;
|
|
78
|
+
/**
|
|
79
|
+
* @group Permissions
|
|
80
|
+
*
|
|
81
|
+
* @remarks
|
|
82
|
+
* Describes the apps permission to access a recording device.
|
|
83
|
+
*
|
|
84
|
+
* - `notDetermined` The user has not yet made a choice.
|
|
85
|
+
* - `restricted` The user cannot change the client's status, possibly due to active restrictions such as parental controls being in place.
|
|
86
|
+
* - `denied` The user explicitly denied access to the hardware supporting a media type for the client.
|
|
87
|
+
* - `authorized` Application is authorized to access the hardware.
|
|
88
|
+
*/
|
|
89
|
+
export type AuthorizationStatus = 'notDetermined' | 'restricted' | 'denied' | 'authorized';
|
|
90
|
+
/**
|
|
91
|
+
* @group Discovery
|
|
92
|
+
*/
|
|
93
|
+
export interface AppleDevice {
|
|
94
|
+
id: string;
|
|
95
|
+
name: string;
|
|
96
|
+
model_id?: string;
|
|
97
|
+
availability: 'available';
|
|
10
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* @group Discovery
|
|
101
|
+
*/
|
|
11
102
|
export interface Camera {
|
|
12
103
|
id: string;
|
|
13
104
|
name: string;
|
|
@@ -15,6 +106,9 @@ export interface Camera {
|
|
|
15
106
|
manufacturer: string;
|
|
16
107
|
availability: 'available' | 'lidClosed' | 'unknownSuspended';
|
|
17
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* @group Discovery
|
|
111
|
+
*/
|
|
18
112
|
export interface Microphone {
|
|
19
113
|
id: string;
|
|
20
114
|
name: string;
|
|
@@ -22,36 +116,23 @@ export interface Microphone {
|
|
|
22
116
|
manufacturer: string;
|
|
23
117
|
availability: 'available' | 'lidClosed' | 'unknownSuspended';
|
|
24
118
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
119
|
+
/**
|
|
120
|
+
* @group Discovery
|
|
121
|
+
*/
|
|
122
|
+
export interface Window {
|
|
123
|
+
id: number;
|
|
124
|
+
title?: string;
|
|
125
|
+
frame: Bounds;
|
|
126
|
+
level: number;
|
|
127
|
+
application_process_id?: number;
|
|
128
|
+
application_name?: string;
|
|
30
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* @group Utilities
|
|
132
|
+
*/
|
|
31
133
|
export interface Bounds {
|
|
32
134
|
x: number;
|
|
33
135
|
y: number;
|
|
34
136
|
width: number;
|
|
35
137
|
height: number;
|
|
36
138
|
}
|
|
37
|
-
export declare class RecordKit {
|
|
38
|
-
private ipcRecordKit;
|
|
39
|
-
initialize(args: {
|
|
40
|
-
rpcBinaryPath: string;
|
|
41
|
-
fallbackToNodeModules: boolean;
|
|
42
|
-
logRpcMessages?: boolean;
|
|
43
|
-
}): Promise<void>;
|
|
44
|
-
getWindows(): Promise<Window[]>;
|
|
45
|
-
getCameras(): Promise<Camera[]>;
|
|
46
|
-
getMicrophones(): Promise<Microphone[]>;
|
|
47
|
-
getAppleDevices(): Promise<AppleDevice[]>;
|
|
48
|
-
getCameraAuthorizationStatus(): Promise<AuthorizationStatus>;
|
|
49
|
-
getMicrophoneAuthorizationStatus(): Promise<AuthorizationStatus>;
|
|
50
|
-
getScreenRecordingAccess(): Promise<boolean>;
|
|
51
|
-
requestCameraAccess(): Promise<boolean>;
|
|
52
|
-
requestMicrophoneAccess(): Promise<boolean>;
|
|
53
|
-
requestScreenRecordingAccess(): Promise<void>;
|
|
54
|
-
createRecorder(schema: RecorderSchema): Promise<Recorder>;
|
|
55
|
-
}
|
|
56
|
-
export declare let recordkit: RecordKit;
|
|
57
|
-
export {};
|
package/out/RecordKit.js
CHANGED
|
@@ -1,45 +1,93 @@
|
|
|
1
1
|
import { IpcRecordKit } from "./IpcRecordKit.js";
|
|
2
2
|
import { Recorder } from "./Recorder.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
+
/**
|
|
5
|
+
* Entry point for the RecordKit SDK, an instance is available as `recordkit` that can be imported from the module. Do not instantiate this class directly.
|
|
6
|
+
*
|
|
7
|
+
* @groupDescription Discovery
|
|
8
|
+
* Discover the windows and devices that are available to record.
|
|
9
|
+
*
|
|
10
|
+
* @groupDescription Permissions
|
|
11
|
+
* Check and request the apps permission to access the recording devices.
|
|
12
|
+
*/
|
|
4
13
|
export class RecordKit {
|
|
5
14
|
ipcRecordKit = new IpcRecordKit();
|
|
15
|
+
/** @ignore */
|
|
16
|
+
constructor() { }
|
|
17
|
+
/**
|
|
18
|
+
* Initialize the RecordKit SDK.
|
|
19
|
+
*
|
|
20
|
+
* ⚠️ Must be called before calling any other RecordKit method.
|
|
21
|
+
*
|
|
22
|
+
* @param args
|
|
23
|
+
*/
|
|
6
24
|
async initialize(args) {
|
|
7
25
|
let rpcBinaryPath = args.rpcBinaryPath;
|
|
8
|
-
if (args.fallbackToNodeModules) {
|
|
26
|
+
if (args.fallbackToNodeModules ?? true) {
|
|
9
27
|
if (!existsSync(rpcBinaryPath)) {
|
|
10
|
-
console.log('Falling back to RPC binary from node_modules, no file at given RPC binary path.');
|
|
11
28
|
rpcBinaryPath = rpcBinaryPath.replace('node_modules/electron/dist/Electron.app/Contents/Resources', 'node_modules/@nonstrict/recordkit/bin');
|
|
29
|
+
console.log(`Falling back to RPC binary from node_modules at ${rpcBinaryPath}`);
|
|
12
30
|
}
|
|
13
31
|
}
|
|
14
32
|
return this.ipcRecordKit.initialize(rpcBinaryPath, args.logRpcMessages);
|
|
15
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* @group Discovery
|
|
36
|
+
*/
|
|
16
37
|
async getWindows() {
|
|
17
38
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getWindows' });
|
|
18
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* @group Discovery
|
|
42
|
+
*/
|
|
19
43
|
async getCameras() {
|
|
20
44
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getCameras' });
|
|
21
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* @group Discovery
|
|
48
|
+
*/
|
|
22
49
|
async getMicrophones() {
|
|
23
50
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getMicrophones' });
|
|
24
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* @group Discovery
|
|
54
|
+
*/
|
|
25
55
|
async getAppleDevices() {
|
|
26
56
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getAppleDevices' });
|
|
27
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* @group Permissions
|
|
60
|
+
*/
|
|
28
61
|
async getCameraAuthorizationStatus() {
|
|
29
62
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getCameraAuthorizationStatus' });
|
|
30
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* @group Permissions
|
|
66
|
+
*/
|
|
31
67
|
async getMicrophoneAuthorizationStatus() {
|
|
32
68
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getMicrophoneAuthorizationStatus' });
|
|
33
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* @group Permissions
|
|
72
|
+
*/
|
|
34
73
|
async getScreenRecordingAccess() {
|
|
35
74
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getScreenRecordingAccess' });
|
|
36
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* @group Permissions
|
|
78
|
+
*/
|
|
37
79
|
async requestCameraAccess() {
|
|
38
80
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestCameraAccess' });
|
|
39
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* @group Permissions
|
|
84
|
+
*/
|
|
40
85
|
async requestMicrophoneAccess() {
|
|
41
86
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestMicrophoneAccess' });
|
|
42
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* @group Permissions
|
|
90
|
+
*/
|
|
43
91
|
async requestScreenRecordingAccess() {
|
|
44
92
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestScreenRecordingAccess' });
|
|
45
93
|
}
|
|
@@ -47,5 +95,6 @@ export class RecordKit {
|
|
|
47
95
|
return Recorder.newInstance(this.ipcRecordKit.nsrpc, schema);
|
|
48
96
|
}
|
|
49
97
|
}
|
|
98
|
+
/** @ignore */
|
|
50
99
|
export let recordkit = new RecordKit();
|
|
51
100
|
//# sourceMappingURL=RecordKit.js.map
|
package/out/RecordKit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordKit.js","sourceRoot":"","sources":["../src/RecordKit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"RecordKit.js","sourceRoot":"","sources":["../src/RecordKit.ts"],"names":[],"mappings":"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"}
|
package/out/Recorder.d.ts
CHANGED
|
@@ -3,17 +3,43 @@
|
|
|
3
3
|
import { NSRPC } from "./NonstrictRPC.js";
|
|
4
4
|
import { EventEmitter } from "stream";
|
|
5
5
|
import { AppleDevice, Camera, Microphone, Window } from "./RecordKit.js";
|
|
6
|
+
/**
|
|
7
|
+
* @group Recording
|
|
8
|
+
*/
|
|
9
|
+
export declare class Recorder extends EventEmitter {
|
|
10
|
+
private readonly rpc;
|
|
11
|
+
private readonly target;
|
|
12
|
+
/** @ignore */
|
|
13
|
+
static newInstance(rpc: NSRPC, schema: RecorderSchema): Promise<Recorder>;
|
|
14
|
+
/** @ignore */
|
|
15
|
+
constructor(rpc: NSRPC, target: string);
|
|
16
|
+
prepare(): Promise<void>;
|
|
17
|
+
start(): Promise<void>;
|
|
18
|
+
stop(): Promise<RecordingResult>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @group Recording
|
|
22
|
+
*/
|
|
6
23
|
export interface RecorderSchema {
|
|
7
24
|
output_directory?: string;
|
|
8
25
|
items: RecorderSchemaItem[];
|
|
9
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* @group Recording
|
|
29
|
+
*/
|
|
10
30
|
export type RecorderSchemaItem = WebcamSchema | WindowBasedCropSchema | iPhonePortraitSchema;
|
|
31
|
+
/**
|
|
32
|
+
* @group Recording Schemas
|
|
33
|
+
*/
|
|
11
34
|
export interface WebcamSchema {
|
|
12
35
|
type: 'webcam';
|
|
13
36
|
filename?: string;
|
|
14
37
|
camera: Camera | string;
|
|
15
38
|
microphone: Microphone | string;
|
|
16
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* @group Recording Schemas
|
|
42
|
+
*/
|
|
17
43
|
export interface WindowBasedCropSchema {
|
|
18
44
|
type: 'windowBasedCrop';
|
|
19
45
|
filename?: string;
|
|
@@ -21,11 +47,17 @@ export interface WindowBasedCropSchema {
|
|
|
21
47
|
shows_cursor?: boolean;
|
|
22
48
|
mouse_events?: boolean;
|
|
23
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* @group Recording Schemas
|
|
52
|
+
*/
|
|
24
53
|
export interface iPhonePortraitSchema {
|
|
25
54
|
type: 'iPhonePortrait';
|
|
26
55
|
filename?: string;
|
|
27
56
|
device: AppleDevice | string;
|
|
28
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* @group Recording
|
|
60
|
+
*/
|
|
29
61
|
export type AbortReason = {
|
|
30
62
|
reason: 'userStopped';
|
|
31
63
|
result: RecordingResult;
|
|
@@ -37,6 +69,9 @@ export type AbortReason = {
|
|
|
37
69
|
reason: 'failed';
|
|
38
70
|
error: RecordKitError;
|
|
39
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* @group Recording
|
|
74
|
+
*/
|
|
40
75
|
export interface RecordingResult {
|
|
41
76
|
url: string;
|
|
42
77
|
info: BundleInfo;
|
|
@@ -46,6 +81,9 @@ export interface RecordKitError {
|
|
|
46
81
|
error_group: string;
|
|
47
82
|
debug_description: string;
|
|
48
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* @group Recording
|
|
86
|
+
*/
|
|
49
87
|
export interface BundleInfo {
|
|
50
88
|
version: 1;
|
|
51
89
|
files: {
|
|
@@ -53,12 +91,3 @@ export interface BundleInfo {
|
|
|
53
91
|
filename: string;
|
|
54
92
|
}[];
|
|
55
93
|
}
|
|
56
|
-
export declare class Recorder extends EventEmitter {
|
|
57
|
-
private readonly rpc;
|
|
58
|
-
private readonly target;
|
|
59
|
-
static newInstance(rpc: NSRPC, schema: RecorderSchema): Promise<Recorder>;
|
|
60
|
-
constructor(rpc: NSRPC, target: string);
|
|
61
|
-
prepare(): Promise<void>;
|
|
62
|
-
start(): Promise<void>;
|
|
63
|
-
stop(): Promise<RecordingResult>;
|
|
64
|
-
}
|
package/out/Recorder.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import { EventEmitter } from "stream";
|
|
3
|
+
/**
|
|
4
|
+
* @group Recording
|
|
5
|
+
*/
|
|
3
6
|
export class Recorder extends EventEmitter {
|
|
4
7
|
rpc;
|
|
5
8
|
target;
|
|
9
|
+
/** @ignore */
|
|
6
10
|
static async newInstance(rpc, schema) {
|
|
7
11
|
const target = 'Recorder_' + randomUUID();
|
|
8
12
|
const object = new Recorder(rpc, target);
|
|
@@ -40,6 +44,7 @@ export class Recorder extends EventEmitter {
|
|
|
40
44
|
});
|
|
41
45
|
return object;
|
|
42
46
|
}
|
|
47
|
+
/** @ignore */
|
|
43
48
|
constructor(rpc, target) {
|
|
44
49
|
super();
|
|
45
50
|
this.rpc = rpc;
|
package/out/Recorder.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Recorder.js","sourceRoot":"","sources":["../src/Recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"Recorder.js","sourceRoot":"","sources":["../src/Recorder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC;;GAEG;AACH,MAAM,OAAO,QAAS,SAAQ,YAAY;IACvB,GAAG,CAAQ;IACX,MAAM,CAAS;IAEhC,cAAc;IACd,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,GAAU,EAAE,MAAsB;QACzD,MAAM,MAAM,GAAG,WAAW,GAAG,UAAU,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAEzC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YAC1B,IAAI,IAAI,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC1B,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;oBACnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAA;gBAC9B,CAAC;gBACD,IAAI,OAAO,IAAI,CAAC,UAAU,IAAI,QAAQ,EAAE,CAAC;oBACvC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,CAAA;gBACtC,CAAC;YACH,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,IAAI,iBAAiB,EAAE,CAAC;gBACnC,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;oBACnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAA;gBAC9B,CAAC;YACH,CAAC;YACD,IAAI,IAAI,CAAC,IAAI,IAAI,gBAAgB,EAAE,CAAC;gBAClC,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;oBACnC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAA;gBAC9B,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,eAAe,GAAG,GAAG,CAAC,eAAe,CAAC;YAC1C,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,GAAG,aAAa,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,MAAqB,CAAC,CAAA,CAAC,CAAC;YAC3F,MAAM,EAAE,kBAAkB;YAC1B,SAAS,EAAE,MAAM;SAClB,CAAC,CAAC;QAEH,MAAM,GAAG,CAAC,UAAU,CAAC;YACnB,MAAM;YACN,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE;YACnC,SAAS,EAAE,MAAM;SAClB,CAAC,CAAC;QAEH,OAAO,MAAM,CAAA;IACf,CAAC;IAED,cAAc;IACd,YAAY,GAAU,EAAE,MAAc;QACpC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,MAAM,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAoB,CAAC;IAC5F,CAAC;CACF"}
|
package/out/index.cjs
CHANGED
|
@@ -210,9 +210,11 @@ class IpcRecordKit {
|
|
|
210
210
|
}
|
|
211
211
|
this.nsrpc.logMessages = logMessages;
|
|
212
212
|
this.childProcess = await new Promise((resolve, reject) => {
|
|
213
|
-
const childProcess = node_child_process.spawn(recordKitRpcPath);
|
|
214
|
-
childProcess.on('
|
|
213
|
+
const childProcess = node_child_process.spawn(recordKitRpcPath, { stdio: ['pipe', 'pipe', process.stderr] });
|
|
214
|
+
childProcess.on('close', (code, signal) => { console.log(`RecordKit RPC closed with code ${code} and signal ${signal}`); });
|
|
215
215
|
childProcess.on('error', (error) => { reject(error); });
|
|
216
|
+
childProcess.on('exit', (code, signal) => { console.log(`RecordKit RPC exited with code ${code} and signal ${signal}`); });
|
|
217
|
+
childProcess.on('spawn', () => { resolve(childProcess); });
|
|
216
218
|
});
|
|
217
219
|
const { stdout } = this.childProcess;
|
|
218
220
|
if (!stdout) {
|
|
@@ -231,9 +233,13 @@ class IpcRecordKit {
|
|
|
231
233
|
}
|
|
232
234
|
}
|
|
233
235
|
|
|
236
|
+
/**
|
|
237
|
+
* @group Recording
|
|
238
|
+
*/
|
|
234
239
|
class Recorder extends stream.EventEmitter {
|
|
235
240
|
rpc;
|
|
236
241
|
target;
|
|
242
|
+
/** @ignore */
|
|
237
243
|
static async newInstance(rpc, schema) {
|
|
238
244
|
const target = 'Recorder_' + crypto.randomUUID();
|
|
239
245
|
const object = new Recorder(rpc, target);
|
|
@@ -271,6 +277,7 @@ class Recorder extends stream.EventEmitter {
|
|
|
271
277
|
});
|
|
272
278
|
return object;
|
|
273
279
|
}
|
|
280
|
+
/** @ignore */
|
|
274
281
|
constructor(rpc, target) {
|
|
275
282
|
super();
|
|
276
283
|
this.rpc = rpc;
|
|
@@ -287,45 +294,93 @@ class Recorder extends stream.EventEmitter {
|
|
|
287
294
|
}
|
|
288
295
|
}
|
|
289
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Entry point for the RecordKit SDK, an instance is available as `recordkit` that can be imported from the module. Do not instantiate this class directly.
|
|
299
|
+
*
|
|
300
|
+
* @groupDescription Discovery
|
|
301
|
+
* Discover the windows and devices that are available to record.
|
|
302
|
+
*
|
|
303
|
+
* @groupDescription Permissions
|
|
304
|
+
* Check and request the apps permission to access the recording devices.
|
|
305
|
+
*/
|
|
290
306
|
class RecordKit {
|
|
291
307
|
ipcRecordKit = new IpcRecordKit();
|
|
308
|
+
/** @ignore */
|
|
309
|
+
constructor() { }
|
|
310
|
+
/**
|
|
311
|
+
* Initialize the RecordKit SDK.
|
|
312
|
+
*
|
|
313
|
+
* ⚠️ Must be called before calling any other RecordKit method.
|
|
314
|
+
*
|
|
315
|
+
* @param args
|
|
316
|
+
*/
|
|
292
317
|
async initialize(args) {
|
|
293
318
|
let rpcBinaryPath = args.rpcBinaryPath;
|
|
294
|
-
if (args.fallbackToNodeModules) {
|
|
319
|
+
if (args.fallbackToNodeModules ?? true) {
|
|
295
320
|
if (!node_fs.existsSync(rpcBinaryPath)) {
|
|
296
|
-
console.log('Falling back to RPC binary from node_modules, no file at given RPC binary path.');
|
|
297
321
|
rpcBinaryPath = rpcBinaryPath.replace('node_modules/electron/dist/Electron.app/Contents/Resources', 'node_modules/@nonstrict/recordkit/bin');
|
|
322
|
+
console.log(`Falling back to RPC binary from node_modules at ${rpcBinaryPath}`);
|
|
298
323
|
}
|
|
299
324
|
}
|
|
300
325
|
return this.ipcRecordKit.initialize(rpcBinaryPath, args.logRpcMessages);
|
|
301
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* @group Discovery
|
|
329
|
+
*/
|
|
302
330
|
async getWindows() {
|
|
303
331
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getWindows' });
|
|
304
332
|
}
|
|
333
|
+
/**
|
|
334
|
+
* @group Discovery
|
|
335
|
+
*/
|
|
305
336
|
async getCameras() {
|
|
306
337
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getCameras' });
|
|
307
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* @group Discovery
|
|
341
|
+
*/
|
|
308
342
|
async getMicrophones() {
|
|
309
343
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getMicrophones' });
|
|
310
344
|
}
|
|
345
|
+
/**
|
|
346
|
+
* @group Discovery
|
|
347
|
+
*/
|
|
311
348
|
async getAppleDevices() {
|
|
312
349
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getAppleDevices' });
|
|
313
350
|
}
|
|
351
|
+
/**
|
|
352
|
+
* @group Permissions
|
|
353
|
+
*/
|
|
314
354
|
async getCameraAuthorizationStatus() {
|
|
315
355
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getCameraAuthorizationStatus' });
|
|
316
356
|
}
|
|
357
|
+
/**
|
|
358
|
+
* @group Permissions
|
|
359
|
+
*/
|
|
317
360
|
async getMicrophoneAuthorizationStatus() {
|
|
318
361
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getMicrophoneAuthorizationStatus' });
|
|
319
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* @group Permissions
|
|
365
|
+
*/
|
|
320
366
|
async getScreenRecordingAccess() {
|
|
321
367
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getScreenRecordingAccess' });
|
|
322
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* @group Permissions
|
|
371
|
+
*/
|
|
323
372
|
async requestCameraAccess() {
|
|
324
373
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestCameraAccess' });
|
|
325
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* @group Permissions
|
|
377
|
+
*/
|
|
326
378
|
async requestMicrophoneAccess() {
|
|
327
379
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestMicrophoneAccess' });
|
|
328
380
|
}
|
|
381
|
+
/**
|
|
382
|
+
* @group Permissions
|
|
383
|
+
*/
|
|
329
384
|
async requestScreenRecordingAccess() {
|
|
330
385
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestScreenRecordingAccess' });
|
|
331
386
|
}
|
|
@@ -333,6 +388,7 @@ class RecordKit {
|
|
|
333
388
|
return Recorder.newInstance(this.ipcRecordKit.nsrpc, schema);
|
|
334
389
|
}
|
|
335
390
|
}
|
|
391
|
+
/** @ignore */
|
|
336
392
|
let recordkit = new RecordKit();
|
|
337
393
|
|
|
338
394
|
exports.recordkit = recordkit;
|
package/out/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["finalizationRegistry.js","NonstrictRPC.js","IpcRecordKit.js","Recorder.js","RecordKit.js"],"sourcesContent":["export const finalizationRegistry = new FinalizationRegistry(async (destructor) => { await destructor(); });\n//# sourceMappingURL=finalizationRegistry.js.map","import { randomUUID } from \"crypto\";\nimport { finalizationRegistry } from \"./finalizationRegistry.js\";\nexport class NSRPC {\n logMessages = false;\n send;\n responseHandlers = new Map();\n closureTargets = new Map();\n constructor(send) {\n this.send = send;\n }\n receive(data) {\n // TODO: For now we just assume the message is a valid NSRPC message, but we should:\n // - Check if the nsrpc property is set to a number in the range of 1..<2\n // - Validate the message against the defined interfaces above\n let message;\n try {\n if (this.logMessages) {\n console.log(\"< \", data.trimEnd());\n }\n message = JSON.parse(data);\n }\n catch (error) {\n if (this.logMessages) {\n console.log(\"!! Above message is invalid JSON, will be ignored.\");\n }\n return;\n }\n if (\"status\" in message) {\n // This is a response, dispatch it so it can be handled\n const responseHandler = this.responseHandlers.get(message.id);\n this.responseHandlers.delete(message.id);\n if (responseHandler === undefined) {\n // TODO: Got a response for a request we don't know about, log this\n return;\n }\n if (\"error\" in message) {\n responseHandler.reject(message.error);\n }\n else {\n responseHandler.resolve(message.result);\n }\n }\n else {\n // This is a request\n const responseBody = this.handleRequest(message);\n if (responseBody !== undefined) {\n this.sendResponse(message.id, responseBody);\n }\n }\n }\n /* Sending helpers */\n sendMessage(message) {\n const stringMessage = JSON.stringify(message);\n if (this.logMessages) {\n console.log(\"> \", stringMessage);\n }\n this.send(stringMessage);\n }\n sendResponse(id, response) {\n if (id === undefined) {\n return;\n }\n this.sendMessage({ ...response, nsrpc: 1, id });\n }\n async sendRequest(request) {\n const id = \"req_\" + randomUUID();\n const response = new Promise((resolve, reject) => {\n this.responseHandlers.set(id, { resolve, reject });\n });\n this.sendMessage({ ...request, nsrpc: 1, id });\n return response;\n }\n /* Request handling */\n handleRequest(request) {\n switch (request.procedure) {\n case \"init\":\n return {\n status: 501,\n error: {\n debugDescription: \"Init procedure not implemented.\",\n userMessage: \"Failed to communicate with external process. (Procedure not implemented)\",\n },\n };\n case \"perform\":\n if (\"action\" in request) {\n return {\n status: 501,\n error: {\n debugDescription: \"Perform procedure for (static) methods not implemented.\",\n userMessage: \"Failed to communicate with external process. (Procedure not implemented)\",\n },\n };\n }\n else {\n return this.handleClosureRequest(request);\n }\n case \"release\":\n return {\n status: 501,\n error: {\n debugDescription: \"Release procedure not implemented.\",\n userMessage: \"Failed to communicate with external process. (Procedure not implemented)\",\n },\n };\n }\n }\n handleClosureRequest(request) {\n const handler = this.closureTargets.get(request.target);\n if (handler === undefined) {\n return {\n status: 404,\n error: {\n debugDescription: `Perform target '${request.target}' not found.`,\n userMessage: \"Failed to communicate with external process. (Target not found)\",\n },\n };\n }\n try {\n const rawresult = handler(request.params ?? {});\n const result = rawresult === undefined ? undefined : rawresult;\n return {\n status: 200,\n result,\n };\n }\n catch (error) {\n return {\n status: 202,\n // TODO: Would be good to have an error type that we can throw that fills these fields more specifically. (But for now it doesn't matter since this is just communicated back the the CLI and not to the user.)\n error: {\n debugDescription: `${error}`,\n userMessage: \"Handler failed to perform request.\",\n underlyingError: error,\n },\n };\n }\n }\n /* Perform remote procedures */\n async initialize(args) {\n const target = args.target;\n finalizationRegistry.register(args.lifecycle, async () => {\n await this.release(target);\n });\n await this.sendRequest({\n target: args.target,\n type: args.type,\n params: args.params,\n procedure: \"init\",\n });\n }\n async perform(body) {\n return await this.sendRequest({\n ...body,\n procedure: \"perform\",\n });\n }\n async release(target) {\n await this.sendRequest({\n procedure: \"release\",\n target,\n });\n }\n /* Register locally available targets/actions */\n registerClosure(options) {\n const target = `target_${options.prefix}_${randomUUID()}`;\n this.closureTargets.set(target, options.handler);\n finalizationRegistry.register(options.lifecycle, () => {\n this.closureTargets.delete(target);\n });\n return target;\n }\n}\n//# sourceMappingURL=NonstrictRPC.js.map","import { spawn } from 'node:child_process';\nimport * as readline from 'readline';\nimport { NSRPC } from \"./NonstrictRPC.js\";\nexport class IpcRecordKit {\n childProcess;\n nsrpc;\n constructor() {\n this.nsrpc = new NSRPC((message) => this.write(message));\n }\n async initialize(recordKitRpcPath, logMessages = false) {\n if (this.childProcess !== undefined) {\n throw new Error('RecordKit RPC: Already initialized.');\n }\n this.nsrpc.logMessages = logMessages;\n this.childProcess = await new Promise((resolve, reject) => {\n const childProcess = spawn(recordKitRpcPath);\n childProcess.on('spawn', () => { resolve(childProcess); });\n childProcess.on('error', (error) => { reject(error); });\n });\n const { stdout } = this.childProcess;\n if (!stdout) {\n throw new Error('RecordKit RPC: No stdout stream on child process.');\n }\n readline.createInterface({ input: stdout }).on('line', (line) => {\n this.nsrpc.receive(line);\n });\n }\n write(message) {\n const stdin = this.childProcess?.stdin;\n if (!stdin) {\n throw new Error('RecordKit RPC: Missing stdin stream.');\n }\n stdin.write(message + \"\\n\");\n }\n}\n//# sourceMappingURL=IpcRecordKit.js.map","import { randomUUID } from \"crypto\";\nimport { EventEmitter } from \"stream\";\nexport class Recorder extends EventEmitter {\n rpc;\n target;\n static async newInstance(rpc, schema) {\n const target = 'Recorder_' + randomUUID();\n const object = new Recorder(rpc, target);\n schema.items.forEach(item => {\n if (item.type == 'webcam') {\n if (typeof item.camera != 'string') {\n item.camera = item.camera.id;\n }\n if (typeof item.microphone != 'string') {\n item.microphone = item.microphone.id;\n }\n }\n if (item.type == 'windowBasedCrop') {\n if (typeof item.window != 'number') {\n item.window = item.window.id;\n }\n }\n if (item.type == 'iPhonePortrait') {\n if (typeof item.device != 'string') {\n item.device = item.device.id;\n }\n }\n });\n const weakRefObject = new WeakRef(object);\n const onAbortInstance = rpc.registerClosure({\n handler: (params) => { weakRefObject.deref()?.emit('abort', params.reason); },\n prefix: 'Recorder.onAbort',\n lifecycle: object\n });\n await rpc.initialize({\n target,\n type: 'Recorder',\n params: { schema, onAbortInstance },\n lifecycle: object\n });\n return object;\n }\n constructor(rpc, target) {\n super();\n this.rpc = rpc;\n this.target = target;\n }\n async prepare() {\n await this.rpc.perform({ target: this.target, action: 'prepare' });\n }\n async start() {\n await this.rpc.perform({ target: this.target, action: 'start' });\n }\n async stop() {\n return await this.rpc.perform({ target: this.target, action: 'stop' });\n }\n}\n//# sourceMappingURL=Recorder.js.map","import { IpcRecordKit } from \"./IpcRecordKit.js\";\nimport { Recorder } from \"./Recorder.js\";\nimport { existsSync } from \"node:fs\";\nexport class RecordKit {\n ipcRecordKit = new IpcRecordKit();\n async initialize(args) {\n let rpcBinaryPath = args.rpcBinaryPath;\n if (args.fallbackToNodeModules) {\n if (!existsSync(rpcBinaryPath)) {\n console.log('Falling back to RPC binary from node_modules, no file at given RPC binary path.');\n rpcBinaryPath = rpcBinaryPath.replace('node_modules/electron/dist/Electron.app/Contents/Resources', 'node_modules/@nonstrict/recordkit/bin');\n }\n }\n return this.ipcRecordKit.initialize(rpcBinaryPath, args.logRpcMessages);\n }\n async getWindows() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getWindows' });\n }\n async getCameras() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getCameras' });\n }\n async getMicrophones() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getMicrophones' });\n }\n async getAppleDevices() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getAppleDevices' });\n }\n async getCameraAuthorizationStatus() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getCameraAuthorizationStatus' });\n }\n async getMicrophoneAuthorizationStatus() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getMicrophoneAuthorizationStatus' });\n }\n async getScreenRecordingAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getScreenRecordingAccess' });\n }\n async requestCameraAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestCameraAccess' });\n }\n async requestMicrophoneAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestMicrophoneAccess' });\n }\n async requestScreenRecordingAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestScreenRecordingAccess' });\n }\n async createRecorder(schema) {\n return Recorder.newInstance(this.ipcRecordKit.nsrpc, schema);\n }\n}\nexport let recordkit = new RecordKit();\n//# sourceMappingURL=RecordKit.js.map"],"names":["randomUUID","spawn","readline","EventEmitter","existsSync"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["finalizationRegistry.js","NonstrictRPC.js","IpcRecordKit.js","Recorder.js","RecordKit.js"],"sourcesContent":["export const finalizationRegistry = new FinalizationRegistry(async (destructor) => { await destructor(); });\n//# sourceMappingURL=finalizationRegistry.js.map","import { randomUUID } from \"crypto\";\nimport { finalizationRegistry } from \"./finalizationRegistry.js\";\nexport class NSRPC {\n logMessages = false;\n send;\n responseHandlers = new Map();\n closureTargets = new Map();\n constructor(send) {\n this.send = send;\n }\n receive(data) {\n // TODO: For now we just assume the message is a valid NSRPC message, but we should:\n // - Check if the nsrpc property is set to a number in the range of 1..<2\n // - Validate the message against the defined interfaces above\n let message;\n try {\n if (this.logMessages) {\n console.log(\"< \", data.trimEnd());\n }\n message = JSON.parse(data);\n }\n catch (error) {\n if (this.logMessages) {\n console.log(\"!! Above message is invalid JSON, will be ignored.\");\n }\n return;\n }\n if (\"status\" in message) {\n // This is a response, dispatch it so it can be handled\n const responseHandler = this.responseHandlers.get(message.id);\n this.responseHandlers.delete(message.id);\n if (responseHandler === undefined) {\n // TODO: Got a response for a request we don't know about, log this\n return;\n }\n if (\"error\" in message) {\n responseHandler.reject(message.error);\n }\n else {\n responseHandler.resolve(message.result);\n }\n }\n else {\n // This is a request\n const responseBody = this.handleRequest(message);\n if (responseBody !== undefined) {\n this.sendResponse(message.id, responseBody);\n }\n }\n }\n /* Sending helpers */\n sendMessage(message) {\n const stringMessage = JSON.stringify(message);\n if (this.logMessages) {\n console.log(\"> \", stringMessage);\n }\n this.send(stringMessage);\n }\n sendResponse(id, response) {\n if (id === undefined) {\n return;\n }\n this.sendMessage({ ...response, nsrpc: 1, id });\n }\n async sendRequest(request) {\n const id = \"req_\" + randomUUID();\n const response = new Promise((resolve, reject) => {\n this.responseHandlers.set(id, { resolve, reject });\n });\n this.sendMessage({ ...request, nsrpc: 1, id });\n return response;\n }\n /* Request handling */\n handleRequest(request) {\n switch (request.procedure) {\n case \"init\":\n return {\n status: 501,\n error: {\n debugDescription: \"Init procedure not implemented.\",\n userMessage: \"Failed to communicate with external process. (Procedure not implemented)\",\n },\n };\n case \"perform\":\n if (\"action\" in request) {\n return {\n status: 501,\n error: {\n debugDescription: \"Perform procedure for (static) methods not implemented.\",\n userMessage: \"Failed to communicate with external process. (Procedure not implemented)\",\n },\n };\n }\n else {\n return this.handleClosureRequest(request);\n }\n case \"release\":\n return {\n status: 501,\n error: {\n debugDescription: \"Release procedure not implemented.\",\n userMessage: \"Failed to communicate with external process. (Procedure not implemented)\",\n },\n };\n }\n }\n handleClosureRequest(request) {\n const handler = this.closureTargets.get(request.target);\n if (handler === undefined) {\n return {\n status: 404,\n error: {\n debugDescription: `Perform target '${request.target}' not found.`,\n userMessage: \"Failed to communicate with external process. (Target not found)\",\n },\n };\n }\n try {\n const rawresult = handler(request.params ?? {});\n const result = rawresult === undefined ? undefined : rawresult;\n return {\n status: 200,\n result,\n };\n }\n catch (error) {\n return {\n status: 202,\n // TODO: Would be good to have an error type that we can throw that fills these fields more specifically. (But for now it doesn't matter since this is just communicated back the the CLI and not to the user.)\n error: {\n debugDescription: `${error}`,\n userMessage: \"Handler failed to perform request.\",\n underlyingError: error,\n },\n };\n }\n }\n /* Perform remote procedures */\n async initialize(args) {\n const target = args.target;\n finalizationRegistry.register(args.lifecycle, async () => {\n await this.release(target);\n });\n await this.sendRequest({\n target: args.target,\n type: args.type,\n params: args.params,\n procedure: \"init\",\n });\n }\n async perform(body) {\n return await this.sendRequest({\n ...body,\n procedure: \"perform\",\n });\n }\n async release(target) {\n await this.sendRequest({\n procedure: \"release\",\n target,\n });\n }\n /* Register locally available targets/actions */\n registerClosure(options) {\n const target = `target_${options.prefix}_${randomUUID()}`;\n this.closureTargets.set(target, options.handler);\n finalizationRegistry.register(options.lifecycle, () => {\n this.closureTargets.delete(target);\n });\n return target;\n }\n}\n//# sourceMappingURL=NonstrictRPC.js.map","import { spawn } from 'node:child_process';\nimport * as readline from 'readline';\nimport { NSRPC } from \"./NonstrictRPC.js\";\nexport class IpcRecordKit {\n childProcess;\n nsrpc;\n constructor() {\n this.nsrpc = new NSRPC((message) => this.write(message));\n }\n async initialize(recordKitRpcPath, logMessages = false) {\n if (this.childProcess !== undefined) {\n throw new Error('RecordKit RPC: Already initialized.');\n }\n this.nsrpc.logMessages = logMessages;\n this.childProcess = await new Promise((resolve, reject) => {\n const childProcess = spawn(recordKitRpcPath, { stdio: ['pipe', 'pipe', process.stderr] });\n childProcess.on('close', (code, signal) => { console.log(`RecordKit RPC closed with code ${code} and signal ${signal}`); });\n childProcess.on('error', (error) => { reject(error); });\n childProcess.on('exit', (code, signal) => { console.log(`RecordKit RPC exited with code ${code} and signal ${signal}`); });\n childProcess.on('spawn', () => { resolve(childProcess); });\n });\n const { stdout } = this.childProcess;\n if (!stdout) {\n throw new Error('RecordKit RPC: No stdout stream on child process.');\n }\n readline.createInterface({ input: stdout }).on('line', (line) => {\n this.nsrpc.receive(line);\n });\n }\n write(message) {\n const stdin = this.childProcess?.stdin;\n if (!stdin) {\n throw new Error('RecordKit RPC: Missing stdin stream.');\n }\n stdin.write(message + \"\\n\");\n }\n}\n//# sourceMappingURL=IpcRecordKit.js.map","import { randomUUID } from \"crypto\";\nimport { EventEmitter } from \"stream\";\n/**\n * @group Recording\n */\nexport class Recorder extends EventEmitter {\n rpc;\n target;\n /** @ignore */\n static async newInstance(rpc, schema) {\n const target = 'Recorder_' + randomUUID();\n const object = new Recorder(rpc, target);\n schema.items.forEach(item => {\n if (item.type == 'webcam') {\n if (typeof item.camera != 'string') {\n item.camera = item.camera.id;\n }\n if (typeof item.microphone != 'string') {\n item.microphone = item.microphone.id;\n }\n }\n if (item.type == 'windowBasedCrop') {\n if (typeof item.window != 'number') {\n item.window = item.window.id;\n }\n }\n if (item.type == 'iPhonePortrait') {\n if (typeof item.device != 'string') {\n item.device = item.device.id;\n }\n }\n });\n const weakRefObject = new WeakRef(object);\n const onAbortInstance = rpc.registerClosure({\n handler: (params) => { weakRefObject.deref()?.emit('abort', params.reason); },\n prefix: 'Recorder.onAbort',\n lifecycle: object\n });\n await rpc.initialize({\n target,\n type: 'Recorder',\n params: { schema, onAbortInstance },\n lifecycle: object\n });\n return object;\n }\n /** @ignore */\n constructor(rpc, target) {\n super();\n this.rpc = rpc;\n this.target = target;\n }\n async prepare() {\n await this.rpc.perform({ target: this.target, action: 'prepare' });\n }\n async start() {\n await this.rpc.perform({ target: this.target, action: 'start' });\n }\n async stop() {\n return await this.rpc.perform({ target: this.target, action: 'stop' });\n }\n}\n//# sourceMappingURL=Recorder.js.map","import { IpcRecordKit } from \"./IpcRecordKit.js\";\nimport { Recorder } from \"./Recorder.js\";\nimport { existsSync } from \"node:fs\";\n/**\n * Entry point for the RecordKit SDK, an instance is available as `recordkit` that can be imported from the module. Do not instantiate this class directly.\n *\n * @groupDescription Discovery\n * Discover the windows and devices that are available to record.\n *\n * @groupDescription Permissions\n * Check and request the apps permission to access the recording devices.\n */\nexport class RecordKit {\n ipcRecordKit = new IpcRecordKit();\n /** @ignore */\n constructor() { }\n /**\n * Initialize the RecordKit SDK.\n *\n * ⚠️ Must be called before calling any other RecordKit method.\n *\n * @param args\n */\n async initialize(args) {\n let rpcBinaryPath = args.rpcBinaryPath;\n if (args.fallbackToNodeModules ?? true) {\n if (!existsSync(rpcBinaryPath)) {\n rpcBinaryPath = rpcBinaryPath.replace('node_modules/electron/dist/Electron.app/Contents/Resources', 'node_modules/@nonstrict/recordkit/bin');\n console.log(`Falling back to RPC binary from node_modules at ${rpcBinaryPath}`);\n }\n }\n return this.ipcRecordKit.initialize(rpcBinaryPath, args.logRpcMessages);\n }\n /**\n * @group Discovery\n */\n async getWindows() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getWindows' });\n }\n /**\n * @group Discovery\n */\n async getCameras() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getCameras' });\n }\n /**\n * @group Discovery\n */\n async getMicrophones() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getMicrophones' });\n }\n /**\n * @group Discovery\n */\n async getAppleDevices() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getAppleDevices' });\n }\n /**\n * @group Permissions\n */\n async getCameraAuthorizationStatus() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getCameraAuthorizationStatus' });\n }\n /**\n * @group Permissions\n */\n async getMicrophoneAuthorizationStatus() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getMicrophoneAuthorizationStatus' });\n }\n /**\n * @group Permissions\n */\n async getScreenRecordingAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getScreenRecordingAccess' });\n }\n /**\n * @group Permissions\n */\n async requestCameraAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestCameraAccess' });\n }\n /**\n * @group Permissions\n */\n async requestMicrophoneAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestMicrophoneAccess' });\n }\n /**\n * @group Permissions\n */\n async requestScreenRecordingAccess() {\n return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestScreenRecordingAccess' });\n }\n async createRecorder(schema) {\n return Recorder.newInstance(this.ipcRecordKit.nsrpc, schema);\n }\n}\n/** @ignore */\nexport let recordkit = new RecordKit();\n//# sourceMappingURL=RecordKit.js.map"],"names":["randomUUID","spawn","readline","EventEmitter","existsSync"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nonstrict/recordkit",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "Powerful screen recording for your Electron app on macOS.",
|
|
5
|
+
"homepage": "https://nonstrict.eu/recordkit",
|
|
6
|
+
"repository": "nonstrict-hq/RecordKit.Electron",
|
|
5
7
|
"type": "module",
|
|
6
8
|
"main": "out/index.js",
|
|
7
9
|
"types": "out/index.d.ts",
|
|
@@ -14,8 +16,7 @@
|
|
|
14
16
|
},
|
|
15
17
|
"scripts": {
|
|
16
18
|
"test": "jest",
|
|
17
|
-
"build": "rm -rf out && tsc && rollup -c"
|
|
18
|
-
"prepublish": "npm run build"
|
|
19
|
+
"build": "rm -rf out && tsc && rollup -c"
|
|
19
20
|
},
|
|
20
21
|
"keywords": [
|
|
21
22
|
"recording",
|
|
@@ -31,7 +32,7 @@
|
|
|
31
32
|
"author": {
|
|
32
33
|
"name": "Nonstrict B.V.",
|
|
33
34
|
"email": "team+recordkit@nonstrict.com",
|
|
34
|
-
"url": "https://nonstrict.eu/
|
|
35
|
+
"url": "https://nonstrict.eu/"
|
|
35
36
|
},
|
|
36
37
|
"license": "SEE LICENSE IN License.md",
|
|
37
38
|
"devDependencies": {
|
package/src/IpcRecordKit.ts
CHANGED
|
@@ -15,9 +15,11 @@ export class IpcRecordKit {
|
|
|
15
15
|
|
|
16
16
|
this.nsrpc.logMessages = logMessages;
|
|
17
17
|
this.childProcess = await new Promise<ChildProcess>((resolve, reject) => {
|
|
18
|
-
const childProcess = spawn(recordKitRpcPath)
|
|
19
|
-
childProcess.on('
|
|
18
|
+
const childProcess = spawn(recordKitRpcPath, { stdio: ['pipe', 'pipe', process.stderr] })
|
|
19
|
+
childProcess.on('close', (code, signal) => { console.log(`RecordKit RPC closed with code ${code} and signal ${signal}`) })
|
|
20
20
|
childProcess.on('error', (error) => { reject(error) })
|
|
21
|
+
childProcess.on('exit', (code, signal) => { console.log(`RecordKit RPC exited with code ${code} and signal ${signal}`) })
|
|
22
|
+
childProcess.on('spawn', () => { resolve(childProcess) })
|
|
21
23
|
})
|
|
22
24
|
|
|
23
25
|
const { stdout } = this.childProcess
|
package/src/RecordKit.ts
CHANGED
|
@@ -1,103 +1,118 @@
|
|
|
1
1
|
import { IpcRecordKit } from "./IpcRecordKit.js";
|
|
2
|
-
import { Recorder, RecorderSchema
|
|
2
|
+
import { Recorder, RecorderSchema } from "./Recorder.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
frame: Bounds
|
|
15
|
-
level: number // Int
|
|
16
|
-
application_process_id?: number // Int32
|
|
17
|
-
application_name?: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface Camera {
|
|
21
|
-
id: string;
|
|
22
|
-
name: string;
|
|
23
|
-
model_id: string;
|
|
24
|
-
manufacturer: string;
|
|
25
|
-
availability: 'available' | 'lidClosed' | 'unknownSuspended'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface Microphone {
|
|
29
|
-
id: string;
|
|
30
|
-
name: string;
|
|
31
|
-
model_id: string;
|
|
32
|
-
manufacturer: string;
|
|
33
|
-
availability: 'available' | 'lidClosed' | 'unknownSuspended'
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface AppleDevice {
|
|
37
|
-
id: string;
|
|
38
|
-
name: string;
|
|
39
|
-
model_id?: string;
|
|
40
|
-
availability: 'available'
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface Bounds {
|
|
44
|
-
x: number;
|
|
45
|
-
y: number;
|
|
46
|
-
width: number;
|
|
47
|
-
height: number;
|
|
48
|
-
}
|
|
49
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Entry point for the RecordKit SDK, an instance is available as `recordkit` that can be imported from the module. Do not instantiate this class directly.
|
|
7
|
+
*
|
|
8
|
+
* @groupDescription Discovery
|
|
9
|
+
* Discover the windows and devices that are available to record.
|
|
10
|
+
*
|
|
11
|
+
* @groupDescription Permissions
|
|
12
|
+
* Check and request the apps permission to access the recording devices.
|
|
13
|
+
*/
|
|
50
14
|
export class RecordKit {
|
|
51
15
|
private ipcRecordKit = new IpcRecordKit()
|
|
52
16
|
|
|
53
|
-
|
|
17
|
+
/** @ignore */
|
|
18
|
+
constructor() { }
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initialize the RecordKit SDK.
|
|
22
|
+
*
|
|
23
|
+
* ⚠️ Must be called before calling any other RecordKit method.
|
|
24
|
+
*
|
|
25
|
+
* @param args
|
|
26
|
+
*/
|
|
27
|
+
async initialize(args: {
|
|
28
|
+
/**
|
|
29
|
+
* Path to the `recordkit-rpc` binary, most of the time this should be set to `path.join(process.resourcesPath, 'recordkit-rpc')`.
|
|
30
|
+
*/
|
|
31
|
+
rpcBinaryPath: string,
|
|
32
|
+
/**
|
|
33
|
+
* Whether to fallback to the RPC binary from `node_modules` if the given path does not exist. When enabled an extra check to see if the given path exists is performed. Most of the time this should be set to `!app.isPackaged`.
|
|
34
|
+
*/
|
|
35
|
+
fallbackToNodeModules?: boolean,
|
|
36
|
+
/** @ignore */
|
|
37
|
+
logRpcMessages?: boolean
|
|
38
|
+
}): Promise<void> {
|
|
54
39
|
let rpcBinaryPath = args.rpcBinaryPath
|
|
55
|
-
if (args.fallbackToNodeModules) {
|
|
40
|
+
if (args.fallbackToNodeModules ?? true) {
|
|
56
41
|
if (!existsSync(rpcBinaryPath)) {
|
|
57
|
-
console.log('Falling back to RPC binary from node_modules, no file at given RPC binary path.')
|
|
58
42
|
rpcBinaryPath = rpcBinaryPath.replace('node_modules/electron/dist/Electron.app/Contents/Resources', 'node_modules/@nonstrict/recordkit/bin')
|
|
43
|
+
console.log(`Falling back to RPC binary from node_modules at ${rpcBinaryPath}`)
|
|
59
44
|
}
|
|
60
45
|
}
|
|
61
46
|
|
|
62
47
|
return this.ipcRecordKit.initialize(rpcBinaryPath, args.logRpcMessages)
|
|
63
48
|
}
|
|
64
49
|
|
|
50
|
+
/**
|
|
51
|
+
* @group Discovery
|
|
52
|
+
*/
|
|
65
53
|
async getWindows(): Promise<Window[]> {
|
|
66
54
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getWindows' }) as Window[]
|
|
67
55
|
}
|
|
68
56
|
|
|
57
|
+
/**
|
|
58
|
+
* @group Discovery
|
|
59
|
+
*/
|
|
69
60
|
async getCameras(): Promise<Camera[]> {
|
|
70
61
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getCameras' }) as Camera[]
|
|
71
62
|
}
|
|
72
63
|
|
|
64
|
+
/**
|
|
65
|
+
* @group Discovery
|
|
66
|
+
*/
|
|
73
67
|
async getMicrophones(): Promise<Microphone[]> {
|
|
74
68
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getMicrophones' }) as Microphone[]
|
|
75
69
|
}
|
|
76
70
|
|
|
71
|
+
/**
|
|
72
|
+
* @group Discovery
|
|
73
|
+
*/
|
|
77
74
|
async getAppleDevices(): Promise<AppleDevice[]> {
|
|
78
75
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'Recorder', action: 'getAppleDevices' }) as AppleDevice[]
|
|
79
76
|
}
|
|
80
77
|
|
|
78
|
+
/**
|
|
79
|
+
* @group Permissions
|
|
80
|
+
*/
|
|
81
81
|
async getCameraAuthorizationStatus(): Promise<AuthorizationStatus> {
|
|
82
82
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getCameraAuthorizationStatus' }) as AuthorizationStatus
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @group Permissions
|
|
87
|
+
*/
|
|
85
88
|
async getMicrophoneAuthorizationStatus(): Promise<AuthorizationStatus> {
|
|
86
89
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getMicrophoneAuthorizationStatus' }) as AuthorizationStatus
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
/**
|
|
93
|
+
* @group Permissions
|
|
94
|
+
*/
|
|
89
95
|
async getScreenRecordingAccess(): Promise<boolean> {
|
|
90
96
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'getScreenRecordingAccess' }) as boolean
|
|
91
97
|
}
|
|
92
98
|
|
|
99
|
+
/**
|
|
100
|
+
* @group Permissions
|
|
101
|
+
*/
|
|
93
102
|
async requestCameraAccess(): Promise<boolean> {
|
|
94
103
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestCameraAccess' }) as boolean
|
|
95
104
|
}
|
|
96
105
|
|
|
106
|
+
/**
|
|
107
|
+
* @group Permissions
|
|
108
|
+
*/
|
|
97
109
|
async requestMicrophoneAccess(): Promise<boolean> {
|
|
98
110
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestMicrophoneAccess' }) as boolean
|
|
99
111
|
}
|
|
100
112
|
|
|
113
|
+
/**
|
|
114
|
+
* @group Permissions
|
|
115
|
+
*/
|
|
101
116
|
async requestScreenRecordingAccess(): Promise<void> {
|
|
102
117
|
return await this.ipcRecordKit.nsrpc.perform({ type: 'AuthorizationStatus', action: 'requestScreenRecordingAccess' }) as void
|
|
103
118
|
}
|
|
@@ -107,4 +122,76 @@ export class RecordKit {
|
|
|
107
122
|
}
|
|
108
123
|
}
|
|
109
124
|
|
|
110
|
-
|
|
125
|
+
/** @ignore */
|
|
126
|
+
export let recordkit = new RecordKit();
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @group Permissions
|
|
130
|
+
*
|
|
131
|
+
* @remarks
|
|
132
|
+
* Describes the apps permission to access a recording device.
|
|
133
|
+
*
|
|
134
|
+
* - `notDetermined` The user has not yet made a choice.
|
|
135
|
+
* - `restricted` The user cannot change the client's status, possibly due to active restrictions such as parental controls being in place.
|
|
136
|
+
* - `denied` The user explicitly denied access to the hardware supporting a media type for the client.
|
|
137
|
+
* - `authorized` Application is authorized to access the hardware.
|
|
138
|
+
*/
|
|
139
|
+
export type AuthorizationStatus =
|
|
140
|
+
| 'notDetermined' // The user has not yet made a choice.
|
|
141
|
+
| 'restricted' // The user cannot change the client's status, possibly due to active restrictions such as parental controls being in place.
|
|
142
|
+
| 'denied' // The user explicitly denied access to the hardware supporting a media type for the client.
|
|
143
|
+
| 'authorized' // Application is authorized to access the hardware.
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @group Discovery
|
|
147
|
+
*/
|
|
148
|
+
export interface AppleDevice {
|
|
149
|
+
id: string;
|
|
150
|
+
name: string;
|
|
151
|
+
model_id?: string;
|
|
152
|
+
availability: 'available'
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* @group Discovery
|
|
157
|
+
*/
|
|
158
|
+
export interface Camera {
|
|
159
|
+
id: string;
|
|
160
|
+
name: string;
|
|
161
|
+
model_id: string;
|
|
162
|
+
manufacturer: string;
|
|
163
|
+
availability: 'available' | 'lidClosed' | 'unknownSuspended'
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @group Discovery
|
|
168
|
+
*/
|
|
169
|
+
export interface Microphone {
|
|
170
|
+
id: string;
|
|
171
|
+
name: string;
|
|
172
|
+
model_id: string;
|
|
173
|
+
manufacturer: string;
|
|
174
|
+
availability: 'available' | 'lidClosed' | 'unknownSuspended'
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @group Discovery
|
|
179
|
+
*/
|
|
180
|
+
export interface Window {
|
|
181
|
+
id: number; // UInt32
|
|
182
|
+
title?: string;
|
|
183
|
+
frame: Bounds
|
|
184
|
+
level: number // Int
|
|
185
|
+
application_process_id?: number // Int32
|
|
186
|
+
application_name?: string
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @group Utilities
|
|
191
|
+
*/
|
|
192
|
+
export interface Bounds {
|
|
193
|
+
x: number;
|
|
194
|
+
y: number;
|
|
195
|
+
width: number;
|
|
196
|
+
height: number;
|
|
197
|
+
}
|
package/src/Recorder.ts
CHANGED
|
@@ -4,65 +4,14 @@ import { NSRPC } from "./NonstrictRPC.js";
|
|
|
4
4
|
import { EventEmitter } from "stream";
|
|
5
5
|
import { AppleDevice, Camera, Microphone, Window } from "./RecordKit.js";
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export type RecorderSchemaItem =
|
|
13
|
-
| WebcamSchema
|
|
14
|
-
| WindowBasedCropSchema
|
|
15
|
-
| iPhonePortraitSchema
|
|
16
|
-
|
|
17
|
-
export interface WebcamSchema {
|
|
18
|
-
type: 'webcam'
|
|
19
|
-
filename?: string
|
|
20
|
-
camera: Camera | string
|
|
21
|
-
microphone: Microphone | string
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface WindowBasedCropSchema {
|
|
25
|
-
type: 'windowBasedCrop'
|
|
26
|
-
filename?: string
|
|
27
|
-
window: Window | number // UInt32
|
|
28
|
-
shows_cursor?: boolean
|
|
29
|
-
mouse_events?: boolean
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface iPhonePortraitSchema {
|
|
33
|
-
type: 'iPhonePortrait'
|
|
34
|
-
filename?: string
|
|
35
|
-
device: AppleDevice | string
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export type AbortReason =
|
|
39
|
-
| { reason: 'userStopped'; result: RecordingResult; }
|
|
40
|
-
| { reason: 'interrupted'; result: RecordingResult; error: RecordKitError; }
|
|
41
|
-
| { reason: 'failed'; error: RecordKitError; }
|
|
42
|
-
|
|
43
|
-
export interface RecordingResult {
|
|
44
|
-
url: string
|
|
45
|
-
info: BundleInfo
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export interface RecordKitError {
|
|
49
|
-
message?: string // Message describing the problem and possible recovery options, intended to be shown directly to the end-user.
|
|
50
|
-
error_group: string // Generic title, used for grouping related errors
|
|
51
|
-
debug_description: string // Detailed technical description of this error, used in debugging
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface BundleInfo {
|
|
55
|
-
version: 1,
|
|
56
|
-
files: {
|
|
57
|
-
type: 'screen' | 'webcam' | 'mouse' | 'appleDevice'
|
|
58
|
-
filename: string
|
|
59
|
-
}[]
|
|
60
|
-
}
|
|
61
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @group Recording
|
|
9
|
+
*/
|
|
62
10
|
export class Recorder extends EventEmitter {
|
|
63
11
|
private readonly rpc: NSRPC;
|
|
64
12
|
private readonly target: string;
|
|
65
13
|
|
|
14
|
+
/** @ignore */
|
|
66
15
|
static async newInstance(rpc: NSRPC, schema: RecorderSchema): Promise<Recorder> {
|
|
67
16
|
const target = 'Recorder_' + randomUUID();
|
|
68
17
|
const object = new Recorder(rpc, target);
|
|
@@ -105,6 +54,7 @@ export class Recorder extends EventEmitter {
|
|
|
105
54
|
return object
|
|
106
55
|
}
|
|
107
56
|
|
|
57
|
+
/** @ignore */
|
|
108
58
|
constructor(rpc: NSRPC, target: string) {
|
|
109
59
|
super();
|
|
110
60
|
this.rpc = rpc;
|
|
@@ -123,3 +73,82 @@ export class Recorder extends EventEmitter {
|
|
|
123
73
|
return await this.rpc.perform({ target: this.target, action: 'stop' }) as RecordingResult;
|
|
124
74
|
}
|
|
125
75
|
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @group Recording
|
|
79
|
+
*/
|
|
80
|
+
export interface RecorderSchema {
|
|
81
|
+
output_directory?: string
|
|
82
|
+
items: RecorderSchemaItem[]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @group Recording
|
|
87
|
+
*/
|
|
88
|
+
export type RecorderSchemaItem =
|
|
89
|
+
| WebcamSchema
|
|
90
|
+
| WindowBasedCropSchema
|
|
91
|
+
| iPhonePortraitSchema
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @group Recording Schemas
|
|
95
|
+
*/
|
|
96
|
+
export interface WebcamSchema {
|
|
97
|
+
type: 'webcam'
|
|
98
|
+
filename?: string
|
|
99
|
+
camera: Camera | string
|
|
100
|
+
microphone: Microphone | string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @group Recording Schemas
|
|
105
|
+
*/
|
|
106
|
+
export interface WindowBasedCropSchema {
|
|
107
|
+
type: 'windowBasedCrop'
|
|
108
|
+
filename?: string
|
|
109
|
+
window: Window | number // UInt32
|
|
110
|
+
shows_cursor?: boolean
|
|
111
|
+
mouse_events?: boolean
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @group Recording Schemas
|
|
116
|
+
*/
|
|
117
|
+
export interface iPhonePortraitSchema {
|
|
118
|
+
type: 'iPhonePortrait'
|
|
119
|
+
filename?: string
|
|
120
|
+
device: AppleDevice | string
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @group Recording
|
|
125
|
+
*/
|
|
126
|
+
export type AbortReason =
|
|
127
|
+
| { reason: 'userStopped'; result: RecordingResult; }
|
|
128
|
+
| { reason: 'interrupted'; result: RecordingResult; error: RecordKitError; }
|
|
129
|
+
| { reason: 'failed'; error: RecordKitError; }
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @group Recording
|
|
133
|
+
*/
|
|
134
|
+
export interface RecordingResult {
|
|
135
|
+
url: string
|
|
136
|
+
info: BundleInfo
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface RecordKitError {
|
|
140
|
+
message?: string // Message describing the problem and possible recovery options, intended to be shown directly to the end-user.
|
|
141
|
+
error_group: string // Generic title, used for grouping related errors
|
|
142
|
+
debug_description: string // Detailed technical description of this error, used in debugging
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @group Recording
|
|
147
|
+
*/
|
|
148
|
+
export interface BundleInfo {
|
|
149
|
+
version: 1,
|
|
150
|
+
files: {
|
|
151
|
+
type: 'screen' | 'webcam' | 'mouse' | 'appleDevice'
|
|
152
|
+
filename: string
|
|
153
|
+
}[]
|
|
154
|
+
}
|
package/typedoc.json
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
"entryPoints": [
|
|
3
|
+
"src/index.ts"
|
|
4
|
+
],
|
|
5
|
+
"navigationLinks": {
|
|
6
|
+
"Back to the Homepage": "http://nonstrict.eu/recordkit"
|
|
7
|
+
},
|
|
8
|
+
"excludeExternals": true,
|
|
9
|
+
"excludePrivate": true,
|
|
10
|
+
"excludeProtected": true,
|
|
11
|
+
"disableSources": true,
|
|
12
|
+
"sort": [
|
|
13
|
+
"source-order",
|
|
14
|
+
"kind",
|
|
15
|
+
"instance-first",
|
|
16
|
+
"alphabetical"
|
|
17
|
+
],
|
|
18
|
+
"sortEntryPoints": false,
|
|
6
19
|
}
|