@blokjs/trigger-cron 0.6.17 → 0.6.19

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.
@@ -9,7 +9,7 @@
9
9
  *
10
10
  * Uses the 'cron' package for cron parsing and scheduling.
11
11
  */
12
- import { DefaultLogger, NodeMap, TriggerBase, } from "@blokjs/runner";
12
+ import { DefaultLogger, DeferredDispatchSignal, NodeMap, TriggerBase, WaitDispatchRequest, } from "@blokjs/runner";
13
13
  import { SpanStatusCode, metrics, trace } from "@opentelemetry/api";
14
14
  import { CronJob } from "cron";
15
15
  import { v4 as uuid } from "uuid";
@@ -58,6 +58,19 @@ export class CronTrigger extends TriggerBase {
58
58
  async listen() {
59
59
  const startTime = this.startCounter();
60
60
  try {
61
+ // F5 · install crash/orphan/janitor/shutdown handlers so a
62
+ // cron-only process gets the same run-state integrity + storage
63
+ // hygiene guarantees as HTTP/Worker. Each handler is idempotent
64
+ // + individually kill-switched.
65
+ this.installOperationalHandlers(this.logger);
66
+ // F6 · feed the WorkflowRegistry from the nodeMap so `subworkflow:`
67
+ // steps + trigger/workflow/process-global middleware resolve in a
68
+ // cron-only deployment (no HTTP trigger to populate the registry).
69
+ this.registerWorkflowsFromNodeMap(this.logger);
70
+ // F14 · seed the process-global middleware chain from
71
+ // `BLOK_GLOBAL_MIDDLEWARE` (idempotent — programmatic
72
+ // setGlobalMiddleware takes precedence).
73
+ this.seedGlobalMiddlewareFromEnv(this.logger);
61
74
  // Find all workflows with cron triggers
62
75
  const cronWorkflows = this.getCronWorkflows();
63
76
  if (cronWorkflows.length === 0) {
@@ -288,6 +301,29 @@ export class CronTrigger extends TriggerBase {
288
301
  resolve(response);
289
302
  }
290
303
  catch (error) {
304
+ // F5 · a cron workflow with a `wait` step (or a scheduling
305
+ // gate) throws DeferredDispatchSignal / WaitDispatchRequest
306
+ // to defer the run — that's a successful deferral, NOT a
307
+ // failure. TriggerBase.run already marked the run
308
+ // delayed/queued/debounced and (for HTTP) persisted the
309
+ // dispatch. Cron's in-process scheduler owns the eventual
310
+ // re-fire, so we just record success and don't bump
311
+ // `cron_errors`.
312
+ if (error instanceof DeferredDispatchSignal || error instanceof WaitDispatchRequest) {
313
+ span.setAttribute("success", true);
314
+ span.setAttribute("deferred", true);
315
+ span.setStatus({ code: SpanStatusCode.OK });
316
+ cronExecutions.add(1, {
317
+ env: process.env.NODE_ENV,
318
+ job_id: jobId,
319
+ workflow_name: this.configuration.name,
320
+ manual: String(manual),
321
+ success: "true",
322
+ });
323
+ this.logger.log(`Cron job deferred ${jobId}: ${error.message}`);
324
+ resolve({ ctx: {}, metrics: {} });
325
+ return;
326
+ }
291
327
  const errorMessage = error.message;
292
328
  // Set span error
293
329
  span.setAttribute("success", false);
@@ -312,4 +348,4 @@ export class CronTrigger extends TriggerBase {
312
348
  }
313
349
  }
314
350
  export default CronTrigger;
315
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3JvblRyaWdnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvQ3JvblRyaWdnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7R0FVRztBQUdILE9BQU8sRUFFTixhQUFhLEVBRWIsT0FBTyxFQUNQLFdBQVcsR0FFWCxNQUFNLGdCQUFnQixDQUFDO0FBRXhCLE9BQU8sRUFBYSxjQUFjLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQy9FLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLEVBQUUsSUFBSSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUE0RGxDOztHQUVHO0FBQ0gsTUFBTSxPQUFnQixXQUFZLFNBQVEsV0FBVztJQUMxQyxPQUFPLEdBQWtCLEVBQW1CLENBQUM7SUFDcEMsTUFBTSxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxJQUFJLHVCQUF1QixFQUNuRCxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsSUFBSSxPQUFPLENBQ3RDLENBQUM7SUFDaUIsTUFBTSxHQUFHLElBQUksYUFBYSxFQUFFLENBQUM7SUFDdEMsSUFBSSxHQUE4QixJQUFJLEdBQUcsRUFBRSxDQUFDO0lBTXREO1FBQ0MsS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDakIsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQ3RCLENBQUM7SUFFRDs7T0FFRztJQUNILFNBQVM7UUFDUixJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssR0FBRyxJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQ25DLE1BQU0sUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3pDLEtBQUssTUFBTSxHQUFHLElBQUksUUFBUSxFQUFFLENBQUM7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QUFDO29CQUNoQixNQUFNLFlBQVksR0FBSSxLQUFlLENBQUMsT0FBTyxDQUFDO29CQUU5QyxpQkFBaUI7b0JBQ2pCLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO29CQUNwQyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQWMsQ0FBQyxDQUFDO29CQUNyQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLGNBQWMsQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUM7b0JBRXRFLHVCQUF1QjtvQkFDdkIsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUU7d0JBQ2pCLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVE7d0JBQ3pCLE1BQU0sRUFBRSxLQUFLO3dCQUNiLGFBQWEsRUFBRSxJQUFJLENBQUMsYUFBYSxFQUFFLElBQUksSUFBSSxTQUFTO3dCQUNwRCxNQUFNLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQztxQkFDdEIsQ0FBQyxDQUFDO29CQUVILElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLG1CQUFtQixLQUFLLEtBQUssWUFBWSxFQUFFLEVBQUcsS0FBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUV2RixPQUFPLENBQUMsRUFBRSxHQUFHLEVBQUUsRUFBYSxFQUFFLE9BQU8sRUFBRSxFQUFpQixFQUFFLENBQUMsQ0FBQztnQkFDN0QsQ0FBQzt3QkFBUyxDQUFDO29CQUNWLFlBQVksQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDO29CQUM3QixJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ1osQ0FBQztZQUNGLENBQUMsQ0FBQyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0NBQ0Q7QUFFRCxlQUFlLFdBQVcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ3JvblRyaWdnZXIgLSBTY2hlZHVsZWQgd29ya2Zsb3cgZXhlY3V0aW9uIGJhc2VkIG9uIGNyb24gZXhwcmVzc2lvbnNcbiAqXG4gKiBFeHRlbmRzIFRyaWdnZXJCYXNlIHRvIHN1cHBvcnQgc2NoZWR1bGVkIHRyaWdnZXJzOlxuICogLSBDcm9uIGV4cHJlc3Npb25zIChlLmcuLCBcIjAgKiAqICogKlwiIGZvciBob3VybHkpXG4gKiAtIFRpbWV6b25lLWF3YXJlIHNjaGVkdWxpbmdcbiAqIC0gT3ZlcmxhcCBwcmV2ZW50aW9uXG4gKiAtIE1hbnVhbCB0cmlnZ2VyIHN1cHBvcnRcbiAqXG4gKiBVc2VzIHRoZSAnY3JvbicgcGFja2FnZSBmb3IgY3JvbiBwYXJzaW5nIGFuZCBzY2hlZHVsaW5nLlxuICovXG5cbmltcG9ydCB0eXBlIHsgQ3JvblRyaWdnZXJPcHRzLCBIZWxwZXJSZXNwb25zZSB9IGZyb20gXCJAYmxva2pzL2hlbHBlclwiO1xuaW1wb3J0IHtcblx0dHlwZSBCbG9rU2VydmljZSxcblx0RGVmYXVsdExvZ2dlcixcblx0dHlwZSBHbG9iYWxPcHRpb25zLFxuXHROb2RlTWFwLFxuXHRUcmlnZ2VyQmFzZSxcblx0dHlwZSBUcmlnZ2VyUmVzcG9uc2UsXG59IGZyb20gXCJAYmxva2pzL3J1bm5lclwiO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0LCBNZXRyaWNzVHlwZSwgUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiQGJsb2tqcy9zaGFyZWRcIjtcbmltcG9ydCB7IHR5cGUgU3BhbiwgU3BhblN0YXR1c0NvZGUsIG1ldHJpY3MsIHRyYWNlIH0gZnJvbSBcIkBvcGVudGVsZW1ldHJ5L2FwaVwiO1xuaW1wb3J0IHsgQ3JvbkpvYiB9IGZyb20gXCJjcm9uXCI7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSBcInV1aWRcIjtcblxuLyoqXG4gKiBTY2hlZHVsZWQgam9iIGluZm9ybWF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2NoZWR1bGVkSm9iIHtcblx0LyoqIFVuaXF1ZSBqb2IgSUQgKi9cblx0aWQ6IHN0cmluZztcblx0LyoqIFdvcmtmbG93IHBhdGggKi9cblx0d29ya2Zsb3dQYXRoOiBzdHJpbmc7XG5cdC8qKiBDcm9uIGV4cHJlc3Npb24gKi9cblx0c2NoZWR1bGU6IHN0cmluZztcblx0LyoqIFRpbWV6b25lICovXG5cdHRpbWV6b25lOiBzdHJpbmc7XG5cdC8qKiBBbGxvdyBvdmVybGFwcGluZyBleGVjdXRpb25zICovXG5cdG92ZXJsYXA6IGJvb2xlYW47XG5cdC8qKiBXaGV0aGVyIHRoZSBqb2IgaXMgY3VycmVudGx5IHJ1bm5pbmcgKi9cblx0cnVubmluZzogYm9vbGVhbjtcblx0LyoqIExhc3QgZXhlY3V0aW9uIHRpbWUgKi9cblx0bGFzdFJ1bj86IERhdGU7XG5cdC8qKiBOZXh0IHNjaGVkdWxlZCB0aW1lICovXG5cdG5leHRSdW4/OiBEYXRlO1xuXHQvKiogSW50ZXJuYWwgQ3JvbkpvYiBpbnN0YW5jZSAqL1xuXHRqb2I6IENyb25Kb2I7XG59XG5cbi8qKlxuICogRXhlY3V0aW9uIGNvbnRleHQgcGFzc2VkIHRvIHRoZSB3b3JrZmxvd1xuICovXG5leHBvcnQgaW50ZXJmYWNlIENyb25FeGVjdXRpb25Db250ZXh0IHtcblx0LyoqIEpvYiBJRCAqL1xuXHRqb2JJZDogc3RyaW5nO1xuXHQvKiogU2NoZWR1bGVkIHRpbWUgKHdoZW4gaXQgd2FzIHN1cHBvc2VkIHRvIHJ1bikgKi9cblx0c2NoZWR1bGVkVGltZTogRGF0ZTtcblx0LyoqIEFjdHVhbCBleGVjdXRpb24gdGltZSAqL1xuXHRleGVjdXRpb25UaW1lOiBEYXRlO1xuXHQvKiogQ3JvbiBleHByZXNzaW9uICovXG5cdHNjaGVkdWxlOiBzdHJpbmc7XG5cdC8qKiBUaW1lem9uZSAqL1xuXHR0aW1lem9uZTogc3RyaW5nO1xuXHQvKiogV2hldGhlciB0aGlzIGlzIGEgbWFudWFsIHRyaWdnZXIgKi9cblx0bWFudWFsOiBib29sZWFuO1xufVxuXG4vKipcbiAqIFdvcmtmbG93IG1vZGVsIHdpdGggY3JvbiB0cmlnZ2VyIGNvbmZpZ3VyYXRpb25cbiAqL1xuaW50ZXJmYWNlIENyb25Xb3JrZmxvd01vZGVsIHtcblx0cGF0aDogc3RyaW5nO1xuXHRjb25maWc6IHtcblx0XHRuYW1lOiBzdHJpbmc7XG5cdFx0dmVyc2lvbjogc3RyaW5nO1xuXHRcdHRyaWdnZXI/OiB7XG5cdFx0XHRjcm9uPzogQ3JvblRyaWdnZXJPcHRzO1xuXHRcdFx0W2tleTogc3RyaW5nXTogdW5rbm93bjtcblx0XHR9O1xuXHRcdFtrZXk6IHN0cmluZ106IHVua25vd247XG5cdH07XG59XG5cbi8qKlxuICogQ3JvblRyaWdnZXIgLSBTY2hlZHVsZWQgd29ya2Zsb3cgZXhlY3V0aW9uXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBDcm9uVHJpZ2dlciBleHRlbmRzIFRyaWdnZXJCYXNlIHtcblx0cHJvdGVjdGVkIG5vZGVNYXA6IEdsb2JhbE9wdGlvbnMgPSB7fSBhcyBHbG9iYWxPcHRpb25zO1xuXHRwcm90ZWN0ZWQgcmVhZG9ubHkgdHJhY2VyID0gdHJhY2UuZ2V0VHJhY2VyKFxuXHRcdHByb2Nlc3MuZW52LlBST0pFQ1RfTkFNRSB8fCBcInRyaWdnZXItY3Jvbi13b3JrZmxvd1wiLFxuXHRcdHByb2Nlc3MuZW52LlBST0pFQ1RfVkVSU0lPTiB8fCBcIjAuMC4xXCIsXG5cdCk7XG5cdHByb3RlY3RlZCByZWFkb25seSBsb2dnZXIgPSBuZXcgRGVmYXVsdExvZ2dlcigpO1xuXHRwcm90ZWN0ZWQgam9iczogTWFwPHN0cmluZywgU2NoZWR1bGVkSm9iPiA9IG5ldyBNYXAoKTtcblxuXHQvLyBTdWJjbGFzc2VzIHByb3ZpZGUgdGhlc2Vcblx0cHJvdGVjdGVkIGFic3RyYWN0IG5vZGVzOiBSZWNvcmQ8c3RyaW5nLCBCbG9rU2VydmljZTx1bmtub3duPj47XG5cdHByb3RlY3RlZCBhYnN0cmFjdCB3b3JrZmxvd3M6IFJlY29yZDxzdHJpbmcsIEhlbHBlclJlc3BvbnNlPjtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHRzdXBlcigpO1xuXHRcdHRoaXMubG9hZE5vZGVzKCk7XG5cdFx0dGhpcy5sb2FkV29ya2Zsb3dzKCk7XG5cdH1cblxuXHQvKipcblx0ICogTG9hZCBub2RlcyBpbnRvIHRoZSBub2RlIG1hcFxuXHQgKi9cblx0bG9hZE5vZGVzKCk6IHZvaWQge1xuXHRcdHRoaXMubm9kZU1hcC5ub2RlcyA9IG5ldyBOb2RlTWFwKCk7XG5cdFx0Y29uc3Qgbm9kZUtleXMgPSBPYmplY3Qua2V5cyh0aGlzLm5vZGVzKTtcblx0XHRmb3IgKGNvbnN0IGtleSBvZiBub2RlS2V5cykge1xuXHRcdFx0dGhpcy5ub2RlTWFwLm5vZGVzLmFkZE5vZGUoa2V5LCB0aGlzLm5vZGVzW2tleV0pO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBMb2FkIHdvcmtmbG93cyBpbnRvIHRoZSB3b3JrZmxvdyBtYXBcblx0ICovXG5cdGxvYWRXb3JrZmxvd3MoKTogdm9pZCB7XG5cdFx0dGhpcy5ub2RlTWFwLndvcmtmbG93cyA9IHRoaXMud29ya2Zsb3dzO1xuXHR9XG5cblx0LyoqXG5cdCAqIENvbnZlcnQgY3JvbiBEYXRlVGltZSB0byBEYXRlXG5cdCAqIFRoZSBjcm9uIHBhY2thZ2UgdXNlcyBsdXhvbiBEYXRlVGltZSB3aGljaCBoYXMgdG9KU0RhdGUoKVxuXHQgKi9cblx0cHJvdGVjdGVkIHRvRGF0ZShkYXRlVGltZTogdW5rbm93bik6IERhdGUge1xuXHRcdGlmIChkYXRlVGltZSAmJiB0eXBlb2YgZGF0ZVRpbWUgPT09IFwib2JqZWN0XCIgJiYgXCJ0b0pTRGF0ZVwiIGluIGRhdGVUaW1lKSB7XG5cdFx0XHRyZXR1cm4gKGRhdGVUaW1lIGFzIHsgdG9KU0RhdGU6ICgpID0+IERhdGUgfSkudG9KU0RhdGUoKTtcblx0XHR9XG5cdFx0cmV0dXJuIGRhdGVUaW1lIGluc3RhbmNlb2YgRGF0ZSA/IGRhdGVUaW1lIDogbmV3IERhdGUoZGF0ZVRpbWUgYXMgc3RyaW5nIHwgbnVtYmVyKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTdGFydCB0aGUgY3JvbiBzY2hlZHVsZXIgLSBtYWluIGVudHJ5IHBvaW50XG5cdCAqL1xuXHRhc3luYyBsaXN0ZW4oKTogUHJvbWlzZTxudW1iZXI+IHtcblx0XHRjb25zdCBzdGFydFRpbWUgPSB0aGlzLnN0YXJ0Q291bnRlcigpO1xuXG5cdFx0dHJ5IHtcblx0XHRcdC8vIEZpbmQgYWxsIHdvcmtmbG93cyB3aXRoIGNyb24gdHJpZ2dlcnNcblx0XHRcdGNvbnN0IGNyb25Xb3JrZmxvd3MgPSB0aGlzLmdldENyb25Xb3JrZmxvd3MoKTtcblxuXHRcdFx0aWYgKGNyb25Xb3JrZmxvd3MubGVuZ3RoID09PSAwKSB7XG5cdFx0XHRcdHRoaXMubG9nZ2VyLmxvZyhcIk5vIHdvcmtmbG93cyB3aXRoIGNyb24gdHJpZ2dlcnMgZm91bmRcIik7XG5cdFx0XHRcdHJldHVybiB0aGlzLmVuZENvdW50ZXIoc3RhcnRUaW1lKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ3JlYXRlIGFuZCBzdGFydCBjcm9uIGpvYnMgZm9yIGVhY2ggd29ya2Zsb3dcblx0XHRcdGZvciAoY29uc3Qgd29ya2Zsb3cgb2YgY3JvbldvcmtmbG93cykge1xuXHRcdFx0XHRjb25zdCBjb25maWcgPSB3b3JrZmxvdy5jb25maWcudHJpZ2dlcj8uY3JvbiBhcyBDcm9uVHJpZ2dlck9wdHM7XG5cdFx0XHRcdGNvbnN0IGpvYklkID0gYGNyb24tJHt3b3JrZmxvdy5wYXRofS0ke3V1aWQoKS5zbGljZSgwLCA4KX1gO1xuXG5cdFx0XHRcdC8vIGBDcm9uVHJpZ2dlck9wdHNgIGlzIGB6LmlucHV0POKApj5gIHNvIGB0aW1lem9uZWAgaXMgYHN0cmluZyB8IHVuZGVmaW5lZGBcblx0XHRcdFx0Ly8gZXZlbiB0aG91Z2ggdGhlIHNjaGVtYSBkZWNsYXJlcyBgLmRlZmF1bHQoXCJVVENcIilgLiBBcHBseSB0aGVcblx0XHRcdFx0Ly8gZGVmYXVsdCBvbmNlIGhlcmUgc28gdGhlIHJlc3Qgb2YgdGhpcyBtZXRob2QgKGFuZCB0aGUgY3JvbiBsaWInc1xuXHRcdFx0XHQvLyBjb25zdHJ1Y3Rvcikgc2VlcyBhIGd1YXJhbnRlZWQgc3RyaW5nLlxuXHRcdFx0XHRjb25zdCB0aW1lem9uZSA9IGNvbmZpZy50aW1lem9uZSA/PyBcIlVUQ1wiO1xuXG5cdFx0XHRcdHRoaXMubG9nZ2VyLmxvZyhgU2NoZWR1bGluZyB3b3JrZmxvdzogJHt3b3JrZmxvdy5wYXRofSB3aXRoIHNjaGVkdWxlOiAke2NvbmZpZy5zY2hlZHVsZX0gKCR7dGltZXpvbmV9KWApO1xuXG5cdFx0XHRcdGNvbnN0IGpvYiA9IG5ldyBDcm9uSm9iKFxuXHRcdFx0XHRcdGNvbmZpZy5zY2hlZHVsZSxcblx0XHRcdFx0XHRhc3luYyAoKSA9PiB7XG5cdFx0XHRcdFx0XHRhd2FpdCB0aGlzLmV4ZWN1dGVXb3JrZmxvdyhqb2JJZCwgd29ya2Zsb3csIGNvbmZpZywgZmFsc2UpO1xuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0bnVsbCwgLy8gb25Db21wbGV0ZVxuXHRcdFx0XHRcdGZhbHNlLCAvLyBzdGFydFxuXHRcdFx0XHRcdHRpbWV6b25lLFxuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdGNvbnN0IHNjaGVkdWxlZEpvYjogU2NoZWR1bGVkSm9iID0ge1xuXHRcdFx0XHRcdGlkOiBqb2JJZCxcblx0XHRcdFx0XHR3b3JrZmxvd1BhdGg6IHdvcmtmbG93LnBhdGgsXG5cdFx0XHRcdFx0c2NoZWR1bGU6IGNvbmZpZy5zY2hlZHVsZSxcblx0XHRcdFx0XHR0aW1lem9uZSxcblx0XHRcdFx0XHRvdmVybGFwOiBjb25maWcub3ZlcmxhcCA/PyBmYWxzZSxcblx0XHRcdFx0XHRydW5uaW5nOiBmYWxzZSxcblx0XHRcdFx0XHRuZXh0UnVuOiB0aGlzLnRvRGF0ZShqb2IubmV4dERhdGUoKSksXG5cdFx0XHRcdFx0am9iLFxuXHRcdFx0XHR9O1xuXG5cdFx0XHRcdHRoaXMuam9icy5zZXQoam9iSWQsIHNjaGVkdWxlZEpvYik7XG5cblx0XHRcdFx0Ly8gU3RhcnQgdGhlIGpvYlxuXHRcdFx0XHRqb2Iuc3RhcnQoKTtcblx0XHRcdFx0dGhpcy5sb2dnZXIubG9nKGBKb2IgJHtqb2JJZH0gc3RhcnRlZC4gTmV4dCBydW46ICR7c2NoZWR1bGVkSm9iLm5leHRSdW59YCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMubG9nZ2VyLmxvZyhgQ3JvbiB0cmlnZ2VyIHN0YXJ0ZWQuICR7dGhpcy5qb2JzLnNpemV9IGpvYihzKSBzY2hlZHVsZWRgKTtcblxuXHRcdFx0Ly8gRW5hYmxlIEhNUiBpbiBkZXZlbG9wbWVudCBtb2RlXG5cdFx0XHRpZiAocHJvY2Vzcy5lbnYuQkxPS19ITVIgPT09IFwidHJ1ZVwiIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBcImRldmVsb3BtZW50XCIpIHtcblx0XHRcdFx0YXdhaXQgdGhpcy5lbmFibGVIb3RSZWxvYWQoKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoaXMuZW5kQ291bnRlcihzdGFydFRpbWUpO1xuXHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHR0aGlzLmxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIHN0YXJ0IGNyb24gdHJpZ2dlcjogJHsoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG5cdFx0XHR0aHJvdyBlcnJvcjtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogU3RvcCBhbGwgY3JvbiBqb2JzXG5cdCAqL1xuXHRhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGZvciAoY29uc3QgW2pvYklkLCBzY2hlZHVsZWRKb2JdIG9mIHRoaXMuam9icykge1xuXHRcdFx0c2NoZWR1bGVkSm9iLmpvYi5zdG9wKCk7XG5cdFx0XHR0aGlzLmxvZ2dlci5sb2coYEpvYiAke2pvYklkfSBzdG9wcGVkYCk7XG5cdFx0fVxuXHRcdHRoaXMuam9icy5jbGVhcigpO1xuXHRcdHRoaXMubG9nZ2VyLmxvZyhcIkNyb24gdHJpZ2dlciBzdG9wcGVkXCIpO1xuXHR9XG5cblx0cHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIG9uSG1yV29ya2Zsb3dDaGFuZ2UoKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0dGhpcy5sb2dnZXIubG9nKFwiW0hNUl0gQ3JvbiB3b3JrZmxvdyBjaGFuZ2VkLCByZWxvYWRpbmcuLi5cIik7XG5cdFx0YXdhaXQgdGhpcy53YWl0Rm9ySW5GbGlnaHRSZXF1ZXN0cygpO1xuXHRcdGF3YWl0IHRoaXMuc3RvcCgpO1xuXHRcdHRoaXMubG9hZFdvcmtmbG93cygpO1xuXHRcdGF3YWl0IHRoaXMubGlzdGVuKCk7XG5cdH1cblxuXHQvKipcblx0ICogTWFudWFsbHkgdHJpZ2dlciBhIHNwZWNpZmljIGpvYlxuXHQgKi9cblx0YXN5bmMgdHJpZ2dlckpvYihqb2JJZDogc3RyaW5nKTogUHJvbWlzZTxUcmlnZ2VyUmVzcG9uc2UgfCBudWxsPiB7XG5cdFx0Y29uc3Qgc2NoZWR1bGVkSm9iID0gdGhpcy5qb2JzLmdldChqb2JJZCk7XG5cdFx0aWYgKCFzY2hlZHVsZWRKb2IpIHtcblx0XHRcdHRoaXMubG9nZ2VyLmVycm9yKGBKb2Igbm90IGZvdW5kOiAke2pvYklkfWApO1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXG5cdFx0Ly8gR2V0IHRoZSB3b3JrZmxvd1xuXHRcdGNvbnN0IHdvcmtmbG93ID0gdGhpcy5nZXRXb3JrZmxvd0J5UGF0aChzY2hlZHVsZWRKb2Iud29ya2Zsb3dQYXRoKTtcblx0XHRpZiAoIXdvcmtmbG93KSB7XG5cdFx0XHR0aGlzLmxvZ2dlci5lcnJvcihgV29ya2Zsb3cgbm90IGZvdW5kOiAke3NjaGVkdWxlZEpvYi53b3JrZmxvd1BhdGh9YCk7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cblx0XHRjb25zdCBjb25maWcgPSB3b3JrZmxvdy5jb25maWcudHJpZ2dlcj8uY3JvbiBhcyBDcm9uVHJpZ2dlck9wdHM7XG5cdFx0cmV0dXJuIHRoaXMuZXhlY3V0ZVdvcmtmbG93KGpvYklkLCB3b3JrZmxvdywgY29uZmlnLCB0cnVlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBHZXQgYWxsIHNjaGVkdWxlZCBqb2JzXG5cdCAqL1xuXHRnZXRKb2JzKCk6IFNjaGVkdWxlZEpvYltdIHtcblx0XHRyZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmpvYnMudmFsdWVzKCkpLm1hcCgoam9iKSA9PiAoe1xuXHRcdFx0Li4uam9iLFxuXHRcdFx0bmV4dFJ1bjogdGhpcy50b0RhdGUoam9iLmpvYi5uZXh0RGF0ZSgpKSxcblx0XHR9KSk7XG5cdH1cblxuXHQvKipcblx0ICogR2V0IGFsbCB3b3JrZmxvd3MgdGhhdCBoYXZlIGNyb24gdHJpZ2dlcnNcblx0ICovXG5cdHByb3RlY3RlZCBnZXRDcm9uV29ya2Zsb3dzKCk6IENyb25Xb3JrZmxvd01vZGVsW10ge1xuXHRcdGNvbnN0IHdvcmtmbG93czogQ3JvbldvcmtmbG93TW9kZWxbXSA9IFtdO1xuXG5cdFx0Zm9yIChjb25zdCBbcGF0aCwgd29ya2Zsb3ddIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMubm9kZU1hcC53b3JrZmxvd3MgfHwge30pKSB7XG5cdFx0XHRjb25zdCB3b3JrZmxvd0NvbmZpZyA9ICh3b3JrZmxvdyBhcyB1bmtub3duIGFzIHsgX2NvbmZpZzogQ3JvbldvcmtmbG93TW9kZWxbXCJjb25maWdcIl0gfSkuX2NvbmZpZztcblxuXHRcdFx0aWYgKHdvcmtmbG93Q29uZmlnPy50cmlnZ2VyKSB7XG5cdFx0XHRcdGNvbnN0IHRyaWdnZXJUeXBlID0gT2JqZWN0LmtleXMod29ya2Zsb3dDb25maWcudHJpZ2dlcilbMF07XG5cblx0XHRcdFx0aWYgKHRyaWdnZXJUeXBlID09PSBcImNyb25cIiAmJiB3b3JrZmxvd0NvbmZpZy50cmlnZ2VyLmNyb24pIHtcblx0XHRcdFx0XHR3b3JrZmxvd3MucHVzaCh7XG5cdFx0XHRcdFx0XHRwYXRoLFxuXHRcdFx0XHRcdFx0Y29uZmlnOiB3b3JrZmxvd0NvbmZpZyxcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB3b3JrZmxvd3M7XG5cdH1cblxuXHQvKipcblx0ICogR2V0IHdvcmtmbG93IGJ5IHBhdGhcblx0ICovXG5cdHByb3RlY3RlZCBnZXRXb3JrZmxvd0J5UGF0aChwYXRoOiBzdHJpbmcpOiBDcm9uV29ya2Zsb3dNb2RlbCB8IG51bGwge1xuXHRcdGNvbnN0IHdvcmtmbG93ID0gdGhpcy5ub2RlTWFwLndvcmtmbG93cz8uW3BhdGhdO1xuXHRcdGlmICghd29ya2Zsb3cpIHJldHVybiBudWxsO1xuXG5cdFx0Y29uc3Qgd29ya2Zsb3dDb25maWcgPSAod29ya2Zsb3cgYXMgdW5rbm93biBhcyB7IF9jb25maWc6IENyb25Xb3JrZmxvd01vZGVsW1wiY29uZmlnXCJdIH0pLl9jb25maWc7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHBhdGgsXG5cdFx0XHRjb25maWc6IHdvcmtmbG93Q29uZmlnLFxuXHRcdH07XG5cdH1cblxuXHQvKipcblx0ICogRXhlY3V0ZSBhIHdvcmtmbG93XG5cdCAqL1xuXHRwcm90ZWN0ZWQgYXN5bmMgZXhlY3V0ZVdvcmtmbG93KFxuXHRcdGpvYklkOiBzdHJpbmcsXG5cdFx0d29ya2Zsb3c6IENyb25Xb3JrZmxvd01vZGVsLFxuXHRcdGNvbmZpZzogQ3JvblRyaWdnZXJPcHRzLFxuXHRcdG1hbnVhbDogYm9vbGVhbixcblx0KTogUHJvbWlzZTxUcmlnZ2VyUmVzcG9uc2U+IHtcblx0XHRjb25zdCBzY2hlZHVsZWRKb2IgPSB0aGlzLmpvYnMuZ2V0KGpvYklkKTtcblx0XHRpZiAoIXNjaGVkdWxlZEpvYikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBKb2Igbm90IGZvdW5kOiAke2pvYklkfWApO1xuXHRcdH1cblxuXHRcdC8vIENoZWNrIGZvciBvdmVybGFwXG5cdFx0aWYgKHNjaGVkdWxlZEpvYi5ydW5uaW5nICYmICFzY2hlZHVsZWRKb2Iub3ZlcmxhcCkge1xuXHRcdFx0dGhpcy5sb2dnZXIubG9nKGBTa2lwcGluZyAke2pvYklkfTogcHJldmlvdXMgZXhlY3V0aW9uIHN0aWxsIHJ1bm5pbmcgKG92ZXJsYXAgZGlzYWJsZWQpYCk7XG5cdFx0XHRyZXR1cm4geyBjdHg6IHt9IGFzIENvbnRleHQsIG1ldHJpY3M6IHt9IGFzIE1ldHJpY3NUeXBlIH07XG5cdFx0fVxuXG5cdFx0Y29uc3QgZXhlY3V0aW9uSWQgPSB1dWlkKCk7XG5cdFx0Y29uc3QgbGFzdERhdGUgPSBzY2hlZHVsZWRKb2Iuam9iLmxhc3REYXRlKCk7XG5cdFx0Y29uc3Qgc2NoZWR1bGVkVGltZSA9IGxhc3REYXRlID8gbmV3IERhdGUobGFzdERhdGUgYXMgdW5rbm93biBhcyBzdHJpbmcgfCBudW1iZXIpIDogbmV3IERhdGUoKTtcblx0XHRjb25zdCBleGVjdXRpb25UaW1lID0gbmV3IERhdGUoKTtcblxuXHRcdC8vIEFwcGx5IHRoZSBzY2hlbWEgZGVmYXVsdCDigJQgc2VlIGV4cGxhbmF0aW9uIGluIGBsaXN0ZW4oKWAuXG5cdFx0Y29uc3QgdGltZXpvbmUgPSBjb25maWcudGltZXpvbmUgPz8gXCJVVENcIjtcblxuXHRcdGNvbnN0IGRlZmF1bHRNZXRlciA9IG1ldHJpY3MuZ2V0TWV0ZXIoXCJkZWZhdWx0XCIpO1xuXHRcdGNvbnN0IGNyb25FeGVjdXRpb25zID0gZGVmYXVsdE1ldGVyLmNyZWF0ZUNvdW50ZXIoXCJjcm9uX2V4ZWN1dGlvbnNcIiwge1xuXHRcdFx0ZGVzY3JpcHRpb246IFwiQ3JvbiBqb2IgZXhlY3V0aW9uc1wiLFxuXHRcdH0pO1xuXHRcdGNvbnN0IGNyb25FcnJvcnMgPSBkZWZhdWx0TWV0ZXIuY3JlYXRlQ291bnRlcihcImNyb25fZXJyb3JzXCIsIHtcblx0XHRcdGRlc2NyaXB0aW9uOiBcIkNyb24gam9iIGV4ZWN1dGlvbiBlcnJvcnNcIixcblx0XHR9KTtcblxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuXHRcdFx0dGhpcy50cmFjZXIuc3RhcnRBY3RpdmVTcGFuKGBjcm9uOiR7d29ya2Zsb3cucGF0aH1gLCBhc3luYyAoc3BhbjogU3BhbikgPT4ge1xuXHRcdFx0XHRzY2hlZHVsZWRKb2IucnVubmluZyA9IHRydWU7XG5cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRjb25zdCBzdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuXG5cdFx0XHRcdFx0Ly8gSW5pdGlhbGl6ZSBjb25maWd1cmF0aW9uIGZvciB0aGlzIHdvcmtmbG93XG5cdFx0XHRcdFx0YXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXQod29ya2Zsb3cucGF0aCwgdGhpcy5ub2RlTWFwKTtcblxuXHRcdFx0XHRcdC8vIENyZWF0ZSBjb250ZXh0XG5cdFx0XHRcdFx0Y29uc3QgY3R4OiBDb250ZXh0ID0gdGhpcy5jcmVhdGVDb250ZXh0KHVuZGVmaW5lZCwgd29ya2Zsb3cucGF0aCwgZXhlY3V0aW9uSWQpO1xuXG5cdFx0XHRcdFx0Ly8gQ3JlYXRlIGV4ZWN1dGlvbiBjb250ZXh0XG5cdFx0XHRcdFx0Y29uc3QgY3JvbkNvbnRleHQ6IENyb25FeGVjdXRpb25Db250ZXh0ID0ge1xuXHRcdFx0XHRcdFx0am9iSWQsXG5cdFx0XHRcdFx0XHRzY2hlZHVsZWRUaW1lLFxuXHRcdFx0XHRcdFx0ZXhlY3V0aW9uVGltZSxcblx0XHRcdFx0XHRcdHNjaGVkdWxlOiBjb25maWcuc2NoZWR1bGUsXG5cdFx0XHRcdFx0XHR0aW1lem9uZSxcblx0XHRcdFx0XHRcdG1hbnVhbCxcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0Ly8gUG9wdWxhdGUgcmVxdWVzdCB3aXRoIGNyb24gY29udGV4dFxuXHRcdFx0XHRcdGN0eC5yZXF1ZXN0ID0ge1xuXHRcdFx0XHRcdFx0Ym9keTogY3JvbkNvbnRleHQsXG5cdFx0XHRcdFx0XHRoZWFkZXJzOiB7XG5cdFx0XHRcdFx0XHRcdFwieC1jcm9uLWpvYi1pZFwiOiBqb2JJZCxcblx0XHRcdFx0XHRcdFx0XCJ4LWNyb24tc2NoZWR1bGVcIjogY29uZmlnLnNjaGVkdWxlLFxuXHRcdFx0XHRcdFx0XHRcIngtY3Jvbi10aW1lem9uZVwiOiBjb25maWcudGltZXpvbmUsXG5cdFx0XHRcdFx0XHRcdFwieC1jcm9uLW1hbnVhbFwiOiBTdHJpbmcobWFudWFsKSxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRxdWVyeToge30sXG5cdFx0XHRcdFx0XHRwYXJhbXM6IHtcblx0XHRcdFx0XHRcdFx0am9iSWQsXG5cdFx0XHRcdFx0XHRcdHNjaGVkdWxlOiBjb25maWcuc2NoZWR1bGUsXG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0Q29udGV4dDtcblxuXHRcdFx0XHRcdC8vIFN0b3JlIGNyb24gY29udGV4dCBpbiB2YXJzXG5cdFx0XHRcdFx0aWYgKCFjdHgudmFycykgY3R4LnZhcnMgPSB7fTtcblx0XHRcdFx0XHRjdHgudmFycy5fY3Jvbl9jb250ZXh0ID0ge1xuXHRcdFx0XHRcdFx0am9iSWQsXG5cdFx0XHRcdFx0XHRzY2hlZHVsZWRUaW1lOiBzY2hlZHVsZWRUaW1lLnRvSVNPU3RyaW5nKCksXG5cdFx0XHRcdFx0XHRleGVjdXRpb25UaW1lOiBleGVjdXRpb25UaW1lLnRvSVNPU3RyaW5nKCksXG5cdFx0XHRcdFx0XHRzY2hlZHVsZTogY29uZmlnLnNjaGVkdWxlLFxuXHRcdFx0XHRcdFx0dGltZXpvbmU6IGNvbmZpZy50aW1lem9uZSxcblx0XHRcdFx0XHRcdG1hbnVhbDogU3RyaW5nKG1hbnVhbCksXG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHRcdGN0eC5sb2dnZXIubG9nKGBFeGVjdXRpbmcgY3JvbiBqb2I6ICR7am9iSWR9ICgke21hbnVhbCA/IFwibWFudWFsXCIgOiBcInNjaGVkdWxlZFwifSlgKTtcblxuXHRcdFx0XHRcdC8vIHYwLjYgwrcgYXBwbHkgdGhlIG1lcmdlZCBtaWRkbGV3YXJlIGNoYWluIChwcm9jZXNzLWdsb2JhbCDihpJcblx0XHRcdFx0XHQvLyB3b3JrZmxvdy1sZXZlbCDihpIgdHJpZ2dlci1sZXZlbCkgYmVmb3JlIHRoZSBtYWluIHdvcmtmbG93XG5cdFx0XHRcdFx0Ly8gYm9keS4gTGV0cyBjcm9uIHdvcmtmbG93cyBjb21wb3NlIGF1dGgtY2hlY2sgKyBhdWRpdC1sb2dcblx0XHRcdFx0XHQvLyBjaGFpbnMgZXhhY3RseSBsaWtlIEhUVFAgdHJpZ2dlcnMuIEEgdGhyb3dpbmcgbWlkZGxld2FyZVxuXHRcdFx0XHRcdC8vIHByb3BhZ2F0ZXMgdG8gdGhlIG91dGVyIGNhdGNoIGFuZCBzdXJmYWNlcyBhcyBhIGNyb24gam9iXG5cdFx0XHRcdFx0Ly8gZmFpbHVyZS5cblx0XHRcdFx0XHRhd2FpdCB0aGlzLmFwcGx5TWlkZGxld2FyZUNoYWluKGN0eCwgdGhpcy5ub2RlTWFwKTtcblxuXHRcdFx0XHRcdC8vIEV4ZWN1dGUgd29ya2Zsb3dcblx0XHRcdFx0XHRjb25zdCByZXNwb25zZTogVHJpZ2dlclJlc3BvbnNlID0gYXdhaXQgdGhpcy5ydW4oY3R4KTtcblx0XHRcdFx0XHRjb25zdCBlbmQgPSBwZXJmb3JtYW5jZS5ub3coKTtcblxuXHRcdFx0XHRcdC8vIFVwZGF0ZSBqb2Igc3RhdGVcblx0XHRcdFx0XHRzY2hlZHVsZWRKb2IubGFzdFJ1biA9IGV4ZWN1dGlvblRpbWU7XG5cdFx0XHRcdFx0c2NoZWR1bGVkSm9iLm5leHRSdW4gPSB0aGlzLnRvRGF0ZShzY2hlZHVsZWRKb2Iuam9iLm5leHREYXRlKCkpO1xuXG5cdFx0XHRcdFx0Ly8gU2V0IHNwYW4gYXR0cmlidXRlc1xuXHRcdFx0XHRcdHNwYW4uc2V0QXR0cmlidXRlKFwic3VjY2Vzc1wiLCB0cnVlKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcImpvYl9pZFwiLCBqb2JJZCk7XG5cdFx0XHRcdFx0c3Bhbi5zZXRBdHRyaWJ1dGUoXCJ3b3JrZmxvd19wYXRoXCIsIHdvcmtmbG93LnBhdGgpO1xuXHRcdFx0XHRcdHNwYW4uc2V0QXR0cmlidXRlKFwic2NoZWR1bGVcIiwgY29uZmlnLnNjaGVkdWxlKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcInRpbWV6b25lXCIsIHRpbWV6b25lKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcIm1hbnVhbFwiLCBtYW51YWwpO1xuXHRcdFx0XHRcdHNwYW4uc2V0QXR0cmlidXRlKFwiZWxhcHNlZF9tc1wiLCBlbmQgLSBzdGFydCk7XG5cdFx0XHRcdFx0c3Bhbi5zZXRTdGF0dXMoeyBjb2RlOiBTcGFuU3RhdHVzQ29kZS5PSyB9KTtcblxuXHRcdFx0XHRcdC8vIFJlY29yZCBtZXRyaWNzXG5cdFx0XHRcdFx0Y3JvbkV4ZWN1dGlvbnMuYWRkKDEsIHtcblx0XHRcdFx0XHRcdGVudjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYsXG5cdFx0XHRcdFx0XHRqb2JfaWQ6IGpvYklkLFxuXHRcdFx0XHRcdFx0d29ya2Zsb3dfbmFtZTogdGhpcy5jb25maWd1cmF0aW9uLm5hbWUsXG5cdFx0XHRcdFx0XHRtYW51YWw6IFN0cmluZyhtYW51YWwpLFxuXHRcdFx0XHRcdFx0c3VjY2VzczogXCJ0cnVlXCIsXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRjdHgubG9nZ2VyLmxvZyhgQ3JvbiBqb2IgY29tcGxldGVkIGluICR7KGVuZCAtIHN0YXJ0KS50b0ZpeGVkKDIpfW1zOiAke2pvYklkfWApO1xuXG5cdFx0XHRcdFx0cmVzb2x2ZShyZXNwb25zZSk7XG5cdFx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdFx0Y29uc3QgZXJyb3JNZXNzYWdlID0gKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlO1xuXG5cdFx0XHRcdFx0Ly8gU2V0IHNwYW4gZXJyb3Jcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcInN1Y2Nlc3NcIiwgZmFsc2UpO1xuXHRcdFx0XHRcdHNwYW4ucmVjb3JkRXhjZXB0aW9uKGVycm9yIGFzIEVycm9yKTtcblx0XHRcdFx0XHRzcGFuLnNldFN0YXR1cyh7IGNvZGU6IFNwYW5TdGF0dXNDb2RlLkVSUk9SLCBtZXNzYWdlOiBlcnJvck1lc3NhZ2UgfSk7XG5cblx0XHRcdFx0XHQvLyBSZWNvcmQgZXJyb3IgbWV0cmljc1xuXHRcdFx0XHRcdGNyb25FcnJvcnMuYWRkKDEsIHtcblx0XHRcdFx0XHRcdGVudjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYsXG5cdFx0XHRcdFx0XHRqb2JfaWQ6IGpvYklkLFxuXHRcdFx0XHRcdFx0d29ya2Zsb3dfbmFtZTogdGhpcy5jb25maWd1cmF0aW9uPy5uYW1lIHx8IFwidW5rbm93blwiLFxuXHRcdFx0XHRcdFx0bWFudWFsOiBTdHJpbmcobWFudWFsKSxcblx0XHRcdFx0XHR9KTtcblxuXHRcdFx0XHRcdHRoaXMubG9nZ2VyLmVycm9yKGBDcm9uIGpvYiBmYWlsZWQgJHtqb2JJZH06ICR7ZXJyb3JNZXNzYWdlfWAsIChlcnJvciBhcyBFcnJvcikuc3RhY2spO1xuXG5cdFx0XHRcdFx0cmVzb2x2ZSh7IGN0eDoge30gYXMgQ29udGV4dCwgbWV0cmljczoge30gYXMgTWV0cmljc1R5cGUgfSk7XG5cdFx0XHRcdH0gZmluYWxseSB7XG5cdFx0XHRcdFx0c2NoZWR1bGVkSm9iLnJ1bm5pbmcgPSBmYWxzZTtcblx0XHRcdFx0XHRzcGFuLmVuZCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fVxufVxuXG5leHBvcnQgZGVmYXVsdCBDcm9uVHJpZ2dlcjtcbiJdfQ==
351
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ3JvblRyaWdnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvQ3JvblRyaWdnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7R0FVRztBQUdILE9BQU8sRUFFTixhQUFhLEVBQ2Isc0JBQXNCLEVBRXRCLE9BQU8sRUFDUCxXQUFXLEVBRVgsbUJBQW1CLEdBQ25CLE1BQU0sZ0JBQWdCLENBQUM7QUFFeEIsT0FBTyxFQUFhLGNBQWMsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDL0UsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsRUFBRSxJQUFJLElBQUksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQTREbEM7O0dBRUc7QUFDSCxNQUFNLE9BQWdCLFdBQVksU0FBUSxXQUFXO0lBQzFDLE9BQU8sR0FBa0IsRUFBbUIsQ0FBQztJQUNwQyxNQUFNLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FDMUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLElBQUksdUJBQXVCLEVBQ25ELE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxJQUFJLE9BQU8sQ0FDdEMsQ0FBQztJQUNpQixNQUFNLEdBQUcsSUFBSSxhQUFhLEVBQUUsQ0FBQztJQUN0QyxJQUFJLEdBQThCLElBQUksR0FBRyxFQUFFLENBQUM7SUFNdEQ7UUFDQyxLQUFLLEVBQUUsQ0FBQztRQUNSLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNqQixJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDdEIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsU0FBUztRQUNSLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxHQUFHLElBQUksT0FBTyxFQUFFLENBQUM7UUFDbkMsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDekMsS0FBSyxNQUFN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QUMsQ0FBQyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDSixDQUFDO0NBQ0Q7QUFFRCxlQUFlLFdBQVcsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ3JvblRyaWdnZXIgLSBTY2hlZHVsZWQgd29ya2Zsb3cgZXhlY3V0aW9uIGJhc2VkIG9uIGNyb24gZXhwcmVzc2lvbnNcbiAqXG4gKiBFeHRlbmRzIFRyaWdnZXJCYXNlIHRvIHN1cHBvcnQgc2NoZWR1bGVkIHRyaWdnZXJzOlxuICogLSBDcm9uIGV4cHJlc3Npb25zIChlLmcuLCBcIjAgKiAqICogKlwiIGZvciBob3VybHkpXG4gKiAtIFRpbWV6b25lLWF3YXJlIHNjaGVkdWxpbmdcbiAqIC0gT3ZlcmxhcCBwcmV2ZW50aW9uXG4gKiAtIE1hbnVhbCB0cmlnZ2VyIHN1cHBvcnRcbiAqXG4gKiBVc2VzIHRoZSAnY3JvbicgcGFja2FnZSBmb3IgY3JvbiBwYXJzaW5nIGFuZCBzY2hlZHVsaW5nLlxuICovXG5cbmltcG9ydCB0eXBlIHsgQ3JvblRyaWdnZXJPcHRzLCBIZWxwZXJSZXNwb25zZSB9IGZyb20gXCJAYmxva2pzL2hlbHBlclwiO1xuaW1wb3J0IHtcblx0dHlwZSBCbG9rU2VydmljZSxcblx0RGVmYXVsdExvZ2dlcixcblx0RGVmZXJyZWREaXNwYXRjaFNpZ25hbCxcblx0dHlwZSBHbG9iYWxPcHRpb25zLFxuXHROb2RlTWFwLFxuXHRUcmlnZ2VyQmFzZSxcblx0dHlwZSBUcmlnZ2VyUmVzcG9uc2UsXG5cdFdhaXREaXNwYXRjaFJlcXVlc3QsXG59IGZyb20gXCJAYmxva2pzL3J1bm5lclwiO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0LCBNZXRyaWNzVHlwZSwgUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiQGJsb2tqcy9zaGFyZWRcIjtcbmltcG9ydCB7IHR5cGUgU3BhbiwgU3BhblN0YXR1c0NvZGUsIG1ldHJpY3MsIHRyYWNlIH0gZnJvbSBcIkBvcGVudGVsZW1ldHJ5L2FwaVwiO1xuaW1wb3J0IHsgQ3JvbkpvYiB9IGZyb20gXCJjcm9uXCI7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSBcInV1aWRcIjtcblxuLyoqXG4gKiBTY2hlZHVsZWQgam9iIGluZm9ybWF0aW9uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2NoZWR1bGVkSm9iIHtcblx0LyoqIFVuaXF1ZSBqb2IgSUQgKi9cblx0aWQ6IHN0cmluZztcblx0LyoqIFdvcmtmbG93IHBhdGggKi9cblx0d29ya2Zsb3dQYXRoOiBzdHJpbmc7XG5cdC8qKiBDcm9uIGV4cHJlc3Npb24gKi9cblx0c2NoZWR1bGU6IHN0cmluZztcblx0LyoqIFRpbWV6b25lICovXG5cdHRpbWV6b25lOiBzdHJpbmc7XG5cdC8qKiBBbGxvdyBvdmVybGFwcGluZyBleGVjdXRpb25zICovXG5cdG92ZXJsYXA6IGJvb2xlYW47XG5cdC8qKiBXaGV0aGVyIHRoZSBqb2IgaXMgY3VycmVudGx5IHJ1bm5pbmcgKi9cblx0cnVubmluZzogYm9vbGVhbjtcblx0LyoqIExhc3QgZXhlY3V0aW9uIHRpbWUgKi9cblx0bGFzdFJ1bj86IERhdGU7XG5cdC8qKiBOZXh0IHNjaGVkdWxlZCB0aW1lICovXG5cdG5leHRSdW4/OiBEYXRlO1xuXHQvKiogSW50ZXJuYWwgQ3JvbkpvYiBpbnN0YW5jZSAqL1xuXHRqb2I6IENyb25Kb2I7XG59XG5cbi8qKlxuICogRXhlY3V0aW9uIGNvbnRleHQgcGFzc2VkIHRvIHRoZSB3b3JrZmxvd1xuICovXG5leHBvcnQgaW50ZXJmYWNlIENyb25FeGVjdXRpb25Db250ZXh0IHtcblx0LyoqIEpvYiBJRCAqL1xuXHRqb2JJZDogc3RyaW5nO1xuXHQvKiogU2NoZWR1bGVkIHRpbWUgKHdoZW4gaXQgd2FzIHN1cHBvc2VkIHRvIHJ1bikgKi9cblx0c2NoZWR1bGVkVGltZTogRGF0ZTtcblx0LyoqIEFjdHVhbCBleGVjdXRpb24gdGltZSAqL1xuXHRleGVjdXRpb25UaW1lOiBEYXRlO1xuXHQvKiogQ3JvbiBleHByZXNzaW9uICovXG5cdHNjaGVkdWxlOiBzdHJpbmc7XG5cdC8qKiBUaW1lem9uZSAqL1xuXHR0aW1lem9uZTogc3RyaW5nO1xuXHQvKiogV2hldGhlciB0aGlzIGlzIGEgbWFudWFsIHRyaWdnZXIgKi9cblx0bWFudWFsOiBib29sZWFuO1xufVxuXG4vKipcbiAqIFdvcmtmbG93IG1vZGVsIHdpdGggY3JvbiB0cmlnZ2VyIGNvbmZpZ3VyYXRpb25cbiAqL1xuaW50ZXJmYWNlIENyb25Xb3JrZmxvd01vZGVsIHtcblx0cGF0aDogc3RyaW5nO1xuXHRjb25maWc6IHtcblx0XHRuYW1lOiBzdHJpbmc7XG5cdFx0dmVyc2lvbjogc3RyaW5nO1xuXHRcdHRyaWdnZXI/OiB7XG5cdFx0XHRjcm9uPzogQ3JvblRyaWdnZXJPcHRzO1xuXHRcdFx0W2tleTogc3RyaW5nXTogdW5rbm93bjtcblx0XHR9O1xuXHRcdFtrZXk6IHN0cmluZ106IHVua25vd247XG5cdH07XG59XG5cbi8qKlxuICogQ3JvblRyaWdnZXIgLSBTY2hlZHVsZWQgd29ya2Zsb3cgZXhlY3V0aW9uXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBDcm9uVHJpZ2dlciBleHRlbmRzIFRyaWdnZXJCYXNlIHtcblx0cHJvdGVjdGVkIG5vZGVNYXA6IEdsb2JhbE9wdGlvbnMgPSB7fSBhcyBHbG9iYWxPcHRpb25zO1xuXHRwcm90ZWN0ZWQgcmVhZG9ubHkgdHJhY2VyID0gdHJhY2UuZ2V0VHJhY2VyKFxuXHRcdHByb2Nlc3MuZW52LlBST0pFQ1RfTkFNRSB8fCBcInRyaWdnZXItY3Jvbi13b3JrZmxvd1wiLFxuXHRcdHByb2Nlc3MuZW52LlBST0pFQ1RfVkVSU0lPTiB8fCBcIjAuMC4xXCIsXG5cdCk7XG5cdHByb3RlY3RlZCByZWFkb25seSBsb2dnZXIgPSBuZXcgRGVmYXVsdExvZ2dlcigpO1xuXHRwcm90ZWN0ZWQgam9iczogTWFwPHN0cmluZywgU2NoZWR1bGVkSm9iPiA9IG5ldyBNYXAoKTtcblxuXHQvLyBTdWJjbGFzc2VzIHByb3ZpZGUgdGhlc2Vcblx0cHJvdGVjdGVkIGFic3RyYWN0IG5vZGVzOiBSZWNvcmQ8c3RyaW5nLCBCbG9rU2VydmljZTx1bmtub3duPj47XG5cdHByb3RlY3RlZCBhYnN0cmFjdCB3b3JrZmxvd3M6IFJlY29yZDxzdHJpbmcsIEhlbHBlclJlc3BvbnNlPjtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblx0XHRzdXBlcigpO1xuXHRcdHRoaXMubG9hZE5vZGVzKCk7XG5cdFx0dGhpcy5sb2FkV29ya2Zsb3dzKCk7XG5cdH1cblxuXHQvKipcblx0ICogTG9hZCBub2RlcyBpbnRvIHRoZSBub2RlIG1hcFxuXHQgKi9cblx0bG9hZE5vZGVzKCk6IHZvaWQge1xuXHRcdHRoaXMubm9kZU1hcC5ub2RlcyA9IG5ldyBOb2RlTWFwKCk7XG5cdFx0Y29uc3Qgbm9kZUtleXMgPSBPYmplY3Qua2V5cyh0aGlzLm5vZGVzKTtcblx0XHRmb3IgKGNvbnN0IGtleSBvZiBub2RlS2V5cykge1xuXHRcdFx0dGhpcy5ub2RlTWFwLm5vZGVzLmFkZE5vZGUoa2V5LCB0aGlzLm5vZGVzW2tleV0pO1xuXHRcdH1cblx0fVxuXG5cdC8qKlxuXHQgKiBMb2FkIHdvcmtmbG93cyBpbnRvIHRoZSB3b3JrZmxvdyBtYXBcblx0ICovXG5cdGxvYWRXb3JrZmxvd3MoKTogdm9pZCB7XG5cdFx0dGhpcy5ub2RlTWFwLndvcmtmbG93cyA9IHRoaXMud29ya2Zsb3dzO1xuXHR9XG5cblx0LyoqXG5cdCAqIENvbnZlcnQgY3JvbiBEYXRlVGltZSB0byBEYXRlXG5cdCAqIFRoZSBjcm9uIHBhY2thZ2UgdXNlcyBsdXhvbiBEYXRlVGltZSB3aGljaCBoYXMgdG9KU0RhdGUoKVxuXHQgKi9cblx0cHJvdGVjdGVkIHRvRGF0ZShkYXRlVGltZTogdW5rbm93bik6IERhdGUge1xuXHRcdGlmIChkYXRlVGltZSAmJiB0eXBlb2YgZGF0ZVRpbWUgPT09IFwib2JqZWN0XCIgJiYgXCJ0b0pTRGF0ZVwiIGluIGRhdGVUaW1lKSB7XG5cdFx0XHRyZXR1cm4gKGRhdGVUaW1lIGFzIHsgdG9KU0RhdGU6ICgpID0+IERhdGUgfSkudG9KU0RhdGUoKTtcblx0XHR9XG5cdFx0cmV0dXJuIGRhdGVUaW1lIGluc3RhbmNlb2YgRGF0ZSA/IGRhdGVUaW1lIDogbmV3IERhdGUoZGF0ZVRpbWUgYXMgc3RyaW5nIHwgbnVtYmVyKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBTdGFydCB0aGUgY3JvbiBzY2hlZHVsZXIgLSBtYWluIGVudHJ5IHBvaW50XG5cdCAqL1xuXHRhc3luYyBsaXN0ZW4oKTogUHJvbWlzZTxudW1iZXI+IHtcblx0XHRjb25zdCBzdGFydFRpbWUgPSB0aGlzLnN0YXJ0Q291bnRlcigpO1xuXG5cdFx0dHJ5IHtcblx0XHRcdC8vIEY1IMK3IGluc3RhbGwgY3Jhc2gvb3JwaGFuL2phbml0b3Ivc2h1dGRvd24gaGFuZGxlcnMgc28gYVxuXHRcdFx0Ly8gY3Jvbi1vbmx5IHByb2Nlc3MgZ2V0cyB0aGUgc2FtZSBydW4tc3RhdGUgaW50ZWdyaXR5ICsgc3RvcmFnZVxuXHRcdFx0Ly8gaHlnaWVuZSBndWFyYW50ZWVzIGFzIEhUVFAvV29ya2VyLiBFYWNoIGhhbmRsZXIgaXMgaWRlbXBvdGVudFxuXHRcdFx0Ly8gKyBpbmRpdmlkdWFsbHkga2lsbC1zd2l0Y2hlZC5cblx0XHRcdHRoaXMuaW5zdGFsbE9wZXJhdGlvbmFsSGFuZGxlcnModGhpcy5sb2dnZXIpO1xuXG5cdFx0XHQvLyBGNiDCtyBmZWVkIHRoZSBXb3JrZmxvd1JlZ2lzdHJ5IGZyb20gdGhlIG5vZGVNYXAgc28gYHN1YndvcmtmbG93OmBcblx0XHRcdC8vIHN0ZXBzICsgdHJpZ2dlci93b3JrZmxvdy9wcm9jZXNzLWdsb2JhbCBtaWRkbGV3YXJlIHJlc29sdmUgaW4gYVxuXHRcdFx0Ly8gY3Jvbi1vbmx5IGRlcGxveW1lbnQgKG5vIEhUVFAgdHJpZ2dlciB0byBwb3B1bGF0ZSB0aGUgcmVnaXN0cnkpLlxuXHRcdFx0dGhpcy5yZWdpc3RlcldvcmtmbG93c0Zyb21Ob2RlTWFwKHRoaXMubG9nZ2VyKTtcblxuXHRcdFx0Ly8gRjE0IMK3IHNlZWQgdGhlIHByb2Nlc3MtZ2xvYmFsIG1pZGRsZXdhcmUgY2hhaW4gZnJvbVxuXHRcdFx0Ly8gYEJMT0tfR0xPQkFMX01JRERMRVdBUkVgIChpZGVtcG90ZW50IOKAlCBwcm9ncmFtbWF0aWNcblx0XHRcdC8vIHNldEdsb2JhbE1pZGRsZXdhcmUgdGFrZXMgcHJlY2VkZW5jZSkuXG5cdFx0XHR0aGlzLnNlZWRHbG9iYWxNaWRkbGV3YXJlRnJvbUVudih0aGlzLmxvZ2dlcik7XG5cblx0XHRcdC8vIEZpbmQgYWxsIHdvcmtmbG93cyB3aXRoIGNyb24gdHJpZ2dlcnNcblx0XHRcdGNvbnN0IGNyb25Xb3JrZmxvd3MgPSB0aGlzLmdldENyb25Xb3JrZmxvd3MoKTtcblxuXHRcdFx0aWYgKGNyb25Xb3JrZmxvd3MubGVuZ3RoID09PSAwKSB7XG5cdFx0XHRcdHRoaXMubG9nZ2VyLmxvZyhcIk5vIHdvcmtmbG93cyB3aXRoIGNyb24gdHJpZ2dlcnMgZm91bmRcIik7XG5cdFx0XHRcdHJldHVybiB0aGlzLmVuZENvdW50ZXIoc3RhcnRUaW1lKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ3JlYXRlIGFuZCBzdGFydCBjcm9uIGpvYnMgZm9yIGVhY2ggd29ya2Zsb3dcblx0XHRcdGZvciAoY29uc3Qgd29ya2Zsb3cgb2YgY3JvbldvcmtmbG93cykge1xuXHRcdFx0XHRjb25zdCBjb25maWcgPSB3b3JrZmxvdy5jb25maWcudHJpZ2dlcj8uY3JvbiBhcyBDcm9uVHJpZ2dlck9wdHM7XG5cdFx0XHRcdGNvbnN0IGpvYklkID0gYGNyb24tJHt3b3JrZmxvdy5wYXRofS0ke3V1aWQoKS5zbGljZSgwLCA4KX1gO1xuXG5cdFx0XHRcdC8vIGBDcm9uVHJpZ2dlck9wdHNgIGlzIGB6LmlucHV0POKApj5gIHNvIGB0aW1lem9uZWAgaXMgYHN0cmluZyB8IHVuZGVmaW5lZGBcblx0XHRcdFx0Ly8gZXZlbiB0aG91Z2ggdGhlIHNjaGVtYSBkZWNsYXJlcyBgLmRlZmF1bHQoXCJVVENcIilgLiBBcHBseSB0aGVcblx0XHRcdFx0Ly8gZGVmYXVsdCBvbmNlIGhlcmUgc28gdGhlIHJlc3Qgb2YgdGhpcyBtZXRob2QgKGFuZCB0aGUgY3JvbiBsaWInc1xuXHRcdFx0XHQvLyBjb25zdHJ1Y3Rvcikgc2VlcyBhIGd1YXJhbnRlZWQgc3RyaW5nLlxuXHRcdFx0XHRjb25zdCB0aW1lem9uZSA9IGNvbmZpZy50aW1lem9uZSA/PyBcIlVUQ1wiO1xuXG5cdFx0XHRcdHRoaXMubG9nZ2VyLmxvZyhgU2NoZWR1bGluZyB3b3JrZmxvdzogJHt3b3JrZmxvdy5wYXRofSB3aXRoIHNjaGVkdWxlOiAke2NvbmZpZy5zY2hlZHVsZX0gKCR7dGltZXpvbmV9KWApO1xuXG5cdFx0XHRcdGNvbnN0IGpvYiA9IG5ldyBDcm9uSm9iKFxuXHRcdFx0XHRcdGNvbmZpZy5zY2hlZHVsZSxcblx0XHRcdFx0XHRhc3luYyAoKSA9PiB7XG5cdFx0XHRcdFx0XHRhd2FpdCB0aGlzLmV4ZWN1dGVXb3JrZmxvdyhqb2JJZCwgd29ya2Zsb3csIGNvbmZpZywgZmFsc2UpO1xuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0bnVsbCwgLy8gb25Db21wbGV0ZVxuXHRcdFx0XHRcdGZhbHNlLCAvLyBzdGFydFxuXHRcdFx0XHRcdHRpbWV6b25lLFxuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdGNvbnN0IHNjaGVkdWxlZEpvYjogU2NoZWR1bGVkSm9iID0ge1xuXHRcdFx0XHRcdGlkOiBqb2JJZCxcblx0XHRcdFx0XHR3b3JrZmxvd1BhdGg6IHdvcmtmbG93LnBhdGgsXG5cdFx0XHRcdFx0c2NoZWR1bGU6IGNvbmZpZy5zY2hlZHVsZSxcblx0XHRcdFx0XHR0aW1lem9uZSxcblx0XHRcdFx0XHRvdmVybGFwOiBjb25maWcub3ZlcmxhcCA/PyBmYWxzZSxcblx0XHRcdFx0XHRydW5uaW5nOiBmYWxzZSxcblx0XHRcdFx0XHRuZXh0UnVuOiB0aGlzLnRvRGF0ZShqb2IubmV4dERhdGUoKSksXG5cdFx0XHRcdFx0am9iLFxuXHRcdFx0XHR9O1xuXG5cdFx0XHRcdHRoaXMuam9icy5zZXQoam9iSWQsIHNjaGVkdWxlZEpvYik7XG5cblx0XHRcdFx0Ly8gU3RhcnQgdGhlIGpvYlxuXHRcdFx0XHRqb2Iuc3RhcnQoKTtcblx0XHRcdFx0dGhpcy5sb2dnZXIubG9nKGBKb2IgJHtqb2JJZH0gc3RhcnRlZC4gTmV4dCBydW46ICR7c2NoZWR1bGVkSm9iLm5leHRSdW59YCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMubG9nZ2VyLmxvZyhgQ3JvbiB0cmlnZ2VyIHN0YXJ0ZWQuICR7dGhpcy5qb2JzLnNpemV9IGpvYihzKSBzY2hlZHVsZWRgKTtcblxuXHRcdFx0Ly8gRW5hYmxlIEhNUiBpbiBkZXZlbG9wbWVudCBtb2RlXG5cdFx0XHRpZiAocHJvY2Vzcy5lbnYuQkxPS19ITVIgPT09IFwidHJ1ZVwiIHx8IHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSBcImRldmVsb3BtZW50XCIpIHtcblx0XHRcdFx0YXdhaXQgdGhpcy5lbmFibGVIb3RSZWxvYWQoKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoaXMuZW5kQ291bnRlcihzdGFydFRpbWUpO1xuXHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHR0aGlzLmxvZ2dlci5lcnJvcihgRmFpbGVkIHRvIHN0YXJ0IGNyb24gdHJpZ2dlcjogJHsoZXJyb3IgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG5cdFx0XHR0aHJvdyBlcnJvcjtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogU3RvcCBhbGwgY3JvbiBqb2JzXG5cdCAqL1xuXHRhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuXHRcdGZvciAoY29uc3QgW2pvYklkLCBzY2hlZHVsZWRKb2JdIG9mIHRoaXMuam9icykge1xuXHRcdFx0c2NoZWR1bGVkSm9iLmpvYi5zdG9wKCk7XG5cdFx0XHR0aGlzLmxvZ2dlci5sb2coYEpvYiAke2pvYklkfSBzdG9wcGVkYCk7XG5cdFx0fVxuXHRcdHRoaXMuam9icy5jbGVhcigpO1xuXHRcdHRoaXMubG9nZ2VyLmxvZyhcIkNyb24gdHJpZ2dlciBzdG9wcGVkXCIpO1xuXHR9XG5cblx0cHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIG9uSG1yV29ya2Zsb3dDaGFuZ2UoKTogUHJvbWlzZTx2b2lkPiB7XG5cdFx0dGhpcy5sb2dnZXIubG9nKFwiW0hNUl0gQ3JvbiB3b3JrZmxvdyBjaGFuZ2VkLCByZWxvYWRpbmcuLi5cIik7XG5cdFx0YXdhaXQgdGhpcy53YWl0Rm9ySW5GbGlnaHRSZXF1ZXN0cygpO1xuXHRcdGF3YWl0IHRoaXMuc3RvcCgpO1xuXHRcdHRoaXMubG9hZFdvcmtmbG93cygpO1xuXHRcdGF3YWl0IHRoaXMubGlzdGVuKCk7XG5cdH1cblxuXHQvKipcblx0ICogTWFudWFsbHkgdHJpZ2dlciBhIHNwZWNpZmljIGpvYlxuXHQgKi9cblx0YXN5bmMgdHJpZ2dlckpvYihqb2JJZDogc3RyaW5nKTogUHJvbWlzZTxUcmlnZ2VyUmVzcG9uc2UgfCBudWxsPiB7XG5cdFx0Y29uc3Qgc2NoZWR1bGVkSm9iID0gdGhpcy5qb2JzLmdldChqb2JJZCk7XG5cdFx0aWYgKCFzY2hlZHVsZWRKb2IpIHtcblx0XHRcdHRoaXMubG9nZ2VyLmVycm9yKGBKb2Igbm90IGZvdW5kOiAke2pvYklkfWApO1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXG5cdFx0Ly8gR2V0IHRoZSB3b3JrZmxvd1xuXHRcdGNvbnN0IHdvcmtmbG93ID0gdGhpcy5nZXRXb3JrZmxvd0J5UGF0aChzY2hlZHVsZWRKb2Iud29ya2Zsb3dQYXRoKTtcblx0XHRpZiAoIXdvcmtmbG93KSB7XG5cdFx0XHR0aGlzLmxvZ2dlci5lcnJvcihgV29ya2Zsb3cgbm90IGZvdW5kOiAke3NjaGVkdWxlZEpvYi53b3JrZmxvd1BhdGh9YCk7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cblx0XHRjb25zdCBjb25maWcgPSB3b3JrZmxvdy5jb25maWcudHJpZ2dlcj8uY3JvbiBhcyBDcm9uVHJpZ2dlck9wdHM7XG5cdFx0cmV0dXJuIHRoaXMuZXhlY3V0ZVdvcmtmbG93KGpvYklkLCB3b3JrZmxvdywgY29uZmlnLCB0cnVlKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBHZXQgYWxsIHNjaGVkdWxlZCBqb2JzXG5cdCAqL1xuXHRnZXRKb2JzKCk6IFNjaGVkdWxlZEpvYltdIHtcblx0XHRyZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmpvYnMudmFsdWVzKCkpLm1hcCgoam9iKSA9PiAoe1xuXHRcdFx0Li4uam9iLFxuXHRcdFx0bmV4dFJ1bjogdGhpcy50b0RhdGUoam9iLmpvYi5uZXh0RGF0ZSgpKSxcblx0XHR9KSk7XG5cdH1cblxuXHQvKipcblx0ICogR2V0IGFsbCB3b3JrZmxvd3MgdGhhdCBoYXZlIGNyb24gdHJpZ2dlcnNcblx0ICovXG5cdHByb3RlY3RlZCBnZXRDcm9uV29ya2Zsb3dzKCk6IENyb25Xb3JrZmxvd01vZGVsW10ge1xuXHRcdGNvbnN0IHdvcmtmbG93czogQ3JvbldvcmtmbG93TW9kZWxbXSA9IFtdO1xuXG5cdFx0Zm9yIChjb25zdCBbcGF0aCwgd29ya2Zsb3ddIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMubm9kZU1hcC53b3JrZmxvd3MgfHwge30pKSB7XG5cdFx0XHRjb25zdCB3b3JrZmxvd0NvbmZpZyA9ICh3b3JrZmxvdyBhcyB1bmtub3duIGFzIHsgX2NvbmZpZzogQ3JvbldvcmtmbG93TW9kZWxbXCJjb25maWdcIl0gfSkuX2NvbmZpZztcblxuXHRcdFx0aWYgKHdvcmtmbG93Q29uZmlnPy50cmlnZ2VyKSB7XG5cdFx0XHRcdGNvbnN0IHRyaWdnZXJUeXBlID0gT2JqZWN0LmtleXMod29ya2Zsb3dDb25maWcudHJpZ2dlcilbMF07XG5cblx0XHRcdFx0aWYgKHRyaWdnZXJUeXBlID09PSBcImNyb25cIiAmJiB3b3JrZmxvd0NvbmZpZy50cmlnZ2VyLmNyb24pIHtcblx0XHRcdFx0XHR3b3JrZmxvd3MucHVzaCh7XG5cdFx0XHRcdFx0XHRwYXRoLFxuXHRcdFx0XHRcdFx0Y29uZmlnOiB3b3JrZmxvd0NvbmZpZyxcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB3b3JrZmxvd3M7XG5cdH1cblxuXHQvKipcblx0ICogR2V0IHdvcmtmbG93IGJ5IHBhdGhcblx0ICovXG5cdHByb3RlY3RlZCBnZXRXb3JrZmxvd0J5UGF0aChwYXRoOiBzdHJpbmcpOiBDcm9uV29ya2Zsb3dNb2RlbCB8IG51bGwge1xuXHRcdGNvbnN0IHdvcmtmbG93ID0gdGhpcy5ub2RlTWFwLndvcmtmbG93cz8uW3BhdGhdO1xuXHRcdGlmICghd29ya2Zsb3cpIHJldHVybiBudWxsO1xuXG5cdFx0Y29uc3Qgd29ya2Zsb3dDb25maWcgPSAod29ya2Zsb3cgYXMgdW5rbm93biBhcyB7IF9jb25maWc6IENyb25Xb3JrZmxvd01vZGVsW1wiY29uZmlnXCJdIH0pLl9jb25maWc7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHBhdGgsXG5cdFx0XHRjb25maWc6IHdvcmtmbG93Q29uZmlnLFxuXHRcdH07XG5cdH1cblxuXHQvKipcblx0ICogRXhlY3V0ZSBhIHdvcmtmbG93XG5cdCAqL1xuXHRwcm90ZWN0ZWQgYXN5bmMgZXhlY3V0ZVdvcmtmbG93KFxuXHRcdGpvYklkOiBzdHJpbmcsXG5cdFx0d29ya2Zsb3c6IENyb25Xb3JrZmxvd01vZGVsLFxuXHRcdGNvbmZpZzogQ3JvblRyaWdnZXJPcHRzLFxuXHRcdG1hbnVhbDogYm9vbGVhbixcblx0KTogUHJvbWlzZTxUcmlnZ2VyUmVzcG9uc2U+IHtcblx0XHRjb25zdCBzY2hlZHVsZWRKb2IgPSB0aGlzLmpvYnMuZ2V0KGpvYklkKTtcblx0XHRpZiAoIXNjaGVkdWxlZEpvYikge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKGBKb2Igbm90IGZvdW5kOiAke2pvYklkfWApO1xuXHRcdH1cblxuXHRcdC8vIENoZWNrIGZvciBvdmVybGFwXG5cdFx0aWYgKHNjaGVkdWxlZEpvYi5ydW5uaW5nICYmICFzY2hlZHVsZWRKb2Iub3ZlcmxhcCkge1xuXHRcdFx0dGhpcy5sb2dnZXIubG9nKGBTa2lwcGluZyAke2pvYklkfTogcHJldmlvdXMgZXhlY3V0aW9uIHN0aWxsIHJ1bm5pbmcgKG92ZXJsYXAgZGlzYWJsZWQpYCk7XG5cdFx0XHRyZXR1cm4geyBjdHg6IHt9IGFzIENvbnRleHQsIG1ldHJpY3M6IHt9IGFzIE1ldHJpY3NUeXBlIH07XG5cdFx0fVxuXG5cdFx0Y29uc3QgZXhlY3V0aW9uSWQgPSB1dWlkKCk7XG5cdFx0Y29uc3QgbGFzdERhdGUgPSBzY2hlZHVsZWRKb2Iuam9iLmxhc3REYXRlKCk7XG5cdFx0Y29uc3Qgc2NoZWR1bGVkVGltZSA9IGxhc3REYXRlID8gbmV3IERhdGUobGFzdERhdGUgYXMgdW5rbm93biBhcyBzdHJpbmcgfCBudW1iZXIpIDogbmV3IERhdGUoKTtcblx0XHRjb25zdCBleGVjdXRpb25UaW1lID0gbmV3IERhdGUoKTtcblxuXHRcdC8vIEFwcGx5IHRoZSBzY2hlbWEgZGVmYXVsdCDigJQgc2VlIGV4cGxhbmF0aW9uIGluIGBsaXN0ZW4oKWAuXG5cdFx0Y29uc3QgdGltZXpvbmUgPSBjb25maWcudGltZXpvbmUgPz8gXCJVVENcIjtcblxuXHRcdGNvbnN0IGRlZmF1bHRNZXRlciA9IG1ldHJpY3MuZ2V0TWV0ZXIoXCJkZWZhdWx0XCIpO1xuXHRcdGNvbnN0IGNyb25FeGVjdXRpb25zID0gZGVmYXVsdE1ldGVyLmNyZWF0ZUNvdW50ZXIoXCJjcm9uX2V4ZWN1dGlvbnNcIiwge1xuXHRcdFx0ZGVzY3JpcHRpb246IFwiQ3JvbiBqb2IgZXhlY3V0aW9uc1wiLFxuXHRcdH0pO1xuXHRcdGNvbnN0IGNyb25FcnJvcnMgPSBkZWZhdWx0TWV0ZXIuY3JlYXRlQ291bnRlcihcImNyb25fZXJyb3JzXCIsIHtcblx0XHRcdGRlc2NyaXB0aW9uOiBcIkNyb24gam9iIGV4ZWN1dGlvbiBlcnJvcnNcIixcblx0XHR9KTtcblxuXHRcdHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuXHRcdFx0dGhpcy50cmFjZXIuc3RhcnRBY3RpdmVTcGFuKGBjcm9uOiR7d29ya2Zsb3cucGF0aH1gLCBhc3luYyAoc3BhbjogU3BhbikgPT4ge1xuXHRcdFx0XHRzY2hlZHVsZWRKb2IucnVubmluZyA9IHRydWU7XG5cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRjb25zdCBzdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpO1xuXG5cdFx0XHRcdFx0Ly8gSW5pdGlhbGl6ZSBjb25maWd1cmF0aW9uIGZvciB0aGlzIHdvcmtmbG93XG5cdFx0XHRcdFx0YXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXQod29ya2Zsb3cucGF0aCwgdGhpcy5ub2RlTWFwKTtcblxuXHRcdFx0XHRcdC8vIENyZWF0ZSBjb250ZXh0XG5cdFx0XHRcdFx0Y29uc3QgY3R4OiBDb250ZXh0ID0gdGhpcy5jcmVhdGVDb250ZXh0KHVuZGVmaW5lZCwgd29ya2Zsb3cucGF0aCwgZXhlY3V0aW9uSWQpO1xuXG5cdFx0XHRcdFx0Ly8gQ3JlYXRlIGV4ZWN1dGlvbiBjb250ZXh0XG5cdFx0XHRcdFx0Y29uc3QgY3JvbkNvbnRleHQ6IENyb25FeGVjdXRpb25Db250ZXh0ID0ge1xuXHRcdFx0XHRcdFx0am9iSWQsXG5cdFx0XHRcdFx0XHRzY2hlZHVsZWRUaW1lLFxuXHRcdFx0XHRcdFx0ZXhlY3V0aW9uVGltZSxcblx0XHRcdFx0XHRcdHNjaGVkdWxlOiBjb25maWcuc2NoZWR1bGUsXG5cdFx0XHRcdFx0XHR0aW1lem9uZSxcblx0XHRcdFx0XHRcdG1hbnVhbCxcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0Ly8gUG9wdWxhdGUgcmVxdWVzdCB3aXRoIGNyb24gY29udGV4dFxuXHRcdFx0XHRcdGN0eC5yZXF1ZXN0ID0ge1xuXHRcdFx0XHRcdFx0Ym9keTogY3JvbkNvbnRleHQsXG5cdFx0XHRcdFx0XHRoZWFkZXJzOiB7XG5cdFx0XHRcdFx0XHRcdFwieC1jcm9uLWpvYi1pZFwiOiBqb2JJZCxcblx0XHRcdFx0XHRcdFx0XCJ4LWNyb24tc2NoZWR1bGVcIjogY29uZmlnLnNjaGVkdWxlLFxuXHRcdFx0XHRcdFx0XHRcIngtY3Jvbi10aW1lem9uZVwiOiBjb25maWcudGltZXpvbmUsXG5cdFx0XHRcdFx0XHRcdFwieC1jcm9uLW1hbnVhbFwiOiBTdHJpbmcobWFudWFsKSxcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRxdWVyeToge30sXG5cdFx0XHRcdFx0XHRwYXJhbXM6IHtcblx0XHRcdFx0XHRcdFx0am9iSWQsXG5cdFx0XHRcdFx0XHRcdHNjaGVkdWxlOiBjb25maWcuc2NoZWR1bGUsXG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdH0gYXMgdW5rbm93biBhcyBSZXF1ZXN0Q29udGV4dDtcblxuXHRcdFx0XHRcdC8vIFN0b3JlIGNyb24gY29udGV4dCBpbiB2YXJzXG5cdFx0XHRcdFx0aWYgKCFjdHgudmFycykgY3R4LnZhcnMgPSB7fTtcblx0XHRcdFx0XHRjdHgudmFycy5fY3Jvbl9jb250ZXh0ID0ge1xuXHRcdFx0XHRcdFx0am9iSWQsXG5cdFx0XHRcdFx0XHRzY2hlZHVsZWRUaW1lOiBzY2hlZHVsZWRUaW1lLnRvSVNPU3RyaW5nKCksXG5cdFx0XHRcdFx0XHRleGVjdXRpb25UaW1lOiBleGVjdXRpb25UaW1lLnRvSVNPU3RyaW5nKCksXG5cdFx0XHRcdFx0XHRzY2hlZHVsZTogY29uZmlnLnNjaGVkdWxlLFxuXHRcdFx0XHRcdFx0dGltZXpvbmU6IGNvbmZpZy50aW1lem9uZSxcblx0XHRcdFx0XHRcdG1hbnVhbDogU3RyaW5nKG1hbnVhbCksXG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHRcdGN0eC5sb2dnZXIubG9nKGBFeGVjdXRpbmcgY3JvbiBqb2I6ICR7am9iSWR9ICgke21hbnVhbCA/IFwibWFudWFsXCIgOiBcInNjaGVkdWxlZFwifSlgKTtcblxuXHRcdFx0XHRcdC8vIHYwLjYgwrcgYXBwbHkgdGhlIG1lcmdlZCBtaWRkbGV3YXJlIGNoYWluIChwcm9jZXNzLWdsb2JhbCDihpJcblx0XHRcdFx0XHQvLyB3b3JrZmxvdy1sZXZlbCDihpIgdHJpZ2dlci1sZXZlbCkgYmVmb3JlIHRoZSBtYWluIHdvcmtmbG93XG5cdFx0XHRcdFx0Ly8gYm9keS4gTGV0cyBjcm9uIHdvcmtmbG93cyBjb21wb3NlIGF1dGgtY2hlY2sgKyBhdWRpdC1sb2dcblx0XHRcdFx0XHQvLyBjaGFpbnMgZXhhY3RseSBsaWtlIEhUVFAgdHJpZ2dlcnMuIEEgdGhyb3dpbmcgbWlkZGxld2FyZVxuXHRcdFx0XHRcdC8vIHByb3BhZ2F0ZXMgdG8gdGhlIG91dGVyIGNhdGNoIGFuZCBzdXJmYWNlcyBhcyBhIGNyb24gam9iXG5cdFx0XHRcdFx0Ly8gZmFpbHVyZS5cblx0XHRcdFx0XHRhd2FpdCB0aGlzLmFwcGx5TWlkZGxld2FyZUNoYWluKGN0eCwgdGhpcy5ub2RlTWFwKTtcblxuXHRcdFx0XHRcdC8vIEV4ZWN1dGUgd29ya2Zsb3dcblx0XHRcdFx0XHRjb25zdCByZXNwb25zZTogVHJpZ2dlclJlc3BvbnNlID0gYXdhaXQgdGhpcy5ydW4oY3R4KTtcblx0XHRcdFx0XHRjb25zdCBlbmQgPSBwZXJmb3JtYW5jZS5ub3coKTtcblxuXHRcdFx0XHRcdC8vIFVwZGF0ZSBqb2Igc3RhdGVcblx0XHRcdFx0XHRzY2hlZHVsZWRKb2IubGFzdFJ1biA9IGV4ZWN1dGlvblRpbWU7XG5cdFx0XHRcdFx0c2NoZWR1bGVkSm9iLm5leHRSdW4gPSB0aGlzLnRvRGF0ZShzY2hlZHVsZWRKb2Iuam9iLm5leHREYXRlKCkpO1xuXG5cdFx0XHRcdFx0Ly8gU2V0IHNwYW4gYXR0cmlidXRlc1xuXHRcdFx0XHRcdHNwYW4uc2V0QXR0cmlidXRlKFwic3VjY2Vzc1wiLCB0cnVlKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcImpvYl9pZFwiLCBqb2JJZCk7XG5cdFx0XHRcdFx0c3Bhbi5zZXRBdHRyaWJ1dGUoXCJ3b3JrZmxvd19wYXRoXCIsIHdvcmtmbG93LnBhdGgpO1xuXHRcdFx0XHRcdHNwYW4uc2V0QXR0cmlidXRlKFwic2NoZWR1bGVcIiwgY29uZmlnLnNjaGVkdWxlKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcInRpbWV6b25lXCIsIHRpbWV6b25lKTtcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcIm1hbnVhbFwiLCBtYW51YWwpO1xuXHRcdFx0XHRcdHNwYW4uc2V0QXR0cmlidXRlKFwiZWxhcHNlZF9tc1wiLCBlbmQgLSBzdGFydCk7XG5cdFx0XHRcdFx0c3Bhbi5zZXRTdGF0dXMoeyBjb2RlOiBTcGFuU3RhdHVzQ29kZS5PSyB9KTtcblxuXHRcdFx0XHRcdC8vIFJlY29yZCBtZXRyaWNzXG5cdFx0XHRcdFx0Y3JvbkV4ZWN1dGlvbnMuYWRkKDEsIHtcblx0XHRcdFx0XHRcdGVudjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYsXG5cdFx0XHRcdFx0XHRqb2JfaWQ6IGpvYklkLFxuXHRcdFx0XHRcdFx0d29ya2Zsb3dfbmFtZTogdGhpcy5jb25maWd1cmF0aW9uLm5hbWUsXG5cdFx0XHRcdFx0XHRtYW51YWw6IFN0cmluZyhtYW51YWwpLFxuXHRcdFx0XHRcdFx0c3VjY2VzczogXCJ0cnVlXCIsXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRjdHgubG9nZ2VyLmxvZyhgQ3JvbiBqb2IgY29tcGxldGVkIGluICR7KGVuZCAtIHN0YXJ0KS50b0ZpeGVkKDIpfW1zOiAke2pvYklkfWApO1xuXG5cdFx0XHRcdFx0cmVzb2x2ZShyZXNwb25zZSk7XG5cdFx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cdFx0XHRcdFx0Ly8gRjUgwrcgYSBjcm9uIHdvcmtmbG93IHdpdGggYSBgd2FpdGAgc3RlcCAob3IgYSBzY2hlZHVsaW5nXG5cdFx0XHRcdFx0Ly8gZ2F0ZSkgdGhyb3dzIERlZmVycmVkRGlzcGF0Y2hTaWduYWwgLyBXYWl0RGlzcGF0Y2hSZXF1ZXN0XG5cdFx0XHRcdFx0Ly8gdG8gZGVmZXIgdGhlIHJ1biDigJQgdGhhdCdzIGEgc3VjY2Vzc2Z1bCBkZWZlcnJhbCwgTk9UIGFcblx0XHRcdFx0XHQvLyBmYWlsdXJlLiBUcmlnZ2VyQmFzZS5ydW4gYWxyZWFkeSBtYXJrZWQgdGhlIHJ1blxuXHRcdFx0XHRcdC8vIGRlbGF5ZWQvcXVldWVkL2RlYm91bmNlZCBhbmQgKGZvciBIVFRQKSBwZXJzaXN0ZWQgdGhlXG5cdFx0XHRcdFx0Ly8gZGlzcGF0Y2guIENyb24ncyBpbi1wcm9jZXNzIHNjaGVkdWxlciBvd25zIHRoZSBldmVudHVhbFxuXHRcdFx0XHRcdC8vIHJlLWZpcmUsIHNvIHdlIGp1c3QgcmVjb3JkIHN1Y2Nlc3MgYW5kIGRvbid0IGJ1bXBcblx0XHRcdFx0XHQvLyBgY3Jvbl9lcnJvcnNgLlxuXHRcdFx0XHRcdGlmIChlcnJvciBpbnN0YW5jZW9mIERlZmVycmVkRGlzcGF0Y2hTaWduYWwgfHwgZXJyb3IgaW5zdGFuY2VvZiBXYWl0RGlzcGF0Y2hSZXF1ZXN0KSB7XG5cdFx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcInN1Y2Nlc3NcIiwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcImRlZmVycmVkXCIsIHRydWUpO1xuXHRcdFx0XHRcdFx0c3Bhbi5zZXRTdGF0dXMoeyBjb2RlOiBTcGFuU3RhdHVzQ29kZS5PSyB9KTtcblxuXHRcdFx0XHRcdFx0Y3JvbkV4ZWN1dGlvbnMuYWRkKDEsIHtcblx0XHRcdFx0XHRcdFx0ZW52OiBwcm9jZXNzLmVudi5OT0RFX0VOVixcblx0XHRcdFx0XHRcdFx0am9iX2lkOiBqb2JJZCxcblx0XHRcdFx0XHRcdFx0d29ya2Zsb3dfbmFtZTogdGhpcy5jb25maWd1cmF0aW9uLm5hbWUsXG5cdFx0XHRcdFx0XHRcdG1hbnVhbDogU3RyaW5nKG1hbnVhbCksXG5cdFx0XHRcdFx0XHRcdHN1Y2Nlc3M6IFwidHJ1ZVwiLFxuXHRcdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRcdHRoaXMubG9nZ2VyLmxvZyhgQ3JvbiBqb2IgZGVmZXJyZWQgJHtqb2JJZH06ICR7KGVycm9yIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuXHRcdFx0XHRcdFx0cmVzb2x2ZSh7IGN0eDoge30gYXMgQ29udGV4dCwgbWV0cmljczoge30gYXMgTWV0cmljc1R5cGUgfSk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y29uc3QgZXJyb3JNZXNzYWdlID0gKGVycm9yIGFzIEVycm9yKS5tZXNzYWdlO1xuXG5cdFx0XHRcdFx0Ly8gU2V0IHNwYW4gZXJyb3Jcblx0XHRcdFx0XHRzcGFuLnNldEF0dHJpYnV0ZShcInN1Y2Nlc3NcIiwgZmFsc2UpO1xuXHRcdFx0XHRcdHNwYW4ucmVjb3JkRXhjZXB0aW9uKGVycm9yIGFzIEVycm9yKTtcblx0XHRcdFx0XHRzcGFuLnNldFN0YXR1cyh7IGNvZGU6IFNwYW5TdGF0dXNDb2RlLkVSUk9SLCBtZXNzYWdlOiBlcnJvck1lc3NhZ2UgfSk7XG5cblx0XHRcdFx0XHQvLyBSZWNvcmQgZXJyb3IgbWV0cmljc1xuXHRcdFx0XHRcdGNyb25FcnJvcnMuYWRkKDEsIHtcblx0XHRcdFx0XHRcdGVudjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYsXG5cdFx0XHRcdFx0XHRqb2JfaWQ6IGpvYklkLFxuXHRcdFx0XHRcdFx0d29ya2Zsb3dfbmFtZTogdGhpcy5jb25maWd1cmF0aW9uPy5uYW1lIHx8IFwidW5rbm93blwiLFxuXHRcdFx0XHRcdFx0bWFudWFsOiBTdHJpbmcobWFudWFsKSxcblx0XHRcdFx0XHR9KTtcblxuXHRcdFx0XHRcdHRoaXMubG9nZ2VyLmVycm9yKGBDcm9uIGpvYiBmYWlsZWQgJHtqb2JJZH06ICR7ZXJyb3JNZXNzYWdlfWAsIChlcnJvciBhcyBFcnJvcikuc3RhY2spO1xuXG5cdFx0XHRcdFx0cmVzb2x2ZSh7IGN0eDoge30gYXMgQ29udGV4dCwgbWV0cmljczoge30gYXMgTWV0cmljc1R5cGUgfSk7XG5cdFx0XHRcdH0gZmluYWxseSB7XG5cdFx0XHRcdFx0c2NoZWR1bGVkSm9iLnJ1bm5pbmcgPSBmYWxzZTtcblx0XHRcdFx0XHRzcGFuLmVuZCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9KTtcblx0fVxufVxuXG5leHBvcnQgZGVmYXVsdCBDcm9uVHJpZ2dlcjtcbiJdfQ==
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@blokjs/trigger-cron",
3
- "version": "0.6.17",
3
+ "version": "0.6.19",
4
+ "files": ["dist"],
4
5
  "description": "Cron/scheduled trigger for Blok workflows - supports cron expressions and interval-based scheduling",
5
6
  "type": "module",
6
7
  "main": "dist/index.js",
@@ -14,9 +15,9 @@
14
15
  "author": "Deskree Technologies Inc.",
15
16
  "license": "Apache-2.0",
16
17
  "dependencies": {
17
- "@blokjs/helper": "^0.6.17",
18
- "@blokjs/runner": "^0.6.17",
19
- "@blokjs/shared": "^0.6.17",
18
+ "@blokjs/helper": "^0.6.19",
19
+ "@blokjs/runner": "^0.6.19",
20
+ "@blokjs/shared": "^0.6.19",
20
21
  "@opentelemetry/api": "^1.9.0",
21
22
  "cron": "^4.4.0",
22
23
  "uuid": "^11.1.0"
package/CHANGELOG.md DELETED
@@ -1,22 +0,0 @@
1
- # @blokjs/trigger-cron
2
-
3
- ## 0.2.0
4
-
5
- ### Minor Changes
6
-
7
- - Initial public release of Blok packages.
8
-
9
- This release includes:
10
-
11
- - Core packages: @blokjs/shared, @blokjs/helper, @blokjs/runner
12
- - Node packages: @blokjs/api-call, @blokjs/if-else, @blokjs/react
13
- - Trigger packages: pubsub, queue, webhook, websocket, worker, cron, grpc
14
- - CLI tool: blokctl
15
- - Editor support: @blokjs/lsp-server, @blokjs/syntax
16
-
17
- ### Patch Changes
18
-
19
- - Updated dependencies
20
- - @blokjs/shared@0.2.0
21
- - @blokjs/helper@0.2.0
22
- - @blokjs/runner@0.2.0
@@ -1,119 +0,0 @@
1
- /**
2
- * CronTrigger Tests
3
- */
4
-
5
- import { describe, expect, it, vi } from "vitest";
6
-
7
- describe("CronTrigger", () => {
8
- describe("ScheduledJob Interface", () => {
9
- it("should accept valid scheduled job structure", () => {
10
- const mockJob = {
11
- nextDate: () => new Date(),
12
- lastDate: () => new Date(),
13
- start: vi.fn(),
14
- stop: vi.fn(),
15
- };
16
-
17
- const scheduledJob = {
18
- id: "cron-test-abc123",
19
- workflowPath: "daily-cleanup",
20
- schedule: "0 2 * * *",
21
- timezone: "America/New_York",
22
- overlap: false,
23
- running: false,
24
- lastRun: new Date(),
25
- nextRun: new Date(),
26
- job: mockJob,
27
- };
28
-
29
- expect(scheduledJob.id).toBe("cron-test-abc123");
30
- expect(scheduledJob.schedule).toBe("0 2 * * *");
31
- expect(scheduledJob.timezone).toBe("America/New_York");
32
- expect(scheduledJob.overlap).toBe(false);
33
- });
34
- });
35
-
36
- describe("CronExecutionContext Interface", () => {
37
- it("should create valid execution context", () => {
38
- const context = {
39
- jobId: "cron-job-123",
40
- scheduledTime: new Date("2024-01-01T02:00:00Z"),
41
- executionTime: new Date("2024-01-01T02:00:01Z"),
42
- schedule: "0 2 * * *",
43
- timezone: "UTC",
44
- manual: false,
45
- };
46
-
47
- expect(context.jobId).toBe("cron-job-123");
48
- expect(context.scheduledTime.toISOString()).toBe("2024-01-01T02:00:00.000Z");
49
- expect(context.manual).toBe(false);
50
- });
51
-
52
- it("should support manual trigger context", () => {
53
- const context = {
54
- jobId: "cron-job-456",
55
- scheduledTime: new Date(),
56
- executionTime: new Date(),
57
- schedule: "0 * * * *",
58
- timezone: "Europe/London",
59
- manual: true,
60
- };
61
-
62
- expect(context.manual).toBe(true);
63
- });
64
- });
65
-
66
- describe("CronTriggerOpts Schema", () => {
67
- it("should validate cron trigger configuration", () => {
68
- const validConfig = {
69
- schedule: "0 * * * *",
70
- timezone: "America/Los_Angeles",
71
- overlap: false,
72
- };
73
-
74
- expect(validConfig.schedule).toBe("0 * * * *");
75
- expect(validConfig.timezone).toBe("America/Los_Angeles");
76
- expect(validConfig.overlap).toBe(false);
77
- });
78
-
79
- it("should support common cron expressions", () => {
80
- const schedules = [
81
- { expr: "* * * * *", desc: "Every minute" },
82
- { expr: "0 * * * *", desc: "Every hour" },
83
- { expr: "0 0 * * *", desc: "Every day at midnight" },
84
- { expr: "0 0 * * 0", desc: "Every Sunday" },
85
- { expr: "0 0 1 * *", desc: "First day of month" },
86
- { expr: "*/5 * * * *", desc: "Every 5 minutes" },
87
- { expr: "0 9-17 * * 1-5", desc: "Hourly, 9-5 on weekdays" },
88
- ];
89
-
90
- for (const schedule of schedules) {
91
- expect(schedule.expr).toBeDefined();
92
- expect(schedule.desc).toBeDefined();
93
- }
94
- });
95
- });
96
-
97
- describe("Timezone Support", () => {
98
- it("should support common timezones", () => {
99
- const timezones = [
100
- "UTC",
101
- "America/New_York",
102
- "America/Los_Angeles",
103
- "Europe/London",
104
- "Europe/Paris",
105
- "Asia/Tokyo",
106
- "Australia/Sydney",
107
- ];
108
-
109
- for (const tz of timezones) {
110
- const config = {
111
- schedule: "0 0 * * *",
112
- timezone: tz,
113
- overlap: false,
114
- };
115
- expect(config.timezone).toBe(tz);
116
- }
117
- });
118
- });
119
- });
@@ -1,449 +0,0 @@
1
- /**
2
- * CronTrigger - Scheduled workflow execution based on cron expressions
3
- *
4
- * Extends TriggerBase to support scheduled triggers:
5
- * - Cron expressions (e.g., "0 * * * *" for hourly)
6
- * - Timezone-aware scheduling
7
- * - Overlap prevention
8
- * - Manual trigger support
9
- *
10
- * Uses the 'cron' package for cron parsing and scheduling.
11
- */
12
-
13
- import type { CronTriggerOpts, HelperResponse } from "@blokjs/helper";
14
- import {
15
- type BlokService,
16
- DefaultLogger,
17
- type GlobalOptions,
18
- NodeMap,
19
- TriggerBase,
20
- type TriggerResponse,
21
- } from "@blokjs/runner";
22
- import type { Context, MetricsType, RequestContext } from "@blokjs/shared";
23
- import { type Span, SpanStatusCode, metrics, trace } from "@opentelemetry/api";
24
- import { CronJob } from "cron";
25
- import { v4 as uuid } from "uuid";
26
-
27
- /**
28
- * Scheduled job information
29
- */
30
- export interface ScheduledJob {
31
- /** Unique job ID */
32
- id: string;
33
- /** Workflow path */
34
- workflowPath: string;
35
- /** Cron expression */
36
- schedule: string;
37
- /** Timezone */
38
- timezone: string;
39
- /** Allow overlapping executions */
40
- overlap: boolean;
41
- /** Whether the job is currently running */
42
- running: boolean;
43
- /** Last execution time */
44
- lastRun?: Date;
45
- /** Next scheduled time */
46
- nextRun?: Date;
47
- /** Internal CronJob instance */
48
- job: CronJob;
49
- }
50
-
51
- /**
52
- * Execution context passed to the workflow
53
- */
54
- export interface CronExecutionContext {
55
- /** Job ID */
56
- jobId: string;
57
- /** Scheduled time (when it was supposed to run) */
58
- scheduledTime: Date;
59
- /** Actual execution time */
60
- executionTime: Date;
61
- /** Cron expression */
62
- schedule: string;
63
- /** Timezone */
64
- timezone: string;
65
- /** Whether this is a manual trigger */
66
- manual: boolean;
67
- }
68
-
69
- /**
70
- * Workflow model with cron trigger configuration
71
- */
72
- interface CronWorkflowModel {
73
- path: string;
74
- config: {
75
- name: string;
76
- version: string;
77
- trigger?: {
78
- cron?: CronTriggerOpts;
79
- [key: string]: unknown;
80
- };
81
- [key: string]: unknown;
82
- };
83
- }
84
-
85
- /**
86
- * CronTrigger - Scheduled workflow execution
87
- */
88
- export abstract class CronTrigger extends TriggerBase {
89
- protected nodeMap: GlobalOptions = {} as GlobalOptions;
90
- protected readonly tracer = trace.getTracer(
91
- process.env.PROJECT_NAME || "trigger-cron-workflow",
92
- process.env.PROJECT_VERSION || "0.0.1",
93
- );
94
- protected readonly logger = new DefaultLogger();
95
- protected jobs: Map<string, ScheduledJob> = new Map();
96
-
97
- // Subclasses provide these
98
- protected abstract nodes: Record<string, BlokService<unknown>>;
99
- protected abstract workflows: Record<string, HelperResponse>;
100
-
101
- constructor() {
102
- super();
103
- this.loadNodes();
104
- this.loadWorkflows();
105
- }
106
-
107
- /**
108
- * Load nodes into the node map
109
- */
110
- loadNodes(): void {
111
- this.nodeMap.nodes = new NodeMap();
112
- const nodeKeys = Object.keys(this.nodes);
113
- for (const key of nodeKeys) {
114
- this.nodeMap.nodes.addNode(key, this.nodes[key]);
115
- }
116
- }
117
-
118
- /**
119
- * Load workflows into the workflow map
120
- */
121
- loadWorkflows(): void {
122
- this.nodeMap.workflows = this.workflows;
123
- }
124
-
125
- /**
126
- * Convert cron DateTime to Date
127
- * The cron package uses luxon DateTime which has toJSDate()
128
- */
129
- protected toDate(dateTime: unknown): Date {
130
- if (dateTime && typeof dateTime === "object" && "toJSDate" in dateTime) {
131
- return (dateTime as { toJSDate: () => Date }).toJSDate();
132
- }
133
- return dateTime instanceof Date ? dateTime : new Date(dateTime as string | number);
134
- }
135
-
136
- /**
137
- * Start the cron scheduler - main entry point
138
- */
139
- async listen(): Promise<number> {
140
- const startTime = this.startCounter();
141
-
142
- try {
143
- // Find all workflows with cron triggers
144
- const cronWorkflows = this.getCronWorkflows();
145
-
146
- if (cronWorkflows.length === 0) {
147
- this.logger.log("No workflows with cron triggers found");
148
- return this.endCounter(startTime);
149
- }
150
-
151
- // Create and start cron jobs for each workflow
152
- for (const workflow of cronWorkflows) {
153
- const config = workflow.config.trigger?.cron as CronTriggerOpts;
154
- const jobId = `cron-${workflow.path}-${uuid().slice(0, 8)}`;
155
-
156
- // `CronTriggerOpts` is `z.input<…>` so `timezone` is `string | undefined`
157
- // even though the schema declares `.default("UTC")`. Apply the
158
- // default once here so the rest of this method (and the cron lib's
159
- // constructor) sees a guaranteed string.
160
- const timezone = config.timezone ?? "UTC";
161
-
162
- this.logger.log(`Scheduling workflow: ${workflow.path} with schedule: ${config.schedule} (${timezone})`);
163
-
164
- const job = new CronJob(
165
- config.schedule,
166
- async () => {
167
- await this.executeWorkflow(jobId, workflow, config, false);
168
- },
169
- null, // onComplete
170
- false, // start
171
- timezone,
172
- );
173
-
174
- const scheduledJob: ScheduledJob = {
175
- id: jobId,
176
- workflowPath: workflow.path,
177
- schedule: config.schedule,
178
- timezone,
179
- overlap: config.overlap ?? false,
180
- running: false,
181
- nextRun: this.toDate(job.nextDate()),
182
- job,
183
- };
184
-
185
- this.jobs.set(jobId, scheduledJob);
186
-
187
- // Start the job
188
- job.start();
189
- this.logger.log(`Job ${jobId} started. Next run: ${scheduledJob.nextRun}`);
190
- }
191
-
192
- this.logger.log(`Cron trigger started. ${this.jobs.size} job(s) scheduled`);
193
-
194
- // Enable HMR in development mode
195
- if (process.env.BLOK_HMR === "true" || process.env.NODE_ENV === "development") {
196
- await this.enableHotReload();
197
- }
198
-
199
- return this.endCounter(startTime);
200
- } catch (error) {
201
- this.logger.error(`Failed to start cron trigger: ${(error as Error).message}`);
202
- throw error;
203
- }
204
- }
205
-
206
- /**
207
- * Stop all cron jobs
208
- */
209
- async stop(): Promise<void> {
210
- for (const [jobId, scheduledJob] of this.jobs) {
211
- scheduledJob.job.stop();
212
- this.logger.log(`Job ${jobId} stopped`);
213
- }
214
- this.jobs.clear();
215
- this.logger.log("Cron trigger stopped");
216
- }
217
-
218
- protected override async onHmrWorkflowChange(): Promise<void> {
219
- this.logger.log("[HMR] Cron workflow changed, reloading...");
220
- await this.waitForInFlightRequests();
221
- await this.stop();
222
- this.loadWorkflows();
223
- await this.listen();
224
- }
225
-
226
- /**
227
- * Manually trigger a specific job
228
- */
229
- async triggerJob(jobId: string): Promise<TriggerResponse | null> {
230
- const scheduledJob = this.jobs.get(jobId);
231
- if (!scheduledJob) {
232
- this.logger.error(`Job not found: ${jobId}`);
233
- return null;
234
- }
235
-
236
- // Get the workflow
237
- const workflow = this.getWorkflowByPath(scheduledJob.workflowPath);
238
- if (!workflow) {
239
- this.logger.error(`Workflow not found: ${scheduledJob.workflowPath}`);
240
- return null;
241
- }
242
-
243
- const config = workflow.config.trigger?.cron as CronTriggerOpts;
244
- return this.executeWorkflow(jobId, workflow, config, true);
245
- }
246
-
247
- /**
248
- * Get all scheduled jobs
249
- */
250
- getJobs(): ScheduledJob[] {
251
- return Array.from(this.jobs.values()).map((job) => ({
252
- ...job,
253
- nextRun: this.toDate(job.job.nextDate()),
254
- }));
255
- }
256
-
257
- /**
258
- * Get all workflows that have cron triggers
259
- */
260
- protected getCronWorkflows(): CronWorkflowModel[] {
261
- const workflows: CronWorkflowModel[] = [];
262
-
263
- for (const [path, workflow] of Object.entries(this.nodeMap.workflows || {})) {
264
- const workflowConfig = (workflow as unknown as { _config: CronWorkflowModel["config"] })._config;
265
-
266
- if (workflowConfig?.trigger) {
267
- const triggerType = Object.keys(workflowConfig.trigger)[0];
268
-
269
- if (triggerType === "cron" && workflowConfig.trigger.cron) {
270
- workflows.push({
271
- path,
272
- config: workflowConfig,
273
- });
274
- }
275
- }
276
- }
277
-
278
- return workflows;
279
- }
280
-
281
- /**
282
- * Get workflow by path
283
- */
284
- protected getWorkflowByPath(path: string): CronWorkflowModel | null {
285
- const workflow = this.nodeMap.workflows?.[path];
286
- if (!workflow) return null;
287
-
288
- const workflowConfig = (workflow as unknown as { _config: CronWorkflowModel["config"] })._config;
289
- return {
290
- path,
291
- config: workflowConfig,
292
- };
293
- }
294
-
295
- /**
296
- * Execute a workflow
297
- */
298
- protected async executeWorkflow(
299
- jobId: string,
300
- workflow: CronWorkflowModel,
301
- config: CronTriggerOpts,
302
- manual: boolean,
303
- ): Promise<TriggerResponse> {
304
- const scheduledJob = this.jobs.get(jobId);
305
- if (!scheduledJob) {
306
- throw new Error(`Job not found: ${jobId}`);
307
- }
308
-
309
- // Check for overlap
310
- if (scheduledJob.running && !scheduledJob.overlap) {
311
- this.logger.log(`Skipping ${jobId}: previous execution still running (overlap disabled)`);
312
- return { ctx: {} as Context, metrics: {} as MetricsType };
313
- }
314
-
315
- const executionId = uuid();
316
- const lastDate = scheduledJob.job.lastDate();
317
- const scheduledTime = lastDate ? new Date(lastDate as unknown as string | number) : new Date();
318
- const executionTime = new Date();
319
-
320
- // Apply the schema default — see explanation in `listen()`.
321
- const timezone = config.timezone ?? "UTC";
322
-
323
- const defaultMeter = metrics.getMeter("default");
324
- const cronExecutions = defaultMeter.createCounter("cron_executions", {
325
- description: "Cron job executions",
326
- });
327
- const cronErrors = defaultMeter.createCounter("cron_errors", {
328
- description: "Cron job execution errors",
329
- });
330
-
331
- return new Promise((resolve) => {
332
- this.tracer.startActiveSpan(`cron:${workflow.path}`, async (span: Span) => {
333
- scheduledJob.running = true;
334
-
335
- try {
336
- const start = performance.now();
337
-
338
- // Initialize configuration for this workflow
339
- await this.configuration.init(workflow.path, this.nodeMap);
340
-
341
- // Create context
342
- const ctx: Context = this.createContext(undefined, workflow.path, executionId);
343
-
344
- // Create execution context
345
- const cronContext: CronExecutionContext = {
346
- jobId,
347
- scheduledTime,
348
- executionTime,
349
- schedule: config.schedule,
350
- timezone,
351
- manual,
352
- };
353
-
354
- // Populate request with cron context
355
- ctx.request = {
356
- body: cronContext,
357
- headers: {
358
- "x-cron-job-id": jobId,
359
- "x-cron-schedule": config.schedule,
360
- "x-cron-timezone": config.timezone,
361
- "x-cron-manual": String(manual),
362
- },
363
- query: {},
364
- params: {
365
- jobId,
366
- schedule: config.schedule,
367
- },
368
- } as unknown as RequestContext;
369
-
370
- // Store cron context in vars
371
- if (!ctx.vars) ctx.vars = {};
372
- ctx.vars._cron_context = {
373
- jobId,
374
- scheduledTime: scheduledTime.toISOString(),
375
- executionTime: executionTime.toISOString(),
376
- schedule: config.schedule,
377
- timezone: config.timezone,
378
- manual: String(manual),
379
- };
380
-
381
- ctx.logger.log(`Executing cron job: ${jobId} (${manual ? "manual" : "scheduled"})`);
382
-
383
- // v0.6 · apply the merged middleware chain (process-global →
384
- // workflow-level → trigger-level) before the main workflow
385
- // body. Lets cron workflows compose auth-check + audit-log
386
- // chains exactly like HTTP triggers. A throwing middleware
387
- // propagates to the outer catch and surfaces as a cron job
388
- // failure.
389
- await this.applyMiddlewareChain(ctx, this.nodeMap);
390
-
391
- // Execute workflow
392
- const response: TriggerResponse = await this.run(ctx);
393
- const end = performance.now();
394
-
395
- // Update job state
396
- scheduledJob.lastRun = executionTime;
397
- scheduledJob.nextRun = this.toDate(scheduledJob.job.nextDate());
398
-
399
- // Set span attributes
400
- span.setAttribute("success", true);
401
- span.setAttribute("job_id", jobId);
402
- span.setAttribute("workflow_path", workflow.path);
403
- span.setAttribute("schedule", config.schedule);
404
- span.setAttribute("timezone", timezone);
405
- span.setAttribute("manual", manual);
406
- span.setAttribute("elapsed_ms", end - start);
407
- span.setStatus({ code: SpanStatusCode.OK });
408
-
409
- // Record metrics
410
- cronExecutions.add(1, {
411
- env: process.env.NODE_ENV,
412
- job_id: jobId,
413
- workflow_name: this.configuration.name,
414
- manual: String(manual),
415
- success: "true",
416
- });
417
-
418
- ctx.logger.log(`Cron job completed in ${(end - start).toFixed(2)}ms: ${jobId}`);
419
-
420
- resolve(response);
421
- } catch (error) {
422
- const errorMessage = (error as Error).message;
423
-
424
- // Set span error
425
- span.setAttribute("success", false);
426
- span.recordException(error as Error);
427
- span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
428
-
429
- // Record error metrics
430
- cronErrors.add(1, {
431
- env: process.env.NODE_ENV,
432
- job_id: jobId,
433
- workflow_name: this.configuration?.name || "unknown",
434
- manual: String(manual),
435
- });
436
-
437
- this.logger.error(`Cron job failed ${jobId}: ${errorMessage}`, (error as Error).stack);
438
-
439
- resolve({ ctx: {} as Context, metrics: {} as MetricsType });
440
- } finally {
441
- scheduledJob.running = false;
442
- span.end();
443
- }
444
- });
445
- });
446
- }
447
- }
448
-
449
- export default CronTrigger;
package/src/index.ts DELETED
@@ -1,72 +0,0 @@
1
- /**
2
- * @blokjs/trigger-cron
3
- *
4
- * Cron/scheduled trigger for Blok workflows.
5
- * Execute workflows on a schedule using cron expressions.
6
- *
7
- * Features:
8
- * - Standard cron expression syntax
9
- * - Timezone-aware scheduling
10
- * - Overlap prevention
11
- * - Manual trigger support
12
- * - Job management API
13
- *
14
- * @example
15
- * ```typescript
16
- * import { CronTrigger } from "@blokjs/trigger-cron";
17
- *
18
- * class MyCronTrigger extends CronTrigger {
19
- * protected nodes = myNodes;
20
- * protected workflows = myWorkflows;
21
- * }
22
- *
23
- * const trigger = new MyCronTrigger();
24
- * await trigger.listen();
25
- *
26
- * // List all scheduled jobs
27
- * const jobs = trigger.getJobs();
28
- *
29
- * // Manually trigger a job
30
- * await trigger.triggerJob("cron-my-workflow-abc123");
31
- * ```
32
- *
33
- * Workflow Definition:
34
- * ```typescript
35
- * Workflow({ name: "daily-cleanup", version: "1.0.0" })
36
- * .addTrigger("cron", {
37
- * schedule: "0 2 * * *", // Run at 2 AM daily
38
- * timezone: "America/New_York",
39
- * overlap: false,
40
- * })
41
- * .addStep({ ... });
42
- * ```
43
- *
44
- * Cron Expression Format:
45
- * ```
46
- * * * * * * *
47
- * │ │ │ │ │ │
48
- * │ │ │ │ │ └── Day of week (0-7, Sun=0,7)
49
- * │ │ │ │ └──── Month (1-12)
50
- * │ │ │ └────── Day of month (1-31)
51
- * │ │ └──────── Hour (0-23)
52
- * │ └────────── Minute (0-59)
53
- * └──────────── Second (0-59, optional)
54
- * ```
55
- *
56
- * Common schedules:
57
- * - "* * * * *" - Every minute
58
- * - "0 * * * *" - Every hour
59
- * - "0 0 * * *" - Every day at midnight
60
- * - "0 0 * * 0" - Every Sunday at midnight
61
- * - "0 0 1 * *" - First day of every month
62
- */
63
-
64
- // Core exports
65
- export {
66
- CronTrigger,
67
- type ScheduledJob,
68
- type CronExecutionContext,
69
- } from "./CronTrigger";
70
-
71
- // Re-export types from helper for convenience
72
- export type { CronTriggerOpts } from "@blokjs/helper";
package/tsconfig.json DELETED
@@ -1,32 +0,0 @@
1
- {
2
- "ts-node": {
3
- "transpileOnly": true
4
- },
5
- "compilerOptions": {
6
- "target": "ES2022",
7
- "module": "es2022",
8
- "lib": ["ES2022"],
9
- "declaration": true,
10
- "strict": true,
11
- "noImplicitAny": true,
12
- "strictNullChecks": true,
13
- "noImplicitThis": true,
14
- "alwaysStrict": true,
15
- "noUnusedLocals": false,
16
- "noUnusedParameters": false,
17
- "noImplicitReturns": true,
18
- "noFallthroughCasesInSwitch": false,
19
- "inlineSourceMap": true,
20
- "inlineSources": true,
21
- "experimentalDecorators": true,
22
- "emitDecoratorMetadata": true,
23
- "skipLibCheck": true,
24
- "esModuleInterop": true,
25
- "resolveJsonModule": true,
26
- "outDir": "./dist",
27
- "rootDir": "./src",
28
- "moduleResolution": "bundler"
29
- },
30
- "include": ["src/**/*"],
31
- "exclude": ["node_modules", "dist", "**/*.test.ts"]
32
- }