@dbx-tools/core 0.6.65 → 0.6.67

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.
@@ -0,0 +1,355 @@
1
+ /**
2
+ * Keyed mutual exclusion across the main thread and its worker threads.
3
+ *
4
+ * {@link withProcessLock} serializes callbacks that share a key: one runs at a
5
+ * time, the rest queue in arrival order, and different keys proceed
6
+ * concurrently. Unlike a plain in-module `Promise` chain, the queue is shared by
7
+ * every thread wired up through {@link processLockWorkerOptions}, so a worker
8
+ * pool cannot run two callbacks for the same key at once.
9
+ *
10
+ * The name says `process`: this coordinates the THREADS of one Node process. It
11
+ * is not cross-process and not cross-host - a second `node` invocation, or a
12
+ * second app replica, has its own coordinator and shares nothing. When the scope
13
+ * is a deployment rather than a process, use
14
+ * `@dbx-tools/postgres`'s `withAdvisoryLock`, which puts the arbiter in
15
+ * PostgreSQL where every replica can see it.
16
+ *
17
+ * The main thread owns the only coordinator. Each participating thread gets one
18
+ * `MessagePort` to it, and a lock is granted by a message back over that port.
19
+ * Consequently:
20
+ *
21
+ * - the lock is ADVISORY, like Postgres advisory locks - it protects a
22
+ * critical section only insofar as every writer takes the same key;
23
+ * - fairness is FIFO per key, since the coordinator queues waiters in the
24
+ * order their requests arrive;
25
+ * - a thread that dies while holding a lock releases it, because its port
26
+ * closing is what hands the key to the next waiter (see
27
+ * {@link LockCoordinator.removePort}).
28
+ *
29
+ * @module
30
+ */
31
+ import { isMainThread, MessageChannel, parentPort, workerData, } from "node:worker_threads";
32
+ import { error, hash, object } from "@dbx-tools/shared-core";
33
+ /**
34
+ * `workerData` slot carrying the coordinator port into a worker, and the
35
+ * `parentPort` message `type` for the late {@link attachProcessLock} handshake.
36
+ * Namespaced because both travel through channels an application also uses:
37
+ * `workerData` is the caller's own object, and `parentPort` carries the caller's
38
+ * own messages.
39
+ */
40
+ const LOCK_PORT_KEY = "__dbxToolsProcessLockPort";
41
+ const ATTACH_MESSAGE_TYPE = "__dbxToolsProcessLockAttach";
42
+ /**
43
+ * Arbiter for every key, living on the main thread.
44
+ *
45
+ * Holds no timers and no handles of its own: a port is unref'd by its client
46
+ * while idle (see {@link LockClient}), so an idle coordinator never keeps the
47
+ * process alive.
48
+ */
49
+ class LockCoordinator {
50
+ states = new Map();
51
+ /** Serve one client. Called once per participating thread. */
52
+ addPort(port) {
53
+ port.on("message", (message) => {
54
+ switch (message.type) {
55
+ case "acquire":
56
+ this.acquire(message.key, message.requestId, port);
57
+ break;
58
+ case "release":
59
+ this.release(message.key, message.requestId);
60
+ break;
61
+ default:
62
+ break;
63
+ }
64
+ });
65
+ // A closed port means its thread exited or was terminated. Releasing here is
66
+ // what keeps one crashed worker from wedging a key for the process lifetime.
67
+ port.on("close", () => this.removePort(port));
68
+ // The coordinator side stays unref'd for its whole life. It is a pure
69
+ // responder - it never has business of its own pending - so keeping the
70
+ // event loop alive for it would mean a process that used a lock once could
71
+ // never exit. A request always arrives from a client that has ref'd ITS
72
+ // port, so the loop is awake whenever there is actually something to serve.
73
+ port.unref();
74
+ port.start();
75
+ }
76
+ acquire(key, requestId, port) {
77
+ const waiter = { requestId, port };
78
+ const state = this.states.get(key);
79
+ if (!state) {
80
+ this.states.set(key, { owner: waiter, queue: [] });
81
+ grant(waiter);
82
+ return;
83
+ }
84
+ state.queue.push(waiter);
85
+ }
86
+ /**
87
+ * Hand the key on, ignoring a release from anyone but the current owner.
88
+ *
89
+ * A stale release is expected, not defensive coding: an aborted acquisition
90
+ * sends one for a request that never owned the key, and honouring it would
91
+ * revoke the lock from whoever holds it now.
92
+ */
93
+ release(key, requestId) {
94
+ const state = this.states.get(key);
95
+ if (state?.owner.requestId !== requestId)
96
+ return;
97
+ this.grantNext(key, state);
98
+ }
99
+ /** Promote the next waiter, or drop the key when nobody wants it. */
100
+ grantNext(key, state) {
101
+ const next = state.queue.shift();
102
+ if (!next) {
103
+ this.states.delete(key);
104
+ return;
105
+ }
106
+ state.owner = next;
107
+ grant(next);
108
+ }
109
+ /**
110
+ * Drop a dead thread from every key: release the ones it owned and remove it
111
+ * from the queues it was waiting in.
112
+ *
113
+ * Queue removal must happen FIRST. A thread can appear as both the owner of
114
+ * one key and a waiter for another, and promoting it out of a queue it can no
115
+ * longer answer for would grant a lock to a closed port - stalling that key
116
+ * until the process ends.
117
+ */
118
+ removePort(port) {
119
+ for (const state of this.states.values()) {
120
+ if (state.queue.length > 0) {
121
+ state.queue = state.queue.filter((waiter) => waiter.port !== port);
122
+ }
123
+ }
124
+ for (const [key, state] of [...this.states]) {
125
+ if (state.owner.port === port)
126
+ this.grantNext(key, state);
127
+ }
128
+ }
129
+ }
130
+ /** Notify a waiter that it now owns its key. */
131
+ function grant(waiter) {
132
+ waiter.port.postMessage({ type: "granted", requestId: waiter.requestId });
133
+ }
134
+ /**
135
+ * A thread's end of the conversation: sends requests, awaits grants, and runs
136
+ * callbacks.
137
+ *
138
+ * Owns the event-loop bookkeeping. The port is unref'd while idle so holding a
139
+ * lock module never blocks process exit, and ref'd exactly while this thread has
140
+ * an outstanding request or an unreleased lock - otherwise Node would consider
141
+ * itself out of work and exit mid-critical-section, dropping the grant that was
142
+ * already on its way.
143
+ */
144
+ class LockClient {
145
+ port;
146
+ pending = new Map();
147
+ /** Requests + held locks. The port is ref'd while this is above zero. */
148
+ active = 0;
149
+ closed = false;
150
+ constructor(port) {
151
+ this.port = port;
152
+ port.on("message", (message) => {
153
+ if (message.type !== "granted")
154
+ return;
155
+ this.settle(message.requestId);
156
+ });
157
+ port.on("close", () => {
158
+ this.closed = true;
159
+ // The coordinator is gone (main thread exiting, or this worker being torn
160
+ // down). Fail the waiters rather than hang them: a caller blocked on a
161
+ // lock that can never be granted is indistinguishable from a deadlock.
162
+ const closeError = new Error("Process lock port closed before the lock was granted");
163
+ for (const settle of [...this.pending.values()])
164
+ settle(closeError);
165
+ });
166
+ port.unref();
167
+ port.start();
168
+ }
169
+ /** Resolve or reject one pending request and drop its ref. */
170
+ settle(requestId, failure) {
171
+ const settle = this.pending.get(requestId);
172
+ if (!settle)
173
+ return;
174
+ this.pending.delete(requestId);
175
+ settle(failure);
176
+ }
177
+ /** Ref the port for the first unit of outstanding work. */
178
+ retain() {
179
+ if (this.active++ === 0)
180
+ this.port.ref();
181
+ }
182
+ /** Unref once nothing is outstanding, so the thread can exit. */
183
+ release() {
184
+ if (--this.active === 0)
185
+ this.port.unref();
186
+ }
187
+ async run(key, fn) {
188
+ if (this.closed) {
189
+ throw new Error("Process lock port is closed");
190
+ }
191
+ const requestId = hash.id();
192
+ this.retain();
193
+ try {
194
+ await new Promise((resolve, reject) => {
195
+ this.pending.set(requestId, (failure) => (failure ? reject(failure) : resolve()));
196
+ try {
197
+ this.port.postMessage({ type: "acquire", requestId, key });
198
+ }
199
+ catch (cause) {
200
+ this.pending.delete(requestId);
201
+ reject(error.toError(cause));
202
+ }
203
+ });
204
+ }
205
+ catch (cause) {
206
+ // Never granted, so there is nothing to release - just drop the ref.
207
+ this.release();
208
+ throw cause;
209
+ }
210
+ try {
211
+ return await fn();
212
+ }
213
+ finally {
214
+ // Post before unref'ing: the release must be in flight while the port is
215
+ // still holding the loop open, or the next waiter is stranded.
216
+ if (!this.closed) {
217
+ this.port.postMessage({ type: "release", requestId, key });
218
+ }
219
+ this.release();
220
+ }
221
+ }
222
+ }
223
+ /** The coordinator, on the main thread only. */
224
+ const coordinator = isMainThread ? new LockCoordinator() : undefined;
225
+ /**
226
+ * This thread's client, created on first use.
227
+ *
228
+ * Lazy so importing this module costs nothing and, more importantly, so a worker
229
+ * that never locks anything is never forced to have been started through
230
+ * {@link processLockWorkerOptions}. The main thread wires a channel to its own
231
+ * coordinator; a worker adopts the port it was handed.
232
+ */
233
+ let client;
234
+ function lockClient() {
235
+ if (client)
236
+ return client;
237
+ if (coordinator) {
238
+ const { port1, port2 } = new MessageChannel();
239
+ coordinator.addPort(port1);
240
+ client = new LockClient(port2);
241
+ return client;
242
+ }
243
+ const port = workerData?.[LOCK_PORT_KEY];
244
+ if (!port) {
245
+ throw new Error("This worker has no process-lock port. Start it with processLockWorkerOptions() " +
246
+ "(or call attachProcessLock(worker) and await processLockAttached()).");
247
+ }
248
+ client = new LockClient(port);
249
+ return client;
250
+ }
251
+ /**
252
+ * Run `fn` while holding the lock named by `key`, releasing it when `fn`
253
+ * settles.
254
+ *
255
+ * Callers sharing a key are serialized across the main thread and every worker
256
+ * started through {@link processLockWorkerOptions}; distinct keys never block
257
+ * each other. Returns whatever `fn` returns and propagates what it throws, so it
258
+ * drops into an existing expression without restructuring.
259
+ *
260
+ * `key` is any value with a stable identity - a string, a `["invoice", id]`
261
+ * tuple, a config object - canonicalized by `object.toStableKey`, the same rule
262
+ * `@dbx-tools/postgres` uses for advisory-lock ids and channel names. Structure
263
+ * is part of the identity: `["invoice", 7]` and `"invoice_7"` are different
264
+ * locks.
265
+ *
266
+ * @example
267
+ * await withProcessLock(["cache", name], async () => {
268
+ * if (!(await exists(name))) await build(name);
269
+ * });
270
+ */
271
+ export function withProcessLock(key, fn) {
272
+ return lockClient().run(lockKey(key), fn);
273
+ }
274
+ /** Canonical string identity for a lock key (see `object.toStableKey`). */
275
+ function lockKey(key) {
276
+ return object
277
+ .toOneOrMany(key)
278
+ .map((part) => object.toStableKey(part))
279
+ .join("\u0000");
280
+ }
281
+ /**
282
+ * Add the coordinator port to a `Worker`'s options so the worker can lock
283
+ * immediately - during module initialization, before any message is handled.
284
+ *
285
+ * Preserves the caller's `workerData` and `transferList`; the port is
286
+ * transferred, as `MessagePort` cannot be cloned.
287
+ *
288
+ * @example
289
+ * new Worker(url, processLockWorkerOptions({ workerData: { tenant } }));
290
+ */
291
+ export function processLockWorkerOptions(options = {}) {
292
+ const port = createCoordinatorPort("processLockWorkerOptions");
293
+ const existing = object.isRecord(options.workerData) ? options.workerData : {};
294
+ return {
295
+ ...options,
296
+ workerData: { ...existing, [LOCK_PORT_KEY]: port },
297
+ transferList: [...(options.transferList ?? []), port],
298
+ };
299
+ }
300
+ /**
301
+ * Wire an ALREADY-RUNNING worker into the lock, for a worker this code did not
302
+ * construct (a pool from a library, say).
303
+ *
304
+ * Prefer {@link processLockWorkerOptions}: the port arrives with a message, so
305
+ * the worker cannot lock during module initialization and must await
306
+ * {@link processLockAttached} first. The worker side needs no other change -
307
+ * `withProcessLock` works normally once the port lands.
308
+ */
309
+ export function attachProcessLock(worker) {
310
+ const port = createCoordinatorPort("attachProcessLock");
311
+ worker.postMessage({ type: ATTACH_MESSAGE_TYPE, port }, [port]);
312
+ }
313
+ /** A fresh coordinator-side channel, or a clear error off the main thread. */
314
+ function createCoordinatorPort(caller) {
315
+ if (!coordinator) {
316
+ throw new Error(`${caller}() must be called from the main thread`);
317
+ }
318
+ const { port1, port2 } = new MessageChannel();
319
+ coordinator.addPort(port1);
320
+ return port2;
321
+ }
322
+ /**
323
+ * In a worker, resolve once the {@link attachProcessLock} port has arrived.
324
+ *
325
+ * Only needed on the attach path, and safe to await regardless: it returns
326
+ * immediately when the worker already has a port (the
327
+ * {@link processLockWorkerOptions} case) or when called on the main thread, so
328
+ * shared worker code does not branch on how it was started.
329
+ *
330
+ * A `parentPort` listener keeps the worker alive, which is CORRECT here and
331
+ * deliberately not unref'd: this promise is pending work, and a worker allowed to
332
+ * exit while awaiting its port would die silently instead of locking. The
333
+ * listener is removed as soon as the port lands, so the worker is free to exit
334
+ * again the moment the wait is over.
335
+ */
336
+ export function processLockAttached() {
337
+ if (isMainThread || client || workerData?.[LOCK_PORT_KEY]) {
338
+ return Promise.resolve();
339
+ }
340
+ const port = parentPort;
341
+ if (!port) {
342
+ return Promise.reject(new Error("processLockAttached() must be called from a worker thread"));
343
+ }
344
+ return new Promise((resolve) => {
345
+ const onMessage = (message) => {
346
+ if (!object.isRecord(message) || message.type !== ATTACH_MESSAGE_TYPE)
347
+ return;
348
+ port.off("message", onMessage);
349
+ client = new LockClient(message.port);
350
+ resolve();
351
+ };
352
+ port.on("message", onMessage);
353
+ });
354
+ }
355
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvY2Vzcy1sb2NrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Byb2Nlc3MtbG9jay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E2Qkc7QUFFSCxPQUFPLEVBQ0wsWUFBWSxFQUNaLGNBQWMsRUFDZCxVQUFVLEVBQ1YsVUFBVSxHQUlYLE1BQU0scUJBQXFCLENBQUM7QUFDN0IsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFFN0Q7Ozs7OztHQU1HO0FBQ0gsTUFBTSxhQUFhLEdBQUcsMkJBQTJCLENBQUM7QUFDbEQsTUFBTSxtQkFBbUIsR0FBRyw2QkFBNkIsQ0FBQztBQTBDMUQ7Ozs7OztHQU1HO0FBQ0gsTUFBTSxlQUFlO0lBQ0YsTUFBTSxHQUFHLElBQUksR0FBRyxFQUFxQixDQUFDO0lBRXZELDhEQUE4RDtJQUM5RCxPQUFPLENBQUMsSUFBaUI7UUFDdkIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxPQUFvQixFQUFFLEVBQUU7WUFDMUMsUUFBUSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUM7Z0JBQ3JCLEtBQUssU0FBUztvQkFDWixJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQztvQkFDbkQsTUFBTTtnQkFDUixLQUFLLFNBQVM7b0JBQ1osSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztvQkFDN0MsTUFBTTtnQkFDUjtvQkFDRSxNQUFNO1lBQ1YsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0gsNkVBQTZFO1FBQzdFLDZFQUE2RTtRQUM3RSxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FB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QUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLG1CQUFtQjtnQkFBRSxPQUFPO1lBQzlFLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sR0FBRyxJQUFJLFVBQVUsQ0FBRSxPQUFvQyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3BFLE9BQU8sRUFBRSxDQUFDO1FBQ1osQ0FBQyxDQUFDO1FBQ0YsSUFBSSxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDaEMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBLZXllZCBtdXR1YWwgZXhjbHVzaW9uIGFjcm9zcyB0aGUgbWFpbiB0aHJlYWQgYW5kIGl0cyB3b3JrZXIgdGhyZWFkcy5cbiAqXG4gKiB7QGxpbmsgd2l0aFByb2Nlc3NMb2NrfSBzZXJpYWxpemVzIGNhbGxiYWNrcyB0aGF0IHNoYXJlIGEga2V5OiBvbmUgcnVucyBhdCBhXG4gKiB0aW1lLCB0aGUgcmVzdCBxdWV1ZSBpbiBhcnJpdmFsIG9yZGVyLCBhbmQgZGlmZmVyZW50IGtleXMgcHJvY2VlZFxuICogY29uY3VycmVudGx5LiBVbmxpa2UgYSBwbGFpbiBpbi1tb2R1bGUgYFByb21pc2VgIGNoYWluLCB0aGUgcXVldWUgaXMgc2hhcmVkIGJ5XG4gKiBldmVyeSB0aHJlYWQgd2lyZWQgdXAgdGhyb3VnaCB7QGxpbmsgcHJvY2Vzc0xvY2tXb3JrZXJPcHRpb25zfSwgc28gYSB3b3JrZXJcbiAqIHBvb2wgY2Fubm90IHJ1biB0d28gY2FsbGJhY2tzIGZvciB0aGUgc2FtZSBrZXkgYXQgb25jZS5cbiAqXG4gKiBUaGUgbmFtZSBzYXlzIGBwcm9jZXNzYDogdGhpcyBjb29yZGluYXRlcyB0aGUgVEhSRUFEUyBvZiBvbmUgTm9kZSBwcm9jZXNzLiBJdFxuICogaXMgbm90IGNyb3NzLXByb2Nlc3MgYW5kIG5vdCBjcm9zcy1ob3N0IC0gYSBzZWNvbmQgYG5vZGVgIGludm9jYXRpb24sIG9yIGFcbiAqIHNlY29uZCBhcHAgcmVwbGljYSwgaGFzIGl0cyBvd24gY29vcmRpbmF0b3IgYW5kIHNoYXJlcyBub3RoaW5nLiBXaGVuIHRoZSBzY29wZVxuICogaXMgYSBkZXBsb3ltZW50IHJhdGhlciB0aGFuIGEgcHJvY2VzcywgdXNlXG4gKiBgQGRieC10b29scy9wb3N0Z3Jlc2AncyBgd2l0aEFkdmlzb3J5TG9ja2AsIHdoaWNoIHB1dHMgdGhlIGFyYml0ZXIgaW5cbiAqIFBvc3RncmVTUUwgd2hlcmUgZXZlcnkgcmVwbGljYSBjYW4gc2VlIGl0LlxuICpcbiAqIFRoZSBtYWluIHRocmVhZCBvd25zIHRoZSBvbmx5IGNvb3JkaW5hdG9yLiBFYWNoIHBhcnRpY2lwYXRpbmcgdGhyZWFkIGdldHMgb25lXG4gKiBgTWVzc2FnZVBvcnRgIHRvIGl0LCBhbmQgYSBsb2NrIGlzIGdyYW50ZWQgYnkgYSBtZXNzYWdlIGJhY2sgb3ZlciB0aGF0IHBvcnQuXG4gKiBDb25zZXF1ZW50bHk6XG4gKlxuICogICAtIHRoZSBsb2NrIGlzIEFEVklTT1JZLCBsaWtlIFBvc3RncmVzIGFkdmlzb3J5IGxvY2tzIC0gaXQgcHJvdGVjdHMgYVxuICogICAgIGNyaXRpY2FsIHNlY3Rpb24gb25seSBpbnNvZmFyIGFzIGV2ZXJ5IHdyaXRlciB0YWtlcyB0aGUgc2FtZSBrZXk7XG4gKiAgIC0gZmFpcm5lc3MgaXMgRklGTyBwZXIga2V5LCBzaW5jZSB0aGUgY29vcmRpbmF0b3IgcXVldWVzIHdhaXRlcnMgaW4gdGhlXG4gKiAgICAgb3JkZXIgdGhlaXIgcmVxdWVzdHMgYXJyaXZlO1xuICogICAtIGEgdGhyZWFkIHRoYXQgZGllcyB3aGlsZSBob2xkaW5nIGEgbG9jayByZWxlYXNlcyBpdCwgYmVjYXVzZSBpdHMgcG9ydFxuICogICAgIGNsb3NpbmcgaXMgd2hhdCBoYW5kcyB0aGUga2V5IHRvIHRoZSBuZXh0IHdhaXRlciAoc2VlXG4gKiAgICAge0BsaW5rIExvY2tDb29yZGluYXRvci5yZW1vdmVQb3J0fSkuXG4gKlxuICogQG1vZHVsZVxuICovXG5cbmltcG9ydCB7XG4gIGlzTWFpblRocmVhZCxcbiAgTWVzc2FnZUNoYW5uZWwsXG4gIHBhcmVudFBvcnQsXG4gIHdvcmtlckRhdGEsXG4gIHR5cGUgTWVzc2FnZVBvcnQsXG4gIHR5cGUgV29ya2VyLFxuICB0eXBlIFdvcmtlck9wdGlvbnMsXG59IGZyb20gXCJub2RlOndvcmtlcl90aHJlYWRzXCI7XG5pbXBvcnQgeyBlcnJvciwgaGFzaCwgb2JqZWN0IH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcblxuLyoqXG4gKiBgd29ya2VyRGF0YWAgc2xvdCBjYXJyeWluZyB0aGUgY29vcmRpbmF0b3IgcG9ydCBpbnRvIGEgd29ya2VyLCBhbmQgdGhlXG4gKiBgcGFyZW50UG9ydGAgbWVzc2FnZSBgdHlwZWAgZm9yIHRoZSBsYXRlIHtAbGluayBhdHRhY2hQcm9jZXNzTG9ja30gaGFuZHNoYWtlLlxuICogTmFtZXNwYWNlZCBiZWNhdXNlIGJvdGggdHJhdmVsIHRocm91Z2ggY2hhbm5lbHMgYW4gYXBwbGljYXRpb24gYWxzbyB1c2VzOlxuICogYHdvcmtlckRhdGFgIGlzIHRoZSBjYWxsZXIncyBvd24gb2JqZWN0LCBhbmQgYHBhcmVudFBvcnRgIGNhcnJpZXMgdGhlIGNhbGxlcidzXG4gKiBvd24gbWVzc2FnZXMuXG4gKi9cbmNvbnN0IExPQ0tfUE9SVF9LRVkgPSBcIl9fZGJ4VG9vbHNQcm9jZXNzTG9ja1BvcnRcIjtcbmNvbnN0IEFUVEFDSF9NRVNTQUdFX1RZUEUgPSBcIl9fZGJ4VG9vbHNQcm9jZXNzTG9ja0F0dGFjaFwiO1xuXG4vKiogU2VudCBieSBhIGNsaWVudCB0byB0aGUgY29vcmRpbmF0b3IuICovXG50eXBlIExvY2tSZXF1ZXN0ID1cbiAgfCB7IHR5cGU6IFwiYWNxdWlyZVwiOyByZXF1ZXN0SWQ6IHN0cmluZzsga2V5OiBzdHJpbmcgfVxuICB8IHsgdHlwZTogXCJyZWxlYXNlXCI7IHJlcXVlc3RJZDogc3RyaW5nOyBrZXk6IHN0cmluZyB9O1xuXG4vKiogU2VudCBieSB0aGUgY29vcmRpbmF0b3IgdG8gdGhlIGNsaWVudCB0aGF0IG5vdyBvd25zIHRoZSBrZXkuICovXG50eXBlIExvY2tSZXNwb25zZSA9IHsgdHlwZTogXCJncmFudGVkXCI7IHJlcXVlc3RJZDogc3RyaW5nIH07XG5cbnR5cGUgTG9ja01lc3NhZ2UgPSBMb2NrUmVxdWVzdCB8IExvY2tSZXNwb25zZTtcblxuLyoqIFRoZSBgcGFyZW50UG9ydGAgZW52ZWxvcGUgdGhhdCBoYW5kcyBhIGxhdGUtYXR0YWNoZWQgd29ya2VyIGl0cyBwb3J0LiAqL1xuaW50ZXJmYWNlIEF0dGFjaE1lc3NhZ2Uge1xuICB0eXBlOiB0eXBlb2YgQVRUQUNIX01FU1NBR0VfVFlQRTtcbiAgcG9ydDogTWVzc2FnZVBvcnQ7XG59XG5cbi8qKiBPbmUgb3V0c3RhbmRpbmcgb3IgZ3JhbnRlZCBhY3F1aXNpdGlvbi4gKi9cbmludGVyZmFjZSBMb2NrV2FpdGVyIHtcbiAgcmVxdWVzdElkOiBzdHJpbmc7XG4gIHBvcnQ6IE1lc3NhZ2VQb3J0O1xufVxuXG4vKiogU2hhcGUgb2YgdGhlIGB3b3JrZXJEYXRhYCBzbGljZSB0aGlzIG1vZHVsZSByZWFkcy4gKi9cbmludGVyZmFjZSBMb2NrV29ya2VyRGF0YSB7XG4gIFtMT0NLX1BPUlRfS0VZXT86IE1lc3NhZ2VQb3J0O1xufVxuXG4vKipcbiAqIEEga2V5J3Mgb3duZXIgcGx1cyBpdHMgRklGTyBxdWV1ZSBvZiB3YWl0ZXJzLlxuICpcbiAqIE93bmVyIGFuZCBxdWV1ZSBsaXZlIGluIE9ORSBtYXAgZW50cnkgcmF0aGVyIHRoYW4gdHdvIHBhcmFsbGVsIG1hcHMgc28gYSBrZXlcbiAqIGNhbm5vdCBlbmQgdXAgaGFsZi1wcmVzZW50IC0gYSBxdWV1ZSB3aG9zZSBvd25lciBtYXAgZW50cnkgd2FzIGFscmVhZHkgZGVsZXRlZFxuICogd291bGQgc3RyYW5kIGl0cyB3YWl0ZXJzIGZvcmV2ZXIsIGFuZCB0aGUgZW50cnkgaXMgZHJvcHBlZCBvbmx5IHdoZW4gdGhlIGtleVxuICogaXMgYm90aCB1bm93bmVkIGFuZCB1bndhbnRlZC5cbiAqL1xuaW50ZXJmYWNlIExvY2tTdGF0ZSB7XG4gIG93bmVyOiBMb2NrV2FpdGVyO1xuICBxdWV1ZTogTG9ja1dhaXRlcltdO1xufVxuXG4vKipcbiAqIEFyYml0ZXIgZm9yIGV2ZXJ5IGtleSwgbGl2aW5nIG9uIHRoZSBtYWluIHRocmVhZC5cbiAqXG4gKiBIb2xkcyBubyB0aW1lcnMgYW5kIG5vIGhhbmRsZXMgb2YgaXRzIG93bjogYSBwb3J0IGlzIHVucmVmJ2QgYnkgaXRzIGNsaWVudFxuICogd2hpbGUgaWRsZSAoc2VlIHtAbGluayBMb2NrQ2xpZW50fSksIHNvIGFuIGlkbGUgY29vcmRpbmF0b3IgbmV2ZXIga2VlcHMgdGhlXG4gKiBwcm9jZXNzIGFsaXZlLlxuICovXG5jbGFzcyBMb2NrQ29vcmRpbmF0b3Ige1xuICBwcml2YXRlIHJlYWRvbmx5IHN0YXRlcyA9IG5ldyBNYXA8c3RyaW5nLCBMb2NrU3RhdGU+KCk7XG5cbiAgLyoqIFNlcnZlIG9uZSBjbGllbnQuIENhbGxlZCBvbmNlIHBlciBwYXJ0aWNpcGF0aW5nIHRocmVhZC4gKi9cbiAgYWRkUG9ydChwb3J0OiBNZXNzYWdlUG9ydCk6IHZvaWQge1xuICAgIHBvcnQub24oXCJtZXNzYWdlXCIsIChtZXNzYWdlOiBMb2NrTWVzc2FnZSkgPT4ge1xuICAgICAgc3dpdGNoIChtZXNzYWdlLnR5cGUpIHtcbiAgICAgICAgY2FzZSBcImFjcXVpcmVcIjpcbiAgICAgICAgICB0aGlzLmFjcXVpcmUobWVzc2FnZS5rZXksIG1lc3NhZ2UucmVxdWVzdElkLCBwb3J0KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcInJlbGVhc2VcIjpcbiAgICAgICAgICB0aGlzLnJlbGVhc2UobWVzc2FnZS5rZXksIG1lc3NhZ2UucmVxdWVzdElkKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9KTtcbiAgICAvLyBBIGNsb3NlZCBwb3J0IG1lYW5zIGl0cyB0aHJlYWQgZXhpdGVkIG9yIHdhcyB0ZXJtaW5hdGVkLiBSZWxlYXNpbmcgaGVyZSBpc1xuICAgIC8vIHdoYXQga2VlcHMgb25lIGNyYXNoZWQgd29ya2VyIGZyb20gd2VkZ2luZyBhIGtleSBmb3IgdGhlIHByb2Nlc3MgbGlmZXRpbWUuXG4gICAgcG9ydC5vbihcImNsb3NlXCIsICgpID0+IHRoaXMucmVtb3ZlUG9ydChwb3J0KSk7XG4gICAgLy8gVGhlIGNvb3JkaW5hdG9yIHNpZGUgc3RheXMgdW5yZWYnZCBmb3IgaXRzIHdob2xlIGxpZmUuIEl0IGlzIGEgcHVyZVxuICAgIC8vIHJlc3BvbmRlciAtIGl0IG5ldmVyIGhhcyBidXNpbmVzcyBvZiBpdHMgb3duIHBlbmRpbmcgLSBzbyBrZWVwaW5nIHRoZVxuICAgIC8vIGV2ZW50IGxvb3AgYWxpdmUgZm9yIGl0IHdvdWxkIG1lYW4gYSBwcm9jZXNzIHRoYXQgdXNlZCBhIGxvY2sgb25jZSBjb3VsZFxuICAgIC8vIG5ldmVyIGV4aXQuIEEgcmVxdWVzdCBhbHdheXMgYXJyaXZlcyBmcm9tIGEgY2xpZW50IHRoYXQgaGFzIHJlZidkIElUU1xuICAgIC8vIHBvcnQsIHNvIHRoZSBsb29wIGlzIGF3YWtlIHdoZW5ldmVyIHRoZXJlIGlzIGFjdHVhbGx5IHNvbWV0aGluZyB0byBzZXJ2ZS5cbiAgICBwb3J0LnVucmVmKCk7XG4gICAgcG9ydC5zdGFydCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBhY3F1aXJlKGtleTogc3RyaW5nLCByZXF1ZXN0SWQ6IHN0cmluZywgcG9ydDogTWVzc2FnZVBvcnQpOiB2b2lkIHtcbiAgICBjb25zdCB3YWl0ZXI6IExvY2tXYWl0ZXIgPSB7IHJlcXVlc3RJZCwgcG9ydCB9O1xuICAgIGNvbnN0IHN0YXRlID0gdGhpcy5zdGF0ZXMuZ2V0KGtleSk7XG4gICAgaWYgKCFzdGF0ZSkge1xuICAgICAgdGhpcy5zdGF0ZXMuc2V0KGtleSwgeyBvd25lcjogd2FpdGVyLCBxdWV1ZTogW10gfSk7XG4gICAgICBncmFudCh3YWl0ZXIpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBzdGF0ZS5xdWV1ZS5wdXNoKHdhaXRlcik7XG4gIH1cblxuICAvKipcbiAgICogSGFuZCB0aGUga2V5IG9uLCBpZ25vcmluZyBhIHJlbGVhc2UgZnJvbSBhbnlvbmUgYnV0IHRoZSBjdXJyZW50IG93bmVyLlxuICAgKlxuICAgKiBBIHN0YWxlIHJlbGVhc2UgaXMgZXhwZWN0ZWQsIG5vdCBkZWZlbnNpdmUgY29kaW5nOiBhbiBhYm9ydGVkIGFjcXVpc2l0aW9uXG4gICAqIHNlbmRzIG9uZSBmb3IgYSByZXF1ZXN0IHRoYXQgbmV2ZXIgb3duZWQgdGhlIGtleSwgYW5kIGhvbm91cmluZyBpdCB3b3VsZFxuICAgKiByZXZva2UgdGhlIGxvY2sgZnJvbSB3aG9ldmVyIGhvbGRzIGl0IG5vdy5cbiAgICovXG4gIHByaXZhdGUgcmVsZWFzZShrZXk6IHN0cmluZywgcmVxdWVzdElkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBzdGF0ZSA9IHRoaXMuc3RhdGVzLmdldChrZXkpO1xuICAgIGlmIChzdGF0ZT8ub3duZXIucmVxdWVzdElkICE9PSByZXF1ZXN0SWQpIHJldHVybjtcbiAgICB0aGlzLmdyYW50TmV4dChrZXksIHN0YXRlKTtcbiAgfVxuXG4gIC8qKiBQcm9tb3RlIHRoZSBuZXh0IHdhaXRlciwgb3IgZHJvcCB0aGUga2V5IHdoZW4gbm9ib2R5IHdhbnRzIGl0LiAqL1xuICBwcml2YXRlIGdyYW50TmV4dChrZXk6IHN0cmluZywgc3RhdGU6IExvY2tTdGF0ZSk6IHZvaWQge1xuICAgIGNvbnN0IG5leHQgPSBzdGF0ZS5xdWV1ZS5zaGlmdCgpO1xuICAgIGlmICghbmV4dCkge1xuICAgICAgdGhpcy5zdGF0ZXMuZGVsZXRlKGtleSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHN0YXRlLm93bmVyID0gbmV4dDtcbiAgICBncmFudChuZXh0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEcm9wIGEgZGVhZCB0aHJlYWQgZnJvbSBldmVyeSBrZXk6IHJlbGVhc2UgdGhlIG9uZXMgaXQgb3duZWQgYW5kIHJlbW92ZSBpdFxuICAgKiBmcm9tIHRoZSBxdWV1ZXMgaXQgd2FzIHdhaXRpbmcgaW4uXG4gICAqXG4gICAqIFF1ZXVlIHJlbW92YWwgbXVzdCBoYXBwZW4gRklSU1QuIEEgdGhyZWFkIGNhbiBhcHBlYXIgYXMgYm90aCB0aGUgb3duZXIgb2ZcbiAgICogb25lIGtleSBhbmQgYSB3YWl0ZXIgZm9yIGFub3RoZXIsIGFuZCBwcm9tb3RpbmcgaXQgb3V0IG9mIGEgcXVldWUgaXQgY2FuIG5vXG4gICAqIGxvbmdlciBhbnN3ZXIgZm9yIHdvdWxkIGdyYW50IGEgbG9jayB0byBhIGNsb3NlZCBwb3J0IC0gc3RhbGxpbmcgdGhhdCBrZXlcbiAgICogdW50aWwgdGhlIHByb2Nlc3MgZW5kcy5cbiAgICovXG4gIHByaXZhdGUgcmVtb3ZlUG9ydChwb3J0OiBNZXNzYWdlUG9ydCk6IHZvaWQge1xuICAgIGZvciAoY29uc3Qgc3RhdGUgb2YgdGhpcy5zdGF0ZXMudmFsdWVzKCkpIHtcbiAgICAgIGlmIChzdGF0ZS5xdWV1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgIHN0YXRlLnF1ZXVlID0gc3RhdGUucXVldWUuZmlsdGVyKCh3YWl0ZXIpID0+IHdhaXRlci5wb3J0ICE9PSBwb3J0KTtcbiAgICAgIH1cbiAgICB9XG4gICAgZm9yIChjb25zdCBba2V5LCBzdGF0ZV0gb2YgWy4uLnRoaXMuc3RhdGVzXSkge1xuICAgICAgaWYgKHN0YXRlLm93bmVyLnBvcnQgPT09IHBvcnQpIHRoaXMuZ3JhbnROZXh0KGtleSwgc3RhdGUpO1xuICAgIH1cbiAgfVxufVxuXG4vKiogTm90aWZ5IGEgd2FpdGVyIHRoYXQgaXQgbm93IG93bnMgaXRzIGtleS4gKi9cbmZ1bmN0aW9uIGdyYW50KHdhaXRlcjogTG9ja1dhaXRlcik6IHZvaWQge1xuICB3YWl0ZXIucG9ydC5wb3N0TWVzc2FnZSh7IHR5cGU6IFwiZ3JhbnRlZFwiLCByZXF1ZXN0SWQ6IHdhaXRlci5yZXF1ZXN0SWQgfSBzYXRpc2ZpZXMgTG9ja1Jlc3BvbnNlKTtcbn1cblxuLyoqXG4gKiBBIHRocmVhZCdzIGVuZCBvZiB0aGUgY29udmVyc2F0aW9uOiBzZW5kcyByZXF1ZXN0cywgYXdhaXRzIGdyYW50cywgYW5kIHJ1bnNcbiAqIGNhbGxiYWNrcy5cbiAqXG4gKiBPd25zIHRoZSBldmVudC1sb29wIGJvb2trZWVwaW5nLiBUaGUgcG9ydCBpcyB1bnJlZidkIHdoaWxlIGlkbGUgc28gaG9sZGluZyBhXG4gKiBsb2NrIG1vZHVsZSBuZXZlciBibG9ja3MgcHJvY2VzcyBleGl0LCBhbmQgcmVmJ2QgZXhhY3RseSB3aGlsZSB0aGlzIHRocmVhZCBoYXNcbiAqIGFuIG91dHN0YW5kaW5nIHJlcXVlc3Qgb3IgYW4gdW5yZWxlYXNlZCBsb2NrIC0gb3RoZXJ3aXNlIE5vZGUgd291bGQgY29uc2lkZXJcbiAqIGl0c2VsZiBvdXQgb2Ygd29yayBhbmQgZXhpdCBtaWQtY3JpdGljYWwtc2VjdGlvbiwgZHJvcHBpbmcgdGhlIGdyYW50IHRoYXQgd2FzXG4gKiBhbHJlYWR5IG9uIGl0cyB3YXkuXG4gKi9cbmNsYXNzIExvY2tDbGllbnQge1xuICBwcml2YXRlIHJlYWRvbmx5IHBlbmRpbmcgPSBuZXcgTWFwPHN0cmluZywgKGVycm9yPzogRXJyb3IpID0+IHZvaWQ+KCk7XG4gIC8qKiBSZXF1ZXN0cyArIGhlbGQgbG9ja3MuIFRoZSBwb3J0IGlzIHJlZidkIHdoaWxlIHRoaXMgaXMgYWJvdmUgemVyby4gKi9cbiAgcHJpdmF0ZSBhY3RpdmUgPSAwO1xuICBwcml2YXRlIGNsb3NlZCA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgcG9ydDogTWVzc2FnZVBvcnQpIHtcbiAgICBwb3J0Lm9uKFwibWVzc2FnZVwiLCAobWVzc2FnZTogTG9ja01lc3NhZ2UpID0+IHtcbiAgICAgIGlmIChtZXNzYWdlLnR5cGUgIT09IFwiZ3JhbnRlZFwiKSByZXR1cm47XG4gICAgICB0aGlzLnNldHRsZShtZXNzYWdlLnJlcXVlc3RJZCk7XG4gICAgfSk7XG4gICAgcG9ydC5vbihcImNsb3NlXCIsICgpID0+IHtcbiAgICAgIHRoaXMuY2xvc2VkID0gdHJ1ZTtcbiAgICAgIC8vIFRoZSBjb29yZGluYXRvciBpcyBnb25lIChtYWluIHRocmVhZCBleGl0aW5nLCBvciB0aGlzIHdvcmtlciBiZWluZyB0b3JuXG4gICAgICAvLyBkb3duKS4gRmFpbCB0aGUgd2FpdGVycyByYXRoZXIgdGhhbiBoYW5nIHRoZW06IGEgY2FsbGVyIGJsb2NrZWQgb24gYVxuICAgICAgLy8gbG9jayB0aGF0IGNhbiBuZXZlciBiZSBncmFudGVkIGlzIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gYSBkZWFkbG9jay5cbiAgICAgIGNvbnN0IGNsb3NlRXJyb3IgPSBuZXcgRXJyb3IoXCJQcm9jZXNzIGxvY2sgcG9ydCBjbG9zZWQgYmVmb3JlIHRoZSBsb2NrIHdhcyBncmFudGVkXCIpO1xuICAgICAgZm9yIChjb25zdCBzZXR0bGUgb2YgWy4uLnRoaXMucGVuZGluZy52YWx1ZXMoKV0pIHNldHRsZShjbG9zZUVycm9yKTtcbiAgICB9KTtcbiAgICBwb3J0LnVucmVmKCk7XG4gICAgcG9ydC5zdGFydCgpO1xuICB9XG5cbiAgLyoqIFJlc29sdmUgb3IgcmVqZWN0IG9uZSBwZW5kaW5nIHJlcXVlc3QgYW5kIGRyb3AgaXRzIHJlZi4gKi9cbiAgcHJpdmF0ZSBzZXR0bGUocmVxdWVzdElkOiBzdHJpbmcsIGZhaWx1cmU/OiBFcnJvcik6IHZvaWQge1xuICAgIGNvbnN0IHNldHRsZSA9IHRoaXMucGVuZGluZy5nZXQocmVxdWVzdElkKTtcbiAgICBpZiAoIXNldHRsZSkgcmV0dXJuO1xuICAgIHRoaXMucGVuZGluZy5kZWxldGUocmVxdWVzdElkKTtcbiAgICBzZXR0bGUoZmFpbHVyZSk7XG4gIH1cblxuICAvKiogUmVmIHRoZSBwb3J0IGZvciB0aGUgZmlyc3QgdW5pdCBvZiBvdXRzdGFuZGluZyB3b3JrLiAqL1xuICBwcml2YXRlIHJldGFpbigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5hY3RpdmUrKyA9PT0gMCkgdGhpcy5wb3J0LnJlZigpO1xuICB9XG5cbiAgLyoqIFVucmVmIG9uY2Ugbm90aGluZyBpcyBvdXRzdGFuZGluZywgc28gdGhlIHRocmVhZCBjYW4gZXhpdC4gKi9cbiAgcHJpdmF0ZSByZWxlYXNlKCk6IHZvaWQge1xuICAgIGlmICgtLXRoaXMuYWN0aXZlID09PSAwKSB0aGlzLnBvcnQudW5yZWYoKTtcbiAgfVxuXG4gIGFzeW5jIHJ1bjxUPihrZXk6IHN0cmluZywgZm46ICgpID0+IFQgfCBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgaWYgKHRoaXMuY2xvc2VkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJQcm9jZXNzIGxvY2sgcG9ydCBpcyBjbG9zZWRcIik7XG4gICAgfVxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IGhhc2guaWQoKTtcbiAgICB0aGlzLnJldGFpbigpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHRoaXMucGVuZGluZy5zZXQocmVxdWVzdElkLCAoZmFpbHVyZSkgPT4gKGZhaWx1cmUgPyByZWplY3QoZmFpbHVyZSkgOiByZXNvbHZlKCkpKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2UoeyB0eXBlOiBcImFjcXVpcmVcIiwgcmVxdWVzdElkLCBrZXkgfSBzYXRpc2ZpZXMgTG9ja1JlcXVlc3QpO1xuICAgICAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgICAgIHRoaXMucGVuZGluZy5kZWxldGUocmVxdWVzdElkKTtcbiAgICAgICAgICByZWplY3QoZXJyb3IudG9FcnJvcihjYXVzZSkpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChjYXVzZSkge1xuICAgICAgLy8gTmV2ZXIgZ3JhbnRlZCwgc28gdGhlcmUgaXMgbm90aGluZyB0byByZWxlYXNlIC0ganVzdCBkcm9wIHRoZSByZWYuXG4gICAgICB0aGlzLnJlbGVhc2UoKTtcbiAgICAgIHRocm93IGNhdXNlO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IGZuKCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIC8vIFBvc3QgYmVmb3JlIHVucmVmJ2luZzogdGhlIHJlbGVhc2UgbXVzdCBiZSBpbiBmbGlnaHQgd2hpbGUgdGhlIHBvcnQgaXNcbiAgICAgIC8vIHN0aWxsIGhvbGRpbmcgdGhlIGxvb3Agb3Blbiwgb3IgdGhlIG5leHQgd2FpdGVyIGlzIHN0cmFuZGVkLlxuICAgICAgaWYgKCF0aGlzLmNsb3NlZCkge1xuICAgICAgICB0aGlzLnBvcnQucG9zdE1lc3NhZ2UoeyB0eXBlOiBcInJlbGVhc2VcIiwgcmVxdWVzdElkLCBrZXkgfSBzYXRpc2ZpZXMgTG9ja1JlcXVlc3QpO1xuICAgICAgfVxuICAgICAgdGhpcy5yZWxlYXNlKCk7XG4gICAgfVxuICB9XG59XG5cbi8qKiBUaGUgY29vcmRpbmF0b3IsIG9uIHRoZSBtYWluIHRocmVhZCBvbmx5LiAqL1xuY29uc3QgY29vcmRpbmF0b3IgPSBpc01haW5UaHJlYWQgPyBuZXcgTG9ja0Nvb3JkaW5hdG9yKCkgOiB1bmRlZmluZWQ7XG5cbi8qKlxuICogVGhpcyB0aHJlYWQncyBjbGllbnQsIGNyZWF0ZWQgb24gZmlyc3QgdXNlLlxuICpcbiAqIExhenkgc28gaW1wb3J0aW5nIHRoaXMgbW9kdWxlIGNvc3RzIG5vdGhpbmcgYW5kLCBtb3JlIGltcG9ydGFudGx5LCBzbyBhIHdvcmtlclxuICogdGhhdCBuZXZlciBsb2NrcyBhbnl0aGluZyBpcyBuZXZlciBmb3JjZWQgdG8gaGF2ZSBiZWVuIHN0YXJ0ZWQgdGhyb3VnaFxuICoge0BsaW5rIHByb2Nlc3NMb2NrV29ya2VyT3B0aW9uc30uIFRoZSBtYWluIHRocmVhZCB3aXJlcyBhIGNoYW5uZWwgdG8gaXRzIG93blxuICogY29vcmRpbmF0b3I7IGEgd29ya2VyIGFkb3B0cyB0aGUgcG9ydCBpdCB3YXMgaGFuZGVkLlxuICovXG5sZXQgY2xpZW50OiBMb2NrQ2xpZW50IHwgdW5kZWZpbmVkO1xuXG5mdW5jdGlvbiBsb2NrQ2xpZW50KCk6IExvY2tDbGllbnQge1xuICBpZiAoY2xpZW50KSByZXR1cm4gY2xpZW50O1xuICBpZiAoY29vcmRpbmF0b3IpIHtcbiAgICBjb25zdCB7IHBvcnQxLCBwb3J0MiB9ID0gbmV3IE1lc3NhZ2VDaGFubmVsKCk7XG4gICAgY29vcmRpbmF0b3IuYWRkUG9ydChwb3J0MSk7XG4gICAgY2xpZW50ID0gbmV3IExvY2tDbGllbnQocG9ydDIpO1xuICAgIHJldHVybiBjbGllbnQ7XG4gIH1cbiAgY29uc3QgcG9ydCA9ICh3b3JrZXJEYXRhIGFzIExvY2tXb3JrZXJEYXRhIHwgdW5kZWZpbmVkKT8uW0xPQ0tfUE9SVF9LRVldO1xuICBpZiAoIXBvcnQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBcIlRoaXMgd29ya2VyIGhhcyBubyBwcm9jZXNzLWxvY2sgcG9ydC4gU3RhcnQgaXQgd2l0aCBwcm9jZXNzTG9ja1dvcmtlck9wdGlvbnMoKSBcIiArXG4gICAgICAgIFwiKG9yIGNhbGwgYXR0YWNoUHJvY2Vzc0xvY2sod29ya2VyKSBhbmQgYXdhaXQgcHJvY2Vzc0xvY2tBdHRhY2hlZCgpKS5cIixcbiAgICApO1xuICB9XG4gIGNsaWVudCA9IG5ldyBMb2NrQ2xpZW50KHBvcnQpO1xuICByZXR1cm4gY2xpZW50O1xufVxuXG4vKipcbiAqIFJ1biBgZm5gIHdoaWxlIGhvbGRpbmcgdGhlIGxvY2sgbmFtZWQgYnkgYGtleWAsIHJlbGVhc2luZyBpdCB3aGVuIGBmbmBcbiAqIHNldHRsZXMuXG4gKlxuICogQ2FsbGVycyBzaGFyaW5nIGEga2V5IGFyZSBzZXJpYWxpemVkIGFjcm9zcyB0aGUgbWFpbiB0aHJlYWQgYW5kIGV2ZXJ5IHdvcmtlclxuICogc3RhcnRlZCB0aHJvdWdoIHtAbGluayBwcm9jZXNzTG9ja1dvcmtlck9wdGlvbnN9OyBkaXN0aW5jdCBrZXlzIG5ldmVyIGJsb2NrXG4gKiBlYWNoIG90aGVyLiBSZXR1cm5zIHdoYXRldmVyIGBmbmAgcmV0dXJucyBhbmQgcHJvcGFnYXRlcyB3aGF0IGl0IHRocm93cywgc28gaXRcbiAqIGRyb3BzIGludG8gYW4gZXhpc3RpbmcgZXhwcmVzc2lvbiB3aXRob3V0IHJlc3RydWN0dXJpbmcuXG4gKlxuICogYGtleWAgaXMgYW55IHZhbHVlIHdpdGggYSBzdGFibGUgaWRlbnRpdHkgLSBhIHN0cmluZywgYSBgW1wiaW52b2ljZVwiLCBpZF1gXG4gKiB0dXBsZSwgYSBjb25maWcgb2JqZWN0IC0gY2Fub25pY2FsaXplZCBieSBgb2JqZWN0LnRvU3RhYmxlS2V5YCwgdGhlIHNhbWUgcnVsZVxuICogYEBkYngtdG9vbHMvcG9zdGdyZXNgIHVzZXMgZm9yIGFkdmlzb3J5LWxvY2sgaWRzIGFuZCBjaGFubmVsIG5hbWVzLiBTdHJ1Y3R1cmVcbiAqIGlzIHBhcnQgb2YgdGhlIGlkZW50aXR5OiBgW1wiaW52b2ljZVwiLCA3XWAgYW5kIGBcImludm9pY2VfN1wiYCBhcmUgZGlmZmVyZW50XG4gKiBsb2Nrcy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYXdhaXQgd2l0aFByb2Nlc3NMb2NrKFtcImNhY2hlXCIsIG5hbWVdLCBhc3luYyAoKSA9PiB7XG4gKiAgIGlmICghKGF3YWl0IGV4aXN0cyhuYW1lKSkpIGF3YWl0IGJ1aWxkKG5hbWUpO1xuICogfSk7XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3aXRoUHJvY2Vzc0xvY2s8VD4oa2V5OiB1bmtub3duLCBmbjogKCkgPT4gVCB8IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgcmV0dXJuIGxvY2tDbGllbnQoKS5ydW4obG9ja0tleShrZXkpLCBmbik7XG59XG5cbi8qKiBDYW5vbmljYWwgc3RyaW5nIGlkZW50aXR5IGZvciBhIGxvY2sga2V5IChzZWUgYG9iamVjdC50b1N0YWJsZUtleWApLiAqL1xuZnVuY3Rpb24gbG9ja0tleShrZXk6IHVua25vd24pOiBzdHJpbmcge1xuICByZXR1cm4gb2JqZWN0XG4gICAgLnRvT25lT3JNYW55KGtleSlcbiAgICAubWFwKChwYXJ0KSA9PiBvYmplY3QudG9TdGFibGVLZXkocGFydCkpXG4gICAgLmpvaW4oXCJcXHUwMDAwXCIpO1xufVxuXG4vKipcbiAqIEFkZCB0aGUgY29vcmRpbmF0b3IgcG9ydCB0byBhIGBXb3JrZXJgJ3Mgb3B0aW9ucyBzbyB0aGUgd29ya2VyIGNhbiBsb2NrXG4gKiBpbW1lZGlhdGVseSAtIGR1cmluZyBtb2R1bGUgaW5pdGlhbGl6YXRpb24sIGJlZm9yZSBhbnkgbWVzc2FnZSBpcyBoYW5kbGVkLlxuICpcbiAqIFByZXNlcnZlcyB0aGUgY2FsbGVyJ3MgYHdvcmtlckRhdGFgIGFuZCBgdHJhbnNmZXJMaXN0YDsgdGhlIHBvcnQgaXNcbiAqIHRyYW5zZmVycmVkLCBhcyBgTWVzc2FnZVBvcnRgIGNhbm5vdCBiZSBjbG9uZWQuXG4gKlxuICogQGV4YW1wbGVcbiAqIG5ldyBXb3JrZXIodXJsLCBwcm9jZXNzTG9ja1dvcmtlck9wdGlvbnMoeyB3b3JrZXJEYXRhOiB7IHRlbmFudCB9IH0pKTtcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByb2Nlc3NMb2NrV29ya2VyT3B0aW9ucyhvcHRpb25zOiBXb3JrZXJPcHRpb25zID0ge30pOiBXb3JrZXJPcHRpb25zIHtcbiAgY29uc3QgcG9ydCA9IGNyZWF0ZUNvb3JkaW5hdG9yUG9ydChcInByb2Nlc3NMb2NrV29ya2VyT3B0aW9uc1wiKTtcbiAgY29uc3QgZXhpc3RpbmcgPSBvYmplY3QuaXNSZWNvcmQob3B0aW9ucy53b3JrZXJEYXRhKSA/IG9wdGlvbnMud29ya2VyRGF0YSA6IHt9O1xuICByZXR1cm4ge1xuICAgIC4uLm9wdGlvbnMsXG4gICAgd29ya2VyRGF0YTogeyAuLi5leGlzdGluZywgW0xPQ0tfUE9SVF9LRVldOiBwb3J0IH0sXG4gICAgdHJhbnNmZXJMaXN0OiBbLi4uKG9wdGlvbnMudHJhbnNmZXJMaXN0ID8/IFtdKSwgcG9ydF0sXG4gIH07XG59XG5cbi8qKlxuICogV2lyZSBhbiBBTFJFQURZLVJVTk5JTkcgd29ya2VyIGludG8gdGhlIGxvY2ssIGZvciBhIHdvcmtlciB0aGlzIGNvZGUgZGlkIG5vdFxuICogY29uc3RydWN0IChhIHBvb2wgZnJvbSBhIGxpYnJhcnksIHNheSkuXG4gKlxuICogUHJlZmVyIHtAbGluayBwcm9jZXNzTG9ja1dvcmtlck9wdGlvbnN9OiB0aGUgcG9ydCBhcnJpdmVzIHdpdGggYSBtZXNzYWdlLCBzb1xuICogdGhlIHdvcmtlciBjYW5ub3QgbG9jayBkdXJpbmcgbW9kdWxlIGluaXRpYWxpemF0aW9uIGFuZCBtdXN0IGF3YWl0XG4gKiB7QGxpbmsgcHJvY2Vzc0xvY2tBdHRhY2hlZH0gZmlyc3QuIFRoZSB3b3JrZXIgc2lkZSBuZWVkcyBubyBvdGhlciBjaGFuZ2UgLVxuICogYHdpdGhQcm9jZXNzTG9ja2Agd29ya3Mgbm9ybWFsbHkgb25jZSB0aGUgcG9ydCBsYW5kcy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFByb2Nlc3NMb2NrKHdvcmtlcjogV29ya2VyKTogdm9pZCB7XG4gIGNvbnN0IHBvcnQgPSBjcmVhdGVDb29yZGluYXRvclBvcnQoXCJhdHRhY2hQcm9jZXNzTG9ja1wiKTtcbiAgd29ya2VyLnBvc3RNZXNzYWdlKHsgdHlwZTogQVRUQUNIX01FU1NBR0VfVFlQRSwgcG9ydCB9IHNhdGlzZmllcyBBdHRhY2hNZXNzYWdlLCBbcG9ydF0pO1xufVxuXG4vKiogQSBmcmVzaCBjb29yZGluYXRvci1zaWRlIGNoYW5uZWwsIG9yIGEgY2xlYXIgZXJyb3Igb2ZmIHRoZSBtYWluIHRocmVhZC4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUNvb3JkaW5hdG9yUG9ydChjYWxsZXI6IHN0cmluZyk6IE1lc3NhZ2VQb3J0IHtcbiAgaWYgKCFjb29yZGluYXRvcikge1xuICAgIHRocm93IG5ldyBFcnJvcihgJHtjYWxsZXJ9KCkgbXVzdCBiZSBjYWxsZWQgZnJvbSB0aGUgbWFpbiB0aHJlYWRgKTtcbiAgfVxuICBjb25zdCB7IHBvcnQxLCBwb3J0MiB9ID0gbmV3IE1lc3NhZ2VDaGFubmVsKCk7XG4gIGNvb3JkaW5hdG9yLmFkZFBvcnQocG9ydDEpO1xuICByZXR1cm4gcG9ydDI7XG59XG5cbi8qKlxuICogSW4gYSB3b3JrZXIsIHJlc29sdmUgb25jZSB0aGUge0BsaW5rIGF0dGFjaFByb2Nlc3NMb2NrfSBwb3J0IGhhcyBhcnJpdmVkLlxuICpcbiAqIE9ubHkgbmVlZGVkIG9uIHRoZSBhdHRhY2ggcGF0aCwgYW5kIHNhZmUgdG8gYXdhaXQgcmVnYXJkbGVzczogaXQgcmV0dXJuc1xuICogaW1tZWRpYXRlbHkgd2hlbiB0aGUgd29ya2VyIGFscmVhZHkgaGFzIGEgcG9ydCAodGhlXG4gKiB7QGxpbmsgcHJvY2Vzc0xvY2tXb3JrZXJPcHRpb25zfSBjYXNlKSBvciB3aGVuIGNhbGxlZCBvbiB0aGUgbWFpbiB0aHJlYWQsIHNvXG4gKiBzaGFyZWQgd29ya2VyIGNvZGUgZG9lcyBub3QgYnJhbmNoIG9uIGhvdyBpdCB3YXMgc3RhcnRlZC5cbiAqXG4gKiBBIGBwYXJlbnRQb3J0YCBsaXN0ZW5lciBrZWVwcyB0aGUgd29ya2VyIGFsaXZlLCB3aGljaCBpcyBDT1JSRUNUIGhlcmUgYW5kXG4gKiBkZWxpYmVyYXRlbHkgbm90IHVucmVmJ2Q6IHRoaXMgcHJvbWlzZSBpcyBwZW5kaW5nIHdvcmssIGFuZCBhIHdvcmtlciBhbGxvd2VkIHRvXG4gKiBleGl0IHdoaWxlIGF3YWl0aW5nIGl0cyBwb3J0IHdvdWxkIGRpZSBzaWxlbnRseSBpbnN0ZWFkIG9mIGxvY2tpbmcuIFRoZVxuICogbGlzdGVuZXIgaXMgcmVtb3ZlZCBhcyBzb29uIGFzIHRoZSBwb3J0IGxhbmRzLCBzbyB0aGUgd29ya2VyIGlzIGZyZWUgdG8gZXhpdFxuICogYWdhaW4gdGhlIG1vbWVudCB0aGUgd2FpdCBpcyBvdmVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvY2Vzc0xvY2tBdHRhY2hlZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgaWYgKGlzTWFpblRocmVhZCB8fCBjbGllbnQgfHwgKHdvcmtlckRhdGEgYXMgTG9ja1dvcmtlckRhdGEgfCB1bmRlZmluZWQpPy5bTE9DS19QT1JUX0tFWV0pIHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKCk7XG4gIH1cbiAgY29uc3QgcG9ydCA9IHBhcmVudFBvcnQ7XG4gIGlmICghcG9ydCkge1xuICAgIHJldHVybiBQcm9taXNlLnJlamVjdChuZXcgRXJyb3IoXCJwcm9jZXNzTG9ja0F0dGFjaGVkKCkgbXVzdCBiZSBjYWxsZWQgZnJvbSBhIHdvcmtlciB0aHJlYWRcIikpO1xuICB9XG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPigocmVzb2x2ZSkgPT4ge1xuICAgIGNvbnN0IG9uTWVzc2FnZSA9IChtZXNzYWdlOiB1bmtub3duKTogdm9pZCA9PiB7XG4gICAgICBpZiAoIW9iamVjdC5pc1JlY29yZChtZXNzYWdlKSB8fCBtZXNzYWdlLnR5cGUgIT09IEFUVEFDSF9NRVNTQUdFX1RZUEUpIHJldHVybjtcbiAgICAgIHBvcnQub2ZmKFwibWVzc2FnZVwiLCBvbk1lc3NhZ2UpO1xuICAgICAgY2xpZW50ID0gbmV3IExvY2tDbGllbnQoKG1lc3NhZ2UgYXMgdW5rbm93biBhcyBBdHRhY2hNZXNzYWdlKS5wb3J0KTtcbiAgICAgIHJlc29sdmUoKTtcbiAgICB9O1xuICAgIHBvcnQub24oXCJtZXNzYWdlXCIsIG9uTWVzc2FnZSk7XG4gIH0pO1xufVxuIl19
@@ -1 +1 @@
1
- {"root":["../src/brand.ts","../src/exec.ts","../src/file.ts","../src/project.ts","../index.ts"],"version":"5.9.3"}
1
+ {"root":["../src/bin.ts","../src/brand.ts","../src/exec.ts","../src/file.ts","../src/process-lock.ts","../src/project.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -23,7 +23,9 @@
23
23
  "typescript": "^5.9.3"
24
24
  },
25
25
  "dependencies": {
26
- "@dbx-tools/shared-core": "0.6.65",
26
+ "@dbx-tools/shared-core": "0.6.67",
27
+ "extract-zip": "^2.0.1",
28
+ "tar": "^7.5.22",
27
29
  "yaml": "^2.9.0"
28
30
  },
29
31
  "main": "./lib/index.js",
@@ -40,7 +42,7 @@
40
42
  "./package.json": "./package.json"
41
43
  }
42
44
  },
43
- "version": "0.6.65",
45
+ "version": "0.6.67",
44
46
  "types": "./lib/index.d.ts",
45
47
  "type": "module",
46
48
  "exports": {