@authrim/setup 0.1.20 → 0.1.24

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.
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiDH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAgXD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuErE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAiDH,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAiXD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuErE"}
@@ -24,12 +24,13 @@ function printBanner() {
24
24
  console.log('');
25
25
  console.log(chalk.blue('╔═══════════════════════════════════════════════════════════╗'));
26
26
  console.log(chalk.blue('║') +
27
- chalk.bold.white(' 🔐 Authrim Setup v0.1.14 ') +
27
+ chalk.bold.white(' 🔐 Authrim Setup v0.1.24 ') +
28
28
  chalk.blue('║'));
29
29
  console.log(chalk.blue('║') +
30
30
  chalk.gray(' OIDC Provider on Cloudflare Workers ') +
31
31
  chalk.blue('║'));
32
32
  console.log(chalk.blue('╚═══════════════════════════════════════════════════════════╝'));
33
+ console.log(chalk.gray(' Press Ctrl+C at any time to exit'));
33
34
  console.log('');
34
35
  }
35
36
  // =============================================================================
@@ -396,28 +397,214 @@ export async function initCommand(options) {
396
397
  // CLI Setup Flow
397
398
  // =============================================================================
398
399
  async function runCliSetup(options) {
399
- // Step 1: Choose setup mode
400
- const setupMode = await select({
401
- message: 'Choose setup mode',
402
- choices: [
403
- {
404
- value: 'quick',
405
- name: '⚡ Quick Setup (5 minutes)',
406
- description: 'Deploy Authrim with minimal configuration',
407
- },
408
- {
409
- value: 'normal',
410
- name: '🔧 Custom Setup',
411
- description: 'Configure all options step by step',
412
- },
413
- ],
414
- });
415
- if (setupMode === 'quick') {
416
- await runQuickSetup(options);
400
+ // Main menu loop - keeps returning to menu until user exits
401
+ while (true) {
402
+ const setupMode = await select({
403
+ message: 'What would you like to do?',
404
+ choices: [
405
+ {
406
+ value: 'quick',
407
+ name: ' Quick Setup (5 minutes)',
408
+ description: 'Deploy Authrim with minimal configuration',
409
+ },
410
+ {
411
+ value: 'normal',
412
+ name: '🔧 Custom Setup',
413
+ description: 'Configure all options step by step',
414
+ },
415
+ {
416
+ value: 'manage',
417
+ name: '📋 View Existing Environments',
418
+ description: 'View, inspect, or delete existing environments',
419
+ },
420
+ {
421
+ value: 'load',
422
+ name: '📂 Load Existing Configuration',
423
+ description: 'Resume setup from authrim-config.json',
424
+ },
425
+ {
426
+ value: 'exit',
427
+ name: '❌ Exit',
428
+ description: 'Exit setup',
429
+ },
430
+ ],
431
+ });
432
+ if (setupMode === 'exit') {
433
+ console.log('');
434
+ console.log(chalk.gray('Goodbye!'));
435
+ console.log('');
436
+ break;
437
+ }
438
+ if (setupMode === 'quick') {
439
+ await runQuickSetup(options);
440
+ break; // Exit after setup completes
441
+ }
442
+ else if (setupMode === 'normal') {
443
+ await runNormalSetup(options);
444
+ break; // Exit after setup completes
445
+ }
446
+ else if (setupMode === 'manage') {
447
+ await runManageEnvironments();
448
+ // Returns to main menu after manage
449
+ console.log('');
450
+ }
451
+ else if (setupMode === 'load') {
452
+ const shouldContinue = await runLoadConfig();
453
+ if (!shouldContinue) {
454
+ // Returns to main menu
455
+ console.log('');
456
+ }
457
+ else {
458
+ break; // Exit after deploy
459
+ }
460
+ }
461
+ }
462
+ }
463
+ // =============================================================================
464
+ // Manage Existing Environments
465
+ // =============================================================================
466
+ async function runManageEnvironments() {
467
+ // Loop to allow multiple operations before returning to main menu
468
+ while (true) {
469
+ console.log('');
470
+ console.log(chalk.blue('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
471
+ console.log(chalk.bold('📋 Existing Environments'));
472
+ console.log(chalk.blue('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
473
+ console.log('');
474
+ const spinner = ora('Detecting environments...').start();
475
+ const environments = await detectEnvironments();
476
+ spinner.stop();
477
+ if (environments.length === 0) {
478
+ console.log(chalk.yellow('No Authrim environments found.'));
479
+ console.log('');
480
+ return;
481
+ }
482
+ console.log(chalk.bold('Detected Environments:'));
483
+ console.log('');
484
+ for (const env of environments) {
485
+ console.log(` ${chalk.cyan(env.env)}`);
486
+ console.log(chalk.gray(` Workers: ${env.workers.length}, D1: ${env.d1.length}, KV: ${env.kv.length}`));
487
+ }
488
+ console.log('');
489
+ const action = await select({
490
+ message: 'Select action',
491
+ choices: [
492
+ {
493
+ value: 'info',
494
+ name: '🔍 View Details',
495
+ description: 'Show detailed resource information',
496
+ },
497
+ {
498
+ value: 'delete',
499
+ name: '🗑️ Delete Environment',
500
+ description: 'Remove environment and resources',
501
+ },
502
+ { value: 'back', name: '← Back to Main Menu', description: 'Return to main menu' },
503
+ ],
504
+ });
505
+ if (action === 'back') {
506
+ return;
507
+ }
508
+ const envChoices = environments.map((e) => ({
509
+ name: `${e.env} (${e.workers.length} workers, ${e.d1.length} D1, ${e.kv.length} KV)`,
510
+ value: e.env,
511
+ }));
512
+ envChoices.push({ name: '← Back', value: '__back__' });
513
+ const envName = await select({
514
+ message: 'Select environment',
515
+ choices: envChoices,
516
+ });
517
+ if (envName === '__back__') {
518
+ continue; // Go back to action selection
519
+ }
520
+ if (action === 'info') {
521
+ const { infoCommand } = await import('./info.js');
522
+ await infoCommand({ env: envName });
523
+ }
524
+ else if (action === 'delete') {
525
+ const { deleteCommand } = await import('./delete.js');
526
+ await deleteCommand({ env: envName });
527
+ }
528
+ // After action, ask if user wants to continue managing
529
+ console.log('');
530
+ const continueManaging = await confirm({
531
+ message: 'Continue managing environments?',
532
+ default: true,
533
+ });
534
+ if (!continueManaging) {
535
+ return;
536
+ }
537
+ }
538
+ }
539
+ // =============================================================================
540
+ // Load Existing Configuration
541
+ // =============================================================================
542
+ async function runLoadConfig() {
543
+ console.log('');
544
+ console.log(chalk.blue('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
545
+ console.log(chalk.bold('📂 Load Existing Configuration'));
546
+ console.log(chalk.blue('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
547
+ console.log('');
548
+ // Check for config file in current directory
549
+ const defaultConfigPath = './authrim-config.json';
550
+ const configExists = existsSync(defaultConfigPath);
551
+ let configPath = defaultConfigPath;
552
+ if (configExists) {
553
+ console.log(chalk.green(`✓ Found: ${defaultConfigPath}`));
554
+ console.log('');
555
+ const action = await select({
556
+ message: 'What would you like to do?',
557
+ choices: [
558
+ { value: 'load', name: '📂 Load this configuration' },
559
+ { value: 'other', name: '📁 Specify different file' },
560
+ { value: 'back', name: '← Back to Main Menu' },
561
+ ],
562
+ });
563
+ if (action === 'back') {
564
+ return false; // Return to main menu
565
+ }
566
+ if (action === 'other') {
567
+ configPath = await input({
568
+ message: 'Enter configuration file path',
569
+ validate: (value) => {
570
+ if (!value)
571
+ return 'Please enter a path';
572
+ if (!existsSync(value))
573
+ return `File not found: ${value}`;
574
+ return true;
575
+ },
576
+ });
577
+ }
417
578
  }
418
579
  else {
419
- await runNormalSetup(options);
580
+ console.log(chalk.yellow('No authrim-config.json found in current directory.'));
581
+ console.log('');
582
+ console.log(chalk.gray('💡 Tip: You can specify a config file with:'));
583
+ console.log(chalk.cyan(' npx @authrim/setup --config /path/to/authrim-config.json'));
584
+ console.log('');
585
+ const action = await select({
586
+ message: 'What would you like to do?',
587
+ choices: [
588
+ { value: 'specify', name: '📁 Specify file path' },
589
+ { value: 'back', name: '← Back to Main Menu' },
590
+ ],
591
+ });
592
+ if (action === 'back') {
593
+ return false;
594
+ }
595
+ configPath = await input({
596
+ message: 'Enter configuration file path',
597
+ validate: (value) => {
598
+ if (!value)
599
+ return 'Please enter a path';
600
+ if (!existsSync(value))
601
+ return `File not found: ${value}`;
602
+ return true;
603
+ },
604
+ });
420
605
  }
606
+ await handleExistingConfig(configPath);
607
+ return true; // Config was loaded and processed
421
608
  }
422
609
  // =============================================================================
423
610
  // Quick Setup
@@ -471,17 +658,25 @@ async function runQuickSetup(options) {
471
658
  return true;
472
659
  },
473
660
  });
474
- // Step 3: Domain configuration
661
+ // Step 3: Show infrastructure info
662
+ console.log('');
663
+ console.log(chalk.gray(' Workers to deploy: ' + envPrefix + '-ar-router, ' + envPrefix + '-ar-auth, ...'));
664
+ console.log(chalk.gray(' Default API: https://' + envPrefix + '-ar-router.workers.dev'));
665
+ console.log('');
666
+ // Step 4: Domain configuration (single-tenant mode only in Quick Setup)
475
667
  const useCustomDomain = await confirm({
476
- message: 'Configure custom domain?',
668
+ message: 'Configure custom domain? (for Issuer URL)',
477
669
  default: false,
478
670
  });
479
671
  let apiDomain = null;
480
672
  let loginUiDomain = null;
481
673
  let adminUiDomain = null;
482
674
  if (useCustomDomain) {
675
+ console.log('');
676
+ console.log(chalk.gray(' In single-tenant mode, Issuer URL = API domain'));
677
+ console.log('');
483
678
  apiDomain = await input({
484
- message: 'API (issuer) domain',
679
+ message: 'API / Issuer domain (e.g., auth.example.com)',
485
680
  validate: (value) => {
486
681
  if (!value)
487
682
  return true; // Allow empty for workers.dev fallback
@@ -505,7 +700,7 @@ async function runQuickSetup(options) {
505
700
  config.urls = {
506
701
  api: {
507
702
  custom: apiDomain || null,
508
- auto: `https://${envPrefix}-ar-router.workers.dev`, // Placeholder
703
+ auto: `https://${envPrefix}-ar-router.workers.dev`,
509
704
  },
510
705
  loginUi: {
511
706
  custom: loginUiDomain || null,
@@ -522,10 +717,14 @@ async function runQuickSetup(options) {
522
717
  console.log(chalk.bold('📋 Configuration Summary'));
523
718
  console.log(chalk.blue('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
524
719
  console.log('');
525
- console.log(` Environment: ${chalk.cyan(envPrefix)}`);
526
- console.log(` API URL: ${chalk.cyan(config.urls.api.custom || config.urls.api.auto)}`);
527
- console.log(` Login UI: ${chalk.cyan(config.urls.loginUi.custom || config.urls.loginUi.auto)}`);
528
- console.log(` Admin UI: ${chalk.cyan(config.urls.adminUi.custom || config.urls.adminUi.auto)}`);
720
+ console.log(chalk.bold('Infrastructure:'));
721
+ console.log(` Environment: ${chalk.cyan(envPrefix)}`);
722
+ console.log(` Worker Prefix: ${chalk.cyan(envPrefix + '-ar-*')}`);
723
+ console.log('');
724
+ console.log(chalk.bold('URLs (Single-tenant):'));
725
+ console.log(` Issuer URL: ${chalk.cyan(config.urls.api.custom || config.urls.api.auto)}`);
726
+ console.log(` Login UI: ${chalk.cyan(config.urls.loginUi.custom || config.urls.loginUi.auto)}`);
727
+ console.log(` Admin UI: ${chalk.cyan(config.urls.adminUi.custom || config.urls.adminUi.auto)}`);
529
728
  console.log('');
530
729
  const proceed = await confirm({
531
730
  message: 'Start setup with this configuration?',
@@ -612,38 +811,150 @@ async function runNormalSetup(options) {
612
811
  ],
613
812
  default: 'basic-op',
614
813
  });
615
- // Step 4: Domain configuration
616
- const useCustomDomain = await confirm({
617
- message: 'Configure custom domain?',
814
+ // Step 4: Infrastructure overview (Workers are auto-generated from env)
815
+ console.log('');
816
+ console.log(chalk.blue('━━━ Infrastructure (Auto-generated) ━━━'));
817
+ console.log('');
818
+ console.log(chalk.gray(' The following Workers will be deployed:'));
819
+ console.log(` Router: ${chalk.cyan(envPrefix + '-ar-router')}`);
820
+ console.log(` Auth: ${chalk.cyan(envPrefix + '-ar-auth')}`);
821
+ console.log(` Token: ${chalk.cyan(envPrefix + '-ar-token')}`);
822
+ console.log(` Management: ${chalk.cyan(envPrefix + '-ar-management')}`);
823
+ console.log(chalk.gray(' ... and other supporting workers'));
824
+ console.log('');
825
+ console.log(chalk.gray(' Default endpoints (without custom domain):'));
826
+ console.log(` API: ${chalk.gray('https://' + envPrefix + '-ar-router.workers.dev')}`);
827
+ console.log(` UI: ${chalk.gray('https://' + envPrefix + '-ar-ui.pages.dev')}`);
828
+ console.log('');
829
+ // Step 5: Tenant configuration
830
+ console.log(chalk.blue('━━━ Tenant Mode ━━━'));
831
+ console.log('');
832
+ const multiTenant = await confirm({
833
+ message: 'Enable multi-tenant mode? (subdomain-based tenant isolation)',
618
834
  default: false,
619
835
  });
836
+ let tenantName = 'default';
837
+ let tenantDisplayName = 'Default Tenant';
838
+ let baseDomain;
839
+ // Step 6: URL configuration (depends on tenant mode)
620
840
  let apiDomain = null;
621
841
  let loginUiDomain = null;
622
842
  let adminUiDomain = null;
623
- if (useCustomDomain) {
624
- apiDomain = await input({
625
- message: 'API (issuer) domain',
843
+ if (multiTenant) {
844
+ // Multi-tenant mode: base domain is required, becomes the issuer base
845
+ console.log('');
846
+ console.log(chalk.blue('━━━ Multi-tenant URL Configuration ━━━'));
847
+ console.log('');
848
+ console.log(chalk.gray(' In multi-tenant mode:'));
849
+ console.log(chalk.gray(' • Each tenant has a subdomain: https://{tenant}.{base-domain}'));
850
+ console.log(chalk.gray(' • The base domain points to the router Worker'));
851
+ console.log(chalk.gray(' • Issuer URL is dynamically built from Host header'));
852
+ console.log('');
853
+ baseDomain = await input({
854
+ message: 'Base domain (e.g., authrim.com)',
626
855
  validate: (value) => {
627
856
  if (!value)
628
- return true;
857
+ return 'Base domain is required for multi-tenant mode';
629
858
  if (!/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(value)) {
630
- return 'Please enter a valid domain';
859
+ return 'Please enter a valid domain (e.g., authrim.com)';
631
860
  }
632
861
  return true;
633
862
  },
634
863
  });
635
- loginUiDomain = await input({
636
- message: 'Login UI domain (Enter to skip)',
637
- default: '',
864
+ console.log('');
865
+ console.log(chalk.green(' Issuer URL format: https://{tenant}.' + baseDomain));
866
+ console.log(chalk.gray(' Example: https://acme.' + baseDomain));
867
+ console.log('');
868
+ // API domain in multi-tenant is the base domain (or custom apex)
869
+ apiDomain = baseDomain;
870
+ tenantName = await input({
871
+ message: 'Default tenant name (identifier)',
872
+ default: 'default',
873
+ validate: (value) => {
874
+ if (!/^[a-z][a-z0-9-]*$/.test(value)) {
875
+ return 'Only lowercase alphanumeric and hyphens allowed';
876
+ }
877
+ return true;
878
+ },
638
879
  });
639
- adminUiDomain = await input({
640
- message: 'Admin UI domain (Enter to skip)',
641
- default: '',
880
+ tenantDisplayName = await input({
881
+ message: 'Default tenant display name',
882
+ default: 'Default Tenant',
883
+ });
884
+ // UI domains for multi-tenant
885
+ console.log('');
886
+ console.log(chalk.blue('━━━ UI Domain Configuration ━━━'));
887
+ console.log('');
888
+ const useCustomUiDomain = await confirm({
889
+ message: 'Configure custom UI domains?',
890
+ default: false,
642
891
  });
892
+ if (useCustomUiDomain) {
893
+ loginUiDomain = await input({
894
+ message: 'Login UI domain (e.g., login.example.com)',
895
+ default: '',
896
+ });
897
+ adminUiDomain = await input({
898
+ message: 'Admin UI domain (e.g., admin.example.com)',
899
+ default: '',
900
+ });
901
+ }
902
+ }
903
+ else {
904
+ // Single-tenant mode
905
+ console.log('');
906
+ console.log(chalk.blue('━━━ Single-tenant URL Configuration ━━━'));
907
+ console.log('');
908
+ console.log(chalk.gray(' In single-tenant mode:'));
909
+ console.log(chalk.gray(' • Issuer URL = API custom domain (or workers.dev fallback)'));
910
+ console.log(chalk.gray(' • All clients share the same issuer'));
911
+ console.log('');
912
+ tenantDisplayName = await input({
913
+ message: 'Organization name (display name)',
914
+ default: 'Default Tenant',
915
+ });
916
+ const useCustomDomain = await confirm({
917
+ message: 'Configure custom domain?',
918
+ default: false,
919
+ });
920
+ if (useCustomDomain) {
921
+ console.log('');
922
+ console.log(chalk.gray(' Enter custom domains (leave empty to use Cloudflare defaults)'));
923
+ console.log('');
924
+ apiDomain = await input({
925
+ message: 'API / Issuer domain (e.g., auth.example.com)',
926
+ validate: (value) => {
927
+ if (!value)
928
+ return true;
929
+ if (!/^[a-z0-9][a-z0-9.-]*\.[a-z]{2,}$/.test(value)) {
930
+ return 'Please enter a valid domain';
931
+ }
932
+ return true;
933
+ },
934
+ });
935
+ loginUiDomain = await input({
936
+ message: 'Login UI domain (Enter to skip)',
937
+ default: '',
938
+ });
939
+ adminUiDomain = await input({
940
+ message: 'Admin UI domain (Enter to skip)',
941
+ default: '',
942
+ });
943
+ }
944
+ if (apiDomain) {
945
+ console.log('');
946
+ console.log(chalk.green(' ✓ Issuer URL: https://' + apiDomain));
947
+ }
948
+ else {
949
+ console.log('');
950
+ console.log(chalk.green(' ✓ Issuer URL: https://' + envPrefix + '-ar-router.workers.dev'));
951
+ console.log(chalk.gray(' (using Cloudflare workers.dev domain)'));
952
+ }
643
953
  }
644
954
  // Step 5: Optional components
645
955
  console.log('');
646
956
  console.log(chalk.blue('━━━ Optional Components ━━━'));
957
+ console.log(chalk.gray(' Note: Social Login and Policy Engine are standard components'));
647
958
  console.log('');
648
959
  const enableSaml = await confirm({
649
960
  message: 'Enable SAML support?',
@@ -653,14 +964,6 @@ async function runNormalSetup(options) {
653
964
  message: 'Enable Verifiable Credentials?',
654
965
  default: false,
655
966
  });
656
- const enableBridge = await confirm({
657
- message: 'Enable External IdP Bridge?',
658
- default: false,
659
- });
660
- const enablePolicy = await confirm({
661
- message: 'Enable ReBAC Policy service?',
662
- default: false,
663
- });
664
967
  // Step 6: Feature flags
665
968
  console.log('');
666
969
  console.log(chalk.blue('━━━ Feature Flags ━━━'));
@@ -772,13 +1075,19 @@ async function runNormalSetup(options) {
772
1075
  // Create configuration
773
1076
  const config = createDefaultConfig(envPrefix);
774
1077
  config.profile = profile;
1078
+ config.tenant = {
1079
+ name: tenantName,
1080
+ displayName: tenantDisplayName,
1081
+ multiTenant,
1082
+ baseDomain,
1083
+ };
775
1084
  config.components = {
776
1085
  ...config.components,
777
1086
  saml: enableSaml,
778
1087
  async: enableQueue, // async is tied to queue
779
1088
  vc: enableVc,
780
- bridge: enableBridge,
781
- policy: enablePolicy,
1089
+ bridge: true, // Standard component
1090
+ policy: true, // Standard component
782
1091
  };
783
1092
  config.urls = {
784
1093
  api: {
@@ -816,20 +1125,43 @@ async function runNormalSetup(options) {
816
1125
  console.log(chalk.bold('📋 Configuration Summary'));
817
1126
  console.log(chalk.blue('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
818
1127
  console.log('');
819
- console.log(chalk.bold('Basic Settings:'));
820
- console.log(` Environment: ${chalk.cyan(envPrefix)}`);
821
- console.log(` Profile: ${chalk.cyan(profile)}`);
1128
+ // Infrastructure
1129
+ console.log(chalk.bold('Infrastructure:'));
1130
+ console.log(` Environment: ${chalk.cyan(envPrefix)}`);
1131
+ console.log(` Worker Prefix: ${chalk.cyan(envPrefix + '-ar-*')}`);
1132
+ console.log(` Profile: ${chalk.cyan(profile)}`);
822
1133
  console.log('');
823
- console.log(chalk.bold('URL Settings:'));
824
- console.log(` API URL: ${chalk.cyan(config.urls.api.custom || config.urls.api.auto)}`);
1134
+ // Tenant mode and Issuer
1135
+ console.log(chalk.bold('Tenant & Issuer:'));
1136
+ console.log(` Mode: ${multiTenant ? chalk.cyan('Multi-tenant') : chalk.cyan('Single-tenant')}`);
1137
+ if (multiTenant && baseDomain) {
1138
+ console.log(` Base Domain: ${chalk.cyan(baseDomain)}`);
1139
+ console.log(` Issuer Format: ${chalk.cyan('https://{tenant}.' + baseDomain)}`);
1140
+ console.log(` Example: ${chalk.gray('https://acme.' + baseDomain)}`);
1141
+ }
1142
+ else {
1143
+ const issuerUrl = config.urls.api.custom || config.urls.api.auto;
1144
+ console.log(` Issuer URL: ${chalk.cyan(issuerUrl)}`);
1145
+ }
1146
+ console.log(` Default Tenant: ${chalk.cyan(tenantName)}`);
1147
+ console.log(` Display Name: ${chalk.cyan(tenantDisplayName)}`);
1148
+ console.log('');
1149
+ // Public URLs
1150
+ console.log(chalk.bold('Public URLs:'));
1151
+ if (multiTenant && baseDomain) {
1152
+ console.log(` API Router: ${chalk.cyan('*.' + baseDomain)} → ${chalk.gray(envPrefix + '-ar-router')}`);
1153
+ }
1154
+ else {
1155
+ console.log(` API Router: ${chalk.cyan(config.urls.api.custom || config.urls.api.auto)}`);
1156
+ }
825
1157
  console.log(` Login UI: ${chalk.cyan(config.urls.loginUi.custom || config.urls.loginUi.auto)}`);
826
1158
  console.log(` Admin UI: ${chalk.cyan(config.urls.adminUi.custom || config.urls.adminUi.auto)}`);
827
1159
  console.log('');
828
1160
  console.log(chalk.bold('Components:'));
829
1161
  console.log(` SAML: ${enableSaml ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
830
1162
  console.log(` VC: ${enableVc ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
831
- console.log(` Bridge: ${enableBridge ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
832
- console.log(` Policy: ${enablePolicy ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1163
+ console.log(` Social Login: ${chalk.green('Enabled')} ${chalk.gray('(standard)')}`);
1164
+ console.log(` Policy Engine: ${chalk.green('Enabled')} ${chalk.gray('(standard)')}`);
833
1165
  console.log('');
834
1166
  console.log(chalk.bold('Feature Flags:'));
835
1167
  console.log(` Queue: ${enableQueue ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
@@ -1356,11 +1688,11 @@ async function editUrls(config) {
1356
1688
  // =============================================================================
1357
1689
  async function editComponents(config) {
1358
1690
  console.log(chalk.bold('\nCurrent Component Settings:'));
1359
- console.log(` SAML: ${config.components.saml ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1360
- console.log(` Async: ${config.components.async ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1361
- console.log(` VC: ${config.components.vc ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1362
- console.log(` Bridge: ${config.components.bridge ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1363
- console.log(` Policy: ${config.components.policy ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1691
+ console.log(` SAML: ${config.components.saml ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1692
+ console.log(` Async: ${config.components.async ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1693
+ console.log(` VC: ${config.components.vc ? chalk.green('Enabled') : chalk.gray('Disabled')}`);
1694
+ console.log(` Social Login: ${chalk.green('Enabled')} ${chalk.gray('(standard - always on)')}`);
1695
+ console.log(` Policy Engine: ${chalk.green('Enabled')} ${chalk.gray('(standard - always on)')}`);
1364
1696
  console.log('');
1365
1697
  config.components.saml = await confirm({
1366
1698
  message: 'Enable SAML support?',
@@ -1374,14 +1706,9 @@ async function editComponents(config) {
1374
1706
  message: 'Enable Verifiable Credentials?',
1375
1707
  default: config.components.vc,
1376
1708
  });
1377
- config.components.bridge = await confirm({
1378
- message: 'Enable External IdP Bridge?',
1379
- default: config.components.bridge,
1380
- });
1381
- config.components.policy = await confirm({
1382
- message: 'Enable ReBAC Policy service?',
1383
- default: config.components.policy,
1384
- });
1709
+ // Standard components are always enabled
1710
+ config.components.bridge = true;
1711
+ config.components.policy = true;
1385
1712
  return true;
1386
1713
  }
1387
1714
  // =============================================================================