@serve.zone/dcrouter 6.10.0 → 6.12.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.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/dcrouter',
6
- version: '6.10.0',
6
+ version: '6.12.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,
@@ -854,6 +854,18 @@ export async function fetchCertificateExport(domain: string) {
854
854
  });
855
855
  }
856
856
 
857
+ // ============================================================================
858
+ // Remote Ingress Standalone Functions
859
+ // ============================================================================
860
+
861
+ export async function fetchConnectionToken(edgeId: string) {
862
+ const context = getActionContext();
863
+ const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
864
+ interfaces.requests.IReq_GetRemoteIngressConnectionToken
865
+ >('/typedrequest', 'getRemoteIngressConnectionToken');
866
+ return request.fire({ identity: context.identity, edgeId });
867
+ }
868
+
857
869
  // ============================================================================
858
870
  // Remote Ingress Actions
859
871
  // ============================================================================
@@ -916,11 +928,12 @@ export const createRemoteIngressAction = remoteIngressStatePart.createAction<{
916
928
  });
917
929
 
918
930
  if (response.success) {
919
- // Refresh the list and store the new secret for display
931
+ // Refresh the list
920
932
  await remoteIngressStatePart.dispatchAction(fetchRemoteIngressAction, null);
933
+
921
934
  return {
922
935
  ...statePartArg.getState(),
923
- newEdgeSecret: response.edge.secret,
936
+ newEdgeId: response.edge.id,
924
937
  };
925
938
  }
926
939
 
@@ -1011,7 +1024,7 @@ export const regenerateRemoteIngressSecretAction = remoteIngressStatePart.create
1011
1024
  if (response.success) {
1012
1025
  return {
1013
1026
  ...currentState,
1014
- newEdgeSecret: response.secret,
1027
+ newEdgeId: edgeId,
1015
1028
  };
1016
1029
  }
1017
1030
 
@@ -1025,11 +1038,11 @@ export const regenerateRemoteIngressSecretAction = remoteIngressStatePart.create
1025
1038
  }
1026
1039
  );
1027
1040
 
1028
- export const clearNewEdgeSecretAction = remoteIngressStatePart.createAction(
1041
+ export const clearNewEdgeIdAction = remoteIngressStatePart.createAction(
1029
1042
  async (statePartArg) => {
1030
1043
  return {
1031
1044
  ...statePartArg.getState(),
1032
- newEdgeSecret: null,
1045
+ newEdgeId: null,
1033
1046
  };
1034
1047
  }
1035
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
  ` : ''}
@@ -346,6 +372,38 @@ export class OpsViewRemoteIngress extends DeesElement {
346
372
  );
347
373
  },
348
374
  },
375
+ {
376
+ name: 'Copy Token',
377
+ iconName: 'lucide:ClipboardCopy',
378
+ type: ['inRow', 'contextmenu'] as any,
379
+ actionFunc: async (actionData: any) => {
380
+ const edge = actionData.item as interfaces.data.IRemoteIngress;
381
+ const { DeesToast } = await import('@design.estate/dees-catalog');
382
+ try {
383
+ const response = await appstate.fetchConnectionToken(edge.id);
384
+ if (response.success && 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
+ }
398
+ DeesToast.show({ message: `Connection token copied for ${edge.name}`, type: 'success', duration: 3000 });
399
+ } else {
400
+ DeesToast.show({ message: response.message || 'Failed to get token', type: 'error', duration: 4000 });
401
+ }
402
+ } catch (err) {
403
+ DeesToast.show({ message: `Failed: ${err.message}`, type: 'error', duration: 4000 });
404
+ }
405
+ },
406
+ },
349
407
  {
350
408
  name: 'Delete',
351
409
  iconName: 'lucide:trash2',
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