@tablecraft-app/plugin-etcd 1.18.0 → 1.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +60 -9
- package/package.json +1 -1
- package/table-craft-plugin.json +1 -1
package/index.js
CHANGED
|
@@ -41289,6 +41289,18 @@ function createEtcd(settings) {
|
|
|
41289
41289
|
if (settings.tls !== null) useTls(etcd, settings.tls);
|
|
41290
41290
|
return etcd;
|
|
41291
41291
|
}
|
|
41292
|
+
/**
|
|
41293
|
+
* Stops a watch or keep-alive stream the plugin no longer needs. etcd3 takes an error on a stream
|
|
41294
|
+
* that is still writable for a failed host and closes every gRPC client of the connection
|
|
41295
|
+
* (`stream.writable && this.client.markFailed(resource, err)` in etcd3 1.1.2 lib/rpc.js, see
|
|
41296
|
+
* https://github.com/microsoft/etcd3/blob/v1.1.2/src/rpc.ts); a call queued behind that, such
|
|
41297
|
+
* as the next get over TLS, then fails with "Channel closed before call started". Half-closing
|
|
41298
|
+
* first turns the CANCELLED that `cancel()` raises into a local teardown.
|
|
41299
|
+
*/
|
|
41300
|
+
function closeStream(stream) {
|
|
41301
|
+
stream.end();
|
|
41302
|
+
stream.cancel();
|
|
41303
|
+
}
|
|
41292
41304
|
function errorText(cause) {
|
|
41293
41305
|
return cause instanceof Error ? cause.message : String(cause);
|
|
41294
41306
|
}
|
|
@@ -42155,7 +42167,7 @@ function namespaceCall(call, mapper, serializable = false) {
|
|
|
42155
42167
|
listener(mapResponse(response, mapper));
|
|
42156
42168
|
} catch (error) {
|
|
42157
42169
|
for (const handler of errors) handler(error);
|
|
42158
|
-
raw
|
|
42170
|
+
closeStream(raw);
|
|
42159
42171
|
}
|
|
42160
42172
|
} : listener);
|
|
42161
42173
|
return scoped;
|
|
@@ -42943,7 +42955,7 @@ var EtcdLeases = class {
|
|
|
42943
42955
|
clearTimeout(timer);
|
|
42944
42956
|
clearTimeout(timeout);
|
|
42945
42957
|
if (reason !== null) stoppedReason = reason;
|
|
42946
|
-
stream
|
|
42958
|
+
if (stream !== void 0) closeStream(stream);
|
|
42947
42959
|
pending?.reject(new Error(reason ?? "Lease renewal stopped; the lease was not revoked."));
|
|
42948
42960
|
pending = void 0;
|
|
42949
42961
|
release();
|
|
@@ -42982,7 +42994,7 @@ var EtcdLeases = class {
|
|
|
42982
42994
|
try {
|
|
42983
42995
|
stream = await this.host.globalCall((etcd) => etcd.leaseClient.leaseKeepAlive());
|
|
42984
42996
|
if (closed) {
|
|
42985
|
-
stream
|
|
42997
|
+
closeStream(stream);
|
|
42986
42998
|
return {
|
|
42987
42999
|
once,
|
|
42988
43000
|
close,
|
|
@@ -43062,6 +43074,7 @@ var MAX_RETRIES = 2;
|
|
|
43062
43074
|
var DECIMAL = /^(0|[1-9]\d*)$/;
|
|
43063
43075
|
var MAX_CURSOR_LENGTH = 2048;
|
|
43064
43076
|
var SIGNING_KEY_BYTES = 32;
|
|
43077
|
+
var COMPACTED$1 = /required revision has been compacted/i;
|
|
43065
43078
|
/** Session-private authentication keeps cursor state bounded without retaining searches. */
|
|
43066
43079
|
var HistoryState = class {
|
|
43067
43080
|
#secret = randomBytes(SIGNING_KEY_BYTES);
|
|
@@ -43108,6 +43121,23 @@ function positionOf(cursor, key, state) {
|
|
|
43108
43121
|
return invalid("invalid cursor. Start a new history search.");
|
|
43109
43122
|
}
|
|
43110
43123
|
}
|
|
43124
|
+
async function terminalVersion(call, key, position, deadline) {
|
|
43125
|
+
const read = async (revision) => {
|
|
43126
|
+
const kv = (await call((etcd) => etcd.kv.range({
|
|
43127
|
+
key,
|
|
43128
|
+
...revision === void 0 ? {} : { revision }
|
|
43129
|
+
}, { deadline }))).kvs[0];
|
|
43130
|
+
return kv?.mod_revision === position.terminal ? kv : null;
|
|
43131
|
+
};
|
|
43132
|
+
const current = await read();
|
|
43133
|
+
if (current !== null) return current;
|
|
43134
|
+
try {
|
|
43135
|
+
return await read(position.snapshot);
|
|
43136
|
+
} catch (cause) {
|
|
43137
|
+
if (COMPACTED$1.test(errorText(cause))) return null;
|
|
43138
|
+
throw cause;
|
|
43139
|
+
}
|
|
43140
|
+
}
|
|
43111
43141
|
/** Replay ends only at the pinned key's actual terminal event, never at a watch header. */
|
|
43112
43142
|
async function keyHistory(call, request, state) {
|
|
43113
43143
|
state.checkOpen();
|
|
@@ -43152,7 +43182,7 @@ async function keyHistory(call, request, state) {
|
|
|
43152
43182
|
await call(async (etcd) => {
|
|
43153
43183
|
const stream = await etcd.watchClient.watch({ deadline });
|
|
43154
43184
|
if (state.signal.aborted || Date.now() >= deadline) {
|
|
43155
|
-
stream
|
|
43185
|
+
closeStream(stream);
|
|
43156
43186
|
state.checkOpen();
|
|
43157
43187
|
return;
|
|
43158
43188
|
}
|
|
@@ -43163,7 +43193,7 @@ async function keyHistory(call, request, state) {
|
|
|
43163
43193
|
done = true;
|
|
43164
43194
|
clearTimeout(timer);
|
|
43165
43195
|
state.signal.removeEventListener("abort", onClose);
|
|
43166
|
-
stream
|
|
43196
|
+
closeStream(stream);
|
|
43167
43197
|
if (error === void 0) resolve();
|
|
43168
43198
|
else reject(error instanceof Error ? error : new Error(errorText(error)));
|
|
43169
43199
|
};
|
|
@@ -43243,9 +43273,30 @@ async function keyHistory(call, request, state) {
|
|
|
43243
43273
|
unavailable: compactRevision,
|
|
43244
43274
|
next: (BigInt(compactRevision) + 1n).toString()
|
|
43245
43275
|
};
|
|
43246
|
-
|
|
43247
|
-
|
|
43276
|
+
const terminalRevision = position.terminal;
|
|
43277
|
+
if (terminalRevision !== null && BigInt(compactRevision) >= BigInt(terminalRevision)) {
|
|
43248
43278
|
stopReason = "compacted";
|
|
43279
|
+
const terminal = await terminalVersion(call, key, position, deadline);
|
|
43280
|
+
if (terminal !== null && events.at(-1)?.modRevision !== terminalRevision) {
|
|
43281
|
+
const size = terminal.key.length + terminal.value.length;
|
|
43282
|
+
if (size > maxBytes && events.length === 0) throw new PluginError("statementFailed", "etcd history event exceeds the byte limit. Increase maxBytes or inspect the current value.");
|
|
43283
|
+
if (usedBytes + size > maxBytes || events.length >= count) {
|
|
43284
|
+
stopReason = usedBytes + size > maxBytes ? "byteLimit" : "pageLimit";
|
|
43285
|
+
position = {
|
|
43286
|
+
...position,
|
|
43287
|
+
next: terminalRevision
|
|
43288
|
+
};
|
|
43289
|
+
break;
|
|
43290
|
+
}
|
|
43291
|
+
usedBytes += size;
|
|
43292
|
+
events.push({
|
|
43293
|
+
...revisionOf(terminal),
|
|
43294
|
+
kind: "PUT",
|
|
43295
|
+
key: keyBytesOf(terminal.key),
|
|
43296
|
+
value: keyBytesOf(terminal.value)
|
|
43297
|
+
});
|
|
43298
|
+
}
|
|
43299
|
+
reachedEnd = true;
|
|
43249
43300
|
break;
|
|
43250
43301
|
}
|
|
43251
43302
|
if (++retries > MAX_RETRIES) {
|
|
@@ -43486,7 +43537,7 @@ var EtcdWatcher = class {
|
|
|
43486
43537
|
generation++;
|
|
43487
43538
|
const old = stream;
|
|
43488
43539
|
stream = void 0;
|
|
43489
|
-
old
|
|
43540
|
+
if (old !== void 0) closeStream(old);
|
|
43490
43541
|
};
|
|
43491
43542
|
const markGap = (reason, toRevision) => {
|
|
43492
43543
|
gap = {
|
|
@@ -43536,7 +43587,7 @@ var EtcdWatcher = class {
|
|
|
43536
43587
|
try {
|
|
43537
43588
|
const opened = await this.host.call((etcd) => etcd.watchClient.watch());
|
|
43538
43589
|
if (mine !== generation || state === "stopped" || state === "gap") {
|
|
43539
|
-
opened
|
|
43590
|
+
closeStream(opened);
|
|
43540
43591
|
return;
|
|
43541
43592
|
}
|
|
43542
43593
|
stream = opened;
|
package/package.json
CHANGED