@selvajs/cli 4.20.0-beta.21 → 4.20.0-beta.22

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": "@selvajs/cli",
3
- "version": "4.20.0-beta.21",
3
+ "version": "4.20.0-beta.22",
4
4
  "description": "Scaffold and operate a Selva white-label deployment. `npx @selvajs/cli <dir>` to bootstrap, `selva <cmd>` to manage.",
5
5
  "license": "MIT",
6
6
  "author": "VektorNode",
@@ -260,6 +260,11 @@ function buildConfigReport(manifest, env, options = {}) {
260
260
  const raw = k.source === 'alias' ? env[k.alias] : env[spec.key];
261
261
  return {
262
262
  key: spec.key,
263
+ ...(spec.label ? { label: spec.label } : {}),
264
+ type: spec.type,
265
+ required: spec.required === true,
266
+ ...(spec.type === 'int' && spec.zero ? { zero: spec.zero } : {}),
267
+ ...(spec.type === 'int' && spec.unit ? { unit: spec.unit } : {}),
263
268
  class: spec.class,
264
269
  summary: spec.summary === true,
265
270
  description: spec.description,
@@ -407,9 +412,10 @@ Object.freeze({
407
412
  maxPerWindow: 20
408
413
  });
409
414
  // ../server/src/config/settings.ts
410
- var flag = (key, description, impact) =>
415
+ var flag = (key, label, description, impact) =>
411
416
  defineSetting({
412
417
  key: `SELVA_FLAG_${key}`,
418
+ label,
413
419
  type: 'bool',
414
420
  default: false,
415
421
  onInvalid: 'fail',
@@ -417,9 +423,10 @@ var flag = (key, description, impact) =>
417
423
  description,
418
424
  ...(impact ? { impact } : {})
419
425
  });
420
- var tunableInt = (key, fallback, description, extra = {}) =>
426
+ var tunableInt = (key, fallback, label, description, extra = {}) =>
421
427
  defineSetting({
422
428
  key,
429
+ label,
423
430
  type: 'int',
424
431
  min: 1,
425
432
  default: fallback,
@@ -430,31 +437,50 @@ var tunableInt = (key, fallback, description, extra = {}) =>
430
437
  });
431
438
  var MB = 1048576;
432
439
  var ENGINE_SETTINGS = composeManifest([
433
- ...['AUTH', 'DATA', 'STORAGE'].map((slot) =>
440
+ ...[
441
+ [
442
+ 'AUTH',
443
+ 'Sign-in',
444
+ 'Who checks passwords: local (this server), supabase, or header (your SSO proxy).'
445
+ ],
446
+ [
447
+ 'DATA',
448
+ 'Database',
449
+ 'Where users, orgs and projects live: local (files on this server) or supabase.'
450
+ ],
451
+ [
452
+ 'STORAGE',
453
+ 'File storage',
454
+ 'Where uploaded .gh files and images live: local (this server) or supabase.'
455
+ ]
456
+ ].map(([slot, label, description]) =>
434
457
  defineSetting({
435
458
  key: `SELVA_${slot}_PROVIDER`,
459
+ label,
436
460
  type: 'string',
437
461
  default: 'local',
438
462
  onInvalid: 'fail',
439
463
  class: 'bootstrap',
440
464
  summary: true,
441
- description: `${slot.toLowerCase()} provider: local, supabase${slot === 'AUTH' ? ' or header' : ''}.`,
465
+ description,
442
466
  impact:
443
467
  'Switching it does not move any data: the instance starts on what the new provider holds.'
444
468
  })
445
469
  ),
446
470
  defineSetting({
447
471
  key: 'SELVA_TENANCY',
472
+ label: 'Organizations',
448
473
  type: 'enum',
449
474
  values: ['single', 'multi'],
450
475
  default: 'single',
451
476
  onInvalid: 'fail',
452
477
  class: 'bootstrap',
453
478
  summary: true,
454
- description: 'single: one org per deployment. multi: users create their own orgs.'
479
+ description: 'single: everyone shares one organization. multi: users can create their own.'
455
480
  }),
456
481
  defineSetting({
457
482
  key: 'SELVA_CONFIG_PATH',
483
+ label: 'Custom config file',
458
484
  type: 'string',
459
485
  onInvalid: 'fail',
460
486
  class: 'bootstrap',
@@ -462,6 +488,7 @@ var ENGINE_SETTINGS = composeManifest([
462
488
  }),
463
489
  defineSetting({
464
490
  key: 'SELVA_HMAC_KEY',
491
+ label: 'Signing key',
465
492
  type: 'string',
466
493
  minLength: 32,
467
494
  required: true,
@@ -470,12 +497,14 @@ var ENGINE_SETTINGS = composeManifest([
470
497
  sensitive: true,
471
498
  generated: true,
472
499
  summary: true,
473
- description: 'Signs sessions (local auth), OAuth codes, MCP client ids and solve-event tokens.',
500
+ description:
501
+ 'Stops sign-ins, links and tokens from being forged. Generated at install; never share it.',
474
502
  impact:
475
503
  'Changing it without SELVA_HMAC_KEY_PREVIOUS breaks what it signed: run `selva keys rotate hmac`.'
476
504
  }),
477
505
  defineSetting({
478
506
  key: 'SELVA_AT_REST_KEY',
507
+ label: 'Encryption key',
479
508
  type: 'key',
480
509
  required: true,
481
510
  onInvalid: 'fail',
@@ -483,12 +512,13 @@ var ENGINE_SETTINGS = composeManifest([
483
512
  sensitive: true,
484
513
  generated: true,
485
514
  summary: true,
486
- description: 'Encrypts stored Rhino.Compute API keys.',
515
+ description: 'Encrypts the Rhino.Compute API keys stored here. Generated at install.',
487
516
  impact:
488
517
  'Changing it without SELVA_AT_REST_KEY_PREVIOUS makes stored API keys unreadable: run `selva keys rotate at-rest`.'
489
518
  }),
490
519
  defineSetting({
491
520
  key: 'SELVA_HMAC_KEY_PREVIOUS',
521
+ label: 'Previous signing key',
492
522
  type: 'string',
493
523
  minLength: 32,
494
524
  onInvalid: 'fail',
@@ -496,11 +526,12 @@ var ENGINE_SETTINGS = composeManifest([
496
526
  sensitive: true,
497
527
  generated: true,
498
528
  summary: true,
499
- description: 'The HMAC key before the last rotation. Still accepted for what it signed.',
529
+ description: 'Kept after a rotation so what the old signing key signed works until it expires.',
500
530
  impact: 'Removing it ends sessions, MCP clients and links signed before the rotation.'
501
531
  }),
502
532
  defineSetting({
503
533
  key: 'SELVA_AT_REST_KEY_PREVIOUS',
534
+ label: 'Previous encryption key',
504
535
  type: 'key',
505
536
  onInvalid: 'fail',
506
537
  class: 'secret',
@@ -508,11 +539,12 @@ var ENGINE_SETTINGS = composeManifest([
508
539
  generated: true,
509
540
  summary: true,
510
541
  description:
511
- 'The encryption key before the last rotation. Stored API keys are re-sealed at boot.',
542
+ 'Kept after a rotation until stored API keys are re-encrypted, which happens at the next start.',
512
543
  impact: 'Remove it only once /admin/system shows no API key on the previous key.'
513
544
  }),
514
545
  defineSetting({
515
546
  key: 'SELVA_HMAC_KEY_PREVIOUS_EXPIRES',
547
+ label: 'Previous signing key expiry',
516
548
  type: 'string',
517
549
  onInvalid: 'fail',
518
550
  class: 'secret',
@@ -523,6 +555,7 @@ var ENGINE_SETTINGS = composeManifest([
523
555
  }),
524
556
  defineSetting({
525
557
  key: 'SELVA_AT_REST_KEY_PREVIOUS_EXPIRES',
558
+ label: 'Previous encryption key expiry',
526
559
  type: 'string',
527
560
  onInvalid: 'fail',
528
561
  class: 'secret',
@@ -533,49 +566,61 @@ var ENGINE_SETTINGS = composeManifest([
533
566
  }),
534
567
  defineSetting({
535
568
  key: 'BOOTSTRAP_INSTANCE_ADMIN_EMAIL',
569
+ label: 'Recovery admin email',
536
570
  type: 'string',
537
571
  onInvalid: 'fail',
538
572
  class: 'bootstrap',
539
573
  sensitive: true,
540
574
  summary: true,
541
575
  description:
542
- 'Only this address may claim instance admin while none exists. Break-glass recovery.'
576
+ 'While no instance admin exists, only this address may become one. For first setup and lockouts.'
543
577
  }),
544
578
  defineSetting({
545
579
  key: 'SIGN_IN_MAX_AGE_DAYS',
580
+ label: 'Force sign-in again after',
546
581
  type: 'int',
547
582
  min: 0,
548
583
  default: 0,
549
584
  onInvalid: 'fail',
550
585
  class: 'setting',
551
586
  summary: true,
552
- description: 'How long one sign-in at the identity provider lasts. 0 is off.',
587
+ zero: 'Never',
588
+ unit: 'days',
589
+ description: 'Days before users must sign in at the identity provider again. 0 is never.',
553
590
  impact: 'API tokens of anyone who has not signed in within this many days are revoked.'
554
591
  }),
555
- flag('ALLOW_ORG_CREATION', 'Self-service org creation (read by host apps).'),
592
+ flag('ALLOW_ORG_CREATION', 'Users create orgs', 'Self-service org creation (read by host apps).'),
556
593
  flag(
557
594
  'ALLOW_CROSS_ORG_PUBLIC',
595
+ 'Public across orgs',
558
596
  'Public projects are visible to every signed-in user, not just the publishing org.',
559
597
  'Turning it on widens who sees existing public projects.'
560
598
  ),
561
- flag('ALLOW_ORG_COMPUTE_OVERRIDE', 'Orgs may configure their own Rhino.Compute server.'),
599
+ flag(
600
+ 'ALLOW_ORG_COMPUTE_OVERRIDE',
601
+ 'Orgs bring their own compute',
602
+ 'Orgs may configure their own Rhino.Compute server.'
603
+ ),
562
604
  flag(
563
605
  'ENABLE_SHARING',
606
+ 'Share links',
564
607
  'Per-definition share links for anonymous access.',
565
608
  'Turning it off stops every existing share link from resolving.'
566
609
  ),
567
610
  flag(
568
611
  'ENABLE_PLATFORM_PROJECTS',
612
+ 'Platform projects',
569
613
  'Projects owned by instance admins and granted to orgs or users.'
570
614
  ),
571
615
  ...[
572
- ['NAME', 'Product name in the header and titles.'],
573
- ['COPYRIGHT_NAME', 'Footer copyright owner. Defaults to the brand name.'],
574
- ['TAGLINE', 'Subtitle on the landing page.'],
575
- ['DESCRIPTION', 'Meta description for search and link previews.']
576
- ].map(([key, description]) =>
616
+ ['NAME', 'Product name', 'Product name in the header and titles.'],
617
+ ['COPYRIGHT_NAME', 'Copyright holder', 'Footer copyright owner. Defaults to the brand name.'],
618
+ ['TAGLINE', 'Tagline', 'Subtitle on the landing page.'],
619
+ ['DESCRIPTION', 'Site description', 'Meta description for search and link previews.']
620
+ ].map(([key, label, description]) =>
577
621
  defineSetting({
578
622
  key: `SELVA_BRAND_${key}`,
623
+ label,
579
624
  type: 'string',
580
625
  onInvalid: 'fail',
581
626
  class: 'setting',
@@ -584,6 +629,7 @@ var ENGINE_SETTINGS = composeManifest([
584
629
  ),
585
630
  defineSetting({
586
631
  key: 'SMTP_HOST',
632
+ label: 'Mail server',
587
633
  type: 'string',
588
634
  onInvalid: 'fail',
589
635
  class: 'setting',
@@ -591,6 +637,7 @@ var ENGINE_SETTINGS = composeManifest([
591
637
  }),
592
638
  defineSetting({
593
639
  key: 'SMTP_PORT',
640
+ label: 'Mail server port',
594
641
  type: 'int',
595
642
  min: 1,
596
643
  max: 65535,
@@ -601,6 +648,7 @@ var ENGINE_SETTINGS = composeManifest([
601
648
  }),
602
649
  defineSetting({
603
650
  key: 'SMTP_USER',
651
+ label: 'Mail username',
604
652
  type: 'string',
605
653
  onInvalid: 'fail',
606
654
  class: 'setting',
@@ -609,6 +657,7 @@ var ENGINE_SETTINGS = composeManifest([
609
657
  }),
610
658
  defineSetting({
611
659
  key: 'SMTP_PASS',
660
+ label: 'Mail password',
612
661
  type: 'string',
613
662
  onInvalid: 'fail',
614
663
  class: 'secret',
@@ -617,6 +666,7 @@ var ENGINE_SETTINGS = composeManifest([
617
666
  }),
618
667
  defineSetting({
619
668
  key: 'SMTP_FROM',
669
+ label: 'Sender address',
620
670
  type: 'string',
621
671
  onInvalid: 'fail',
622
672
  class: 'setting',
@@ -625,52 +675,123 @@ var ENGINE_SETTINGS = composeManifest([
625
675
  }),
626
676
  defineSetting({
627
677
  key: 'SMTP_SECURE',
678
+ label: 'Mail TLS mode',
628
679
  type: 'bool',
629
680
  onInvalid: 'fail',
630
681
  class: 'tunable',
631
682
  description: 'Override the TLS mode inferred from the port.',
632
683
  legacy: { bool: 'exact-true' }
633
684
  }),
634
- tunableInt('COMPUTE_SOLVE_DEADLINE_MS', 1e5, 'Longest one solve may run.', {
685
+ tunableInt('COMPUTE_SOLVE_DEADLINE_MS', 1e5, 'Solve time limit', 'Longest one solve may run.', {
686
+ unit: 'ms',
635
687
  aliases: ['MAX_SOLVE_DURATION_MS'],
636
688
  impact: 'Past the reverse proxy read timeout, solves fail there with a 502 instead.'
637
689
  }),
638
- tunableInt('COMPUTE_RATE_LIMIT_WINDOW_MS', 1e5, 'Compute rate-limit window.'),
639
- tunableInt('COMPUTE_RATE_LIMIT_MAX', 120, 'Solves per user or share link per window.'),
640
- tunableInt('MAX_DEFINITION_FILE_SIZE_BYTES', 50 * MB, 'Largest .gh upload.'),
641
- tunableInt('MAX_IMAGE_FILE_SIZE_BYTES', 10 * MB, 'Largest cover image upload.'),
642
- tunableInt('COMPUTE_REQUEST_MAX_BYTES', 256 * MB, 'Largest solve request body.', {
643
- impact: 'Must stay at or below BODY_SIZE_LIMIT, or that limit rejects first.'
644
- }),
645
- tunableInt('COMPUTE_RESPONSE_MAX_BYTES', 300 * MB, 'Largest solve response body.'),
646
- tunableInt('REMOTE_DEFINITION_FETCH_TIMEOUT_MS', 3e4, 'Deadline for fetching a remote .gh.'),
647
- tunableInt('REMOTE_DEFINITION_CACHE_TTL_MS', 3e5, 'How long remote .gh bytes stay cached.', {
648
- aliases: ['DEFINITION_CACHE_TTL_MS']
690
+ tunableInt(
691
+ 'COMPUTE_RATE_LIMIT_WINDOW_MS',
692
+ 1e5,
693
+ 'Solve rate limit window',
694
+ 'Compute rate-limit window.',
695
+ { unit: 'ms' }
696
+ ),
697
+ tunableInt(
698
+ 'COMPUTE_RATE_LIMIT_MAX',
699
+ 120,
700
+ 'Solves per window',
701
+ 'Solves per user or share link per window.'
702
+ ),
703
+ tunableInt('MAX_DEFINITION_FILE_SIZE_BYTES', 50 * MB, 'Max .gh upload', 'Largest .gh upload.', {
704
+ unit: 'bytes'
649
705
  }),
706
+ tunableInt(
707
+ 'MAX_IMAGE_FILE_SIZE_BYTES',
708
+ 10 * MB,
709
+ 'Max image upload',
710
+ 'Largest cover image upload.',
711
+ { unit: 'bytes' }
712
+ ),
713
+ tunableInt(
714
+ 'COMPUTE_REQUEST_MAX_BYTES',
715
+ 256 * MB,
716
+ 'Max solve request',
717
+ 'Largest solve request body.',
718
+ {
719
+ unit: 'bytes',
720
+ impact: 'Must stay at or below BODY_SIZE_LIMIT, or that limit rejects first.'
721
+ }
722
+ ),
723
+ tunableInt(
724
+ 'COMPUTE_RESPONSE_MAX_BYTES',
725
+ 300 * MB,
726
+ 'Max solve response',
727
+ 'Largest solve response body.',
728
+ { unit: 'bytes' }
729
+ ),
730
+ tunableInt(
731
+ 'REMOTE_DEFINITION_FETCH_TIMEOUT_MS',
732
+ 3e4,
733
+ 'Remote .gh fetch timeout',
734
+ 'Deadline for fetching a remote .gh.',
735
+ { unit: 'ms' }
736
+ ),
737
+ tunableInt(
738
+ 'REMOTE_DEFINITION_CACHE_TTL_MS',
739
+ 3e5,
740
+ 'Remote .gh cache time',
741
+ 'How long remote .gh bytes stay cached.',
742
+ {
743
+ unit: 'ms',
744
+ aliases: ['DEFINITION_CACHE_TTL_MS']
745
+ }
746
+ ),
650
747
  tunableInt(
651
748
  'COMPUTE_MAX_QUEUE_DEPTH',
652
749
  0,
750
+ 'Solve queue length',
653
751
  'Solves allowed to wait per compute server. 0 is unbounded.',
654
- { min: 0 }
752
+ {
753
+ min: 0,
754
+ zero: 'No limit'
755
+ }
756
+ ),
757
+ tunableInt(
758
+ 'COMPUTE_QUEUE_WAIT_MS',
759
+ 0,
760
+ 'Max queue wait',
761
+ 'Longest a solve may wait queued. 0 is no deadline.',
762
+ {
763
+ min: 0,
764
+ unit: 'ms',
765
+ zero: 'No limit'
766
+ }
767
+ ),
768
+ tunableInt(
769
+ 'COMPUTE_DEFINITION_CACHE_MB',
770
+ 256,
771
+ 'Definition cache size',
772
+ 'Definition cache budget. 0 turns it off.',
773
+ {
774
+ min: 0,
775
+ unit: 'mb',
776
+ zero: 'Off',
777
+ aliases: ['COMPUTE_DEFINITION_BYTE_CACHE_MB']
778
+ }
655
779
  ),
656
- tunableInt('COMPUTE_QUEUE_WAIT_MS', 0, 'Longest a solve may wait queued. 0 is no deadline.', {
657
- min: 0
658
- }),
659
- tunableInt('COMPUTE_DEFINITION_CACHE_MB', 256, 'Definition cache budget. 0 turns it off.', {
660
- min: 0,
661
- aliases: ['COMPUTE_DEFINITION_BYTE_CACHE_MB']
662
- }),
663
780
  tunableInt(
664
781
  'COMPUTE_SOLVE_CACHE_MB',
665
782
  256,
783
+ 'Solve cache size',
666
784
  'Solve cache budget per warm compute server. 0 turns it off.',
667
785
  {
668
786
  min: 0,
787
+ unit: 'mb',
788
+ zero: 'Off',
669
789
  aliases: ['COMPUTE_RESPONSE_CACHE_MB']
670
790
  }
671
791
  ),
672
792
  defineSetting({
673
793
  key: 'COMPUTE_REUSE_DEFINITION_CACHE',
794
+ label: 'Reuse compute server definition cache',
674
795
  type: 'bool',
675
796
  default: true,
676
797
  onInvalid: 'default',
@@ -681,6 +802,7 @@ var ENGINE_SETTINGS = composeManifest([
681
802
  }),
682
803
  defineSetting({
683
804
  key: 'COMPUTE_SERVER_CACHESOLVE',
805
+ label: 'Compute server solve cache',
684
806
  type: 'bool',
685
807
  default: true,
686
808
  onInvalid: 'default',
@@ -690,19 +812,26 @@ var ENGINE_SETTINGS = composeManifest([
690
812
  tunableInt(
691
813
  'API_TOKEN_RATE_LIMIT_WINDOW_MS',
692
814
  DEFAULT_API_RATE_LIMIT.windowMs,
693
- 'API token rate-limit window.'
815
+ 'API rate limit window',
816
+ 'API token rate-limit window.',
817
+ { unit: 'ms' }
694
818
  ),
695
819
  tunableInt(
696
820
  'API_TOKEN_RATE_LIMIT_MAX',
697
821
  DEFAULT_API_RATE_LIMIT.maxPerWindow,
822
+ 'API requests per window',
698
823
  'Requests per API token per window. 0 is off.',
699
- { min: 0 }
824
+ {
825
+ min: 0,
826
+ zero: 'Off'
827
+ }
700
828
  )
701
829
  ]);
702
830
  // ../providers/header-auth/src/config.ts
703
831
  var header = (key, fallback, slot) =>
704
832
  defineSetting({
705
833
  key,
834
+ label: `${slot[0].toUpperCase()}${slot.slice(1)} header`,
706
835
  type: 'string',
707
836
  default: fallback,
708
837
  onInvalid: 'fail',
@@ -713,6 +842,7 @@ var header = (key, fallback, slot) =>
713
842
  var HEADER_AUTH_SETTINGS = composeManifest([
714
843
  defineSetting({
715
844
  key: 'HEADER_AUTH_DATA_DIR',
845
+ label: 'Allowlist folder',
716
846
  type: 'string',
717
847
  onInvalid: 'fail',
718
848
  class: 'bootstrap',
@@ -726,12 +856,13 @@ var HEADER_AUTH_SETTINGS = composeManifest([
726
856
  var LOCAL_SETTINGS = composeManifest([
727
857
  defineSetting({
728
858
  key: 'DATA_PATH',
859
+ label: 'Data folder',
729
860
  type: 'string',
730
861
  required: true,
731
862
  onInvalid: 'fail',
732
863
  class: 'bootstrap',
733
864
  summary: true,
734
- description: 'Directory holding users, orgs, projects and uploaded files.',
865
+ description: 'Folder on this server holding users, orgs, projects and uploads. Back it up.',
735
866
  impact: 'Pointing it elsewhere starts an empty instance; the old data stays where it was.'
736
867
  })
737
868
  ]);
@@ -739,6 +870,7 @@ var LOCAL_SETTINGS = composeManifest([
739
870
  var SUPABASE_SETTINGS = composeManifest([
740
871
  defineSetting({
741
872
  key: 'SUPABASE_URL',
873
+ label: 'Supabase project',
742
874
  type: 'url',
743
875
  required: true,
744
876
  onInvalid: 'fail',
@@ -749,6 +881,7 @@ var SUPABASE_SETTINGS = composeManifest([
749
881
  }),
750
882
  defineSetting({
751
883
  key: 'SUPABASE_ANON_KEY',
884
+ label: 'Supabase publishable key',
752
885
  type: 'string',
753
886
  required: true,
754
887
  onInvalid: 'fail',
@@ -757,6 +890,7 @@ var SUPABASE_SETTINGS = composeManifest([
757
890
  }),
758
891
  defineSetting({
759
892
  key: 'SUPABASE_SERVICE_ROLE_KEY',
893
+ label: 'Supabase secret key',
760
894
  type: 'string',
761
895
  required: true,
762
896
  onInvalid: 'fail',
@@ -766,6 +900,7 @@ var SUPABASE_SETTINGS = composeManifest([
766
900
  }),
767
901
  defineSetting({
768
902
  key: 'SUPABASE_JWT_SIGNING_KEY',
903
+ label: 'Supabase JWT signing key',
769
904
  type: 'string',
770
905
  onInvalid: 'fail',
771
906
  class: 'secret',
@@ -775,6 +910,7 @@ var SUPABASE_SETTINGS = composeManifest([
775
910
  }),
776
911
  defineSetting({
777
912
  key: 'SUPABASE_JWT_SECRET',
913
+ label: 'Supabase JWT secret (legacy)',
778
914
  type: 'string',
779
915
  onInvalid: 'fail',
780
916
  class: 'secret',
@@ -783,6 +919,7 @@ var SUPABASE_SETTINGS = composeManifest([
783
919
  }),
784
920
  defineSetting({
785
921
  key: 'SUPABASE_ENABLE_SELF_SIGNUP',
922
+ label: 'Self sign-up',
786
923
  type: 'bool',
787
924
  default: false,
788
925
  onInvalid: 'fail',
@@ -792,6 +929,7 @@ var SUPABASE_SETTINGS = composeManifest([
792
929
  }),
793
930
  defineSetting({
794
931
  key: 'SUPABASE_ALLOW_EMAIL_LINK_SIGNUP',
932
+ label: 'Sign-up by email link',
795
933
  type: 'bool',
796
934
  default: true,
797
935
  onInvalid: 'fail',
@@ -801,6 +939,7 @@ var SUPABASE_SETTINGS = composeManifest([
801
939
  }),
802
940
  defineSetting({
803
941
  key: 'SUPABASE_OAUTH_PROVIDERS',
942
+ label: 'OAuth sign-in buttons',
804
943
  type: 'list',
805
944
  default: [],
806
945
  onInvalid: 'fail',
@@ -809,6 +948,7 @@ var SUPABASE_SETTINGS = composeManifest([
809
948
  }),
810
949
  defineSetting({
811
950
  key: 'SUPABASE_TOKEN_VERIFICATION',
951
+ label: 'Session check mode',
812
952
  type: 'enum',
813
953
  values: ['hybrid', 'strict'],
814
954
  default: 'hybrid',
@@ -820,15 +960,18 @@ var SUPABASE_SETTINGS = composeManifest([
820
960
  }),
821
961
  defineSetting({
822
962
  key: 'SUPABASE_REVALIDATE_MS',
963
+ label: 'Session recheck interval',
823
964
  type: 'int',
824
965
  min: 1,
825
966
  default: 6e4,
967
+ unit: 'ms',
826
968
  onInvalid: 'default',
827
969
  class: 'tunable',
828
970
  description: 'Hybrid recheck window: the longest a revoked session keeps working.'
829
971
  }),
830
972
  defineSetting({
831
973
  key: 'SUPABASE_PUBLIC_BUCKET',
974
+ label: 'Public files bucket',
832
975
  type: 'string',
833
976
  default: 'selva-public',
834
977
  onInvalid: 'fail',
@@ -837,6 +980,7 @@ var SUPABASE_SETTINGS = composeManifest([
837
980
  }),
838
981
  defineSetting({
839
982
  key: 'SUPABASE_PRIVATE_BUCKET',
983
+ label: 'Private files bucket',
840
984
  type: 'string',
841
985
  default: 'selva-private',
842
986
  onInvalid: 'fail',
@@ -845,6 +989,7 @@ var SUPABASE_SETTINGS = composeManifest([
845
989
  }),
846
990
  defineSetting({
847
991
  key: 'SUPABASE_PRIVATE_URL_PREFIX',
992
+ label: 'Private file URL prefix',
848
993
  type: 'string',
849
994
  default: '/api/files',
850
995
  onInvalid: 'fail',
@@ -857,16 +1002,18 @@ var SUPABASE_SETTINGS = composeManifest([
857
1002
  var APP_SETTINGS = composeManifest([
858
1003
  defineSetting({
859
1004
  key: 'ORIGIN',
1005
+ label: 'Public address',
860
1006
  type: 'url',
861
1007
  onInvalid: 'fail',
862
1008
  class: 'bootstrap',
863
1009
  summary: true,
864
- description: 'Public URL of the app. Required behind a reverse proxy.',
1010
+ description: 'The URL people use to reach Selva, such as https://selva.example.com.',
865
1011
  impact:
866
1012
  'Wrong or unset behind a proxy: form posts fail the CSRF check and invite links carry an internal host.'
867
1013
  }),
868
1014
  defineSetting({
869
1015
  key: 'PORT',
1016
+ label: 'Port',
870
1017
  type: 'int',
871
1018
  min: 1,
872
1019
  max: 65535,
@@ -877,44 +1024,51 @@ var APP_SETTINGS = composeManifest([
877
1024
  }),
878
1025
  defineSetting({
879
1026
  key: 'HOST',
1027
+ label: 'Listen address',
880
1028
  type: 'string',
881
1029
  default: '0.0.0.0',
882
1030
  onInvalid: 'fail',
883
1031
  class: 'bootstrap',
884
1032
  summary: true,
885
- description: 'Address the app binds to. 127.0.0.1 behind a proxy.',
1033
+ description:
1034
+ 'Which network address the app accepts connections on. 127.0.0.1 when a proxy sits in front.',
886
1035
  impact: 'Under header auth, anything that reaches the port directly can claim to be any user.'
887
1036
  }),
888
1037
  defineSetting({
889
1038
  key: 'BODY_SIZE_LIMIT',
1039
+ label: 'Max request size',
890
1040
  type: 'string',
891
1041
  default: '512K',
892
1042
  onInvalid: 'fail',
893
1043
  class: 'bootstrap',
894
1044
  summary: true,
895
- description: 'Largest request body adapter-node accepts (K, M or G suffix).',
1045
+ description: 'Largest request the server accepts at all, uploads included (K, M or G suffix).',
896
1046
  impact: 'Below COMPUTE_REQUEST_MAX_BYTES, uploads and file inputs fail with 413.'
897
1047
  }),
898
1048
  defineSetting({
899
1049
  key: 'ADDRESS_HEADER',
1050
+ label: 'Visitor IP header',
900
1051
  type: 'string',
901
1052
  onInvalid: 'fail',
902
1053
  class: 'bootstrap',
903
1054
  summary: true,
904
- description: 'Header carrying the client IP behind a proxy (X-Forwarded-For).',
1055
+ description:
1056
+ 'Header your proxy uses to pass on the visitor’s IP address. Usually X-Forwarded-For.',
905
1057
  impact: 'Unset behind a proxy: every client shares one rate-limit bucket.'
906
1058
  }),
907
1059
  defineSetting({
908
1060
  key: 'XFF_DEPTH',
1061
+ label: 'Proxies in front',
909
1062
  type: 'int',
910
1063
  min: 1,
911
1064
  onInvalid: 'fail',
912
1065
  class: 'bootstrap',
913
1066
  summary: true,
914
- description: 'Number of proxies in front of the app.'
1067
+ description: 'How many proxies sit between visitors and the app. Usually 1.'
915
1068
  }),
916
1069
  defineSetting({
917
1070
  key: 'PROTOCOL_HEADER',
1071
+ label: 'Protocol header',
918
1072
  type: 'string',
919
1073
  onInvalid: 'fail',
920
1074
  class: 'bootstrap',
@@ -922,6 +1076,7 @@ var APP_SETTINGS = composeManifest([
922
1076
  }),
923
1077
  defineSetting({
924
1078
  key: 'HOST_HEADER',
1079
+ label: 'Host header',
925
1080
  type: 'string',
926
1081
  onInvalid: 'fail',
927
1082
  class: 'bootstrap',
@@ -929,6 +1084,7 @@ var APP_SETTINGS = composeManifest([
929
1084
  }),
930
1085
  defineSetting({
931
1086
  key: 'NODE_ENV',
1087
+ label: 'Run mode',
932
1088
  type: 'string',
933
1089
  onInvalid: 'fail',
934
1090
  class: 'bootstrap',
@@ -936,6 +1092,7 @@ var APP_SETTINGS = composeManifest([
936
1092
  }),
937
1093
  defineSetting({
938
1094
  key: 'ALLOW_INSECURE_COOKIES',
1095
+ label: 'Allow sign-in over http',
939
1096
  type: 'bool',
940
1097
  default: false,
941
1098
  onInvalid: 'fail',
@@ -945,6 +1102,7 @@ var APP_SETTINGS = composeManifest([
945
1102
  }),
946
1103
  defineSetting({
947
1104
  key: 'INSTALL_DIR',
1105
+ label: 'Install folder',
948
1106
  type: 'string',
949
1107
  onInvalid: 'fail',
950
1108
  class: 'bootstrap',
@@ -953,6 +1111,7 @@ var APP_SETTINGS = composeManifest([
953
1111
  }),
954
1112
  defineSetting({
955
1113
  key: 'SELVA_EVENT_CALLBACK_ORIGIN',
1114
+ label: 'Solve event callback address',
956
1115
  type: 'url',
957
1116
  onInvalid: 'fail',
958
1117
  class: 'bootstrap',
@@ -961,6 +1120,7 @@ var APP_SETTINGS = composeManifest([
961
1120
  }),
962
1121
  defineSetting({
963
1122
  key: 'MCP_ALLOWED_ORIGINS',
1123
+ label: 'Extra MCP origins',
964
1124
  type: 'list',
965
1125
  default: [],
966
1126
  onInvalid: 'fail',
@@ -969,6 +1129,7 @@ var APP_SETTINGS = composeManifest([
969
1129
  }),
970
1130
  defineSetting({
971
1131
  key: 'LOG_LEVEL',
1132
+ label: 'Log level',
972
1133
  type: 'enum',
973
1134
  values: ['debug', 'info', 'warn', 'error'],
974
1135
  onInvalid: 'default',
@@ -977,6 +1138,7 @@ var APP_SETTINGS = composeManifest([
977
1138
  }),
978
1139
  defineSetting({
979
1140
  key: 'SELVA_FLAG_COMPUTE_DEBUG',
1141
+ label: 'Compute debug logging',
980
1142
  type: 'string',
981
1143
  default: 'off',
982
1144
  onInvalid: 'default',
@@ -987,6 +1149,7 @@ var APP_SETTINGS = composeManifest([
987
1149
  }),
988
1150
  defineSetting({
989
1151
  key: 'SELVA_FLAG_COMPUTE_DEBUG_VERBOSE',
1152
+ label: 'Compute debug logging (old name)',
990
1153
  type: 'bool',
991
1154
  onInvalid: 'default',
992
1155
  class: 'setting',
@@ -994,6 +1157,7 @@ var APP_SETTINGS = composeManifest([
994
1157
  }),
995
1158
  defineSetting({
996
1159
  key: 'SENTRY_DSN',
1160
+ label: 'Sentry error reporting',
997
1161
  type: 'url',
998
1162
  onInvalid: 'fail',
999
1163
  class: 'secret',
@@ -1002,6 +1166,7 @@ var APP_SETTINGS = composeManifest([
1002
1166
  }),
1003
1167
  defineSetting({
1004
1168
  key: 'SELVA_RELEASE',
1169
+ label: 'Release tag',
1005
1170
  type: 'string',
1006
1171
  onInvalid: 'fail',
1007
1172
  class: 'tunable',