velocious 1.0.685 → 1.0.686

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.
@@ -7,6 +7,49 @@ import JsonSocket from "./json-socket.js"
7
7
 
8
8
  const DEFAULT_REQUEST_TIMEOUT_MS = 10000
9
9
  export const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 120000
10
+ const LIFECYCLE_CONNECT_RETRY_DELAY_MS = 50
11
+ const TRANSIENT_CONNECT_ERROR_CODES = new Set(["ECONNABORTED", "ECONNREFUSED", "ENOENT"])
12
+
13
+ /**
14
+ * Whether a lifecycle request failure is a transient "endpoint not ready yet"
15
+ * connect failure (the coordinator's control socket opens asynchronously after
16
+ * its process starts) rather than a definitive protocol or state rejection.
17
+ * @param {unknown} error - The rejection reason.
18
+ * @returns {boolean} - Whether the request may be retried.
19
+ */
20
+ function isTransientConnectError(error) {
21
+ if (typeof error !== "object" || error === null) return false
22
+ const code = /** @type {{code?: unknown}} */ (error).code
23
+
24
+ return typeof code === "string" && TRANSIENT_CONNECT_ERROR_CODES.has(code)
25
+ }
26
+
27
+ /**
28
+ * Waits before the next lifecycle connect retry, rejecting with the signal
29
+ * reason when the caller-owned deadline fires mid-wait.
30
+ * @param {number} delayMs - Wait between attempts.
31
+ * @param {AbortSignal} signal - Caller-owned deadline signal.
32
+ * @returns {Promise<void>} - Resolves after the delay, or rejects on abort.
33
+ */
34
+ async function waitBeforeNextAttempt(delayMs, signal) {
35
+ await new Promise((resolve, reject) => {
36
+ if (signal.aborted) {
37
+ reject(signal.reason)
38
+
39
+ return
40
+ }
41
+ const timer = setTimeout(() => {
42
+ signal.removeEventListener("abort", onAbort)
43
+ resolve(undefined)
44
+ }, delayMs)
45
+ const onAbort = () => {
46
+ clearTimeout(timer)
47
+ reject(signal.reason)
48
+ }
49
+
50
+ signal.addEventListener("abort", onAbort)
51
+ })
52
+ }
10
53
 
11
54
  /** One-request acknowledged lifecycle client. */
12
55
  export default class BackgroundJobsLifecycleClient {
@@ -59,14 +102,35 @@ export default class BackgroundJobsLifecycleClient {
59
102
  }
60
103
 
61
104
  /**
62
- * Sends the lifecycle request under its caller-owned deadline.
105
+ * Sends the lifecycle request under its caller-owned deadline. Retries
106
+ * transient "endpoint not ready yet" connect failures (the coordinator opens
107
+ * its control socket asynchronously after its process starts) until the
108
+ * deadline; any definitive protocol or state rejection fails immediately.
63
109
  * @param {object} args - Request details.
64
110
  * @param {"activate" | "retire"} args.action - Lifecycle action.
65
111
  * @param {AbortSignal} args.signal - Request deadline signal.
66
112
  * @returns {Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>} - Resulting state.
67
113
  */
68
114
  async _runRequest({action, signal}) {
69
- const requestId = randomUUID()
115
+ while (true) {
116
+ try {
117
+ return await this._attemptRequest(action, randomUUID(), signal)
118
+ } catch (error) {
119
+ if (!isTransientConnectError(error)) throw error
120
+ if (signal.aborted) throw signal.reason
121
+ await waitBeforeNextAttempt(LIFECYCLE_CONNECT_RETRY_DELAY_MS, signal)
122
+ }
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Performs one lifecycle request attempt against the control socket.
128
+ * @param {"activate" | "retire"} action - Lifecycle action.
129
+ * @param {string} requestId - Request identity for acknowledgement matching.
130
+ * @param {AbortSignal} signal - Request deadline signal.
131
+ * @returns {Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>} - Resulting state.
132
+ */
133
+ async _attemptRequest(action, requestId, signal) {
70
134
  const socket = net.createConnection(this.socketPath)
71
135
  const jsonSocket = new JsonSocket(socket)
72
136
 
@@ -35,7 +35,10 @@ export default class BackgroundJobsLifecycleClient {
35
35
  */
36
36
  _request(action: "activate" | "retire"): Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>;
37
37
  /**
38
- * Sends the lifecycle request under its caller-owned deadline.
38
+ * Sends the lifecycle request under its caller-owned deadline. Retries
39
+ * transient "endpoint not ready yet" connect failures (the coordinator opens
40
+ * its control socket asynchronously after its process starts) until the
41
+ * deadline; any definitive protocol or state rejection fails immediately.
39
42
  * @param {object} args - Request details.
40
43
  * @param {"activate" | "retire"} args.action - Lifecycle action.
41
44
  * @param {AbortSignal} args.signal - Request deadline signal.
@@ -45,5 +48,13 @@ export default class BackgroundJobsLifecycleClient {
45
48
  action: "activate" | "retire";
46
49
  signal: AbortSignal;
47
50
  }): Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>;
51
+ /**
52
+ * Performs one lifecycle request attempt against the control socket.
53
+ * @param {"activate" | "retire"} action - Lifecycle action.
54
+ * @param {string} requestId - Request identity for acknowledgement matching.
55
+ * @param {AbortSignal} signal - Request deadline signal.
56
+ * @returns {Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>} - Resulting state.
57
+ */
58
+ _attemptRequest(action: "activate" | "retire", requestId: string, signal: AbortSignal): Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>;
48
59
  }
49
60
  //# sourceMappingURL=lifecycle-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle-client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/lifecycle-client.js"],"names":[],"mappings":"AAQA,eAAO,MAAM,gCAAgC,SAAS,CAAA;AAEtD,iDAAiD;AACjD,MAAM,CAAC,OAAO,OAAO,6BAA6B;IAezC,YAAY;IACZ,UAAU;IAIV,gBAAgB;IAnBvB;;;;;;;OAOG;IACH,YAAY,EAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,gBAA6C,EAAC,EALjG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO,CAC7C;QAAsB,YAAY,AAAlC,CACA,EADQ,MAAM,CACd;QAAsB,UAAU,AAAhC,CACA,EADQ,MAAM,CACd;QAAsB,gBAAgB,AAAtC,CACF,EADU,MAAM,CAChB;KACmG,EAcnG;IAED;;;OAGG;IACG,QAAQ,IAFD,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAEtB;IAE3D;;;OAGG;IACG,MAAM,IAFC,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAE1B;IAEvD;;;;OAIG;IACG,QAAQ,CAAC,MAAM,EAHV,UAAU,GAAG,QAGH,GAFR,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAOhF;IAED;;;;;;OAMG;IACG,WAAW,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,EAJ/B;QAAoC,MAAM,EAAlC,UAAU,GAAG,QAAQ,CAC7B;QAA0B,MAAM,EAAxB,WAAW,CACnB;KAE+B,GAFrB,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CA4DhF;CACF"}
1
+ {"version":3,"file":"lifecycle-client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/lifecycle-client.js"],"names":[],"mappings":"AAQA,eAAO,MAAM,gCAAgC,SAAS,CAAA;AA6CtD,iDAAiD;AACjD,MAAM,CAAC,OAAO,OAAO,6BAA6B;IAezC,YAAY;IACZ,UAAU;IAIV,gBAAgB;IAnBvB;;;;;;;OAOG;IACH,YAAY,EAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,gBAA6C,EAAC,EALjG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO,CAC7C;QAAsB,YAAY,AAAlC,CACA,EADQ,MAAM,CACd;QAAsB,UAAU,AAAhC,CACA,EADQ,MAAM,CACd;QAAsB,gBAAgB,AAAtC,CACF,EADU,MAAM,CAChB;KACmG,EAcnG;IAED;;;OAGG;IACG,QAAQ,IAFD,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAEtB;IAE3D;;;OAGG;IACG,MAAM,IAFC,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAE1B;IAEvD;;;;OAIG;IACG,QAAQ,CAAC,MAAM,EAHV,UAAU,GAAG,QAGH,GAFR,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAOhF;IAED;;;;;;;;;OASG;IACG,WAAW,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,EAJ/B;QAAoC,MAAM,EAAlC,UAAU,GAAG,QAAQ,CAC7B;QAA0B,MAAM,EAAxB,WAAW,CACnB;KAE+B,GAFrB,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAYhF;IAED;;;;;;OAMG;IACG,eAAe,CAAC,MAAM,EALjB,UAAU,GAAG,QAKI,EAAE,SAAS,EAJ5B,MAI4B,EAAE,MAAM,EAHpC,WAGoC,GAFlC,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CA2DhF;CACF"}
@@ -5,6 +5,45 @@ import timeout from "awaitery/build/timeout.js";
5
5
  import JsonSocket from "./json-socket.js";
6
6
  const DEFAULT_REQUEST_TIMEOUT_MS = 10000;
7
7
  export const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 120000;
8
+ const LIFECYCLE_CONNECT_RETRY_DELAY_MS = 50;
9
+ const TRANSIENT_CONNECT_ERROR_CODES = new Set(["ECONNABORTED", "ECONNREFUSED", "ENOENT"]);
10
+ /**
11
+ * Whether a lifecycle request failure is a transient "endpoint not ready yet"
12
+ * connect failure (the coordinator's control socket opens asynchronously after
13
+ * its process starts) rather than a definitive protocol or state rejection.
14
+ * @param {unknown} error - The rejection reason.
15
+ * @returns {boolean} - Whether the request may be retried.
16
+ */
17
+ function isTransientConnectError(error) {
18
+ if (typeof error !== "object" || error === null)
19
+ return false;
20
+ const code = /** @type {{code?: unknown}} */ (error).code;
21
+ return typeof code === "string" && TRANSIENT_CONNECT_ERROR_CODES.has(code);
22
+ }
23
+ /**
24
+ * Waits before the next lifecycle connect retry, rejecting with the signal
25
+ * reason when the caller-owned deadline fires mid-wait.
26
+ * @param {number} delayMs - Wait between attempts.
27
+ * @param {AbortSignal} signal - Caller-owned deadline signal.
28
+ * @returns {Promise<void>} - Resolves after the delay, or rejects on abort.
29
+ */
30
+ async function waitBeforeNextAttempt(delayMs, signal) {
31
+ await new Promise((resolve, reject) => {
32
+ if (signal.aborted) {
33
+ reject(signal.reason);
34
+ return;
35
+ }
36
+ const timer = setTimeout(() => {
37
+ signal.removeEventListener("abort", onAbort);
38
+ resolve(undefined);
39
+ }, delayMs);
40
+ const onAbort = () => {
41
+ clearTimeout(timer);
42
+ reject(signal.reason);
43
+ };
44
+ signal.addEventListener("abort", onAbort);
45
+ });
46
+ }
8
47
  /** One-request acknowledged lifecycle client. */
9
48
  export default class BackgroundJobsLifecycleClient {
10
49
  /**
@@ -54,14 +93,37 @@ export default class BackgroundJobsLifecycleClient {
54
93
  }, async ({ control }) => await this._runRequest({ action, signal: control.signal }));
55
94
  }
56
95
  /**
57
- * Sends the lifecycle request under its caller-owned deadline.
96
+ * Sends the lifecycle request under its caller-owned deadline. Retries
97
+ * transient "endpoint not ready yet" connect failures (the coordinator opens
98
+ * its control socket asynchronously after its process starts) until the
99
+ * deadline; any definitive protocol or state rejection fails immediately.
58
100
  * @param {object} args - Request details.
59
101
  * @param {"activate" | "retire"} args.action - Lifecycle action.
60
102
  * @param {AbortSignal} args.signal - Request deadline signal.
61
103
  * @returns {Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>} - Resulting state.
62
104
  */
63
105
  async _runRequest({ action, signal }) {
64
- const requestId = randomUUID();
106
+ while (true) {
107
+ try {
108
+ return await this._attemptRequest(action, randomUUID(), signal);
109
+ }
110
+ catch (error) {
111
+ if (!isTransientConnectError(error))
112
+ throw error;
113
+ if (signal.aborted)
114
+ throw signal.reason;
115
+ await waitBeforeNextAttempt(LIFECYCLE_CONNECT_RETRY_DELAY_MS, signal);
116
+ }
117
+ }
118
+ }
119
+ /**
120
+ * Performs one lifecycle request attempt against the control socket.
121
+ * @param {"activate" | "retire"} action - Lifecycle action.
122
+ * @param {string} requestId - Request identity for acknowledgement matching.
123
+ * @param {AbortSignal} signal - Request deadline signal.
124
+ * @returns {Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>} - Resulting state.
125
+ */
126
+ async _attemptRequest(action, requestId, signal) {
65
127
  const socket = net.createConnection(this.socketPath);
66
128
  const jsonSocket = new JsonSocket(socket);
67
129
  return await new Promise((resolve, reject) => {
@@ -123,4 +185,4 @@ export default class BackgroundJobsLifecycleClient {
123
185
  });
124
186
  }
125
187
  }
126
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZWN5Y2xlLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvbGlmZWN5Y2xlLWNsaWVudC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEdBQUcsTUFBTSxVQUFVLENBQUE7QUFDMUIsT0FBTyxPQUFPLE1BQU0sMkJBQTJCLENBQUE7QUFDL0MsT0FBTyxVQUFVLE1BQU0sa0JBQWtCLENBQUE7QUFFekMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLENBQUE7QUFDeEMsTUFBTSxDQUFDLE1BQU0sZ0NBQWdDLEdBQUcsTUFBTSxDQUFBO0FBRXRELGlEQUFpRDtBQUNqRCxNQUFNLENBQUMsT0FBTyxPQUFPLDZCQUE2QjtJQUNoRDs7Ozs7OztPQU9HO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixHQUFHLDBCQUEwQixFQUFDO1FBQ2xHLE1BQU0sZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLHFDQUFxQyxDQUFDO1lBQzNFLFlBQVk7WUFDWixtQkFBbUIsRUFBRSxVQUFVO1lBQy9CLFVBQVUsRUFBRSwrQkFBK0I7U0FDNUMsQ0FBQyxDQUFBO1FBQ0YsSUFBSSxDQUFDLFlBQVksR0FBRyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUE7UUFDakQsSUFBSSxDQUFDLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQTtRQUN0RCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLGdCQUFnQixHQUFHLENBQUMsSUFBSSxnQkFBZ0IsR0FBRyxnQ0FBZ0MsRUFBRSxDQUFDO1lBQ3ZILE1BQU0sSUFBSSxTQUFTLENBQUMscURBQXFELGdDQUFnQyxFQUFFLENBQUMsQ0FBQTtRQUM5RyxDQUFDO1FBQ0QsSUFBSSxDQUFDLGdC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Q0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUE7b0JBQy9FLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7b0JBQy9CLE9BQU07Z0JBQ1IsQ0FBQztnQkFDRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssK0JBQStCLElBQUksT0FBTyxDQUFDLFlBQVksS0FBSyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7b0JBQ25HLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLG1EQUFtRCxDQUFDLENBQUMsQ0FBQyxDQUFBO29CQUN4RixPQUFNO2dCQUNSLENBQUM7Z0JBQ0QsTUFBTSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUE7WUFDbkQsQ0FBQyxDQUFDLENBQUE7WUFDRixNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQTtZQUNqQyxJQUFJLE1BQU0sQ0FBQyxPQUFPO2dCQUFFLE9BQU8sRUFBRSxDQUFBO1FBQy9CLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tIFwibm9kZTpjcnlwdG9cIlxuaW1wb3J0IG5ldCBmcm9tIFwibm9kZTpuZXRcIlxuaW1wb3J0IHRpbWVvdXQgZnJvbSBcImF3YWl0ZXJ5L2J1aWxkL3RpbWVvdXQuanNcIlxuaW1wb3J0IEpzb25Tb2NrZXQgZnJvbSBcIi4vanNvbi1zb2NrZXQuanNcIlxuXG5jb25zdCBERUZBVUxUX1JFUVVFU1RfVElNRU9VVF9NUyA9IDEwMDAwXG5leHBvcnQgY29uc3QgTUFYX0xJRkVDWUNMRV9SRVFVRVNUX1RJTUVPVVRfTVMgPSAxMjAwMDBcblxuLyoqIE9uZS1yZXF1ZXN0IGFja25vd2xlZGdlZCBsaWZlY3ljbGUgY2xpZW50LiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQmFja2dyb3VuZEpvYnNMaWZlY3ljbGVDbGllbnQge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIGxpZmVjeWNsZSBjbGllbnQuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQ2xpZW50IG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuZ2VuZXJhdGlvbklkXSAtIEV4cGxpY2l0IGdlbmVyYXRpb24gaWRlbnRpdHkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5zb2NrZXRQYXRoXSAtIEV4cGxpY2l0IGNvbnRyb2wgc29ja2V0IHBhdGguXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5yZXF1ZXN0VGltZW91dE1zXSAtIFJlcXVlc3QgZGVhZGxpbmUgYmVsb3cgdGhlIHN1cGVydmlzb3IgaG9vayB0aW1lb3V0IChkZWZhdWx0OiAxMDAwMCkuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7Y29uZmlndXJhdGlvbiwgZ2VuZXJhdGlvbklkLCBzb2NrZXRQYXRoLCByZXF1ZXN0VGltZW91dE1zID0gREVGQVVMVF9SRVFVRVNUX1RJTUVPVVRfTVN9KSB7XG4gICAgY29uc3QgZ2VuZXJhdGlvbkNvbmZpZyA9IGNvbmZpZ3VyYXRpb24ucmVzb2x2ZUJhY2tncm91bmRKb2JzR2VuZXJhdGlvbkNvbmZpZyh7XG4gICAgICBnZW5lcmF0aW9uSWQsXG4gICAgICBsaWZlY3ljbGVTb2NrZXRQYXRoOiBzb2NrZXRQYXRoLFxuICAgICAgc291cmNlTmFtZTogXCJCYWNrZ3JvdW5kSm9ic0xpZmVjeWNsZUNsaWVudFwiXG4gICAgfSlcbiAgICB0aGlzLmdlbmVyYXRpb25JZCA9IGdlbmVyYXRpb25Db25maWcuZ2VuZXJhdGlvbklkXG4gICAgdGhpcy5zb2NrZXRQYXRoID0gZ2VuZXJhdGlvbkNvbmZpZy5saWZlY3ljbGVTb2NrZXRQYXRoXG4gICAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHJlcXVlc3RUaW1lb3V0TXMpIHx8IHJlcXVlc3RUaW1lb3V0TXMgPCAxIHx8IHJlcXVlc3RUaW1lb3V0TXMgPiBNQVhfTElGRUNZQ0xFX1JFUVVFU1RfVElNRU9VVF9NUykge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgcmVxdWVzdFRpbWVvdXRNcyBtdXN0IGJlIGFuIGludGVnZXIgYmV0d2VlbiAxIGFuZCAke01BWF9MSUZFQ1lDTEVfUkVRVUVTVF9USU1FT1VUX01TfWApXG4gICAgfVxuICAgIHRoaXMucmVxdWVzdFRpbWVvdXRNcyA9IHJlcXVlc3RUaW1lb3V0TXNcbiAgICBpZiAoIXRoaXMuZ2VuZXJhdGlvbklkKSB0aHJvdyBuZXcgRXJyb3IoXCJCYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIGNsaWVudCByZXF1aXJlcyBnZW5lcmF0aW9uSWRcIilcbiAgICBpZiAoIXRoaXMuc29ja2V0UGF0aCkgdGhyb3cgbmV3IEVycm9yKFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSBjbGllbnQgcmVxdWlyZXMgbGlmZWN5Y2xlU29ja2V0UGF0aFwiKVxuICB9XG5cbiAgLyoqXG4gICAqIEFjdGl2YXRlcyB0aGUgZ2VuZXJhdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25MaWZlY3ljbGVTdGF0ZT59IC0gUmVzdWx0aW5nIHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgYWN0aXZhdGUoKSB7IHJldHVybiBhd2FpdCB0aGlzLl9yZXF1ZXN0KFwiYWN0aXZhdGVcIikgfVxuXG4gIC8qKlxuICAgKiBSZXRpcmVzIHRoZSBnZW5lcmF0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JzR2VuZXJhdGlvbkxpZmVjeWNsZVN0YXRlPn0gLSBSZXN1bHRpbmcgc3RhdGUuXG4gICAqL1xuICBhc3luYyByZXRpcmUoKSB7IHJldHVybiBhd2FpdCB0aGlzLl9yZXF1ZXN0KFwicmV0aXJlXCIpIH1cblxuICAvKipcbiAgICogU2VuZHMgZXhhY3RseSBvbmUgbGlmZWN5Y2xlIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7XCJhY3RpdmF0ZVwiIHwgXCJyZXRpcmVcIn0gYWN0aW9uIC0gTGlmZWN5Y2xlIGFjdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25MaWZlY3ljbGVTdGF0ZT59IC0gUmVzdWx0aW5nIHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgX3JlcXVlc3QoYWN0aW9uKSB7XG4gICAgcmV0dXJuIGF3YWl0IHRpbWVvdXQoe1xuICAgICAgZXJyb3JNZXNzYWdlOiBgQmFja2dyb3VuZCBqb2JzICR7YWN0aW9ufSByZXF1ZXN0IGZvciAke3RoaXMuZ2VuZXJhdGlvbklkfSB0aW1lZCBvdXQgYWZ0ZXIgJHt0aGlzLnJlcXVlc3RUaW1lb3V0TXN9bXMgYXQgJHt0aGlzLnNvY2tldFBhdGh9YCxcbiAgICAgIHRpbWVvdXQ6IHRoaXMucmVxdWVzdFRpbWVvdXRNc1xuICAgIH0sIGFzeW5jICh7Y29udHJvbH0pID0+IGF3YWl0IHRoaXMuX3J1blJlcXVlc3Qoe2FjdGlvbiwgc2lnbmFsOiBjb250cm9sLnNpZ25hbH0pKVxuICB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIHRoZSBsaWZlY3ljbGUgcmVxdWVzdCB1bmRlciBpdHMgY2FsbGVyLW93bmVkIGRlYWRsaW5lLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFJlcXVlc3QgZGV0YWlscy5cbiAgICogQHBhcmFtIHtcImFjdGl2YXRlXCIgfCBcInJldGlyZVwifSBhcmdzLmFjdGlvbiAtIExpZmVjeWNsZSBhY3Rpb24uXG4gICAqIEBwYXJhbSB7QWJvcnRTaWduYWx9IGFyZ3Muc2lnbmFsIC0gUmVxdWVzdCBkZWFkbGluZSBzaWduYWwuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYnNHZW5lcmF0aW9uTGlmZWN5Y2xlU3RhdGU+fSAtIFJlc3VsdGluZyBzdGF0ZS5cbiAgICovXG4gIGFzeW5jIF9ydW5SZXF1ZXN0KHthY3Rpb24sIHNpZ25hbH0pIHtcbiAgICBjb25zdCByZXF1ZXN0SWQgPSByYW5kb21VVUlEKClcbiAgICBjb25zdCBzb2NrZXQgPSBuZXQuY3JlYXRlQ29ubmVjdGlvbih0aGlzLnNvY2tldFBhdGgpXG4gICAgY29uc3QganNvblNvY2tldCA9IG5ldyBKc29uU29ja2V0KHNvY2tldClcblxuICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBsZXQgZmluaXNoZWQgPSBmYWxzZVxuICAgICAgLyoqXG4gICAgICAgKiBTZXR0bGVzIHRoZSByZXF1ZXN0IG9uY2UuXG4gICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRlYXJkb3duIG9wdGlvbnMuXG4gICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmRlc3Ryb3ldIC0gRGVzdHJveSBpbnN0ZWFkIG9mIGNsb3NpbmcuXG4gICAgICAgKiBAcGFyYW0geygpID0+IHZvaWR9IGNhbGxiYWNrIC0gU2V0dGxlbWVudCBjYWxsYmFjay5cbiAgICAgICAqL1xuICAgICAgY29uc3QgZmluaXNoID0gKHtkZXN0cm95ID0gZmFsc2V9LCBjYWxsYmFjaykgPT4ge1xuICAgICAgICBpZiAoZmluaXNoZWQpIHJldHVyblxuICAgICAgICBmaW5pc2hlZCA9IHRydWVcbiAgICAgICAgc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0KVxuICAgICAgICBzb2NrZXQucmVtb3ZlTGlzdGVuZXIoXCJjb25uZWN0XCIsIG9uQ29ubmVjdClcbiAgICAgICAganNvblNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoKVxuICAgICAgICBpZiAoZGVzdHJveSkganNvblNvY2tldC5kZXN0cm95KClcbiAgICAgICAgZWxzZSBqc29uU29ja2V0LmNsb3NlKClcbiAgICAgICAgY2FsbGJhY2soKVxuICAgICAgfVxuXG4gICAgICBjb25zdCBvbkFib3J0ID0gKCkgPT4gZmluaXNoKHtkZXN0cm95OiB0cnVlfSwgKCkgPT4gcmVqZWN0KHNpZ25hbC5yZWFzb24gaW5zdGFuY2VvZiBFcnJvciA/IHNpZ25hbC5yZWFzb24gOiBuZXcgRXJyb3IoXCJCYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIHJlcXVlc3QgYWJvcnRlZFwiKSkpXG4gICAgICBjb25zdCBvbkNvbm5lY3QgPSAoKSA9PiB7XG4gICAgICAgIGpzb25Tb2NrZXQuc2VuZCh7XG4gICAgICAgICAgdHlwZTogXCJiYWNrZ3JvdW5kLWpvYnMtbGlmZWN5Y2xlXCIsXG4gICAgICAgICAgYWN0aW9uLFxuICAgICAgICAgIGdlbmVyYXRpb25JZDogdGhpcy5nZW5lcmF0aW9uSWQsXG4gICAgICAgICAgcmVxdWVzdElkXG4gICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydClcbiAgICAgIGpzb25Tb2NrZXQub24oXCJlcnJvclwiLCAoZXJyb3IpID0+IGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KGVycm9yKSkpXG4gICAgICBqc29uU29ja2V0Lm9uKFwiY2xvc2VcIiwgKCkgPT4gZmluaXNoKHtkZXN0cm95OiB0cnVlfSwgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgc29ja2V0IGNsb3NlZCBiZWZvcmUgYWNrbm93bGVkZ2VtZW50XCIpKSkpXG4gICAgICBqc29uU29ja2V0Lm9uKFwibWVzc2FnZVwiLCAobWVzc2FnZSkgPT4ge1xuICAgICAgICBpZiAobWVzc2FnZT8ucmVxdWVzdElkICE9PSByZXF1ZXN0SWQgfHwgbWVzc2FnZS5hY3Rpb24gIT09IGFjdGlvbikge1xuICAgICAgICAgIGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgcmVzcG9uc2UgZGlkIG5vdCBtYXRjaCBpdHMgcmVxdWVzdFwiKSkpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJiYWNrZ3JvdW5kLWpvYnMtbGlmZWN5Y2xlLWVycm9yXCIpIHtcbiAgICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihtZXNzYWdlLmVycm9yPy5tZXNzYWdlIHx8IFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSByZXF1ZXN0IGZhaWxlZFwiKVxuICAgICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZS5lcnJvcj8ubmFtZSA9PT0gXCJzdHJpbmdcIikgZXJyb3IubmFtZSA9IG1lc3NhZ2UuZXJyb3IubmFtZVxuICAgICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZS5lcnJvcj8uc3RhY2sgPT09IFwic3RyaW5nXCIpIGVycm9yLnN0YWNrID0gbWVzc2FnZS5lcnJvci5zdGFja1xuICAgICAgICAgIGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KGVycm9yKSlcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBpZiAobWVzc2FnZS50eXBlICE9PSBcImJhY2tncm91bmQtam9icy1saWZlY3ljbGUtYWNrXCIgfHwgbWVzc2FnZS5nZW5lcmF0aW9uSWQgIT09IHRoaXMuZ2VuZXJhdGlvbklkKSB7XG4gICAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZWplY3QobmV3IEVycm9yKFwiSW52YWxpZCBiYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIGFja25vd2xlZGdlbWVudFwiKSkpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZXNvbHZlKG1lc3NhZ2UubGlmZWN5Y2xlU3RhdGUpKVxuICAgICAgfSlcbiAgICAgIHNvY2tldC5vbmNlKFwiY29ubmVjdFwiLCBvbkNvbm5lY3QpXG4gICAgICBpZiAoc2lnbmFsLmFib3J0ZWQpIG9uQWJvcnQoKVxuICAgIH0pXG4gIH1cbn1cbiJdfQ==
188
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZWN5Y2xlLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvbGlmZWN5Y2xlLWNsaWVudC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEdBQUcsTUFBTSxVQUFVLENBQUE7QUFDMUIsT0FBTyxPQUFPLE1BQU0sMkJBQTJCLENBQUE7QUFDL0MsT0FBTyxVQUFVLE1BQU0sa0JBQWtCLENBQUE7QUFFekMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLENBQUE7QUFDeEMsTUFBTSxDQUFDLE1BQU0sZ0NBQWdDLEdBQUcsTUFBTSxDQUFBO0FBQ3RELE1BQU0sZ0NBQWdDLEdBQUcsRUFBRSxDQUFBO0FBQzNDLE1BQU0sNkJBQTZCLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxjQUFjLEVBQUUsY0FBYyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUE7QUFFekY7Ozs7OztHQU1HO0FBQ0gsU0FBUyx1QkFBdUIsQ0FBQyxLQUFLO0lBQ3BDLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssS0FBSyxJQUFJO1FBQUUsT0FBTyxLQUFLLENBQUE7SUFDN0QsTUFBTSxJQUFJLEdBQUcsK0JBQStCLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUE7SUFFekQsT0FBTyxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksNkJBQTZCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFBO0FBQzVFLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxLQUFLLFVBQVUscUJBQXFCLENBQUMsT0FBTyxFQUFFLE1BQU07SUFDbEQsTUFBTSxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNwQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNuQixN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QUFTLEVBQUUsU0FBUyxDQUFDLENBQUE7WUFDakMsSUFBSSxNQUFNLENBQUMsT0FBTztnQkFBRSxPQUFPLEVBQUUsQ0FBQTtRQUMvQixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSBcIm5vZGU6Y3J5cHRvXCJcbmltcG9ydCBuZXQgZnJvbSBcIm5vZGU6bmV0XCJcbmltcG9ydCB0aW1lb3V0IGZyb20gXCJhd2FpdGVyeS9idWlsZC90aW1lb3V0LmpzXCJcbmltcG9ydCBKc29uU29ja2V0IGZyb20gXCIuL2pzb24tc29ja2V0LmpzXCJcblxuY29uc3QgREVGQVVMVF9SRVFVRVNUX1RJTUVPVVRfTVMgPSAxMDAwMFxuZXhwb3J0IGNvbnN0IE1BWF9MSUZFQ1lDTEVfUkVRVUVTVF9USU1FT1VUX01TID0gMTIwMDAwXG5jb25zdCBMSUZFQ1lDTEVfQ09OTkVDVF9SRVRSWV9ERUxBWV9NUyA9IDUwXG5jb25zdCBUUkFOU0lFTlRfQ09OTkVDVF9FUlJPUl9DT0RFUyA9IG5ldyBTZXQoW1wiRUNPTk5BQk9SVEVEXCIsIFwiRUNPTk5SRUZVU0VEXCIsIFwiRU5PRU5UXCJdKVxuXG4vKipcbiAqIFdoZXRoZXIgYSBsaWZlY3ljbGUgcmVxdWVzdCBmYWlsdXJlIGlzIGEgdHJhbnNpZW50IFwiZW5kcG9pbnQgbm90IHJlYWR5IHlldFwiXG4gKiBjb25uZWN0IGZhaWx1cmUgKHRoZSBjb29yZGluYXRvcidzIGNvbnRyb2wgc29ja2V0IG9wZW5zIGFzeW5jaHJvbm91c2x5IGFmdGVyXG4gKiBpdHMgcHJvY2VzcyBzdGFydHMpIHJhdGhlciB0aGFuIGEgZGVmaW5pdGl2ZSBwcm90b2NvbCBvciBzdGF0ZSByZWplY3Rpb24uXG4gKiBAcGFyYW0ge3Vua25vd259IGVycm9yIC0gVGhlIHJlamVjdGlvbiByZWFzb24uXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBXaGV0aGVyIHRoZSByZXF1ZXN0IG1heSBiZSByZXRyaWVkLlxuICovXG5mdW5jdGlvbiBpc1RyYW5zaWVudENvbm5lY3RFcnJvcihlcnJvcikge1xuICBpZiAodHlwZW9mIGVycm9yICE9PSBcIm9iamVjdFwiIHx8IGVycm9yID09PSBudWxsKSByZXR1cm4gZmFsc2VcbiAgY29uc3QgY29kZSA9IC8qKiBAdHlwZSB7e2NvZGU/OiB1bmtub3dufX0gKi8gKGVycm9yKS5jb2RlXG5cbiAgcmV0dXJuIHR5cGVvZiBjb2RlID09PSBcInN0cmluZ1wiICYmIFRSQU5TSUVOVF9DT05ORUNUX0VSUk9SX0NPREVTLmhhcyhjb2RlKVxufVxuXG4vKipcbiAqIFdhaXRzIGJlZm9yZSB0aGUgbmV4dCBsaWZlY3ljbGUgY29ubmVjdCByZXRyeSwgcmVqZWN0aW5nIHdpdGggdGhlIHNpZ25hbFxuICogcmVhc29uIHdoZW4gdGhlIGNhbGxlci1vd25lZCBkZWFkbGluZSBmaXJlcyBtaWQtd2FpdC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBkZWxheU1zIC0gV2FpdCBiZXR3ZWVuIGF0dGVtcHRzLlxuICogQHBhcmFtIHtBYm9ydFNpZ25hbH0gc2lnbmFsIC0gQ2FsbGVyLW93bmVkIGRlYWRsaW5lIHNpZ25hbC5cbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIGFmdGVyIHRoZSBkZWxheSwgb3IgcmVqZWN0cyBvbiBhYm9ydC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gd2FpdEJlZm9yZU5leHRBdHRlbXB0KGRlbGF5TXMsIHNpZ25hbCkge1xuICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB7XG4gICAgICByZWplY3Qoc2lnbmFsLnJlYXNvbilcblxuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGNvbnN0IHRpbWVyID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICBzaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQpXG4gICAgICByZXNvbHZlKHVuZGVmaW5lZClcbiAgICB9LCBkZWxheU1zKVxuICAgIGNvbnN0IG9uQWJvcnQgPSAoKSA9PiB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXIpXG4gICAgICByZWplY3Qoc2lnbmFsLnJlYXNvbilcbiAgICB9XG5cbiAgICBzaWduYWwuYWRkRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQpXG4gIH0pXG59XG5cbi8qKiBPbmUtcmVxdWVzdCBhY2tub3dsZWRnZWQgbGlmZWN5Y2xlIGNsaWVudC4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJhY2tncm91bmRKb2JzTGlmZWN5Y2xlQ2xpZW50IHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBsaWZlY3ljbGUgY2xpZW50LlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIENsaWVudCBvcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gYXJncy5jb25maWd1cmF0aW9uIC0gQ29uZmlndXJhdGlvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLmdlbmVyYXRpb25JZF0gLSBFeHBsaWNpdCBnZW5lcmF0aW9uIGlkZW50aXR5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3Muc29ja2V0UGF0aF0gLSBFeHBsaWNpdCBjb250cm9sIHNvY2tldCBwYXRoLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MucmVxdWVzdFRpbWVvdXRNc10gLSBSZXF1ZXN0IGRlYWRsaW5lIGJlbG93IHRoZSBzdXBlcnZpc29yIGhvb2sgdGltZW91dCAoZGVmYXVsdDogMTAwMDApLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe2NvbmZpZ3VyYXRpb24sIGdlbmVyYXRpb25JZCwgc29ja2V0UGF0aCwgcmVxdWVzdFRpbWVvdXRNcyA9IERFRkFVTFRfUkVRVUVTVF9USU1FT1VUX01TfSkge1xuICAgIGNvbnN0IGdlbmVyYXRpb25Db25maWcgPSBjb25maWd1cmF0aW9uLnJlc29sdmVCYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25Db25maWcoe1xuICAgICAgZ2VuZXJhdGlvbklkLFxuICAgICAgbGlmZWN5Y2xlU29ja2V0UGF0aDogc29ja2V0UGF0aCxcbiAgICAgIHNvdXJjZU5hbWU6IFwiQmFja2dyb3VuZEpvYnNMaWZlY3ljbGVDbGllbnRcIlxuICAgIH0pXG4gICAgdGhpcy5nZW5lcmF0aW9uSWQgPSBnZW5lcmF0aW9uQ29uZmlnLmdlbmVyYXRpb25JZFxuICAgIHRoaXMuc29ja2V0UGF0aCA9IGdlbmVyYXRpb25Db25maWcubGlmZWN5Y2xlU29ja2V0UGF0aFxuICAgIGlmICghTnVtYmVyLmlzSW50ZWdlcihyZXF1ZXN0VGltZW91dE1zKSB8fCByZXF1ZXN0VGltZW91dE1zIDwgMSB8fCByZXF1ZXN0VGltZW91dE1zID4gTUFYX0xJRkVDWUNMRV9SRVFVRVNUX1RJTUVPVVRfTVMpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYHJlcXVlc3RUaW1lb3V0TXMgbXVzdCBiZSBhbiBpbnRlZ2VyIGJldHdlZW4gMSBhbmQgJHtNQVhfTElGRUNZQ0xFX1JFUVVFU1RfVElNRU9VVF9NU31gKVxuICAgIH1cbiAgICB0aGlzLnJlcXVlc3RUaW1lb3V0TXMgPSByZXF1ZXN0VGltZW91dE1zXG4gICAgaWYgKCF0aGlzLmdlbmVyYXRpb25JZCkgdGhyb3cgbmV3IEVycm9yKFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSBjbGllbnQgcmVxdWlyZXMgZ2VuZXJhdGlvbklkXCIpXG4gICAgaWYgKCF0aGlzLnNvY2tldFBhdGgpIHRocm93IG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgY2xpZW50IHJlcXVpcmVzIGxpZmVjeWNsZVNvY2tldFBhdGhcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBBY3RpdmF0ZXMgdGhlIGdlbmVyYXRpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYnNHZW5lcmF0aW9uTGlmZWN5Y2xlU3RhdGU+fSAtIFJlc3VsdGluZyBzdGF0ZS5cbiAgICovXG4gIGFzeW5jIGFjdGl2YXRlKCkgeyByZXR1cm4gYXdhaXQgdGhpcy5fcmVxdWVzdChcImFjdGl2YXRlXCIpIH1cblxuICAvKipcbiAgICogUmV0aXJlcyB0aGUgZ2VuZXJhdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25MaWZlY3ljbGVTdGF0ZT59IC0gUmVzdWx0aW5nIHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgcmV0aXJlKCkgeyByZXR1cm4gYXdhaXQgdGhpcy5fcmVxdWVzdChcInJldGlyZVwiKSB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIGV4YWN0bHkgb25lIGxpZmVjeWNsZSByZXF1ZXN0LlxuICAgKiBAcGFyYW0ge1wiYWN0aXZhdGVcIiB8IFwicmV0aXJlXCJ9IGFjdGlvbiAtIExpZmVjeWNsZSBhY3Rpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYnNHZW5lcmF0aW9uTGlmZWN5Y2xlU3RhdGU+fSAtIFJlc3VsdGluZyBzdGF0ZS5cbiAgICovXG4gIGFzeW5jIF9yZXF1ZXN0KGFjdGlvbikge1xuICAgIHJldHVybiBhd2FpdCB0aW1lb3V0KHtcbiAgICAgIGVycm9yTWVzc2FnZTogYEJhY2tncm91bmQgam9icyAke2FjdGlvbn0gcmVxdWVzdCBmb3IgJHt0aGlzLmdlbmVyYXRpb25JZH0gdGltZWQgb3V0IGFmdGVyICR7dGhpcy5yZXF1ZXN0VGltZW91dE1zfW1zIGF0ICR7dGhpcy5zb2NrZXRQYXRofWAsXG4gICAgICB0aW1lb3V0OiB0aGlzLnJlcXVlc3RUaW1lb3V0TXNcbiAgICB9LCBhc3luYyAoe2NvbnRyb2x9KSA9PiBhd2FpdCB0aGlzLl9ydW5SZXF1ZXN0KHthY3Rpb24sIHNpZ25hbDogY29udHJvbC5zaWduYWx9KSlcbiAgfVxuXG4gIC8qKlxuICAgKiBTZW5kcyB0aGUgbGlmZWN5Y2xlIHJlcXVlc3QgdW5kZXIgaXRzIGNhbGxlci1vd25lZCBkZWFkbGluZS4gUmV0cmllc1xuICAgKiB0cmFuc2llbnQgXCJlbmRwb2ludCBub3QgcmVhZHkgeWV0XCIgY29ubmVjdCBmYWlsdXJlcyAodGhlIGNvb3JkaW5hdG9yIG9wZW5zXG4gICAqIGl0cyBjb250cm9sIHNvY2tldCBhc3luY2hyb25vdXNseSBhZnRlciBpdHMgcHJvY2VzcyBzdGFydHMpIHVudGlsIHRoZVxuICAgKiBkZWFkbGluZTsgYW55IGRlZmluaXRpdmUgcHJvdG9jb2wgb3Igc3RhdGUgcmVqZWN0aW9uIGZhaWxzIGltbWVkaWF0ZWx5LlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFJlcXVlc3QgZGV0YWlscy5cbiAgICogQHBhcmFtIHtcImFjdGl2YXRlXCIgfCBcInJldGlyZVwifSBhcmdzLmFjdGlvbiAtIExpZmVjeWNsZSBhY3Rpb24uXG4gICAqIEBwYXJhbSB7QWJvcnRTaWduYWx9IGFyZ3Muc2lnbmFsIC0gUmVxdWVzdCBkZWFkbGluZSBzaWduYWwuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYnNHZW5lcmF0aW9uTGlmZWN5Y2xlU3RhdGU+fSAtIFJlc3VsdGluZyBzdGF0ZS5cbiAgICovXG4gIGFzeW5jIF9ydW5SZXF1ZXN0KHthY3Rpb24sIHNpZ25hbH0pIHtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHRoaXMuX2F0dGVtcHRSZXF1ZXN0KGFjdGlvbiwgcmFuZG9tVVVJRCgpLCBzaWduYWwpXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoIWlzVHJhbnNpZW50Q29ubmVjdEVycm9yKGVycm9yKSkgdGhyb3cgZXJyb3JcbiAgICAgICAgaWYgKHNpZ25hbC5hYm9ydGVkKSB0aHJvdyBzaWduYWwucmVhc29uXG4gICAgICAgIGF3YWl0IHdhaXRCZWZvcmVOZXh0QXR0ZW1wdChMSUZFQ1lDTEVfQ09OTkVDVF9SRVRSWV9ERUxBWV9NUywgc2lnbmFsKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtcyBvbmUgbGlmZWN5Y2xlIHJlcXVlc3QgYXR0ZW1wdCBhZ2FpbnN0IHRoZSBjb250cm9sIHNvY2tldC5cbiAgICogQHBhcmFtIHtcImFjdGl2YXRlXCIgfCBcInJldGlyZVwifSBhY3Rpb24gLSBMaWZlY3ljbGUgYWN0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVxdWVzdElkIC0gUmVxdWVzdCBpZGVudGl0eSBmb3IgYWNrbm93bGVkZ2VtZW50IG1hdGNoaW5nLlxuICAgKiBAcGFyYW0ge0Fib3J0U2lnbmFsfSBzaWduYWwgLSBSZXF1ZXN0IGRlYWRsaW5lIHNpZ25hbC5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25MaWZlY3ljbGVTdGF0ZT59IC0gUmVzdWx0aW5nIHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgX2F0dGVtcHRSZXF1ZXN0KGFjdGlvbiwgcmVxdWVzdElkLCBzaWduYWwpIHtcbiAgICBjb25zdCBzb2NrZXQgPSBuZXQuY3JlYXRlQ29ubmVjdGlvbih0aGlzLnNvY2tldFBhdGgpXG4gICAgY29uc3QganNvblNvY2tldCA9IG5ldyBKc29uU29ja2V0KHNvY2tldClcblxuICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBsZXQgZmluaXNoZWQgPSBmYWxzZVxuICAgICAgLyoqXG4gICAgICAgKiBTZXR0bGVzIHRoZSByZXF1ZXN0IG9uY2UuXG4gICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRlYXJkb3duIG9wdGlvbnMuXG4gICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmRlc3Ryb3ldIC0gRGVzdHJveSBpbnN0ZWFkIG9mIGNsb3NpbmcuXG4gICAgICAgKiBAcGFyYW0geygpID0+IHZvaWR9IGNhbGxiYWNrIC0gU2V0dGxlbWVudCBjYWxsYmFjay5cbiAgICAgICAqL1xuICAgICAgY29uc3QgZmluaXNoID0gKHtkZXN0cm95ID0gZmFsc2V9LCBjYWxsYmFjaykgPT4ge1xuICAgICAgICBpZiAoZmluaXNoZWQpIHJldHVyblxuICAgICAgICBmaW5pc2hlZCA9IHRydWVcbiAgICAgICAgc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0KVxuICAgICAgICBzb2NrZXQucmVtb3ZlTGlzdGVuZXIoXCJjb25uZWN0XCIsIG9uQ29ubmVjdClcbiAgICAgICAganNvblNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoKVxuICAgICAgICBpZiAoZGVzdHJveSkganNvblNvY2tldC5kZXN0cm95KClcbiAgICAgICAgZWxzZSBqc29uU29ja2V0LmNsb3NlKClcbiAgICAgICAgY2FsbGJhY2soKVxuICAgICAgfVxuXG4gICAgICBjb25zdCBvbkFib3J0ID0gKCkgPT4gZmluaXNoKHtkZXN0cm95OiB0cnVlfSwgKCkgPT4gcmVqZWN0KHNpZ25hbC5yZWFzb24gaW5zdGFuY2VvZiBFcnJvciA/IHNpZ25hbC5yZWFzb24gOiBuZXcgRXJyb3IoXCJCYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIHJlcXVlc3QgYWJvcnRlZFwiKSkpXG4gICAgICBjb25zdCBvbkNvbm5lY3QgPSAoKSA9PiB7XG4gICAgICAgIGpzb25Tb2NrZXQuc2VuZCh7XG4gICAgICAgICAgdHlwZTogXCJiYWNrZ3JvdW5kLWpvYnMtbGlmZWN5Y2xlXCIsXG4gICAgICAgICAgYWN0aW9uLFxuICAgICAgICAgIGdlbmVyYXRpb25JZDogdGhpcy5nZW5lcmF0aW9uSWQsXG4gICAgICAgICAgcmVxdWVzdElkXG4gICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydClcbiAgICAgIGpzb25Tb2NrZXQub24oXCJlcnJvclwiLCAoZXJyb3IpID0+IGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KGVycm9yKSkpXG4gICAgICBqc29uU29ja2V0Lm9uKFwiY2xvc2VcIiwgKCkgPT4gZmluaXNoKHtkZXN0cm95OiB0cnVlfSwgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgc29ja2V0IGNsb3NlZCBiZWZvcmUgYWNrbm93bGVkZ2VtZW50XCIpKSkpXG4gICAgICBqc29uU29ja2V0Lm9uKFwibWVzc2FnZVwiLCAobWVzc2FnZSkgPT4ge1xuICAgICAgICBpZiAobWVzc2FnZT8ucmVxdWVzdElkICE9PSByZXF1ZXN0SWQgfHwgbWVzc2FnZS5hY3Rpb24gIT09IGFjdGlvbikge1xuICAgICAgICAgIGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgcmVzcG9uc2UgZGlkIG5vdCBtYXRjaCBpdHMgcmVxdWVzdFwiKSkpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJiYWNrZ3JvdW5kLWpvYnMtbGlmZWN5Y2xlLWVycm9yXCIpIHtcbiAgICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihtZXNzYWdlLmVycm9yPy5tZXNzYWdlIHx8IFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSByZXF1ZXN0IGZhaWxlZFwiKVxuICAgICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZS5lcnJvcj8ubmFtZSA9PT0gXCJzdHJpbmdcIikgZXJyb3IubmFtZSA9IG1lc3NhZ2UuZXJyb3IubmFtZVxuICAgICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZS5lcnJvcj8uc3RhY2sgPT09IFwic3RyaW5nXCIpIGVycm9yLnN0YWNrID0gbWVzc2FnZS5lcnJvci5zdGFja1xuICAgICAgICAgIGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KGVycm9yKSlcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBpZiAobWVzc2FnZS50eXBlICE9PSBcImJhY2tncm91bmQtam9icy1saWZlY3ljbGUtYWNrXCIgfHwgbWVzc2FnZS5nZW5lcmF0aW9uSWQgIT09IHRoaXMuZ2VuZXJhdGlvbklkKSB7XG4gICAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZWplY3QobmV3IEVycm9yKFwiSW52YWxpZCBiYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIGFja25vd2xlZGdlbWVudFwiKSkpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZXNvbHZlKG1lc3NhZ2UubGlmZWN5Y2xlU3RhdGUpKVxuICAgICAgfSlcbiAgICAgIHNvY2tldC5vbmNlKFwiY29ubmVjdFwiLCBvbkNvbm5lY3QpXG4gICAgICBpZiAoc2lnbmFsLmFib3J0ZWQpIG9uQWJvcnQoKVxuICAgIH0pXG4gIH1cbn1cbiJdfQ==
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "velocious": "build/bin/velocious.js"
4
4
  },
5
5
  "name": "velocious",
6
- "version": "1.0.685",
6
+ "version": "1.0.686",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -7,6 +7,49 @@ import JsonSocket from "./json-socket.js"
7
7
 
8
8
  const DEFAULT_REQUEST_TIMEOUT_MS = 10000
9
9
  export const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 120000
10
+ const LIFECYCLE_CONNECT_RETRY_DELAY_MS = 50
11
+ const TRANSIENT_CONNECT_ERROR_CODES = new Set(["ECONNABORTED", "ECONNREFUSED", "ENOENT"])
12
+
13
+ /**
14
+ * Whether a lifecycle request failure is a transient "endpoint not ready yet"
15
+ * connect failure (the coordinator's control socket opens asynchronously after
16
+ * its process starts) rather than a definitive protocol or state rejection.
17
+ * @param {unknown} error - The rejection reason.
18
+ * @returns {boolean} - Whether the request may be retried.
19
+ */
20
+ function isTransientConnectError(error) {
21
+ if (typeof error !== "object" || error === null) return false
22
+ const code = /** @type {{code?: unknown}} */ (error).code
23
+
24
+ return typeof code === "string" && TRANSIENT_CONNECT_ERROR_CODES.has(code)
25
+ }
26
+
27
+ /**
28
+ * Waits before the next lifecycle connect retry, rejecting with the signal
29
+ * reason when the caller-owned deadline fires mid-wait.
30
+ * @param {number} delayMs - Wait between attempts.
31
+ * @param {AbortSignal} signal - Caller-owned deadline signal.
32
+ * @returns {Promise<void>} - Resolves after the delay, or rejects on abort.
33
+ */
34
+ async function waitBeforeNextAttempt(delayMs, signal) {
35
+ await new Promise((resolve, reject) => {
36
+ if (signal.aborted) {
37
+ reject(signal.reason)
38
+
39
+ return
40
+ }
41
+ const timer = setTimeout(() => {
42
+ signal.removeEventListener("abort", onAbort)
43
+ resolve(undefined)
44
+ }, delayMs)
45
+ const onAbort = () => {
46
+ clearTimeout(timer)
47
+ reject(signal.reason)
48
+ }
49
+
50
+ signal.addEventListener("abort", onAbort)
51
+ })
52
+ }
10
53
 
11
54
  /** One-request acknowledged lifecycle client. */
12
55
  export default class BackgroundJobsLifecycleClient {
@@ -59,14 +102,35 @@ export default class BackgroundJobsLifecycleClient {
59
102
  }
60
103
 
61
104
  /**
62
- * Sends the lifecycle request under its caller-owned deadline.
105
+ * Sends the lifecycle request under its caller-owned deadline. Retries
106
+ * transient "endpoint not ready yet" connect failures (the coordinator opens
107
+ * its control socket asynchronously after its process starts) until the
108
+ * deadline; any definitive protocol or state rejection fails immediately.
63
109
  * @param {object} args - Request details.
64
110
  * @param {"activate" | "retire"} args.action - Lifecycle action.
65
111
  * @param {AbortSignal} args.signal - Request deadline signal.
66
112
  * @returns {Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>} - Resulting state.
67
113
  */
68
114
  async _runRequest({action, signal}) {
69
- const requestId = randomUUID()
115
+ while (true) {
116
+ try {
117
+ return await this._attemptRequest(action, randomUUID(), signal)
118
+ } catch (error) {
119
+ if (!isTransientConnectError(error)) throw error
120
+ if (signal.aborted) throw signal.reason
121
+ await waitBeforeNextAttempt(LIFECYCLE_CONNECT_RETRY_DELAY_MS, signal)
122
+ }
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Performs one lifecycle request attempt against the control socket.
128
+ * @param {"activate" | "retire"} action - Lifecycle action.
129
+ * @param {string} requestId - Request identity for acknowledgement matching.
130
+ * @param {AbortSignal} signal - Request deadline signal.
131
+ * @returns {Promise<import("./types.js").BackgroundJobsGenerationLifecycleState>} - Resulting state.
132
+ */
133
+ async _attemptRequest(action, requestId, signal) {
70
134
  const socket = net.createConnection(this.socketPath)
71
135
  const jsonSocket = new JsonSocket(socket)
72
136