@aifabrix/builder 2.31.1 → 2.32.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/README.md +9 -9
- package/integration/hubspot/README.md +2 -2
- package/integration/hubspot/hubspot-deploy-company.json +17 -14
- package/integration/hubspot/hubspot-deploy-contact.json +19 -16
- package/integration/hubspot/hubspot-deploy-deal.json +21 -18
- package/lib/api/types/datasources.types.js +31 -5
- package/lib/api/types/wizard.types.js +142 -0
- package/lib/api/wizard.api.js +177 -0
- package/lib/{app-config.js → app/config.js} +4 -4
- package/lib/{app-deploy.js → app/deploy.js} +8 -8
- package/lib/app/display.js +90 -0
- package/lib/{app-dockerfile.js → app/dockerfile.js} +4 -4
- package/lib/{app-down.js → app/down.js} +4 -4
- package/lib/app/helpers.js +218 -0
- package/lib/app/index.js +298 -0
- package/lib/{app-list.js → app/list.js} +6 -6
- package/lib/{app-push.js → app/push.js} +4 -4
- package/lib/{app-readme.js → app/readme.js} +34 -13
- package/lib/{app-register.js → app/register.js} +9 -9
- package/lib/{app-rotate-secret.js → app/rotate-secret.js} +10 -10
- package/lib/{app-run-helpers.js → app/run-helpers.js} +10 -10
- package/lib/{app-run.js → app/run.js} +6 -6
- package/lib/{build.js → build/index.js} +59 -32
- package/lib/build/package.json +7 -0
- package/lib/cli.js +245 -179
- package/lib/commands/app.js +3 -3
- package/lib/commands/datasource.js +4 -4
- package/lib/commands/login-credentials.js +209 -0
- package/lib/commands/login-device.js +254 -0
- package/lib/commands/login.js +67 -378
- package/lib/commands/logout.js +1 -1
- package/lib/commands/secrets-set.js +1 -1
- package/lib/commands/secure.js +2 -2
- package/lib/commands/wizard.js +498 -0
- package/lib/{audit-logger.js → core/audit-logger.js} +1 -1
- package/lib/{config.js → core/config.js} +28 -26
- package/lib/{diff.js → core/diff.js} +157 -72
- package/lib/{secrets.js → core/secrets.js} +86 -49
- package/lib/{templates.js → core/templates-env.js} +14 -222
- package/lib/core/templates.js +279 -0
- package/lib/{datasource-deploy.js → datasource/deploy.js} +6 -6
- package/lib/{datasource-diff.js → datasource/diff.js} +2 -2
- package/lib/datasource/list.js +223 -0
- package/lib/{datasource-validate.js → datasource/validate.js} +2 -2
- package/lib/{deployer.js → deployment/deployer.js} +48 -18
- package/lib/{environment-deploy.js → deployment/environment.js} +163 -84
- package/lib/{push.js → deployment/push.js} +1 -1
- package/lib/external-system/deploy-helpers.js +145 -0
- package/lib/{external-system-deploy.js → external-system/deploy.js} +156 -111
- package/lib/external-system/download-helpers.js +114 -0
- package/lib/{external-system-download.js → external-system/download.js} +92 -135
- package/lib/{external-system-generator.js → external-system/generator.js} +15 -11
- package/lib/external-system/test-auth.js +40 -0
- package/lib/external-system/test-execution.js +84 -0
- package/lib/external-system/test-helpers.js +109 -0
- package/lib/{external-system-test.js → external-system/test.js} +174 -192
- package/lib/{generator-builders.js → generator/builders.js} +87 -10
- package/lib/{generator-external.js → generator/external.js} +115 -52
- package/lib/{github-generator.js → generator/github.js} +116 -15
- package/lib/{generator-helpers.js → generator/helpers.js} +92 -42
- package/lib/{generator.js → generator/index.js} +49 -22
- package/lib/{generator-split.js → generator/split.js} +108 -55
- package/lib/generator/wizard-prompts.js +357 -0
- package/lib/generator/wizard.js +490 -0
- package/lib/{infra.js → infrastructure/index.js} +49 -22
- package/lib/schema/external-datasource.schema.json +145 -133
- package/lib/schema/external-system.schema.json +42 -0
- package/lib/utils/api.js +9 -5
- package/lib/utils/app-register-api.js +60 -32
- package/lib/utils/app-register-auth.js +172 -47
- package/lib/utils/app-register-config.js +130 -59
- package/lib/utils/app-run-containers.js +29 -8
- package/lib/utils/build-helpers.js +1 -1
- package/lib/utils/cli-utils.js +78 -30
- package/lib/utils/compose-generator.js +145 -65
- package/lib/utils/config-paths.js +2 -0
- package/lib/utils/deployment-errors.js +1 -1
- package/lib/utils/device-code.js +99 -41
- package/lib/utils/env-config-loader.js +1 -1
- package/lib/utils/env-copy.js +21 -18
- package/lib/utils/env-endpoints.js +115 -67
- package/lib/utils/env-map.js +13 -14
- package/lib/utils/env-ports.js +45 -25
- package/lib/utils/env-template.js +84 -42
- package/lib/utils/error-formatter.js +26 -9
- package/lib/utils/error-formatters/error-parser.js +90 -4
- package/lib/utils/error-formatters/http-status-errors.js +54 -17
- package/lib/utils/error-formatters/network-errors.js +103 -26
- package/lib/utils/external-system-display.js +184 -90
- package/lib/utils/external-system-validators.js +164 -42
- package/lib/utils/file-upload.js +109 -0
- package/lib/utils/health-check.js +199 -83
- package/lib/utils/infra-containers.js +1 -1
- package/lib/utils/infra-status.js +66 -15
- package/lib/utils/local-secrets.js +45 -25
- package/lib/utils/paths.js +45 -33
- package/lib/utils/schema-loader.js +42 -25
- package/lib/utils/schema-resolver.js +123 -74
- package/lib/utils/secrets-encryption.js +62 -25
- package/lib/utils/secrets-helpers.js +126 -63
- package/lib/utils/secrets-path.js +1 -1
- package/lib/utils/secrets-url.js +1 -1
- package/lib/utils/token-manager-refresh.js +181 -0
- package/lib/utils/token-manager.js +76 -123
- package/lib/utils/variable-transformer.js +154 -77
- package/lib/utils/yaml-preserve.js +41 -47
- package/lib/{template-validator.js → validation/template.js} +54 -23
- package/lib/{validate.js → validation/validate.js} +205 -125
- package/lib/{validator.js → validation/validator.js} +58 -39
- package/package.json +31 -2
- package/templates/external-system/deploy.ps1.hbs +34 -0
- package/templates/external-system/deploy.sh.hbs +34 -0
- package/templates/external-system/external-datasource.json.hbs +31 -12
- package/lib/app.js +0 -467
- package/lib/datasource-list.js +0 -141
- /package/lib/{app-prompts.js → app/prompts.js} +0 -0
- /package/lib/{env-reader.js → core/env-reader.js} +0 -0
- /package/lib/{key-generator.js → core/key-generator.js} +0 -0
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const chalk = require('chalk');
|
|
15
|
-
const logger = require('
|
|
15
|
+
const logger = require('../utils/logger');
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Handle added field in comparison
|
|
@@ -83,6 +83,37 @@ function isNestedObject(value) {
|
|
|
83
83
|
* @param {string} [path=''] - Current path in object (for nested fields)
|
|
84
84
|
* @returns {Object} Comparison result with added, removed, changed fields
|
|
85
85
|
*/
|
|
86
|
+
/**
|
|
87
|
+
* Compares a single key between two objects
|
|
88
|
+
* @function compareSingleKey
|
|
89
|
+
* @param {string} key - Key to compare
|
|
90
|
+
* @param {Object} obj1 - First object
|
|
91
|
+
* @param {Object} obj2 - Second object
|
|
92
|
+
* @param {string} newPath - Current path in object
|
|
93
|
+
* @param {Object} result - Comparison result object
|
|
94
|
+
*/
|
|
95
|
+
function compareSingleKey(key, obj1, obj2, newPath, result) {
|
|
96
|
+
const val1 = obj1 && obj1[key];
|
|
97
|
+
const val2 = obj2 && obj2[key];
|
|
98
|
+
|
|
99
|
+
if (!(key in obj1)) {
|
|
100
|
+
handleAddedField(key, val2, newPath, result);
|
|
101
|
+
} else if (!(key in obj2)) {
|
|
102
|
+
handleRemovedField(key, val1, newPath, result);
|
|
103
|
+
} else if (isNestedObject(val1) && isNestedObject(val2)) {
|
|
104
|
+
// Recursively compare nested objects
|
|
105
|
+
const nestedResult = compareObjects(val1, val2, newPath);
|
|
106
|
+
result.added.push(...nestedResult.added);
|
|
107
|
+
result.removed.push(...nestedResult.removed);
|
|
108
|
+
result.changed.push(...nestedResult.changed);
|
|
109
|
+
if (!nestedResult.identical) {
|
|
110
|
+
result.identical = false;
|
|
111
|
+
}
|
|
112
|
+
} else if (JSON.stringify(val1) !== JSON.stringify(val2)) {
|
|
113
|
+
handleChangedField(val1, val2, newPath, result);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
86
117
|
function compareObjects(obj1, obj2, currentPath = '') {
|
|
87
118
|
const result = {
|
|
88
119
|
added: [],
|
|
@@ -95,25 +126,7 @@ function compareObjects(obj1, obj2, currentPath = '') {
|
|
|
95
126
|
|
|
96
127
|
for (const key of allKeys) {
|
|
97
128
|
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
98
|
-
|
|
99
|
-
const val2 = obj2 && obj2[key];
|
|
100
|
-
|
|
101
|
-
if (!(key in obj1)) {
|
|
102
|
-
handleAddedField(key, val2, newPath, result);
|
|
103
|
-
} else if (!(key in obj2)) {
|
|
104
|
-
handleRemovedField(key, val1, newPath, result);
|
|
105
|
-
} else if (isNestedObject(val1) && isNestedObject(val2)) {
|
|
106
|
-
// Recursively compare nested objects
|
|
107
|
-
const nestedResult = compareObjects(val1, val2, newPath);
|
|
108
|
-
result.added.push(...nestedResult.added);
|
|
109
|
-
result.removed.push(...nestedResult.removed);
|
|
110
|
-
result.changed.push(...nestedResult.changed);
|
|
111
|
-
if (!nestedResult.identical) {
|
|
112
|
-
result.identical = false;
|
|
113
|
-
}
|
|
114
|
-
} else if (JSON.stringify(val1) !== JSON.stringify(val2)) {
|
|
115
|
-
handleChangedField(val1, val2, newPath, result);
|
|
116
|
-
}
|
|
129
|
+
compareSingleKey(key, obj1, obj2, newPath, result);
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
return result;
|
|
@@ -170,49 +183,68 @@ function identifyBreakingChanges(comparison) {
|
|
|
170
183
|
* const result = await compareFiles('./old.json', './new.json');
|
|
171
184
|
* // Returns: { identical: false, added: [...], removed: [...], changed: [...] }
|
|
172
185
|
*/
|
|
173
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Validates file paths
|
|
188
|
+
* @function validateFilePaths
|
|
189
|
+
* @param {string} file1 - First file path
|
|
190
|
+
* @param {string} file2 - Second file path
|
|
191
|
+
* @throws {Error} If paths are invalid
|
|
192
|
+
*/
|
|
193
|
+
function validateFilePaths(file1, file2) {
|
|
174
194
|
if (!file1 || typeof file1 !== 'string') {
|
|
175
195
|
throw new Error('First file path is required');
|
|
176
196
|
}
|
|
177
197
|
if (!file2 || typeof file2 !== 'string') {
|
|
178
198
|
throw new Error('Second file path is required');
|
|
179
199
|
}
|
|
180
|
-
|
|
181
|
-
// Validate files exist
|
|
182
200
|
if (!fs.existsSync(file1)) {
|
|
183
201
|
throw new Error(`File not found: ${file1}`);
|
|
184
202
|
}
|
|
185
203
|
if (!fs.existsSync(file2)) {
|
|
186
204
|
throw new Error(`File not found: ${file2}`);
|
|
187
205
|
}
|
|
206
|
+
}
|
|
188
207
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
throw new Error(`Failed to parse ${file1}: ${error.message}`);
|
|
198
|
-
}
|
|
199
|
-
|
|
208
|
+
/**
|
|
209
|
+
* Reads and parses a JSON file
|
|
210
|
+
* @function readAndParseFile
|
|
211
|
+
* @param {string} filePath - File path
|
|
212
|
+
* @returns {Object} Parsed JSON object
|
|
213
|
+
* @throws {Error} If file cannot be read or parsed
|
|
214
|
+
*/
|
|
215
|
+
function readAndParseFile(filePath) {
|
|
200
216
|
try {
|
|
201
|
-
|
|
202
|
-
|
|
217
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
218
|
+
return JSON.parse(content);
|
|
203
219
|
} catch (error) {
|
|
204
|
-
throw new Error(`Failed to parse ${
|
|
220
|
+
throw new Error(`Failed to parse ${filePath}: ${error.message}`);
|
|
205
221
|
}
|
|
222
|
+
}
|
|
206
223
|
|
|
207
|
-
|
|
208
|
-
|
|
224
|
+
/**
|
|
225
|
+
* Extracts version from parsed object
|
|
226
|
+
* @function extractVersion
|
|
227
|
+
* @param {Object} parsed - Parsed JSON object
|
|
228
|
+
* @returns {string} Version string
|
|
229
|
+
*/
|
|
230
|
+
function extractVersion(parsed) {
|
|
231
|
+
return parsed.version || parsed.metadata?.version || 'unknown';
|
|
232
|
+
}
|
|
209
233
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
234
|
+
/**
|
|
235
|
+
* Builds comparison result object
|
|
236
|
+
* @function buildComparisonResult
|
|
237
|
+
* @param {Object} comparison - Comparison result from compareObjects
|
|
238
|
+
* @param {Object} parsed1 - First parsed object
|
|
239
|
+
* @param {Object} parsed2 - Second parsed object
|
|
240
|
+
* @param {string} file1 - First file path
|
|
241
|
+
* @param {string} file2 - Second file path
|
|
242
|
+
* @returns {Object} Complete comparison result
|
|
243
|
+
*/
|
|
244
|
+
function buildComparisonResult(comparison, parsed1, parsed2, file1, file2) {
|
|
245
|
+
const version1 = extractVersion(parsed1);
|
|
246
|
+
const version2 = extractVersion(parsed2);
|
|
213
247
|
const versionChanged = version1 !== version2;
|
|
214
|
-
|
|
215
|
-
// Identify breaking changes
|
|
216
248
|
const breakingChanges = identifyBreakingChanges(comparison);
|
|
217
249
|
|
|
218
250
|
return {
|
|
@@ -235,6 +267,16 @@ async function compareFiles(file1, file2) {
|
|
|
235
267
|
};
|
|
236
268
|
}
|
|
237
269
|
|
|
270
|
+
async function compareFiles(file1, file2) {
|
|
271
|
+
validateFilePaths(file1, file2);
|
|
272
|
+
|
|
273
|
+
const parsed1 = readAndParseFile(file1);
|
|
274
|
+
const parsed2 = readAndParseFile(file2);
|
|
275
|
+
|
|
276
|
+
const comparison = compareObjects(parsed1, parsed2);
|
|
277
|
+
return buildComparisonResult(comparison, parsed1, parsed2, file1, file2);
|
|
278
|
+
}
|
|
279
|
+
|
|
238
280
|
/**
|
|
239
281
|
* Formats and displays diff output
|
|
240
282
|
* Shows differences in a user-friendly format with color coding
|
|
@@ -242,61 +284,104 @@ async function compareFiles(file1, file2) {
|
|
|
242
284
|
* @function formatDiffOutput
|
|
243
285
|
* @param {Object} diffResult - Comparison result from compareFiles
|
|
244
286
|
*/
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
logger.log(chalk.yellow('\nFiles are different'));
|
|
254
|
-
|
|
255
|
-
// Version information
|
|
287
|
+
/**
|
|
288
|
+
* Displays version information if changed
|
|
289
|
+
* @function displayVersionInfo
|
|
290
|
+
* @param {Object} diffResult - Comparison result
|
|
291
|
+
*/
|
|
292
|
+
function displayVersionInfo(diffResult) {
|
|
256
293
|
if (diffResult.versionChanged) {
|
|
257
294
|
logger.log(chalk.blue(`\nVersion: ${diffResult.version1} → ${diffResult.version2}`));
|
|
258
295
|
}
|
|
296
|
+
}
|
|
259
297
|
|
|
260
|
-
|
|
261
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Displays breaking changes
|
|
300
|
+
* @function displayBreakingChanges
|
|
301
|
+
* @param {Object[]} breakingChanges - Array of breaking changes
|
|
302
|
+
*/
|
|
303
|
+
function displayBreakingChanges(breakingChanges) {
|
|
304
|
+
if (breakingChanges.length > 0) {
|
|
262
305
|
logger.log(chalk.red('\n⚠️ Breaking Changes:'));
|
|
263
|
-
|
|
306
|
+
breakingChanges.forEach(change => {
|
|
264
307
|
logger.log(chalk.red(` • ${change.description}`));
|
|
265
308
|
});
|
|
266
309
|
}
|
|
310
|
+
}
|
|
267
311
|
|
|
268
|
-
|
|
269
|
-
|
|
312
|
+
/**
|
|
313
|
+
* Displays added fields
|
|
314
|
+
* @function displayAddedFields
|
|
315
|
+
* @param {Object[]} added - Array of added fields
|
|
316
|
+
*/
|
|
317
|
+
function displayAddedFields(added) {
|
|
318
|
+
if (added.length > 0) {
|
|
270
319
|
logger.log(chalk.green('\nAdded Fields:'));
|
|
271
|
-
|
|
320
|
+
added.forEach(field => {
|
|
272
321
|
logger.log(chalk.green(` + ${field.path}: ${JSON.stringify(field.value)}`));
|
|
273
322
|
});
|
|
274
323
|
}
|
|
324
|
+
}
|
|
275
325
|
|
|
276
|
-
|
|
277
|
-
|
|
326
|
+
/**
|
|
327
|
+
* Displays removed fields
|
|
328
|
+
* @function displayRemovedFields
|
|
329
|
+
* @param {Object[]} removed - Array of removed fields
|
|
330
|
+
*/
|
|
331
|
+
function displayRemovedFields(removed) {
|
|
332
|
+
if (removed.length > 0) {
|
|
278
333
|
logger.log(chalk.red('\nRemoved Fields:'));
|
|
279
|
-
|
|
334
|
+
removed.forEach(field => {
|
|
280
335
|
logger.log(chalk.red(` - ${field.path}: ${JSON.stringify(field.value)}`));
|
|
281
336
|
});
|
|
282
337
|
}
|
|
338
|
+
}
|
|
283
339
|
|
|
284
|
-
|
|
285
|
-
|
|
340
|
+
/**
|
|
341
|
+
* Displays changed fields
|
|
342
|
+
* @function displayChangedFields
|
|
343
|
+
* @param {Object[]} changed - Array of changed fields
|
|
344
|
+
*/
|
|
345
|
+
function displayChangedFields(changed) {
|
|
346
|
+
if (changed.length > 0) {
|
|
286
347
|
logger.log(chalk.yellow('\nChanged Fields:'));
|
|
287
|
-
|
|
348
|
+
changed.forEach(change => {
|
|
288
349
|
logger.log(chalk.yellow(` ~ ${change.path}:`));
|
|
289
350
|
logger.log(chalk.gray(` Old: ${JSON.stringify(change.oldValue)}`));
|
|
290
351
|
logger.log(chalk.gray(` New: ${JSON.stringify(change.newValue)}`));
|
|
291
352
|
});
|
|
292
353
|
}
|
|
354
|
+
}
|
|
293
355
|
|
|
294
|
-
|
|
356
|
+
/**
|
|
357
|
+
* Displays summary statistics
|
|
358
|
+
* @function displaySummary
|
|
359
|
+
* @param {Object} summary - Summary object
|
|
360
|
+
*/
|
|
361
|
+
function displaySummary(summary) {
|
|
295
362
|
logger.log(chalk.blue('\nSummary:'));
|
|
296
|
-
logger.log(chalk.blue(` Added: ${
|
|
297
|
-
logger.log(chalk.blue(` Removed: ${
|
|
298
|
-
logger.log(chalk.blue(` Changed: ${
|
|
299
|
-
logger.log(chalk.blue(` Breaking: ${
|
|
363
|
+
logger.log(chalk.blue(` Added: ${summary.totalAdded}`));
|
|
364
|
+
logger.log(chalk.blue(` Removed: ${summary.totalRemoved}`));
|
|
365
|
+
logger.log(chalk.blue(` Changed: ${summary.totalChanged}`));
|
|
366
|
+
logger.log(chalk.blue(` Breaking: ${summary.totalBreaking}`));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function formatDiffOutput(diffResult) {
|
|
370
|
+
logger.log(chalk.blue(`\nComparing: ${diffResult.file1} ↔ ${diffResult.file2}`));
|
|
371
|
+
|
|
372
|
+
if (diffResult.identical) {
|
|
373
|
+
logger.log(chalk.green('\n✓ Files are identical'));
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
logger.log(chalk.yellow('\nFiles are different'));
|
|
378
|
+
|
|
379
|
+
displayVersionInfo(diffResult);
|
|
380
|
+
displayBreakingChanges(diffResult.breakingChanges);
|
|
381
|
+
displayAddedFields(diffResult.added);
|
|
382
|
+
displayRemovedFields(diffResult.removed);
|
|
383
|
+
displayChangedFields(diffResult.changed);
|
|
384
|
+
displaySummary(diffResult.summary);
|
|
300
385
|
}
|
|
301
386
|
|
|
302
387
|
module.exports = {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
const path = require('path');
|
|
14
14
|
const yaml = require('js-yaml');
|
|
15
|
-
const logger = require('
|
|
15
|
+
const logger = require('../utils/logger');
|
|
16
16
|
const config = require('./config');
|
|
17
17
|
const {
|
|
18
18
|
interpolateEnvVars,
|
|
@@ -26,24 +26,24 @@ const {
|
|
|
26
26
|
applyCanonicalSecretsOverride,
|
|
27
27
|
ensureNonEmptySecrets,
|
|
28
28
|
validateSecrets
|
|
29
|
-
} = require('
|
|
30
|
-
const { processEnvVariables } = require('
|
|
31
|
-
const { buildEnvVarMap } = require('
|
|
32
|
-
const { resolveServicePortsInEnvContent } = require('
|
|
29
|
+
} = require('../utils/secrets-helpers');
|
|
30
|
+
const { processEnvVariables } = require('../utils/env-copy');
|
|
31
|
+
const { buildEnvVarMap } = require('../utils/env-map');
|
|
32
|
+
const { resolveServicePortsInEnvContent } = require('../utils/secrets-url');
|
|
33
33
|
const {
|
|
34
34
|
generateMissingSecrets,
|
|
35
35
|
createDefaultSecrets
|
|
36
|
-
} = require('
|
|
36
|
+
} = require('../utils/secrets-generator');
|
|
37
37
|
const {
|
|
38
38
|
resolveSecretsPath,
|
|
39
39
|
getActualSecretsPath
|
|
40
|
-
} = require('
|
|
40
|
+
} = require('../utils/secrets-path');
|
|
41
41
|
const {
|
|
42
42
|
loadUserSecrets,
|
|
43
43
|
loadDefaultSecrets
|
|
44
|
-
} = require('
|
|
45
|
-
const { decryptSecret, isEncrypted } = require('
|
|
46
|
-
const pathsUtil = require('
|
|
44
|
+
} = require('../utils/secrets-utils');
|
|
45
|
+
const { decryptSecret, isEncrypted } = require('../utils/secrets-encryption');
|
|
46
|
+
const pathsUtil = require('../utils/paths');
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Generates a canonical secret name from an environment variable key.
|
|
@@ -58,7 +58,10 @@ function getCanonicalSecretName(key) {
|
|
|
58
58
|
if (!key || typeof key !== 'string') {
|
|
59
59
|
return '';
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
// Insert hyphens before capital letters (camelCase -> kebab-case)
|
|
62
|
+
// Then convert to lowercase and replace non-alphanumeric with hyphens
|
|
63
|
+
const withHyphens = key.replace(/([a-z0-9])([A-Z])/g, '$1-$2');
|
|
64
|
+
const lower = withHyphens.toLowerCase();
|
|
62
65
|
const hyphenated = lower.replace(/[^a-z0-9]/g, '-');
|
|
63
66
|
const collapsed = hyphenated.replace(/-+/g, '-');
|
|
64
67
|
return collapsed.replace(/^-+|-+$/g, '');
|
|
@@ -217,21 +220,23 @@ async function resolveKvReferences(envTemplate, secrets, environment = 'local',
|
|
|
217
220
|
* // Returns: './builder/myapp/.env'
|
|
218
221
|
*/
|
|
219
222
|
/**
|
|
220
|
-
*
|
|
221
|
-
* Sets PORT to container port (build.containerPort or port from variables.yaml)
|
|
222
|
-
* NOT the host port (which includes developer-id offset)
|
|
223
|
+
* Gets base docker environment config
|
|
223
224
|
* @async
|
|
224
|
-
* @function
|
|
225
|
-
* @
|
|
226
|
-
* @param {string} variablesPath - Path to variables.yaml file
|
|
227
|
-
* @returns {Promise<string>} Updated content with PORT set
|
|
225
|
+
* @function getBaseDockerEnv
|
|
226
|
+
* @returns {Promise<Object>} Docker environment config
|
|
228
227
|
*/
|
|
229
|
-
async function
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
228
|
+
async function getBaseDockerEnv() {
|
|
229
|
+
const { getEnvHosts } = require('../utils/env-endpoints');
|
|
230
|
+
return await getEnvHosts('docker');
|
|
231
|
+
}
|
|
233
232
|
|
|
234
|
-
|
|
233
|
+
/**
|
|
234
|
+
* Applies config.yaml override to docker environment
|
|
235
|
+
* @function applyDockerEnvOverride
|
|
236
|
+
* @param {Object} dockerEnv - Base docker environment config
|
|
237
|
+
* @returns {Object} Updated docker environment config
|
|
238
|
+
*/
|
|
239
|
+
function applyDockerEnvOverride(dockerEnv) {
|
|
235
240
|
try {
|
|
236
241
|
const os = require('os');
|
|
237
242
|
const cfgPath = path.join(os.homedir(), '.aifabrix', 'config.yaml');
|
|
@@ -239,38 +244,70 @@ async function updatePortForDocker(resolved, variablesPath) {
|
|
|
239
244
|
const cfgContent = fs.readFileSync(cfgPath, 'utf8');
|
|
240
245
|
const cfg = yaml.load(cfgContent) || {};
|
|
241
246
|
if (cfg && cfg.environments && cfg.environments.docker) {
|
|
242
|
-
|
|
247
|
+
return { ...dockerEnv, ...cfg.environments.docker };
|
|
243
248
|
}
|
|
244
249
|
}
|
|
245
250
|
} catch {
|
|
246
251
|
// Ignore config.yaml read errors, continue with env-config values
|
|
247
252
|
}
|
|
253
|
+
return dockerEnv;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Gets container port from variables.yaml
|
|
258
|
+
* @function getContainerPortFromVariables
|
|
259
|
+
* @param {string} variablesPath - Path to variables.yaml
|
|
260
|
+
* @returns {number|null} Container port or null
|
|
261
|
+
*/
|
|
262
|
+
function getContainerPortFromVariables(variablesPath) {
|
|
263
|
+
if (!variablesPath || !fs.existsSync(variablesPath)) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
try {
|
|
267
|
+
const variablesContent = fs.readFileSync(variablesPath, 'utf8');
|
|
268
|
+
const variables = yaml.load(variablesContent);
|
|
269
|
+
// Use containerPort if specified, otherwise use base port (no developer-id offset)
|
|
270
|
+
return variables?.build?.containerPort || variables?.port || null;
|
|
271
|
+
} catch {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Gets container port from docker environment config
|
|
278
|
+
* @function getContainerPortFromDockerEnv
|
|
279
|
+
* @param {Object} dockerEnv - Docker environment config
|
|
280
|
+
* @returns {number} Container port (defaults to 3000)
|
|
281
|
+
*/
|
|
282
|
+
function getContainerPortFromDockerEnv(dockerEnv) {
|
|
283
|
+
if (dockerEnv.PORT === undefined || dockerEnv.PORT === null) {
|
|
284
|
+
return 3000;
|
|
285
|
+
}
|
|
286
|
+
const portVal = typeof dockerEnv.PORT === 'number' ? dockerEnv.PORT : parseInt(dockerEnv.PORT, 10);
|
|
287
|
+
return Number.isNaN(portVal) ? 3000 : portVal;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Updates PORT in resolved content for docker environment
|
|
292
|
+
* Sets PORT to container port (build.containerPort or port from variables.yaml)
|
|
293
|
+
* NOT the host port (which includes developer-id offset)
|
|
294
|
+
* @async
|
|
295
|
+
* @function updatePortForDocker
|
|
296
|
+
* @param {string} resolved - Resolved environment content
|
|
297
|
+
* @param {string} variablesPath - Path to variables.yaml file
|
|
298
|
+
* @returns {Promise<string>} Updated content with PORT set
|
|
299
|
+
*/
|
|
300
|
+
async function updatePortForDocker(resolved, variablesPath) {
|
|
301
|
+
// Step 1: Get base config from env-config.yaml
|
|
302
|
+
let dockerEnv = await getBaseDockerEnv();
|
|
303
|
+
|
|
304
|
+
// Step 2: Apply config.yaml → environments.docker override (if exists)
|
|
305
|
+
dockerEnv = applyDockerEnvOverride(dockerEnv);
|
|
248
306
|
|
|
249
307
|
// Step 3: Get PORT value for container (should be container port, NOT host port)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if (variablesPath && fs.existsSync(variablesPath)) {
|
|
254
|
-
try {
|
|
255
|
-
const variablesContent = fs.readFileSync(variablesPath, 'utf8');
|
|
256
|
-
const variables = yaml.load(variablesContent);
|
|
257
|
-
// Use containerPort if specified, otherwise use base port (no developer-id offset)
|
|
258
|
-
containerPort = variables?.build?.containerPort || variables?.port || 3000;
|
|
259
|
-
} catch {
|
|
260
|
-
// Fallback to default
|
|
261
|
-
containerPort = 3000;
|
|
262
|
-
}
|
|
263
|
-
} else {
|
|
264
|
-
// Fallback: check dockerEnv.PORT (but this should be container port, not host port)
|
|
265
|
-
if (dockerEnv.PORT !== undefined && dockerEnv.PORT !== null) {
|
|
266
|
-
const portVal = typeof dockerEnv.PORT === 'number' ? dockerEnv.PORT : parseInt(dockerEnv.PORT, 10);
|
|
267
|
-
if (!Number.isNaN(portVal)) {
|
|
268
|
-
containerPort = portVal;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
if (containerPort === null || containerPort === undefined) {
|
|
272
|
-
containerPort = 3000;
|
|
273
|
-
}
|
|
308
|
+
let containerPort = getContainerPortFromVariables(variablesPath);
|
|
309
|
+
if (containerPort === null) {
|
|
310
|
+
containerPort = getContainerPortFromDockerEnv(dockerEnv);
|
|
274
311
|
}
|
|
275
312
|
|
|
276
313
|
// PORT in container should be the container port (no developer-id adjustment)
|
|
@@ -294,7 +331,7 @@ async function applyEnvironmentTransformations(resolved, environment, variablesP
|
|
|
294
331
|
// Interpolate ${VAR} references created by rewriteInfraEndpoints
|
|
295
332
|
// Get the actual host and port values from env-endpoints.js directly
|
|
296
333
|
// to ensure they are correctly populated in envVars for interpolation
|
|
297
|
-
const { getEnvHosts, getServiceHost, getServicePort, getLocalhostOverride } = require('
|
|
334
|
+
const { getEnvHosts, getServiceHost, getServicePort, getLocalhostOverride } = require('../utils/env-endpoints');
|
|
298
335
|
const hosts = await getEnvHosts('docker');
|
|
299
336
|
const localhostOverride = getLocalhostOverride('docker');
|
|
300
337
|
const redisHost = getServiceHost(hosts.REDIS_HOST, 'docker', 'redis', localhostOverride);
|