@burgan-tech/vnext-workflow-cli 1.0.2 → 1.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.
package/README.md CHANGED
@@ -254,18 +254,85 @@ wf csx --file x.csx # Process a single file
254
254
  **Purpose**: Configuration management
255
255
 
256
256
  ```bash
257
- wf config get # Show all settings
257
+ wf config get # Show all settings (active domain)
258
258
  wf config get PROJECT_ROOT # Show a specific setting
259
- wf config set DB_PASSWORD pass # Change a setting
259
+ wf config set DB_PASSWORD pass # Change a setting (on active domain)
260
260
  ```
261
261
 
262
+ **Note:** `config get` and `config set` always operate on the **active domain**. Use `wf domain use <name>` to switch domains.
263
+
264
+ ---
265
+
266
+ ### `wf domain [action] [name] [options]`
267
+
268
+ **Purpose**: Multidomain management
269
+
270
+ Manage multiple domain configurations. Switch between domains with a single command. All CLI commands automatically use the active domain's settings.
271
+
272
+ ```bash
273
+ # Show active domain name
274
+ wf domain active
275
+
276
+ # List all domains
277
+ wf domain list
278
+ wf domain --list
279
+
280
+ # Add a new domain
281
+ wf domain add staging --API_BASE_URL http://staging.example.com:4201 --DB_NAME vNext_StagingDb
282
+
283
+ # Add a domain with multiple settings
284
+ wf domain add production \
285
+ --API_BASE_URL http://prod.example.com:4201 \
286
+ --DB_NAME vNext_ProdDb \
287
+ --DB_HOST prod-db.example.com \
288
+ --DB_USER prod_user \
289
+ --DB_PASSWORD prod_pass
290
+
291
+ # Switch active domain
292
+ wf domain use staging
293
+
294
+ # Remove a domain
295
+ wf domain remove staging
296
+ ```
297
+
298
+ **Notes:**
299
+ - When adding a domain, any unspecified settings are inherited from the `default` domain.
300
+ - The `default` domain cannot be removed.
301
+ - If the active domain is removed, the CLI automatically switches to `default`.
302
+
262
303
  ---
263
304
 
264
305
  ## ⚙️ Configuration Variables
265
306
 
266
307
  Config file location: `~/.config/vnext-workflow-cli/config.json`
267
308
 
268
- ### All Available Settings
309
+ ### Config File Format
310
+
311
+ The config file uses a domain-aware structure. Each domain has its own set of configuration values:
312
+
313
+ ```json
314
+ {
315
+ "ACTIVE_DOMAIN": "default",
316
+ "DOMAINS": [
317
+ {
318
+ "DOMAIN_NAME": "default",
319
+ "AUTO_DISCOVER": true,
320
+ "API_BASE_URL": "http://localhost:4201",
321
+ "API_VERSION": "v1",
322
+ "DB_HOST": "localhost",
323
+ "DB_PORT": 5432,
324
+ "DB_NAME": "vNext_WorkflowDb",
325
+ "DB_USER": "postgres",
326
+ "DB_PASSWORD": "postgres",
327
+ "USE_DOCKER": false,
328
+ "DOCKER_POSTGRES_CONTAINER": "vnext-postgres",
329
+ "DEBUG_MODE": false
330
+ }
331
+ ]
332
+ }
333
+ ```
334
+
335
+ ### All Available Settings (Per Domain)
269
336
 
270
337
  | Variable | Default | Description |
271
338
  |----------|---------|-------------|
@@ -287,7 +354,7 @@ Config file location: `~/.config/vnext-workflow-cli/config.json`
287
354
  ### Quick Setup Examples
288
355
 
289
356
  ```bash
290
- # API settings
357
+ # API settings (applied to active domain)
291
358
  wf config set API_BASE_URL http://localhost:4201
292
359
  wf config set API_VERSION v1
293
360
 
@@ -351,6 +418,26 @@ wf reset
351
418
  wf csx
352
419
  ```
353
420
 
421
+ ### 6. Multidomain Workflow
422
+ ```bash
423
+ # Add domains
424
+ wf domain add domain-a --API_BASE_URL http://localhost:4201 --DB_NAME vNext_DomainA
425
+ wf domain add domain-b --API_BASE_URL http://localhost:4221 --DB_NAME vNext_DomainB
426
+
427
+ # Work on Domain A
428
+ wf domain use domain-a
429
+ wf check
430
+ wf update
431
+
432
+ # Switch to Domain B - config is applied automatically
433
+ wf domain use domain-b
434
+ wf check
435
+ wf update
436
+
437
+ # See all domains
438
+ wf domain list
439
+ ```
440
+
354
441
  ---
355
442
 
356
443
  ## 🔄 Command Comparison
@@ -364,6 +451,89 @@ wf csx
364
451
 
365
452
  ---
366
453
 
454
+ ## 🔀 Multidomain Support
455
+
456
+ ### Overview
457
+
458
+ The CLI supports managing multiple domain configurations. Each domain has its own `API_BASE_URL`, `DB_NAME`, and other settings. Switch between domains with a single command.
459
+
460
+ ### Backward Compatibility
461
+
462
+ - Existing single-domain configurations are automatically migrated to the new format.
463
+ - A `default` domain is created with your existing settings.
464
+ - If you don't use multidomain features, everything works exactly as before.
465
+ - All `wf config get/set` commands continue to work (they operate on the active domain).
466
+
467
+ ### Migration
468
+
469
+ When upgrading from an older version, the CLI automatically migrates the config file:
470
+
471
+ **Before (old flat format):**
472
+ ```json
473
+ {
474
+ "API_BASE_URL": "http://localhost:4201",
475
+ "DB_NAME": "vNext_WorkflowDb"
476
+ }
477
+ ```
478
+
479
+ **After (new domain-aware format):**
480
+ ```json
481
+ {
482
+ "ACTIVE_DOMAIN": "default",
483
+ "DOMAINS": [
484
+ {
485
+ "DOMAIN_NAME": "default",
486
+ "AUTO_DISCOVER": true,
487
+ "API_BASE_URL": "http://localhost:4201",
488
+ "API_VERSION": "v1",
489
+ "DB_HOST": "localhost",
490
+ "DB_PORT": 5432,
491
+ "DB_NAME": "vNext_WorkflowDb",
492
+ "DB_USER": "postgres",
493
+ "DB_PASSWORD": "postgres",
494
+ "USE_DOCKER": false,
495
+ "DOCKER_POSTGRES_CONTAINER": "vnext-postgres",
496
+ "DEBUG_MODE": false
497
+ }
498
+ ]
499
+ }
500
+ ```
501
+
502
+ Your existing values are preserved. Any missing keys are filled in from defaults (11 keys total).
503
+
504
+ No manual action is required. The migration happens automatically on first run.
505
+
506
+ ### Domain Commands
507
+
508
+ | Command | Description |
509
+ |---------|-------------|
510
+ | `wf domain active` | Show active domain name |
511
+ | `wf domain list` | List all domains with active indicator |
512
+ | `wf domain --list` | List all domains (shorthand) |
513
+ | `wf domain add <name> [options]` | Add a new domain |
514
+ | `wf domain use <name>` | Switch active domain |
515
+ | `wf domain remove <name>` | Remove a domain |
516
+
517
+ ### Available Options for `wf domain add`
518
+
519
+ | Option | Description |
520
+ |--------|-------------|
521
+ | `--API_BASE_URL <url>` | API base URL |
522
+ | `--API_VERSION <version>` | API version |
523
+ | `--DB_HOST <host>` | Database host |
524
+ | `--DB_PORT <port>` | Database port |
525
+ | `--DB_NAME <name>` | Database name |
526
+ | `--DB_USER <user>` | Database user |
527
+ | `--DB_PASSWORD <password>` | Database password |
528
+ | `--AUTO_DISCOVER <true/false>` | Auto discover components |
529
+ | `--USE_DOCKER <true/false>` | Use Docker for DB |
530
+ | `--DOCKER_POSTGRES_CONTAINER <name>` | Docker container name |
531
+ | `--DEBUG_MODE <true/false>` | Debug mode |
532
+
533
+ Unspecified options inherit from the `default` domain.
534
+
535
+ ---
536
+
367
537
  ## 🆘 Troubleshooting
368
538
 
369
539
  ### "vnext.config.json not found"
@@ -501,6 +671,7 @@ vnext-workflow-cli/
501
671
  │ │ ├── check.js
502
672
  │ │ ├── config.js
503
673
  │ │ ├── csx.js
674
+ │ │ ├── domain.js # Multidomain management
504
675
  │ │ ├── reset.js
505
676
  │ │ ├── sync.js
506
677
  │ │ └── update.js
package/bin/workflow.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { program } = require('commander');
3
+ const { program, Argument } = require('commander');
4
4
  const chalk = require('chalk');
5
5
  const pkg = require('../package.json');
6
6
 
@@ -11,6 +11,7 @@ const updateCommand = require('../src/commands/update');
11
11
  const syncCommand = require('../src/commands/sync');
12
12
  const resetCommand = require('../src/commands/reset');
13
13
  const configCommand = require('../src/commands/config');
14
+ const domainCommand = require('../src/commands/domain');
14
15
 
15
16
  program
16
17
  .name('workflow')
@@ -20,46 +21,80 @@ program
20
21
  // Check command
21
22
  program
22
23
  .command('check')
23
- .description('Sistem kontrolü (API, DB, klasörler)')
24
+ .description('System check (API, DB, directories)')
24
25
  .action(checkCommand);
25
26
 
26
27
  // CSX command
27
28
  program
28
29
  .command('csx')
29
- .description('CSX dosyalarını güncelle')
30
- .option('-a, --all', 'Tüm CSX dosyalarını güncelle')
31
- .option('-f, --file <path>', 'Belirli bir CSX dosyasını güncelle')
30
+ .description('Update CSX files')
31
+ .option('-a, --all', 'Update all CSX files')
32
+ .option('-f, --file <path>', 'Update a specific CSX file')
32
33
  .action(csxCommand);
33
34
 
34
35
  // Update command
35
36
  program
36
37
  .command('update')
37
- .description('Workflow\'ları güncelle')
38
- .option('-a, --all', 'Tüm workflow\'ları güncelle')
39
- .option('-f, --file <path>', 'Belirli bir workflow\'u güncelle')
38
+ .description('Update workflows')
39
+ .option('-a, --all', 'Update all workflows')
40
+ .option('-f, --file <path>', 'Update a specific workflow')
40
41
  .action(updateCommand);
41
42
 
42
43
  // Sync command
43
44
  program
44
45
  .command('sync')
45
- .description('DB\'de eksik olanları ekle')
46
+ .description('Add missing entries to DB')
46
47
  .action(syncCommand);
47
48
 
48
49
  // Reset command
49
50
  program
50
51
  .command('reset')
51
- .description('Workflow\'ları resetle (force update)')
52
+ .description('Reset workflows (force update)')
52
53
  .action(resetCommand);
53
54
 
54
55
  // Config command
55
56
  program
56
57
  .command('config')
57
- .description('Konfigürasyon yönetimi')
58
- .argument('<action>', 'set veya get')
58
+ .description('Configuration management')
59
+ .argument('<action>', 'set or get')
59
60
  .argument('[key]', 'Config key')
60
61
  .argument('[value]', 'Config value')
61
62
  .action(configCommand);
62
63
 
64
+ // Domain command
65
+ program
66
+ .command('domain')
67
+ .description('Domain management (multidomain support)')
68
+ .addArgument(new Argument('[action]', 'Action to perform').choices(['active', 'add', 'use', 'list', 'remove']))
69
+ .argument('[name]', 'Domain name')
70
+ .option('-l, --list', 'List domains')
71
+ .option('--API_BASE_URL <url>', 'API base URL')
72
+ .option('--API_VERSION <version>', 'API version')
73
+ .option('--DB_HOST <host>', 'Database host')
74
+ .option('--DB_PORT <port>', 'Database port')
75
+ .option('--DB_NAME <dbname>', 'Database name')
76
+ .option('--DB_USER <user>', 'Database username')
77
+ .option('--DB_PASSWORD <password>', 'Database password')
78
+ .option('--AUTO_DISCOVER <value>', 'Auto discover (true/false)')
79
+ .option('--USE_DOCKER <value>', 'Use Docker (true/false)')
80
+ .option('--DOCKER_POSTGRES_CONTAINER <container>', 'Docker PostgreSQL container name')
81
+ .option('--DEBUG_MODE <value>', 'Debug mode (true/false)')
82
+ .addHelpText('after', `
83
+ Examples:
84
+ wf domain active Show active domain name
85
+ wf domain list List domains
86
+ wf domain --list List domains
87
+ wf domain add domain-a --API_BASE_URL http://localhost:4201 --DB_NAME myDb Add a new domain
88
+ wf domain use domain-a Switch active domain
89
+ wf domain remove domain-a Remove a domain
90
+
91
+ Notes:
92
+ - When adding a domain, unspecified settings are inherited from the default domain.
93
+ - The default domain cannot be deleted.
94
+ - If the active domain is deleted, it automatically switches back to default.
95
+ `)
96
+ .action(domainCommand);
97
+
63
98
  // Parse arguments
64
99
  program.parse(process.argv);
65
100
 
@@ -67,4 +102,3 @@ program.parse(process.argv);
67
102
  if (!process.argv.slice(2).length) {
68
103
  program.outputHelp();
69
104
  }
70
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burgan-tech/vnext-workflow-cli",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "vNext Workflow Manager - CLI tool for managing workflows, tasks, schemas and more",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -7,21 +7,28 @@ async function configCommand(action, key, value) {
7
7
  const val = config.get(key);
8
8
  console.log(chalk.cyan(`${key}:`), val);
9
9
  } else {
10
- // Show all config
11
- console.log(chalk.cyan.bold('\n📝 Current Configuration:\n'));
10
+ // Show all config with active domain info
12
11
  const all = config.getAll();
12
+ console.log(chalk.cyan.bold('\n📝 Current Configuration:\n'));
13
+ console.log(chalk.yellow(` Active Domain: ${all.ACTIVE_DOMAIN}\n`));
13
14
  for (const [k, v] of Object.entries(all)) {
14
- console.log(chalk.cyan(`${k}:`), chalk.white(v));
15
+ if (k === 'ACTIVE_DOMAIN' || k === 'DOMAIN_NAME') continue;
16
+ console.log(chalk.cyan(` ${k}:`), chalk.white(v));
15
17
  }
16
- console.log(chalk.dim(`\nConfig file: ${config.path}\n`));
18
+ console.log(chalk.dim(`\n Config file: ${config.path}`));
19
+ console.log(chalk.dim(` Tip: Use "wf domain list" to see all domains.\n`));
17
20
  }
18
21
  } else if (action === 'set') {
19
22
  if (!key || value === undefined) {
20
23
  console.log(chalk.red('Usage: workflow config set <key> <value>'));
21
24
  return;
22
25
  }
23
- config.set(key, value);
24
- console.log(chalk.green(`✓ ${key} = ${value}`));
26
+ try {
27
+ config.set(key, value);
28
+ console.log(chalk.green(`✓ ${key} = ${value}`));
29
+ } catch (error) {
30
+ console.log(chalk.red(`✗ ${error.message}`));
31
+ }
25
32
  } else {
26
33
  console.log(chalk.red('Invalid action. Use: get or set'));
27
34
  }
@@ -0,0 +1,161 @@
1
+ const chalk = require('chalk');
2
+ const config = require('../lib/config');
3
+
4
+ const VALID_KEYS = [
5
+ 'API_BASE_URL', 'API_VERSION', 'DB_HOST', 'DB_PORT', 'DB_NAME',
6
+ 'DB_USER', 'DB_PASSWORD', 'AUTO_DISCOVER', 'USE_DOCKER',
7
+ 'DOCKER_POSTGRES_CONTAINER', 'DEBUG_MODE'
8
+ ];
9
+
10
+ const NUMERIC_KEYS = ['DB_PORT'];
11
+ const BOOLEAN_KEYS = ['AUTO_DISCOVER', 'USE_DOCKER', 'DEBUG_MODE'];
12
+
13
+ /**
14
+ * Coerces a string value to the correct type based on key.
15
+ * Only known numeric keys become numbers; only known boolean keys become booleans.
16
+ * All other values remain as strings.
17
+ */
18
+ function coerceValue(key, value) {
19
+ if (BOOLEAN_KEYS.includes(key)) {
20
+ return value === 'true';
21
+ }
22
+ if (NUMERIC_KEYS.includes(key)) {
23
+ const num = Number(value);
24
+ return isNaN(num) ? value : num;
25
+ }
26
+ return value;
27
+ }
28
+
29
+ /**
30
+ * Extracts and coerces valid domain config options from Commander options object.
31
+ */
32
+ function extractOptions(options) {
33
+ const parsed = {};
34
+ for (const key of VALID_KEYS) {
35
+ if (options[key] !== undefined) {
36
+ parsed[key] = coerceValue(key, options[key]);
37
+ }
38
+ }
39
+ return parsed;
40
+ }
41
+
42
+ /**
43
+ * Main domain command handler.
44
+ * Dispatches to add, use, list, or remove based on action argument.
45
+ */
46
+ async function domainCommand(action, name, options) {
47
+ // Support wf domain --list
48
+ if (options.list || action === 'list') {
49
+ return listDomains();
50
+ }
51
+
52
+ if (action === 'active') {
53
+ return showActiveDomain();
54
+ }
55
+
56
+ if (action === 'add') {
57
+ return addDomain(name, options);
58
+ }
59
+
60
+ if (action === 'use') {
61
+ return useDomain(name);
62
+ }
63
+
64
+ if (action === 'remove') {
65
+ return removeDomain(name);
66
+ }
67
+
68
+ // No valid action - show usage
69
+ console.log(chalk.cyan.bold('\n🌐 Domain Management\n'));
70
+ console.log('Usage:');
71
+ console.log(chalk.white(' wf domain active Show active domain'));
72
+ console.log(chalk.white(' wf domain list List all domains'));
73
+ console.log(chalk.white(' wf domain add <name> [--API_BASE_URL ...] [--DB_NAME ...] Add a domain'));
74
+ console.log(chalk.white(' wf domain use <name> Switch active domain'));
75
+ console.log(chalk.white(' wf domain remove <name> Remove a domain'));
76
+ console.log('');
77
+ }
78
+
79
+ function showActiveDomain() {
80
+ console.log(config.get('ACTIVE_DOMAIN'));
81
+ }
82
+
83
+ function addDomain(name, options) {
84
+ if (!name) {
85
+ console.log(chalk.red('Usage: wf domain add <name> [--API_BASE_URL <url>] [--DB_NAME <name>] ...'));
86
+ return;
87
+ }
88
+
89
+ try {
90
+ const parsed = extractOptions(options);
91
+ const domain = config.addDomain(name, parsed);
92
+
93
+ console.log(chalk.green(`\n✓ Domain "${name}" added successfully.\n`));
94
+ printDomainConfig(domain);
95
+ } catch (error) {
96
+ console.log(chalk.red(`\n✗ Error: ${error.message}\n`));
97
+ }
98
+ }
99
+
100
+ function useDomain(name) {
101
+ if (!name) {
102
+ console.log(chalk.red('Usage: wf domain use <name>'));
103
+ return;
104
+ }
105
+
106
+ try {
107
+ config.useDomain(name);
108
+ console.log(chalk.green(`\n✓ Active domain switched to "${name}".\n`));
109
+
110
+ // Show key applied config values
111
+ const domainConfig = config.getActiveDomainConfig();
112
+ console.log(chalk.cyan('Applied settings:'));
113
+ console.log(chalk.cyan(' API_BASE_URL:'), chalk.white(domainConfig.API_BASE_URL));
114
+ console.log(chalk.cyan(' DB_NAME: '), chalk.white(domainConfig.DB_NAME));
115
+ console.log('');
116
+ } catch (error) {
117
+ console.log(chalk.red(`\n✗ Error: ${error.message}\n`));
118
+ }
119
+ }
120
+
121
+ function listDomains() {
122
+ const { activeDomain, domains } = config.listDomains();
123
+
124
+ console.log(chalk.cyan.bold('\n🌐 Domains:\n'));
125
+
126
+ for (const domain of domains) {
127
+ const isActive = domain.DOMAIN_NAME === activeDomain;
128
+ const marker = isActive ? chalk.green('▸ ') : ' ';
129
+ const label = isActive
130
+ ? chalk.green.bold(domain.DOMAIN_NAME) + chalk.green(' (active)')
131
+ : chalk.white(domain.DOMAIN_NAME);
132
+
133
+ console.log(`${marker}${label}`);
134
+ console.log(chalk.dim(` API: ${domain.API_BASE_URL} DB: ${domain.DB_NAME}`));
135
+ }
136
+
137
+ console.log('');
138
+ }
139
+
140
+ function removeDomain(name) {
141
+ if (!name) {
142
+ console.log(chalk.red('Usage: wf domain remove <name>'));
143
+ return;
144
+ }
145
+
146
+ try {
147
+ config.removeDomain(name);
148
+ console.log(chalk.green(`\n✓ Domain "${name}" removed.\n`));
149
+ } catch (error) {
150
+ console.log(chalk.red(`\n✗ Error: ${error.message}\n`));
151
+ }
152
+ }
153
+
154
+ function printDomainConfig(domain) {
155
+ for (const [key, value] of Object.entries(domain)) {
156
+ console.log(chalk.cyan(` ${key}:`), chalk.white(value));
157
+ }
158
+ console.log('');
159
+ }
160
+
161
+ module.exports = domainCommand;
package/src/lib/api.js CHANGED
@@ -1,9 +1,9 @@
1
1
  const axios = require('axios');
2
2
 
3
3
  /**
4
- * API bağlantısını test eder
4
+ * Tests the API connection
5
5
  * @param {string} baseUrl - API base URL
6
- * @returns {Promise<boolean>} Bağlantı durumu
6
+ * @returns {Promise<boolean>} Connection status
7
7
  */
8
8
  async function testApiConnection(baseUrl) {
9
9
  try {
@@ -17,9 +17,9 @@ async function testApiConnection(baseUrl) {
17
17
  }
18
18
 
19
19
  /**
20
- * Komponenti API'ye publish eder
20
+ * Publishes a component to the API
21
21
  * @param {string} baseUrl - API base URL
22
- * @param {Object} componentData - Komponent JSON verisi
22
+ * @param {Object} componentData - Component JSON data
23
23
  * @returns {Promise<Object>} API response
24
24
  */
25
25
  async function publishComponent(baseUrl, componentData) {
@@ -39,7 +39,7 @@ async function publishComponent(baseUrl, componentData) {
39
39
  data: response.data
40
40
  };
41
41
  } catch (error) {
42
- // API hata detaylarını çıkar
42
+ // Extract API error details
43
43
  let errorMessage = error.message;
44
44
  let errorDetails = null;
45
45
 
@@ -68,10 +68,10 @@ async function publishComponent(baseUrl, componentData) {
68
68
  }
69
69
 
70
70
  /**
71
- * Sistemi yeniden başlatır
71
+ * Reinitializes the system
72
72
  * @param {string} baseUrl - API base URL
73
73
  * @param {string} version - API version
74
- * @returns {Promise<boolean>} Başarı durumu
74
+ * @returns {Promise<boolean>} Success status
75
75
  */
76
76
  async function reinitializeSystem(baseUrl, version) {
77
77
  const url = `${baseUrl}/api/${version}/definitions/re-initialize`;
package/src/lib/config.js CHANGED
@@ -1,67 +1,239 @@
1
1
  const Conf = require('conf');
2
- const path = require('path');
2
+
3
+ // Default config values for a domain
4
+ const DEFAULT_DOMAIN_CONFIG = {
5
+ AUTO_DISCOVER: true,
6
+ API_BASE_URL: 'http://localhost:4201',
7
+ API_VERSION: 'v1',
8
+ DB_HOST: 'localhost',
9
+ DB_PORT: 5432,
10
+ DB_NAME: 'vNext_WorkflowDb',
11
+ DB_USER: 'postgres',
12
+ DB_PASSWORD: 'postgres',
13
+ USE_DOCKER: false,
14
+ DOCKER_POSTGRES_CONTAINER: 'vnext-postgres',
15
+ DEBUG_MODE: false
16
+ };
17
+
18
+ const DOMAIN_CONFIG_KEYS = Object.keys(DEFAULT_DOMAIN_CONFIG);
3
19
 
4
20
  const config = new Conf({
5
- projectName: 'vnext-workflow-cli',
6
- defaults: {
7
- AUTO_DISCOVER: true,
8
- API_BASE_URL: 'http://localhost:4201',
9
- API_VERSION: 'v1',
10
- DB_HOST: 'localhost',
11
- DB_PORT: 5432,
12
- DB_NAME: 'vNext_WorkflowDb',
13
- DB_USER: 'postgres',
14
- DB_PASSWORD: 'postgres',
15
- USE_DOCKER: false,
16
- DOCKER_POSTGRES_CONTAINER: 'vnext-postgres',
17
- DEBUG_MODE: false
18
- }
21
+ projectName: 'vnext-workflow-cli'
19
22
  });
20
23
 
21
24
  /**
22
- * Gets a config value
23
- * PROJECT_ROOT always returns current working directory (process.cwd())
25
+ * Migrates old flat config to new domain-aware format.
26
+ * Old: { API_BASE_URL: "...", DB_NAME: "..." }
27
+ * New: { ACTIVE_DOMAIN: "default", DOMAINS: [{ DOMAIN_NAME: "default", ... }] }
28
+ */
29
+ function migrateConfig() {
30
+ const store = config.store;
31
+
32
+ // Already in new format - skip
33
+ if (store.ACTIVE_DOMAIN !== undefined && Array.isArray(store.DOMAINS)) {
34
+ return;
35
+ }
36
+
37
+ // Collect existing values from old flat config
38
+ const existingValues = {};
39
+ for (const key of DOMAIN_CONFIG_KEYS) {
40
+ if (store[key] !== undefined) {
41
+ existingValues[key] = store[key];
42
+ }
43
+ }
44
+
45
+ // Create default domain: defaults + any existing overrides
46
+ const defaultDomain = {
47
+ DOMAIN_NAME: 'default',
48
+ ...DEFAULT_DOMAIN_CONFIG,
49
+ ...existingValues
50
+ };
51
+
52
+ // Clear old keys and set new format via conf API
53
+ for (const key of DOMAIN_CONFIG_KEYS) {
54
+ config.delete(key);
55
+ }
56
+ config.set('ACTIVE_DOMAIN', 'default');
57
+ config.set('DOMAINS', [defaultDomain]);
58
+ }
59
+
60
+ // Run migration on module load
61
+ migrateConfig();
62
+
63
+ /**
64
+ * Returns the active domain config object.
65
+ * @returns {Object} Active domain config
66
+ */
67
+ function getActiveDomainConfig() {
68
+ const activeDomain = config.get('ACTIVE_DOMAIN');
69
+ const domains = config.get('DOMAINS') || [];
70
+ const domain = domains.find(d => d.DOMAIN_NAME === activeDomain);
71
+
72
+ if (!domain) {
73
+ throw new Error(`Active domain "${activeDomain}" not found in config.`);
74
+ }
75
+ return domain;
76
+ }
77
+
78
+ /**
79
+ * Gets a config value from the active domain.
80
+ * PROJECT_ROOT always returns process.cwd().
24
81
  * @param {string} key - Config key
25
82
  * @returns {any} Config value
26
83
  */
27
84
  function get(key) {
28
- // PROJECT_ROOT is always the current working directory
29
85
  if (key === 'PROJECT_ROOT') {
30
86
  return process.cwd();
31
87
  }
32
- return config.get(key);
88
+ if (key === 'ACTIVE_DOMAIN') {
89
+ return config.get('ACTIVE_DOMAIN');
90
+ }
91
+ const domainConfig = getActiveDomainConfig();
92
+ return domainConfig[key];
33
93
  }
34
94
 
35
95
  /**
36
- * Sets a config value
37
- * PROJECT_ROOT cannot be set (ignored)
96
+ * Sets a config value on the active domain.
97
+ * PROJECT_ROOT cannot be set (always uses cwd).
38
98
  * @param {string} key - Config key
39
99
  * @param {any} value - Config value
40
100
  */
41
101
  function set(key, value) {
42
- // PROJECT_ROOT cannot be saved - always uses cwd
43
- if (key === 'PROJECT_ROOT') {
44
- console.log('Note: PROJECT_ROOT is always the current working directory and cannot be changed.');
45
- return;
102
+ const RESERVED_KEYS = {
103
+ PROJECT_ROOT: 'PROJECT_ROOT is always the current working directory and cannot be changed.',
104
+ DOMAIN_NAME: 'DOMAIN_NAME cannot be changed directly. Use "wf domain add/remove" instead.',
105
+ ACTIVE_DOMAIN: 'ACTIVE_DOMAIN cannot be changed directly. Use "wf domain use <name>" instead.'
106
+ };
107
+
108
+ if (RESERVED_KEYS[key]) {
109
+ throw new Error(RESERVED_KEYS[key]);
110
+ }
111
+
112
+ const activeDomainName = config.get('ACTIVE_DOMAIN');
113
+ const domains = config.get('DOMAINS') || [];
114
+ const idx = domains.findIndex(d => d.DOMAIN_NAME === activeDomainName);
115
+
116
+ if (idx === -1) {
117
+ throw new Error(`Active domain "${activeDomainName}" not found.`);
46
118
  }
47
- config.set(key, value);
119
+
120
+ domains[idx][key] = value;
121
+ config.set('DOMAINS', domains);
48
122
  }
49
123
 
50
124
  /**
51
- * Gets all config values including PROJECT_ROOT
52
- * @returns {Object} All config values
125
+ * Gets all config values from the active domain.
126
+ * @returns {Object} All config values including PROJECT_ROOT and ACTIVE_DOMAIN
53
127
  */
54
128
  function getAll() {
129
+ const domainConfig = getActiveDomainConfig();
55
130
  return {
56
131
  PROJECT_ROOT: process.cwd(),
57
- ...config.store
132
+ ACTIVE_DOMAIN: config.get('ACTIVE_DOMAIN'),
133
+ ...domainConfig
58
134
  };
59
135
  }
60
136
 
137
+ /**
138
+ * Resets config to default state.
139
+ */
140
+ function clear() {
141
+ config.clear();
142
+ config.set('ACTIVE_DOMAIN', 'default');
143
+ config.set('DOMAINS', [{
144
+ DOMAIN_NAME: 'default',
145
+ ...DEFAULT_DOMAIN_CONFIG
146
+ }]);
147
+ }
148
+
149
+ /**
150
+ * Adds a new domain. Missing values are inherited from the default domain.
151
+ * @param {string} name - Domain name
152
+ * @param {Object} options - Domain config overrides
153
+ * @returns {Object} Created domain config
154
+ */
155
+ function addDomain(name, options) {
156
+ const domains = config.get('DOMAINS') || [];
157
+
158
+ if (domains.find(d => d.DOMAIN_NAME === name)) {
159
+ throw new Error(`Domain "${name}" already exists.`);
160
+ }
161
+
162
+ // Use default domain as base, fall back to DEFAULT_DOMAIN_CONFIG
163
+ const defaultDomain = domains.find(d => d.DOMAIN_NAME === 'default');
164
+ const base = defaultDomain
165
+ ? { ...defaultDomain }
166
+ : { ...DEFAULT_DOMAIN_CONFIG };
167
+ delete base.DOMAIN_NAME;
168
+
169
+ const newDomain = {
170
+ DOMAIN_NAME: name,
171
+ ...base,
172
+ ...options
173
+ };
174
+
175
+ domains.push(newDomain);
176
+ config.set('DOMAINS', domains);
177
+ return newDomain;
178
+ }
179
+
180
+ /**
181
+ * Switches the active domain.
182
+ * @param {string} name - Domain name to activate
183
+ */
184
+ function useDomain(name) {
185
+ const domains = config.get('DOMAINS') || [];
186
+ if (!domains.find(d => d.DOMAIN_NAME === name)) {
187
+ throw new Error(`Domain "${name}" not found.`);
188
+ }
189
+ config.set('ACTIVE_DOMAIN', name);
190
+ }
191
+
192
+ /**
193
+ * Lists all domains with active domain info.
194
+ * @returns {Object} { activeDomain, domains }
195
+ */
196
+ function listDomains() {
197
+ return {
198
+ activeDomain: config.get('ACTIVE_DOMAIN'),
199
+ domains: config.get('DOMAINS') || []
200
+ };
201
+ }
202
+
203
+ /**
204
+ * Removes a domain. Cannot remove the default domain.
205
+ * If the removed domain was active, switches to default.
206
+ * @param {string} name - Domain name to remove
207
+ */
208
+ function removeDomain(name) {
209
+ if (name === 'default') {
210
+ throw new Error('Cannot remove the default domain.');
211
+ }
212
+
213
+ const domains = config.get('DOMAINS') || [];
214
+ const filtered = domains.filter(d => d.DOMAIN_NAME !== name);
215
+
216
+ if (filtered.length === domains.length) {
217
+ throw new Error(`Domain "${name}" not found.`);
218
+ }
219
+
220
+ config.set('DOMAINS', filtered);
221
+
222
+ if (config.get('ACTIVE_DOMAIN') === name) {
223
+ config.set('ACTIVE_DOMAIN', 'default');
224
+ }
225
+ }
226
+
61
227
  module.exports = {
62
228
  get,
63
229
  set,
64
230
  getAll,
65
- clear: () => config.clear(),
66
- path: config.path
231
+ clear,
232
+ path: config.path,
233
+ addDomain,
234
+ useDomain,
235
+ listDomains,
236
+ removeDomain,
237
+ getActiveDomainConfig,
238
+ DEFAULT_DOMAIN_CONFIG
67
239
  };
package/src/lib/db.js CHANGED
@@ -5,11 +5,11 @@ const util = require('util');
5
5
  const execPromise = util.promisify(exec);
6
6
 
7
7
  /**
8
- * DB bağlantısını test eder
8
+ * Tests the DB connection
9
9
  */
10
10
  async function testDbConnection(dbConfig) {
11
11
  if (dbConfig.useDocker) {
12
- // Docker üzerinden test
12
+ // Test via Docker
13
13
  try {
14
14
  const cmd = `docker exec ${dbConfig.dockerContainer} psql -U ${dbConfig.user} -d ${dbConfig.database} -c "SELECT 1;"`;
15
15
  await execPromise(cmd);
@@ -18,7 +18,7 @@ async function testDbConnection(dbConfig) {
18
18
  return false;
19
19
  }
20
20
  } else {
21
- // Direkt bağlantı
21
+ // Direct connection
22
22
  const client = new Client({
23
23
  host: dbConfig.host,
24
24
  port: dbConfig.port,
@@ -39,15 +39,15 @@ async function testDbConnection(dbConfig) {
39
39
  }
40
40
 
41
41
  /**
42
- * Workflow'un DB'deki ID'sini bulur
43
- * NOT: Version kontrolü yapmıyoruz, sadece Key'e bakıyoruz (bash script gibi)
42
+ * Finds the workflow's ID in the DB
43
+ * NOTE: We don't check version, only the Key (like the bash script)
44
44
  */
45
45
  async function getInstanceId(dbConfig, schema, key, version) {
46
46
  const dbSchema = schema.replace(/-/g, '_');
47
47
  const query = `SELECT "Id" FROM "${dbSchema}"."Instances" WHERE "Key" = $1 ORDER BY "CreatedAt" DESC LIMIT 1`;
48
48
 
49
49
  if (dbConfig.useDocker) {
50
- // Docker üzerinden - SQL içindeki double quote'ları backslash ile escape et
50
+ // Via Docker - escape double quotes in SQL with backslash
51
51
  const cmd = `docker exec ${dbConfig.dockerContainer} psql -U ${dbConfig.user} -d ${dbConfig.database} -t -c "SELECT \\"Id\\" FROM \\"${dbSchema}\\".\\"Instances\\" WHERE \\"Key\\" = '${key}' ORDER BY \\"CreatedAt\\" DESC LIMIT 1"`;
52
52
  try {
53
53
  const { stdout } = await execPromise(cmd);
@@ -57,7 +57,7 @@ async function getInstanceId(dbConfig, schema, key, version) {
57
57
  return null;
58
58
  }
59
59
  } else {
60
- // Direkt bağlantı
60
+ // Direct connection
61
61
  const client = new Client({
62
62
  host: dbConfig.host,
63
63
  port: dbConfig.port,
@@ -78,13 +78,13 @@ async function getInstanceId(dbConfig, schema, key, version) {
78
78
  }
79
79
 
80
80
  /**
81
- * Workflow'u DB'den siler
81
+ * Deletes a workflow from the DB
82
82
  */
83
83
  async function deleteWorkflow(dbConfig, schema, instanceId) {
84
84
  const dbSchema = schema.replace(/-/g, '_');
85
85
 
86
86
  if (dbConfig.useDocker) {
87
- // Docker üzerinden - Double quote'ları escape et
87
+ // Via Docker - escape double quotes
88
88
  const cmd = `docker exec ${dbConfig.dockerContainer} psql -U ${dbConfig.user} -d ${dbConfig.database} -c "DELETE FROM \\"${dbSchema}\\".\\"Instances\\" WHERE \\"Id\\" = '${instanceId}'"`;
89
89
  try {
90
90
  await execPromise(cmd);
@@ -93,7 +93,7 @@ async function deleteWorkflow(dbConfig, schema, instanceId) {
93
93
  return false;
94
94
  }
95
95
  } else {
96
- // Direkt bağlantı
96
+ // Direct connection
97
97
  const query = `DELETE FROM "${dbSchema}"."Instances" WHERE "Id" = $1`;
98
98
  const client = new Client({
99
99
  host: dbConfig.host,