@serve.zone/dcrouter 13.43.0 → 13.43.2
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 +894 -896
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/config/classes.reference-resolver.d.ts +3 -3
- package/dist_ts/config/classes.reference-resolver.js +16 -40
- package/dist_ts/config/classes.route-config-manager.d.ts +3 -2
- package/dist_ts/config/classes.route-config-manager.js +38 -36
- package/dist_ts/config/classes.source-policy-compiler.d.ts +9 -4
- package/dist_ts/config/classes.source-policy-compiler.js +92 -26
- package/dist_ts/opsserver/handlers/workhoster.handler.d.ts +1 -0
- package/dist_ts/opsserver/handlers/workhoster.handler.js +25 -3
- package/dist_ts_interfaces/data/route-management.d.ts +7 -8
- package/dist_ts_migrations/index.js +102 -1
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/network/ops-view-routes.d.ts +1 -1
- package/dist_ts_web/elements/network/ops-view-routes.js +111 -134
- package/package.json +1 -1
- package/readme.md +44 -45
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/config/classes.reference-resolver.ts +16 -40
- package/ts/config/classes.route-config-manager.ts +41 -40
- package/ts/config/classes.source-policy-compiler.ts +115 -30
- package/ts/opsserver/handlers/workhoster.handler.ts +26 -2
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/network/ops-view-routes.ts +112 -136
package/readme.md
CHANGED
|
@@ -146,19 +146,20 @@ dcrouter keeps generated and operator-created routes separate so automation can
|
|
|
146
146
|
|
|
147
147
|
System routes are persisted with stable `systemKey` values. API-created routes are the editable route layer intended for operators and automation.
|
|
148
148
|
|
|
149
|
-
## Route Source
|
|
149
|
+
## Route Source Bindings
|
|
150
150
|
|
|
151
|
-
API-created route records pass `metadata.
|
|
151
|
+
API-created route records pass ordered `metadata.sourceBindings[]` alongside the SmartProxy route config to express source and path policy variants without duplicating whole routes by hand. Each binding points at a source profile id through `sourceProfileRef`. Dashboard presets resolve seeded profile names to ids before saving.
|
|
152
152
|
|
|
153
153
|
Runtime behavior:
|
|
154
154
|
|
|
155
155
|
- Source matching uses the referenced `SourceProfile.security.ipAllowList`.
|
|
156
156
|
- Bindings are evaluated in order and the first matching source profile wins.
|
|
157
157
|
- A matched binding that exceeds its configured rate or connection limit is terminal and returns `429`; dcrouter does not fall through to later bindings.
|
|
158
|
-
- Source-
|
|
159
|
-
-
|
|
160
|
-
-
|
|
161
|
-
-
|
|
158
|
+
- Source-binding rate limits are always keyed by source IP; dcrouter ignores `path` and `header` keying on source-binding and path-policy overrides.
|
|
159
|
+
- Private-only binding lists are valid. dcrouter adds a same-match terminal deny fallback so unmatched sources fail closed.
|
|
160
|
+
- A public or wildcard binding is optional. When present, it must be last and must use `*`, or both `0.0.0.0/0` and `::/0`, in `security.ipAllowList`.
|
|
161
|
+
- Create/update paths reject source bindings with missing source profiles, source profiles without source matches, or any all-source binding that shadows later bindings; persisted invalid bindings fail closed at compile time.
|
|
162
|
+
- Server-side caps bound policy expansion to 16 source bindings, 12 path policies per binding, 64 path patterns per path policy, 256 characters and 8 wildcards per custom path pattern, 512 compiled SmartProxy route-port variants per stored route, and enough priority headroom above the stored route priority for generated source-binding variants.
|
|
162
163
|
|
|
163
164
|
Path policies let a source binding override rate limits or connection limits for specific path classes. dcrouter currently ships Gitea-oriented classes: `git-smart-http`, `static`, `normal-html`, `expensive-html`, `raw`, and `archive`. Path-specific variants win over the same binding's fallback; if every path policy is path-specific, dcrouter adds a source-level fallback route for unmatched paths so normal browsing cannot fall through to a later source binding. The Gitea preset keeps `git-smart-http` high-limit and separate from HTML crawling paths so normal `git clone`, `git fetch`, `git push`, and Git LFS traffic are not subject to the lower HTML crawler limits.
|
|
164
165
|
|
|
@@ -177,45 +178,43 @@ const createRoutePayload = {
|
|
|
177
178
|
},
|
|
178
179
|
},
|
|
179
180
|
metadata: {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
],
|
|
218
|
-
},
|
|
181
|
+
sourceBindings: [
|
|
182
|
+
{
|
|
183
|
+
sourceProfileRef: trustedProfileId,
|
|
184
|
+
maxConnections: 5000,
|
|
185
|
+
onExceeded: { type: '429' },
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
sourceProfileRef: publicProfileId,
|
|
189
|
+
onExceeded: { type: '429' },
|
|
190
|
+
pathPolicies: [
|
|
191
|
+
{
|
|
192
|
+
pathClass: 'git-smart-http',
|
|
193
|
+
rateLimit: { enabled: true, maxRequests: 1200, window: 60, keyBy: 'ip' },
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
pathClass: 'static',
|
|
197
|
+
rateLimit: { enabled: true, maxRequests: 600, window: 60, keyBy: 'ip' },
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
pathClass: 'raw',
|
|
201
|
+
rateLimit: { enabled: true, maxRequests: 120, window: 60, keyBy: 'ip' },
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
pathClass: 'archive',
|
|
205
|
+
rateLimit: { enabled: true, maxRequests: 30, window: 60, keyBy: 'ip' },
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
pathClass: 'expensive-html',
|
|
209
|
+
rateLimit: { enabled: true, maxRequests: 30, window: 60, keyBy: 'ip' },
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
pathClass: 'normal-html',
|
|
213
|
+
rateLimit: { enabled: true, maxRequests: 120, window: 60, keyBy: 'ip' },
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
},
|
|
217
|
+
],
|
|
219
218
|
},
|
|
220
219
|
};
|
|
221
220
|
```
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
IRouteMetadata,
|
|
8
8
|
IRoute,
|
|
9
9
|
IRouteSecurity,
|
|
10
|
-
|
|
10
|
+
IRouteSourceBinding,
|
|
11
11
|
} from '../../ts_interfaces/data/route-management.js';
|
|
12
12
|
|
|
13
13
|
const MAX_INHERITANCE_DEPTH = 5;
|
|
@@ -288,8 +288,8 @@ export class ReferenceResolver {
|
|
|
288
288
|
|
|
289
289
|
/**
|
|
290
290
|
* Resolve references for a single route.
|
|
291
|
-
*
|
|
292
|
-
*
|
|
291
|
+
* Resolves source binding display names and/or network target references.
|
|
292
|
+
* Source profile security is resolved at apply time by SourcePolicyCompiler.
|
|
293
293
|
* Returns the resolved route and updated metadata.
|
|
294
294
|
*/
|
|
295
295
|
public resolveRoute(
|
|
@@ -298,27 +298,12 @@ export class ReferenceResolver {
|
|
|
298
298
|
): { route: plugins.smartproxy.IRouteConfig; metadata: IRouteMetadata } {
|
|
299
299
|
const resolvedMetadata: IRouteMetadata = { ...metadata };
|
|
300
300
|
|
|
301
|
-
if (resolvedMetadata.
|
|
302
|
-
const
|
|
303
|
-
if (
|
|
304
|
-
resolvedMetadata.
|
|
305
|
-
resolvedMetadata.sourceProfileRef = undefined;
|
|
306
|
-
resolvedMetadata.sourceProfileName = undefined;
|
|
301
|
+
if (resolvedMetadata.sourceBindings?.length) {
|
|
302
|
+
const resolvedSourceBindings = this.resolveRouteSourceBindings(resolvedMetadata.sourceBindings);
|
|
303
|
+
if (resolvedSourceBindings) {
|
|
304
|
+
resolvedMetadata.sourceBindings = resolvedSourceBindings;
|
|
307
305
|
resolvedMetadata.lastResolvedAt = Date.now();
|
|
308
306
|
}
|
|
309
|
-
} else if (resolvedMetadata.sourceProfileRef) {
|
|
310
|
-
const resolvedSecurity = this.resolveSourceProfile(resolvedMetadata.sourceProfileRef);
|
|
311
|
-
if (resolvedSecurity) {
|
|
312
|
-
const profile = this.profiles.get(resolvedMetadata.sourceProfileRef);
|
|
313
|
-
route = {
|
|
314
|
-
...route,
|
|
315
|
-
security: this.cloneSecurityFields(resolvedSecurity),
|
|
316
|
-
};
|
|
317
|
-
resolvedMetadata.sourceProfileName = profile?.name;
|
|
318
|
-
resolvedMetadata.lastResolvedAt = Date.now();
|
|
319
|
-
} else {
|
|
320
|
-
logger.log('warn', `Source profile '${resolvedMetadata.sourceProfileRef}' not found during resolution`);
|
|
321
|
-
}
|
|
322
307
|
}
|
|
323
308
|
|
|
324
309
|
if (resolvedMetadata.networkTargetRef) {
|
|
@@ -387,12 +372,12 @@ export class ReferenceResolver {
|
|
|
387
372
|
// Private: source profile resolution with inheritance
|
|
388
373
|
// =========================================================================
|
|
389
374
|
|
|
390
|
-
private
|
|
391
|
-
const bindings =
|
|
375
|
+
private resolveRouteSourceBindings(sourceBindings: IRouteSourceBinding[]): IRouteSourceBinding[] | undefined {
|
|
376
|
+
const bindings = sourceBindings
|
|
392
377
|
.map((binding) => {
|
|
393
378
|
const profile = this.profiles.get(binding.sourceProfileRef);
|
|
394
379
|
if (!profile) {
|
|
395
|
-
logger.log('warn', `Source profile '${binding.sourceProfileRef}' not found during source
|
|
380
|
+
logger.log('warn', `Source profile '${binding.sourceProfileRef}' not found during source binding resolution`);
|
|
396
381
|
return binding;
|
|
397
382
|
}
|
|
398
383
|
return {
|
|
@@ -402,7 +387,7 @@ export class ReferenceResolver {
|
|
|
402
387
|
})
|
|
403
388
|
.filter((binding) => binding.sourceProfileRef);
|
|
404
389
|
|
|
405
|
-
return bindings.length > 0 ?
|
|
390
|
+
return bindings.length > 0 ? bindings : undefined;
|
|
406
391
|
}
|
|
407
392
|
|
|
408
393
|
private metadataUsesSourceProfile(metadata: IRouteMetadata | undefined, profileId: string): boolean {
|
|
@@ -411,10 +396,7 @@ export class ReferenceResolver {
|
|
|
411
396
|
|
|
412
397
|
private getSourceProfileRefsFromMetadata(metadata: IRouteMetadata | undefined): string[] {
|
|
413
398
|
const refs = new Set<string>();
|
|
414
|
-
|
|
415
|
-
refs.add(metadata.sourceProfileRef);
|
|
416
|
-
}
|
|
417
|
-
for (const binding of metadata?.sourcePolicy?.bindings || []) {
|
|
399
|
+
for (const binding of metadata?.sourceBindings || []) {
|
|
418
400
|
if (binding.sourceProfileRef) {
|
|
419
401
|
refs.add(binding.sourceProfileRef);
|
|
420
402
|
}
|
|
@@ -623,22 +605,16 @@ export class ReferenceResolver {
|
|
|
623
605
|
}
|
|
624
606
|
|
|
625
607
|
private clearSourceProfileFromMetadata(metadata: IRouteMetadata, profileId: string): IRouteMetadata {
|
|
626
|
-
const
|
|
627
|
-
?
|
|
628
|
-
bindings: metadata.sourcePolicy.bindings.filter(
|
|
629
|
-
(binding) => binding.sourceProfileRef !== profileId,
|
|
630
|
-
),
|
|
631
|
-
}
|
|
608
|
+
const sourceBindings = metadata.sourceBindings?.length
|
|
609
|
+
? metadata.sourceBindings.filter((binding) => binding.sourceProfileRef !== profileId)
|
|
632
610
|
: undefined;
|
|
633
611
|
|
|
634
612
|
const nextMetadata: IRouteMetadata = {
|
|
635
613
|
...metadata,
|
|
636
|
-
|
|
637
|
-
sourceProfileName: metadata.sourceProfileRef === profileId ? undefined : metadata.sourceProfileName,
|
|
638
|
-
sourcePolicy: sourcePolicy?.bindings.length ? sourcePolicy : undefined,
|
|
614
|
+
sourceBindings: sourceBindings?.length ? sourceBindings : undefined,
|
|
639
615
|
};
|
|
640
616
|
|
|
641
|
-
if (!nextMetadata.
|
|
617
|
+
if (!nextMetadata.sourceBindings && !nextMetadata.networkTargetRef) {
|
|
642
618
|
nextMetadata.lastResolvedAt = undefined;
|
|
643
619
|
}
|
|
644
620
|
|
|
@@ -9,7 +9,7 @@ import type {
|
|
|
9
9
|
IRouteWarning,
|
|
10
10
|
IRouteMetadata,
|
|
11
11
|
IRoutePathPolicyBinding,
|
|
12
|
-
|
|
12
|
+
IRouteSourceBinding,
|
|
13
13
|
IRouteSecurity,
|
|
14
14
|
} from '../../ts_interfaces/data/route-management.js';
|
|
15
15
|
import type { IDcRouterRouteConfig } from '../../ts_interfaces/data/remoteingress.js';
|
|
@@ -142,9 +142,9 @@ export class RouteConfigManager {
|
|
|
142
142
|
): Promise<string> {
|
|
143
143
|
const id = plugins.uuid.v4();
|
|
144
144
|
const now = Date.now();
|
|
145
|
-
const
|
|
146
|
-
if (
|
|
147
|
-
throw new Error(
|
|
145
|
+
const sourceBindingsPayloadError = SourcePolicyCompiler.validateSourceBindingsPayload(metadata?.sourceBindings);
|
|
146
|
+
if (sourceBindingsPayloadError) {
|
|
147
|
+
throw new Error(sourceBindingsPayloadError);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// Ensure route has a name
|
|
@@ -159,9 +159,9 @@ export class RouteConfigManager {
|
|
|
159
159
|
route = resolved.route;
|
|
160
160
|
resolvedMetadata = this.normalizeRouteMetadata(resolved.metadata);
|
|
161
161
|
}
|
|
162
|
-
const
|
|
163
|
-
if (
|
|
164
|
-
throw new Error(
|
|
162
|
+
const sourceBindingsValidationError = this.validateSourceBindings(resolvedMetadata?.sourceBindings, route);
|
|
163
|
+
if (sourceBindingsValidationError) {
|
|
164
|
+
throw new Error(sourceBindingsValidationError);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
const stored: IRoute = {
|
|
@@ -193,12 +193,11 @@ export class RouteConfigManager {
|
|
|
193
193
|
if (!stored) {
|
|
194
194
|
return { success: false, message: 'Route not found' };
|
|
195
195
|
}
|
|
196
|
-
const
|
|
197
|
-
if (
|
|
198
|
-
return { success: false, message:
|
|
196
|
+
const sourceBindingsPayloadError = SourcePolicyCompiler.validateSourceBindingsPayload(patch.metadata?.sourceBindings);
|
|
197
|
+
if (sourceBindingsPayloadError) {
|
|
198
|
+
return { success: false, message: sourceBindingsPayloadError };
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
const previousSourceProfileRef = stored.metadata?.sourceProfileRef;
|
|
202
201
|
const previousRoute = structuredClone(stored.route);
|
|
203
202
|
const previousMetadata = structuredClone(stored.metadata);
|
|
204
203
|
const previousEnabled = stored.enabled;
|
|
@@ -244,13 +243,6 @@ export class RouteConfigManager {
|
|
|
244
243
|
...stored.metadata,
|
|
245
244
|
...patch.metadata,
|
|
246
245
|
});
|
|
247
|
-
if (
|
|
248
|
-
previousSourceProfileRef
|
|
249
|
-
&& !stored.metadata?.sourceProfileRef
|
|
250
|
-
&& !patch.route?.security
|
|
251
|
-
) {
|
|
252
|
-
delete stored.route.security;
|
|
253
|
-
}
|
|
254
246
|
}
|
|
255
247
|
|
|
256
248
|
// Re-resolve if metadata refs exist and resolver is available
|
|
@@ -260,12 +252,12 @@ export class RouteConfigManager {
|
|
|
260
252
|
stored.metadata = this.normalizeRouteMetadata(resolved.metadata);
|
|
261
253
|
}
|
|
262
254
|
|
|
263
|
-
const
|
|
264
|
-
if (
|
|
255
|
+
const sourceBindingsValidationError = this.validateSourceBindings(stored.metadata?.sourceBindings, stored.route);
|
|
256
|
+
if (sourceBindingsValidationError) {
|
|
265
257
|
stored.route = previousRoute;
|
|
266
258
|
stored.metadata = previousMetadata;
|
|
267
259
|
stored.enabled = previousEnabled;
|
|
268
|
-
return { success: false, message:
|
|
260
|
+
return { success: false, message: sourceBindingsValidationError };
|
|
269
261
|
}
|
|
270
262
|
|
|
271
263
|
stored.updatedAt = Date.now();
|
|
@@ -487,10 +479,8 @@ export class RouteConfigManager {
|
|
|
487
479
|
};
|
|
488
480
|
|
|
489
481
|
const normalized: IRouteMetadata = {
|
|
490
|
-
|
|
491
|
-
sourcePolicy: this.normalizeSourcePolicy(metadata.sourcePolicy),
|
|
482
|
+
sourceBindings: this.normalizeSourceBindings(metadata.sourceBindings),
|
|
492
483
|
networkTargetRef: normalizeString(metadata.networkTargetRef),
|
|
493
|
-
sourceProfileName: normalizeString(metadata.sourceProfileName),
|
|
494
484
|
networkTargetName: normalizeString(metadata.networkTargetName),
|
|
495
485
|
lastResolvedAt: typeof metadata.lastResolvedAt === 'number' && Number.isFinite(metadata.lastResolvedAt)
|
|
496
486
|
? metadata.lastResolvedAt
|
|
@@ -511,13 +501,10 @@ export class RouteConfigManager {
|
|
|
511
501
|
externalKey: normalizeString(metadata.externalKey),
|
|
512
502
|
};
|
|
513
503
|
|
|
514
|
-
if (!normalized.sourceProfileRef) {
|
|
515
|
-
normalized.sourceProfileName = undefined;
|
|
516
|
-
}
|
|
517
504
|
if (!normalized.networkTargetRef) {
|
|
518
505
|
normalized.networkTargetName = undefined;
|
|
519
506
|
}
|
|
520
|
-
if (!normalized.
|
|
507
|
+
if (!normalized.sourceBindings && !normalized.networkTargetRef) {
|
|
521
508
|
normalized.lastResolvedAt = undefined;
|
|
522
509
|
}
|
|
523
510
|
if (normalized.ownerType !== 'gatewayClient' && normalized.ownerType !== 'workhoster') {
|
|
@@ -542,14 +529,13 @@ export class RouteConfigManager {
|
|
|
542
529
|
return normalized;
|
|
543
530
|
}
|
|
544
531
|
|
|
545
|
-
private
|
|
546
|
-
|
|
547
|
-
if (!Array.isArray(bindings)) {
|
|
532
|
+
private normalizeSourceBindings(sourceBindings?: Partial<IRouteSourceBinding>[]): IRouteSourceBinding[] | undefined {
|
|
533
|
+
if (!Array.isArray(sourceBindings)) {
|
|
548
534
|
return undefined;
|
|
549
535
|
}
|
|
550
536
|
|
|
551
|
-
const normalizedBindings:
|
|
552
|
-
for (const binding of
|
|
537
|
+
const normalizedBindings: IRouteSourceBinding[] = [];
|
|
538
|
+
for (const binding of sourceBindings) {
|
|
553
539
|
const sourceProfileRef = typeof binding.sourceProfileRef === 'string'
|
|
554
540
|
? binding.sourceProfileRef.trim()
|
|
555
541
|
: '';
|
|
@@ -583,7 +569,7 @@ export class RouteConfigManager {
|
|
|
583
569
|
});
|
|
584
570
|
}
|
|
585
571
|
|
|
586
|
-
return normalizedBindings.length > 0 ?
|
|
572
|
+
return normalizedBindings.length > 0 ? normalizedBindings : undefined;
|
|
587
573
|
}
|
|
588
574
|
|
|
589
575
|
private normalizePathPolicies(
|
|
@@ -631,15 +617,15 @@ export class RouteConfigManager {
|
|
|
631
617
|
return normalizedPathPolicies.length > 0 ? normalizedPathPolicies : undefined;
|
|
632
618
|
}
|
|
633
619
|
|
|
634
|
-
private
|
|
635
|
-
|
|
620
|
+
private validateSourceBindings(
|
|
621
|
+
sourceBindings: IRouteSourceBinding[] | undefined,
|
|
636
622
|
route: IDcRouterRouteConfig,
|
|
637
623
|
): string | undefined {
|
|
638
|
-
const shapeError = SourcePolicyCompiler.
|
|
624
|
+
const shapeError = SourcePolicyCompiler.validateSourceBindingsShape(sourceBindings, route);
|
|
639
625
|
if (shapeError) {
|
|
640
626
|
return shapeError;
|
|
641
627
|
}
|
|
642
|
-
return SourcePolicyCompiler.
|
|
628
|
+
return SourcePolicyCompiler.validateResolvedSourceBindings(sourceBindings, this.referenceResolver);
|
|
643
629
|
}
|
|
644
630
|
|
|
645
631
|
private normalizeRateLimit(rateLimit?: IRouteSecurity['rateLimit']): IRouteSecurity['rateLimit'] | undefined {
|
|
@@ -756,14 +742,29 @@ export class RouteConfigManager {
|
|
|
756
742
|
}
|
|
757
743
|
|
|
758
744
|
private prepareStoredRoutesForApply(storedRoute: IRoute): plugins.smartproxy.IRouteConfig[] {
|
|
745
|
+
if (this.isManagedAccessRoute(storedRoute) && !storedRoute.metadata?.sourceBindings?.length) {
|
|
746
|
+
return [];
|
|
747
|
+
}
|
|
759
748
|
const hydratedRoute = this.hydrateStoredRoute?.(storedRoute);
|
|
760
|
-
const
|
|
749
|
+
const sourceBoundRoutes = SourcePolicyCompiler.compileRoute(
|
|
761
750
|
hydratedRoute || storedRoute.route,
|
|
762
751
|
storedRoute.metadata,
|
|
763
752
|
this.referenceResolver,
|
|
764
753
|
storedRoute.id,
|
|
765
754
|
);
|
|
766
|
-
return
|
|
755
|
+
return sourceBoundRoutes.map((route) => this.prepareRouteForApply(route, storedRoute.id));
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
private isManagedAccessRoute(storedRoute: IRoute): boolean {
|
|
759
|
+
const metadata = storedRoute.metadata;
|
|
760
|
+
if (storedRoute.origin !== 'api' || !metadata) {
|
|
761
|
+
return false;
|
|
762
|
+
}
|
|
763
|
+
return metadata.ownerType === 'gatewayClient'
|
|
764
|
+
|| metadata.ownerType === 'workhoster'
|
|
765
|
+
|| Boolean(metadata.gatewayClientId)
|
|
766
|
+
|| Boolean(metadata.workHosterId)
|
|
767
|
+
|| Boolean(metadata.externalKey);
|
|
767
768
|
}
|
|
768
769
|
|
|
769
770
|
private prepareRouteForApply(
|