devicely 2.1.4 → 2.1.5
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/bin/devicely.js +105 -1
- package/lib/androidDeviceDetection.js +276 -1
- package/lib/appMappings.js +337 -1
- package/lib/deviceDetection.js +394 -1
- package/lib/devices.js +54 -1
- package/lib/doctor.js +94 -1
- package/lib/executor.js +104 -1
- package/lib/logger.js +35 -1
- package/lib/scriptLoader.js +75 -1
- package/lib/server.js +3483 -1
- package/package.json +3 -12
- package/scripts/compile-shell-scripts.js +208 -0
- package/scripts/encrypt-shell-simple.js +75 -0
- package/scripts/obfuscate-shell.js +160 -0
- package/scripts/shell/android_device_control +0 -0
- package/scripts/shell/android_device_control.sh +848 -0
- package/scripts/shell/apps_presets.conf +271 -0
- package/scripts/shell/connect_android_usb +0 -0
- package/scripts/shell/connect_android_usb_multi_final +0 -0
- package/scripts/shell/connect_android_usb_multi_final.sh +289 -0
- package/scripts/shell/connect_android_wireless +0 -0
- package/scripts/shell/connect_android_wireless.sh +58 -0
- package/scripts/shell/connect_android_wireless_multi_final +0 -0
- package/scripts/shell/connect_android_wireless_multi_final.sh +476 -0
- package/scripts/shell/connect_ios_usb +0 -0
- package/scripts/shell/connect_ios_usb_multi_final +0 -0
- package/scripts/shell/connect_ios_usb_multi_final.sh +4225 -0
- package/scripts/shell/connect_ios_wireless_multi_final +0 -0
- package/scripts/shell/connect_ios_wireless_multi_final.sh +4167 -0
- package/scripts/shell/create_production_scripts +0 -0
- package/scripts/shell/create_production_scripts.sh +38 -0
- package/scripts/shell/devices.conf +24 -0
- package/scripts/shell/diagnose_wireless_ios +0 -0
- package/scripts/shell/find_element_coordinates +0 -0
- package/scripts/shell/find_wda +0 -0
- package/scripts/shell/install_uiautomator2 +0 -0
- package/scripts/shell/install_uiautomator2.sh +93 -0
- package/scripts/shell/ios_device_control +0 -0
- package/scripts/shell/ios_device_control.sh +220 -0
- package/scripts/shell/organize_project +0 -0
- package/scripts/shell/organize_project.sh +59 -0
- package/scripts/shell/pre-publish-check +0 -0
- package/scripts/shell/pre-publish-check.sh +238 -0
- package/scripts/shell/publish +0 -0
- package/scripts/shell/publish-to-npm +0 -0
- package/scripts/shell/publish-to-npm.sh +366 -0
- package/scripts/shell/publish.sh +100 -0
- package/scripts/shell/setup +0 -0
- package/scripts/shell/setup.sh +121 -0
- package/scripts/shell/setup_android +0 -0
- package/scripts/shell/start +0 -0
- package/scripts/shell/start.sh +59 -0
- package/scripts/shell/sync-to-npm-package-final +0 -0
- package/scripts/shell/sync-to-npm-package-final.sh +60 -0
- package/scripts/shell/test-local-package.sh +95 -0
- package/scripts/shell/test_android_locators +0 -0
- package/scripts/shell/test_connect +0 -0
- package/scripts/shell/test_device_detection +0 -0
- package/scripts/shell/test_fixes +0 -0
- package/scripts/shell/test_getlocators_fix +0 -0
- package/scripts/shell/test_recording_feature +0 -0
- package/scripts/shell/verify-shell-protection +0 -0
- package/scripts/shell/verify-shell-protection.sh +73 -0
- package/scripts/shell/verify_distribution +0 -0
- package/lib/package-lock.json +0 -1678
- package/lib/package.json +0 -30
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_225900.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_225942.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_231101.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260205_232911.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260208_095103.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhone17_20260208_095720.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115040.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115047.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115118.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115125.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_115143.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120107.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120118.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120137.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_120201.png +0 -0
- package/lib/screenshots/screenshot_ios_iPhoneXR17x_20260206_134529.png +0 -0
- package/scripts/shell/android_device_control.enc +0 -1
- package/scripts/shell/connect_android_usb_multi_final.enc +0 -1
- package/scripts/shell/connect_android_wireless.enc +0 -1
- package/scripts/shell/connect_android_wireless_multi_final.enc +0 -1
- package/scripts/shell/connect_ios_usb_multi_final.enc +0 -1
- package/scripts/shell/connect_ios_wireless_multi_final.enc +0 -1
- package/scripts/shell/ios_device_control.enc +0 -1
package/lib/doctor.js
CHANGED
|
@@ -1 +1,94 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* System requirements checker for Devicely
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { execSync } = require('child_process');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
|
|
8
|
+
function checkCommand(command, name) {
|
|
9
|
+
try {
|
|
10
|
+
execSync(`which ${command}`, { stdio: 'ignore' });
|
|
11
|
+
console.log(`${chalk.green('✓')} ${name} installed`);
|
|
12
|
+
return true;
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.log(`${chalk.red('✗')} ${name} not found`);
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getVersion(command) {
|
|
20
|
+
try {
|
|
21
|
+
const version = execSync(command, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] });
|
|
22
|
+
return version.trim().split('\n')[0];
|
|
23
|
+
} catch (error) {
|
|
24
|
+
return 'Unknown';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function checkDoctor() {
|
|
29
|
+
console.log('\n📋 System Requirements Check\n');
|
|
30
|
+
|
|
31
|
+
let allGood = true;
|
|
32
|
+
|
|
33
|
+
// Node.js
|
|
34
|
+
console.log(chalk.bold('Node.js:'));
|
|
35
|
+
const nodeVersion = process.version;
|
|
36
|
+
console.log(`${chalk.green('✓')} Version: ${nodeVersion}\n`);
|
|
37
|
+
|
|
38
|
+
// iOS Tools
|
|
39
|
+
console.log(chalk.bold('iOS Automation Tools:'));
|
|
40
|
+
const hasXcode = checkCommand('xcodebuild', 'Xcode');
|
|
41
|
+
const hasIdevice = checkCommand('idevice_id', 'libimobiledevice');
|
|
42
|
+
const hasIproxy = checkCommand('iproxy', 'usbmuxd');
|
|
43
|
+
allGood = allGood && hasXcode && hasIdevice && hasIproxy;
|
|
44
|
+
console.log('');
|
|
45
|
+
|
|
46
|
+
// Android Tools
|
|
47
|
+
console.log(chalk.bold('Android Automation Tools:'));
|
|
48
|
+
const hasAdb = checkCommand('adb', 'Android Debug Bridge (adb)');
|
|
49
|
+
allGood = allGood && hasAdb;
|
|
50
|
+
|
|
51
|
+
if (hasAdb) {
|
|
52
|
+
const adbVersion = getVersion('adb --version');
|
|
53
|
+
console.log(` Version: ${adbVersion}`);
|
|
54
|
+
}
|
|
55
|
+
console.log('');
|
|
56
|
+
|
|
57
|
+
// Python (for UIAutomator2)
|
|
58
|
+
console.log(chalk.bold('Python:'));
|
|
59
|
+
const hasPython = checkCommand('python3', 'Python 3');
|
|
60
|
+
if (hasPython) {
|
|
61
|
+
const pythonVersion = getVersion('python3 --version');
|
|
62
|
+
console.log(` Version: ${pythonVersion}`);
|
|
63
|
+
}
|
|
64
|
+
console.log('');
|
|
65
|
+
|
|
66
|
+
// Summary
|
|
67
|
+
if (allGood) {
|
|
68
|
+
console.log(chalk.green.bold('✅ All requirements met!'));
|
|
69
|
+
console.log(chalk.gray('\nYou can start using Devicely with: devicely start'));
|
|
70
|
+
} else {
|
|
71
|
+
console.log(chalk.yellow.bold('⚠️ Some requirements are missing'));
|
|
72
|
+
console.log(chalk.gray('\n📖 Installation Guide:'));
|
|
73
|
+
|
|
74
|
+
if (!hasIdevice || !hasIproxy) {
|
|
75
|
+
console.log(chalk.gray('\nFor iOS support:'));
|
|
76
|
+
console.log(' brew install libimobiledevice usbmuxd');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!hasAdb) {
|
|
80
|
+
console.log(chalk.gray('\nFor Android support:'));
|
|
81
|
+
console.log(' brew install android-platform-tools');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (!hasPython) {
|
|
85
|
+
console.log(chalk.gray('\nFor Python:'));
|
|
86
|
+
console.log(' brew install python3');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.log('');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
checkDoctor
|
|
94
|
+
};
|
package/lib/executor.js
CHANGED
|
@@ -1 +1,104 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Command executor for Devicely CLI
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { spawn } = require('child_process');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const chalk = require('chalk');
|
|
8
|
+
|
|
9
|
+
// Import deviceDetection from appropriate location
|
|
10
|
+
let discoverAllDevices;
|
|
11
|
+
try {
|
|
12
|
+
({ discoverAllDevices } = require('./deviceDetection'));
|
|
13
|
+
} catch (err) {
|
|
14
|
+
({ discoverAllDevices } = require('../../deviceDetection'));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function executeCommand(command, options = {}) {
|
|
18
|
+
const devices = await discoverAllDevices();
|
|
19
|
+
|
|
20
|
+
if (!devices || devices.length === 0) {
|
|
21
|
+
console.log(chalk.red('\n❌ No devices found'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let targetDevices = devices.filter(d => d.status === 'online');
|
|
26
|
+
|
|
27
|
+
if (options.device) {
|
|
28
|
+
targetDevices = devices.filter(d =>
|
|
29
|
+
d.name === options.device && d.status === 'online'
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (targetDevices.length === 0) {
|
|
33
|
+
console.log(chalk.red(`\n❌ Device "${options.device}" not found or offline`));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (targetDevices.length === 0) {
|
|
39
|
+
console.log(chalk.yellow('\n⚠️ No online devices found'));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(chalk.cyan(`\nExecuting on ${targetDevices.length} device(s):`));
|
|
44
|
+
targetDevices.forEach(d => console.log(` • ${d.name}`));
|
|
45
|
+
console.log('');
|
|
46
|
+
|
|
47
|
+
const scriptDir = path.join(__dirname, '../../scripts/shell');
|
|
48
|
+
|
|
49
|
+
for (const device of targetDevices) {
|
|
50
|
+
const platform = device.platform;
|
|
51
|
+
const type = device.type;
|
|
52
|
+
|
|
53
|
+
let scriptName;
|
|
54
|
+
if (platform === 'ios' && type === 'usb') {
|
|
55
|
+
scriptName = 'connect_ios_usb_multi_final.sh';
|
|
56
|
+
} else if (platform === 'ios' && type === 'wireless') {
|
|
57
|
+
scriptName = 'connect_ios_wireless_multi_final.sh';
|
|
58
|
+
} else if (platform === 'android' && type === 'usb') {
|
|
59
|
+
scriptName = 'connect_android_usb_multi_final.sh';
|
|
60
|
+
} else if (platform === 'android' && type === 'wireless') {
|
|
61
|
+
scriptName = 'connect_android_wireless_multi_final.sh';
|
|
62
|
+
} else {
|
|
63
|
+
console.log(chalk.yellow(`⚠️ Unsupported device type: ${platform}-${type}`));
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const scriptPath = path.join(scriptDir, scriptName);
|
|
68
|
+
|
|
69
|
+
console.log(chalk.blue(`[${device.name}] Running command...`));
|
|
70
|
+
|
|
71
|
+
const child = spawn(scriptPath, ['-d', device.name, ...command.split(' ')], {
|
|
72
|
+
stdio: 'pipe'
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
child.stdout.on('data', (data) => {
|
|
76
|
+
const lines = data.toString().split('\n').filter(l => l.trim());
|
|
77
|
+
lines.forEach(line => {
|
|
78
|
+
console.log(chalk.gray(` ${line}`));
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
child.stderr.on('data', (data) => {
|
|
83
|
+
const lines = data.toString().split('\n').filter(l => l.trim());
|
|
84
|
+
lines.forEach(line => {
|
|
85
|
+
console.log(chalk.red(` ${line}`));
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await new Promise((resolve) => {
|
|
90
|
+
child.on('close', (code) => {
|
|
91
|
+
if (code === 0) {
|
|
92
|
+
console.log(chalk.green(`[${device.name}] ✅ Success\n`));
|
|
93
|
+
} else {
|
|
94
|
+
console.log(chalk.red(`[${device.name}] ❌ Failed (exit code: ${code})\n`));
|
|
95
|
+
}
|
|
96
|
+
resolve();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
executeCommand
|
|
104
|
+
};
|
package/lib/logger.js
CHANGED
|
@@ -1 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
// Centralized Logger for Production
|
|
2
|
+
// Use environment variable to control debug output
|
|
3
|
+
|
|
4
|
+
const DEBUG_MODE = process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development';
|
|
5
|
+
|
|
6
|
+
class Logger {
|
|
7
|
+
constructor(module) {
|
|
8
|
+
this.module = module;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
debug(...args) {
|
|
12
|
+
if (DEBUG_MODE) {
|
|
13
|
+
console.log(`[DEBUG][${this.module}]`, ...args);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
info(...args) {
|
|
18
|
+
console.log(`[INFO][${this.module}]`, ...args);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
warn(...args) {
|
|
22
|
+
console.warn(`[WARN][${this.module}]`, ...args);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
error(...args) {
|
|
26
|
+
console.error(`[ERROR][${this.module}]`, ...args);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Keep critical startup/connection messages
|
|
30
|
+
startup(...args) {
|
|
31
|
+
console.log(`[STARTUP][${this.module}]`, ...args);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = Logger;
|
package/lib/scriptLoader.js
CHANGED
|
@@ -1 +1,75 @@
|
|
|
1
|
-
const
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
|
|
6
|
+
function generateKey() {
|
|
7
|
+
const pkg = require('../package.json');
|
|
8
|
+
return crypto.createHash('sha256').update(pkg.name + pkg.version).digest();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function decryptScript(encPath) {
|
|
12
|
+
const data = JSON.parse(fs.readFileSync(encPath, 'utf8'));
|
|
13
|
+
const key = generateKey();
|
|
14
|
+
const decipher = crypto.createDecipheriv('aes-256-cbc', key, Buffer.from(data.iv, 'hex'));
|
|
15
|
+
let decrypted = decipher.update(data.content, 'hex', 'utf8');
|
|
16
|
+
decrypted += decipher.final('utf8');
|
|
17
|
+
return decrypted;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function prepareScripts() {
|
|
21
|
+
const shellDir = path.join(__dirname, '../scripts/shell');
|
|
22
|
+
const tmpDir = path.join(os.tmpdir(), 'devicely_scripts_' + process.pid);
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(tmpDir)) {
|
|
25
|
+
fs.mkdirSync(tmpDir, { recursive: true, mode: 0o700 });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!fs.existsSync(shellDir)) {
|
|
29
|
+
return tmpDir;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const encFiles = fs.readdirSync(shellDir).filter(f => f.endsWith('.enc'));
|
|
33
|
+
|
|
34
|
+
if (encFiles.length === 0) {
|
|
35
|
+
return tmpDir;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
console.log(`🔓 Decrypting ${encFiles.length} protected scripts...`);
|
|
39
|
+
|
|
40
|
+
encFiles.forEach(encFile => {
|
|
41
|
+
const encPath = path.join(shellDir, encFile);
|
|
42
|
+
const scriptName = encFile.replace('.enc', '.sh');
|
|
43
|
+
const tmpScript = path.join(tmpDir, scriptName);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const content = decryptScript(encPath);
|
|
47
|
+
fs.writeFileSync(tmpScript, content, { mode: 0o755 });
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(` ❌ Failed to decrypt ${encFile}: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log(`✅ Scripts ready in temp directory\n`);
|
|
54
|
+
|
|
55
|
+
process.on('exit', () => {
|
|
56
|
+
try {
|
|
57
|
+
if (fs.existsSync(tmpDir)) {
|
|
58
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
59
|
+
}
|
|
60
|
+
} catch(e) {}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
process.on('SIGINT', () => {
|
|
64
|
+
try {
|
|
65
|
+
if (fs.existsSync(tmpDir)) {
|
|
66
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
67
|
+
}
|
|
68
|
+
} catch(e) {}
|
|
69
|
+
process.exit();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return tmpDir;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = { prepareScripts, decryptScript };
|