illuma-rpa 1.0.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.
Files changed (44) hide show
  1. package/.github/workflows/publish.yml +129 -0
  2. package/LICENSE +107 -0
  3. package/README.md +202 -0
  4. package/dist/index.d.ts +10 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +23 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/keyboard.d.ts +82 -0
  9. package/dist/keyboard.d.ts.map +1 -0
  10. package/dist/keyboard.js +116 -0
  11. package/dist/keyboard.js.map +1 -0
  12. package/dist/mouse.d.ts +61 -0
  13. package/dist/mouse.d.ts.map +1 -0
  14. package/dist/mouse.js +107 -0
  15. package/dist/mouse.js.map +1 -0
  16. package/dist/native.d.ts +63 -0
  17. package/dist/native.d.ts.map +1 -0
  18. package/dist/native.js +91 -0
  19. package/dist/native.js.map +1 -0
  20. package/dist/screen.d.ts +39 -0
  21. package/dist/screen.d.ts.map +1 -0
  22. package/dist/screen.js +43 -0
  23. package/dist/screen.js.map +1 -0
  24. package/dist/window.d.ts +61 -0
  25. package/dist/window.d.ts.map +1 -0
  26. package/dist/window.js +66 -0
  27. package/dist/window.js.map +1 -0
  28. package/libnut-core/CHANGELOG.md +122 -0
  29. package/libnut-core/LICENSE.md +201 -0
  30. package/libnut-core/README.md +26 -0
  31. package/libnut-core/index.d.ts +82 -0
  32. package/libnut-core/index.js +51 -0
  33. package/libnut-core/package-lock.json +1430 -0
  34. package/libnut-core/package.json +59 -0
  35. package/libnut-core/patch-packagename.js +18 -0
  36. package/libnut-core/permissionCheck.js +82 -0
  37. package/package.json +61 -0
  38. package/src/index.ts +10 -0
  39. package/src/keyboard.ts +125 -0
  40. package/src/mouse.ts +114 -0
  41. package/src/native.ts +103 -0
  42. package/src/screen.ts +59 -0
  43. package/src/window.ts +89 -0
  44. package/tsconfig.json +20 -0
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "libnut",
3
+ "version": "2.7.1",
4
+ "description": "libnut is an N-API module for desktop automation with node",
5
+ "main": "index.js",
6
+ "typings": "index.d.ts",
7
+ "scripts": {
8
+ "clean": "cmake-js clean",
9
+ "patch": "node ./patch-packagename.js",
10
+ "build:debug": "cmake-js rebuild --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\" --debug",
11
+ "build:release": "cmake-js rebuild --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\"",
12
+ "prepublishOnly": "npm run build:release",
13
+ "publish:next": "npm publish --tag next"
14
+ },
15
+ "homepage": "https://nutjs.dev",
16
+ "author": {
17
+ "name": "dry Software UG (haftungsbeschränkt)",
18
+ "email": "info@dry.software",
19
+ "url": "https://dry.software"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/nut-tree/nut.js/issues"
23
+ },
24
+ "keywords": [
25
+ "GUI",
26
+ "Automation",
27
+ "mouse",
28
+ "keyboard",
29
+ "screenshot",
30
+ "image",
31
+ "desktop",
32
+ "screen",
33
+ "recognition",
34
+ "autohotkey"
35
+ ],
36
+ "license": "Apache-2.0",
37
+ "dependencies": {
38
+ "bindings": "1.5.0"
39
+ },
40
+ "devDependencies": {
41
+ "cmake-js": "7.3.0",
42
+ "node-addon-api": "7.1.0"
43
+ },
44
+ "optionalDependencies": {
45
+ "@nut-tree/node-mac-permissions": "2.2.1"
46
+ },
47
+ "engines": {
48
+ "node": ">=10.15.3"
49
+ },
50
+ "os": [
51
+ "darwin",
52
+ "linux",
53
+ "win32"
54
+ ],
55
+ "cpu": [
56
+ "x64",
57
+ "arm64"
58
+ ]
59
+ }
@@ -0,0 +1,18 @@
1
+ const fs = require("fs");
2
+ const { join } = require("path");
3
+
4
+ if (process.env.CI) {
5
+ const filename = join(__dirname, "package.json");
6
+ const packageJson = require(filename);
7
+
8
+ const plattformPackageName = `@nut-tree/libnut-${process.platform}`;
9
+ packageJson.name = plattformPackageName;
10
+
11
+ try {
12
+ fs.writeFileSync(filename, JSON.stringify(packageJson, null, 2));
13
+ } catch (err) {
14
+ console.log(err);
15
+ process.exit(-1);
16
+ }
17
+ console.log(`Patched package name to '${plattformPackageName}'`);
18
+ }
@@ -0,0 +1,82 @@
1
+ let libnut = require("bindings")("libnut");
2
+
3
+ let hasScreenRecordingPermission = false;
4
+ let hasAccessibilityPermission = false;
5
+
6
+ try {
7
+ const permissions = require("@nut-tree/node-mac-permissions");
8
+
9
+ const wrapWithWarning = (message, nativeFunction) => (...args) => {
10
+ console.warn(message);
11
+ return nativeFunction(...args);
12
+ };
13
+
14
+ const askForAccessibility = (nativeFunction, functionName) => {
15
+ if (process.platform !== 'darwin' || hasAccessibilityPermission) {
16
+ return nativeFunction;
17
+ }
18
+ const accessibilityStatus = permissions.getAuthStatus("accessibility");
19
+
20
+ if (accessibilityStatus === 'authorized') {
21
+ hasAccessibilityPermission = true;
22
+ return nativeFunction;
23
+ } else if (accessibilityStatus === 'not determined' || accessibilityStatus === 'denied') {
24
+ permissions.askForAccessibilityAccess();
25
+ return wrapWithWarning(`##### WARNING! The application running this script tries to access accessibility features to execute ${functionName}! Please grant requested access and visit https://github.com/nut-tree/nut.js#macos for further information. #####`, nativeFunction);
26
+ }
27
+ }
28
+ const askForScreenRecording = (nativeFunction, functionName) => {
29
+ if (process.platform !== 'darwin' || hasScreenRecordingPermission) {
30
+ return nativeFunction;
31
+ }
32
+ const screenCaptureStatus = permissions.getAuthStatus("screen");
33
+
34
+ if (screenCaptureStatus === 'authorized') {
35
+ hasScreenRecordingPermission = true;
36
+ return nativeFunction;
37
+ } else if (screenCaptureStatus === 'not determined' || screenCaptureStatus === 'denied') {
38
+ permissions.askForScreenCaptureAccess();
39
+ return wrapWithWarning(`##### WARNING! The application running this script tries to screen recording features to execute ${functionName}! Please grant the requested access and visit https://github.com/nut-tree/nut.js#macos for further information. #####`, nativeFunction);
40
+ }
41
+ }
42
+
43
+ const accessibilityAccess = [
44
+ "dragMouse",
45
+ "moveMouse",
46
+ "getMousePos",
47
+ "mouseClick",
48
+ "mouseToggle",
49
+ "scrollMouse",
50
+ "keyTap",
51
+ "keyToggle",
52
+ "typeString",
53
+ "getScreenSize",
54
+ "highlight",
55
+ "captureScreen",
56
+ "getWindows",
57
+ "getActiveWindow",
58
+ "getWindowRect",
59
+ "getWindowTitle",
60
+ "focusWindow",
61
+ "resizeWindow"
62
+ ];
63
+ const screenCaptureAccess = [
64
+ "getWindowTitle",
65
+ "captureScreen",
66
+ ];
67
+
68
+ for (const functionName of accessibilityAccess) {
69
+ const originalFunction = libnut[functionName];
70
+ libnut[functionName] = (...args) => askForAccessibility(originalFunction, functionName)(...args);
71
+ }
72
+ for (const functionName of screenCaptureAccess) {
73
+ const originalFunction = libnut[functionName];
74
+ libnut[functionName] = (...args) => askForScreenRecording(originalFunction, functionName)(...args);
75
+ }
76
+ } catch (e) {
77
+ console.warn(`Encountered error establishing macOS permission checks:`, e.message);
78
+ console.warn(`Returning original module.`);
79
+ libnut = require("bindings")("libnut");
80
+ } finally {
81
+ module.exports = libnut;
82
+ }
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "illuma-rpa",
3
+ "version": "1.0.0",
4
+ "description": "Cross-platform desktop automation for Node.js - mouse, keyboard, screen capture",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "license": "Apache-2.0",
8
+ "author": "Illuma",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/illuma-ai/illuma-rpa.git"
12
+ },
13
+ "homepage": "https://github.com/illuma-ai/illuma-rpa",
14
+ "bugs": {
15
+ "url": "https://github.com/illuma-ai/illuma-rpa/issues"
16
+ },
17
+ "scripts": {
18
+ "clean": "rimraf dist",
19
+ "build": "pnpm run clean && tsc -p .",
20
+ "build:native": "cd libnut-core && npm run build:release",
21
+ "test": "jest",
22
+ "prepublishOnly": "pnpm run build",
23
+ "publish:npm": "npm publish --access public"
24
+ },
25
+ "keywords": [
26
+ "automation",
27
+ "desktop",
28
+ "rpa",
29
+ "mouse",
30
+ "keyboard",
31
+ "screenshot",
32
+ "screen",
33
+ "ui-automation",
34
+ "robot",
35
+ "native",
36
+ "electron"
37
+ ],
38
+ "engines": {
39
+ "node": ">=16"
40
+ },
41
+ "os": [
42
+ "win32",
43
+ "darwin",
44
+ "linux"
45
+ ],
46
+ "cpu": [
47
+ "x64",
48
+ "arm64"
49
+ ],
50
+ "dependencies": {
51
+ "jimp": "0.22.10"
52
+ },
53
+ "devDependencies": {
54
+ "@types/node": "^20.0.0",
55
+ "rimraf": "^5.0.0",
56
+ "typescript": "^5.3.0",
57
+ "jest": "^29.7.0",
58
+ "@types/jest": "^29.5.0",
59
+ "ts-jest": "^29.1.0"
60
+ }
61
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * illuma-rpa
3
+ * Cross-platform desktop automation for Node.js
4
+ */
5
+
6
+ export { mouse, Mouse } from './mouse';
7
+ export { keyboard, Keyboard, Key } from './keyboard';
8
+ export { screen, Screen, Screenshot } from './screen';
9
+ export { window, Window, WindowInfo } from './window';
10
+ export { loadNativeBinding } from './native';
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Keyboard control module
3
+ */
4
+
5
+ import { getNative } from './native';
6
+
7
+ /**
8
+ * Key constants for keyboard input
9
+ */
10
+ export const Key = {
11
+ // Modifiers
12
+ Ctrl: 'control',
13
+ Control: 'control',
14
+ Alt: 'alt',
15
+ Shift: 'shift',
16
+ Meta: 'command', // Win key on Windows, Cmd on macOS
17
+ Win: 'command',
18
+ Cmd: 'command',
19
+
20
+ // Navigation
21
+ Up: 'up',
22
+ Down: 'down',
23
+ Left: 'left',
24
+ Right: 'right',
25
+ Home: 'home',
26
+ End: 'end',
27
+ PageUp: 'pageup',
28
+ PageDown: 'pagedown',
29
+
30
+ // Editing
31
+ Enter: 'enter',
32
+ Return: 'enter',
33
+ Tab: 'tab',
34
+ Backspace: 'backspace',
35
+ Delete: 'delete',
36
+ Escape: 'escape',
37
+ Esc: 'escape',
38
+ Space: 'space',
39
+ Insert: 'insert',
40
+
41
+ // Function keys
42
+ F1: 'f1', F2: 'f2', F3: 'f3', F4: 'f4',
43
+ F5: 'f5', F6: 'f6', F7: 'f7', F8: 'f8',
44
+ F9: 'f9', F10: 'f10', F11: 'f11', F12: 'f12',
45
+
46
+ // Other
47
+ PrintScreen: 'printscreen',
48
+ CapsLock: 'capslock',
49
+ NumLock: 'numlock',
50
+ ScrollLock: 'scrolllock',
51
+ } as const;
52
+
53
+ export type KeyType = typeof Key[keyof typeof Key] | string;
54
+
55
+ export class Keyboard {
56
+ private delay = 0;
57
+
58
+ /**
59
+ * Set delay between key presses (ms)
60
+ */
61
+ setDelay(ms: number): void {
62
+ this.delay = ms;
63
+ getNative().setKeyboardDelay(ms);
64
+ }
65
+
66
+ /**
67
+ * Type a string of text
68
+ */
69
+ async type(text: string): Promise<void> {
70
+ getNative().typeString(text);
71
+ }
72
+
73
+ /**
74
+ * Type text with delay between characters
75
+ */
76
+ async typeDelayed(text: string, delayMs: number = 50): Promise<void> {
77
+ // Convert delay to characters per minute
78
+ const cpm = Math.round(60000 / delayMs);
79
+ getNative().typeStringDelayed(text, cpm);
80
+ }
81
+
82
+ /**
83
+ * Press and release a key or key combination
84
+ */
85
+ async press(...keys: KeyType[]): Promise<void> {
86
+ if (keys.length === 0) return;
87
+
88
+ if (keys.length === 1) {
89
+ getNative().keyTap(keys[0]);
90
+ } else {
91
+ // Last key is the main key, others are modifiers
92
+ const mainKey = keys[keys.length - 1];
93
+ const modifiers = keys.slice(0, -1);
94
+ getNative().keyTap(mainKey, modifiers);
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Hold a key down
100
+ */
101
+ async hold(...keys: KeyType[]): Promise<void> {
102
+ for (const key of keys) {
103
+ getNative().keyToggle(key, 'down');
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Release a held key
109
+ */
110
+ async release(...keys: KeyType[]): Promise<void> {
111
+ for (const key of keys) {
112
+ getNative().keyToggle(key, 'up');
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Press a key combination (e.g., Ctrl+C)
118
+ */
119
+ async combo(...keys: KeyType[]): Promise<void> {
120
+ await this.press(...keys);
121
+ }
122
+ }
123
+
124
+ // Export singleton instance
125
+ export const keyboard = new Keyboard();
package/src/mouse.ts ADDED
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Mouse control module
3
+ */
4
+
5
+ import { getNative } from './native';
6
+
7
+ export interface Point {
8
+ x: number;
9
+ y: number;
10
+ }
11
+
12
+ export type MouseButton = 'left' | 'right' | 'middle';
13
+
14
+ export class Mouse {
15
+ private delay = 10;
16
+
17
+ /**
18
+ * Set delay between mouse actions (ms)
19
+ */
20
+ setDelay(ms: number): void {
21
+ this.delay = ms;
22
+ getNative().setMouseDelay(ms);
23
+ }
24
+
25
+ /**
26
+ * Move mouse to absolute position
27
+ */
28
+ async moveTo(x: number, y: number): Promise<void> {
29
+ getNative().moveMouse(x, y);
30
+ }
31
+
32
+ /**
33
+ * Move mouse smoothly to position
34
+ */
35
+ async moveSmooth(x: number, y: number): Promise<void> {
36
+ getNative().moveMouseSmooth(x, y);
37
+ }
38
+
39
+ /**
40
+ * Click mouse button
41
+ */
42
+ async click(button: MouseButton = 'left'): Promise<void> {
43
+ getNative().mouseClick(button, false);
44
+ }
45
+
46
+ /**
47
+ * Double click
48
+ */
49
+ async doubleClick(button: MouseButton = 'left'): Promise<void> {
50
+ getNative().mouseClick(button, true);
51
+ }
52
+
53
+ /**
54
+ * Right click (convenience method)
55
+ */
56
+ async rightClick(): Promise<void> {
57
+ await this.click('right');
58
+ }
59
+
60
+ /**
61
+ * Press mouse button down
62
+ */
63
+ async down(button: MouseButton = 'left'): Promise<void> {
64
+ getNative().mouseToggle('down', button);
65
+ }
66
+
67
+ /**
68
+ * Release mouse button
69
+ */
70
+ async up(button: MouseButton = 'left'): Promise<void> {
71
+ getNative().mouseToggle('up', button);
72
+ }
73
+
74
+ /**
75
+ * Drag from current position to target
76
+ */
77
+ async drag(startX: number, startY: number, endX: number, endY: number): Promise<void> {
78
+ await this.moveTo(startX, startY);
79
+ await this.down();
80
+ await this.moveTo(endX, endY);
81
+ await this.up();
82
+ }
83
+
84
+ /**
85
+ * Drag to target from current position
86
+ */
87
+ async dragTo(x: number, y: number): Promise<void> {
88
+ getNative().dragMouse(x, y);
89
+ }
90
+
91
+ /**
92
+ * Scroll mouse wheel
93
+ */
94
+ async scroll(direction: 'up' | 'down' | 'left' | 'right', amount: number = 3): Promise<void> {
95
+ let x = 0, y = 0;
96
+ switch (direction) {
97
+ case 'up': y = amount; break;
98
+ case 'down': y = -amount; break;
99
+ case 'left': x = -amount; break;
100
+ case 'right': x = amount; break;
101
+ }
102
+ getNative().scrollMouse(x, y);
103
+ }
104
+
105
+ /**
106
+ * Get current mouse position
107
+ */
108
+ getPosition(): Point {
109
+ return getNative().getMousePos();
110
+ }
111
+ }
112
+
113
+ // Export singleton instance
114
+ export const mouse = new Mouse();
package/src/native.ts ADDED
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Native binding loader
3
+ * Automatically loads the correct platform-specific binary
4
+ */
5
+
6
+ import * as path from 'path';
7
+
8
+ export interface NativeBinding {
9
+ // Keyboard
10
+ setKeyboardDelay(ms: number): void;
11
+ keyTap(key: string, modifier?: string | string[]): void;
12
+ keyToggle(key: string, down: string, modifier?: string | string[]): void;
13
+ typeString(str: string): void;
14
+ typeStringDelayed(str: string, cpm: number): void;
15
+
16
+ // Mouse
17
+ setMouseDelay(delay: number): void;
18
+ moveMouse(x: number, y: number): void;
19
+ moveMouseSmooth(x: number, y: number): void;
20
+ mouseClick(button?: string, double?: boolean): void;
21
+ mouseToggle(down?: string, button?: string): void;
22
+ dragMouse(x: number, y: number): void;
23
+ scrollMouse(x: number, y: number): void;
24
+ getMousePos(): { x: number; y: number };
25
+
26
+ // Screen
27
+ getScreenSize(): { width: number; height: number };
28
+ screen: {
29
+ capture(x?: number, y?: number, width?: number, height?: number): {
30
+ width: number;
31
+ height: number;
32
+ image: Buffer;
33
+ byteWidth: number;
34
+ bitsPerPixel: number;
35
+ bytesPerPixel: number;
36
+ };
37
+ };
38
+
39
+ // Window
40
+ getWindows(): number[];
41
+ getActiveWindow(): number;
42
+ getWindowRect(handle: number): { x: number; y: number; width: number; height: number };
43
+ getWindowTitle(handle: number): string;
44
+ focusWindow(handle: number): void;
45
+ resizeWindow(handle: number, size: { width: number; height: number }): void;
46
+ moveWindow(handle: number, pos: { x: number; y: number }): void;
47
+ }
48
+
49
+ let native: NativeBinding | null = null;
50
+
51
+ /**
52
+ * Load the native binding for the current platform
53
+ */
54
+ export function loadNativeBinding(): NativeBinding {
55
+ if (native) {
56
+ return native;
57
+ }
58
+
59
+ const platform = process.platform;
60
+ const arch = process.arch;
61
+ const packageName = `illuma-rpa-${platform}-${arch}`;
62
+
63
+ // Try loading from optional dependency
64
+ try {
65
+ native = require(packageName);
66
+ return native!;
67
+ } catch {
68
+ // Fallback: try loading from local build
69
+ }
70
+
71
+ // Try loading from local libnut-core build
72
+ const localPaths = [
73
+ path.join(__dirname, '../libnut-core/build/Release/libnut.node'),
74
+ path.join(__dirname, '../../libnut-core/build/Release/libnut.node'),
75
+ path.join(process.cwd(), 'libnut-core/build/Release/libnut.node'),
76
+ ];
77
+
78
+ for (const localPath of localPaths) {
79
+ try {
80
+ native = require(localPath);
81
+ return native!;
82
+ } catch {
83
+ continue;
84
+ }
85
+ }
86
+
87
+ throw new Error(
88
+ `Failed to load native binding for ${platform}-${arch}.\n` +
89
+ `Please ensure one of the following:\n` +
90
+ ` 1. Install the platform package: npm install ${packageName}\n` +
91
+ ` 2. Build from source: cd libnut-core && npm run build:release`
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Get the native binding (lazy load)
97
+ */
98
+ export function getNative(): NativeBinding {
99
+ if (!native) {
100
+ loadNativeBinding();
101
+ }
102
+ return native!;
103
+ }
package/src/screen.ts ADDED
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Screen capture module
3
+ */
4
+
5
+ import { getNative } from './native';
6
+
7
+ export interface Screenshot {
8
+ width: number;
9
+ height: number;
10
+ image: Buffer;
11
+ byteWidth: number;
12
+ bitsPerPixel: number;
13
+ bytesPerPixel: number;
14
+ }
15
+
16
+ export interface ScreenSize {
17
+ width: number;
18
+ height: number;
19
+ }
20
+
21
+ export class Screen {
22
+ /**
23
+ * Capture the entire screen
24
+ */
25
+ async capture(): Promise<Screenshot> {
26
+ return getNative().screen.capture();
27
+ }
28
+
29
+ /**
30
+ * Capture a region of the screen
31
+ */
32
+ async captureRegion(x: number, y: number, width: number, height: number): Promise<Screenshot> {
33
+ return getNative().screen.capture(x, y, width, height);
34
+ }
35
+
36
+ /**
37
+ * Get the screen size
38
+ */
39
+ getSize(): ScreenSize {
40
+ return getNative().getScreenSize();
41
+ }
42
+
43
+ /**
44
+ * Get screen width
45
+ */
46
+ getWidth(): number {
47
+ return this.getSize().width;
48
+ }
49
+
50
+ /**
51
+ * Get screen height
52
+ */
53
+ getHeight(): number {
54
+ return this.getSize().height;
55
+ }
56
+ }
57
+
58
+ // Export singleton instance
59
+ export const screen = new Screen();