@edgible-team/cli 1.2.13 → 1.2.17
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/README.md +5 -3
- package/dist/client/api-client.d.ts +13 -1
- package/dist/client/api-client.d.ts.map +1 -1
- package/dist/client/api-client.js +19 -0
- package/dist/commands/agent/install.d.ts +2 -1
- package/dist/commands/agent/install.d.ts.map +1 -1
- package/dist/commands/agent/install.js +24 -7
- package/dist/commands/agent/start.d.ts +5 -1
- package/dist/commands/agent/start.d.ts.map +1 -1
- package/dist/commands/agent/start.js +19 -280
- package/dist/commands/agent/uninstall.d.ts.map +1 -1
- package/dist/commands/agent/uninstall.js +14 -7
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +3 -2
- package/dist/commands/ai/setup.d.ts +1 -1
- package/dist/commands/ai/setup.d.ts.map +1 -1
- package/dist/commands/ai.js +1 -1
- package/dist/commands/application/create-docker-compose.d.ts +3 -1
- package/dist/commands/application/create-docker-compose.d.ts.map +1 -1
- package/dist/commands/application/create-docker-compose.js +25 -69
- package/dist/commands/application/create-existing.d.ts +2 -2
- package/dist/commands/application/create-existing.d.ts.map +1 -1
- package/dist/commands/application/create-existing.js +27 -132
- package/dist/commands/application/create-managed-process.d.ts +3 -1
- package/dist/commands/application/create-managed-process.d.ts.map +1 -1
- package/dist/commands/application/create-managed-process.js +31 -75
- package/dist/commands/application/delete.d.ts +2 -1
- package/dist/commands/application/delete.d.ts.map +1 -1
- package/dist/commands/application/delete.js +19 -5
- package/dist/commands/application/update.d.ts +3 -0
- package/dist/commands/application/update.d.ts.map +1 -1
- package/dist/commands/application/update.js +45 -1
- package/dist/commands/application.d.ts.map +1 -1
- package/dist/commands/application.js +33 -19
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +44 -0
- package/dist/commands/debug.js +1 -1
- package/dist/commands/device/application-health.d.ts +7 -0
- package/dist/commands/device/application-health.d.ts.map +1 -0
- package/dist/commands/device/application-health.js +103 -0
- package/dist/commands/device/delete.d.ts +7 -0
- package/dist/commands/device/delete.d.ts.map +1 -0
- package/dist/commands/device/delete.js +69 -0
- package/dist/commands/device/health.d.ts +7 -0
- package/dist/commands/device/health.d.ts.map +1 -0
- package/dist/commands/device/health.js +78 -0
- package/dist/commands/device/list.d.ts +5 -0
- package/dist/commands/device/list.d.ts.map +1 -0
- package/dist/commands/device/list.js +46 -0
- package/dist/commands/device/telemetry.d.ts +8 -0
- package/dist/commands/device/telemetry.d.ts.map +1 -0
- package/dist/commands/device/telemetry.js +59 -0
- package/dist/commands/device.d.ts +6 -0
- package/dist/commands/device.d.ts.map +1 -0
- package/dist/commands/device.js +86 -0
- package/dist/commands/stack/deploy.d.ts +8 -0
- package/dist/commands/stack/deploy.d.ts.map +1 -0
- package/dist/commands/stack/deploy.js +61 -0
- package/dist/commands/stack/diff.d.ts +7 -0
- package/dist/commands/stack/diff.d.ts.map +1 -0
- package/dist/commands/stack/diff.js +66 -0
- package/dist/commands/stack/status.d.ts +9 -0
- package/dist/commands/stack/status.d.ts.map +1 -0
- package/dist/commands/stack/status.js +55 -0
- package/dist/commands/stack/teardown.d.ts +8 -0
- package/dist/commands/stack/teardown.d.ts.map +1 -0
- package/dist/commands/stack/teardown.js +107 -0
- package/dist/commands/stack/validate.d.ts +7 -0
- package/dist/commands/stack/validate.d.ts.map +1 -0
- package/dist/commands/stack/validate.js +44 -0
- package/dist/commands/stack.d.ts +10 -0
- package/dist/commands/stack.d.ts.map +1 -0
- package/dist/commands/stack.js +117 -0
- package/dist/commands/utils/auth-prompt.d.ts +25 -0
- package/dist/commands/utils/auth-prompt.d.ts.map +1 -0
- package/dist/commands/utils/auth-prompt.js +115 -0
- package/dist/commands/utils/device-prompt.d.ts +18 -0
- package/dist/commands/utils/device-prompt.d.ts.map +1 -0
- package/dist/commands/utils/device-prompt.js +58 -0
- package/dist/commands/utils/output-formatter.d.ts +13 -0
- package/dist/commands/utils/output-formatter.d.ts.map +1 -1
- package/dist/commands/utils/output-formatter.js +21 -0
- package/dist/index.js +4 -0
- package/dist/services/LocalAgentManager.d.ts +2 -1
- package/dist/services/LocalAgentManager.d.ts.map +1 -1
- package/dist/services/LocalAgentManager.js +6 -4
- package/dist/services/application/ApplicationService.d.ts +19 -0
- package/dist/services/application/ApplicationService.d.ts.map +1 -1
- package/dist/services/application/ApplicationService.js +14 -1
- package/dist/services/device/DeviceService.d.ts +62 -0
- package/dist/services/device/DeviceService.d.ts.map +1 -0
- package/dist/services/device/DeviceService.js +235 -0
- package/dist/services/edgible.d.ts +3 -1
- package/dist/services/edgible.d.ts.map +1 -1
- package/dist/services/edgible.js +5 -4
- package/dist/services/instances.d.ts +27 -1
- package/dist/services/instances.d.ts.map +1 -1
- package/dist/services/instances.js +53 -4
- package/dist/services/stack/DependencyGraphManager.d.ts +69 -0
- package/dist/services/stack/DependencyGraphManager.d.ts.map +1 -0
- package/dist/services/stack/DependencyGraphManager.js +204 -0
- package/dist/services/stack/DeviceResolver.d.ts +63 -0
- package/dist/services/stack/DeviceResolver.d.ts.map +1 -0
- package/dist/services/stack/DeviceResolver.js +147 -0
- package/dist/services/stack/GatewayResolver.d.ts +84 -0
- package/dist/services/stack/GatewayResolver.d.ts.map +1 -0
- package/dist/services/stack/GatewayResolver.js +179 -0
- package/dist/services/stack/StackParser.d.ts +38 -0
- package/dist/services/stack/StackParser.d.ts.map +1 -0
- package/dist/services/stack/StackParser.js +234 -0
- package/dist/services/stack/StackService.d.ts +76 -0
- package/dist/services/stack/StackService.d.ts.map +1 -0
- package/dist/services/stack/StackService.js +476 -0
- package/dist/types/AgentConfig.d.ts +26 -0
- package/dist/types/AgentConfig.d.ts.map +1 -1
- package/dist/types/ApiRequests.d.ts +5 -1
- package/dist/types/ApiRequests.d.ts.map +1 -1
- package/dist/types/ApiResponses.d.ts +5 -0
- package/dist/types/ApiResponses.d.ts.map +1 -1
- package/dist/types/JobTypes.d.ts +103 -0
- package/dist/types/JobTypes.d.ts.map +1 -0
- package/dist/types/JobTypes.js +80 -0
- package/dist/types/WebSocketMessages.d.ts +89 -0
- package/dist/types/WebSocketMessages.d.ts.map +1 -0
- package/dist/types/WebSocketMessages.js +5 -0
- package/dist/types/backendJobs.d.ts +102 -0
- package/dist/types/backendJobs.d.ts.map +1 -0
- package/dist/types/backendJobs.js +5 -0
- package/dist/types/models/ApplicationData.d.ts +1 -1
- package/dist/types/models/ApplicationData.d.ts.map +1 -1
- package/dist/types/models/DeviceData.d.ts +4 -0
- package/dist/types/models/DeviceData.d.ts.map +1 -1
- package/dist/types/stack.d.ts +191 -0
- package/dist/types/stack.d.ts.map +1 -0
- package/dist/types/stack.js +5 -0
- package/dist/types/validation/schemas.d.ts +20 -20
- package/dist/types/validation/schemas.js +1 -1
- package/dist/utils/stack-errors.d.ts +103 -0
- package/dist/utils/stack-errors.d.ts.map +1 -0
- package/dist/utils/stack-errors.js +158 -0
- package/dist/utils/stack-file.d.ts +11 -0
- package/dist/utils/stack-file.d.ts.map +1 -0
- package/dist/utils/stack-file.js +66 -0
- package/dist/validation/stack-schemas.d.ts +535 -0
- package/dist/validation/stack-schemas.d.ts.map +1 -0
- package/dist/validation/stack-schemas.js +178 -0
- package/package.json +4 -2
- package/dist/commands/agent/agent-handlers.d.ts +0 -45
- package/dist/commands/agent/agent-handlers.d.ts.map +0 -1
- package/dist/commands/agent/agent-handlers.js +0 -1159
- package/dist/commands/application/api-keys.d.ts +0 -3
- package/dist/commands/application/api-keys.d.ts.map +0 -1
- package/dist/commands/application/api-keys.js +0 -227
- package/dist/commands/application/create-compose.d.ts +0 -3
- package/dist/commands/application/create-compose.d.ts.map +0 -1
- package/dist/commands/application/create-compose.js +0 -381
- package/dist/commands/application/create-interactive.d.ts +0 -3
- package/dist/commands/application/create-interactive.d.ts.map +0 -1
- package/dist/commands/application/create-interactive.js +0 -326
- package/dist/commands/application/create-workload.d.ts +0 -5
- package/dist/commands/application/create-workload.d.ts.map +0 -1
- package/dist/commands/application/create-workload.js +0 -48
- package/dist/commands/application/short-codes.d.ts +0 -3
- package/dist/commands/application/short-codes.d.ts.map +0 -1
- package/dist/commands/application/short-codes.js +0 -226
- package/dist/commands/application/toggle.d.ts +0 -2
- package/dist/commands/application/toggle.d.ts.map +0 -1
- package/dist/commands/application/toggle.js +0 -78
- package/dist/commands/examples/migrated-command-example.d.ts +0 -31
- package/dist/commands/examples/migrated-command-example.d.ts.map +0 -1
- package/dist/commands/examples/migrated-command-example.js +0 -180
- package/dist/commands/managedGateway/create.d.ts +0 -6
- package/dist/commands/managedGateway/create.d.ts.map +0 -1
- package/dist/commands/managedGateway/create.js +0 -50
- package/dist/commands/managedGateway/delete.d.ts +0 -5
- package/dist/commands/managedGateway/delete.d.ts.map +0 -1
- package/dist/commands/managedGateway/delete.js +0 -57
- package/dist/commands/managedGateway/get.d.ts +0 -4
- package/dist/commands/managedGateway/get.d.ts.map +0 -1
- package/dist/commands/managedGateway/get.js +0 -71
- package/dist/commands/managedGateway/haproxy-stats.d.ts +0 -6
- package/dist/commands/managedGateway/haproxy-stats.d.ts.map +0 -1
- package/dist/commands/managedGateway/haproxy-stats.js +0 -131
- package/dist/commands/managedGateway/list.d.ts +0 -4
- package/dist/commands/managedGateway/list.d.ts.map +0 -1
- package/dist/commands/managedGateway/list.js +0 -50
- package/dist/commands/managedGateway/logs.d.ts +0 -10
- package/dist/commands/managedGateway/logs.d.ts.map +0 -1
- package/dist/commands/managedGateway/logs.js +0 -100
- package/dist/commands/managedGateway/reboot.d.ts +0 -5
- package/dist/commands/managedGateway/reboot.d.ts.map +0 -1
- package/dist/commands/managedGateway/reboot.js +0 -95
- package/dist/commands/managedGateway/resync.d.ts +0 -10
- package/dist/commands/managedGateway/resync.d.ts.map +0 -1
- package/dist/commands/managedGateway/resync.js +0 -69
- package/dist/commands/managedGateway/ssh.d.ts +0 -4
- package/dist/commands/managedGateway/ssh.d.ts.map +0 -1
- package/dist/commands/managedGateway/ssh.js +0 -130
- package/dist/commands/managedGateway/wipe-logs.d.ts +0 -4
- package/dist/commands/managedGateway/wipe-logs.d.ts.map +0 -1
- package/dist/commands/managedGateway/wipe-logs.js +0 -67
- package/dist/commands/managedGateway/wireguard.d.ts +0 -4
- package/dist/commands/managedGateway/wireguard.d.ts.map +0 -1
- package/dist/commands/managedGateway/wireguard.js +0 -68
- package/dist/di/bindings.d.ts +0 -15
- package/dist/di/bindings.d.ts.map +0 -1
- package/dist/di/bindings.js +0 -99
- package/dist/di/container.d.ts +0 -44
- package/dist/di/container.d.ts.map +0 -1
- package/dist/di/container.js +0 -88
- package/dist/di/types.d.ts +0 -23
- package/dist/di/types.d.ts.map +0 -1
- package/dist/di/types.js +0 -32
- package/dist/repositories/config-repository.d.ts +0 -46
- package/dist/repositories/config-repository.d.ts.map +0 -1
- package/dist/repositories/config-repository.js +0 -62
- package/dist/repositories/gateway-repository.d.ts +0 -37
- package/dist/repositories/gateway-repository.d.ts.map +0 -1
- package/dist/repositories/gateway-repository.js +0 -35
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Gateway Resolver Service
|
|
4
|
+
* Resolves gateway requirements for published applications
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.GatewayResolver = void 0;
|
|
8
|
+
const stack_errors_1 = require("../../utils/stack-errors");
|
|
9
|
+
class GatewayResolver {
|
|
10
|
+
constructor(apiClient, organizationId, logger) {
|
|
11
|
+
this.apiClient = apiClient;
|
|
12
|
+
this.organizationId = organizationId;
|
|
13
|
+
this.logger = logger;
|
|
14
|
+
this.gatewayCache = null;
|
|
15
|
+
this.cacheTimestamp = null;
|
|
16
|
+
this.CACHE_TTL_MS = 60000; // 1 minute cache
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve gateway requirements for applications
|
|
20
|
+
* For published apps, finds or suggests managed gateways
|
|
21
|
+
* @param applications List of applications to resolve gateways for
|
|
22
|
+
* @param autoCreate If true, will create gateways automatically (requires confirmation in caller)
|
|
23
|
+
* @returns Map of appName -> gatewayIds
|
|
24
|
+
*/
|
|
25
|
+
async resolveGateways(applications, autoCreate = false) {
|
|
26
|
+
const result = new Map();
|
|
27
|
+
const publishedApps = applications.filter(app => app.published);
|
|
28
|
+
if (publishedApps.length === 0) {
|
|
29
|
+
this.logger.debug('No published applications, skipping gateway resolution');
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
this.logger.debug(`Resolving gateways for ${publishedApps.length} published applications`);
|
|
33
|
+
// Get available managed gateways
|
|
34
|
+
const managedGateways = await this.listManagedGateways();
|
|
35
|
+
if (managedGateways.length === 0 && !autoCreate) {
|
|
36
|
+
throw new stack_errors_1.GatewayProvisioningError(publishedApps[0].name, 'No managed gateways available and auto-create is disabled');
|
|
37
|
+
}
|
|
38
|
+
// For MVP: use the first available managed gateway for all published apps
|
|
39
|
+
// Future: implement proper gateway selection based on region, capacity, etc.
|
|
40
|
+
if (managedGateways.length > 0) {
|
|
41
|
+
const gateway = managedGateways[0];
|
|
42
|
+
this.logger.debug(`Using existing managed gateway: ${gateway.id} (${gateway.name})`);
|
|
43
|
+
for (const app of publishedApps) {
|
|
44
|
+
result.set(app.name, [gateway.id]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// No gateways available and autoCreate is true
|
|
49
|
+
// The caller (StackService) should handle gateway creation with user confirmation
|
|
50
|
+
this.logger.warn('No managed gateways available. Gateway creation required.');
|
|
51
|
+
for (const app of publishedApps) {
|
|
52
|
+
result.set(app.name, []); // Empty array signals gateway creation needed
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve gateway for a single application
|
|
59
|
+
* @param appName Application name
|
|
60
|
+
* @param published Whether the app should be published
|
|
61
|
+
* @returns Array of gateway IDs (empty if not published)
|
|
62
|
+
*/
|
|
63
|
+
async resolveGateway(appName, published) {
|
|
64
|
+
if (!published) {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
const managedGateways = await this.listManagedGateways();
|
|
68
|
+
if (managedGateways.length === 0) {
|
|
69
|
+
throw new stack_errors_1.GatewayProvisioningError(appName, 'No managed gateways available');
|
|
70
|
+
}
|
|
71
|
+
// Use the first available managed gateway
|
|
72
|
+
const gateway = managedGateways[0];
|
|
73
|
+
this.logger.debug(`Resolved gateway for '${appName}': ${gateway.id}`);
|
|
74
|
+
return [gateway.id];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* List all managed gateways (with caching)
|
|
78
|
+
* @returns Array of managed gateway info
|
|
79
|
+
*/
|
|
80
|
+
async listManagedGateways() {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
// Return cached gateways if still valid
|
|
83
|
+
if (this.gatewayCache !== null &&
|
|
84
|
+
this.cacheTimestamp !== null &&
|
|
85
|
+
now - this.cacheTimestamp < this.CACHE_TTL_MS) {
|
|
86
|
+
this.logger.debug('Using cached gateway list');
|
|
87
|
+
return this.gatewayCache;
|
|
88
|
+
}
|
|
89
|
+
// Fetch gateways from API
|
|
90
|
+
this.logger.debug('Fetching managed gateways');
|
|
91
|
+
try {
|
|
92
|
+
const response = await this.apiClient.listManagedGateways();
|
|
93
|
+
// Transform API response to our format
|
|
94
|
+
// Note: The actual response structure may vary based on API implementation
|
|
95
|
+
const gateways = (response.gateways || response.managedGateways || []).map((gw) => ({
|
|
96
|
+
id: gw.id || gw.gatewayId,
|
|
97
|
+
name: gw.name || gw.gatewayName || 'Unnamed Gateway',
|
|
98
|
+
region: gw.region || 'unknown',
|
|
99
|
+
status: gw.status || 'unknown',
|
|
100
|
+
applicationsCount: gw.applicationsCount || gw.applications?.length || 0,
|
|
101
|
+
}));
|
|
102
|
+
// Filter to only active gateways
|
|
103
|
+
const activeGateways = gateways.filter(gw => gw.status === 'active' || gw.status === 'running' || gw.status === 'online');
|
|
104
|
+
// Update cache
|
|
105
|
+
this.gatewayCache = activeGateways;
|
|
106
|
+
this.cacheTimestamp = now;
|
|
107
|
+
this.logger.debug(`Fetched ${activeGateways.length} active managed gateways`);
|
|
108
|
+
return activeGateways;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
this.logger.error(`Failed to fetch managed gateways: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
112
|
+
// If listing fails, it might be an API permission issue or no gateways exist
|
|
113
|
+
// Return empty array instead of throwing to allow graceful handling
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check if gateway creation is needed
|
|
119
|
+
* @param applications List of applications
|
|
120
|
+
* @returns True if any published app needs a gateway but none available
|
|
121
|
+
*/
|
|
122
|
+
async needsGatewayCreation(applications) {
|
|
123
|
+
const hasPublishedApps = applications.some(app => app.published);
|
|
124
|
+
if (!hasPublishedApps) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
const managedGateways = await this.listManagedGateways();
|
|
128
|
+
return managedGateways.length === 0;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Select best gateway for an application
|
|
132
|
+
* Future enhancement: implement intelligent selection based on:
|
|
133
|
+
* - Region proximity to device
|
|
134
|
+
* - Current capacity/load
|
|
135
|
+
* - Application count
|
|
136
|
+
* - Performance metrics
|
|
137
|
+
*
|
|
138
|
+
* @param appName Application name
|
|
139
|
+
* @param deviceRegion Region where device is located
|
|
140
|
+
* @returns Gateway ID or null if none suitable
|
|
141
|
+
*/
|
|
142
|
+
async selectBestGateway(appName, deviceRegion) {
|
|
143
|
+
const gateways = await this.listManagedGateways();
|
|
144
|
+
if (gateways.length === 0) {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
// For MVP: just return the first gateway
|
|
148
|
+
// Future: implement smart selection logic
|
|
149
|
+
return gateways[0].id;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Clear the gateway cache (useful for testing or forcing refresh)
|
|
153
|
+
*/
|
|
154
|
+
clearCache() {
|
|
155
|
+
this.gatewayCache = null;
|
|
156
|
+
this.cacheTimestamp = null;
|
|
157
|
+
this.logger.debug('Gateway cache cleared');
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Get gateway details
|
|
161
|
+
* @param gatewayId Gateway ID
|
|
162
|
+
* @returns Gateway info or null if not found
|
|
163
|
+
*/
|
|
164
|
+
async getGateway(gatewayId) {
|
|
165
|
+
const gateways = await this.listManagedGateways();
|
|
166
|
+
return gateways.find(gw => gw.id === gatewayId) || null;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Check if a gateway exists and is available
|
|
170
|
+
* @param gatewayId Gateway ID
|
|
171
|
+
* @returns True if gateway exists and is active
|
|
172
|
+
*/
|
|
173
|
+
async gatewayAvailable(gatewayId) {
|
|
174
|
+
const gateway = await this.getGateway(gatewayId);
|
|
175
|
+
return gateway !== null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
exports.GatewayResolver = GatewayResolver;
|
|
179
|
+
//# sourceMappingURL=GatewayResolver.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stack Parser Service
|
|
3
|
+
* Parses and validates application stack YAML files
|
|
4
|
+
*/
|
|
5
|
+
import { Logger } from '../../utils/logger';
|
|
6
|
+
import { ApplicationStack, StackValidationResult } from '../../types/stack';
|
|
7
|
+
export declare class StackParser {
|
|
8
|
+
private logger;
|
|
9
|
+
constructor(logger: Logger);
|
|
10
|
+
/**
|
|
11
|
+
* Parse a stack file from disk
|
|
12
|
+
* @param filePath Path to the stack YAML file
|
|
13
|
+
* @returns Parsed and validated ApplicationStack
|
|
14
|
+
*/
|
|
15
|
+
parseFile(filePath: string): Promise<ApplicationStack>;
|
|
16
|
+
/**
|
|
17
|
+
* Substitute environment variables in content
|
|
18
|
+
* Supports ${VAR} and ${VAR:-default} syntax
|
|
19
|
+
* @param content File content with env var placeholders
|
|
20
|
+
* @param filePath Path to the stack file (for finding .env)
|
|
21
|
+
* @returns Content with substituted variables
|
|
22
|
+
*/
|
|
23
|
+
private substituteEnvVars;
|
|
24
|
+
/**
|
|
25
|
+
* Parse .env file and set environment variables
|
|
26
|
+
* Does not overwrite existing environment variables
|
|
27
|
+
* @param content .env file content
|
|
28
|
+
*/
|
|
29
|
+
private parseEnvFile;
|
|
30
|
+
/**
|
|
31
|
+
* Validate a stack file without fully parsing
|
|
32
|
+
* Returns validation result with errors and warnings
|
|
33
|
+
* @param filePath Path to the stack YAML file
|
|
34
|
+
* @returns Validation result
|
|
35
|
+
*/
|
|
36
|
+
validate(filePath: string): Promise<StackValidationResult>;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=StackParser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StackParser.d.ts","sourceRoot":"","sources":["../../../src/services/stack/StackParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAS5E,qBAAa,WAAW;IACV,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;;;OAIG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA4D5D;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IA6BzB;;;;OAIG;IACH,OAAO,CAAC,YAAY;IA2BpB;;;;;OAKG;IACG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAoEjE"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Stack Parser Service
|
|
4
|
+
* Parses and validates application stack YAML files
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.StackParser = void 0;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const yaml = __importStar(require("js-yaml"));
|
|
44
|
+
const stack_schemas_1 = require("../../validation/stack-schemas");
|
|
45
|
+
const stack_errors_1 = require("../../utils/stack-errors");
|
|
46
|
+
class StackParser {
|
|
47
|
+
constructor(logger) {
|
|
48
|
+
this.logger = logger;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Parse a stack file from disk
|
|
52
|
+
* @param filePath Path to the stack YAML file
|
|
53
|
+
* @returns Parsed and validated ApplicationStack
|
|
54
|
+
*/
|
|
55
|
+
async parseFile(filePath) {
|
|
56
|
+
this.logger.debug(`Parsing stack file: ${filePath}`);
|
|
57
|
+
// Resolve to absolute path
|
|
58
|
+
const absolutePath = path.resolve(filePath);
|
|
59
|
+
// Check if file exists
|
|
60
|
+
if (!fs.existsSync(absolutePath)) {
|
|
61
|
+
throw new stack_errors_1.StackFileNotFoundError(absolutePath);
|
|
62
|
+
}
|
|
63
|
+
// Read file content
|
|
64
|
+
let content;
|
|
65
|
+
try {
|
|
66
|
+
content = fs.readFileSync(absolutePath, 'utf-8');
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
throw new stack_errors_1.StackParseError(`Failed to read stack file: ${error instanceof Error ? error.message : 'Unknown error'}`, absolutePath);
|
|
70
|
+
}
|
|
71
|
+
// Substitute environment variables
|
|
72
|
+
content = this.substituteEnvVars(content, absolutePath);
|
|
73
|
+
// Parse YAML
|
|
74
|
+
let rawStack;
|
|
75
|
+
try {
|
|
76
|
+
rawStack = yaml.load(content);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const yamlError = error;
|
|
80
|
+
throw new stack_errors_1.StackParseError(`Invalid YAML: ${yamlError.message || 'Syntax error'}`, absolutePath, yamlError.mark?.line);
|
|
81
|
+
}
|
|
82
|
+
// Check if YAML is empty or null
|
|
83
|
+
if (!rawStack || typeof rawStack !== 'object') {
|
|
84
|
+
throw new stack_errors_1.StackParseError('Stack file is empty or invalid', absolutePath);
|
|
85
|
+
}
|
|
86
|
+
// Validate schema
|
|
87
|
+
const result = stack_schemas_1.applicationStackSchema.safeParse(rawStack);
|
|
88
|
+
if (!result.success) {
|
|
89
|
+
const errors = result.error.errors.map((err) => ({
|
|
90
|
+
path: err.path.join('.'),
|
|
91
|
+
message: err.message,
|
|
92
|
+
}));
|
|
93
|
+
throw new stack_errors_1.StackValidationError('Stack validation failed', errors);
|
|
94
|
+
}
|
|
95
|
+
this.logger.debug(`Successfully parsed stack: ${result.data.metadata.name}`);
|
|
96
|
+
return result.data;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Substitute environment variables in content
|
|
100
|
+
* Supports ${VAR} and ${VAR:-default} syntax
|
|
101
|
+
* @param content File content with env var placeholders
|
|
102
|
+
* @param filePath Path to the stack file (for finding .env)
|
|
103
|
+
* @returns Content with substituted variables
|
|
104
|
+
*/
|
|
105
|
+
substituteEnvVars(content, filePath) {
|
|
106
|
+
// Load .env file if it exists in the same directory
|
|
107
|
+
const envFilePath = path.join(path.dirname(filePath), '.env');
|
|
108
|
+
if (fs.existsSync(envFilePath)) {
|
|
109
|
+
this.logger.debug(`Loading environment variables from ${envFilePath}`);
|
|
110
|
+
try {
|
|
111
|
+
const envContent = fs.readFileSync(envFilePath, 'utf-8');
|
|
112
|
+
this.parseEnvFile(envContent);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
this.logger.warn(`Failed to load .env file: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Replace ${VAR:-default} and ${VAR}
|
|
119
|
+
return content.replace(/\$\{([^}:]+)(?::-(.*?))?\}/g, (match, varName, defaultValue) => {
|
|
120
|
+
const value = process.env[varName];
|
|
121
|
+
if (value !== undefined) {
|
|
122
|
+
return value;
|
|
123
|
+
}
|
|
124
|
+
if (defaultValue !== undefined) {
|
|
125
|
+
return defaultValue;
|
|
126
|
+
}
|
|
127
|
+
throw new stack_errors_1.EnvironmentVariableError(varName);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Parse .env file and set environment variables
|
|
132
|
+
* Does not overwrite existing environment variables
|
|
133
|
+
* @param content .env file content
|
|
134
|
+
*/
|
|
135
|
+
parseEnvFile(content) {
|
|
136
|
+
const lines = content.split('\n');
|
|
137
|
+
for (const line of lines) {
|
|
138
|
+
const trimmed = line.trim();
|
|
139
|
+
// Skip empty lines and comments
|
|
140
|
+
if (!trimmed || trimmed.startsWith('#')) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// Parse KEY=VALUE
|
|
144
|
+
const match = trimmed.match(/^([^=]+)=(.*)$/);
|
|
145
|
+
if (match) {
|
|
146
|
+
const key = match[1].trim();
|
|
147
|
+
const value = match[2].trim();
|
|
148
|
+
// Remove quotes if present
|
|
149
|
+
const unquoted = value.replace(/^["'](.*)["']$/, '$1');
|
|
150
|
+
// Only set if not already set
|
|
151
|
+
if (process.env[key] === undefined) {
|
|
152
|
+
process.env[key] = unquoted;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Validate a stack file without fully parsing
|
|
159
|
+
* Returns validation result with errors and warnings
|
|
160
|
+
* @param filePath Path to the stack YAML file
|
|
161
|
+
* @returns Validation result
|
|
162
|
+
*/
|
|
163
|
+
async validate(filePath) {
|
|
164
|
+
const errors = [];
|
|
165
|
+
const warnings = [];
|
|
166
|
+
try {
|
|
167
|
+
await this.parseFile(filePath);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
if (error instanceof stack_errors_1.StackValidationError) {
|
|
171
|
+
errors.push(...error.errors);
|
|
172
|
+
}
|
|
173
|
+
else if (error instanceof stack_errors_1.StackParseError) {
|
|
174
|
+
errors.push({
|
|
175
|
+
path: 'file',
|
|
176
|
+
message: error.message,
|
|
177
|
+
line: error.line,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else if (error instanceof stack_errors_1.StackFileNotFoundError) {
|
|
181
|
+
errors.push({
|
|
182
|
+
path: 'file',
|
|
183
|
+
message: error.message,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
else if (error instanceof stack_errors_1.EnvironmentVariableError) {
|
|
187
|
+
errors.push({
|
|
188
|
+
path: 'environment',
|
|
189
|
+
message: error.message,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
errors.push({
|
|
194
|
+
path: 'unknown',
|
|
195
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Add warnings for best practices
|
|
200
|
+
if (errors.length === 0) {
|
|
201
|
+
try {
|
|
202
|
+
const stack = await this.parseFile(filePath);
|
|
203
|
+
// Warn if no dependencies specified but multiple apps
|
|
204
|
+
if (stack.applications.length > 1) {
|
|
205
|
+
const hasAnyDependencies = stack.applications.some(app => app.dependsOn && app.dependsOn.length > 0);
|
|
206
|
+
if (!hasAnyDependencies) {
|
|
207
|
+
warnings.push({
|
|
208
|
+
path: 'applications',
|
|
209
|
+
message: 'No dependencies specified. Applications will be deployed in file order.',
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Warn if all applications are unpublished
|
|
214
|
+
const allUnpublished = stack.applications.every(app => !app.published);
|
|
215
|
+
if (allUnpublished) {
|
|
216
|
+
warnings.push({
|
|
217
|
+
path: 'applications',
|
|
218
|
+
message: 'All applications are unpublished. They will not be accessible via public URLs.',
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
// Ignore errors during warning checks
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
valid: errors.length === 0,
|
|
228
|
+
errors,
|
|
229
|
+
warnings,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
exports.StackParser = StackParser;
|
|
234
|
+
//# sourceMappingURL=StackParser.js.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stack Service
|
|
3
|
+
* Main orchestration service for application stack operations
|
|
4
|
+
*/
|
|
5
|
+
import { Logger } from '../../utils/logger';
|
|
6
|
+
import { ApiClient } from '../../client';
|
|
7
|
+
import { ApplicationService } from '../application/ApplicationService';
|
|
8
|
+
import { StackValidationResult, DeployOptions, DeployResult, TeardownOptions, TeardownResult, StackStatus, StackDiff } from '../../types/stack';
|
|
9
|
+
export declare class StackService {
|
|
10
|
+
private apiClient;
|
|
11
|
+
private applicationService;
|
|
12
|
+
private organizationId;
|
|
13
|
+
private logger;
|
|
14
|
+
private parser;
|
|
15
|
+
private deviceResolver;
|
|
16
|
+
private gatewayResolver;
|
|
17
|
+
private dependencyManager;
|
|
18
|
+
constructor(apiClient: ApiClient, applicationService: ApplicationService, organizationId: string, logger: Logger);
|
|
19
|
+
/**
|
|
20
|
+
* Validate a stack file
|
|
21
|
+
* @param filePath Path to stack file
|
|
22
|
+
* @returns Validation result
|
|
23
|
+
*/
|
|
24
|
+
validateStack(filePath: string): Promise<StackValidationResult>;
|
|
25
|
+
/**
|
|
26
|
+
* Deploy a stack
|
|
27
|
+
* @param options Deploy options
|
|
28
|
+
* @returns Deploy result
|
|
29
|
+
*/
|
|
30
|
+
deployStack(options: DeployOptions): Promise<DeployResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Teardown a stack
|
|
33
|
+
* @param options Teardown options
|
|
34
|
+
* @returns Teardown result
|
|
35
|
+
*/
|
|
36
|
+
teardownStack(options: TeardownOptions): Promise<TeardownResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Get status of applications in a stack
|
|
39
|
+
* @param filePath Path to stack file
|
|
40
|
+
* @returns Stack status
|
|
41
|
+
*/
|
|
42
|
+
getStackStatus(filePath: string): Promise<StackStatus>;
|
|
43
|
+
/**
|
|
44
|
+
* Get diff between stack definition and deployed state
|
|
45
|
+
* @param filePath Path to stack file
|
|
46
|
+
* @returns Stack diff
|
|
47
|
+
*/
|
|
48
|
+
diffStack(filePath: string): Promise<StackDiff>;
|
|
49
|
+
/**
|
|
50
|
+
* Resolve stack: resolve device names and gateways
|
|
51
|
+
* @param stack Application stack
|
|
52
|
+
* @param applications Applications to resolve (filtered subset)
|
|
53
|
+
* @returns Resolved stack
|
|
54
|
+
*/
|
|
55
|
+
private resolveStack;
|
|
56
|
+
/**
|
|
57
|
+
* Deploy a single application
|
|
58
|
+
* @param app Application to deploy
|
|
59
|
+
* @param resolved Resolved stack information
|
|
60
|
+
* @returns Deployed application info
|
|
61
|
+
*/
|
|
62
|
+
private deployApplication;
|
|
63
|
+
/**
|
|
64
|
+
* Get deployed applications matching stack apps
|
|
65
|
+
* @param applications Stack applications to check
|
|
66
|
+
* @returns Array of application statuses
|
|
67
|
+
*/
|
|
68
|
+
private getDeployedApplications;
|
|
69
|
+
/**
|
|
70
|
+
* Encode docker-compose file to base64
|
|
71
|
+
* @param composeFilePath Path to docker-compose file (relative to stack file or absolute)
|
|
72
|
+
* @returns Base64-prefixed compose content ready for API submission
|
|
73
|
+
*/
|
|
74
|
+
private encodeDockerComposeFile;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=StackService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StackService.d.ts","sourceRoot":"","sources":["../../../src/services/stack/StackService.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAKvE,OAAO,EAKL,qBAAqB,EACrB,aAAa,EACb,YAAY,EACZ,eAAe,EACf,cAAc,EACd,WAAW,EAEX,SAAS,EAGV,MAAM,mBAAmB,CAAC;AAO3B,qBAAa,YAAY;IAOrB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,kBAAkB;IAC1B,OAAO,CAAC,cAAc;IACtB,OAAO,CAAC,MAAM;IAThB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,iBAAiB,CAAyB;gBAGxC,SAAS,EAAE,SAAS,EACpB,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,MAAM;IAQxB;;;;OAIG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAgCrE;;;;OAIG;IACG,WAAW,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAoGhE;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC;IAuEtE;;;;OAIG;IACG,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAY5D;;;;OAIG;IACG,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IA0CrD;;;;;OAKG;YACW,YAAY;IA4B1B;;;;;OAKG;YACW,iBAAiB;IAiF/B;;;;OAIG;YACW,uBAAuB;IAyCrC;;;;OAIG;YACW,uBAAuB;CA4BtC"}
|