@serve.zone/dcrouter 15.6.0 → 15.7.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.
Files changed (50) hide show
  1. package/deno.json +1 -1
  2. package/dist_serve/bundle.js +423 -407
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/classes.dcrouter.d.ts +4 -1
  5. package/dist_ts/classes.dcrouter.js +45 -1
  6. package/dist_ts/db/documents/classes.email-server-settings.doc.d.ts +2 -1
  7. package/dist_ts/db/documents/classes.email-server-settings.doc.js +8 -2
  8. package/dist_ts/db/documents/classes.remote-ingress-edge.doc.d.ts +2 -1
  9. package/dist_ts/db/documents/classes.remote-ingress-edge.doc.js +8 -2
  10. package/dist_ts/email/classes.email-settings.manager.d.ts +5 -1
  11. package/dist_ts/email/classes.email-settings.manager.js +24 -1
  12. package/dist_ts/opsserver/handlers/config.handler.js +2 -1
  13. package/dist_ts/opsserver/handlers/email-settings.handler.js +2 -1
  14. package/dist_ts/opsserver/handlers/remoteingress.handler.js +3 -2
  15. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +6 -2
  16. package/dist_ts/remoteingress/classes.remoteingress-manager.js +65 -2
  17. package/dist_ts/remoteingress/classes.tunnel-manager.d.ts +6 -0
  18. package/dist_ts/remoteingress/classes.tunnel-manager.js +36 -1
  19. package/dist_ts_apiclient/classes.remoteingress.d.ts +10 -0
  20. package/dist_ts_apiclient/classes.remoteingress.js +23 -1
  21. package/dist_ts_interfaces/data/email-settings.d.ts +4 -0
  22. package/dist_ts_interfaces/data/remoteingress.d.ts +18 -0
  23. package/dist_ts_interfaces/requests/config.d.ts +1 -0
  24. package/dist_ts_interfaces/requests/remoteingress.d.ts +3 -1
  25. package/dist_ts_migrations/index.d.ts +1 -0
  26. package/dist_ts_migrations/index.js +80 -9
  27. package/dist_ts_web/00_commitinfo_data.js +1 -1
  28. package/dist_ts_web/appstate/remoteingress.d.ts +2 -0
  29. package/dist_ts_web/appstate/remoteingress.js +3 -1
  30. package/dist_ts_web/elements/email/ops-view-email-domains.js +7 -1
  31. package/dist_ts_web/elements/network/ops-view-remoteingress.d.ts +2 -0
  32. package/dist_ts_web/elements/network/ops-view-remoteingress.js +54 -2
  33. package/package.json +5 -5
  34. package/readme.md +22 -0
  35. package/ts/00_commitinfo_data.ts +1 -1
  36. package/ts/classes.dcrouter.ts +56 -4
  37. package/ts/db/documents/classes.email-server-settings.doc.ts +4 -1
  38. package/ts/db/documents/classes.remote-ingress-edge.doc.ts +4 -1
  39. package/ts/email/classes.email-settings.manager.ts +29 -0
  40. package/ts/opsserver/handlers/config.handler.ts +1 -0
  41. package/ts/opsserver/handlers/email-settings.handler.ts +1 -0
  42. package/ts/opsserver/handlers/remoteingress.handler.ts +2 -0
  43. package/ts/remoteingress/classes.remoteingress-manager.ts +78 -3
  44. package/ts/remoteingress/classes.tunnel-manager.ts +46 -0
  45. package/ts_apiclient/classes.remoteingress.ts +26 -0
  46. package/ts_apiclient/readme.md +8 -0
  47. package/ts_web/00_commitinfo_data.ts +1 -1
  48. package/ts_web/appstate/remoteingress.ts +4 -0
  49. package/ts_web/elements/email/ops-view-email-domains.ts +6 -0
  50. package/ts_web/elements/network/ops-view-remoteingress.ts +55 -1
@@ -259,6 +259,7 @@ export class OpsViewRemoteIngress extends DeesElement {
259
259
  transport: this.getTransportHtml(edge.id),
260
260
  publicIp: this.getEdgePublicIp(edge.id),
261
261
  ports: this.getPortsHtml(edge),
262
+ smtpEgress: this.getEgressHtml(edge),
262
263
  tunnels: this.getEdgeTunnelCount(edge.id),
263
264
  maxConnections: this.getMaxConnectionsHtml(edge),
264
265
  window: this.getWindowHtml(edge.id),
@@ -281,6 +282,9 @@ export class OpsViewRemoteIngress extends DeesElement {
281
282
  <dees-input-text .key=${'listenPorts'} .label=${'Manual Ports'} .description=${'Comma-separated port numbers, optional'}></dees-input-text>
282
283
  <dees-input-checkbox .key=${'autoDerivePorts'} .label=${'Auto-derive ports from routes'} .value=${true}></dees-input-checkbox>
283
284
  <dees-input-text .key=${'maxStreamsPerEdge'} .label=${'Max Connections'} .description=${'Optional maximum concurrent client connections for this edge. Leave empty to use the hub default.'}></dees-input-text>
285
+ <dees-input-checkbox .key=${'egressEnabled'} .label=${'Allow outbound SMTP egress'} .value=${false}></dees-input-checkbox>
286
+ <dees-input-text .key=${'egressAllowedHostPatterns'} .label=${'SMTP Egress Host Patterns'} .description=${'Optional comma-separated MX host patterns. Leave empty to allow public MX hosts on port 25.'}></dees-input-text>
287
+ <dees-input-text .key=${'egressMaxConcurrentStreams'} .label=${'SMTP Egress Max Streams'} .description=${'Optional concurrent outbound SMTP stream cap for this edge.'}></dees-input-text>
284
288
  <dees-input-text .key=${'tags'} .label=${'Tags'} .description=${'Comma-separated, optional'}></dees-input-text>
285
289
  </dees-form>
286
290
  `,
@@ -305,8 +309,10 @@ export class OpsViewRemoteIngress extends DeesElement {
305
309
  : undefined;
306
310
  const autoDerivePorts = formData.autoDerivePorts !== false;
307
311
  let performance: interfaces.data.IRemoteIngressPerformanceConfig | undefined;
312
+ let egress: interfaces.data.IRemoteIngressEgressPolicyConfig;
308
313
  try {
309
314
  performance = this.collectPerformanceOverride(formData);
315
+ egress = this.collectEgressPolicy(formData);
310
316
  } catch (err: unknown) {
311
317
  const { DeesToast } = await import('@design.estate/dees-catalog');
312
318
  DeesToast.show({ message: (err as Error).message, type: 'error', duration: 4000 });
@@ -317,7 +323,7 @@ export class OpsViewRemoteIngress extends DeesElement {
317
323
  : undefined;
318
324
  await appstate.remoteIngressStatePart.dispatchAction(
319
325
  appstate.createRemoteIngressAction,
320
- { name, listenPorts, autoDerivePorts, performance, tags },
326
+ { name, listenPorts, autoDerivePorts, performance, egress, tags },
321
327
  );
322
328
  await modalArg.destroy();
323
329
  },
@@ -375,6 +381,9 @@ export class OpsViewRemoteIngress extends DeesElement {
375
381
  <dees-input-text .key=${'listenPorts'} .label=${'Manual Ports'} .description=${'Comma-separated port numbers'} .value=${(edge.listenPorts || []).join(', ')}></dees-input-text>
376
382
  <dees-input-checkbox .key=${'autoDerivePorts'} .label=${'Auto-derive ports from routes'} .value=${edge.autoDerivePorts !== false}></dees-input-checkbox>
377
383
  <dees-input-text .key=${'maxStreamsPerEdge'} .label=${'Max Connections'} .description=${'Optional maximum concurrent client connections for this edge. Leave empty to use the hub default.'} .value=${edge.performance?.maxStreamsPerEdge?.toString() || ''}></dees-input-text>
384
+ <dees-input-checkbox .key=${'egressEnabled'} .label=${'Allow outbound SMTP egress'} .value=${edge.egress?.enabled === true}></dees-input-checkbox>
385
+ <dees-input-text .key=${'egressAllowedHostPatterns'} .label=${'SMTP Egress Host Patterns'} .description=${'Optional comma-separated MX host patterns. Leave empty to allow public MX hosts on port 25.'} .value=${(edge.egress?.allowedHostPatterns || []).join(', ')}></dees-input-text>
386
+ <dees-input-text .key=${'egressMaxConcurrentStreams'} .label=${'SMTP Egress Max Streams'} .description=${'Optional concurrent outbound SMTP stream cap for this edge.'} .value=${edge.egress?.maxConcurrentStreams?.toString() || ''}></dees-input-text>
378
387
  <dees-input-text .key=${'tags'} .label=${'Tags'} .description=${'Comma-separated'} .value=${(edge.tags || []).join(', ')}></dees-input-text>
379
388
  </dees-form>
380
389
  `,
@@ -397,8 +406,10 @@ export class OpsViewRemoteIngress extends DeesElement {
397
406
  : [];
398
407
  const autoDerivePorts = formData.autoDerivePorts !== false;
399
408
  let performance: interfaces.data.IRemoteIngressPerformanceConfig | undefined;
409
+ let egress: interfaces.data.IRemoteIngressEgressPolicyConfig;
400
410
  try {
401
411
  performance = this.collectPerformanceOverride(formData, edge.performance);
412
+ egress = this.collectEgressPolicy(formData, edge.egress);
402
413
  } catch (err: unknown) {
403
414
  const { DeesToast } = await import('@design.estate/dees-catalog');
404
415
  DeesToast.show({ message: (err as Error).message, type: 'error', duration: 4000 });
@@ -415,6 +426,7 @@ export class OpsViewRemoteIngress extends DeesElement {
415
426
  listenPorts,
416
427
  autoDerivePorts,
417
428
  performance,
429
+ egress,
418
430
  tags,
419
431
  },
420
432
  );
@@ -534,6 +546,16 @@ export class OpsViewRemoteIngress extends DeesElement {
534
546
  `;
535
547
  }
536
548
 
549
+ private getEgressHtml(edge: interfaces.data.IRemoteIngress): TemplateResult | string {
550
+ if (!edge.egress?.enabled) return '-';
551
+ return html`
552
+ <div class="metricStack">
553
+ <strong>SMTP</strong>
554
+ <span class="metricMuted">port ${(edge.egress.allowedPorts || [25]).join(', ')}</span>
555
+ </div>
556
+ `;
557
+ }
558
+
537
559
  private getTransportHtml(edgeId: string): TemplateResult | string {
538
560
  const status = this.getEdgeStatus(edgeId);
539
561
  if (!status?.connected) return '-';
@@ -618,6 +640,38 @@ export class OpsViewRemoteIngress extends DeesElement {
618
640
  return base ? {} : undefined;
619
641
  }
620
642
 
643
+ private collectEgressPolicy(
644
+ formData: Record<string, any>,
645
+ base?: interfaces.data.IRemoteIngressEgressPolicyConfig,
646
+ ): interfaces.data.IRemoteIngressEgressPolicyConfig {
647
+ const enabled = formData.egressEnabled !== false && Boolean(formData.egressEnabled);
648
+ if (!enabled) {
649
+ return { enabled: false };
650
+ }
651
+ const next: interfaces.data.IRemoteIngressEgressPolicyConfig = {
652
+ ...(base || {}),
653
+ enabled: true,
654
+ allowedPorts: [25],
655
+ };
656
+ const hostPatternsText = `${formData.egressAllowedHostPatterns || ''}`.trim();
657
+ if (hostPatternsText) {
658
+ next.allowedHostPatterns = hostPatternsText.split(',').map((pattern) => pattern.trim()).filter(Boolean);
659
+ } else {
660
+ delete next.allowedHostPatterns;
661
+ }
662
+ const maxStreamsText = `${formData.egressMaxConcurrentStreams || ''}`.trim();
663
+ if (maxStreamsText) {
664
+ const maxConcurrentStreams = Number.parseInt(maxStreamsText, 10);
665
+ if (!Number.isInteger(maxConcurrentStreams) || maxConcurrentStreams < 1) {
666
+ throw new Error('SMTP Egress Max Streams must be a positive integer');
667
+ }
668
+ next.maxConcurrentStreams = maxConcurrentStreams;
669
+ } else {
670
+ delete next.maxConcurrentStreams;
671
+ }
672
+ return next;
673
+ }
674
+
621
675
  private async showHubSettingsDialog(): Promise<void> {
622
676
  const { DeesModal, DeesToast } = await import('@design.estate/dees-catalog');
623
677
  const hubSettings = this.riState.hubSettings;