@aifabrix/builder 2.0.0 → 2.0.3

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 (61) hide show
  1. package/README.md +5 -3
  2. package/bin/aifabrix.js +9 -3
  3. package/jest.config.integration.js +30 -0
  4. package/lib/app-config.js +157 -0
  5. package/lib/app-deploy.js +233 -82
  6. package/lib/app-dockerfile.js +112 -0
  7. package/lib/app-prompts.js +244 -0
  8. package/lib/app-push.js +172 -0
  9. package/lib/app-run.js +235 -144
  10. package/lib/app.js +208 -274
  11. package/lib/audit-logger.js +2 -0
  12. package/lib/build.js +177 -125
  13. package/lib/cli.js +76 -86
  14. package/lib/commands/app.js +414 -0
  15. package/lib/commands/login.js +304 -0
  16. package/lib/config.js +78 -0
  17. package/lib/deployer.js +225 -81
  18. package/lib/env-reader.js +45 -30
  19. package/lib/generator.js +308 -191
  20. package/lib/github-generator.js +67 -7
  21. package/lib/infra.js +156 -61
  22. package/lib/push.js +105 -10
  23. package/lib/schema/application-schema.json +30 -2
  24. package/lib/schema/env-config.yaml +9 -1
  25. package/lib/schema/infrastructure-schema.json +589 -0
  26. package/lib/secrets.js +229 -24
  27. package/lib/template-validator.js +205 -0
  28. package/lib/templates.js +305 -170
  29. package/lib/utils/api.js +329 -0
  30. package/lib/utils/cli-utils.js +97 -0
  31. package/lib/utils/compose-generator.js +185 -0
  32. package/lib/utils/docker-build.js +173 -0
  33. package/lib/utils/dockerfile-utils.js +131 -0
  34. package/lib/utils/environment-checker.js +125 -0
  35. package/lib/utils/error-formatter.js +61 -0
  36. package/lib/utils/health-check.js +187 -0
  37. package/lib/utils/logger.js +53 -0
  38. package/lib/utils/template-helpers.js +223 -0
  39. package/lib/utils/variable-transformer.js +271 -0
  40. package/lib/validator.js +27 -112
  41. package/package.json +14 -10
  42. package/templates/README.md +75 -3
  43. package/templates/applications/keycloak/Dockerfile +36 -0
  44. package/templates/applications/keycloak/env.template +32 -0
  45. package/templates/applications/keycloak/rbac.yaml +37 -0
  46. package/templates/applications/keycloak/variables.yaml +56 -0
  47. package/templates/applications/miso-controller/Dockerfile +125 -0
  48. package/templates/applications/miso-controller/env.template +129 -0
  49. package/templates/applications/miso-controller/rbac.yaml +214 -0
  50. package/templates/applications/miso-controller/variables.yaml +56 -0
  51. package/templates/github/release.yaml.hbs +5 -26
  52. package/templates/github/steps/npm.hbs +24 -0
  53. package/templates/infra/compose.yaml +6 -6
  54. package/templates/python/docker-compose.hbs +19 -12
  55. package/templates/python/main.py +80 -0
  56. package/templates/python/requirements.txt +4 -0
  57. package/templates/typescript/Dockerfile.hbs +2 -2
  58. package/templates/typescript/docker-compose.hbs +19 -12
  59. package/templates/typescript/index.ts +116 -0
  60. package/templates/typescript/package.json +26 -0
  61. package/templates/typescript/tsconfig.json +24 -0
package/lib/templates.js CHANGED
@@ -9,41 +9,88 @@ const yaml = require('js-yaml');
9
9
 
10
10
  /**
11
11
  * Generate variables.yaml content for an application
12
+ * Matches application-schema.json structure
12
13
  * @param {string} appName - Application name
13
14
  * @param {Object} config - Configuration options
14
15
  * @returns {string} YAML content
15
16
  */
16
17
  function generateVariablesYaml(appName, config) {
18
+ const displayName = appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
19
+
20
+ // Parse image name to separate name and tag
21
+ let imageName = appName;
22
+ let imageTag = 'latest';
23
+ const imageNameWithTag = `${appName}:latest`;
24
+ const colonIndex = imageNameWithTag.lastIndexOf(':');
25
+ if (colonIndex !== -1) {
26
+ imageName = imageNameWithTag.substring(0, colonIndex);
27
+ imageTag = imageNameWithTag.substring(colonIndex + 1);
28
+ }
29
+
17
30
  const variables = {
18
31
  app: {
19
32
  key: appName,
20
- name: appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase()),
33
+ displayName: displayName,
21
34
  description: `${appName.replace(/-/g, ' ')} application`,
22
- version: '1.0.0'
35
+ type: 'webapp'
23
36
  },
24
- build: {
25
- language: config.language || 'typescript',
26
- port: parseInt(config.port, 10) || 3000,
27
- environment: 'development'
37
+ image: {
38
+ name: imageName,
39
+ tag: imageTag,
40
+ registry: '',
41
+ registryMode: 'external'
28
42
  },
29
- services: {
43
+ port: parseInt(config.port, 10) || 3000,
44
+ requires: {
30
45
  database: config.database || false,
31
46
  redis: config.redis || false,
32
- storage: config.storage || false,
33
- authentication: config.authentication || false
47
+ storage: config.storage || false
34
48
  },
35
- security: {
36
- enableRBAC: config.authentication || false,
37
- requireAuth: config.authentication || false,
38
- auditLogging: true
49
+ build: {
50
+ language: config.language || 'typescript',
51
+ envOutputPath: null,
52
+ context: `../${appName}`,
53
+ dockerfile: '',
54
+ secrets: null
39
55
  },
40
- monitoring: {
41
- healthCheck: true,
42
- metrics: true,
43
- logging: true
56
+ repository: {
57
+ enabled: false,
58
+ repositoryUrl: ''
59
+ },
60
+ deployment: {
61
+ controllerUrl: '',
62
+ environment: 'dev',
63
+ clientId: '',
64
+ clientSecret: ''
44
65
  }
45
66
  };
46
67
 
68
+ // Add databases array when database is enabled
69
+ if (config.database) {
70
+ // Database names must match schema pattern: ^[a-z0-9_]+$ (no hyphens)
71
+ const dbName = appName.replace(/-/g, '_');
72
+ variables.requires.databases = [
73
+ { name: dbName }
74
+ ];
75
+ }
76
+
77
+ // Add optional healthCheck at top level
78
+ if (config.healthCheck !== false) {
79
+ variables.healthCheck = {
80
+ path: '/health',
81
+ interval: 30
82
+ };
83
+ }
84
+
85
+ // Add optional authentication at top level
86
+ if (config.authentication) {
87
+ variables.authentication = {
88
+ type: 'azure',
89
+ enableSSO: true,
90
+ requiredRoles: ['aifabrix-user']
91
+ };
92
+ }
93
+
47
94
  return yaml.dump(variables, {
48
95
  indent: 2,
49
96
  lineWidth: 120,
@@ -53,185 +100,295 @@ function generateVariablesYaml(appName, config) {
53
100
  }
54
101
 
55
102
  /**
56
- * Generate env.template content with conditional variables
103
+ * Builds core application environment variables
57
104
  * @param {Object} config - Configuration options
58
- * @param {Object} existingEnv - Existing environment variables
59
- * @returns {string} Environment template content
105
+ * @returns {Object} Core environment variables
60
106
  */
61
- function generateEnvTemplate(config, existingEnv = {}) {
62
- const envVars = {
63
- // Core application settings
107
+ function buildCoreEnv(config) {
108
+ return {
64
109
  'NODE_ENV': 'development',
65
110
  'PORT': config.port || 3000,
66
111
  'APP_NAME': config.appName || 'myapp',
67
112
  'LOG_LEVEL': 'info'
68
113
  };
114
+ }
69
115
 
70
- // Add database variables if enabled
71
- if (config.database) {
72
- envVars['DATABASE_URL'] = 'kv://database-url';
73
- envVars['DB_HOST'] = 'localhost';
74
- envVars['DB_PORT'] = '5432';
75
- envVars['DB_NAME'] = config.appName || 'myapp';
76
- envVars['DB_USER'] = 'kv://database-user';
77
- envVars['DB_PASSWORD'] = 'kv://database-password';
116
+ function buildDatabaseEnv(config) {
117
+ if (!config.database) {
118
+ return {};
78
119
  }
79
120
 
80
- // Add Redis variables if enabled
81
- if (config.redis) {
82
- envVars['REDIS_URL'] = 'kv://redis-url';
83
- envVars['REDIS_HOST'] = 'localhost';
84
- envVars['REDIS_PORT'] = '6379';
85
- envVars['REDIS_PASSWORD'] = 'kv://redis-password';
121
+ const appName = config.appName || 'myapp';
122
+ // Database names must use underscores (PostgreSQL doesn't allow hyphens)
123
+ const dbName = appName.replace(/-/g, '_');
124
+
125
+ return {
126
+ 'DATABASE_URL': `kv://databases-${appName}-0-urlKeyVault`,
127
+ 'DB_HOST': '${DB_HOST}',
128
+ 'DB_PORT': '5432',
129
+ 'DB_NAME': dbName,
130
+ 'DB_USER': `${dbName}_user`,
131
+ 'DB_PASSWORD': `kv://databases-${appName}-0-passwordKeyVault`
132
+ };
133
+ }
134
+
135
+ function buildRedisEnv(config) {
136
+ if (!config.redis) {
137
+ return {};
86
138
  }
87
139
 
88
- // Add storage variables if enabled
89
- if (config.storage) {
90
- envVars['STORAGE_TYPE'] = 'local';
91
- envVars['STORAGE_PATH'] = '/app/storage';
92
- envVars['STORAGE_URL'] = 'kv://storage-url';
93
- envVars['STORAGE_KEY'] = 'kv://storage-key';
94
- envVars['STORAGE_SECRET'] = 'kv://storage-secret';
140
+ return {
141
+ 'REDIS_URL': 'kv://redis-url',
142
+ 'REDIS_HOST': '${REDIS_HOST}',
143
+ 'REDIS_PORT': '6379',
144
+ 'REDIS_PASSWORD': 'kv://redis-password'
145
+ };
146
+ }
147
+
148
+ function buildStorageEnv(config) {
149
+ if (!config.storage) {
150
+ return {};
95
151
  }
96
152
 
97
- // Add authentication variables if enabled
98
- if (config.authentication) {
99
- envVars['JWT_SECRET'] = 'kv://jwt-secret';
100
- envVars['JWT_EXPIRES_IN'] = '24h';
101
- envVars['AUTH_PROVIDER'] = 'local';
102
- envVars['SESSION_SECRET'] = 'kv://session-secret';
153
+ return {
154
+ 'STORAGE_TYPE': 'local',
155
+ 'STORAGE_PATH': '/app/storage',
156
+ 'STORAGE_URL': 'kv://storage-url',
157
+ 'STORAGE_KEY': 'kv://storage-key',
158
+ 'STORAGE_SECRET': 'kv://storage-secret'
159
+ };
160
+ }
161
+
162
+ function buildAuthEnv(config) {
163
+ if (!config.authentication) {
164
+ return {};
165
+ }
166
+
167
+ return {
168
+ 'JWT_SECRET': 'kv://jwt-secret',
169
+ 'JWT_EXPIRES_IN': '24h',
170
+ 'AUTH_PROVIDER': 'local',
171
+ 'SESSION_SECRET': 'kv://session-secret'
172
+ };
173
+ }
174
+
175
+ function buildMonitoringEnv(config) {
176
+ if (!config.controller) {
177
+ return {};
103
178
  }
104
179
 
180
+ return {
181
+ 'MISO_CONTROLLER_URL': config.controllerUrl || 'https://controller.aifabrix.ai',
182
+ 'MISO_ENVIRONMENT': 'dev',
183
+ 'MISO_CLIENTID': 'kv://miso-clientid',
184
+ 'MISO_CLIENTSECRET': 'kv://miso-clientsecret'
185
+ };
186
+ }
187
+
188
+ /**
189
+ * Adds core variables section to template lines
190
+ * @param {Array<string>} lines - Template lines array
191
+ * @param {Object} envVars - Environment variables
192
+ */
193
+ function addCoreVariables(lines, envVars) {
194
+ Object.entries(envVars).forEach(([key, value]) => {
195
+ if (key.startsWith('NODE_ENV') || key.startsWith('PORT') ||
196
+ key.startsWith('APP_NAME') || key.startsWith('LOG_LEVEL')) {
197
+ lines.push(`${key}=${value}`);
198
+ }
199
+ });
200
+ }
201
+
202
+ function addMonitoringSection(lines, envVars) {
203
+ lines.push('', '# MISO Controller Configuration', '');
204
+ lines.push(`MISO_CONTROLLER_URL=${envVars['MISO_CONTROLLER_URL']}`);
205
+ lines.push(`MISO_ENVIRONMENT=${envVars['MISO_ENVIRONMENT']}`);
206
+ lines.push(`MISO_CLIENTID=${envVars['MISO_CLIENTID']}`);
207
+ lines.push(`MISO_CLIENTSECRET=${envVars['MISO_CLIENTSECRET']}`);
208
+ }
209
+
210
+ function addDatabaseSection(lines, envVars) {
211
+ lines.push('', '# =============================================================================');
212
+ lines.push('# DATABASE CONFIGURATION');
213
+ lines.push('# =============================================================================');
214
+ lines.push('# Connects to external postgres from aifabrix-setup');
215
+ lines.push('');
216
+ // Add all DB_* and DATABASE_* variables together (sorted for consistency)
217
+ const dbVars = Object.entries(envVars)
218
+ .filter(([key]) => key.startsWith('DB_') || key.startsWith('DATABASE_'))
219
+ .sort(([a], [b]) => {
220
+ // Sort DB_* before DATABASE_*, then alphabetically
221
+ const aPrefix = a.startsWith('DB_') ? 0 : 1;
222
+ const bPrefix = b.startsWith('DB_') ? 0 : 1;
223
+ if (aPrefix !== bPrefix) return aPrefix - bPrefix;
224
+ return a.localeCompare(b);
225
+ });
226
+ dbVars.forEach(([key, value]) => {
227
+ lines.push(`${key}=${value}`);
228
+ });
229
+ }
230
+
231
+ function addRedisSection(lines, envVars) {
232
+ lines.push('', '# =============================================================================');
233
+ lines.push('# REDIS CONFIGURATION');
234
+ lines.push('# =============================================================================');
235
+ lines.push('# Connects to external redis from aifabrix-setup');
236
+ lines.push('');
237
+ Object.entries(envVars).forEach(([key, value]) => {
238
+ if (key.startsWith('REDIS_')) {
239
+ lines.push(`${key}=${value}`);
240
+ }
241
+ });
242
+ }
243
+
244
+ function addStorageSection(lines, envVars) {
245
+ lines.push('', '# =============================================================================');
246
+ lines.push('# STORAGE CONFIGURATION');
247
+ lines.push('# =============================================================================');
248
+ lines.push('');
249
+ Object.entries(envVars).forEach(([key, value]) => {
250
+ if (key.startsWith('STORAGE_')) {
251
+ lines.push(`${key}=${value}`);
252
+ }
253
+ });
254
+ }
255
+
256
+ function addAuthenticationSection(lines, envVars) {
257
+ lines.push('', '# =============================================================================');
258
+ lines.push('# AUTHENTICATION CONFIGURATION');
259
+ lines.push('# =============================================================================');
260
+ lines.push('# Connects to external keycloak from aifabrix-setup');
261
+ lines.push('');
262
+ // Add all JWT_*, AUTH_*, and SESSION_* variables together (sorted for consistency)
263
+ const authVars = Object.entries(envVars)
264
+ .filter(([key]) => key.startsWith('JWT_') || key.startsWith('AUTH_') || key.startsWith('SESSION_'))
265
+ .sort(([a], [b]) => {
266
+ // Sort by prefix priority: JWT_ (0), AUTH_ (1), SESSION_ (2), then alphabetically
267
+ const getPrefixPriority = (key) => {
268
+ if (key.startsWith('JWT_')) return 0;
269
+ if (key.startsWith('AUTH_')) return 1;
270
+ if (key.startsWith('SESSION_')) return 2;
271
+ return 3;
272
+ };
273
+ const aPriority = getPrefixPriority(a);
274
+ const bPriority = getPrefixPriority(b);
275
+ if (aPriority !== bPriority) return aPriority - bPriority;
276
+ return a.localeCompare(b);
277
+ });
278
+ authVars.forEach(([key, value]) => {
279
+ lines.push(`${key}=${value}`);
280
+ });
281
+ }
282
+
283
+ /**
284
+ * Generate env.template content with conditional variables
285
+ * @param {Object} config - Configuration options
286
+ * @param {Object} existingEnv - Existing environment variables
287
+ * @returns {string} Environment template content
288
+ */
289
+ function generateEnvTemplate(config, existingEnv = {}) {
290
+ const envVars = {
291
+ ...buildCoreEnv(config),
292
+ ...buildDatabaseEnv(config),
293
+ ...buildRedisEnv(config),
294
+ ...buildStorageEnv(config),
295
+ ...buildAuthEnv(config),
296
+ ...buildMonitoringEnv(config)
297
+ };
298
+
105
299
  // Merge with existing environment variables
106
300
  Object.assign(envVars, existingEnv);
107
301
 
108
302
  // Generate template content
109
303
  const lines = [
110
- '# AI Fabrix Environment Template',
111
- '# Copy this file to .env and fill in the actual values',
112
- '# Values marked with kv:// are secrets stored in Azure Key Vault',
304
+ '# Environment Variables Template',
305
+ '# Use kv:// references for secrets (resolved from .aifabrix/secrets.yaml)',
306
+ '# Use ${VAR} for environment-specific values',
113
307
  '',
114
- '# Core Application Settings',
308
+ '# =============================================================================',
309
+ '# APPLICATION ENVIRONMENT',
310
+ '# =============================================================================',
115
311
  ''
116
312
  ];
117
313
 
118
314
  // Add core variables
119
- Object.entries(envVars).forEach(([key, value]) => {
120
- if (key.startsWith('NODE_ENV') || key.startsWith('PORT') ||
121
- key.startsWith('APP_NAME') || key.startsWith('LOG_LEVEL')) {
122
- lines.push(`${key}=${value}`);
123
- }
124
- });
315
+ addCoreVariables(lines, envVars);
125
316
 
126
317
  // Add service-specific sections
127
318
  if (config.database) {
128
- lines.push('', '# Database Configuration', '');
129
- Object.entries(envVars).forEach(([key, value]) => {
130
- if (key.startsWith('DB_') || key.startsWith('DATABASE_')) {
131
- lines.push(`${key}=${value}`);
132
- }
133
- });
319
+ addDatabaseSection(lines, envVars);
134
320
  }
135
321
 
136
322
  if (config.redis) {
137
- lines.push('', '# Redis Configuration', '');
138
- Object.entries(envVars).forEach(([key, value]) => {
139
- if (key.startsWith('REDIS_')) {
140
- lines.push(`${key}=${value}`);
141
- }
142
- });
323
+ addRedisSection(lines, envVars);
143
324
  }
144
325
 
145
326
  if (config.storage) {
146
- lines.push('', '# Storage Configuration', '');
147
- Object.entries(envVars).forEach(([key, value]) => {
148
- if (key.startsWith('STORAGE_')) {
149
- lines.push(`${key}=${value}`);
150
- }
151
- });
327
+ addStorageSection(lines, envVars);
152
328
  }
153
329
 
154
330
  if (config.authentication) {
155
- lines.push('', '# Authentication Configuration', '');
156
- Object.entries(envVars).forEach(([key, value]) => {
157
- if (key.startsWith('JWT_') || key.startsWith('AUTH_') || key.startsWith('SESSION_')) {
158
- lines.push(`${key}=${value}`);
159
- }
160
- });
331
+ addAuthenticationSection(lines, envVars);
332
+ }
333
+
334
+ if (config.controller) {
335
+ addMonitoringSection(lines, envVars);
161
336
  }
162
337
 
163
338
  return lines.join('\n');
164
339
  }
165
340
 
166
- /**
167
- * Generate rbac.yaml content for RBAC configuration
168
- * @param {string} appName - Application name
169
- * @param {Object} config - Configuration options
170
- * @returns {string} RBAC YAML content
171
- */
172
341
  function generateRbacYaml(appName, config) {
173
342
  if (!config.authentication) {
174
343
  return null;
175
344
  }
176
345
 
177
- const rbac = {
178
- apiVersion: 'v1',
179
- kind: 'RBACConfig',
180
- metadata: {
181
- name: `${appName}-rbac`,
182
- namespace: 'default'
346
+ // Format roles with name, value, and description
347
+ const roles = [
348
+ {
349
+ name: 'AI Fabrix Admin',
350
+ value: 'aifabrix-admin',
351
+ description: 'Full access to all application features and configurations'
352
+ },
353
+ {
354
+ name: 'AI Fabrix User',
355
+ value: 'aifabrix-user',
356
+ description: 'Basic user access to the application'
183
357
  },
184
- spec: {
185
- roles: [
186
- {
187
- name: 'admin',
188
- description: 'Full administrative access',
189
- permissions: ['*']
190
- },
191
- {
192
- name: 'user',
193
- description: 'Standard user access',
194
- permissions: ['read', 'write']
195
- },
196
- {
197
- name: 'viewer',
198
- description: 'Read-only access',
199
- permissions: ['read']
200
- }
201
- ],
202
- policies: [
203
- {
204
- name: 'admin-policy',
205
- role: 'admin',
206
- resources: ['*'],
207
- actions: ['*']
208
- },
209
- {
210
- name: 'user-policy',
211
- role: 'user',
212
- resources: ['data', 'profile'],
213
- actions: ['read', 'write']
214
- },
215
- {
216
- name: 'viewer-policy',
217
- role: 'viewer',
218
- resources: ['data'],
219
- actions: ['read']
220
- }
221
- ],
222
- bindings: [
223
- {
224
- name: 'admin-binding',
225
- role: 'admin',
226
- subjects: [
227
- {
228
- kind: 'User',
229
- name: 'admin@example.com'
230
- }
231
- ]
232
- }
233
- ]
358
+ {
359
+ name: 'AI Fabrix Developer',
360
+ value: 'aifabrix-developer',
361
+ description: 'Developer access for testing and debugging'
234
362
  }
363
+ ];
364
+
365
+ // Format permissions with name, roles array, and description
366
+ const permissions = [
367
+ {
368
+ name: `${appName}:read`,
369
+ roles: ['aifabrix-user', 'aifabrix-admin', 'aifabrix-developer'],
370
+ description: 'Read access to application data'
371
+ },
372
+ {
373
+ name: `${appName}:write`,
374
+ roles: ['aifabrix-admin', 'aifabrix-developer'],
375
+ description: 'Create and edit application data'
376
+ },
377
+ {
378
+ name: `${appName}:delete`,
379
+ roles: ['aifabrix-admin'],
380
+ description: 'Delete application data'
381
+ },
382
+ {
383
+ name: `${appName}:admin`,
384
+ roles: ['aifabrix-admin'],
385
+ description: 'Administrative access to application configuration'
386
+ }
387
+ ];
388
+
389
+ const rbac = {
390
+ roles: roles,
391
+ permissions: permissions
235
392
  };
236
393
 
237
394
  return yaml.dump(rbac, {
@@ -242,55 +399,33 @@ function generateRbacYaml(appName, config) {
242
399
  });
243
400
  }
244
401
 
245
- /**
246
- * Generate secrets.yaml content for sensitive values
247
- * @param {Object} config - Configuration options
248
- * @param {Object} existingSecrets - Existing secrets from .env
249
- * @returns {string} Secrets YAML content
250
- */
251
402
  function generateSecretsYaml(config, existingSecrets = {}) {
252
403
  const secrets = {
253
404
  apiVersion: 'v1',
254
405
  kind: 'Secret',
255
- metadata: {
256
- name: 'app-secrets',
257
- namespace: 'default'
258
- },
406
+ metadata: { name: 'app-secrets', namespace: 'default' },
259
407
  type: 'Opaque',
260
408
  data: {}
261
409
  };
262
-
263
- // Add secrets based on enabled services
264
410
  if (config.database) {
265
411
  secrets.data['database-password'] = 'base64-encoded-password';
266
412
  secrets.data['database-user'] = 'base64-encoded-user';
267
413
  }
268
-
269
414
  if (config.redis) {
270
415
  secrets.data['redis-password'] = 'base64-encoded-redis-password';
271
416
  }
272
-
273
417
  if (config.storage) {
274
418
  secrets.data['storage-key'] = 'base64-encoded-storage-key';
275
419
  secrets.data['storage-secret'] = 'base64-encoded-storage-secret';
276
420
  }
277
-
278
421
  if (config.authentication) {
279
422
  secrets.data['jwt-secret'] = 'base64-encoded-jwt-secret';
280
423
  secrets.data['session-secret'] = 'base64-encoded-session-secret';
281
424
  }
282
-
283
- // Add existing secrets
284
425
  Object.entries(existingSecrets).forEach(([key, value]) => {
285
426
  secrets.data[key] = Buffer.from(value).toString('base64');
286
427
  });
287
-
288
- return yaml.dump(secrets, {
289
- indent: 2,
290
- lineWidth: 120,
291
- noRefs: true,
292
- sortKeys: false
293
- });
428
+ return yaml.dump(secrets, { indent: 2, lineWidth: 120, noRefs: true, sortKeys: false });
294
429
  }
295
430
 
296
431
  module.exports = {