@pipeline-builder/api-core 5.2.2 → 5.2.4
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/lib/constants/ai-providers.d.ts +3 -22
- package/lib/constants/ai-providers.js +6 -56
- package/lib/errors/app-errors.d.ts +14 -0
- package/lib/errors/app-errors.js +21 -1
- package/lib/helpers/index.d.ts +1 -0
- package/lib/helpers/index.js +2 -1
- package/lib/helpers/sse-helpers.d.ts +33 -3
- package/lib/helpers/sse-helpers.js +91 -19
- package/lib/helpers/support-calendar.d.ts +69 -0
- package/lib/helpers/support-calendar.js +179 -0
- package/lib/middleware/auth.js +6 -3
- package/lib/middleware/deferred-quota-check.d.ts +5 -0
- package/lib/middleware/deferred-quota-check.js +33 -0
- package/lib/middleware/ecosystem-guard.d.ts +3 -3
- package/lib/middleware/ecosystem-guard.js +5 -5
- package/lib/middleware/index.d.ts +5 -2
- package/lib/middleware/index.js +6 -3
- package/lib/middleware/on-behalf.d.ts +37 -0
- package/lib/middleware/on-behalf.js +143 -0
- package/lib/middleware/permission-gates.d.ts +11 -0
- package/lib/middleware/permission-gates.js +7 -1
- package/lib/middleware/quota-exempt-routes.d.ts +36 -0
- package/lib/middleware/quota-exempt-routes.js +47 -0
- package/lib/middleware/route-table.d.ts +104 -0
- package/lib/middleware/route-table.js +72 -2
- package/lib/middleware/service-tokens.d.ts +8 -0
- package/lib/middleware/service-tokens.js +5 -3
- package/lib/middleware/step-up.js +11 -1
- package/lib/services/ai-call-weight.d.ts +24 -0
- package/lib/services/ai-call-weight.js +77 -0
- package/lib/services/alert-delivery.d.ts +99 -0
- package/lib/services/alert-delivery.js +132 -0
- package/lib/services/audit-context.d.ts +105 -0
- package/lib/services/audit-context.js +134 -0
- package/lib/services/index.d.ts +10 -2
- package/lib/services/index.js +10 -2
- package/lib/services/org-ai-client.d.ts +61 -0
- package/lib/services/org-ai-client.js +112 -0
- package/lib/services/pagerduty-inbound.d.ts +101 -0
- package/lib/services/pagerduty-inbound.js +195 -0
- package/lib/services/pagerduty.d.ts +109 -0
- package/lib/services/pagerduty.js +186 -0
- package/lib/services/quota-increment-batcher.d.ts +81 -0
- package/lib/services/quota-increment-batcher.js +166 -0
- package/lib/services/quota.d.ts +158 -14
- package/lib/services/quota.js +252 -22
- package/lib/services/remote-audit-client.d.ts +44 -1
- package/lib/services/remote-audit-client.js +106 -20
- package/lib/services/version-vuln-policy.d.ts +174 -0
- package/lib/services/version-vuln-policy.js +242 -0
- package/lib/types/ai-catalog.d.ts +63 -0
- package/lib/types/ai-catalog.js +82 -0
- package/lib/types/ask-proposals.js +6 -6
- package/lib/types/build-catalog.d.ts +154 -0
- package/lib/types/build-catalog.js +158 -0
- package/lib/types/common.d.ts +37 -3
- package/lib/types/common.js +20 -2
- package/lib/types/ecosystem-notifications.d.ts +5 -5
- package/lib/types/ecosystem-notifications.js +9 -3
- package/lib/types/error-codes.d.ts +13 -6
- package/lib/types/error-codes.js +18 -8
- package/lib/types/feature-flags.d.ts +71 -1
- package/lib/types/feature-flags.js +131 -11
- package/lib/types/index.d.ts +6 -4
- package/lib/types/index.js +12 -5
- package/lib/types/metadata-keys.d.ts +6 -0
- package/lib/types/metadata-keys.js +4 -1
- package/lib/types/permissions.d.ts +351 -3
- package/lib/types/permissions.js +610 -21
- package/lib/types/pipeline.d.ts +39 -0
- package/lib/types/pipeline.js +57 -1
- package/lib/types/plugin-health.d.ts +0 -2
- package/lib/types/plugin-health.js +1 -11
- package/lib/types/plugin-scan.d.ts +192 -42
- package/lib/types/plugin-scan.js +159 -43
- package/lib/types/quota-catalog.d.ts +247 -0
- package/lib/types/quota-catalog.js +122 -0
- package/lib/types/quota-tiers.d.ts +150 -0
- package/lib/types/quota-tiers.js +167 -2
- package/lib/types/remote-audit-actions.d.ts +1 -1
- package/lib/types/remote-audit-actions.js +217 -4
- package/lib/types/wire-vocabulary.js +8 -1
- package/lib/utils/index.d.ts +1 -1
- package/lib/utils/index.js +2 -2
- package/lib/utils/response.d.ts +35 -2
- package/lib/utils/response.js +42 -3
- package/lib/validation/ai-schemas.d.ts +27 -0
- package/lib/validation/ai-schemas.js +31 -5
- package/lib/validation/plugin-schemas.d.ts +15 -0
- package/lib/validation/plugin-schemas.js +28 -1
- package/package.json +31 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* ON-BEHALF calls: a service forwarding the end user's own bearer token to a
|
|
5
|
+
* peer, as part of a request that was ALREADY metered where it arrived.
|
|
6
|
+
*
|
|
7
|
+
* The ask agent acts strictly as the calling user — its tools forward the
|
|
8
|
+
* user's token so the peer's tenancy, permission and compliance gates apply as
|
|
9
|
+
* if the user had called them — and pipeline's confirm-placeholder-plugins does
|
|
10
|
+
* the same against the plugin service. Each of those hops is a USER request to
|
|
11
|
+
* the peer, so the peer's `apiCalls` meter billed it: one agent turn was 10-20
|
|
12
|
+
* apiCalls on top of the turn itself (which is metered, and AI-reserved).
|
|
13
|
+
*
|
|
14
|
+
* The marker that waives that second charge has to be something the USER CANNOT
|
|
15
|
+
* PRODUCE, or any member could stop paying for API calls by setting a header.
|
|
16
|
+
* So it is a SIGNED SERVICE TOKEN (the calling service's own ES256 key, the same
|
|
17
|
+
* key material `requireAuth` trusts for service principals), carried in
|
|
18
|
+
* {@link ON_BEHALF_HEADER} beside the user's untouched `Authorization`:
|
|
19
|
+
*
|
|
20
|
+
* - `type: 'on_behalf'` — never `access`, so the marker is useless as a bearer
|
|
21
|
+
* token anywhere (`requireAuth` and `verifyServicePrincipal` both demand
|
|
22
|
+
* `type: 'access'`);
|
|
23
|
+
* - `obo` + `organizationId` — BOUND to the user and org it vouches for, and
|
|
24
|
+
* honoured only when both equal the request's verified `req.user`;
|
|
25
|
+
* - the signer must be on {@link ON_BEHALF_CALLERS} — a service that forwards
|
|
26
|
+
* user tokens by design — and not on the service-token denylist;
|
|
27
|
+
* - 120 s TTL, minted per outbound call.
|
|
28
|
+
*
|
|
29
|
+
* What a valid marker changes is narrow: the apiCalls/automationCalls METER and
|
|
30
|
+
* CHECK skip the request (`callQuotaExemption`). Tenancy, permissions, audit and
|
|
31
|
+
* every reservation-gated quota (aiCalls, pipelines, plugins) apply exactly as
|
|
32
|
+
* before — an on-behalf `/generate` still reserves its own aiCalls slot.
|
|
33
|
+
*/
|
|
34
|
+
import { randomUUID } from 'crypto';
|
|
35
|
+
import { issuerAudienceOptions } from './jwt-verify.js';
|
|
36
|
+
import { isServiceTokenDenied, serviceNameOf } from './service-tokens.js';
|
|
37
|
+
import { currentAuditContext } from '../services/audit-context.js';
|
|
38
|
+
import { isServiceKid, signServiceJwt, verifyServiceJwt } from '../services/service-keys.js';
|
|
39
|
+
import { decodeJwtHeader } from '../utils/jwk.js';
|
|
40
|
+
import { createLogger } from '../utils/logger.js';
|
|
41
|
+
import { emitCounter } from '../utils/metric-emitter.js';
|
|
42
|
+
const logger = createLogger('on-behalf');
|
|
43
|
+
/** The header carrying the signed on-behalf marker (lower-case, as Node reads it). */
|
|
44
|
+
export const ON_BEHALF_HEADER = 'x-pb-on-behalf';
|
|
45
|
+
/**
|
|
46
|
+
* Services whose on-behalf marker is honoured: the ones that forward a user's
|
|
47
|
+
* token as a matter of design. A marker signed by any other service — valid
|
|
48
|
+
* signature or not — is ignored, so a compromised peer that never forwards user
|
|
49
|
+
* tokens cannot start waiving its tenants' meters.
|
|
50
|
+
*/
|
|
51
|
+
export const ON_BEHALF_CALLERS = ['ask', 'pipeline'];
|
|
52
|
+
/** Marker lifetime. Minted per outbound call, so it only has to outlive one hop. */
|
|
53
|
+
const ON_BEHALF_TTL_SECONDS = 120;
|
|
54
|
+
/** The `type` claim that makes the marker unusable as an access token. */
|
|
55
|
+
const ON_BEHALF_TOKEN_TYPE = 'on_behalf';
|
|
56
|
+
/**
|
|
57
|
+
* Headers to add beside a forwarded user `Authorization` so the peer does not
|
|
58
|
+
* bill the hop a second time. Mint per call (the marker expires in 120 s).
|
|
59
|
+
*
|
|
60
|
+
* The subject defaults to the ambient audit context's VERIFIED principal (the
|
|
61
|
+
* inbound request this call serves). Returns `{}` — the hop is billed normally,
|
|
62
|
+
* the safe direction — when there is no user principal to vouch for, or when
|
|
63
|
+
* this process cannot sign (no service key).
|
|
64
|
+
*/
|
|
65
|
+
export function onBehalfHeaders(subject) {
|
|
66
|
+
const principal = subject ?? ambientSubject();
|
|
67
|
+
if (!principal)
|
|
68
|
+
return {};
|
|
69
|
+
try {
|
|
70
|
+
const token = signServiceJwt({
|
|
71
|
+
type: ON_BEHALF_TOKEN_TYPE,
|
|
72
|
+
principalType: 'service',
|
|
73
|
+
obo: principal.sub,
|
|
74
|
+
organizationId: principal.organizationId,
|
|
75
|
+
jti: randomUUID(),
|
|
76
|
+
}, { serviceName: process.env.SERVICE_NAME || 'api', expiresInSeconds: ON_BEHALF_TTL_SECONDS, ...issuerAudienceOptions() });
|
|
77
|
+
return { [ON_BEHALF_HEADER]: token };
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
logger.debug('On-behalf marker not minted; the peer will meter the hop', { error: String(err) });
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function ambientSubject() {
|
|
85
|
+
const user = currentAuditContext()?.principal?.();
|
|
86
|
+
if (!user || user.principalType === 'service' || !user.sub || !user.organizationId)
|
|
87
|
+
return undefined;
|
|
88
|
+
return { sub: user.sub, organizationId: user.organizationId };
|
|
89
|
+
}
|
|
90
|
+
/** Memo per request: the meter (on `finish`) and the check (in requireAuth) both ask. */
|
|
91
|
+
const verdicts = new WeakMap();
|
|
92
|
+
/**
|
|
93
|
+
* The internal service that vouched for this request with a VALID on-behalf
|
|
94
|
+
* marker, else `undefined`. Requires the request to be authenticated (`req.user`
|
|
95
|
+
* set by requireAuth) — the marker is only meaningful against a verified user.
|
|
96
|
+
*
|
|
97
|
+
* Every rejection of a PRESENT header is counted on
|
|
98
|
+
* `quota_on_behalf_rejected_total{reason}`: a forged header from a user lands
|
|
99
|
+
* there as `invalid` (no service key signs it), and the request is billed.
|
|
100
|
+
*/
|
|
101
|
+
export function onBehalfCaller(req) {
|
|
102
|
+
const memo = verdicts.get(req);
|
|
103
|
+
if (memo !== undefined)
|
|
104
|
+
return memo ?? undefined;
|
|
105
|
+
const verdict = verifyMarker(req);
|
|
106
|
+
verdicts.set(req, verdict);
|
|
107
|
+
return verdict ?? undefined;
|
|
108
|
+
}
|
|
109
|
+
function verifyMarker(req) {
|
|
110
|
+
const raw = req.headers?.[ON_BEHALF_HEADER];
|
|
111
|
+
const token = Array.isArray(raw) ? raw[0] : raw;
|
|
112
|
+
if (!token)
|
|
113
|
+
return null;
|
|
114
|
+
const reject = (reason) => {
|
|
115
|
+
emitCounter('quota_on_behalf_rejected_total', { reason });
|
|
116
|
+
return null;
|
|
117
|
+
};
|
|
118
|
+
const user = req.user;
|
|
119
|
+
if (!user?.sub || !user.organizationId)
|
|
120
|
+
return reject('unauthenticated');
|
|
121
|
+
try {
|
|
122
|
+
const header = decodeJwtHeader(token);
|
|
123
|
+
if (!header?.kid || !isServiceKid(header.kid))
|
|
124
|
+
return reject('invalid');
|
|
125
|
+
const claims = verifyServiceJwt(token, { kid: header.kid, ...issuerAudienceOptions() });
|
|
126
|
+
if (claims.type !== ON_BEHALF_TOKEN_TYPE || claims.principalType !== 'service')
|
|
127
|
+
return reject('invalid');
|
|
128
|
+
const caller = serviceNameOf(claims);
|
|
129
|
+
if (!caller || isServiceTokenDenied(claims))
|
|
130
|
+
return reject('denied');
|
|
131
|
+
if (!ON_BEHALF_CALLERS.includes(caller))
|
|
132
|
+
return reject('caller');
|
|
133
|
+
if (claims.obo !== user.sub)
|
|
134
|
+
return reject('subject');
|
|
135
|
+
if (String(claims.organizationId ?? '').toLowerCase() !== user.organizationId.toLowerCase())
|
|
136
|
+
return reject('org');
|
|
137
|
+
return caller;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return reject('invalid');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib24tYmVoYWxmLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZGRsZXdhcmUvb24tYmVoYWxmLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQThCRztBQUVILE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFcEMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDeEQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzFFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ25FLE9BQU8sRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDN0YsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFekQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBRXpDLHNGQUFzRjtBQUN0RixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUVqRDs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLGlCQUFpQixHQUFzQixDQUFDLEtBQUssRUFBRSxVQUFVLENBQUMsQ0FBQztBQUV4RSxvRkFBb0Y7QUFDcEYsTUFBTSxxQkFBcUIsR0FBRyxHQUFHLENBQUM7QUFFbEMsMEVBQTBFO0FBQzFFLE1BQU0sb0JBQW9CLEdBQUcsV0FBVyxDQUFDO0FBVXpDOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLGVBQWUsQ0FBQyxPQUF5QjtJQUN2RCxNQUFN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ZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBPTi1CRUhBTEYgY2FsbHM6IGEgc2VydmljZSBmb3J3YXJkaW5nIHRoZSBlbmQgdXNlcidzIG93biBiZWFyZXIgdG9rZW4gdG8gYVxuICogcGVlciwgYXMgcGFydCBvZiBhIHJlcXVlc3QgdGhhdCB3YXMgQUxSRUFEWSBtZXRlcmVkIHdoZXJlIGl0IGFycml2ZWQuXG4gKlxuICogVGhlIGFzayBhZ2VudCBhY3RzIHN0cmljdGx5IGFzIHRoZSBjYWxsaW5nIHVzZXIg4oCUIGl0cyB0b29scyBmb3J3YXJkIHRoZVxuICogdXNlcidzIHRva2VuIHNvIHRoZSBwZWVyJ3MgdGVuYW5jeSwgcGVybWlzc2lvbiBhbmQgY29tcGxpYW5jZSBnYXRlcyBhcHBseSBhc1xuICogaWYgdGhlIHVzZXIgaGFkIGNhbGxlZCB0aGVtIOKAlCBhbmQgcGlwZWxpbmUncyBjb25maXJtLXBsYWNlaG9sZGVyLXBsdWdpbnMgZG9lc1xuICogdGhlIHNhbWUgYWdhaW5zdCB0aGUgcGx1Z2luIHNlcnZpY2UuIEVhY2ggb2YgdGhvc2UgaG9wcyBpcyBhIFVTRVIgcmVxdWVzdCB0b1xuICogdGhlIHBlZXIsIHNvIHRoZSBwZWVyJ3MgYGFwaUNhbGxzYCBtZXRlciBiaWxsZWQgaXQ6IG9uZSBhZ2VudCB0dXJuIHdhcyAxMC0yMFxuICogYXBpQ2FsbHMgb24gdG9wIG9mIHRoZSB0dXJuIGl0c2VsZiAod2hpY2ggaXMgbWV0ZXJlZCwgYW5kIEFJLXJlc2VydmVkKS5cbiAqXG4gKiBUaGUgbWFya2VyIHRoYXQgd2FpdmVzIHRoYXQgc2Vjb25kIGNoYXJnZSBoYXMgdG8gYmUgc29tZXRoaW5nIHRoZSBVU0VSIENBTk5PVFxuICogUFJPRFVDRSwgb3IgYW55IG1lbWJlciBjb3VsZCBzdG9wIHBheWluZyBmb3IgQVBJIGNhbGxzIGJ5IHNldHRpbmcgYSBoZWFkZXIuXG4gKiBTbyBpdCBpcyBhIFNJR05FRCBTRVJWSUNFIFRPS0VOICh0aGUgY2FsbGluZyBzZXJ2aWNlJ3Mgb3duIEVTMjU2IGtleSwgdGhlIHNhbWVcbiAqIGtleSBtYXRlcmlhbCBgcmVxdWlyZUF1dGhgIHRydXN0cyBmb3Igc2VydmljZSBwcmluY2lwYWxzKSwgY2FycmllZCBpblxuICoge0BsaW5rIE9OX0JFSEFMRl9IRUFERVJ9IGJlc2lkZSB0aGUgdXNlcidzIHVudG91Y2hlZCBgQXV0aG9yaXphdGlvbmA6XG4gKlxuICogIC0gYHR5cGU6ICdvbl9iZWhhbGYnYCDigJQgbmV2ZXIgYGFjY2Vzc2AsIHNvIHRoZSBtYXJrZXIgaXMgdXNlbGVzcyBhcyBhIGJlYXJlclxuICogICAgdG9rZW4gYW55d2hlcmUgKGByZXF1aXJlQXV0aGAgYW5kIGB2ZXJpZnlTZXJ2aWNlUHJpbmNpcGFsYCBib3RoIGRlbWFuZFxuICogICAgYHR5cGU6ICdhY2Nlc3MnYCk7XG4gKiAgLSBgb2JvYCArIGBvcmdhbml6YXRpb25JZGAg4oCUIEJPVU5EIHRvIHRoZSB1c2VyIGFuZCBvcmcgaXQgdm91Y2hlcyBmb3IsIGFuZFxuICogICAgaG9ub3VyZWQgb25seSB3aGVuIGJvdGggZXF1YWwgdGhlIHJlcXVlc3QncyB2ZXJpZmllZCBgcmVxLnVzZXJgO1xuICogIC0gdGhlIHNpZ25lciBtdXN0IGJlIG9uIHtAbGluayBPTl9CRUhBTEZfQ0FMTEVSU30g4oCUIGEgc2VydmljZSB0aGF0IGZvcndhcmRzXG4gKiAgICB1c2VyIHRva2VucyBieSBkZXNpZ24g4oCUIGFuZCBub3Qgb24gdGhlIHNlcnZpY2UtdG9rZW4gZGVueWxpc3Q7XG4gKiAgLSAxMjAgcyBUVEwsIG1pbnRlZCBwZXIgb3V0Ym91bmQgY2FsbC5cbiAqXG4gKiBXaGF0IGEgdmFsaWQgbWFya2VyIGNoYW5nZXMgaXMgbmFycm93OiB0aGUgYXBpQ2FsbHMvYXV0b21hdGlvbkNhbGxzIE1FVEVSIGFuZFxuICogQ0hFQ0sgc2tpcCB0aGUgcmVxdWVzdCAoYGNhbGxRdW90YUV4ZW1wdGlvbmApLiBUZW5hbmN5LCBwZXJtaXNzaW9ucywgYXVkaXQgYW5kXG4gKiBldmVyeSByZXNlcnZhdGlvbi1nYXRlZCBxdW90YSAoYWlDYWxscywgcGlwZWxpbmVzLCBwbHVnaW5zKSBhcHBseSBleGFjdGx5IGFzXG4gKiBiZWZvcmUg4oCUIGFuIG9uLWJlaGFsZiBgL2dlbmVyYXRlYCBzdGlsbCByZXNlcnZlcyBpdHMgb3duIGFpQ2FsbHMgc2xvdC5cbiAqL1xuXG5pbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSAnY3J5cHRvJztcbmltcG9ydCB0eXBlIHsgUmVxdWVzdCB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgaXNzdWVyQXVkaWVuY2VPcHRpb25zIH0gZnJvbSAnLi9qd3QtdmVyaWZ5LmpzJztcbmltcG9ydCB7IGlzU2VydmljZVRva2VuRGVuaWVkLCBzZXJ2aWNlTmFtZU9mIH0gZnJvbSAnLi9zZXJ2aWNlLXRva2Vucy5qcyc7XG5pbXBvcnQgeyBjdXJyZW50QXVkaXRDb250ZXh0IH0gZnJvbSAnLi4vc2VydmljZXMvYXVkaXQtY29udGV4dC5qcyc7XG5pbXBvcnQgeyBpc1NlcnZpY2VLaWQsIHNpZ25TZXJ2aWNlSnd0LCB2ZXJpZnlTZXJ2aWNlSnd0IH0gZnJvbSAnLi4vc2VydmljZXMvc2VydmljZS1rZXlzLmpzJztcbmltcG9ydCB7IGRlY29kZUp3dEhlYWRlciB9IGZyb20gJy4uL3V0aWxzL2p3ay5qcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZW1pdENvdW50ZXIgfSBmcm9tICcuLi91dGlscy9tZXRyaWMtZW1pdHRlci5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignb24tYmVoYWxmJyk7XG5cbi8qKiBUaGUgaGVhZGVyIGNhcnJ5aW5nIHRoZSBzaWduZWQgb24tYmVoYWxmIG1hcmtlciAobG93ZXItY2FzZSwgYXMgTm9kZSByZWFkcyBpdCkuICovXG5leHBvcnQgY29uc3QgT05fQkVIQUxGX0hFQURFUiA9ICd4LXBiLW9uLWJlaGFsZic7XG5cbi8qKlxuICogU2VydmljZXMgd2hvc2Ugb24tYmVoYWxmIG1hcmtlciBpcyBob25vdXJlZDogdGhlIG9uZXMgdGhhdCBmb3J3YXJkIGEgdXNlcidzXG4gKiB0b2tlbiBhcyBhIG1hdHRlciBvZiBkZXNpZ24uIEEgbWFya2VyIHNpZ25lZCBieSBhbnkgb3RoZXIgc2VydmljZSDigJQgdmFsaWRcbiAqIHNpZ25hdHVyZSBvciBub3Qg4oCUIGlzIGlnbm9yZWQsIHNvIGEgY29tcHJvbWlzZWQgcGVlciB0aGF0IG5ldmVyIGZvcndhcmRzIHVzZXJcbiAqIHRva2VucyBjYW5ub3Qgc3RhcnQgd2FpdmluZyBpdHMgdGVuYW50cycgbWV0ZXJzLlxuICovXG5leHBvcnQgY29uc3QgT05fQkVIQUxGX0NBTExFUlM6IHJlYWRvbmx5IHN0cmluZ1tdID0gWydhc2snLCAncGlwZWxpbmUnXTtcblxuLyoqIE1hcmtlciBsaWZldGltZS4gTWludGVkIHBlciBvdXRib3VuZCBjYWxsLCBzbyBpdCBvbmx5IGhhcyB0byBvdXRsaXZlIG9uZSBob3AuICovXG5jb25zdCBPTl9CRUhBTEZfVFRMX1NFQ09ORFMgPSAxMjA7XG5cbi8qKiBUaGUgYHR5cGVgIGNsYWltIHRoYXQgbWFrZXMgdGhlIG1hcmtlciB1bnVzYWJsZSBhcyBhbiBhY2Nlc3MgdG9rZW4uICovXG5jb25zdCBPTl9CRUhBTEZfVE9LRU5fVFlQRSA9ICdvbl9iZWhhbGYnO1xuXG4vKiogV2hvIGEgbWFya2VyIHZvdWNoZXMgZm9yLiBEZWZhdWx0cyB0byB0aGUgYW1iaWVudCByZXF1ZXN0J3MgdmVyaWZpZWQgcHJpbmNpcGFsLiAqL1xuZXhwb3J0IGludGVyZmFjZSBPbkJlaGFsZlN1YmplY3Qge1xuICAvKiogVGhlIHVzZXIgKGBzdWJgKSB3aG9zZSB0b2tlbiByaWRlcyB0aGUgc2FtZSByZXF1ZXN0LiAqL1xuICBzdWI6IHN0cmluZztcbiAgLyoqIFRoZWlyIGFjdGl2ZSBvcmcuICovXG4gIG9yZ2FuaXphdGlvbklkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogSGVhZGVycyB0byBhZGQgYmVzaWRlIGEgZm9yd2FyZGVkIHVzZXIgYEF1dGhvcml6YXRpb25gIHNvIHRoZSBwZWVyIGRvZXMgbm90XG4gKiBiaWxsIHRoZSBob3AgYSBzZWNvbmQgdGltZS4gTWludCBwZXIgY2FsbCAodGhlIG1hcmtlciBleHBpcmVzIGluIDEyMCBzKS5cbiAqXG4gKiBUaGUgc3ViamVjdCBkZWZhdWx0cyB0byB0aGUgYW1iaWVudCBhdWRpdCBjb250ZXh0J3MgVkVSSUZJRUQgcHJpbmNpcGFsICh0aGVcbiAqIGluYm91bmQgcmVxdWVzdCB0aGlzIGNhbGwgc2VydmVzKS4gUmV0dXJucyBge31gIOKAlCB0aGUgaG9wIGlzIGJpbGxlZCBub3JtYWxseSxcbiAqIHRoZSBzYWZlIGRpcmVjdGlvbiDigJQgd2hlbiB0aGVyZSBpcyBubyB1c2VyIHByaW5jaXBhbCB0byB2b3VjaCBmb3IsIG9yIHdoZW5cbiAqIHRoaXMgcHJvY2VzcyBjYW5ub3Qgc2lnbiAobm8gc2VydmljZSBrZXkpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gb25CZWhhbGZIZWFkZXJzKHN1YmplY3Q/OiBPbkJlaGFsZlN1YmplY3QpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3QgcHJpbmNpcGFsID0gc3ViamVjdCA/PyBhbWJpZW50U3ViamVjdCgpO1xuICBpZiAoIXByaW5jaXBhbCkgcmV0dXJuIHt9O1xuICB0cnkge1xuICAgIGNvbnN0IHRva2VuID0gc2lnblNlcnZpY2VKd3QoXG4gICAgICB7XG4gICAgICAgIHR5cGU6IE9OX0JFSEFMRl9UT0tFTl9UWVBFLFxuICAgICAgICBwcmluY2lwYWxUeXBlOiAnc2VydmljZScsXG4gICAgICAgIG9ibzogcHJpbmNpcGFsLnN1YixcbiAgICAgICAgb3JnYW5pemF0aW9uSWQ6IHByaW5jaXBhbC5vcmdhbml6YXRpb25JZCxcbiAgICAgICAganRpOiByYW5kb21VVUlEKCksXG4gICAgICB9LFxuICAgICAgeyBzZXJ2aWNlTmFtZTogcHJvY2Vzcy5lbnYuU0VSVklDRV9OQU1FIHx8ICdhcGknLCBleHBpcmVzSW5TZWNvbmRzOiBPTl9CRUhBTEZfVFRMX1NFQ09ORFMsIC4uLmlzc3VlckF1ZGllbmNlT3B0aW9ucygpIH0sXG4gICAgKTtcbiAgICByZXR1cm4geyBbT05fQkVIQUxGX0hFQURFUl06IHRva2VuIH07XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci5kZWJ1ZygnT24tYmVoYWxmIG1hcmtlciBub3QgbWludGVkOyB0aGUgcGVlciB3aWxsIG1ldGVyIHRoZSBob3AnLCB7IGVycm9yOiBTdHJpbmcoZXJyKSB9KTtcbiAgICByZXR1cm4ge307XG4gIH1cbn1cblxuZnVuY3Rpb24gYW1iaWVudFN1YmplY3QoKTogT25CZWhhbGZTdWJqZWN0IHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgdXNlciA9IGN1cnJlbnRBdWRpdENvbnRleHQoKT8ucHJpbmNpcGFsPy4oKTtcbiAgaWYgKCF1c2VyIHx8IHVzZXIucHJpbmNpcGFsVHlwZSA9PT0gJ3NlcnZpY2UnIHx8ICF1c2VyLnN1YiB8fCAhdXNlci5vcmdhbml6YXRpb25JZCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIHsgc3ViOiB1c2VyLnN1Yiwgb3JnYW5pemF0aW9uSWQ6IHVzZXIub3JnYW5pemF0aW9uSWQgfTtcbn1cblxuLyoqIE1lbW8gcGVyIHJlcXVlc3Q6IHRoZSBtZXRlciAob24gYGZpbmlzaGApIGFuZCB0aGUgY2hlY2sgKGluIHJlcXVpcmVBdXRoKSBib3RoIGFzay4gKi9cbmNvbnN0IHZlcmRpY3RzID0gbmV3IFdlYWtNYXA8UmVxdWVzdCwgc3RyaW5nIHwgbnVsbD4oKTtcblxuLyoqXG4gKiBUaGUgaW50ZXJuYWwgc2VydmljZSB0aGF0IHZvdWNoZWQgZm9yIHRoaXMgcmVxdWVzdCB3aXRoIGEgVkFMSUQgb24tYmVoYWxmXG4gKiBtYXJrZXIsIGVsc2UgYHVuZGVmaW5lZGAuIFJlcXVpcmVzIHRoZSByZXF1ZXN0IHRvIGJlIGF1dGhlbnRpY2F0ZWQgKGByZXEudXNlcmBcbiAqIHNldCBieSByZXF1aXJlQXV0aCkg4oCUIHRoZSBtYXJrZXIgaXMgb25seSBtZWFuaW5nZnVsIGFnYWluc3QgYSB2ZXJpZmllZCB1c2VyLlxuICpcbiAqIEV2ZXJ5IHJlamVjdGlvbiBvZiBhIFBSRVNFTlQgaGVhZGVyIGlzIGNvdW50ZWQgb25cbiAqIGBxdW90YV9vbl9iZWhhbGZfcmVqZWN0ZWRfdG90YWx7cmVhc29ufWA6IGEgZm9yZ2VkIGhlYWRlciBmcm9tIGEgdXNlciBsYW5kc1xuICogdGhlcmUgYXMgYGludmFsaWRgIChubyBzZXJ2aWNlIGtleSBzaWducyBpdCksIGFuZCB0aGUgcmVxdWVzdCBpcyBiaWxsZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBvbkJlaGFsZkNhbGxlcihyZXE6IFJlcXVlc3QpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCBtZW1vID0gdmVyZGljdHMuZ2V0KHJlcSk7XG4gIGlmIChtZW1vICE9PSB1bmRlZmluZWQpIHJldHVybiBtZW1vID8/IHVuZGVmaW5lZDtcbiAgY29uc3QgdmVyZGljdCA9IHZlcmlmeU1hcmtlcihyZXEpO1xuICB2ZXJkaWN0cy5zZXQocmVxLCB2ZXJkaWN0KTtcbiAgcmV0dXJuIHZlcmRpY3QgPz8gdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiB2ZXJpZnlNYXJrZXIocmVxOiBSZXF1ZXN0KTogc3RyaW5nIHwgbnVsbCB7XG4gIGNvbnN0IHJhdyA9IHJlcS5oZWFkZXJzPy5bT05fQkVIQUxGX0hFQURFUl07XG4gIGNvbnN0IHRva2VuID0gQXJyYXkuaXNBcnJheShyYXcpID8gcmF3WzBdIDogcmF3O1xuICBpZiAoIXRva2VuKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgcmVqZWN0ID0gKHJlYXNvbjogc3RyaW5nKTogbnVsbCA9PiB7XG4gICAgZW1pdENvdW50ZXIoJ3F1b3RhX29uX2JlaGFsZl9yZWplY3RlZF90b3RhbCcsIHsgcmVhc29uIH0pO1xuICAgIHJldHVybiBudWxsO1xuICB9O1xuICBjb25zdCB1c2VyID0gcmVxLnVzZXI7XG4gIGlmICghdXNlcj8uc3ViIHx8ICF1c2VyLm9yZ2FuaXphdGlvbklkKSByZXR1cm4gcmVqZWN0KCd1bmF1dGhlbnRpY2F0ZWQnKTtcbiAgdHJ5IHtcbiAgICBjb25zdCBoZWFkZXIgPSBkZWNvZGVKd3RIZWFkZXIodG9rZW4pO1xuICAgIGlmICghaGVhZGVyPy5raWQgfHwgIWlzU2VydmljZUtpZChoZWFkZXIua2lkKSkgcmV0dXJuIHJlamVjdCgnaW52YWxpZCcpO1xuICAgIGNvbnN0IGNsYWltcyA9IHZlcmlmeVNlcnZpY2VKd3Q8eyB0eXBlPzogc3RyaW5nOyBwcmluY2lwYWxUeXBlPzogc3RyaW5nOyBzdWI/OiBzdHJpbmc7IG9ibz86IHN0cmluZzsgb3JnYW5pemF0aW9uSWQ/OiBzdHJpbmcgfT4oXG4gICAgICB0b2tlbiwgeyBraWQ6IGhlYWRlci5raWQsIC4uLmlzc3VlckF1ZGllbmNlT3B0aW9ucygpIH0sXG4gICAgKTtcbiAgICBpZiAoY2xhaW1zLnR5cGUgIT09IE9OX0JFSEFMRl9UT0tFTl9UWVBFIHx8IGNsYWltcy5wcmluY2lwYWxUeXBlICE9PSAnc2VydmljZScpIHJldHVybiByZWplY3QoJ2ludmFsaWQnKTtcbiAgICBjb25zdCBjYWxsZXIgPSBzZXJ2aWNlTmFtZU9mKGNsYWltcyk7XG4gICAgaWYgKCFjYWxsZXIgfHwgaXNTZXJ2aWNlVG9rZW5EZW5pZWQoY2xhaW1zKSkgcmV0dXJuIHJlamVjdCgnZGVuaWVkJyk7XG4gICAgaWYgKCFPTl9CRUhBTEZfQ0FMTEVSUy5pbmNsdWRlcyhjYWxsZXIpKSByZXR1cm4gcmVqZWN0KCdjYWxsZXInKTtcbiAgICBpZiAoY2xhaW1zLm9ibyAhPT0gdXNlci5zdWIpIHJldHVybiByZWplY3QoJ3N1YmplY3QnKTtcbiAgICBpZiAoU3RyaW5nKGNsYWltcy5vcmdhbml6YXRpb25JZCA/PyAnJykudG9Mb3dlckNhc2UoKSAhPT0gdXNlci5vcmdhbml6YXRpb25JZC50b0xvd2VyQ2FzZSgpKSByZXR1cm4gcmVqZWN0KCdvcmcnKTtcbiAgICByZXR1cm4gY2FsbGVyO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gcmVqZWN0KCdpbnZhbGlkJyk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* `authz.denied` audit sink they report refusals to.
|
|
4
4
|
*/
|
|
5
5
|
import type { Request, Response, NextFunction } from 'express';
|
|
6
|
+
import { type AuditAuthBlock } from '../services/audit-context.js';
|
|
6
7
|
import { type Permission } from '../types/permissions.js';
|
|
7
8
|
/**
|
|
8
9
|
* Whether the request's user holds `permission`. Superadmins implicitly hold
|
|
@@ -26,6 +27,16 @@ export interface AuthzDenialInfo {
|
|
|
26
27
|
path: string;
|
|
27
28
|
/** What was required: the missing permission(s), or 'system-admin'. */
|
|
28
29
|
required: string;
|
|
30
|
+
/** Client ip (`req.ip`, proxy-resolved). */
|
|
31
|
+
ip?: string;
|
|
32
|
+
/** Sanitized, length-capped User-Agent. */
|
|
33
|
+
userAgent?: string;
|
|
34
|
+
/** The request's correlation id (the ambient audit context's, else a valid `X-Request-Id`). */
|
|
35
|
+
requestId?: string;
|
|
36
|
+
/** The real sysadmin behind an impersonation token, from the verified token. */
|
|
37
|
+
impersonatorId?: string;
|
|
38
|
+
/** The credential that was refused (key id, session, scope, …) — the `_auth` block. */
|
|
39
|
+
auth?: AuditAuthBlock;
|
|
29
40
|
}
|
|
30
41
|
/**
|
|
31
42
|
* Register (or clear, with `undefined`) the process-wide authorization-denial
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { tagRouteGate } from './route-table.js';
|
|
4
4
|
import { isServicePrincipal, serviceNameOf } from './service-tokens.js';
|
|
5
5
|
import { HttpStatus } from '../constants/http-status.js';
|
|
6
|
+
import { auditAuthBlock, currentAuditContext, sanitizeCorrelationId, sanitizeUserAgent } from '../services/audit-context.js';
|
|
6
7
|
import { serviceIdentity } from '../services/service-keys.js';
|
|
7
8
|
import { ErrorCode } from '../types/error-codes.js';
|
|
8
9
|
import { hasPermission } from '../types/permissions.js';
|
|
@@ -60,6 +61,11 @@ export function recordAuthzDenial(req, required) {
|
|
|
60
61
|
// query param, and this path is persisted verbatim into the audit log.
|
|
61
62
|
path: (req.originalUrl || req.url).split('?')[0],
|
|
62
63
|
required,
|
|
64
|
+
ip: req.ip,
|
|
65
|
+
userAgent: sanitizeUserAgent(req.headers?.['user-agent']),
|
|
66
|
+
requestId: currentAuditContext()?.requestId ?? sanitizeCorrelationId(req.headers?.['x-request-id']),
|
|
67
|
+
impersonatorId: req.user?.impersonatorId,
|
|
68
|
+
auth: auditAuthBlock(req.user),
|
|
63
69
|
});
|
|
64
70
|
}
|
|
65
71
|
catch {
|
|
@@ -257,4 +263,4 @@ export function requireFeature(feature) {
|
|
|
257
263
|
next();
|
|
258
264
|
}, { kind: 'feature', feature });
|
|
259
265
|
}
|
|
260
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVybWlzc2lvbi1nYXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL3Blcm1pc3Npb24tZ2F0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQVF0QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDOUQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3BELE9BQU8sRUFBbUIsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDekUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFakQsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLGlCQUFpQixDQUFDLENBQUM7QUFDL0M7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxHQUFZLEVBQUUsVUFBc0I7SUFDcEUsT0FBTyxhQUFhLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsVUFBVSxFQUFFLEdBQUcsQ0FBQyxJQUFJLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFDbEYsQ0FBQztBQW9CRDs7Ozs7OztHQU9HO0FBQ0gsSUFBSSxrQkFBaUUsQ0FBQztBQUV0RTs7O0dBR0c7QUFDSCxNQUFNLFVBQVUscUJBQXFCLENBQUMsRUFBaUQ7SUFDckYsa0JBQWtCLEdBQUcsRUFBRSxDQUFDO0FBQzFCLENBQUM7QUFF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QUMsSUFBSSxDQUFDLFlBQVksS0FBSyxJQUFJO1lBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQztRQUVsRCxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDMUMsNERBQTREO1lBQzVELDJEQUEyRDtZQUMzRCxzRUFBc0U7WUFDdEUsaUJBQWlCLENBQUMsR0FBRyxFQUFFLFdBQVcsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUM3QyxPQUFPLFNBQVMsQ0FDZCxHQUFHLEVBQUUsVUFBVSxDQUFDLFNBQVMsRUFDekIsd0NBQXdDLE9BQU8sR0FBRyxFQUNsRCxTQUFTLENBQUMsd0JBQXdCLENBQ25DLENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxFQUFFLENBQUM7SUFDVCxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7QUFDbkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIEF1dGhvcml6YXRpb24gZ2F0ZXMg4oCUIHBlcm1pc3Npb25zLCBzeXN0ZW0gYWRtaW4sIGZlYXR1cmVzIOKAlCBhbmQgdGhlXG4gKiBgYXV0aHouZGVuaWVkYCBhdWRpdCBzaW5rIHRoZXkgcmVwb3J0IHJlZnVzYWxzIHRvLlxuICovXG5cbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UsIE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgdGFnUm91dGVHYXRlIH0gZnJvbSAnLi9yb3V0ZS10YWJsZS5qcyc7XG5pbXBvcnQgeyBpc1NlcnZpY2VQcmluY2lwYWwsIHNlcnZpY2VOYW1lT2YgfSBmcm9tICcuL3NlcnZpY2UtdG9rZW5zLmpzJztcbmltcG9ydCB7IEh0dHBTdGF0dXMgfSBmcm9tICcuLi9jb25zdGFudHMvaHR0cC1zdGF0dXMuanMnO1xuaW1wb3J0IHsgc2VydmljZUlkZW50aXR5IH0gZnJvbSAnLi4vc2VydmljZXMvc2VydmljZS1rZXlzLmpzJztcbmltcG9ydCB7IEVycm9yQ29kZSB9IGZyb20gJy4uL3R5cGVzL2Vycm9yLWNvZGVzLmpzJztcbmltcG9ydCB7IHR5cGUgUGVybWlzc2lvbiwgaGFzUGVybWlzc2lvbiB9IGZyb20gJy4uL3R5cGVzL3Blcm1pc3Npb25zLmpzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBlbWl0Q291bnRlciB9IGZyb20gJy4uL3V0aWxzL21ldHJpYy1lbWl0dGVyLmpzJztcbmltcG9ydCB7IHNlbmRFcnJvciB9IGZyb20gJy4uL3V0aWxzL3Jlc3BvbnNlLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdhdXRoLW1pZGRsZXdhcmUnKTtcbi8qKlxuICogV2hldGhlciB0aGUgcmVxdWVzdCdzIHVzZXIgaG9sZHMgYHBlcm1pc3Npb25gLiBTdXBlcmFkbWlucyBpbXBsaWNpdGx5IGhvbGRcbiAqIGV2ZXJ5IHBlcm1pc3Npb24uIFJlYWRzIHRoZSByZXNvbHZlZCBgcGVybWlzc2lvbnNgIGNsYWltIChzZXQgYXQgdG9rZW4gaXNzdWUsXG4gKiBvciByZS1kZXJpdmVkIHBlciByZXF1ZXN0IGJ5IHRoZSBwbGF0Zm9ybSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VySGFzUGVybWlzc2lvbihyZXE6IFJlcXVlc3QsIHBlcm1pc3Npb246IFBlcm1pc3Npb24pOiBib29sZWFuIHtcbiAgcmV0dXJuIGhhc1Blcm1pc3Npb24ocmVxLnVzZXI/LnBlcm1pc3Npb25zLCBwZXJtaXNzaW9uLCByZXEudXNlcj8uaXNTdXBlckFkbWluKTtcbn1cblxuLyoqXG4gKiBDb250ZXh0IHBhc3NlZCB0byBhIHJlZ2lzdGVyZWQgYXV0aG9yaXphdGlvbi1kZW5pYWwgYXVkaXRvciB3aGVuIGFcbiAqIHN0YXRlLWNoYW5naW5nIHJlcXVlc3QgaXMgcmVqZWN0ZWQgYnkgYHJlcXVpcmVQZXJtaXNzaW9uYCAvXG4gKiBgcmVxdWlyZVN5c3RlbUFkbWluYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBBdXRoekRlbmlhbEluZm8ge1xuICAvKiogVGhlIGRlbmllZCB1c2VyJ3MgaWQgKGBzdWJgKSwgaWYgYXV0aGVudGljYXRlZC4gKi9cbiAgYWN0b3JJZD86IHN0cmluZztcbiAgYWN0b3JFbWFpbD86IHN0cmluZztcbiAgLyoqIFRoZSB1c2VyJ3MgYWN0aXZlIG9yZyBhdCBkZW5pYWwgdGltZS4gKi9cbiAgb3JnSWQ/OiBzdHJpbmc7XG4gIC8qKiBIVFRQIG1ldGhvZCArIHBhdGggb2YgdGhlIHJlamVjdGVkIHJlcXVlc3QuICovXG4gIG1ldGhvZDogc3RyaW5nO1xuICBwYXRoOiBzdHJpbmc7XG4gIC8qKiBXaGF0IHdhcyByZXF1aXJlZDogdGhlIG1pc3NpbmcgcGVybWlzc2lvbihzKSwgb3IgJ3N5c3RlbS1hZG1pbicuICovXG4gIHJlcXVpcmVkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9uYWwgc2luayBmb3IgZGVuaWVkLWF1dGhvcml6YXRpb24gZXZlbnRzLiBMZWZ0IHVuc2V0IGJ5IGRlZmF1bHQgc29cbiAqIGFwaS1jb3JlIHN0YXlzIGRlY291cGxlZCBmcm9tIGFueSBhdWRpdCB0cmFuc3BvcnQg4oCUIGEgc2VydmljZSByZWdpc3RlcnMgb25lXG4gKiBhdCBib290ICh0eXBpY2FsbHkgZm9yd2FyZGluZyB0byBpdHMgYFJlbW90ZUF1ZGl0Q2xpZW50YCBhcyBhblxuICogYGF1dGh6LmRlbmllZGAgZXZlbnQsIG9yLCBvbiBwbGF0Zm9ybSwgdG8gdGhlIGxvY2FsIGBhdWRpdCgpYCBoZWxwZXIpLlxuICogTVVTVCBiZSBiZXN0LWVmZm9ydDogaXQgaXMgaW52b2tlZCBpbnNpZGUgdGhlIHJlcXVlc3QgcGF0aCwgc28gaXQgbXVzdCBuZXZlclxuICogdGhyb3cgb3IgYmxvY2sgKHRoZSBnYXRlIHdyYXBzIHRoZSBjYWxsIGluIHRyeS9jYXRjaCByZWdhcmRsZXNzKS5cbiAqL1xubGV0IGF1dGh6RGVuaWFsQXVkaXRvcjogKChpbmZvOiBBdXRoekRlbmlhbEluZm8pID0+IHZvaWQpIHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIFJlZ2lzdGVyIChvciBjbGVhciwgd2l0aCBgdW5kZWZpbmVkYCkgdGhlIHByb2Nlc3Mtd2lkZSBhdXRob3JpemF0aW9uLWRlbmlhbFxuICogYXVkaXRvci4gSWRlbXBvdGVudDsgdGhlIGxhc3QgcmVnaXN0cmF0aW9uIHdpbnMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXRBdXRoekRlbmlhbEF1ZGl0b3IoZm46ICgoaW5mbzogQXV0aHpEZW5pYWxJbmZvKSA9PiB2b2lkKSB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICBhdXRoekRlbmlhbEF1ZGl0b3IgPSBmbjtcbn1cblxuLyoqXG4gKiBFbWl0IGEgZGVuaWFsIGV2ZW50LCBiZXN0LWVmZm9ydC4gT25seSBmaXJlcyBmb3Igc3RhdGUtY2hhbmdpbmcgKG5vbi1HRVQsXG4gKiBub24tSEVBRC9PUFRJT05TKSByZXF1ZXN0cyDigJQgYSByZWplY3RlZCBHRVQgaXMgbG93LXNpZ25hbCBwcm9iaW5nIG5vaXNlIGFuZFxuICogd291bGQgYW1wbGlmeSBhdWRpdCB2b2x1bWUgdW5kZXIgYSBzY2FuLiBOZXZlciB0aHJvd3MuXG4gKlxuICogVGhlIHBlcm1pc3Npb24gZ2F0ZXMgaGVyZSBjYWxsIGl0IHRoZW1zZWx2ZXMuIEV4cG9ydCBpdCBmb3IgZGF0YS1kcml2ZW4gY2hlY2tzXG4gKiBhIHJvdXRlIG1ha2VzIGlubGluZSAoY3Jvc3Mtb3JnIGFjY2Vzcywgc2VydmljZS1vbmx5IGVuZHBvaW50cyksIHNvIHRob3NlIDQwM3NcbiAqIHJlYWNoIHRoZSBzYW1lIGBhdXRoei5kZW5pZWRgIHRyYWlsLiBgcmVxdWlyZWRgIG5hbWVzIHdoYXQgd2FzIG1pc3NpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWNvcmRBdXRoekRlbmlhbChyZXE6IFJlcXVlc3QsIHJlcXVpcmVkOiBzdHJpbmcpOiB2b2lkIHtcbiAgY29uc3QgYXVkaXRvciA9IGF1dGh6RGVuaWFsQXVkaXRvcjtcbiAgaWYgKCFhdWRpdG9yKSByZXR1cm47XG4gIGNvbnN0IG1ldGhvZCA9IHJlcS5tZXRob2QudG9VcHBlckNhc2UoKTtcbiAgaWYgKG1ldGhvZCA9PT0gJ0dFVCcgfHwgbWV0aG9kID09PSAnSEVBRCcgfHwgbWV0aG9kID09PSAnT1BUSU9OUycpIHJldHVybjtcbiAgdHJ5IHtcbiAgICBhdWRpdG9yKHtcbiAgICAgIGFjdG9ySWQ6IHJlcS51c2VyPy5zdWIsXG4gICAgICBhY3RvckVtYWlsOiByZXEudXNlcj8uZW1haWwsXG4gICAgICBvcmdJZDogcmVxLnVzZXI/Lm9yZ2FuaXphdGlvbklkLFxuICAgICAgbWV0aG9kLFxuICAgICAgLy8gU3RyaXAgdGhlIHF1ZXJ5IHN0cmluZyDigJQgYSBkZW5pZWQgcmVxdWVzdCBtYXkgY2FycnkgYSB0b2tlbi9zZWNyZXQgYXMgYVxuICAgICAgLy8gcXVlcnkgcGFyYW0sIGFuZCB0aGlzIHBhdGggaXMgcGVyc2lzdGVkIHZlcmJhdGltIGludG8gdGhlIGF1ZGl0IGxvZy5cbiAgICAgIHBhdGg6IChyZXEub3JpZ2luYWxVcmwgfHwgcmVxLnVybCkuc3BsaXQoJz8nKVswXSxcbiAgICAgIHJlcXVpcmVkLFxuICAgIH0pO1xuICB9IGNhdGNoIHtcbiAgICAvLyBCZXN0LWVmZm9ydCDigJQgYSBicm9rZW4gYXVkaXRvciBtdXN0IG5ldmVyIGJyZWFrIHRoZSBhdXRoIGdhdGUuXG4gIH1cbn1cblxuLyoqIFRoZSBzaGFyZWQgZ2F0ZSBwcmVhbWJsZTogYW5zd2VyIDQwMSBhbmQgcmV0dXJuIGZhbHNlIHdoZW4gdW5hdXRoZW50aWNhdGVkLiAqL1xuZnVuY3Rpb24gcmVxdWlyZVVzZXIocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKTogcmVxIGlzIFJlcXVlc3QgJiB7IHVzZXI6IE5vbk51bGxhYmxlPFJlcXVlc3RbJ3VzZXInXT4gfSB7XG4gIGlmIChyZXEudXNlcikgcmV0dXJuIHRydWU7XG4gIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKiogQXVkaXQgKyBhbnN3ZXIgYSBwZXJtaXNzaW9uIHJlZnVzYWwgKGBtaXNzaW5nYCBkZWZhdWx0cyB0byBldmVyeSByZXF1aXJlZCBwZXJtaXNzaW9uKS4gKi9cbmZ1bmN0aW9uIGRlbnlQZXJtaXNzaW9uKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgcGVybWlzc2lvbnM6IFBlcm1pc3Npb25bXSwgbW9kZTogJ29yJyB8ICdhbmQnLCBtaXNzaW5nOiBQZXJtaXNzaW9uW10gPSBwZXJtaXNzaW9ucyk6IHZvaWQge1xuICByZWNvcmRBdXRoekRlbmlhbChyZXEsIHBlcm1pc3Npb25zLmpvaW4oYCAke21vZGV9IGApKTtcbiAgc2VuZEVycm9yKFxuICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgYE1pc3NpbmcgcmVxdWlyZWQgcGVybWlzc2lvbjogJHttaXNzaW5nLmpvaW4oYCAke21vZGV9IGApfWAsXG4gICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgKTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlcyB0aGF0IHRoZSB1c2VyIGhvbGQgQVQgTEVBU1QgT05FIG9mIHRoZSBnaXZlbiBwZXJtaXNzaW9ucyAob3IgYmUgYVxuICogc3VwZXJhZG1pbikuIFVzZSBhZnRlciByZXF1aXJlQXV0aC4gTWlycm9ycyBgcmVxdWlyZVJvbGVgJ3MgYW55LW9mIHNlbWFudGljcztcbiAqIHBhc3MgYSBzaW5nbGUgcGVybWlzc2lvbiBmb3IgYSBzcGVjaWZpYyBhY3Rpb24sIG9yIHNldmVyYWwgd2hlbiBhbnkgb25lIG9mXG4gKiB0aGVtIHNob3VsZCBncmFudCBhY2Nlc3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlUGVybWlzc2lvbiguLi5wZXJtaXNzaW9uczogUGVybWlzc2lvbltdKSB7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXF1aXJlVXNlcihyZXEsIHJlcykpIHJldHVybjtcbiAgICAvLyB1c2VySGFzUGVybWlzc2lvbiDihpIgaGFzUGVybWlzc2lvbiBhbHJlYWR5IGdyYW50cyBzdXBlcmFkbWlucyBldmVyeVxuICAgIC8vIHBlcm1pc3Npb24sIHNvIHRoaXMgc2luZ2xlIGNoZWNrIGNvdmVycyBib3RoIHRoZSBzdXBlcmFkbWluIGJ5cGFzcyBhbmRcbiAgICAvLyB0aGUgYW55LW9mIG1lbWJlcnNoaXAgdGVzdCB3aXRob3V0IHJlLWlubGluaW5nIGVpdGhlci5cbiAgICBpZiAocGVybWlzc2lvbnMuc29tZSgocCkgPT4gdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSkpIHJldHVybiBuZXh0KCk7XG4gICAgZGVueVBlcm1pc3Npb24ocmVxLCByZXMsIHBlcm1pc3Npb25zLCAnb3InKTtcbiAgfSwgeyBraW5kOiAncGVybWlzc2lvbicsIG1vZGU6ICdhbnknLCBwZXJtaXNzaW9ucyB9KTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlcyB0aGF0IHRoZSB1c2VyIGhvbGQgRVZFUlkgb25lIG9mIHRoZSBnaXZlbiBwZXJtaXNzaW9ucyAob3IgYmUgYVxuICogc3VwZXJhZG1pbikg4oCUIHRoZSBBTkQgY291bnRlcnBhcnQgdG8gYHJlcXVpcmVQZXJtaXNzaW9uYCdzIGFueS1vZi4gVXNlIGZvciBhXG4gKiBzZW5zaXRpdmUgYWN0aW9uIHRoYXQgbGVnaXRpbWF0ZWx5IGRlbWFuZHMgdHdvIGRpc3RpbmN0IGNhcGFiaWxpdGllcyBhdCBvbmNlXG4gKiAoZS5nLiBhIGNyb3NzLXN1cmZhY2Ugb3BlcmF0aW9uKSwgc28gdGhlIGd1YXJhbnRlZSBpcyBleHBsaWNpdCByYXRoZXIgdGhhblxuICogYXBwcm94aW1hdGVkIGJ5IGNoYWluaW5nIHR3byBgcmVxdWlyZVBlcm1pc3Npb25gIGdhdGVzLiBTdXBlcmFkbWlucyBieXBhc3NcbiAqICh0aGV5IGltcGxpY2l0bHkgaG9sZCBldmVyeSBwZXJtaXNzaW9uKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBbGxQZXJtaXNzaW9ucyguLi5wZXJtaXNzaW9uczogUGVybWlzc2lvbltdKSB7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXF1aXJlVXNlcihyZXEsIHJlcykpIHJldHVybjtcbiAgICBjb25zdCBtaXNzaW5nID0gcGVybWlzc2lvbnMuZmlsdGVyKChwKSA9PiAhdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSk7XG4gICAgaWYgKG1pc3NpbmcubGVuZ3RoID09PSAwKSByZXR1cm4gbmV4dCgpO1xuICAgIGRlbnlQZXJtaXNzaW9uKHJlcSwgcmVzLCBwZXJtaXNzaW9ucywgJ2FuZCcsIG1pc3NpbmcpO1xuICB9LCB7IGtpbmQ6ICdwZXJtaXNzaW9uJywgbW9kZTogJ2FsbCcsIHBlcm1pc3Npb25zIH0pO1xufVxuXG4vKipcbiAqIExpa2Uge0BsaW5rIHJlcXVpcmVQZXJtaXNzaW9ufSAoYW55LW9mKSBidXQgQUxTTyBhZG1pdHMgYW4gaW50ZXJuYWwgc2VydmljZVxuICogcHJpbmNpcGFsIChgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCkuIEZvciBSRUFEIGVuZHBvaW50cyB0aGF0IEJPVEhcbiAqIGludGVyYWN0aXZlIHVzZXJzIOKAlCB3aG8gbXVzdCBob2xkIG9uZSBvZiB0aGUgYDpyZWFkYCBjYXBhYmlsaXRpZXMg4oCUIEFORFxuICogc2VydmljZS10by1zZXJ2aWNlIGNhbGxlcnMgbGVnaXRpbWF0ZWx5IGhpdDsgc2VydmljZSB0b2tlbnMgY2Fycnkgbm9cbiAqIHBlcm1pc3Npb24gY2xhaW1zICh0aGV5J3JlIGxlYXN0LXByaXZpbGVnZSBgcm9sZTptZW1iZXJgKSwgc28gYSBwbGFpblxuICogYHJlcXVpcmVQZXJtaXNzaW9uYCB3b3VsZCB3cm9uZ2x5IDQwMyB0aGVtLiBTdXBlcmFkbWlucyBwYXNzIHZpYVxuICogYHVzZXJIYXNQZXJtaXNzaW9uYCdzIGltcGxpY2l0LWFsbC4gVXNlIG9ubHkgd2hlcmUgYSBzZXJ2aWNlIGNhbGxlciBpcyBhIGtub3duLFxuICogaW50ZW5kZWQgY29uc3VtZXIgb2YgdGhlIHJvdXRlICh2ZXJpZnkgdGhlIGNhbGxlcnMpOyBwcmVmZXIgcGxhaW5cbiAqIGByZXF1aXJlUGVybWlzc2lvbmAgZm9yIHB1cmVseSB1c2VyLWZhY2luZyByZWFkcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVQZXJtaXNzaW9uT3JTZXJ2aWNlKC4uLnBlcm1pc3Npb25zOiBQZXJtaXNzaW9uW10pIHtcbiAgcmV0dXJuIHRhZ1JvdXRlR2F0ZSgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcXVpcmVVc2VyKHJlcSwgcmVzKSkgcmV0dXJuO1xuICAgIGlmIChpc1NlcnZpY2VQcmluY2lwYWwocmVxKSB8fCBwZXJtaXNzaW9ucy5zb21lKChwKSA9PiB1c2VySGFzUGVybWlzc2lvbihyZXEsIHApKSkgcmV0dXJuIG5leHQoKTtcbiAgICBkZW55UGVybWlzc2lvbihyZXEsIHJlcywgcGVybWlzc2lvbnMsICdvcicpO1xuICB9LCB7IGtpbmQ6ICdwZXJtaXNzaW9uJywgbW9kZTogJ2FueScsIHBlcm1pc3Npb25zLCBhbGxvd1NlcnZpY2U6IHRydWUgfSk7XG59XG5cbi8qKlxuICogR2F0ZSBhbiBlbmRwb2ludCB0byBpbnRlcm5hbCBzZXJ2aWNlLXRvLXNlcnZpY2UgY2FsbGVycyBvbmx5IChhXG4gKiBgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCBwcmluY2lwYWwgbWludGVkIHZpYSB7QGxpbmsgc2lnblNlcnZpY2VUb2tlbn0gLyBgZ2V0U2VydmljZUF1dGhIZWFkZXJgKS5cbiAqIFJlamVjdHMgYW55IHVzZXIgdG9rZW4uIEZvciBOT04tdXNlci1mYWNpbmcgZW5kcG9pbnRzIOKAlCBlbnRpdHktZXZlbnQgaW5nZXN0LFxuICogYXV0by1zdWJzY3JpYmUsIGFuZCBzaW1pbGFyIHBlZXItc2VydmljZSBob29rcyDigJQgdGhhdCBhIGJyb3dzZXIgbXVzdCBuZXZlclxuICogcmVhY2guIENvbXBvc2UgYWZ0ZXIgYHJlcXVpcmVBdXRoYCBzbyBgcmVxLnVzZXJgIGlzIHBvcHVsYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCB7XG4gIGlmICghaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcSkpIHtcbiAgICAvLyA0MDMgKG5vdCA0MDApIOKAlCB0aGlzIGlzIGFuIGF1dGhvcml6YXRpb24gcmVmdXNhbDsgc3RhdHVzIG11c3QgbWF0Y2ggdGhlXG4gICAgLy8gSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TIGNvZGUgYW5kIHRoZSBzaWJsaW5nIGdhdGVzIChyZXF1aXJlUGVybWlzc2lvbiwgZXRjLikuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLCAnSW50ZXJuYWwgc2VydmljZSBjYWxscyBvbmx5JywgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyk7XG4gIH1cbiAgbmV4dCgpO1xufVxudGFnUm91dGVHYXRlKHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsLCB7IGtpbmQ6ICdzZXJ2aWNlUHJpbmNpcGFsJyB9KTtcblxuLyoqXG4gKiBUSEUgZ2F0ZSBmb3IgYW4gSU5URVJOQUwgcm91dGUg4oCUIHRoZSBvbmUgZXZlcnkgYC9pbnRlcm5hbC8qYCBwYXRoLCB0aGVcbiAqIHF1b3RhIHVzYWdlIGNvdW50ZXJzLCB0aGUgZW50aXR5LWV2ZW50IGluZ2VzdCBhbmQgdGhlIGF1ZGl0IGluZ2VzdCBnbyB0aHJvdWdoLlxuICpcbiAqIFR3byBydWxlcywgYm90aCBmYWlsLWNsb3NlZDpcbiAqXG4gKiAgMS4gKipObyB1c2VyIHRva2VuLCBldmVyLioqIE5vdCBhIG1lbWJlcidzLCBub3QgYSBzdXBlcmFkbWluJ3MsIG5vdCBhXG4gKiAgICAgc2VydmljZS1hY2NvdW50IGtleSdzLiBBbiBpbnRlcm5hbCByb3V0ZSBpcyBhIHBlZXItc2VydmljZSBBUEkgc3VyZmFjZSwgc29cbiAqICAgICBcImEgc3VmZmljaWVudGx5IHByaXZpbGVnZWQgaHVtYW5cIiBpcyBub3QgYW4gYWNjZXB0YWJsZSBjYWxsZXIg4oCUIHRoYXRcbiAqICAgICBlcXVpdmFsZW5jZSBpcyBleGFjdGx5IGhvdyBhIGJyb3dzZXItcmVhY2hhYmxlIHBhdGggYmVjb21lcyBhIHRlbmFudFxuICogICAgIGJvdW5kYXJ5IGJ1Zy4gYHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsYCBhbHJlYWR5IHJlZnVzZWQgdXNlcnM7IHRoaXMgYWxzb1xuICogICAgIGNsb3NlcyB0aGUgYHx8IGlzU3lzdGVtQWRtaW4ocmVxKWAgZXNjYXBlIGhhdGNoZXMgdGhhdCBoYWQgZ3Jvd24gYXJvdW5kXG4gKiAgICAgdGhlIGluZGl2aWR1YWwgaW50ZXJuYWwgcm91dGVzLlxuICogIDIuICoqT25seSB0aGUgTkFNRUQgY2FsbGVycy4qKiBgY2FsbGVyc2AgbGlzdHMgdGhlIHNlcnZpY2VzIHRoYXQgbGVnaXRpbWF0ZWx5XG4gKiAgICAgY2FsbCB0aGlzIHJvdXRlLCBhbmQgdGhlIG5hbWUgaXMgY3J5cHRvZ3JhcGhpY2FsbHkgYm91bmQgdG8gdGhlIHNpZ25pbmdcbiAqICAgICBrZXkgKGBzZXJ2aWNlcy9zZXJ2aWNlLWtleXMudHNgKSwgc28gdGhpcyBpcyBhbiBpZGVudGl0eSBjaGVjayByYXRoZXIgdGhhblxuICogICAgIGEgY2xhaW0gY2hlY2suIEl0IGlzIHRoZSBzYW1lIGFsbG93LWxpc3QgdGhlIG1lc2ggcG9saWN5IG5hbWVzLCBhdCB0aGVcbiAqICAgICBsYXllciB0aGF0IGFsc28gaG9sZHMgaW4gZG9ja2VyIGNvbXBvc2UsIHdoZXJlIHRoZXJlIGlzIG5vIG1lc2ggYXQgYWxsIOKAlFxuICogICAgIHRoZSBJc3RpbyBgQXV0aG9yaXphdGlvblBvbGljeWAgaXMgZGVmZW5jZSBpbiBkZXB0aCBvbiB0b3AsIG5ldmVyIHRoZVxuICogICAgIGVuZm9yY2VtZW50LlxuICpcbiAqIENvbXBvc2UgYWZ0ZXIgYHJlcXVpcmVBdXRoYCBzbyBgcmVxLnVzZXJgIGlzIHBvcHVsYXRlZC4gUmVmdXNhbHMgYXJlIGNvdW50ZWRcbiAqIChgaW50ZXJuYWxfcm91dGVfcmVmdXNlZF90b3RhbGApIGFuZCBhdWRpdGVkIHRocm91Z2ggdGhlIHNoYXJlZCBgYXV0aHouZGVuaWVkYFxuICogc2luay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVJbnRlcm5hbFNlcnZpY2Uob3B0aW9uczogeyBjYWxsZXJzOiByZWFkb25seSBzdHJpbmdbXSB9KSB7XG4gIGNvbnN0IGFsbG93ZWQgPSBuZXcgU2V0KG9wdGlvbnMuY2FsbGVycyk7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgY29uc3QgcmVmdXNlID0gKHJlYXNvbjogJ3VuYXV0aGVudGljYXRlZCcgfCAndXNlcl90b2tlbicgfCAnd3JvbmdfY2FsbGVyJyk6IHZvaWQgPT4ge1xuICAgICAgZW1pdENvdW50ZXIoJ2ludGVybmFsX3JvdXRlX3JlZnVzZWRfdG90YWwnLCB7XG4gICAgICAgIHNlcnZpY2U6IHNlcnZpY2VJZGVudGl0eSgpLFxuICAgICAgICByb3V0ZTogcmVxLnJvdXRlPy5wYXRoID8gYCR7cmVxLm1ldGhvZH0gJHtyZXEuYmFzZVVybH0ke3JlcS5yb3V0ZS5wYXRofWAgOiBgJHtyZXEubWV0aG9kfSAkeyhyZXEub3JpZ2luYWxVcmwgfHwgcmVxLnVybCkuc3BsaXQoJz8nKVswXX1gLFxuICAgICAgICByZWFzb24sXG4gICAgICAgIGNhbGxlcjogc2VydmljZU5hbWVPZihyZXEudXNlcikgPz8gJ25vbmUnLFxuICAgICAgfSk7XG4gICAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsIGBpbnRlcm5hbC1zZXJ2aWNlICgke29wdGlvbnMuY2FsbGVycy5qb2luKCcsICcpfSlgKTtcbiAgICAgIGlmIChyZWFzb24gPT09ICd1bmF1dGhlbnRpY2F0ZWQnKSB7XG4gICAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgICB9XG4gICAgICBsb2dnZXIud2FybignUmVmdXNlZCBhbiBpbnRlcm5hbCByb3V0ZScsIHsgcmVhc29uLCBwYXRoOiAocmVxLm9yaWdpbmFsVXJsIHx8IHJlcS51cmwpLnNwbGl0KCc/JylbMF0sIGNhbGxlcjogc2VydmljZU5hbWVPZihyZXEudXNlcikgfSk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sICdJbnRlcm5hbCBzZXJ2aWNlIGNhbGxzIG9ubHknLCBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TKTtcbiAgICB9O1xuXG4gICAgaWYgKCFyZXEudXNlcikgcmV0dXJuIHJlZnVzZSgndW5hdXRoZW50aWNhdGVkJyk7XG4gICAgaWYgKCFpc1NlcnZpY2VQcmluY2lwYWwocmVxKSkgcmV0dXJuIHJlZnVzZSgndXNlcl90b2tlbicpO1xuICAgIGNvbnN0IGNhbGxlciA9IHNlcnZpY2VOYW1lT2YocmVxLnVzZXIpO1xuICAgIGlmICghY2FsbGVyIHx8ICFhbGxvd2VkLmhhcyhjYWxsZXIpKSByZXR1cm4gcmVmdXNlKCd3cm9uZ19jYWxsZXInKTtcbiAgICBuZXh0KCk7XG4gIH0sIHsga2luZDogJ3NlcnZpY2VQcmluY2lwYWwnIH0sIHsga2luZDogJ2ludGVybmFsU2VydmljZScsIGNhbGxlcnM6IFsuLi5vcHRpb25zLmNhbGxlcnNdIH0pO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoZSByZXF1ZXN0IGlzIGZyb20gYSBzeXN0ZW0gYWRtaW4uXG4gKlxuICogQXV0aG9yaXR5IGlzIGdyYW50ZWQgc29sZWx5IGJ5IHRoZSB1c2VyLWxldmVsIGBpc1N1cGVyQWRtaW5gIGZsYWcgY2FycmllZFxuICogaW4gdGhlIEpXVCDigJQgbmV2ZXIgYnkgbWVtYmVyc2hpcCBpbiB0aGUgd2VsbC1rbm93biAnc3lzdGVtJyBvcmcsIHdoaWNoIHdvdWxkXG4gKiBjb25mbGF0ZSBhIFBpcGVsaW5lIEJ1aWxkZXIgb3BlcmF0b3Igd2l0aCBhIGN1c3RvbWVyIHRlbmFudCBhbmQgbGV0IGFueVxuICogd3JpdGUgdGhhdCBjcmVhdGVkIGEgJ3N5c3RlbSctbmFtZWQgb3JnIHF1aWV0bHkgZ3JhbnQgY3Jvc3Mtb3JnIGF1dGhvcml0eS4gVGhlIGBzeXN0ZW1gIG9yZyBzdGlsbCBleGlzdHMgYXMgYSAqY29udGVudCBob2xkZXIqIGZvciBzaGFyZWRcbiAqIHNhbXBsZSBkYXRhOyBpdCBjb25mZXJzIG5vIHByaXZpbGVnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtQWRtaW4ocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gIHJldHVybiByZXEudXNlcj8uaXNTdXBlckFkbWluID09PSB0cnVlO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB0b2tlbiBjYXJyaWVzIGEgc3BlY2lmaWMgY2FwYWJpbGl0eSBgc2NvcGVgIChlLmcuXG4gKiBgJ3JlcG9ydGluZzppbmdlc3QnYCkuIFVzZWQgdG8gZ2F0ZSBlbmRwb2ludHMgdGhhdCBhY2NlcHQgYSBuYXJyb3cgbWFjaGluZVxuICogaWRlbnRpdHkg4oCUIGEgbm9ybWFsIGludGVyYWN0aXZlIHVzZXIgdG9rZW4gaGFzIG5vIGBzY29wZWAgYW5kIHJldHVybnMgZmFsc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNTY29wZShyZXE6IFJlcXVlc3QsIHNjb3BlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5zY29wZSA9PT0gc2NvcGU7XG59XG5cbi8qKiBSZXF1aXJlcyBhIHN5c3RlbSBhZG1pbiDigJQgZ3JhbnRlZCBzb2xlbHkgYnkgdGhlIGBpc1N1cGVyQWRtaW5gIHRva2VuIGNsYWltLlxuICogIFVzZSBhZnRlciByZXF1aXJlQXV0aC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlU3lzdGVtQWRtaW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghaXNTeXN0ZW1BZG1pbihyZXEpKSB7XG4gICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCAnc3lzdGVtLWFkbWluJyk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICAnQWNjZXNzIGRlbmllZC4gT25seSBzeXN0ZW0gYWRtaW5pc3RyYXRvcnMgY2FuIHBlcmZvcm0gdGhpcyBhY3Rpb24uJyxcbiAgICAgIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMsXG4gICAgKTtcbiAgfVxuICBuZXh0KCk7XG59XG50YWdSb3V0ZUdhdGUocmVxdWlyZVN5c3RlbUFkbWluLCB7IGtpbmQ6ICdzeXN0ZW1BZG1pbicgfSk7XG5cbi8qKlxuICogUmVxdWlyZSBhIHNwZWNpZmljIGZlYXR1cmUgZmxhZy4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLlxuICogQ2hlY2tzIHRoZSBgZmVhdHVyZXNgIGFycmF5IGluIHRoZSBKV1QgcGF5bG9hZCAoc2V0IGF0IHRva2VuIGlzc3VhbmNlKS5cbiAqIFN5c2FkbWlucyAoaXNTdXBlckFkbWluKSBieXBhc3Mg4oCUIHRoZXkgYWx3YXlzIGhhdmUgZXZlcnkgZmVhdHVyZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVGZWF0dXJlKGZlYXR1cmU6IHN0cmluZykge1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxdWlyZVVzZXIocmVxLCByZXMpKSByZXR1cm47XG5cbiAgICAvLyBTeXNhZG1pbnMgZ2V0IGFsbCBmZWF0dXJlczsgdGhlIGBmZWF0dXJlc2AgYXJyYXkgb24gdGhlaXIgdG9rZW4gaXNcbiAgICAvLyBwb3B1bGF0ZWQgd2l0aCBldmVyeSBmbGFnIGF0IGlzc3VhbmNlIHRpbWUgYnV0IHRoZSBieXBhc3MgaGVyZSBrZWVwc1xuICAgIC8vIHRoZSBydWxlIGV4cGxpY2l0IGFuZCBzdXJ2aXZlcyBhIHRva2VuIGlzc3VlZCBiZWZvcmUgYSBuZXcgZmVhdHVyZVxuICAgIC8vIGZsYWcgd2FzIGFkZGVkLlxuICAgIGlmIChyZXEudXNlci5pc1N1cGVyQWRtaW4gPT09IHRydWUpIHJldHVybiBuZXh0KCk7XG5cbiAgICBpZiAoIXJlcS51c2VyLmZlYXR1cmVzPy5pbmNsdWRlcyhmZWF0dXJlKSkge1xuICAgICAgLy8gUm91dGUgZmVhdHVyZS1nYXRlIGRlbmlhbHMgdGhyb3VnaCB0aGUgc2FtZSBhdWRpdCBzaW5rIGFzXG4gICAgICAvLyByZXF1aXJlUGVybWlzc2lvbiAvIHJlcXVpcmVTeXN0ZW1BZG1pbiBzbyBhIHByb2JlIGZvciBhblxuICAgICAgLy8gdW5lbnRpdGxlZCBjYXBhYmlsaXR5IGxlYXZlcyBhIHRyYWlsIChzdGF0ZS1jaGFuZ2luZyBtZXRob2RzIG9ubHkpLlxuICAgICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCBgZmVhdHVyZToke2ZlYXR1cmV9YCk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICBgVGhpcyBmZWF0dXJlIHJlcXVpcmVzIGEgaGlnaGVyIHBsYW4gKCR7ZmVhdHVyZX0pYCxcbiAgICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9LCB7IGtpbmQ6ICdmZWF0dXJlJywgZmVhdHVyZSB9KTtcbn1cblxuIl19
|
|
266
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVybWlzc2lvbi1nYXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL3Blcm1pc3Npb24tZ2F0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQVF0QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3hFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsY0FBYyxFQUFFLG1CQUFtQixFQUFFLHFCQUFxQixFQUFFLGlCQUFpQixFQUF1QixNQUFNLDhCQUE4QixDQUFDO0FBQ2xKLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUM5RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDcEQsT0FBTyxFQUFtQixhQUFhLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVqRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUMvQzs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGlCQUFpQixDQUFDLEdBQVksRUFBRSxVQUFzQjtJQUNwRSxPQUFPLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxZQUFZLENBQUMsQ0FBQztBQUNsRixDQUFDO0FBOEJEOzs7Ozs7O0dBT0c7QUFDSCxJQUFJLGtCQUFpRSxDQUFDO0FBRXRFOzs7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QVMsQ0FBQyx3QkFBd0IsQ0FDbkMsQ0FBQztJQUNKLENBQUM7SUFDRCxJQUFJLEVBQUUsQ0FBQztBQUNULENBQUM7QUFDRCxZQUFZLENBQUMsa0JBQWtCLEVBQUUsRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztBQUUxRDs7OztHQUlHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxPQUFlO0lBQzVDLE9BQU8sWUFBWSxDQUFDLENBQUMsR0FBWSxFQUFFLEdBQWEsRUFBRSxJQUFrQixFQUFRLEVBQUU7UUFDNUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO1lBQUUsT0FBTztRQUVuQyxxRUFBcUU7UUFDckUsdUVBQXVFO1FBQ3ZFLHFFQUFxRTtRQUNyRSxrQkFBa0I7UUFDbEIsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLFlBQVksS0FBSyxJQUFJO1lBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQztRQUVsRCxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDMUMsNERBQTREO1lBQzVELDJEQUEyRDtZQUMzRCxzRUFBc0U7WUFDdEUsaUJBQWlCLENBQUMsR0FBRyxFQUFFLFdBQVcsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUM3QyxPQUFPLFNBQVMsQ0FDZCxHQUFHLEVBQUUsVUFBVSxDQUFDLFNBQVMsRUFDekIsd0NBQXdDLE9BQU8sR0FBRyxFQUNsRCxTQUFTLENBQUMsd0JBQXdCLENBQ25DLENBQUM7UUFDSixDQUFDO1FBRUQsSUFBSSxFQUFFLENBQUM7SUFDVCxDQUFDLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7QUFDbkMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIEF1dGhvcml6YXRpb24gZ2F0ZXMg4oCUIHBlcm1pc3Npb25zLCBzeXN0ZW0gYWRtaW4sIGZlYXR1cmVzIOKAlCBhbmQgdGhlXG4gKiBgYXV0aHouZGVuaWVkYCBhdWRpdCBzaW5rIHRoZXkgcmVwb3J0IHJlZnVzYWxzIHRvLlxuICovXG5cbmltcG9ydCB0eXBlIHsgUmVxdWVzdCwgUmVzcG9uc2UsIE5leHRGdW5jdGlvbiB9IGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IHsgdGFnUm91dGVHYXRlIH0gZnJvbSAnLi9yb3V0ZS10YWJsZS5qcyc7XG5pbXBvcnQgeyBpc1NlcnZpY2VQcmluY2lwYWwsIHNlcnZpY2VOYW1lT2YgfSBmcm9tICcuL3NlcnZpY2UtdG9rZW5zLmpzJztcbmltcG9ydCB7IEh0dHBTdGF0dXMgfSBmcm9tICcuLi9jb25zdGFudHMvaHR0cC1zdGF0dXMuanMnO1xuaW1wb3J0IHsgYXVkaXRBdXRoQmxvY2ssIGN1cnJlbnRBdWRpdENvbnRleHQsIHNhbml0aXplQ29ycmVsYXRpb25JZCwgc2FuaXRpemVVc2VyQWdlbnQsIHR5cGUgQXVkaXRBdXRoQmxvY2sgfSBmcm9tICcuLi9zZXJ2aWNlcy9hdWRpdC1jb250ZXh0LmpzJztcbmltcG9ydCB7IHNlcnZpY2VJZGVudGl0eSB9IGZyb20gJy4uL3NlcnZpY2VzL3NlcnZpY2Uta2V5cy5qcyc7XG5pbXBvcnQgeyBFcnJvckNvZGUgfSBmcm9tICcuLi90eXBlcy9lcnJvci1jb2Rlcy5qcyc7XG5pbXBvcnQgeyB0eXBlIFBlcm1pc3Npb24sIGhhc1Blcm1pc3Npb24gfSBmcm9tICcuLi90eXBlcy9wZXJtaXNzaW9ucy5qcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZW1pdENvdW50ZXIgfSBmcm9tICcuLi91dGlscy9tZXRyaWMtZW1pdHRlci5qcyc7XG5pbXBvcnQgeyBzZW5kRXJyb3IgfSBmcm9tICcuLi91dGlscy9yZXNwb25zZS5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignYXV0aC1taWRkbGV3YXJlJyk7XG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB1c2VyIGhvbGRzIGBwZXJtaXNzaW9uYC4gU3VwZXJhZG1pbnMgaW1wbGljaXRseSBob2xkXG4gKiBldmVyeSBwZXJtaXNzaW9uLiBSZWFkcyB0aGUgcmVzb2x2ZWQgYHBlcm1pc3Npb25zYCBjbGFpbSAoc2V0IGF0IHRva2VuIGlzc3VlLFxuICogb3IgcmUtZGVyaXZlZCBwZXIgcmVxdWVzdCBieSB0aGUgcGxhdGZvcm0pLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlckhhc1Blcm1pc3Npb24ocmVxOiBSZXF1ZXN0LCBwZXJtaXNzaW9uOiBQZXJtaXNzaW9uKTogYm9vbGVhbiB7XG4gIHJldHVybiBoYXNQZXJtaXNzaW9uKHJlcS51c2VyPy5wZXJtaXNzaW9ucywgcGVybWlzc2lvbiwgcmVxLnVzZXI/LmlzU3VwZXJBZG1pbik7XG59XG5cbi8qKlxuICogQ29udGV4dCBwYXNzZWQgdG8gYSByZWdpc3RlcmVkIGF1dGhvcml6YXRpb24tZGVuaWFsIGF1ZGl0b3Igd2hlbiBhXG4gKiBzdGF0ZS1jaGFuZ2luZyByZXF1ZXN0IGlzIHJlamVjdGVkIGJ5IGByZXF1aXJlUGVybWlzc2lvbmAgL1xuICogYHJlcXVpcmVTeXN0ZW1BZG1pbmAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXV0aHpEZW5pYWxJbmZvIHtcbiAgLyoqIFRoZSBkZW5pZWQgdXNlcidzIGlkIChgc3ViYCksIGlmIGF1dGhlbnRpY2F0ZWQuICovXG4gIGFjdG9ySWQ/OiBzdHJpbmc7XG4gIGFjdG9yRW1haWw/OiBzdHJpbmc7XG4gIC8qKiBUaGUgdXNlcidzIGFjdGl2ZSBvcmcgYXQgZGVuaWFsIHRpbWUuICovXG4gIG9yZ0lkPzogc3RyaW5nO1xuICAvKiogSFRUUCBtZXRob2QgKyBwYXRoIG9mIHRoZSByZWplY3RlZCByZXF1ZXN0LiAqL1xuICBtZXRob2Q6IHN0cmluZztcbiAgcGF0aDogc3RyaW5nO1xuICAvKiogV2hhdCB3YXMgcmVxdWlyZWQ6IHRoZSBtaXNzaW5nIHBlcm1pc3Npb24ocyksIG9yICdzeXN0ZW0tYWRtaW4nLiAqL1xuICByZXF1aXJlZDogc3RyaW5nO1xuICAvKiogQ2xpZW50IGlwIChgcmVxLmlwYCwgcHJveHktcmVzb2x2ZWQpLiAqL1xuICBpcD86IHN0cmluZztcbiAgLyoqIFNhbml0aXplZCwgbGVuZ3RoLWNhcHBlZCBVc2VyLUFnZW50LiAqL1xuICB1c2VyQWdlbnQ/OiBzdHJpbmc7XG4gIC8qKiBUaGUgcmVxdWVzdCdzIGNvcnJlbGF0aW9uIGlkICh0aGUgYW1iaWVudCBhdWRpdCBjb250ZXh0J3MsIGVsc2UgYSB2YWxpZCBgWC1SZXF1ZXN0LUlkYCkuICovXG4gIHJlcXVlc3RJZD86IHN0cmluZztcbiAgLyoqIFRoZSByZWFsIHN5c2FkbWluIGJlaGluZCBhbiBpbXBlcnNvbmF0aW9uIHRva2VuLCBmcm9tIHRoZSB2ZXJpZmllZCB0b2tlbi4gKi9cbiAgaW1wZXJzb25hdG9ySWQ/OiBzdHJpbmc7XG4gIC8qKiBUaGUgY3JlZGVudGlhbCB0aGF0IHdhcyByZWZ1c2VkIChrZXkgaWQsIHNlc3Npb24sIHNjb3BlLCDigKYpIOKAlCB0aGUgYF9hdXRoYCBibG9jay4gKi9cbiAgYXV0aD86IEF1ZGl0QXV0aEJsb2NrO1xufVxuXG4vKipcbiAqIE9wdGlvbmFsIHNpbmsgZm9yIGRlbmllZC1hdXRob3JpemF0aW9uIGV2ZW50cy4gTGVmdCB1bnNldCBieSBkZWZhdWx0IHNvXG4gKiBhcGktY29yZSBzdGF5cyBkZWNvdXBsZWQgZnJvbSBhbnkgYXVkaXQgdHJhbnNwb3J0IOKAlCBhIHNlcnZpY2UgcmVnaXN0ZXJzIG9uZVxuICogYXQgYm9vdCAodHlwaWNhbGx5IGZvcndhcmRpbmcgdG8gaXRzIGBSZW1vdGVBdWRpdENsaWVudGAgYXMgYW5cbiAqIGBhdXRoei5kZW5pZWRgIGV2ZW50LCBvciwgb24gcGxhdGZvcm0sIHRvIHRoZSBsb2NhbCBgYXVkaXQoKWAgaGVscGVyKS5cbiAqIE1VU1QgYmUgYmVzdC1lZmZvcnQ6IGl0IGlzIGludm9rZWQgaW5zaWRlIHRoZSByZXF1ZXN0IHBhdGgsIHNvIGl0IG11c3QgbmV2ZXJcbiAqIHRocm93IG9yIGJsb2NrICh0aGUgZ2F0ZSB3cmFwcyB0aGUgY2FsbCBpbiB0cnkvY2F0Y2ggcmVnYXJkbGVzcykuXG4gKi9cbmxldCBhdXRoekRlbmlhbEF1ZGl0b3I6ICgoaW5mbzogQXV0aHpEZW5pYWxJbmZvKSA9PiB2b2lkKSB8IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBSZWdpc3RlciAob3IgY2xlYXIsIHdpdGggYHVuZGVmaW5lZGApIHRoZSBwcm9jZXNzLXdpZGUgYXV0aG9yaXphdGlvbi1kZW5pYWxcbiAqIGF1ZGl0b3IuIElkZW1wb3RlbnQ7IHRoZSBsYXN0IHJlZ2lzdHJhdGlvbiB3aW5zLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0QXV0aHpEZW5pYWxBdWRpdG9yKGZuOiAoKGluZm86IEF1dGh6RGVuaWFsSW5mbykgPT4gdm9pZCkgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgYXV0aHpEZW5pYWxBdWRpdG9yID0gZm47XG59XG5cbi8qKlxuICogRW1pdCBhIGRlbmlhbCBldmVudCwgYmVzdC1lZmZvcnQuIE9ubHkgZmlyZXMgZm9yIHN0YXRlLWNoYW5naW5nIChub24tR0VULFxuICogbm9uLUhFQUQvT1BUSU9OUykgcmVxdWVzdHMg4oCUIGEgcmVqZWN0ZWQgR0VUIGlzIGxvdy1zaWduYWwgcHJvYmluZyBub2lzZSBhbmRcbiAqIHdvdWxkIGFtcGxpZnkgYXVkaXQgdm9sdW1lIHVuZGVyIGEgc2Nhbi4gTmV2ZXIgdGhyb3dzLlxuICpcbiAqIFRoZSBwZXJtaXNzaW9uIGdhdGVzIGhlcmUgY2FsbCBpdCB0aGVtc2VsdmVzLiBFeHBvcnQgaXQgZm9yIGRhdGEtZHJpdmVuIGNoZWNrc1xuICogYSByb3V0ZSBtYWtlcyBpbmxpbmUgKGNyb3NzLW9yZyBhY2Nlc3MsIHNlcnZpY2Utb25seSBlbmRwb2ludHMpLCBzbyB0aG9zZSA0MDNzXG4gKiByZWFjaCB0aGUgc2FtZSBgYXV0aHouZGVuaWVkYCB0cmFpbC4gYHJlcXVpcmVkYCBuYW1lcyB3aGF0IHdhcyBtaXNzaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVjb3JkQXV0aHpEZW5pYWwocmVxOiBSZXF1ZXN0LCByZXF1aXJlZDogc3RyaW5nKTogdm9pZCB7XG4gIGNvbnN0IGF1ZGl0b3IgPSBhdXRoekRlbmlhbEF1ZGl0b3I7XG4gIGlmICghYXVkaXRvcikgcmV0dXJuO1xuICBjb25zdCBtZXRob2QgPSByZXEubWV0aG9kLnRvVXBwZXJDYXNlKCk7XG4gIGlmIChtZXRob2QgPT09ICdHRVQnIHx8IG1ldGhvZCA9PT0gJ0hFQUQnIHx8IG1ldGhvZCA9PT0gJ09QVElPTlMnKSByZXR1cm47XG4gIHRyeSB7XG4gICAgYXVkaXRvcih7XG4gICAgICBhY3RvcklkOiByZXEudXNlcj8uc3ViLFxuICAgICAgYWN0b3JFbWFpbDogcmVxLnVzZXI/LmVtYWlsLFxuICAgICAgb3JnSWQ6IHJlcS51c2VyPy5vcmdhbml6YXRpb25JZCxcbiAgICAgIG1ldGhvZCxcbiAgICAgIC8vIFN0cmlwIHRoZSBxdWVyeSBzdHJpbmcg4oCUIGEgZGVuaWVkIHJlcXVlc3QgbWF5IGNhcnJ5IGEgdG9rZW4vc2VjcmV0IGFzIGFcbiAgICAgIC8vIHF1ZXJ5IHBhcmFtLCBhbmQgdGhpcyBwYXRoIGlzIHBlcnNpc3RlZCB2ZXJiYXRpbSBpbnRvIHRoZSBhdWRpdCBsb2cuXG4gICAgICBwYXRoOiAocmVxLm9yaWdpbmFsVXJsIHx8IHJlcS51cmwpLnNwbGl0KCc/JylbMF0sXG4gICAgICByZXF1aXJlZCxcbiAgICAgIGlwOiByZXEuaXAsXG4gICAgICB1c2VyQWdlbnQ6IHNhbml0aXplVXNlckFnZW50KHJlcS5oZWFkZXJzPy5bJ3VzZXItYWdlbnQnXSksXG4gICAgICByZXF1ZXN0SWQ6IGN1cnJlbnRBdWRpdENvbnRleHQoKT8ucmVxdWVzdElkID8/IHNhbml0aXplQ29ycmVsYXRpb25JZChyZXEuaGVhZGVycz8uWyd4LXJlcXVlc3QtaWQnXSksXG4gICAgICBpbXBlcnNvbmF0b3JJZDogcmVxLnVzZXI/LmltcGVyc29uYXRvcklkLFxuICAgICAgYXV0aDogYXVkaXRBdXRoQmxvY2socmVxLnVzZXIpLFxuICAgIH0pO1xuICB9IGNhdGNoIHtcbiAgICAvLyBCZXN0LWVmZm9ydCDigJQgYSBicm9rZW4gYXVkaXRvciBtdXN0IG5ldmVyIGJyZWFrIHRoZSBhdXRoIGdhdGUuXG4gIH1cbn1cblxuLyoqIFRoZSBzaGFyZWQgZ2F0ZSBwcmVhbWJsZTogYW5zd2VyIDQwMSBhbmQgcmV0dXJuIGZhbHNlIHdoZW4gdW5hdXRoZW50aWNhdGVkLiAqL1xuZnVuY3Rpb24gcmVxdWlyZVVzZXIocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlKTogcmVxIGlzIFJlcXVlc3QgJiB7IHVzZXI6IE5vbk51bGxhYmxlPFJlcXVlc3RbJ3VzZXInXT4gfSB7XG4gIGlmIChyZXEudXNlcikgcmV0dXJuIHRydWU7XG4gIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuVU5BVVRIT1JJWkVELCAnQXV0aGVudGljYXRpb24gcmVxdWlyZWQnLCBFcnJvckNvZGUuVU5BVVRIT1JJWkVEKTtcbiAgcmV0dXJuIGZhbHNlO1xufVxuXG4vKiogQXVkaXQgKyBhbnN3ZXIgYSBwZXJtaXNzaW9uIHJlZnVzYWwgKGBtaXNzaW5nYCBkZWZhdWx0cyB0byBldmVyeSByZXF1aXJlZCBwZXJtaXNzaW9uKS4gKi9cbmZ1bmN0aW9uIGRlbnlQZXJtaXNzaW9uKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgcGVybWlzc2lvbnM6IFBlcm1pc3Npb25bXSwgbW9kZTogJ29yJyB8ICdhbmQnLCBtaXNzaW5nOiBQZXJtaXNzaW9uW10gPSBwZXJtaXNzaW9ucyk6IHZvaWQge1xuICByZWNvcmRBdXRoekRlbmlhbChyZXEsIHBlcm1pc3Npb25zLmpvaW4oYCAke21vZGV9IGApKTtcbiAgc2VuZEVycm9yKFxuICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgYE1pc3NpbmcgcmVxdWlyZWQgcGVybWlzc2lvbjogJHttaXNzaW5nLmpvaW4oYCAke21vZGV9IGApfWAsXG4gICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgKTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlcyB0aGF0IHRoZSB1c2VyIGhvbGQgQVQgTEVBU1QgT05FIG9mIHRoZSBnaXZlbiBwZXJtaXNzaW9ucyAob3IgYmUgYVxuICogc3VwZXJhZG1pbikuIFVzZSBhZnRlciByZXF1aXJlQXV0aC4gTWlycm9ycyBgcmVxdWlyZVJvbGVgJ3MgYW55LW9mIHNlbWFudGljcztcbiAqIHBhc3MgYSBzaW5nbGUgcGVybWlzc2lvbiBmb3IgYSBzcGVjaWZpYyBhY3Rpb24sIG9yIHNldmVyYWwgd2hlbiBhbnkgb25lIG9mXG4gKiB0aGVtIHNob3VsZCBncmFudCBhY2Nlc3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlUGVybWlzc2lvbiguLi5wZXJtaXNzaW9uczogUGVybWlzc2lvbltdKSB7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXF1aXJlVXNlcihyZXEsIHJlcykpIHJldHVybjtcbiAgICAvLyB1c2VySGFzUGVybWlzc2lvbiDihpIgaGFzUGVybWlzc2lvbiBhbHJlYWR5IGdyYW50cyBzdXBlcmFkbWlucyBldmVyeVxuICAgIC8vIHBlcm1pc3Npb24sIHNvIHRoaXMgc2luZ2xlIGNoZWNrIGNvdmVycyBib3RoIHRoZSBzdXBlcmFkbWluIGJ5cGFzcyBhbmRcbiAgICAvLyB0aGUgYW55LW9mIG1lbWJlcnNoaXAgdGVzdCB3aXRob3V0IHJlLWlubGluaW5nIGVpdGhlci5cbiAgICBpZiAocGVybWlzc2lvbnMuc29tZSgocCkgPT4gdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSkpIHJldHVybiBuZXh0KCk7XG4gICAgZGVueVBlcm1pc3Npb24ocmVxLCByZXMsIHBlcm1pc3Npb25zLCAnb3InKTtcbiAgfSwgeyBraW5kOiAncGVybWlzc2lvbicsIG1vZGU6ICdhbnknLCBwZXJtaXNzaW9ucyB9KTtcbn1cblxuLyoqXG4gKiBSZXF1aXJlcyB0aGF0IHRoZSB1c2VyIGhvbGQgRVZFUlkgb25lIG9mIHRoZSBnaXZlbiBwZXJtaXNzaW9ucyAob3IgYmUgYVxuICogc3VwZXJhZG1pbikg4oCUIHRoZSBBTkQgY291bnRlcnBhcnQgdG8gYHJlcXVpcmVQZXJtaXNzaW9uYCdzIGFueS1vZi4gVXNlIGZvciBhXG4gKiBzZW5zaXRpdmUgYWN0aW9uIHRoYXQgbGVnaXRpbWF0ZWx5IGRlbWFuZHMgdHdvIGRpc3RpbmN0IGNhcGFiaWxpdGllcyBhdCBvbmNlXG4gKiAoZS5nLiBhIGNyb3NzLXN1cmZhY2Ugb3BlcmF0aW9uKSwgc28gdGhlIGd1YXJhbnRlZSBpcyBleHBsaWNpdCByYXRoZXIgdGhhblxuICogYXBwcm94aW1hdGVkIGJ5IGNoYWluaW5nIHR3byBgcmVxdWlyZVBlcm1pc3Npb25gIGdhdGVzLiBTdXBlcmFkbWlucyBieXBhc3NcbiAqICh0aGV5IGltcGxpY2l0bHkgaG9sZCBldmVyeSBwZXJtaXNzaW9uKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVBbGxQZXJtaXNzaW9ucyguLi5wZXJtaXNzaW9uczogUGVybWlzc2lvbltdKSB7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgaWYgKCFyZXF1aXJlVXNlcihyZXEsIHJlcykpIHJldHVybjtcbiAgICBjb25zdCBtaXNzaW5nID0gcGVybWlzc2lvbnMuZmlsdGVyKChwKSA9PiAhdXNlckhhc1Blcm1pc3Npb24ocmVxLCBwKSk7XG4gICAgaWYgKG1pc3NpbmcubGVuZ3RoID09PSAwKSByZXR1cm4gbmV4dCgpO1xuICAgIGRlbnlQZXJtaXNzaW9uKHJlcSwgcmVzLCBwZXJtaXNzaW9ucywgJ2FuZCcsIG1pc3NpbmcpO1xuICB9LCB7IGtpbmQ6ICdwZXJtaXNzaW9uJywgbW9kZTogJ2FsbCcsIHBlcm1pc3Npb25zIH0pO1xufVxuXG4vKipcbiAqIExpa2Uge0BsaW5rIHJlcXVpcmVQZXJtaXNzaW9ufSAoYW55LW9mKSBidXQgQUxTTyBhZG1pdHMgYW4gaW50ZXJuYWwgc2VydmljZVxuICogcHJpbmNpcGFsIChgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCkuIEZvciBSRUFEIGVuZHBvaW50cyB0aGF0IEJPVEhcbiAqIGludGVyYWN0aXZlIHVzZXJzIOKAlCB3aG8gbXVzdCBob2xkIG9uZSBvZiB0aGUgYDpyZWFkYCBjYXBhYmlsaXRpZXMg4oCUIEFORFxuICogc2VydmljZS10by1zZXJ2aWNlIGNhbGxlcnMgbGVnaXRpbWF0ZWx5IGhpdDsgc2VydmljZSB0b2tlbnMgY2Fycnkgbm9cbiAqIHBlcm1pc3Npb24gY2xhaW1zICh0aGV5J3JlIGxlYXN0LXByaXZpbGVnZSBgcm9sZTptZW1iZXJgKSwgc28gYSBwbGFpblxuICogYHJlcXVpcmVQZXJtaXNzaW9uYCB3b3VsZCB3cm9uZ2x5IDQwMyB0aGVtLiBTdXBlcmFkbWlucyBwYXNzIHZpYVxuICogYHVzZXJIYXNQZXJtaXNzaW9uYCdzIGltcGxpY2l0LWFsbC4gVXNlIG9ubHkgd2hlcmUgYSBzZXJ2aWNlIGNhbGxlciBpcyBhIGtub3duLFxuICogaW50ZW5kZWQgY29uc3VtZXIgb2YgdGhlIHJvdXRlICh2ZXJpZnkgdGhlIGNhbGxlcnMpOyBwcmVmZXIgcGxhaW5cbiAqIGByZXF1aXJlUGVybWlzc2lvbmAgZm9yIHB1cmVseSB1c2VyLWZhY2luZyByZWFkcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVQZXJtaXNzaW9uT3JTZXJ2aWNlKC4uLnBlcm1pc3Npb25zOiBQZXJtaXNzaW9uW10pIHtcbiAgcmV0dXJuIHRhZ1JvdXRlR2F0ZSgocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiB2b2lkID0+IHtcbiAgICBpZiAoIXJlcXVpcmVVc2VyKHJlcSwgcmVzKSkgcmV0dXJuO1xuICAgIGlmIChpc1NlcnZpY2VQcmluY2lwYWwocmVxKSB8fCBwZXJtaXNzaW9ucy5zb21lKChwKSA9PiB1c2VySGFzUGVybWlzc2lvbihyZXEsIHApKSkgcmV0dXJuIG5leHQoKTtcbiAgICBkZW55UGVybWlzc2lvbihyZXEsIHJlcywgcGVybWlzc2lvbnMsICdvcicpO1xuICB9LCB7IGtpbmQ6ICdwZXJtaXNzaW9uJywgbW9kZTogJ2FueScsIHBlcm1pc3Npb25zLCBhbGxvd1NlcnZpY2U6IHRydWUgfSk7XG59XG5cbi8qKlxuICogR2F0ZSBhbiBlbmRwb2ludCB0byBpbnRlcm5hbCBzZXJ2aWNlLXRvLXNlcnZpY2UgY2FsbGVycyBvbmx5IChhXG4gKiBgcHJpbmNpcGFsVHlwZTogJ3NlcnZpY2UnYCBwcmluY2lwYWwgbWludGVkIHZpYSB7QGxpbmsgc2lnblNlcnZpY2VUb2tlbn0gLyBgZ2V0U2VydmljZUF1dGhIZWFkZXJgKS5cbiAqIFJlamVjdHMgYW55IHVzZXIgdG9rZW4uIEZvciBOT04tdXNlci1mYWNpbmcgZW5kcG9pbnRzIOKAlCBlbnRpdHktZXZlbnQgaW5nZXN0LFxuICogYXV0by1zdWJzY3JpYmUsIGFuZCBzaW1pbGFyIHBlZXItc2VydmljZSBob29rcyDigJQgdGhhdCBhIGJyb3dzZXIgbXVzdCBuZXZlclxuICogcmVhY2guIENvbXBvc2UgYWZ0ZXIgYHJlcXVpcmVBdXRoYCBzbyBgcmVxLnVzZXJgIGlzIHBvcHVsYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCB7XG4gIGlmICghaXNTZXJ2aWNlUHJpbmNpcGFsKHJlcSkpIHtcbiAgICAvLyA0MDMgKG5vdCA0MDApIOKAlCB0aGlzIGlzIGFuIGF1dGhvcml6YXRpb24gcmVmdXNhbDsgc3RhdHVzIG11c3QgbWF0Y2ggdGhlXG4gICAgLy8gSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TIGNvZGUgYW5kIHRoZSBzaWJsaW5nIGdhdGVzIChyZXF1aXJlUGVybWlzc2lvbiwgZXRjLikuXG4gICAgcmV0dXJuIHNlbmRFcnJvcihyZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLCAnSW50ZXJuYWwgc2VydmljZSBjYWxscyBvbmx5JywgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyk7XG4gIH1cbiAgbmV4dCgpO1xufVxudGFnUm91dGVHYXRlKHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsLCB7IGtpbmQ6ICdzZXJ2aWNlUHJpbmNpcGFsJyB9KTtcblxuLyoqXG4gKiBUSEUgZ2F0ZSBmb3IgYW4gSU5URVJOQUwgcm91dGUg4oCUIHRoZSBvbmUgZXZlcnkgYC9pbnRlcm5hbC8qYCBwYXRoLCB0aGVcbiAqIHF1b3RhIHVzYWdlIGNvdW50ZXJzLCB0aGUgZW50aXR5LWV2ZW50IGluZ2VzdCBhbmQgdGhlIGF1ZGl0IGluZ2VzdCBnbyB0aHJvdWdoLlxuICpcbiAqIFR3byBydWxlcywgYm90aCBmYWlsLWNsb3NlZDpcbiAqXG4gKiAgMS4gKipObyB1c2VyIHRva2VuLCBldmVyLioqIE5vdCBhIG1lbWJlcidzLCBub3QgYSBzdXBlcmFkbWluJ3MsIG5vdCBhXG4gKiAgICAgc2VydmljZS1hY2NvdW50IGtleSdzLiBBbiBpbnRlcm5hbCByb3V0ZSBpcyBhIHBlZXItc2VydmljZSBBUEkgc3VyZmFjZSwgc29cbiAqICAgICBcImEgc3VmZmljaWVudGx5IHByaXZpbGVnZWQgaHVtYW5cIiBpcyBub3QgYW4gYWNjZXB0YWJsZSBjYWxsZXIg4oCUIHRoYXRcbiAqICAgICBlcXVpdmFsZW5jZSBpcyBleGFjdGx5IGhvdyBhIGJyb3dzZXItcmVhY2hhYmxlIHBhdGggYmVjb21lcyBhIHRlbmFudFxuICogICAgIGJvdW5kYXJ5IGJ1Zy4gYHJlcXVpcmVTZXJ2aWNlUHJpbmNpcGFsYCBhbHJlYWR5IHJlZnVzZWQgdXNlcnM7IHRoaXMgYWxzb1xuICogICAgIGNsb3NlcyB0aGUgYHx8IGlzU3lzdGVtQWRtaW4ocmVxKWAgZXNjYXBlIGhhdGNoZXMgdGhhdCBoYWQgZ3Jvd24gYXJvdW5kXG4gKiAgICAgdGhlIGluZGl2aWR1YWwgaW50ZXJuYWwgcm91dGVzLlxuICogIDIuICoqT25seSB0aGUgTkFNRUQgY2FsbGVycy4qKiBgY2FsbGVyc2AgbGlzdHMgdGhlIHNlcnZpY2VzIHRoYXQgbGVnaXRpbWF0ZWx5XG4gKiAgICAgY2FsbCB0aGlzIHJvdXRlLCBhbmQgdGhlIG5hbWUgaXMgY3J5cHRvZ3JhcGhpY2FsbHkgYm91bmQgdG8gdGhlIHNpZ25pbmdcbiAqICAgICBrZXkgKGBzZXJ2aWNlcy9zZXJ2aWNlLWtleXMudHNgKSwgc28gdGhpcyBpcyBhbiBpZGVudGl0eSBjaGVjayByYXRoZXIgdGhhblxuICogICAgIGEgY2xhaW0gY2hlY2suIEl0IGlzIHRoZSBzYW1lIGFsbG93LWxpc3QgdGhlIG1lc2ggcG9saWN5IG5hbWVzLCBhdCB0aGVcbiAqICAgICBsYXllciB0aGF0IGFsc28gaG9sZHMgaW4gZG9ja2VyIGNvbXBvc2UsIHdoZXJlIHRoZXJlIGlzIG5vIG1lc2ggYXQgYWxsIOKAlFxuICogICAgIHRoZSBJc3RpbyBgQXV0aG9yaXphdGlvblBvbGljeWAgaXMgZGVmZW5jZSBpbiBkZXB0aCBvbiB0b3AsIG5ldmVyIHRoZVxuICogICAgIGVuZm9yY2VtZW50LlxuICpcbiAqIENvbXBvc2UgYWZ0ZXIgYHJlcXVpcmVBdXRoYCBzbyBgcmVxLnVzZXJgIGlzIHBvcHVsYXRlZC4gUmVmdXNhbHMgYXJlIGNvdW50ZWRcbiAqIChgaW50ZXJuYWxfcm91dGVfcmVmdXNlZF90b3RhbGApIGFuZCBhdWRpdGVkIHRocm91Z2ggdGhlIHNoYXJlZCBgYXV0aHouZGVuaWVkYFxuICogc2luay5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVJbnRlcm5hbFNlcnZpY2Uob3B0aW9uczogeyBjYWxsZXJzOiByZWFkb25seSBzdHJpbmdbXSB9KSB7XG4gIGNvbnN0IGFsbG93ZWQgPSBuZXcgU2V0KG9wdGlvbnMuY2FsbGVycyk7XG4gIHJldHVybiB0YWdSb3V0ZUdhdGUoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgY29uc3QgcmVmdXNlID0gKHJlYXNvbjogJ3VuYXV0aGVudGljYXRlZCcgfCAndXNlcl90b2tlbicgfCAnd3JvbmdfY2FsbGVyJyk6IHZvaWQgPT4ge1xuICAgICAgZW1pdENvdW50ZXIoJ2ludGVybmFsX3JvdXRlX3JlZnVzZWRfdG90YWwnLCB7XG4gICAgICAgIHNlcnZpY2U6IHNlcnZpY2VJZGVudGl0eSgpLFxuICAgICAgICByb3V0ZTogcmVxLnJvdXRlPy5wYXRoID8gYCR7cmVxLm1ldGhvZH0gJHtyZXEuYmFzZVVybH0ke3JlcS5yb3V0ZS5wYXRofWAgOiBgJHtyZXEubWV0aG9kfSAkeyhyZXEub3JpZ2luYWxVcmwgfHwgcmVxLnVybCkuc3BsaXQoJz8nKVswXX1gLFxuICAgICAgICByZWFzb24sXG4gICAgICAgIGNhbGxlcjogc2VydmljZU5hbWVPZihyZXEudXNlcikgPz8gJ25vbmUnLFxuICAgICAgfSk7XG4gICAgICByZWNvcmRBdXRoekRlbmlhbChyZXEsIGBpbnRlcm5hbC1zZXJ2aWNlICgke29wdGlvbnMuY2FsbGVycy5qb2luKCcsICcpfSlgKTtcbiAgICAgIGlmIChyZWFzb24gPT09ICd1bmF1dGhlbnRpY2F0ZWQnKSB7XG4gICAgICAgIHJldHVybiBzZW5kRXJyb3IocmVzLCBIdHRwU3RhdHVzLlVOQVVUSE9SSVpFRCwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgRXJyb3JDb2RlLlVOQVVUSE9SSVpFRCk7XG4gICAgICB9XG4gICAgICBsb2dnZXIud2FybignUmVmdXNlZCBhbiBpbnRlcm5hbCByb3V0ZScsIHsgcmVhc29uLCBwYXRoOiAocmVxLm9yaWdpbmFsVXJsIHx8IHJlcS51cmwpLnNwbGl0KCc/JylbMF0sIGNhbGxlcjogc2VydmljZU5hbWVPZihyZXEudXNlcikgfSk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sICdJbnRlcm5hbCBzZXJ2aWNlIGNhbGxzIG9ubHknLCBFcnJvckNvZGUuSU5TVUZGSUNJRU5UX1BFUk1JU1NJT05TKTtcbiAgICB9O1xuXG4gICAgaWYgKCFyZXEudXNlcikgcmV0dXJuIHJlZnVzZSgndW5hdXRoZW50aWNhdGVkJyk7XG4gICAgaWYgKCFpc1NlcnZpY2VQcmluY2lwYWwocmVxKSkgcmV0dXJuIHJlZnVzZSgndXNlcl90b2tlbicpO1xuICAgIGNvbnN0IGNhbGxlciA9IHNlcnZpY2VOYW1lT2YocmVxLnVzZXIpO1xuICAgIGlmICghY2FsbGVyIHx8ICFhbGxvd2VkLmhhcyhjYWxsZXIpKSByZXR1cm4gcmVmdXNlKCd3cm9uZ19jYWxsZXInKTtcbiAgICBuZXh0KCk7XG4gIH0sIHsga2luZDogJ3NlcnZpY2VQcmluY2lwYWwnIH0sIHsga2luZDogJ2ludGVybmFsU2VydmljZScsIGNhbGxlcnM6IFsuLi5vcHRpb25zLmNhbGxlcnNdIH0pO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoZSByZXF1ZXN0IGlzIGZyb20gYSBzeXN0ZW0gYWRtaW4uXG4gKlxuICogQXV0aG9yaXR5IGlzIGdyYW50ZWQgc29sZWx5IGJ5IHRoZSB1c2VyLWxldmVsIGBpc1N1cGVyQWRtaW5gIGZsYWcgY2FycmllZFxuICogaW4gdGhlIEpXVCDigJQgbmV2ZXIgYnkgbWVtYmVyc2hpcCBpbiB0aGUgd2VsbC1rbm93biAnc3lzdGVtJyBvcmcsIHdoaWNoIHdvdWxkXG4gKiBjb25mbGF0ZSBhIFBpcGVsaW5lIEJ1aWxkZXIgb3BlcmF0b3Igd2l0aCBhIGN1c3RvbWVyIHRlbmFudCBhbmQgbGV0IGFueVxuICogd3JpdGUgdGhhdCBjcmVhdGVkIGEgJ3N5c3RlbSctbmFtZWQgb3JnIHF1aWV0bHkgZ3JhbnQgY3Jvc3Mtb3JnIGF1dGhvcml0eS4gVGhlIGBzeXN0ZW1gIG9yZyBzdGlsbCBleGlzdHMgYXMgYSAqY29udGVudCBob2xkZXIqIGZvciBzaGFyZWRcbiAqIHNhbXBsZSBkYXRhOyBpdCBjb25mZXJzIG5vIHByaXZpbGVnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU3lzdGVtQWRtaW4ocmVxOiBSZXF1ZXN0KTogYm9vbGVhbiB7XG4gIHJldHVybiByZXEudXNlcj8uaXNTdXBlckFkbWluID09PSB0cnVlO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgdGhlIHJlcXVlc3QncyB0b2tlbiBjYXJyaWVzIGEgc3BlY2lmaWMgY2FwYWJpbGl0eSBgc2NvcGVgIChlLmcuXG4gKiBgJ3JlcG9ydGluZzppbmdlc3QnYCkuIFVzZWQgdG8gZ2F0ZSBlbmRwb2ludHMgdGhhdCBhY2NlcHQgYSBuYXJyb3cgbWFjaGluZVxuICogaWRlbnRpdHkg4oCUIGEgbm9ybWFsIGludGVyYWN0aXZlIHVzZXIgdG9rZW4gaGFzIG5vIGBzY29wZWAgYW5kIHJldHVybnMgZmFsc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoYXNTY29wZShyZXE6IFJlcXVlc3QsIHNjb3BlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHJlcS51c2VyPy5zY29wZSA9PT0gc2NvcGU7XG59XG5cbi8qKiBSZXF1aXJlcyBhIHN5c3RlbSBhZG1pbiDigJQgZ3JhbnRlZCBzb2xlbHkgYnkgdGhlIGBpc1N1cGVyQWRtaW5gIHRva2VuIGNsYWltLlxuICogIFVzZSBhZnRlciByZXF1aXJlQXV0aC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlU3lzdGVtQWRtaW4oXG4gIHJlcTogUmVxdWVzdCxcbiAgcmVzOiBSZXNwb25zZSxcbiAgbmV4dDogTmV4dEZ1bmN0aW9uLFxuKTogdm9pZCB7XG4gIGlmICghaXNTeXN0ZW1BZG1pbihyZXEpKSB7XG4gICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCAnc3lzdGVtLWFkbWluJyk7XG4gICAgcmV0dXJuIHNlbmRFcnJvcihcbiAgICAgIHJlcywgSHR0cFN0YXR1cy5GT1JCSURERU4sXG4gICAgICAnQWNjZXNzIGRlbmllZC4gT25seSBzeXN0ZW0gYWRtaW5pc3RyYXRvcnMgY2FuIHBlcmZvcm0gdGhpcyBhY3Rpb24uJyxcbiAgICAgIEVycm9yQ29kZS5JTlNVRkZJQ0lFTlRfUEVSTUlTU0lPTlMsXG4gICAgKTtcbiAgfVxuICBuZXh0KCk7XG59XG50YWdSb3V0ZUdhdGUocmVxdWlyZVN5c3RlbUFkbWluLCB7IGtpbmQ6ICdzeXN0ZW1BZG1pbicgfSk7XG5cbi8qKlxuICogUmVxdWlyZSBhIHNwZWNpZmljIGZlYXR1cmUgZmxhZy4gVXNlIGFmdGVyIHJlcXVpcmVBdXRoLlxuICogQ2hlY2tzIHRoZSBgZmVhdHVyZXNgIGFycmF5IGluIHRoZSBKV1QgcGF5bG9hZCAoc2V0IGF0IHRva2VuIGlzc3VhbmNlKS5cbiAqIFN5c2FkbWlucyAoaXNTdXBlckFkbWluKSBieXBhc3Mg4oCUIHRoZXkgYWx3YXlzIGhhdmUgZXZlcnkgZmVhdHVyZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVGZWF0dXJlKGZlYXR1cmU6IHN0cmluZykge1xuICByZXR1cm4gdGFnUm91dGVHYXRlKChyZXE6IFJlcXVlc3QsIHJlczogUmVzcG9uc2UsIG5leHQ6IE5leHRGdW5jdGlvbik6IHZvaWQgPT4ge1xuICAgIGlmICghcmVxdWlyZVVzZXIocmVxLCByZXMpKSByZXR1cm47XG5cbiAgICAvLyBTeXNhZG1pbnMgZ2V0IGFsbCBmZWF0dXJlczsgdGhlIGBmZWF0dXJlc2AgYXJyYXkgb24gdGhlaXIgdG9rZW4gaXNcbiAgICAvLyBwb3B1bGF0ZWQgd2l0aCBldmVyeSBmbGFnIGF0IGlzc3VhbmNlIHRpbWUgYnV0IHRoZSBieXBhc3MgaGVyZSBrZWVwc1xuICAgIC8vIHRoZSBydWxlIGV4cGxpY2l0IGFuZCBzdXJ2aXZlcyBhIHRva2VuIGlzc3VlZCBiZWZvcmUgYSBuZXcgZmVhdHVyZVxuICAgIC8vIGZsYWcgd2FzIGFkZGVkLlxuICAgIGlmIChyZXEudXNlci5pc1N1cGVyQWRtaW4gPT09IHRydWUpIHJldHVybiBuZXh0KCk7XG5cbiAgICBpZiAoIXJlcS51c2VyLmZlYXR1cmVzPy5pbmNsdWRlcyhmZWF0dXJlKSkge1xuICAgICAgLy8gUm91dGUgZmVhdHVyZS1nYXRlIGRlbmlhbHMgdGhyb3VnaCB0aGUgc2FtZSBhdWRpdCBzaW5rIGFzXG4gICAgICAvLyByZXF1aXJlUGVybWlzc2lvbiAvIHJlcXVpcmVTeXN0ZW1BZG1pbiBzbyBhIHByb2JlIGZvciBhblxuICAgICAgLy8gdW5lbnRpdGxlZCBjYXBhYmlsaXR5IGxlYXZlcyBhIHRyYWlsIChzdGF0ZS1jaGFuZ2luZyBtZXRob2RzIG9ubHkpLlxuICAgICAgcmVjb3JkQXV0aHpEZW5pYWwocmVxLCBgZmVhdHVyZToke2ZlYXR1cmV9YCk7XG4gICAgICByZXR1cm4gc2VuZEVycm9yKFxuICAgICAgICByZXMsIEh0dHBTdGF0dXMuRk9SQklEREVOLFxuICAgICAgICBgVGhpcyBmZWF0dXJlIHJlcXVpcmVzIGEgaGlnaGVyIHBsYW4gKCR7ZmVhdHVyZX0pYCxcbiAgICAgICAgRXJyb3JDb2RlLklOU1VGRklDSUVOVF9QRVJNSVNTSU9OUyxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbmV4dCgpO1xuICB9LCB7IGtpbmQ6ICdmZWF0dXJlJywgZmVhdHVyZSB9KTtcbn1cblxuIl19
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The routes that never spend `apiCalls` (or `automationCalls`), fleet-wide.
|
|
3
|
+
*
|
|
4
|
+
* Every service meters and gates its authenticated user surface on `apiCalls`
|
|
5
|
+
* (`meterQuotaOnSuccess` + `checkQuota`, mounted at the app-routes level). A few
|
|
6
|
+
* reads are made BY THE CONSOLE ITSELF, on every page load or on a timer, not by
|
|
7
|
+
* a person doing something — metering them would burn an idle tab's org budget
|
|
8
|
+
* all day, and gating them would make a quota-exhausted org's console unable to
|
|
9
|
+
* render the very banner that says so. This list is that carve-out, and it is
|
|
10
|
+
* deliberately short: each entry names its caller and why it is free.
|
|
11
|
+
*
|
|
12
|
+
* ONE list, read in three places, so they cannot drift:
|
|
13
|
+
* - `meterQuotaOnSuccess` skips a matching request (no increment);
|
|
14
|
+
* - `checkQuota` skips a matching request (never 429s);
|
|
15
|
+
* - `buildRouteTable` marks the route `quota.exempt`, and the quota coverage
|
|
16
|
+
* check (api-core testing) treats it as covered.
|
|
17
|
+
*
|
|
18
|
+
* Each `path` is matched against BOTH the concrete request path
|
|
19
|
+
* (`/organization/64f…/seat-usage`) and the route-table pattern
|
|
20
|
+
* (`/organization/:id/seat-usage`), so a `:param` segment is written as
|
|
21
|
+
* `[^/]+`. Paths are service-local (nginx strips `/api`).
|
|
22
|
+
*
|
|
23
|
+
* The quota service itself is not on the list because it meters nothing: its
|
|
24
|
+
* reads (`GET /quotas`, which QuotaBanner polls every 60s) never cost a call.
|
|
25
|
+
* Documented in docs/quotas.md ("Exempt routes").
|
|
26
|
+
*/
|
|
27
|
+
export interface QuotaExemptRoute {
|
|
28
|
+
method: 'GET' | 'POST';
|
|
29
|
+
/** Anchored pattern over the service-local path. */
|
|
30
|
+
path: RegExp;
|
|
31
|
+
/** Who calls it, and why it must be free. */
|
|
32
|
+
reason: string;
|
|
33
|
+
}
|
|
34
|
+
export declare const QUOTA_EXEMPT_ROUTES: readonly QuotaExemptRoute[];
|
|
35
|
+
/** Whether `method` + `path` (a request path or a route-table pattern) is quota-exempt. */
|
|
36
|
+
export declare function isQuotaExemptRoute(method: string | undefined, path: string): boolean;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
export const QUOTA_EXEMPT_ROUTES = [
|
|
4
|
+
{
|
|
5
|
+
method: 'GET',
|
|
6
|
+
path: /^\/user\/profile$/,
|
|
7
|
+
reason: 'Session bootstrap: the console reads the signed-in profile on every page load.',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
method: 'GET',
|
|
11
|
+
path: /^\/user\/organizations$/,
|
|
12
|
+
reason: 'The org switcher, read on every page load.',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
method: 'GET',
|
|
16
|
+
path: /^\/organization\/[^/]+\/feature-entitlements$/,
|
|
17
|
+
reason: 'Navigation gating (which features render unlocked), read on every page load.',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
method: 'GET',
|
|
21
|
+
path: /^\/organization\/[^/]+\/seat-usage$/,
|
|
22
|
+
reason: 'Billing/quota page read beside the (unmetered) quota reads; an exhausted org must still see what it is using.',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
method: 'GET',
|
|
26
|
+
path: /^\/messages\/unread\/count$/,
|
|
27
|
+
reason: 'The sidebar unread badge, polled every 30s whenever the live channel is down.',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
method: 'POST',
|
|
31
|
+
path: /^\/messages\/notifications\/ticket$/,
|
|
32
|
+
reason: 'SSE ticket mint for the live notification channel; re-minted on every reconnect.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
method: 'POST',
|
|
36
|
+
path: /^\/reports\/execution\/stream\/ticket$/,
|
|
37
|
+
reason: 'SSE ticket mint for the live execution-status channel; re-minted on every reconnect.',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
/** Whether `method` + `path` (a request path or a route-table pattern) is quota-exempt. */
|
|
41
|
+
export function isQuotaExemptRoute(method, path) {
|
|
42
|
+
// HEAD is GET without a body (Express folds it the same way).
|
|
43
|
+
const upper = (method ?? '').toUpperCase();
|
|
44
|
+
const m = upper === 'HEAD' ? 'GET' : upper;
|
|
45
|
+
return QUOTA_EXEMPT_ROUTES.some((r) => r.method === m && r.path.test(path));
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicXVvdGEtZXhlbXB0LXJvdXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL3F1b3RhLWV4ZW1wdC1yb3V0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQW9DdEMsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQWdDO0lBQzlEO1FBQ0UsTUFBTSxFQUFFLEtBQUs7UUFDYixJQUFJLEVBQUUsbUJBQW1CO1FBQ3pCLE1BQU0sRUFBRSxnRkFBZ0Y7S0FDekY7SUFDRDtRQUNFLE1BQU0sRUFBRSxLQUFLO1FBQ2IsSUFBSSxFQUFFLHlCQUF5QjtRQUMvQixNQUFNLEVBQUUsNENBQTRDO0tBQ3JEO0lBQ0Q7UUFDRSxNQUFNLEVBQUUsS0FBSztRQUNiLElBQUksRUFBRSwrQ0FBK0M7UUFDckQsTUFBTSxFQUFFLDhFQUE4RTtLQUN2RjtJQUNEO1FBQ0UsTUFBTSxFQUFFLEtBQUs7UUFDYixJQUFJLEVBQUUscUNBQXFDO1FBQzNDLE1BQU0sRUFBRSwrR0FBK0c7S0FDeEg7SUFDRDtRQUNFLE1BQU0sRUFBRSxLQUFLO1FBQ2IsSUFBSSxFQUFFLDZCQUE2QjtRQUNuQyxNQUFNLEVBQUUsK0VBQStFO0tBQ3hGO0lBQ0Q7UUFDRSxNQUFNLEVBQUUsTUFBTTtRQUNkLElBQUksRUFBRSxxQ0FBcUM7UUFDM0MsTUFBTSxFQUFFLGtGQUFrRjtLQUMzRjtJQUNEO1FBQ0UsTUFBTSxFQUFFLE1BQU07UUFDZCxJQUFJLEVBQUUsd0NBQXdDO1FBQzlDLE1BQU0sRUFBRSxzRkFBc0Y7S0FDL0Y7Q0FDRixDQUFDO0FBRUYsMkZBQTJGO0FBQzNGLE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxNQUEwQixFQUFFLElBQVk7SUFDekUsOERBQThEO0lBQzlELE1BQU0sS0FBSyxHQUFHLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0lBQzNDLE1BQU0sQ0FBQyxHQUFHLEtBQUssS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQzNDLE9BQU8sbUJBQW1CLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0FBQzlFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBUaGUgcm91dGVzIHRoYXQgbmV2ZXIgc3BlbmQgYGFwaUNhbGxzYCAob3IgYGF1dG9tYXRpb25DYWxsc2ApLCBmbGVldC13aWRlLlxuICpcbiAqIEV2ZXJ5IHNlcnZpY2UgbWV0ZXJzIGFuZCBnYXRlcyBpdHMgYXV0aGVudGljYXRlZCB1c2VyIHN1cmZhY2Ugb24gYGFwaUNhbGxzYFxuICogKGBtZXRlclF1b3RhT25TdWNjZXNzYCArIGBjaGVja1F1b3RhYCwgbW91bnRlZCBhdCB0aGUgYXBwLXJvdXRlcyBsZXZlbCkuIEEgZmV3XG4gKiByZWFkcyBhcmUgbWFkZSBCWSBUSEUgQ09OU09MRSBJVFNFTEYsIG9uIGV2ZXJ5IHBhZ2UgbG9hZCBvciBvbiBhIHRpbWVyLCBub3QgYnlcbiAqIGEgcGVyc29uIGRvaW5nIHNvbWV0aGluZyDigJQgbWV0ZXJpbmcgdGhlbSB3b3VsZCBidXJuIGFuIGlkbGUgdGFiJ3Mgb3JnIGJ1ZGdldFxuICogYWxsIGRheSwgYW5kIGdhdGluZyB0aGVtIHdvdWxkIG1ha2UgYSBxdW90YS1leGhhdXN0ZWQgb3JnJ3MgY29uc29sZSB1bmFibGUgdG9cbiAqIHJlbmRlciB0aGUgdmVyeSBiYW5uZXIgdGhhdCBzYXlzIHNvLiBUaGlzIGxpc3QgaXMgdGhhdCBjYXJ2ZS1vdXQsIGFuZCBpdCBpc1xuICogZGVsaWJlcmF0ZWx5IHNob3J0OiBlYWNoIGVudHJ5IG5hbWVzIGl0cyBjYWxsZXIgYW5kIHdoeSBpdCBpcyBmcmVlLlxuICpcbiAqIE9ORSBsaXN0LCByZWFkIGluIHRocmVlIHBsYWNlcywgc28gdGhleSBjYW5ub3QgZHJpZnQ6XG4gKiAgIC0gYG1ldGVyUXVvdGFPblN1Y2Nlc3NgIHNraXBzIGEgbWF0Y2hpbmcgcmVxdWVzdCAobm8gaW5jcmVtZW50KTtcbiAqICAgLSBgY2hlY2tRdW90YWAgc2tpcHMgYSBtYXRjaGluZyByZXF1ZXN0IChuZXZlciA0MjlzKTtcbiAqICAgLSBgYnVpbGRSb3V0ZVRhYmxlYCBtYXJrcyB0aGUgcm91dGUgYHF1b3RhLmV4ZW1wdGAsIGFuZCB0aGUgcXVvdGEgY292ZXJhZ2VcbiAqICAgICBjaGVjayAoYXBpLWNvcmUgdGVzdGluZykgdHJlYXRzIGl0IGFzIGNvdmVyZWQuXG4gKlxuICogRWFjaCBgcGF0aGAgaXMgbWF0Y2hlZCBhZ2FpbnN0IEJPVEggdGhlIGNvbmNyZXRlIHJlcXVlc3QgcGF0aFxuICogKGAvb3JnYW5pemF0aW9uLzY0ZuKApi9zZWF0LXVzYWdlYCkgYW5kIHRoZSByb3V0ZS10YWJsZSBwYXR0ZXJuXG4gKiAoYC9vcmdhbml6YXRpb24vOmlkL3NlYXQtdXNhZ2VgKSwgc28gYSBgOnBhcmFtYCBzZWdtZW50IGlzIHdyaXR0ZW4gYXNcbiAqIGBbXi9dK2AuIFBhdGhzIGFyZSBzZXJ2aWNlLWxvY2FsIChuZ2lueCBzdHJpcHMgYC9hcGlgKS5cbiAqXG4gKiBUaGUgcXVvdGEgc2VydmljZSBpdHNlbGYgaXMgbm90IG9uIHRoZSBsaXN0IGJlY2F1c2UgaXQgbWV0ZXJzIG5vdGhpbmc6IGl0c1xuICogcmVhZHMgKGBHRVQgL3F1b3Rhc2AsIHdoaWNoIFF1b3RhQmFubmVyIHBvbGxzIGV2ZXJ5IDYwcykgbmV2ZXIgY29zdCBhIGNhbGwuXG4gKiBEb2N1bWVudGVkIGluIGRvY3MvcXVvdGFzLm1kIChcIkV4ZW1wdCByb3V0ZXNcIikuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUXVvdGFFeGVtcHRSb3V0ZSB7XG4gIG1ldGhvZDogJ0dFVCcgfCAnUE9TVCc7XG4gIC8qKiBBbmNob3JlZCBwYXR0ZXJuIG92ZXIgdGhlIHNlcnZpY2UtbG9jYWwgcGF0aC4gKi9cbiAgcGF0aDogUmVnRXhwO1xuICAvKiogV2hvIGNhbGxzIGl0LCBhbmQgd2h5IGl0IG11c3QgYmUgZnJlZS4gKi9cbiAgcmVhc29uOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjb25zdCBRVU9UQV9FWEVNUFRfUk9VVEVTOiByZWFkb25seSBRdW90YUV4ZW1wdFJvdXRlW10gPSBbXG4gIHtcbiAgICBtZXRob2Q6ICdHRVQnLFxuICAgIHBhdGg6IC9eXFwvdXNlclxcL3Byb2ZpbGUkLyxcbiAgICByZWFzb246ICdTZXNzaW9uIGJvb3RzdHJhcDogdGhlIGNvbnNvbGUgcmVhZHMgdGhlIHNpZ25lZC1pbiBwcm9maWxlIG9uIGV2ZXJ5IHBhZ2UgbG9hZC4nLFxuICB9LFxuICB7XG4gICAgbWV0aG9kOiAnR0VUJyxcbiAgICBwYXRoOiAvXlxcL3VzZXJcXC9vcmdhbml6YXRpb25zJC8sXG4gICAgcmVhc29uOiAnVGhlIG9yZyBzd2l0Y2hlciwgcmVhZCBvbiBldmVyeSBwYWdlIGxvYWQuJyxcbiAgfSxcbiAge1xuICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgcGF0aDogL15cXC9vcmdhbml6YXRpb25cXC9bXi9dK1xcL2ZlYXR1cmUtZW50aXRsZW1lbnRzJC8sXG4gICAgcmVhc29uOiAnTmF2aWdhdGlvbiBnYXRpbmcgKHdoaWNoIGZlYXR1cmVzIHJlbmRlciB1bmxvY2tlZCksIHJlYWQgb24gZXZlcnkgcGFnZSBsb2FkLicsXG4gIH0sXG4gIHtcbiAgICBtZXRob2Q6ICdHRVQnLFxuICAgIHBhdGg6IC9eXFwvb3JnYW5pemF0aW9uXFwvW14vXStcXC9zZWF0LXVzYWdlJC8sXG4gICAgcmVhc29uOiAnQmlsbGluZy9xdW90YSBwYWdlIHJlYWQgYmVzaWRlIHRoZSAodW5tZXRlcmVkKSBxdW90YSByZWFkczsgYW4gZXhoYXVzdGVkIG9yZyBtdXN0IHN0aWxsIHNlZSB3aGF0IGl0IGlzIHVzaW5nLicsXG4gIH0sXG4gIHtcbiAgICBtZXRob2Q6ICdHRVQnLFxuICAgIHBhdGg6IC9eXFwvbWVzc2FnZXNcXC91bnJlYWRcXC9jb3VudCQvLFxuICAgIHJlYXNvbjogJ1RoZSBzaWRlYmFyIHVucmVhZCBiYWRnZSwgcG9sbGVkIGV2ZXJ5IDMwcyB3aGVuZXZlciB0aGUgbGl2ZSBjaGFubmVsIGlzIGRvd24uJyxcbiAgfSxcbiAge1xuICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgIHBhdGg6IC9eXFwvbWVzc2FnZXNcXC9ub3RpZmljYXRpb25zXFwvdGlja2V0JC8sXG4gICAgcmVhc29uOiAnU1NFIHRpY2tldCBtaW50IGZvciB0aGUgbGl2ZSBub3RpZmljYXRpb24gY2hhbm5lbDsgcmUtbWludGVkIG9uIGV2ZXJ5IHJlY29ubmVjdC4nLFxuICB9LFxuICB7XG4gICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgcGF0aDogL15cXC9yZXBvcnRzXFwvZXhlY3V0aW9uXFwvc3RyZWFtXFwvdGlja2V0JC8sXG4gICAgcmVhc29uOiAnU1NFIHRpY2tldCBtaW50IGZvciB0aGUgbGl2ZSBleGVjdXRpb24tc3RhdHVzIGNoYW5uZWw7IHJlLW1pbnRlZCBvbiBldmVyeSByZWNvbm5lY3QuJyxcbiAgfSxcbl07XG5cbi8qKiBXaGV0aGVyIGBtZXRob2RgICsgYHBhdGhgIChhIHJlcXVlc3QgcGF0aCBvciBhIHJvdXRlLXRhYmxlIHBhdHRlcm4pIGlzIHF1b3RhLWV4ZW1wdC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1F1b3RhRXhlbXB0Um91dGUobWV0aG9kOiBzdHJpbmcgfCB1bmRlZmluZWQsIHBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAvLyBIRUFEIGlzIEdFVCB3aXRob3V0IGEgYm9keSAoRXhwcmVzcyBmb2xkcyBpdCB0aGUgc2FtZSB3YXkpLlxuICBjb25zdCB1cHBlciA9IChtZXRob2QgPz8gJycpLnRvVXBwZXJDYXNlKCk7XG4gIGNvbnN0IG0gPSB1cHBlciA9PT0gJ0hFQUQnID8gJ0dFVCcgOiB1cHBlcjtcbiAgcmV0dXJuIFFVT1RBX0VYRU1QVF9ST1VURVMuc29tZSgocikgPT4gci5tZXRob2QgPT09IG0gJiYgci5wYXRoLnRlc3QocGF0aCkpO1xufVxuIl19
|
|
@@ -9,6 +9,28 @@ import type { Permission } from '../types/permissions.js';
|
|
|
9
9
|
* `HUMAN_SESSION_REQUIRED`), e.g. minting another credential.
|
|
10
10
|
*/
|
|
11
11
|
export type OrgAdminAssuranceMachines = 'allow' | 'refuse';
|
|
12
|
+
/**
|
|
13
|
+
* The CLOSED set of principal kinds a `dynamicAuthz` rule may admit.
|
|
14
|
+
*
|
|
15
|
+
* A route whose authority is resolved in the handler still has to say WHO can
|
|
16
|
+
* get through it. These are the kinds, deliberately coarse — the precise
|
|
17
|
+
* predicate lives in the prose rule and in the code:
|
|
18
|
+
*
|
|
19
|
+
* - `superadmin` — the `User.isSuperAdmin` flag (`isSystemAdmin(req)`).
|
|
20
|
+
* - `system-org` — a member of the system org holding a named permission;
|
|
21
|
+
* list the ids in `permissions` so the coverage scan and
|
|
22
|
+
* the contract can see them.
|
|
23
|
+
* - `tenant-admin` — an admin or owner of the target's own org, or of an
|
|
24
|
+
* ancestor of it. NOT a superadmin by virtue of the flag:
|
|
25
|
+
* several of these rules refuse the flag on purpose.
|
|
26
|
+
* - `tenant-member` — any member of the target's org, admin or not.
|
|
27
|
+
* - `subject` — the very user the request is about (self-service).
|
|
28
|
+
* - `service` — a service principal / internal caller.
|
|
29
|
+
* - `gateway` — the ingress itself supplies the fact (the console
|
|
30
|
+
* `auth_request` passes the console class in a header).
|
|
31
|
+
*/
|
|
32
|
+
export declare const DYNAMIC_PRINCIPALS: readonly ['superadmin', 'system-org', 'tenant-admin', 'tenant-member', 'subject', 'service', 'gateway'];
|
|
33
|
+
export type DynamicPrincipal = typeof DYNAMIC_PRINCIPALS[number];
|
|
12
34
|
/** One requirement a gate middleware enforces. */
|
|
13
35
|
export type RouteGate = {
|
|
14
36
|
kind: 'auth';
|
|
@@ -19,6 +41,40 @@ export type RouteGate = {
|
|
|
19
41
|
allowService?: boolean;
|
|
20
42
|
} | {
|
|
21
43
|
kind: 'systemAdmin';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Authorization the route CANNOT express statically, resolved in the handler.
|
|
47
|
+
*
|
|
48
|
+
* Some authority depends on the request: impersonation asks whether the caller
|
|
49
|
+
* is a sysadmin OR an admin of an ancestor of the TARGET user's org, which is
|
|
50
|
+
* only answerable once the target is known. Those gates were correct but
|
|
51
|
+
* invisible — the route table showed no requirement, and
|
|
52
|
+
* `docs/permission-contract.md` is derived from the table, so the artifact the
|
|
53
|
+
* repo calls its review surface read blank for the strongest privilege in the
|
|
54
|
+
* system.
|
|
55
|
+
*
|
|
56
|
+
* This records the requirement in prose AND as a closed set of principal
|
|
57
|
+
* kinds. It authorizes NOTHING; the handler still does the work. Its value is
|
|
58
|
+
* that a reviewer reading the contract sees a stated rule instead of an empty
|
|
59
|
+
* cell, and that removing the real check leaves a declaration behind that no
|
|
60
|
+
* longer matches.
|
|
61
|
+
*
|
|
62
|
+
* WHY `reachableBy` EXISTS BESIDE THE PROSE. Prose is unreviewable by a test,
|
|
63
|
+
* and one of these rules was wrong: the impersonation `decide` route declared
|
|
64
|
+
* "a DIFFERENT sysadmin than the requester (two-person rule)", which is only
|
|
65
|
+
* its break-glass branch — the ordinary branch is the tenant's named approver
|
|
66
|
+
* or a genuine tenant admin, and a sysadmin alone is explicitly REFUSED there.
|
|
67
|
+
* Nothing could notice, because the only machine-readable fields said
|
|
68
|
+
* `systemAdmin: false, permissions: []`. A closed set makes the author
|
|
69
|
+
* enumerate principals, lets the coverage scan assert the declaration exists,
|
|
70
|
+
* and lets "which routes can the superadmin flag reach?" be answered by a
|
|
71
|
+
* query instead of by reading six paragraphs.
|
|
72
|
+
*/
|
|
73
|
+
| {
|
|
74
|
+
kind: 'dynamicAuthz';
|
|
75
|
+
rule: string;
|
|
76
|
+
reachableBy: readonly DynamicPrincipal[];
|
|
77
|
+
permissions?: readonly Permission[];
|
|
22
78
|
} | {
|
|
23
79
|
kind: 'servicePrincipal';
|
|
24
80
|
}
|
|
@@ -60,6 +116,15 @@ export type RouteGate = {
|
|
|
60
116
|
} | {
|
|
61
117
|
kind: 'audit';
|
|
62
118
|
actions: readonly string[];
|
|
119
|
+
}
|
|
120
|
+
/** A quota middleware: `meter` increments the type once per 2xx
|
|
121
|
+
* (`meterQuotaOnSuccess`), `check` 429s when the type is spent (`checkQuota`).
|
|
122
|
+
* Recorded so the quota coverage check can see an unmetered user route — and a
|
|
123
|
+
* route metered TWICE, which double-bills every call. */
|
|
124
|
+
| {
|
|
125
|
+
kind: 'quota';
|
|
126
|
+
mode: 'meter' | 'check';
|
|
127
|
+
quotaType: string;
|
|
63
128
|
};
|
|
64
129
|
/**
|
|
65
130
|
* Attach gate metadata to a middleware function (appends to any existing tags)
|
|
@@ -77,6 +142,18 @@ export declare function getRouteGates(fn: unknown): readonly RouteGate[];
|
|
|
77
142
|
* `router.post('/', audited('pipeline.create'), handler)`. The handler still
|
|
78
143
|
* emits the event itself.
|
|
79
144
|
*/
|
|
145
|
+
/**
|
|
146
|
+
* Declare authorization that the handler resolves (see the `dynamicAuthz` gate).
|
|
147
|
+
* A no-op middleware, exactly like {@link audited}: it records the rule on the
|
|
148
|
+
* route table so the contract can print it.
|
|
149
|
+
*
|
|
150
|
+
* `rule` is read by a human, so it should name the real predicate — e.g.
|
|
151
|
+
* `'sysadmin, or an admin of an ancestor org of the target user'`.
|
|
152
|
+
*/
|
|
153
|
+
export declare function dynamicAuthz(rule: string, opts: {
|
|
154
|
+
reachableBy: readonly DynamicPrincipal[];
|
|
155
|
+
permissions?: readonly Permission[];
|
|
156
|
+
}): (req: unknown, res: unknown, next: () => void) => void;
|
|
80
157
|
export declare function audited(...actions: string[]): (req: unknown, res: unknown, next: () => void) => void;
|
|
81
158
|
/** Resolved requirements for one method + path. */
|
|
82
159
|
export interface RouteTableEntry {
|
|
@@ -92,6 +169,20 @@ export interface RouteTableEntry {
|
|
|
92
169
|
}>;
|
|
93
170
|
systemAdmin: boolean;
|
|
94
171
|
servicePrincipal: boolean;
|
|
172
|
+
/** Authorization the HANDLER resolves, in prose — see the `dynamicAuthz` gate.
|
|
173
|
+
* Empty when the route's authority is fully expressed by the gates above. */
|
|
174
|
+
dynamicAuthz: string[];
|
|
175
|
+
/** The principal kinds those dynamic rules admit, deduped and sorted. Absent
|
|
176
|
+
* when the route declares no dynamic rule, so tables without one are
|
|
177
|
+
* unchanged. This is the machine-readable half of `dynamicAuthz`: it is how
|
|
178
|
+
* "which routes can the superadmin flag reach?" is answerable without
|
|
179
|
+
* reading prose. */
|
|
180
|
+
dynamicReachableBy?: DynamicPrincipal[];
|
|
181
|
+
/** Permission ids a dynamic rule consults inside the handler, deduped and
|
|
182
|
+
* sorted. Absent when none does. These are REAL enforcement — the coverage
|
|
183
|
+
* scan counts a `userHasPermission(req, 'x')` in a controller — so the
|
|
184
|
+
* contract should not read as though the route asked for nothing. */
|
|
185
|
+
dynamicPermissions?: Permission[];
|
|
95
186
|
/**
|
|
96
187
|
* The services allowed to call this route when it is INTERNAL (`requireInternalService`).
|
|
97
188
|
* An empty array means the route is not internal — a user token may reach it,
|
|
@@ -132,6 +223,19 @@ export interface RouteTableEntry {
|
|
|
132
223
|
features: string[];
|
|
133
224
|
scopes: string[];
|
|
134
225
|
audit: string[];
|
|
226
|
+
/**
|
|
227
|
+
* The quota middleware in the chain: the types metered (once per 2xx) and
|
|
228
|
+
* checked (429 when spent). `metered` is NOT deduped — a type listed twice is
|
|
229
|
+
* metered twice, which the coverage check flags. `exempt` marks a route on the
|
|
230
|
+
* fleet-wide `QUOTA_EXEMPT_ROUTES` list, where the `apiCalls` meter and check
|
|
231
|
+
* are no-ops at runtime (so `apiCalls` is left out of both lists). Absent when
|
|
232
|
+
* the chain has no quota middleware and the route is not exempt.
|
|
233
|
+
*/
|
|
234
|
+
quota?: {
|
|
235
|
+
metered: string[];
|
|
236
|
+
checked: string[];
|
|
237
|
+
exempt?: true;
|
|
238
|
+
};
|
|
135
239
|
}
|
|
136
240
|
/**
|
|
137
241
|
* Build the route table of an assembled Express app (or router): one entry per
|