@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,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Example of a migrated command using all the new infrastructure
|
|
4
|
+
* This demonstrates how to use:
|
|
5
|
+
* - Dependency injection
|
|
6
|
+
* - Logger abstraction
|
|
7
|
+
* - Validation with Zod
|
|
8
|
+
* - Command wrapper
|
|
9
|
+
* - Shared utilities
|
|
10
|
+
* - Proper TypeScript types
|
|
11
|
+
*
|
|
12
|
+
* This is a reference implementation for migrating other commands
|
|
13
|
+
*/
|
|
14
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
15
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
|
+
};
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.setupExampleGatewayCreateCommand = setupExampleGatewayCreateCommand;
|
|
19
|
+
const container_1 = require("../../di/container");
|
|
20
|
+
const types_1 = require("../../di/types");
|
|
21
|
+
const command_wrapper_1 = require("../base/command-wrapper");
|
|
22
|
+
const validator_1 = require("../../validation/validator");
|
|
23
|
+
const schemas_1 = require("../../validation/schemas");
|
|
24
|
+
const gateway_prompt_1 = require("../utils/gateway-prompt");
|
|
25
|
+
const output_formatter_1 = require("../utils/output-formatter");
|
|
26
|
+
const config_validator_1 = require("../utils/config-validator");
|
|
27
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
28
|
+
/**
|
|
29
|
+
* Example: Migrated gateway create command
|
|
30
|
+
* This shows the pattern for all command migrations
|
|
31
|
+
*/
|
|
32
|
+
function setupExampleGatewayCreateCommand(program) {
|
|
33
|
+
const gatewayCommand = program
|
|
34
|
+
.command('gateway')
|
|
35
|
+
.description('Manage gateways')
|
|
36
|
+
.alias('gw');
|
|
37
|
+
gatewayCommand
|
|
38
|
+
.command('create')
|
|
39
|
+
.description('Create a new gateway device and EC2 instance')
|
|
40
|
+
.option('-n, --name <name>', 'Gateway name')
|
|
41
|
+
.option('-d, --description <description>', 'Gateway description')
|
|
42
|
+
.option('-p, --profile <profile>', 'AWS profile to use')
|
|
43
|
+
.option('-r, --region <region>', 'AWS region')
|
|
44
|
+
.option('-t, --instance-type <type>', 'EC2 instance type', 't3.micro')
|
|
45
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
46
|
+
// Get dependencies from container
|
|
47
|
+
const container = (0, container_1.getContainer)();
|
|
48
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
49
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
50
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
51
|
+
// Validate configuration
|
|
52
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
53
|
+
requireAuth: true,
|
|
54
|
+
requireOrganization: true,
|
|
55
|
+
});
|
|
56
|
+
// Validate and parse options using Zod
|
|
57
|
+
const validatedOptions = (0, validator_1.validateOptions)(schemas_1.createGatewayRequestSchema, {
|
|
58
|
+
name: options.name,
|
|
59
|
+
description: options.description,
|
|
60
|
+
awsProfile: options.profile,
|
|
61
|
+
region: options.region,
|
|
62
|
+
instanceType: options.instanceType,
|
|
63
|
+
});
|
|
64
|
+
// Log command execution
|
|
65
|
+
logger.info('Creating gateway', { name: validatedOptions.name });
|
|
66
|
+
// Use the service
|
|
67
|
+
const result = await gatewayService.createGateway({
|
|
68
|
+
name: validatedOptions.name,
|
|
69
|
+
description: validatedOptions.description,
|
|
70
|
+
awsProfile: validatedOptions.awsProfile,
|
|
71
|
+
region: validatedOptions.region,
|
|
72
|
+
instanceType: validatedOptions.instanceType,
|
|
73
|
+
});
|
|
74
|
+
// Format output
|
|
75
|
+
console.log((0, output_formatter_1.formatSuccess)('Gateway created successfully!'));
|
|
76
|
+
console.log(chalk_1.default.blue('\n📋 Gateway Details:'));
|
|
77
|
+
console.log((0, output_formatter_1.formatGateway)({
|
|
78
|
+
device: result.gateway,
|
|
79
|
+
ec2Instance: result.ec2Instance,
|
|
80
|
+
}));
|
|
81
|
+
logger.debug('Gateway creation completed', { gatewayId: result.gateway.id });
|
|
82
|
+
}, {
|
|
83
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
84
|
+
requireAuth: true,
|
|
85
|
+
requireOrganization: true,
|
|
86
|
+
}));
|
|
87
|
+
/**
|
|
88
|
+
* Example: Migrated gateway list command
|
|
89
|
+
*/
|
|
90
|
+
gatewayCommand
|
|
91
|
+
.command('list')
|
|
92
|
+
.description('List all gateway devices')
|
|
93
|
+
.option('--json', 'Output as JSON')
|
|
94
|
+
.alias('ls')
|
|
95
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
96
|
+
const container = (0, container_1.getContainer)();
|
|
97
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
98
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
99
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
100
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
101
|
+
requireAuth: true,
|
|
102
|
+
requireOrganization: true,
|
|
103
|
+
});
|
|
104
|
+
logger.debug('Listing gateways');
|
|
105
|
+
const response = await gatewayService.listGateways();
|
|
106
|
+
if (options.json) {
|
|
107
|
+
console.log(JSON.stringify({
|
|
108
|
+
gateways: response.gateways.map((gateway) => ({
|
|
109
|
+
id: gateway.device.id,
|
|
110
|
+
name: gateway.device.name,
|
|
111
|
+
description: gateway.device.description,
|
|
112
|
+
ec2Instance: gateway.ec2Instance?.instanceId,
|
|
113
|
+
publicIp: gateway.ec2Instance?.publicIp,
|
|
114
|
+
privateIp: gateway.ec2Instance?.privateIp,
|
|
115
|
+
region: gateway.ec2Instance?.region,
|
|
116
|
+
state: gateway.ec2Instance?.state,
|
|
117
|
+
createdAt: gateway.device.createdAt,
|
|
118
|
+
})),
|
|
119
|
+
}, null, 2));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (response.gateways.length === 0) {
|
|
123
|
+
console.log(chalk_1.default.yellow('⚠ No gateways found'));
|
|
124
|
+
console.log(chalk_1.default.gray('Use "edgible gateway create" to create a gateway'));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
console.log(chalk_1.default.blue.bold('🌐 Gateway Devices:\n'));
|
|
128
|
+
response.gateways.forEach((gateway) => {
|
|
129
|
+
console.log((0, output_formatter_1.formatGateway)(gateway));
|
|
130
|
+
});
|
|
131
|
+
}, {
|
|
132
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
133
|
+
requireAuth: true,
|
|
134
|
+
requireOrganization: true,
|
|
135
|
+
}));
|
|
136
|
+
/**
|
|
137
|
+
* Example: Migrated gateway delete command using shared utilities
|
|
138
|
+
*/
|
|
139
|
+
gatewayCommand
|
|
140
|
+
.command('delete')
|
|
141
|
+
.description('Delete a gateway device and EC2 instance')
|
|
142
|
+
.option('-i, --id <id>', 'Gateway ID to delete')
|
|
143
|
+
.option('-f, --force', 'Force delete even if applications exist')
|
|
144
|
+
.alias('rm')
|
|
145
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
146
|
+
const container = (0, container_1.getContainer)();
|
|
147
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
148
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
149
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
150
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
151
|
+
requireAuth: true,
|
|
152
|
+
requireOrganization: true,
|
|
153
|
+
});
|
|
154
|
+
// Use shared utility to get gateway ID
|
|
155
|
+
const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
|
|
156
|
+
if (!gatewayId) {
|
|
157
|
+
throw new Error('Gateway ID is required');
|
|
158
|
+
}
|
|
159
|
+
logger.info('Deleting gateway', { gatewayId });
|
|
160
|
+
await gatewayService.deleteGateway(gatewayId, options.force || false);
|
|
161
|
+
console.log((0, output_formatter_1.formatSuccess)('Gateway deleted successfully!'));
|
|
162
|
+
}, {
|
|
163
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
164
|
+
requireAuth: true,
|
|
165
|
+
requireOrganization: true,
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Migration checklist:
|
|
170
|
+
*
|
|
171
|
+
* ✅ Use DI container to get services
|
|
172
|
+
* ✅ Use logger instead of console.log
|
|
173
|
+
* ✅ Validate inputs with Zod schemas
|
|
174
|
+
* ✅ Use wrapCommand for error handling
|
|
175
|
+
* ✅ Use shared utilities for common operations
|
|
176
|
+
* ✅ Use proper TypeScript types (no any)
|
|
177
|
+
* ✅ Validate configuration before execution
|
|
178
|
+
* ✅ Format output consistently
|
|
179
|
+
*/
|
|
180
|
+
//# sourceMappingURL=migrated-command-example.js.map
|
|
@@ -0,0 +1,494 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.setupGatewayCommands = setupGatewayCommands;
|
|
40
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
41
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
const command_wrapper_1 = require("./base/command-wrapper");
|
|
44
|
+
const container_1 = require("../di/container");
|
|
45
|
+
const types_1 = require("../di/types");
|
|
46
|
+
const config_validator_1 = require("./utils/config-validator");
|
|
47
|
+
const output_formatter_1 = require("./utils/output-formatter");
|
|
48
|
+
const gateway_prompt_1 = require("./utils/gateway-prompt");
|
|
49
|
+
/**
|
|
50
|
+
* Gateway command group
|
|
51
|
+
*/
|
|
52
|
+
function setupGatewayCommands(program) {
|
|
53
|
+
const gatewayCommand = program
|
|
54
|
+
.command('gateway')
|
|
55
|
+
.description('Manage gateways')
|
|
56
|
+
.alias('gw');
|
|
57
|
+
gatewayCommand
|
|
58
|
+
.command('create')
|
|
59
|
+
.description('Create a new gateway device and EC2 instance')
|
|
60
|
+
.addHelpText('after', `
|
|
61
|
+
Examples:
|
|
62
|
+
$ edgible gateway create --name mygateway --region us-east-1
|
|
63
|
+
$ edgible gateway create --name mygateway --profile default --instance-type t3.micro
|
|
64
|
+
`)
|
|
65
|
+
.option('-n, --name <name>', 'Gateway name')
|
|
66
|
+
.option('-d, --description <description>', 'Gateway description')
|
|
67
|
+
.option('-p, --profile <profile>', 'AWS profile to use')
|
|
68
|
+
.option('-r, --region <region>', 'AWS region')
|
|
69
|
+
.option('-t, --instance-type <type>', 'EC2 instance type', 't3.micro')
|
|
70
|
+
.alias('new')
|
|
71
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
72
|
+
const container = (0, container_1.getContainer)();
|
|
73
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
74
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
75
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
76
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
77
|
+
requireAuth: true,
|
|
78
|
+
requireOrganization: true,
|
|
79
|
+
});
|
|
80
|
+
let gatewayName = options.name;
|
|
81
|
+
let description = options.description;
|
|
82
|
+
let awsProfile = options.profile;
|
|
83
|
+
let region = options.region;
|
|
84
|
+
let instanceType = options.instanceType || 't3.micro';
|
|
85
|
+
// If not provided via options, prompt for input
|
|
86
|
+
if (!gatewayName) {
|
|
87
|
+
const nameAnswer = await inquirer_1.default.prompt([
|
|
88
|
+
{
|
|
89
|
+
type: 'input',
|
|
90
|
+
name: 'name',
|
|
91
|
+
message: 'Enter gateway name:',
|
|
92
|
+
validate: (input) => {
|
|
93
|
+
if (!input.trim()) {
|
|
94
|
+
return 'Gateway name is required';
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
]);
|
|
100
|
+
gatewayName = nameAnswer.name.trim();
|
|
101
|
+
}
|
|
102
|
+
if (!description) {
|
|
103
|
+
const descAnswer = await inquirer_1.default.prompt([
|
|
104
|
+
{
|
|
105
|
+
type: 'input',
|
|
106
|
+
name: 'description',
|
|
107
|
+
message: 'Enter gateway description (optional):',
|
|
108
|
+
default: `Gateway: ${gatewayName}`,
|
|
109
|
+
},
|
|
110
|
+
]);
|
|
111
|
+
description = descAnswer.description.trim();
|
|
112
|
+
}
|
|
113
|
+
if (!awsProfile) {
|
|
114
|
+
// Check available AWS profiles
|
|
115
|
+
const { AWSService } = await Promise.resolve().then(() => __importStar(require('../services/aws')));
|
|
116
|
+
const awsService = new AWSService();
|
|
117
|
+
const awsCheck = await awsService.checkAWSCLI();
|
|
118
|
+
if (!awsCheck.available) {
|
|
119
|
+
logger.error('AWS CLI is not installed or not available');
|
|
120
|
+
console.log(chalk_1.default.red('✗ AWS CLI is not installed or not available'));
|
|
121
|
+
console.log(chalk_1.default.gray('Please install AWS CLI and configure credentials'));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const profileChoices = awsCheck.profiles.map((profile) => ({
|
|
125
|
+
name: profile,
|
|
126
|
+
value: profile,
|
|
127
|
+
}));
|
|
128
|
+
if (profileChoices.length === 0) {
|
|
129
|
+
logger.error('No AWS profiles found');
|
|
130
|
+
console.log(chalk_1.default.red('✗ No AWS profiles found'));
|
|
131
|
+
console.log(chalk_1.default.gray('Please run "aws configure" to set up your AWS credentials'));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const profileAnswer = await inquirer_1.default.prompt([
|
|
135
|
+
{
|
|
136
|
+
type: 'list',
|
|
137
|
+
name: 'profile',
|
|
138
|
+
message: 'Select AWS profile:',
|
|
139
|
+
choices: profileChoices,
|
|
140
|
+
},
|
|
141
|
+
]);
|
|
142
|
+
awsProfile = profileAnswer.profile;
|
|
143
|
+
}
|
|
144
|
+
if (!region) {
|
|
145
|
+
const regionAnswer = await inquirer_1.default.prompt([
|
|
146
|
+
{
|
|
147
|
+
type: 'input',
|
|
148
|
+
name: 'region',
|
|
149
|
+
message: 'Enter AWS region:',
|
|
150
|
+
default: 'us-east-1',
|
|
151
|
+
validate: (input) => {
|
|
152
|
+
if (!input.trim()) {
|
|
153
|
+
return 'AWS region is required';
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
]);
|
|
159
|
+
region = regionAnswer.region.trim();
|
|
160
|
+
}
|
|
161
|
+
logger.info('Creating gateway', { name: gatewayName, region, instanceType });
|
|
162
|
+
const createConfig = {
|
|
163
|
+
name: gatewayName,
|
|
164
|
+
};
|
|
165
|
+
if (description && description.trim())
|
|
166
|
+
createConfig.description = description;
|
|
167
|
+
if (awsProfile && awsProfile.trim())
|
|
168
|
+
createConfig.awsProfile = awsProfile;
|
|
169
|
+
if (region && region.trim())
|
|
170
|
+
createConfig.region = region;
|
|
171
|
+
if (instanceType && instanceType.trim())
|
|
172
|
+
createConfig.instanceType = instanceType;
|
|
173
|
+
const result = await gatewayService.createGateway(createConfig);
|
|
174
|
+
console.log(chalk_1.default.green('\n✓ Gateway created successfully!'));
|
|
175
|
+
console.log(chalk_1.default.blue('\n📋 Gateway Details:'));
|
|
176
|
+
console.log((0, output_formatter_1.formatGateway)({
|
|
177
|
+
device: result.gateway,
|
|
178
|
+
ec2Instance: result.ec2Instance,
|
|
179
|
+
}));
|
|
180
|
+
}, {
|
|
181
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
182
|
+
requireAuth: true,
|
|
183
|
+
requireOrganization: true,
|
|
184
|
+
}));
|
|
185
|
+
gatewayCommand
|
|
186
|
+
.command('list')
|
|
187
|
+
.description('List all gateway devices')
|
|
188
|
+
.option('--json', 'Output as JSON')
|
|
189
|
+
.alias('ls')
|
|
190
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
191
|
+
const container = (0, container_1.getContainer)();
|
|
192
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
193
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
194
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
195
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
196
|
+
requireAuth: true,
|
|
197
|
+
requireOrganization: true,
|
|
198
|
+
});
|
|
199
|
+
logger.debug('Listing gateways');
|
|
200
|
+
const response = await gatewayService.listGateways();
|
|
201
|
+
if (response.gateways.length === 0) {
|
|
202
|
+
console.log(chalk_1.default.yellow('⚠ No gateways found'));
|
|
203
|
+
console.log(chalk_1.default.gray('Use "edgible gateway create" to create a gateway'));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (options.json) {
|
|
207
|
+
console.log(JSON.stringify({
|
|
208
|
+
gateways: response.gateways.map((gateway) => ({
|
|
209
|
+
id: gateway.device.id,
|
|
210
|
+
name: gateway.device.name,
|
|
211
|
+
description: gateway.device.description,
|
|
212
|
+
ec2Instance: gateway.ec2Instance?.instanceId,
|
|
213
|
+
publicIp: gateway.ec2Instance?.publicIp,
|
|
214
|
+
privateIp: gateway.ec2Instance?.privateIp,
|
|
215
|
+
region: gateway.ec2Instance?.region,
|
|
216
|
+
state: gateway.ec2Instance?.state,
|
|
217
|
+
createdAt: gateway.device.createdAt,
|
|
218
|
+
})),
|
|
219
|
+
}, null, 2));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
console.log((0, output_formatter_1.formatList)(response.gateways, (gateway) => (0, output_formatter_1.formatGateway)(gateway), '🌐 Gateway Devices:', 'No gateways found'));
|
|
223
|
+
}, {
|
|
224
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
225
|
+
requireAuth: true,
|
|
226
|
+
requireOrganization: true,
|
|
227
|
+
}));
|
|
228
|
+
gatewayCommand
|
|
229
|
+
.command('get')
|
|
230
|
+
.description('Get status of a specific gateway')
|
|
231
|
+
.option('-i, --id <id>', 'Gateway ID')
|
|
232
|
+
.alias('status')
|
|
233
|
+
.alias('info')
|
|
234
|
+
.action(async (options) => {
|
|
235
|
+
console.log(chalk_1.default.yellow('Not yet implemented.'));
|
|
236
|
+
});
|
|
237
|
+
gatewayCommand
|
|
238
|
+
.command('update')
|
|
239
|
+
.description('Update an existing gateway')
|
|
240
|
+
.option('-i, --id <id>', 'Gateway ID')
|
|
241
|
+
.action(async (options) => {
|
|
242
|
+
console.log(chalk_1.default.yellow('Not yet implemented.'));
|
|
243
|
+
});
|
|
244
|
+
gatewayCommand
|
|
245
|
+
.command('delete')
|
|
246
|
+
.description('Delete a gateway device and EC2 instance')
|
|
247
|
+
.option('-i, --id <id>', 'Gateway ID to delete')
|
|
248
|
+
.option('-f, --force', 'Force delete even if applications exist')
|
|
249
|
+
.alias('rm')
|
|
250
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
251
|
+
const container = (0, container_1.getContainer)();
|
|
252
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
253
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
254
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
255
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
256
|
+
requireAuth: true,
|
|
257
|
+
requireOrganization: true,
|
|
258
|
+
});
|
|
259
|
+
const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
|
|
260
|
+
if (!gatewayId) {
|
|
261
|
+
throw new Error('Gateway ID is required');
|
|
262
|
+
}
|
|
263
|
+
// Confirm deletion
|
|
264
|
+
const confirm = await inquirer_1.default.prompt([
|
|
265
|
+
{
|
|
266
|
+
type: 'confirm',
|
|
267
|
+
name: 'confirm',
|
|
268
|
+
message: `Are you sure you want to delete gateway ${gatewayId}?`,
|
|
269
|
+
default: false,
|
|
270
|
+
},
|
|
271
|
+
]);
|
|
272
|
+
if (!confirm.confirm) {
|
|
273
|
+
logger.info('Gateway deletion cancelled');
|
|
274
|
+
console.log(chalk_1.default.gray('Deletion cancelled'));
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
logger.info('Deleting gateway', { gatewayId, force: options.force || false });
|
|
278
|
+
await gatewayService.deleteGateway(gatewayId, options.force || false);
|
|
279
|
+
console.log(chalk_1.default.green('✓ Gateway deleted successfully!'));
|
|
280
|
+
}, {
|
|
281
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
282
|
+
requireAuth: true,
|
|
283
|
+
requireOrganization: true,
|
|
284
|
+
}));
|
|
285
|
+
gatewayCommand
|
|
286
|
+
.command('resync')
|
|
287
|
+
.description('Resync agent code on a gateway')
|
|
288
|
+
.option('-i, --id <id>', 'Gateway ID to resync')
|
|
289
|
+
.option('-v, --version <version>', 'Agent version to deploy')
|
|
290
|
+
.option('--local', 'Upload agent from local dist directory instead of downloading from S3')
|
|
291
|
+
.option('--install-from-local', 'Upload agent from local dist directory instead of downloading from S3')
|
|
292
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
293
|
+
// Map --local to installFromLocal for backward compatibility
|
|
294
|
+
const installFromLocal = options.local || options.installFromLocal;
|
|
295
|
+
const container = (0, container_1.getContainer)();
|
|
296
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
297
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
298
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
299
|
+
const edgibleService = container.get(types_1.TYPES.EdgibleService);
|
|
300
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
301
|
+
requireAuth: true,
|
|
302
|
+
requireOrganization: true,
|
|
303
|
+
});
|
|
304
|
+
const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
|
|
305
|
+
if (!gatewayId) {
|
|
306
|
+
throw new Error('Gateway ID is required');
|
|
307
|
+
}
|
|
308
|
+
logger.info('Resyncing agent on gateway', { gatewayId, version: options.version, installFromLocal });
|
|
309
|
+
// TODO: Extract resyncGatewayAgent to GatewaySshService
|
|
310
|
+
const result = await edgibleService.resyncGatewayAgent(gatewayId, options.version, installFromLocal);
|
|
311
|
+
console.log(chalk_1.default.green('\n✓ Agent resynced successfully!'));
|
|
312
|
+
console.log(chalk_1.default.blue('\n📋 Resync Details:'));
|
|
313
|
+
console.log(chalk_1.default.white(` Gateway ID: ${gatewayId}`));
|
|
314
|
+
console.log(chalk_1.default.white(` Agent Version: ${result.agentVersion}`));
|
|
315
|
+
console.log(chalk_1.default.white(` Sync Time: ${new Date(result.syncTimestamp).toLocaleString()}`));
|
|
316
|
+
}, {
|
|
317
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
318
|
+
requireAuth: true,
|
|
319
|
+
requireOrganization: true,
|
|
320
|
+
}));
|
|
321
|
+
gatewayCommand
|
|
322
|
+
.command('logs')
|
|
323
|
+
.description('Retrieve agent logs from a gateway')
|
|
324
|
+
.option('-i, --id <id>', 'Gateway ID to get logs from')
|
|
325
|
+
.option('-n, --lines <number>', 'Number of log lines', '50')
|
|
326
|
+
.option('-f, --follow', 'Follow logs in real-time')
|
|
327
|
+
.option('-l, --level <level>', 'Log level filter', 'all')
|
|
328
|
+
.option('-c, --comprehensive', 'Show comprehensive diagnostics (status, system info, WireGuard, Caddy, etc.)')
|
|
329
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
330
|
+
const container = (0, container_1.getContainer)();
|
|
331
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
332
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
333
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
334
|
+
const edgibleService = container.get(types_1.TYPES.EdgibleService);
|
|
335
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
336
|
+
requireAuth: true,
|
|
337
|
+
requireOrganization: true,
|
|
338
|
+
});
|
|
339
|
+
const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
|
|
340
|
+
if (!gatewayId) {
|
|
341
|
+
throw new Error('Gateway ID is required');
|
|
342
|
+
}
|
|
343
|
+
const lines = parseInt(options.lines || '50') || 50;
|
|
344
|
+
const follow = options.follow || false;
|
|
345
|
+
const level = options.level || 'all';
|
|
346
|
+
const comprehensive = options.comprehensive || false;
|
|
347
|
+
logger.info('Retrieving gateway logs', {
|
|
348
|
+
gatewayId,
|
|
349
|
+
lines: follow ? undefined : lines,
|
|
350
|
+
follow,
|
|
351
|
+
level,
|
|
352
|
+
comprehensive,
|
|
353
|
+
});
|
|
354
|
+
// TODO: Extract getGatewayLogs to GatewayDiagnosticsService
|
|
355
|
+
const result = await edgibleService.getGatewayLogs(gatewayId, {
|
|
356
|
+
lines: follow ? undefined : lines,
|
|
357
|
+
follow: follow,
|
|
358
|
+
level: level,
|
|
359
|
+
comprehensive: comprehensive,
|
|
360
|
+
});
|
|
361
|
+
if (result.success) {
|
|
362
|
+
console.log(result.logs);
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
logger.error('Failed to retrieve logs');
|
|
366
|
+
console.log(chalk_1.default.red('✗ Failed to retrieve logs'));
|
|
367
|
+
}
|
|
368
|
+
}, {
|
|
369
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
370
|
+
requireAuth: true,
|
|
371
|
+
requireOrganization: true,
|
|
372
|
+
}));
|
|
373
|
+
gatewayCommand
|
|
374
|
+
.command('ssh')
|
|
375
|
+
.description('Connect to a gateway via SSH (interactive shell)')
|
|
376
|
+
.option('-i, --id <id>', 'Gateway ID to connect to')
|
|
377
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
378
|
+
const container = (0, container_1.getContainer)();
|
|
379
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
380
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
381
|
+
const gatewayRepository = container.get(types_1.TYPES.GatewayRepository);
|
|
382
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
383
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
384
|
+
requireAuth: true,
|
|
385
|
+
requireOrganization: true,
|
|
386
|
+
});
|
|
387
|
+
const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
|
|
388
|
+
if (!gatewayId) {
|
|
389
|
+
throw new Error('Gateway ID is required');
|
|
390
|
+
}
|
|
391
|
+
const gatewayInfo = gatewayRepository.getGateway(gatewayId);
|
|
392
|
+
if (!gatewayInfo) {
|
|
393
|
+
throw new Error('Gateway not found in local configuration');
|
|
394
|
+
}
|
|
395
|
+
logger.info('Connecting to gateway via SSH', { gatewayId, publicIp: gatewayInfo.publicIp });
|
|
396
|
+
console.log(chalk_1.default.blue(`\nConnecting to gateway: ${gatewayId}`));
|
|
397
|
+
console.log(chalk_1.default.gray(`Public IP: ${gatewayInfo.publicIp}`));
|
|
398
|
+
console.log(chalk_1.default.gray(`Region: ${gatewayInfo.region}`));
|
|
399
|
+
console.log(chalk_1.default.yellow('\nOpening SSH connection...\n'));
|
|
400
|
+
// Get SSH key path
|
|
401
|
+
const { AWSService } = await Promise.resolve().then(() => __importStar(require('../services/aws')));
|
|
402
|
+
const awsService = new AWSService(configRepository.getAWSProfile(), gatewayInfo.region);
|
|
403
|
+
// Wait for instance to be ready
|
|
404
|
+
console.log(chalk_1.default.gray('Waiting for instance to be ready...'));
|
|
405
|
+
const isReady = await awsService.waitForSSHReady(gatewayInfo.ec2InstanceId);
|
|
406
|
+
if (!isReady) {
|
|
407
|
+
logger.error('Instance is not ready for SSH connections', { instanceId: gatewayInfo.ec2InstanceId });
|
|
408
|
+
console.log(chalk_1.default.red('✗ Instance is not ready for SSH connections'));
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
// Build SSH command
|
|
412
|
+
const sshKeyPath = gatewayInfo.keyPath;
|
|
413
|
+
const sshCommand = `ssh -i "${sshKeyPath}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ec2-user@${gatewayInfo.publicIp}`;
|
|
414
|
+
console.log(chalk_1.default.green('✓ Opening interactive SSH session...'));
|
|
415
|
+
console.log(chalk_1.default.gray('─'.repeat(80)));
|
|
416
|
+
console.log(chalk_1.default.gray('Tip: Type "exit" to disconnect from the gateway\n'));
|
|
417
|
+
// Execute SSH using child_process
|
|
418
|
+
const sshProcess = (0, child_process_1.spawn)('sh', ['-c', sshCommand], {
|
|
419
|
+
stdio: 'inherit',
|
|
420
|
+
shell: false,
|
|
421
|
+
});
|
|
422
|
+
sshProcess.on('error', (error) => {
|
|
423
|
+
logger.error('SSH connection error', error);
|
|
424
|
+
console.error(chalk_1.default.red('✗ SSH connection error:'), error.message);
|
|
425
|
+
console.log(chalk_1.default.yellow('\nMake sure SSH is installed and the key file has correct permissions (chmod 600)'));
|
|
426
|
+
throw error;
|
|
427
|
+
});
|
|
428
|
+
sshProcess.on('exit', (code) => {
|
|
429
|
+
if (code === 0) {
|
|
430
|
+
logger.debug('SSH session ended normally');
|
|
431
|
+
console.log(chalk_1.default.gray('\nSSH session ended'));
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
logger.warn('SSH session ended with non-zero code', { code });
|
|
435
|
+
console.log(chalk_1.default.yellow(`\nSSH session ended with code: ${code}`));
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
}, {
|
|
439
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
440
|
+
requireAuth: true,
|
|
441
|
+
requireOrganization: true,
|
|
442
|
+
}));
|
|
443
|
+
gatewayCommand
|
|
444
|
+
.command('wipe-logs')
|
|
445
|
+
.description('Clear agent log file on a gateway')
|
|
446
|
+
.option('-i, --id <id>', 'Gateway ID to wipe logs for')
|
|
447
|
+
.action((0, command_wrapper_1.wrapCommand)(async (options) => {
|
|
448
|
+
const container = (0, container_1.getContainer)();
|
|
449
|
+
const logger = container.get(types_1.TYPES.Logger);
|
|
450
|
+
const configRepository = container.get(types_1.TYPES.ConfigRepository);
|
|
451
|
+
const gatewayService = container.get(types_1.TYPES.GatewayService);
|
|
452
|
+
const edgibleService = container.get(types_1.TYPES.EdgibleService);
|
|
453
|
+
(0, config_validator_1.validateConfig)(configRepository, {
|
|
454
|
+
requireAuth: true,
|
|
455
|
+
requireOrganization: true,
|
|
456
|
+
});
|
|
457
|
+
const gatewayId = await (0, gateway_prompt_1.getGatewayId)(gatewayService, options.id, { required: true });
|
|
458
|
+
if (!gatewayId) {
|
|
459
|
+
throw new Error('Gateway ID is required');
|
|
460
|
+
}
|
|
461
|
+
logger.info('Wiping gateway logs', { gatewayId });
|
|
462
|
+
// Confirm action
|
|
463
|
+
const confirm = await inquirer_1.default.prompt([
|
|
464
|
+
{
|
|
465
|
+
type: 'confirm',
|
|
466
|
+
name: 'confirm',
|
|
467
|
+
message: `Are you sure you want to clear all logs on gateway ${gatewayId}?`,
|
|
468
|
+
default: false,
|
|
469
|
+
},
|
|
470
|
+
]);
|
|
471
|
+
if (!confirm.confirm) {
|
|
472
|
+
logger.info('Log wipe cancelled');
|
|
473
|
+
console.log(chalk_1.default.gray('Log wipe cancelled'));
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
// Get gateway logs and wipe them
|
|
477
|
+
const result = await edgibleService.wipeGatewayLogs(gatewayId);
|
|
478
|
+
if (result.success) {
|
|
479
|
+
console.log(chalk_1.default.green('✓ Gateway logs cleared successfully!'));
|
|
480
|
+
console.log(chalk_1.default.gray(` Log file: ${result.logFile || 'agent.log'}`));
|
|
481
|
+
}
|
|
482
|
+
else {
|
|
483
|
+
console.log(chalk_1.default.red('✗ Failed to clear logs'));
|
|
484
|
+
if (result.message) {
|
|
485
|
+
console.log(chalk_1.default.yellow(result.message));
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}, {
|
|
489
|
+
configRepository: (0, container_1.getContainer)().get(types_1.TYPES.ConfigRepository),
|
|
490
|
+
requireAuth: true,
|
|
491
|
+
requireOrganization: true,
|
|
492
|
+
}));
|
|
493
|
+
}
|
|
494
|
+
//# sourceMappingURL=gateway.js.map
|