@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,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration validation utilities
|
|
4
|
+
* Centralizes config validation logic
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.validateConfig = validateConfig;
|
|
8
|
+
exports.requireOrganizationId = requireOrganizationId;
|
|
9
|
+
exports.requireDeviceId = requireDeviceId;
|
|
10
|
+
exports.requireEmail = requireEmail;
|
|
11
|
+
const errors_1 = require("../../utils/errors");
|
|
12
|
+
/**
|
|
13
|
+
* Validate configuration based on requirements
|
|
14
|
+
*/
|
|
15
|
+
function validateConfig(configRepository, options = {}) {
|
|
16
|
+
const { requireAuth = false, requireOrganization = false, requireDeviceId = false, requireEmail = false, requireAwsProfile = false, } = options;
|
|
17
|
+
const config = configRepository.getConfig();
|
|
18
|
+
if (requireAuth) {
|
|
19
|
+
const hasTokens = !!(config.accessToken || config.idToken);
|
|
20
|
+
const hasDeviceCreds = !!(config.deviceId && config.devicePassword);
|
|
21
|
+
if (!hasTokens && !hasDeviceCreds) {
|
|
22
|
+
throw new errors_1.ConfigError('Not authenticated. Please run "edgible login" first.');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (requireOrganization) {
|
|
26
|
+
if (!config.organizationId) {
|
|
27
|
+
throw new errors_1.ConfigError('No organization found. Please login first.');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (requireDeviceId) {
|
|
31
|
+
if (!config.deviceId) {
|
|
32
|
+
throw new errors_1.ConfigError('No device ID found. Please login first.');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (requireEmail) {
|
|
36
|
+
if (!config.email) {
|
|
37
|
+
throw new errors_1.ConfigError('No email found in configuration.');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (requireAwsProfile) {
|
|
41
|
+
if (!config.awsProfile) {
|
|
42
|
+
throw new errors_1.ConfigError('No AWS profile configured. Please set AWS profile first.');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get organization ID or throw error
|
|
48
|
+
*/
|
|
49
|
+
function requireOrganizationId(configRepository) {
|
|
50
|
+
const config = configRepository.getConfig();
|
|
51
|
+
if (!config.organizationId) {
|
|
52
|
+
throw new errors_1.ConfigError('No organization ID found. Please login first.');
|
|
53
|
+
}
|
|
54
|
+
return config.organizationId;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get device ID or throw error
|
|
58
|
+
*/
|
|
59
|
+
function requireDeviceId(configRepository) {
|
|
60
|
+
const config = configRepository.getConfig();
|
|
61
|
+
if (!config.deviceId) {
|
|
62
|
+
throw new errors_1.ConfigError('No device ID found. Please login first.');
|
|
63
|
+
}
|
|
64
|
+
return config.deviceId;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get email or throw error
|
|
68
|
+
*/
|
|
69
|
+
function requireEmail(configRepository) {
|
|
70
|
+
const config = configRepository.getConfig();
|
|
71
|
+
if (!config.email) {
|
|
72
|
+
throw new errors_1.ConfigError('No email found in configuration.');
|
|
73
|
+
}
|
|
74
|
+
return config.email;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=config-validator.js.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared gateway selection utilities
|
|
4
|
+
* Eliminates duplication across commands
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.promptGatewaySelection = promptGatewaySelection;
|
|
11
|
+
exports.getGatewayId = getGatewayId;
|
|
12
|
+
exports.validateGatewayExists = validateGatewayExists;
|
|
13
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
14
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
15
|
+
/**
|
|
16
|
+
* Prompt user to select a gateway from available gateways
|
|
17
|
+
*/
|
|
18
|
+
async function promptGatewaySelection(gatewayService, options = {}) {
|
|
19
|
+
const { allowNone = false, message = 'Select gateway:', required = true } = options;
|
|
20
|
+
try {
|
|
21
|
+
const response = await gatewayService.listGateways();
|
|
22
|
+
if (response.gateways.length === 0) {
|
|
23
|
+
if (allowNone) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
console.log(chalk_1.default.yellow('⚠ No gateways found'));
|
|
27
|
+
console.log(chalk_1.default.gray('Use "edgible gateway create" to create a gateway'));
|
|
28
|
+
if (required) {
|
|
29
|
+
throw new Error('No gateways available');
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const gatewayChoices = response.gateways.map((gateway) => ({
|
|
34
|
+
name: `${gateway.device.name} (${gateway.device.id})`,
|
|
35
|
+
value: gateway.device.id,
|
|
36
|
+
}));
|
|
37
|
+
if (allowNone) {
|
|
38
|
+
gatewayChoices.push({
|
|
39
|
+
name: 'None',
|
|
40
|
+
value: '',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const answer = await inquirer_1.default.prompt([
|
|
44
|
+
{
|
|
45
|
+
type: 'list',
|
|
46
|
+
name: 'gatewayId',
|
|
47
|
+
message,
|
|
48
|
+
choices: gatewayChoices,
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
return answer.gatewayId === '' ? null : answer.gatewayId;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
console.error(chalk_1.default.red('Error listing gateways:'), error instanceof Error ? error.message : 'Unknown error');
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get gateway by ID, or prompt if not provided
|
|
60
|
+
*/
|
|
61
|
+
async function getGatewayId(gatewayService, providedId, options = {}) {
|
|
62
|
+
if (providedId) {
|
|
63
|
+
return providedId;
|
|
64
|
+
}
|
|
65
|
+
return await promptGatewaySelection(gatewayService, options);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Validate gateway exists
|
|
69
|
+
*/
|
|
70
|
+
async function validateGatewayExists(gatewayService, gatewayId) {
|
|
71
|
+
try {
|
|
72
|
+
const response = await gatewayService.listGateways();
|
|
73
|
+
return response.gateways.some((gateway) => gateway.device.id === gatewayId);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=gateway-prompt.js.map
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Input parsing utilities
|
|
4
|
+
* Converts string inputs to proper types and validates them
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.parsePort = parsePort;
|
|
8
|
+
exports.parseProtocol = parseProtocol;
|
|
9
|
+
exports.parseDeviceId = parseDeviceId;
|
|
10
|
+
exports.parseGatewayIds = parseGatewayIds;
|
|
11
|
+
exports.parseBoolean = parseBoolean;
|
|
12
|
+
exports.parseNumber = parseNumber;
|
|
13
|
+
exports.parseCommandOptions = parseCommandOptions;
|
|
14
|
+
const zod_1 = require("zod");
|
|
15
|
+
const schemas_1 = require("../../validation/schemas");
|
|
16
|
+
const errors_1 = require("../../utils/errors");
|
|
17
|
+
/**
|
|
18
|
+
* Parse port from string
|
|
19
|
+
*/
|
|
20
|
+
function parsePort(value) {
|
|
21
|
+
if (typeof value === 'number') {
|
|
22
|
+
return schemas_1.portSchema.parse(value);
|
|
23
|
+
}
|
|
24
|
+
if (!value) {
|
|
25
|
+
throw new errors_1.ValidationError('Port is required');
|
|
26
|
+
}
|
|
27
|
+
const parsed = parseInt(value, 10);
|
|
28
|
+
if (isNaN(parsed)) {
|
|
29
|
+
throw new errors_1.ValidationError(`Invalid port number: ${value}`);
|
|
30
|
+
}
|
|
31
|
+
return schemas_1.portSchema.parse(parsed);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Parse protocol from string
|
|
35
|
+
*/
|
|
36
|
+
function parseProtocol(value) {
|
|
37
|
+
if (!value) {
|
|
38
|
+
return 'http'; // Default
|
|
39
|
+
}
|
|
40
|
+
return schemas_1.protocolSchema.parse(value.toLowerCase());
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Parse device ID from string
|
|
44
|
+
*/
|
|
45
|
+
function parseDeviceId(value) {
|
|
46
|
+
if (!value) {
|
|
47
|
+
throw new errors_1.ValidationError('Device ID is required');
|
|
48
|
+
}
|
|
49
|
+
return schemas_1.deviceIdSchema.parse(value);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Parse gateway IDs from comma-separated string
|
|
53
|
+
*/
|
|
54
|
+
function parseGatewayIds(value) {
|
|
55
|
+
if (!value) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const ids = value.split(',').map((id) => id.trim()).filter((id) => id.length > 0);
|
|
59
|
+
return ids.map((id) => schemas_1.gatewayIdSchema.parse(id));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse boolean from string or boolean
|
|
63
|
+
*/
|
|
64
|
+
function parseBoolean(value) {
|
|
65
|
+
if (typeof value === 'boolean') {
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
if (!value) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
const lower = value.toLowerCase();
|
|
72
|
+
return lower === 'true' || lower === '1' || lower === 'yes';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Parse number from string with validation
|
|
76
|
+
*/
|
|
77
|
+
function parseNumber(value, min, max) {
|
|
78
|
+
if (typeof value === 'number') {
|
|
79
|
+
if (min !== undefined && value < min) {
|
|
80
|
+
throw new errors_1.ValidationError(`Value must be at least ${min}`);
|
|
81
|
+
}
|
|
82
|
+
if (max !== undefined && value > max) {
|
|
83
|
+
throw new errors_1.ValidationError(`Value must be at most ${max}`);
|
|
84
|
+
}
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
if (!value) {
|
|
88
|
+
throw new errors_1.ValidationError('Number is required');
|
|
89
|
+
}
|
|
90
|
+
const parsed = parseFloat(value);
|
|
91
|
+
if (isNaN(parsed)) {
|
|
92
|
+
throw new errors_1.ValidationError(`Invalid number: ${value}`);
|
|
93
|
+
}
|
|
94
|
+
if (min !== undefined && parsed < min) {
|
|
95
|
+
throw new errors_1.ValidationError(`Value must be at least ${min}`);
|
|
96
|
+
}
|
|
97
|
+
if (max !== undefined && parsed > max) {
|
|
98
|
+
throw new errors_1.ValidationError(`Value must be at most ${max}`);
|
|
99
|
+
}
|
|
100
|
+
return parsed;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Parse and validate command options
|
|
104
|
+
*/
|
|
105
|
+
function parseCommandOptions(schema, options) {
|
|
106
|
+
try {
|
|
107
|
+
return schema.parse(options);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
if (error instanceof zod_1.z.ZodError) {
|
|
111
|
+
const issues = error.issues.map((issue) => {
|
|
112
|
+
const path = issue.path.length > 0 ? issue.path.join('.') : 'root';
|
|
113
|
+
return `${path}: ${issue.message}`;
|
|
114
|
+
});
|
|
115
|
+
throw new errors_1.ValidationError(`Invalid options: ${issues.join(', ')}`);
|
|
116
|
+
}
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=input-parser.js.map
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Output formatting utilities
|
|
4
|
+
* Provides consistent formatting across commands
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.formatApplication = formatApplication;
|
|
11
|
+
exports.formatGateway = formatGateway;
|
|
12
|
+
exports.formatList = formatList;
|
|
13
|
+
exports.formatError = formatError;
|
|
14
|
+
exports.formatSuccess = formatSuccess;
|
|
15
|
+
exports.formatWarning = formatWarning;
|
|
16
|
+
exports.formatInfo = formatInfo;
|
|
17
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
+
/**
|
|
19
|
+
* Format application output
|
|
20
|
+
*/
|
|
21
|
+
function formatApplication(app) {
|
|
22
|
+
const statusColor = app.status === 'active' ? chalk_1.default.green : chalk_1.default.red;
|
|
23
|
+
const statusIcon = app.status === 'active' ? '●' : '○';
|
|
24
|
+
let output = '';
|
|
25
|
+
output += `${statusIcon} ${app.name}\n`;
|
|
26
|
+
output += chalk_1.default.gray(` ID: ${app.id}\n`);
|
|
27
|
+
output += chalk_1.default.gray(` Serving IP: ${chalk_1.default.cyan.bold(app.servingIp)}\n`);
|
|
28
|
+
output += chalk_1.default.gray(` Port: ${app.port}\n`);
|
|
29
|
+
output += chalk_1.default.gray(` Protocol: ${app.protocol.toUpperCase()}\n`);
|
|
30
|
+
output += chalk_1.default.gray(` Status: ${statusColor(app.status)}\n`);
|
|
31
|
+
if (app.workloadId) {
|
|
32
|
+
output += chalk_1.default.gray(` Workload ID: ${app.workloadId}\n`);
|
|
33
|
+
}
|
|
34
|
+
output += chalk_1.default.gray(` Created: ${new Date(app.createdAt).toLocaleString()}\n`);
|
|
35
|
+
if (app.description) {
|
|
36
|
+
output += chalk_1.default.gray(` Description: ${app.description}\n`);
|
|
37
|
+
}
|
|
38
|
+
output += chalk_1.default.cyan(` URL: ${app.protocol}://${app.servingIp}:${app.port}\n`);
|
|
39
|
+
return output;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Format gateway output
|
|
43
|
+
*/
|
|
44
|
+
function formatGateway(gateway) {
|
|
45
|
+
const statusColor = gateway.ec2Instance?.state === 'running' ? chalk_1.default.green : chalk_1.default.red;
|
|
46
|
+
const statusIcon = gateway.ec2Instance?.state === 'running' ? '●' : '○';
|
|
47
|
+
let output = '';
|
|
48
|
+
output += `${statusIcon} ${gateway.device.name}\n`;
|
|
49
|
+
output += chalk_1.default.gray(` Device ID: ${gateway.device.id}\n`);
|
|
50
|
+
output += chalk_1.default.gray(` Description: ${gateway.device.description || 'No description'}\n`);
|
|
51
|
+
if (gateway.applicationCount !== undefined) {
|
|
52
|
+
output += chalk_1.default.gray(` Applications: ${gateway.applicationCount}\n`);
|
|
53
|
+
}
|
|
54
|
+
if (gateway.ec2Instance) {
|
|
55
|
+
output += chalk_1.default.gray(` EC2 Instance: ${gateway.ec2Instance.instanceId}\n`);
|
|
56
|
+
output += chalk_1.default.gray(` Public IP: ${chalk_1.default.cyan.bold(gateway.ec2Instance.publicIp)}\n`);
|
|
57
|
+
output += chalk_1.default.gray(` Private IP: ${gateway.ec2Instance.privateIp}\n`);
|
|
58
|
+
output += chalk_1.default.gray(` Region: ${gateway.ec2Instance.region}\n`);
|
|
59
|
+
output += chalk_1.default.gray(` State: ${statusColor(gateway.ec2Instance.state)}\n`);
|
|
60
|
+
}
|
|
61
|
+
output += chalk_1.default.gray(` Created: ${new Date(gateway.device.createdAt).toLocaleString()}\n`);
|
|
62
|
+
return output;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Format list of items as table-like output
|
|
66
|
+
*/
|
|
67
|
+
function formatList(items, formatItem, header, emptyMessage) {
|
|
68
|
+
if (items.length === 0) {
|
|
69
|
+
return emptyMessage ? chalk_1.default.yellow(`⚠ ${emptyMessage}`) : '';
|
|
70
|
+
}
|
|
71
|
+
let output = '';
|
|
72
|
+
if (header) {
|
|
73
|
+
output += chalk_1.default.blue.bold(`${header}\n\n`);
|
|
74
|
+
}
|
|
75
|
+
items.forEach((item, index) => {
|
|
76
|
+
output += formatItem(item, index);
|
|
77
|
+
output += '\n';
|
|
78
|
+
});
|
|
79
|
+
return output;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Format error message with context
|
|
83
|
+
*/
|
|
84
|
+
function formatError(message, suggestion) {
|
|
85
|
+
let output = chalk_1.default.red(`✗ ${message}\n`);
|
|
86
|
+
if (suggestion) {
|
|
87
|
+
output += chalk_1.default.gray(` ${suggestion}\n`);
|
|
88
|
+
}
|
|
89
|
+
return output;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Format success message
|
|
93
|
+
*/
|
|
94
|
+
function formatSuccess(message) {
|
|
95
|
+
return chalk_1.default.green(`✓ ${message}\n`);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Format warning message
|
|
99
|
+
*/
|
|
100
|
+
function formatWarning(message) {
|
|
101
|
+
return chalk_1.default.yellow(`⚠ ${message}\n`);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Format info message
|
|
105
|
+
*/
|
|
106
|
+
function formatInfo(message) {
|
|
107
|
+
return chalk_1.default.blue(`${message}\n`);
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=output-formatter.js.map
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Application configuration management
|
|
4
|
+
* Centralizes all configuration loading and validation
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.loadConfig = loadConfig;
|
|
8
|
+
exports.validateConfig = validateConfig;
|
|
9
|
+
exports.getConfig = getConfig;
|
|
10
|
+
exports.resetConfig = resetConfig;
|
|
11
|
+
const urls_1 = require("../utils/urls");
|
|
12
|
+
// Production defaults - these are used when environment variables are not set
|
|
13
|
+
const DEFAULT_REGION = 'us-east-1';
|
|
14
|
+
const DEFAULT_INSTANCE_TYPE = 't3.micro';
|
|
15
|
+
/**
|
|
16
|
+
* Load configuration from environment variables and defaults
|
|
17
|
+
*
|
|
18
|
+
* Environment variable precedence:
|
|
19
|
+
* 1. User's environment variables (process.env.*) - highest priority
|
|
20
|
+
* 2. Production defaults (constants above) - fallback
|
|
21
|
+
*
|
|
22
|
+
* Note: Environment variables are read directly from process.env at runtime.
|
|
23
|
+
* Users can set these via shell/system environment variables.
|
|
24
|
+
*
|
|
25
|
+
* Available environment variables:
|
|
26
|
+
* - LOG_LEVEL: Set log level (default: 'INFO')
|
|
27
|
+
* Note: API_BASE_URL is now hardcoded based on stage (STAGE or SST_STAGE env var)
|
|
28
|
+
* - NO_COLOR: Disable colored output (set to '1' or 'true')
|
|
29
|
+
* - PLAIN_OUTPUT: Enable plain text output (set to '1' or 'true')
|
|
30
|
+
* - DEFAULT_REGION: Default AWS region (default: 'us-east-1')
|
|
31
|
+
* - DEFAULT_INSTANCE_TYPE: Default EC2 instance type (default: 't3.micro')
|
|
32
|
+
*/
|
|
33
|
+
function loadConfig() {
|
|
34
|
+
const apiBaseUrl = (0, urls_1.getApiBaseUrl)();
|
|
35
|
+
const logLevel = process.env.LOG_LEVEL || 'INFO';
|
|
36
|
+
const colorEnabled = process.env.NO_COLOR !== '1' && process.env.NO_COLOR !== 'true';
|
|
37
|
+
const plain = process.env.PLAIN_OUTPUT === '1' || process.env.PLAIN_OUTPUT === 'true';
|
|
38
|
+
const defaultRegion = process.env.DEFAULT_REGION || DEFAULT_REGION;
|
|
39
|
+
const defaultInstanceType = process.env.DEFAULT_INSTANCE_TYPE || DEFAULT_INSTANCE_TYPE;
|
|
40
|
+
return {
|
|
41
|
+
apiBaseUrl,
|
|
42
|
+
logLevel,
|
|
43
|
+
colorEnabled,
|
|
44
|
+
plain,
|
|
45
|
+
defaultRegion,
|
|
46
|
+
defaultInstanceType,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate configuration
|
|
51
|
+
*/
|
|
52
|
+
function validateConfig(config) {
|
|
53
|
+
const errors = [];
|
|
54
|
+
// Validate API URL
|
|
55
|
+
try {
|
|
56
|
+
new URL(config.apiBaseUrl);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
errors.push(`Invalid API base URL: ${config.apiBaseUrl}`);
|
|
60
|
+
}
|
|
61
|
+
// Validate log level
|
|
62
|
+
const validLogLevels = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'NONE', 'SILENT'];
|
|
63
|
+
if (!validLogLevels.includes(config.logLevel.toUpperCase())) {
|
|
64
|
+
errors.push(`Invalid log level: ${config.logLevel}. Valid values: ${validLogLevels.join(', ')}`);
|
|
65
|
+
}
|
|
66
|
+
// Validate region format (basic check)
|
|
67
|
+
if (!/^[a-z0-9-]+$/.test(config.defaultRegion)) {
|
|
68
|
+
errors.push(`Invalid default region format: ${config.defaultRegion}`);
|
|
69
|
+
}
|
|
70
|
+
// Validate instance type format (basic check)
|
|
71
|
+
if (!/^[a-z0-9.]+$/.test(config.defaultInstanceType)) {
|
|
72
|
+
errors.push(`Invalid default instance type format: ${config.defaultInstanceType}`);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
valid: errors.length === 0,
|
|
76
|
+
errors,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get configuration singleton
|
|
81
|
+
*/
|
|
82
|
+
let configInstance = null;
|
|
83
|
+
function getConfig() {
|
|
84
|
+
if (!configInstance) {
|
|
85
|
+
configInstance = loadConfig();
|
|
86
|
+
const validation = validateConfig(configInstance);
|
|
87
|
+
if (!validation.valid) {
|
|
88
|
+
console.warn('Configuration validation warnings:', validation.errors);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return configInstance;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Reset configuration (useful for testing)
|
|
95
|
+
*/
|
|
96
|
+
function resetConfig() {
|
|
97
|
+
configInstance = null;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=app-config.js.map
|