@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.
Files changed (219) hide show
  1. package/README.md +5 -3
  2. package/dist/client/api-client.d.ts +13 -1
  3. package/dist/client/api-client.d.ts.map +1 -1
  4. package/dist/client/api-client.js +19 -0
  5. package/dist/commands/agent/install.d.ts +2 -1
  6. package/dist/commands/agent/install.d.ts.map +1 -1
  7. package/dist/commands/agent/install.js +24 -7
  8. package/dist/commands/agent/start.d.ts +5 -1
  9. package/dist/commands/agent/start.d.ts.map +1 -1
  10. package/dist/commands/agent/start.js +19 -280
  11. package/dist/commands/agent/uninstall.d.ts.map +1 -1
  12. package/dist/commands/agent/uninstall.js +14 -7
  13. package/dist/commands/agent.d.ts.map +1 -1
  14. package/dist/commands/agent.js +3 -2
  15. package/dist/commands/ai/setup.d.ts +1 -1
  16. package/dist/commands/ai/setup.d.ts.map +1 -1
  17. package/dist/commands/ai.js +1 -1
  18. package/dist/commands/application/create-docker-compose.d.ts +3 -1
  19. package/dist/commands/application/create-docker-compose.d.ts.map +1 -1
  20. package/dist/commands/application/create-docker-compose.js +25 -69
  21. package/dist/commands/application/create-existing.d.ts +2 -2
  22. package/dist/commands/application/create-existing.d.ts.map +1 -1
  23. package/dist/commands/application/create-existing.js +27 -132
  24. package/dist/commands/application/create-managed-process.d.ts +3 -1
  25. package/dist/commands/application/create-managed-process.d.ts.map +1 -1
  26. package/dist/commands/application/create-managed-process.js +31 -75
  27. package/dist/commands/application/delete.d.ts +2 -1
  28. package/dist/commands/application/delete.d.ts.map +1 -1
  29. package/dist/commands/application/delete.js +19 -5
  30. package/dist/commands/application/update.d.ts +3 -0
  31. package/dist/commands/application/update.d.ts.map +1 -1
  32. package/dist/commands/application/update.js +45 -1
  33. package/dist/commands/application.d.ts.map +1 -1
  34. package/dist/commands/application.js +33 -19
  35. package/dist/commands/auth.d.ts.map +1 -1
  36. package/dist/commands/auth.js +44 -0
  37. package/dist/commands/debug.js +1 -1
  38. package/dist/commands/device/application-health.d.ts +7 -0
  39. package/dist/commands/device/application-health.d.ts.map +1 -0
  40. package/dist/commands/device/application-health.js +103 -0
  41. package/dist/commands/device/delete.d.ts +7 -0
  42. package/dist/commands/device/delete.d.ts.map +1 -0
  43. package/dist/commands/device/delete.js +69 -0
  44. package/dist/commands/device/health.d.ts +7 -0
  45. package/dist/commands/device/health.d.ts.map +1 -0
  46. package/dist/commands/device/health.js +78 -0
  47. package/dist/commands/device/list.d.ts +5 -0
  48. package/dist/commands/device/list.d.ts.map +1 -0
  49. package/dist/commands/device/list.js +46 -0
  50. package/dist/commands/device/telemetry.d.ts +8 -0
  51. package/dist/commands/device/telemetry.d.ts.map +1 -0
  52. package/dist/commands/device/telemetry.js +59 -0
  53. package/dist/commands/device.d.ts +6 -0
  54. package/dist/commands/device.d.ts.map +1 -0
  55. package/dist/commands/device.js +86 -0
  56. package/dist/commands/stack/deploy.d.ts +8 -0
  57. package/dist/commands/stack/deploy.d.ts.map +1 -0
  58. package/dist/commands/stack/deploy.js +61 -0
  59. package/dist/commands/stack/diff.d.ts +7 -0
  60. package/dist/commands/stack/diff.d.ts.map +1 -0
  61. package/dist/commands/stack/diff.js +66 -0
  62. package/dist/commands/stack/status.d.ts +9 -0
  63. package/dist/commands/stack/status.d.ts.map +1 -0
  64. package/dist/commands/stack/status.js +55 -0
  65. package/dist/commands/stack/teardown.d.ts +8 -0
  66. package/dist/commands/stack/teardown.d.ts.map +1 -0
  67. package/dist/commands/stack/teardown.js +107 -0
  68. package/dist/commands/stack/validate.d.ts +7 -0
  69. package/dist/commands/stack/validate.d.ts.map +1 -0
  70. package/dist/commands/stack/validate.js +44 -0
  71. package/dist/commands/stack.d.ts +10 -0
  72. package/dist/commands/stack.d.ts.map +1 -0
  73. package/dist/commands/stack.js +117 -0
  74. package/dist/commands/utils/auth-prompt.d.ts +25 -0
  75. package/dist/commands/utils/auth-prompt.d.ts.map +1 -0
  76. package/dist/commands/utils/auth-prompt.js +115 -0
  77. package/dist/commands/utils/device-prompt.d.ts +18 -0
  78. package/dist/commands/utils/device-prompt.d.ts.map +1 -0
  79. package/dist/commands/utils/device-prompt.js +58 -0
  80. package/dist/commands/utils/output-formatter.d.ts +13 -0
  81. package/dist/commands/utils/output-formatter.d.ts.map +1 -1
  82. package/dist/commands/utils/output-formatter.js +21 -0
  83. package/dist/index.js +4 -0
  84. package/dist/services/LocalAgentManager.d.ts +2 -1
  85. package/dist/services/LocalAgentManager.d.ts.map +1 -1
  86. package/dist/services/LocalAgentManager.js +6 -4
  87. package/dist/services/application/ApplicationService.d.ts +19 -0
  88. package/dist/services/application/ApplicationService.d.ts.map +1 -1
  89. package/dist/services/application/ApplicationService.js +14 -1
  90. package/dist/services/device/DeviceService.d.ts +62 -0
  91. package/dist/services/device/DeviceService.d.ts.map +1 -0
  92. package/dist/services/device/DeviceService.js +235 -0
  93. package/dist/services/edgible.d.ts +3 -1
  94. package/dist/services/edgible.d.ts.map +1 -1
  95. package/dist/services/edgible.js +5 -4
  96. package/dist/services/instances.d.ts +27 -1
  97. package/dist/services/instances.d.ts.map +1 -1
  98. package/dist/services/instances.js +53 -4
  99. package/dist/services/stack/DependencyGraphManager.d.ts +69 -0
  100. package/dist/services/stack/DependencyGraphManager.d.ts.map +1 -0
  101. package/dist/services/stack/DependencyGraphManager.js +204 -0
  102. package/dist/services/stack/DeviceResolver.d.ts +63 -0
  103. package/dist/services/stack/DeviceResolver.d.ts.map +1 -0
  104. package/dist/services/stack/DeviceResolver.js +147 -0
  105. package/dist/services/stack/GatewayResolver.d.ts +84 -0
  106. package/dist/services/stack/GatewayResolver.d.ts.map +1 -0
  107. package/dist/services/stack/GatewayResolver.js +179 -0
  108. package/dist/services/stack/StackParser.d.ts +38 -0
  109. package/dist/services/stack/StackParser.d.ts.map +1 -0
  110. package/dist/services/stack/StackParser.js +234 -0
  111. package/dist/services/stack/StackService.d.ts +76 -0
  112. package/dist/services/stack/StackService.d.ts.map +1 -0
  113. package/dist/services/stack/StackService.js +476 -0
  114. package/dist/types/AgentConfig.d.ts +26 -0
  115. package/dist/types/AgentConfig.d.ts.map +1 -1
  116. package/dist/types/ApiRequests.d.ts +5 -1
  117. package/dist/types/ApiRequests.d.ts.map +1 -1
  118. package/dist/types/ApiResponses.d.ts +5 -0
  119. package/dist/types/ApiResponses.d.ts.map +1 -1
  120. package/dist/types/JobTypes.d.ts +103 -0
  121. package/dist/types/JobTypes.d.ts.map +1 -0
  122. package/dist/types/JobTypes.js +80 -0
  123. package/dist/types/WebSocketMessages.d.ts +89 -0
  124. package/dist/types/WebSocketMessages.d.ts.map +1 -0
  125. package/dist/types/WebSocketMessages.js +5 -0
  126. package/dist/types/backendJobs.d.ts +102 -0
  127. package/dist/types/backendJobs.d.ts.map +1 -0
  128. package/dist/types/backendJobs.js +5 -0
  129. package/dist/types/models/ApplicationData.d.ts +1 -1
  130. package/dist/types/models/ApplicationData.d.ts.map +1 -1
  131. package/dist/types/models/DeviceData.d.ts +4 -0
  132. package/dist/types/models/DeviceData.d.ts.map +1 -1
  133. package/dist/types/stack.d.ts +191 -0
  134. package/dist/types/stack.d.ts.map +1 -0
  135. package/dist/types/stack.js +5 -0
  136. package/dist/types/validation/schemas.d.ts +20 -20
  137. package/dist/types/validation/schemas.js +1 -1
  138. package/dist/utils/stack-errors.d.ts +103 -0
  139. package/dist/utils/stack-errors.d.ts.map +1 -0
  140. package/dist/utils/stack-errors.js +158 -0
  141. package/dist/utils/stack-file.d.ts +11 -0
  142. package/dist/utils/stack-file.d.ts.map +1 -0
  143. package/dist/utils/stack-file.js +66 -0
  144. package/dist/validation/stack-schemas.d.ts +535 -0
  145. package/dist/validation/stack-schemas.d.ts.map +1 -0
  146. package/dist/validation/stack-schemas.js +178 -0
  147. package/package.json +4 -2
  148. package/dist/commands/agent/agent-handlers.d.ts +0 -45
  149. package/dist/commands/agent/agent-handlers.d.ts.map +0 -1
  150. package/dist/commands/agent/agent-handlers.js +0 -1159
  151. package/dist/commands/application/api-keys.d.ts +0 -3
  152. package/dist/commands/application/api-keys.d.ts.map +0 -1
  153. package/dist/commands/application/api-keys.js +0 -227
  154. package/dist/commands/application/create-compose.d.ts +0 -3
  155. package/dist/commands/application/create-compose.d.ts.map +0 -1
  156. package/dist/commands/application/create-compose.js +0 -381
  157. package/dist/commands/application/create-interactive.d.ts +0 -3
  158. package/dist/commands/application/create-interactive.d.ts.map +0 -1
  159. package/dist/commands/application/create-interactive.js +0 -326
  160. package/dist/commands/application/create-workload.d.ts +0 -5
  161. package/dist/commands/application/create-workload.d.ts.map +0 -1
  162. package/dist/commands/application/create-workload.js +0 -48
  163. package/dist/commands/application/short-codes.d.ts +0 -3
  164. package/dist/commands/application/short-codes.d.ts.map +0 -1
  165. package/dist/commands/application/short-codes.js +0 -226
  166. package/dist/commands/application/toggle.d.ts +0 -2
  167. package/dist/commands/application/toggle.d.ts.map +0 -1
  168. package/dist/commands/application/toggle.js +0 -78
  169. package/dist/commands/examples/migrated-command-example.d.ts +0 -31
  170. package/dist/commands/examples/migrated-command-example.d.ts.map +0 -1
  171. package/dist/commands/examples/migrated-command-example.js +0 -180
  172. package/dist/commands/managedGateway/create.d.ts +0 -6
  173. package/dist/commands/managedGateway/create.d.ts.map +0 -1
  174. package/dist/commands/managedGateway/create.js +0 -50
  175. package/dist/commands/managedGateway/delete.d.ts +0 -5
  176. package/dist/commands/managedGateway/delete.d.ts.map +0 -1
  177. package/dist/commands/managedGateway/delete.js +0 -57
  178. package/dist/commands/managedGateway/get.d.ts +0 -4
  179. package/dist/commands/managedGateway/get.d.ts.map +0 -1
  180. package/dist/commands/managedGateway/get.js +0 -71
  181. package/dist/commands/managedGateway/haproxy-stats.d.ts +0 -6
  182. package/dist/commands/managedGateway/haproxy-stats.d.ts.map +0 -1
  183. package/dist/commands/managedGateway/haproxy-stats.js +0 -131
  184. package/dist/commands/managedGateway/list.d.ts +0 -4
  185. package/dist/commands/managedGateway/list.d.ts.map +0 -1
  186. package/dist/commands/managedGateway/list.js +0 -50
  187. package/dist/commands/managedGateway/logs.d.ts +0 -10
  188. package/dist/commands/managedGateway/logs.d.ts.map +0 -1
  189. package/dist/commands/managedGateway/logs.js +0 -100
  190. package/dist/commands/managedGateway/reboot.d.ts +0 -5
  191. package/dist/commands/managedGateway/reboot.d.ts.map +0 -1
  192. package/dist/commands/managedGateway/reboot.js +0 -95
  193. package/dist/commands/managedGateway/resync.d.ts +0 -10
  194. package/dist/commands/managedGateway/resync.d.ts.map +0 -1
  195. package/dist/commands/managedGateway/resync.js +0 -69
  196. package/dist/commands/managedGateway/ssh.d.ts +0 -4
  197. package/dist/commands/managedGateway/ssh.d.ts.map +0 -1
  198. package/dist/commands/managedGateway/ssh.js +0 -130
  199. package/dist/commands/managedGateway/wipe-logs.d.ts +0 -4
  200. package/dist/commands/managedGateway/wipe-logs.d.ts.map +0 -1
  201. package/dist/commands/managedGateway/wipe-logs.js +0 -67
  202. package/dist/commands/managedGateway/wireguard.d.ts +0 -4
  203. package/dist/commands/managedGateway/wireguard.d.ts.map +0 -1
  204. package/dist/commands/managedGateway/wireguard.js +0 -68
  205. package/dist/di/bindings.d.ts +0 -15
  206. package/dist/di/bindings.d.ts.map +0 -1
  207. package/dist/di/bindings.js +0 -99
  208. package/dist/di/container.d.ts +0 -44
  209. package/dist/di/container.d.ts.map +0 -1
  210. package/dist/di/container.js +0 -88
  211. package/dist/di/types.d.ts +0 -23
  212. package/dist/di/types.d.ts.map +0 -1
  213. package/dist/di/types.js +0 -32
  214. package/dist/repositories/config-repository.d.ts +0 -46
  215. package/dist/repositories/config-repository.d.ts.map +0 -1
  216. package/dist/repositories/config-repository.js +0 -62
  217. package/dist/repositories/gateway-repository.d.ts +0 -37
  218. package/dist/repositories/gateway-repository.d.ts.map +0 -1
  219. 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"}