@edgible-team/cli 1.0.1
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 +136 -0
- package/README.md +450 -0
- package/dist/client/api-client.js +1057 -0
- package/dist/client/index.js +21 -0
- package/dist/commands/agent.js +1280 -0
- package/dist/commands/ai.js +608 -0
- package/dist/commands/application.js +885 -0
- package/dist/commands/auth.js +570 -0
- package/dist/commands/base/BaseCommand.js +93 -0
- package/dist/commands/base/CommandHandler.js +7 -0
- package/dist/commands/base/command-wrapper.js +58 -0
- package/dist/commands/base/middleware.js +77 -0
- package/dist/commands/config.js +116 -0
- package/dist/commands/connectivity.js +59 -0
- package/dist/commands/debug.js +98 -0
- package/dist/commands/discover.js +144 -0
- package/dist/commands/examples/migrated-command-example.js +180 -0
- package/dist/commands/gateway.js +494 -0
- package/dist/commands/managedGateway.js +787 -0
- package/dist/commands/utils/config-validator.js +76 -0
- package/dist/commands/utils/gateway-prompt.js +79 -0
- package/dist/commands/utils/input-parser.js +120 -0
- package/dist/commands/utils/output-formatter.js +109 -0
- package/dist/config/app-config.js +99 -0
- package/dist/detection/SystemCapabilityDetector.js +1244 -0
- package/dist/detection/ToolDetector.js +305 -0
- package/dist/detection/WorkloadDetector.js +314 -0
- package/dist/di/bindings.js +99 -0
- package/dist/di/container.js +88 -0
- package/dist/di/types.js +32 -0
- package/dist/index.js +52 -0
- package/dist/interfaces/IDaemonManager.js +3 -0
- package/dist/repositories/config-repository.js +62 -0
- package/dist/repositories/gateway-repository.js +35 -0
- package/dist/scripts/postinstall.js +101 -0
- package/dist/services/AgentStatusManager.js +299 -0
- package/dist/services/ConnectivityTester.js +271 -0
- package/dist/services/DependencyInstaller.js +475 -0
- package/dist/services/LocalAgentManager.js +2216 -0
- package/dist/services/application/ApplicationService.js +299 -0
- package/dist/services/auth/AuthService.js +214 -0
- package/dist/services/aws.js +644 -0
- package/dist/services/daemon/DaemonManagerFactory.js +65 -0
- package/dist/services/daemon/DockerDaemonManager.js +395 -0
- package/dist/services/daemon/LaunchdDaemonManager.js +257 -0
- package/dist/services/daemon/PodmanDaemonManager.js +369 -0
- package/dist/services/daemon/SystemdDaemonManager.js +221 -0
- package/dist/services/daemon/WindowsServiceDaemonManager.js +210 -0
- package/dist/services/daemon/index.js +16 -0
- package/dist/services/edgible.js +3060 -0
- package/dist/services/gateway/GatewayService.js +334 -0
- package/dist/state/config.js +146 -0
- package/dist/types/AgentConfig.js +5 -0
- package/dist/types/AgentStatus.js +5 -0
- package/dist/types/ApiClient.js +5 -0
- package/dist/types/ApiRequests.js +5 -0
- package/dist/types/ApiResponses.js +5 -0
- package/dist/types/Application.js +5 -0
- package/dist/types/CaddyJson.js +5 -0
- package/dist/types/UnifiedAgentStatus.js +56 -0
- package/dist/types/WireGuard.js +5 -0
- package/dist/types/Workload.js +5 -0
- package/dist/types/agent.js +5 -0
- package/dist/types/command-options.js +5 -0
- package/dist/types/connectivity.js +5 -0
- package/dist/types/errors.js +250 -0
- package/dist/types/gateway-types.js +5 -0
- package/dist/types/index.js +48 -0
- package/dist/types/models/ApplicationData.js +5 -0
- package/dist/types/models/CertificateData.js +5 -0
- package/dist/types/models/DeviceData.js +5 -0
- package/dist/types/models/DevicePoolData.js +5 -0
- package/dist/types/models/OrganizationData.js +5 -0
- package/dist/types/models/OrganizationInviteData.js +5 -0
- package/dist/types/models/ProviderConfiguration.js +5 -0
- package/dist/types/models/ResourceData.js +5 -0
- package/dist/types/models/ServiceResourceData.js +5 -0
- package/dist/types/models/UserData.js +5 -0
- package/dist/types/route.js +5 -0
- package/dist/types/validation/schemas.js +218 -0
- package/dist/types/validation.js +5 -0
- package/dist/utils/FileIntegrityManager.js +256 -0
- package/dist/utils/PathMigration.js +219 -0
- package/dist/utils/PathResolver.js +235 -0
- package/dist/utils/PlatformDetector.js +277 -0
- package/dist/utils/console-logger.js +130 -0
- package/dist/utils/docker-compose-parser.js +179 -0
- package/dist/utils/errors.js +130 -0
- package/dist/utils/health-checker.js +155 -0
- package/dist/utils/json-logger.js +72 -0
- package/dist/utils/log-formatter.js +293 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/network-utils.js +217 -0
- package/dist/utils/output.js +182 -0
- package/dist/utils/passwordValidation.js +91 -0
- package/dist/utils/progress.js +167 -0
- package/dist/utils/sudo-checker.js +22 -0
- package/dist/utils/urls.js +32 -0
- package/dist/utils/validation.js +31 -0
- package/dist/validation/schemas.js +175 -0
- package/dist/validation/validator.js +67 -0
- package/package.json +83 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PathResolver = void 0;
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
/**
|
|
40
|
+
* PathResolver provides centralized path management following industry standards:
|
|
41
|
+
* - XDG Base Directory specification on Linux
|
|
42
|
+
* - Platform-specific conventions on macOS and Windows
|
|
43
|
+
* - Proper handling of sudo contexts (preserves real user)
|
|
44
|
+
*/
|
|
45
|
+
class PathResolver {
|
|
46
|
+
/**
|
|
47
|
+
* Get the real user's home directory, even when running under sudo.
|
|
48
|
+
* Detects the actual user via SUDO_USER environment variable.
|
|
49
|
+
*
|
|
50
|
+
* @returns The real user's home directory path
|
|
51
|
+
*/
|
|
52
|
+
static getRealUserHome() {
|
|
53
|
+
// Check if running under sudo
|
|
54
|
+
const sudoUser = process.env['SUDO_USER'];
|
|
55
|
+
if (sudoUser) {
|
|
56
|
+
// If current user is root but SUDO_USER is set, get the sudo user's home
|
|
57
|
+
if (process.getuid && process.getuid() === 0 && sudoUser) {
|
|
58
|
+
const fs = require('fs');
|
|
59
|
+
const { execSync } = require('child_process');
|
|
60
|
+
try {
|
|
61
|
+
// Try to get the home directory using getent (Linux) or dscl (macOS)
|
|
62
|
+
if (process.platform === 'linux') {
|
|
63
|
+
try {
|
|
64
|
+
const homeDir = execSync(`getent passwd ${sudoUser} | cut -d: -f6`, { encoding: 'utf8' }).trim();
|
|
65
|
+
if (fs.existsSync(homeDir)) {
|
|
66
|
+
return homeDir;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Fall through to default path construction
|
|
71
|
+
}
|
|
72
|
+
// Fallback: construct path
|
|
73
|
+
const homeDir = `/home/${sudoUser}`;
|
|
74
|
+
if (fs.existsSync(homeDir)) {
|
|
75
|
+
return homeDir;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (process.platform === 'darwin') {
|
|
79
|
+
try {
|
|
80
|
+
const homeDir = execSync(`dscl . -read /Users/${sudoUser} NFSHomeDirectory | cut -d' ' -f2`, { encoding: 'utf8' }).trim();
|
|
81
|
+
if (fs.existsSync(homeDir)) {
|
|
82
|
+
return homeDir;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Fall through to default path construction
|
|
87
|
+
}
|
|
88
|
+
// Fallback: construct path
|
|
89
|
+
const homeDir = `/Users/${sudoUser}`;
|
|
90
|
+
if (fs.existsSync(homeDir)) {
|
|
91
|
+
return homeDir;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
// Fall through to default behavior
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Default: use current user's home directory
|
|
101
|
+
return os.homedir();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get the user-level data directory for CLI configuration and data.
|
|
105
|
+
* Follows XDG Base Directory spec on Linux, platform conventions elsewhere.
|
|
106
|
+
*
|
|
107
|
+
* @returns The user data directory path
|
|
108
|
+
*/
|
|
109
|
+
static getUserDataPath() {
|
|
110
|
+
const platform = os.platform();
|
|
111
|
+
const realHome = this.getRealUserHome();
|
|
112
|
+
if (platform === 'linux') {
|
|
113
|
+
// Follow XDG Base Directory specification
|
|
114
|
+
const xdgDataHome = process.env['XDG_DATA_HOME'];
|
|
115
|
+
if (xdgDataHome) {
|
|
116
|
+
return path.join(xdgDataHome, 'edgible');
|
|
117
|
+
}
|
|
118
|
+
// Default: ~/.local/share/edgible
|
|
119
|
+
return path.join(realHome, '.local', 'share', 'edgible');
|
|
120
|
+
}
|
|
121
|
+
else if (platform === 'darwin') {
|
|
122
|
+
// macOS: ~/Library/Application Support/Edgible
|
|
123
|
+
return path.join(realHome, 'Library', 'Application Support', 'Edgible');
|
|
124
|
+
}
|
|
125
|
+
else if (platform === 'win32') {
|
|
126
|
+
// Windows: %APPDATA%\Edgible
|
|
127
|
+
const appData = process.env['APPDATA'] || path.join(realHome, 'AppData', 'Roaming');
|
|
128
|
+
return path.join(appData, 'Edgible');
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
// Fallback for other platforms
|
|
132
|
+
return path.join(realHome, '.edgible');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get the system-level data directory for agent services.
|
|
137
|
+
* Used when the agent runs as a system service (systemd, launchd, etc.)
|
|
138
|
+
*
|
|
139
|
+
* @returns The system data directory path
|
|
140
|
+
*/
|
|
141
|
+
static getSystemDataPath() {
|
|
142
|
+
const platform = os.platform();
|
|
143
|
+
if (platform === 'linux') {
|
|
144
|
+
// Linux: /var/lib/edgible
|
|
145
|
+
return '/var/lib/edgible';
|
|
146
|
+
}
|
|
147
|
+
else if (platform === 'darwin') {
|
|
148
|
+
// macOS: /Library/Application Support/Edgible
|
|
149
|
+
return '/Library/Application Support/Edgible';
|
|
150
|
+
}
|
|
151
|
+
else if (platform === 'win32') {
|
|
152
|
+
// Windows: C:\ProgramData\Edgible
|
|
153
|
+
const programData = process.env['ProgramData'] || 'C:\\ProgramData';
|
|
154
|
+
return path.join(programData, 'Edgible');
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
// Fallback for other platforms
|
|
158
|
+
return '/var/lib/edgible';
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get the agent configuration directory path.
|
|
163
|
+
* For CLI: returns user data path + '/agent'
|
|
164
|
+
* For system services: returns system data path + '/agent'
|
|
165
|
+
*
|
|
166
|
+
* @param useSystemPath - If true, use system path; otherwise use user path
|
|
167
|
+
* @returns The agent configuration directory path
|
|
168
|
+
*/
|
|
169
|
+
static getAgentConfigPath(useSystemPath = false) {
|
|
170
|
+
const basePath = useSystemPath ? this.getSystemDataPath() : this.getUserDataPath();
|
|
171
|
+
return path.join(basePath, 'agent');
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get the CLI configuration file path.
|
|
175
|
+
*
|
|
176
|
+
* @returns The CLI config.json file path
|
|
177
|
+
*/
|
|
178
|
+
static getCliConfigPath() {
|
|
179
|
+
const userDataPath = this.getUserDataPath();
|
|
180
|
+
return path.join(userDataPath, 'config.json');
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get the agent configuration file path.
|
|
184
|
+
*
|
|
185
|
+
* @param useSystemPath - If true, use system path; otherwise use user path
|
|
186
|
+
* @returns The agent.config.json file path
|
|
187
|
+
*/
|
|
188
|
+
static getAgentConfigFilePath(useSystemPath = false) {
|
|
189
|
+
const agentConfigPath = this.getAgentConfigPath(useSystemPath);
|
|
190
|
+
return path.join(agentConfigPath, 'agent.config.json');
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get the agent status file path.
|
|
194
|
+
*
|
|
195
|
+
* @param useSystemPath - If true, use system path; otherwise use user path
|
|
196
|
+
* @returns The status.json file path
|
|
197
|
+
*/
|
|
198
|
+
static getAgentStatusPath(useSystemPath = false) {
|
|
199
|
+
const agentConfigPath = this.getAgentConfigPath(useSystemPath);
|
|
200
|
+
return path.join(agentConfigPath, 'status.json');
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Resolve the agent config path based on installation type.
|
|
204
|
+
* For systemd/launchd/windows-service: uses system path
|
|
205
|
+
* For docker/podman: uses system path (mounted in container)
|
|
206
|
+
* Otherwise: uses user path
|
|
207
|
+
*
|
|
208
|
+
* @param installationType - The agent installation type
|
|
209
|
+
* @returns The appropriate agent config path
|
|
210
|
+
*/
|
|
211
|
+
static resolveAgentConfigPath(installationType) {
|
|
212
|
+
const useSystemPath = installationType === 'systemd' ||
|
|
213
|
+
installationType === 'launchd' ||
|
|
214
|
+
installationType === 'windows-service' ||
|
|
215
|
+
installationType === 'docker' ||
|
|
216
|
+
installationType === 'podman';
|
|
217
|
+
return this.getAgentConfigPath(useSystemPath);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Resolve the agent config file path based on installation type.
|
|
221
|
+
*
|
|
222
|
+
* @param installationType - The agent installation type
|
|
223
|
+
* @returns The appropriate agent config file path
|
|
224
|
+
*/
|
|
225
|
+
static resolveAgentConfigFilePath(installationType) {
|
|
226
|
+
const useSystemPath = installationType === 'systemd' ||
|
|
227
|
+
installationType === 'launchd' ||
|
|
228
|
+
installationType === 'windows-service' ||
|
|
229
|
+
installationType === 'docker' ||
|
|
230
|
+
installationType === 'podman';
|
|
231
|
+
return this.getAgentConfigFilePath(useSystemPath);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
exports.PathResolver = PathResolver;
|
|
235
|
+
//# sourceMappingURL=PathResolver.js.map
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.PlatformDetector = void 0;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const util_1 = require("util");
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
41
|
+
class PlatformDetector {
|
|
42
|
+
/**
|
|
43
|
+
* Get the current platform
|
|
44
|
+
*/
|
|
45
|
+
static getPlatform() {
|
|
46
|
+
const platform = os.platform();
|
|
47
|
+
if (platform === 'darwin')
|
|
48
|
+
return 'darwin';
|
|
49
|
+
if (platform === 'win32')
|
|
50
|
+
return 'win32';
|
|
51
|
+
return 'linux';
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Check if running as root/administrator
|
|
55
|
+
*/
|
|
56
|
+
static async isRoot() {
|
|
57
|
+
const platform = this.getPlatform();
|
|
58
|
+
if (platform === 'win32') {
|
|
59
|
+
try {
|
|
60
|
+
// On Windows, try to access a protected directory
|
|
61
|
+
await execAsync('net session >nul 2>&1');
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// On Unix-like systems, check if UID is 0
|
|
70
|
+
return process.getuid !== undefined && process.getuid() === 0;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if systemd is available (Linux)
|
|
75
|
+
*/
|
|
76
|
+
static async hasSystemd() {
|
|
77
|
+
if (this.getPlatform() !== 'linux')
|
|
78
|
+
return false;
|
|
79
|
+
try {
|
|
80
|
+
await execAsync('which systemctl');
|
|
81
|
+
// Check if systemd is running
|
|
82
|
+
const { stdout } = await execAsync('ps -p 1 -o comm=');
|
|
83
|
+
return stdout.trim() === 'systemd';
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Check if launchd is available (macOS)
|
|
91
|
+
*/
|
|
92
|
+
static async hasLaunchd() {
|
|
93
|
+
if (this.getPlatform() !== 'darwin')
|
|
94
|
+
return false;
|
|
95
|
+
try {
|
|
96
|
+
await execAsync('which launchctl');
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check if Docker is available
|
|
105
|
+
*/
|
|
106
|
+
static async hasDocker() {
|
|
107
|
+
try {
|
|
108
|
+
await execAsync('docker --version');
|
|
109
|
+
// Also check if Docker daemon is running
|
|
110
|
+
await execAsync('docker ps');
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check if Podman is available
|
|
119
|
+
*/
|
|
120
|
+
static async hasPodman() {
|
|
121
|
+
try {
|
|
122
|
+
await execAsync('podman --version');
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if Node.js is available
|
|
131
|
+
*/
|
|
132
|
+
static async hasNode() {
|
|
133
|
+
try {
|
|
134
|
+
await execAsync('node --version');
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Get the path to Node.js executable
|
|
143
|
+
*/
|
|
144
|
+
static async getNodePath() {
|
|
145
|
+
const platform = this.getPlatform();
|
|
146
|
+
try {
|
|
147
|
+
const command = platform === 'win32' ? 'where node' : 'which node';
|
|
148
|
+
const { stdout } = await execAsync(command);
|
|
149
|
+
return stdout.trim().split('\n')[0]; // Get first result
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return platform === 'win32' ? 'node.exe' : 'node';
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get all available installation options for the current platform
|
|
157
|
+
*/
|
|
158
|
+
static async getAvailableOptions() {
|
|
159
|
+
const platform = this.getPlatform();
|
|
160
|
+
const isRoot = await this.isRoot();
|
|
161
|
+
const hasSystemd = await this.hasSystemd();
|
|
162
|
+
const hasLaunchd = await this.hasLaunchd();
|
|
163
|
+
const hasDocker = await this.hasDocker();
|
|
164
|
+
const hasPodman = await this.hasPodman();
|
|
165
|
+
const options = [];
|
|
166
|
+
// Linux: systemd option
|
|
167
|
+
if (platform === 'linux') {
|
|
168
|
+
options.push({
|
|
169
|
+
type: 'systemd',
|
|
170
|
+
name: 'System Service (systemd)',
|
|
171
|
+
description: 'Run as a native Linux systemd service',
|
|
172
|
+
requires: ['systemd', 'root privileges'],
|
|
173
|
+
pros: ['Native performance', 'Direct system access', 'Integrated with system logs'],
|
|
174
|
+
cons: ['Requires root privileges', 'Platform-specific'],
|
|
175
|
+
bestFor: 'Production servers, bare metal deployments',
|
|
176
|
+
available: hasSystemd && isRoot,
|
|
177
|
+
requiresRoot: true
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// macOS: launchd option
|
|
181
|
+
if (platform === 'darwin') {
|
|
182
|
+
options.push({
|
|
183
|
+
type: 'launchd',
|
|
184
|
+
name: 'System Service (launchd)',
|
|
185
|
+
description: 'Run as a native macOS launchd service',
|
|
186
|
+
requires: ['launchd', 'root privileges'],
|
|
187
|
+
pros: ['Native macOS integration', 'System-managed lifecycle', 'Integrated logs'],
|
|
188
|
+
cons: ['Requires root privileges', 'macOS-specific'],
|
|
189
|
+
bestFor: 'macOS servers, development machines',
|
|
190
|
+
available: hasLaunchd && isRoot,
|
|
191
|
+
requiresRoot: true
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
// Windows: Windows Service option
|
|
195
|
+
if (platform === 'win32') {
|
|
196
|
+
options.push({
|
|
197
|
+
type: 'windows-service',
|
|
198
|
+
name: 'Windows Service',
|
|
199
|
+
description: 'Run as a native Windows service',
|
|
200
|
+
requires: ['Administrator privileges'],
|
|
201
|
+
pros: ['Native Windows integration', 'System-managed lifecycle', 'Windows Event Log'],
|
|
202
|
+
cons: ['Requires administrator privileges', 'Windows-specific'],
|
|
203
|
+
bestFor: 'Windows servers, production deployments',
|
|
204
|
+
available: isRoot,
|
|
205
|
+
requiresRoot: true
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
// Docker option (all platforms)
|
|
209
|
+
options.push({
|
|
210
|
+
type: 'docker',
|
|
211
|
+
name: 'Docker Container',
|
|
212
|
+
description: 'Run as a Docker container with systemd/launchd wrapper',
|
|
213
|
+
requires: ['Docker', platform !== 'win32' ? 'root privileges' : 'Docker Desktop'],
|
|
214
|
+
pros: ['Isolated environment', 'Easy updates', 'Cross-platform', 'Reproducible'],
|
|
215
|
+
cons: ['Requires Docker daemon', 'Slight performance overhead', 'Needs privileged mode'],
|
|
216
|
+
bestFor: 'Containerized infrastructure, development, CI/CD',
|
|
217
|
+
available: hasDocker && (platform === 'win32' || isRoot),
|
|
218
|
+
requiresRoot: platform !== 'win32'
|
|
219
|
+
});
|
|
220
|
+
// Podman option (all platforms)
|
|
221
|
+
options.push({
|
|
222
|
+
type: 'podman',
|
|
223
|
+
name: 'Podman Container (Rootless)',
|
|
224
|
+
description: 'Run as a rootless Podman container',
|
|
225
|
+
requires: ['Podman'],
|
|
226
|
+
pros: ['Rootless operation', 'Container isolation', 'Docker-compatible', 'No daemon required'],
|
|
227
|
+
cons: ['Requires Podman', 'Some network limitations in rootless mode'],
|
|
228
|
+
bestFor: 'User-space deployments, restricted environments, development',
|
|
229
|
+
available: hasPodman,
|
|
230
|
+
requiresRoot: false
|
|
231
|
+
});
|
|
232
|
+
return options;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get the recommended installation type for the current platform
|
|
236
|
+
*/
|
|
237
|
+
static async getRecommendedType() {
|
|
238
|
+
const options = await this.getAvailableOptions();
|
|
239
|
+
const available = options.filter(opt => opt.available);
|
|
240
|
+
if (available.length === 0) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
// Prefer native options first, then containers
|
|
244
|
+
const platform = this.getPlatform();
|
|
245
|
+
if (platform === 'linux' && available.find(opt => opt.type === 'systemd')) {
|
|
246
|
+
return 'systemd';
|
|
247
|
+
}
|
|
248
|
+
if (platform === 'darwin' && available.find(opt => opt.type === 'launchd')) {
|
|
249
|
+
return 'launchd';
|
|
250
|
+
}
|
|
251
|
+
if (platform === 'win32' && available.find(opt => opt.type === 'windows-service')) {
|
|
252
|
+
return 'windows-service';
|
|
253
|
+
}
|
|
254
|
+
// Fall back to containers
|
|
255
|
+
if (available.find(opt => opt.type === 'docker')) {
|
|
256
|
+
return 'docker';
|
|
257
|
+
}
|
|
258
|
+
if (available.find(opt => opt.type === 'podman')) {
|
|
259
|
+
return 'podman';
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Get installation requirements message for when not running as root
|
|
265
|
+
*/
|
|
266
|
+
static getRootRequirementMessage() {
|
|
267
|
+
const platform = this.getPlatform();
|
|
268
|
+
if (platform === 'win32') {
|
|
269
|
+
return 'Please run this command as Administrator to use native Windows Service or Docker options.';
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
return 'Please run this command with sudo to use native system service or Docker options.';
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
exports.PlatformDetector = PlatformDetector;
|
|
277
|
+
//# sourceMappingURL=PlatformDetector.js.map
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ConsoleLogger = void 0;
|
|
7
|
+
exports.getLogger = getLogger;
|
|
8
|
+
exports.setLogger = setLogger;
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const logger_1 = require("./logger");
|
|
11
|
+
/**
|
|
12
|
+
* Console logger implementation
|
|
13
|
+
* Formats and outputs logs to console with colors and formatting
|
|
14
|
+
*/
|
|
15
|
+
class ConsoleLogger {
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.level = logger_1.LogLevel.INFO;
|
|
18
|
+
this.colorEnabled = true;
|
|
19
|
+
this.plain = false;
|
|
20
|
+
this.level = options.level ?? logger_1.LogLevel.INFO;
|
|
21
|
+
this.colorEnabled = options.colorEnabled ?? true;
|
|
22
|
+
this.plain = options.plain ?? false;
|
|
23
|
+
}
|
|
24
|
+
setLevel(level) {
|
|
25
|
+
this.level = level;
|
|
26
|
+
}
|
|
27
|
+
getLevel() {
|
|
28
|
+
return this.level;
|
|
29
|
+
}
|
|
30
|
+
setColorEnabled(enabled) {
|
|
31
|
+
this.colorEnabled = enabled;
|
|
32
|
+
}
|
|
33
|
+
setPlain(plain) {
|
|
34
|
+
this.plain = plain;
|
|
35
|
+
}
|
|
36
|
+
debug(message, ...args) {
|
|
37
|
+
if (this.shouldLog(logger_1.LogLevel.DEBUG)) {
|
|
38
|
+
this.log(logger_1.LogLevel.DEBUG, message, args);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
info(message, ...args) {
|
|
42
|
+
if (this.shouldLog(logger_1.LogLevel.INFO)) {
|
|
43
|
+
this.log(logger_1.LogLevel.INFO, message, args);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
warn(message, ...args) {
|
|
47
|
+
if (this.shouldLog(logger_1.LogLevel.WARN)) {
|
|
48
|
+
this.log(logger_1.LogLevel.WARN, message, args);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
error(message, ...args) {
|
|
52
|
+
if (this.shouldLog(logger_1.LogLevel.ERROR)) {
|
|
53
|
+
this.log(logger_1.LogLevel.ERROR, message, args);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
shouldLog(level) {
|
|
57
|
+
return level >= this.level;
|
|
58
|
+
}
|
|
59
|
+
log(level, message, args) {
|
|
60
|
+
const entry = {
|
|
61
|
+
timestamp: new Date(),
|
|
62
|
+
level,
|
|
63
|
+
message,
|
|
64
|
+
args,
|
|
65
|
+
};
|
|
66
|
+
if (this.plain) {
|
|
67
|
+
this.logPlain(entry);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.logFormatted(entry);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
logPlain(entry) {
|
|
74
|
+
const levelName = (0, logger_1.getLogLevelName)(entry.level);
|
|
75
|
+
const formatted = `${levelName}: ${entry.message}`;
|
|
76
|
+
if (entry.args.length > 0) {
|
|
77
|
+
console.log(formatted, ...entry.args);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
console.log(formatted);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
logFormatted(entry) {
|
|
84
|
+
const prefix = this.getPrefix(entry.level);
|
|
85
|
+
if (entry.args.length > 0) {
|
|
86
|
+
console.log(prefix, entry.message, ...entry.args);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.log(prefix, entry.message);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
getPrefix(level) {
|
|
93
|
+
if (!this.colorEnabled) {
|
|
94
|
+
return `[${(0, logger_1.getLogLevelName)(level)}]`;
|
|
95
|
+
}
|
|
96
|
+
switch (level) {
|
|
97
|
+
case logger_1.LogLevel.DEBUG:
|
|
98
|
+
return chalk_1.default.gray('[DEBUG]');
|
|
99
|
+
case logger_1.LogLevel.INFO:
|
|
100
|
+
return chalk_1.default.blue('[INFO]');
|
|
101
|
+
case logger_1.LogLevel.WARN:
|
|
102
|
+
return chalk_1.default.yellow('[WARN]');
|
|
103
|
+
case logger_1.LogLevel.ERROR:
|
|
104
|
+
return chalk_1.default.red('[ERROR]');
|
|
105
|
+
default:
|
|
106
|
+
return `[${(0, logger_1.getLogLevelName)(level)}]`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.ConsoleLogger = ConsoleLogger;
|
|
111
|
+
/**
|
|
112
|
+
* Default logger instance (can be replaced for testing)
|
|
113
|
+
*/
|
|
114
|
+
let defaultLogger = null;
|
|
115
|
+
/**
|
|
116
|
+
* Get or create default logger instance
|
|
117
|
+
*/
|
|
118
|
+
function getLogger() {
|
|
119
|
+
if (!defaultLogger) {
|
|
120
|
+
defaultLogger = new ConsoleLogger();
|
|
121
|
+
}
|
|
122
|
+
return defaultLogger;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Set default logger instance (useful for testing)
|
|
126
|
+
*/
|
|
127
|
+
function setLogger(logger) {
|
|
128
|
+
defaultLogger = logger;
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=console-logger.js.map
|