@serve.zone/dcrouter 13.15.0 → 13.16.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 +510 -517
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.dcrouter.d.ts +3 -6
- package/dist_ts/classes.dcrouter.js +39 -53
- package/dist_ts/config/classes.reference-resolver.d.ts +8 -8
- package/dist_ts/config/classes.reference-resolver.js +6 -6
- package/dist_ts/config/classes.route-config-manager.d.ts +13 -13
- package/dist_ts/config/classes.route-config-manager.js +117 -144
- package/dist_ts/config/classes.target-profile-manager.d.ts +2 -2
- package/dist_ts/config/classes.target-profile-manager.js +7 -18
- package/dist_ts/db/documents/{classes.stored-route.doc.d.ts → classes.route.doc.d.ts} +6 -3
- package/dist_ts/db/documents/{classes.stored-route.doc.js → classes.route.doc.js} +21 -9
- package/dist_ts/db/documents/index.d.ts +1 -2
- package/dist_ts/db/documents/index.js +2 -3
- package/dist_ts/monitoring/classes.metricsmanager.js +86 -8
- package/dist_ts/opsserver/handlers/network-target.handler.js +3 -3
- package/dist_ts/opsserver/handlers/route-management.handler.js +3 -23
- package/dist_ts/opsserver/handlers/source-profile.handler.js +3 -3
- package/dist_ts_apiclient/classes.route.d.ts +2 -5
- package/dist_ts_apiclient/classes.route.js +13 -42
- package/dist_ts_interfaces/data/route-management.d.ts +8 -17
- package/dist_ts_interfaces/requests/route-management.d.ts +6 -37
- package/dist_ts_migrations/index.js +23 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate.d.ts +0 -5
- package/dist_ts_web/appstate.js +1 -38
- package/dist_ts_web/elements/network/ops-view-routes.js +60 -110
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.dcrouter.ts +45 -55
- package/ts/config/classes.reference-resolver.ts +13 -13
- package/ts/config/classes.route-config-manager.ts +128 -146
- package/ts/config/classes.target-profile-manager.ts +7 -20
- package/ts/db/documents/{classes.stored-route.doc.ts → classes.route.doc.ts} +16 -5
- package/ts/db/documents/index.ts +1 -2
- package/ts/monitoring/classes.metricsmanager.ts +80 -7
- package/ts/opsserver/handlers/network-target.handler.ts +2 -2
- package/ts/opsserver/handlers/route-management.handler.ts +2 -34
- package/ts/opsserver/handlers/source-profile.handler.ts +2 -2
- package/ts_apiclient/classes.route.ts +12 -49
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate.ts +0 -52
- package/ts_web/elements/network/ops-view-routes.ts +65 -123
- package/dist_ts/db/documents/classes.route-override.doc.d.ts +0 -10
- package/dist_ts/db/documents/classes.route-override.doc.js +0 -91
- package/ts/db/documents/classes.route-override.doc.ts +0 -32
|
@@ -724,8 +724,8 @@ export class MetricsManager {
|
|
|
724
724
|
const connectionsByRoute = proxyMetrics.connections.byRoute();
|
|
725
725
|
const throughputByRoute = proxyMetrics.throughput.byRoute();
|
|
726
726
|
|
|
727
|
-
// Map route name →
|
|
728
|
-
const
|
|
727
|
+
// Map route name → ALL its domains (not just the first one)
|
|
728
|
+
const routeDomains = new Map<string, string[]>();
|
|
729
729
|
if (this.dcRouter.smartProxy) {
|
|
730
730
|
for (const route of this.dcRouter.smartProxy.routeManager.getRoutes()) {
|
|
731
731
|
if (!route.name || !route.match.domains) continue;
|
|
@@ -733,29 +733,101 @@ export class MetricsManager {
|
|
|
733
733
|
? route.match.domains
|
|
734
734
|
: [route.match.domains];
|
|
735
735
|
if (domains.length > 0) {
|
|
736
|
-
|
|
736
|
+
routeDomains.set(route.name, domains);
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
739
|
}
|
|
740
740
|
|
|
741
|
-
//
|
|
741
|
+
// Use protocol cache to discover actual active domains (resolves wildcards)
|
|
742
|
+
const activeDomains = new Set<string>();
|
|
743
|
+
const domainToBackend = new Map<string, string>(); // domain → host:port
|
|
744
|
+
for (const entry of protocolCache) {
|
|
745
|
+
if (entry.domain) {
|
|
746
|
+
activeDomains.add(entry.domain);
|
|
747
|
+
domainToBackend.set(entry.domain, `${entry.host}:${entry.port}`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Build reverse map: domain → route name(s) that handle it
|
|
752
|
+
// For concrete domains: direct lookup from route config
|
|
753
|
+
// For wildcard patterns: match active domains from protocol cache
|
|
754
|
+
const domainToRoutes = new Map<string, string[]>();
|
|
755
|
+
for (const [routeName, domains] of routeDomains) {
|
|
756
|
+
for (const pattern of domains) {
|
|
757
|
+
if (pattern.includes('*')) {
|
|
758
|
+
// Wildcard pattern — match against active domains from protocol cache
|
|
759
|
+
const regex = new RegExp('^' + pattern.replace(/\./g, '\\.').replace(/\*/g, '[^.]+') + '$');
|
|
760
|
+
for (const activeDomain of activeDomains) {
|
|
761
|
+
if (regex.test(activeDomain)) {
|
|
762
|
+
const existing = domainToRoutes.get(activeDomain);
|
|
763
|
+
if (existing) { existing.push(routeName); }
|
|
764
|
+
else { domainToRoutes.set(activeDomain, [routeName]); }
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
} else {
|
|
768
|
+
// Concrete domain
|
|
769
|
+
const existing = domainToRoutes.get(pattern);
|
|
770
|
+
if (existing) { existing.push(routeName); }
|
|
771
|
+
else { domainToRoutes.set(pattern, [routeName]); }
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// Aggregate metrics per domain
|
|
777
|
+
// For each domain, sum metrics from all routes that serve it,
|
|
778
|
+
// divided by the number of domains each route serves
|
|
742
779
|
const domainAgg = new Map<string, {
|
|
743
780
|
activeConnections: number;
|
|
744
781
|
bytesInPerSec: number;
|
|
745
782
|
bytesOutPerSec: number;
|
|
746
783
|
routeCount: number;
|
|
747
784
|
}>();
|
|
785
|
+
|
|
786
|
+
// Track which routes are accounted for
|
|
787
|
+
const accountedRoutes = new Set<string>();
|
|
788
|
+
|
|
789
|
+
for (const [domain, routeNames] of domainToRoutes) {
|
|
790
|
+
let totalConns = 0;
|
|
791
|
+
let totalIn = 0;
|
|
792
|
+
let totalOut = 0;
|
|
793
|
+
|
|
794
|
+
for (const routeName of routeNames) {
|
|
795
|
+
accountedRoutes.add(routeName);
|
|
796
|
+
const conns = connectionsByRoute.get(routeName) || 0;
|
|
797
|
+
const tp = throughputByRoute.get(routeName) || { in: 0, out: 0 };
|
|
798
|
+
// Count how many resolved domains share this route
|
|
799
|
+
let domainsInRoute = 0;
|
|
800
|
+
for (const [, routes] of domainToRoutes) {
|
|
801
|
+
if (routes.includes(routeName)) domainsInRoute++;
|
|
802
|
+
}
|
|
803
|
+
const share = Math.max(domainsInRoute, 1);
|
|
804
|
+
totalConns += conns / share;
|
|
805
|
+
totalIn += tp.in / share;
|
|
806
|
+
totalOut += tp.out / share;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
domainAgg.set(domain, {
|
|
810
|
+
activeConnections: Math.round(totalConns),
|
|
811
|
+
bytesInPerSec: totalIn,
|
|
812
|
+
bytesOutPerSec: totalOut,
|
|
813
|
+
routeCount: routeNames.length,
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// Include routes with no domain config (fallback: use route name)
|
|
748
818
|
for (const [routeName, activeConns] of connectionsByRoute) {
|
|
749
|
-
|
|
819
|
+
if (accountedRoutes.has(routeName)) continue;
|
|
820
|
+
if (routeDomains.has(routeName)) continue; // has domains but no traffic matched
|
|
750
821
|
const tp = throughputByRoute.get(routeName) || { in: 0, out: 0 };
|
|
751
|
-
|
|
822
|
+
if (activeConns === 0 && tp.in === 0 && tp.out === 0) continue;
|
|
823
|
+
const existing = domainAgg.get(routeName);
|
|
752
824
|
if (existing) {
|
|
753
825
|
existing.activeConnections += activeConns;
|
|
754
826
|
existing.bytesInPerSec += tp.in;
|
|
755
827
|
existing.bytesOutPerSec += tp.out;
|
|
756
828
|
existing.routeCount++;
|
|
757
829
|
} else {
|
|
758
|
-
domainAgg.set(
|
|
830
|
+
domainAgg.set(routeName, {
|
|
759
831
|
activeConnections: activeConns,
|
|
760
832
|
bytesInPerSec: tp.in,
|
|
761
833
|
bytesOutPerSec: tp.out,
|
|
@@ -763,6 +835,7 @@ export class MetricsManager {
|
|
|
763
835
|
});
|
|
764
836
|
}
|
|
765
837
|
}
|
|
838
|
+
|
|
766
839
|
const domainActivity = Array.from(domainAgg.entries())
|
|
767
840
|
.map(([domain, data]) => ({
|
|
768
841
|
domain,
|
|
@@ -135,7 +135,7 @@ export class NetworkTargetHandler {
|
|
|
135
135
|
const result = await resolver.deleteTarget(
|
|
136
136
|
dataArg.id,
|
|
137
137
|
dataArg.force ?? false,
|
|
138
|
-
manager.
|
|
138
|
+
manager.getRoutes(),
|
|
139
139
|
);
|
|
140
140
|
|
|
141
141
|
if (result.success && dataArg.force) {
|
|
@@ -158,7 +158,7 @@ export class NetworkTargetHandler {
|
|
|
158
158
|
if (!resolver || !manager) {
|
|
159
159
|
return { routes: [] };
|
|
160
160
|
}
|
|
161
|
-
const usage = resolver.getTargetUsageForId(dataArg.id, manager.
|
|
161
|
+
const usage = resolver.getTargetUsageForId(dataArg.id, manager.getRoutes());
|
|
162
162
|
return { routes: usage.map((u) => ({ id: u.id, name: u.routeName })) };
|
|
163
163
|
},
|
|
164
164
|
),
|
|
@@ -72,7 +72,7 @@ export class RouteManagementHandler {
|
|
|
72
72
|
return { success: false, message: 'Route management not initialized' };
|
|
73
73
|
}
|
|
74
74
|
const id = await manager.createRoute(dataArg.route, userId, dataArg.enabled ?? true, dataArg.metadata);
|
|
75
|
-
return { success: true,
|
|
75
|
+
return { success: true, routeId: id };
|
|
76
76
|
},
|
|
77
77
|
),
|
|
78
78
|
);
|
|
@@ -113,39 +113,7 @@ export class RouteManagementHandler {
|
|
|
113
113
|
),
|
|
114
114
|
);
|
|
115
115
|
|
|
116
|
-
//
|
|
117
|
-
this.typedrouter.addTypedHandler(
|
|
118
|
-
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_SetRouteOverride>(
|
|
119
|
-
'setRouteOverride',
|
|
120
|
-
async (dataArg) => {
|
|
121
|
-
const userId = await this.requireAuth(dataArg, 'routes:write');
|
|
122
|
-
const manager = this.opsServerRef.dcRouterRef.routeConfigManager;
|
|
123
|
-
if (!manager) {
|
|
124
|
-
return { success: false, message: 'Route management not initialized' };
|
|
125
|
-
}
|
|
126
|
-
await manager.setOverride(dataArg.routeName, dataArg.enabled, userId);
|
|
127
|
-
return { success: true };
|
|
128
|
-
},
|
|
129
|
-
),
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
// Remove override from a hardcoded route
|
|
133
|
-
this.typedrouter.addTypedHandler(
|
|
134
|
-
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_RemoveRouteOverride>(
|
|
135
|
-
'removeRouteOverride',
|
|
136
|
-
async (dataArg) => {
|
|
137
|
-
await this.requireAuth(dataArg, 'routes:write');
|
|
138
|
-
const manager = this.opsServerRef.dcRouterRef.routeConfigManager;
|
|
139
|
-
if (!manager) {
|
|
140
|
-
return { success: false, message: 'Route management not initialized' };
|
|
141
|
-
}
|
|
142
|
-
const ok = await manager.removeOverride(dataArg.routeName);
|
|
143
|
-
return { success: ok, message: ok ? undefined : 'Override not found' };
|
|
144
|
-
},
|
|
145
|
-
),
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
// Toggle programmatic route
|
|
116
|
+
// Toggle route
|
|
149
117
|
this.typedrouter.addTypedHandler(
|
|
150
118
|
new plugins.typedrequest.TypedHandler<interfaces.requests.IReq_ToggleRoute>(
|
|
151
119
|
'toggleRoute',
|
|
@@ -136,7 +136,7 @@ export class SourceProfileHandler {
|
|
|
136
136
|
const result = await resolver.deleteProfile(
|
|
137
137
|
dataArg.id,
|
|
138
138
|
dataArg.force ?? false,
|
|
139
|
-
manager.
|
|
139
|
+
manager.getRoutes(),
|
|
140
140
|
);
|
|
141
141
|
|
|
142
142
|
// If force-deleted with affected routes, re-apply
|
|
@@ -160,7 +160,7 @@ export class SourceProfileHandler {
|
|
|
160
160
|
if (!resolver || !manager) {
|
|
161
161
|
return { routes: [] };
|
|
162
162
|
}
|
|
163
|
-
const usage = resolver.getProfileUsageForId(dataArg.id, manager.
|
|
163
|
+
const usage = resolver.getProfileUsageForId(dataArg.id, manager.getRoutes());
|
|
164
164
|
return { routes: usage.map((u) => ({ id: u.id, name: u.routeName })) };
|
|
165
165
|
},
|
|
166
166
|
),
|
|
@@ -7,10 +7,9 @@ export class Route {
|
|
|
7
7
|
|
|
8
8
|
// Data from IMergedRoute
|
|
9
9
|
public routeConfig: IRouteConfig;
|
|
10
|
-
public
|
|
10
|
+
public id: string;
|
|
11
11
|
public enabled: boolean;
|
|
12
|
-
public
|
|
13
|
-
public storedRouteId?: string;
|
|
12
|
+
public origin: 'config' | 'email' | 'dns' | 'api';
|
|
14
13
|
public createdAt?: number;
|
|
15
14
|
public updatedAt?: number;
|
|
16
15
|
|
|
@@ -22,21 +21,17 @@ export class Route {
|
|
|
22
21
|
constructor(clientRef: DcRouterApiClient, data: interfaces.data.IMergedRoute) {
|
|
23
22
|
this.clientRef = clientRef;
|
|
24
23
|
this.routeConfig = data.route;
|
|
25
|
-
this.
|
|
24
|
+
this.id = data.id;
|
|
26
25
|
this.enabled = data.enabled;
|
|
27
|
-
this.
|
|
28
|
-
this.storedRouteId = data.storedRouteId;
|
|
26
|
+
this.origin = data.origin;
|
|
29
27
|
this.createdAt = data.createdAt;
|
|
30
28
|
this.updatedAt = data.updatedAt;
|
|
31
29
|
}
|
|
32
30
|
|
|
33
31
|
public async update(changes: Partial<IRouteConfig>): Promise<void> {
|
|
34
|
-
if (!this.storedRouteId) {
|
|
35
|
-
throw new Error('Cannot update a hardcoded route. Use setOverride() instead.');
|
|
36
|
-
}
|
|
37
32
|
const response = await this.clientRef.request<interfaces.requests.IReq_UpdateRoute>(
|
|
38
33
|
'updateRoute',
|
|
39
|
-
this.clientRef.buildRequestPayload({ id: this.
|
|
34
|
+
this.clientRef.buildRequestPayload({ id: this.id, route: changes }) as any,
|
|
40
35
|
);
|
|
41
36
|
if (!response.success) {
|
|
42
37
|
throw new Error(response.message || 'Failed to update route');
|
|
@@ -44,12 +39,9 @@ export class Route {
|
|
|
44
39
|
}
|
|
45
40
|
|
|
46
41
|
public async delete(): Promise<void> {
|
|
47
|
-
if (!this.storedRouteId) {
|
|
48
|
-
throw new Error('Cannot delete a hardcoded route. Use setOverride() instead.');
|
|
49
|
-
}
|
|
50
42
|
const response = await this.clientRef.request<interfaces.requests.IReq_DeleteRoute>(
|
|
51
43
|
'deleteRoute',
|
|
52
|
-
this.clientRef.buildRequestPayload({ id: this.
|
|
44
|
+
this.clientRef.buildRequestPayload({ id: this.id }) as any,
|
|
53
45
|
);
|
|
54
46
|
if (!response.success) {
|
|
55
47
|
throw new Error(response.message || 'Failed to delete route');
|
|
@@ -57,41 +49,15 @@ export class Route {
|
|
|
57
49
|
}
|
|
58
50
|
|
|
59
51
|
public async toggle(enabled: boolean): Promise<void> {
|
|
60
|
-
if (!this.storedRouteId) {
|
|
61
|
-
throw new Error('Cannot toggle a hardcoded route. Use setOverride() instead.');
|
|
62
|
-
}
|
|
63
52
|
const response = await this.clientRef.request<interfaces.requests.IReq_ToggleRoute>(
|
|
64
53
|
'toggleRoute',
|
|
65
|
-
this.clientRef.buildRequestPayload({ id: this.
|
|
54
|
+
this.clientRef.buildRequestPayload({ id: this.id, enabled }) as any,
|
|
66
55
|
);
|
|
67
56
|
if (!response.success) {
|
|
68
57
|
throw new Error(response.message || 'Failed to toggle route');
|
|
69
58
|
}
|
|
70
59
|
this.enabled = enabled;
|
|
71
60
|
}
|
|
72
|
-
|
|
73
|
-
public async setOverride(enabled: boolean): Promise<void> {
|
|
74
|
-
const response = await this.clientRef.request<interfaces.requests.IReq_SetRouteOverride>(
|
|
75
|
-
'setRouteOverride',
|
|
76
|
-
this.clientRef.buildRequestPayload({ routeName: this.name, enabled }) as any,
|
|
77
|
-
);
|
|
78
|
-
if (!response.success) {
|
|
79
|
-
throw new Error(response.message || 'Failed to set route override');
|
|
80
|
-
}
|
|
81
|
-
this.overridden = true;
|
|
82
|
-
this.enabled = enabled;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
public async removeOverride(): Promise<void> {
|
|
86
|
-
const response = await this.clientRef.request<interfaces.requests.IReq_RemoveRouteOverride>(
|
|
87
|
-
'removeRouteOverride',
|
|
88
|
-
this.clientRef.buildRequestPayload({ routeName: this.name }) as any,
|
|
89
|
-
);
|
|
90
|
-
if (!response.success) {
|
|
91
|
-
throw new Error(response.message || 'Failed to remove route override');
|
|
92
|
-
}
|
|
93
|
-
this.overridden = false;
|
|
94
|
-
}
|
|
95
61
|
}
|
|
96
62
|
|
|
97
63
|
export class RouteBuilder {
|
|
@@ -144,9 +110,8 @@ export class RouteBuilder {
|
|
|
144
110
|
}
|
|
145
111
|
|
|
146
112
|
// Return a Route instance by re-fetching the list
|
|
147
|
-
// The created route is programmatic, so we find it by storedRouteId
|
|
148
113
|
const { routes } = await new RouteManager(this.clientRef).list();
|
|
149
|
-
const created = routes.find((r) => r.
|
|
114
|
+
const created = routes.find((r) => r.id === response.routeId);
|
|
150
115
|
if (created) {
|
|
151
116
|
return created;
|
|
152
117
|
}
|
|
@@ -154,10 +119,9 @@ export class RouteBuilder {
|
|
|
154
119
|
// Fallback: construct from known data
|
|
155
120
|
return new Route(this.clientRef, {
|
|
156
121
|
route: this.routeConfig as IRouteConfig,
|
|
157
|
-
|
|
122
|
+
id: response.routeId || '',
|
|
158
123
|
enabled: this.isEnabled,
|
|
159
|
-
|
|
160
|
-
storedRouteId: response.storedRouteId,
|
|
124
|
+
origin: 'api',
|
|
161
125
|
});
|
|
162
126
|
}
|
|
163
127
|
}
|
|
@@ -190,10 +154,9 @@ export class RouteManager {
|
|
|
190
154
|
}
|
|
191
155
|
return new Route(this.clientRef, {
|
|
192
156
|
route: routeConfig,
|
|
193
|
-
|
|
157
|
+
id: response.routeId || '',
|
|
194
158
|
enabled: enabled ?? true,
|
|
195
|
-
|
|
196
|
-
storedRouteId: response.storedRouteId,
|
|
159
|
+
origin: 'api',
|
|
197
160
|
});
|
|
198
161
|
}
|
|
199
162
|
|
package/ts_web/appstate.ts
CHANGED
|
@@ -2219,58 +2219,6 @@ export const toggleRouteAction = routeManagementStatePart.createAction<{
|
|
|
2219
2219
|
}
|
|
2220
2220
|
});
|
|
2221
2221
|
|
|
2222
|
-
export const setRouteOverrideAction = routeManagementStatePart.createAction<{
|
|
2223
|
-
routeName: string;
|
|
2224
|
-
enabled: boolean;
|
|
2225
|
-
}>(async (statePartArg, dataArg, actionContext): Promise<IRouteManagementState> => {
|
|
2226
|
-
const context = getActionContext();
|
|
2227
|
-
const currentState = statePartArg.getState()!;
|
|
2228
|
-
|
|
2229
|
-
try {
|
|
2230
|
-
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
|
2231
|
-
interfaces.requests.IReq_SetRouteOverride
|
|
2232
|
-
>('/typedrequest', 'setRouteOverride');
|
|
2233
|
-
|
|
2234
|
-
await request.fire({
|
|
2235
|
-
identity: context.identity!,
|
|
2236
|
-
routeName: dataArg.routeName,
|
|
2237
|
-
enabled: dataArg.enabled,
|
|
2238
|
-
});
|
|
2239
|
-
|
|
2240
|
-
return await actionContext!.dispatch(fetchMergedRoutesAction, null);
|
|
2241
|
-
} catch (error: unknown) {
|
|
2242
|
-
return {
|
|
2243
|
-
...currentState,
|
|
2244
|
-
error: error instanceof Error ? error.message : 'Failed to set override',
|
|
2245
|
-
};
|
|
2246
|
-
}
|
|
2247
|
-
});
|
|
2248
|
-
|
|
2249
|
-
export const removeRouteOverrideAction = routeManagementStatePart.createAction<string>(
|
|
2250
|
-
async (statePartArg, routeName, actionContext): Promise<IRouteManagementState> => {
|
|
2251
|
-
const context = getActionContext();
|
|
2252
|
-
const currentState = statePartArg.getState()!;
|
|
2253
|
-
|
|
2254
|
-
try {
|
|
2255
|
-
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
|
|
2256
|
-
interfaces.requests.IReq_RemoveRouteOverride
|
|
2257
|
-
>('/typedrequest', 'removeRouteOverride');
|
|
2258
|
-
|
|
2259
|
-
await request.fire({
|
|
2260
|
-
identity: context.identity!,
|
|
2261
|
-
routeName,
|
|
2262
|
-
});
|
|
2263
|
-
|
|
2264
|
-
return await actionContext!.dispatch(fetchMergedRoutesAction, null);
|
|
2265
|
-
} catch (error: unknown) {
|
|
2266
|
-
return {
|
|
2267
|
-
...currentState,
|
|
2268
|
-
error: error instanceof Error ? error.message : 'Failed to remove override',
|
|
2269
|
-
};
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
);
|
|
2273
|
-
|
|
2274
2222
|
// ============================================================================
|
|
2275
2223
|
// API Token Actions
|
|
2276
2224
|
// ============================================================================
|