@pipeline-builder/api-core 4.1.3 → 4.1.5
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/cache-service.d.ts +11 -26
- package/lib/services/cache-service.js +20 -74
- 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 +95 -43
- package/lib/services/env-redis.d.ts +27 -0
- package/lib/services/env-redis.js +63 -1
- 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/quota.js +12 -4
- 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.js +30 -18
- 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 +72 -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 +4 -0
- package/lib/utils/index.js +5 -1
- package/lib/utils/jwk.d.ts +98 -0
- package/lib/utils/jwk.js +139 -0
- package/lib/utils/logger.d.ts +30 -1
- package/lib/utils/logger.js +74 -27
- 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/utils/sensitive-patterns.d.ts +49 -0
- package/lib/utils/sensitive-patterns.js +149 -0
- package/lib/validation/common-schemas.js +5 -4
- package/package.json +20 -1
|
@@ -1,37 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Durable, at-least-once event backbone (Redis Streams).
|
|
3
|
-
*
|
|
4
|
-
* The platform's cross-service signalling today is point-to-point HTTP plus
|
|
5
|
-
* polling reconcilers plus an IN-PROCESS best-effort emitter ({@link entityEvents}).
|
|
6
|
-
* There is no durable bus, so a signal produced on one pod is either delivered
|
|
7
|
-
* synchronously over HTTP (coupling + retry-storm risk) or lost if the consumer
|
|
8
|
-
* is momentarily down (the reconcilers exist to paper over exactly that).
|
|
9
|
-
*
|
|
10
|
-
* This is that missing bus, as a reusable primitive:
|
|
11
|
-
* - **publish(topic, payload)** → `XADD` onto a bounded (`MAXLEN ~`) per-topic
|
|
12
|
-
* stream. Durable across restarts, shared by all replicas.
|
|
13
|
-
* - **subscribe({topic, group, consumer, handler})** → a `XREADGROUP` consumer.
|
|
14
|
-
* Consumer GROUPS give at-least-once: each group gets every message once, a
|
|
15
|
-
* message stays pending until the handler `XACK`s it, and `XAUTOCLAIM`
|
|
16
|
-
* reclaims messages stranded by a crashed consumer. Multiple groups on one
|
|
17
|
-
* topic = independent fan-out (e.g. quota-sync AND audit both react).
|
|
18
|
-
*
|
|
19
|
-
* FAIL-SAFE + OPT-IN, exactly like the audit spool: {@link createEnvRedisDurableEventBus}
|
|
20
|
-
* returns `null` when Redis isn't configured, so a service without it simply
|
|
21
|
-
* doesn't use the bus (keeps today's behavior). A publish failure is dropped-with-
|
|
22
|
-
* -metric, never thrown; a handler throw leaves the message un-acked for redelivery.
|
|
23
|
-
*
|
|
24
|
-
* Migrating a specific reconciler (e.g. billing→quota entitlement sync) onto this
|
|
25
|
-
* is deliberately follow-on work — this lands the backbone + an additive entity-
|
|
26
|
-
* event bridge; the reconcilers stay as the belt-and-suspenders backstop until a
|
|
27
|
-
* flow is fully cut over.
|
|
28
|
-
*/
|
|
29
|
-
import type { EntityEventSubscriber } from './entity-events.js';
|
|
30
|
-
/** A delivered event: its stream id, topic, and decoded payload. */
|
|
1
|
+
/** A delivered event: its stream id, topic, publish time, and decoded payload. */
|
|
31
2
|
export interface EventEnvelope<T = unknown> {
|
|
32
3
|
/** Redis Stream entry id (`<ms>-<seq>`) — also the idempotency handle. */
|
|
33
4
|
id: string;
|
|
34
5
|
topic: string;
|
|
6
|
+
/**
|
|
7
|
+
* When the event was published (the Redis server time embedded in the stream
|
|
8
|
+
* id). A redelivery keeps its ORIGINAL publish time, so a consumer applying
|
|
9
|
+
* last-writer-wins state (e.g. an entitlement sync) can order events by it
|
|
10
|
+
* instead of by delivery time and refuse to let a stale retry overwrite a
|
|
11
|
+
* newer state.
|
|
12
|
+
*/
|
|
13
|
+
publishedAt: Date;
|
|
35
14
|
payload: T;
|
|
36
15
|
}
|
|
37
16
|
export interface SubscribeOptions<T = unknown> {
|
|
@@ -49,6 +28,11 @@ export interface SubscribeOptions<T = unknown> {
|
|
|
49
28
|
blockMs?: number;
|
|
50
29
|
/** A pending message idle this long (ms) is reclaimed from a dead consumer (default 60000). */
|
|
51
30
|
minIdleMs?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Deliveries after which an un-acked message is dead-lettered to
|
|
33
|
+
* `evt:<topic>:dlq` and acked instead of being redelivered again (default 10).
|
|
34
|
+
*/
|
|
35
|
+
maxDeliveries?: number;
|
|
52
36
|
}
|
|
53
37
|
export interface EventSubscription {
|
|
54
38
|
/** Stop the consumer loop. Resolves once the in-flight read returns. */
|
|
@@ -71,7 +55,15 @@ export interface RedisStreamClient {
|
|
|
71
55
|
xreadgroup(...args: (string | number)[]): Promise<unknown>;
|
|
72
56
|
xack(key: string, group: string, ...ids: string[]): Promise<number>;
|
|
73
57
|
xautoclaim(...args: (string | number)[]): Promise<unknown>;
|
|
58
|
+
xpending(key: string, group: string, ...args: (string | number)[]): Promise<unknown>;
|
|
59
|
+
xrange(key: string, start: string, end: string, ...args: (string | number)[]): Promise<unknown>;
|
|
60
|
+
/** A new connection with the same options — each subscriber reads on its own. */
|
|
61
|
+
duplicate(): RedisStreamClient;
|
|
62
|
+
quit?(): Promise<unknown>;
|
|
63
|
+
on?(event: 'error', cb: (err: unknown) => void): unknown;
|
|
74
64
|
}
|
|
65
|
+
/** Dead-letter stream for a topic. */
|
|
66
|
+
export declare function deadLetterStreamKey(topic: string): string;
|
|
75
67
|
/** Build a durable event bus over a Redis Streams client. */
|
|
76
68
|
export declare function createRedisDurableEventBus(redis: RedisStreamClient, opts?: {
|
|
77
69
|
maxLen?: number;
|
|
@@ -85,12 +77,3 @@ export declare function createRedisDurableEventBus(redis: RedisStreamClient, opt
|
|
|
85
77
|
export declare function createEnvRedisDurableEventBus(opts?: {
|
|
86
78
|
maxLen?: number;
|
|
87
79
|
}): DurableEventBus | null;
|
|
88
|
-
/** Topic the entity-event bridge publishes to. */
|
|
89
|
-
export declare const ENTITY_EVENT_TOPIC = "entity-events";
|
|
90
|
-
/**
|
|
91
|
-
* An {@link EntityEventSubscriber} that forwards each entity event to the durable
|
|
92
|
-
* bus. `bus.publish` is fail-safe (drops-with-metric, never throws), matching the
|
|
93
|
-
* emitter's fire-and-forget contract. Note `EntityEvent.timestamp` (a Date)
|
|
94
|
-
* serializes to an ISO string on the wire — a consumer re-hydrates as needed.
|
|
95
|
-
*/
|
|
96
|
-
export declare function createEntityEventBusPublisher(bus: DurableEventBus): EntityEventSubscriber;
|
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
// Copyright 2026 Pipeline Builder Contributors
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Durable, at-least-once event backbone (Redis Streams).
|
|
5
|
+
*
|
|
6
|
+
* The platform's cross-service signalling today is point-to-point HTTP plus
|
|
7
|
+
* polling reconcilers plus an IN-PROCESS best-effort emitter ({@link entityEvents}).
|
|
8
|
+
* There is no durable bus, so a signal produced on one pod is either delivered
|
|
9
|
+
* synchronously over HTTP (coupling + retry-storm risk) or lost if the consumer
|
|
10
|
+
* is momentarily down (the reconcilers exist to paper over exactly that).
|
|
11
|
+
*
|
|
12
|
+
* This is that missing bus, as a reusable primitive:
|
|
13
|
+
* - **publish(topic, payload)** → `XADD` onto a bounded (`MAXLEN ~`) per-topic
|
|
14
|
+
* stream. Durable across restarts, shared by all replicas.
|
|
15
|
+
* - **subscribe({topic, group, consumer, handler})** → a `XREADGROUP` consumer
|
|
16
|
+
* on its OWN connection (`duplicate()`), so a blocking read never delays a
|
|
17
|
+
* publish. Consumer GROUPS give at-least-once: each group gets every message
|
|
18
|
+
* once, a message stays pending until the handler `XACK`s it, and `XAUTOCLAIM`
|
|
19
|
+
* reclaims messages stranded by a crashed consumer. A message that has been
|
|
20
|
+
* delivered `maxDeliveries` times without an ack is moved to a dead-letter
|
|
21
|
+
* stream (`evt:<topic>:dlq`) and acked, so a poison message can't redeliver
|
|
22
|
+
* forever. Multiple groups on one topic = independent fan-out.
|
|
23
|
+
*
|
|
24
|
+
* FAIL-SAFE + OPT-IN, exactly like the audit spool: {@link createEnvRedisDurableEventBus}
|
|
25
|
+
* returns `null` when Redis isn't configured, so a service without it simply
|
|
26
|
+
* doesn't use the bus (keeps today's behavior). A publish failure is dropped-with-
|
|
27
|
+
* -metric, never thrown; a handler throw leaves the message un-acked for redelivery.
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
3
30
|
import { createEnvRedisClient } from './env-redis.js';
|
|
4
31
|
import { createLogger } from '../utils/logger.js';
|
|
5
32
|
import { emitCounter } from '../utils/metric-emitter.js';
|
|
@@ -8,12 +35,22 @@ const DEFAULT_MAXLEN = 10_000;
|
|
|
8
35
|
const DEFAULT_BATCH = 16;
|
|
9
36
|
const DEFAULT_BLOCK_MS = 5_000;
|
|
10
37
|
const DEFAULT_MIN_IDLE_MS = 60_000;
|
|
38
|
+
const DEFAULT_MAX_DELIVERIES = 10;
|
|
11
39
|
function errMsg(err) {
|
|
12
40
|
return err instanceof Error ? err.message : String(err);
|
|
13
41
|
}
|
|
14
42
|
function streamKey(topic) {
|
|
15
43
|
return `evt:${topic}`;
|
|
16
44
|
}
|
|
45
|
+
/** Dead-letter stream for a topic. */
|
|
46
|
+
export function deadLetterStreamKey(topic) {
|
|
47
|
+
return `evt:${topic}:dlq`;
|
|
48
|
+
}
|
|
49
|
+
/** Publish time from a stream id (`<ms>-<seq>`); epoch 0 for an unparseable id. */
|
|
50
|
+
function publishedAtFromId(id) {
|
|
51
|
+
const ms = Number(id.split('-')[0]);
|
|
52
|
+
return new Date(Number.isFinite(ms) ? ms : 0);
|
|
53
|
+
}
|
|
17
54
|
/** True when the error is Redis' "group already exists" (idempotent create). */
|
|
18
55
|
function isBusyGroup(err) {
|
|
19
56
|
return errMsg(err).includes('BUSYGROUP');
|
|
@@ -46,15 +83,16 @@ function parseEntries(topic, entries) {
|
|
|
46
83
|
// A missing `d` field (an entry not written by publish()) OR a corrupt JSON
|
|
47
84
|
// payload both yield an undefined-payload envelope so `deliver()` ACKs it —
|
|
48
85
|
// a poison message must never wedge the group by staying perpetually pending.
|
|
86
|
+
const publishedAt = publishedAtFromId(id);
|
|
49
87
|
if (raw === undefined) {
|
|
50
|
-
out.push({ id, topic, payload: undefined });
|
|
88
|
+
out.push({ id, topic, publishedAt, payload: undefined });
|
|
51
89
|
continue;
|
|
52
90
|
}
|
|
53
91
|
try {
|
|
54
|
-
out.push({ id, topic, payload: JSON.parse(raw) });
|
|
92
|
+
out.push({ id, topic, publishedAt, payload: JSON.parse(raw) });
|
|
55
93
|
}
|
|
56
94
|
catch {
|
|
57
|
-
out.push({ id, topic, payload: undefined });
|
|
95
|
+
out.push({ id, topic, publishedAt, payload: undefined });
|
|
58
96
|
}
|
|
59
97
|
}
|
|
60
98
|
return out;
|
|
@@ -80,11 +118,18 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
80
118
|
subscribe(subOpts) {
|
|
81
119
|
const { topic, group, consumer, handler } = subOpts;
|
|
82
120
|
const key = streamKey(topic);
|
|
121
|
+
const dlqKey = deadLetterStreamKey(topic);
|
|
83
122
|
const batch = Math.max(1, subOpts.batchSize ?? DEFAULT_BATCH);
|
|
84
123
|
const blockMs = Math.max(0, subOpts.blockMs ?? DEFAULT_BLOCK_MS);
|
|
85
124
|
const minIdle = Math.max(0, subOpts.minIdleMs ?? DEFAULT_MIN_IDLE_MS);
|
|
125
|
+
const maxDeliveries = Math.max(1, subOpts.maxDeliveries ?? DEFAULT_MAX_DELIVERIES);
|
|
126
|
+
// `XREADGROUP BLOCK` holds its connection for up to `blockMs`; on the
|
|
127
|
+
// shared client every publish queued behind it. Read on a dedicated one.
|
|
128
|
+
const reader = redis.duplicate();
|
|
129
|
+
// A duplicated ioredis connection doesn't inherit listeners; without one a
|
|
130
|
+
// connection error is an unhandled 'error' event that crashes the process.
|
|
131
|
+
reader.on?.('error', (err) => logger.warn('Event bus reader connection error', { topic, group, error: errMsg(err) }));
|
|
86
132
|
let stopped = false;
|
|
87
|
-
let started = false;
|
|
88
133
|
const deliver = async (envs) => {
|
|
89
134
|
for (const env of envs) {
|
|
90
135
|
try {
|
|
@@ -92,7 +137,7 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
92
137
|
await handler(env);
|
|
93
138
|
// Ack on success OR on an undefined (corrupt) payload — a poison
|
|
94
139
|
// message must not block the group forever.
|
|
95
|
-
await
|
|
140
|
+
await reader.xack(key, group, env.id);
|
|
96
141
|
emitCounter('event_bus_delivered_total', { topic, group });
|
|
97
142
|
}
|
|
98
143
|
catch (err) {
|
|
@@ -104,6 +149,41 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
104
149
|
}
|
|
105
150
|
}
|
|
106
151
|
};
|
|
152
|
+
/**
|
|
153
|
+
* Move every idle pending message that has already been delivered
|
|
154
|
+
* `maxDeliveries` times to the dead-letter stream and ack it. The entry
|
|
155
|
+
* keeps its payload plus where it came from, so an operator can inspect or
|
|
156
|
+
* replay it. If copying fails the message is left pending (retried next
|
|
157
|
+
* pass) — it is never acked without being preserved.
|
|
158
|
+
*/
|
|
159
|
+
const deadLetterExhausted = async () => {
|
|
160
|
+
const pending = await reader.xpending(key, group, 'IDLE', minIdle, '-', '+', batch);
|
|
161
|
+
if (!Array.isArray(pending))
|
|
162
|
+
return;
|
|
163
|
+
for (const p of pending) {
|
|
164
|
+
if (!Array.isArray(p) || p.length < 4)
|
|
165
|
+
continue;
|
|
166
|
+
const id = String(p[0]);
|
|
167
|
+
const deliveries = Number(p[3]);
|
|
168
|
+
if (!(deliveries >= maxDeliveries))
|
|
169
|
+
continue;
|
|
170
|
+
const entries = await reader.xrange(key, id, id);
|
|
171
|
+
const fields = Array.isArray(entries) && Array.isArray(entries[0]) && Array.isArray(entries[0][1]) ? entries[0][1] : [];
|
|
172
|
+
let raw = '';
|
|
173
|
+
for (let i = 0; i + 1 < fields.length; i += 2) {
|
|
174
|
+
if (String(fields[i]) === 'd') {
|
|
175
|
+
raw = String(fields[i + 1]);
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
await reader.xadd(dlqKey, 'MAXLEN', '~', maxLen, '*', 'd', raw, 'sourceId', id, 'group', group, 'deliveries', deliveries);
|
|
180
|
+
await reader.xack(key, group, id);
|
|
181
|
+
emitCounter('event_bus_dead_lettered_total', { topic, group });
|
|
182
|
+
logger.error('Event exceeded max deliveries; moved to dead-letter stream', {
|
|
183
|
+
topic, group, id, deliveries, deadLetterStream: dlqKey,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
};
|
|
107
187
|
// The consumer group must exist before XREADGROUP can succeed. Creating it
|
|
108
188
|
// is retried inside the loop: at startup the client may not have connected
|
|
109
189
|
// yet, and a single failed attempt used to leave the consumer reading a
|
|
@@ -112,7 +192,7 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
112
192
|
const ensureGroup = async () => {
|
|
113
193
|
try {
|
|
114
194
|
// MKSTREAM so the stream need not exist yet; '$' = only new messages.
|
|
115
|
-
await
|
|
195
|
+
await reader.xgroup('CREATE', key, group, '$', 'MKSTREAM');
|
|
116
196
|
groupReady = true;
|
|
117
197
|
}
|
|
118
198
|
catch (err) {
|
|
@@ -126,8 +206,10 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
126
206
|
try {
|
|
127
207
|
if (!groupReady)
|
|
128
208
|
await ensureGroup();
|
|
129
|
-
// 1)
|
|
130
|
-
|
|
209
|
+
// 1) Dead-letter messages that have exhausted their deliveries, then
|
|
210
|
+
// reclaim the rest stranded by a failed/crashed consumer.
|
|
211
|
+
await deadLetterExhausted();
|
|
212
|
+
const claimed = await reader.xautoclaim(key, group, consumer, minIdle, '0', 'COUNT', batch);
|
|
131
213
|
// XAUTOCLAIM reply: [nextCursor, entries, deletedIds]
|
|
132
214
|
if (Array.isArray(claimed) && claimed.length >= 2) {
|
|
133
215
|
await deliver(parseEntries(topic, claimed[1]));
|
|
@@ -135,7 +217,7 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
135
217
|
if (stopped)
|
|
136
218
|
break;
|
|
137
219
|
// 2) Read new, never-delivered messages for this group ('>').
|
|
138
|
-
const res = await
|
|
220
|
+
const res = await reader.xreadgroup('GROUP', group, consumer, 'COUNT', batch, 'BLOCK', blockMs, 'STREAMS', key, '>');
|
|
139
221
|
// XREADGROUP reply: [[streamKey, entries]] | null (on block timeout)
|
|
140
222
|
if (Array.isArray(res) && res.length > 0 && Array.isArray(res[0]) && res[0].length >= 2) {
|
|
141
223
|
await deliver(parseEntries(topic, res[0][1]));
|
|
@@ -153,12 +235,8 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
153
235
|
}
|
|
154
236
|
}
|
|
155
237
|
};
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
started = true;
|
|
159
|
-
loopPromise = loop();
|
|
160
|
-
logger.info('Event bus consumer started', { topic, group, consumer });
|
|
161
|
-
}
|
|
238
|
+
const loopPromise = loop();
|
|
239
|
+
logger.info('Event bus consumer started', { topic, group, consumer, maxDeliveries });
|
|
162
240
|
return {
|
|
163
241
|
async stop() {
|
|
164
242
|
stopped = true;
|
|
@@ -166,6 +244,7 @@ export function createRedisDurableEventBus(redis, opts = {}) {
|
|
|
166
244
|
// down its DB) doesn't race a message still being processed. Bounded by
|
|
167
245
|
// the XREADGROUP BLOCK window. Never rejects — the loop swallows errors.
|
|
168
246
|
await loopPromise.catch(() => undefined);
|
|
247
|
+
await Promise.resolve(reader.quit?.()).catch(() => undefined);
|
|
169
248
|
},
|
|
170
249
|
};
|
|
171
250
|
},
|
|
@@ -184,31 +263,4 @@ export function createEnvRedisDurableEventBus(opts = {}) {
|
|
|
184
263
|
logger.info('Redis durable event bus initialized');
|
|
185
264
|
return createRedisDurableEventBus(inst, opts);
|
|
186
265
|
}
|
|
187
|
-
// ---------------------------------------------------------------------------
|
|
188
|
-
// Entity-event bridge (additive, opt-in)
|
|
189
|
-
//
|
|
190
|
-
// Lets a service give its in-process {@link entityEvents} emitter a DURABLE,
|
|
191
|
-
// cross-pod delivery leg WITHOUT changing existing behavior: register the
|
|
192
|
-
// returned subscriber and every entity mutation is ALSO published to the bus.
|
|
193
|
-
// A consumer elsewhere (`bus.subscribe`) then reacts at-least-once across pods
|
|
194
|
-
// and restarts. The in-process subscribers keep firing exactly as before, so
|
|
195
|
-
// this is purely additive — no double-processing unless a service intentionally
|
|
196
|
-
// runs a bus consumer for the same reaction. Kept here (not in entity-events.ts)
|
|
197
|
-
// so that module stays infrastructure-free per its own contract.
|
|
198
|
-
// ---------------------------------------------------------------------------
|
|
199
|
-
/** Topic the entity-event bridge publishes to. */
|
|
200
|
-
export const ENTITY_EVENT_TOPIC = 'entity-events';
|
|
201
|
-
/**
|
|
202
|
-
* An {@link EntityEventSubscriber} that forwards each entity event to the durable
|
|
203
|
-
* bus. `bus.publish` is fail-safe (drops-with-metric, never throws), matching the
|
|
204
|
-
* emitter's fire-and-forget contract. Note `EntityEvent.timestamp` (a Date)
|
|
205
|
-
* serializes to an ISO string on the wire — a consumer re-hydrates as needed.
|
|
206
|
-
*/
|
|
207
|
-
export function createEntityEventBusPublisher(bus) {
|
|
208
|
-
return {
|
|
209
|
-
async onEntityEvent(event) {
|
|
210
|
-
await bus.publish(ENTITY_EVENT_TOPIC, event);
|
|
211
|
-
},
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHVyYWJsZS1ldmVudC1idXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvZHVyYWJsZS1ldmVudC1idXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQWdDdEMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUV6RCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsbUJBQW1CLENBQUMsQ0FBQztBQW9EakQsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDO0FBQzlCLE1BQU0sYUFBYSxHQUFHLEVBQUUsQ0FBQztBQUN6QixNQUFNLGdCQUFnQixHQUFHLEtBQUssQ0FBQztBQUMvQixNQUFNLG1CQUFtQixHQUFHLE1BQU0sQ0FBQztBQUVuQyxTQUFTLE1BQU0sQ0FBQyxHQUFZO0lBQzFCLE9BQU8sR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0FBQzFELENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxLQUFhO0lBQzlCLE9BQU8sT0FBTyxLQUFLLEVBQUUsQ0FBQztBQUN4QixDQUFDO0FBRUQsZ0ZBQWdGO0FBQ2hGLFNBQVMsV0FBVyxDQUFDLEdBQVk7SUFDL0IsT0FBTyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQzNDLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILFNBQVMsWUFBWSxDQUFJLEtBQWEsRUFBRSxPQUFnQjtJQUN0RCxNQUFNLEdBQUcsR0FBdUIsRUFBRSxDQUFDO0lBQ25DLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE9B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QUFFO0FBQ0YsNkVBQTZFO0FBQzdFLDBFQUEwRTtBQUMxRSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDZFQUE2RTtBQUM3RSxnRkFBZ0Y7QUFDaEYsaUZBQWlGO0FBQ2pGLGlFQUFpRTtBQUNqRSw4RUFBOEU7QUFFOUUsa0RBQWtEO0FBQ2xELE1BQU0sQ0FBQyxNQUFNLGtCQUFrQixHQUFHLGVBQWUsQ0FBQztBQUVsRDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSw2QkFBNkIsQ0FBQyxHQUFvQjtJQUNoRSxPQUFPO1FBQ0wsS0FBSyxDQUFDLGFBQWEsQ0FBQyxLQUFrQjtZQUNwQyxNQUFNLEdBQUcsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDL0MsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogRHVyYWJsZSwgYXQtbGVhc3Qtb25jZSBldmVudCBiYWNrYm9uZSAoUmVkaXMgU3RyZWFtcykuXG4gKlxuICogVGhlIHBsYXRmb3JtJ3MgY3Jvc3Mtc2VydmljZSBzaWduYWxsaW5nIHRvZGF5IGlzIHBvaW50LXRvLXBvaW50IEhUVFAgcGx1c1xuICogcG9sbGluZyByZWNvbmNpbGVycyBwbHVzIGFuIElOLVBST0NFU1MgYmVzdC1lZmZvcnQgZW1pdHRlciAoe0BsaW5rIGVudGl0eUV2ZW50c30pLlxuICogVGhlcmUgaXMgbm8gZHVyYWJsZSBidXMsIHNvIGEgc2lnbmFsIHByb2R1Y2VkIG9uIG9uZSBwb2QgaXMgZWl0aGVyIGRlbGl2ZXJlZFxuICogc3luY2hyb25vdXNseSBvdmVyIEhUVFAgKGNvdXBsaW5nICsgcmV0cnktc3Rvcm0gcmlzaykgb3IgbG9zdCBpZiB0aGUgY29uc3VtZXJcbiAqIGlzIG1vbWVudGFyaWx5IGRvd24gKHRoZSByZWNvbmNpbGVycyBleGlzdCB0byBwYXBlciBvdmVyIGV4YWN0bHkgdGhhdCkuXG4gKlxuICogVGhpcyBpcyB0aGF0IG1pc3NpbmcgYnVzLCBhcyBhIHJldXNhYmxlIHByaW1pdGl2ZTpcbiAqICAtICoqcHVibGlzaCh0b3BpYywgcGF5bG9hZCkqKiDihpIgYFhBRERgIG9udG8gYSBib3VuZGVkIChgTUFYTEVOIH5gKSBwZXItdG9waWNcbiAqICAgIHN0cmVhbS4gRHVyYWJsZSBhY3Jvc3MgcmVzdGFydHMsIHNoYXJlZCBieSBhbGwgcmVwbGljYXMuXG4gKiAgLSAqKnN1YnNjcmliZSh7dG9waWMsIGdyb3VwLCBjb25zdW1lciwgaGFuZGxlcn0pKiog4oaSIGEgYFhSRUFER1JPVVBgIGNvbnN1bWVyLlxuICogICAgQ29uc3VtZXIgR1JPVVBTIGdpdmUgYXQtbGVhc3Qtb25jZTogZWFjaCBncm91cCBnZXRzIGV2ZXJ5IG1lc3NhZ2Ugb25jZSwgYVxuICogICAgbWVzc2FnZSBzdGF5cyBwZW5kaW5nIHVudGlsIHRoZSBoYW5kbGVyIGBYQUNLYHMgaXQsIGFuZCBgWEFVVE9DTEFJTWBcbiAqICAgIHJlY2xhaW1zIG1lc3NhZ2VzIHN0cmFuZGVkIGJ5IGEgY3Jhc2hlZCBjb25zdW1lci4gTXVsdGlwbGUgZ3JvdXBzIG9uIG9uZVxuICogICAgdG9waWMgPSBpbmRlcGVuZGVudCBmYW4tb3V0IChlLmcuIHF1b3RhLXN5bmMgQU5EIGF1ZGl0IGJvdGggcmVhY3QpLlxuICpcbiAqIEZBSUwtU0FGRSArIE9QVC1JTiwgZXhhY3RseSBsaWtlIHRoZSBhdWRpdCBzcG9vbDoge0BsaW5rIGNyZWF0ZUVudlJlZGlzRHVyYWJsZUV2ZW50QnVzfVxuICogcmV0dXJucyBgbnVsbGAgd2hlbiBSZWRpcyBpc24ndCBjb25maWd1cmVkLCBzbyBhIHNlcnZpY2Ugd2l0aG91dCBpdCBzaW1wbHlcbiAqIGRvZXNuJ3QgdXNlIHRoZSBidXMgKGtlZXBzIHRvZGF5J3MgYmVoYXZpb3IpLiBBIHB1Ymxpc2ggZmFpbHVyZSBpcyBkcm9wcGVkLXdpdGgtXG4gKiAtbWV0cmljLCBuZXZlciB0aHJvd247IGEgaGFuZGxlciB0aHJvdyBsZWF2ZXMgdGhlIG1lc3NhZ2UgdW4tYWNrZWQgZm9yIHJlZGVsaXZlcnkuXG4gKlxuICogTWlncmF0aW5nIGEgc3BlY2lmaWMgcmVjb25jaWxlciAoZS5nLiBiaWxsaW5n4oaScXVvdGEgZW50aXRsZW1lbnQgc3luYykgb250byB0aGlzXG4gKiBpcyBkZWxpYmVyYXRlbHkgZm9sbG93LW9uIHdvcmsg4oCUIHRoaXMgbGFuZHMgdGhlIGJhY2tib25lICsgYW4gYWRkaXRpdmUgZW50aXR5LVxuICogZXZlbnQgYnJpZGdlOyB0aGUgcmVjb25jaWxlcnMgc3RheSBhcyB0aGUgYmVsdC1hbmQtc3VzcGVuZGVycyBiYWNrc3RvcCB1bnRpbCBhXG4gKiBmbG93IGlzIGZ1bGx5IGN1dCBvdmVyLlxuICovXG5cbmltcG9ydCB0eXBlIHsgRW50aXR5RXZlbnQsIEVudGl0eUV2ZW50U3Vic2NyaWJlciB9IGZyb20gJy4vZW50aXR5LWV2ZW50cy5qcyc7XG5pbXBvcnQgeyBjcmVhdGVFbnZSZWRpc0NsaWVudCB9IGZyb20gJy4vZW52LXJlZGlzLmpzJztcbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBlbWl0Q291bnRlciB9IGZyb20gJy4uL3V0aWxzL21ldHJpYy1lbWl0dGVyLmpzJztcblxuY29uc3QgbG9nZ2VyID0gY3JlYXRlTG9nZ2VyKCdkdXJhYmxlLWV2ZW50LWJ1cycpO1xuXG4vKiogQSBkZWxpdmVyZWQgZXZlbnQ6IGl0cyBzdHJlYW0gaWQsIHRvcGljLCBhbmQgZGVjb2RlZCBwYXlsb2FkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBFdmVudEVudmVsb3BlPFQgPSB1bmtub3duPiB7XG4gIC8qKiBSZWRpcyBTdHJlYW0gZW50cnkgaWQgKGA8bXM+LTxzZXE+YCkg4oCUIGFsc28gdGhlIGlkZW1wb3RlbmN5IGhhbmRsZS4gKi9cbiAgaWQ6IHN0cmluZztcbiAgdG9waWM6IHN0cmluZztcbiAgcGF5bG9hZDogVDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTdWJzY3JpYmVPcHRpb25zPFQgPSB1bmtub3duPiB7XG4gIC8qKiBUb3BpYyAoc3RyZWFtKSB0byBjb25zdW1lLiAqL1xuICB0b3BpYzogc3RyaW5nO1xuICAvKiogQ29uc3VtZXIgZ3JvdXAg4oCUIG9uZSBkZWxpdmVyeSBwZXIgZ3JvdXA7IGRpc3RpbmN0IGdyb3VwcyBmYW4gb3V0LiAqL1xuICBncm91cDogc3RyaW5nO1xuICAvKiogVGhpcyBjb25zdW1lcidzIGlkIHdpdGhpbiB0aGUgZ3JvdXAgKGUuZy4gYCR7c2VydmljZX0tJHtwaWR9YCkuICovXG4gIGNvbnN1bWVyOiBzdHJpbmc7XG4gIC8qKiBBc3luYyBoYW5kbGVyLiBSZXNvbHZlcyDih5IgdGhlIG1lc3NhZ2UgaXMgYWNrZWQ7IHRocm93cyDih5IgbGVmdCBwZW5kaW5nIGZvciByZWRlbGl2ZXJ5LiAqL1xuICBoYW5kbGVyOiAoZW52OiBFdmVudEVudmVsb3BlPFQ+KSA9PiBQcm9taXNlPHZvaWQ+O1xuICAvKiogTWF4IG1lc3NhZ2VzIHBlciByZWFkIChkZWZhdWx0IDE2KS4gKi9cbiAgYmF0Y2hTaXplPzogbnVtYmVyO1xuICAvKiogWFJFQURHUk9VUCBibG9jayB0aW1lIGluIG1zIChkZWZhdWx0IDUwMDApLiAqL1xuICBibG9ja01zPzogbnVtYmVyO1xuICAvKiogQSBwZW5kaW5nIG1lc3NhZ2UgaWRsZSB0aGlzIGxvbmcgKG1zKSBpcyByZWNsYWltZWQgZnJvbSBhIGRlYWQgY29uc3VtZXIgKGRlZmF1bHQgNjAwMDApLiAqL1xuICBtaW5JZGxlTXM/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRTdWJzY3JpcHRpb24ge1xuICAvKiogU3RvcCB0aGUgY29uc3VtZXIgbG9vcC4gUmVzb2x2ZXMgb25jZSB0aGUgaW4tZmxpZ2h0IHJlYWQgcmV0dXJucy4gKi9cbiAgc3RvcCgpOiBQcm9taXNlPHZvaWQ+O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIER1cmFibGVFdmVudEJ1cyB7XG4gIC8qKiBQdWJsaXNoIGEgcGF5bG9hZCB0byBhIHRvcGljLiBSZXR1cm5zIHRoZSBzdHJlYW0gaWQsIG9yIG51bGwgb24gZmFpbHVyZSAoZHJvcHBlZCwgbmV2ZXIgdGhyb3dzKS4gKi9cbiAgcHVibGlzaDxUPih0b3BpYzogc3RyaW5nLCBwYXlsb2FkOiBUKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPjtcbiAgLyoqIFN0YXJ0IGEgY29uc3VtZXItZ3JvdXAgcmVhZGVyIGZvciBhIHRvcGljLiBGaXJlLWFuZC1mb3JnZXQgbG9vcDsgY2FsbCBgc3RvcCgpYCB0byBlbmQgaXQuICovXG4gIHN1YnNjcmliZTxUPihvcHRzOiBTdWJzY3JpYmVPcHRpb25zPFQ+KTogRXZlbnRTdWJzY3JpcHRpb247XG59XG5cbi8qKlxuICogVGhlIHN1YnNldCBvZiBpb3JlZGlzJyBTdHJlYW0gQVBJIHRoZSBidXMgdXNlcy4gS2VwdCBtaW5pbWFsIHNvIGEgdGVzdCBjYW5cbiAqIHN1cHBseSBhbiBpbi1tZW1vcnkgZmFrZSBhbmQgc28gbWVyZWx5IGltcG9ydGluZyB0aGlzIG5ldmVyIGhhcmQtZGVwZW5kcyBvblxuICogaW9yZWRpcyAoY29uc3RydWN0ZWQgdmlhIHRoZSBzaGFyZWQgZW52IGhlbHBlcikuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVkaXNTdHJlYW1DbGllbnQge1xuICB4YWRkKGtleTogc3RyaW5nLCAuLi5hcmdzOiAoc3RyaW5nIHwgbnVtYmVyKVtdKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPjtcbiAgeGdyb3VwKC4uLmFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10pOiBQcm9taXNlPHVua25vd24+O1xuICB4cmVhZGdyb3VwKC4uLmFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10pOiBQcm9taXNlPHVua25vd24+O1xuICB4YWNrKGtleTogc3RyaW5nLCBncm91cDogc3RyaW5nLCAuLi5pZHM6IHN0cmluZ1tdKTogUHJvbWlzZTxudW1iZXI+O1xuICB4YXV0b2NsYWltKC4uLmFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10pOiBQcm9taXNlPHVua25vd24+O1xufVxuXG5jb25zdCBERUZBVUxUX01BWExFTiA9IDEwXzAwMDtcbmNvbnN0IERFRkFVTFRfQkFUQ0ggPSAxNjtcbmNvbnN0IERFRkFVTFRfQkxPQ0tfTVMgPSA1XzAwMDtcbmNvbnN0IERFRkFVTFRfTUlOX0lETEVfTVMgPSA2MF8wMDA7XG5cbmZ1bmN0aW9uIGVyck1zZyhlcnI6IHVua25vd24pOiBzdHJpbmcge1xuICByZXR1cm4gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpO1xufVxuXG5mdW5jdGlvbiBzdHJlYW1LZXkodG9waWM6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgZXZ0OiR7dG9waWN9YDtcbn1cblxuLyoqIFRydWUgd2hlbiB0aGUgZXJyb3IgaXMgUmVkaXMnIFwiZ3JvdXAgYWxyZWFkeSBleGlzdHNcIiAoaWRlbXBvdGVudCBjcmVhdGUpLiAqL1xuZnVuY3Rpb24gaXNCdXN5R3JvdXAoZXJyOiB1bmtub3duKTogYm9vbGVhbiB7XG4gIHJldHVybiBlcnJNc2coZXJyKS5pbmNsdWRlcygnQlVTWUdST1VQJyk7XG59XG5cbi8qKlxuICogUGFyc2UgdGhlIG5lc3RlZCBhcnJheSBzaGFwZSBYUkVBREdST1VQIC8gWEFVVE9DTEFJTSByZXR1cm4gaW50byBmbGF0IGVudmVsb3Blcy5cbiAqIFhSRUFER1JPVVA6IGBbW3N0cmVhbUtleSwgW1tpZCwgW2YsIHYsIC4uLl1dLCAuLi5dXV1gLlxuICogWEFVVE9DTEFJTTogYFtuZXh0Q3Vyc29yLCBbW2lkLCBbZiwgdiwgLi4uXV0sIC4uLl0sIGRlbGV0ZWRJZHNdYC5cbiAqIFdlIHN0b3JlIHRoZSBKU09OIHBheWxvYWQgdW5kZXIgYSBzaW5nbGUgZmllbGQgYGRgLlxuICovXG5mdW5jdGlvbiBwYXJzZUVudHJpZXM8VD4odG9waWM6IHN0cmluZywgZW50cmllczogdW5rbm93bik6IEV2ZW50RW52ZWxvcGU8VD5bXSB7XG4gIGNvbnN0IG91dDogRXZlbnRFbnZlbG9wZTxUPltdID0gW107XG4gIGlmICghQXJyYXkuaXNBcnJheShlbnRyaWVzKSkgcmV0dXJuIG91dDtcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBlbnRyaWVzKSB7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGVudHJ5KSB8fCBlbnRyeS5sZW5ndGggPCAyKSBjb250aW51ZTtcbiAgICBjb25zdCBpZCA9IFN0cmluZyhlbnRyeVswXSk7XG4gICAgY29uc3QgZmllbGRzID0gZW50cnlbMV07XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KGZpZWxkcykpIGNvbnRpbnVlO1xuICAgIC8vIGZpZWxkcyBpcyBbbmFtZSwgdmFsdWUsIG5hbWUsIHZhbHVlLCAuLi5dOyBmaW5kICdkJy5cbiAgICBsZXQgcmF3OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgKyAxIDwgZmllbGRzLmxlbmd0aDsgaSArPSAyKSB7XG4gICAgICBpZiAoU3RyaW5nKGZpZWxkc1tpXSkgPT09ICdkJykgeyByYXcgPSBTdHJpbmcoZmllbGRzW2kgKyAxXSk7IGJyZWFrOyB9XG4gICAgfVxuICAgIC8vIEEgbWlzc2luZyBgZGAgZmllbGQgKGFuIGVudHJ5IG5vdCB3cml0dGVuIGJ5IHB1Ymxpc2goKSkgT1IgYSBjb3JydXB0IEpTT05cbiAgICAvLyBwYXlsb2FkIGJvdGggeWllbGQgYW4gdW5kZWZpbmVkLXBheWxvYWQgZW52ZWxvcGUgc28gYGRlbGl2ZXIoKWAgQUNLcyBpdCDigJRcbiAgICAvLyBhIHBvaXNvbiBtZXNzYWdlIG11c3QgbmV2ZXIgd2VkZ2UgdGhlIGdyb3VwIGJ5IHN0YXlpbmcgcGVycGV0dWFsbHkgcGVuZGluZy5cbiAgICBpZiAocmF3ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIG91dC5wdXNoKHsgaWQsIHRvcGljLCBwYXlsb2FkOiB1bmRlZmluZWQgYXMgdW5rbm93biBhcyBUIH0pO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBvdXQucHVzaCh7IGlkLCB0b3BpYywgcGF5bG9hZDogSlNPTi5wYXJzZShyYXcpIGFzIFQgfSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICBvdXQucHVzaCh7IGlkLCB0b3BpYywgcGF5bG9hZDogdW5kZWZpbmVkIGFzIHVua25vd24gYXMgVCB9KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIEJ1aWxkIGEgZHVyYWJsZSBldmVudCBidXMgb3ZlciBhIFJlZGlzIFN0cmVhbXMgY2xpZW50LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJlZGlzRHVyYWJsZUV2ZW50QnVzKFxuICByZWRpczogUmVkaXNTdHJlYW1DbGllbnQsXG4gIG9wdHM6IHsgbWF4TGVuPzogbnVtYmVyIH0gPSB7fSxcbik6IER1cmFibGVFdmVudEJ1cyB7XG4gIGNvbnN0IG1heExlbiA9IE1hdGgubWF4KDEsIG9wdHMubWF4TGVuID8/IERFRkFVTFRfTUFYTEVOKTtcblxuICByZXR1cm4ge1xuICAgIGFzeW5jIHB1Ymxpc2g8VD4odG9waWM6IHN0cmluZywgcGF5bG9hZDogVCk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICAgICAgY29uc3Qga2V5ID0gc3RyZWFtS2V5KHRvcGljKTtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIE1BWExFTiB+IDxuPiBib3VuZHMgdGhlIHN0cmVhbSBhcHByb3hpbWF0ZWx5IChjaGVhcCk7IGAqYCA9IHNlcnZlciBpZC5cbiAgICAgICAgY29uc3QgaWQgPSBhd2FpdCByZWRpcy54YWRkKGtleSwgJ01BWExFTicsICd+JywgbWF4TGVuLCAnKicsICdkJywgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xuICAgICAgICBlbWl0Q291bnRlcignZXZlbnRfYnVzX3B1Ymxpc2hlZF90b3RhbCcsIHsgdG9waWMgfSk7XG4gICAgICAgIHJldHVybiBpZDtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBlbWl0Q291bnRlcignZXZlbnRfYnVzX3B1Ymxpc2hfZmFpbGVkX3RvdGFsJywgeyB0b3BpYyB9KTtcbiAgICAgICAgbG9nZ2VyLndhcm4oJ0V2ZW50IGJ1cyBwdWJsaXNoIGZhaWxlZCAoZXZlbnQgZHJvcHBlZCknLCB7IHRvcGljLCBlcnJvcjogZXJyTXNnKGVycikgfSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH0sXG5cbiAgICBzdWJzY3JpYmU8VD4oc3ViT3B0czogU3Vic2NyaWJlT3B0aW9uczxUPik6IEV2ZW50U3Vic2NyaXB0aW9uIHtcbiAgICAgIGNvbnN0IHsgdG9waWMsIGdyb3VwLCBjb25zdW1lciwgaGFuZGxlciB9ID0gc3ViT3B0cztcbiAgICAgIGNvbnN0IGtleSA9IHN0cmVhbUtleSh0b3BpYyk7XG4gICAgICBjb25zdCBiYXRjaCA9IE1hdGgubWF4KDEsIHN1Yk9wdHMuYmF0Y2hTaXplID8/IERFRkFVTFRfQkFUQ0gpO1xuICAgICAgY29uc3QgYmxvY2tNcyA9IE1hdGgubWF4KDAsIHN1Yk9wdHMuYmxvY2tNcyA/PyBERUZBVUxUX0JMT0NLX01TKTtcbiAgICAgIGNvbnN0IG1pbklkbGUgPSBNYXRoLm1heCgwLCBzdWJPcHRzLm1pbklkbGVNcyA/PyBERUZBVUxUX01JTl9JRExFX01TKTtcblxuICAgICAgbGV0IHN0b3BwZWQgPSBmYWxzZTtcbiAgICAgIGxldCBzdGFydGVkID0gZmFsc2U7XG5cbiAgICAgIGNvbnN0IGRlbGl2ZXIgPSBhc3luYyAoZW52czogRXZlbnRFbnZlbG9wZTxUPltdKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGZvciAoY29uc3QgZW52IG9mIGVudnMpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKGVudi5wYXlsb2FkICE9PSB1bmRlZmluZWQpIGF3YWl0IGhhbmRsZXIoZW52KTtcbiAgICAgICAgICAgIC8vIEFjayBvbiBzdWNjZXNzIE9SIG9uIGFuIHVuZGVmaW5lZCAoY29ycnVwdCkgcGF5bG9hZCDigJQgYSBwb2lzb25cbiAgICAgICAgICAgIC8vIG1lc3NhZ2UgbXVzdCBub3QgYmxvY2sgdGhlIGdyb3VwIGZvcmV2ZXIuXG4gICAgICAgICAgICBhd2FpdCByZWRpcy54YWNrKGtleSwgZ3JvdXAsIGVudi5pZCk7XG4gICAgICAgICAgICBlbWl0Q291bnRlcignZXZlbnRfYnVzX2RlbGl2ZXJlZF90b3RhbCcsIHsgdG9waWMsIGdyb3VwIH0pO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgLy8gTGVhdmUgaXQgcGVuZGluZyAobm8gWEFDSykg4oCUIFhBVVRPQ0xBSU0gcmVkZWxpdmVycyBpdCBhZnRlciBtaW5JZGxlLlxuICAgICAgICAgICAgZW1pdENvdW50ZXIoJ2V2ZW50X2J1c19oYW5kbGVyX2ZhaWxlZF90b3RhbCcsIHsgdG9waWMsIGdyb3VwIH0pO1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ0V2ZW50IGhhbmRsZXIgZmFpbGVkOyBsZWF2aW5nIG1lc3NhZ2UgcGVuZGluZyBmb3IgcmVkZWxpdmVyeScsIHtcbiAgICAgICAgICAgICAgdG9waWMsIGdyb3VwLCBpZDogZW52LmlkLCBlcnJvcjogZXJyTXNnKGVyciksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIC8vIFRoZSBjb25zdW1lciBncm91cCBtdXN0IGV4aXN0IGJlZm9yZSBYUkVBREdST1VQIGNhbiBzdWNjZWVkLiBDcmVhdGluZyBpdFxuICAgICAgLy8gaXMgcmV0cmllZCBpbnNpZGUgdGhlIGxvb3A6IGF0IHN0YXJ0dXAgdGhlIGNsaWVudCBtYXkgbm90IGhhdmUgY29ubmVjdGVkXG4gICAgICAvLyB5ZXQsIGFuZCBhIHNpbmdsZSBmYWlsZWQgYXR0ZW1wdCB1c2VkIHRvIGxlYXZlIHRoZSBjb25zdW1lciByZWFkaW5nIGFcbiAgICAgIC8vIGdyb3VwIHRoYXQgd2FzIG5ldmVyIGNyZWF0ZWQg4oCUIGZvcmV2ZXIuXG4gICAgICBsZXQgZ3JvdXBSZWFkeSA9IGZhbHNlO1xuICAgICAgY29uc3QgZW5zdXJlR3JvdXAgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gTUtTVFJFQU0gc28gdGhlIHN0cmVhbSBuZWVkIG5vdCBleGlzdCB5ZXQ7ICckJyA9IG9ubHkgbmV3IG1lc3NhZ2VzLlxuICAgICAgICAgIGF3YWl0IHJlZGlzLnhncm91cCgnQ1JFQVRFJywga2V5LCBncm91cCwgJyQnLCAnTUtTVFJFQU0nKTtcbiAgICAgICAgICBncm91cFJlYWR5ID0gdHJ1ZTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgaWYgKCFpc0J1c3lHcm91cChlcnIpKSB0aHJvdyBlcnI7XG4gICAgICAgICAgZ3JvdXBSZWFkeSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGxvb3AgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIHdoaWxlICghc3RvcHBlZCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZiAoIWdyb3VwUmVhZHkpIGF3YWl0IGVuc3VyZUdyb3VwKCk7XG4gICAgICAgICAgICAvLyAxKSBSZWNsYWltIG1lc3NhZ2VzIHN0cmFuZGVkIGJ5IGEgY3Jhc2hlZCBjb25zdW1lciBpbiB0aGlzIGdyb3VwLlxuICAgICAgICAgICAgY29uc3QgY2xhaW1lZCA9IGF3YWl0IHJlZGlzLnhhdXRvY2xhaW0oa2V5LCBncm91cCwgY29uc3VtZXIsIG1pbklkbGUsICcwJywgJ0NPVU5UJywgYmF0Y2gpO1xuICAgICAgICAgICAgLy8gWEFVVE9DTEFJTSByZXBseTogW25leHRDdXJzb3IsIGVudHJpZXMsIGRlbGV0ZWRJZHNdXG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShjbGFpbWVkKSAmJiBjbGFpbWVkLmxlbmd0aCA+PSAyKSB7XG4gICAgICAgICAgICAgIGF3YWl0IGRlbGl2ZXIocGFyc2VFbnRyaWVzPFQ+KHRvcGljLCBjbGFpbWVkWzFdKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoc3RvcHBlZCkgYnJlYWs7XG5cbiAgICAgICAgICAgIC8vIDIpIFJlYWQgbmV3LCBuZXZlci1kZWxpdmVyZWQgbWVzc2FnZXMgZm9yIHRoaXMgZ3JvdXAgKCc+JykuXG4gICAgICAgICAgICBjb25zdCByZXMgPSBhd2FpdCByZWRpcy54cmVhZGdyb3VwKFxuICAgICAgICAgICAgICAnR1JPVVAnLCBncm91cCwgY29uc3VtZXIsICdDT1VOVCcsIGJhdGNoLCAnQkxPQ0snLCBibG9ja01zLCAnU1RSRUFNUycsIGtleSwgJz4nLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIC8vIFhSRUFER1JPVVAgcmVwbHk6IFtbc3RyZWFtS2V5LCBlbnRyaWVzXV0gfCBudWxsIChvbiBibG9jayB0aW1lb3V0KVxuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmVzKSAmJiByZXMubGVuZ3RoID4gMCAmJiBBcnJheS5pc0FycmF5KHJlc1swXSkgJiYgcmVzWzBdLmxlbmd0aCA+PSAyKSB7XG4gICAgICAgICAgICAgIGF3YWl0IGRlbGl2ZXIocGFyc2VFbnRyaWVzPFQ+KHRvcGljLCByZXNbMF1bMV0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGlmIChzdG9wcGVkKSBicmVhaztcbiAgICAgICAgICAgIC8vIFRoZSBzdHJlYW0gb3IgZ3JvdXAgd2FzIGRlbGV0ZWQgb3V0IGZyb20gdW5kZXIgdXMg4oCUIHJlY3JlYXRlIGl0LlxuICAgICAgICAgICAgaWYgKC9OT0dST1VQL2kudGVzdChlcnJNc2coZXJyKSkpIGdyb3VwUmVhZHkgPSBmYWxzZTtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdFdmVudCBidXMgY29uc3VtZXIgbG9vcCBlcnJvcjsgYmFja2luZyBvZmYnLCB7IHRvcGljLCBncm91cCwgZXJyb3I6IGVyck1zZyhlcnIpIH0pO1xuICAgICAgICAgICAgLy8gQmFjayBvZmYgc28gYSBwZXJzaXN0ZW50IFJlZGlzIGVycm9yIGRvZXNuJ3QgaG90LXNwaW4uXG4gICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocikgPT4gc2V0VGltZW91dChyLCAxMDAwKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBsZXQgbG9vcFByb21pc2UgPSBQcm9taXNlLnJlc29sdmUoKTtcbiAgICAgIGlmICghc3RhcnRlZCkge1xuICAgICAgICBzdGFydGVkID0gdHJ1ZTtcbiAgICAgICAgbG9vcFByb21pc2UgPSBsb29wKCk7XG4gICAgICAgIGxvZ2dlci5pbmZvKCdFdmVudCBidXMgY29uc3VtZXIgc3RhcnRlZCcsIHsgdG9waWMsIGdyb3VwLCBjb25zdW1lciB9KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYXN5bmMgc3RvcCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgICBzdG9wcGVkID0gdHJ1ZTtcbiAgICAgICAgICAvLyBBd2FpdCB0aGUgaW4tZmxpZ2h0IHJlYWQvaGFuZGxlciBzbyBhIGNhbGxlciAoZS5nLiBhIHNlcnZpY2Ugc2h1dHRpbmdcbiAgICAgICAgICAvLyBkb3duIGl0cyBEQikgZG9lc24ndCByYWNlIGEgbWVzc2FnZSBzdGlsbCBiZWluZyBwcm9jZXNzZWQuIEJvdW5kZWQgYnlcbiAgICAgICAgICAvLyB0aGUgWFJFQURHUk9VUCBCTE9DSyB3aW5kb3cuIE5ldmVyIHJlamVjdHMg4oCUIHRoZSBsb29wIHN3YWxsb3dzIGVycm9ycy5cbiAgICAgICAgICBhd2FpdCBsb29wUHJvbWlzZS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9LFxuICB9O1xufVxuXG4vKipcbiAqIEJ1aWxkIGEgZHVyYWJsZSBldmVudCBidXMgZnJvbSB0aGUgYW1iaWVudCBSZWRpcyBlbnYgdmlhIHRoZSBzaGFyZWRcbiAqIGBjcmVhdGVFbnZSZWRpc0NsaWVudGAuIFJldHVybnMgYG51bGxgIHdoZW4gUmVkaXMgaXMgbm90IGNvbmZpZ3VyZWQg4oCUIHRoZVxuICogY2FsbGVyIHRoZW4gcnVucyB3aXRob3V0IGEgYnVzICh0b2RheSdzIEhUVFAvcmVjb25jaWxlciBiZWhhdmlvciksIG5ldmVyXG4gKiBjcmFzaGluZy4gT3B0IGluIHdpdGggYSBzaW5nbGUgYm9vdCBsaW5lIHdoZXJlIGEgc2VydmljZSB3YW50cyBkdXJhYmxlIGV2ZW50cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUVudlJlZGlzRHVyYWJsZUV2ZW50QnVzKG9wdHM6IHsgbWF4TGVuPzogbnVtYmVyIH0gPSB7fSk6IER1cmFibGVFdmVudEJ1cyB8IG51bGwge1xuICBjb25zdCBpbnN0ID0gY3JlYXRlRW52UmVkaXNDbGllbnQ8UmVkaXNTdHJlYW1DbGllbnQ+KCdldmVudC1idXMnKTtcbiAgaWYgKCFpbnN0KSByZXR1cm4gbnVsbDtcbiAgbG9nZ2VyLmluZm8oJ1JlZGlzIGR1cmFibGUgZXZlbnQgYnVzIGluaXRpYWxpemVkJyk7XG4gIHJldHVybiBjcmVhdGVSZWRpc0R1cmFibGVFdmVudEJ1cyhpbnN0LCBvcHRzKTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBFbnRpdHktZXZlbnQgYnJpZGdlIChhZGRpdGl2ZSwgb3B0LWluKVxuLy9cbi8vIExldHMgYSBzZXJ2aWNlIGdpdmUgaXRzIGluLXByb2Nlc3Mge0BsaW5rIGVudGl0eUV2ZW50c30gZW1pdHRlciBhIERVUkFCTEUsXG4vLyBjcm9zcy1wb2QgZGVsaXZlcnkgbGVnIFdJVEhPVVQgY2hhbmdpbmcgZXhpc3RpbmcgYmVoYXZpb3I6IHJlZ2lzdGVyIHRoZVxuLy8gcmV0dXJuZWQgc3Vic2NyaWJlciBhbmQgZXZlcnkgZW50aXR5IG11dGF0aW9uIGlzIEFMU08gcHVibGlzaGVkIHRvIHRoZSBidXMuXG4vLyBBIGNvbnN1bWVyIGVsc2V3aGVyZSAoYGJ1cy5zdWJzY3JpYmVgKSB0aGVuIHJlYWN0cyBhdC1sZWFzdC1vbmNlIGFjcm9zcyBwb2RzXG4vLyBhbmQgcmVzdGFydHMuIFRoZSBpbi1wcm9jZXNzIHN1YnNjcmliZXJzIGtlZXAgZmlyaW5nIGV4YWN0bHkgYXMgYmVmb3JlLCBzb1xuLy8gdGhpcyBpcyBwdXJlbHkgYWRkaXRpdmUg4oCUIG5vIGRvdWJsZS1wcm9jZXNzaW5nIHVubGVzcyBhIHNlcnZpY2UgaW50ZW50aW9uYWxseVxuLy8gcnVucyBhIGJ1cyBjb25zdW1lciBmb3IgdGhlIHNhbWUgcmVhY3Rpb24uIEtlcHQgaGVyZSAobm90IGluIGVudGl0eS1ldmVudHMudHMpXG4vLyBzbyB0aGF0IG1vZHVsZSBzdGF5cyBpbmZyYXN0cnVjdHVyZS1mcmVlIHBlciBpdHMgb3duIGNvbnRyYWN0LlxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKiBUb3BpYyB0aGUgZW50aXR5LWV2ZW50IGJyaWRnZSBwdWJsaXNoZXMgdG8uICovXG5leHBvcnQgY29uc3QgRU5USVRZX0VWRU5UX1RPUElDID0gJ2VudGl0eS1ldmVudHMnO1xuXG4vKipcbiAqIEFuIHtAbGluayBFbnRpdHlFdmVudFN1YnNjcmliZXJ9IHRoYXQgZm9yd2FyZHMgZWFjaCBlbnRpdHkgZXZlbnQgdG8gdGhlIGR1cmFibGVcbiAqIGJ1cy4gYGJ1cy5wdWJsaXNoYCBpcyBmYWlsLXNhZmUgKGRyb3BzLXdpdGgtbWV0cmljLCBuZXZlciB0aHJvd3MpLCBtYXRjaGluZyB0aGVcbiAqIGVtaXR0ZXIncyBmaXJlLWFuZC1mb3JnZXQgY29udHJhY3QuIE5vdGUgYEVudGl0eUV2ZW50LnRpbWVzdGFtcGAgKGEgRGF0ZSlcbiAqIHNlcmlhbGl6ZXMgdG8gYW4gSVNPIHN0cmluZyBvbiB0aGUgd2lyZSDigJQgYSBjb25zdW1lciByZS1oeWRyYXRlcyBhcyBuZWVkZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFbnRpdHlFdmVudEJ1c1B1Ymxpc2hlcihidXM6IER1cmFibGVFdmVudEJ1cyk6IEVudGl0eUV2ZW50U3Vic2NyaWJlciB7XG4gIHJldHVybiB7XG4gICAgYXN5bmMgb25FbnRpdHlFdmVudChldmVudDogRW50aXR5RXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgIGF3YWl0IGJ1cy5wdWJsaXNoKEVOVElUWV9FVkVOVF9UT1BJQywgZXZlbnQpO1xuICAgIH0sXG4gIH07XG59XG4iXX0=
|
|
266
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHVyYWJsZS1ldmVudC1idXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvZHVyYWJsZS1ldmVudC1idXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsK0NBQStDO0FBQy9DLHNDQUFzQztBQUV0Qzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQkc7QUFFSCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRXpELE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBdUVqRCxNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUM7QUFDOUIsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFDO0FBQ3pCLE1BQU0sZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0FBQy9CLE1BQU0sbUJBQW1CLEdBQUcsTUFBTSxDQUFDO0FBQ25DLE1BQU0sc0JBQXNCLEdBQUcsRUFBRSxDQUFDO0FBRWxDLFNBQVMsTUFBTSxDQUFDLEdBQVk7SUFDMUIsT0FBTyxHQUFHLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7QUFDMUQsQ0FBQztBQUVELFNBQVMsU0FBUyxDQUFDLEtBQWE7SUFDOUIsT0FBTyxPQUFPLEtBQUssRUFBRSxDQUFDO0FBQ3hCLENBQUM7QUFFRCxzQ0FBc0M7QUFDdEMsTUFBTSxVQUFVLG1CQUFtQixDQUFDLEtBQWE7SUFDL0MsT0FBTyxPQUFPLEtBQUssTUFBTSxDQUFDO0FBQzVCLENBQUM7QUFFRCxtRkFBbUY7QUFDbkYsU0FBUyxpQkFBaUIsQ0FBQyxFQUFVO0lBQ25DLE1BQU0sRUFBRSxHQUFHLE1BQU0sQ0FBQyxFQUFF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RyxJQUFJLEVBQUUsQ0FBQztZQUMzQixNQUFNLENBQUMsSUFBSSxDQUFDLDRCQUE0QixFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztZQUVyRixPQUFPO2dCQUNMLEtBQUssQ0FBQyxJQUFJO29CQUNSLE9BQU8sR0FBRyxJQUFJLENBQUM7b0JBQ2Ysd0VBQXdFO29CQUN4RSx3RUFBd0U7b0JBQ3hFLHlFQUF5RTtvQkFDekUsTUFBTSxXQUFXLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUN6QyxNQUFNLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7Z0JBQ2hFLENBQUM7YUFDRixDQUFDO1FBQ0osQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFVBQVUsNkJBQTZCLENBQUMsSUFBSSxHQUF3QixFQUFFO0lBQzFFLE1BQU0sSUFBSSxHQUFHLG9CQUFvQixDQUFvQixXQUFXLENBQUMsQ0FBQztJQUNsRSxJQUFJLENBQUMsSUFBSTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3ZCLE1BQU0sQ0FBQyxJQUFJLENBQUMscUNBQXFDLENBQUMsQ0FBQztJQUNuRCxPQUFPLDBCQUEwQixDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztBQUNoRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbi8qKlxuICogRHVyYWJsZSwgYXQtbGVhc3Qtb25jZSBldmVudCBiYWNrYm9uZSAoUmVkaXMgU3RyZWFtcykuXG4gKlxuICogVGhlIHBsYXRmb3JtJ3MgY3Jvc3Mtc2VydmljZSBzaWduYWxsaW5nIHRvZGF5IGlzIHBvaW50LXRvLXBvaW50IEhUVFAgcGx1c1xuICogcG9sbGluZyByZWNvbmNpbGVycyBwbHVzIGFuIElOLVBST0NFU1MgYmVzdC1lZmZvcnQgZW1pdHRlciAoe0BsaW5rIGVudGl0eUV2ZW50c30pLlxuICogVGhlcmUgaXMgbm8gZHVyYWJsZSBidXMsIHNvIGEgc2lnbmFsIHByb2R1Y2VkIG9uIG9uZSBwb2QgaXMgZWl0aGVyIGRlbGl2ZXJlZFxuICogc3luY2hyb25vdXNseSBvdmVyIEhUVFAgKGNvdXBsaW5nICsgcmV0cnktc3Rvcm0gcmlzaykgb3IgbG9zdCBpZiB0aGUgY29uc3VtZXJcbiAqIGlzIG1vbWVudGFyaWx5IGRvd24gKHRoZSByZWNvbmNpbGVycyBleGlzdCB0byBwYXBlciBvdmVyIGV4YWN0bHkgdGhhdCkuXG4gKlxuICogVGhpcyBpcyB0aGF0IG1pc3NpbmcgYnVzLCBhcyBhIHJldXNhYmxlIHByaW1pdGl2ZTpcbiAqICAtICoqcHVibGlzaCh0b3BpYywgcGF5bG9hZCkqKiDihpIgYFhBRERgIG9udG8gYSBib3VuZGVkIChgTUFYTEVOIH5gKSBwZXItdG9waWNcbiAqICAgIHN0cmVhbS4gRHVyYWJsZSBhY3Jvc3MgcmVzdGFydHMsIHNoYXJlZCBieSBhbGwgcmVwbGljYXMuXG4gKiAgLSAqKnN1YnNjcmliZSh7dG9waWMsIGdyb3VwLCBjb25zdW1lciwgaGFuZGxlcn0pKiog4oaSIGEgYFhSRUFER1JPVVBgIGNvbnN1bWVyXG4gKiAgICBvbiBpdHMgT1dOIGNvbm5lY3Rpb24gKGBkdXBsaWNhdGUoKWApLCBzbyBhIGJsb2NraW5nIHJlYWQgbmV2ZXIgZGVsYXlzIGFcbiAqICAgIHB1Ymxpc2guIENvbnN1bWVyIEdST1VQUyBnaXZlIGF0LWxlYXN0LW9uY2U6IGVhY2ggZ3JvdXAgZ2V0cyBldmVyeSBtZXNzYWdlXG4gKiAgICBvbmNlLCBhIG1lc3NhZ2Ugc3RheXMgcGVuZGluZyB1bnRpbCB0aGUgaGFuZGxlciBgWEFDS2BzIGl0LCBhbmQgYFhBVVRPQ0xBSU1gXG4gKiAgICByZWNsYWltcyBtZXNzYWdlcyBzdHJhbmRlZCBieSBhIGNyYXNoZWQgY29uc3VtZXIuIEEgbWVzc2FnZSB0aGF0IGhhcyBiZWVuXG4gKiAgICBkZWxpdmVyZWQgYG1heERlbGl2ZXJpZXNgIHRpbWVzIHdpdGhvdXQgYW4gYWNrIGlzIG1vdmVkIHRvIGEgZGVhZC1sZXR0ZXJcbiAqICAgIHN0cmVhbSAoYGV2dDo8dG9waWM+OmRscWApIGFuZCBhY2tlZCwgc28gYSBwb2lzb24gbWVzc2FnZSBjYW4ndCByZWRlbGl2ZXJcbiAqICAgIGZvcmV2ZXIuIE11bHRpcGxlIGdyb3VwcyBvbiBvbmUgdG9waWMgPSBpbmRlcGVuZGVudCBmYW4tb3V0LlxuICpcbiAqIEZBSUwtU0FGRSArIE9QVC1JTiwgZXhhY3RseSBsaWtlIHRoZSBhdWRpdCBzcG9vbDoge0BsaW5rIGNyZWF0ZUVudlJlZGlzRHVyYWJsZUV2ZW50QnVzfVxuICogcmV0dXJucyBgbnVsbGAgd2hlbiBSZWRpcyBpc24ndCBjb25maWd1cmVkLCBzbyBhIHNlcnZpY2Ugd2l0aG91dCBpdCBzaW1wbHlcbiAqIGRvZXNuJ3QgdXNlIHRoZSBidXMgKGtlZXBzIHRvZGF5J3MgYmVoYXZpb3IpLiBBIHB1Ymxpc2ggZmFpbHVyZSBpcyBkcm9wcGVkLXdpdGgtXG4gKiAtbWV0cmljLCBuZXZlciB0aHJvd247IGEgaGFuZGxlciB0aHJvdyBsZWF2ZXMgdGhlIG1lc3NhZ2UgdW4tYWNrZWQgZm9yIHJlZGVsaXZlcnkuXG4gKlxuICovXG5cbmltcG9ydCB7IGNyZWF0ZUVudlJlZGlzQ2xpZW50IH0gZnJvbSAnLi9lbnYtcmVkaXMuanMnO1xuaW1wb3J0IHsgY3JlYXRlTG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IGVtaXRDb3VudGVyIH0gZnJvbSAnLi4vdXRpbHMvbWV0cmljLWVtaXR0ZXIuanMnO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2R1cmFibGUtZXZlbnQtYnVzJyk7XG5cbi8qKiBBIGRlbGl2ZXJlZCBldmVudDogaXRzIHN0cmVhbSBpZCwgdG9waWMsIHB1Ymxpc2ggdGltZSwgYW5kIGRlY29kZWQgcGF5bG9hZC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRFbnZlbG9wZTxUID0gdW5rbm93bj4ge1xuICAvKiogUmVkaXMgU3RyZWFtIGVudHJ5IGlkIChgPG1zPi08c2VxPmApIOKAlCBhbHNvIHRoZSBpZGVtcG90ZW5jeSBoYW5kbGUuICovXG4gIGlkOiBzdHJpbmc7XG4gIHRvcGljOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBXaGVuIHRoZSBldmVudCB3YXMgcHVibGlzaGVkICh0aGUgUmVkaXMgc2VydmVyIHRpbWUgZW1iZWRkZWQgaW4gdGhlIHN0cmVhbVxuICAgKiBpZCkuIEEgcmVkZWxpdmVyeSBrZWVwcyBpdHMgT1JJR0lOQUwgcHVibGlzaCB0aW1lLCBzbyBhIGNvbnN1bWVyIGFwcGx5aW5nXG4gICAqIGxhc3Qtd3JpdGVyLXdpbnMgc3RhdGUgKGUuZy4gYW4gZW50aXRsZW1lbnQgc3luYykgY2FuIG9yZGVyIGV2ZW50cyBieSBpdFxuICAgKiBpbnN0ZWFkIG9mIGJ5IGRlbGl2ZXJ5IHRpbWUgYW5kIHJlZnVzZSB0byBsZXQgYSBzdGFsZSByZXRyeSBvdmVyd3JpdGUgYVxuICAgKiBuZXdlciBzdGF0ZS5cbiAgICovXG4gIHB1Ymxpc2hlZEF0OiBEYXRlO1xuICBwYXlsb2FkOiBUO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN1YnNjcmliZU9wdGlvbnM8VCA9IHVua25vd24+IHtcbiAgLyoqIFRvcGljIChzdHJlYW0pIHRvIGNvbnN1bWUuICovXG4gIHRvcGljOiBzdHJpbmc7XG4gIC8qKiBDb25zdW1lciBncm91cCDigJQgb25lIGRlbGl2ZXJ5IHBlciBncm91cDsgZGlzdGluY3QgZ3JvdXBzIGZhbiBvdXQuICovXG4gIGdyb3VwOiBzdHJpbmc7XG4gIC8qKiBUaGlzIGNvbnN1bWVyJ3MgaWQgd2l0aGluIHRoZSBncm91cCAoZS5nLiBgJHtzZXJ2aWNlfS0ke3BpZH1gKS4gKi9cbiAgY29uc3VtZXI6IHN0cmluZztcbiAgLyoqIEFzeW5jIGhhbmRsZXIuIFJlc29sdmVzIOKHkiB0aGUgbWVzc2FnZSBpcyBhY2tlZDsgdGhyb3dzIOKHkiBsZWZ0IHBlbmRpbmcgZm9yIHJlZGVsaXZlcnkuICovXG4gIGhhbmRsZXI6IChlbnY6IEV2ZW50RW52ZWxvcGU8VD4pID0+IFByb21pc2U8dm9pZD47XG4gIC8qKiBNYXggbWVzc2FnZXMgcGVyIHJlYWQgKGRlZmF1bHQgMTYpLiAqL1xuICBiYXRjaFNpemU/OiBudW1iZXI7XG4gIC8qKiBYUkVBREdST1VQIGJsb2NrIHRpbWUgaW4gbXMgKGRlZmF1bHQgNTAwMCkuICovXG4gIGJsb2NrTXM/OiBudW1iZXI7XG4gIC8qKiBBIHBlbmRpbmcgbWVzc2FnZSBpZGxlIHRoaXMgbG9uZyAobXMpIGlzIHJlY2xhaW1lZCBmcm9tIGEgZGVhZCBjb25zdW1lciAoZGVmYXVsdCA2MDAwMCkuICovXG4gIG1pbklkbGVNcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIERlbGl2ZXJpZXMgYWZ0ZXIgd2hpY2ggYW4gdW4tYWNrZWQgbWVzc2FnZSBpcyBkZWFkLWxldHRlcmVkIHRvXG4gICAqIGBldnQ6PHRvcGljPjpkbHFgIGFuZCBhY2tlZCBpbnN0ZWFkIG9mIGJlaW5nIHJlZGVsaXZlcmVkIGFnYWluIChkZWZhdWx0IDEwKS5cbiAgICovXG4gIG1heERlbGl2ZXJpZXM/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRTdWJzY3JpcHRpb24ge1xuICAvKiogU3RvcCB0aGUgY29uc3VtZXIgbG9vcC4gUmVzb2x2ZXMgb25jZSB0aGUgaW4tZmxpZ2h0IHJlYWQgcmV0dXJucy4gKi9cbiAgc3RvcCgpOiBQcm9taXNlPHZvaWQ+O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIER1cmFibGVFdmVudEJ1cyB7XG4gIC8qKiBQdWJsaXNoIGEgcGF5bG9hZCB0byBhIHRvcGljLiBSZXR1cm5zIHRoZSBzdHJlYW0gaWQsIG9yIG51bGwgb24gZmFpbHVyZSAoZHJvcHBlZCwgbmV2ZXIgdGhyb3dzKS4gKi9cbiAgcHVibGlzaDxUPih0b3BpYzogc3RyaW5nLCBwYXlsb2FkOiBUKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPjtcbiAgLyoqIFN0YXJ0IGEgY29uc3VtZXItZ3JvdXAgcmVhZGVyIGZvciBhIHRvcGljLiBGaXJlLWFuZC1mb3JnZXQgbG9vcDsgY2FsbCBgc3RvcCgpYCB0byBlbmQgaXQuICovXG4gIHN1YnNjcmliZTxUPihvcHRzOiBTdWJzY3JpYmVPcHRpb25zPFQ+KTogRXZlbnRTdWJzY3JpcHRpb247XG59XG5cbi8qKlxuICogVGhlIHN1YnNldCBvZiBpb3JlZGlzJyBTdHJlYW0gQVBJIHRoZSBidXMgdXNlcy4gS2VwdCBtaW5pbWFsIHNvIGEgdGVzdCBjYW5cbiAqIHN1cHBseSBhbiBpbi1tZW1vcnkgZmFrZSBhbmQgc28gbWVyZWx5IGltcG9ydGluZyB0aGlzIG5ldmVyIGhhcmQtZGVwZW5kcyBvblxuICogaW9yZWRpcyAoY29uc3RydWN0ZWQgdmlhIHRoZSBzaGFyZWQgZW52IGhlbHBlcikuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVkaXNTdHJlYW1DbGllbnQge1xuICB4YWRkKGtleTogc3RyaW5nLCAuLi5hcmdzOiAoc3RyaW5nIHwgbnVtYmVyKVtdKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPjtcbiAgeGdyb3VwKC4uLmFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10pOiBQcm9taXNlPHVua25vd24+O1xuICB4cmVhZGdyb3VwKC4uLmFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10pOiBQcm9taXNlPHVua25vd24+O1xuICB4YWNrKGtleTogc3RyaW5nLCBncm91cDogc3RyaW5nLCAuLi5pZHM6IHN0cmluZ1tdKTogUHJvbWlzZTxudW1iZXI+O1xuICB4YXV0b2NsYWltKC4uLmFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10pOiBQcm9taXNlPHVua25vd24+O1xuICB4cGVuZGluZyhrZXk6IHN0cmluZywgZ3JvdXA6IHN0cmluZywgLi4uYXJnczogKHN0cmluZyB8IG51bWJlcilbXSk6IFByb21pc2U8dW5rbm93bj47XG4gIHhyYW5nZShrZXk6IHN0cmluZywgc3RhcnQ6IHN0cmluZywgZW5kOiBzdHJpbmcsIC4uLmFyZ3M6IChzdHJpbmcgfCBudW1iZXIpW10pOiBQcm9taXNlPHVua25vd24+O1xuICAvKiogQSBuZXcgY29ubmVjdGlvbiB3aXRoIHRoZSBzYW1lIG9wdGlvbnMg4oCUIGVhY2ggc3Vic2NyaWJlciByZWFkcyBvbiBpdHMgb3duLiAqL1xuICBkdXBsaWNhdGUoKTogUmVkaXNTdHJlYW1DbGllbnQ7XG4gIHF1aXQ/KCk6IFByb21pc2U8dW5rbm93bj47XG4gIG9uPyhldmVudDogJ2Vycm9yJywgY2I6IChlcnI6IHVua25vd24pID0+IHZvaWQpOiB1bmtub3duO1xufVxuXG5jb25zdCBERUZBVUxUX01BWExFTiA9IDEwXzAwMDtcbmNvbnN0IERFRkFVTFRfQkFUQ0ggPSAxNjtcbmNvbnN0IERFRkFVTFRfQkxPQ0tfTVMgPSA1XzAwMDtcbmNvbnN0IERFRkFVTFRfTUlOX0lETEVfTVMgPSA2MF8wMDA7XG5jb25zdCBERUZBVUxUX01BWF9ERUxJVkVSSUVTID0gMTA7XG5cbmZ1bmN0aW9uIGVyck1zZyhlcnI6IHVua25vd24pOiBzdHJpbmcge1xuICByZXR1cm4gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpO1xufVxuXG5mdW5jdGlvbiBzdHJlYW1LZXkodG9waWM6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgZXZ0OiR7dG9waWN9YDtcbn1cblxuLyoqIERlYWQtbGV0dGVyIHN0cmVhbSBmb3IgYSB0b3BpYy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZWFkTGV0dGVyU3RyZWFtS2V5KHRvcGljOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gYGV2dDoke3RvcGljfTpkbHFgO1xufVxuXG4vKiogUHVibGlzaCB0aW1lIGZyb20gYSBzdHJlYW0gaWQgKGA8bXM+LTxzZXE+YCk7IGVwb2NoIDAgZm9yIGFuIHVucGFyc2VhYmxlIGlkLiAqL1xuZnVuY3Rpb24gcHVibGlzaGVkQXRGcm9tSWQoaWQ6IHN0cmluZyk6IERhdGUge1xuICBjb25zdCBtcyA9IE51bWJlcihpZC5zcGxpdCgnLScpWzBdKTtcbiAgcmV0dXJuIG5ldyBEYXRlKE51bWJlci5pc0Zpbml0ZShtcykgPyBtcyA6IDApO1xufVxuXG4vKiogVHJ1ZSB3aGVuIHRoZSBlcnJvciBpcyBSZWRpcycgXCJncm91cCBhbHJlYWR5IGV4aXN0c1wiIChpZGVtcG90ZW50IGNyZWF0ZSkuICovXG5mdW5jdGlvbiBpc0J1c3lHcm91cChlcnI6IHVua25vd24pOiBib29sZWFuIHtcbiAgcmV0dXJuIGVyck1zZyhlcnIpLmluY2x1ZGVzKCdCVVNZR1JPVVAnKTtcbn1cblxuLyoqXG4gKiBQYXJzZSB0aGUgbmVzdGVkIGFycmF5IHNoYXBlIFhSRUFER1JPVVAgLyBYQVVUT0NMQUlNIHJldHVybiBpbnRvIGZsYXQgZW52ZWxvcGVzLlxuICogWFJFQURHUk9VUDogYFtbc3RyZWFtS2V5LCBbW2lkLCBbZiwgdiwgLi4uXV0sIC4uLl1dXWAuXG4gKiBYQVVUT0NMQUlNOiBgW25leHRDdXJzb3IsIFtbaWQsIFtmLCB2LCAuLi5dXSwgLi4uXSwgZGVsZXRlZElkc11gLlxuICogV2Ugc3RvcmUgdGhlIEpTT04gcGF5bG9hZCB1bmRlciBhIHNpbmdsZSBmaWVsZCBgZGAuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlRW50cmllczxUPih0b3BpYzogc3RyaW5nLCBlbnRyaWVzOiB1bmtub3duKTogRXZlbnRFbnZlbG9wZTxUPltdIHtcbiAgY29uc3Qgb3V0OiBFdmVudEVudmVsb3BlPFQ+W10gPSBbXTtcbiAgaWYgKCFBcnJheS5pc0FycmF5KGVudHJpZXMpKSByZXR1cm4gb3V0O1xuICBmb3IgKGNvbnN0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoZW50cnkpIHx8IGVudHJ5Lmxlbmd0aCA8IDIpIGNvbnRpbnVlO1xuICAgIGNvbnN0IGlkID0gU3RyaW5nKGVudHJ5WzBdKTtcbiAgICBjb25zdCBmaWVsZHMgPSBlbnRyeVsxXTtcbiAgICBpZiAoIUFycmF5LmlzQXJyYXkoZmllbGRzKSkgY29udGludWU7XG4gICAgLy8gZmllbGRzIGlzIFtuYW1lLCB2YWx1ZSwgbmFtZSwgdmFsdWUsIC4uLl07IGZpbmQgJ2QnLlxuICAgIGxldCByYXc6IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSArIDEgPCBmaWVsZHMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgIGlmIChTdHJpbmcoZmllbGRzW2ldKSA9PT0gJ2QnKSB7IHJhdyA9IFN0cmluZyhmaWVsZHNbaSArIDFdKTsgYnJlYWs7IH1cbiAgICB9XG4gICAgLy8gQSBtaXNzaW5nIGBkYCBmaWVsZCAoYW4gZW50cnkgbm90IHdyaXR0ZW4gYnkgcHVibGlzaCgpKSBPUiBhIGNvcnJ1cHQgSlNPTlxuICAgIC8vIHBheWxvYWQgYm90aCB5aWVsZCBhbiB1bmRlZmluZWQtcGF5bG9hZCBlbnZlbG9wZSBzbyBgZGVsaXZlcigpYCBBQ0tzIGl0IOKAlFxuICAgIC8vIGEgcG9pc29uIG1lc3NhZ2UgbXVzdCBuZXZlciB3ZWRnZSB0aGUgZ3JvdXAgYnkgc3RheWluZyBwZXJwZXR1YWxseSBwZW5kaW5nLlxuICAgIGNvbnN0IHB1Ymxpc2hlZEF0ID0gcHVibGlzaGVkQXRGcm9tSWQoaWQpO1xuICAgIGlmIChyYXcgPT09IHVuZGVmaW5lZCkge1xuICAgICAgb3V0LnB1c2goeyBpZCwgdG9waWMsIHB1Ymxpc2hlZEF0LCBwYXlsb2FkOiB1bmRlZmluZWQgYXMgdW5rbm93biBhcyBUIH0pO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBvdXQucHVzaCh7IGlkLCB0b3BpYywgcHVibGlzaGVkQXQsIHBheWxvYWQ6IEpTT04ucGFyc2UocmF3KSBhcyBUIH0pO1xuICAgIH0gY2F0Y2gge1xuICAgICAgb3V0LnB1c2goeyBpZCwgdG9waWMsIHB1Ymxpc2hlZEF0LCBwYXlsb2FkOiB1bmRlZmluZWQgYXMgdW5rbm93biBhcyBUIH0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gb3V0O1xufVxuXG4vKiogQnVpbGQgYSBkdXJhYmxlIGV2ZW50IGJ1cyBvdmVyIGEgUmVkaXMgU3RyZWFtcyBjbGllbnQuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlUmVkaXNEdXJhYmxlRXZlbnRCdXMoXG4gIHJlZGlzOiBSZWRpc1N0cmVhbUNsaWVudCxcbiAgb3B0czogeyBtYXhMZW4/OiBudW1iZXIgfSA9IHt9LFxuKTogRHVyYWJsZUV2ZW50QnVzIHtcbiAgY29uc3QgbWF4TGVuID0gTWF0aC5tYXgoMSwgb3B0cy5tYXhMZW4gPz8gREVGQVVMVF9NQVhMRU4pO1xuXG4gIHJldHVybiB7XG4gICAgYXN5bmMgcHVibGlzaDxUPih0b3BpYzogc3RyaW5nLCBwYXlsb2FkOiBUKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgICBjb25zdCBrZXkgPSBzdHJlYW1LZXkodG9waWMpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gTUFYTEVOIH4gPG4+IGJvdW5kcyB0aGUgc3RyZWFtIGFwcHJveGltYXRlbHkgKGNoZWFwKTsgYCpgID0gc2VydmVyIGlkLlxuICAgICAgICBjb25zdCBpZCA9IGF3YWl0IHJlZGlzLnhhZGQoa2V5LCAnTUFYTEVOJywgJ34nLCBtYXhMZW4sICcqJywgJ2QnLCBKU09OLnN0cmluZ2lmeShwYXlsb2FkKSk7XG4gICAgICAgIGVtaXRDb3VudGVyKCdldmVudF9idXNfcHVibGlzaGVkX3RvdGFsJywgeyB0b3BpYyB9KTtcbiAgICAgICAgcmV0dXJuIGlkO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGVtaXRDb3VudGVyKCdldmVudF9idXNfcHVibGlzaF9mYWlsZWRfdG90YWwnLCB7IHRvcGljIH0pO1xuICAgICAgICBsb2dnZXIud2FybignRXZlbnQgYnVzIHB1Ymxpc2ggZmFpbGVkIChldmVudCBkcm9wcGVkKScsIHsgdG9waWMsIGVycm9yOiBlcnJNc2coZXJyKSB9KTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSxcblxuICAgIHN1YnNjcmliZTxUPihzdWJPcHRzOiBTdWJzY3JpYmVPcHRpb25zPFQ+KTogRXZlbnRTdWJzY3JpcHRpb24ge1xuICAgICAgY29uc3QgeyB0b3BpYywgZ3JvdXAsIGNvbnN1bWVyLCBoYW5kbGVyIH0gPSBzdWJPcHRzO1xuICAgICAgY29uc3Qga2V5ID0gc3RyZWFtS2V5KHRvcGljKTtcbiAgICAgIGNvbnN0IGRscUtleSA9IGRlYWRMZXR0ZXJTdHJlYW1LZXkodG9waWMpO1xuICAgICAgY29uc3QgYmF0Y2ggPSBNYXRoLm1heCgxLCBzdWJPcHRzLmJhdGNoU2l6ZSA/PyBERUZBVUxUX0JBVENIKTtcbiAgICAgIGNvbnN0IGJsb2NrTXMgPSBNYXRoLm1heCgwLCBzdWJPcHRzLmJsb2NrTXMgPz8gREVGQVVMVF9CTE9DS19NUyk7XG4gICAgICBjb25zdCBtaW5JZGxlID0gTWF0aC5tYXgoMCwgc3ViT3B0cy5taW5JZGxlTXMgPz8gREVGQVVMVF9NSU5fSURMRV9NUyk7XG4gICAgICBjb25zdCBtYXhEZWxpdmVyaWVzID0gTWF0aC5tYXgoMSwgc3ViT3B0cy5tYXhEZWxpdmVyaWVzID8/IERFRkFVTFRfTUFYX0RFTElWRVJJRVMpO1xuXG4gICAgICAvLyBgWFJFQURHUk9VUCBCTE9DS2AgaG9sZHMgaXRzIGNvbm5lY3Rpb24gZm9yIHVwIHRvIGBibG9ja01zYDsgb24gdGhlXG4gICAgICAvLyBzaGFyZWQgY2xpZW50IGV2ZXJ5IHB1Ymxpc2ggcXVldWVkIGJlaGluZCBpdC4gUmVhZCBvbiBhIGRlZGljYXRlZCBvbmUuXG4gICAgICBjb25zdCByZWFkZXIgPSByZWRpcy5kdXBsaWNhdGUoKTtcbiAgICAgIC8vIEEgZHVwbGljYXRlZCBpb3JlZGlzIGNvbm5lY3Rpb24gZG9lc24ndCBpbmhlcml0IGxpc3RlbmVyczsgd2l0aG91dCBvbmUgYVxuICAgICAgLy8gY29ubmVjdGlvbiBlcnJvciBpcyBhbiB1bmhhbmRsZWQgJ2Vycm9yJyBldmVudCB0aGF0IGNyYXNoZXMgdGhlIHByb2Nlc3MuXG4gICAgICByZWFkZXIub24/LignZXJyb3InLCAoZXJyKSA9PiBsb2dnZXIud2FybignRXZlbnQgYnVzIHJlYWRlciBjb25uZWN0aW9uIGVycm9yJywgeyB0b3BpYywgZ3JvdXAsIGVycm9yOiBlcnJNc2coZXJyKSB9KSk7XG5cbiAgICAgIGxldCBzdG9wcGVkID0gZmFsc2U7XG5cbiAgICAgIGNvbnN0IGRlbGl2ZXIgPSBhc3luYyAoZW52czogRXZlbnRFbnZlbG9wZTxUPltdKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIGZvciAoY29uc3QgZW52IG9mIGVudnMpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKGVudi5wYXlsb2FkICE9PSB1bmRlZmluZWQpIGF3YWl0IGhhbmRsZXIoZW52KTtcbiAgICAgICAgICAgIC8vIEFjayBvbiBzdWNjZXNzIE9SIG9uIGFuIHVuZGVmaW5lZCAoY29ycnVwdCkgcGF5bG9hZCDigJQgYSBwb2lzb25cbiAgICAgICAgICAgIC8vIG1lc3NhZ2UgbXVzdCBub3QgYmxvY2sgdGhlIGdyb3VwIGZvcmV2ZXIuXG4gICAgICAgICAgICBhd2FpdCByZWFkZXIueGFjayhrZXksIGdyb3VwLCBlbnYuaWQpO1xuICAgICAgICAgICAgZW1pdENvdW50ZXIoJ2V2ZW50X2J1c19kZWxpdmVyZWRfdG90YWwnLCB7IHRvcGljLCBncm91cCB9KTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIC8vIExlYXZlIGl0IHBlbmRpbmcgKG5vIFhBQ0spIOKAlCBYQVVUT0NMQUlNIHJlZGVsaXZlcnMgaXQgYWZ0ZXIgbWluSWRsZS5cbiAgICAgICAgICAgIGVtaXRDb3VudGVyKCdldmVudF9idXNfaGFuZGxlcl9mYWlsZWRfdG90YWwnLCB7IHRvcGljLCBncm91cCB9KTtcbiAgICAgICAgICAgIGxvZ2dlci53YXJuKCdFdmVudCBoYW5kbGVyIGZhaWxlZDsgbGVhdmluZyBtZXNzYWdlIHBlbmRpbmcgZm9yIHJlZGVsaXZlcnknLCB7XG4gICAgICAgICAgICAgIHRvcGljLCBncm91cCwgaWQ6IGVudi5pZCwgZXJyb3I6IGVyck1zZyhlcnIpLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICAvKipcbiAgICAgICAqIE1vdmUgZXZlcnkgaWRsZSBwZW5kaW5nIG1lc3NhZ2UgdGhhdCBoYXMgYWxyZWFkeSBiZWVuIGRlbGl2ZXJlZFxuICAgICAgICogYG1heERlbGl2ZXJpZXNgIHRpbWVzIHRvIHRoZSBkZWFkLWxldHRlciBzdHJlYW0gYW5kIGFjayBpdC4gVGhlIGVudHJ5XG4gICAgICAgKiBrZWVwcyBpdHMgcGF5bG9hZCBwbHVzIHdoZXJlIGl0IGNhbWUgZnJvbSwgc28gYW4gb3BlcmF0b3IgY2FuIGluc3BlY3Qgb3JcbiAgICAgICAqIHJlcGxheSBpdC4gSWYgY29weWluZyBmYWlscyB0aGUgbWVzc2FnZSBpcyBsZWZ0IHBlbmRpbmcgKHJldHJpZWQgbmV4dFxuICAgICAgICogcGFzcykg4oCUIGl0IGlzIG5ldmVyIGFja2VkIHdpdGhvdXQgYmVpbmcgcHJlc2VydmVkLlxuICAgICAgICovXG4gICAgICBjb25zdCBkZWFkTGV0dGVyRXhoYXVzdGVkID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBjb25zdCBwZW5kaW5nID0gYXdhaXQgcmVhZGVyLnhwZW5kaW5nKGtleSwgZ3JvdXAsICdJRExFJywgbWluSWRsZSwgJy0nLCAnKycsIGJhdGNoKTtcbiAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHBlbmRpbmcpKSByZXR1cm47XG4gICAgICAgIGZvciAoY29uc3QgcCBvZiBwZW5kaW5nKSB7XG4gICAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHApIHx8IHAubGVuZ3RoIDwgNCkgY29udGludWU7XG4gICAgICAgICAgY29uc3QgaWQgPSBTdHJpbmcocFswXSk7XG4gICAgICAgICAgY29uc3QgZGVsaXZlcmllcyA9IE51bWJlcihwWzNdKTtcbiAgICAgICAgICBpZiAoIShkZWxpdmVyaWVzID49IG1heERlbGl2ZXJpZXMpKSBjb250aW51ZTtcbiAgICAgICAgICBjb25zdCBlbnRyaWVzID0gYXdhaXQgcmVhZGVyLnhyYW5nZShrZXksIGlkLCBpZCk7XG4gICAgICAgICAgY29uc3QgZmllbGRzID0gQXJyYXkuaXNBcnJheShlbnRyaWVzKSAmJiBBcnJheS5pc0FycmF5KGVudHJpZXNbMF0pICYmIEFycmF5LmlzQXJyYXkoZW50cmllc1swXVsxXSkgPyBlbnRyaWVzWzBdWzFdIDogW107XG4gICAgICAgICAgbGV0IHJhdyA9ICcnO1xuICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpICsgMSA8IGZpZWxkcy5sZW5ndGg7IGkgKz0gMikge1xuICAgICAgICAgICAgaWYgKFN0cmluZyhmaWVsZHNbaV0pID09PSAnZCcpIHsgcmF3ID0gU3RyaW5nKGZpZWxkc1tpICsgMV0pOyBicmVhazsgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBhd2FpdCByZWFkZXIueGFkZChcbiAgICAgICAgICAgIGRscUtleSwgJ01BWExFTicsICd+JywgbWF4TGVuLCAnKicsXG4gICAgICAgICAgICAnZCcsIHJhdywgJ3NvdXJjZUlkJywgaWQsICdncm91cCcsIGdyb3VwLCAnZGVsaXZlcmllcycsIGRlbGl2ZXJpZXMsXG4gICAgICAgICAgKTtcbiAgICAgICAgICBhd2FpdCByZWFkZXIueGFjayhrZXksIGdyb3VwLCBpZCk7XG4gICAgICAgICAgZW1pdENvdW50ZXIoJ2V2ZW50X2J1c19kZWFkX2xldHRlcmVkX3RvdGFsJywgeyB0b3BpYywgZ3JvdXAgfSk7XG4gICAgICAgICAgbG9nZ2VyLmVycm9yKCdFdmVudCBleGNlZWRlZCBtYXggZGVsaXZlcmllczsgbW92ZWQgdG8gZGVhZC1sZXR0ZXIgc3RyZWFtJywge1xuICAgICAgICAgICAgdG9waWMsIGdyb3VwLCBpZCwgZGVsaXZlcmllcywgZGVhZExldHRlclN0cmVhbTogZGxxS2V5LFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICAvLyBUaGUgY29uc3VtZXIgZ3JvdXAgbXVzdCBleGlzdCBiZWZvcmUgWFJFQURHUk9VUCBjYW4gc3VjY2VlZC4gQ3JlYXRpbmcgaXRcbiAgICAgIC8vIGlzIHJldHJpZWQgaW5zaWRlIHRoZSBsb29wOiBhdCBzdGFydHVwIHRoZSBjbGllbnQgbWF5IG5vdCBoYXZlIGNvbm5lY3RlZFxuICAgICAgLy8geWV0LCBhbmQgYSBzaW5nbGUgZmFpbGVkIGF0dGVtcHQgdXNlZCB0byBsZWF2ZSB0aGUgY29uc3VtZXIgcmVhZGluZyBhXG4gICAgICAvLyBncm91cCB0aGF0IHdhcyBuZXZlciBjcmVhdGVkIOKAlCBmb3JldmVyLlxuICAgICAgbGV0IGdyb3VwUmVhZHkgPSBmYWxzZTtcbiAgICAgIGNvbnN0IGVuc3VyZUdyb3VwID0gYXN5bmMgKCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIE1LU1RSRUFNIHNvIHRoZSBzdHJlYW0gbmVlZCBub3QgZXhpc3QgeWV0OyAnJCcgPSBvbmx5IG5ldyBtZXNzYWdlcy5cbiAgICAgICAgICBhd2FpdCByZWFkZXIueGdyb3VwKCdDUkVBVEUnLCBrZXksIGdyb3VwLCAnJCcsICdNS1NUUkVBTScpO1xuICAgICAgICAgIGdyb3VwUmVhZHkgPSB0cnVlO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICBpZiAoIWlzQnVzeUdyb3VwKGVycikpIHRocm93IGVycjtcbiAgICAgICAgICBncm91cFJlYWR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgY29uc3QgbG9vcCA9IGFzeW5jICgpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgICAgd2hpbGUgKCFzdG9wcGVkKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICghZ3JvdXBSZWFkeSkgYXdhaXQgZW5zdXJlR3JvdXAoKTtcbiAgICAgICAgICAgIC8vIDEpIERlYWQtbGV0dGVyIG1lc3NhZ2VzIHRoYXQgaGF2ZSBleGhhdXN0ZWQgdGhlaXIgZGVsaXZlcmllcywgdGhlblxuICAgICAgICAgICAgLy8gICAgcmVjbGFpbSB0aGUgcmVzdCBzdHJhbmRlZCBieSBhIGZhaWxlZC9jcmFzaGVkIGNvbnN1bWVyLlxuICAgICAgICAgICAgYXdhaXQgZGVhZExldHRlckV4aGF1c3RlZCgpO1xuICAgICAgICAgICAgY29uc3QgY2xhaW1lZCA9IGF3YWl0IHJlYWRlci54YXV0b2NsYWltKGtleSwgZ3JvdXAsIGNvbnN1bWVyLCBtaW5JZGxlLCAnMCcsICdDT1VOVCcsIGJhdGNoKTtcbiAgICAgICAgICAgIC8vIFhBVVRPQ0xBSU0gcmVwbHk6IFtuZXh0Q3Vyc29yLCBlbnRyaWVzLCBkZWxldGVkSWRzXVxuICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoY2xhaW1lZCkgJiYgY2xhaW1lZC5sZW5ndGggPj0gMikge1xuICAgICAgICAgICAgICBhd2FpdCBkZWxpdmVyKHBhcnNlRW50cmllczxUPih0b3BpYywgY2xhaW1lZFsxXSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHN0b3BwZWQpIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyAyKSBSZWFkIG5ldywgbmV2ZXItZGVsaXZlcmVkIG1lc3NhZ2VzIGZvciB0aGlzIGdyb3VwICgnPicpLlxuICAgICAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgcmVhZGVyLnhyZWFkZ3JvdXAoXG4gICAgICAgICAgICAgICdHUk9VUCcsIGdyb3VwLCBjb25zdW1lciwgJ0NPVU5UJywgYmF0Y2gsICdCTE9DSycsIGJsb2NrTXMsICdTVFJFQU1TJywga2V5LCAnPicsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy8gWFJFQURHUk9VUCByZXBseTogW1tzdHJlYW1LZXksIGVudHJpZXNdXSB8IG51bGwgKG9uIGJsb2NrIHRpbWVvdXQpXG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShyZXMpICYmIHJlcy5sZW5ndGggPiAwICYmIEFycmF5LmlzQXJyYXkocmVzWzBdKSAmJiByZXNbMF0ubGVuZ3RoID49IDIpIHtcbiAgICAgICAgICAgICAgYXdhaXQgZGVsaXZlcihwYXJzZUVudHJpZXM8VD4odG9waWMsIHJlc1swXVsxXSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgaWYgKHN0b3BwZWQpIGJyZWFrO1xuICAgICAgICAgICAgLy8gVGhlIHN0cmVhbSBvciBncm91cCB3YXMgZGVsZXRlZCBvdXQgZnJvbSB1bmRlciB1cyDigJQgcmVjcmVhdGUgaXQuXG4gICAgICAgICAgICBpZiAoL05PR1JPVVAvaS50ZXN0KGVyck1zZyhlcnIpKSkgZ3JvdXBSZWFkeSA9IGZhbHNlO1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oJ0V2ZW50IGJ1cyBjb25zdW1lciBsb29wIGVycm9yOyBiYWNraW5nIG9mZicsIHsgdG9waWMsIGdyb3VwLCBlcnJvcjogZXJyTXNnKGVycikgfSk7XG4gICAgICAgICAgICAvLyBCYWNrIG9mZiBzbyBhIHBlcnNpc3RlbnQgUmVkaXMgZXJyb3IgZG9lc24ndCBob3Qtc3Bpbi5cbiAgICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyKSA9PiBzZXRUaW1lb3V0KHIsIDEwMDApKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGxvb3BQcm9taXNlID0gbG9vcCgpO1xuICAgICAgbG9nZ2VyLmluZm8oJ0V2ZW50IGJ1cyBjb25zdW1lciBzdGFydGVkJywgeyB0b3BpYywgZ3JvdXAsIGNvbnN1bWVyLCBtYXhEZWxpdmVyaWVzIH0pO1xuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAgIHN0b3BwZWQgPSB0cnVlO1xuICAgICAgICAgIC8vIEF3YWl0IHRoZSBpbi1mbGlnaHQgcmVhZC9oYW5kbGVyIHNvIGEgY2FsbGVyIChlLmcuIGEgc2VydmljZSBzaHV0dGluZ1xuICAgICAgICAgIC8vIGRvd24gaXRzIERCKSBkb2Vzbid0IHJhY2UgYSBtZXNzYWdlIHN0aWxsIGJlaW5nIHByb2Nlc3NlZC4gQm91bmRlZCBieVxuICAgICAgICAgIC8vIHRoZSBYUkVBREdST1VQIEJMT0NLIHdpbmRvdy4gTmV2ZXIgcmVqZWN0cyDigJQgdGhlIGxvb3Agc3dhbGxvd3MgZXJyb3JzLlxuICAgICAgICAgIGF3YWl0IGxvb3BQcm9taXNlLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgICAgICAgYXdhaXQgUHJvbWlzZS5yZXNvbHZlKHJlYWRlci5xdWl0Py4oKSkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgfSxcbiAgfTtcbn1cblxuLyoqXG4gKiBCdWlsZCBhIGR1cmFibGUgZXZlbnQgYnVzIGZyb20gdGhlIGFtYmllbnQgUmVkaXMgZW52IHZpYSB0aGUgc2hhcmVkXG4gKiBgY3JlYXRlRW52UmVkaXNDbGllbnRgLiBSZXR1cm5zIGBudWxsYCB3aGVuIFJlZGlzIGlzIG5vdCBjb25maWd1cmVkIOKAlCB0aGVcbiAqIGNhbGxlciB0aGVuIHJ1bnMgd2l0aG91dCBhIGJ1cyAodG9kYXkncyBIVFRQL3JlY29uY2lsZXIgYmVoYXZpb3IpLCBuZXZlclxuICogY3Jhc2hpbmcuIE9wdCBpbiB3aXRoIGEgc2luZ2xlIGJvb3QgbGluZSB3aGVyZSBhIHNlcnZpY2Ugd2FudHMgZHVyYWJsZSBldmVudHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVFbnZSZWRpc0R1cmFibGVFdmVudEJ1cyhvcHRzOiB7IG1heExlbj86IG51bWJlciB9ID0ge30pOiBEdXJhYmxlRXZlbnRCdXMgfCBudWxsIHtcbiAgY29uc3QgaW5zdCA9IGNyZWF0ZUVudlJlZGlzQ2xpZW50PFJlZGlzU3RyZWFtQ2xpZW50PignZXZlbnQtYnVzJyk7XG4gIGlmICghaW5zdCkgcmV0dXJuIG51bGw7XG4gIGxvZ2dlci5pbmZvKCdSZWRpcyBkdXJhYmxlIGV2ZW50IGJ1cyBpbml0aWFsaXplZCcpO1xuICByZXR1cm4gY3JlYXRlUmVkaXNEdXJhYmxlRXZlbnRCdXMoaW5zdCwgb3B0cyk7XG59XG4iXX0=
|
|
@@ -94,3 +94,30 @@ export interface ReadyAwareRedis {
|
|
|
94
94
|
* (e.g. a test double) counts as ready.
|
|
95
95
|
*/
|
|
96
96
|
export declare function whenRedisReady(client: ReadyAwareRedis, timeoutMs?: number): Promise<void>;
|
|
97
|
+
/** Default bound for {@link createRedisReadyGate}: short enough for a request path. */
|
|
98
|
+
export declare const REQUEST_PATH_REDIS_READY_TIMEOUT_MS = 2000;
|
|
99
|
+
/**
|
|
100
|
+
* A request-path readiness gate for a lazily built env Redis client.
|
|
101
|
+
*
|
|
102
|
+
* The env client has no offline queue, so a command issued before the first
|
|
103
|
+
* connection completes is rejected outright — the first request after a lazy
|
|
104
|
+
* construction would otherwise hit that rejection (e.g. the first step-up per
|
|
105
|
+
* pod failing, or the first impersonation check reading "unavailable").
|
|
106
|
+
*
|
|
107
|
+
* The returned function resolves once the client is ready, or after
|
|
108
|
+
* `timeoutMs` — it NEVER rejects: the caller then runs its command and keeps its
|
|
109
|
+
* own fail-open / fail-closed semantics. Concurrent callers share one wait. After
|
|
110
|
+
* a wait times out (Redis genuinely down) later calls stop waiting until the
|
|
111
|
+
* client reports `ready` again, so an outage costs one bounded wait instead of
|
|
112
|
+
* adding `timeoutMs` to every request.
|
|
113
|
+
*/
|
|
114
|
+
export declare function createRedisReadyGate(client: ReadyAwareRedis, timeoutMs?: number): () => Promise<void>;
|
|
115
|
+
/** The subset of ioredis needed by {@link incrWindow}. */
|
|
116
|
+
export interface RedisEvalClient {
|
|
117
|
+
eval(script: string, numKeys: number, ...args: (string | number)[]): Promise<unknown>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Increment `key` within a window of `windowMs` and return the new count.
|
|
121
|
+
* Throws when Redis errors — callers choose their own failure policy.
|
|
122
|
+
*/
|
|
123
|
+
export declare function incrWindow(redis: RedisEvalClient, key: string, windowMs: number): Promise<number>;
|