@pipeline-builder/api-core 4.1.2 → 4.1.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 (81) hide show
  1. package/README.md +3 -3
  2. package/lib/errors/app-errors.d.ts +0 -4
  3. package/lib/errors/app-errors.js +1 -8
  4. package/lib/helpers/restore-helpers.d.ts +3 -3
  5. package/lib/helpers/restore-helpers.js +4 -4
  6. package/lib/helpers/sse-helpers.d.ts +8 -1
  7. package/lib/helpers/sse-helpers.js +11 -3
  8. package/lib/middleware/auth.d.ts +174 -43
  9. package/lib/middleware/auth.js +384 -179
  10. package/lib/middleware/index.d.ts +1 -0
  11. package/lib/middleware/index.js +2 -1
  12. package/lib/middleware/route-table.d.ts +104 -0
  13. package/lib/middleware/route-table.js +230 -0
  14. package/lib/middleware/step-up.d.ts +48 -16
  15. package/lib/middleware/step-up.js +74 -36
  16. package/lib/services/api-key-exchange.d.ts +25 -0
  17. package/lib/services/api-key-exchange.js +219 -0
  18. package/lib/services/audit-spool.d.ts +2 -3
  19. package/lib/services/audit-spool.js +3 -4
  20. package/lib/services/cache-service.d.ts +65 -21
  21. package/lib/services/cache-service.js +173 -78
  22. package/lib/services/compliance-event-subscriber.d.ts +5 -4
  23. package/lib/services/compliance-event-subscriber.js +8 -6
  24. package/lib/services/durable-event-bus.d.ts +22 -39
  25. package/lib/services/durable-event-bus.js +109 -47
  26. package/lib/services/env-redis.d.ts +114 -35
  27. package/lib/services/env-redis.js +215 -73
  28. package/lib/services/http-client.d.ts +10 -15
  29. package/lib/services/http-client.js +32 -27
  30. package/lib/services/index.d.ts +3 -0
  31. package/lib/services/index.js +4 -1
  32. package/lib/services/jwks-cache.d.ts +102 -0
  33. package/lib/services/jwks-cache.js +222 -0
  34. package/lib/services/leader-lock.d.ts +6 -3
  35. package/lib/services/leader-lock.js +20 -5
  36. package/lib/services/quota.d.ts +44 -10
  37. package/lib/services/quota.js +95 -51
  38. package/lib/services/remote-audit-client.d.ts +1 -1
  39. package/lib/services/remote-audit-client.js +32 -1
  40. package/lib/services/scheduler.d.ts +2 -3
  41. package/lib/services/scheduler.js +2 -2
  42. package/lib/services/service-boot.d.ts +4 -2
  43. package/lib/services/service-boot.js +7 -3
  44. package/lib/services/service-keys.d.ts +83 -0
  45. package/lib/services/service-keys.js +354 -0
  46. package/lib/services/sse-ticket-store.d.ts +55 -22
  47. package/lib/services/sse-ticket-store.js +122 -79
  48. package/lib/services/token-revocation.d.ts +1 -1
  49. package/lib/services/token-revocation.js +31 -19
  50. package/lib/testing/route-coverage.d.ts +64 -0
  51. package/lib/testing/route-coverage.js +183 -0
  52. package/lib/testing/service-tokens.d.ts +66 -0
  53. package/lib/testing/service-tokens.js +137 -0
  54. package/lib/testing/tier-mock.d.ts +2 -2
  55. package/lib/testing/tier-mock.js +3 -3
  56. package/lib/testing/user-tokens.d.ts +75 -0
  57. package/lib/testing/user-tokens.js +115 -0
  58. package/lib/types/catalog-metadata.d.ts +0 -2
  59. package/lib/types/catalog-metadata.js +1 -3
  60. package/lib/types/common.d.ts +103 -4
  61. package/lib/types/common.js +11 -1
  62. package/lib/types/error-codes.d.ts +15 -0
  63. package/lib/types/error-codes.js +22 -1
  64. package/lib/types/permissions.d.ts +35 -1
  65. package/lib/types/permissions.js +70 -2
  66. package/lib/utils/api-key.d.ts +34 -0
  67. package/lib/utils/api-key.js +75 -0
  68. package/lib/utils/env.d.ts +0 -2
  69. package/lib/utils/env.js +1 -6
  70. package/lib/utils/index.d.ts +3 -0
  71. package/lib/utils/index.js +4 -1
  72. package/lib/utils/jwk.d.ts +98 -0
  73. package/lib/utils/jwk.js +139 -0
  74. package/lib/utils/logger.d.ts +4 -1
  75. package/lib/utils/logger.js +1 -22
  76. package/lib/utils/secret-encryption.d.ts +7 -2
  77. package/lib/utils/secret-encryption.js +47 -4
  78. package/lib/utils/secret-rotation.d.ts +17 -0
  79. package/lib/utils/secret-rotation.js +54 -0
  80. package/lib/validation/common-schemas.js +5 -4
  81. package/package.json +20 -1
@@ -1,48 +1,59 @@
1
1
  // Copyright 2026 Pipeline Builder Contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
- import { buildJwtVerifyOptions, verifyJwtWithRotation, isServicePrincipal } from './auth.js';
4
- import { createEnvRedisClient } from '../services/env-redis.js';
3
+ import { verifyUserJwt, isServiceAccountPrincipal, isServicePrincipal } from './auth.js';
4
+ import { tagRouteGate } from './route-table.js';
5
+ import { createEnvRedisClient, createRedisReadyGate } from '../services/env-redis.js';
5
6
  import { getHeaderString } from '../utils/headers.js';
6
7
  import { createLogger } from '../utils/logger.js';
7
8
  import { sendError } from '../utils/response.js';
8
9
  const logger = createLogger('step-up');
9
10
  const HEADER = 'x-step-up-token';
10
11
  /**
11
- * Verify a step-up token: valid signature (primary `JWT_SECRET`, or
12
- * `JWT_SECRET_PREVIOUS` during a rotation), allow-listed algorithm, issuer and
13
- * audience when configured, AND the `type: 'step-up'` + `jti` claims — a plain
14
- * access token shares the secret and `sub`, so without asserting the step-up
15
- * shape it would bypass the gate. Throws on any failure. Does NOT bind to a
16
- * caller — `requireStepUp` does the `sub` match and single-use consume.
12
+ * The factors that count as a SECOND FACTOR, for routes that may only be
13
+ * unlocked by one (#8: impersonation, KMS, IdP settings, platform admin).
17
14
  *
18
- * Delegates to `requireAuth`'s own primitives rather than re-implementing them.
19
- * The hand-rolled copy this replaced dropped TWO of their guards: it never
20
- * pinned issuer/audience (so a step-up token from any other system sharing
21
- * `JWT_SECRET` was accepted wherever `JWT_ISSUER`/`JWT_AUDIENCE` are set), and
22
- * its previous-secret retry had no expiry/not-before carve-out, so an EXPIRED
23
- * token was retried and surfaced as a signature error instead of an expiry one.
15
+ * A password or a provider re-auth proves the same single factor the session was
16
+ * already opened with, so on those routes they are not enough: the point is that
17
+ * someone holding only a stolen session — or only a stolen password — cannot
18
+ * proceed.
24
19
  */
25
- export function verifyStepUpToken(token) {
26
- if (!process.env.JWT_SECRET)
27
- throw new Error('JWT_SECRET environment variable is required');
28
- const payload = verifyJwtWithRotation(token, buildJwtVerifyOptions());
20
+ export const STRONG_STEP_UP_METHODS = ['webauthn', 'totp'];
21
+ /**
22
+ * Verify a step-up token: a valid ES256 signature from one of platform's
23
+ * published signing keys, issuer and audience when configured, AND the
24
+ * `type: 'step-up'` + `jti` claims — a plain access token is signed by the same
25
+ * key and carries the same `sub`, so without asserting the step-up shape it
26
+ * would bypass the gate. Throws on any failure (an unfetchable key set included:
27
+ * an unverifiable token is not a step-up). Does NOT bind to a caller —
28
+ * `requireStepUp` does the `sub` match and single-use consume.
29
+ *
30
+ * Delegates to `requireAuth`'s own primitive (`verifyUserJwt`) rather than
31
+ * re-implementing it. The hand-rolled copy this replaced dropped TWO of its
32
+ * guards: it never pinned issuer/audience, and its previous-secret retry had no
33
+ * expiry/not-before carve-out, so an EXPIRED token surfaced as a signature error.
34
+ */
35
+ export async function verifyStepUpToken(token) {
36
+ const payload = await verifyUserJwt(token);
29
37
  if (payload.type !== 'step-up' || !payload.jti || !payload.sub) {
30
38
  throw new Error('INVALID_STEP_UP_TOKEN');
31
39
  }
32
40
  return payload;
33
41
  }
34
- // -- Single-use jti store -----------------------------------------------------
35
- // Redis SET NX EX when Redis is configured (cross-instance single-use); else a
36
- // bounded process-local map with TTL sweep (per-process). A step-up token is
37
- // 60s-lived. When Redis IS configured it's the authoritative store: a Redis
38
- // error FAILS CLOSED (throws → STEP_UP_INVALID, user re-verifies) rather than
39
- // degrading to the per-instance mem guard, which would accept a cross-instance
40
- // replay during the outage. The mem guard is used ONLY when Redis is absent.
41
42
  let _redis;
42
- function redis() {
43
+ let _redisReady;
44
+ /**
45
+ * The jti client, built lazily. The env client has no offline queue, so a SET on
46
+ * a connection that isn't up yet is rejected — which used to fail the FIRST
47
+ * step-up on every pod. Wait (bounded, never rejecting) for readiness before
48
+ * handing it out; a genuinely down Redis still fails closed on the SET below.
49
+ */
50
+ async function redis() {
43
51
  if (_redis === undefined) {
44
52
  _redis = createEnvRedisClient('step-up-jti');
53
+ _redisReady = _redis ? createRedisReadyGate(_redis) : undefined;
45
54
  }
55
+ if (_redisReady)
56
+ await _redisReady();
46
57
  return _redis;
47
58
  }
48
59
  const memJti = new Map(); // jti -> expiry epoch ms
@@ -80,7 +91,7 @@ function evictOldestJti() {
80
91
  */
81
92
  export async function consumeStepUpJti(jti, expEpochSeconds) {
82
93
  const ttlSeconds = Math.max(1, expEpochSeconds - Math.floor(Date.now() / 1000));
83
- const client = redis();
94
+ const client = await redis();
84
95
  if (client) {
85
96
  // Redis configured ⇒ authoritative cross-instance store. SET NX EX → 'OK'
86
97
  // when newly set, null when already consumed. A thrown Redis error is NOT
@@ -96,23 +107,43 @@ export async function consumeStepUpJti(jti, expEpochSeconds) {
96
107
  memJti.set(jti, Date.now() + ttlSeconds * 1000);
97
108
  return true;
98
109
  }
99
- /**
100
- * Express middleware: require a valid, caller-bound, single-use step-up token in
101
- * the `X-Step-Up-Token` header. Must run AFTER `requireAuth` (needs `req.user`).
102
- */
103
- export async function requireStepUp(req, res, next) {
110
+ export function requireStepUp(reqOrOptions, res, next) {
111
+ // The direct form RETURNS the promise (Express ignores it; a test awaits it),
112
+ // so composing the gate as `router.post('/x', requireStepUp, h)` behaves
113
+ // exactly as it did before the options form existed.
114
+ if (res && next && 'headers' in reqOrOptions) {
115
+ return _requireStepUp({}, reqOrOptions, res, next);
116
+ }
117
+ const options = reqOrOptions;
118
+ return tagRouteGate((reqInner, resInner, nextInner) => {
119
+ void _requireStepUp(options, reqInner, resInner, nextInner);
120
+ }, { kind: 'stepUp', ...(options.methods ? { methods: [...options.methods] } : {}) });
121
+ }
122
+ tagRouteGate(requireStepUp, { kind: 'stepUp' });
123
+ async function _requireStepUp(options, req, res, next) {
104
124
  // Verified internal service principals are EXEMPT: step-up is a re-verify-the-
105
125
  // HUMAN gate (they replay a password-reverify token), which a service token
106
126
  // structurally cannot produce. Services already bypass `requirePermission` on
107
127
  // the same trust basis (a signed service JWT), and internal callers of a
108
128
  // step-up-gated route — e.g. the platform org-cascade's `DELETE /quotas/:orgId`
109
129
  // or the billing→quota entitlement sync — would otherwise be hard-blocked.
110
- // Safe: a service token can only be minted with `JWT_SECRET`, so this can't be
111
- // spoofed by an external client to skip step-up.
130
+ // Safe: a service token can only be minted with a SERVICE's own ES256 key
131
+ // (#14), which no external client holds, so this can't be spoofed to skip
132
+ // step-up.
112
133
  if (isServicePrincipal(req)) {
113
134
  next();
114
135
  return;
115
136
  }
137
+ // An ORG SERVICE ACCOUNT is the opposite case: it is subject to every gate a
138
+ // member is, and there is no person behind it to re-verify — so it can NEVER
139
+ // pass step-up. Refuse explicitly (rather than letting it fall through to the
140
+ // `sub`-bound token check, which would fail with a confusing STEP_UP_MISMATCH)
141
+ // so "a machine credential never satisfies an assurance requirement" is a
142
+ // property of this gate, not a side effect of how step-up tokens are minted.
143
+ if (isServiceAccountPrincipal(req)) {
144
+ sendError(res, 403, 'A service account cannot perform this action — it requires a person to re-verify', 'STEP_UP_NOT_AVAILABLE');
145
+ return;
146
+ }
116
147
  const callerSub = req.user?.sub;
117
148
  if (!callerSub) {
118
149
  sendError(res, 401, 'Authentication required', 'UNAUTHORIZED');
@@ -125,7 +156,7 @@ export async function requireStepUp(req, res, next) {
125
156
  }
126
157
  let payload;
127
158
  try {
128
- payload = verifyStepUpToken(token);
159
+ payload = await verifyStepUpToken(token);
129
160
  }
130
161
  catch {
131
162
  sendError(res, 401, 'Step-up token invalid or expired', 'STEP_UP_INVALID');
@@ -135,6 +166,13 @@ export async function requireStepUp(req, res, next) {
135
166
  sendError(res, 401, 'Step-up token does not match session', 'STEP_UP_MISMATCH');
136
167
  return;
137
168
  }
169
+ // Factor restriction (#8). Checked BEFORE the jti is consumed, so a token
170
+ // earned by the wrong factor can still be spent on a route that accepts it —
171
+ // burning it here would make the refusal destructive as well as confusing.
172
+ if (options.methods && !(payload.method && options.methods.includes(payload.method))) {
173
+ sendError(res, 401, 'This action must be confirmed with a passkey or an authenticator code', 'STEP_UP_METHOD_REQUIRED', { methods: [...options.methods] });
174
+ return;
175
+ }
138
176
  try {
139
177
  if (!(await consumeStepUpJti(payload.jti, payload.exp))) {
140
178
  sendError(res, 401, 'Step-up token already used or expired', 'STEP_UP_REPLAY');
@@ -148,4 +186,4 @@ export async function requireStepUp(req, res, next) {
148
186
  }
149
187
  next();
150
188
  }
151
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC11cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL3N0ZXAtdXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQW9CdEMsT0FBTyxFQUFFLHFCQUFxQixFQUFFLHFCQUFxQixFQUFFLGtCQUFrQixFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzdGLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRWpELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN2QyxNQUFNLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQztBQVdqQzs7Ozs7Ozs7Ozs7Ozs7R0FjRztBQUNILE1BQU0sVUFBVSxpQkFBaUIsQ0FBQyxLQUFhO0lBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVU7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7SUFDNUYsTUFBTSxPQUFPLEdBQUcscUJBQXFCLENBQUMsS0FBSyxFQUFFLHFCQUFxQixFQUFFLENBQWtDLENBQUM7SUFFdkcsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDL0QsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFDRCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDO0FBRUQsZ0ZBQWdGO0FBQ2hGLCtFQUErRTtBQUMvRSw2RUFBNkU7QUFDN0UsNEVBQTRF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QUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3hELFNBQVMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLHVDQUF1QyxFQUFFLGdCQUFnQixDQUFDLENBQUM7WUFDL0UsT0FBTztRQUNULENBQUM7SUFDSCxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE1BQU0sQ0FBQyxLQUFLLENBQUMsNkJBQTZCLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNwRSxTQUFTLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSw2QkFBNkIsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1FBQ3RFLE9BQU87SUFDVCxDQUFDO0lBRUQsSUFBSSxFQUFFLENBQUM7QUFDVCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogYHJlcXVpcmVTdGVwVXBgIOKAlCBhIHNoYXJlZCBzdGVwLXVwIChyZWNlbnQtcGFzc3dvcmQtcmV2ZXJpZnkpIGdhdGUgZm9yIHRoZVxuICogc3RhdGVsZXNzIGFwaSBzZXJ2aWNlcywgbWlycm9yaW5nIHRoZSBwbGF0Zm9ybSBtaWRkbGV3YXJlIG9mIHRoZSBzYW1lIG5hbWUuXG4gKlxuICogRmxvdzogdGhlIFVJIGhpdHMgYFBPU1QgL2FwaS9hdXRoL3N0ZXAtdXBgIChwbGF0Zm9ybSkgdG8gcmUtdmVyaWZ5IHRoZSB1c2VyJ3NcbiAqIHBhc3N3b3JkOyBwbGF0Zm9ybSBtaW50cyBhIHNob3J0LWxpdmVkICg2MHMpIGBzdGVwLXVwYCBKV1Qgc2lnbmVkIHdpdGggdGhlXG4gKiBTQU1FIGBKV1RfU0VDUkVUYCB0aGVzZSBzZXJ2aWNlcyBhbHJlYWR5IHZlcmlmeSBhY2Nlc3MgdG9rZW5zIHdpdGguIFRoZSBVSVxuICogcmVwbGF5cyBpdCBhcyB0aGUgYFgtU3RlcC1VcC1Ub2tlbmAgaGVhZGVyIG9uIHRoZSBkZXN0cnVjdGl2ZS9zZW5zaXRpdmUgY2FsbDtcbiAqIHRoaXMgbWlkZGxld2FyZSB2ZXJpZmllcyBpdCwgYmluZHMgaXQgdG8gdGhlIGNhbGxlciAoYHN1YmAgbWF0Y2gpLCBhbmRcbiAqIGNvbnN1bWVzIGl0cyBganRpYCBvbmNlIChSZWRpcy1iYWNrZWQgY3Jvc3MtaW5zdGFuY2Ugd2hlbiBjb25maWd1cmVkLCBlbHNlIGFcbiAqIGJvdW5kZWQgcHJvY2Vzcy1sb2NhbCBzZXQpIHNvIGEgcmVwbGF5IGluc2lkZSB0aGUgVFRMIGlzIHJlamVjdGVkLlxuICpcbiAqIFdIWSBoZXJlOiByZXN0b3JlIGVuZHBvaW50cyBvbiB0aGUgYXBpIHNlcnZpY2VzIChwaXBlbGluZS9wbHVnaW4vLi4uKSBhcmVcbiAqIHN0ZXAtdXAtZ2F0ZWQsIGJ1dCBzdGVwLXVwIHByZXZpb3VzbHkgbGl2ZWQgb25seSBpbiBgcGxhdGZvcm1gLiBUaGlzIHBvcnRzIHRoZVxuICogdmVyaWZ5ICsgc2luZ2xlLXVzZSBqdGkgaW50byBhcGktY29yZSBzbyBhbnkgc2VydmljZSBjYW4gcmVxdWlyZSBpdC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QsIFJlc3BvbnNlLCBOZXh0RnVuY3Rpb24gfSBmcm9tICdleHByZXNzJztcbmltcG9ydCB7IGJ1aWxkSnd0VmVyaWZ5T3B0aW9ucywgdmVyaWZ5Snd0V2l0aFJvdGF0aW9uLCBpc1NlcnZpY2VQcmluY2lwYWwgfSBmcm9tICcuL2F1dGguanMnO1xuaW1wb3J0IHsgY3JlYXRlRW52UmVkaXNDbGllbnQgfSBmcm9tICcuLi9zZXJ2aWNlcy9lbnYtcmVkaXMuanMnO1xuaW1wb3J0IHsgZ2V0SGVhZGVyU3RyaW5nIH0gZnJvbSAnLi4vdXRpbHMvaGVhZGVycy5qcyc7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuaW1wb3J0IHsgc2VuZEVycm9yIH0gZnJvbSAnLi4vdXRpbHMvcmVzcG9uc2UuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ3N0ZXAtdXAnKTtcbmNvbnN0IEhFQURFUiA9ICd4LXN0ZXAtdXAtdG9rZW4nO1xuXG4vKiogUGF5bG9hZCBvZiBhIHBsYXRmb3JtLWlzc3VlZCBzdGVwLXVwIHRva2VuIChzZWUgcGxhdGZvcm0gaXNzdWVTdGVwVXBUb2tlbikuICovXG5leHBvcnQgaW50ZXJmYWNlIFN0ZXBVcFRva2VuUGF5bG9hZCB7XG4gIHR5cGU6ICdzdGVwLXVwJztcbiAgc3ViOiBzdHJpbmc7XG4gIGp0aTogc3RyaW5nO1xuICBpYXQ6IG51bWJlcjtcbiAgZXhwOiBudW1iZXI7XG59XG5cbi8qKlxuICogVmVyaWZ5IGEgc3RlcC11cCB0b2tlbjogdmFsaWQgc2lnbmF0dXJlIChwcmltYXJ5IGBKV1RfU0VDUkVUYCwgb3JcbiAqIGBKV1RfU0VDUkVUX1BSRVZJT1VTYCBkdXJpbmcgYSByb3RhdGlvbiksIGFsbG93LWxpc3RlZCBhbGdvcml0aG0sIGlzc3VlciBhbmRcbiAqIGF1ZGllbmNlIHdoZW4gY29uZmlndXJlZCwgQU5EIHRoZSBgdHlwZTogJ3N0ZXAtdXAnYCArIGBqdGlgIGNsYWltcyDigJQgYSBwbGFpblxuICogYWNjZXNzIHRva2VuIHNoYXJlcyB0aGUgc2VjcmV0IGFuZCBgc3ViYCwgc28gd2l0aG91dCBhc3NlcnRpbmcgdGhlIHN0ZXAtdXBcbiAqIHNoYXBlIGl0IHdvdWxkIGJ5cGFzcyB0aGUgZ2F0ZS4gVGhyb3dzIG9uIGFueSBmYWlsdXJlLiBEb2VzIE5PVCBiaW5kIHRvIGFcbiAqIGNhbGxlciDigJQgYHJlcXVpcmVTdGVwVXBgIGRvZXMgdGhlIGBzdWJgIG1hdGNoIGFuZCBzaW5nbGUtdXNlIGNvbnN1bWUuXG4gKlxuICogRGVsZWdhdGVzIHRvIGByZXF1aXJlQXV0aGAncyBvd24gcHJpbWl0aXZlcyByYXRoZXIgdGhhbiByZS1pbXBsZW1lbnRpbmcgdGhlbS5cbiAqIFRoZSBoYW5kLXJvbGxlZCBjb3B5IHRoaXMgcmVwbGFjZWQgZHJvcHBlZCBUV08gb2YgdGhlaXIgZ3VhcmRzOiBpdCBuZXZlclxuICogcGlubmVkIGlzc3Vlci9hdWRpZW5jZSAoc28gYSBzdGVwLXVwIHRva2VuIGZyb20gYW55IG90aGVyIHN5c3RlbSBzaGFyaW5nXG4gKiBgSldUX1NFQ1JFVGAgd2FzIGFjY2VwdGVkIHdoZXJldmVyIGBKV1RfSVNTVUVSYC9gSldUX0FVRElFTkNFYCBhcmUgc2V0KSwgYW5kXG4gKiBpdHMgcHJldmlvdXMtc2VjcmV0IHJldHJ5IGhhZCBubyBleHBpcnkvbm90LWJlZm9yZSBjYXJ2ZS1vdXQsIHNvIGFuIEVYUElSRURcbiAqIHRva2VuIHdhcyByZXRyaWVkIGFuZCBzdXJmYWNlZCBhcyBhIHNpZ25hdHVyZSBlcnJvciBpbnN0ZWFkIG9mIGFuIGV4cGlyeSBvbmUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2ZXJpZnlTdGVwVXBUb2tlbih0b2tlbjogc3RyaW5nKTogU3RlcFVwVG9rZW5QYXlsb2FkIHtcbiAgaWYgKCFwcm9jZXNzLmVudi5KV1RfU0VDUkVUKSB0aHJvdyBuZXcgRXJyb3IoJ0pXVF9TRUNSRVQgZW52aXJvbm1lbnQgdmFyaWFibGUgaXMgcmVxdWlyZWQnKTtcbiAgY29uc3QgcGF5bG9hZCA9IHZlcmlmeUp3dFdpdGhSb3RhdGlvbih0b2tlbiwgYnVpbGRKd3RWZXJpZnlPcHRpb25zKCkpIGFzIHVua25vd24gYXMgU3RlcFVwVG9rZW5QYXlsb2FkO1xuXG4gIGlmIChwYXlsb2FkLnR5cGUgIT09ICdzdGVwLXVwJyB8fCAhcGF5bG9hZC5qdGkgfHwgIXBheWxvYWQuc3ViKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdJTlZBTElEX1NURVBfVVBfVE9LRU4nKTtcbiAgfVxuICByZXR1cm4gcGF5bG9hZDtcbn1cblxuLy8gLS0gU2luZ2xlLXVzZSBqdGkgc3RvcmUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIFJlZGlzIFNFVCBOWCBFWCB3aGVuIFJlZGlzIGlzIGNvbmZpZ3VyZWQgKGNyb3NzLWluc3RhbmNlIHNpbmdsZS11c2UpOyBlbHNlIGFcbi8vIGJvdW5kZWQgcHJvY2Vzcy1sb2NhbCBtYXAgd2l0aCBUVEwgc3dlZXAgKHBlci1wcm9jZXNzKS4gQSBzdGVwLXVwIHRva2VuIGlzXG4vLyA2MHMtbGl2ZWQuIFdoZW4gUmVkaXMgSVMgY29uZmlndXJlZCBpdCdzIHRoZSBhdXRob3JpdGF0aXZlIHN0b3JlOiBhIFJlZGlzXG4vLyBlcnJvciBGQUlMUyBDTE9TRUQgKHRocm93cyDihpIgU1RFUF9VUF9JTlZBTElELCB1c2VyIHJlLXZlcmlmaWVzKSByYXRoZXIgdGhhblxuLy8gZGVncmFkaW5nIHRvIHRoZSBwZXItaW5zdGFuY2UgbWVtIGd1YXJkLCB3aGljaCB3b3VsZCBhY2NlcHQgYSBjcm9zcy1pbnN0YW5jZVxuLy8gcmVwbGF5IGR1cmluZyB0aGUgb3V0YWdlLiBUaGUgbWVtIGd1YXJkIGlzIHVzZWQgT05MWSB3aGVuIFJlZGlzIGlzIGFic2VudC5cblxubGV0IF9yZWRpczogeyBzZXQ6ICguLi5hcmdzOiB1bmtub3duW10pID0+IFByb21pc2U8dW5rbm93bj4gfSB8IG51bGwgfCB1bmRlZmluZWQ7XG5mdW5jdGlvbiByZWRpcygpOiB7IHNldDogKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gUHJvbWlzZTx1bmtub3duPiB9IHwgbnVsbCB7XG4gIGlmIChfcmVkaXMgPT09IHVuZGVmaW5lZCkge1xuICAgIF9yZWRpcyA9IGNyZWF0ZUVudlJlZGlzQ2xpZW50PHsgc2V0OiAoLi4uYXJnczogdW5rbm93bltdKSA9PiBQcm9taXNlPHVua25vd24+IH0+KCdzdGVwLXVwLWp0aScpO1xuICB9XG4gIHJldHVybiBfcmVkaXM7XG59XG5cbmNvbnN0IG1lbUp0aSA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7IC8vIGp0aSAtPiBleHBpcnkgZXBvY2ggbXNcbmNvbnN0IG1lbVN3ZWVwID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICBmb3IgKGNvbnN0IFtqdGksIGV4cF0gb2YgbWVtSnRpKSBpZiAoZXhwIDw9IG5vdykgbWVtSnRpLmRlbGV0ZShqdGkpO1xufSwgMzBfMDAwKTtcbm1lbVN3ZWVwLnVucmVmPy4oKTtcblxuLyoqXG4gKiBIYXJkIGNlaWxpbmcgb24gdGhlIHByb2Nlc3MtbG9jYWwganRpIHNldC5cbiAqXG4gKiBUaGUgMzBzIHN3ZWVwIGFsb25lIGRvZXMgTk9UIGJvdW5kIGl0OiBlbnRyaWVzIG9ubHkgbGVhdmUgb25jZSB0aGVpciB0b2tlbidzXG4gKiBUVEwgaGFzIHBhc3NlZCwgc28gYSBidXJzdCBvZiBzdGVwLXVwIHRyYWZmaWMgKG9yIGEgZmxvb2Qgb2YgZGlzdGluY3QgZm9yZ2VkXG4gKiBqdGlzIG9uIGEgUmVkaXMtbGVzcyBkZXBsb3ltZW50KSBncm93cyB0aGUgbWFwIGZhc3RlciB0aGFuIHRoZSBzd2VlcCBkcmFpbnNcbiAqIGl0LiBUaGlzIGlzIGEgcmVwbGF5IGd1YXJkLCBzbyBzaGVkZGluZyB0aGUgT0xERVNUIGVudHJpZXMgaXMgdGhlIHNhZmVcbiAqIGRpcmVjdGlvbjogdGhlIHdvcnN0IGNhc2UgaXMgdGhhdCBhIGxvbmctZXhwaXJlZCBqdGkgY291bGQgYmUgcmVwbGF5ZWQsIGFuZFxuICogZXhwaXJ5IGlzIGVuZm9yY2VkIGluZGVwZW5kZW50bHkgYnkgdGhlIHRva2VuJ3Mgb3duIGBleHBgLlxuICovXG5jb25zdCBNRU1fSlRJX01BWCA9IDEwXzAwMDtcblxuLyoqIERyb3AgdGhlIHNvb25lc3QtdG8tZXhwaXJlIGVudHJpZXMgdW50aWwgdGhlIG1hcCBpcyB1bmRlciB0aGUgY2VpbGluZy4gKi9cbmZ1bmN0aW9uIGV2aWN0T2xkZXN0SnRpKCk6IHZvaWQge1xuICBpZiAobWVtSnRpLnNpemUgPCBNRU1fSlRJX01BWCkgcmV0dXJuO1xuICBjb25zdCBieUV4cGlyeSA9IFsuLi5tZW1KdGkuZW50cmllcygpXS5zb3J0KChhLCBiKSA9PiBhWzFdIC0gYlsxXSk7XG4gIGNvbnN0IGV4Y2VzcyA9IG1lbUp0aS5zaXplIC0gTUVNX0pUSV9NQVggKyAxO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGV4Y2VzczsgaSArPSAxKSBtZW1KdGkuZGVsZXRlKGJ5RXhwaXJ5W2ldWzBdKTtcbn1cblxuLyoqXG4gKiBDb25zdW1lIGEgc3RlcC11cCBganRpYCBleGFjdGx5IG9uY2UuIFJldHVybnMgdHJ1ZSBpZiB0aGlzIGNhbGwgY2xhaW1lZCBpdFxuICogKGZpcnN0IHVzZSksIGZhbHNlIGlmIGl0IHdhcyBhbHJlYWR5IGNvbnN1bWVkIChyZXBsYXkpLiBgZXhwRXBvY2hTZWNvbmRzYCBpc1xuICogdGhlIHRva2VuJ3MgYGV4cGAsIHNvIHRoZSBtYXJrZXIgYXV0by1leHBpcmVzIHdpdGggdGhlIHRva2VuLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29uc3VtZVN0ZXBVcEp0aShqdGk6IHN0cmluZywgZXhwRXBvY2hTZWNvbmRzOiBudW1iZXIpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3QgdHRsU2Vjb25kcyA9IE1hdGgubWF4KDEsIGV4cEVwb2NoU2Vjb25kcyAtIE1hdGguZmxvb3IoRGF0ZS5ub3coKSAvIDEwMDApKTtcbiAgY29uc3QgY2xpZW50ID0gcmVkaXMoKTtcbiAgaWYgKGNsaWVudCkge1xuICAgIC8vIFJlZGlzIGNvbmZpZ3VyZWQg4oeSIGF1dGhvcml0YXRpdmUgY3Jvc3MtaW5zdGFuY2Ugc3RvcmUuIFNFVCBOWCBFWCDihpIgJ09LJ1xuICAgIC8vIHdoZW4gbmV3bHkgc2V0LCBudWxsIHdoZW4gYWxyZWFkeSBjb25zdW1lZC4gQSB0aHJvd24gUmVkaXMgZXJyb3IgaXMgTk9UXG4gICAgLy8gY2F1Z2h0IGhlcmU6IGl0IHByb3BhZ2F0ZXMgc28gYHJlcXVpcmVTdGVwVXBgIGZhaWxzIGNsb3NlZCAoU1RFUF9VUF9JTlZBTElEKVxuICAgIC8vIGluc3RlYWQgb2Ygc2lsZW50bHkgZGVncmFkaW5nIHRvIHRoZSBwZXItaW5zdGFuY2UgbWVtIGd1YXJkLlxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGNsaWVudC5zZXQoYHN0ZXB1cDpqdGk6JHtqdGl9YCwgJzEnLCAnRVgnLCB0dGxTZWNvbmRzLCAnTlgnKTtcbiAgICByZXR1cm4gcmVzID09PSAnT0snO1xuICB9XG4gIC8vIE5vIFJlZGlzIOKHkiBzaW5nbGUtaW5zdGFuY2UgZGVwbG95bWVudDsgdGhlIHByb2Nlc3MtbG9jYWwgbWFwIElTIHRoZSBzdG9yZS5cbiAgaWYgKG1lbUp0aS5oYXMoanRpKSkgcmV0dXJuIGZhbHNlO1xuICBldmljdE9sZGVzdEp0aSgpO1xuICBtZW1KdGkuc2V0KGp0aSwgRGF0ZS5ub3coKSArIHR0bFNlY29uZHMgKiAxMDAwKTtcbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKlxuICogRXhwcmVzcyBtaWRkbGV3YXJlOiByZXF1aXJlIGEgdmFsaWQsIGNhbGxlci1ib3VuZCwgc2luZ2xlLXVzZSBzdGVwLXVwIHRva2VuIGluXG4gKiB0aGUgYFgtU3RlcC1VcC1Ub2tlbmAgaGVhZGVyLiBNdXN0IHJ1biBBRlRFUiBgcmVxdWlyZUF1dGhgIChuZWVkcyBgcmVxLnVzZXJgKS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlcXVpcmVTdGVwVXAocmVxOiBSZXF1ZXN0LCByZXM6IFJlc3BvbnNlLCBuZXh0OiBOZXh0RnVuY3Rpb24pOiBQcm9taXNlPHZvaWQ+IHtcbiAgLy8gVmVyaWZpZWQgaW50ZXJuYWwgc2VydmljZSBwcmluY2lwYWxzIGFyZSBFWEVNUFQ6IHN0ZXAtdXAgaXMgYSByZS12ZXJpZnktdGhlLVxuICAvLyBIVU1BTiBnYXRlICh0aGV5IHJlcGxheSBhIHBhc3N3b3JkLXJldmVyaWZ5IHRva2VuKSwgd2hpY2ggYSBzZXJ2aWNlIHRva2VuXG4gIC8vIHN0cnVjdHVyYWxseSBjYW5ub3QgcHJvZHVjZS4gU2VydmljZXMgYWxyZWFkeSBieXBhc3MgYHJlcXVpcmVQZXJtaXNzaW9uYCBvblxuICAvLyB0aGUgc2FtZSB0cnVzdCBiYXNpcyAoYSBzaWduZWQgc2VydmljZSBKV1QpLCBhbmQgaW50ZXJuYWwgY2FsbGVycyBvZiBhXG4gIC8vIHN0ZXAtdXAtZ2F0ZWQgcm91dGUg4oCUIGUuZy4gdGhlIHBsYXRmb3JtIG9yZy1jYXNjYWRlJ3MgYERFTEVURSAvcXVvdGFzLzpvcmdJZGBcbiAgLy8gb3IgdGhlIGJpbGxpbmfihpJxdW90YSBlbnRpdGxlbWVudCBzeW5jIOKAlCB3b3VsZCBvdGhlcndpc2UgYmUgaGFyZC1ibG9ja2VkLlxuICAvLyBTYWZlOiBhIHNlcnZpY2UgdG9rZW4gY2FuIG9ubHkgYmUgbWludGVkIHdpdGggYEpXVF9TRUNSRVRgLCBzbyB0aGlzIGNhbid0IGJlXG4gIC8vIHNwb29mZWQgYnkgYW4gZXh0ZXJuYWwgY2xpZW50IHRvIHNraXAgc3RlcC11cC5cbiAgaWYgKGlzU2VydmljZVByaW5jaXBhbChyZXEpKSB7XG4gICAgbmV4dCgpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGNhbGxlclN1YiA9IChyZXEgYXMgUmVxdWVzdCAmIHsgdXNlcj86IHsgc3ViPzogc3RyaW5nIH0gfSkudXNlcj8uc3ViO1xuICBpZiAoIWNhbGxlclN1Yikge1xuICAgIHNlbmRFcnJvcihyZXMsIDQwMSwgJ0F1dGhlbnRpY2F0aW9uIHJlcXVpcmVkJywgJ1VOQVVUSE9SSVpFRCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHRva2VuID0gZ2V0SGVhZGVyU3RyaW5nKHJlcS5oZWFkZXJzW0hFQURFUl0pO1xuICBpZiAoIXRva2VuKSB7XG4gICAgc2VuZEVycm9yKHJlcywgNDAxLCAnU3RlcC11cCB2ZXJpZmljYXRpb24gcmVxdWlyZWQnLCAnU1RFUF9VUF9SRVFVSVJFRCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGxldCBwYXlsb2FkOiBTdGVwVXBUb2tlblBheWxvYWQ7XG4gIHRyeSB7XG4gICAgcGF5bG9hZCA9IHZlcmlmeVN0ZXBVcFRva2VuKHRva2VuKTtcbiAgfSBjYXRjaCB7XG4gICAgc2VuZEVycm9yKHJlcywgNDAxLCAnU3RlcC11cCB0b2tlbiBpbnZhbGlkIG9yIGV4cGlyZWQnLCAnU1RFUF9VUF9JTlZBTElEJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHBheWxvYWQuc3ViICE9PSBjYWxsZXJTdWIpIHtcbiAgICBzZW5kRXJyb3IocmVzLCA0MDEsICdTdGVwLXVwIHRva2VuIGRvZXMgbm90IG1hdGNoIHNlc3Npb24nLCAnU1RFUF9VUF9NSVNNQVRDSCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHRyeSB7XG4gICAgaWYgKCEoYXdhaXQgY29uc3VtZVN0ZXBVcEp0aShwYXlsb2FkLmp0aSwgcGF5bG9hZC5leHApKSkge1xuICAgICAgc2VuZEVycm9yKHJlcywgNDAxLCAnU3RlcC11cCB0b2tlbiBhbHJlYWR5IHVzZWQgb3IgZXhwaXJlZCcsICdTVEVQX1VQX1JFUExBWScpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLmVycm9yKCdTdGVwLXVwIGp0aSBjb25zdW1lIGVycm9yZWQnLCB7IGVycm9yOiBTdHJpbmcoZXJyKSB9KTtcbiAgICBzZW5kRXJyb3IocmVzLCA0MDEsICdTdGVwLXVwIHZlcmlmaWNhdGlvbiBmYWlsZWQnLCAnU1RFUF9VUF9JTlZBTElEJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgbmV4dCgpO1xufVxuIl19
189
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC11cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL3N0ZXAtdXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQXFCdEMsT0FBTyxFQUFFLGFBQWEsRUFBRSx5QkFBeUIsRUFBRSxrQkFBa0IsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN6RixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDaEQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLG9CQUFvQixFQUF3QixNQUFNLDBCQUEwQixDQUFDO0FBQzVHLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN0RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBRWpELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN2QyxNQUFNLE1BQU0sR0FBRyxpQkFBaUIsQ0FBQztBQVNqQzs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUE0QixDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztBQXFCcEY7Ozs7Ozs7Ozs7Ozs7R0FhRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsaUJBQWlCLENBQUMsS0FBYTtJQUNuRCxNQUFNLE9BQU8sR0FBRyxNQUFNLGFBQWEsQ0FBcUIsS0FBSyxDQUFDLENBQUM7SUFFL0QsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDL0QsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFDRCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDO0FB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RTtJQUMxRSw2RUFBNkU7SUFDN0UsMkVBQTJFO0lBQzNFLElBQUksT0FBTyxDQUFDLE9BQU8sSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3JGLFNBQVMsQ0FDUCxHQUFHLEVBQUUsR0FBRyxFQUNSLHVFQUF1RSxFQUN2RSx5QkFBeUIsRUFDekIsRUFBRSxPQUFPLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUNsQyxDQUFDO1FBQ0YsT0FBTztJQUNULENBQUM7SUFFRCxJQUFJLENBQUM7UUFDSCxJQUFJLENBQUMsQ0FBQyxNQUFNLGdCQUFnQixDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN4RCxTQUFTLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSx1Q0FBdUMsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO1lBQy9FLE9BQU87UUFDVCxDQUFDO0lBQ0gsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixNQUFNLENBQUMsS0FBSyxDQUFDLDZCQUE2QixFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDcEUsU0FBUyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsNkJBQTZCLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztRQUN0RSxPQUFPO0lBQ1QsQ0FBQztJQUVELElBQUksRUFBRSxDQUFDO0FBQ1QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG4vKipcbiAqIGByZXF1aXJlU3RlcFVwYCDigJQgYSBzaGFyZWQgc3RlcC11cCAocmVjZW50LXBhc3N3b3JkLXJldmVyaWZ5KSBnYXRlIGZvciB0aGVcbiAqIHN0YXRlbGVzcyBhcGkgc2VydmljZXMsIG1pcnJvcmluZyB0aGUgcGxhdGZvcm0gbWlkZGxld2FyZSBvZiB0aGUgc2FtZSBuYW1lLlxuICpcbiAqIEZsb3c6IHRoZSBVSSBoaXRzIGBQT1NUIC9hcGkvYXV0aC9zdGVwLXVwYCAocGxhdGZvcm0pIHRvIHJlLXZlcmlmeSB0aGUgdXNlcjtcbiAqIHBsYXRmb3JtIG1pbnRzIGEgc2hvcnQtbGl2ZWQgKDYwcykgYHN0ZXAtdXBgIEpXVCB3aXRoIHRoZSBTQU1FIEVTMjU2IHNpZ25pbmdcbiAqIGtleSBpdCBtaW50cyBhY2Nlc3MgdG9rZW5zIHdpdGgsIHNvIHRoZXNlIHNlcnZpY2VzIHZlcmlmeSBpdCB0aHJvdWdoIHRoZSBzYW1lXG4gKiBKV0tTLiBUaGUgVUlcbiAqIHJlcGxheXMgaXQgYXMgdGhlIGBYLVN0ZXAtVXAtVG9rZW5gIGhlYWRlciBvbiB0aGUgZGVzdHJ1Y3RpdmUvc2Vuc2l0aXZlIGNhbGw7XG4gKiB0aGlzIG1pZGRsZXdhcmUgdmVyaWZpZXMgaXQsIGJpbmRzIGl0IHRvIHRoZSBjYWxsZXIgKGBzdWJgIG1hdGNoKSwgYW5kXG4gKiBjb25zdW1lcyBpdHMgYGp0aWAgb25jZSAoUmVkaXMtYmFja2VkIGNyb3NzLWluc3RhbmNlIHdoZW4gY29uZmlndXJlZCwgZWxzZSBhXG4gKiBib3VuZGVkIHByb2Nlc3MtbG9jYWwgc2V0KSBzbyBhIHJlcGxheSBpbnNpZGUgdGhlIFRUTCBpcyByZWplY3RlZC5cbiAqXG4gKiBXSFkgaGVyZTogcmVzdG9yZSBlbmRwb2ludHMgb24gdGhlIGFwaSBzZXJ2aWNlcyAocGlwZWxpbmUvcGx1Z2luLy4uLikgYXJlXG4gKiBzdGVwLXVwLWdhdGVkLCBidXQgc3RlcC11cCBwcmV2aW91c2x5IGxpdmVkIG9ubHkgaW4gYHBsYXRmb3JtYC4gVGhpcyBwb3J0cyB0aGVcbiAqIHZlcmlmeSArIHNpbmdsZS11c2UganRpIGludG8gYXBpLWNvcmUgc28gYW55IHNlcnZpY2UgY2FuIHJlcXVpcmUgaXQuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBSZXF1ZXN0LCBSZXNwb25zZSwgTmV4dEZ1bmN0aW9uIH0gZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgeyB2ZXJpZnlVc2VySnd0LCBpc1NlcnZpY2VBY2NvdW50UHJpbmNpcGFsLCBpc1NlcnZpY2VQcmluY2lwYWwgfSBmcm9tICcuL2F1dGguanMnO1xuaW1wb3J0IHsgdGFnUm91dGVHYXRlIH0gZnJvbSAnLi9yb3V0ZS10YWJsZS5qcyc7XG5pbXBvcnQgeyBjcmVhdGVFbnZSZWRpc0NsaWVudCwgY3JlYXRlUmVkaXNSZWFkeUdhdGUsIHR5cGUgUmVhZHlBd2FyZVJlZGlzIH0gZnJvbSAnLi4vc2VydmljZXMvZW52LXJlZGlzLmpzJztcbmltcG9ydCB7IGdldEhlYWRlclN0cmluZyB9IGZyb20gJy4uL3V0aWxzL2hlYWRlcnMuanMnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IHNlbmRFcnJvciB9IGZyb20gJy4uL3V0aWxzL3Jlc3BvbnNlLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdzdGVwLXVwJyk7XG5jb25zdCBIRUFERVIgPSAneC1zdGVwLXVwLXRva2VuJztcblxuLyoqXG4gKiBIb3cgYSBzdGVwLXVwIHRva2VuIHdhcyBlYXJuZWQuIE1pcnJvcnMgcGxhdGZvcm0ncyBgU3RlcFVwTWV0aG9kYDsga2VwdCBoZXJlXG4gKiBhcyBpdHMgb3duIHVuaW9uIHNvIGEgdmVyaWZpZXIgY2FuIG5hbWUgdGhlIGZhY3RvcnMgaXQgYWNjZXB0cyB3aXRob3V0XG4gKiBpbXBvcnRpbmcgcGxhdGZvcm0uXG4gKi9cbmV4cG9ydCB0eXBlIFN0ZXBVcE1ldGhvZCA9ICdwYXNzd29yZCcgfCAnd2ViYXV0aG4nIHwgJ3RvdHAnIHwgJ3JlYXV0aCc7XG5cbi8qKlxuICogVGhlIGZhY3RvcnMgdGhhdCBjb3VudCBhcyBhIFNFQ09ORCBGQUNUT1IsIGZvciByb3V0ZXMgdGhhdCBtYXkgb25seSBiZVxuICogdW5sb2NrZWQgYnkgb25lICgjODogaW1wZXJzb25hdGlvbiwgS01TLCBJZFAgc2V0dGluZ3MsIHBsYXRmb3JtIGFkbWluKS5cbiAqXG4gKiBBIHBhc3N3b3JkIG9yIGEgcHJvdmlkZXIgcmUtYXV0aCBwcm92ZXMgdGhlIHNhbWUgc2luZ2xlIGZhY3RvciB0aGUgc2Vzc2lvbiB3YXNcbiAqIGFscmVhZHkgb3BlbmVkIHdpdGgsIHNvIG9uIHRob3NlIHJvdXRlcyB0aGV5IGFyZSBub3QgZW5vdWdoOiB0aGUgcG9pbnQgaXMgdGhhdFxuICogc29tZW9uZSBob2xkaW5nIG9ubHkgYSBzdG9sZW4gc2Vzc2lvbiDigJQgb3Igb25seSBhIHN0b2xlbiBwYXNzd29yZCDigJQgY2Fubm90XG4gKiBwcm9jZWVkLlxuICovXG5leHBvcnQgY29uc3QgU1RST05HX1NURVBfVVBfTUVUSE9EUzogcmVhZG9ubHkgU3RlcFVwTWV0aG9kW10gPSBbJ3dlYmF1dGhuJywgJ3RvdHAnXTtcblxuLyoqIFBheWxvYWQgb2YgYSBwbGF0Zm9ybS1pc3N1ZWQgc3RlcC11cCB0b2tlbiAoc2VlIHBsYXRmb3JtIGlzc3VlU3RlcFVwVG9rZW4pLiAqL1xuZXhwb3J0IGludGVyZmFjZSBTdGVwVXBUb2tlblBheWxvYWQge1xuICB0eXBlOiAnc3RlcC11cCc7XG4gIHN1Yjogc3RyaW5nO1xuICBqdGk6IHN0cmluZztcbiAgLyoqIFdoaWNoIGZhY3RvciBlYXJuZWQgaXQuIEFic2VudCBvbmx5IG9uIGEgdG9rZW4gbWludGVkIGJlZm9yZSB0aGUgY2xhaW1cbiAgICogIGV4aXN0ZWQsIHdoaWNoIGEgbWV0aG9kLXJlc3RyaWN0ZWQgZ2F0ZSB0cmVhdHMgYXMgXCJub3QgcHJvdmVuXCIuICovXG4gIG1ldGhvZD86IFN0ZXBVcE1ldGhvZDtcbiAgaWF0OiBudW1iZXI7XG4gIGV4cDogbnVtYmVyO1xufVxuXG4vKiogT3B0aW9ucyBmb3Ige0BsaW5rIHJlcXVpcmVTdGVwVXB9LiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZXF1aXJlU3RlcFVwT3B0aW9ucyB7XG4gIC8qKiBSZXN0cmljdCB3aGljaCBmYWN0b3JzIG1heSBlYXJuIHRoZSBzdGVwLXVwIChlLmcuIHtAbGluayBTVFJPTkdfU1RFUF9VUF9NRVRIT0RTfSkuXG4gICAqICBPbWl0dGVkIG1lYW5zIGFueSBmYWN0b3IgdGhlIHBsYXRmb3JtIHdpbGwgaXNzdWUgYSB0b2tlbiBmb3IuICovXG4gIG1ldGhvZHM/OiByZWFkb25seSBTdGVwVXBNZXRob2RbXTtcbn1cblxuLyoqXG4gKiBWZXJpZnkgYSBzdGVwLXVwIHRva2VuOiBhIHZhbGlkIEVTMjU2IHNpZ25hdHVyZSBmcm9tIG9uZSBvZiBwbGF0Zm9ybSdzXG4gKiBwdWJsaXNoZWQgc2lnbmluZyBrZXlzLCBpc3N1ZXIgYW5kIGF1ZGllbmNlIHdoZW4gY29uZmlndXJlZCwgQU5EIHRoZVxuICogYHR5cGU6ICdzdGVwLXVwJ2AgKyBganRpYCBjbGFpbXMg4oCUIGEgcGxhaW4gYWNjZXNzIHRva2VuIGlzIHNpZ25lZCBieSB0aGUgc2FtZVxuICoga2V5IGFuZCBjYXJyaWVzIHRoZSBzYW1lIGBzdWJgLCBzbyB3aXRob3V0IGFzc2VydGluZyB0aGUgc3RlcC11cCBzaGFwZSBpdFxuICogd291bGQgYnlwYXNzIHRoZSBnYXRlLiBUaHJvd3Mgb24gYW55IGZhaWx1cmUgKGFuIHVuZmV0Y2hhYmxlIGtleSBzZXQgaW5jbHVkZWQ6XG4gKiBhbiB1bnZlcmlmaWFibGUgdG9rZW4gaXMgbm90IGEgc3RlcC11cCkuIERvZXMgTk9UIGJpbmQgdG8gYSBjYWxsZXIg4oCUXG4gKiBgcmVxdWlyZVN0ZXBVcGAgZG9lcyB0aGUgYHN1YmAgbWF0Y2ggYW5kIHNpbmdsZS11c2UgY29uc3VtZS5cbiAqXG4gKiBEZWxlZ2F0ZXMgdG8gYHJlcXVpcmVBdXRoYCdzIG93biBwcmltaXRpdmUgKGB2ZXJpZnlVc2VySnd0YCkgcmF0aGVyIHRoYW5cbiAqIHJlLWltcGxlbWVudGluZyBpdC4gVGhlIGhhbmQtcm9sbGVkIGNvcHkgdGhpcyByZXBsYWNlZCBkcm9wcGVkIFRXTyBvZiBpdHNcbiAqIGd1YXJkczogaXQgbmV2ZXIgcGlubmVkIGlzc3Vlci9hdWRpZW5jZSwgYW5kIGl0cyBwcmV2aW91cy1zZWNyZXQgcmV0cnkgaGFkIG5vXG4gKiBleHBpcnkvbm90LWJlZm9yZSBjYXJ2ZS1vdXQsIHNvIGFuIEVYUElSRUQgdG9rZW4gc3VyZmFjZWQgYXMgYSBzaWduYXR1cmUgZXJyb3IuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2ZXJpZnlTdGVwVXBUb2tlbih0b2tlbjogc3RyaW5nKTogUHJvbWlzZTxTdGVwVXBUb2tlblBheWxvYWQ+IHtcbiAgY29uc3QgcGF5bG9hZCA9IGF3YWl0IHZlcmlmeVVzZXJKd3Q8U3RlcFVwVG9rZW5QYXlsb2FkPih0b2tlbik7XG5cbiAgaWYgKHBheWxvYWQudHlwZSAhPT0gJ3N0ZXAtdXAnIHx8ICFwYXlsb2FkLmp0aSB8fCAhcGF5bG9hZC5zdWIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0lOVkFMSURfU1RFUF9VUF9UT0tFTicpO1xuICB9XG4gIHJldHVybiBwYXlsb2FkO1xufVxuXG4vLyAtLSBTaW5nbGUtdXNlIGp0aSBzdG9yZSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gUmVkaXMgU0VUIE5YIEVYIHdoZW4gUmVkaXMgaXMgY29uZmlndXJlZCAoY3Jvc3MtaW5zdGFuY2Ugc2luZ2xlLXVzZSk7IGVsc2UgYVxuLy8gYm91bmRlZCBwcm9jZXNzLWxvY2FsIG1hcCB3aXRoIFRUTCBzd2VlcCAocGVyLXByb2Nlc3MpLiBBIHN0ZXAtdXAgdG9rZW4gaXNcbi8vIDYwcy1saXZlZC4gV2hlbiBSZWRpcyBJUyBjb25maWd1cmVkIGl0J3MgdGhlIGF1dGhvcml0YXRpdmUgc3RvcmU6IGEgUmVkaXNcbi8vIGVycm9yIEZBSUxTIENMT1NFRCAodGhyb3dzIOKGkiBTVEVQX1VQX0lOVkFMSUQsIHVzZXIgcmUtdmVyaWZpZXMpIHJhdGhlciB0aGFuXG4vLyBkZWdyYWRpbmcgdG8gdGhlIHBlci1pbnN0YW5jZSBtZW0gZ3VhcmQsIHdoaWNoIHdvdWxkIGFjY2VwdCBhIGNyb3NzLWluc3RhbmNlXG4vLyByZXBsYXkgZHVyaW5nIHRoZSBvdXRhZ2UuIFRoZSBtZW0gZ3VhcmQgaXMgdXNlZCBPTkxZIHdoZW4gUmVkaXMgaXMgYWJzZW50LlxuXG50eXBlIEp0aVJlZGlzID0gUmVhZHlBd2FyZVJlZGlzICYgeyBzZXQ6ICguLi5hcmdzOiB1bmtub3duW10pID0+IFByb21pc2U8dW5rbm93bj4gfTtcbmxldCBfcmVkaXM6IEp0aVJlZGlzIHwgbnVsbCB8IHVuZGVmaW5lZDtcbmxldCBfcmVkaXNSZWFkeTogKCgpID0+IFByb21pc2U8dm9pZD4pIHwgdW5kZWZpbmVkO1xuLyoqXG4gKiBUaGUganRpIGNsaWVudCwgYnVpbHQgbGF6aWx5LiBUaGUgZW52IGNsaWVudCBoYXMgbm8gb2ZmbGluZSBxdWV1ZSwgc28gYSBTRVQgb25cbiAqIGEgY29ubmVjdGlvbiB0aGF0IGlzbid0IHVwIHlldCBpcyByZWplY3RlZCDigJQgd2hpY2ggdXNlZCB0byBmYWlsIHRoZSBGSVJTVFxuICogc3RlcC11cCBvbiBldmVyeSBwb2QuIFdhaXQgKGJvdW5kZWQsIG5ldmVyIHJlamVjdGluZykgZm9yIHJlYWRpbmVzcyBiZWZvcmVcbiAqIGhhbmRpbmcgaXQgb3V0OyBhIGdlbnVpbmVseSBkb3duIFJlZGlzIHN0aWxsIGZhaWxzIGNsb3NlZCBvbiB0aGUgU0VUIGJlbG93LlxuICovXG5hc3luYyBmdW5jdGlvbiByZWRpcygpOiBQcm9taXNlPEp0aVJlZGlzIHwgbnVsbD4ge1xuICBpZiAoX3JlZGlzID09PSB1bmRlZmluZWQpIHtcbiAgICBfcmVkaXMgPSBjcmVhdGVFbnZSZWRpc0NsaWVudDxKdGlSZWRpcz4oJ3N0ZXAtdXAtanRpJyk7XG4gICAgX3JlZGlzUmVhZHkgPSBfcmVkaXMgPyBjcmVhdGVSZWRpc1JlYWR5R2F0ZShfcmVkaXMpIDogdW5kZWZpbmVkO1xuICB9XG4gIGlmIChfcmVkaXNSZWFkeSkgYXdhaXQgX3JlZGlzUmVhZHkoKTtcbiAgcmV0dXJuIF9yZWRpcztcbn1cblxuY29uc3QgbWVtSnRpID0gbmV3IE1hcDxzdHJpbmcsIG51bWJlcj4oKTsgLy8ganRpIC0+IGV4cGlyeSBlcG9jaCBtc1xuY29uc3QgbWVtU3dlZXAgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG4gIGZvciAoY29uc3QgW2p0aSwgZXhwXSBvZiBtZW1KdGkpIGlmIChleHAgPD0gbm93KSBtZW1KdGkuZGVsZXRlKGp0aSk7XG59LCAzMF8wMDApO1xubWVtU3dlZXAudW5yZWY/LigpO1xuXG4vKipcbiAqIEhhcmQgY2VpbGluZyBvbiB0aGUgcHJvY2Vzcy1sb2NhbCBqdGkgc2V0LlxuICpcbiAqIFRoZSAzMHMgc3dlZXAgYWxvbmUgZG9lcyBOT1QgYm91bmQgaXQ6IGVudHJpZXMgb25seSBsZWF2ZSBvbmNlIHRoZWlyIHRva2VuJ3NcbiAqIFRUTCBoYXMgcGFzc2VkLCBzbyBhIGJ1cnN0IG9mIHN0ZXAtdXAgdHJhZmZpYyAob3IgYSBmbG9vZCBvZiBkaXN0aW5jdCBmb3JnZWRcbiAqIGp0aXMgb24gYSBSZWRpcy1sZXNzIGRlcGxveW1lbnQpIGdyb3dzIHRoZSBtYXAgZmFzdGVyIHRoYW4gdGhlIHN3ZWVwIGRyYWluc1xuICogaXQuIFRoaXMgaXMgYSByZXBsYXkgZ3VhcmQsIHNvIHNoZWRkaW5nIHRoZSBPTERFU1QgZW50cmllcyBpcyB0aGUgc2FmZVxuICogZGlyZWN0aW9uOiB0aGUgd29yc3QgY2FzZSBpcyB0aGF0IGEgbG9uZy1leHBpcmVkIGp0aSBjb3VsZCBiZSByZXBsYXllZCwgYW5kXG4gKiBleHBpcnkgaXMgZW5mb3JjZWQgaW5kZXBlbmRlbnRseSBieSB0aGUgdG9rZW4ncyBvd24gYGV4cGAuXG4gKi9cbmNvbnN0IE1FTV9KVElfTUFYID0gMTBfMDAwO1xuXG4vKiogRHJvcCB0aGUgc29vbmVzdC10by1leHBpcmUgZW50cmllcyB1bnRpbCB0aGUgbWFwIGlzIHVuZGVyIHRoZSBjZWlsaW5nLiAqL1xuZnVuY3Rpb24gZXZpY3RPbGRlc3RKdGkoKTogdm9pZCB7XG4gIGlmIChtZW1KdGkuc2l6ZSA8IE1FTV9KVElfTUFYKSByZXR1cm47XG4gIGNvbnN0IGJ5RXhwaXJ5ID0gWy4uLm1lbUp0aS5lbnRyaWVzKCldLnNvcnQoKGEsIGIpID0+IGFbMV0gLSBiWzFdKTtcbiAgY29uc3QgZXhjZXNzID0gbWVtSnRpLnNpemUgLSBNRU1fSlRJX01BWCArIDE7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgZXhjZXNzOyBpICs9IDEpIG1lbUp0aS5kZWxldGUoYnlFeHBpcnlbaV1bMF0pO1xufVxuXG4vKipcbiAqIENvbnN1bWUgYSBzdGVwLXVwIGBqdGlgIGV4YWN0bHkgb25jZS4gUmV0dXJucyB0cnVlIGlmIHRoaXMgY2FsbCBjbGFpbWVkIGl0XG4gKiAoZmlyc3QgdXNlKSwgZmFsc2UgaWYgaXQgd2FzIGFscmVhZHkgY29uc3VtZWQgKHJlcGxheSkuIGBleHBFcG9jaFNlY29uZHNgIGlzXG4gKiB0aGUgdG9rZW4ncyBgZXhwYCwgc28gdGhlIG1hcmtlciBhdXRvLWV4cGlyZXMgd2l0aCB0aGUgdG9rZW4uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjb25zdW1lU3RlcFVwSnRpKGp0aTogc3RyaW5nLCBleHBFcG9jaFNlY29uZHM6IG51bWJlcik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBjb25zdCB0dGxTZWNvbmRzID0gTWF0aC5tYXgoMSwgZXhwRXBvY2hTZWNvbmRzIC0gTWF0aC5mbG9vcihEYXRlLm5vdygpIC8gMTAwMCkpO1xuICBjb25zdCBjbGllbnQgPSBhd2FpdCByZWRpcygpO1xuICBpZiAoY2xpZW50KSB7XG4gICAgLy8gUmVkaXMgY29uZmlndXJlZCDih5IgYXV0aG9yaXRhdGl2ZSBjcm9zcy1pbnN0YW5jZSBzdG9yZS4gU0VUIE5YIEVYIOKGkiAnT0snXG4gICAgLy8gd2hlbiBuZXdseSBzZXQsIG51bGwgd2hlbiBhbHJlYWR5IGNvbnN1bWVkLiBBIHRocm93biBSZWRpcyBlcnJvciBpcyBOT1RcbiAgICAvLyBjYXVnaHQgaGVyZTogaXQgcHJvcGFnYXRlcyBzbyBgcmVxdWlyZVN0ZXBVcGAgZmFpbHMgY2xvc2VkIChTVEVQX1VQX0lOVkFMSUQpXG4gICAgLy8gaW5zdGVhZCBvZiBzaWxlbnRseSBkZWdyYWRpbmcgdG8gdGhlIHBlci1pbnN0YW5jZSBtZW0gZ3VhcmQuXG4gICAgY29uc3QgcmVzID0gYXdhaXQgY2xpZW50LnNldChgc3RlcHVwOmp0aToke2p0aX1gLCAnMScsICdFWCcsIHR0bFNlY29uZHMsICdOWCcpO1xuICAgIHJldHVybiByZXMgPT09ICdPSyc7XG4gIH1cbiAgLy8gTm8gUmVkaXMg4oeSIHNpbmdsZS1pbnN0YW5jZSBkZXBsb3ltZW50OyB0aGUgcHJvY2Vzcy1sb2NhbCBtYXAgSVMgdGhlIHN0b3JlLlxuICBpZiAobWVtSnRpLmhhcyhqdGkpKSByZXR1cm4gZmFsc2U7XG4gIGV2aWN0T2xkZXN0SnRpKCk7XG4gIG1lbUp0aS5zZXQoanRpLCBEYXRlLm5vdygpICsgdHRsU2Vjb25kcyAqIDEwMDApO1xuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBFeHByZXNzIG1pZGRsZXdhcmU6IHJlcXVpcmUgYSB2YWxpZCwgY2FsbGVyLWJvdW5kLCBzaW5nbGUtdXNlIHN0ZXAtdXAgdG9rZW4gaW5cbiAqIHRoZSBgWC1TdGVwLVVwLVRva2VuYCBoZWFkZXIuIE11c3QgcnVuIEFGVEVSIGByZXF1aXJlQXV0aGAgKG5lZWRzIGByZXEudXNlcmApLlxuICpcbiAqIFVzZSBkaXJlY3RseSAoYHJvdXRlci5wb3N0KCcveCcsIHJlcXVpcmVBdXRoLCByZXF1aXJlU3RlcFVwLCBoKWApIGZvciB0aGVcbiAqIG9yZGluYXJ5IGFueS1mYWN0b3IgZ2F0ZSwgb3IgY2FsbCBpdCB3aXRoIGB7IG1ldGhvZHMgfWAgdG8gZGVtYW5kIHRoYXQgdGhlXG4gKiBjb25maXJtYXRpb24gd2FzIGVhcm5lZCBieSBhIHNwZWNpZmljIGZhY3RvciDigJQgYHJlcXVpcmVTdGVwVXAoeyBtZXRob2RzOlxuICogU1RST05HX1NURVBfVVBfTUVUSE9EUyB9KWAgb24gdGhlIHJvdXRlcyB3aGVyZSBhIHBhc3N3b3JkIHJlLXByb21wdCBpcyBub3QgYVxuICogbWVhbmluZ2Z1bCBzZWNvbmQgcHJvb2YuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlU3RlcFVwKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogUHJvbWlzZTx2b2lkPjtcbmV4cG9ydCBmdW5jdGlvbiByZXF1aXJlU3RlcFVwKG9wdGlvbnM6IFJlcXVpcmVTdGVwVXBPcHRpb25zKTogKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKSA9PiB2b2lkO1xuZXhwb3J0IGZ1bmN0aW9uIHJlcXVpcmVTdGVwVXAoXG4gIHJlcU9yT3B0aW9uczogUmVxdWVzdCB8IFJlcXVpcmVTdGVwVXBPcHRpb25zLFxuICByZXM/OiBSZXNwb25zZSxcbiAgbmV4dD86IE5leHRGdW5jdGlvbixcbik6IFByb21pc2U8dm9pZD4gfCAoKHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKSA9PiB2b2lkKSB7XG4gIC8vIFRoZSBkaXJlY3QgZm9ybSBSRVRVUk5TIHRoZSBwcm9taXNlIChFeHByZXNzIGlnbm9yZXMgaXQ7IGEgdGVzdCBhd2FpdHMgaXQpLFxuICAvLyBzbyBjb21wb3NpbmcgdGhlIGdhdGUgYXMgYHJvdXRlci5wb3N0KCcveCcsIHJlcXVpcmVTdGVwVXAsIGgpYCBiZWhhdmVzXG4gIC8vIGV4YWN0bHkgYXMgaXQgZGlkIGJlZm9yZSB0aGUgb3B0aW9ucyBmb3JtIGV4aXN0ZWQuXG4gIGlmIChyZXMgJiYgbmV4dCAmJiAnaGVhZGVycycgaW4gcmVxT3JPcHRpb25zKSB7XG4gICAgcmV0dXJuIF9yZXF1aXJlU3RlcFVwKHt9LCByZXFPck9wdGlvbnMgYXMgUmVxdWVzdCwgcmVzLCBuZXh0KTtcbiAgfVxuICBjb25zdCBvcHRpb25zID0gcmVxT3JPcHRpb25zIGFzIFJlcXVpcmVTdGVwVXBPcHRpb25zO1xuICByZXR1cm4gdGFnUm91dGVHYXRlKFxuICAgIChyZXFJbm5lcjogUmVxdWVzdCwgcmVzSW5uZXI6IFJlc3BvbnNlLCBuZXh0SW5uZXI6IE5leHRGdW5jdGlvbikgPT4ge1xuICAgICAgdm9pZCBfcmVxdWlyZVN0ZXBVcChvcHRpb25zLCByZXFJbm5lciwgcmVzSW5uZXIsIG5leHRJbm5lcik7XG4gICAgfSxcbiAgICB7IGtpbmQ6ICdzdGVwVXAnLCAuLi4ob3B0aW9ucy5tZXRob2RzID8geyBtZXRob2RzOiBbLi4ub3B0aW9ucy5tZXRob2RzXSB9IDoge30pIH0sXG4gICk7XG59XG50YWdSb3V0ZUdhdGUocmVxdWlyZVN0ZXBVcCwgeyBraW5kOiAnc3RlcFVwJyB9KTtcblxuYXN5bmMgZnVuY3Rpb24gX3JlcXVpcmVTdGVwVXAob3B0aW9uczogUmVxdWlyZVN0ZXBVcE9wdGlvbnMsIHJlcTogUmVxdWVzdCwgcmVzOiBSZXNwb25zZSwgbmV4dDogTmV4dEZ1bmN0aW9uKTogUHJvbWlzZTx2b2lkPiB7XG4gIC8vIFZlcmlmaWVkIGludGVybmFsIHNlcnZpY2UgcHJpbmNpcGFscyBhcmUgRVhFTVBUOiBzdGVwLXVwIGlzIGEgcmUtdmVyaWZ5LXRoZS1cbiAgLy8gSFVNQU4gZ2F0ZSAodGhleSByZXBsYXkgYSBwYXNzd29yZC1yZXZlcmlmeSB0b2tlbiksIHdoaWNoIGEgc2VydmljZSB0b2tlblxuICAvLyBzdHJ1Y3R1cmFsbHkgY2Fubm90IHByb2R1Y2UuIFNlcnZpY2VzIGFscmVhZHkgYnlwYXNzIGByZXF1aXJlUGVybWlzc2lvbmAgb25cbiAgLy8gdGhlIHNhbWUgdHJ1c3QgYmFzaXMgKGEgc2lnbmVkIHNlcnZpY2UgSldUKSwgYW5kIGludGVybmFsIGNhbGxlcnMgb2YgYVxuICAvLyBzdGVwLXVwLWdhdGVkIHJvdXRlIOKAlCBlLmcuIHRoZSBwbGF0Zm9ybSBvcmctY2FzY2FkZSdzIGBERUxFVEUgL3F1b3Rhcy86b3JnSWRgXG4gIC8vIG9yIHRoZSBiaWxsaW5n4oaScXVvdGEgZW50aXRsZW1lbnQgc3luYyDigJQgd291bGQgb3RoZXJ3aXNlIGJlIGhhcmQtYmxvY2tlZC5cbiAgLy8gU2FmZTogYSBzZXJ2aWNlIHRva2VuIGNhbiBvbmx5IGJlIG1pbnRlZCB3aXRoIGEgU0VSVklDRSdzIG93biBFUzI1NiBrZXlcbiAgLy8gKCMxNCksIHdoaWNoIG5vIGV4dGVybmFsIGNsaWVudCBob2xkcywgc28gdGhpcyBjYW4ndCBiZSBzcG9vZmVkIHRvIHNraXBcbiAgLy8gc3RlcC11cC5cbiAgaWYgKGlzU2VydmljZVByaW5jaXBhbChyZXEpKSB7XG4gICAgbmV4dCgpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIEFuIE9SRyBTRVJWSUNFIEFDQ09VTlQgaXMgdGhlIG9wcG9zaXRlIGNhc2U6IGl0IGlzIHN1YmplY3QgdG8gZXZlcnkgZ2F0ZSBhXG4gIC8vIG1lbWJlciBpcywgYW5kIHRoZXJlIGlzIG5vIHBlcnNvbiBiZWhpbmQgaXQgdG8gcmUtdmVyaWZ5IOKAlCBzbyBpdCBjYW4gTkVWRVJcbiAgLy8gcGFzcyBzdGVwLXVwLiBSZWZ1c2UgZXhwbGljaXRseSAocmF0aGVyIHRoYW4gbGV0dGluZyBpdCBmYWxsIHRocm91Z2ggdG8gdGhlXG4gIC8vIGBzdWJgLWJvdW5kIHRva2VuIGNoZWNrLCB3aGljaCB3b3VsZCBmYWlsIHdpdGggYSBjb25mdXNpbmcgU1RFUF9VUF9NSVNNQVRDSClcbiAgLy8gc28gXCJhIG1hY2hpbmUgY3JlZGVudGlhbCBuZXZlciBzYXRpc2ZpZXMgYW4gYXNzdXJhbmNlIHJlcXVpcmVtZW50XCIgaXMgYVxuICAvLyBwcm9wZXJ0eSBvZiB0aGlzIGdhdGUsIG5vdCBhIHNpZGUgZWZmZWN0IG9mIGhvdyBzdGVwLXVwIHRva2VucyBhcmUgbWludGVkLlxuICBpZiAoaXNTZXJ2aWNlQWNjb3VudFByaW5jaXBhbChyZXEpKSB7XG4gICAgc2VuZEVycm9yKHJlcywgNDAzLCAnQSBzZXJ2aWNlIGFjY291bnQgY2Fubm90IHBlcmZvcm0gdGhpcyBhY3Rpb24g4oCUIGl0IHJlcXVpcmVzIGEgcGVyc29uIHRvIHJlLXZlcmlmeScsICdTVEVQX1VQX05PVF9BVkFJTEFCTEUnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBjYWxsZXJTdWIgPSAocmVxIGFzIFJlcXVlc3QgJiB7IHVzZXI/OiB7IHN1Yj86IHN0cmluZyB9IH0pLnVzZXI/LnN1YjtcbiAgaWYgKCFjYWxsZXJTdWIpIHtcbiAgICBzZW5kRXJyb3IocmVzLCA0MDEsICdBdXRoZW50aWNhdGlvbiByZXF1aXJlZCcsICdVTkFVVEhPUklaRUQnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB0b2tlbiA9IGdldEhlYWRlclN0cmluZyhyZXEuaGVhZGVyc1tIRUFERVJdKTtcbiAgaWYgKCF0b2tlbikge1xuICAgIHNlbmRFcnJvcihyZXMsIDQwMSwgJ1N0ZXAtdXAgdmVyaWZpY2F0aW9uIHJlcXVpcmVkJywgJ1NURVBfVVBfUkVRVUlSRUQnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBsZXQgcGF5bG9hZDogU3RlcFVwVG9rZW5QYXlsb2FkO1xuICB0cnkge1xuICAgIHBheWxvYWQgPSBhd2FpdCB2ZXJpZnlTdGVwVXBUb2tlbih0b2tlbik7XG4gIH0gY2F0Y2gge1xuICAgIHNlbmRFcnJvcihyZXMsIDQwMSwgJ1N0ZXAtdXAgdG9rZW4gaW52YWxpZCBvciBleHBpcmVkJywgJ1NURVBfVVBfSU5WQUxJRCcpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmIChwYXlsb2FkLnN1YiAhPT0gY2FsbGVyU3ViKSB7XG4gICAgc2VuZEVycm9yKHJlcywgNDAxLCAnU3RlcC11cCB0b2tlbiBkb2VzIG5vdCBtYXRjaCBzZXNzaW9uJywgJ1NURVBfVVBfTUlTTUFUQ0gnKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBGYWN0b3IgcmVzdHJpY3Rpb24gKCM4KS4gQ2hlY2tlZCBCRUZPUkUgdGhlIGp0aSBpcyBjb25zdW1lZCwgc28gYSB0b2tlblxuICAvLyBlYXJuZWQgYnkgdGhlIHdyb25nIGZhY3RvciBjYW4gc3RpbGwgYmUgc3BlbnQgb24gYSByb3V0ZSB0aGF0IGFjY2VwdHMgaXQg4oCUXG4gIC8vIGJ1cm5pbmcgaXQgaGVyZSB3b3VsZCBtYWtlIHRoZSByZWZ1c2FsIGRlc3RydWN0aXZlIGFzIHdlbGwgYXMgY29uZnVzaW5nLlxuICBpZiAob3B0aW9ucy5tZXRob2RzICYmICEocGF5bG9hZC5tZXRob2QgJiYgb3B0aW9ucy5tZXRob2RzLmluY2x1ZGVzKHBheWxvYWQubWV0aG9kKSkpIHtcbiAgICBzZW5kRXJyb3IoXG4gICAgICByZXMsIDQwMSxcbiAgICAgICdUaGlzIGFjdGlvbiBtdXN0IGJlIGNvbmZpcm1lZCB3aXRoIGEgcGFzc2tleSBvciBhbiBhdXRoZW50aWNhdG9yIGNvZGUnLFxuICAgICAgJ1NURVBfVVBfTUVUSE9EX1JFUVVJUkVEJyxcbiAgICAgIHsgbWV0aG9kczogWy4uLm9wdGlvbnMubWV0aG9kc10gfSxcbiAgICApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIHRyeSB7XG4gICAgaWYgKCEoYXdhaXQgY29uc3VtZVN0ZXBVcEp0aShwYXlsb2FkLmp0aSwgcGF5bG9hZC5leHApKSkge1xuICAgICAgc2VuZEVycm9yKHJlcywgNDAxLCAnU3RlcC11cCB0b2tlbiBhbHJlYWR5IHVzZWQgb3IgZXhwaXJlZCcsICdTVEVQX1VQX1JFUExBWScpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nZ2VyLmVycm9yKCdTdGVwLXVwIGp0aSBjb25zdW1lIGVycm9yZWQnLCB7IGVycm9yOiBTdHJpbmcoZXJyKSB9KTtcbiAgICBzZW5kRXJyb3IocmVzLCA0MDEsICdTdGVwLXVwIHZlcmlmaWNhdGlvbiBmYWlsZWQnLCAnU1RFUF9VUF9JTlZBTElEJyk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgbmV4dCgpO1xufVxuIl19
@@ -0,0 +1,25 @@
1
+ /** The key was presented to platform and refused (unknown, revoked, expired). */
2
+ export declare class ApiKeyRejectedError extends Error {
3
+ constructor(message?: string);
4
+ }
5
+ /** Platform could not be reached (or answered 5xx) — the key's validity is unknown. */
6
+ export declare class ApiKeyExchangeUnavailableError extends Error {
7
+ constructor(message?: string);
8
+ }
9
+ /**
10
+ * Name this process in the exchange call's service token. Called from
11
+ * `wireServiceSecurity` at boot (and by the plugin service, which wires its
12
+ * boot security by hand).
13
+ */
14
+ export declare function setApiKeyExchangeServiceName(name: string): void;
15
+ /**
16
+ * The JWT for `key`, from cache when possible. Throws {@link ApiKeyRejectedError}
17
+ * when platform refused the key and {@link ApiKeyExchangeUnavailableError} when
18
+ * it could not be asked.
19
+ */
20
+ export declare function exchangeApiKey(key: string): Promise<string>;
21
+ /**
22
+ * Drop every cached exchange. For tests and for a process that wants to force
23
+ * re-validation; production relies on the TTLs above.
24
+ */
25
+ export declare function resetApiKeyExchangeCache(): void;
@@ -0,0 +1,219 @@
1
+ // Copyright 2026 Pipeline Builder Contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Trade an opaque access key for a short-lived JWT, once, and cache it.
5
+ *
6
+ * Only platform, billing and quota have MongoDB, so the stateless services
7
+ * cannot look up a key hash — and asking platform to validate EVERY request
8
+ * would put it on the hot path of the whole fleet. Instead this module does the
9
+ * exchange once per key (`POST /auth/token/exchange`) and caches the returned
10
+ * JWT in-process until it expires, so `requireAuth` only ever verifies a JWT.
11
+ *
12
+ * Properties that matter:
13
+ *
14
+ * - **Revocation latency is bounded by the token TTL** (5 minutes). A revoked
15
+ * key can no longer be exchanged, and the cached token it already produced
16
+ * dies on its own.
17
+ * - **Early, jittered refresh.** The cached token is re-exchanged in the
18
+ * background at ~75% of its life (±20% jitter) so no request ever blocks on
19
+ * the exchange, and a fleet of pods holding the same key doesn't stampede
20
+ * platform at the same instant.
21
+ * - **One in-flight exchange per key.** Concurrent requests share a promise.
22
+ * - **Short negative cache.** A key platform rejected is remembered for 30s, so
23
+ * a misconfigured client (or a scanner) can't turn every request into a
24
+ * platform round-trip.
25
+ * - **Platform down is a 503, never a 200.** The caller maps
26
+ * {@link ApiKeyExchangeUnavailableError} to "try again", with a metric — it is
27
+ * deliberately NOT fail-open: an unverifiable credential is not an identity.
28
+ *
29
+ * The exchange request itself carries this service's own signed service token,
30
+ * which is what exempts it from platform's IP-keyed `/auth` rate limiter (every
31
+ * pod's exchanges would otherwise share one bucket) and names the caller in
32
+ * platform's audit trail.
33
+ */
34
+ import { getServiceAuthHeader, SYSTEM_ORG_ID } from '../middleware/auth.js';
35
+ import { InternalHttpClient } from '../services/http-client.js';
36
+ import { hashApiKey } from '../utils/api-key.js';
37
+ import { createLogger } from '../utils/logger.js';
38
+ import { emitCounter } from '../utils/metric-emitter.js';
39
+ const logger = createLogger('api-key-exchange');
40
+ /** Most distinct keys held in the process-wide cache before the oldest are dropped. */
41
+ const MAX_CACHED_KEYS = 1000;
42
+ /** How long a platform REJECTION is remembered (ms). */
43
+ const NEGATIVE_TTL_MS = 30_000;
44
+ /** Fraction of a token's life after which a background re-exchange is started. */
45
+ const REFRESH_AT_FRACTION = 0.75;
46
+ /** ± jitter applied to the refresh point, as a fraction of the token's life.
47
+ * Wide enough to de-synchronize a fleet, narrow enough to leave a clear tail of
48
+ * still-valid token after the latest possible refresh. */
49
+ const REFRESH_JITTER_FRACTION = 0.1;
50
+ /** The key was presented to platform and refused (unknown, revoked, expired). */
51
+ export class ApiKeyRejectedError extends Error {
52
+ constructor(message = 'Access key is invalid, revoked or expired') {
53
+ super(message);
54
+ this.name = 'ApiKeyRejectedError';
55
+ }
56
+ }
57
+ /** Platform could not be reached (or answered 5xx) — the key's validity is unknown. */
58
+ export class ApiKeyExchangeUnavailableError extends Error {
59
+ constructor(message = 'Access-key verification is temporarily unavailable') {
60
+ super(message);
61
+ this.name = 'ApiKeyExchangeUnavailableError';
62
+ }
63
+ }
64
+ /** Cache of successful exchanges, keyed by `sha256(key)` — never by the key itself. */
65
+ const tokenCache = new Map();
66
+ /** Cache of rejections, keyed the same way; value is the epoch ms it expires. */
67
+ const rejectionCache = new Map();
68
+ /** In-flight exchanges, so concurrent requests for one key share a round-trip. */
69
+ const inFlight = new Map();
70
+ /** The service name minted into the exchange call's own service token. */
71
+ let serviceName = process.env.SERVICE_NAME || 'unknown';
72
+ /**
73
+ * Name this process in the exchange call's service token. Called from
74
+ * `wireServiceSecurity` at boot (and by the plugin service, which wires its
75
+ * boot security by hand).
76
+ */
77
+ export function setApiKeyExchangeServiceName(name) {
78
+ serviceName = name;
79
+ }
80
+ /** Platform's in-cluster address — the same env pair every other caller uses. */
81
+ function platformClient() {
82
+ return new InternalHttpClient({
83
+ host: process.env.PLATFORM_SERVICE_HOST || 'platform',
84
+ port: parseInt(process.env.PLATFORM_SERVICE_PORT || '3000', 10),
85
+ timeout: parseInt(process.env.API_KEY_EXCHANGE_TIMEOUT_MS || '3000', 10),
86
+ });
87
+ }
88
+ /** The epoch ms at which a token with `ttlSeconds` of life should be refreshed early. */
89
+ function jitteredRefreshAt(issuedAt, ttlSeconds) {
90
+ const lifeMs = ttlSeconds * 1000;
91
+ const jitter = (Math.random() * 2 - 1) * REFRESH_JITTER_FRACTION;
92
+ // Clamp into (0, 1) so the refresh point is always before expiry and never in
93
+ // the past, whatever TTL platform returns.
94
+ const fraction = Math.min(0.95, Math.max(0.1, REFRESH_AT_FRACTION + jitter));
95
+ return issuedAt + lifeMs * fraction;
96
+ }
97
+ /** Drop the oldest entries once the cache is over its cap (keys are long-lived, tokens are not). */
98
+ function evictIfFull() {
99
+ if (tokenCache.size <= MAX_CACHED_KEYS)
100
+ return;
101
+ const now = Date.now();
102
+ for (const [hash, entry] of tokenCache) {
103
+ if (entry.expiresAt <= now)
104
+ tokenCache.delete(hash);
105
+ }
106
+ // Map preserves insertion order — drop from the front until back under the cap.
107
+ while (tokenCache.size > MAX_CACHED_KEYS) {
108
+ const oldest = tokenCache.keys().next();
109
+ if (oldest.done)
110
+ break;
111
+ tokenCache.delete(oldest.value);
112
+ }
113
+ }
114
+ /** One real round-trip to platform. Throws the two typed errors above. */
115
+ async function performExchange(key, hash) {
116
+ const client = platformClient();
117
+ let status;
118
+ let body;
119
+ try {
120
+ const res = await client.post('/auth/token/exchange', { key }, {
121
+ headers: {
122
+ Authorization: getServiceAuthHeader({ serviceName, role: 'member', orgId: SYSTEM_ORG_ID }),
123
+ },
124
+ // The exchange is a pure read of the key record plus a token mint — safe to
125
+ // retry, and a lost retry only costs one extra mint.
126
+ idempotent: true,
127
+ });
128
+ status = res.statusCode;
129
+ body = res.body;
130
+ }
131
+ catch (err) {
132
+ emitCounter('api_key_exchange_total', { result: 'unavailable' });
133
+ emitCounter('api_key_exchange_failures_total', { reason: 'unavailable' });
134
+ logger.warn('Access-key exchange failed to reach platform', {
135
+ error: err instanceof Error ? err.message : String(err),
136
+ });
137
+ throw new ApiKeyExchangeUnavailableError();
138
+ }
139
+ if (status === 401 || status === 403 || status === 400 || status === 404) {
140
+ rejectionCache.set(hash, Date.now() + NEGATIVE_TTL_MS);
141
+ emitCounter('api_key_exchange_total', { result: 'rejected' });
142
+ emitCounter('api_key_exchange_failures_total', { reason: 'rejected' });
143
+ throw new ApiKeyRejectedError();
144
+ }
145
+ const accessToken = body?.data?.accessToken;
146
+ if (status >= 400 || typeof accessToken !== 'string' || accessToken.length === 0) {
147
+ // 429 and 5xx land here: platform is up but can't answer right now, which is
148
+ // "unknown", not "invalid" — never cache it as a rejection.
149
+ emitCounter('api_key_exchange_total', { result: 'unavailable' });
150
+ emitCounter('api_key_exchange_failures_total', { reason: status === 429 ? 'throttled' : 'server_error' });
151
+ throw new ApiKeyExchangeUnavailableError();
152
+ }
153
+ const ttlSeconds = typeof body?.data?.expiresIn === 'number' && body.data.expiresIn > 0
154
+ ? body.data.expiresIn
155
+ : 60;
156
+ const now = Date.now();
157
+ const entry = {
158
+ token: accessToken,
159
+ expiresAt: now + ttlSeconds * 1000,
160
+ refreshAt: jitteredRefreshAt(now, ttlSeconds),
161
+ };
162
+ tokenCache.set(hash, entry);
163
+ rejectionCache.delete(hash);
164
+ evictIfFull();
165
+ emitCounter('api_key_exchange_total', { result: 'success' });
166
+ return entry;
167
+ }
168
+ /** Exchange, sharing a single in-flight round-trip per key. */
169
+ function exchangeOnce(key, hash) {
170
+ const pending = inFlight.get(hash);
171
+ if (pending)
172
+ return pending;
173
+ const promise = performExchange(key, hash).finally(() => inFlight.delete(hash));
174
+ inFlight.set(hash, promise);
175
+ return promise;
176
+ }
177
+ /**
178
+ * The JWT for `key`, from cache when possible. Throws {@link ApiKeyRejectedError}
179
+ * when platform refused the key and {@link ApiKeyExchangeUnavailableError} when
180
+ * it could not be asked.
181
+ */
182
+ export async function exchangeApiKey(key) {
183
+ const hash = hashApiKey(key);
184
+ const now = Date.now();
185
+ const rejectedUntil = rejectionCache.get(hash);
186
+ if (rejectedUntil !== undefined) {
187
+ if (rejectedUntil > now) {
188
+ emitCounter('api_key_exchange_cache_total', { result: 'rejected' });
189
+ throw new ApiKeyRejectedError();
190
+ }
191
+ rejectionCache.delete(hash);
192
+ }
193
+ const cached = tokenCache.get(hash);
194
+ if (cached && cached.expiresAt > now) {
195
+ if (cached.refreshAt <= now && !inFlight.has(hash)) {
196
+ // Early refresh: warm the cache WITHOUT making this request wait. A failed
197
+ // background refresh is not this request's problem — the cached token is
198
+ // still valid, and the next request past expiry exchanges inline.
199
+ emitCounter('api_key_exchange_cache_total', { result: 'refresh' });
200
+ void exchangeOnce(key, hash).catch(() => { });
201
+ }
202
+ else {
203
+ emitCounter('api_key_exchange_cache_total', { result: 'hit' });
204
+ }
205
+ return cached.token;
206
+ }
207
+ emitCounter('api_key_exchange_cache_total', { result: 'miss' });
208
+ return (await exchangeOnce(key, hash)).token;
209
+ }
210
+ /**
211
+ * Drop every cached exchange. For tests and for a process that wants to force
212
+ * re-validation; production relies on the TTLs above.
213
+ */
214
+ export function resetApiKeyExchangeCache() {
215
+ tokenCache.clear();
216
+ rejectionCache.clear();
217
+ inFlight.clear();
218
+ }
219
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBpLWtleS1leGNoYW5nZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9hcGkta2V5LWV4Y2hhbmdlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7QUFFdEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQThCRztBQUVILE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxhQUFhLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUM1RSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUV6RCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsa0JBQWtCLENBQUMsQ0FBQztBQUVoRCx1RkFBdUY7QUFDdkYsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDO0FBRTdCLHdEQUF3RDtBQUN4RCxNQUFNLGVBQWUsR0FBRyxNQUFNLENBQUM7QUFFL0Isa0ZBQWtGO0FBQ2xGLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDO0FBRWpDOzsyREFFMkQ7QUFDM0QsTUFBTSx1QkFBdUIsR0FBRyxHQUFHLENBQUM7QUFFcEMsaUZBQWlGO0FBQ2pGLE1BQU0sT0FBTyxtQkFBb0IsU0FBUSxLQUFLO0lBQzVDLFlBQVksT0FBTyxHQUFHLDJDQUEyQztRQUMvRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLHFCQUFxQixDQUFDO0lBQ3BDLENBQUM7Q0FDRjtBQUVELHVGQUF1RjtBQUN2RixNQUFNLE9BQU8sOEJBQStCLFNBQVEsS0FBSztJQUN2RCxZQUFZLE9BQU8sR0FBRyxvREFBb0Q7UUFDeEUsS0FBSyxD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SSxNQUFNLElBQUksTUFBTSxDQUFDLFNBQVMsR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUNyQyxJQUFJLE1BQU0sQ0FBQyxTQUFTLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ25ELDJFQUEyRTtZQUMzRSx5RUFBeUU7WUFDekUsa0VBQWtFO1lBQ2xFLFdBQVcsQ0FBQyw4QkFBOEIsRUFBRSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1lBQ25FLEtBQUssWUFBWSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEdBQTZDLENBQUMsQ0FBQyxDQUFDO1FBQzFGLENBQUM7YUFBTSxDQUFDO1lBQ04sV0FBVyxDQUFDLDhCQUE4QixFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDakUsQ0FBQztRQUNELE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQztJQUN0QixDQUFDO0lBRUQsV0FBVyxDQUFDLDhCQUE4QixFQUFFLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDaEUsT0FBTyxDQUFDLE1BQU0sWUFBWSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztBQUMvQyxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLHdCQUF3QjtJQUN0QyxVQUFVLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDbkIsY0FBYyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBQ3ZCLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQztBQUNuQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogVHJhZGUgYW4gb3BhcXVlIGFjY2VzcyBrZXkgZm9yIGEgc2hvcnQtbGl2ZWQgSldULCBvbmNlLCBhbmQgY2FjaGUgaXQuXG4gKlxuICogT25seSBwbGF0Zm9ybSwgYmlsbGluZyBhbmQgcXVvdGEgaGF2ZSBNb25nb0RCLCBzbyB0aGUgc3RhdGVsZXNzIHNlcnZpY2VzXG4gKiBjYW5ub3QgbG9vayB1cCBhIGtleSBoYXNoIOKAlCBhbmQgYXNraW5nIHBsYXRmb3JtIHRvIHZhbGlkYXRlIEVWRVJZIHJlcXVlc3RcbiAqIHdvdWxkIHB1dCBpdCBvbiB0aGUgaG90IHBhdGggb2YgdGhlIHdob2xlIGZsZWV0LiBJbnN0ZWFkIHRoaXMgbW9kdWxlIGRvZXMgdGhlXG4gKiBleGNoYW5nZSBvbmNlIHBlciBrZXkgKGBQT1NUIC9hdXRoL3Rva2VuL2V4Y2hhbmdlYCkgYW5kIGNhY2hlcyB0aGUgcmV0dXJuZWRcbiAqIEpXVCBpbi1wcm9jZXNzIHVudGlsIGl0IGV4cGlyZXMsIHNvIGByZXF1aXJlQXV0aGAgb25seSBldmVyIHZlcmlmaWVzIGEgSldULlxuICpcbiAqIFByb3BlcnRpZXMgdGhhdCBtYXR0ZXI6XG4gKlxuICogLSAqKlJldm9jYXRpb24gbGF0ZW5jeSBpcyBib3VuZGVkIGJ5IHRoZSB0b2tlbiBUVEwqKiAoNSBtaW51dGVzKS4gQSByZXZva2VkXG4gKiAgIGtleSBjYW4gbm8gbG9uZ2VyIGJlIGV4Y2hhbmdlZCwgYW5kIHRoZSBjYWNoZWQgdG9rZW4gaXQgYWxyZWFkeSBwcm9kdWNlZFxuICogICBkaWVzIG9uIGl0cyBvd24uXG4gKiAtICoqRWFybHksIGppdHRlcmVkIHJlZnJlc2guKiogVGhlIGNhY2hlZCB0b2tlbiBpcyByZS1leGNoYW5nZWQgaW4gdGhlXG4gKiAgIGJhY2tncm91bmQgYXQgfjc1JSBvZiBpdHMgbGlmZSAowrEyMCUgaml0dGVyKSBzbyBubyByZXF1ZXN0IGV2ZXIgYmxvY2tzIG9uXG4gKiAgIHRoZSBleGNoYW5nZSwgYW5kIGEgZmxlZXQgb2YgcG9kcyBob2xkaW5nIHRoZSBzYW1lIGtleSBkb2Vzbid0IHN0YW1wZWRlXG4gKiAgIHBsYXRmb3JtIGF0IHRoZSBzYW1lIGluc3RhbnQuXG4gKiAtICoqT25lIGluLWZsaWdodCBleGNoYW5nZSBwZXIga2V5LioqIENvbmN1cnJlbnQgcmVxdWVzdHMgc2hhcmUgYSBwcm9taXNlLlxuICogLSAqKlNob3J0IG5lZ2F0aXZlIGNhY2hlLioqIEEga2V5IHBsYXRmb3JtIHJlamVjdGVkIGlzIHJlbWVtYmVyZWQgZm9yIDMwcywgc29cbiAqICAgYSBtaXNjb25maWd1cmVkIGNsaWVudCAob3IgYSBzY2FubmVyKSBjYW4ndCB0dXJuIGV2ZXJ5IHJlcXVlc3QgaW50byBhXG4gKiAgIHBsYXRmb3JtIHJvdW5kLXRyaXAuXG4gKiAtICoqUGxhdGZvcm0gZG93biBpcyBhIDUwMywgbmV2ZXIgYSAyMDAuKiogVGhlIGNhbGxlciBtYXBzXG4gKiAgIHtAbGluayBBcGlLZXlFeGNoYW5nZVVuYXZhaWxhYmxlRXJyb3J9IHRvIFwidHJ5IGFnYWluXCIsIHdpdGggYSBtZXRyaWMg4oCUIGl0IGlzXG4gKiAgIGRlbGliZXJhdGVseSBOT1QgZmFpbC1vcGVuOiBhbiB1bnZlcmlmaWFibGUgY3JlZGVudGlhbCBpcyBub3QgYW4gaWRlbnRpdHkuXG4gKlxuICogVGhlIGV4Y2hhbmdlIHJlcXVlc3QgaXRzZWxmIGNhcnJpZXMgdGhpcyBzZXJ2aWNlJ3Mgb3duIHNpZ25lZCBzZXJ2aWNlIHRva2VuLFxuICogd2hpY2ggaXMgd2hhdCBleGVtcHRzIGl0IGZyb20gcGxhdGZvcm0ncyBJUC1rZXllZCBgL2F1dGhgIHJhdGUgbGltaXRlciAoZXZlcnlcbiAqIHBvZCdzIGV4Y2hhbmdlcyB3b3VsZCBvdGhlcndpc2Ugc2hhcmUgb25lIGJ1Y2tldCkgYW5kIG5hbWVzIHRoZSBjYWxsZXIgaW5cbiAqIHBsYXRmb3JtJ3MgYXVkaXQgdHJhaWwuXG4gKi9cblxuaW1wb3J0IHsgZ2V0U2VydmljZUF1dGhIZWFkZXIsIFNZU1RFTV9PUkdfSUQgfSBmcm9tICcuLi9taWRkbGV3YXJlL2F1dGguanMnO1xuaW1wb3J0IHsgSW50ZXJuYWxIdHRwQ2xpZW50IH0gZnJvbSAnLi4vc2VydmljZXMvaHR0cC1jbGllbnQuanMnO1xuaW1wb3J0IHsgaGFzaEFwaUtleSB9IGZyb20gJy4uL3V0aWxzL2FwaS1rZXkuanMnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IGVtaXRDb3VudGVyIH0gZnJvbSAnLi4vdXRpbHMvbWV0cmljLWVtaXR0ZXIuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2FwaS1rZXktZXhjaGFuZ2UnKTtcblxuLyoqIE1vc3QgZGlzdGluY3Qga2V5cyBoZWxkIGluIHRoZSBwcm9jZXNzLXdpZGUgY2FjaGUgYmVmb3JlIHRoZSBvbGRlc3QgYXJlIGRyb3BwZWQuICovXG5jb25zdCBNQVhfQ0FDSEVEX0tFWVMgPSAxMDAwO1xuXG4vKiogSG93IGxvbmcgYSBwbGF0Zm9ybSBSRUpFQ1RJT04gaXMgcmVtZW1iZXJlZCAobXMpLiAqL1xuY29uc3QgTkVHQVRJVkVfVFRMX01TID0gMzBfMDAwO1xuXG4vKiogRnJhY3Rpb24gb2YgYSB0b2tlbidzIGxpZmUgYWZ0ZXIgd2hpY2ggYSBiYWNrZ3JvdW5kIHJlLWV4Y2hhbmdlIGlzIHN0YXJ0ZWQuICovXG5jb25zdCBSRUZSRVNIX0FUX0ZSQUNUSU9OID0gMC43NTtcblxuLyoqIMKxIGppdHRlciBhcHBsaWVkIHRvIHRoZSByZWZyZXNoIHBvaW50LCBhcyBhIGZyYWN0aW9uIG9mIHRoZSB0b2tlbidzIGxpZmUuXG4gKiAgV2lkZSBlbm91Z2ggdG8gZGUtc3luY2hyb25pemUgYSBmbGVldCwgbmFycm93IGVub3VnaCB0byBsZWF2ZSBhIGNsZWFyIHRhaWwgb2ZcbiAqICBzdGlsbC12YWxpZCB0b2tlbiBhZnRlciB0aGUgbGF0ZXN0IHBvc3NpYmxlIHJlZnJlc2guICovXG5jb25zdCBSRUZSRVNIX0pJVFRFUl9GUkFDVElPTiA9IDAuMTtcblxuLyoqIFRoZSBrZXkgd2FzIHByZXNlbnRlZCB0byBwbGF0Zm9ybSBhbmQgcmVmdXNlZCAodW5rbm93biwgcmV2b2tlZCwgZXhwaXJlZCkuICovXG5leHBvcnQgY2xhc3MgQXBpS2V5UmVqZWN0ZWRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSA9ICdBY2Nlc3Mga2V5IGlzIGludmFsaWQsIHJldm9rZWQgb3IgZXhwaXJlZCcpIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLm5hbWUgPSAnQXBpS2V5UmVqZWN0ZWRFcnJvcic7XG4gIH1cbn1cblxuLyoqIFBsYXRmb3JtIGNvdWxkIG5vdCBiZSByZWFjaGVkIChvciBhbnN3ZXJlZCA1eHgpIOKAlCB0aGUga2V5J3MgdmFsaWRpdHkgaXMgdW5rbm93bi4gKi9cbmV4cG9ydCBjbGFzcyBBcGlLZXlFeGNoYW5nZVVuYXZhaWxhYmxlRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UgPSAnQWNjZXNzLWtleSB2ZXJpZmljYXRpb24gaXMgdGVtcG9yYXJpbHkgdW5hdmFpbGFibGUnKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5uYW1lID0gJ0FwaUtleUV4Y2hhbmdlVW5hdmFpbGFibGVFcnJvcic7XG4gIH1cbn1cblxuaW50ZXJmYWNlIENhY2hlRW50cnkge1xuICAvKiogVGhlIGV4Y2hhbmdlZCBKV1QuICovXG4gIHRva2VuOiBzdHJpbmc7XG4gIC8qKiBFcG9jaCBtcyBhdCB3aGljaCB0aGUgSldUIHN0b3BzIGJlaW5nIHVzYWJsZS4gKi9cbiAgZXhwaXJlc0F0OiBudW1iZXI7XG4gIC8qKiBFcG9jaCBtcyBhZnRlciB3aGljaCBhIGJhY2tncm91bmQgcmUtZXhjaGFuZ2Ugc2hvdWxkIGJlIHN0YXJ0ZWQuICovXG4gIHJlZnJlc2hBdDogbnVtYmVyO1xufVxuXG4vKiogQ2FjaGUgb2Ygc3VjY2Vzc2Z1bCBleGNoYW5nZXMsIGtleWVkIGJ5IGBzaGEyNTYoa2V5KWAg4oCUIG5ldmVyIGJ5IHRoZSBrZXkgaXRzZWxmLiAqL1xuY29uc3QgdG9rZW5DYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBDYWNoZUVudHJ5PigpO1xuLyoqIENhY2hlIG9mIHJlamVjdGlvbnMsIGtleWVkIHRoZSBzYW1lIHdheTsgdmFsdWUgaXMgdGhlIGVwb2NoIG1zIGl0IGV4cGlyZXMuICovXG5jb25zdCByZWplY3Rpb25DYWNoZSA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4vKiogSW4tZmxpZ2h0IGV4Y2hhbmdlcywgc28gY29uY3VycmVudCByZXF1ZXN0cyBmb3Igb25lIGtleSBzaGFyZSBhIHJvdW5kLXRyaXAuICovXG5jb25zdCBpbkZsaWdodCA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPENhY2hlRW50cnk+PigpO1xuXG4vKiogVGhlIHNlcnZpY2UgbmFtZSBtaW50ZWQgaW50byB0aGUgZXhjaGFuZ2UgY2FsbCdzIG93biBzZXJ2aWNlIHRva2VuLiAqL1xubGV0IHNlcnZpY2VOYW1lID0gcHJvY2Vzcy5lbnYuU0VSVklDRV9OQU1FIHx8ICd1bmtub3duJztcblxuLyoqXG4gKiBOYW1lIHRoaXMgcHJvY2VzcyBpbiB0aGUgZXhjaGFuZ2UgY2FsbCdzIHNlcnZpY2UgdG9rZW4uIENhbGxlZCBmcm9tXG4gKiBgd2lyZVNlcnZpY2VTZWN1cml0eWAgYXQgYm9vdCAoYW5kIGJ5IHRoZSBwbHVnaW4gc2VydmljZSwgd2hpY2ggd2lyZXMgaXRzXG4gKiBib290IHNlY3VyaXR5IGJ5IGhhbmQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0QXBpS2V5RXhjaGFuZ2VTZXJ2aWNlTmFtZShuYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgc2VydmljZU5hbWUgPSBuYW1lO1xufVxuXG4vKiogUGxhdGZvcm0ncyBpbi1jbHVzdGVyIGFkZHJlc3Mg4oCUIHRoZSBzYW1lIGVudiBwYWlyIGV2ZXJ5IG90aGVyIGNhbGxlciB1c2VzLiAqL1xuZnVuY3Rpb24gcGxhdGZvcm1DbGllbnQoKTogSW50ZXJuYWxIdHRwQ2xpZW50IHtcbiAgcmV0dXJuIG5ldyBJbnRlcm5hbEh0dHBDbGllbnQoe1xuICAgIGhvc3Q6IHByb2Nlc3MuZW52LlBMQVRGT1JNX1NFUlZJQ0VfSE9TVCB8fCAncGxhdGZvcm0nLFxuICAgIHBvcnQ6IHBhcnNlSW50KHByb2Nlc3MuZW52LlBMQVRGT1JNX1NFUlZJQ0VfUE9SVCB8fCAnMzAwMCcsIDEwKSxcbiAgICB0aW1lb3V0OiBwYXJzZUludChwcm9jZXNzLmVudi5BUElfS0VZX0VYQ0hBTkdFX1RJTUVPVVRfTVMgfHwgJzMwMDAnLCAxMCksXG4gIH0pO1xufVxuXG4vKiogVGhlIGVwb2NoIG1zIGF0IHdoaWNoIGEgdG9rZW4gd2l0aCBgdHRsU2Vjb25kc2Agb2YgbGlmZSBzaG91bGQgYmUgcmVmcmVzaGVkIGVhcmx5LiAqL1xuZnVuY3Rpb24gaml0dGVyZWRSZWZyZXNoQXQoaXNzdWVkQXQ6IG51bWJlciwgdHRsU2Vjb25kczogbnVtYmVyKTogbnVtYmVyIHtcbiAgY29uc3QgbGlmZU1zID0gdHRsU2Vjb25kcyAqIDEwMDA7XG4gIGNvbnN0IGppdHRlciA9IChNYXRoLnJhbmRvbSgpICogMiAtIDEpICogUkVGUkVTSF9KSVRURVJfRlJBQ1RJT047XG4gIC8vIENsYW1wIGludG8gKDAsIDEpIHNvIHRoZSByZWZyZXNoIHBvaW50IGlzIGFsd2F5cyBiZWZvcmUgZXhwaXJ5IGFuZCBuZXZlciBpblxuICAvLyB0aGUgcGFzdCwgd2hhdGV2ZXIgVFRMIHBsYXRmb3JtIHJldHVybnMuXG4gIGNvbnN0IGZyYWN0aW9uID0gTWF0aC5taW4oMC45NSwgTWF0aC5tYXgoMC4xLCBSRUZSRVNIX0FUX0ZSQUNUSU9OICsgaml0dGVyKSk7XG4gIHJldHVybiBpc3N1ZWRBdCArIGxpZmVNcyAqIGZyYWN0aW9uO1xufVxuXG4vKiogRHJvcCB0aGUgb2xkZXN0IGVudHJpZXMgb25jZSB0aGUgY2FjaGUgaXMgb3ZlciBpdHMgY2FwIChrZXlzIGFyZSBsb25nLWxpdmVkLCB0b2tlbnMgYXJlIG5vdCkuICovXG5mdW5jdGlvbiBldmljdElmRnVsbCgpOiB2b2lkIHtcbiAgaWYgKHRva2VuQ2FjaGUuc2l6ZSA8PSBNQVhfQ0FDSEVEX0tFWVMpIHJldHVybjtcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgZm9yIChjb25zdCBbaGFzaCwgZW50cnldIG9mIHRva2VuQ2FjaGUpIHtcbiAgICBpZiAoZW50cnkuZXhwaXJlc0F0IDw9IG5vdykgdG9rZW5DYWNoZS5kZWxldGUoaGFzaCk7XG4gIH1cbiAgLy8gTWFwIHByZXNlcnZlcyBpbnNlcnRpb24gb3JkZXIg4oCUIGRyb3AgZnJvbSB0aGUgZnJvbnQgdW50aWwgYmFjayB1bmRlciB0aGUgY2FwLlxuICB3aGlsZSAodG9rZW5DYWNoZS5zaXplID4gTUFYX0NBQ0hFRF9LRVlTKSB7XG4gICAgY29uc3Qgb2xkZXN0ID0gdG9rZW5DYWNoZS5rZXlzKCkubmV4dCgpO1xuICAgIGlmIChvbGRlc3QuZG9uZSkgYnJlYWs7XG4gICAgdG9rZW5DYWNoZS5kZWxldGUob2xkZXN0LnZhbHVlKTtcbiAgfVxufVxuXG5pbnRlcmZhY2UgRXhjaGFuZ2VSZXNwb25zZSB7XG4gIHN1Y2Nlc3M/OiBib29sZWFuO1xuICBkYXRhPzogeyBhY2Nlc3NUb2tlbj86IHN0cmluZzsgZXhwaXJlc0luPzogbnVtYmVyIH07XG59XG5cbi8qKiBPbmUgcmVhbCByb3VuZC10cmlwIHRvIHBsYXRmb3JtLiBUaHJvd3MgdGhlIHR3byB0eXBlZCBlcnJvcnMgYWJvdmUuICovXG5hc3luYyBmdW5jdGlvbiBwZXJmb3JtRXhjaGFuZ2Uoa2V5OiBzdHJpbmcsIGhhc2g6IHN0cmluZyk6IFByb21pc2U8Q2FjaGVFbnRyeT4ge1xuICBjb25zdCBjbGllbnQgPSBwbGF0Zm9ybUNsaWVudCgpO1xuICBsZXQgc3RhdHVzOiBudW1iZXI7XG4gIGxldCBib2R5OiBFeGNoYW5nZVJlc3BvbnNlO1xuICB0cnkge1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IGNsaWVudC5wb3N0PEV4Y2hhbmdlUmVzcG9uc2U+KCcvYXV0aC90b2tlbi9leGNoYW5nZScsIHsga2V5IH0sIHtcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgQXV0aG9yaXphdGlvbjogZ2V0U2VydmljZUF1dGhIZWFkZXIoeyBzZXJ2aWNlTmFtZSwgcm9sZTogJ21lbWJlcicsIG9yZ0lkOiBTWVNURU1fT1JHX0lEIH0pLFxuICAgICAgfSxcbiAgICAgIC8vIFRoZSBleGNoYW5nZSBpcyBhIHB1cmUgcmVhZCBvZiB0aGUga2V5IHJlY29yZCBwbHVzIGEgdG9rZW4gbWludCDigJQgc2FmZSB0b1xuICAgICAgLy8gcmV0cnksIGFuZCBhIGxvc3QgcmV0cnkgb25seSBjb3N0cyBvbmUgZXh0cmEgbWludC5cbiAgICAgIGlkZW1wb3RlbnQ6IHRydWUsXG4gICAgfSk7XG4gICAgc3RhdHVzID0gcmVzLnN0YXR1c0NvZGU7XG4gICAgYm9keSA9IHJlcy5ib2R5O1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBlbWl0Q291bnRlcignYXBpX2tleV9leGNoYW5nZV90b3RhbCcsIHsgcmVzdWx0OiAndW5hdmFpbGFibGUnIH0pO1xuICAgIGVtaXRDb3VudGVyKCdhcGlfa2V5X2V4Y2hhbmdlX2ZhaWx1cmVzX3RvdGFsJywgeyByZWFzb246ICd1bmF2YWlsYWJsZScgfSk7XG4gICAgbG9nZ2VyLndhcm4oJ0FjY2Vzcy1rZXkgZXhjaGFuZ2UgZmFpbGVkIHRvIHJlYWNoIHBsYXRmb3JtJywge1xuICAgICAgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBTdHJpbmcoZXJyKSxcbiAgICB9KTtcbiAgICB0aHJvdyBuZXcgQXBpS2V5RXhjaGFuZ2VVbmF2YWlsYWJsZUVycm9yKCk7XG4gIH1cblxuICBpZiAoc3RhdHVzID09PSA0MDEgfHwgc3RhdHVzID09PSA0MDMgfHwgc3RhdHVzID09PSA0MDAgfHwgc3RhdHVzID09PSA0MDQpIHtcbiAgICByZWplY3Rpb25DYWNoZS5zZXQoaGFzaCwgRGF0ZS5ub3coKSArIE5FR0FUSVZFX1RUTF9NUyk7XG4gICAgZW1pdENvdW50ZXIoJ2FwaV9rZXlfZXhjaGFuZ2VfdG90YWwnLCB7IHJlc3VsdDogJ3JlamVjdGVkJyB9KTtcbiAgICBlbWl0Q291bnRlcignYXBpX2tleV9leGNoYW5nZV9mYWlsdXJlc190b3RhbCcsIHsgcmVhc29uOiAncmVqZWN0ZWQnIH0pO1xuICAgIHRocm93IG5ldyBBcGlLZXlSZWplY3RlZEVycm9yKCk7XG4gIH1cblxuICBjb25zdCBhY2Nlc3NUb2tlbiA9IGJvZHk/LmRhdGE/LmFjY2Vzc1Rva2VuO1xuICBpZiAoc3RhdHVzID49IDQwMCB8fCB0eXBlb2YgYWNjZXNzVG9rZW4gIT09ICdzdHJpbmcnIHx8IGFjY2Vzc1Rva2VuLmxlbmd0aCA9PT0gMCkge1xuICAgIC8vIDQyOSBhbmQgNXh4IGxhbmQgaGVyZTogcGxhdGZvcm0gaXMgdXAgYnV0IGNhbid0IGFuc3dlciByaWdodCBub3csIHdoaWNoIGlzXG4gICAgLy8gXCJ1bmtub3duXCIsIG5vdCBcImludmFsaWRcIiDigJQgbmV2ZXIgY2FjaGUgaXQgYXMgYSByZWplY3Rpb24uXG4gICAgZW1pdENvdW50ZXIoJ2FwaV9rZXlfZXhjaGFuZ2VfdG90YWwnLCB7IHJlc3VsdDogJ3VuYXZhaWxhYmxlJyB9KTtcbiAgICBlbWl0Q291bnRlcignYXBpX2tleV9leGNoYW5nZV9mYWlsdXJlc190b3RhbCcsIHsgcmVhc29uOiBzdGF0dXMgPT09IDQyOSA/ICd0aHJvdHRsZWQnIDogJ3NlcnZlcl9lcnJvcicgfSk7XG4gICAgdGhyb3cgbmV3IEFwaUtleUV4Y2hhbmdlVW5hdmFpbGFibGVFcnJvcigpO1xuICB9XG5cbiAgY29uc3QgdHRsU2Vjb25kcyA9IHR5cGVvZiBib2R5Py5kYXRhPy5leHBpcmVzSW4gPT09ICdudW1iZXInICYmIGJvZHkuZGF0YS5leHBpcmVzSW4gPiAwXG4gICAgPyBib2R5LmRhdGEuZXhwaXJlc0luXG4gICAgOiA2MDtcbiAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgY29uc3QgZW50cnk6IENhY2hlRW50cnkgPSB7XG4gICAgdG9rZW46IGFjY2Vzc1Rva2VuLFxuICAgIGV4cGlyZXNBdDogbm93ICsgdHRsU2Vjb25kcyAqIDEwMDAsXG4gICAgcmVmcmVzaEF0OiBqaXR0ZXJlZFJlZnJlc2hBdChub3csIHR0bFNlY29uZHMpLFxuICB9O1xuICB0b2tlbkNhY2hlLnNldChoYXNoLCBlbnRyeSk7XG4gIHJlamVjdGlvbkNhY2hlLmRlbGV0ZShoYXNoKTtcbiAgZXZpY3RJZkZ1bGwoKTtcbiAgZW1pdENvdW50ZXIoJ2FwaV9rZXlfZXhjaGFuZ2VfdG90YWwnLCB7IHJlc3VsdDogJ3N1Y2Nlc3MnIH0pO1xuICByZXR1cm4gZW50cnk7XG59XG5cbi8qKiBFeGNoYW5nZSwgc2hhcmluZyBhIHNpbmdsZSBpbi1mbGlnaHQgcm91bmQtdHJpcCBwZXIga2V5LiAqL1xuZnVuY3Rpb24gZXhjaGFuZ2VPbmNlKGtleTogc3RyaW5nLCBoYXNoOiBzdHJpbmcpOiBQcm9taXNlPENhY2hlRW50cnk+IHtcbiAgY29uc3QgcGVuZGluZyA9IGluRmxpZ2h0LmdldChoYXNoKTtcbiAgaWYgKHBlbmRpbmcpIHJldHVybiBwZW5kaW5nO1xuICBjb25zdCBwcm9taXNlID0gcGVyZm9ybUV4Y2hhbmdlKGtleSwgaGFzaCkuZmluYWxseSgoKSA9PiBpbkZsaWdodC5kZWxldGUoaGFzaCkpO1xuICBpbkZsaWdodC5zZXQoaGFzaCwgcHJvbWlzZSk7XG4gIHJldHVybiBwcm9taXNlO1xufVxuXG4vKipcbiAqIFRoZSBKV1QgZm9yIGBrZXlgLCBmcm9tIGNhY2hlIHdoZW4gcG9zc2libGUuIFRocm93cyB7QGxpbmsgQXBpS2V5UmVqZWN0ZWRFcnJvcn1cbiAqIHdoZW4gcGxhdGZvcm0gcmVmdXNlZCB0aGUga2V5IGFuZCB7QGxpbmsgQXBpS2V5RXhjaGFuZ2VVbmF2YWlsYWJsZUVycm9yfSB3aGVuXG4gKiBpdCBjb3VsZCBub3QgYmUgYXNrZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBleGNoYW5nZUFwaUtleShrZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IGhhc2ggPSBoYXNoQXBpS2V5KGtleSk7XG4gIGNvbnN0IG5vdyA9IERhdGUubm93KCk7XG5cbiAgY29uc3QgcmVqZWN0ZWRVbnRpbCA9IHJlamVjdGlvbkNhY2hlLmdldChoYXNoKTtcbiAgaWYgKHJlamVjdGVkVW50aWwgIT09IHVuZGVmaW5lZCkge1xuICAgIGlmIChyZWplY3RlZFVudGlsID4gbm93KSB7XG4gICAgICBlbWl0Q291bnRlcignYXBpX2tleV9leGNoYW5nZV9jYWNoZV90b3RhbCcsIHsgcmVzdWx0OiAncmVqZWN0ZWQnIH0pO1xuICAgICAgdGhyb3cgbmV3IEFwaUtleVJlamVjdGVkRXJyb3IoKTtcbiAgICB9XG4gICAgcmVqZWN0aW9uQ2FjaGUuZGVsZXRlKGhhc2gpO1xuICB9XG5cbiAgY29uc3QgY2FjaGVkID0gdG9rZW5DYWNoZS5nZXQoaGFzaCk7XG4gIGlmIChjYWNoZWQgJiYgY2FjaGVkLmV4cGlyZXNBdCA+IG5vdykge1xuICAgIGlmIChjYWNoZWQucmVmcmVzaEF0IDw9IG5vdyAmJiAhaW5GbGlnaHQuaGFzKGhhc2gpKSB7XG4gICAgICAvLyBFYXJseSByZWZyZXNoOiB3YXJtIHRoZSBjYWNoZSBXSVRIT1VUIG1ha2luZyB0aGlzIHJlcXVlc3Qgd2FpdC4gQSBmYWlsZWRcbiAgICAgIC8vIGJhY2tncm91bmQgcmVmcmVzaCBpcyBub3QgdGhpcyByZXF1ZXN0J3MgcHJvYmxlbSDigJQgdGhlIGNhY2hlZCB0b2tlbiBpc1xuICAgICAgLy8gc3RpbGwgdmFsaWQsIGFuZCB0aGUgbmV4dCByZXF1ZXN0IHBhc3QgZXhwaXJ5IGV4Y2hhbmdlcyBpbmxpbmUuXG4gICAgICBlbWl0Q291bnRlcignYXBpX2tleV9leGNoYW5nZV9jYWNoZV90b3RhbCcsIHsgcmVzdWx0OiAncmVmcmVzaCcgfSk7XG4gICAgICB2b2lkIGV4Y2hhbmdlT25jZShrZXksIGhhc2gpLmNhdGNoKCgpID0+IHsgLyogbG9nZ2VkICsgY291bnRlZCBpbiBwZXJmb3JtRXhjaGFuZ2UgKi8gfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGVtaXRDb3VudGVyKCdhcGlfa2V5X2V4Y2hhbmdlX2NhY2hlX3RvdGFsJywgeyByZXN1bHQ6ICdoaXQnIH0pO1xuICAgIH1cbiAgICByZXR1cm4gY2FjaGVkLnRva2VuO1xuICB9XG5cbiAgZW1pdENvdW50ZXIoJ2FwaV9rZXlfZXhjaGFuZ2VfY2FjaGVfdG90YWwnLCB7IHJlc3VsdDogJ21pc3MnIH0pO1xuICByZXR1cm4gKGF3YWl0IGV4Y2hhbmdlT25jZShrZXksIGhhc2gpKS50b2tlbjtcbn1cblxuLyoqXG4gKiBEcm9wIGV2ZXJ5IGNhY2hlZCBleGNoYW5nZS4gRm9yIHRlc3RzIGFuZCBmb3IgYSBwcm9jZXNzIHRoYXQgd2FudHMgdG8gZm9yY2VcbiAqIHJlLXZhbGlkYXRpb247IHByb2R1Y3Rpb24gcmVsaWVzIG9uIHRoZSBUVExzIGFib3ZlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRBcGlLZXlFeGNoYW5nZUNhY2hlKCk6IHZvaWQge1xuICB0b2tlbkNhY2hlLmNsZWFyKCk7XG4gIHJlamVjdGlvbkNhY2hlLmNsZWFyKCk7XG4gIGluRmxpZ2h0LmNsZWFyKCk7XG59XG4iXX0=
@@ -67,10 +67,9 @@ export declare function createRedisAuditSpool(redis: RedisListClient, opts?: {
67
67
  key?: string;
68
68
  }): AuditSpool;
69
69
  /**
70
- * Build a Redis-backed audit spool from the ambient `REDIS_URL` / `REDIS_HOST`
70
+ * Build a Redis-backed audit spool from the ambient `REDIS_URL` / `REDIS_SENTINELS`
71
71
  * env via the shared `createEnvRedisClient`. Returns `null` when Redis is not
72
- * configured or the client can't be constructed — the caller then runs without a
73
- * spool (pre-spool best-effort behavior), never crashing. The shared helper loads
72
+ * configured — the caller then runs without a spool (best-effort behavior). The shared helper loads
74
73
  * ioredis via `createRequire`, so this stays importable where Redis isn't present.
75
74
  */
76
75
  export declare function createEnvRedisAuditSpool(opts?: {