@serve.zone/dcrouter 6.11.0 → 6.13.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.
package/ts/readme.md ADDED
@@ -0,0 +1,146 @@
1
+ # @serve.zone/dcrouter
2
+
3
+ The core DcRouter package — a unified datacenter gateway orchestrator. 🚀
4
+
5
+ This is the main entry point for DcRouter. It provides the `DcRouter` class that wires together SmartProxy, smartmta, SmartDNS, SmartRadius, RemoteIngress, and the OpsServer dashboard into a single cohesive service.
6
+
7
+ ## Issue Reporting and Security
8
+
9
+ For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pnpm add @serve.zone/dcrouter
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```typescript
20
+ import { DcRouter } from '@serve.zone/dcrouter';
21
+
22
+ const router = new DcRouter({
23
+ smartProxyConfig: {
24
+ routes: [
25
+ {
26
+ name: 'web-app',
27
+ match: { domains: ['example.com'], ports: [443] },
28
+ action: {
29
+ type: 'forward',
30
+ targets: [{ host: '192.168.1.10', port: 8080 }],
31
+ tls: { mode: 'terminate', certificate: 'auto' }
32
+ }
33
+ }
34
+ ],
35
+ acme: { email: 'admin@example.com', enabled: true, useProduction: true }
36
+ }
37
+ });
38
+
39
+ await router.start();
40
+ // OpsServer dashboard at http://localhost:3000
41
+
42
+ // Graceful shutdown
43
+ await router.stop();
44
+ ```
45
+
46
+ ## Module Structure
47
+
48
+ ```
49
+ ts/
50
+ ├── index.ts # Main exports (DcRouter, re-exported smartmta types)
51
+ ├── classes.dcrouter.ts # DcRouter orchestrator class + IDcRouterOptions
52
+ ├── classes.cert-provision-scheduler.ts # Per-domain cert backoff scheduler
53
+ ├── classes.storage-cert-manager.ts # SmartAcme cert manager backed by StorageManager
54
+ ├── logger.ts # Structured logging utility
55
+ ├── paths.ts # Centralized data directory paths
56
+ ├── plugins.ts # All dependency imports
57
+ ├── cache/ # Cache database (smartdata + LocalTsmDb)
58
+ │ ├── classes.cachedb.ts # CacheDb singleton
59
+ │ ├── classes.cachecleaner.ts # TTL-based cleanup
60
+ │ └── documents/ # Cached document models
61
+ ├── config/ # Configuration utilities
62
+ ├── errors/ # Error classes and retry logic
63
+ ├── monitoring/ # MetricsManager (SmartMetrics integration)
64
+ ├── opsserver/ # OpsServer dashboard + API handlers
65
+ │ ├── classes.opsserver.ts # HTTP server + TypedRouter setup
66
+ │ └── handlers/ # TypedRequest handlers by domain
67
+ │ ├── admin.handler.ts # Auth (login/logout/verify)
68
+ │ ├── stats.handler.ts # Statistics + health
69
+ │ ├── config.handler.ts # Configuration (read-only)
70
+ │ ├── logs.handler.ts # Log retrieval
71
+ │ ├── email.handler.ts # Email operations
72
+ │ ├── certificate.handler.ts # Certificate management
73
+ │ ├── radius.handler.ts # RADIUS management
74
+ │ └── remoteingress.handler.ts # Remote ingress edge + token management
75
+ ├── radius/ # RADIUS server integration
76
+ ├── remoteingress/ # Remote ingress hub integration
77
+ │ ├── classes.remoteingress-manager.ts # Edge CRUD + port derivation
78
+ │ └── classes.tunnel-manager.ts # Rust hub lifecycle + status tracking
79
+ ├── security/ # Security utilities
80
+ ├── sms/ # SMS integration
81
+ └── storage/ # StorageManager (filesystem/custom/memory)
82
+ ```
83
+
84
+ ## Exports
85
+
86
+ ```typescript
87
+ // Main class
88
+ export { DcRouter, IDcRouterOptions } from './classes.dcrouter.js';
89
+
90
+ // Re-exported from smartmta
91
+ export { UnifiedEmailServer } from '@push.rocks/smartmta';
92
+ export type { IUnifiedEmailServerOptions, IEmailRoute, IEmailDomainConfig } from '@push.rocks/smartmta';
93
+
94
+ // RADIUS
95
+ export { RadiusServer, IRadiusServerConfig } from './radius/index.js';
96
+
97
+ // Remote Ingress
98
+ export { RemoteIngressManager, TunnelManager } from './remoteingress/index.js';
99
+ ```
100
+
101
+ ## Key Classes
102
+
103
+ ### `DcRouter`
104
+
105
+ The central orchestrator. Accepts `IDcRouterOptions` and manages the lifecycle of all sub-services:
106
+
107
+ | Config Section | Service Started | Package |
108
+ |----------------|----------------|---------|
109
+ | `smartProxyConfig` | SmartProxy (HTTP/HTTPS/TCP/SNI) | `@push.rocks/smartproxy` |
110
+ | `emailConfig` | UnifiedEmailServer (SMTP) | `@push.rocks/smartmta` |
111
+ | `dnsNsDomains` + `dnsScopes` | DnsServer (UDP + DoH) | `@push.rocks/smartdns` |
112
+ | `radiusConfig` | RadiusServer (auth + accounting) | `@push.rocks/smartradius` |
113
+ | `remoteIngressConfig` | RemoteIngressManager + TunnelManager | `@serve.zone/remoteingress` |
114
+ | `tls` + `dnsChallenge` | SmartAcme (ACME cert provisioning) | `@push.rocks/smartacme` |
115
+ | `cacheConfig` | CacheDb (embedded MongoDB) | `@push.rocks/smartdata` |
116
+ | *(always)* | OpsServer (dashboard + API) | `@api.global/typedserver` |
117
+ | *(always)* | MetricsManager | `@push.rocks/smartmetrics` |
118
+
119
+ ### `RemoteIngressManager`
120
+
121
+ Manages CRUD for remote ingress edge registrations. Persists edges via StorageManager. Provides port derivation from routes tagged with `remoteIngress.enabled`.
122
+
123
+ ### `TunnelManager`
124
+
125
+ Manages the Rust-based RemoteIngressHub lifecycle. Syncs allowed edges, tracks connection status, and exposes edge statuses (connected, publicIp, activeTunnels, lastHeartbeat).
126
+
127
+ ## License and Legal Information
128
+
129
+ This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](../LICENSE) file.
130
+
131
+ **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
132
+
133
+ ### Trademarks
134
+
135
+ This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
136
+
137
+ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
138
+
139
+ ### Company Information
140
+
141
+ Task Venture Capital GmbH
142
+ Registered at District Court Bremen HRB 35230 HB, Germany
143
+
144
+ For any legal inquiries or further information, please contact us via email at hello@task.vc.
145
+
146
+ By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
@@ -242,11 +242,15 @@ export class RemoteIngressManager {
242
242
  /**
243
243
  * Get the list of allowed edges (enabled only) for the Rust hub.
244
244
  */
245
- public getAllowedEdges(): Array<{ id: string; secret: string }> {
246
- const result: Array<{ id: string; secret: string }> = [];
245
+ public getAllowedEdges(): Array<{ id: string; secret: string; listenPorts: number[] }> {
246
+ const result: Array<{ id: string; secret: string; listenPorts: number[] }> = [];
247
247
  for (const edge of this.edges.values()) {
248
248
  if (edge.enabled) {
249
- result.push({ id: edge.id, secret: edge.secret });
249
+ result.push({
250
+ id: edge.id,
251
+ secret: edge.secret,
252
+ listenPorts: this.getEffectiveListenPorts(edge),
253
+ });
250
254
  }
251
255
  }
252
256
  return result;
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '6.11.0',
6
+ version: '6.13.0',
7
7
  description: 'A multifaceted routing service handling mail and SMS delivery functions.'
8
8
  }
@@ -200,7 +200,7 @@ export interface IRemoteIngressState {
200
200
  edges: interfaces.data.IRemoteIngress[];
201
201
  statuses: interfaces.data.IRemoteIngressStatus[];
202
202
  selectedEdgeId: string | null;
203
- newEdgeSecret: string | null;
203
+ newEdgeId: string | null;
204
204
  isLoading: boolean;
205
205
  error: string | null;
206
206
  lastUpdated: number;
@@ -212,7 +212,7 @@ export const remoteIngressStatePart = await appState.getStatePart<IRemoteIngress
212
212
  edges: [],
213
213
  statuses: [],
214
214
  selectedEdgeId: null,
215
- newEdgeSecret: null,
215
+ newEdgeId: null,
216
216
  isLoading: false,
217
217
  error: null,
218
218
  lastUpdated: 0,
@@ -928,11 +928,12 @@ export const createRemoteIngressAction = remoteIngressStatePart.createAction<{
928
928
  });
929
929
 
930
930
  if (response.success) {
931
- // Refresh the list and store the new secret for display
931
+ // Refresh the list
932
932
  await remoteIngressStatePart.dispatchAction(fetchRemoteIngressAction, null);
933
+
933
934
  return {
934
935
  ...statePartArg.getState(),
935
- newEdgeSecret: response.edge.secret,
936
+ newEdgeId: response.edge.id,
936
937
  };
937
938
  }
938
939
 
@@ -1023,7 +1024,7 @@ export const regenerateRemoteIngressSecretAction = remoteIngressStatePart.create
1023
1024
  if (response.success) {
1024
1025
  return {
1025
1026
  ...currentState,
1026
- newEdgeSecret: response.secret,
1027
+ newEdgeId: edgeId,
1027
1028
  };
1028
1029
  }
1029
1030
 
@@ -1037,11 +1038,11 @@ export const regenerateRemoteIngressSecretAction = remoteIngressStatePart.create
1037
1038
  }
1038
1039
  );
1039
1040
 
1040
- export const clearNewEdgeSecretAction = remoteIngressStatePart.createAction(
1041
+ export const clearNewEdgeIdAction = remoteIngressStatePart.createAction(
1041
1042
  async (statePartArg) => {
1042
1043
  return {
1043
1044
  ...statePartArg.getState(),
1044
- newEdgeSecret: null,
1045
+ newEdgeId: null,
1045
1046
  };
1046
1047
  }
1047
1048
  );
@@ -382,7 +382,7 @@ export class OpsViewCertificates extends DeesElement {
382
382
  },
383
383
  {
384
384
  name: 'View Details',
385
- iconName: 'lucide:Search',
385
+ iconName: 'fa:magnifyingGlass',
386
386
  type: ['doubleClick', 'contextmenu'],
387
387
  actionFunc: async (actionData: { item: interfaces.requests.ICertificateInfo }) => {
388
388
  const cert = actionData.item;
@@ -287,7 +287,7 @@ export class OpsViewNetwork extends DeesElement {
287
287
  .dataActions=${[
288
288
  {
289
289
  name: 'View Details',
290
- iconName: 'lucide:Search',
290
+ iconName: 'fa:magnifyingGlass',
291
291
  type: ['inRow', 'doubleClick', 'contextmenu'],
292
292
  actionFunc: async (actionData) => {
293
293
  await this.showRequestDetails(actionData.item);
@@ -435,7 +435,7 @@ export class OpsViewNetwork extends DeesElement {
435
435
  actions: [
436
436
  {
437
437
  name: 'View Details',
438
- iconName: 'lucide:Search',
438
+ iconName: 'fa:magnifyingGlass',
439
439
  action: async () => {
440
440
  },
441
441
  },
@@ -176,13 +176,39 @@ export class OpsViewRemoteIngress extends DeesElement {
176
176
  return html`
177
177
  <ops-sectionheading>Remote Ingress</ops-sectionheading>
178
178
 
179
- ${this.riState.newEdgeSecret ? html`
179
+ ${this.riState.newEdgeId ? html`
180
180
  <div class="secretDialog">
181
- <strong>Edge Secret (copy now - shown only once):</strong>
182
- <code>${this.riState.newEdgeSecret}</code>
183
- <div class="warning">This secret will not be shown again. Save it securely.</div>
181
+ <strong>Edge created successfully!</strong>
182
+ <div class="warning">Copy the connection token now. Use it with edge.start({ token: '...' }).</div>
184
183
  <dees-button
185
- @click=${() => appstate.remoteIngressStatePart.dispatchAction(appstate.clearNewEdgeSecretAction, null)}
184
+ @click=${async () => {
185
+ const { DeesToast } = await import('@design.estate/dees-catalog');
186
+ try {
187
+ const response = await appstate.fetchConnectionToken(this.riState.newEdgeId);
188
+ if (response.success && response.token) {
189
+ if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
190
+ await navigator.clipboard.writeText(response.token);
191
+ } else {
192
+ const textarea = document.createElement('textarea');
193
+ textarea.value = response.token;
194
+ textarea.style.position = 'fixed';
195
+ textarea.style.opacity = '0';
196
+ document.body.appendChild(textarea);
197
+ textarea.select();
198
+ document.execCommand('copy');
199
+ document.body.removeChild(textarea);
200
+ }
201
+ DeesToast.show({ message: 'Connection token copied!', type: 'success', duration: 3000 });
202
+ } else {
203
+ DeesToast.show({ message: response.message || 'Failed to get token', type: 'error', duration: 4000 });
204
+ }
205
+ } catch (err) {
206
+ DeesToast.show({ message: `Failed: ${err.message}`, type: 'error', duration: 4000 });
207
+ }
208
+ }}
209
+ >Copy Connection Token</dees-button>
210
+ <dees-button
211
+ @click=${() => appstate.remoteIngressStatePart.dispatchAction(appstate.clearNewEdgeIdAction, null)}
186
212
  >Dismiss</dees-button>
187
213
  </div>
188
214
  ` : ''}
@@ -348,7 +374,7 @@ export class OpsViewRemoteIngress extends DeesElement {
348
374
  },
349
375
  {
350
376
  name: 'Copy Token',
351
- iconName: 'lucide:clipboard-copy',
377
+ iconName: 'lucide:ClipboardCopy',
352
378
  type: ['inRow', 'contextmenu'] as any,
353
379
  actionFunc: async (actionData: any) => {
354
380
  const edge = actionData.item as interfaces.data.IRemoteIngress;
@@ -356,7 +382,19 @@ export class OpsViewRemoteIngress extends DeesElement {
356
382
  try {
357
383
  const response = await appstate.fetchConnectionToken(edge.id);
358
384
  if (response.success && response.token) {
359
- await navigator.clipboard.writeText(response.token);
385
+ // Use clipboard API with fallback for non-HTTPS contexts
386
+ if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
387
+ await navigator.clipboard.writeText(response.token);
388
+ } else {
389
+ const textarea = document.createElement('textarea');
390
+ textarea.value = response.token;
391
+ textarea.style.position = 'fixed';
392
+ textarea.style.opacity = '0';
393
+ document.body.appendChild(textarea);
394
+ textarea.select();
395
+ document.execCommand('copy');
396
+ document.body.removeChild(textarea);
397
+ }
360
398
  DeesToast.show({ message: `Connection token copied for ${edge.name}`, type: 'success', duration: 3000 });
361
399
  } else {
362
400
  DeesToast.show({ message: response.message || 'Failed to get token', type: 'error', duration: 4000 });
package/ts_web/readme.md CHANGED
@@ -40,6 +40,15 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
40
40
  - Expiry date monitoring and alerts
41
41
  - Per-domain backoff status for failed provisions
42
42
  - One-click reprovisioning per domain
43
+ - Certificate import, export, and deletion
44
+
45
+ ### 🌍 Remote Ingress Management
46
+ - Edge node registration with name, ports, and tags
47
+ - Real-time connection status (connected/disconnected/disabled)
48
+ - Public IP and active tunnel count per edge
49
+ - Auto-derived port display with manual/derived breakdown
50
+ - **Connection token generation** — one-click "Copy Token" for easy edge provisioning
51
+ - Enable/disable, edit, secret regeneration, and delete actions
43
52
 
44
53
  ### 📜 Log Viewer
45
54
  - Real-time log streaming
@@ -85,6 +94,7 @@ ts_web/
85
94
  ├── ops-view-network.ts # Network monitoring
86
95
  ├── ops-view-emails.ts # Email queue management
87
96
  ├── ops-view-certificates.ts # Certificate overview & reprovisioning
97
+ ├── ops-view-remoteingress.ts # Remote ingress edge management
88
98
  ├── ops-view-logs.ts # Log viewer
89
99
  ├── ops-view-config.ts # Configuration display
90
100
  ├── ops-view-security.ts # Security dashboard
@@ -106,6 +116,8 @@ The app uses `@push.rocks/smartstate` with multiple state parts:
106
116
  | `logStatePart` | Soft | Recent logs, streaming status, filters |
107
117
  | `networkStatePart` | Soft | Connections, IPs, throughput rates |
108
118
  | `emailOpsStatePart` | Soft | Email queues, bounces, suppression list |
119
+ | `certificateStatePart` | Soft | Certificate list, summary, loading state |
120
+ | `remoteIngressStatePart` | Soft | Edge list, statuses, new edge secret |
109
121
 
110
122
  ### Actions
111
123
 
@@ -128,6 +140,23 @@ fetchSecurityIncidentsAction() // Security events
128
140
  fetchBounceRecordsAction() // Bounce records
129
141
  resendEmailAction(emailId) // Re-queue failed email
130
142
  removeFromSuppressionAction(email) // Remove from suppression list
143
+
144
+ // Certificates
145
+ fetchCertificateOverviewAction() // All certificates with summary
146
+ reprovisionCertificateAction(domain) // Reprovision a certificate
147
+ deleteCertificateAction(domain) // Delete a certificate
148
+ importCertificateAction(cert) // Import a certificate
149
+ fetchCertificateExport(domain) // Export (standalone function)
150
+
151
+ // Remote Ingress
152
+ fetchRemoteIngressAction() // Edges + statuses
153
+ createRemoteIngressAction(data) // Create new edge
154
+ updateRemoteIngressAction(data) // Update edge settings
155
+ deleteRemoteIngressAction(id) // Remove edge
156
+ regenerateRemoteIngressSecretAction(id) // New secret
157
+ toggleRemoteIngressAction(id, enabled) // Enable/disable
158
+ clearNewEdgeSecretAction() // Dismiss secret banner
159
+ fetchConnectionToken(edgeId) // Get connection token (standalone function)
131
160
  ```
132
161
 
133
162
  ### Client-Side Routing
@@ -141,6 +170,7 @@ removeFromSuppressionAction(email) // Remove from suppression list
141
170
  /emails/failed → Failed emails
142
171
  /emails/security → Security incidents
143
172
  /certificates → Certificate management
173
+ /remoteingress → Remote ingress edge management
144
174
  /logs → Log viewer
145
175
  /configuration → System configuration
146
176
  /security → Security dashboard