@serve.zone/dcrouter 13.42.4 → 13.43.1
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/deno.json +1 -1
- package/dist_serve/bundle.js +722 -678
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.js +3 -3
- package/dist_ts/config/classes.route-config-manager.d.ts +4 -2
- package/dist_ts/config/classes.route-config-manager.js +17 -9
- package/dist_ts/config/helpers.http-redirects.d.ts +10 -0
- package/dist_ts/config/helpers.http-redirects.js +387 -0
- package/dist_ts/config/index.d.ts +1 -0
- package/dist_ts/config/index.js +2 -1
- package/dist_ts/opsserver/handlers/route-management.handler.js +10 -1
- package/dist_ts_interfaces/data/route-management.d.ts +20 -0
- package/dist_ts_interfaces/requests/route-management.d.ts +14 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +2 -0
- package/dist_ts_web/appstate.js +28 -1
- package/dist_ts_web/elements/access/ops-view-apitokens.js +2 -1
- package/dist_ts_web/elements/access/ops-view-gatewayclients.js +2 -1
- package/dist_ts_web/elements/network/index.d.ts +1 -0
- package/dist_ts_web/elements/network/index.js +2 -1
- package/dist_ts_web/elements/network/ops-view-redirects.d.ts +18 -0
- package/dist_ts_web/elements/network/ops-view-redirects.js +236 -0
- package/dist_ts_web/elements/network/ops-view-routes.js +2 -1
- package/dist_ts_web/elements/ops-dashboard.js +3 -1
- package/dist_ts_web/router.js +2 -2
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +2 -2
- package/ts/config/classes.route-config-manager.ts +22 -10
- package/ts/config/helpers.http-redirects.ts +462 -0
- package/ts/config/index.ts +1 -0
- package/ts/opsserver/handlers/route-management.handler.ts +15 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +32 -0
- package/ts_web/elements/access/ops-view-apitokens.ts +1 -0
- package/ts_web/elements/access/ops-view-gatewayclients.ts +1 -0
- package/ts_web/elements/network/index.ts +1 -0
- package/ts_web/elements/network/ops-view-redirects.ts +202 -0
- package/ts_web/elements/network/ops-view-routes.ts +1 -0
- package/ts_web/elements/ops-dashboard.ts +2 -0
- package/ts_web/router.ts +1 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DeesElement,
|
|
3
|
+
html,
|
|
4
|
+
customElement,
|
|
5
|
+
type TemplateResult,
|
|
6
|
+
css,
|
|
7
|
+
state,
|
|
8
|
+
cssManager,
|
|
9
|
+
} from '@design.estate/dees-element';
|
|
10
|
+
import { type IStatsTile } from '@design.estate/dees-catalog';
|
|
11
|
+
import * as appstate from '../../appstate.js';
|
|
12
|
+
import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
13
|
+
import { viewHostCss } from '../shared/css.js';
|
|
14
|
+
|
|
15
|
+
declare global {
|
|
16
|
+
interface HTMLElementTagNameMap {
|
|
17
|
+
'ops-view-redirects': OpsViewRedirects;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@customElement('ops-view-redirects')
|
|
22
|
+
export class OpsViewRedirects extends DeesElement {
|
|
23
|
+
@state()
|
|
24
|
+
accessor routeState: appstate.IRouteManagementState = appstate.routeManagementStatePart.getState()!;
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
super();
|
|
28
|
+
const routeSub = appstate.routeManagementStatePart.select().subscribe((routeState) => {
|
|
29
|
+
this.routeState = routeState;
|
|
30
|
+
});
|
|
31
|
+
this.rxSubscriptions.push(routeSub);
|
|
32
|
+
|
|
33
|
+
const loginSub = appstate.loginStatePart
|
|
34
|
+
.select((state) => state.isLoggedIn)
|
|
35
|
+
.subscribe((isLoggedIn) => {
|
|
36
|
+
if (isLoggedIn) {
|
|
37
|
+
void this.refreshData();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
this.rxSubscriptions.push(loginSub);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async connectedCallback() {
|
|
44
|
+
await super.connectedCallback();
|
|
45
|
+
await this.refreshData();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public static styles = [
|
|
49
|
+
cssManager.defaultStyles,
|
|
50
|
+
viewHostCss,
|
|
51
|
+
css`
|
|
52
|
+
.redirectsContainer {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
gap: 24px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.empty-state {
|
|
59
|
+
text-align: center;
|
|
60
|
+
padding: 48px 24px;
|
|
61
|
+
color: ${cssManager.bdTheme('#6b7280', '#9ca3af')};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.empty-state p {
|
|
65
|
+
margin: 8px 0;
|
|
66
|
+
}
|
|
67
|
+
`,
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
public render(): TemplateResult {
|
|
71
|
+
const redirects = this.routeState.httpRedirects || [];
|
|
72
|
+
const activeCount = redirects.filter((redirect) => redirect.status === 'active').length;
|
|
73
|
+
const coveredCount = redirects.filter((redirect) => redirect.status === 'covered').length;
|
|
74
|
+
const skippedCount = redirects.filter((redirect) => redirect.status === 'skipped').length;
|
|
75
|
+
const remoteIngressCount = redirects.filter((redirect) => redirect.remoteIngress).length;
|
|
76
|
+
|
|
77
|
+
const statsTiles: IStatsTile[] = [
|
|
78
|
+
{
|
|
79
|
+
id: 'totalRedirects',
|
|
80
|
+
title: 'Total Redirects',
|
|
81
|
+
type: 'number',
|
|
82
|
+
value: redirects.length,
|
|
83
|
+
icon: 'lucide:CornerDownRight',
|
|
84
|
+
description: 'Derived HTTP to HTTPS scopes',
|
|
85
|
+
color: '#3b82f6',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: 'activeRedirects',
|
|
89
|
+
title: 'Active',
|
|
90
|
+
type: 'number',
|
|
91
|
+
value: activeCount,
|
|
92
|
+
icon: 'lucide:CircleCheck',
|
|
93
|
+
description: 'Generated at runtime',
|
|
94
|
+
color: '#22c55e',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: 'coveredRedirects',
|
|
98
|
+
title: 'Covered',
|
|
99
|
+
type: 'number',
|
|
100
|
+
value: coveredCount,
|
|
101
|
+
icon: 'lucide:ShieldCheck',
|
|
102
|
+
description: 'Handled by explicit HTTP routes',
|
|
103
|
+
color: '#8b5cf6',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: 'skippedRedirects',
|
|
107
|
+
title: 'Skipped',
|
|
108
|
+
type: 'number',
|
|
109
|
+
value: skippedCount,
|
|
110
|
+
icon: 'lucide:AlertTriangle',
|
|
111
|
+
description: 'Overlaps explicit HTTP routes',
|
|
112
|
+
color: skippedCount > 0 ? '#f59e0b' : '#6b7280',
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'remoteIngressRedirects',
|
|
116
|
+
title: 'Remote Ingress',
|
|
117
|
+
type: 'number',
|
|
118
|
+
value: remoteIngressCount,
|
|
119
|
+
icon: 'lucide:Globe',
|
|
120
|
+
description: 'Also exposed to edge nodes',
|
|
121
|
+
color: '#0ea5e9',
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
|
|
125
|
+
return html`
|
|
126
|
+
<dees-heading level="3">Redirects</dees-heading>
|
|
127
|
+
<div class="redirectsContainer">
|
|
128
|
+
<dees-statsgrid .tiles=${statsTiles}></dees-statsgrid>
|
|
129
|
+
|
|
130
|
+
${redirects.length > 0
|
|
131
|
+
? html`
|
|
132
|
+
<dees-table
|
|
133
|
+
.heading1=${'HTTP to HTTPS Redirects'}
|
|
134
|
+
.heading2=${'Runtime redirects derived from enabled HTTPS routes'}
|
|
135
|
+
.data=${redirects}
|
|
136
|
+
.showColumnFilters=${true}
|
|
137
|
+
.displayFunction=${(redirect: interfaces.data.IHttpRedirectInfo) => ({
|
|
138
|
+
Status: this.formatStatus(redirect.status),
|
|
139
|
+
'Domain Pattern': redirect.domainPattern,
|
|
140
|
+
Path: redirect.pathPattern || '*',
|
|
141
|
+
From: this.formatHttpTemplate(redirect, 'http'),
|
|
142
|
+
To: this.formatHttpTemplate(redirect, 'https'),
|
|
143
|
+
Code: redirect.statusCode,
|
|
144
|
+
Priority: redirect.priority,
|
|
145
|
+
'Source HTTPS Route': redirect.sourceRouteNames.join(', ') || '-',
|
|
146
|
+
'Covered By': redirect.coveredByRouteNames.join(', ') || '-',
|
|
147
|
+
Notes: this.formatNotes(redirect),
|
|
148
|
+
})}
|
|
149
|
+
.dataActions=${[
|
|
150
|
+
{
|
|
151
|
+
name: 'Refresh',
|
|
152
|
+
iconName: 'lucide:RefreshCw',
|
|
153
|
+
type: ['header' as const],
|
|
154
|
+
actionFunc: async () => this.refreshData(),
|
|
155
|
+
},
|
|
156
|
+
]}
|
|
157
|
+
></dees-table>
|
|
158
|
+
`
|
|
159
|
+
: html`
|
|
160
|
+
<dees-table
|
|
161
|
+
.heading1=${'HTTP to HTTPS Redirects'}
|
|
162
|
+
.heading2=${'Runtime redirects derived from enabled HTTPS routes'}
|
|
163
|
+
.data=${[]}
|
|
164
|
+
.displayFunction=${() => ({})}
|
|
165
|
+
.dataActions=${[
|
|
166
|
+
{
|
|
167
|
+
name: 'Refresh',
|
|
168
|
+
iconName: 'lucide:RefreshCw',
|
|
169
|
+
type: ['header' as const],
|
|
170
|
+
actionFunc: async () => this.refreshData(),
|
|
171
|
+
},
|
|
172
|
+
]}
|
|
173
|
+
></dees-table>
|
|
174
|
+
<div class="empty-state">
|
|
175
|
+
<p>No derived redirects</p>
|
|
176
|
+
<p>Enable HTTPS routes with explicit domains to generate HTTP to HTTPS redirects.</p>
|
|
177
|
+
</div>
|
|
178
|
+
`}
|
|
179
|
+
</div>
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private async refreshData(): Promise<void> {
|
|
184
|
+
await appstate.routeManagementStatePart.dispatchAction(appstate.fetchHttpRedirectsAction, null);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
private formatStatus(status: interfaces.data.THttpRedirectStatus): string {
|
|
188
|
+
return status.charAt(0).toUpperCase() + status.slice(1);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private formatHttpTemplate(redirect: interfaces.data.IHttpRedirectInfo, protocol: 'http' | 'https'): string {
|
|
192
|
+
return `${protocol}://${redirect.domainPattern}${redirect.pathPattern || '{path}'}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private formatNotes(redirect: interfaces.data.IHttpRedirectInfo): string {
|
|
196
|
+
const notes = redirect.notes ? [redirect.notes] : [];
|
|
197
|
+
if (redirect.remoteIngress) {
|
|
198
|
+
notes.push('Remote Ingress enabled');
|
|
199
|
+
}
|
|
200
|
+
return notes.join(' ') || 'Generated from HTTPS route';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
@@ -23,6 +23,7 @@ import { OpsViewConfig } from './overview/ops-view-config.js';
|
|
|
23
23
|
// Network group
|
|
24
24
|
import { OpsViewNetworkActivity } from './network/ops-view-network-activity.js';
|
|
25
25
|
import { OpsViewRoutes } from './network/ops-view-routes.js';
|
|
26
|
+
import { OpsViewRedirects } from './network/ops-view-redirects.js';
|
|
26
27
|
import { OpsViewSourceProfiles } from './network/ops-view-sourceprofiles.js';
|
|
27
28
|
import { OpsViewNetworkTargets } from './network/ops-view-networktargets.js';
|
|
28
29
|
import { OpsViewTargetProfiles } from './network/ops-view-targetprofiles.js';
|
|
@@ -100,6 +101,7 @@ export class OpsDashboard extends DeesElement {
|
|
|
100
101
|
subViews: [
|
|
101
102
|
{ slug: 'activity', name: 'Network Activity', iconName: 'lucide:activity', element: OpsViewNetworkActivity },
|
|
102
103
|
{ slug: 'routes', name: 'Routes', iconName: 'lucide:route', element: OpsViewRoutes },
|
|
104
|
+
{ slug: 'redirects', name: 'Redirects', iconName: 'lucide:CornerDownRight', element: OpsViewRedirects },
|
|
103
105
|
{ slug: 'sourceprofiles', name: 'Source Profiles', iconName: 'lucide:shieldCheck', element: OpsViewSourceProfiles },
|
|
104
106
|
{ slug: 'networktargets', name: 'Network Targets', iconName: 'lucide:server', element: OpsViewNetworkTargets },
|
|
105
107
|
{ slug: 'targetprofiles', name: 'Target Profiles', iconName: 'lucide:target', element: OpsViewTargetProfiles },
|
package/ts_web/router.ts
CHANGED
|
@@ -9,7 +9,7 @@ const flatViews = ['logs'] as const;
|
|
|
9
9
|
// Tabbed views and their valid subviews
|
|
10
10
|
const subviewMap: Record<string, readonly string[]> = {
|
|
11
11
|
overview: ['stats', 'configuration'] as const,
|
|
12
|
-
network: ['activity', 'routes', 'sourceprofiles', 'networktargets', 'targetprofiles', 'remoteingress', 'vpn'] as const,
|
|
12
|
+
network: ['activity', 'routes', 'redirects', 'sourceprofiles', 'networktargets', 'targetprofiles', 'remoteingress', 'vpn'] as const,
|
|
13
13
|
email: ['log', 'security', 'domains'] as const,
|
|
14
14
|
access: ['gatewayclients', 'apitokens', 'users'] as const,
|
|
15
15
|
security: ['overview', 'blocked', 'authentication'] as const,
|