@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.
Files changed (91) hide show
  1. package/lib/constants/ai-providers.d.ts +3 -22
  2. package/lib/constants/ai-providers.js +6 -56
  3. package/lib/errors/app-errors.d.ts +14 -0
  4. package/lib/errors/app-errors.js +21 -1
  5. package/lib/helpers/index.d.ts +1 -0
  6. package/lib/helpers/index.js +2 -1
  7. package/lib/helpers/sse-helpers.d.ts +33 -3
  8. package/lib/helpers/sse-helpers.js +91 -19
  9. package/lib/helpers/support-calendar.d.ts +69 -0
  10. package/lib/helpers/support-calendar.js +179 -0
  11. package/lib/middleware/auth.js +6 -3
  12. package/lib/middleware/deferred-quota-check.d.ts +5 -0
  13. package/lib/middleware/deferred-quota-check.js +33 -0
  14. package/lib/middleware/ecosystem-guard.d.ts +3 -3
  15. package/lib/middleware/ecosystem-guard.js +5 -5
  16. package/lib/middleware/index.d.ts +5 -2
  17. package/lib/middleware/index.js +6 -3
  18. package/lib/middleware/on-behalf.d.ts +37 -0
  19. package/lib/middleware/on-behalf.js +143 -0
  20. package/lib/middleware/permission-gates.d.ts +11 -0
  21. package/lib/middleware/permission-gates.js +7 -1
  22. package/lib/middleware/quota-exempt-routes.d.ts +36 -0
  23. package/lib/middleware/quota-exempt-routes.js +47 -0
  24. package/lib/middleware/route-table.d.ts +104 -0
  25. package/lib/middleware/route-table.js +72 -2
  26. package/lib/middleware/service-tokens.d.ts +8 -0
  27. package/lib/middleware/service-tokens.js +5 -3
  28. package/lib/middleware/step-up.js +11 -1
  29. package/lib/services/ai-call-weight.d.ts +24 -0
  30. package/lib/services/ai-call-weight.js +77 -0
  31. package/lib/services/alert-delivery.d.ts +99 -0
  32. package/lib/services/alert-delivery.js +132 -0
  33. package/lib/services/audit-context.d.ts +105 -0
  34. package/lib/services/audit-context.js +134 -0
  35. package/lib/services/index.d.ts +10 -2
  36. package/lib/services/index.js +10 -2
  37. package/lib/services/org-ai-client.d.ts +61 -0
  38. package/lib/services/org-ai-client.js +112 -0
  39. package/lib/services/pagerduty-inbound.d.ts +101 -0
  40. package/lib/services/pagerduty-inbound.js +195 -0
  41. package/lib/services/pagerduty.d.ts +109 -0
  42. package/lib/services/pagerduty.js +186 -0
  43. package/lib/services/quota-increment-batcher.d.ts +81 -0
  44. package/lib/services/quota-increment-batcher.js +166 -0
  45. package/lib/services/quota.d.ts +158 -14
  46. package/lib/services/quota.js +252 -22
  47. package/lib/services/remote-audit-client.d.ts +44 -1
  48. package/lib/services/remote-audit-client.js +106 -20
  49. package/lib/services/version-vuln-policy.d.ts +174 -0
  50. package/lib/services/version-vuln-policy.js +242 -0
  51. package/lib/types/ai-catalog.d.ts +63 -0
  52. package/lib/types/ai-catalog.js +82 -0
  53. package/lib/types/ask-proposals.js +6 -6
  54. package/lib/types/build-catalog.d.ts +154 -0
  55. package/lib/types/build-catalog.js +158 -0
  56. package/lib/types/common.d.ts +37 -3
  57. package/lib/types/common.js +20 -2
  58. package/lib/types/ecosystem-notifications.d.ts +5 -5
  59. package/lib/types/ecosystem-notifications.js +9 -3
  60. package/lib/types/error-codes.d.ts +13 -6
  61. package/lib/types/error-codes.js +18 -8
  62. package/lib/types/feature-flags.d.ts +71 -1
  63. package/lib/types/feature-flags.js +131 -11
  64. package/lib/types/index.d.ts +6 -4
  65. package/lib/types/index.js +12 -5
  66. package/lib/types/metadata-keys.d.ts +6 -0
  67. package/lib/types/metadata-keys.js +4 -1
  68. package/lib/types/permissions.d.ts +351 -3
  69. package/lib/types/permissions.js +610 -21
  70. package/lib/types/pipeline.d.ts +39 -0
  71. package/lib/types/pipeline.js +57 -1
  72. package/lib/types/plugin-health.d.ts +0 -2
  73. package/lib/types/plugin-health.js +1 -11
  74. package/lib/types/plugin-scan.d.ts +192 -42
  75. package/lib/types/plugin-scan.js +159 -43
  76. package/lib/types/quota-catalog.d.ts +247 -0
  77. package/lib/types/quota-catalog.js +122 -0
  78. package/lib/types/quota-tiers.d.ts +150 -0
  79. package/lib/types/quota-tiers.js +167 -2
  80. package/lib/types/remote-audit-actions.d.ts +1 -1
  81. package/lib/types/remote-audit-actions.js +217 -4
  82. package/lib/types/wire-vocabulary.js +8 -1
  83. package/lib/utils/index.d.ts +1 -1
  84. package/lib/utils/index.js +2 -2
  85. package/lib/utils/response.d.ts +35 -2
  86. package/lib/utils/response.js +42 -3
  87. package/lib/validation/ai-schemas.d.ts +27 -0
  88. package/lib/validation/ai-schemas.js +31 -5
  89. package/lib/validation/plugin-schemas.d.ts +15 -0
  90. package/lib/validation/plugin-schemas.js +28 -1
  91. 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