@serve.zone/dcrouter 6.11.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/dist_serve/bundle.js +311 -309
- package/dist_ts/00_commitinfo_data.js +1 -1
- 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/readme.md +146 -0
- 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_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
|