@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
@@ -4,91 +4,233 @@ import { createRequire } from 'module';
4
4
  import { createLogger } from '../utils/logger.js';
5
5
  const logger = createLogger('env-redis');
6
6
  /**
7
- * Parse `REDIS_SENTINELS` (comma-separated `host:port` list) into the ioredis
8
- * `{ host, port }[]` sentinel array. Blank/garbage entries are skipped; a
9
- * missing port defaults to the Sentinel default 26379. Returns an empty array
10
- * when the env is unset/empty (→ non-sentinel mode).
7
+ * The ONE place Redis connection settings are read from the environment.
8
+ *
9
+ * Two shapes, exactly one of which may be set:
10
+ *
11
+ * - **Standalone** — `REDIS_URL` (`redis://host:6379[/db]`, or `rediss://` for
12
+ * TLS). Credentials may sit in the URL or in `REDIS_PASSWORD`.
13
+ * - **HA (Sentinel)** — `REDIS_SENTINELS` (comma-separated `host:port`) plus
14
+ * `REDIS_SENTINEL_MASTER` (default `mymaster`) and optional
15
+ * `REDIS_SENTINEL_PASSWORD`. `REDIS_PASSWORD` authenticates to the data nodes.
16
+ * ioredis follows the master across a failover.
17
+ *
18
+ * Neither set → Redis is off, and each caller degrades to its documented
19
+ * no-Redis behavior.
20
+ *
21
+ * `REDIS_HOST` / `REDIS_PORT` are not read. `REDIS_HOST` is refused outright so a
22
+ * stale config fails at startup instead of silently running without Redis.
23
+ * `REDIS_PORT` can't be refused: Kubernetes injects `REDIS_PORT=tcp://<ip>:6379`
24
+ * into every pod in a namespace with a Service named `redis`, which is exactly
25
+ * why a host/port pair was unsafe to parse.
26
+ *
27
+ * Misconfiguration throws {@link RedisConfigError}. Writers and readers of the
28
+ * same keys (revocation, step-up, leader locks) must resolve Redis identically;
29
+ * a config that quietly resolved to "no Redis" on one side is how revocation
30
+ * once did nothing at all.
31
+ */
32
+ /** Thrown for a Redis environment that can't be used as written. */
33
+ export class RedisConfigError extends Error {
34
+ constructor(message) {
35
+ super(message);
36
+ this.name = 'RedisConfigError';
37
+ }
38
+ }
39
+ /**
40
+ * Parse `REDIS_SENTINELS` into `{ host, port }[]`. Blank entries are skipped and
41
+ * a missing port means the Sentinel default 26379; a port that isn't a valid
42
+ * TCP port is a configuration error.
11
43
  */
12
44
  export function parseSentinels(raw) {
13
45
  if (!raw)
14
46
  return [];
15
47
  return raw.split(',').map((s) => s.trim()).filter(Boolean).map((entry) => {
16
- const [host, port] = entry.split(':');
17
- return { host, port: parseInt(port ?? '26379', 10) || 26379 };
18
- }).filter((s) => !!s.host);
48
+ const idx = entry.lastIndexOf(':');
49
+ const host = idx === -1 ? entry : entry.slice(0, idx);
50
+ const portText = idx === -1 ? '' : entry.slice(idx + 1);
51
+ const port = portText === '' ? 26379 : Number(portText);
52
+ if (!host || !Number.isInteger(port) || port < 1 || port > 65535) {
53
+ throw new RedisConfigError(`REDIS_SENTINELS entry "${entry}" is not host:port`);
54
+ }
55
+ return { host, port };
56
+ });
57
+ }
58
+ /**
59
+ * Resolve the Redis connection from `env`, or `null` when Redis isn't
60
+ * configured. Throws {@link RedisConfigError} for an unusable configuration.
61
+ */
62
+ export function resolveRedisConnection(env = process.env) {
63
+ if (env.REDIS_HOST) {
64
+ throw new RedisConfigError('REDIS_HOST is not supported. Set REDIS_URL=redis://<host>:<port> (or REDIS_SENTINELS for HA) and remove REDIS_HOST/REDIS_PORT.');
65
+ }
66
+ const sentinels = parseSentinels(env.REDIS_SENTINELS);
67
+ const url = env.REDIS_URL?.trim();
68
+ const password = env.REDIS_PASSWORD || undefined;
69
+ if (sentinels.length > 0 && url) {
70
+ throw new RedisConfigError('Set REDIS_URL or REDIS_SENTINELS, not both.');
71
+ }
72
+ if (sentinels.length > 0) {
73
+ return {
74
+ mode: 'sentinel',
75
+ sentinels,
76
+ masterName: env.REDIS_SENTINEL_MASTER || 'mymaster',
77
+ password,
78
+ sentinelPassword: env.REDIS_SENTINEL_PASSWORD || undefined,
79
+ };
80
+ }
81
+ if (url) {
82
+ let parsed;
83
+ try {
84
+ parsed = new URL(url);
85
+ }
86
+ catch {
87
+ throw new RedisConfigError('REDIS_URL is not a valid URL (expected redis://<host>:<port>).');
88
+ }
89
+ if (parsed.protocol !== 'redis:' && parsed.protocol !== 'rediss:') {
90
+ throw new RedisConfigError(`REDIS_URL must use redis:// or rediss://, got ${parsed.protocol}//`);
91
+ }
92
+ if (!parsed.hostname)
93
+ throw new RedisConfigError('REDIS_URL has no host.');
94
+ return { mode: 'url', url, password };
95
+ }
96
+ return null;
97
+ }
98
+ /** A log-safe description of a connection (never includes credentials). */
99
+ export function describeRedisConnection(conn) {
100
+ if (conn.mode === 'sentinel') {
101
+ return { mode: 'sentinel', master: conn.masterName, sentinels: conn.sentinels.length };
102
+ }
103
+ const u = new URL(conn.url);
104
+ return { mode: 'url', host: u.hostname, port: u.port || '6379', tls: u.protocol === 'rediss:' };
105
+ }
106
+ function loadIoredis() {
107
+ const req = createRequire(import.meta.url);
108
+ const mod = req('ioredis');
109
+ return (mod.Redis ?? mod.default ?? mod);
19
110
  }
20
111
  /**
21
- * Construct an ioredis client from the standard `REDIS_URL` or
22
- * `REDIS_HOST`/`REDIS_PORT` env — OR, for HA, from Redis Sentinel via
23
- * `REDIS_SENTINELS` + `REDIS_SENTINEL_MASTER`. The shared construction was
24
- * previously duplicated across the leader-lock, audit-spool, and
25
- * token-revocation env factories.
112
+ * Construct an ioredis client for a resolved connection. `options` are merged
113
+ * into the client options (e.g. `{ db, maxRetriesPerRequest: null }` for BullMQ).
114
+ * An `error` listener is always attached so a dropped connection is logged
115
+ * rather than surfacing as an unhandled `'error'` event that crashes Node.
116
+ */
117
+ export function createRedisClient(conn, label, options = {}) {
118
+ const Ctor = loadIoredis();
119
+ const auth = conn.password ? { password: conn.password } : {};
120
+ const inst = conn.mode === 'sentinel'
121
+ ? new Ctor({
122
+ sentinels: conn.sentinels,
123
+ name: conn.masterName,
124
+ ...(conn.sentinelPassword ? { sentinelPassword: conn.sentinelPassword } : {}),
125
+ ...auth,
126
+ ...options,
127
+ })
128
+ : new Ctor(conn.url, { ...auth, ...options });
129
+ inst
130
+ .on('error', (e) => logger.warn(`Redis ${label} client error`, { error: e instanceof Error ? e.message : String(e) }));
131
+ return inst;
132
+ }
133
+ /**
134
+ * The shared application Redis client: `null` when Redis isn't configured, so
135
+ * the caller degrades to its no-Redis behavior.
26
136
  *
27
- * Connection modes (first that matches wins):
28
- * 1. SENTINEL — `REDIS_SENTINELS` set (comma-separated `host:port`): ioredis
29
- * resolves the current master from the sentinels (`name` = `REDIS_SENTINEL_MASTER`,
30
- * default `mymaster`) and transparently reconnects to the new master after a
31
- * failover. This is how the app gets HA against a single-node Redis loss —
32
- * also the shape a managed ElastiCache (cluster-mode-disabled) speaks.
33
- * 2. URL — `REDIS_URL`.
34
- * 3. HOST/PORT — `REDIS_HOST`(+`REDIS_PORT`).
137
+ * Commands fail fast (`maxRetriesPerRequest: 1`, no offline queue) because the
138
+ * request-path callers are best-effort or fail closed on their own terms — a
139
+ * request must not hang behind a Redis outage. That includes the moments before
140
+ * the first connection completes: a background caller that runs at startup must
141
+ * either tolerate a rejected command or wait with {@link whenRedisReady}.
35
142
  *
36
- * Semantics every caller relies on (kept identical across the consolidation):
37
- * - Returns `null` when NONE of sentinels/url/host is set, so a caller degrades
38
- * to its no-Redis fallback (run-on-every-pod / best-effort / fail-open).
39
- * - FAIL-SAFE: any ioredis load or construction error is swallowed and returns
40
- * `null` — Redis being unavailable must never crash the importing service.
41
- * - `ioredis` is a runtime-only optional dep loaded via `createRequire`, so this
42
- * module stays importable in CJS bundles and where Redis isn't installed.
43
- * - `maxRetriesPerRequest: 1` + `enableOfflineQueue: false`: commands fail fast
44
- * rather than queueing during an outage (callers are fail-open/best-effort).
45
- * - An `error` listener is attached (ioredis auto-reconnects) so a dropped
46
- * connection can't surface as an unhandled `'error'` event that crashes Node.
143
+ * Throws {@link RedisConfigError} for a bad configuration, and if Redis is
144
+ * configured but `ioredis` can't be loaded — both are deployment errors that
145
+ * must not quietly turn Redis-backed guarantees off.
146
+ */
147
+ export function createEnvRedisClient(label) {
148
+ const conn = resolveRedisConnection();
149
+ if (!conn)
150
+ return null;
151
+ const inst = createRedisClient(conn, label, { maxRetriesPerRequest: 1, enableOfflineQueue: false });
152
+ logger.info(`Redis ${label} client created`, describeRedisConnection(conn));
153
+ return inst;
154
+ }
155
+ /**
156
+ * Resolve once `client` is connected and ready for commands, or reject after
157
+ * `timeoutMs`. For startup work (creating a consumer group, subscribing) that
158
+ * otherwise races the first connection. A client without ioredis' `status`
159
+ * (e.g. a test double) counts as ready.
160
+ */
161
+ export function whenRedisReady(client, timeoutMs = 30_000) {
162
+ if (client.status === undefined || client.status === 'ready' || !client.once)
163
+ return Promise.resolve();
164
+ return new Promise((resolve, reject) => {
165
+ const onReady = () => { clearTimeout(timer); resolve(); };
166
+ const timer = setTimeout(() => {
167
+ client.off?.('ready', onReady);
168
+ reject(new Error(`Redis not ready after ${timeoutMs}ms`));
169
+ }, timeoutMs);
170
+ timer.unref?.();
171
+ client.once('ready', onReady);
172
+ });
173
+ }
174
+ /** Default bound for {@link createRedisReadyGate}: short enough for a request path. */
175
+ export const REQUEST_PATH_REDIS_READY_TIMEOUT_MS = 2_000;
176
+ /**
177
+ * A request-path readiness gate for a lazily built env Redis client.
47
178
  *
48
- * Optional auth: `REDIS_PASSWORD` (data-node AUTH) and `REDIS_SENTINEL_PASSWORD`
49
- * (sentinel AUTH, sentinel mode only) are threaded through when set.
179
+ * The env client has no offline queue, so a command issued before the first
180
+ * connection completes is rejected outright — the first request after a lazy
181
+ * construction would otherwise hit that rejection (e.g. the first step-up per
182
+ * pod failing, or the first impersonation check reading "unavailable").
50
183
  *
51
- * @param label short human name for this client, used in the two warn logs.
184
+ * The returned function resolves once the client is ready, or after
185
+ * `timeoutMs` — it NEVER rejects: the caller then runs its command and keeps its
186
+ * own fail-open / fail-closed semantics. Concurrent callers share one wait. After
187
+ * a wait times out (Redis genuinely down) later calls stop waiting until the
188
+ * client reports `ready` again, so an outage costs one bounded wait instead of
189
+ * adding `timeoutMs` to every request.
52
190
  */
53
- export function createEnvRedisClient(label) {
54
- try {
55
- const sentinels = parseSentinels(process.env.REDIS_SENTINELS);
56
- const url = process.env.REDIS_URL;
57
- const host = process.env.REDIS_HOST;
58
- if (sentinels.length === 0 && !url && !host)
59
- return null;
60
- const req = createRequire(import.meta.url);
61
- const mod = req('ioredis');
62
- const RedisCtor = (mod.Redis ?? mod.default ?? mod);
63
- const redisOpts = { maxRetriesPerRequest: 1, enableOfflineQueue: false };
64
- if (process.env.REDIS_PASSWORD)
65
- redisOpts.password = process.env.REDIS_PASSWORD;
66
- let inst;
67
- if (sentinels.length > 0) {
68
- // Sentinel mode: ioredis tracks the master via the sentinels + auto-fails-over.
69
- const sentinelOpts = {
70
- sentinels,
71
- name: process.env.REDIS_SENTINEL_MASTER || 'mymaster',
72
- ...redisOpts,
73
- };
74
- if (process.env.REDIS_SENTINEL_PASSWORD)
75
- sentinelOpts.sentinelPassword = process.env.REDIS_SENTINEL_PASSWORD;
76
- inst = new RedisCtor(sentinelOpts);
77
- logger.info(`Redis ${label}: Sentinel mode`, { master: sentinelOpts.name, sentinels: sentinels.length });
78
- }
79
- else if (url) {
80
- inst = new RedisCtor(url, redisOpts);
191
+ export function createRedisReadyGate(client, timeoutMs = REQUEST_PATH_REDIS_READY_TIMEOUT_MS) {
192
+ let inflight = null;
193
+ let gaveUp = false;
194
+ return () => {
195
+ if (client.status === undefined || client.status === 'ready' || !client.once) {
196
+ gaveUp = false;
197
+ return Promise.resolve();
81
198
  }
82
- else {
83
- inst = new RedisCtor({ host, port: parseInt(process.env.REDIS_PORT ?? '6379', 10), ...redisOpts });
199
+ if (gaveUp)
200
+ return Promise.resolve();
201
+ if (!inflight) {
202
+ inflight = whenRedisReady(client, timeoutMs)
203
+ .catch(() => {
204
+ gaveUp = true;
205
+ // Re-arm the wait once the connection comes back.
206
+ client.once('ready', () => { gaveUp = false; });
207
+ })
208
+ .finally(() => { inflight = null; });
84
209
  }
85
- inst
86
- .on('error', (e) => logger.warn(`Redis ${label} client error`, { error: e instanceof Error ? e.message : String(e) }));
87
- return inst;
88
- }
89
- catch (err) {
90
- logger.warn(`Redis unavailable for ${label}`, { error: err instanceof Error ? err.message : String(err) });
91
- return null;
92
- }
210
+ return inflight;
211
+ };
212
+ }
213
+ /**
214
+ * INCR a fixed-window counter and make sure it carries a TTL, atomically.
215
+ *
216
+ * A separate `INCR` then `EXPIRE` is not atomic: if the EXPIRE is lost (a
217
+ * connection drop, a failover between the two commands) the key never expires
218
+ * and the counter stays over its limit forever. The script also heals a key
219
+ * that somehow lacks a TTL (`PTTL` = -1) rather than only setting it on the
220
+ * first hit.
221
+ */
222
+ const INCR_WINDOW_SCRIPT = `
223
+ local n = redis.call('INCR', KEYS[1])
224
+ if n == 1 or redis.call('PTTL', KEYS[1]) < 0 then
225
+ redis.call('PEXPIRE', KEYS[1], ARGV[1])
226
+ end
227
+ return n`;
228
+ /**
229
+ * Increment `key` within a window of `windowMs` and return the new count.
230
+ * Throws when Redis errors — callers choose their own failure policy.
231
+ */
232
+ export async function incrWindow(redis, key, windowMs) {
233
+ const n = await redis.eval(INCR_WINDOW_SCRIPT, 1, key, Math.max(1, Math.ceil(windowMs)));
234
+ return Number(n);
93
235
  }
94
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LXJlZGlzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL2Vudi1yZWRpcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFdkMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRWxELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUV6Qzs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQUMsR0FBdUI7SUFDcEQsSUFBSSxDQUFDLEdBQUc7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUNwQixPQUFPLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDdkUsTUFBTSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3RDLE9BQU8sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxJQUFJLElBQUksT0FBTyxFQUFFLEVBQUUsQ0FBQyxJQUFJLEtBQUssRUFBRSxDQUFDO0lBQ2hFLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUM3QixDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBZ0NHO0FBQ0gsTUFBTSxVQUFVLG9CQUFvQixDQUFjLEtBQWE7SUFDN0QsSUFBSSxDQUFDO1FBQ0gsTUFB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InNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAyMDI2IFBpcGVsaW5lIEJ1aWxkZXIgQ29udHJpYnV0b3JzXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQgeyBjcmVhdGVSZXF1aXJlIH0gZnJvbSAnbW9kdWxlJztcblxuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdlbnYtcmVkaXMnKTtcblxuLyoqXG4gKiBQYXJzZSBgUkVESVNfU0VOVElORUxTYCAoY29tbWEtc2VwYXJhdGVkIGBob3N0OnBvcnRgIGxpc3QpIGludG8gdGhlIGlvcmVkaXNcbiAqIGB7IGhvc3QsIHBvcnQgfVtdYCBzZW50aW5lbCBhcnJheS4gQmxhbmsvZ2FyYmFnZSBlbnRyaWVzIGFyZSBza2lwcGVkOyBhXG4gKiBtaXNzaW5nIHBvcnQgZGVmYXVsdHMgdG8gdGhlIFNlbnRpbmVsIGRlZmF1bHQgMjYzNzkuIFJldHVybnMgYW4gZW1wdHkgYXJyYXlcbiAqIHdoZW4gdGhlIGVudiBpcyB1bnNldC9lbXB0eSAo4oaSIG5vbi1zZW50aW5lbCBtb2RlKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlU2VudGluZWxzKHJhdzogc3RyaW5nIHwgdW5kZWZpbmVkKTogQXJyYXk8eyBob3N0OiBzdHJpbmc7IHBvcnQ6IG51bWJlciB9PiB7XG4gIGlmICghcmF3KSByZXR1cm4gW107XG4gIHJldHVybiByYXcuc3BsaXQoJywnKS5tYXAoKHMpID0+IHMudHJpbSgpKS5maWx0ZXIoQm9vbGVhbikubWFwKChlbnRyeSkgPT4ge1xuICAgIGNvbnN0IFtob3N0LCBwb3J0XSA9IGVudHJ5LnNwbGl0KCc6Jyk7XG4gICAgcmV0dXJuIHsgaG9zdCwgcG9ydDogcGFyc2VJbnQocG9ydCA/PyAnMjYzNzknLCAxMCkgfHwgMjYzNzkgfTtcbiAgfSkuZmlsdGVyKChzKSA9PiAhIXMuaG9zdCk7XG59XG5cbi8qKlxuICogQ29uc3RydWN0IGFuIGlvcmVkaXMgY2xpZW50IGZyb20gdGhlIHN0YW5kYXJkIGBSRURJU19VUkxgIG9yXG4gKiBgUkVESVNfSE9TVGAvYFJFRElTX1BPUlRgIGVudiDigJQgT1IsIGZvciBIQSwgZnJvbSBSZWRpcyBTZW50aW5lbCB2aWFcbiAqIGBSRURJU19TRU5USU5FTFNgICsgYFJFRElTX1NFTlRJTkVMX01BU1RFUmAuIFRoZSBzaGFyZWQgY29uc3RydWN0aW9uIHdhc1xuICogcHJldmlvdXNseSBkdXBsaWNhdGVkIGFjcm9zcyB0aGUgbGVhZGVyLWxvY2ssIGF1ZGl0LXNwb29sLCBhbmRcbiAqIHRva2VuLXJldm9jYXRpb24gZW52IGZhY3Rvcmllcy5cbiAqXG4gKiBDb25uZWN0aW9uIG1vZGVzIChmaXJzdCB0aGF0IG1hdGNoZXMgd2lucyk6XG4gKiAxLiBTRU5USU5FTCDigJQgYFJFRElTX1NFTlRJTkVMU2Agc2V0IChjb21tYS1zZXBhcmF0ZWQgYGhvc3Q6cG9ydGApOiBpb3JlZGlzXG4gKiAgICByZXNvbHZlcyB0aGUgY3VycmVudCBtYXN0ZXIgZnJvbSB0aGUgc2VudGluZWxzIChgbmFtZWAgPSBgUkVESVNfU0VOVElORUxfTUFTVEVSYCxcbiAqICAgIGRlZmF1bHQgYG15bWFzdGVyYCkgYW5kIHRyYW5zcGFyZW50bHkgcmVjb25uZWN0cyB0byB0aGUgbmV3IG1hc3RlciBhZnRlciBhXG4gKiAgICBmYWlsb3Zlci4gVGhpcyBpcyBob3cgdGhlIGFwcCBnZXRzIEhBIGFnYWluc3QgYSBzaW5nbGUtbm9kZSBSZWRpcyBsb3NzIOKAlFxuICogICAgYWxzbyB0aGUgc2hhcGUgYSBtYW5hZ2VkIEVsYXN0aUNhY2hlIChjbHVzdGVyLW1vZGUtZGlzYWJsZWQpIHNwZWFrcy5cbiAqIDIuIFVSTCDigJQgYFJFRElTX1VSTGAuXG4gKiAzLiBIT1NUL1BPUlQg4oCUIGBSRURJU19IT1NUYCgrYFJFRElTX1BPUlRgKS5cbiAqXG4gKiBTZW1hbnRpY3MgZXZlcnkgY2FsbGVyIHJlbGllcyBvbiAoa2VwdCBpZGVudGljYWwgYWNyb3NzIHRoZSBjb25zb2xpZGF0aW9uKTpcbiAqIC0gUmV0dXJucyBgbnVsbGAgd2hlbiBOT05FIG9mIHNlbnRpbmVscy91cmwvaG9zdCBpcyBzZXQsIHNvIGEgY2FsbGVyIGRlZ3JhZGVzXG4gKiAgIHRvIGl0cyBuby1SZWRpcyBmYWxsYmFjayAocnVuLW9uLWV2ZXJ5LXBvZCAvIGJlc3QtZWZmb3J0IC8gZmFpbC1vcGVuKS5cbiAqIC0gRkFJTC1TQUZFOiBhbnkgaW9yZWRpcyBsb2FkIG9yIGNvbnN0cnVjdGlvbiBlcnJvciBpcyBzd2FsbG93ZWQgYW5kIHJldHVybnNcbiAqICAgYG51bGxgIOKAlCBSZWRpcyBiZWluZyB1bmF2YWlsYWJsZSBtdXN0IG5ldmVyIGNyYXNoIHRoZSBpbXBvcnRpbmcgc2VydmljZS5cbiAqIC0gYGlvcmVkaXNgIGlzIGEgcnVudGltZS1vbmx5IG9wdGlvbmFsIGRlcCBsb2FkZWQgdmlhIGBjcmVhdGVSZXF1aXJlYCwgc28gdGhpc1xuICogICBtb2R1bGUgc3RheXMgaW1wb3J0YWJsZSBpbiBDSlMgYnVuZGxlcyBhbmQgd2hlcmUgUmVkaXMgaXNuJ3QgaW5zdGFsbGVkLlxuICogLSBgbWF4UmV0cmllc1BlclJlcXVlc3Q6IDFgICsgYGVuYWJsZU9mZmxpbmVRdWV1ZTogZmFsc2VgOiBjb21tYW5kcyBmYWlsIGZhc3RcbiAqICAgcmF0aGVyIHRoYW4gcXVldWVpbmcgZHVyaW5nIGFuIG91dGFnZSAoY2FsbGVycyBhcmUgZmFpbC1vcGVuL2Jlc3QtZWZmb3J0KS5cbiAqIC0gQW4gYGVycm9yYCBsaXN0ZW5lciBpcyBhdHRhY2hlZCAoaW9yZWRpcyBhdXRvLXJlY29ubmVjdHMpIHNvIGEgZHJvcHBlZFxuICogICBjb25uZWN0aW9uIGNhbid0IHN1cmZhY2UgYXMgYW4gdW5oYW5kbGVkIGAnZXJyb3InYCBldmVudCB0aGF0IGNyYXNoZXMgTm9kZS5cbiAqXG4gKiBPcHRpb25hbCBhdXRoOiBgUkVESVNfUEFTU1dPUkRgIChkYXRhLW5vZGUgQVVUSCkgYW5kIGBSRURJU19TRU5USU5FTF9QQVNTV09SRGBcbiAqIChzZW50aW5lbCBBVVRILCBzZW50aW5lbCBtb2RlIG9ubHkpIGFyZSB0aHJlYWRlZCB0aHJvdWdoIHdoZW4gc2V0LlxuICpcbiAqIEBwYXJhbSBsYWJlbCBzaG9ydCBodW1hbiBuYW1lIGZvciB0aGlzIGNsaWVudCwgdXNlZCBpbiB0aGUgdHdvIHdhcm4gbG9ncy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVudlJlZGlzQ2xpZW50PFQgPSB1bmtub3duPihsYWJlbDogc3RyaW5nKTogVCB8IG51bGwge1xuICB0cnkge1xuICAgIGNvbnN0IHNlbnRpbmVscyA9IHBhcnNlU2VudGluZWxzKHByb2Nlc3MuZW52LlJFRElTX1NFTlRJTkVMUyk7XG4gICAgY29uc3QgdXJsID0gcHJvY2Vzcy5lbnYuUkVESVNfVVJMO1xuICAgIGNvbnN0IGhvc3QgPSBwcm9jZXNzLmVudi5SRURJU19IT1NUO1xuICAgIGlmIChzZW50aW5lbHMubGVuZ3RoID09PSAwICYmICF1cmwgJiYgIWhvc3QpIHJldHVybiBudWxsO1xuICAgIGNvbnN0IHJlcSA9IGNyZWF0ZVJlcXVpcmUoaW1wb3J0Lm1ldGEudXJsKTtcbiAgICBjb25zdCBtb2QgPSByZXEoJ2lvcmVkaXMnKSBhcyB7XG4gICAgICBSZWRpcz86IG5ldyAoLi4uYXJnczogdW5rbm93bltdKSA9PiB1bmtub3duO1xuICAgICAgZGVmYXVsdD86IG5ldyAoLi4uYXJnczogdW5rbm93bltdKSA9PiB1bmtub3duO1xuICAgIH07XG4gICAgY29uc3QgUmVkaXNDdG9yID0gKG1vZC5SZWRpcyA/PyBtb2QuZGVmYXVsdCA/PyBtb2QpIGFzIG5ldyAoLi4uYXJnczogdW5rbm93bltdKSA9PiBUO1xuICAgIGNvbnN0IHJlZGlzT3B0czogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7IG1heFJldHJpZXNQZXJSZXF1ZXN0OiAxLCBlbmFibGVPZmZsaW5lUXVldWU6IGZhbHNlIH07XG4gICAgaWYgKHByb2Nlc3MuZW52LlJFRElTX1BBU1NXT1JEKSByZWRpc09wdHMucGFzc3dvcmQgPSBwcm9jZXNzLmVudi5SRURJU19QQVNTV09SRDtcblxuICAgIGxldCBpbnN0OiBUO1xuICAgIGlmIChzZW50aW5lbHMubGVuZ3RoID4gMCkge1xuICAgICAgLy8gU2VudGluZWwgbW9kZTogaW9yZWRpcyB0cmFja3MgdGhlIG1hc3RlciB2aWEgdGhlIHNlbnRpbmVscyArIGF1dG8tZmFpbHMtb3Zlci5cbiAgICAgIGNvbnN0IHNlbnRpbmVsT3B0czogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7XG4gICAgICAgIHNlbnRpbmVscyxcbiAgICAgICAgbmFtZTogcHJvY2Vzcy5lbnYuUkVESVNfU0VOVElORUxfTUFTVEVSIHx8ICdteW1hc3RlcicsXG4gICAgICAgIC4uLnJlZGlzT3B0cyxcbiAgICAgIH07XG4gICAgICBpZiAocHJvY2Vzcy5lbnYuUkVESVNfU0VOVElORUxfUEFTU1dPUkQpIHNlbnRpbmVsT3B0cy5zZW50aW5lbFBhc3N3b3JkID0gcHJvY2Vzcy5lbnYuUkVESVNfU0VOVElORUxfUEFTU1dPUkQ7XG4gICAgICBpbnN0ID0gbmV3IFJlZGlzQ3RvcihzZW50aW5lbE9wdHMpO1xuICAgICAgbG9nZ2VyLmluZm8oYFJlZGlzICR7bGFiZWx9OiBTZW50aW5lbCBtb2RlYCwgeyBtYXN0ZXI6IHNlbnRpbmVsT3B0cy5uYW1lLCBzZW50aW5lbHM6IHNlbnRpbmVscy5sZW5ndGggfSk7XG4gICAgfSBlbHNlIGlmICh1cmwpIHtcbiAgICAgIGluc3QgPSBuZXcgUmVkaXNDdG9yKHVybCwgcmVkaXNPcHRzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaW5zdCA9IG5ldyBSZWRpc0N0b3IoeyBob3N0LCBwb3J0OiBwYXJzZUludChwcm9jZXNzLmVudi5SRURJU19QT1JUID8/ICc2Mzc5JywgMTApLCAuLi5yZWRpc09wdHMgfSk7XG4gICAgfVxuICAgIChpbnN0IGFzIHVua25vd24gYXMgeyBvbjogKGV2dDogc3RyaW5nLCBjYjogKGU6IHVua25vd24pID0+IHZvaWQpID0+IHZvaWQgfSlcbiAgICAgIC5vbignZXJyb3InLCAoZSkgPT4gbG9nZ2VyLndhcm4oYFJlZGlzICR7bGFiZWx9IGNsaWVudCBlcnJvcmAsIHsgZXJyb3I6IGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6IFN0cmluZyhlKSB9KSk7XG4gICAgcmV0dXJuIGluc3Q7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGxvZ2dlci53YXJuKGBSZWRpcyB1bmF2YWlsYWJsZSBmb3IgJHtsYWJlbH1gLCB7IGVycm9yOiBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycikgfSk7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbn1cbiJdfQ==
236
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LXJlZGlzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL2Vudi1yZWRpcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDO0FBRXRDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFdkMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRWxELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUV6Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXlCRztBQUVILG9FQUFvRTtBQUNwRSxNQUFNLE9BQU8sZ0JBQWlCLFNBQVEsS0FBSztJQUN6QyxZQUFZLE9BQWU7UUFDekIsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxrQkFBa0IsQ0FBQztJQUNqQyxDQUFDO0NBQ0Y7QUFpQkQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQUMsR0FBdUI7SUFDcEQsSUFBSSxDQUFDLEdBQUc7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUNwQixPQUFPLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDdkUsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQyxNQUFNLElBQUksR0FBRyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDdEQsTUFBTSxRQUFR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LENBQUM7UUFDRCxJQUFJLE1BQU07WUFBRSxPQUFPLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNyQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDZCxRQUFRLEdBQUcsY0FBYyxDQUFDLE1BQU0sRUFBRSxTQUFTLENBQUM7aUJBQ3pDLEtBQUssQ0FBQyxHQUFHLEVBQUU7Z0JBQ1YsTUFBTSxHQUFHLElBQUksQ0FBQztnQkFDZCxrREFBa0Q7Z0JBQ2xELE1BQU0sQ0FBQyxJQUFLLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxHQUFHLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNuRCxDQUFDLENBQUM7aUJBQ0QsT0FBTyxDQUFDLEdBQUcsRUFBRSxHQUFHLFFBQVEsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUN6QyxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQU9EOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxrQkFBa0IsR0FBRzs7Ozs7U0FLbEIsQ0FBQztBQUVWOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxLQUFLLFVBQVUsVUFBVSxDQUFDLEtBQXNCLEVBQUUsR0FBVyxFQUFFLFFBQWdCO0lBQ3BGLE1BQU0sQ0FBQyxHQUFHLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pGLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHsgY3JlYXRlUmVxdWlyZSB9IGZyb20gJ21vZHVsZSc7XG5cbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignZW52LXJlZGlzJyk7XG5cbi8qKlxuICogVGhlIE9ORSBwbGFjZSBSZWRpcyBjb25uZWN0aW9uIHNldHRpbmdzIGFyZSByZWFkIGZyb20gdGhlIGVudmlyb25tZW50LlxuICpcbiAqIFR3byBzaGFwZXMsIGV4YWN0bHkgb25lIG9mIHdoaWNoIG1heSBiZSBzZXQ6XG4gKlxuICogLSAqKlN0YW5kYWxvbmUqKiDigJQgYFJFRElTX1VSTGAgKGByZWRpczovL2hvc3Q6NjM3OVsvZGJdYCwgb3IgYHJlZGlzczovL2AgZm9yXG4gKiAgIFRMUykuIENyZWRlbnRpYWxzIG1heSBzaXQgaW4gdGhlIFVSTCBvciBpbiBgUkVESVNfUEFTU1dPUkRgLlxuICogLSAqKkhBIChTZW50aW5lbCkqKiDigJQgYFJFRElTX1NFTlRJTkVMU2AgKGNvbW1hLXNlcGFyYXRlZCBgaG9zdDpwb3J0YCkgcGx1c1xuICogICBgUkVESVNfU0VOVElORUxfTUFTVEVSYCAoZGVmYXVsdCBgbXltYXN0ZXJgKSBhbmQgb3B0aW9uYWxcbiAqICAgYFJFRElTX1NFTlRJTkVMX1BBU1NXT1JEYC4gYFJFRElTX1BBU1NXT1JEYCBhdXRoZW50aWNhdGVzIHRvIHRoZSBkYXRhIG5vZGVzLlxuICogICBpb3JlZGlzIGZvbGxvd3MgdGhlIG1hc3RlciBhY3Jvc3MgYSBmYWlsb3Zlci5cbiAqXG4gKiBOZWl0aGVyIHNldCDihpIgUmVkaXMgaXMgb2ZmLCBhbmQgZWFjaCBjYWxsZXIgZGVncmFkZXMgdG8gaXRzIGRvY3VtZW50ZWRcbiAqIG5vLVJlZGlzIGJlaGF2aW9yLlxuICpcbiAqIGBSRURJU19IT1NUYCAvIGBSRURJU19QT1JUYCBhcmUgbm90IHJlYWQuIGBSRURJU19IT1NUYCBpcyByZWZ1c2VkIG91dHJpZ2h0IHNvIGFcbiAqIHN0YWxlIGNvbmZpZyBmYWlscyBhdCBzdGFydHVwIGluc3RlYWQgb2Ygc2lsZW50bHkgcnVubmluZyB3aXRob3V0IFJlZGlzLlxuICogYFJFRElTX1BPUlRgIGNhbid0IGJlIHJlZnVzZWQ6IEt1YmVybmV0ZXMgaW5qZWN0cyBgUkVESVNfUE9SVD10Y3A6Ly88aXA+OjYzNzlgXG4gKiBpbnRvIGV2ZXJ5IHBvZCBpbiBhIG5hbWVzcGFjZSB3aXRoIGEgU2VydmljZSBuYW1lZCBgcmVkaXNgLCB3aGljaCBpcyBleGFjdGx5XG4gKiB3aHkgYSBob3N0L3BvcnQgcGFpciB3YXMgdW5zYWZlIHRvIHBhcnNlLlxuICpcbiAqIE1pc2NvbmZpZ3VyYXRpb24gdGhyb3dzIHtAbGluayBSZWRpc0NvbmZpZ0Vycm9yfS4gV3JpdGVycyBhbmQgcmVhZGVycyBvZiB0aGVcbiAqIHNhbWUga2V5cyAocmV2b2NhdGlvbiwgc3RlcC11cCwgbGVhZGVyIGxvY2tzKSBtdXN0IHJlc29sdmUgUmVkaXMgaWRlbnRpY2FsbHk7XG4gKiBhIGNvbmZpZyB0aGF0IHF1aWV0bHkgcmVzb2x2ZWQgdG8gXCJubyBSZWRpc1wiIG9uIG9uZSBzaWRlIGlzIGhvdyByZXZvY2F0aW9uXG4gKiBvbmNlIGRpZCBub3RoaW5nIGF0IGFsbC5cbiAqL1xuXG4vKiogVGhyb3duIGZvciBhIFJlZGlzIGVudmlyb25tZW50IHRoYXQgY2FuJ3QgYmUgdXNlZCBhcyB3cml0dGVuLiAqL1xuZXhwb3J0IGNsYXNzIFJlZGlzQ29uZmlnRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2U6IHN0cmluZykge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgIHRoaXMubmFtZSA9ICdSZWRpc0NvbmZpZ0Vycm9yJztcbiAgfVxufVxuXG4vKiogUmVzb2x2ZWQgY29ubmVjdGlvbiwgaW5kZXBlbmRlbnQgb2YgYW55IGNsaWVudCBsaWJyYXJ5LiAqL1xuZXhwb3J0IHR5cGUgUmVkaXNDb25uZWN0aW9uID1cbiAgfCB7XG4gICAgbW9kZTogJ3NlbnRpbmVsJztcbiAgICBzZW50aW5lbHM6IEFycmF5PHsgaG9zdDogc3RyaW5nOyBwb3J0OiBudW1iZXIgfT47XG4gICAgbWFzdGVyTmFtZTogc3RyaW5nO1xuICAgIHBhc3N3b3JkPzogc3RyaW5nO1xuICAgIHNlbnRpbmVsUGFzc3dvcmQ/OiBzdHJpbmc7XG4gIH1cbiAgfCB7XG4gICAgbW9kZTogJ3VybCc7XG4gICAgdXJsOiBzdHJpbmc7XG4gICAgcGFzc3dvcmQ/OiBzdHJpbmc7XG4gIH07XG5cbi8qKlxuICogUGFyc2UgYFJFRElTX1NFTlRJTkVMU2AgaW50byBgeyBob3N0LCBwb3J0IH1bXWAuIEJsYW5rIGVudHJpZXMgYXJlIHNraXBwZWQgYW5kXG4gKiBhIG1pc3NpbmcgcG9ydCBtZWFucyB0aGUgU2VudGluZWwgZGVmYXVsdCAyNjM3OTsgYSBwb3J0IHRoYXQgaXNuJ3QgYSB2YWxpZFxuICogVENQIHBvcnQgaXMgYSBjb25maWd1cmF0aW9uIGVycm9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VTZW50aW5lbHMocmF3OiBzdHJpbmcgfCB1bmRlZmluZWQpOiBBcnJheTx7IGhvc3Q6IHN0cmluZzsgcG9ydDogbnVtYmVyIH0+IHtcbiAgaWYgKCFyYXcpIHJldHVybiBbXTtcbiAgcmV0dXJuIHJhdy5zcGxpdCgnLCcpLm1hcCgocykgPT4gcy50cmltKCkpLmZpbHRlcihCb29sZWFuKS5tYXAoKGVudHJ5KSA9PiB7XG4gICAgY29uc3QgaWR4ID0gZW50cnkubGFzdEluZGV4T2YoJzonKTtcbiAgICBjb25zdCBob3N0ID0gaWR4ID09PSAtMSA/IGVudHJ5IDogZW50cnkuc2xpY2UoMCwgaWR4KTtcbiAgICBjb25zdCBwb3J0VGV4dCA9IGlkeCA9PT0gLTEgPyAnJyA6IGVudHJ5LnNsaWNlKGlkeCArIDEpO1xuICAgIGNvbnN0IHBvcnQgPSBwb3J0VGV4dCA9PT0gJycgPyAyNjM3OSA6IE51bWJlcihwb3J0VGV4dCk7XG4gICAgaWYgKCFob3N0IHx8ICFOdW1iZXIuaXNJbnRlZ2VyKHBvcnQpIHx8IHBvcnQgPCAxIHx8IHBvcnQgPiA2NTUzNSkge1xuICAgICAgdGhyb3cgbmV3IFJlZGlzQ29uZmlnRXJyb3IoYFJFRElTX1NFTlRJTkVMUyBlbnRyeSBcIiR7ZW50cnl9XCIgaXMgbm90IGhvc3Q6cG9ydGApO1xuICAgIH1cbiAgICByZXR1cm4geyBob3N0LCBwb3J0IH07XG4gIH0pO1xufVxuXG4vKipcbiAqIFJlc29sdmUgdGhlIFJlZGlzIGNvbm5lY3Rpb24gZnJvbSBgZW52YCwgb3IgYG51bGxgIHdoZW4gUmVkaXMgaXNuJ3RcbiAqIGNvbmZpZ3VyZWQuIFRocm93cyB7QGxpbmsgUmVkaXNDb25maWdFcnJvcn0gZm9yIGFuIHVudXNhYmxlIGNvbmZpZ3VyYXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlUmVkaXNDb25uZWN0aW9uKGVudjogTm9kZUpTLlByb2Nlc3NFbnYgPSBwcm9jZXNzLmVudik6IFJlZGlzQ29ubmVjdGlvbiB8IG51bGwge1xuICBpZiAoZW52LlJFRElTX0hPU1QpIHtcbiAgICB0aHJvdyBuZXcgUmVkaXNDb25maWdFcnJvcihcbiAgICAgICdSRURJU19IT1NUIGlzIG5vdCBzdXBwb3J0ZWQuIFNldCBSRURJU19VUkw9cmVkaXM6Ly88aG9zdD46PHBvcnQ+IChvciBSRURJU19TRU5USU5FTFMgZm9yIEhBKSBhbmQgcmVtb3ZlIFJFRElTX0hPU1QvUkVESVNfUE9SVC4nLFxuICAgICk7XG4gIH1cblxuICBjb25zdCBzZW50aW5lbHMgPSBwYXJzZVNlbnRpbmVscyhlbnYuUkVESVNfU0VOVElORUxTKTtcbiAgY29uc3QgdXJsID0gZW52LlJFRElTX1VSTD8udHJpbSgpO1xuICBjb25zdCBwYXNzd29yZCA9IGVudi5SRURJU19QQVNTV09SRCB8fCB1bmRlZmluZWQ7XG5cbiAgaWYgKHNlbnRpbmVscy5sZW5ndGggPiAwICYmIHVybCkge1xuICAgIHRocm93IG5ldyBSZWRpc0NvbmZpZ0Vycm9yKCdTZXQgUkVESVNfVVJMIG9yIFJFRElTX1NFTlRJTkVMUywgbm90IGJvdGguJyk7XG4gIH1cblxuICBpZiAoc2VudGluZWxzLmxlbmd0aCA+IDApIHtcbiAgICByZXR1cm4ge1xuICAgICAgbW9kZTogJ3NlbnRpbmVsJyxcbiAgICAgIHNlbnRpbmVscyxcbiAgICAgIG1hc3Rlck5hbWU6IGVudi5SRURJU19TRU5USU5FTF9NQVNURVIgfHwgJ215bWFzdGVyJyxcbiAgICAgIHBhc3N3b3JkLFxuICAgICAgc2VudGluZWxQYXNzd29yZDogZW52LlJFRElTX1NFTlRJTkVMX1BBU1NXT1JEIHx8IHVuZGVmaW5lZCxcbiAgICB9O1xuICB9XG5cbiAgaWYgKHVybCkge1xuICAgIGxldCBwYXJzZWQ6IFVSTDtcbiAgICB0cnkge1xuICAgICAgcGFyc2VkID0gbmV3IFVSTCh1cmwpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhyb3cgbmV3IFJlZGlzQ29uZmlnRXJyb3IoJ1JFRElTX1VSTCBpcyBub3QgYSB2YWxpZCBVUkwgKGV4cGVjdGVkIHJlZGlzOi8vPGhvc3Q+Ojxwb3J0PikuJyk7XG4gICAgfVxuICAgIGlmIChwYXJzZWQucHJvdG9jb2wgIT09ICdyZWRpczonICYmIHBhcnNlZC5wcm90b2NvbCAhPT0gJ3JlZGlzczonKSB7XG4gICAgICB0aHJvdyBuZXcgUmVkaXNDb25maWdFcnJvcihgUkVESVNfVVJMIG11c3QgdXNlIHJlZGlzOi8vIG9yIHJlZGlzczovLywgZ290ICR7cGFyc2VkLnByb3RvY29sfS8vYCk7XG4gICAgfVxuICAgIGlmICghcGFyc2VkLmhvc3RuYW1lKSB0aHJvdyBuZXcgUmVkaXNDb25maWdFcnJvcignUkVESVNfVVJMIGhhcyBubyBob3N0LicpO1xuICAgIHJldHVybiB7IG1vZGU6ICd1cmwnLCB1cmwsIHBhc3N3b3JkIH07XG4gIH1cblxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqIEEgbG9nLXNhZmUgZGVzY3JpcHRpb24gb2YgYSBjb25uZWN0aW9uIChuZXZlciBpbmNsdWRlcyBjcmVkZW50aWFscykuICovXG5leHBvcnQgZnVuY3Rpb24gZGVzY3JpYmVSZWRpc0Nvbm5lY3Rpb24oY29ubjogUmVkaXNDb25uZWN0aW9uKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICBpZiAoY29ubi5tb2RlID09PSAnc2VudGluZWwnKSB7XG4gICAgcmV0dXJuIHsgbW9kZTogJ3NlbnRpbmVsJywgbWFzdGVyOiBjb25uLm1hc3Rlck5hbWUsIHNlbnRpbmVsczogY29ubi5zZW50aW5lbHMubGVuZ3RoIH07XG4gIH1cbiAgY29uc3QgdSA9IG5ldyBVUkwoY29ubi51cmwpO1xuICByZXR1cm4geyBtb2RlOiAndXJsJywgaG9zdDogdS5ob3N0bmFtZSwgcG9ydDogdS5wb3J0IHx8ICc2Mzc5JywgdGxzOiB1LnByb3RvY29sID09PSAncmVkaXNzOicgfTtcbn1cblxudHlwZSBSZWRpc0N0b3I8VD4gPSBuZXcgKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gVDtcblxuZnVuY3Rpb24gbG9hZElvcmVkaXM8VD4oKTogUmVkaXNDdG9yPFQ+IHtcbiAgY29uc3QgcmVxID0gY3JlYXRlUmVxdWlyZShpbXBvcnQubWV0YS51cmwpO1xuICBjb25zdCBtb2QgPSByZXEoJ2lvcmVkaXMnKSBhcyB7IFJlZGlzPzogUmVkaXNDdG9yPFQ+OyBkZWZhdWx0PzogUmVkaXNDdG9yPFQ+IH07XG4gIHJldHVybiAobW9kLlJlZGlzID8/IG1vZC5kZWZhdWx0ID8/IG1vZCkgYXMgUmVkaXNDdG9yPFQ+O1xufVxuXG4vKipcbiAqIENvbnN0cnVjdCBhbiBpb3JlZGlzIGNsaWVudCBmb3IgYSByZXNvbHZlZCBjb25uZWN0aW9uLiBgb3B0aW9uc2AgYXJlIG1lcmdlZFxuICogaW50byB0aGUgY2xpZW50IG9wdGlvbnMgKGUuZy4gYHsgZGIsIG1heFJldHJpZXNQZXJSZXF1ZXN0OiBudWxsIH1gIGZvciBCdWxsTVEpLlxuICogQW4gYGVycm9yYCBsaXN0ZW5lciBpcyBhbHdheXMgYXR0YWNoZWQgc28gYSBkcm9wcGVkIGNvbm5lY3Rpb24gaXMgbG9nZ2VkXG4gKiByYXRoZXIgdGhhbiBzdXJmYWNpbmcgYXMgYW4gdW5oYW5kbGVkIGAnZXJyb3InYCBldmVudCB0aGF0IGNyYXNoZXMgTm9kZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJlZGlzQ2xpZW50PFQgPSB1bmtub3duPihcbiAgY29ubjogUmVkaXNDb25uZWN0aW9uLFxuICBsYWJlbDogc3RyaW5nLFxuICBvcHRpb25zOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9LFxuKTogVCB7XG4gIGNvbnN0IEN0b3IgPSBsb2FkSW9yZWRpczxUPigpO1xuICBjb25zdCBhdXRoID0gY29ubi5wYXNzd29yZCA/IHsgcGFzc3dvcmQ6IGNvbm4ucGFzc3dvcmQgfSA6IHt9O1xuICBjb25zdCBpbnN0ID0gY29ubi5tb2RlID09PSAnc2VudGluZWwnXG4gICAgPyBuZXcgQ3Rvcih7XG4gICAgICBzZW50aW5lbHM6IGNvbm4uc2VudGluZWxzLFxuICAgICAgbmFtZTogY29ubi5tYXN0ZXJOYW1lLFxuICAgICAgLi4uKGNvbm4uc2VudGluZWxQYXNzd29yZCA/IHsgc2VudGluZWxQYXNzd29yZDogY29ubi5zZW50aW5lbFBhc3N3b3JkIH0gOiB7fSksXG4gICAgICAuLi5hdXRoLFxuICAgICAgLi4ub3B0aW9ucyxcbiAgICB9KVxuICAgIDogbmV3IEN0b3IoY29ubi51cmwsIHsgLi4uYXV0aCwgLi4ub3B0aW9ucyB9KTtcbiAgKGluc3QgYXMgdW5rbm93biBhcyB7IG9uOiAoZXZ0OiBzdHJpbmcsIGNiOiAoZTogdW5rbm93bikgPT4gdm9pZCkgPT4gdm9pZCB9KVxuICAgIC5vbignZXJyb3InLCAoZSkgPT4gbG9nZ2VyLndhcm4oYFJlZGlzICR7bGFiZWx9IGNsaWVudCBlcnJvcmAsIHsgZXJyb3I6IGUgaW5zdGFuY2VvZiBFcnJvciA/IGUubWVzc2FnZSA6IFN0cmluZyhlKSB9KSk7XG4gIHJldHVybiBpbnN0O1xufVxuXG4vKipcbiAqIFRoZSBzaGFyZWQgYXBwbGljYXRpb24gUmVkaXMgY2xpZW50OiBgbnVsbGAgd2hlbiBSZWRpcyBpc24ndCBjb25maWd1cmVkLCBzb1xuICogdGhlIGNhbGxlciBkZWdyYWRlcyB0byBpdHMgbm8tUmVkaXMgYmVoYXZpb3IuXG4gKlxuICogQ29tbWFuZHMgZmFpbCBmYXN0IChgbWF4UmV0cmllc1BlclJlcXVlc3Q6IDFgLCBubyBvZmZsaW5lIHF1ZXVlKSBiZWNhdXNlIHRoZVxuICogcmVxdWVzdC1wYXRoIGNhbGxlcnMgYXJlIGJlc3QtZWZmb3J0IG9yIGZhaWwgY2xvc2VkIG9uIHRoZWlyIG93biB0ZXJtcyDigJQgYVxuICogcmVxdWVzdCBtdXN0IG5vdCBoYW5nIGJlaGluZCBhIFJlZGlzIG91dGFnZS4gVGhhdCBpbmNsdWRlcyB0aGUgbW9tZW50cyBiZWZvcmVcbiAqIHRoZSBmaXJzdCBjb25uZWN0aW9uIGNvbXBsZXRlczogYSBiYWNrZ3JvdW5kIGNhbGxlciB0aGF0IHJ1bnMgYXQgc3RhcnR1cCBtdXN0XG4gKiBlaXRoZXIgdG9sZXJhdGUgYSByZWplY3RlZCBjb21tYW5kIG9yIHdhaXQgd2l0aCB7QGxpbmsgd2hlblJlZGlzUmVhZHl9LlxuICpcbiAqIFRocm93cyB7QGxpbmsgUmVkaXNDb25maWdFcnJvcn0gZm9yIGEgYmFkIGNvbmZpZ3VyYXRpb24sIGFuZCBpZiBSZWRpcyBpc1xuICogY29uZmlndXJlZCBidXQgYGlvcmVkaXNgIGNhbid0IGJlIGxvYWRlZCDigJQgYm90aCBhcmUgZGVwbG95bWVudCBlcnJvcnMgdGhhdFxuICogbXVzdCBub3QgcXVpZXRseSB0dXJuIFJlZGlzLWJhY2tlZCBndWFyYW50ZWVzIG9mZi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVudlJlZGlzQ2xpZW50PFQgPSB1bmtub3duPihsYWJlbDogc3RyaW5nKTogVCB8IG51bGwge1xuICBjb25zdCBjb25uID0gcmVzb2x2ZVJlZGlzQ29ubmVjdGlvbigpO1xuICBpZiAoIWNvbm4pIHJldHVybiBudWxsO1xuICBjb25zdCBpbnN0ID0gY3JlYXRlUmVkaXNDbGllbnQ8VD4oY29ubiwgbGFiZWwsIHsgbWF4UmV0cmllc1BlclJlcXVlc3Q6IDEsIGVuYWJsZU9mZmxpbmVRdWV1ZTogZmFsc2UgfSk7XG4gIGxvZ2dlci5pbmZvKGBSZWRpcyAke2xhYmVsfSBjbGllbnQgY3JlYXRlZGAsIGRlc2NyaWJlUmVkaXNDb25uZWN0aW9uKGNvbm4pKTtcbiAgcmV0dXJuIGluc3Q7XG59XG5cbi8qKiBUaGUgc3Vic2V0IG9mIGlvcmVkaXMgbmVlZGVkIHRvIHdhaXQgZm9yIGEgY29ubmVjdGlvbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVhZHlBd2FyZVJlZGlzIHtcbiAgc3RhdHVzPzogc3RyaW5nO1xuICBvbmNlPyhldmVudDogc3RyaW5nLCBjYjogKC4uLmFyZ3M6IHVua25vd25bXSkgPT4gdm9pZCk6IHVua25vd247XG4gIG9mZj8oZXZlbnQ6IHN0cmluZywgY2I6ICguLi5hcmdzOiB1bmtub3duW10pID0+IHZvaWQpOiB1bmtub3duO1xufVxuXG4vKipcbiAqIFJlc29sdmUgb25jZSBgY2xpZW50YCBpcyBjb25uZWN0ZWQgYW5kIHJlYWR5IGZvciBjb21tYW5kcywgb3IgcmVqZWN0IGFmdGVyXG4gKiBgdGltZW91dE1zYC4gRm9yIHN0YXJ0dXAgd29yayAoY3JlYXRpbmcgYSBjb25zdW1lciBncm91cCwgc3Vic2NyaWJpbmcpIHRoYXRcbiAqIG90aGVyd2lzZSByYWNlcyB0aGUgZmlyc3QgY29ubmVjdGlvbi4gQSBjbGllbnQgd2l0aG91dCBpb3JlZGlzJyBgc3RhdHVzYFxuICogKGUuZy4gYSB0ZXN0IGRvdWJsZSkgY291bnRzIGFzIHJlYWR5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gd2hlblJlZGlzUmVhZHkoY2xpZW50OiBSZWFkeUF3YXJlUmVkaXMsIHRpbWVvdXRNcyA9IDMwXzAwMCk6IFByb21pc2U8dm9pZD4ge1xuICBpZiAoY2xpZW50LnN0YXR1cyA9PT0gdW5kZWZpbmVkIHx8IGNsaWVudC5zdGF0dXMgPT09ICdyZWFkeScgfHwgIWNsaWVudC5vbmNlKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3Qgb25SZWFkeSA9ICgpID0+IHsgY2xlYXJUaW1lb3V0KHRpbWVyKTsgcmVzb2x2ZSgpOyB9O1xuICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBjbGllbnQub2ZmPy4oJ3JlYWR5Jywgb25SZWFkeSk7XG4gICAgICByZWplY3QobmV3IEVycm9yKGBSZWRpcyBub3QgcmVhZHkgYWZ0ZXIgJHt0aW1lb3V0TXN9bXNgKSk7XG4gICAgfSwgdGltZW91dE1zKTtcbiAgICB0aW1lci51bnJlZj8uKCk7XG4gICAgY2xpZW50Lm9uY2UhKCdyZWFkeScsIG9uUmVhZHkpO1xuICB9KTtcbn1cblxuLyoqIERlZmF1bHQgYm91bmQgZm9yIHtAbGluayBjcmVhdGVSZWRpc1JlYWR5R2F0ZX06IHNob3J0IGVub3VnaCBmb3IgYSByZXF1ZXN0IHBhdGguICovXG5leHBvcnQgY29uc3QgUkVRVUVTVF9QQVRIX1JFRElTX1JFQURZX1RJTUVPVVRfTVMgPSAyXzAwMDtcblxuLyoqXG4gKiBBIHJlcXVlc3QtcGF0aCByZWFkaW5lc3MgZ2F0ZSBmb3IgYSBsYXppbHkgYnVpbHQgZW52IFJlZGlzIGNsaWVudC5cbiAqXG4gKiBUaGUgZW52IGNsaWVudCBoYXMgbm8gb2ZmbGluZSBxdWV1ZSwgc28gYSBjb21tYW5kIGlzc3VlZCBiZWZvcmUgdGhlIGZpcnN0XG4gKiBjb25uZWN0aW9uIGNvbXBsZXRlcyBpcyByZWplY3RlZCBvdXRyaWdodCDigJQgdGhlIGZpcnN0IHJlcXVlc3QgYWZ0ZXIgYSBsYXp5XG4gKiBjb25zdHJ1Y3Rpb24gd291bGQgb3RoZXJ3aXNlIGhpdCB0aGF0IHJlamVjdGlvbiAoZS5nLiB0aGUgZmlyc3Qgc3RlcC11cCBwZXJcbiAqIHBvZCBmYWlsaW5nLCBvciB0aGUgZmlyc3QgaW1wZXJzb25hdGlvbiBjaGVjayByZWFkaW5nIFwidW5hdmFpbGFibGVcIikuXG4gKlxuICogVGhlIHJldHVybmVkIGZ1bmN0aW9uIHJlc29sdmVzIG9uY2UgdGhlIGNsaWVudCBpcyByZWFkeSwgb3IgYWZ0ZXJcbiAqIGB0aW1lb3V0TXNgIOKAlCBpdCBORVZFUiByZWplY3RzOiB0aGUgY2FsbGVyIHRoZW4gcnVucyBpdHMgY29tbWFuZCBhbmQga2VlcHMgaXRzXG4gKiBvd24gZmFpbC1vcGVuIC8gZmFpbC1jbG9zZWQgc2VtYW50aWNzLiBDb25jdXJyZW50IGNhbGxlcnMgc2hhcmUgb25lIHdhaXQuIEFmdGVyXG4gKiBhIHdhaXQgdGltZXMgb3V0IChSZWRpcyBnZW51aW5lbHkgZG93bikgbGF0ZXIgY2FsbHMgc3RvcCB3YWl0aW5nIHVudGlsIHRoZVxuICogY2xpZW50IHJlcG9ydHMgYHJlYWR5YCBhZ2Fpbiwgc28gYW4gb3V0YWdlIGNvc3RzIG9uZSBib3VuZGVkIHdhaXQgaW5zdGVhZCBvZlxuICogYWRkaW5nIGB0aW1lb3V0TXNgIHRvIGV2ZXJ5IHJlcXVlc3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVSZWRpc1JlYWR5R2F0ZShcbiAgY2xpZW50OiBSZWFkeUF3YXJlUmVkaXMsXG4gIHRpbWVvdXRNcyA9IFJFUVVFU1RfUEFUSF9SRURJU19SRUFEWV9USU1FT1VUX01TLFxuKTogKCkgPT4gUHJvbWlzZTx2b2lkPiB7XG4gIGxldCBpbmZsaWdodDogUHJvbWlzZTx2b2lkPiB8IG51bGwgPSBudWxsO1xuICBsZXQgZ2F2ZVVwID0gZmFsc2U7XG4gIHJldHVybiAoKSA9PiB7XG4gICAgaWYgKGNsaWVudC5zdGF0dXMgPT09IHVuZGVmaW5lZCB8fCBjbGllbnQuc3RhdHVzID09PSAncmVhZHknIHx8ICFjbGllbnQub25jZSkge1xuICAgICAgZ2F2ZVVwID0gZmFsc2U7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgfVxuICAgIGlmIChnYXZlVXApIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICBpZiAoIWluZmxpZ2h0KSB7XG4gICAgICBpbmZsaWdodCA9IHdoZW5SZWRpc1JlYWR5KGNsaWVudCwgdGltZW91dE1zKVxuICAgICAgICAuY2F0Y2goKCkgPT4ge1xuICAgICAgICAgIGdhdmVVcCA9IHRydWU7XG4gICAgICAgICAgLy8gUmUtYXJtIHRoZSB3YWl0IG9uY2UgdGhlIGNvbm5lY3Rpb24gY29tZXMgYmFjay5cbiAgICAgICAgICBjbGllbnQub25jZSEoJ3JlYWR5JywgKCkgPT4geyBnYXZlVXAgPSBmYWxzZTsgfSk7XG4gICAgICAgIH0pXG4gICAgICAgIC5maW5hbGx5KCgpID0+IHsgaW5mbGlnaHQgPSBudWxsOyB9KTtcbiAgICB9XG4gICAgcmV0dXJuIGluZmxpZ2h0O1xuICB9O1xufVxuXG4vKiogVGhlIHN1YnNldCBvZiBpb3JlZGlzIG5lZWRlZCBieSB7QGxpbmsgaW5jcldpbmRvd30uICovXG5leHBvcnQgaW50ZXJmYWNlIFJlZGlzRXZhbENsaWVudCB7XG4gIGV2YWwoc2NyaXB0OiBzdHJpbmcsIG51bUtleXM6IG51bWJlciwgLi4uYXJnczogKHN0cmluZyB8IG51bWJlcilbXSk6IFByb21pc2U8dW5rbm93bj47XG59XG5cbi8qKlxuICogSU5DUiBhIGZpeGVkLXdpbmRvdyBjb3VudGVyIGFuZCBtYWtlIHN1cmUgaXQgY2FycmllcyBhIFRUTCwgYXRvbWljYWxseS5cbiAqXG4gKiBBIHNlcGFyYXRlIGBJTkNSYCB0aGVuIGBFWFBJUkVgIGlzIG5vdCBhdG9taWM6IGlmIHRoZSBFWFBJUkUgaXMgbG9zdCAoYVxuICogY29ubmVjdGlvbiBkcm9wLCBhIGZhaWxvdmVyIGJldHdlZW4gdGhlIHR3byBjb21tYW5kcykgdGhlIGtleSBuZXZlciBleHBpcmVzXG4gKiBhbmQgdGhlIGNvdW50ZXIgc3RheXMgb3ZlciBpdHMgbGltaXQgZm9yZXZlci4gVGhlIHNjcmlwdCBhbHNvIGhlYWxzIGEga2V5XG4gKiB0aGF0IHNvbWVob3cgbGFja3MgYSBUVEwgKGBQVFRMYCA9IC0xKSByYXRoZXIgdGhhbiBvbmx5IHNldHRpbmcgaXQgb24gdGhlXG4gKiBmaXJzdCBoaXQuXG4gKi9cbmNvbnN0IElOQ1JfV0lORE9XX1NDUklQVCA9IGBcbmxvY2FsIG4gPSByZWRpcy5jYWxsKCdJTkNSJywgS0VZU1sxXSlcbmlmIG4gPT0gMSBvciByZWRpcy5jYWxsKCdQVFRMJywgS0VZU1sxXSkgPCAwIHRoZW5cbiAgcmVkaXMuY2FsbCgnUEVYUElSRScsIEtFWVNbMV0sIEFSR1ZbMV0pXG5lbmRcbnJldHVybiBuYDtcblxuLyoqXG4gKiBJbmNyZW1lbnQgYGtleWAgd2l0aGluIGEgd2luZG93IG9mIGB3aW5kb3dNc2AgYW5kIHJldHVybiB0aGUgbmV3IGNvdW50LlxuICogVGhyb3dzIHdoZW4gUmVkaXMgZXJyb3JzIOKAlCBjYWxsZXJzIGNob29zZSB0aGVpciBvd24gZmFpbHVyZSBwb2xpY3kuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbmNyV2luZG93KHJlZGlzOiBSZWRpc0V2YWxDbGllbnQsIGtleTogc3RyaW5nLCB3aW5kb3dNczogbnVtYmVyKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgY29uc3QgbiA9IGF3YWl0IHJlZGlzLmV2YWwoSU5DUl9XSU5ET1dfU0NSSVBULCAxLCBrZXksIE1hdGgubWF4KDEsIE1hdGguY2VpbCh3aW5kb3dNcykpKTtcbiAgcmV0dXJuIE51bWJlcihuKTtcbn1cbiJdfQ==
@@ -55,32 +55,29 @@ export interface HttpClientResponse<T = unknown> {
55
55
  */
56
56
  export interface HttpClientOptions {
57
57
  /**
58
- * A shared `http.Agent` to reuse across clients (pools sockets to the same
59
- * host). When supplied, the client does NOT own it — {@link InternalHttpClient.destroy}
60
- * leaves a borrowed agent untouched so other clients keep working.
58
+ * A caller-owned `http.Agent` to use instead of the process-wide shared one.
59
+ * The client never destroys it.
61
60
  */
62
61
  agent?: http.Agent;
63
- /** Cap on concurrent keep-alive sockets when minting an agent (default 64). */
62
+ /** Cap on concurrent keep-alive sockets for the shared agent (default 64). */
64
63
  maxSockets?: number;
65
64
  }
65
+ /**
66
+ * Close every shared keep-alive agent (idle sockets are released; in-flight
67
+ * requests finish). For process shutdown and tests — a later request simply
68
+ * builds a fresh agent.
69
+ */
70
+ export declare function destroySharedHttpAgents(): void;
66
71
  export declare class InternalHttpClient {
67
72
  private config;
68
73
  private agent;
69
- /** True only when this client MINTED its agent (so destroy() may tear it down). */
70
- private readonly ownsAgent;
71
74
  /**
72
75
  * Create a new HTTP client instance.
73
76
  *
74
77
  * @param config - Service configuration
75
- * @param options - Optional connection-pool controls (shared agent / socket cap)
78
+ * @param options - Optional connection-pool controls (own agent / socket cap)
76
79
  */
77
80
  constructor(config: ServiceConfig, options?: HttpClientOptions);
78
- /**
79
- * Release the keep-alive socket pool. Idempotent and safe to call on shutdown.
80
- * A borrowed (caller-supplied) agent is left intact — only an agent this client
81
- * created is destroyed, so tearing down one client can't sever another's pool.
82
- */
83
- destroy(): void;
84
81
  /**
85
82
  * Make a GET request.
86
83
  */
@@ -121,8 +118,6 @@ export declare class InternalHttpClient {
121
118
  * @returns Client wrapper with safe methods
122
119
  */
123
120
  export declare function createSafeClient(config: ServiceConfig, options?: HttpClientOptions): {
124
- /** Release the underlying keep-alive socket pool (no-op on a borrowed agent). */
125
- destroy(): void;
126
121
  /**
127
122
  * Safe GET request - returns null on error.
128
123
  */