velocious 1.0.660 → 1.0.661

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2450,7 +2450,13 @@ deduplication. Each call has its own internal replay identity, so two identical
2450
2450
  calls create distinct jobs unless the caller explicitly requests queued
2451
2451
  deduplication or durable idempotency. The retired main commits and wakes the
2452
2452
  queue but never dispatches the follow-up; the active generation owns that work.
2453
- Ordinary retired enqueue, replace, and cancel requests remain rejected.
2453
+ If the first sent request loses its acknowledgement after the main accepts the
2454
+ generation fence, whether through connection loss or deadline expiry, the Node
2455
+ client makes one recovery attempt with the exact same producer proof and
2456
+ invocation identity. Legacy/default connections never replay automatically, even
2457
+ if execution context supplied producer metadata. Pre-send generation failures
2458
+ and explicit enqueue rejections are not retried. Ordinary retired enqueue,
2459
+ replace, and cancel requests remain rejected.
2454
2460
 
2455
2461
  Velocious provides the opt-in generation protocol; production still requires a
2456
2462
  supervisor that preserves old generation units and release pins, and a deploy
@@ -2722,7 +2728,7 @@ Set `deduplicateWhileQueued: true` to coalesce an enqueue onto the earliest iden
2722
2728
 
2723
2729
  Use `options: {idempotencyKey}` when producer replay must converge on the original durable job across every state and even after terminal-job pruning. Ownership is scoped to the resolved job class name, resolved queue, and key; reusing that scope with changed canonical arguments or behavior-affecting options fails. This is distinct from queued-only deduplication, and ownership rows are intentionally retained until a future explicit reconciliation/deletion policy. See [durable idempotent enqueue](docs/background-jobs.md#durable-idempotent-enqueue).
2724
2730
 
2725
- The Node producer rejects and destroys its one-shot socket when the main closes before acknowledging or when an enqueue acknowledgement stalls for 5 seconds. Because the main may already have committed the job, this is an ambiguous outcome: replay with the same durable `idempotencyKey` to recover the original job id without creating a duplicate. Direct `BackgroundJobsClient` users can set a different bounded `enqueueTimeoutMs` constructor option. See [durable idempotent enqueue](docs/background-jobs.md#durable-idempotent-enqueue).
2731
+ The Node producer rejects and destroys its one-shot socket when the main closes before acknowledging or when an enqueue acknowledgement stalls for 5 seconds. Because the main may already have committed the job, this is an ambiguous outcome. A call made by an executing generation-owned job automatically makes one recovery attempt with its exact internal producer proof and per-call invocation identity, but never after a pre-send generation failure or explicit enqueue rejection. Ordinary enqueues are not retried automatically: replay one with the same durable `idempotencyKey` to recover the original job id without creating a duplicate. Direct `BackgroundJobsClient` users can set a different bounded `enqueueTimeoutMs` constructor option. See [durable idempotent enqueue](docs/background-jobs.md#durable-idempotent-enqueue).
2726
2732
 
2727
2733
  Select a non-default runtime explicitly with `options: {executionMode: "inline" | "forked" | "spawned"}`.
2728
2734
 
@@ -49,34 +49,57 @@ export default class BackgroundJobsClient {
49
49
  * @returns {Promise<string>} - Job id.
50
50
  */
51
51
  async enqueue({jobName, args, options, producerInvocationId, producerProof}) {
52
- const request = await this._request()
52
+ const message = {
53
+ type: /** @type {const} */ ("enqueue"),
54
+ jobName,
55
+ args,
56
+ options,
57
+ ...(producerInvocationId ? {producerInvocationId} : {}),
58
+ ...(producerProof ? {producerProof} : {})
59
+ }
60
+ const acknowledgement = {explicitlyRejected: false, generationFenced: false, requestSent: false}
61
+ /**
62
+ * Sends one enqueue attempt. An owned caller may replay this exact message
63
+ * once when transport acknowledgement remains ambiguous after send.
64
+ * @param {{explicitlyRejected: boolean, generationFenced: boolean, requestSent: boolean} | undefined} attemptAcknowledgement - First-attempt observations.
65
+ * @returns {Promise<string>} - Job id.
66
+ */
67
+ const enqueueAttempt = async (attemptAcknowledgement) => {
68
+ const request = await this._request()
53
69
 
54
- return await timeout({
55
- errorMessage: `Background job enqueue acknowledgement timed out after ${this.enqueueTimeoutMs}ms`,
56
- timeout: this.enqueueTimeoutMs
57
- }, async ({control}) => await request.run({
58
- signal: control.signal,
59
- onConnect: (jsonSocket) => {
60
- jsonSocket.send({
61
- type: "enqueue",
62
- jobName,
63
- args,
64
- options,
65
- ...(producerInvocationId ? {producerInvocationId} : {}),
66
- ...(producerProof ? {producerProof} : {})
67
- })
68
- },
69
- onMessage: ({message, resolve, reject}) => {
70
- if (message?.type === "enqueued") {
71
- resolve(message.jobId)
72
- return
73
- }
70
+ return await timeout({
71
+ errorMessage: `Background job enqueue acknowledgement timed out after ${this.enqueueTimeoutMs}ms`,
72
+ timeout: this.enqueueTimeoutMs
73
+ }, async ({control}) => await request.run({
74
+ signal: control.signal,
75
+ onConnect: (jsonSocket) => {
76
+ jsonSocket.send(message)
77
+ if (attemptAcknowledgement) {
78
+ attemptAcknowledgement.generationFenced = Boolean(request.generationId)
79
+ attemptAcknowledgement.requestSent = true
80
+ }
81
+ },
82
+ onMessage: ({message, resolve, reject}) => {
83
+ if (message?.type === "enqueued") {
84
+ resolve(message.jobId)
85
+ return
86
+ }
74
87
 
75
- if (message?.type === "enqueue-error") {
76
- reject(new Error(message.error || "Failed to enqueue job"))
88
+ if (message?.type === "enqueue-error") {
89
+ if (attemptAcknowledgement) attemptAcknowledgement.explicitlyRejected = true
90
+ reject(new Error(message.error || "Failed to enqueue job"))
91
+ }
77
92
  }
78
- }
79
- }))
93
+ }))
94
+ }
95
+
96
+ try {
97
+ return await enqueueAttempt(acknowledgement)
98
+ } catch (error) {
99
+ if (!producerInvocationId || !producerProof || !acknowledgement.generationFenced || !acknowledgement.requestSent || acknowledgement.explicitlyRejected) throw error
100
+ }
101
+
102
+ return await enqueueAttempt(undefined)
80
103
  }
81
104
 
82
105
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/client.js"],"names":[],"mappings":"AAIA,OAAO,2BAA2B,MAAM,qBAAqB,CAAA;AAK7D,MAAM,CAAC,OAAO,OAAO,oBAAoB;IAUhC,oBAAoB;IACpB,gBAAgB;IAChB,4BAA4B;IAC5B,oBAAoB;IAZ3B;;;;;;;OAOG;IACH,YAAY,EAAC,aAAa,EAAE,gBAA6C,EAAE,4BAAsE,EAAE,YAAY,EAAC,AAN7J,CAKF,EAJE;QAAqD,aAAa,AAAlE,CACA,EADQ,OAAO,qBAAqB,EAAE,OAAO,CAC7C;QAAsB,gBAAgB,AAAtC,CACA,EADQ,MAAM,CACd;QAAsB,4BAA4B,AAAlD,CACA,EADQ,MAAM,CACd;QAAsB,YAAY,AAAlC,CACF,EADU,MAAM,CAChB;KACoK,EAKpK;IAED;;;OAGG;IACG,QAAQ,IAFD,OAAO,CAAC,2BAA2B,CAAC,CAWhD;IAED;;;;;;;;;OASG;IACG,OAAO,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAC,EAPxE;QAAqB,OAAO,EAApB,MAAM,CACd;QAAmD,IAAI,EAA/C,KAAK,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAC5C;QAAyD,OAAO,AAAhE,CACA,EADQ,OAAO,YAAY,EAAE,oBAAoB,CACjD;QAAsB,oBAAoB,AAA1C,CACA,EADQ,MAAM,CACd;QAA+D,aAAa,AAA5E,CACA,EADQ,OAAO,YAAY,EAAE,0BAA0B,CACvD;KAEwE,GAF9D,OAAO,CAAC,MAAM,CAAC,CA+B3B;IAED;;;;;;;;OAQG;IACG,gBAAgB,CAAC,EAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAC,EANzD;QAAqB,WAAW,EAAxB,MAAM,CACd;QAAqB,OAAO,EAApB,MAAM,CACd;QAAmD,IAAI,EAA/C,KAAK,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAC5C;QAAyD,OAAO,AAAhE,CACA,EADQ,OAAO,YAAY,EAAE,oBAAoB,CACjD;KAEyD,GAF/C,OAAO,CAAC,OAAO,YAAY,EAAE,8BAA8B,CAAC,CAwBxE;IAED;;;;;OAKG;IACG,eAAe,CAAC,EAAC,WAAW,EAAC,EAHhC;QAAqB,WAAW,EAAxB,MAAM,CACd;KAEgC,GAFtB,OAAO,CAAC,OAAO,YAAY,EAAE,+BAA+B,CAAC,CAoBzE;CACF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/client.js"],"names":[],"mappings":"AAIA,OAAO,2BAA2B,MAAM,qBAAqB,CAAA;AAK7D,MAAM,CAAC,OAAO,OAAO,oBAAoB;IAUhC,oBAAoB;IACpB,gBAAgB;IAChB,4BAA4B;IAC5B,oBAAoB;IAZ3B;;;;;;;OAOG;IACH,YAAY,EAAC,aAAa,EAAE,gBAA6C,EAAE,4BAAsE,EAAE,YAAY,EAAC,AAN7J,CAKF,EAJE;QAAqD,aAAa,AAAlE,CACA,EADQ,OAAO,qBAAqB,EAAE,OAAO,CAC7C;QAAsB,gBAAgB,AAAtC,CACA,EADQ,MAAM,CACd;QAAsB,4BAA4B,AAAlD,CACA,EADQ,MAAM,CACd;QAAsB,YAAY,AAAlC,CACF,EADU,MAAM,CAChB;KACoK,EAKpK;IAED;;;OAGG;IACG,QAAQ,IAFD,OAAO,CAAC,2BAA2B,CAAC,CAWhD;IAED;;;;;;;;;OASG;IACG,OAAO,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAC,EAPxE;QAAqB,OAAO,EAApB,MAAM,CACd;QAAmD,IAAI,EAA/C,KAAK,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAC5C;QAAyD,OAAO,AAAhE,CACA,EADQ,OAAO,YAAY,EAAE,oBAAoB,CACjD;QAAsB,oBAAoB,AAA1C,CACA,EADQ,MAAM,CACd;QAA+D,aAAa,AAA5E,CACA,EADQ,OAAO,YAAY,EAAE,0BAA0B,CACvD;KAEwE,GAF9D,OAAO,CAAC,MAAM,CAAC,CAsD3B;IAED;;;;;;;;OAQG;IACG,gBAAgB,CAAC,EAAC,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAC,EANzD;QAAqB,WAAW,EAAxB,MAAM,CACd;QAAqB,OAAO,EAApB,MAAM,CACd;QAAmD,IAAI,EAA/C,KAAK,CAAC,UAAU,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAC5C;QAAyD,OAAO,AAAhE,CACA,EADQ,OAAO,YAAY,EAAE,oBAAoB,CACjD;KAEyD,GAF/C,OAAO,CAAC,OAAO,YAAY,EAAE,8BAA8B,CAAC,CAwBxE;IAED;;;;;OAKG;IACG,eAAe,CAAC,EAAC,WAAW,EAAC,EAHhC;QAAqB,WAAW,EAAxB,MAAM,CACd;KAEgC,GAFtB,OAAO,CAAC,OAAO,YAAY,EAAE,+BAA+B,CAAC,CAoBzE;CACF"}
@@ -43,32 +43,56 @@ export default class BackgroundJobsClient {
43
43
  * @returns {Promise<string>} - Job id.
44
44
  */
45
45
  async enqueue({ jobName, args, options, producerInvocationId, producerProof }) {
46
- const request = await this._request();
47
- return await timeout({
48
- errorMessage: `Background job enqueue acknowledgement timed out after ${this.enqueueTimeoutMs}ms`,
49
- timeout: this.enqueueTimeoutMs
50
- }, async ({ control }) => await request.run({
51
- signal: control.signal,
52
- onConnect: (jsonSocket) => {
53
- jsonSocket.send({
54
- type: "enqueue",
55
- jobName,
56
- args,
57
- options,
58
- ...(producerInvocationId ? { producerInvocationId } : {}),
59
- ...(producerProof ? { producerProof } : {})
60
- });
61
- },
62
- onMessage: ({ message, resolve, reject }) => {
63
- if (message?.type === "enqueued") {
64
- resolve(message.jobId);
65
- return;
66
- }
67
- if (message?.type === "enqueue-error") {
68
- reject(new Error(message.error || "Failed to enqueue job"));
46
+ const message = {
47
+ type: /** @type {const} */ ("enqueue"),
48
+ jobName,
49
+ args,
50
+ options,
51
+ ...(producerInvocationId ? { producerInvocationId } : {}),
52
+ ...(producerProof ? { producerProof } : {})
53
+ };
54
+ const acknowledgement = { explicitlyRejected: false, generationFenced: false, requestSent: false };
55
+ /**
56
+ * Sends one enqueue attempt. An owned caller may replay this exact message
57
+ * once when transport acknowledgement remains ambiguous after send.
58
+ * @param {{explicitlyRejected: boolean, generationFenced: boolean, requestSent: boolean} | undefined} attemptAcknowledgement - First-attempt observations.
59
+ * @returns {Promise<string>} - Job id.
60
+ */
61
+ const enqueueAttempt = async (attemptAcknowledgement) => {
62
+ const request = await this._request();
63
+ return await timeout({
64
+ errorMessage: `Background job enqueue acknowledgement timed out after ${this.enqueueTimeoutMs}ms`,
65
+ timeout: this.enqueueTimeoutMs
66
+ }, async ({ control }) => await request.run({
67
+ signal: control.signal,
68
+ onConnect: (jsonSocket) => {
69
+ jsonSocket.send(message);
70
+ if (attemptAcknowledgement) {
71
+ attemptAcknowledgement.generationFenced = Boolean(request.generationId);
72
+ attemptAcknowledgement.requestSent = true;
73
+ }
74
+ },
75
+ onMessage: ({ message, resolve, reject }) => {
76
+ if (message?.type === "enqueued") {
77
+ resolve(message.jobId);
78
+ return;
79
+ }
80
+ if (message?.type === "enqueue-error") {
81
+ if (attemptAcknowledgement)
82
+ attemptAcknowledgement.explicitlyRejected = true;
83
+ reject(new Error(message.error || "Failed to enqueue job"));
84
+ }
69
85
  }
70
- }
71
- }));
86
+ }));
87
+ };
88
+ try {
89
+ return await enqueueAttempt(acknowledgement);
90
+ }
91
+ catch (error) {
92
+ if (!producerInvocationId || !producerProof || !acknowledgement.generationFenced || !acknowledgement.requestSent || acknowledgement.explicitlyRejected)
93
+ throw error;
94
+ }
95
+ return await enqueueAttempt(undefined);
72
96
  }
73
97
  /**
74
98
  * Atomically replaces the queued owner of a stable schedule key.
@@ -124,4 +148,4 @@ export default class BackgroundJobsClient {
124
148
  });
125
149
  }
126
150
  }
127
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2JhY2tncm91bmQtam9icy9jbGllbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sT0FBTyxNQUFNLDJCQUEyQixDQUFBO0FBQy9DLE9BQU8scUJBQXFCLE1BQU0sOEJBQThCLENBQUE7QUFDaEUsT0FBTywyQkFBMkIsTUFBTSxxQkFBcUIsQ0FBQTtBQUM3RCxPQUFPLEVBQUUsdUNBQXVDLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQTtBQUV2SSxNQUFNLDBCQUEwQixHQUFHLElBQUksQ0FBQTtBQUV2QyxNQUFNLENBQUMsT0FBTyxPQUFPLG9CQUFvQjtJQUN2Qzs7Ozs7OztPQU9HO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBRSxnQkFBZ0IsR0FBRywwQkFBMEIsRUFBRSw0QkFBNEIsR0FBRyx1Q0FBdUMsRUFBRSxZQUFZLEVBQUMsR0FBRyxFQUFFO1FBQ25LLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxhQUFhLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLHFCQUFxQixFQUFFLENBQUE7UUFDcEcsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQixDQUFBO1FBQ3hDLElBQUksQ0FBQyw0QkFBNEIsR0FBRyxvQ0FBb0MsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFBO1FBQ3RHLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxZQUFZLENBQUE7SUFDMUMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxRQUFRO1FBQ1osTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUE7UUFDckQsTUFBTSxFQUFDLElBQUksRUFBRSxJQUFJLEVBQUMsR0FBRyxhQUFhLENBQUMsdUJBQXVCLEVBQUUsQ0FBQTtRQUM1RCxNQUFNLEVBQUMsWUFBWSxFQUFDLEdB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aGVja1xuXG5pbXBvcnQgdGltZW91dCBmcm9tIFwiYXdhaXRlcnkvYnVpbGQvdGltZW91dC5qc1wiXG5pbXBvcnQgY29uZmlndXJhdGlvblJlc29sdmVyIGZyb20gXCIuLi9jb25maWd1cmF0aW9uLXJlc29sdmVyLmpzXCJcbmltcG9ydCBCYWNrZ3JvdW5kSm9ic1NvY2tldFJlcXVlc3QgZnJvbSBcIi4vc29ja2V0LXJlcXVlc3QuanNcIlxuaW1wb3J0IHsgREVGQVVMVF9HRU5FUkFUSU9OX0hBTkRTSEFLRV9USU1FT1VUX01TLCB2YWxpZGF0ZUdlbmVyYXRpb25IYW5kc2hha2VUaW1lb3V0TXMgfSBmcm9tIFwiLi9nZW5lcmF0aW9uLWhhbmRzaGFrZS10aW1lb3V0LWVycm9yLmpzXCJcblxuY29uc3QgREVGQVVMVF9FTlFVRVVFX1RJTUVPVVRfTVMgPSA1MDAwXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJhY2tncm91bmRKb2JzQ2xpZW50IHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbYXJnc10gLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gW2FyZ3MuY29uZmlndXJhdGlvbl0gLSBDb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MuZW5xdWV1ZVRpbWVvdXRNc10gLSBNYXhpbXVtIHRpbWUgdG8gd2FpdCBmb3IgYW4gZW5xdWV1ZSBhY2tub3dsZWRnZW1lbnQgaW4gbWlsbGlzZWNvbmRzIChkZWZhdWx0OiA1MDAwKS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLmdlbmVyYXRpb25IYW5kc2hha2VUaW1lb3V0TXNdIC0gTWF4aW11bSB0aW1lIHRvIHdhaXQgZm9yIGdlbmVyYXRpb24gYWNrbm93bGVkZ2VtZW50IChkZWZhdWx0OiA0MDAwKS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLmdlbmVyYXRpb25JZF0gLSBFeHBsaWNpdCByZWxlYXNlIGdlbmVyYXRpb24gaWRlbnRpdHkuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7Y29uZmlndXJhdGlvbiwgZW5xdWV1ZVRpbWVvdXRNcyA9IERFRkFVTFRfRU5RVUVVRV9USU1FT1VUX01TLCBnZW5lcmF0aW9uSGFuZHNoYWtlVGltZW91dE1zID0gREVGQVVMVF9HRU5FUkFUSU9OX0hBTkRTSEFLRV9USU1FT1VUX01TLCBnZW5lcmF0aW9uSWR9ID0ge30pIHtcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb25Qcm9taXNlID0gY29uZmlndXJhdGlvbiA/IFByb21pc2UucmVzb2x2ZShjb25maWd1cmF0aW9uKSA6IGNvbmZpZ3VyYXRpb25SZXNvbHZlcigpXG4gICAgdGhpcy5lbnF1ZXVlVGltZW91dE1zID0gZW5xdWV1ZVRpbWVvdXRNc1xuICAgIHRoaXMuZ2VuZXJhdGlvbkhhbmRzaGFrZVRpbWVvdXRNcyA9IHZhbGlkYXRlR2VuZXJhdGlvbkhhbmRzaGFrZVRpbWVvdXRNcyhnZW5lcmF0aW9uSGFuZHNoYWtlVGltZW91dE1zKVxuICAgIHRoaXMuZXhwbGljaXRHZW5lcmF0aW9uSWQgPSBnZW5lcmF0aW9uSWRcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgYSBvbmUtc2hvdCBjbGllbnQgc29ja2V0IHJlcXVlc3QgZnJvbSB0aGUgcmVzb2x2ZWQgY29uZmlndXJhdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8QmFja2dyb3VuZEpvYnNTb2NrZXRSZXF1ZXN0Pn0gLSBTb2NrZXQgcmVxdWVzdC5cbiAgICovXG4gIGFzeW5jIF9yZXF1ZXN0KCkge1xuICAgIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb25Qcm9taXNlXG4gICAgY29uc3Qge2hvc3QsIHBvcnR9ID0gY29uZmlndXJhdGlvbi5nZXRCYWNrZ3JvdW5kSm9ic0NvbmZpZygpXG4gICAgY29uc3Qge2dlbmVyYXRpb25JZH0gPSBjb25maWd1cmF0aW9uLnJlc29sdmVCYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25Db25maWcoe1xuICAgICAgZ2VuZXJhdGlvbklkOiB0aGlzLmV4cGxpY2l0R2VuZXJhdGlvbklkLFxuICAgICAgc291cmNlTmFtZTogXCJCYWNrZ3JvdW5kSm9ic0NsaWVudFwiXG4gICAgfSlcblxuICAgIHJldHVybiBuZXcgQmFja2dyb3VuZEpvYnNTb2NrZXRSZXF1ZXN0KHtob3N0LCBwb3J0LCByb2xlOiBcImNsaWVudFwiLCBnZW5lcmF0aW9uSGFuZHNoYWtlVGltZW91dE1zOiB0aGlzLmdlbmVyYXRpb25IYW5kc2hha2VUaW1lb3V0TXMsIGdlbmVyYXRpb25JZH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyBlbnF1ZXVlLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmpvYk5hbWUgLSBKb2IgbmFtZS5cbiAgICogQHBhcmFtIHtBcnJheTxSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj59IGFyZ3MuYXJncyAtIEpvYiBhcmdzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYk9wdGlvbnN9IFthcmdzLm9wdGlvbnNdIC0gSm9iIG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5wcm9kdWNlckludm9jYXRpb25JZF0gLSBTdGFibGUgaWRlbnRpdHkgZm9yIG9uZSBvd25lZCBlbnF1ZXVlIGludm9jYXRpb24uXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iUHJvZHVjZXJQcm9vZn0gW2FyZ3MucHJvZHVjZXJQcm9vZl0gLSBFeGFjdCBpbnRlcm5hbCBwcm9kdWNlciBoYW5kb2ZmLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSAtIEpvYiBpZC5cbiAgICovXG4gIGFzeW5jIGVucXVldWUoe2pvYk5hbWUsIGFyZ3MsIG9wdGlvbnMsIHByb2R1Y2VySW52b2NhdGlvbklkLCBwcm9kdWNlclByb29mfSkge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBhd2FpdCB0aGlzLl9yZXF1ZXN0KClcblxuICAgIHJldHVybiBhd2FpdCB0aW1lb3V0KHtcbiAgICAgIGVycm9yTWVzc2FnZTogYEJhY2tncm91bmQgam9iIGVucXVldWUgYWNrbm93bGVkZ2VtZW50IHRpbWVkIG91dCBhZnRlciAke3RoaXMuZW5xdWV1ZVRpbWVvdXRNc31tc2AsXG4gICAgICB0aW1lb3V0OiB0aGlzLmVucXVldWVUaW1lb3V0TXNcbiAgICB9LCBhc3luYyAoe2NvbnRyb2x9KSA9PiBhd2FpdCByZXF1ZXN0LnJ1bih7XG4gICAgICBzaWduYWw6IGNvbnRyb2wuc2lnbmFsLFxuICAgICAgb25Db25uZWN0OiAoanNvblNvY2tldCkgPT4ge1xuICAgICAgICBqc29uU29ja2V0LnNlbmQoe1xuICAgICAgICAgIHR5cGU6IFwiZW5xdWV1ZVwiLFxuICAgICAgICAgIGpvYk5hbWUsXG4gICAgICAgICAgYXJncyxcbiAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgIC4uLihwcm9kdWNlckludm9jYXRpb25JZCA/IHtwcm9kdWNlckludm9jYXRpb25JZH0gOiB7fSksXG4gICAgICAgICAgLi4uKHByb2R1Y2VyUHJvb2YgPyB7cHJvZHVjZXJQcm9vZn0gOiB7fSlcbiAgICAgICAgfSlcbiAgICAgIH0sXG4gICAgICBvbk1lc3NhZ2U6ICh7bWVzc2FnZSwgcmVzb2x2ZSwgcmVqZWN0fSkgPT4ge1xuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJlbnF1ZXVlZFwiKSB7XG4gICAgICAgICAgcmVzb2x2ZShtZXNzYWdlLmpvYklkKVxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1lc3NhZ2U/LnR5cGUgPT09IFwiZW5xdWV1ZS1lcnJvclwiKSB7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihtZXNzYWdlLmVycm9yIHx8IFwiRmFpbGVkIHRvIGVucXVldWUgam9iXCIpKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSkpXG4gIH1cblxuICAvKipcbiAgICogQXRvbWljYWxseSByZXBsYWNlcyB0aGUgcXVldWVkIG93bmVyIG9mIGEgc3RhYmxlIHNjaGVkdWxlIGtleS5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gYXJncy5zY2hlZHVsZUtleSAtIFN0YWJsZSBsb2dpY2FsIHNjaGVkdWxlIGtleS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muam9iTmFtZSAtIEpvYiBuYW1lLlxuICAgKiBAcGFyYW0ge0FycmF5PFJldHVyblR5cGU8dHlwZW9mIEpTT04ucGFyc2U+Pn0gYXJncy5hcmdzIC0gSm9iIGFyZ3MuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iT3B0aW9uc30gW2FyZ3Mub3B0aW9uc10gLSBKb2Igb3B0aW9ucy5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iUmVwbGFjZW1lbnRSZXN1bHQ+fSAtIFJlcGxhY2VtZW50IHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIHJlcGxhY2VTY2hlZHVsZWQoe3NjaGVkdWxlS2V5LCBqb2JOYW1lLCBhcmdzLCBvcHRpb25zfSkge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBhd2FpdCB0aGlzLl9yZXF1ZXN0KClcblxuICAgIHJldHVybiBhd2FpdCByZXF1ZXN0LnJ1bih7XG4gICAgICBvbkNvbm5lY3Q6IChqc29uU29ja2V0KSA9PiB7XG4gICAgICAgIGpzb25Tb2NrZXQuc2VuZCh7dHlwZTogXCJyZXBsYWNlLXNjaGVkdWxlZFwiLCBzY2hlZHVsZUtleSwgam9iTmFtZSwgYXJncywgb3B0aW9uc30pXG4gICAgICB9LFxuICAgICAgb25NZXNzYWdlOiAoe21lc3NhZ2UsIHJlc29sdmUsIHJlamVjdH0pID0+IHtcbiAgICAgICAgaWYgKG1lc3NhZ2U/LnR5cGUgPT09IFwic2NoZWR1bGUtcmVwbGFjZWRcIikge1xuICAgICAgICAgIHJlc29sdmUoe1xuICAgICAgICAgICAgam9iSWQ6IG1lc3NhZ2Uuam9iSWQsXG4gICAgICAgICAgICBwcmV2aW91c0pvYklkOiBtZXNzYWdlLnByZXZpb3VzSm9iSWQsXG4gICAgICAgICAgICBwcmV2aW91c1N0YXR1czogbWVzc2FnZS5wcmV2aW91c1N0YXR1c1xuICAgICAgICAgIH0pXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJyZXBsYWNlLXNjaGVkdWxlZC1lcnJvclwiKSB7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihtZXNzYWdlLmVycm9yIHx8IFwiRmFpbGVkIHRvIHJlcGxhY2Ugc2NoZWR1bGVkIGpvYlwiKSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvKipcbiAgICogQ2FuY2VscyBvciBkZXRhY2hlcyB0aGUgY3VycmVudCBvd25lciBvZiBhIHN0YWJsZSBzY2hlZHVsZSBrZXkuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muc2NoZWR1bGVLZXkgLSBTdGFibGUgbG9naWNhbCBzY2hlZHVsZSBrZXkuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYkNhbmNlbGxhdGlvblJlc3VsdD59IC0gQ2FuY2VsbGF0aW9uIHJlc3VsdC5cbiAgICovXG4gIGFzeW5jIGNhbmNlbFNjaGVkdWxlZCh7c2NoZWR1bGVLZXl9KSB7XG4gICAgY29uc3QgcmVxdWVzdCA9IGF3YWl0IHRoaXMuX3JlcXVlc3QoKVxuXG4gICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QucnVuKHtcbiAgICAgIG9uQ29ubmVjdDogKGpzb25Tb2NrZXQpID0+IHtcbiAgICAgICAganNvblNvY2tldC5zZW5kKHt0eXBlOiBcImNhbmNlbC1zY2hlZHVsZWRcIiwgc2NoZWR1bGVLZXl9KVxuICAgICAgfSxcbiAgICAgIG9uTWVzc2FnZTogKHttZXNzYWdlLCByZXNvbHZlLCByZWplY3R9KSA9PiB7XG4gICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcInNjaGVkdWxlLWNhbmNlbGxlZFwiKSB7XG4gICAgICAgICAgcmVzb2x2ZSh7am9iSWQ6IG1lc3NhZ2Uuam9iSWQsIG91dGNvbWU6IG1lc3NhZ2Uub3V0Y29tZX0pXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJjYW5jZWwtc2NoZWR1bGVkLWVycm9yXCIpIHtcbiAgICAgICAgICByZWplY3QobmV3IEVycm9yKG1lc3NhZ2UuZXJyb3IgfHwgXCJGYWlsZWQgdG8gY2FuY2VsIHNjaGVkdWxlZCBqb2JcIikpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KVxuICB9XG59XG4iXX0=
151
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2JhY2tncm91bmQtam9icy9jbGllbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sT0FBTyxNQUFNLDJCQUEyQixDQUFBO0FBQy9DLE9BQU8scUJBQXFCLE1BQU0sOEJBQThCLENBQUE7QUFDaEUsT0FBTywyQkFBMkIsTUFBTSxxQkFBcUIsQ0FBQTtBQUM3RCxPQUFPLEVBQUUsdUNBQXVDLEVBQUUsb0NBQW9DLEVBQUUsTUFBTSx5Q0FBeUMsQ0FBQTtBQUV2SSxNQUFNLDBCQUEwQixHQUFHLElBQUksQ0FBQTtBQUV2QyxNQUFNLENBQUMsT0FBTyxPQUFPLG9CQUFvQjtJQUN2Qzs7Ozs7OztPQU9HO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBRSxnQkFBZ0IsR0FBRywwQkFBMEIsRUFBRSw0QkFBNEIsR0FBRyx1Q0FBdUMsRUFBRSxZQUFZLEVBQUMsR0FBRyxFQUFFO1FBQ25LLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxhQUFhLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDLHFCQUFxQixFQUFFLENBQUE7UUFDcEcsSUFBSSxDQUFDLGdCQUFnQixHQUFHLGdCQUFnQixDQUFBO1FBQ3hDLElBQUksQ0FBQyw0QkFBNEIsR0FBRyxvQ0FBb0MsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFBO1FBQ3RHLElBQUksQ0FBQyxvQkFBb0IsR0FBRyxZQUFZLENBQUE7SUFDMUMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxRQUFRO1FBQ1osTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUE7UUFDckQsTUFBTSxFQUFDLElBQUksRUFBRSxJQUFJLEVBQUMsR0FBRyxhQUFhLENBQUMsdUJBQXVCLEVBQUUsQ0FBQTtRQUM1RCxNQUFNLEVBQUMsWUFBWSxFQUFDLEdB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QTtJQUNKLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxlQUFlLENBQUMsRUFBQyxXQUFXLEVBQUM7UUFDakMsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUE7UUFFckMsT0FBTyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7WUFDdkIsU0FBUyxFQUFFLENBQUMsVUFBVSxFQUFFLEVBQUU7Z0JBQ3hCLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBQyxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsV0FBVyxFQUFDLENBQUMsQ0FBQTtZQUMxRCxDQUFDO1lBQ0QsU0FBUyxFQUFFLENBQUMsRUFBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBQyxFQUFFLEVBQUU7Z0JBQ3hDLElBQUksT0FBTyxFQUFFLElBQUksS0FBSyxvQkFBb0IsRUFBRSxDQUFDO29CQUMzQyxPQUFPLENBQUMsRUFBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU8sRUFBQyxDQUFDLENBQUE7b0JBQ3pELE9BQU07Z0JBQ1IsQ0FBQztnQkFFRCxJQUFJLE9BQU8sRUFBRSxJQUFJLEtBQUssd0JBQXdCLEVBQUUsQ0FBQztvQkFDL0MsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLElBQUksZ0NBQWdDLENBQUMsQ0FBQyxDQUFBO2dCQUN0RSxDQUFDO1lBQ0gsQ0FBQztTQUNGLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgdGltZW91dCBmcm9tIFwiYXdhaXRlcnkvYnVpbGQvdGltZW91dC5qc1wiXG5pbXBvcnQgY29uZmlndXJhdGlvblJlc29sdmVyIGZyb20gXCIuLi9jb25maWd1cmF0aW9uLXJlc29sdmVyLmpzXCJcbmltcG9ydCBCYWNrZ3JvdW5kSm9ic1NvY2tldFJlcXVlc3QgZnJvbSBcIi4vc29ja2V0LXJlcXVlc3QuanNcIlxuaW1wb3J0IHsgREVGQVVMVF9HRU5FUkFUSU9OX0hBTkRTSEFLRV9USU1FT1VUX01TLCB2YWxpZGF0ZUdlbmVyYXRpb25IYW5kc2hha2VUaW1lb3V0TXMgfSBmcm9tIFwiLi9nZW5lcmF0aW9uLWhhbmRzaGFrZS10aW1lb3V0LWVycm9yLmpzXCJcblxuY29uc3QgREVGQVVMVF9FTlFVRVVFX1RJTUVPVVRfTVMgPSA1MDAwXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEJhY2tncm91bmRKb2JzQ2xpZW50IHtcbiAgLyoqXG4gICAqIFJ1bnMgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBbYXJnc10gLSBPcHRpb25zLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4uL2NvbmZpZ3VyYXRpb24uanNcIikuZGVmYXVsdH0gW2FyZ3MuY29uZmlndXJhdGlvbl0gLSBDb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge251bWJlcn0gW2FyZ3MuZW5xdWV1ZVRpbWVvdXRNc10gLSBNYXhpbXVtIHRpbWUgdG8gd2FpdCBmb3IgYW4gZW5xdWV1ZSBhY2tub3dsZWRnZW1lbnQgaW4gbWlsbGlzZWNvbmRzIChkZWZhdWx0OiA1MDAwKS5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLmdlbmVyYXRpb25IYW5kc2hha2VUaW1lb3V0TXNdIC0gTWF4aW11bSB0aW1lIHRvIHdhaXQgZm9yIGdlbmVyYXRpb24gYWNrbm93bGVkZ2VtZW50IChkZWZhdWx0OiA0MDAwKS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLmdlbmVyYXRpb25JZF0gLSBFeHBsaWNpdCByZWxlYXNlIGdlbmVyYXRpb24gaWRlbnRpdHkuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7Y29uZmlndXJhdGlvbiwgZW5xdWV1ZVRpbWVvdXRNcyA9IERFRkFVTFRfRU5RVUVVRV9USU1FT1VUX01TLCBnZW5lcmF0aW9uSGFuZHNoYWtlVGltZW91dE1zID0gREVGQVVMVF9HRU5FUkFUSU9OX0hBTkRTSEFLRV9USU1FT1VUX01TLCBnZW5lcmF0aW9uSWR9ID0ge30pIHtcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb25Qcm9taXNlID0gY29uZmlndXJhdGlvbiA/IFByb21pc2UucmVzb2x2ZShjb25maWd1cmF0aW9uKSA6IGNvbmZpZ3VyYXRpb25SZXNvbHZlcigpXG4gICAgdGhpcy5lbnF1ZXVlVGltZW91dE1zID0gZW5xdWV1ZVRpbWVvdXRNc1xuICAgIHRoaXMuZ2VuZXJhdGlvbkhhbmRzaGFrZVRpbWVvdXRNcyA9IHZhbGlkYXRlR2VuZXJhdGlvbkhhbmRzaGFrZVRpbWVvdXRNcyhnZW5lcmF0aW9uSGFuZHNoYWtlVGltZW91dE1zKVxuICAgIHRoaXMuZXhwbGljaXRHZW5lcmF0aW9uSWQgPSBnZW5lcmF0aW9uSWRcbiAgfVxuXG4gIC8qKlxuICAgKiBCdWlsZHMgYSBvbmUtc2hvdCBjbGllbnQgc29ja2V0IHJlcXVlc3QgZnJvbSB0aGUgcmVzb2x2ZWQgY29uZmlndXJhdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8QmFja2dyb3VuZEpvYnNTb2NrZXRSZXF1ZXN0Pn0gLSBTb2NrZXQgcmVxdWVzdC5cbiAgICovXG4gIGFzeW5jIF9yZXF1ZXN0KCkge1xuICAgIGNvbnN0IGNvbmZpZ3VyYXRpb24gPSBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb25Qcm9taXNlXG4gICAgY29uc3Qge2hvc3QsIHBvcnR9ID0gY29uZmlndXJhdGlvbi5nZXRCYWNrZ3JvdW5kSm9ic0NvbmZpZygpXG4gICAgY29uc3Qge2dlbmVyYXRpb25JZH0gPSBjb25maWd1cmF0aW9uLnJlc29sdmVCYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25Db25maWcoe1xuICAgICAgZ2VuZXJhdGlvbklkOiB0aGlzLmV4cGxpY2l0R2VuZXJhdGlvbklkLFxuICAgICAgc291cmNlTmFtZTogXCJCYWNrZ3JvdW5kSm9ic0NsaWVudFwiXG4gICAgfSlcblxuICAgIHJldHVybiBuZXcgQmFja2dyb3VuZEpvYnNTb2NrZXRSZXF1ZXN0KHtob3N0LCBwb3J0LCByb2xlOiBcImNsaWVudFwiLCBnZW5lcmF0aW9uSGFuZHNoYWtlVGltZW91dE1zOiB0aGlzLmdlbmVyYXRpb25IYW5kc2hha2VUaW1lb3V0TXMsIGdlbmVyYXRpb25JZH0pXG4gIH1cblxuICAvKipcbiAgICogUnVucyBlbnF1ZXVlLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmpvYk5hbWUgLSBKb2IgbmFtZS5cbiAgICogQHBhcmFtIHtBcnJheTxSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj59IGFyZ3MuYXJncyAtIEpvYiBhcmdzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYk9wdGlvbnN9IFthcmdzLm9wdGlvbnNdIC0gSm9iIG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5wcm9kdWNlckludm9jYXRpb25JZF0gLSBTdGFibGUgaWRlbnRpdHkgZm9yIG9uZSBvd25lZCBlbnF1ZXVlIGludm9jYXRpb24uXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9iUHJvZHVjZXJQcm9vZn0gW2FyZ3MucHJvZHVjZXJQcm9vZl0gLSBFeGFjdCBpbnRlcm5hbCBwcm9kdWNlciBoYW5kb2ZmLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSAtIEpvYiBpZC5cbiAgICovXG4gIGFzeW5jIGVucXVldWUoe2pvYk5hbWUsIGFyZ3MsIG9wdGlvbnMsIHByb2R1Y2VySW52b2NhdGlvbklkLCBwcm9kdWNlclByb29mfSkge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSB7XG4gICAgICB0eXBlOiAvKiogQHR5cGUge2NvbnN0fSAqLyAoXCJlbnF1ZXVlXCIpLFxuICAgICAgam9iTmFtZSxcbiAgICAgIGFyZ3MsXG4gICAgICBvcHRpb25zLFxuICAgICAgLi4uKHByb2R1Y2VySW52b2NhdGlvbklkID8ge3Byb2R1Y2VySW52b2NhdGlvbklkfSA6IHt9KSxcbiAgICAgIC4uLihwcm9kdWNlclByb29mID8ge3Byb2R1Y2VyUHJvb2Z9IDoge30pXG4gICAgfVxuICAgIGNvbnN0IGFja25vd2xlZGdlbWVudCA9IHtleHBsaWNpdGx5UmVqZWN0ZWQ6IGZhbHNlLCBnZW5lcmF0aW9uRmVuY2VkOiBmYWxzZSwgcmVxdWVzdFNlbnQ6IGZhbHNlfVxuICAgIC8qKlxuICAgICAqIFNlbmRzIG9uZSBlbnF1ZXVlIGF0dGVtcHQuIEFuIG93bmVkIGNhbGxlciBtYXkgcmVwbGF5IHRoaXMgZXhhY3QgbWVzc2FnZVxuICAgICAqIG9uY2Ugd2hlbiB0cmFuc3BvcnQgYWNrbm93bGVkZ2VtZW50IHJlbWFpbnMgYW1iaWd1b3VzIGFmdGVyIHNlbmQuXG4gICAgICogQHBhcmFtIHt7ZXhwbGljaXRseVJlamVjdGVkOiBib29sZWFuLCBnZW5lcmF0aW9uRmVuY2VkOiBib29sZWFuLCByZXF1ZXN0U2VudDogYm9vbGVhbn0gfCB1bmRlZmluZWR9IGF0dGVtcHRBY2tub3dsZWRnZW1lbnQgLSBGaXJzdC1hdHRlbXB0IG9ic2VydmF0aW9ucy5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSAtIEpvYiBpZC5cbiAgICAgKi9cbiAgICBjb25zdCBlbnF1ZXVlQXR0ZW1wdCA9IGFzeW5jIChhdHRlbXB0QWNrbm93bGVkZ2VtZW50KSA9PiB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gYXdhaXQgdGhpcy5fcmVxdWVzdCgpXG5cbiAgICAgIHJldHVybiBhd2FpdCB0aW1lb3V0KHtcbiAgICAgICAgZXJyb3JNZXNzYWdlOiBgQmFja2dyb3VuZCBqb2IgZW5xdWV1ZSBhY2tub3dsZWRnZW1lbnQgdGltZWQgb3V0IGFmdGVyICR7dGhpcy5lbnF1ZXVlVGltZW91dE1zfW1zYCxcbiAgICAgICAgdGltZW91dDogdGhpcy5lbnF1ZXVlVGltZW91dE1zXG4gICAgICB9LCBhc3luYyAoe2NvbnRyb2x9KSA9PiBhd2FpdCByZXF1ZXN0LnJ1bih7XG4gICAgICAgIHNpZ25hbDogY29udHJvbC5zaWduYWwsXG4gICAgICAgIG9uQ29ubmVjdDogKGpzb25Tb2NrZXQpID0+IHtcbiAgICAgICAgICBqc29uU29ja2V0LnNlbmQobWVzc2FnZSlcbiAgICAgICAgICBpZiAoYXR0ZW1wdEFja25vd2xlZGdlbWVudCkge1xuICAgICAgICAgICAgYXR0ZW1wdEFja25vd2xlZGdlbWVudC5nZW5lcmF0aW9uRmVuY2VkID0gQm9vbGVhbihyZXF1ZXN0LmdlbmVyYXRpb25JZClcbiAgICAgICAgICAgIGF0dGVtcHRBY2tub3dsZWRnZW1lbnQucmVxdWVzdFNlbnQgPSB0cnVlXG4gICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBvbk1lc3NhZ2U6ICh7bWVzc2FnZSwgcmVzb2x2ZSwgcmVqZWN0fSkgPT4ge1xuICAgICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcImVucXVldWVkXCIpIHtcbiAgICAgICAgICAgIHJlc29sdmUobWVzc2FnZS5qb2JJZClcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcImVucXVldWUtZXJyb3JcIikge1xuICAgICAgICAgICAgaWYgKGF0dGVtcHRBY2tub3dsZWRnZW1lbnQpIGF0dGVtcHRBY2tub3dsZWRnZW1lbnQuZXhwbGljaXRseVJlamVjdGVkID0gdHJ1ZVxuICAgICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihtZXNzYWdlLmVycm9yIHx8IFwiRmFpbGVkIHRvIGVucXVldWUgam9iXCIpKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSkpXG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBhd2FpdCBlbnF1ZXVlQXR0ZW1wdChhY2tub3dsZWRnZW1lbnQpXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmICghcHJvZHVjZXJJbnZvY2F0aW9uSWQgfHwgIXByb2R1Y2VyUHJvb2YgfHwgIWFja25vd2xlZGdlbWVudC5nZW5lcmF0aW9uRmVuY2VkIHx8ICFhY2tub3dsZWRnZW1lbnQucmVxdWVzdFNlbnQgfHwgYWNrbm93bGVkZ2VtZW50LmV4cGxpY2l0bHlSZWplY3RlZCkgdGhyb3cgZXJyb3JcbiAgICB9XG5cbiAgICByZXR1cm4gYXdhaXQgZW5xdWV1ZUF0dGVtcHQodW5kZWZpbmVkKVxuICB9XG5cbiAgLyoqXG4gICAqIEF0b21pY2FsbHkgcmVwbGFjZXMgdGhlIHF1ZXVlZCBvd25lciBvZiBhIHN0YWJsZSBzY2hlZHVsZSBrZXkuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gT3B0aW9ucy5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGFyZ3Muc2NoZWR1bGVLZXkgLSBTdGFibGUgbG9naWNhbCBzY2hlZHVsZSBrZXkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLmpvYk5hbWUgLSBKb2IgbmFtZS5cbiAgICogQHBhcmFtIHtBcnJheTxSZXR1cm5UeXBlPHR5cGVvZiBKU09OLnBhcnNlPj59IGFyZ3MuYXJncyAtIEpvYiBhcmdzLlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYk9wdGlvbnN9IFthcmdzLm9wdGlvbnNdIC0gSm9iIG9wdGlvbnMuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYlJlcGxhY2VtZW50UmVzdWx0Pn0gLSBSZXBsYWNlbWVudCByZXN1bHQuXG4gICAqL1xuICBhc3luYyByZXBsYWNlU2NoZWR1bGVkKHtzY2hlZHVsZUtleSwgam9iTmFtZSwgYXJncywgb3B0aW9uc30pIHtcbiAgICBjb25zdCByZXF1ZXN0ID0gYXdhaXQgdGhpcy5fcmVxdWVzdCgpXG5cbiAgICByZXR1cm4gYXdhaXQgcmVxdWVzdC5ydW4oe1xuICAgICAgb25Db25uZWN0OiAoanNvblNvY2tldCkgPT4ge1xuICAgICAgICBqc29uU29ja2V0LnNlbmQoe3R5cGU6IFwicmVwbGFjZS1zY2hlZHVsZWRcIiwgc2NoZWR1bGVLZXksIGpvYk5hbWUsIGFyZ3MsIG9wdGlvbnN9KVxuICAgICAgfSxcbiAgICAgIG9uTWVzc2FnZTogKHttZXNzYWdlLCByZXNvbHZlLCByZWplY3R9KSA9PiB7XG4gICAgICAgIGlmIChtZXNzYWdlPy50eXBlID09PSBcInNjaGVkdWxlLXJlcGxhY2VkXCIpIHtcbiAgICAgICAgICByZXNvbHZlKHtcbiAgICAgICAgICAgIGpvYklkOiBtZXNzYWdlLmpvYklkLFxuICAgICAgICAgICAgcHJldmlvdXNKb2JJZDogbWVzc2FnZS5wcmV2aW91c0pvYklkLFxuICAgICAgICAgICAgcHJldmlvdXNTdGF0dXM6IG1lc3NhZ2UucHJldmlvdXNTdGF0dXNcbiAgICAgICAgICB9KVxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1lc3NhZ2U/LnR5cGUgPT09IFwicmVwbGFjZS1zY2hlZHVsZWQtZXJyb3JcIikge1xuICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IobWVzc2FnZS5lcnJvciB8fCBcIkZhaWxlZCB0byByZXBsYWNlIHNjaGVkdWxlZCBqb2JcIikpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIENhbmNlbHMgb3IgZGV0YWNoZXMgdGhlIGN1cnJlbnQgb3duZXIgb2YgYSBzdGFibGUgc2NoZWR1bGUga2V5LlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhcmdzLnNjaGVkdWxlS2V5IC0gU3RhYmxlIGxvZ2ljYWwgc2NoZWR1bGUga2V5LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JDYW5jZWxsYXRpb25SZXN1bHQ+fSAtIENhbmNlbGxhdGlvbiByZXN1bHQuXG4gICAqL1xuICBhc3luYyBjYW5jZWxTY2hlZHVsZWQoe3NjaGVkdWxlS2V5fSkge1xuICAgIGNvbnN0IHJlcXVlc3QgPSBhd2FpdCB0aGlzLl9yZXF1ZXN0KClcblxuICAgIHJldHVybiBhd2FpdCByZXF1ZXN0LnJ1bih7XG4gICAgICBvbkNvbm5lY3Q6IChqc29uU29ja2V0KSA9PiB7XG4gICAgICAgIGpzb25Tb2NrZXQuc2VuZCh7dHlwZTogXCJjYW5jZWwtc2NoZWR1bGVkXCIsIHNjaGVkdWxlS2V5fSlcbiAgICAgIH0sXG4gICAgICBvbk1lc3NhZ2U6ICh7bWVzc2FnZSwgcmVzb2x2ZSwgcmVqZWN0fSkgPT4ge1xuICAgICAgICBpZiAobWVzc2FnZT8udHlwZSA9PT0gXCJzY2hlZHVsZS1jYW5jZWxsZWRcIikge1xuICAgICAgICAgIHJlc29sdmUoe2pvYklkOiBtZXNzYWdlLmpvYklkLCBvdXRjb21lOiBtZXNzYWdlLm91dGNvbWV9KVxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1lc3NhZ2U/LnR5cGUgPT09IFwiY2FuY2VsLXNjaGVkdWxlZC1lcnJvclwiKSB7XG4gICAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihtZXNzYWdlLmVycm9yIHx8IFwiRmFpbGVkIHRvIGNhbmNlbCBzY2hlZHVsZWQgam9iXCIpKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSlcbiAgfVxufVxuIl19
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.660",
6
+ "version": "1.0.661",
7
7
  "main": "build/index.js",
8
8
  "types": "build/index.d.ts",
9
9
  "files": [
@@ -49,34 +49,57 @@ export default class BackgroundJobsClient {
49
49
  * @returns {Promise<string>} - Job id.
50
50
  */
51
51
  async enqueue({jobName, args, options, producerInvocationId, producerProof}) {
52
- const request = await this._request()
52
+ const message = {
53
+ type: /** @type {const} */ ("enqueue"),
54
+ jobName,
55
+ args,
56
+ options,
57
+ ...(producerInvocationId ? {producerInvocationId} : {}),
58
+ ...(producerProof ? {producerProof} : {})
59
+ }
60
+ const acknowledgement = {explicitlyRejected: false, generationFenced: false, requestSent: false}
61
+ /**
62
+ * Sends one enqueue attempt. An owned caller may replay this exact message
63
+ * once when transport acknowledgement remains ambiguous after send.
64
+ * @param {{explicitlyRejected: boolean, generationFenced: boolean, requestSent: boolean} | undefined} attemptAcknowledgement - First-attempt observations.
65
+ * @returns {Promise<string>} - Job id.
66
+ */
67
+ const enqueueAttempt = async (attemptAcknowledgement) => {
68
+ const request = await this._request()
53
69
 
54
- return await timeout({
55
- errorMessage: `Background job enqueue acknowledgement timed out after ${this.enqueueTimeoutMs}ms`,
56
- timeout: this.enqueueTimeoutMs
57
- }, async ({control}) => await request.run({
58
- signal: control.signal,
59
- onConnect: (jsonSocket) => {
60
- jsonSocket.send({
61
- type: "enqueue",
62
- jobName,
63
- args,
64
- options,
65
- ...(producerInvocationId ? {producerInvocationId} : {}),
66
- ...(producerProof ? {producerProof} : {})
67
- })
68
- },
69
- onMessage: ({message, resolve, reject}) => {
70
- if (message?.type === "enqueued") {
71
- resolve(message.jobId)
72
- return
73
- }
70
+ return await timeout({
71
+ errorMessage: `Background job enqueue acknowledgement timed out after ${this.enqueueTimeoutMs}ms`,
72
+ timeout: this.enqueueTimeoutMs
73
+ }, async ({control}) => await request.run({
74
+ signal: control.signal,
75
+ onConnect: (jsonSocket) => {
76
+ jsonSocket.send(message)
77
+ if (attemptAcknowledgement) {
78
+ attemptAcknowledgement.generationFenced = Boolean(request.generationId)
79
+ attemptAcknowledgement.requestSent = true
80
+ }
81
+ },
82
+ onMessage: ({message, resolve, reject}) => {
83
+ if (message?.type === "enqueued") {
84
+ resolve(message.jobId)
85
+ return
86
+ }
74
87
 
75
- if (message?.type === "enqueue-error") {
76
- reject(new Error(message.error || "Failed to enqueue job"))
88
+ if (message?.type === "enqueue-error") {
89
+ if (attemptAcknowledgement) attemptAcknowledgement.explicitlyRejected = true
90
+ reject(new Error(message.error || "Failed to enqueue job"))
91
+ }
77
92
  }
78
- }
79
- }))
93
+ }))
94
+ }
95
+
96
+ try {
97
+ return await enqueueAttempt(acknowledgement)
98
+ } catch (error) {
99
+ if (!producerInvocationId || !producerProof || !acknowledgement.generationFenced || !acknowledgement.requestSent || acknowledgement.explicitlyRejected) throw error
100
+ }
101
+
102
+ return await enqueueAttempt(undefined)
80
103
  }
81
104
 
82
105
  /**