@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/dist_serve/bundle.js +311 -309
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/opsserver/handlers/remoteingress.handler.js +3 -3
- package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +1 -0
- package/dist_ts/remoteingress/classes.remoteingress-manager.js +6 -2
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +2 -2
- package/dist_ts_web/appstate.js +7 -7
- package/dist_ts_web/elements/ops-view-certificates.js +2 -2
- package/dist_ts_web/elements/ops-view-network.js +3 -3
- package/dist_ts_web/elements/ops-view-remoteingress.js +50 -8
- package/package.json +2 -2
- package/readme.md +165 -8
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/opsserver/handlers/remoteingress.handler.ts +2 -2
- package/ts/readme.md +146 -0
- package/ts/remoteingress/classes.remoteingress-manager.ts +7 -3
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +8 -7
- package/ts_web/elements/ops-view-certificates.ts +1 -1
- package/ts_web/elements/ops-view-network.ts +2 -2
- package/ts_web/elements/ops-view-remoteingress.ts +45 -7
- package/ts_web/readme.md +30 -0
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({
|
|
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;
|
package/ts_web/appstate.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
931
|
+
// Refresh the list
|
|
932
932
|
await remoteIngressStatePart.dispatchAction(fetchRemoteIngressAction, null);
|
|
933
|
+
|
|
933
934
|
return {
|
|
934
935
|
...statePartArg.getState(),
|
|
935
|
-
|
|
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
|
-
|
|
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
|
|
1041
|
+
export const clearNewEdgeIdAction = remoteIngressStatePart.createAction(
|
|
1041
1042
|
async (statePartArg) => {
|
|
1042
1043
|
return {
|
|
1043
1044
|
...statePartArg.getState(),
|
|
1044
|
-
|
|
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: '
|
|
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: '
|
|
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: '
|
|
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.
|
|
179
|
+
${this.riState.newEdgeId ? html`
|
|
180
180
|
<div class="secretDialog">
|
|
181
|
-
<strong>Edge
|
|
182
|
-
<
|
|
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=${() =>
|
|
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:
|
|
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
|
-
|
|
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
|