@serve.zone/dcrouter 13.19.1 → 13.20.0

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.
@@ -43,22 +43,28 @@ function parseTargetPort(value: any): number | undefined {
43
43
 
44
44
  function getRouteTargetInputs(formEl: any) {
45
45
  const textInputs = Array.from(formEl.querySelectorAll('dees-input-text')) as any[];
46
+ const checkboxInputs = Array.from(formEl.querySelectorAll('dees-input-checkbox')) as any[];
46
47
  return {
47
48
  hostInput: textInputs.find((input) => input.key === 'targetHost'),
48
49
  portInput: textInputs.find((input) => input.key === 'targetPort'),
50
+ preservePortInput: checkboxInputs.find((input) => input.key === 'preserveMatchPort'),
49
51
  };
50
52
  }
51
53
 
52
54
  function setupTargetInputState(formEl: any) {
53
55
  const updateState = async () => {
54
56
  const data = await formEl.collectFormData();
57
+ const contentEl = formEl.closest('.content') || formEl.parentElement;
55
58
  const usesNetworkTarget = !!getDropdownKey(data.networkTargetRef);
56
- const { hostInput, portInput } = getRouteTargetInputs(formEl);
59
+ const preserveMatchPort = !usesNetworkTarget && Boolean(data.preserveMatchPort);
60
+ const { hostInput, portInput, preservePortInput } = getRouteTargetInputs(formEl);
57
61
  const hostDescription = usesNetworkTarget
58
62
  ? 'Controlled by the selected network target'
59
63
  : 'Used when no network target is selected';
60
64
  const portDescription = usesNetworkTarget
61
65
  ? 'Controlled by the selected network target'
66
+ : preserveMatchPort
67
+ ? 'Forwarded to the backend on the same port the client matched'
62
68
  : 'Used when no network target is selected';
63
69
 
64
70
  if (hostInput) {
@@ -67,10 +73,24 @@ function setupTargetInputState(formEl: any) {
67
73
  hostInput.description = hostDescription;
68
74
  }
69
75
  if (portInput) {
70
- portInput.disabled = usesNetworkTarget;
71
- portInput.required = !usesNetworkTarget;
76
+ portInput.disabled = usesNetworkTarget || preserveMatchPort;
77
+ portInput.required = !usesNetworkTarget && !preserveMatchPort;
72
78
  portInput.description = portDescription;
73
79
  }
80
+ if (preservePortInput) {
81
+ preservePortInput.disabled = usesNetworkTarget;
82
+ preservePortInput.description = usesNetworkTarget
83
+ ? 'Unavailable when a network target is selected'
84
+ : 'Forward to the backend using the same port that matched this route';
85
+ if (usesNetworkTarget) {
86
+ preservePortInput.value = false;
87
+ }
88
+ }
89
+
90
+ const remoteIngressGroup = contentEl?.querySelector('.remoteIngressGroup') as HTMLElement | null;
91
+ if (remoteIngressGroup) {
92
+ remoteIngressGroup.style.display = Boolean(data.remoteIngressEnabled) ? 'flex' : 'none';
93
+ }
74
94
 
75
95
  await formEl.updateRequiredStatus?.();
76
96
  };
@@ -465,10 +485,13 @@ export class OpsViewRoutes extends DeesElement {
465
485
  ? (Array.isArray(route.match.domains) ? route.match.domains : [route.match.domains])
466
486
  : [];
467
487
  const firstTarget = route.action.targets?.[0];
488
+ const currentPreserveMatchPort = firstTarget?.port === 'preserve';
468
489
  const currentTargetHost = firstTarget
469
490
  ? (Array.isArray(firstTarget.host) ? firstTarget.host[0] : firstTarget.host)
470
491
  : '';
471
- const currentTargetPort = firstTarget?.port != null ? String(firstTarget.port) : '';
492
+ const currentTargetPort = typeof firstTarget?.port === 'number' ? String(firstTarget.port) : '';
493
+ const currentRemoteIngressEnabled = route.remoteIngress?.enabled === true;
494
+ const currentEdgeFilter = route.remoteIngress?.edgeFilter || [];
472
495
 
473
496
  // Compute current TLS state for pre-population
474
497
  const currentTls = (route.action as any).tls;
@@ -493,6 +516,11 @@ export class OpsViewRoutes extends DeesElement {
493
516
  <dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions} .selectedOption=${targetOptions.find((o) => o.key === (merged.metadata?.networkTargetRef || '')) || null}></dees-input-dropdown>
494
517
  <dees-input-text .key=${'targetHost'} .label=${'Target Host'} .description=${'Used when no network target is selected'} .value=${currentTargetHost}></dees-input-text>
495
518
  <dees-input-text .key=${'targetPort'} .label=${'Target Port'} .description=${'Used when no network target is selected'} .value=${currentTargetPort}></dees-input-text>
519
+ <dees-input-checkbox .key=${'preserveMatchPort'} .label=${'Preserve incoming port'} .value=${currentPreserveMatchPort}></dees-input-checkbox>
520
+ <dees-input-checkbox .key=${'remoteIngressEnabled'} .label=${'Enable Remote Ingress'} .value=${currentRemoteIngressEnabled}></dees-input-checkbox>
521
+ <div class="remoteIngressGroup" style="display: ${currentRemoteIngressEnabled ? 'flex' : 'none'}; flex-direction: column; gap: 16px;">
522
+ <dees-input-list .key=${'remoteIngressEdgeFilter'} .label=${'Edge Filter'} .description=${'Optional edge IDs or tags. Leave empty to allow all edges.'} .placeholder=${'Add edge ID or tag...'} .value=${currentEdgeFilter}></dees-input-list>
523
+ </div>
496
524
  <dees-input-dropdown .key=${'tlsMode'} .label=${'TLS Mode'} .options=${tlsModeOptions} .selectedOption=${tlsModeOptions.find((o) => o.key === currentTlsMode) || tlsModeOptions[0]}></dees-input-dropdown>
497
525
  <div class="tlsCertificateGroup" style="display: ${needsCert ? 'flex' : 'none'}; flex-direction: column; gap: 16px;">
498
526
  <dees-input-dropdown .key=${'tlsCertificate'} .label=${'Certificate'} .options=${tlsCertOptions} .selectedOption=${tlsCertOptions.find((o) => o.key === currentTlsCert) || tlsCertOptions[0]}></dees-input-dropdown>
@@ -526,14 +554,22 @@ export class OpsViewRoutes extends DeesElement {
526
554
 
527
555
  const profileKey = getDropdownKey(formData.sourceProfileRef);
528
556
  const targetKey = getDropdownKey(formData.networkTargetRef);
529
- const targetPort = parseTargetPort(formData.targetPort)
530
- ?? (targetKey ? parseTargetPort(currentTargetPort) ?? ports[0] : undefined);
557
+ const preserveMatchPort = !targetKey && Boolean(formData.preserveMatchPort);
558
+ const targetPort = preserveMatchPort
559
+ ? 'preserve'
560
+ : parseTargetPort(formData.targetPort)
561
+ ?? (targetKey ? parseTargetPort(currentTargetPort) ?? ports[0] : undefined);
531
562
 
532
563
  if (targetPort === undefined) {
533
564
  alert('Target Port must be a valid port number when no network target is selected.');
534
565
  return;
535
566
  }
536
567
 
568
+ const remoteIngressEnabled = Boolean(formData.remoteIngressEnabled);
569
+ const remoteIngressEdgeFilter: string[] = Array.isArray(formData.remoteIngressEdgeFilter)
570
+ ? formData.remoteIngressEdgeFilter.filter(Boolean)
571
+ : [];
572
+
537
573
  const updatedRoute: any = {
538
574
  name: formData.name,
539
575
  match: {
@@ -549,6 +585,12 @@ export class OpsViewRoutes extends DeesElement {
549
585
  },
550
586
  ],
551
587
  },
588
+ remoteIngress: remoteIngressEnabled
589
+ ? {
590
+ enabled: true,
591
+ ...(remoteIngressEdgeFilter.length > 0 ? { edgeFilter: remoteIngressEdgeFilter } : {}),
592
+ }
593
+ : null,
552
594
  ...(priority != null && !isNaN(priority) ? { priority } : {}),
553
595
  };
554
596
 
@@ -640,6 +682,11 @@ export class OpsViewRoutes extends DeesElement {
640
682
  <dees-input-dropdown .key=${'networkTargetRef'} .label=${'Network Target'} .options=${targetOptions}></dees-input-dropdown>
641
683
  <dees-input-text .key=${'targetHost'} .label=${'Target Host'} .description=${'Used when no network target is selected'} .value=${'localhost'}></dees-input-text>
642
684
  <dees-input-text .key=${'targetPort'} .label=${'Target Port'} .description=${'Used when no network target is selected'}></dees-input-text>
685
+ <dees-input-checkbox .key=${'preserveMatchPort'} .label=${'Preserve incoming port'} .value=${false}></dees-input-checkbox>
686
+ <dees-input-checkbox .key=${'remoteIngressEnabled'} .label=${'Enable Remote Ingress'} .value=${false}></dees-input-checkbox>
687
+ <div class="remoteIngressGroup" style="display: none; flex-direction: column; gap: 16px;">
688
+ <dees-input-list .key=${'remoteIngressEdgeFilter'} .label=${'Edge Filter'} .description=${'Optional edge IDs or tags. Leave empty to allow all edges.'} .placeholder=${'Add edge ID or tag...'}></dees-input-list>
689
+ </div>
643
690
  <dees-input-dropdown .key=${'tlsMode'} .label=${'TLS Mode'} .options=${tlsModeOptions} .selectedOption=${tlsModeOptions[0]}></dees-input-dropdown>
644
691
  <div class="tlsCertificateGroup" style="display: none; flex-direction: column; gap: 16px;">
645
692
  <dees-input-dropdown .key=${'tlsCertificate'} .label=${'Certificate'} .options=${tlsCertOptions} .selectedOption=${tlsCertOptions[0]}></dees-input-dropdown>
@@ -673,14 +720,22 @@ export class OpsViewRoutes extends DeesElement {
673
720
 
674
721
  const profileKey = getDropdownKey(formData.sourceProfileRef);
675
722
  const targetKey = getDropdownKey(formData.networkTargetRef);
676
- const targetPort = parseTargetPort(formData.targetPort)
677
- ?? (targetKey ? ports[0] : undefined);
723
+ const preserveMatchPort = !targetKey && Boolean(formData.preserveMatchPort);
724
+ const targetPort = preserveMatchPort
725
+ ? 'preserve'
726
+ : parseTargetPort(formData.targetPort)
727
+ ?? (targetKey ? ports[0] : undefined);
678
728
 
679
729
  if (targetPort === undefined) {
680
730
  alert('Target Port must be a valid port number when no network target is selected.');
681
731
  return;
682
732
  }
683
733
 
734
+ const remoteIngressEnabled = Boolean(formData.remoteIngressEnabled);
735
+ const remoteIngressEdgeFilter: string[] = Array.isArray(formData.remoteIngressEdgeFilter)
736
+ ? formData.remoteIngressEdgeFilter.filter(Boolean)
737
+ : [];
738
+
684
739
  const route: any = {
685
740
  name: formData.name,
686
741
  match: {
@@ -696,6 +751,14 @@ export class OpsViewRoutes extends DeesElement {
696
751
  },
697
752
  ],
698
753
  },
754
+ ...(remoteIngressEnabled
755
+ ? {
756
+ remoteIngress: {
757
+ enabled: true,
758
+ ...(remoteIngressEdgeFilter.length > 0 ? { edgeFilter: remoteIngressEdgeFilter } : {}),
759
+ },
760
+ }
761
+ : {}),
699
762
  ...(priority != null && !isNaN(priority) ? { priority } : {}),
700
763
  };
701
764