ante-erp-cli 1.11.42 → 1.11.44

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ante-erp-cli",
3
- "version": "1.11.42",
3
+ "version": "1.11.44",
4
4
  "description": "Comprehensive CLI tool for managing ANTE ERP self-hosted installations",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,6 +8,7 @@ import { pullImagesSilent, stopServicesSilent, startServicesSilent, waitForServi
8
8
  import { backup } from './backup.js';
9
9
  import { getCurrentVersion, getLatestVersion } from './update-cli.js';
10
10
  import { generateDockerCompose } from '../templates/docker-compose.yml.js';
11
+ import { generateSecurePassword } from '../utils/password.js';
11
12
 
12
13
  /**
13
14
  * Check if gate-app, guardian-app, facial-web, or pos-app is installed by checking docker-compose.yml
@@ -236,6 +237,121 @@ COMPANY_ID=1
236
237
  writeFileSync(envFile, envContent);
237
238
  }
238
239
 
240
+ /**
241
+ * Ensure customer app JWT configuration exists in .env file
242
+ * @param {string} envFile - Path to .env file
243
+ * @returns {boolean} True if any modifications were made
244
+ */
245
+ function ensureCustomerAppJwtConfig(envFile) {
246
+ let envContent = readFileSync(envFile, 'utf8');
247
+ let modified = false;
248
+
249
+ // Check if CUSTOMER_APP_JWT_SECRET exists
250
+ if (!envContent.includes('CUSTOMER_APP_JWT_SECRET=')) {
251
+ console.log('⚙️ Adding missing CUSTOMER_APP_JWT_SECRET...');
252
+
253
+ // Generate new secret
254
+ const customerAppJwtSecret = generateSecurePassword(64);
255
+
256
+ // Find the ENCRYPTION_KEY line and add after it
257
+ if (envContent.includes('ENCRYPTION_KEY=')) {
258
+ envContent = envContent.replace(
259
+ /(ENCRYPTION_KEY=.*\n)/,
260
+ `$1\n# Customer App JWT Configuration\nCUSTOMER_APP_JWT_SECRET=${customerAppJwtSecret}\n`
261
+ );
262
+ } else {
263
+ // Fallback: add to security keys section or end of file
264
+ envContent += `\n# Customer App JWT Configuration\nCUSTOMER_APP_JWT_SECRET=${customerAppJwtSecret}\n`;
265
+ }
266
+ modified = true;
267
+ }
268
+
269
+ // Check if CUSTOMER_APP_JWT_EXPIRY exists
270
+ if (!envContent.includes('CUSTOMER_APP_JWT_EXPIRY=')) {
271
+ console.log('⚙️ Adding CUSTOMER_APP_JWT_EXPIRY...');
272
+ envContent = envContent.replace(
273
+ /(CUSTOMER_APP_JWT_SECRET=.*\n)/,
274
+ `$1CUSTOMER_APP_JWT_EXPIRY=1y\n`
275
+ );
276
+ modified = true;
277
+ } else {
278
+ // Update old expiry value (15m -> 1y)
279
+ if (envContent.includes('CUSTOMER_APP_JWT_EXPIRY=15m')) {
280
+ console.log('⚙️ Updating CUSTOMER_APP_JWT_EXPIRY from 15m to 1y...');
281
+ envContent = envContent.replace(
282
+ /CUSTOMER_APP_JWT_EXPIRY=15m/,
283
+ 'CUSTOMER_APP_JWT_EXPIRY=1y'
284
+ );
285
+ modified = true;
286
+ }
287
+ }
288
+
289
+ // Check if CUSTOMER_APP_REFRESH_TOKEN_EXPIRY exists
290
+ if (!envContent.includes('CUSTOMER_APP_REFRESH_TOKEN_EXPIRY=')) {
291
+ console.log('⚙️ Adding CUSTOMER_APP_REFRESH_TOKEN_EXPIRY...');
292
+ envContent = envContent.replace(
293
+ /(CUSTOMER_APP_JWT_EXPIRY=.*\n)/,
294
+ `$1CUSTOMER_APP_REFRESH_TOKEN_EXPIRY=1y\n`
295
+ );
296
+ modified = true;
297
+ } else {
298
+ // Update old expiry value (30d -> 1y)
299
+ if (envContent.includes('CUSTOMER_APP_REFRESH_TOKEN_EXPIRY=30d')) {
300
+ console.log('⚙️ Updating CUSTOMER_APP_REFRESH_TOKEN_EXPIRY from 30d to 1y...');
301
+ envContent = envContent.replace(
302
+ /CUSTOMER_APP_REFRESH_TOKEN_EXPIRY=30d/,
303
+ 'CUSTOMER_APP_REFRESH_TOKEN_EXPIRY=1y'
304
+ );
305
+ modified = true;
306
+ }
307
+ }
308
+
309
+ // Write back if modified
310
+ if (modified) {
311
+ writeFileSync(envFile, envContent);
312
+ console.log('✅ Customer app JWT configuration updated');
313
+ }
314
+
315
+ return modified;
316
+ }
317
+
318
+ /**
319
+ * Refresh docker-compose.yml to ensure it has latest environment variable mappings
320
+ * This regenerates the docker-compose.yml without adding new services
321
+ * @param {string} composeFile - Path to docker-compose.yml
322
+ * @param {string} envFile - Path to .env file
323
+ */
324
+ function refreshDockerCompose(composeFile, envFile) {
325
+ const envConfig = parseEnvFile(envFile);
326
+ const currentInstalled = detectInstalledApps(composeFile);
327
+
328
+ // Generate new docker-compose.yml with existing services only
329
+ const newCompose = generateDockerCompose({
330
+ frontendPort: parseInt(envConfig.FRONTEND_PORT) || 8080,
331
+ backendPort: parseInt(envConfig.BACKEND_PORT) || 3001,
332
+ gateAppPort: parseInt(envConfig.GATE_APP_PORT) || 8081,
333
+ guardianAppPort: parseInt(envConfig.GUARDIAN_APP_PORT) || 8082,
334
+ facialWebPort: parseInt(envConfig.FACIAL_WEB_PORT) || 8083,
335
+ posAppPort: parseInt(envConfig.POS_APP_PORT) || 8084,
336
+ clientAppPort: parseInt(envConfig.CLIENT_APP_PORT) || 9005,
337
+ installMain: true,
338
+ installGate: currentInstalled.hasGateApp,
339
+ installGuardian: currentInstalled.hasGuardianApp,
340
+ installFacial: currentInstalled.hasFacialWeb,
341
+ installPos: currentInstalled.hasPosApp,
342
+ installClient: currentInstalled.hasClientApp,
343
+ companyId: parseInt(envConfig.COMPANY_ID) || 1
344
+ });
345
+
346
+ // Backup existing docker-compose.yml
347
+ const timestamp = new Date().toISOString().split('.')[0].replace(/:/g, '-').replace('T', '_');
348
+ renameSync(composeFile, `${composeFile}.${timestamp}.bak`);
349
+
350
+ // Write new docker-compose.yml
351
+ writeFileSync(composeFile, newCompose);
352
+ console.log('✅ Docker Compose configuration refreshed');
353
+ }
354
+
239
355
  /**
240
356
  * Format step title with numbering
241
357
  * @param {number} step - Current step number
@@ -298,6 +414,16 @@ export async function update(options) {
298
414
  // POS App health check removed - not required
299
415
  if (!options.skipCleanup) totalSteps++; // Cleanup step
300
416
 
417
+ // Ensure customer app JWT configuration exists (run before tasks)
418
+ console.log(chalk.gray('Checking customer app JWT configuration...'));
419
+ const envModified = ensureCustomerAppJwtConfig(envFile);
420
+
421
+ // Refresh docker-compose.yml if .env was modified to ensure containers get new variables
422
+ if (envModified) {
423
+ console.log(chalk.gray('Refreshing Docker Compose configuration...'));
424
+ refreshDockerCompose(composeFile, envFile);
425
+ }
426
+
301
427
  // Pre-calculate step numbers for each task (fixes step numbering bug)
302
428
  let currentStep = 0;
303
429
  const stepPreStart = !options.skipBackup ? ++currentStep : null;
@@ -134,6 +134,9 @@ services:
134
134
  JWT_EXPIRATION: \${JWT_EXPIRATION:-24h}
135
135
  DEVELOPER_KEY: \${DEVELOPER_KEY}
136
136
  ENCRYPTION_KEY: \${ENCRYPTION_KEY}
137
+ CUSTOMER_APP_JWT_SECRET: \${CUSTOMER_APP_JWT_SECRET}
138
+ CUSTOMER_APP_JWT_EXPIRY: \${CUSTOMER_APP_JWT_EXPIRY:-1y}
139
+ CUSTOMER_APP_REFRESH_TOKEN_EXPIRY: \${CUSTOMER_APP_REFRESH_TOKEN_EXPIRY:-1y}
137
140
  FRONTEND_URL: \${FRONTEND_URL:-http://localhost:${frontendPort}}
138
141
  API_URL: \${API_URL:-http://localhost:${backendPort}}
139
142
  SOCKET_URL: \${SOCKET_URL:-http://localhost:${backendPort}}
@@ -55,6 +55,11 @@ JWT_EXPIRATION=24h
55
55
  DEVELOPER_KEY=${credentials.developerKey}
56
56
  ENCRYPTION_KEY=${credentials.encryptionKey}
57
57
 
58
+ # Customer App JWT Configuration
59
+ CUSTOMER_APP_JWT_SECRET=${credentials.customerAppJwtSecret}
60
+ CUSTOMER_APP_JWT_EXPIRY=1y
61
+ CUSTOMER_APP_REFRESH_TOKEN_EXPIRY=1y
62
+
58
63
  # ------------------------------------------------------------------------------
59
64
  # APPLICATION URLs
60
65
  # ------------------------------------------------------------------------------
@@ -36,6 +36,7 @@ export function generateCredentials() {
36
36
  jwtSecret: generateSecurePassword(64),
37
37
  developerKey: generateRandomHex(16),
38
38
  encryptionKey: generateRandomHex(16),
39
+ customerAppJwtSecret: generateSecurePassword(64),
39
40
  };
40
41
  }
41
42