@blokjs/trigger-worker 0.4.0 → 0.6.2
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/__tests__/integration/nats-adapter.real-nats.test.ts +116 -0
- package/__tests__/integration/pgboss-adapter.real-pg.test.ts +164 -0
- package/__tests__/integration/rabbitmq-adapter.real-rabbitmq.test.ts +179 -0
- package/__tests__/integration/sqs-adapter.real-sqs.test.ts +228 -0
- package/dist/WorkerTrigger.d.ts +37 -1
- package/dist/WorkerTrigger.js +142 -21
- package/dist/adapters/InMemoryAdapter.js +10 -5
- package/dist/adapters/KafkaAdapter.d.ts +62 -0
- package/dist/adapters/KafkaAdapter.js +236 -0
- package/dist/adapters/NATSAdapter.js +3 -3
- package/dist/adapters/PgBossAdapter.d.ts +56 -0
- package/dist/adapters/PgBossAdapter.js +251 -0
- package/dist/adapters/RabbitMQAdapter.d.ts +51 -0
- package/dist/adapters/RabbitMQAdapter.js +241 -0
- package/dist/adapters/RedisStreamsAdapter.d.ts +64 -0
- package/dist/adapters/RedisStreamsAdapter.js +240 -0
- package/dist/adapters/SQSAdapter.d.ts +61 -0
- package/dist/adapters/SQSAdapter.js +269 -0
- package/dist/adapters/factory.d.ts +34 -0
- package/dist/adapters/factory.js +103 -0
- package/dist/index.d.ts +21 -4
- package/dist/index.js +24 -4
- package/package.json +23 -5
- package/src/WorkerTrigger.ts +153 -22
- package/src/adapters/InMemoryAdapter.ts +9 -5
- package/src/adapters/KafkaAdapter.ts +277 -0
- package/src/adapters/NATSAdapter.ts +4 -2
- package/src/adapters/PgBossAdapter.ts +293 -0
- package/src/adapters/RabbitMQAdapter.ts +285 -0
- package/src/adapters/RedisStreamsAdapter.ts +286 -0
- package/src/adapters/SQSAdapter.ts +306 -0
- package/src/adapters/factory.test.ts +89 -0
- package/src/adapters/factory.ts +111 -0
- package/src/adapters/new-adapters.test.ts +130 -0
- package/src/index.ts +30 -4
- package/template/package.json +6 -6
- package/template/src/workflows/jobs/process-job.ts +37 -35
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQSAdapter — v0.7 PR 5 — Worker adapter backed by AWS SQS via
|
|
3
|
+
* `@aws-sdk/client-sqs`. Polls a queue URL (the `queue` field) with
|
|
4
|
+
* long-polling; processes messages with manual delete (ACK).
|
|
5
|
+
*
|
|
6
|
+
* Semantics:
|
|
7
|
+
* - **Long polling**: `WaitTimeSeconds=20` by default — minimises
|
|
8
|
+
* poll cost. `concurrency` controls how many parallel
|
|
9
|
+
* `ReceiveMessage` loops run.
|
|
10
|
+
* - **Visibility timeout**: configured via `timeout` (ms → s).
|
|
11
|
+
* Messages reappear after this if the worker doesn't delete them.
|
|
12
|
+
* - **Retries**: SQS handles retries automatically via redrive
|
|
13
|
+
* policy on the queue itself. The adapter doesn't simulate
|
|
14
|
+
* retries client-side — set `MaxReceiveCount` on the queue's
|
|
15
|
+
* redrive policy and a DLQ via `deadLetterQueue`.
|
|
16
|
+
* - **FIFO support**: when the queue URL ends with `.fifo`, the
|
|
17
|
+
* adapter passes `MessageGroupId` from `dedupId` or a default.
|
|
18
|
+
*
|
|
19
|
+
* Requires `@aws-sdk/client-sqs` as a peer dependency:
|
|
20
|
+
*
|
|
21
|
+
* bun add @aws-sdk/client-sqs
|
|
22
|
+
*
|
|
23
|
+
* Environment variables (standard AWS SDK):
|
|
24
|
+
* - `AWS_REGION` — default `us-east-1`.
|
|
25
|
+
* - `AWS_ACCESS_KEY_ID` — credentials (or use a profile).
|
|
26
|
+
* - `AWS_SECRET_ACCESS_KEY`
|
|
27
|
+
* - `SQS_ENDPOINT_URL` — for local SQS (LocalStack / ElasticMQ).
|
|
28
|
+
*/
|
|
29
|
+
import type { WorkerTriggerOpts } from "@blokjs/helper";
|
|
30
|
+
import type { WorkerAdapter, WorkerJob, WorkerQueueStats } from "../WorkerTrigger";
|
|
31
|
+
export interface SQSConfig {
|
|
32
|
+
region: string;
|
|
33
|
+
endpoint?: string;
|
|
34
|
+
waitTimeSeconds: number;
|
|
35
|
+
maxNumberOfMessages: number;
|
|
36
|
+
}
|
|
37
|
+
export declare class SQSAdapter implements WorkerAdapter {
|
|
38
|
+
readonly provider: "sqs";
|
|
39
|
+
private readonly config;
|
|
40
|
+
private client;
|
|
41
|
+
private commands;
|
|
42
|
+
private runners;
|
|
43
|
+
private connected;
|
|
44
|
+
private stats;
|
|
45
|
+
constructor(config?: Partial<SQSConfig>);
|
|
46
|
+
connect(): Promise<void>;
|
|
47
|
+
disconnect(): Promise<void>;
|
|
48
|
+
process(config: WorkerTriggerOpts, handler: (job: WorkerJob) => Promise<void>): Promise<void>;
|
|
49
|
+
private runConsumerLoop;
|
|
50
|
+
addJob(queue: string, data: unknown, opts?: {
|
|
51
|
+
priority?: number;
|
|
52
|
+
delay?: number;
|
|
53
|
+
retries?: number;
|
|
54
|
+
timeout?: number;
|
|
55
|
+
jobId?: string;
|
|
56
|
+
}): Promise<string>;
|
|
57
|
+
stopProcessing(queue: string): Promise<void>;
|
|
58
|
+
isConnected(): boolean;
|
|
59
|
+
healthCheck(): Promise<boolean>;
|
|
60
|
+
getQueueStats(queue: string): Promise<WorkerQueueStats>;
|
|
61
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQSAdapter — v0.7 PR 5 — Worker adapter backed by AWS SQS via
|
|
3
|
+
* `@aws-sdk/client-sqs`. Polls a queue URL (the `queue` field) with
|
|
4
|
+
* long-polling; processes messages with manual delete (ACK).
|
|
5
|
+
*
|
|
6
|
+
* Semantics:
|
|
7
|
+
* - **Long polling**: `WaitTimeSeconds=20` by default — minimises
|
|
8
|
+
* poll cost. `concurrency` controls how many parallel
|
|
9
|
+
* `ReceiveMessage` loops run.
|
|
10
|
+
* - **Visibility timeout**: configured via `timeout` (ms → s).
|
|
11
|
+
* Messages reappear after this if the worker doesn't delete them.
|
|
12
|
+
* - **Retries**: SQS handles retries automatically via redrive
|
|
13
|
+
* policy on the queue itself. The adapter doesn't simulate
|
|
14
|
+
* retries client-side — set `MaxReceiveCount` on the queue's
|
|
15
|
+
* redrive policy and a DLQ via `deadLetterQueue`.
|
|
16
|
+
* - **FIFO support**: when the queue URL ends with `.fifo`, the
|
|
17
|
+
* adapter passes `MessageGroupId` from `dedupId` or a default.
|
|
18
|
+
*
|
|
19
|
+
* Requires `@aws-sdk/client-sqs` as a peer dependency:
|
|
20
|
+
*
|
|
21
|
+
* bun add @aws-sdk/client-sqs
|
|
22
|
+
*
|
|
23
|
+
* Environment variables (standard AWS SDK):
|
|
24
|
+
* - `AWS_REGION` — default `us-east-1`.
|
|
25
|
+
* - `AWS_ACCESS_KEY_ID` — credentials (or use a profile).
|
|
26
|
+
* - `AWS_SECRET_ACCESS_KEY`
|
|
27
|
+
* - `SQS_ENDPOINT_URL` — for local SQS (LocalStack / ElasticMQ).
|
|
28
|
+
*/
|
|
29
|
+
import { v4 as uuid } from "uuid";
|
|
30
|
+
export class SQSAdapter {
|
|
31
|
+
provider = "sqs";
|
|
32
|
+
config;
|
|
33
|
+
// biome-ignore lint/suspicious/noExplicitAny: @aws-sdk/client-sqs client + command types are loose.
|
|
34
|
+
client = null;
|
|
35
|
+
// biome-ignore lint/suspicious/noExplicitAny: same as above.
|
|
36
|
+
commands = null;
|
|
37
|
+
runners = new Map();
|
|
38
|
+
connected = false;
|
|
39
|
+
stats = new Map();
|
|
40
|
+
constructor(config) {
|
|
41
|
+
this.config = {
|
|
42
|
+
region: config?.region ?? process.env.AWS_REGION ?? "us-east-1",
|
|
43
|
+
endpoint: config?.endpoint ?? process.env.SQS_ENDPOINT_URL,
|
|
44
|
+
waitTimeSeconds: config?.waitTimeSeconds ?? 20,
|
|
45
|
+
maxNumberOfMessages: config?.maxNumberOfMessages ?? 10,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async connect() {
|
|
49
|
+
if (this.connected)
|
|
50
|
+
return;
|
|
51
|
+
try {
|
|
52
|
+
// biome-ignore lint/suspicious/noExplicitAny: peer dep
|
|
53
|
+
const sdk = await import("@aws-sdk/client-sqs");
|
|
54
|
+
this.client = new sdk.SQSClient({ region: this.config.region, endpoint: this.config.endpoint });
|
|
55
|
+
this.commands = sdk;
|
|
56
|
+
this.connected = true;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
throw new Error(`[blok][sqs] connect failed: ${err.message}. Install @aws-sdk/client-sqs as a peer dependency: bun add @aws-sdk/client-sqs`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async disconnect() {
|
|
63
|
+
if (!this.connected)
|
|
64
|
+
return;
|
|
65
|
+
for (const runner of this.runners.values())
|
|
66
|
+
runner.stop = true;
|
|
67
|
+
// Wait for in-flight loops to drain — up to 500ms each.
|
|
68
|
+
const drainDeadline = Date.now() + 2000;
|
|
69
|
+
while (Date.now() < drainDeadline) {
|
|
70
|
+
let active = 0;
|
|
71
|
+
for (const r of this.runners.values())
|
|
72
|
+
active += r.loops;
|
|
73
|
+
if (active === 0)
|
|
74
|
+
break;
|
|
75
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
76
|
+
}
|
|
77
|
+
this.runners.clear();
|
|
78
|
+
try {
|
|
79
|
+
this.client?.destroy?.();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
/* ignore */
|
|
83
|
+
}
|
|
84
|
+
this.client = null;
|
|
85
|
+
this.connected = false;
|
|
86
|
+
}
|
|
87
|
+
async process(config, handler) {
|
|
88
|
+
if (!this.connected)
|
|
89
|
+
throw new Error("[blok][sqs] not connected. Call connect() first.");
|
|
90
|
+
const runner = { stop: false, loops: 0 };
|
|
91
|
+
this.runners.set(config.queue, runner);
|
|
92
|
+
this.stats.set(config.queue, { completed: 0, failed: 0, active: 0 });
|
|
93
|
+
const stats = this.stats.get(config.queue);
|
|
94
|
+
const concurrency = Math.max(1, config.concurrency ?? 1);
|
|
95
|
+
for (let i = 0; i < concurrency; i += 1) {
|
|
96
|
+
void this.runConsumerLoop(config, handler, runner, stats);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async runConsumerLoop(config, handler, runner, stats) {
|
|
100
|
+
runner.loops += 1;
|
|
101
|
+
try {
|
|
102
|
+
while (!runner.stop) {
|
|
103
|
+
let response = {};
|
|
104
|
+
try {
|
|
105
|
+
response = await this.client.send(new this.commands.ReceiveMessageCommand({
|
|
106
|
+
QueueUrl: config.queue,
|
|
107
|
+
MaxNumberOfMessages: Math.min(10, this.config.maxNumberOfMessages),
|
|
108
|
+
WaitTimeSeconds: this.config.waitTimeSeconds,
|
|
109
|
+
VisibilityTimeout: typeof config.timeout === "number" ? Math.ceil(config.timeout / 1000) : 30,
|
|
110
|
+
AttributeNames: ["All"],
|
|
111
|
+
MessageAttributeNames: ["All"],
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
// Transient — back off briefly then retry.
|
|
116
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const messages = response.Messages ?? [];
|
|
120
|
+
for (const m of messages) {
|
|
121
|
+
if (runner.stop)
|
|
122
|
+
break;
|
|
123
|
+
stats.active += 1;
|
|
124
|
+
// Tracks whether the message has already been settled via
|
|
125
|
+
// the WorkerJob API (`complete` / `fail`). Declared OUTSIDE
|
|
126
|
+
// the try so the catch arm can read it and skip its own
|
|
127
|
+
// nack/fail bookkeeping when the handler explicitly
|
|
128
|
+
// settled. Without this flag we'd double-delete the
|
|
129
|
+
// receipt handle AND a `fail()` call would be silently
|
|
130
|
+
// overruled by the wrapper deleting the message anyway.
|
|
131
|
+
// Caught by the real-broker integration test in
|
|
132
|
+
// `__tests__/integration/sqs-adapter.real-sqs.test.ts`.
|
|
133
|
+
let settled = false;
|
|
134
|
+
try {
|
|
135
|
+
const payloadString = m.Body ?? "";
|
|
136
|
+
let data;
|
|
137
|
+
try {
|
|
138
|
+
data = payloadString.length > 0 ? JSON.parse(payloadString) : null;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
data = payloadString;
|
|
142
|
+
}
|
|
143
|
+
const headers = {};
|
|
144
|
+
for (const [k, v] of Object.entries(m.MessageAttributes ?? {})) {
|
|
145
|
+
if (typeof v.StringValue === "string")
|
|
146
|
+
headers[k] = v.StringValue;
|
|
147
|
+
}
|
|
148
|
+
const job = {
|
|
149
|
+
id: m.MessageId ?? `${config.queue}:${uuid()}`,
|
|
150
|
+
data,
|
|
151
|
+
headers,
|
|
152
|
+
queue: config.queue,
|
|
153
|
+
priority: config.priority ?? 0,
|
|
154
|
+
attempts: Number.parseInt(m.Attributes?.ApproximateReceiveCount ?? "1", 10) - 1,
|
|
155
|
+
maxRetries: config.retries ?? 0,
|
|
156
|
+
createdAt: new Date(),
|
|
157
|
+
timeout: config.timeout,
|
|
158
|
+
raw: m,
|
|
159
|
+
complete: async () => {
|
|
160
|
+
if (settled)
|
|
161
|
+
return;
|
|
162
|
+
if (m.ReceiptHandle) {
|
|
163
|
+
await this.client.send(new this.commands.DeleteMessageCommand({
|
|
164
|
+
QueueUrl: config.queue,
|
|
165
|
+
ReceiptHandle: m.ReceiptHandle,
|
|
166
|
+
}));
|
|
167
|
+
}
|
|
168
|
+
stats.completed += 1;
|
|
169
|
+
settled = true;
|
|
170
|
+
},
|
|
171
|
+
fail: async (_err) => {
|
|
172
|
+
if (settled)
|
|
173
|
+
return;
|
|
174
|
+
stats.failed += 1;
|
|
175
|
+
// No DeleteMessage call — visibility timeout
|
|
176
|
+
// expires and SQS returns the message to the
|
|
177
|
+
// queue automatically. DLQ takeover happens via
|
|
178
|
+
// the queue's RedrivePolicy + MaxReceiveCount.
|
|
179
|
+
settled = true;
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
await handler(job);
|
|
183
|
+
if (!settled && config.ack !== false && m.ReceiptHandle) {
|
|
184
|
+
await this.client.send(new this.commands.DeleteMessageCommand({ QueueUrl: config.queue, ReceiptHandle: m.ReceiptHandle }));
|
|
185
|
+
stats.completed += 1;
|
|
186
|
+
settled = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
if (!settled) {
|
|
191
|
+
stats.failed += 1;
|
|
192
|
+
// Leave the message in flight — SQS visibility
|
|
193
|
+
// timeout expiry returns it to the queue.
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
finally {
|
|
197
|
+
stats.active = Math.max(0, stats.active - 1);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
runner.loops -= 1;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async addJob(queue, data, opts) {
|
|
207
|
+
if (!this.connected)
|
|
208
|
+
throw new Error("[blok][sqs] not connected. Call connect() first.");
|
|
209
|
+
const messageId = opts?.jobId ?? uuid();
|
|
210
|
+
const isFifo = queue.endsWith(".fifo");
|
|
211
|
+
const params = {
|
|
212
|
+
QueueUrl: queue,
|
|
213
|
+
MessageBody: typeof data === "string" ? data : JSON.stringify(data),
|
|
214
|
+
};
|
|
215
|
+
if (isFifo) {
|
|
216
|
+
params.MessageGroupId = opts?.jobId ?? "default";
|
|
217
|
+
params.MessageDeduplicationId = messageId;
|
|
218
|
+
}
|
|
219
|
+
if (typeof opts?.delay === "number" && opts.delay > 0) {
|
|
220
|
+
params.DelaySeconds = Math.min(900, Math.ceil(opts.delay / 1000));
|
|
221
|
+
}
|
|
222
|
+
const result = await this.client.send(new this.commands.SendMessageCommand(params));
|
|
223
|
+
return result.MessageId ?? messageId;
|
|
224
|
+
}
|
|
225
|
+
async stopProcessing(queue) {
|
|
226
|
+
const runner = this.runners.get(queue);
|
|
227
|
+
if (runner)
|
|
228
|
+
runner.stop = true;
|
|
229
|
+
}
|
|
230
|
+
isConnected() {
|
|
231
|
+
return this.connected;
|
|
232
|
+
}
|
|
233
|
+
async healthCheck() {
|
|
234
|
+
if (!this.connected)
|
|
235
|
+
return false;
|
|
236
|
+
try {
|
|
237
|
+
// ListQueues is a cheap permission probe.
|
|
238
|
+
await this.client.send(new this.commands.ListQueuesCommand({ MaxResults: 1 }));
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async getQueueStats(queue) {
|
|
246
|
+
const counters = this.stats.get(queue) ?? { completed: 0, failed: 0, active: 0 };
|
|
247
|
+
let waiting = 0;
|
|
248
|
+
let delayed = 0;
|
|
249
|
+
try {
|
|
250
|
+
const result = await this.client.send(new this.commands.GetQueueAttributesCommand({
|
|
251
|
+
QueueUrl: queue,
|
|
252
|
+
AttributeNames: ["ApproximateNumberOfMessages", "ApproximateNumberOfMessagesDelayed"],
|
|
253
|
+
}));
|
|
254
|
+
waiting = Number.parseInt(result.Attributes?.ApproximateNumberOfMessages ?? "0", 10);
|
|
255
|
+
delayed = Number.parseInt(result.Attributes?.ApproximateNumberOfMessagesDelayed ?? "0", 10);
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
/* ignore */
|
|
259
|
+
}
|
|
260
|
+
return {
|
|
261
|
+
waiting,
|
|
262
|
+
active: counters.active,
|
|
263
|
+
completed: counters.completed,
|
|
264
|
+
failed: counters.failed,
|
|
265
|
+
delayed,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU1FTQWRhcHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVycy9TUVNBZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyQkc7QUFHSCxPQUFPLEVBQUUsRUFBRSxJQUFJLElBQUksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQTZCbEMsTUFBTSxPQUFPLFVBQVU7SUFDYixRQUFRLEdBQUcsS0FBYyxDQUFDO0lBQ2xCLE1BQU0sQ0FBWTtJQUNuQyxvR0FBb0c7SUFDNUYsTUFBTSxHQUFRLElBQUksQ0FBQztJQUMzQiw2REFBNkQ7SUFDckQsUUFBUSxHQUFRLElBQUksQ0FBQztJQUNyQixPQUFPLEdBQTZCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDOUMsU0FBUyxHQUFHLEtBQUssQ0FBQztJQUNsQixLQUFLLEdBQW9DLElBQUksR0FBRyxFQUFFLENBQUM7SUFFM0QsWUFBWSxNQUEyQjtRQUN0QyxJQUFJLENBQUMsTUFBTSxHQUFHO1lBQ2IsTUFBTSxFQUFFLE1BQU0sRUFBRSxNQUFNLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLElBQUksV0FBVztZQUMvRCxRQUFRLEVBQUUsTUFBTSxFQUFFLFFBQVEsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQjtZQUMxRCxlQUFlLEVBQUUsTUFBTSxFQUFFLGVBQWUsSUFBSSxFQUFFO1lBQzlDLG1CQUFtQixFQUFFLE1BQU0sRUFBRSxtQkFBbUIsSUFBSSxFQUFFO1NBQ3RELENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLE9BQU87UUFDWixJQUFJLElBQUksQ0FBQyxTQUFTO1lBQUUsT0FBTztRQUMzQixJQUFJLENBQUM7WUFDSix1REFBdUQ7WUFDdkQsTUFBTSxHQUFHLEdBQVEsTUFBTSxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztZQUNyRCxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUks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O1FBQzdGLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUixZQUFZO1FBQ2IsQ0FBQztRQUNELE9BQU87WUFDTixPQUFPO1lBQ1AsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNO1lBQ3ZCLFNBQVMsRUFBRSxRQUFRLENBQUMsU0FBUztZQUM3QixNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU07WUFDdkIsT0FBTztTQUNQLENBQUM7SUFDSCxDQUFDO0NBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNRU0FkYXB0ZXIg4oCUIHYwLjcgUFIgNSDigJQgV29ya2VyIGFkYXB0ZXIgYmFja2VkIGJ5IEFXUyBTUVMgdmlhXG4gKiBgQGF3cy1zZGsvY2xpZW50LXNxc2AuIFBvbGxzIGEgcXVldWUgVVJMICh0aGUgYHF1ZXVlYCBmaWVsZCkgd2l0aFxuICogbG9uZy1wb2xsaW5nOyBwcm9jZXNzZXMgbWVzc2FnZXMgd2l0aCBtYW51YWwgZGVsZXRlIChBQ0spLlxuICpcbiAqIFNlbWFudGljczpcbiAqICAgLSAqKkxvbmcgcG9sbGluZyoqOiBgV2FpdFRpbWVTZWNvbmRzPTIwYCBieSBkZWZhdWx0IOKAlCBtaW5pbWlzZXNcbiAqICAgICBwb2xsIGNvc3QuIGBjb25jdXJyZW5jeWAgY29udHJvbHMgaG93IG1hbnkgcGFyYWxsZWxcbiAqICAgICBgUmVjZWl2ZU1lc3NhZ2VgIGxvb3BzIHJ1bi5cbiAqICAgLSAqKlZpc2liaWxpdHkgdGltZW91dCoqOiBjb25maWd1cmVkIHZpYSBgdGltZW91dGAgKG1zIOKGkiBzKS5cbiAqICAgICBNZXNzYWdlcyByZWFwcGVhciBhZnRlciB0aGlzIGlmIHRoZSB3b3JrZXIgZG9lc24ndCBkZWxldGUgdGhlbS5cbiAqICAgLSAqKlJldHJpZXMqKjogU1FTIGhhbmRsZXMgcmV0cmllcyBhdXRvbWF0aWNhbGx5IHZpYSByZWRyaXZlXG4gKiAgICAgcG9saWN5IG9uIHRoZSBxdWV1ZSBpdHNlbGYuIFRoZSBhZGFwdGVyIGRvZXNuJ3Qgc2ltdWxhdGVcbiAqICAgICByZXRyaWVzIGNsaWVudC1zaWRlIOKAlCBzZXQgYE1heFJlY2VpdmVDb3VudGAgb24gdGhlIHF1ZXVlJ3NcbiAqICAgICByZWRyaXZlIHBvbGljeSBhbmQgYSBETFEgdmlhIGBkZWFkTGV0dGVyUXVldWVgLlxuICogICAtICoqRklGTyBzdXBwb3J0Kio6IHdoZW4gdGhlIHF1ZXVlIFVSTCBlbmRzIHdpdGggYC5maWZvYCwgdGhlXG4gKiAgICAgYWRhcHRlciBwYXNzZXMgYE1lc3NhZ2VHcm91cElkYCBmcm9tIGBkZWR1cElkYCBvciBhIGRlZmF1bHQuXG4gKlxuICogUmVxdWlyZXMgYEBhd3Mtc2RrL2NsaWVudC1zcXNgIGFzIGEgcGVlciBkZXBlbmRlbmN5OlxuICpcbiAqICAgICBidW4gYWRkIEBhd3Mtc2RrL2NsaWVudC1zcXNcbiAqXG4gKiBFbnZpcm9ubWVudCB2YXJpYWJsZXMgKHN0YW5kYXJkIEFXUyBTREspOlxuICogICAtIGBBV1NfUkVHSU9OYCAgICAgICAgICAgICAg4oCUIGRlZmF1bHQgYHVzLWVhc3QtMWAuXG4gKiAgIC0gYEFXU19BQ0NFU1NfS0VZX0lEYCAgICAgICDigJQgY3JlZGVudGlhbHMgKG9yIHVzZSBhIHByb2ZpbGUpLlxuICogICAtIGBBV1NfU0VDUkVUX0FDQ0VTU19LRVlgXG4gKiAgIC0gYFNRU19FTkRQT0lOVF9VUkxgICAgICAgICDigJQgZm9yIGxvY2FsIFNRUyAoTG9jYWxTdGFjayAvIEVsYXN0aWNNUSkuXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBXb3JrZXJUcmlnZ2VyT3B0cyB9IGZyb20gXCJAYmxva2pzL2hlbHBlclwiO1xuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gXCJ1dWlkXCI7XG5pbXBvcnQgdHlwZSB7IFdvcmtlckFkYXB0ZXIsIFdvcmtlckpvYiwgV29ya2VyUXVldWVTdGF0cyB9IGZyb20gXCIuLi9Xb3JrZXJUcmlnZ2VyXCI7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU1FTQ29uZmlnIHtcblx0cmVnaW9uOiBzdHJpbmc7XG5cdGVuZHBvaW50Pzogc3RyaW5nO1xuXHR3YWl0VGltZVNlY29uZHM6IG51bWJlcjtcblx0bWF4TnVtYmVyT2ZNZXNzYWdlczogbnVtYmVyO1xufVxuXG5pbnRlcmZhY2UgU3FzTWVzc2FnZSB7XG5cdE1lc3NhZ2VJZD86IHN0cmluZztcblx0UmVjZWlwdEhhbmRsZT86IHN0cmluZztcblx0Qm9keT86IHN0cmluZztcblx0QXR0cmlidXRlcz86IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG5cdE1lc3NhZ2VBdHRyaWJ1dGVzPzogUmVjb3JkPHN0cmluZywgeyBTdHJpbmdWYWx1ZT86IHN0cmluZyB9Pjtcbn1cblxuaW50ZXJmYWNlIFF1ZXVlUnVubmVyIHtcblx0c3RvcDogYm9vbGVhbjtcblx0bG9vcHM6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFF1ZXVlU3RhdHNDb3VudGVycyB7XG5cdGNvbXBsZXRlZDogbnVtYmVyO1xuXHRmYWlsZWQ6IG51bWJlcjtcblx0YWN0aXZlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBTUVNBZGFwdGVyIGltcGxlbWVudHMgV29ya2VyQWRhcHRlciB7XG5cdHJlYWRvbmx5IHByb3ZpZGVyID0gXCJzcXNcIiBhcyBjb25zdDtcblx0cHJpdmF0ZSByZWFkb25seSBjb25maWc6IFNRU0NvbmZpZztcblx0Ly8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub0V4cGxpY2l0QW55OiBAYXdzLXNkay9jbGllbnQtc3FzIGNsaWVudCArIGNvbW1hbmQgdHlwZXMgYXJlIGxvb3NlLlxuXHRwcml2YXRlIGNsaWVudDogYW55ID0gbnVsbDtcblx0Ly8gYmlvbWUtaWdub3JlIGxpbnQvc3VzcGljaW91cy9ub0V4cGxpY2l0QW55OiBzYW1lIGFzIGFib3ZlLlxuXHRwcml2YXRlIGNvbW1hbmRzOiBhbnkgPSBudWxsO1xuXHRwcml2YXRlIHJ1bm5lcnM6IE1hcDxzdHJpbmcsIFF1ZXVlUnVubmVyPiA9IG5ldyBNYXAoKTtcblx0cHJpdmF0ZSBjb25uZWN0ZWQgPSBmYWxzZTtcblx0cHJpdmF0ZSBzdGF0czogTWFwPHN0cmluZywgUXVldWVTdGF0c0NvdW50ZXJzPiA9IG5ldyBNYXAoKTtcblxuXHRjb25zdHJ1Y3Rvcihjb25maWc/OiBQYXJ0aWFsPFNRU0NvbmZpZz4pIHtcblx0XHR0aGlzLmNvbmZpZyA9IHtcblx0XHRcdHJlZ2lvbjogY29uZmlnPy5yZWdpb24gPz8gcHJvY2Vzcy5lbnYuQVdTX1JFR0lPTiA/PyBcInVzLWVhc3QtMVwiLFxuXHRcdFx0ZW5kcG9pbnQ6IGNvbmZpZz8uZW5kcG9pbnQgPz8gcHJvY2Vzcy5lbnYuU1FTX0VORFBPSU5UX1VSTCxcblx0XHRcdHdhaXRUaW1lU2Vjb25kczogY29uZmlnPy53YWl0VGltZVNlY29uZHMgPz8gMjAsXG5cdFx0XHRtYXhOdW1iZXJPZk1lc3NhZ2VzOiBjb25maWc/Lm1heE51bWJlck9mTWVzc2FnZXMgPz8gMTAsXG5cdFx0fTtcblx0fVxuXG5cdGFzeW5jIGNvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0aWYgKHRoaXMuY29ubmVjdGVkKSByZXR1cm47XG5cdFx0dHJ5IHtcblx0XHRcdC8vIGJpb21lLWlnbm9yZSBsaW50L3N1c3BpY2lvdXMvbm9FeHBsaWNpdEFueTogcGVlciBkZXBcblx0XHRcdGNvbnN0IHNkazogYW55ID0gYXdhaXQgaW1wb3J0KFwiQGF3cy1zZGsvY2xpZW50LXNxc1wiKTtcblx0XHRcdHRoaXMuY2xpZW50ID0gbmV3IHNkay5TUVNDbGllbnQoeyByZWdpb246IHRoaXMuY29uZmlnLnJlZ2lvbiwgZW5kcG9pbnQ6IHRoaXMuY29uZmlnLmVuZHBvaW50IH0pO1xuXHRcdFx0dGhpcy5jb21tYW5kcyA9IHNkaztcblx0XHRcdHRoaXMuY29ubmVjdGVkID0gdHJ1ZTtcblx0XHR9IGNhdGNoIChlcnIpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcihcblx0XHRcdFx0YFtibG9rXVtzcXNdIGNvbm5lY3QgZmFpbGVkOiAkeyhlcnIgYXMgRXJyb3IpLm1lc3NhZ2V9LiBJbnN0YWxsIEBhd3Mtc2RrL2NsaWVudC1zcXMgYXMgYSBwZWVyIGRlcGVuZGVuY3k6IGJ1biBhZGQgQGF3cy1zZGsvY2xpZW50LXNxc2AsXG5cdFx0XHQpO1xuXHRcdH1cblx0fVxuXG5cdGFzeW5jIGRpc2Nvbm5lY3QoKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0aWYgKCF0aGlzLmNvbm5lY3RlZCkgcmV0dXJuO1xuXHRcdGZvciAoY29uc3QgcnVubmVyIG9mIHRoaXMucnVubmVycy52YWx1ZXMoKSkgcnVubmVyLnN0b3AgPSB0cnVlO1xuXHRcdC8vIFdhaXQgZm9yIGluLWZsaWdodCBsb29wcyB0byBkcmFpbiDigJQgdXAgdG8gNTAwbXMgZWFjaC5cblx0XHRjb25zdCBkcmFpbkRlYWRsaW5lID0gRGF0ZS5ub3coKSArIDIwMDA7XG5cdFx0d2hpbGUgKERhdGUubm93KCkgPCBkcmFpbkRlYWRsaW5lKSB7XG5cdFx0XHRsZXQgYWN0aXZlID0gMDtcblx0XHRcdGZvciAoY29uc3QgciBvZiB0aGlzLnJ1bm5lcnMudmFsdWVzKCkpIGFjdGl2ZSArPSByLmxvb3BzO1xuXHRcdFx0aWYgKGFjdGl2ZSA9PT0gMCkgYnJlYWs7XG5cdFx0XHRhd2FpdCBuZXcgUHJvbWlzZSgocikgPT4gc2V0VGltZW91dChyLCA1MCkpO1xuXHRcdH1cblx0XHR0aGlzLnJ1bm5lcnMuY2xlYXIoKTtcblx0XHR0cnkge1xuXHRcdFx0dGhpcy5jbGllbnQ/LmRlc3Ryb3k/LigpO1xuXHRcdH0gY2F0Y2gge1xuXHRcdFx0LyogaWdub3JlICovXG5cdFx0fVxuXHRcdHRoaXMuY2xpZW50ID0gbnVsbDtcblx0XHR0aGlzLmNvbm5lY3RlZCA9IGZhbHNlO1xuXHR9XG5cblx0YXN5bmMgcHJvY2Vzcyhjb25maWc6IFdvcmtlclRyaWdnZXJPcHRzLCBoYW5kbGVyOiAoam9iOiBXb3JrZXJKb2IpID0+IFByb21pc2U8dm9pZD4pOiBQcm9taXNlPHZvaWQ+IHtcblx0XHRpZiAoIXRoaXMuY29ubmVjdGVkKSB0aHJvdyBuZXcgRXJyb3IoXCJbYmxva11bc3FzXSBub3QgY29ubmVjdGVkLiBDYWxsIGNvbm5lY3QoKSBmaXJzdC5cIik7XG5cdFx0Y29uc3QgcnVubmVyOiBRdWV1ZVJ1bm5lciA9IHsgc3RvcDogZmFsc2UsIGxvb3BzOiAwIH07XG5cdFx0dGhpcy5ydW5uZXJzLnNldChjb25maWcucXVldWUsIHJ1bm5lcik7XG5cdFx0dGhpcy5zdGF0cy5zZXQoY29uZmlnLnF1ZXVlLCB7IGNvbXBsZXRlZDogMCwgZmFpbGVkOiAwLCBhY3RpdmU6IDAgfSk7XG5cdFx0Y29uc3Qgc3RhdHMgPSB0aGlzLnN0YXRzLmdldChjb25maWcucXVldWUpIGFzIFF1ZXVlU3RhdHNDb3VudGVycztcblxuXHRcdGNvbnN0IGNvbmN1cnJlbmN5ID0gTWF0aC5tYXgoMSwgY29uZmlnLmNvbmN1cnJlbmN5ID8/IDEpO1xuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgY29uY3VycmVuY3k7IGkgKz0gMSkge1xuXHRcdFx0dm9pZCB0aGlzLnJ1bkNvbnN1bWVyTG9vcChjb25maWcsIGhhbmRsZXIsIHJ1bm5lciwgc3RhdHMpO1xuXHRcdH1cblx0fVxuXG5cdHByaXZhdGUgYXN5bmMgcnVuQ29uc3VtZXJMb29wKFxuXHRcdGNvbmZpZzogV29ya2VyVHJpZ2dlck9wdHMsXG5cdFx0aGFuZGxlcjogKGpvYjogV29ya2VySm9iKSA9PiBQcm9taXNlPHZvaWQ+LFxuXHRcdHJ1bm5lcjogUXVldWVSdW5uZXIsXG5cdFx0c3RhdHM6IFF1ZXVlU3RhdHNDb3VudGVycyxcblx0KTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0cnVubmVyLmxvb3BzICs9IDE7XG5cdFx0dHJ5IHtcblx0XHRcdHdoaWxlICghcnVubmVyLnN0b3ApIHtcblx0XHRcdFx0bGV0IHJlc3BvbnNlOiB7IE1lc3NhZ2VzPzogU3FzTWVzc2FnZVtdIH0gPSB7fTtcblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRyZXNwb25zZSA9IGF3YWl0IHRoaXMuY2xpZW50LnNlbmQoXG5cdFx0XHRcdFx0XHRuZXcgdGhpcy5jb21tYW5kcy5SZWNlaXZlTWVzc2FnZUNvbW1hbmQoe1xuXHRcdFx0XHRcdFx0XHRRdWV1ZVVybDogY29uZmlnLnF1ZXVlLFxuXHRcdFx0XHRcdFx0XHRNYXhOdW1iZXJPZk1lc3NhZ2VzOiBNYXRoLm1pbigxMCwgdGhpcy5jb25maWcubWF4TnVtYmVyT2ZNZXNzYWdlcyksXG5cdFx0XHRcdFx0XHRcdFdhaXRUaW1lU2Vjb25kczogdGhpcy5jb25maWcud2FpdFRpbWVTZWNvbmRzLFxuXHRcdFx0XHRcdFx0XHRWaXNpYmlsaXR5VGltZW91dDogdHlwZW9mIGNvbmZpZy50aW1lb3V0ID09PSBcIm51bWJlclwiID8gTWF0aC5jZWlsKGNvbmZpZy50aW1lb3V0IC8gMTAwMCkgOiAzMCxcblx0XHRcdFx0XHRcdFx0QXR0cmlidXRlTmFtZXM6IFtcIkFsbFwiXSxcblx0XHRcdFx0XHRcdFx0TWVzc2FnZUF0dHJpYnV0ZU5hbWVzOiBbXCJBbGxcIl0sXG5cdFx0XHRcdFx0XHR9KSxcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9IGNhdGNoIChlcnIpIHtcblx0XHRcdFx0XHQvLyBUcmFuc2llbnQg4oCUIGJhY2sgb2ZmIGJyaWVmbHkgdGhlbiByZXRyeS5cblx0XHRcdFx0XHRhd2FpdCBuZXcgUHJvbWlzZSgocikgPT4gc2V0VGltZW91dChyLCAxMDAwKSk7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y29uc3QgbWVzc2FnZXMgPSByZXNwb25zZS5NZXNzYWdlcyA/PyBbXTtcblx0XHRcdFx0Zm9yIChjb25zdCBtIG9mIG1lc3NhZ2VzKSB7XG5cdFx0XHRcdFx0aWYgKHJ1bm5lci5zdG9wKSBicmVhaztcblx0XHRcdFx0XHRzdGF0cy5hY3RpdmUgKz0gMTtcblx0XHRcdFx0XHQvLyBUcmFja3Mgd2hldGhlciB0aGUgbWVzc2FnZSBoYXMgYWxyZWFkeSBiZWVuIHNldHRsZWQgdmlhXG5cdFx0XHRcdFx0Ly8gdGhlIFdvcmtlckpvYiBBUEkgKGBjb21wbGV0ZWAgLyBgZmFpbGApLiBEZWNsYXJlZCBPVVRTSURFXG5cdFx0XHRcdFx0Ly8gdGhlIHRyeSBzbyB0aGUgY2F0Y2ggYXJtIGNhbiByZWFkIGl0IGFuZCBza2lwIGl0cyBvd25cblx0XHRcdFx0XHQvLyBuYWNrL2ZhaWwgYm9va2tlZXBpbmcgd2hlbiB0aGUgaGFuZGxlciBleHBsaWNpdGx5XG5cdFx0XHRcdFx0Ly8gc2V0dGxlZC4gV2l0aG91dCB0aGlzIGZsYWcgd2UnZCBkb3VibGUtZGVsZXRlIHRoZVxuXHRcdFx0XHRcdC8vIHJlY2VpcHQgaGFuZGxlIEFORCBhIGBmYWlsKClgIGNhbGwgd291bGQgYmUgc2lsZW50bHlcblx0XHRcdFx0XHQvLyBvdmVycnVsZWQgYnkgdGhlIHdyYXBwZXIgZGVsZXRpbmcgdGhlIG1lc3NhZ2UgYW55d2F5LlxuXHRcdFx0XHRcdC8vIENhdWdodCBieSB0aGUgcmVhbC1icm9rZXIgaW50ZWdyYXRpb24gdGVzdCBpblxuXHRcdFx0XHRcdC8vIGBfX3Rlc3RzX18vaW50ZWdyYXRpb24vc3FzLWFkYXB0ZXIucmVhbC1zcXMudGVzdC50c2AuXG5cdFx0XHRcdFx0bGV0IHNldHRsZWQgPSBmYWxzZTtcblx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0Y29uc3QgcGF5bG9hZFN0cmluZyA9IG0uQm9keSA/PyBcIlwiO1xuXHRcdFx0XHRcdFx0bGV0IGRhdGE6IHVua25vd247XG5cdFx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0XHRkYXRhID0gcGF5bG9hZFN0cmluZy5sZW5ndGggPiAwID8gSlNPTi5wYXJzZShwYXlsb2FkU3RyaW5nKSA6IG51bGw7XG5cdFx0XHRcdFx0XHR9IGNhdGNoIHtcblx0XHRcdFx0XHRcdFx0ZGF0YSA9IHBheWxvYWRTdHJpbmc7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG5cdFx0XHRcdFx0XHRmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhtLk1lc3NhZ2VBdHRyaWJ1dGVzID8/IHt9KSkge1xuXHRcdFx0XHRcdFx0XHRpZiAodHlwZW9mIHYuU3RyaW5nVmFsdWUgPT09IFwic3RyaW5nXCIpIGhlYWRlcnNba10gPSB2LlN0cmluZ1ZhbHVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0Y29uc3Qgam9iOiBXb3JrZXJKb2IgPSB7XG5cdFx0XHRcdFx0XHRcdGlkOiBtLk1lc3NhZ2VJZCA/PyBgJHtjb25maWcucXVldWV9OiR7dXVpZCgpfWAsXG5cdFx0XHRcdFx0XHRcdGRhdGEsXG5cdFx0XHRcdFx0XHRcdGhlYWRlcnMsXG5cdFx0XHRcdFx0XHRcdHF1ZXVlOiBjb25maWcucXVldWUsXG5cdFx0XHRcdFx0XHRcdHByaW9yaXR5OiBjb25maWcucHJpb3JpdHkgPz8gMCxcblx0XHRcdFx0XHRcdFx0YXR0ZW1wdHM6IE51bWJlci5wYXJzZUludChtLkF0dHJpYnV0ZXM/LkFwcHJveGltYXRlUmVjZWl2ZUNvdW50ID8/IFwiMVwiLCAxMCkgLSAxLFxuXHRcdFx0XHRcdFx0XHRtYXhSZXRyaWVzOiBjb25maWcucmV0cmllcyA/PyAwLFxuXHRcdFx0XHRcdFx0XHRjcmVhdGVkQXQ6IG5ldyBEYXRlKCksXG5cdFx0XHRcdFx0XHRcdHRpbWVvdXQ6IGNvbmZpZy50aW1lb3V0LFxuXHRcdFx0XHRcdFx0XHRyYXc6IG0sXG5cdFx0XHRcdFx0XHRcdGNvbXBsZXRlOiBhc3luYyAoKSA9PiB7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKHNldHRsZWQpIHJldHVybjtcblx0XHRcdFx0XHRcdFx0XHRpZiAobS5SZWNlaXB0SGFuZGxlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRhd2FpdCB0aGlzLmNsaWVudC5zZW5kKFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRuZXcgdGhpcy5jb21tYW5kcy5EZWxldGVNZXNzYWdlQ29tbWFuZCh7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0UXVldWVVcmw6IGNvbmZpZy5xdWV1ZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRSZWNlaXB0SGFuZGxlOiBtLlJlY2VpcHRIYW5kbGUsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH0pLFxuXHRcdFx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0c3RhdHMuY29tcGxldGVkICs9IDE7XG5cdFx0XHRcdFx0XHRcdFx0c2V0dGxlZCA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRcdGZhaWw6IGFzeW5jIChfZXJyOiBFcnJvcikgPT4ge1xuXHRcdFx0XHRcdFx0XHRcdGlmIChzZXR0bGVkKSByZXR1cm47XG5cdFx0XHRcdFx0XHRcdFx0c3RhdHMuZmFpbGVkICs9IDE7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gTm8gRGVsZXRlTWVzc2FnZSBjYWxsIOKAlCB2aXNpYmlsaXR5IHRpbWVvdXRcblx0XHRcdFx0XHRcdFx0XHQvLyBleHBpcmVzIGFuZCBTUVMgcmV0dXJucyB0aGUgbWVzc2FnZSB0byB0aGVcblx0XHRcdFx0XHRcdFx0XHQvLyBxdWV1ZSBhdXRvbWF0aWNhbGx5LiBETFEgdGFrZW92ZXIgaGFwcGVucyB2aWFcblx0XHRcdFx0XHRcdFx0XHQvLyB0aGUgcXVldWUncyBSZWRyaXZlUG9saWN5ICsgTWF4UmVjZWl2ZUNvdW50LlxuXHRcdFx0XHRcdFx0XHRcdHNldHRsZWQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRcdGF3YWl0IGhhbmRsZXIoam9iKTtcblx0XHRcdFx0XHRcdGlmICghc2V0dGxlZCAmJiBjb25maWcuYWNrICE9PSBmYWxzZSAmJiBtLlJlY2VpcHRIYW5kbGUpIHtcblx0XHRcdFx0XHRcdFx0YXdhaXQgdGhpcy5jbGllbnQuc2VuZChcblx0XHRcdFx0XHRcdFx0XHRuZXcgdGhpcy5jb21tYW5kcy5EZWxldGVNZXNzYWdlQ29tbWFuZCh7IFF1ZXVlVXJsOiBjb25maWcucXVldWUsIFJlY2VpcHRIYW5kbGU6IG0uUmVjZWlwdEhhbmRsZSB9KSxcblx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0c3RhdHMuY29tcGxldGVkICs9IDE7XG5cdFx0XHRcdFx0XHRcdHNldHRsZWQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gY2F0Y2gge1xuXHRcdFx0XHRcdFx0aWYgKCFzZXR0bGVkKSB7XG5cdFx0XHRcdFx0XHRcdHN0YXRzLmZhaWxlZCArPSAxO1xuXHRcdFx0XHRcdFx0XHQvLyBMZWF2ZSB0aGUgbWVzc2FnZSBpbiBmbGlnaHQg4oCUIFNRUyB2aXNpYmlsaXR5XG5cdFx0XHRcdFx0XHRcdC8vIHRpbWVvdXQgZXhwaXJ5IHJldHVybnMgaXQgdG8gdGhlIHF1ZXVlLlxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gZmluYWxseSB7XG5cdFx0XHRcdFx0XHRzdGF0cy5hY3RpdmUgPSBNYXRoLm1heCgwLCBzdGF0cy5hY3RpdmUgLSAxKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9IGZpbmFsbHkge1xuXHRcdFx0cnVubmVyLmxvb3BzIC09IDE7XG5cdFx0fVxuXHR9XG5cblx0YXN5bmMgYWRkSm9iKFxuXHRcdHF1ZXVlOiBzdHJpbmcsXG5cdFx0ZGF0YTogdW5rbm93bixcblx0XHRvcHRzPzogeyBwcmlvcml0eT86IG51bWJlcjsgZGVsYXk/OiBudW1iZXI7IHJldHJpZXM/OiBudW1iZXI7IHRpbWVvdXQ/OiBudW1iZXI7IGpvYklkPzogc3RyaW5nIH0sXG5cdCk6IFByb21pc2U8c3RyaW5nPiB7XG5cdFx0aWYgKCF0aGlzLmNvbm5lY3RlZCkgdGhyb3cgbmV3IEVycm9yKFwiW2Jsb2tdW3Nxc10gbm90IGNvbm5lY3RlZC4gQ2FsbCBjb25uZWN0KCkgZmlyc3QuXCIpO1xuXHRcdGNvbnN0IG1lc3NhZ2VJZCA9IG9wdHM/LmpvYklkID8/IHV1aWQoKTtcblx0XHRjb25zdCBpc0ZpZm8gPSBxdWV1ZS5lbmRzV2l0aChcIi5maWZvXCIpO1xuXHRcdGNvbnN0IHBhcmFtczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7XG5cdFx0XHRRdWV1ZVVybDogcXVldWUsXG5cdFx0XHRNZXNzYWdlQm9keTogdHlwZW9mIGRhdGEgPT09IFwic3RyaW5nXCIgPyBkYXRhIDogSlNPTi5zdHJpbmdpZnkoZGF0YSksXG5cdFx0fTtcblx0XHRpZiAoaXNGaWZvKSB7XG5cdFx0XHRwYXJhbXMuTWVzc2FnZUdyb3VwSWQgPSBvcHRzPy5qb2JJZCA/PyBcImRlZmF1bHRcIjtcblx0XHRcdHBhcmFtcy5NZXNzYWdlRGVkdXBsaWNhdGlvbklkID0gbWVzc2FnZUlkO1xuXHRcdH1cblx0XHRpZiAodHlwZW9mIG9wdHM/LmRlbGF5ID09PSBcIm51bWJlclwiICYmIG9wdHMuZGVsYXkgPiAwKSB7XG5cdFx0XHRwYXJhbXMuRGVsYXlTZWNvbmRzID0gTWF0aC5taW4oOTAwLCBNYXRoLmNlaWwob3B0cy5kZWxheSAvIDEwMDApKTtcblx0XHR9XG5cdFx0Y29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5jbGllbnQuc2VuZChuZXcgdGhpcy5jb21tYW5kcy5TZW5kTWVzc2FnZUNvbW1hbmQocGFyYW1zKSk7XG5cdFx0cmV0dXJuIChyZXN1bHQuTWVzc2FnZUlkIGFzIHN0cmluZykgPz8gbWVzc2FnZUlkO1xuXHR9XG5cblx0YXN5bmMgc3RvcFByb2Nlc3NpbmcocXVldWU6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGNvbnN0IHJ1bm5lciA9IHRoaXMucnVubmVycy5nZXQocXVldWUpO1xuXHRcdGlmIChydW5uZXIpIHJ1bm5lci5zdG9wID0gdHJ1ZTtcblx0fVxuXG5cdGlzQ29ubmVjdGVkKCk6IGJvb2xlYW4ge1xuXHRcdHJldHVybiB0aGlzLmNvbm5lY3RlZDtcblx0fVxuXG5cdGFzeW5jIGhlYWx0aENoZWNrKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuXHRcdGlmICghdGhpcy5jb25uZWN0ZWQpIHJldHVybiBmYWxzZTtcblx0XHR0cnkge1xuXHRcdFx0Ly8gTGlzdFF1ZXVlcyBpcyBhIGNoZWFwIHBlcm1pc3Npb24gcHJvYmUuXG5cdFx0XHRhd2FpdCB0aGlzLmNsaWVudC5zZW5kKG5ldyB0aGlzLmNvbW1hbmRzLkxpc3RRdWV1ZXNDb21tYW5kKHsgTWF4UmVzdWx0czogMSB9KSk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9IGNhdGNoIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdH1cblxuXHRhc3luYyBnZXRRdWV1ZVN0YXRzKHF1ZXVlOiBzdHJpbmcpOiBQcm9taXNlPFdvcmtlclF1ZXVlU3RhdHM+IHtcblx0XHRjb25zdCBjb3VudGVycyA9IHRoaXMuc3RhdHMuZ2V0KHF1ZXVlKSA/PyB7IGNvbXBsZXRlZDogMCwgZmFpbGVkOiAwLCBhY3RpdmU6IDAgfTtcblx0XHRsZXQgd2FpdGluZyA9IDA7XG5cdFx0bGV0IGRlbGF5ZWQgPSAwO1xuXHRcdHRyeSB7XG5cdFx0XHRjb25zdCByZXN1bHQgPSBhd2FpdCB0aGlzLmNsaWVudC5zZW5kKFxuXHRcdFx0XHRuZXcgdGhpcy5jb21tYW5kcy5HZXRRdWV1ZUF0dHJpYnV0ZXNDb21tYW5kKHtcblx0XHRcdFx0XHRRdWV1ZVVybDogcXVldWUsXG5cdFx0XHRcdFx0QXR0cmlidXRlTmFtZXM6IFtcIkFwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc1wiLCBcIkFwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlc0RlbGF5ZWRcIl0sXG5cdFx0XHRcdH0pLFxuXHRcdFx0KTtcblx0XHRcdHdhaXRpbmcgPSBOdW1iZXIucGFyc2VJbnQocmVzdWx0LkF0dHJpYnV0ZXM/LkFwcHJveGltYXRlTnVtYmVyT2ZNZXNzYWdlcyA/PyBcIjBcIiwgMTApO1xuXHRcdFx0ZGVsYXllZCA9IE51bWJlci5wYXJzZUludChyZXN1bHQuQXR0cmlidXRlcz8uQXBwcm94aW1hdGVOdW1iZXJPZk1lc3NhZ2VzRGVsYXllZCA/PyBcIjBcIiwgMTApO1xuXHRcdH0gY2F0Y2gge1xuXHRcdFx0LyogaWdub3JlICovXG5cdFx0fVxuXHRcdHJldHVybiB7XG5cdFx0XHR3YWl0aW5nLFxuXHRcdFx0YWN0aXZlOiBjb3VudGVycy5hY3RpdmUsXG5cdFx0XHRjb21wbGV0ZWQ6IGNvdW50ZXJzLmNvbXBsZXRlZCxcblx0XHRcdGZhaWxlZDogY291bnRlcnMuZmFpbGVkLFxuXHRcdFx0ZGVsYXllZCxcblx0XHR9O1xuXHR9XG59XG4iXX0=
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.7 PR 5 — adapter factory.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a `provider` string to a concrete `WorkerAdapter` instance.
|
|
5
|
+
* Used by the `WorkerTrigger` (to pick the right adapter per workflow
|
|
6
|
+
* based on `trigger.worker.provider`) and by the `@blokjs/worker-publish`
|
|
7
|
+
* helper node (to enqueue jobs from any workflow without bundling all
|
|
8
|
+
* broker clients).
|
|
9
|
+
*
|
|
10
|
+
* Provider resolution order:
|
|
11
|
+
* 1. Explicit `provider` field on the workflow (highest priority).
|
|
12
|
+
* 2. `BLOK_WORKER_ADAPTER` env var (per Q7 resolution in the plan).
|
|
13
|
+
* 3. `"in-memory"` fallback (zero-infra default for dev/tests).
|
|
14
|
+
*
|
|
15
|
+
* Each adapter beyond `in-memory` lazy-imports its broker SDK on first
|
|
16
|
+
* use (BullMQ does this today). Workflows that don't use a given
|
|
17
|
+
* provider don't pay the install or import cost.
|
|
18
|
+
*/
|
|
19
|
+
import type { WorkerProvider } from "@blokjs/helper";
|
|
20
|
+
import type { WorkerAdapter } from "../WorkerTrigger";
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the effective provider for a workflow. The trigger's
|
|
23
|
+
* `provider` field always wins; otherwise fall back to the
|
|
24
|
+
* `BLOK_WORKER_ADAPTER` env var; otherwise `"in-memory"`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveProvider(provider?: WorkerProvider): WorkerProvider;
|
|
27
|
+
/**
|
|
28
|
+
* Construct an adapter for the named provider. Throws a clear error
|
|
29
|
+
* for unknown names — keeps the schema validation and runtime
|
|
30
|
+
* behaviour in sync (the Zod enum catches typos at workflow load).
|
|
31
|
+
*/
|
|
32
|
+
export declare function createWorkerAdapter(provider: WorkerProvider): WorkerAdapter;
|
|
33
|
+
export declare function getOrCreateAdapter(provider: WorkerProvider): WorkerAdapter;
|
|
34
|
+
export declare function _resetAdapterPoolForTests(): void;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.7 PR 5 — adapter factory.
|
|
3
|
+
*
|
|
4
|
+
* Resolves a `provider` string to a concrete `WorkerAdapter` instance.
|
|
5
|
+
* Used by the `WorkerTrigger` (to pick the right adapter per workflow
|
|
6
|
+
* based on `trigger.worker.provider`) and by the `@blokjs/worker-publish`
|
|
7
|
+
* helper node (to enqueue jobs from any workflow without bundling all
|
|
8
|
+
* broker clients).
|
|
9
|
+
*
|
|
10
|
+
* Provider resolution order:
|
|
11
|
+
* 1. Explicit `provider` field on the workflow (highest priority).
|
|
12
|
+
* 2. `BLOK_WORKER_ADAPTER` env var (per Q7 resolution in the plan).
|
|
13
|
+
* 3. `"in-memory"` fallback (zero-infra default for dev/tests).
|
|
14
|
+
*
|
|
15
|
+
* Each adapter beyond `in-memory` lazy-imports its broker SDK on first
|
|
16
|
+
* use (BullMQ does this today). Workflows that don't use a given
|
|
17
|
+
* provider don't pay the install or import cost.
|
|
18
|
+
*/
|
|
19
|
+
import { BullMQAdapter } from "./BullMQAdapter";
|
|
20
|
+
import { InMemoryAdapter } from "./InMemoryAdapter";
|
|
21
|
+
import { KafkaAdapter } from "./KafkaAdapter";
|
|
22
|
+
import { NATSWorkerAdapter } from "./NATSAdapter";
|
|
23
|
+
import { PgBossAdapter } from "./PgBossAdapter";
|
|
24
|
+
import { RabbitMQAdapter } from "./RabbitMQAdapter";
|
|
25
|
+
import { RedisStreamsAdapter } from "./RedisStreamsAdapter";
|
|
26
|
+
import { SQSAdapter } from "./SQSAdapter";
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the effective provider for a workflow. The trigger's
|
|
29
|
+
* `provider` field always wins; otherwise fall back to the
|
|
30
|
+
* `BLOK_WORKER_ADAPTER` env var; otherwise `"in-memory"`.
|
|
31
|
+
*/
|
|
32
|
+
export function resolveProvider(provider) {
|
|
33
|
+
if (provider)
|
|
34
|
+
return provider;
|
|
35
|
+
const envValue = process.env.BLOK_WORKER_ADAPTER;
|
|
36
|
+
if (envValue && isWorkerProvider(envValue))
|
|
37
|
+
return envValue;
|
|
38
|
+
return "in-memory";
|
|
39
|
+
}
|
|
40
|
+
function isWorkerProvider(value) {
|
|
41
|
+
return (value === "in-memory" ||
|
|
42
|
+
value === "nats" ||
|
|
43
|
+
value === "bullmq" ||
|
|
44
|
+
value === "kafka" ||
|
|
45
|
+
value === "rabbitmq" ||
|
|
46
|
+
value === "sqs" ||
|
|
47
|
+
value === "redis" ||
|
|
48
|
+
value === "pg-boss");
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Construct an adapter for the named provider. Throws a clear error
|
|
52
|
+
* for unknown names — keeps the schema validation and runtime
|
|
53
|
+
* behaviour in sync (the Zod enum catches typos at workflow load).
|
|
54
|
+
*/
|
|
55
|
+
export function createWorkerAdapter(provider) {
|
|
56
|
+
switch (provider) {
|
|
57
|
+
case "in-memory":
|
|
58
|
+
return new InMemoryAdapter();
|
|
59
|
+
case "nats":
|
|
60
|
+
return new NATSWorkerAdapter();
|
|
61
|
+
case "bullmq":
|
|
62
|
+
return new BullMQAdapter();
|
|
63
|
+
case "kafka":
|
|
64
|
+
return new KafkaAdapter();
|
|
65
|
+
case "rabbitmq":
|
|
66
|
+
return new RabbitMQAdapter();
|
|
67
|
+
case "sqs":
|
|
68
|
+
return new SQSAdapter();
|
|
69
|
+
case "redis":
|
|
70
|
+
return new RedisStreamsAdapter();
|
|
71
|
+
case "pg-boss":
|
|
72
|
+
return new PgBossAdapter();
|
|
73
|
+
default: {
|
|
74
|
+
const exhaustive = provider;
|
|
75
|
+
throw new Error(`[blok][worker] unknown provider "${exhaustive}". Check WorkerProviderSchema.`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Process-singleton adapter pool — one instance per provider. The
|
|
81
|
+
* trigger calls `getOrCreateAdapter("kafka")` once per workflow, and
|
|
82
|
+
* subsequent workflows on the same provider share the broker
|
|
83
|
+
* connection. Adapters are connected lazily — `getOrCreateAdapter`
|
|
84
|
+
* never connects on its own; the caller calls `adapter.connect()`.
|
|
85
|
+
*
|
|
86
|
+
* Reset via `_resetAdapterPoolForTests()` between vitest suites.
|
|
87
|
+
*/
|
|
88
|
+
const pool = new Map();
|
|
89
|
+
export function getOrCreateAdapter(provider) {
|
|
90
|
+
let adapter = pool.get(provider);
|
|
91
|
+
if (!adapter) {
|
|
92
|
+
adapter = createWorkerAdapter(provider);
|
|
93
|
+
pool.set(provider, adapter);
|
|
94
|
+
}
|
|
95
|
+
return adapter;
|
|
96
|
+
}
|
|
97
|
+
export function _resetAdapterPoolForTests() {
|
|
98
|
+
for (const adapter of pool.values()) {
|
|
99
|
+
void adapter.disconnect?.().catch(() => { });
|
|
100
|
+
}
|
|
101
|
+
pool.clear();
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVycy9mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUlILE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUNoRCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDcEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNsRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDaEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzVELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFMUM7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsUUFBeUI7SUFDeEQsSUFBSSxRQUFRO1FBQUUsT0FBTyxRQUFRLENBQUM7SUFDOUIsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQztJQUNqRCxJQUFJLFFBQVEsSUFBSSxnQkFBZ0IsQ0FBQyxRQUFRLENBQUM7UUFBRSxPQUFPLFFBQVEsQ0FBQztJQUM1RCxPQUFPLFdBQVcsQ0FBQztBQUNwQixDQUFDO0FBRUQsU0FBUyxnQkFBZ0IsQ0FBQyxLQUFhO0lBQ3RDLE9BQU8sQ0FDTixLQUFLLEtBQUssV0FBVztRQUNyQixLQUFLLEtBQUssTUFBTTtRQUNoQixLQUFLLEtBQUssUUFBUTtRQUNsQixLQUFLLEtBQUssT0FBTztRQUNqQixLQUFLLEtBQUssVUFBVTtRQUNwQixLQUFLLEtBQUssS0FBSztRQUNmLEtBQUssS0FBSyxPQUFPO1FBQ2pCLEtBQUssS0FBSyxTQUFTLENBQ25CLENBQUM7QUFDSCxDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FBQyxRQUF3QjtJQUMzRCxRQUFRLFFBQVEsRUFBRSxDQUFDO1FBQ2xCLEtBQUssV0FBVztZQUNmLE9BQU8sSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUM5QixLQUFLLE1BQU07WUFDVixPQUFPLElBQUksaUJBQWlCLEVBQUUsQ0FBQztRQUNoQyxLQUFLLFFBQVE7WUFDWixPQUFPLElBQUksYUFBYSxFQUFFLENBQUM7UUFDNUIsS0FBSyxPQUFPO1lBQ1gsT0FBTyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQzNCLEtBQUssVUFBVTtZQUNkLE9BQU8sSUFBSSxlQUFlLEVBQUUsQ0FBQztRQUM5QixLQUFLLEtBQUs7WUFDVCxPQUFPLElBQUksVUFBVSxFQUFFLENBQUM7UUFDekIsS0FBSyxPQUFPO1lBQ1gsT0FBTyxJQUFJLG1CQUFtQixFQUFFLENBQUM7UUFDbEMsS0FBSyxTQUFTO1lBQ2IsT0FBTyxJQUFJLGFBQWEsRUFBRSxDQUFDO1FBQzVCLE9BQU8sQ0FBQyxDQUFDLENBQUM7WUFDVCxNQUFNLFVBQVUsR0FBVSxRQUFRLENBQUM7WUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQ0FBb0MsVUFBb0IsZ0NBQWdDLENBQUMsQ0FBQztRQUMzRyxDQUFDO0lBQ0YsQ0FBQztBQUNGLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sSUFBSSxHQUF1QyxJQUFJLEdBQUcsRUFBRSxDQUFDO0FBRTNELE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxRQUF3QjtJQUMxRCxJQUFJLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2pDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNkLE9BQU8sR0FBRyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDaEIsQ0FBQztBQUVELE1BQU0sVUFBVSx5QkFBeUI7SUFDeEMsS0FBSyxNQUFNLE9BQU8sSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQztRQUNyQyxLQUFLLE9BQU8sQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRSxDQUFDLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBQ0QsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO0FBQ2QsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogdjAuNyBQUiA1IOKAlCBhZGFwdGVyIGZhY3RvcnkuXG4gKlxuICogUmVzb2x2ZXMgYSBgcHJvdmlkZXJgIHN0cmluZyB0byBhIGNvbmNyZXRlIGBXb3JrZXJBZGFwdGVyYCBpbnN0YW5jZS5cbiAqIFVzZWQgYnkgdGhlIGBXb3JrZXJUcmlnZ2VyYCAodG8gcGljayB0aGUgcmlnaHQgYWRhcHRlciBwZXIgd29ya2Zsb3dcbiAqIGJhc2VkIG9uIGB0cmlnZ2VyLndvcmtlci5wcm92aWRlcmApIGFuZCBieSB0aGUgYEBibG9ranMvd29ya2VyLXB1Ymxpc2hgXG4gKiBoZWxwZXIgbm9kZSAodG8gZW5xdWV1ZSBqb2JzIGZyb20gYW55IHdvcmtmbG93IHdpdGhvdXQgYnVuZGxpbmcgYWxsXG4gKiBicm9rZXIgY2xpZW50cykuXG4gKlxuICogUHJvdmlkZXIgcmVzb2x1dGlvbiBvcmRlcjpcbiAqICAgMS4gRXhwbGljaXQgYHByb3ZpZGVyYCBmaWVsZCBvbiB0aGUgd29ya2Zsb3cgKGhpZ2hlc3QgcHJpb3JpdHkpLlxuICogICAyLiBgQkxPS19XT1JLRVJfQURBUFRFUmAgZW52IHZhciAocGVyIFE3IHJlc29sdXRpb24gaW4gdGhlIHBsYW4pLlxuICogICAzLiBgXCJpbi1tZW1vcnlcImAgZmFsbGJhY2sgKHplcm8taW5mcmEgZGVmYXVsdCBmb3IgZGV2L3Rlc3RzKS5cbiAqXG4gKiBFYWNoIGFkYXB0ZXIgYmV5b25kIGBpbi1tZW1vcnlgIGxhenktaW1wb3J0cyBpdHMgYnJva2VyIFNESyBvbiBmaXJzdFxuICogdXNlIChCdWxsTVEgZG9lcyB0aGlzIHRvZGF5KS4gV29ya2Zsb3dzIHRoYXQgZG9uJ3QgdXNlIGEgZ2l2ZW5cbiAqIHByb3ZpZGVyIGRvbid0IHBheSB0aGUgaW5zdGFsbCBvciBpbXBvcnQgY29zdC5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7IFdvcmtlclByb3ZpZGVyIH0gZnJvbSBcIkBibG9ranMvaGVscGVyXCI7XG5pbXBvcnQgdHlwZSB7IFdvcmtlckFkYXB0ZXIgfSBmcm9tIFwiLi4vV29ya2VyVHJpZ2dlclwiO1xuaW1wb3J0IHsgQnVsbE1RQWRhcHRlciB9IGZyb20gXCIuL0J1bGxNUUFkYXB0ZXJcIjtcbmltcG9ydCB7IEluTWVtb3J5QWRhcHRlciB9IGZyb20gXCIuL0luTWVtb3J5QWRhcHRlclwiO1xuaW1wb3J0IHsgS2Fma2FBZGFwdGVyIH0gZnJvbSBcIi4vS2Fma2FBZGFwdGVyXCI7XG5pbXBvcnQgeyBOQVRTV29ya2VyQWRhcHRlciB9IGZyb20gXCIuL05BVFNBZGFwdGVyXCI7XG5pbXBvcnQgeyBQZ0Jvc3NBZGFwdGVyIH0gZnJvbSBcIi4vUGdCb3NzQWRhcHRlclwiO1xuaW1wb3J0IHsgUmFiYml0TVFBZGFwdGVyIH0gZnJvbSBcIi4vUmFiYml0TVFBZGFwdGVyXCI7XG5pbXBvcnQgeyBSZWRpc1N0cmVhbXNBZGFwdGVyIH0gZnJvbSBcIi4vUmVkaXNTdHJlYW1zQWRhcHRlclwiO1xuaW1wb3J0IHsgU1FTQWRhcHRlciB9IGZyb20gXCIuL1NRU0FkYXB0ZXJcIjtcblxuLyoqXG4gKiBSZXNvbHZlIHRoZSBlZmZlY3RpdmUgcHJvdmlkZXIgZm9yIGEgd29ya2Zsb3cuIFRoZSB0cmlnZ2VyJ3NcbiAqIGBwcm92aWRlcmAgZmllbGQgYWx3YXlzIHdpbnM7IG90aGVyd2lzZSBmYWxsIGJhY2sgdG8gdGhlXG4gKiBgQkxPS19XT1JLRVJfQURBUFRFUmAgZW52IHZhcjsgb3RoZXJ3aXNlIGBcImluLW1lbW9yeVwiYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVQcm92aWRlcihwcm92aWRlcj86IFdvcmtlclByb3ZpZGVyKTogV29ya2VyUHJvdmlkZXIge1xuXHRpZiAocHJvdmlkZXIpIHJldHVybiBwcm92aWRlcjtcblx0Y29uc3QgZW52VmFsdWUgPSBwcm9jZXNzLmVudi5CTE9LX1dPUktFUl9BREFQVEVSO1xuXHRpZiAoZW52VmFsdWUgJiYgaXNXb3JrZXJQcm92aWRlcihlbnZWYWx1ZSkpIHJldHVybiBlbnZWYWx1ZTtcblx0cmV0dXJuIFwiaW4tbWVtb3J5XCI7XG59XG5cbmZ1bmN0aW9uIGlzV29ya2VyUHJvdmlkZXIodmFsdWU6IHN0cmluZyk6IHZhbHVlIGlzIFdvcmtlclByb3ZpZGVyIHtcblx0cmV0dXJuIChcblx0XHR2YWx1ZSA9PT0gXCJpbi1tZW1vcnlcIiB8fFxuXHRcdHZhbHVlID09PSBcIm5hdHNcIiB8fFxuXHRcdHZhbHVlID09PSBcImJ1bGxtcVwiIHx8XG5cdFx0dmFsdWUgPT09IFwia2Fma2FcIiB8fFxuXHRcdHZhbHVlID09PSBcInJhYmJpdG1xXCIgfHxcblx0XHR2YWx1ZSA9PT0gXCJzcXNcIiB8fFxuXHRcdHZhbHVlID09PSBcInJlZGlzXCIgfHxcblx0XHR2YWx1ZSA9PT0gXCJwZy1ib3NzXCJcblx0KTtcbn1cblxuLyoqXG4gKiBDb25zdHJ1Y3QgYW4gYWRhcHRlciBmb3IgdGhlIG5hbWVkIHByb3ZpZGVyLiBUaHJvd3MgYSBjbGVhciBlcnJvclxuICogZm9yIHVua25vd24gbmFtZXMg4oCUIGtlZXBzIHRoZSBzY2hlbWEgdmFsaWRhdGlvbiBhbmQgcnVudGltZVxuICogYmVoYXZpb3VyIGluIHN5bmMgKHRoZSBab2QgZW51bSBjYXRjaGVzIHR5cG9zIGF0IHdvcmtmbG93IGxvYWQpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlV29ya2VyQWRhcHRlcihwcm92aWRlcjogV29ya2VyUHJvdmlkZXIpOiBXb3JrZXJBZGFwdGVyIHtcblx0c3dpdGNoIChwcm92aWRlcikge1xuXHRcdGNhc2UgXCJpbi1tZW1vcnlcIjpcblx0XHRcdHJldHVybiBuZXcgSW5NZW1vcnlBZGFwdGVyKCk7XG5cdFx0Y2FzZSBcIm5hdHNcIjpcblx0XHRcdHJldHVybiBuZXcgTkFUU1dvcmtlckFkYXB0ZXIoKTtcblx0XHRjYXNlIFwiYnVsbG1xXCI6XG5cdFx0XHRyZXR1cm4gbmV3IEJ1bGxNUUFkYXB0ZXIoKTtcblx0XHRjYXNlIFwia2Fma2FcIjpcblx0XHRcdHJldHVybiBuZXcgS2Fma2FBZGFwdGVyKCk7XG5cdFx0Y2FzZSBcInJhYmJpdG1xXCI6XG5cdFx0XHRyZXR1cm4gbmV3IFJhYmJpdE1RQWRhcHRlcigpO1xuXHRcdGNhc2UgXCJzcXNcIjpcblx0XHRcdHJldHVybiBuZXcgU1FTQWRhcHRlcigpO1xuXHRcdGNhc2UgXCJyZWRpc1wiOlxuXHRcdFx0cmV0dXJuIG5ldyBSZWRpc1N0cmVhbXNBZGFwdGVyKCk7XG5cdFx0Y2FzZSBcInBnLWJvc3NcIjpcblx0XHRcdHJldHVybiBuZXcgUGdCb3NzQWRhcHRlcigpO1xuXHRcdGRlZmF1bHQ6IHtcblx0XHRcdGNvbnN0IGV4aGF1c3RpdmU6IG5ldmVyID0gcHJvdmlkZXI7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoYFtibG9rXVt3b3JrZXJdIHVua25vd24gcHJvdmlkZXIgXCIke2V4aGF1c3RpdmUgYXMgc3RyaW5nfVwiLiBDaGVjayBXb3JrZXJQcm92aWRlclNjaGVtYS5gKTtcblx0XHR9XG5cdH1cbn1cblxuLyoqXG4gKiBQcm9jZXNzLXNpbmdsZXRvbiBhZGFwdGVyIHBvb2wg4oCUIG9uZSBpbnN0YW5jZSBwZXIgcHJvdmlkZXIuIFRoZVxuICogdHJpZ2dlciBjYWxscyBgZ2V0T3JDcmVhdGVBZGFwdGVyKFwia2Fma2FcIilgIG9uY2UgcGVyIHdvcmtmbG93LCBhbmRcbiAqIHN1YnNlcXVlbnQgd29ya2Zsb3dzIG9uIHRoZSBzYW1lIHByb3ZpZGVyIHNoYXJlIHRoZSBicm9rZXJcbiAqIGNvbm5lY3Rpb24uIEFkYXB0ZXJzIGFyZSBjb25uZWN0ZWQgbGF6aWx5IOKAlCBgZ2V0T3JDcmVhdGVBZGFwdGVyYFxuICogbmV2ZXIgY29ubmVjdHMgb24gaXRzIG93bjsgdGhlIGNhbGxlciBjYWxscyBgYWRhcHRlci5jb25uZWN0KClgLlxuICpcbiAqIFJlc2V0IHZpYSBgX3Jlc2V0QWRhcHRlclBvb2xGb3JUZXN0cygpYCBiZXR3ZWVuIHZpdGVzdCBzdWl0ZXMuXG4gKi9cbmNvbnN0IHBvb2w6IE1hcDxXb3JrZXJQcm92aWRlciwgV29ya2VyQWRhcHRlcj4gPSBuZXcgTWFwKCk7XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRPckNyZWF0ZUFkYXB0ZXIocHJvdmlkZXI6IFdvcmtlclByb3ZpZGVyKTogV29ya2VyQWRhcHRlciB7XG5cdGxldCBhZGFwdGVyID0gcG9vbC5nZXQocHJvdmlkZXIpO1xuXHRpZiAoIWFkYXB0ZXIpIHtcblx0XHRhZGFwdGVyID0gY3JlYXRlV29ya2VyQWRhcHRlcihwcm92aWRlcik7XG5cdFx0cG9vbC5zZXQocHJvdmlkZXIsIGFkYXB0ZXIpO1xuXHR9XG5cdHJldHVybiBhZGFwdGVyO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gX3Jlc2V0QWRhcHRlclBvb2xGb3JUZXN0cygpOiB2b2lkIHtcblx0Zm9yIChjb25zdCBhZGFwdGVyIG9mIHBvb2wudmFsdWVzKCkpIHtcblx0XHR2b2lkIGFkYXB0ZXIuZGlzY29ubmVjdD8uKCkuY2F0Y2goKCkgPT4ge30pO1xuXHR9XG5cdHBvb2wuY2xlYXIoKTtcbn1cbiJdfQ==
|
package/dist/index.d.ts
CHANGED
|
@@ -10,9 +10,20 @@
|
|
|
10
10
|
* - Delayed job scheduling
|
|
11
11
|
* - Queue statistics and monitoring
|
|
12
12
|
*
|
|
13
|
-
* Adapters:
|
|
14
|
-
* - BullMQ
|
|
15
|
-
* - InMemory
|
|
13
|
+
* Adapters (v0.7+):
|
|
14
|
+
* - BullMQ — Redis-backed, ops-style queues (`bullmq` peer dep)
|
|
15
|
+
* - InMemory — development / tests (no peer deps)
|
|
16
|
+
* - NATS — JetStream durable streams (`nats` peer dep)
|
|
17
|
+
* - Kafka — high-throughput streaming (`kafkajs` peer dep)
|
|
18
|
+
* - RabbitMQ — reliable enterprise queues (`amqplib` peer dep)
|
|
19
|
+
* - SQS — AWS cloud queues (`@aws-sdk/client-sqs` peer dep)
|
|
20
|
+
* - Redis Streams — when Redis is already in stack (`ioredis` peer dep)
|
|
21
|
+
* - pg-boss — no extra infra (`pg-boss` peer dep)
|
|
22
|
+
*
|
|
23
|
+
* v0.7+ — pick the adapter per workflow via `trigger.worker.provider`.
|
|
24
|
+
* `BLOK_WORKER_ADAPTER` env var sets the default. Subclasses can still
|
|
25
|
+
* set `protected adapter` directly for back-compat with the pre-v0.7
|
|
26
|
+
* single-adapter pattern.
|
|
16
27
|
*
|
|
17
28
|
* @example BullMQ
|
|
18
29
|
* ```typescript
|
|
@@ -53,5 +64,11 @@
|
|
|
53
64
|
export { WorkerTrigger, type WorkerAdapter, type WorkerJob, type WorkerQueueStats, } from "./WorkerTrigger";
|
|
54
65
|
export { BullMQAdapter, type BullMQConfig } from "./adapters/BullMQAdapter";
|
|
55
66
|
export { InMemoryAdapter } from "./adapters/InMemoryAdapter";
|
|
67
|
+
export { KafkaAdapter, type KafkaConfig } from "./adapters/KafkaAdapter";
|
|
56
68
|
export { NATSWorkerAdapter, type NATSWorkerConfig } from "./adapters/NATSAdapter";
|
|
57
|
-
export type
|
|
69
|
+
export { PgBossAdapter, type PgBossConfig } from "./adapters/PgBossAdapter";
|
|
70
|
+
export { RabbitMQAdapter, type RabbitMQConfig } from "./adapters/RabbitMQAdapter";
|
|
71
|
+
export { RedisStreamsAdapter, type RedisStreamsConfig } from "./adapters/RedisStreamsAdapter";
|
|
72
|
+
export { SQSAdapter, type SQSConfig } from "./adapters/SQSAdapter";
|
|
73
|
+
export { _resetAdapterPoolForTests, createWorkerAdapter, getOrCreateAdapter, resolveProvider, } from "./adapters/factory";
|
|
74
|
+
export type { WorkerProvider, WorkerTriggerOpts } from "@blokjs/helper";
|
package/dist/index.js
CHANGED
|
@@ -10,9 +10,20 @@
|
|
|
10
10
|
* - Delayed job scheduling
|
|
11
11
|
* - Queue statistics and monitoring
|
|
12
12
|
*
|
|
13
|
-
* Adapters:
|
|
14
|
-
* - BullMQ
|
|
15
|
-
* - InMemory
|
|
13
|
+
* Adapters (v0.7+):
|
|
14
|
+
* - BullMQ — Redis-backed, ops-style queues (`bullmq` peer dep)
|
|
15
|
+
* - InMemory — development / tests (no peer deps)
|
|
16
|
+
* - NATS — JetStream durable streams (`nats` peer dep)
|
|
17
|
+
* - Kafka — high-throughput streaming (`kafkajs` peer dep)
|
|
18
|
+
* - RabbitMQ — reliable enterprise queues (`amqplib` peer dep)
|
|
19
|
+
* - SQS — AWS cloud queues (`@aws-sdk/client-sqs` peer dep)
|
|
20
|
+
* - Redis Streams — when Redis is already in stack (`ioredis` peer dep)
|
|
21
|
+
* - pg-boss — no extra infra (`pg-boss` peer dep)
|
|
22
|
+
*
|
|
23
|
+
* v0.7+ — pick the adapter per workflow via `trigger.worker.provider`.
|
|
24
|
+
* `BLOK_WORKER_ADAPTER` env var sets the default. Subclasses can still
|
|
25
|
+
* set `protected adapter` directly for back-compat with the pre-v0.7
|
|
26
|
+
* single-adapter pattern.
|
|
16
27
|
*
|
|
17
28
|
* @example BullMQ
|
|
18
29
|
* ```typescript
|
|
@@ -55,5 +66,14 @@ export { WorkerTrigger, } from "./WorkerTrigger";
|
|
|
55
66
|
// Adapters
|
|
56
67
|
export { BullMQAdapter } from "./adapters/BullMQAdapter";
|
|
57
68
|
export { InMemoryAdapter } from "./adapters/InMemoryAdapter";
|
|
69
|
+
export { KafkaAdapter } from "./adapters/KafkaAdapter";
|
|
58
70
|
export { NATSWorkerAdapter } from "./adapters/NATSAdapter";
|
|
59
|
-
|
|
71
|
+
export { PgBossAdapter } from "./adapters/PgBossAdapter";
|
|
72
|
+
export { RabbitMQAdapter } from "./adapters/RabbitMQAdapter";
|
|
73
|
+
export { RedisStreamsAdapter } from "./adapters/RedisStreamsAdapter";
|
|
74
|
+
export { SQSAdapter } from "./adapters/SQSAdapter";
|
|
75
|
+
// v0.7 PR 5 — factory + pool. Used by WorkerTrigger and exposed for
|
|
76
|
+
// helper nodes (`@blokjs/worker-publish`) that need to enqueue jobs
|
|
77
|
+
// from any workflow without bundling all broker SDKs.
|
|
78
|
+
export { _resetAdapterPoolForTests, createWorkerAdapter, getOrCreateAdapter, resolveProvider, } from "./adapters/factory";
|
|
79
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBOERHO0FBRUgsZUFBZTtBQUNmLE9BQU8sRUFDTixhQUFhLEdBSWIsTUFBTSxpQkFBaUIsQ0FBQztBQUV6QixXQUFXO0FBQ1gsT0FBTyxFQUFFLGFBQWEsRUFBcUIsTUFBTSwwQkFBMEIsQ0FBQztBQUM1RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFlBQVksRUFBb0IsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RSxPQUFPLEVBQUUsaUJBQWlCLEVBQXlCLE1BQU0sd0JBQXdCLENBQUM7QUFDbEYsT0FBTyxFQUFFLGFBQWEsRUFBcUIsTUFBTSwwQkFBMEIsQ0FBQztBQUM1RSxPQUFPLEVBQUUsZUFBZSxFQUF1QixNQUFNLDRCQUE0QixDQUFDO0FBQ2xGLE9BQU8sRUFBRSxtQkFBbUIsRUFBMkIsTUFBTSxnQ0FBZ0MsQ0FBQztBQUM5RixPQUFPLEVBQUUsVUFBVSxFQUFrQixNQUFNLHVCQUF1QixDQUFDO0FBRW5FLG9FQUFvRTtBQUNwRSxvRUFBb0U7QUFDcEUsc0RBQXNEO0FBQ3RELE9BQU8sRUFDTix5QkFBeUIsRUFDekIsbUJBQW1CLEVBQ25CLGtCQUFrQixFQUNsQixlQUFlLEdBQ2YsTUFBTSxvQkFBb0IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGJsb2tqcy90cmlnZ2VyLXdvcmtlclxuICpcbiAqIFdvcmtlci1iYXNlZCB0cmlnZ2VyIGZvciBCbG9rIHdvcmtmbG93cy5cbiAqIFN1cHBvcnRzIGJhY2tncm91bmQgam9iIHByb2Nlc3Npbmcgd2l0aDpcbiAqIC0gQ29uZmlndXJhYmxlIGNvbmN1cnJlbmN5IHBlciBxdWV1ZVxuICogLSBBdXRvbWF0aWMgcmV0cmllcyB3aXRoIGV4cG9uZW50aWFsIGJhY2tvZmZcbiAqIC0gSm9iIHRpbWVvdXRzXG4gKiAtIFByaW9yaXR5LWJhc2VkIGpvYiBvcmRlcmluZ1xuICogLSBEZWxheWVkIGpvYiBzY2hlZHVsaW5nXG4gKiAtIFF1ZXVlIHN0YXRpc3RpY3MgYW5kIG1vbml0b3JpbmdcbiAqXG4gKiBBZGFwdGVycyAodjAuNyspOlxuICogLSBCdWxsTVEgICAgICAgIOKAlCBSZWRpcy1iYWNrZWQsIG9wcy1zdHlsZSBxdWV1ZXMgKGBidWxsbXFgIHBlZXIgZGVwKVxuICogLSBJbk1lbW9yeSAgICAgIOKAlCBkZXZlbG9wbWVudCAvIHRlc3RzIChubyBwZWVyIGRlcHMpXG4gKiAtIE5BVFMgICAgICAgICAg4oCUIEpldFN0cmVhbSBkdXJhYmxlIHN0cmVhbXMgKGBuYXRzYCBwZWVyIGRlcClcbiAqIC0gS2Fma2EgICAgICAgICDigJQgaGlnaC10aHJvdWdocHV0IHN0cmVhbWluZyAoYGthZmthanNgIHBlZXIgZGVwKVxuICogLSBSYWJiaXRNUSAgICAgIOKAlCByZWxpYWJsZSBlbnRlcnByaXNlIHF1ZXVlcyAoYGFtcXBsaWJgIHBlZXIgZGVwKVxuICogLSBTUVMgICAgICAgICAgIOKAlCBBV1MgY2xvdWQgcXVldWVzIChgQGF3cy1zZGsvY2xpZW50LXNxc2AgcGVlciBkZXApXG4gKiAtIFJlZGlzIFN0cmVhbXMg4oCUIHdoZW4gUmVkaXMgaXMgYWxyZWFkeSBpbiBzdGFjayAoYGlvcmVkaXNgIHBlZXIgZGVwKVxuICogLSBwZy1ib3NzICAgICAgIOKAlCBubyBleHRyYSBpbmZyYSAoYHBnLWJvc3NgIHBlZXIgZGVwKVxuICpcbiAqIHYwLjcrIOKAlCBwaWNrIHRoZSBhZGFwdGVyIHBlciB3b3JrZmxvdyB2aWEgYHRyaWdnZXIud29ya2VyLnByb3ZpZGVyYC5cbiAqIGBCTE9LX1dPUktFUl9BREFQVEVSYCBlbnYgdmFyIHNldHMgdGhlIGRlZmF1bHQuIFN1YmNsYXNzZXMgY2FuIHN0aWxsXG4gKiBzZXQgYHByb3RlY3RlZCBhZGFwdGVyYCBkaXJlY3RseSBmb3IgYmFjay1jb21wYXQgd2l0aCB0aGUgcHJlLXYwLjdcbiAqIHNpbmdsZS1hZGFwdGVyIHBhdHRlcm4uXG4gKlxuICogQGV4YW1wbGUgQnVsbE1RXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBXb3JrZXJUcmlnZ2VyLCBCdWxsTVFBZGFwdGVyIH0gZnJvbSBcIkBibG9ranMvdHJpZ2dlci13b3JrZXJcIjtcbiAqXG4gKiBjbGFzcyBNeVdvcmtlclRyaWdnZXIgZXh0ZW5kcyBXb3JrZXJUcmlnZ2VyIHtcbiAqICAgcHJvdGVjdGVkIGFkYXB0ZXIgPSBuZXcgQnVsbE1RQWRhcHRlcih7XG4gKiAgICAgaG9zdDogXCJsb2NhbGhvc3RcIixcbiAqICAgICBwb3J0OiA2Mzc5LFxuICogICB9KTtcbiAqXG4gKiAgIHByb3RlY3RlZCBub2RlcyA9IG15Tm9kZXM7XG4gKiAgIHByb3RlY3RlZCB3b3JrZmxvd3MgPSBteVdvcmtmbG93cztcbiAqIH1cbiAqXG4gKiBjb25zdCB0cmlnZ2VyID0gbmV3IE15V29ya2VyVHJpZ2dlcigpO1xuICogYXdhaXQgdHJpZ2dlci5saXN0ZW4oKTtcbiAqXG4gKiAvLyBEaXNwYXRjaCBhIGpvYlxuICogYXdhaXQgdHJpZ2dlci5kaXNwYXRjaChcImJhY2tncm91bmQtam9ic1wiLCB7IHVzZXJJZDogXCIxMjNcIiB9LCB7XG4gKiAgIHByaW9yaXR5OiAxMCxcbiAqICAgcmV0cmllczogMyxcbiAqICAgZGVsYXk6IDUwMDAsIC8vIGRlbGF5IDUgc2Vjb25kc1xuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBAZXhhbXBsZSBJbk1lbW9yeSAoZGV2ZWxvcG1lbnQpXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBpbXBvcnQgeyBXb3JrZXJUcmlnZ2VyLCBJbk1lbW9yeUFkYXB0ZXIgfSBmcm9tIFwiQGJsb2tqcy90cmlnZ2VyLXdvcmtlclwiO1xuICpcbiAqIGNsYXNzIERldldvcmtlclRyaWdnZXIgZXh0ZW5kcyBXb3JrZXJUcmlnZ2VyIHtcbiAqICAgcHJvdGVjdGVkIGFkYXB0ZXIgPSBuZXcgSW5NZW1vcnlBZGFwdGVyKCk7XG4gKiAgIHByb3RlY3RlZCBub2RlcyA9IG15Tm9kZXM7XG4gKiAgIHByb3RlY3RlZCB3b3JrZmxvd3MgPSBteVdvcmtmbG93cztcbiAqIH1cbiAqIGBgYFxuICovXG5cbi8vIENvcmUgZXhwb3J0c1xuZXhwb3J0IHtcblx0V29ya2VyVHJpZ2dlcixcblx0dHlwZSBXb3JrZXJBZGFwdGVyLFxuXHR0eXBlIFdvcmtlckpvYixcblx0dHlwZSBXb3JrZXJRdWV1ZVN0YXRzLFxufSBmcm9tIFwiLi9Xb3JrZXJUcmlnZ2VyXCI7XG5cbi8vIEFkYXB0ZXJzXG5leHBvcnQgeyBCdWxsTVFBZGFwdGVyLCB0eXBlIEJ1bGxNUUNvbmZpZyB9IGZyb20gXCIuL2FkYXB0ZXJzL0J1bGxNUUFkYXB0ZXJcIjtcbmV4cG9ydCB7IEluTWVtb3J5QWRhcHRlciB9IGZyb20gXCIuL2FkYXB0ZXJzL0luTWVtb3J5QWRhcHRlclwiO1xuZXhwb3J0IHsgS2Fma2FBZGFwdGVyLCB0eXBlIEthZmthQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvS2Fma2FBZGFwdGVyXCI7XG5leHBvcnQgeyBOQVRTV29ya2VyQWRhcHRlciwgdHlwZSBOQVRTV29ya2VyQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvTkFUU0FkYXB0ZXJcIjtcbmV4cG9ydCB7IFBnQm9zc0FkYXB0ZXIsIHR5cGUgUGdCb3NzQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvUGdCb3NzQWRhcHRlclwiO1xuZXhwb3J0IHsgUmFiYml0TVFBZGFwdGVyLCB0eXBlIFJhYmJpdE1RQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvUmFiYml0TVFBZGFwdGVyXCI7XG5leHBvcnQgeyBSZWRpc1N0cmVhbXNBZGFwdGVyLCB0eXBlIFJlZGlzU3RyZWFtc0NvbmZpZyB9IGZyb20gXCIuL2FkYXB0ZXJzL1JlZGlzU3RyZWFtc0FkYXB0ZXJcIjtcbmV4cG9ydCB7IFNRU0FkYXB0ZXIsIHR5cGUgU1FTQ29uZmlnIH0gZnJvbSBcIi4vYWRhcHRlcnMvU1FTQWRhcHRlclwiO1xuXG4vLyB2MC43IFBSIDUg4oCUIGZhY3RvcnkgKyBwb29sLiBVc2VkIGJ5IFdvcmtlclRyaWdnZXIgYW5kIGV4cG9zZWQgZm9yXG4vLyBoZWxwZXIgbm9kZXMgKGBAYmxva2pzL3dvcmtlci1wdWJsaXNoYCkgdGhhdCBuZWVkIHRvIGVucXVldWUgam9ic1xuLy8gZnJvbSBhbnkgd29ya2Zsb3cgd2l0aG91dCBidW5kbGluZyBhbGwgYnJva2VyIFNES3MuXG5leHBvcnQge1xuXHRfcmVzZXRBZGFwdGVyUG9vbEZvclRlc3RzLFxuXHRjcmVhdGVXb3JrZXJBZGFwdGVyLFxuXHRnZXRPckNyZWF0ZUFkYXB0ZXIsXG5cdHJlc29sdmVQcm92aWRlcixcbn0gZnJvbSBcIi4vYWRhcHRlcnMvZmFjdG9yeVwiO1xuXG4vLyBSZS1leHBvcnQgdHlwZXMgZnJvbSBoZWxwZXIgZm9yIGNvbnZlbmllbmNlXG5leHBvcnQgdHlwZSB7IFdvcmtlclByb3ZpZGVyLCBXb3JrZXJUcmlnZ2VyT3B0cyB9IGZyb20gXCJAYmxva2pzL2hlbHBlclwiO1xuIl19
|