@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.
- package/README.md +3 -3
- package/lib/errors/app-errors.d.ts +0 -4
- package/lib/errors/app-errors.js +1 -8
- package/lib/helpers/restore-helpers.d.ts +3 -3
- package/lib/helpers/restore-helpers.js +4 -4
- package/lib/helpers/sse-helpers.d.ts +8 -1
- package/lib/helpers/sse-helpers.js +11 -3
- package/lib/middleware/auth.d.ts +174 -43
- package/lib/middleware/auth.js +384 -179
- package/lib/middleware/index.d.ts +1 -0
- package/lib/middleware/index.js +2 -1
- package/lib/middleware/route-table.d.ts +104 -0
- package/lib/middleware/route-table.js +230 -0
- package/lib/middleware/step-up.d.ts +48 -16
- package/lib/middleware/step-up.js +74 -36
- package/lib/services/api-key-exchange.d.ts +25 -0
- package/lib/services/api-key-exchange.js +219 -0
- package/lib/services/audit-spool.d.ts +2 -3
- package/lib/services/audit-spool.js +3 -4
- package/lib/services/cache-service.d.ts +65 -21
- package/lib/services/cache-service.js +173 -78
- package/lib/services/compliance-event-subscriber.d.ts +5 -4
- package/lib/services/compliance-event-subscriber.js +8 -6
- package/lib/services/durable-event-bus.d.ts +22 -39
- package/lib/services/durable-event-bus.js +109 -47
- package/lib/services/env-redis.d.ts +114 -35
- package/lib/services/env-redis.js +215 -73
- package/lib/services/http-client.d.ts +10 -15
- package/lib/services/http-client.js +32 -27
- package/lib/services/index.d.ts +3 -0
- package/lib/services/index.js +4 -1
- package/lib/services/jwks-cache.d.ts +102 -0
- package/lib/services/jwks-cache.js +222 -0
- package/lib/services/leader-lock.d.ts +6 -3
- package/lib/services/leader-lock.js +20 -5
- package/lib/services/quota.d.ts +44 -10
- package/lib/services/quota.js +95 -51
- package/lib/services/remote-audit-client.d.ts +1 -1
- package/lib/services/remote-audit-client.js +32 -1
- package/lib/services/scheduler.d.ts +2 -3
- package/lib/services/scheduler.js +2 -2
- package/lib/services/service-boot.d.ts +4 -2
- package/lib/services/service-boot.js +7 -3
- package/lib/services/service-keys.d.ts +83 -0
- package/lib/services/service-keys.js +354 -0
- package/lib/services/sse-ticket-store.d.ts +55 -22
- package/lib/services/sse-ticket-store.js +122 -79
- package/lib/services/token-revocation.d.ts +1 -1
- package/lib/services/token-revocation.js +31 -19
- package/lib/testing/route-coverage.d.ts +64 -0
- package/lib/testing/route-coverage.js +183 -0
- package/lib/testing/service-tokens.d.ts +66 -0
- package/lib/testing/service-tokens.js +137 -0
- package/lib/testing/tier-mock.d.ts +2 -2
- package/lib/testing/tier-mock.js +3 -3
- package/lib/testing/user-tokens.d.ts +75 -0
- package/lib/testing/user-tokens.js +115 -0
- package/lib/types/catalog-metadata.d.ts +0 -2
- package/lib/types/catalog-metadata.js +1 -3
- package/lib/types/common.d.ts +103 -4
- package/lib/types/common.js +11 -1
- package/lib/types/error-codes.d.ts +15 -0
- package/lib/types/error-codes.js +22 -1
- package/lib/types/permissions.d.ts +35 -1
- package/lib/types/permissions.js +70 -2
- package/lib/utils/api-key.d.ts +34 -0
- package/lib/utils/api-key.js +75 -0
- package/lib/utils/env.d.ts +0 -2
- package/lib/utils/env.js +1 -6
- package/lib/utils/index.d.ts +3 -0
- package/lib/utils/index.js +4 -1
- package/lib/utils/jwk.d.ts +98 -0
- package/lib/utils/jwk.js +139 -0
- package/lib/utils/logger.d.ts +4 -1
- package/lib/utils/logger.js +1 -22
- package/lib/utils/secret-encryption.d.ts +7 -2
- package/lib/utils/secret-encryption.js +47 -4
- package/lib/utils/secret-rotation.d.ts +17 -0
- package/lib/utils/secret-rotation.js +54 -0
- package/lib/validation/common-schemas.js +5 -4
- 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
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
22
|
-
*
|
|
23
|
-
* `
|
|
24
|
-
*
|
|
25
|
-
|
|
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
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
*
|
|
49
|
-
*
|
|
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
|
-
*
|
|
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
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return
|
|
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
|
-
|
|
83
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
|
59
|
-
*
|
|
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
|
|
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 (
|
|
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
|
*/
|