dflockd-client 1.10.2 → 1.10.3
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/dist/client.cjs +21 -4
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +21 -4
- package/dist/client.js.map +1 -1
- package/package.json +1 -1
package/dist/client.cjs
CHANGED
|
@@ -52,6 +52,7 @@ __export(client_exports, {
|
|
|
52
52
|
});
|
|
53
53
|
module.exports = __toCommonJS(client_exports);
|
|
54
54
|
var net = __toESM(require("net"), 1);
|
|
55
|
+
var import_string_decoder = require("string_decoder");
|
|
55
56
|
var tls = __toESM(require("tls"), 1);
|
|
56
57
|
var DEFAULT_HOST = "127.0.0.1";
|
|
57
58
|
var DEFAULT_PORT = 6388;
|
|
@@ -117,6 +118,7 @@ function parseLease(value, fallback = 30) {
|
|
|
117
118
|
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
118
119
|
}
|
|
119
120
|
var _readlineBuf = /* @__PURE__ */ new WeakMap();
|
|
121
|
+
var _readlineDecoder = /* @__PURE__ */ new WeakMap();
|
|
120
122
|
var MAX_LINE_LENGTH = 1024 * 1024;
|
|
121
123
|
function readline(sock) {
|
|
122
124
|
return new Promise((resolve, reject) => {
|
|
@@ -128,8 +130,14 @@ function readline(sock) {
|
|
|
128
130
|
resolve(line);
|
|
129
131
|
return;
|
|
130
132
|
}
|
|
133
|
+
let decoder = _readlineDecoder.get(sock);
|
|
134
|
+
if (!decoder) {
|
|
135
|
+
decoder = new import_string_decoder.StringDecoder("utf8");
|
|
136
|
+
_readlineDecoder.set(sock, decoder);
|
|
137
|
+
}
|
|
138
|
+
const dec = decoder;
|
|
131
139
|
const onData = (chunk) => {
|
|
132
|
-
buf +=
|
|
140
|
+
buf += dec.write(chunk);
|
|
133
141
|
const idx = buf.indexOf("\n");
|
|
134
142
|
if (idx !== -1) {
|
|
135
143
|
cleanup();
|
|
@@ -139,22 +147,26 @@ function readline(sock) {
|
|
|
139
147
|
} else if (buf.length > MAX_LINE_LENGTH) {
|
|
140
148
|
cleanup();
|
|
141
149
|
_readlineBuf.delete(sock);
|
|
150
|
+
_readlineDecoder.delete(sock);
|
|
142
151
|
reject(new LockError("server response exceeded maximum line length"));
|
|
143
152
|
}
|
|
144
153
|
};
|
|
145
154
|
const onError = (err) => {
|
|
146
155
|
cleanup();
|
|
147
156
|
_readlineBuf.delete(sock);
|
|
157
|
+
_readlineDecoder.delete(sock);
|
|
148
158
|
reject(err);
|
|
149
159
|
};
|
|
150
160
|
const onClose = () => {
|
|
151
161
|
cleanup();
|
|
152
162
|
_readlineBuf.delete(sock);
|
|
163
|
+
_readlineDecoder.delete(sock);
|
|
153
164
|
reject(new LockError("server closed connection"));
|
|
154
165
|
};
|
|
155
166
|
const onEnd = () => {
|
|
156
167
|
cleanup();
|
|
157
168
|
_readlineBuf.delete(sock);
|
|
169
|
+
_readlineDecoder.delete(sock);
|
|
158
170
|
reject(new LockError("server closed connection"));
|
|
159
171
|
};
|
|
160
172
|
const cleanup = () => {
|
|
@@ -165,6 +177,7 @@ function readline(sock) {
|
|
|
165
177
|
};
|
|
166
178
|
if (sock.readableEnded || sock.destroyed) {
|
|
167
179
|
_readlineBuf.delete(sock);
|
|
180
|
+
_readlineDecoder.delete(sock);
|
|
168
181
|
reject(new LockError("server closed connection"));
|
|
169
182
|
return;
|
|
170
183
|
}
|
|
@@ -700,11 +713,11 @@ var DistributedPrimitive = class {
|
|
|
700
713
|
this.renewInFlight = null;
|
|
701
714
|
if (this.closed || this.token !== savedToken) return;
|
|
702
715
|
const elapsed = Date.now() - start;
|
|
703
|
-
const interval2 = Math.max(1, this.lease * this.renewRatio) * 1e3;
|
|
716
|
+
const interval2 = Math.max(0.1, this.lease * this.renewRatio) * 1e3;
|
|
704
717
|
this.renewTimer = setTimeout(loop, Math.max(0, interval2 - elapsed));
|
|
705
718
|
this.renewTimer.unref();
|
|
706
719
|
};
|
|
707
|
-
const interval = Math.max(1, this.lease * this.renewRatio) * 1e3;
|
|
720
|
+
const interval = Math.max(0.1, this.lease * this.renewRatio) * 1e3;
|
|
708
721
|
this.renewTimer = setTimeout(loop, interval);
|
|
709
722
|
this.renewTimer.unref();
|
|
710
723
|
}
|
|
@@ -793,6 +806,7 @@ async function publish(sock, channel, payload) {
|
|
|
793
806
|
var SignalConnection = class _SignalConnection {
|
|
794
807
|
sock;
|
|
795
808
|
buf = "";
|
|
809
|
+
decoder;
|
|
796
810
|
responseResolve = null;
|
|
797
811
|
responseReject = null;
|
|
798
812
|
cmdQueue = [];
|
|
@@ -807,6 +821,9 @@ var SignalConnection = class _SignalConnection {
|
|
|
807
821
|
*/
|
|
808
822
|
constructor(sock) {
|
|
809
823
|
this.sock = sock;
|
|
824
|
+
const prevDecoder = _readlineDecoder.get(sock);
|
|
825
|
+
this.decoder = prevDecoder ?? new import_string_decoder.StringDecoder("utf8");
|
|
826
|
+
_readlineDecoder.delete(sock);
|
|
810
827
|
const leftover = _readlineBuf.get(sock);
|
|
811
828
|
if (leftover) {
|
|
812
829
|
this.buf = leftover;
|
|
@@ -957,7 +974,7 @@ var SignalConnection = class _SignalConnection {
|
|
|
957
974
|
}
|
|
958
975
|
// ---- internals ----
|
|
959
976
|
onData(chunk) {
|
|
960
|
-
this.buf +=
|
|
977
|
+
this.buf += this.decoder.write(chunk);
|
|
961
978
|
if (this.buf.length > MAX_LINE_LENGTH * 2) {
|
|
962
979
|
this.buf = "";
|
|
963
980
|
this._closed = true;
|
package/dist/client.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import * as net from \"net\";\nimport * as tls from \"tls\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 6388;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class LockError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LockError\";\n }\n}\n\nexport class AcquireTimeoutError extends LockError {\n constructor(key: string) {\n super(`timeout acquiring '${key}'`);\n this.name = \"AcquireTimeoutError\";\n }\n}\n\nexport class AuthError extends LockError {\n constructor() {\n super(\"authentication failed\");\n this.name = \"AuthError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nfunction validateKey(key: string): void {\n if (key === \"\") {\n throw new LockError(\"key must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(key)) {\n throw new LockError(\n \"key must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateAuth(auth: string): void {\n if (/[\\0\\n\\r]/.test(auth)) {\n throw new LockError(\n \"auth token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateToken(token: string): void {\n if (token === \"\") {\n throw new LockError(\"token must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(token)) {\n throw new LockError(\n \"token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Low-level helpers\n// ---------------------------------------------------------------------------\n\nfunction encodeLines(...lines: string[]): Buffer {\n return Buffer.from(lines.map((l) => l + \"\\n\").join(\"\"), \"utf-8\");\n}\n\nfunction writeAll(sock: net.Socket, data: Buffer): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n sock.write(data, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Parse a lease value from a server response part.\n * Returns `fallback` when the value is missing, empty, or non-numeric.\n */\nfunction parseLease(value: string | undefined, fallback: number = 30): number {\n if (value == null || value === \"\") return fallback;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? n : fallback;\n}\n\n/**\n * Read one newline-terminated line from the socket.\n * Resolves with the line (without trailing \\r\\n).\n * Rejects if the connection closes before a full line arrives.\n *\n * NOTE: Concurrent calls to readline() on the same socket are unsafe —\n * callers must serialize reads (the request-response protocol naturally\n * enforces this).\n */\nconst _readlineBuf = new WeakMap<net.Socket, string>();\nconst MAX_LINE_LENGTH = 1024 * 1024; // 1 MB\n\nfunction readline(sock: net.Socket): Promise<string> {\n return new Promise((resolve, reject) => {\n let buf = _readlineBuf.get(sock) ?? \"\";\n\n // Check if a complete line is already buffered from a previous read.\n const existing = buf.indexOf(\"\\n\");\n if (existing !== -1) {\n const line = buf.slice(0, existing).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(existing + 1));\n resolve(line);\n return;\n }\n\n const onData = (chunk: Buffer) => {\n buf += chunk.toString(\"utf-8\");\n const idx = buf.indexOf(\"\\n\");\n if (idx !== -1) {\n cleanup();\n const line = buf.slice(0, idx).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(idx + 1));\n resolve(line);\n } else if (buf.length > MAX_LINE_LENGTH) {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server response exceeded maximum line length\"));\n }\n };\n\n const onError = (err: Error) => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const onEnd = () => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const cleanup = () => {\n sock.removeListener(\"data\", onData);\n sock.removeListener(\"error\", onError);\n sock.removeListener(\"close\", onClose);\n sock.removeListener(\"end\", onEnd);\n };\n\n // If the readable side already ended (e.g. the server closed before we\n // started reading), the 'end'/'close' events won't fire again.\n if (sock.readableEnded || sock.destroyed) {\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n return;\n }\n\n sock.on(\"data\", onData);\n sock.on(\"error\", onError);\n sock.on(\"close\", onClose);\n sock.on(\"end\", onEnd);\n });\n}\n\nasync function connect(\n host: string,\n port: number,\n tlsOptions?: tls.ConnectionOptions,\n auth?: string,\n connectTimeoutMs?: number,\n): Promise<net.Socket> {\n const sock = await new Promise<net.Socket>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n let settled = false;\n\n // tls.connect() registers the callback on \"secureConnect\", not \"connect\".\n const connectEvent = tlsOptions ? \"secureConnect\" : \"connect\";\n\n const onConnect = () => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(\"error\", onError);\n resolve(s);\n };\n\n const onError = (err: Error) => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(err);\n };\n\n let s: net.Socket;\n if (tlsOptions) {\n s = tls.connect({ ...tlsOptions, host, port }, onConnect);\n } else {\n s = net.createConnection({ host, port }, onConnect);\n }\n s.on(\"error\", onError);\n\n if (connectTimeoutMs != null && connectTimeoutMs > 0) {\n timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n s.removeListener(\"error\", onError);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(\n new LockError(\n `connect timed out after ${connectTimeoutMs}ms to ${host}:${port}`,\n ),\n );\n }, connectTimeoutMs);\n }\n });\n\n // Disable Nagle's algorithm for lower latency on small lock commands.\n sock.setNoDelay(true);\n\n // Prevent unhandled 'error' events from crashing the process.\n // Errors are detected through readline's close handler.\n sock.on(\"error\", () => {});\n\n if (auth != null && auth !== \"\") {\n validateAuth(auth);\n let resp: string;\n try {\n await writeAll(sock, encodeLines(\"auth\", \"_\", auth));\n resp = await readline(sock);\n } catch (err) {\n sock.destroy();\n throw err;\n }\n if (resp === \"ok\") {\n return sock;\n }\n sock.destroy();\n if (resp === \"error_auth\") {\n throw new AuthError();\n }\n throw new LockError(`auth failed: '${resp}'`);\n }\n\n return sock;\n}\n\n// ---------------------------------------------------------------------------\n// CRC32 (same algorithm as Python's zlib.crc32)\n// ---------------------------------------------------------------------------\n\nconst CRC32_TABLE = new Uint32Array(256);\nfor (let i = 0; i < 256; i++) {\n let c = i;\n for (let j = 0; j < 8; j++) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n CRC32_TABLE[i] = c;\n}\n\nfunction crc32(buf: Buffer): number {\n let crc = 0xffffffff;\n for (let i = 0; i < buf.length; i++) {\n crc = CRC32_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n// ---------------------------------------------------------------------------\n// Sharding\n// ---------------------------------------------------------------------------\n\nexport type ShardingStrategy = (key: string, numServers: number) => number;\n\nexport function stableHashShard(key: string, numServers: number): number {\n if (numServers <= 0) {\n throw new LockError(\"numServers must be greater than 0\");\n }\n return crc32(Buffer.from(key, \"utf-8\")) % numServers;\n}\n\n// ---------------------------------------------------------------------------\n// Stats types\n// ---------------------------------------------------------------------------\n\nexport interface StatsLock {\n key: string;\n owner_conn_id: number;\n lease_expires_in_s: number;\n waiters: number;\n}\n\nexport interface StatsSemaphore {\n key: string;\n limit: number;\n holders: number;\n waiters: number;\n}\n\nexport interface StatsIdleLock {\n key: string;\n idle_s: number;\n}\n\nexport interface StatsIdleSemaphore {\n key: string;\n idle_s: number;\n}\n\nexport interface Stats {\n connections: number;\n locks: StatsLock[];\n semaphores: StatsSemaphore[];\n idle_locks: StatsIdleLock[];\n idle_semaphores: StatsIdleSemaphore[];\n}\n\n// ---------------------------------------------------------------------------\n// Protocol helpers (shared by lock and semaphore functions)\n// ---------------------------------------------------------------------------\n\nasync function protoAcquire(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n acquireTimeoutS: number,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [acquireTimeoutS];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRenew(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n leaseTtlS?: number,\n): Promise<number> {\n validateKey(key);\n validateToken(token);\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(cmd, key, arg));\n\n const resp = await readline(sock);\n if (resp !== \"ok\" && !resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n // Bare \"ok\" — server confirmed renewal but didn't echo the lease.\n if (resp === \"ok\") return leaseTtlS ?? 30;\n return parseLease(resp.split(\" \")[1]);\n}\n\nasync function protoEnqueue(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n validateKey(key);\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp.startsWith(\"acquired \")) {\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { status: \"acquired\", token, lease: parseLease(respParts[2]) };\n }\n if (resp === \"queued\") {\n return { status: \"queued\", token: null, lease: null };\n }\n throw new LockError(`${label} failed: '${resp}'`);\n}\n\nasync function protoWait(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(waitTimeoutS) || waitTimeoutS < 0) {\n throw new LockError(\"waitTimeoutS must be an integer >= 0\");\n }\n\n await writeAll(sock, encodeLines(cmd, key, String(waitTimeoutS)));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRelease(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n): Promise<void> {\n validateKey(key);\n validateToken(token);\n await writeAll(sock, encodeLines(cmd, key, token));\n\n const resp = await readline(sock);\n if (resp !== \"ok\") {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lock protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function acquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"l\", \"acquire\", key, acquireTimeoutS, leaseTtlS);\n}\n\nexport async function renew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"n\", \"renew\", key, token, leaseTtlS);\n}\n\nexport async function enqueue(\n sock: net.Socket, key: string, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"e\", \"enqueue\", key, leaseTtlS);\n}\n\nexport async function waitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"w\", \"wait\", key, waitTimeoutS);\n}\n\nexport async function release(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"r\", \"release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Semaphore protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function semAcquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, limit: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"sl\", \"sem_acquire\", key, acquireTimeoutS, leaseTtlS, limit);\n}\n\nexport async function semRenew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"sn\", \"sem_renew\", key, token, leaseTtlS);\n}\n\nexport async function semEnqueue(\n sock: net.Socket, key: string, limit: number, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"se\", \"sem_enqueue\", key, leaseTtlS, limit);\n}\n\nexport async function semWaitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"sw\", \"sem_wait\", key, waitTimeoutS);\n}\n\nexport async function semRelease(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"sr\", \"sem_release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Stats protocol function\n// ---------------------------------------------------------------------------\n\nasync function statsProto(sock: net.Socket): Promise<Stats> {\n await writeAll(sock, encodeLines(\"stats\", \"_\", \"\"));\n\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`stats failed: '${resp}'`);\n }\n\n const json = resp.slice(3);\n try {\n return JSON.parse(json) as Stats;\n } catch {\n throw new LockError(`stats: malformed JSON response: '${json}'`);\n }\n}\n\n/**\n * Query server runtime statistics.\n *\n * Opens a short-lived connection, sends the `stats` command, and returns\n * the parsed response.\n *\n * ```ts\n * const s = await stats();\n * console.log(s.connections, s.locks.length);\n * ```\n */\nexport async function stats(\n options?: {\n host?: string;\n port?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n connectTimeoutMs?: number;\n },\n): Promise<Stats> {\n const host = options?.host ?? DEFAULT_HOST;\n const port = options?.port ?? DEFAULT_PORT;\n const sock = await connect(host, port, options?.tls, options?.auth, options?.connectTimeoutMs);\n try {\n return await statsProto(sock);\n } finally {\n sock.destroy();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Option interfaces\n// ---------------------------------------------------------------------------\n\ninterface BaseOptions {\n key: string;\n acquireTimeoutS?: number;\n leaseTtlS?: number;\n /** @deprecated Use `servers` instead. */\n host?: string;\n /** @deprecated Use `servers` instead. */\n port?: number;\n servers?: Array<[host: string, port: number]>;\n shardingStrategy?: ShardingStrategy;\n renewRatio?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n onLockLost?: (key: string, token: string) => void;\n /** TCP connect timeout in milliseconds. Undefined means no timeout. */\n connectTimeoutMs?: number;\n /**\n * Socket idle timeout in milliseconds. If no data is received within this\n * period, the socket emits a 'timeout' event and is destroyed, causing any\n * pending `readline` to reject. Undefined means no timeout.\n */\n socketTimeoutMs?: number;\n}\n\nexport interface DistributedLockOptions extends BaseOptions {}\n\nexport interface DistributedSemaphoreOptions extends BaseOptions {\n limit: number;\n}\n\n// ---------------------------------------------------------------------------\n// Shared base class\n// ---------------------------------------------------------------------------\n\nabstract class DistributedPrimitive {\n readonly key: string;\n readonly acquireTimeoutS: number;\n readonly leaseTtlS: number | undefined;\n readonly servers: Array<[string, number]>;\n readonly shardingStrategy: ShardingStrategy;\n readonly renewRatio: number;\n readonly tls: tls.ConnectionOptions | undefined;\n readonly auth: string | undefined;\n readonly onLockLost: ((key: string, token: string) => void) | undefined;\n readonly connectTimeoutMs: number | undefined;\n readonly socketTimeoutMs: number | undefined;\n\n token: string | null = null;\n lease: number = 0;\n\n private sock: net.Socket | null = null;\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n private renewInFlight: Promise<void> | null = null;\n private closed = false;\n\n constructor(opts: BaseOptions) {\n validateKey(opts.key);\n this.key = opts.key;\n this.acquireTimeoutS = opts.acquireTimeoutS ?? 10;\n this.leaseTtlS = opts.leaseTtlS;\n this.tls = opts.tls;\n this.auth = opts.auth;\n this.onLockLost = opts.onLockLost;\n this.connectTimeoutMs = opts.connectTimeoutMs;\n this.socketTimeoutMs = opts.socketTimeoutMs;\n\n if (!Number.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n if (opts.servers) {\n if (opts.servers.length === 0) {\n throw new LockError(\"servers list must not be empty\");\n }\n this.servers = [...opts.servers];\n } else {\n this.servers = [[opts.host ?? DEFAULT_HOST, opts.port ?? DEFAULT_PORT]];\n }\n\n this.shardingStrategy = opts.shardingStrategy ?? stableHashShard;\n\n const renewRatio = opts.renewRatio ?? 0.5;\n if (!Number.isFinite(renewRatio) || renewRatio <= 0 || renewRatio >= 1) {\n throw new LockError(\"renewRatio must be a finite number between 0 and 1 (exclusive)\");\n }\n this.renewRatio = renewRatio;\n }\n\n // -- abstract protocol hooks (implemented by subclasses) --\n\n protected abstract doAcquire(\n sock: net.Socket,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doEnqueue(\n sock: net.Socket,\n ): Promise<{\n status: \"acquired\" | \"queued\";\n token: string | null;\n lease: number | null;\n }>;\n\n protected abstract doWait(\n sock: net.Socket,\n timeoutS: number,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doRelease(\n sock: net.Socket,\n token: string,\n ): Promise<void>;\n\n protected abstract doRenew(\n sock: net.Socket,\n token: string,\n ): Promise<number>;\n\n // -- public API --\n\n private async openConnection(): Promise<net.Socket> {\n const [host, port] = this.pickServer();\n const sock = await connect(host, port, this.tls, this.auth, this.connectTimeoutMs);\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n // Register the listener once; use setTimeout(ms)/setTimeout(0) to\n // toggle without accumulating duplicate listeners.\n sock.on(\"timeout\", () => {\n sock.destroy(new LockError(\"socket idle timeout\"));\n });\n sock.setTimeout(this.socketTimeoutMs);\n }\n return sock;\n }\n\n /**\n * Suspend or restore the socket idle timeout. Only has effect when\n * `socketTimeoutMs` was set at construction time and a listener was\n * registered in `openConnection`.\n */\n private suspendSocketTimeout(sock: net.Socket): void {\n sock.setTimeout(0);\n }\n\n private restoreSocketTimeout(sock: net.Socket): void {\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n sock.setTimeout(this.socketTimeoutMs);\n }\n }\n\n private pickServer(): [string, number] {\n const idx = this.shardingStrategy(this.key, this.servers.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= this.servers.length) {\n throw new LockError(\n `shardingStrategy returned invalid index ${idx} for ${this.servers.length} server(s)`,\n );\n }\n return this.servers[idx];\n }\n\n /**\n * Acquire the lock / semaphore slot.\n * Returns `true` on success, `false` on timeout.\n * @param opts.force - If `true`, silently close any existing connection\n * before acquiring. Defaults to `false`, which throws if already connected.\n */\n async acquire(opts?: { force?: boolean }): Promise<boolean> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n // Suspend socket idle timeout during the blocking acquire — the server\n // won't send data until the lock is granted or the acquire times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doAcquire(this.sock);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Release the lock / semaphore slot and close the connection.\n *\n * Throws `LockError` if the instance is already closed (e.g. after a\n * previous `release()` or `close()` call).\n *\n * The server-side release itself is best-effort: if the underlying\n * connection is already dead the protocol-level release error is silently\n * ignored so that the method doesn't throw on transient network failures.\n */\n async release(): Promise<void> {\n if (this.closed) {\n throw new LockError(\"not connected; nothing to release\");\n }\n // Capture the token and socket before awaiting anything — a concurrent\n // renew failure can set this.token/this.sock to null (via onLockLost →\n // close()), which would cause us to skip the server-side release and\n // leave the lock held until lease expiry.\n const tokenToRelease = this.token;\n const sockToRelease = this.sock;\n try {\n this.stopRenew();\n // Wait for any in-flight renew to finish before sending the release\n // command — concurrent reads/writes on the same socket are unsafe.\n // Bound the wait to 5s so release() doesn't hang forever when the\n // network is unresponsive and no socketTimeoutMs is configured.\n if (this.renewInFlight) {\n await Promise.race([\n this.renewInFlight,\n new Promise<void>((r) => setTimeout(r, 5000).unref()),\n ]);\n // The loop resumes before us (it registered its .then first) and may\n // have scheduled a new timer. Clear it so it cannot fire during\n // doRelease below.\n this.stopRenew();\n }\n if (sockToRelease != null && tokenToRelease != null) {\n try {\n await this.doRelease(sockToRelease, tokenToRelease);\n } catch {\n // Best-effort: connection may already be dead.\n }\n }\n } finally {\n this.close();\n }\n }\n\n /**\n * Two-phase step 1: connect and join the FIFO queue.\n * Returns `\"acquired\"` (fast-path) or `\"queued\"`.\n * If acquired immediately, the renew loop starts automatically.\n * @param opts.force - If `true`, silently close any existing connection\n * before enqueuing. Defaults to `false`, which throws if already connected.\n */\n async enqueue(opts?: { force?: boolean }): Promise<\"acquired\" | \"queued\"> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n this.suspendSocketTimeout(this.sock);\n const result = await this.doEnqueue(this.sock);\n if (result.status === \"acquired\") {\n this.token = result.token;\n this.lease = result.lease ?? 0;\n this.restoreSocketTimeout(this.sock);\n this.startRenew();\n }\n return result.status;\n } catch (err) {\n this.close();\n throw err;\n }\n }\n\n /**\n * Two-phase step 2: block until the lock / slot is granted.\n * Returns `true` if granted, `false` on timeout.\n * If already acquired during `enqueue()`, returns `true` immediately.\n */\n async wait(timeoutS?: number): Promise<boolean> {\n if (this.token !== null) {\n // Already acquired during enqueue (fast path)\n return true;\n }\n if (this.closed) {\n throw new LockError(\"connection closed; call enqueue() again\");\n }\n if (!this.sock) {\n throw new LockError(\"not connected; call enqueue() first\");\n }\n const timeout = timeoutS ?? this.acquireTimeoutS;\n try {\n // Suspend socket idle timeout during the blocking wait — the server\n // won't send data until the lock/slot is granted or the wait times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doWait(this.sock, timeout);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Run `fn` while holding the lock / slot, then release automatically.\n *\n * If `fn()` throws, its error is always preserved — a concurrent\n * release failure will not mask it.\n */\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n const ok = await this.acquire();\n if (!ok) {\n throw new AcquireTimeoutError(this.key);\n }\n let threw = false;\n try {\n return await fn();\n } catch (err) {\n threw = true;\n throw err;\n } finally {\n try {\n await this.release();\n } catch (releaseErr) {\n // If fn() already threw, swallow the release error so it\n // doesn't mask the original error.\n if (!threw) throw releaseErr;\n }\n }\n }\n\n /** Close the underlying socket (idempotent). */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopRenew();\n this.renewInFlight = null;\n if (this.sock) {\n this.sock.destroy();\n this.sock = null;\n }\n this.token = null;\n this.lease = 0;\n }\n\n // -- internals --\n\n private startRenew(): void {\n this.stopRenew();\n const loop = async () => {\n const savedToken = this.token;\n const sock = this.sock;\n if (!sock || !savedToken) return;\n const start = Date.now();\n const p = (async () => {\n try {\n const newLease = await this.doRenew(sock, savedToken);\n // Guard: if close() ran while the renew was in-flight, don't\n // clobber the reset state (lease=0, token=null).\n if (this.token === savedToken && !this.closed) {\n this.lease = newLease;\n }\n } catch {\n // Only signal lock-lost if we still own this token (close() may have cleared it)\n if (this.token === savedToken) {\n this.token = null;\n if (this.onLockLost) {\n try {\n // Cast to unknown: the declared return type is void, but an\n // async callback will return a Promise at runtime.\n const result: unknown = this.onLockLost(this.key, savedToken);\n // Guard against async callbacks returning a rejected Promise.\n if (result instanceof Promise) {\n result.catch(() => {});\n }\n } catch {\n // Never let a user callback crash the process.\n }\n }\n // Tear down the connection so the instance is in a clean state\n // for re-acquisition. Without this the socket leaks and a\n // subsequent acquire() without { force: true } would throw\n // \"already connected\".\n this.close();\n }\n return;\n }\n })();\n this.renewInFlight = p;\n await p;\n this.renewInFlight = null;\n // Guard: if close() was called while the renew was in-flight, don't\n // schedule another iteration (avoids clobbering a new acquire's timer).\n if (this.closed || this.token !== savedToken) return;\n const elapsed = Date.now() - start;\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, Math.max(0, interval - elapsed));\n this.renewTimer.unref();\n };\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, interval);\n this.renewTimer.unref();\n }\n\n private stopRenew(): void {\n if (this.renewTimer != null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedLock\n// ---------------------------------------------------------------------------\n\nexport class DistributedLock extends DistributedPrimitive {\n constructor(opts: DistributedLockOptions) {\n super(opts);\n }\n\n protected doAcquire(sock: net.Socket) {\n return acquire(sock, this.key, this.acquireTimeoutS, this.leaseTtlS);\n }\n\n protected doEnqueue(sock: net.Socket) {\n return enqueue(sock, this.key, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return waitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return release(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return renew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedSemaphore\n// ---------------------------------------------------------------------------\n\nexport class DistributedSemaphore extends DistributedPrimitive {\n readonly limit: number;\n\n constructor(opts: DistributedSemaphoreOptions) {\n super(opts);\n if (!Number.isInteger(opts.limit) || opts.limit < 1) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n this.limit = opts.limit;\n }\n\n protected doAcquire(sock: net.Socket) {\n return semAcquire(\n sock,\n this.key,\n this.acquireTimeoutS,\n this.limit,\n this.leaseTtlS,\n );\n }\n\n protected doEnqueue(sock: net.Socket) {\n return semEnqueue(sock, this.key, this.limit, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return semWaitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return semRelease(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return semRenew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Signal types\n// ---------------------------------------------------------------------------\n\nexport interface Signal {\n channel: string;\n payload: string;\n}\n\n// ---------------------------------------------------------------------------\n// Signal protocol functions\n// ---------------------------------------------------------------------------\n\nfunction validatePayload(payload: string): void {\n if (payload === \"\") {\n throw new LockError(\"payload must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(payload)) {\n throw new LockError(\n \"payload must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n/**\n * Publish a signal on a channel using a regular socket (request-response).\n * Returns the number of listeners that received the signal.\n *\n * Use this when you only need to publish and don't need to receive signals.\n * For subscribing to signals, use `SignalConnection`.\n */\nexport async function publish(\n sock: net.Socket,\n channel: string,\n payload: string,\n): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n await writeAll(sock, encodeLines(\"signal\", channel, payload));\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n}\n\n// ---------------------------------------------------------------------------\n// SignalConnection\n// ---------------------------------------------------------------------------\n\nexport interface SignalConnectionOptions {\n /** Server host (default `\"127.0.0.1\"`). */\n host?: string;\n /** Server port (default `6388`). */\n port?: number;\n /** TLS options; pass `{}` for default system CA. */\n tls?: tls.ConnectionOptions;\n /** Auth token for servers started with `--auth-token`. */\n auth?: string;\n /** TCP connect timeout in milliseconds. */\n connectTimeoutMs?: number;\n}\n\n/**\n * A connection dedicated to the signal (pub/sub) protocol.\n *\n * Wraps a socket with a background line reader that separates asynchronous\n * `sig` push messages from command responses, allowing `listen`, `unlisten`,\n * and `emit` to be called while signals are being delivered.\n *\n * ```ts\n * const conn = await SignalConnection.connect();\n * conn.onSignal((sig) => console.log(sig.channel, sig.payload));\n * await conn.listen(\"events.>\");\n * ```\n */\nexport class SignalConnection {\n private sock: net.Socket;\n private buf = \"\";\n private responseResolve: ((line: string) => void) | null = null;\n private responseReject: ((err: Error) => void) | null = null;\n private cmdQueue: Array<() => void> = [];\n private cmdBusy = false;\n private signalListeners: Array<(signal: Signal) => void> = [];\n private _closed = false;\n\n /**\n * Wrap an existing socket as a SignalConnection.\n *\n * The socket should already be connected (and authenticated, if needed).\n * Prefer `SignalConnection.connect()` for convenience.\n */\n constructor(sock: net.Socket) {\n this.sock = sock;\n\n // Drain any leftover buffer from the global readline WeakMap.\n const leftover = _readlineBuf.get(sock);\n if (leftover) {\n this.buf = leftover;\n _readlineBuf.delete(sock);\n }\n\n sock.on(\"data\", (chunk: Buffer) => this.onData(chunk));\n sock.on(\"error\", (err: Error) => this.onSocketError(err));\n sock.on(\"close\", () => this.onSocketEnd());\n sock.on(\"end\", () => this.onSocketEnd());\n\n // Process any lines already buffered.\n this.drainLines();\n }\n\n /** Connect to a dflockd server and return a SignalConnection. */\n static async connect(\n opts?: SignalConnectionOptions,\n ): Promise<SignalConnection> {\n const host = opts?.host ?? DEFAULT_HOST;\n const port = opts?.port ?? DEFAULT_PORT;\n const sock = await connect(\n host,\n port,\n opts?.tls,\n opts?.auth,\n opts?.connectTimeoutMs,\n );\n return new SignalConnection(sock);\n }\n\n /**\n * Subscribe to signals matching `pattern`.\n *\n * Patterns support NATS-style wildcards:\n * - `*` matches exactly one dot-separated token\n * - `>` matches one or more trailing tokens\n *\n * If `group` is provided, the subscription joins a queue group where\n * signals are load-balanced (round-robin) among group members.\n */\n async listen(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"listen\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`listen failed: '${resp}'`);\n }\n }\n\n /**\n * Unsubscribe from signals matching `pattern`.\n * The `pattern` and `group` must match a previous `listen()` call.\n */\n async unlisten(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"unlisten\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`unlisten failed: '${resp}'`);\n }\n }\n\n /**\n * Publish a signal on a literal channel (no wildcards).\n * Returns the number of listeners that received the signal.\n */\n async emit(channel: string, payload: string): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n const resp = await this.sendCmd(\"signal\", channel, payload);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n }\n\n /** Register a listener for incoming signals. */\n onSignal(listener: (signal: Signal) => void): void {\n this.signalListeners.push(listener);\n }\n\n /** Remove a previously registered signal listener. */\n offSignal(listener: (signal: Signal) => void): void {\n const idx = this.signalListeners.indexOf(listener);\n if (idx >= 0) this.signalListeners.splice(idx, 1);\n }\n\n /**\n * Async iterator that yields signals as they arrive.\n * Terminates when the connection closes.\n *\n * ```ts\n * for await (const sig of conn) {\n * console.log(sig.channel, sig.payload);\n * }\n * ```\n */\n async *[Symbol.asyncIterator](): AsyncIterableIterator<Signal> {\n const buffer: Signal[] = [];\n let waiter: (() => void) | null = null;\n\n const listener = (sig: Signal) => {\n buffer.push(sig);\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n const onEnd = () => {\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n this.onSignal(listener);\n this.sock.once(\"close\", onEnd);\n\n try {\n while (true) {\n if (buffer.length > 0) {\n yield buffer.shift()!;\n continue;\n }\n if (this._closed) break;\n await new Promise<void>((resolve) => {\n waiter = resolve;\n });\n }\n // Drain any remaining buffered signals.\n while (buffer.length > 0) {\n yield buffer.shift()!;\n }\n } finally {\n this.offSignal(listener);\n this.sock.removeListener(\"close\", onEnd);\n }\n }\n\n /** Close the connection (idempotent). */\n close(): void {\n if (this._closed) return;\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(new LockError(\"connection closed\"));\n }\n\n /** Whether the connection is closed. */\n get isClosed(): boolean {\n return this._closed;\n }\n\n // ---- internals ----\n\n private onData(chunk: Buffer): void {\n this.buf += chunk.toString(\"utf-8\");\n if (this.buf.length > MAX_LINE_LENGTH * 2) {\n this.buf = \"\";\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(\n new LockError(\"server response exceeded maximum buffer size\"),\n );\n return;\n }\n this.drainLines();\n }\n\n private drainLines(): void {\n let idx: number;\n while ((idx = this.buf.indexOf(\"\\n\")) !== -1) {\n const line = this.buf.slice(0, idx).replace(/\\r$/, \"\");\n this.buf = this.buf.slice(idx + 1);\n this.handleLine(line);\n }\n }\n\n private handleLine(line: string): void {\n if (line.startsWith(\"sig \")) {\n const rest = line.slice(4);\n const spaceIdx = rest.indexOf(\" \");\n if (spaceIdx < 0) return; // malformed push, skip\n const sig: Signal = {\n channel: rest.slice(0, spaceIdx),\n payload: rest.slice(spaceIdx + 1),\n };\n for (const listener of [...this.signalListeners]) {\n try {\n listener(sig);\n } catch {\n // Never let a user callback crash the read loop.\n }\n }\n return;\n }\n // Command response.\n if (this.responseResolve) {\n const resolve = this.responseResolve;\n this.responseResolve = null;\n this.responseReject = null;\n resolve(line);\n }\n }\n\n private onSocketError(err: Error): void {\n this._closed = true;\n this.rejectPending(err);\n }\n\n private onSocketEnd(): void {\n this._closed = true;\n this.rejectPending(new LockError(\"server closed connection\"));\n }\n\n private rejectPending(err: Error): void {\n if (this.responseReject) {\n const reject = this.responseReject;\n this.responseResolve = null;\n this.responseReject = null;\n reject(err);\n }\n }\n\n private sendCmd(cmd: string, key: string, arg: string): Promise<string> {\n return new Promise<string>((outerResolve, outerReject) => {\n const execute = () => {\n if (this._closed) {\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(new LockError(\"connection closed\"));\n return;\n }\n let settled = false;\n this.responseResolve = (line: string) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerResolve(line);\n };\n this.responseReject = (err: Error) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n };\n this.sock.write(encodeLines(cmd, key, arg), (err) => {\n if (err && !settled) {\n settled = true;\n this.responseResolve = null;\n this.responseReject = null;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n }\n });\n };\n\n if (this.cmdBusy) {\n this.cmdQueue.push(execute);\n } else {\n this.cmdBusy = true;\n execute();\n }\n });\n }\n\n private dequeueNext(): void {\n const next = this.cmdQueue.shift();\n if (next) {\n this.cmdBusy = true;\n next();\n }\n }\n}\n"],"mappings":"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","names":["connect","interval"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import * as net from \"net\";\nimport { StringDecoder } from \"string_decoder\";\nimport * as tls from \"tls\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 6388;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class LockError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LockError\";\n }\n}\n\nexport class AcquireTimeoutError extends LockError {\n constructor(key: string) {\n super(`timeout acquiring '${key}'`);\n this.name = \"AcquireTimeoutError\";\n }\n}\n\nexport class AuthError extends LockError {\n constructor() {\n super(\"authentication failed\");\n this.name = \"AuthError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nfunction validateKey(key: string): void {\n if (key === \"\") {\n throw new LockError(\"key must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(key)) {\n throw new LockError(\n \"key must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateAuth(auth: string): void {\n if (/[\\0\\n\\r]/.test(auth)) {\n throw new LockError(\n \"auth token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateToken(token: string): void {\n if (token === \"\") {\n throw new LockError(\"token must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(token)) {\n throw new LockError(\n \"token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Low-level helpers\n// ---------------------------------------------------------------------------\n\nfunction encodeLines(...lines: string[]): Buffer {\n return Buffer.from(lines.map((l) => l + \"\\n\").join(\"\"), \"utf-8\");\n}\n\nfunction writeAll(sock: net.Socket, data: Buffer): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n sock.write(data, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Parse a lease value from a server response part.\n * Returns `fallback` when the value is missing, empty, or non-numeric.\n */\nfunction parseLease(value: string | undefined, fallback: number = 30): number {\n if (value == null || value === \"\") return fallback;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? n : fallback;\n}\n\n/**\n * Read one newline-terminated line from the socket.\n * Resolves with the line (without trailing \\r\\n).\n * Rejects if the connection closes before a full line arrives.\n *\n * NOTE: Concurrent calls to readline() on the same socket are unsafe —\n * callers must serialize reads (the request-response protocol naturally\n * enforces this).\n */\nconst _readlineBuf = new WeakMap<net.Socket, string>();\nconst _readlineDecoder = new WeakMap<net.Socket, StringDecoder>();\nconst MAX_LINE_LENGTH = 1024 * 1024; // 1 MB\n\nfunction readline(sock: net.Socket): Promise<string> {\n return new Promise((resolve, reject) => {\n let buf = _readlineBuf.get(sock) ?? \"\";\n\n // Check if a complete line is already buffered from a previous read.\n const existing = buf.indexOf(\"\\n\");\n if (existing !== -1) {\n const line = buf.slice(0, existing).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(existing + 1));\n resolve(line);\n return;\n }\n\n // Use a StringDecoder to correctly handle multi-byte UTF-8 characters\n // that may be split across TCP segment boundaries.\n let decoder = _readlineDecoder.get(sock);\n if (!decoder) {\n decoder = new StringDecoder(\"utf8\");\n _readlineDecoder.set(sock, decoder);\n }\n const dec = decoder;\n\n const onData = (chunk: Buffer) => {\n buf += dec.write(chunk);\n const idx = buf.indexOf(\"\\n\");\n if (idx !== -1) {\n cleanup();\n const line = buf.slice(0, idx).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(idx + 1));\n resolve(line);\n } else if (buf.length > MAX_LINE_LENGTH) {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server response exceeded maximum line length\"));\n }\n };\n\n const onError = (err: Error) => {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const onEnd = () => {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const cleanup = () => {\n sock.removeListener(\"data\", onData);\n sock.removeListener(\"error\", onError);\n sock.removeListener(\"close\", onClose);\n sock.removeListener(\"end\", onEnd);\n };\n\n // If the readable side already ended (e.g. the server closed before we\n // started reading), the 'end'/'close' events won't fire again.\n if (sock.readableEnded || sock.destroyed) {\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server closed connection\"));\n return;\n }\n\n sock.on(\"data\", onData);\n sock.on(\"error\", onError);\n sock.on(\"close\", onClose);\n sock.on(\"end\", onEnd);\n });\n}\n\nasync function connect(\n host: string,\n port: number,\n tlsOptions?: tls.ConnectionOptions,\n auth?: string,\n connectTimeoutMs?: number,\n): Promise<net.Socket> {\n const sock = await new Promise<net.Socket>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n let settled = false;\n\n // tls.connect() registers the callback on \"secureConnect\", not \"connect\".\n const connectEvent = tlsOptions ? \"secureConnect\" : \"connect\";\n\n const onConnect = () => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(\"error\", onError);\n resolve(s);\n };\n\n const onError = (err: Error) => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(err);\n };\n\n let s: net.Socket;\n if (tlsOptions) {\n s = tls.connect({ ...tlsOptions, host, port }, onConnect);\n } else {\n s = net.createConnection({ host, port }, onConnect);\n }\n s.on(\"error\", onError);\n\n if (connectTimeoutMs != null && connectTimeoutMs > 0) {\n timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n s.removeListener(\"error\", onError);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(\n new LockError(\n `connect timed out after ${connectTimeoutMs}ms to ${host}:${port}`,\n ),\n );\n }, connectTimeoutMs);\n }\n });\n\n // Disable Nagle's algorithm for lower latency on small lock commands.\n sock.setNoDelay(true);\n\n // Prevent unhandled 'error' events from crashing the process.\n // Errors are detected through readline's close handler.\n sock.on(\"error\", () => {});\n\n if (auth != null && auth !== \"\") {\n validateAuth(auth);\n let resp: string;\n try {\n await writeAll(sock, encodeLines(\"auth\", \"_\", auth));\n resp = await readline(sock);\n } catch (err) {\n sock.destroy();\n throw err;\n }\n if (resp === \"ok\") {\n return sock;\n }\n sock.destroy();\n if (resp === \"error_auth\") {\n throw new AuthError();\n }\n throw new LockError(`auth failed: '${resp}'`);\n }\n\n return sock;\n}\n\n// ---------------------------------------------------------------------------\n// CRC32 (same algorithm as Python's zlib.crc32)\n// ---------------------------------------------------------------------------\n\nconst CRC32_TABLE = new Uint32Array(256);\nfor (let i = 0; i < 256; i++) {\n let c = i;\n for (let j = 0; j < 8; j++) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n CRC32_TABLE[i] = c;\n}\n\nfunction crc32(buf: Buffer): number {\n let crc = 0xffffffff;\n for (let i = 0; i < buf.length; i++) {\n crc = CRC32_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n// ---------------------------------------------------------------------------\n// Sharding\n// ---------------------------------------------------------------------------\n\nexport type ShardingStrategy = (key: string, numServers: number) => number;\n\nexport function stableHashShard(key: string, numServers: number): number {\n if (numServers <= 0) {\n throw new LockError(\"numServers must be greater than 0\");\n }\n return crc32(Buffer.from(key, \"utf-8\")) % numServers;\n}\n\n// ---------------------------------------------------------------------------\n// Stats types\n// ---------------------------------------------------------------------------\n\nexport interface StatsLock {\n key: string;\n owner_conn_id: number;\n lease_expires_in_s: number;\n waiters: number;\n}\n\nexport interface StatsSemaphore {\n key: string;\n limit: number;\n holders: number;\n waiters: number;\n}\n\nexport interface StatsIdleLock {\n key: string;\n idle_s: number;\n}\n\nexport interface StatsIdleSemaphore {\n key: string;\n idle_s: number;\n}\n\nexport interface Stats {\n connections: number;\n locks: StatsLock[];\n semaphores: StatsSemaphore[];\n idle_locks: StatsIdleLock[];\n idle_semaphores: StatsIdleSemaphore[];\n}\n\n// ---------------------------------------------------------------------------\n// Protocol helpers (shared by lock and semaphore functions)\n// ---------------------------------------------------------------------------\n\nasync function protoAcquire(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n acquireTimeoutS: number,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [acquireTimeoutS];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRenew(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n leaseTtlS?: number,\n): Promise<number> {\n validateKey(key);\n validateToken(token);\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(cmd, key, arg));\n\n const resp = await readline(sock);\n if (resp !== \"ok\" && !resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n // Bare \"ok\" — server confirmed renewal but didn't echo the lease.\n if (resp === \"ok\") return leaseTtlS ?? 30;\n return parseLease(resp.split(\" \")[1]);\n}\n\nasync function protoEnqueue(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n validateKey(key);\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp.startsWith(\"acquired \")) {\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { status: \"acquired\", token, lease: parseLease(respParts[2]) };\n }\n if (resp === \"queued\") {\n return { status: \"queued\", token: null, lease: null };\n }\n throw new LockError(`${label} failed: '${resp}'`);\n}\n\nasync function protoWait(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(waitTimeoutS) || waitTimeoutS < 0) {\n throw new LockError(\"waitTimeoutS must be an integer >= 0\");\n }\n\n await writeAll(sock, encodeLines(cmd, key, String(waitTimeoutS)));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRelease(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n): Promise<void> {\n validateKey(key);\n validateToken(token);\n await writeAll(sock, encodeLines(cmd, key, token));\n\n const resp = await readline(sock);\n if (resp !== \"ok\") {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lock protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function acquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"l\", \"acquire\", key, acquireTimeoutS, leaseTtlS);\n}\n\nexport async function renew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"n\", \"renew\", key, token, leaseTtlS);\n}\n\nexport async function enqueue(\n sock: net.Socket, key: string, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"e\", \"enqueue\", key, leaseTtlS);\n}\n\nexport async function waitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"w\", \"wait\", key, waitTimeoutS);\n}\n\nexport async function release(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"r\", \"release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Semaphore protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function semAcquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, limit: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"sl\", \"sem_acquire\", key, acquireTimeoutS, leaseTtlS, limit);\n}\n\nexport async function semRenew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"sn\", \"sem_renew\", key, token, leaseTtlS);\n}\n\nexport async function semEnqueue(\n sock: net.Socket, key: string, limit: number, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"se\", \"sem_enqueue\", key, leaseTtlS, limit);\n}\n\nexport async function semWaitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"sw\", \"sem_wait\", key, waitTimeoutS);\n}\n\nexport async function semRelease(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"sr\", \"sem_release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Stats protocol function\n// ---------------------------------------------------------------------------\n\nasync function statsProto(sock: net.Socket): Promise<Stats> {\n await writeAll(sock, encodeLines(\"stats\", \"_\", \"\"));\n\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`stats failed: '${resp}'`);\n }\n\n const json = resp.slice(3);\n try {\n return JSON.parse(json) as Stats;\n } catch {\n throw new LockError(`stats: malformed JSON response: '${json}'`);\n }\n}\n\n/**\n * Query server runtime statistics.\n *\n * Opens a short-lived connection, sends the `stats` command, and returns\n * the parsed response.\n *\n * ```ts\n * const s = await stats();\n * console.log(s.connections, s.locks.length);\n * ```\n */\nexport async function stats(\n options?: {\n host?: string;\n port?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n connectTimeoutMs?: number;\n },\n): Promise<Stats> {\n const host = options?.host ?? DEFAULT_HOST;\n const port = options?.port ?? DEFAULT_PORT;\n const sock = await connect(host, port, options?.tls, options?.auth, options?.connectTimeoutMs);\n try {\n return await statsProto(sock);\n } finally {\n sock.destroy();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Option interfaces\n// ---------------------------------------------------------------------------\n\ninterface BaseOptions {\n key: string;\n acquireTimeoutS?: number;\n leaseTtlS?: number;\n /** @deprecated Use `servers` instead. */\n host?: string;\n /** @deprecated Use `servers` instead. */\n port?: number;\n servers?: Array<[host: string, port: number]>;\n shardingStrategy?: ShardingStrategy;\n renewRatio?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n onLockLost?: (key: string, token: string) => void;\n /** TCP connect timeout in milliseconds. Undefined means no timeout. */\n connectTimeoutMs?: number;\n /**\n * Socket idle timeout in milliseconds. If no data is received within this\n * period, the socket emits a 'timeout' event and is destroyed, causing any\n * pending `readline` to reject. Undefined means no timeout.\n */\n socketTimeoutMs?: number;\n}\n\nexport interface DistributedLockOptions extends BaseOptions {}\n\nexport interface DistributedSemaphoreOptions extends BaseOptions {\n limit: number;\n}\n\n// ---------------------------------------------------------------------------\n// Shared base class\n// ---------------------------------------------------------------------------\n\nabstract class DistributedPrimitive {\n readonly key: string;\n readonly acquireTimeoutS: number;\n readonly leaseTtlS: number | undefined;\n readonly servers: Array<[string, number]>;\n readonly shardingStrategy: ShardingStrategy;\n readonly renewRatio: number;\n readonly tls: tls.ConnectionOptions | undefined;\n readonly auth: string | undefined;\n readonly onLockLost: ((key: string, token: string) => void) | undefined;\n readonly connectTimeoutMs: number | undefined;\n readonly socketTimeoutMs: number | undefined;\n\n token: string | null = null;\n lease: number = 0;\n\n private sock: net.Socket | null = null;\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n private renewInFlight: Promise<void> | null = null;\n private closed = false;\n\n constructor(opts: BaseOptions) {\n validateKey(opts.key);\n this.key = opts.key;\n this.acquireTimeoutS = opts.acquireTimeoutS ?? 10;\n this.leaseTtlS = opts.leaseTtlS;\n this.tls = opts.tls;\n this.auth = opts.auth;\n this.onLockLost = opts.onLockLost;\n this.connectTimeoutMs = opts.connectTimeoutMs;\n this.socketTimeoutMs = opts.socketTimeoutMs;\n\n if (!Number.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n if (opts.servers) {\n if (opts.servers.length === 0) {\n throw new LockError(\"servers list must not be empty\");\n }\n this.servers = [...opts.servers];\n } else {\n this.servers = [[opts.host ?? DEFAULT_HOST, opts.port ?? DEFAULT_PORT]];\n }\n\n this.shardingStrategy = opts.shardingStrategy ?? stableHashShard;\n\n const renewRatio = opts.renewRatio ?? 0.5;\n if (!Number.isFinite(renewRatio) || renewRatio <= 0 || renewRatio >= 1) {\n throw new LockError(\"renewRatio must be a finite number between 0 and 1 (exclusive)\");\n }\n this.renewRatio = renewRatio;\n }\n\n // -- abstract protocol hooks (implemented by subclasses) --\n\n protected abstract doAcquire(\n sock: net.Socket,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doEnqueue(\n sock: net.Socket,\n ): Promise<{\n status: \"acquired\" | \"queued\";\n token: string | null;\n lease: number | null;\n }>;\n\n protected abstract doWait(\n sock: net.Socket,\n timeoutS: number,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doRelease(\n sock: net.Socket,\n token: string,\n ): Promise<void>;\n\n protected abstract doRenew(\n sock: net.Socket,\n token: string,\n ): Promise<number>;\n\n // -- public API --\n\n private async openConnection(): Promise<net.Socket> {\n const [host, port] = this.pickServer();\n const sock = await connect(host, port, this.tls, this.auth, this.connectTimeoutMs);\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n // Register the listener once; use setTimeout(ms)/setTimeout(0) to\n // toggle without accumulating duplicate listeners.\n sock.on(\"timeout\", () => {\n sock.destroy(new LockError(\"socket idle timeout\"));\n });\n sock.setTimeout(this.socketTimeoutMs);\n }\n return sock;\n }\n\n /**\n * Suspend or restore the socket idle timeout. Only has effect when\n * `socketTimeoutMs` was set at construction time and a listener was\n * registered in `openConnection`.\n */\n private suspendSocketTimeout(sock: net.Socket): void {\n sock.setTimeout(0);\n }\n\n private restoreSocketTimeout(sock: net.Socket): void {\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n sock.setTimeout(this.socketTimeoutMs);\n }\n }\n\n private pickServer(): [string, number] {\n const idx = this.shardingStrategy(this.key, this.servers.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= this.servers.length) {\n throw new LockError(\n `shardingStrategy returned invalid index ${idx} for ${this.servers.length} server(s)`,\n );\n }\n return this.servers[idx];\n }\n\n /**\n * Acquire the lock / semaphore slot.\n * Returns `true` on success, `false` on timeout.\n * @param opts.force - If `true`, silently close any existing connection\n * before acquiring. Defaults to `false`, which throws if already connected.\n */\n async acquire(opts?: { force?: boolean }): Promise<boolean> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n // Suspend socket idle timeout during the blocking acquire — the server\n // won't send data until the lock is granted or the acquire times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doAcquire(this.sock);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Release the lock / semaphore slot and close the connection.\n *\n * Throws `LockError` if the instance is already closed (e.g. after a\n * previous `release()` or `close()` call).\n *\n * The server-side release itself is best-effort: if the underlying\n * connection is already dead the protocol-level release error is silently\n * ignored so that the method doesn't throw on transient network failures.\n */\n async release(): Promise<void> {\n if (this.closed) {\n throw new LockError(\"not connected; nothing to release\");\n }\n // Capture the token and socket before awaiting anything — a concurrent\n // renew failure can set this.token/this.sock to null (via onLockLost →\n // close()), which would cause us to skip the server-side release and\n // leave the lock held until lease expiry.\n const tokenToRelease = this.token;\n const sockToRelease = this.sock;\n try {\n this.stopRenew();\n // Wait for any in-flight renew to finish before sending the release\n // command — concurrent reads/writes on the same socket are unsafe.\n // Bound the wait to 5s so release() doesn't hang forever when the\n // network is unresponsive and no socketTimeoutMs is configured.\n if (this.renewInFlight) {\n await Promise.race([\n this.renewInFlight,\n new Promise<void>((r) => setTimeout(r, 5000).unref()),\n ]);\n // The loop resumes before us (it registered its .then first) and may\n // have scheduled a new timer. Clear it so it cannot fire during\n // doRelease below.\n this.stopRenew();\n }\n if (sockToRelease != null && tokenToRelease != null) {\n try {\n await this.doRelease(sockToRelease, tokenToRelease);\n } catch {\n // Best-effort: connection may already be dead.\n }\n }\n } finally {\n this.close();\n }\n }\n\n /**\n * Two-phase step 1: connect and join the FIFO queue.\n * Returns `\"acquired\"` (fast-path) or `\"queued\"`.\n * If acquired immediately, the renew loop starts automatically.\n * @param opts.force - If `true`, silently close any existing connection\n * before enqueuing. Defaults to `false`, which throws if already connected.\n */\n async enqueue(opts?: { force?: boolean }): Promise<\"acquired\" | \"queued\"> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n this.suspendSocketTimeout(this.sock);\n const result = await this.doEnqueue(this.sock);\n if (result.status === \"acquired\") {\n this.token = result.token;\n this.lease = result.lease ?? 0;\n this.restoreSocketTimeout(this.sock);\n this.startRenew();\n }\n return result.status;\n } catch (err) {\n this.close();\n throw err;\n }\n }\n\n /**\n * Two-phase step 2: block until the lock / slot is granted.\n * Returns `true` if granted, `false` on timeout.\n * If already acquired during `enqueue()`, returns `true` immediately.\n */\n async wait(timeoutS?: number): Promise<boolean> {\n if (this.token !== null) {\n // Already acquired during enqueue (fast path)\n return true;\n }\n if (this.closed) {\n throw new LockError(\"connection closed; call enqueue() again\");\n }\n if (!this.sock) {\n throw new LockError(\"not connected; call enqueue() first\");\n }\n const timeout = timeoutS ?? this.acquireTimeoutS;\n try {\n // Suspend socket idle timeout during the blocking wait — the server\n // won't send data until the lock/slot is granted or the wait times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doWait(this.sock, timeout);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Run `fn` while holding the lock / slot, then release automatically.\n *\n * If `fn()` throws, its error is always preserved — a concurrent\n * release failure will not mask it.\n */\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n const ok = await this.acquire();\n if (!ok) {\n throw new AcquireTimeoutError(this.key);\n }\n let threw = false;\n try {\n return await fn();\n } catch (err) {\n threw = true;\n throw err;\n } finally {\n try {\n await this.release();\n } catch (releaseErr) {\n // If fn() already threw, swallow the release error so it\n // doesn't mask the original error.\n if (!threw) throw releaseErr;\n }\n }\n }\n\n /** Close the underlying socket (idempotent). */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopRenew();\n this.renewInFlight = null;\n if (this.sock) {\n this.sock.destroy();\n this.sock = null;\n }\n this.token = null;\n this.lease = 0;\n }\n\n // -- internals --\n\n private startRenew(): void {\n this.stopRenew();\n const loop = async () => {\n const savedToken = this.token;\n const sock = this.sock;\n if (!sock || !savedToken) return;\n const start = Date.now();\n const p = (async () => {\n try {\n const newLease = await this.doRenew(sock, savedToken);\n // Guard: if close() ran while the renew was in-flight, don't\n // clobber the reset state (lease=0, token=null).\n if (this.token === savedToken && !this.closed) {\n this.lease = newLease;\n }\n } catch {\n // Only signal lock-lost if we still own this token (close() may have cleared it)\n if (this.token === savedToken) {\n this.token = null;\n if (this.onLockLost) {\n try {\n // Cast to unknown: the declared return type is void, but an\n // async callback will return a Promise at runtime.\n const result: unknown = this.onLockLost(this.key, savedToken);\n // Guard against async callbacks returning a rejected Promise.\n if (result instanceof Promise) {\n result.catch(() => {});\n }\n } catch {\n // Never let a user callback crash the process.\n }\n }\n // Tear down the connection so the instance is in a clean state\n // for re-acquisition. Without this the socket leaks and a\n // subsequent acquire() without { force: true } would throw\n // \"already connected\".\n this.close();\n }\n return;\n }\n })();\n this.renewInFlight = p;\n await p;\n this.renewInFlight = null;\n // Guard: if close() was called while the renew was in-flight, don't\n // schedule another iteration (avoids clobbering a new acquire's timer).\n if (this.closed || this.token !== savedToken) return;\n const elapsed = Date.now() - start;\n const interval = Math.max(0.1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, Math.max(0, interval - elapsed));\n this.renewTimer.unref();\n };\n const interval = Math.max(0.1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, interval);\n this.renewTimer.unref();\n }\n\n private stopRenew(): void {\n if (this.renewTimer != null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedLock\n// ---------------------------------------------------------------------------\n\nexport class DistributedLock extends DistributedPrimitive {\n constructor(opts: DistributedLockOptions) {\n super(opts);\n }\n\n protected doAcquire(sock: net.Socket) {\n return acquire(sock, this.key, this.acquireTimeoutS, this.leaseTtlS);\n }\n\n protected doEnqueue(sock: net.Socket) {\n return enqueue(sock, this.key, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return waitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return release(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return renew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedSemaphore\n// ---------------------------------------------------------------------------\n\nexport class DistributedSemaphore extends DistributedPrimitive {\n readonly limit: number;\n\n constructor(opts: DistributedSemaphoreOptions) {\n super(opts);\n if (!Number.isInteger(opts.limit) || opts.limit < 1) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n this.limit = opts.limit;\n }\n\n protected doAcquire(sock: net.Socket) {\n return semAcquire(\n sock,\n this.key,\n this.acquireTimeoutS,\n this.limit,\n this.leaseTtlS,\n );\n }\n\n protected doEnqueue(sock: net.Socket) {\n return semEnqueue(sock, this.key, this.limit, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return semWaitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return semRelease(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return semRenew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Signal types\n// ---------------------------------------------------------------------------\n\nexport interface Signal {\n channel: string;\n payload: string;\n}\n\n// ---------------------------------------------------------------------------\n// Signal protocol functions\n// ---------------------------------------------------------------------------\n\nfunction validatePayload(payload: string): void {\n if (payload === \"\") {\n throw new LockError(\"payload must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(payload)) {\n throw new LockError(\n \"payload must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n/**\n * Publish a signal on a channel using a regular socket (request-response).\n * Returns the number of listeners that received the signal.\n *\n * Use this when you only need to publish and don't need to receive signals.\n * For subscribing to signals, use `SignalConnection`.\n */\nexport async function publish(\n sock: net.Socket,\n channel: string,\n payload: string,\n): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n await writeAll(sock, encodeLines(\"signal\", channel, payload));\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n}\n\n// ---------------------------------------------------------------------------\n// SignalConnection\n// ---------------------------------------------------------------------------\n\nexport interface SignalConnectionOptions {\n /** Server host (default `\"127.0.0.1\"`). */\n host?: string;\n /** Server port (default `6388`). */\n port?: number;\n /** TLS options; pass `{}` for default system CA. */\n tls?: tls.ConnectionOptions;\n /** Auth token for servers started with `--auth-token`. */\n auth?: string;\n /** TCP connect timeout in milliseconds. */\n connectTimeoutMs?: number;\n}\n\n/**\n * A connection dedicated to the signal (pub/sub) protocol.\n *\n * Wraps a socket with a background line reader that separates asynchronous\n * `sig` push messages from command responses, allowing `listen`, `unlisten`,\n * and `emit` to be called while signals are being delivered.\n *\n * ```ts\n * const conn = await SignalConnection.connect();\n * conn.onSignal((sig) => console.log(sig.channel, sig.payload));\n * await conn.listen(\"events.>\");\n * ```\n */\nexport class SignalConnection {\n private sock: net.Socket;\n private buf = \"\";\n private decoder: StringDecoder;\n private responseResolve: ((line: string) => void) | null = null;\n private responseReject: ((err: Error) => void) | null = null;\n private cmdQueue: Array<() => void> = [];\n private cmdBusy = false;\n private signalListeners: Array<(signal: Signal) => void> = [];\n private _closed = false;\n\n /**\n * Wrap an existing socket as a SignalConnection.\n *\n * The socket should already be connected (and authenticated, if needed).\n * Prefer `SignalConnection.connect()` for convenience.\n */\n constructor(sock: net.Socket) {\n this.sock = sock;\n\n // Take over the readline StringDecoder to preserve any held-back bytes\n // from a multi-byte UTF-8 character split across TCP segments.\n const prevDecoder = _readlineDecoder.get(sock);\n this.decoder = prevDecoder ?? new StringDecoder(\"utf8\");\n _readlineDecoder.delete(sock);\n\n // Drain any leftover buffer from the global readline WeakMap.\n const leftover = _readlineBuf.get(sock);\n if (leftover) {\n this.buf = leftover;\n _readlineBuf.delete(sock);\n }\n\n sock.on(\"data\", (chunk: Buffer) => this.onData(chunk));\n sock.on(\"error\", (err: Error) => this.onSocketError(err));\n sock.on(\"close\", () => this.onSocketEnd());\n sock.on(\"end\", () => this.onSocketEnd());\n\n // Process any lines already buffered.\n this.drainLines();\n }\n\n /** Connect to a dflockd server and return a SignalConnection. */\n static async connect(\n opts?: SignalConnectionOptions,\n ): Promise<SignalConnection> {\n const host = opts?.host ?? DEFAULT_HOST;\n const port = opts?.port ?? DEFAULT_PORT;\n const sock = await connect(\n host,\n port,\n opts?.tls,\n opts?.auth,\n opts?.connectTimeoutMs,\n );\n return new SignalConnection(sock);\n }\n\n /**\n * Subscribe to signals matching `pattern`.\n *\n * Patterns support NATS-style wildcards:\n * - `*` matches exactly one dot-separated token\n * - `>` matches one or more trailing tokens\n *\n * If `group` is provided, the subscription joins a queue group where\n * signals are load-balanced (round-robin) among group members.\n */\n async listen(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"listen\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`listen failed: '${resp}'`);\n }\n }\n\n /**\n * Unsubscribe from signals matching `pattern`.\n * The `pattern` and `group` must match a previous `listen()` call.\n */\n async unlisten(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"unlisten\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`unlisten failed: '${resp}'`);\n }\n }\n\n /**\n * Publish a signal on a literal channel (no wildcards).\n * Returns the number of listeners that received the signal.\n */\n async emit(channel: string, payload: string): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n const resp = await this.sendCmd(\"signal\", channel, payload);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n }\n\n /** Register a listener for incoming signals. */\n onSignal(listener: (signal: Signal) => void): void {\n this.signalListeners.push(listener);\n }\n\n /** Remove a previously registered signal listener. */\n offSignal(listener: (signal: Signal) => void): void {\n const idx = this.signalListeners.indexOf(listener);\n if (idx >= 0) this.signalListeners.splice(idx, 1);\n }\n\n /**\n * Async iterator that yields signals as they arrive.\n * Terminates when the connection closes.\n *\n * ```ts\n * for await (const sig of conn) {\n * console.log(sig.channel, sig.payload);\n * }\n * ```\n */\n async *[Symbol.asyncIterator](): AsyncIterableIterator<Signal> {\n const buffer: Signal[] = [];\n let waiter: (() => void) | null = null;\n\n const listener = (sig: Signal) => {\n buffer.push(sig);\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n const onEnd = () => {\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n this.onSignal(listener);\n this.sock.once(\"close\", onEnd);\n\n try {\n while (true) {\n if (buffer.length > 0) {\n yield buffer.shift()!;\n continue;\n }\n if (this._closed) break;\n await new Promise<void>((resolve) => {\n waiter = resolve;\n });\n }\n // Drain any remaining buffered signals.\n while (buffer.length > 0) {\n yield buffer.shift()!;\n }\n } finally {\n this.offSignal(listener);\n this.sock.removeListener(\"close\", onEnd);\n }\n }\n\n /** Close the connection (idempotent). */\n close(): void {\n if (this._closed) return;\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(new LockError(\"connection closed\"));\n }\n\n /** Whether the connection is closed. */\n get isClosed(): boolean {\n return this._closed;\n }\n\n // ---- internals ----\n\n private onData(chunk: Buffer): void {\n this.buf += this.decoder.write(chunk);\n if (this.buf.length > MAX_LINE_LENGTH * 2) {\n this.buf = \"\";\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(\n new LockError(\"server response exceeded maximum buffer size\"),\n );\n return;\n }\n this.drainLines();\n }\n\n private drainLines(): void {\n let idx: number;\n while ((idx = this.buf.indexOf(\"\\n\")) !== -1) {\n const line = this.buf.slice(0, idx).replace(/\\r$/, \"\");\n this.buf = this.buf.slice(idx + 1);\n this.handleLine(line);\n }\n }\n\n private handleLine(line: string): void {\n if (line.startsWith(\"sig \")) {\n const rest = line.slice(4);\n const spaceIdx = rest.indexOf(\" \");\n if (spaceIdx < 0) return; // malformed push, skip\n const sig: Signal = {\n channel: rest.slice(0, spaceIdx),\n payload: rest.slice(spaceIdx + 1),\n };\n for (const listener of [...this.signalListeners]) {\n try {\n listener(sig);\n } catch {\n // Never let a user callback crash the read loop.\n }\n }\n return;\n }\n // Command response.\n if (this.responseResolve) {\n const resolve = this.responseResolve;\n this.responseResolve = null;\n this.responseReject = null;\n resolve(line);\n }\n }\n\n private onSocketError(err: Error): void {\n this._closed = true;\n this.rejectPending(err);\n }\n\n private onSocketEnd(): void {\n this._closed = true;\n this.rejectPending(new LockError(\"server closed connection\"));\n }\n\n private rejectPending(err: Error): void {\n if (this.responseReject) {\n const reject = this.responseReject;\n this.responseResolve = null;\n this.responseReject = null;\n reject(err);\n }\n }\n\n private sendCmd(cmd: string, key: string, arg: string): Promise<string> {\n return new Promise<string>((outerResolve, outerReject) => {\n const execute = () => {\n if (this._closed) {\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(new LockError(\"connection closed\"));\n return;\n }\n let settled = false;\n this.responseResolve = (line: string) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerResolve(line);\n };\n this.responseReject = (err: Error) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n };\n this.sock.write(encodeLines(cmd, key, arg), (err) => {\n if (err && !settled) {\n settled = true;\n this.responseResolve = null;\n this.responseReject = null;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n }\n });\n };\n\n if (this.cmdBusy) {\n this.cmdQueue.push(execute);\n } else {\n this.cmdBusy = true;\n execute();\n }\n });\n }\n\n private dequeueNext(): void {\n const next = this.cmdQueue.shift();\n if (next) {\n this.cmdBusy = true;\n next();\n }\n }\n}\n"],"mappings":"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","names":["connect","interval"]}
|
package/dist/client.d.cts
CHANGED
package/dist/client.d.ts
CHANGED
package/dist/client.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
2
|
import * as net from "net";
|
|
3
|
+
import { StringDecoder } from "string_decoder";
|
|
3
4
|
import * as tls from "tls";
|
|
4
5
|
var DEFAULT_HOST = "127.0.0.1";
|
|
5
6
|
var DEFAULT_PORT = 6388;
|
|
@@ -65,6 +66,7 @@ function parseLease(value, fallback = 30) {
|
|
|
65
66
|
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
66
67
|
}
|
|
67
68
|
var _readlineBuf = /* @__PURE__ */ new WeakMap();
|
|
69
|
+
var _readlineDecoder = /* @__PURE__ */ new WeakMap();
|
|
68
70
|
var MAX_LINE_LENGTH = 1024 * 1024;
|
|
69
71
|
function readline(sock) {
|
|
70
72
|
return new Promise((resolve, reject) => {
|
|
@@ -76,8 +78,14 @@ function readline(sock) {
|
|
|
76
78
|
resolve(line);
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
81
|
+
let decoder = _readlineDecoder.get(sock);
|
|
82
|
+
if (!decoder) {
|
|
83
|
+
decoder = new StringDecoder("utf8");
|
|
84
|
+
_readlineDecoder.set(sock, decoder);
|
|
85
|
+
}
|
|
86
|
+
const dec = decoder;
|
|
79
87
|
const onData = (chunk) => {
|
|
80
|
-
buf +=
|
|
88
|
+
buf += dec.write(chunk);
|
|
81
89
|
const idx = buf.indexOf("\n");
|
|
82
90
|
if (idx !== -1) {
|
|
83
91
|
cleanup();
|
|
@@ -87,22 +95,26 @@ function readline(sock) {
|
|
|
87
95
|
} else if (buf.length > MAX_LINE_LENGTH) {
|
|
88
96
|
cleanup();
|
|
89
97
|
_readlineBuf.delete(sock);
|
|
98
|
+
_readlineDecoder.delete(sock);
|
|
90
99
|
reject(new LockError("server response exceeded maximum line length"));
|
|
91
100
|
}
|
|
92
101
|
};
|
|
93
102
|
const onError = (err) => {
|
|
94
103
|
cleanup();
|
|
95
104
|
_readlineBuf.delete(sock);
|
|
105
|
+
_readlineDecoder.delete(sock);
|
|
96
106
|
reject(err);
|
|
97
107
|
};
|
|
98
108
|
const onClose = () => {
|
|
99
109
|
cleanup();
|
|
100
110
|
_readlineBuf.delete(sock);
|
|
111
|
+
_readlineDecoder.delete(sock);
|
|
101
112
|
reject(new LockError("server closed connection"));
|
|
102
113
|
};
|
|
103
114
|
const onEnd = () => {
|
|
104
115
|
cleanup();
|
|
105
116
|
_readlineBuf.delete(sock);
|
|
117
|
+
_readlineDecoder.delete(sock);
|
|
106
118
|
reject(new LockError("server closed connection"));
|
|
107
119
|
};
|
|
108
120
|
const cleanup = () => {
|
|
@@ -113,6 +125,7 @@ function readline(sock) {
|
|
|
113
125
|
};
|
|
114
126
|
if (sock.readableEnded || sock.destroyed) {
|
|
115
127
|
_readlineBuf.delete(sock);
|
|
128
|
+
_readlineDecoder.delete(sock);
|
|
116
129
|
reject(new LockError("server closed connection"));
|
|
117
130
|
return;
|
|
118
131
|
}
|
|
@@ -648,11 +661,11 @@ var DistributedPrimitive = class {
|
|
|
648
661
|
this.renewInFlight = null;
|
|
649
662
|
if (this.closed || this.token !== savedToken) return;
|
|
650
663
|
const elapsed = Date.now() - start;
|
|
651
|
-
const interval2 = Math.max(1, this.lease * this.renewRatio) * 1e3;
|
|
664
|
+
const interval2 = Math.max(0.1, this.lease * this.renewRatio) * 1e3;
|
|
652
665
|
this.renewTimer = setTimeout(loop, Math.max(0, interval2 - elapsed));
|
|
653
666
|
this.renewTimer.unref();
|
|
654
667
|
};
|
|
655
|
-
const interval = Math.max(1, this.lease * this.renewRatio) * 1e3;
|
|
668
|
+
const interval = Math.max(0.1, this.lease * this.renewRatio) * 1e3;
|
|
656
669
|
this.renewTimer = setTimeout(loop, interval);
|
|
657
670
|
this.renewTimer.unref();
|
|
658
671
|
}
|
|
@@ -741,6 +754,7 @@ async function publish(sock, channel, payload) {
|
|
|
741
754
|
var SignalConnection = class _SignalConnection {
|
|
742
755
|
sock;
|
|
743
756
|
buf = "";
|
|
757
|
+
decoder;
|
|
744
758
|
responseResolve = null;
|
|
745
759
|
responseReject = null;
|
|
746
760
|
cmdQueue = [];
|
|
@@ -755,6 +769,9 @@ var SignalConnection = class _SignalConnection {
|
|
|
755
769
|
*/
|
|
756
770
|
constructor(sock) {
|
|
757
771
|
this.sock = sock;
|
|
772
|
+
const prevDecoder = _readlineDecoder.get(sock);
|
|
773
|
+
this.decoder = prevDecoder ?? new StringDecoder("utf8");
|
|
774
|
+
_readlineDecoder.delete(sock);
|
|
758
775
|
const leftover = _readlineBuf.get(sock);
|
|
759
776
|
if (leftover) {
|
|
760
777
|
this.buf = leftover;
|
|
@@ -905,7 +922,7 @@ var SignalConnection = class _SignalConnection {
|
|
|
905
922
|
}
|
|
906
923
|
// ---- internals ----
|
|
907
924
|
onData(chunk) {
|
|
908
|
-
this.buf +=
|
|
925
|
+
this.buf += this.decoder.write(chunk);
|
|
909
926
|
if (this.buf.length > MAX_LINE_LENGTH * 2) {
|
|
910
927
|
this.buf = "";
|
|
911
928
|
this._closed = true;
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import * as net from \"net\";\nimport * as tls from \"tls\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 6388;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class LockError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LockError\";\n }\n}\n\nexport class AcquireTimeoutError extends LockError {\n constructor(key: string) {\n super(`timeout acquiring '${key}'`);\n this.name = \"AcquireTimeoutError\";\n }\n}\n\nexport class AuthError extends LockError {\n constructor() {\n super(\"authentication failed\");\n this.name = \"AuthError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nfunction validateKey(key: string): void {\n if (key === \"\") {\n throw new LockError(\"key must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(key)) {\n throw new LockError(\n \"key must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateAuth(auth: string): void {\n if (/[\\0\\n\\r]/.test(auth)) {\n throw new LockError(\n \"auth token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateToken(token: string): void {\n if (token === \"\") {\n throw new LockError(\"token must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(token)) {\n throw new LockError(\n \"token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Low-level helpers\n// ---------------------------------------------------------------------------\n\nfunction encodeLines(...lines: string[]): Buffer {\n return Buffer.from(lines.map((l) => l + \"\\n\").join(\"\"), \"utf-8\");\n}\n\nfunction writeAll(sock: net.Socket, data: Buffer): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n sock.write(data, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Parse a lease value from a server response part.\n * Returns `fallback` when the value is missing, empty, or non-numeric.\n */\nfunction parseLease(value: string | undefined, fallback: number = 30): number {\n if (value == null || value === \"\") return fallback;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? n : fallback;\n}\n\n/**\n * Read one newline-terminated line from the socket.\n * Resolves with the line (without trailing \\r\\n).\n * Rejects if the connection closes before a full line arrives.\n *\n * NOTE: Concurrent calls to readline() on the same socket are unsafe —\n * callers must serialize reads (the request-response protocol naturally\n * enforces this).\n */\nconst _readlineBuf = new WeakMap<net.Socket, string>();\nconst MAX_LINE_LENGTH = 1024 * 1024; // 1 MB\n\nfunction readline(sock: net.Socket): Promise<string> {\n return new Promise((resolve, reject) => {\n let buf = _readlineBuf.get(sock) ?? \"\";\n\n // Check if a complete line is already buffered from a previous read.\n const existing = buf.indexOf(\"\\n\");\n if (existing !== -1) {\n const line = buf.slice(0, existing).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(existing + 1));\n resolve(line);\n return;\n }\n\n const onData = (chunk: Buffer) => {\n buf += chunk.toString(\"utf-8\");\n const idx = buf.indexOf(\"\\n\");\n if (idx !== -1) {\n cleanup();\n const line = buf.slice(0, idx).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(idx + 1));\n resolve(line);\n } else if (buf.length > MAX_LINE_LENGTH) {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server response exceeded maximum line length\"));\n }\n };\n\n const onError = (err: Error) => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const onEnd = () => {\n cleanup();\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const cleanup = () => {\n sock.removeListener(\"data\", onData);\n sock.removeListener(\"error\", onError);\n sock.removeListener(\"close\", onClose);\n sock.removeListener(\"end\", onEnd);\n };\n\n // If the readable side already ended (e.g. the server closed before we\n // started reading), the 'end'/'close' events won't fire again.\n if (sock.readableEnded || sock.destroyed) {\n _readlineBuf.delete(sock);\n reject(new LockError(\"server closed connection\"));\n return;\n }\n\n sock.on(\"data\", onData);\n sock.on(\"error\", onError);\n sock.on(\"close\", onClose);\n sock.on(\"end\", onEnd);\n });\n}\n\nasync function connect(\n host: string,\n port: number,\n tlsOptions?: tls.ConnectionOptions,\n auth?: string,\n connectTimeoutMs?: number,\n): Promise<net.Socket> {\n const sock = await new Promise<net.Socket>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n let settled = false;\n\n // tls.connect() registers the callback on \"secureConnect\", not \"connect\".\n const connectEvent = tlsOptions ? \"secureConnect\" : \"connect\";\n\n const onConnect = () => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(\"error\", onError);\n resolve(s);\n };\n\n const onError = (err: Error) => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(err);\n };\n\n let s: net.Socket;\n if (tlsOptions) {\n s = tls.connect({ ...tlsOptions, host, port }, onConnect);\n } else {\n s = net.createConnection({ host, port }, onConnect);\n }\n s.on(\"error\", onError);\n\n if (connectTimeoutMs != null && connectTimeoutMs > 0) {\n timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n s.removeListener(\"error\", onError);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(\n new LockError(\n `connect timed out after ${connectTimeoutMs}ms to ${host}:${port}`,\n ),\n );\n }, connectTimeoutMs);\n }\n });\n\n // Disable Nagle's algorithm for lower latency on small lock commands.\n sock.setNoDelay(true);\n\n // Prevent unhandled 'error' events from crashing the process.\n // Errors are detected through readline's close handler.\n sock.on(\"error\", () => {});\n\n if (auth != null && auth !== \"\") {\n validateAuth(auth);\n let resp: string;\n try {\n await writeAll(sock, encodeLines(\"auth\", \"_\", auth));\n resp = await readline(sock);\n } catch (err) {\n sock.destroy();\n throw err;\n }\n if (resp === \"ok\") {\n return sock;\n }\n sock.destroy();\n if (resp === \"error_auth\") {\n throw new AuthError();\n }\n throw new LockError(`auth failed: '${resp}'`);\n }\n\n return sock;\n}\n\n// ---------------------------------------------------------------------------\n// CRC32 (same algorithm as Python's zlib.crc32)\n// ---------------------------------------------------------------------------\n\nconst CRC32_TABLE = new Uint32Array(256);\nfor (let i = 0; i < 256; i++) {\n let c = i;\n for (let j = 0; j < 8; j++) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n CRC32_TABLE[i] = c;\n}\n\nfunction crc32(buf: Buffer): number {\n let crc = 0xffffffff;\n for (let i = 0; i < buf.length; i++) {\n crc = CRC32_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n// ---------------------------------------------------------------------------\n// Sharding\n// ---------------------------------------------------------------------------\n\nexport type ShardingStrategy = (key: string, numServers: number) => number;\n\nexport function stableHashShard(key: string, numServers: number): number {\n if (numServers <= 0) {\n throw new LockError(\"numServers must be greater than 0\");\n }\n return crc32(Buffer.from(key, \"utf-8\")) % numServers;\n}\n\n// ---------------------------------------------------------------------------\n// Stats types\n// ---------------------------------------------------------------------------\n\nexport interface StatsLock {\n key: string;\n owner_conn_id: number;\n lease_expires_in_s: number;\n waiters: number;\n}\n\nexport interface StatsSemaphore {\n key: string;\n limit: number;\n holders: number;\n waiters: number;\n}\n\nexport interface StatsIdleLock {\n key: string;\n idle_s: number;\n}\n\nexport interface StatsIdleSemaphore {\n key: string;\n idle_s: number;\n}\n\nexport interface Stats {\n connections: number;\n locks: StatsLock[];\n semaphores: StatsSemaphore[];\n idle_locks: StatsIdleLock[];\n idle_semaphores: StatsIdleSemaphore[];\n}\n\n// ---------------------------------------------------------------------------\n// Protocol helpers (shared by lock and semaphore functions)\n// ---------------------------------------------------------------------------\n\nasync function protoAcquire(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n acquireTimeoutS: number,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [acquireTimeoutS];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRenew(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n leaseTtlS?: number,\n): Promise<number> {\n validateKey(key);\n validateToken(token);\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(cmd, key, arg));\n\n const resp = await readline(sock);\n if (resp !== \"ok\" && !resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n // Bare \"ok\" — server confirmed renewal but didn't echo the lease.\n if (resp === \"ok\") return leaseTtlS ?? 30;\n return parseLease(resp.split(\" \")[1]);\n}\n\nasync function protoEnqueue(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n validateKey(key);\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp.startsWith(\"acquired \")) {\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { status: \"acquired\", token, lease: parseLease(respParts[2]) };\n }\n if (resp === \"queued\") {\n return { status: \"queued\", token: null, lease: null };\n }\n throw new LockError(`${label} failed: '${resp}'`);\n}\n\nasync function protoWait(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(waitTimeoutS) || waitTimeoutS < 0) {\n throw new LockError(\"waitTimeoutS must be an integer >= 0\");\n }\n\n await writeAll(sock, encodeLines(cmd, key, String(waitTimeoutS)));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRelease(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n): Promise<void> {\n validateKey(key);\n validateToken(token);\n await writeAll(sock, encodeLines(cmd, key, token));\n\n const resp = await readline(sock);\n if (resp !== \"ok\") {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lock protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function acquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"l\", \"acquire\", key, acquireTimeoutS, leaseTtlS);\n}\n\nexport async function renew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"n\", \"renew\", key, token, leaseTtlS);\n}\n\nexport async function enqueue(\n sock: net.Socket, key: string, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"e\", \"enqueue\", key, leaseTtlS);\n}\n\nexport async function waitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"w\", \"wait\", key, waitTimeoutS);\n}\n\nexport async function release(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"r\", \"release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Semaphore protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function semAcquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, limit: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"sl\", \"sem_acquire\", key, acquireTimeoutS, leaseTtlS, limit);\n}\n\nexport async function semRenew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"sn\", \"sem_renew\", key, token, leaseTtlS);\n}\n\nexport async function semEnqueue(\n sock: net.Socket, key: string, limit: number, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"se\", \"sem_enqueue\", key, leaseTtlS, limit);\n}\n\nexport async function semWaitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"sw\", \"sem_wait\", key, waitTimeoutS);\n}\n\nexport async function semRelease(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"sr\", \"sem_release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Stats protocol function\n// ---------------------------------------------------------------------------\n\nasync function statsProto(sock: net.Socket): Promise<Stats> {\n await writeAll(sock, encodeLines(\"stats\", \"_\", \"\"));\n\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`stats failed: '${resp}'`);\n }\n\n const json = resp.slice(3);\n try {\n return JSON.parse(json) as Stats;\n } catch {\n throw new LockError(`stats: malformed JSON response: '${json}'`);\n }\n}\n\n/**\n * Query server runtime statistics.\n *\n * Opens a short-lived connection, sends the `stats` command, and returns\n * the parsed response.\n *\n * ```ts\n * const s = await stats();\n * console.log(s.connections, s.locks.length);\n * ```\n */\nexport async function stats(\n options?: {\n host?: string;\n port?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n connectTimeoutMs?: number;\n },\n): Promise<Stats> {\n const host = options?.host ?? DEFAULT_HOST;\n const port = options?.port ?? DEFAULT_PORT;\n const sock = await connect(host, port, options?.tls, options?.auth, options?.connectTimeoutMs);\n try {\n return await statsProto(sock);\n } finally {\n sock.destroy();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Option interfaces\n// ---------------------------------------------------------------------------\n\ninterface BaseOptions {\n key: string;\n acquireTimeoutS?: number;\n leaseTtlS?: number;\n /** @deprecated Use `servers` instead. */\n host?: string;\n /** @deprecated Use `servers` instead. */\n port?: number;\n servers?: Array<[host: string, port: number]>;\n shardingStrategy?: ShardingStrategy;\n renewRatio?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n onLockLost?: (key: string, token: string) => void;\n /** TCP connect timeout in milliseconds. Undefined means no timeout. */\n connectTimeoutMs?: number;\n /**\n * Socket idle timeout in milliseconds. If no data is received within this\n * period, the socket emits a 'timeout' event and is destroyed, causing any\n * pending `readline` to reject. Undefined means no timeout.\n */\n socketTimeoutMs?: number;\n}\n\nexport interface DistributedLockOptions extends BaseOptions {}\n\nexport interface DistributedSemaphoreOptions extends BaseOptions {\n limit: number;\n}\n\n// ---------------------------------------------------------------------------\n// Shared base class\n// ---------------------------------------------------------------------------\n\nabstract class DistributedPrimitive {\n readonly key: string;\n readonly acquireTimeoutS: number;\n readonly leaseTtlS: number | undefined;\n readonly servers: Array<[string, number]>;\n readonly shardingStrategy: ShardingStrategy;\n readonly renewRatio: number;\n readonly tls: tls.ConnectionOptions | undefined;\n readonly auth: string | undefined;\n readonly onLockLost: ((key: string, token: string) => void) | undefined;\n readonly connectTimeoutMs: number | undefined;\n readonly socketTimeoutMs: number | undefined;\n\n token: string | null = null;\n lease: number = 0;\n\n private sock: net.Socket | null = null;\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n private renewInFlight: Promise<void> | null = null;\n private closed = false;\n\n constructor(opts: BaseOptions) {\n validateKey(opts.key);\n this.key = opts.key;\n this.acquireTimeoutS = opts.acquireTimeoutS ?? 10;\n this.leaseTtlS = opts.leaseTtlS;\n this.tls = opts.tls;\n this.auth = opts.auth;\n this.onLockLost = opts.onLockLost;\n this.connectTimeoutMs = opts.connectTimeoutMs;\n this.socketTimeoutMs = opts.socketTimeoutMs;\n\n if (!Number.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n if (opts.servers) {\n if (opts.servers.length === 0) {\n throw new LockError(\"servers list must not be empty\");\n }\n this.servers = [...opts.servers];\n } else {\n this.servers = [[opts.host ?? DEFAULT_HOST, opts.port ?? DEFAULT_PORT]];\n }\n\n this.shardingStrategy = opts.shardingStrategy ?? stableHashShard;\n\n const renewRatio = opts.renewRatio ?? 0.5;\n if (!Number.isFinite(renewRatio) || renewRatio <= 0 || renewRatio >= 1) {\n throw new LockError(\"renewRatio must be a finite number between 0 and 1 (exclusive)\");\n }\n this.renewRatio = renewRatio;\n }\n\n // -- abstract protocol hooks (implemented by subclasses) --\n\n protected abstract doAcquire(\n sock: net.Socket,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doEnqueue(\n sock: net.Socket,\n ): Promise<{\n status: \"acquired\" | \"queued\";\n token: string | null;\n lease: number | null;\n }>;\n\n protected abstract doWait(\n sock: net.Socket,\n timeoutS: number,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doRelease(\n sock: net.Socket,\n token: string,\n ): Promise<void>;\n\n protected abstract doRenew(\n sock: net.Socket,\n token: string,\n ): Promise<number>;\n\n // -- public API --\n\n private async openConnection(): Promise<net.Socket> {\n const [host, port] = this.pickServer();\n const sock = await connect(host, port, this.tls, this.auth, this.connectTimeoutMs);\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n // Register the listener once; use setTimeout(ms)/setTimeout(0) to\n // toggle without accumulating duplicate listeners.\n sock.on(\"timeout\", () => {\n sock.destroy(new LockError(\"socket idle timeout\"));\n });\n sock.setTimeout(this.socketTimeoutMs);\n }\n return sock;\n }\n\n /**\n * Suspend or restore the socket idle timeout. Only has effect when\n * `socketTimeoutMs` was set at construction time and a listener was\n * registered in `openConnection`.\n */\n private suspendSocketTimeout(sock: net.Socket): void {\n sock.setTimeout(0);\n }\n\n private restoreSocketTimeout(sock: net.Socket): void {\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n sock.setTimeout(this.socketTimeoutMs);\n }\n }\n\n private pickServer(): [string, number] {\n const idx = this.shardingStrategy(this.key, this.servers.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= this.servers.length) {\n throw new LockError(\n `shardingStrategy returned invalid index ${idx} for ${this.servers.length} server(s)`,\n );\n }\n return this.servers[idx];\n }\n\n /**\n * Acquire the lock / semaphore slot.\n * Returns `true` on success, `false` on timeout.\n * @param opts.force - If `true`, silently close any existing connection\n * before acquiring. Defaults to `false`, which throws if already connected.\n */\n async acquire(opts?: { force?: boolean }): Promise<boolean> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n // Suspend socket idle timeout during the blocking acquire — the server\n // won't send data until the lock is granted or the acquire times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doAcquire(this.sock);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Release the lock / semaphore slot and close the connection.\n *\n * Throws `LockError` if the instance is already closed (e.g. after a\n * previous `release()` or `close()` call).\n *\n * The server-side release itself is best-effort: if the underlying\n * connection is already dead the protocol-level release error is silently\n * ignored so that the method doesn't throw on transient network failures.\n */\n async release(): Promise<void> {\n if (this.closed) {\n throw new LockError(\"not connected; nothing to release\");\n }\n // Capture the token and socket before awaiting anything — a concurrent\n // renew failure can set this.token/this.sock to null (via onLockLost →\n // close()), which would cause us to skip the server-side release and\n // leave the lock held until lease expiry.\n const tokenToRelease = this.token;\n const sockToRelease = this.sock;\n try {\n this.stopRenew();\n // Wait for any in-flight renew to finish before sending the release\n // command — concurrent reads/writes on the same socket are unsafe.\n // Bound the wait to 5s so release() doesn't hang forever when the\n // network is unresponsive and no socketTimeoutMs is configured.\n if (this.renewInFlight) {\n await Promise.race([\n this.renewInFlight,\n new Promise<void>((r) => setTimeout(r, 5000).unref()),\n ]);\n // The loop resumes before us (it registered its .then first) and may\n // have scheduled a new timer. Clear it so it cannot fire during\n // doRelease below.\n this.stopRenew();\n }\n if (sockToRelease != null && tokenToRelease != null) {\n try {\n await this.doRelease(sockToRelease, tokenToRelease);\n } catch {\n // Best-effort: connection may already be dead.\n }\n }\n } finally {\n this.close();\n }\n }\n\n /**\n * Two-phase step 1: connect and join the FIFO queue.\n * Returns `\"acquired\"` (fast-path) or `\"queued\"`.\n * If acquired immediately, the renew loop starts automatically.\n * @param opts.force - If `true`, silently close any existing connection\n * before enqueuing. Defaults to `false`, which throws if already connected.\n */\n async enqueue(opts?: { force?: boolean }): Promise<\"acquired\" | \"queued\"> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n this.suspendSocketTimeout(this.sock);\n const result = await this.doEnqueue(this.sock);\n if (result.status === \"acquired\") {\n this.token = result.token;\n this.lease = result.lease ?? 0;\n this.restoreSocketTimeout(this.sock);\n this.startRenew();\n }\n return result.status;\n } catch (err) {\n this.close();\n throw err;\n }\n }\n\n /**\n * Two-phase step 2: block until the lock / slot is granted.\n * Returns `true` if granted, `false` on timeout.\n * If already acquired during `enqueue()`, returns `true` immediately.\n */\n async wait(timeoutS?: number): Promise<boolean> {\n if (this.token !== null) {\n // Already acquired during enqueue (fast path)\n return true;\n }\n if (this.closed) {\n throw new LockError(\"connection closed; call enqueue() again\");\n }\n if (!this.sock) {\n throw new LockError(\"not connected; call enqueue() first\");\n }\n const timeout = timeoutS ?? this.acquireTimeoutS;\n try {\n // Suspend socket idle timeout during the blocking wait — the server\n // won't send data until the lock/slot is granted or the wait times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doWait(this.sock, timeout);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Run `fn` while holding the lock / slot, then release automatically.\n *\n * If `fn()` throws, its error is always preserved — a concurrent\n * release failure will not mask it.\n */\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n const ok = await this.acquire();\n if (!ok) {\n throw new AcquireTimeoutError(this.key);\n }\n let threw = false;\n try {\n return await fn();\n } catch (err) {\n threw = true;\n throw err;\n } finally {\n try {\n await this.release();\n } catch (releaseErr) {\n // If fn() already threw, swallow the release error so it\n // doesn't mask the original error.\n if (!threw) throw releaseErr;\n }\n }\n }\n\n /** Close the underlying socket (idempotent). */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopRenew();\n this.renewInFlight = null;\n if (this.sock) {\n this.sock.destroy();\n this.sock = null;\n }\n this.token = null;\n this.lease = 0;\n }\n\n // -- internals --\n\n private startRenew(): void {\n this.stopRenew();\n const loop = async () => {\n const savedToken = this.token;\n const sock = this.sock;\n if (!sock || !savedToken) return;\n const start = Date.now();\n const p = (async () => {\n try {\n const newLease = await this.doRenew(sock, savedToken);\n // Guard: if close() ran while the renew was in-flight, don't\n // clobber the reset state (lease=0, token=null).\n if (this.token === savedToken && !this.closed) {\n this.lease = newLease;\n }\n } catch {\n // Only signal lock-lost if we still own this token (close() may have cleared it)\n if (this.token === savedToken) {\n this.token = null;\n if (this.onLockLost) {\n try {\n // Cast to unknown: the declared return type is void, but an\n // async callback will return a Promise at runtime.\n const result: unknown = this.onLockLost(this.key, savedToken);\n // Guard against async callbacks returning a rejected Promise.\n if (result instanceof Promise) {\n result.catch(() => {});\n }\n } catch {\n // Never let a user callback crash the process.\n }\n }\n // Tear down the connection so the instance is in a clean state\n // for re-acquisition. Without this the socket leaks and a\n // subsequent acquire() without { force: true } would throw\n // \"already connected\".\n this.close();\n }\n return;\n }\n })();\n this.renewInFlight = p;\n await p;\n this.renewInFlight = null;\n // Guard: if close() was called while the renew was in-flight, don't\n // schedule another iteration (avoids clobbering a new acquire's timer).\n if (this.closed || this.token !== savedToken) return;\n const elapsed = Date.now() - start;\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, Math.max(0, interval - elapsed));\n this.renewTimer.unref();\n };\n const interval = Math.max(1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, interval);\n this.renewTimer.unref();\n }\n\n private stopRenew(): void {\n if (this.renewTimer != null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedLock\n// ---------------------------------------------------------------------------\n\nexport class DistributedLock extends DistributedPrimitive {\n constructor(opts: DistributedLockOptions) {\n super(opts);\n }\n\n protected doAcquire(sock: net.Socket) {\n return acquire(sock, this.key, this.acquireTimeoutS, this.leaseTtlS);\n }\n\n protected doEnqueue(sock: net.Socket) {\n return enqueue(sock, this.key, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return waitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return release(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return renew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedSemaphore\n// ---------------------------------------------------------------------------\n\nexport class DistributedSemaphore extends DistributedPrimitive {\n readonly limit: number;\n\n constructor(opts: DistributedSemaphoreOptions) {\n super(opts);\n if (!Number.isInteger(opts.limit) || opts.limit < 1) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n this.limit = opts.limit;\n }\n\n protected doAcquire(sock: net.Socket) {\n return semAcquire(\n sock,\n this.key,\n this.acquireTimeoutS,\n this.limit,\n this.leaseTtlS,\n );\n }\n\n protected doEnqueue(sock: net.Socket) {\n return semEnqueue(sock, this.key, this.limit, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return semWaitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return semRelease(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return semRenew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Signal types\n// ---------------------------------------------------------------------------\n\nexport interface Signal {\n channel: string;\n payload: string;\n}\n\n// ---------------------------------------------------------------------------\n// Signal protocol functions\n// ---------------------------------------------------------------------------\n\nfunction validatePayload(payload: string): void {\n if (payload === \"\") {\n throw new LockError(\"payload must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(payload)) {\n throw new LockError(\n \"payload must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n/**\n * Publish a signal on a channel using a regular socket (request-response).\n * Returns the number of listeners that received the signal.\n *\n * Use this when you only need to publish and don't need to receive signals.\n * For subscribing to signals, use `SignalConnection`.\n */\nexport async function publish(\n sock: net.Socket,\n channel: string,\n payload: string,\n): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n await writeAll(sock, encodeLines(\"signal\", channel, payload));\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n}\n\n// ---------------------------------------------------------------------------\n// SignalConnection\n// ---------------------------------------------------------------------------\n\nexport interface SignalConnectionOptions {\n /** Server host (default `\"127.0.0.1\"`). */\n host?: string;\n /** Server port (default `6388`). */\n port?: number;\n /** TLS options; pass `{}` for default system CA. */\n tls?: tls.ConnectionOptions;\n /** Auth token for servers started with `--auth-token`. */\n auth?: string;\n /** TCP connect timeout in milliseconds. */\n connectTimeoutMs?: number;\n}\n\n/**\n * A connection dedicated to the signal (pub/sub) protocol.\n *\n * Wraps a socket with a background line reader that separates asynchronous\n * `sig` push messages from command responses, allowing `listen`, `unlisten`,\n * and `emit` to be called while signals are being delivered.\n *\n * ```ts\n * const conn = await SignalConnection.connect();\n * conn.onSignal((sig) => console.log(sig.channel, sig.payload));\n * await conn.listen(\"events.>\");\n * ```\n */\nexport class SignalConnection {\n private sock: net.Socket;\n private buf = \"\";\n private responseResolve: ((line: string) => void) | null = null;\n private responseReject: ((err: Error) => void) | null = null;\n private cmdQueue: Array<() => void> = [];\n private cmdBusy = false;\n private signalListeners: Array<(signal: Signal) => void> = [];\n private _closed = false;\n\n /**\n * Wrap an existing socket as a SignalConnection.\n *\n * The socket should already be connected (and authenticated, if needed).\n * Prefer `SignalConnection.connect()` for convenience.\n */\n constructor(sock: net.Socket) {\n this.sock = sock;\n\n // Drain any leftover buffer from the global readline WeakMap.\n const leftover = _readlineBuf.get(sock);\n if (leftover) {\n this.buf = leftover;\n _readlineBuf.delete(sock);\n }\n\n sock.on(\"data\", (chunk: Buffer) => this.onData(chunk));\n sock.on(\"error\", (err: Error) => this.onSocketError(err));\n sock.on(\"close\", () => this.onSocketEnd());\n sock.on(\"end\", () => this.onSocketEnd());\n\n // Process any lines already buffered.\n this.drainLines();\n }\n\n /** Connect to a dflockd server and return a SignalConnection. */\n static async connect(\n opts?: SignalConnectionOptions,\n ): Promise<SignalConnection> {\n const host = opts?.host ?? DEFAULT_HOST;\n const port = opts?.port ?? DEFAULT_PORT;\n const sock = await connect(\n host,\n port,\n opts?.tls,\n opts?.auth,\n opts?.connectTimeoutMs,\n );\n return new SignalConnection(sock);\n }\n\n /**\n * Subscribe to signals matching `pattern`.\n *\n * Patterns support NATS-style wildcards:\n * - `*` matches exactly one dot-separated token\n * - `>` matches one or more trailing tokens\n *\n * If `group` is provided, the subscription joins a queue group where\n * signals are load-balanced (round-robin) among group members.\n */\n async listen(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"listen\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`listen failed: '${resp}'`);\n }\n }\n\n /**\n * Unsubscribe from signals matching `pattern`.\n * The `pattern` and `group` must match a previous `listen()` call.\n */\n async unlisten(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"unlisten\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`unlisten failed: '${resp}'`);\n }\n }\n\n /**\n * Publish a signal on a literal channel (no wildcards).\n * Returns the number of listeners that received the signal.\n */\n async emit(channel: string, payload: string): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n const resp = await this.sendCmd(\"signal\", channel, payload);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n }\n\n /** Register a listener for incoming signals. */\n onSignal(listener: (signal: Signal) => void): void {\n this.signalListeners.push(listener);\n }\n\n /** Remove a previously registered signal listener. */\n offSignal(listener: (signal: Signal) => void): void {\n const idx = this.signalListeners.indexOf(listener);\n if (idx >= 0) this.signalListeners.splice(idx, 1);\n }\n\n /**\n * Async iterator that yields signals as they arrive.\n * Terminates when the connection closes.\n *\n * ```ts\n * for await (const sig of conn) {\n * console.log(sig.channel, sig.payload);\n * }\n * ```\n */\n async *[Symbol.asyncIterator](): AsyncIterableIterator<Signal> {\n const buffer: Signal[] = [];\n let waiter: (() => void) | null = null;\n\n const listener = (sig: Signal) => {\n buffer.push(sig);\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n const onEnd = () => {\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n this.onSignal(listener);\n this.sock.once(\"close\", onEnd);\n\n try {\n while (true) {\n if (buffer.length > 0) {\n yield buffer.shift()!;\n continue;\n }\n if (this._closed) break;\n await new Promise<void>((resolve) => {\n waiter = resolve;\n });\n }\n // Drain any remaining buffered signals.\n while (buffer.length > 0) {\n yield buffer.shift()!;\n }\n } finally {\n this.offSignal(listener);\n this.sock.removeListener(\"close\", onEnd);\n }\n }\n\n /** Close the connection (idempotent). */\n close(): void {\n if (this._closed) return;\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(new LockError(\"connection closed\"));\n }\n\n /** Whether the connection is closed. */\n get isClosed(): boolean {\n return this._closed;\n }\n\n // ---- internals ----\n\n private onData(chunk: Buffer): void {\n this.buf += chunk.toString(\"utf-8\");\n if (this.buf.length > MAX_LINE_LENGTH * 2) {\n this.buf = \"\";\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(\n new LockError(\"server response exceeded maximum buffer size\"),\n );\n return;\n }\n this.drainLines();\n }\n\n private drainLines(): void {\n let idx: number;\n while ((idx = this.buf.indexOf(\"\\n\")) !== -1) {\n const line = this.buf.slice(0, idx).replace(/\\r$/, \"\");\n this.buf = this.buf.slice(idx + 1);\n this.handleLine(line);\n }\n }\n\n private handleLine(line: string): void {\n if (line.startsWith(\"sig \")) {\n const rest = line.slice(4);\n const spaceIdx = rest.indexOf(\" \");\n if (spaceIdx < 0) return; // malformed push, skip\n const sig: Signal = {\n channel: rest.slice(0, spaceIdx),\n payload: rest.slice(spaceIdx + 1),\n };\n for (const listener of [...this.signalListeners]) {\n try {\n listener(sig);\n } catch {\n // Never let a user callback crash the read loop.\n }\n }\n return;\n }\n // Command response.\n if (this.responseResolve) {\n const resolve = this.responseResolve;\n this.responseResolve = null;\n this.responseReject = null;\n resolve(line);\n }\n }\n\n private onSocketError(err: Error): void {\n this._closed = true;\n this.rejectPending(err);\n }\n\n private onSocketEnd(): void {\n this._closed = true;\n this.rejectPending(new LockError(\"server closed connection\"));\n }\n\n private rejectPending(err: Error): void {\n if (this.responseReject) {\n const reject = this.responseReject;\n this.responseResolve = null;\n this.responseReject = null;\n reject(err);\n }\n }\n\n private sendCmd(cmd: string, key: string, arg: string): Promise<string> {\n return new Promise<string>((outerResolve, outerReject) => {\n const execute = () => {\n if (this._closed) {\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(new LockError(\"connection closed\"));\n return;\n }\n let settled = false;\n this.responseResolve = (line: string) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerResolve(line);\n };\n this.responseReject = (err: Error) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n };\n this.sock.write(encodeLines(cmd, key, arg), (err) => {\n if (err && !settled) {\n settled = true;\n this.responseResolve = null;\n this.responseReject = null;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n }\n });\n };\n\n if (this.cmdBusy) {\n this.cmdQueue.push(execute);\n } else {\n this.cmdBusy = true;\n execute();\n }\n });\n }\n\n private dequeueNext(): void {\n const next = this.cmdQueue.shift();\n if (next) {\n this.cmdBusy = true;\n next();\n }\n }\n}\n"],"mappings":"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","names":["connect","interval"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import * as net from \"net\";\nimport { StringDecoder } from \"string_decoder\";\nimport * as tls from \"tls\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_PORT = 6388;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class LockError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"LockError\";\n }\n}\n\nexport class AcquireTimeoutError extends LockError {\n constructor(key: string) {\n super(`timeout acquiring '${key}'`);\n this.name = \"AcquireTimeoutError\";\n }\n}\n\nexport class AuthError extends LockError {\n constructor() {\n super(\"authentication failed\");\n this.name = \"AuthError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Validation helpers\n// ---------------------------------------------------------------------------\n\nfunction validateKey(key: string): void {\n if (key === \"\") {\n throw new LockError(\"key must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(key)) {\n throw new LockError(\n \"key must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateAuth(auth: string): void {\n if (/[\\0\\n\\r]/.test(auth)) {\n throw new LockError(\n \"auth token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\nfunction validateToken(token: string): void {\n if (token === \"\") {\n throw new LockError(\"token must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(token)) {\n throw new LockError(\n \"token must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Low-level helpers\n// ---------------------------------------------------------------------------\n\nfunction encodeLines(...lines: string[]): Buffer {\n return Buffer.from(lines.map((l) => l + \"\\n\").join(\"\"), \"utf-8\");\n}\n\nfunction writeAll(sock: net.Socket, data: Buffer): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n sock.write(data, (err) => {\n if (err) reject(err);\n else resolve();\n });\n });\n}\n\n/**\n * Parse a lease value from a server response part.\n * Returns `fallback` when the value is missing, empty, or non-numeric.\n */\nfunction parseLease(value: string | undefined, fallback: number = 30): number {\n if (value == null || value === \"\") return fallback;\n const n = Number(value);\n return Number.isFinite(n) && n >= 0 ? n : fallback;\n}\n\n/**\n * Read one newline-terminated line from the socket.\n * Resolves with the line (without trailing \\r\\n).\n * Rejects if the connection closes before a full line arrives.\n *\n * NOTE: Concurrent calls to readline() on the same socket are unsafe —\n * callers must serialize reads (the request-response protocol naturally\n * enforces this).\n */\nconst _readlineBuf = new WeakMap<net.Socket, string>();\nconst _readlineDecoder = new WeakMap<net.Socket, StringDecoder>();\nconst MAX_LINE_LENGTH = 1024 * 1024; // 1 MB\n\nfunction readline(sock: net.Socket): Promise<string> {\n return new Promise((resolve, reject) => {\n let buf = _readlineBuf.get(sock) ?? \"\";\n\n // Check if a complete line is already buffered from a previous read.\n const existing = buf.indexOf(\"\\n\");\n if (existing !== -1) {\n const line = buf.slice(0, existing).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(existing + 1));\n resolve(line);\n return;\n }\n\n // Use a StringDecoder to correctly handle multi-byte UTF-8 characters\n // that may be split across TCP segment boundaries.\n let decoder = _readlineDecoder.get(sock);\n if (!decoder) {\n decoder = new StringDecoder(\"utf8\");\n _readlineDecoder.set(sock, decoder);\n }\n const dec = decoder;\n\n const onData = (chunk: Buffer) => {\n buf += dec.write(chunk);\n const idx = buf.indexOf(\"\\n\");\n if (idx !== -1) {\n cleanup();\n const line = buf.slice(0, idx).replace(/\\r$/, \"\");\n _readlineBuf.set(sock, buf.slice(idx + 1));\n resolve(line);\n } else if (buf.length > MAX_LINE_LENGTH) {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server response exceeded maximum line length\"));\n }\n };\n\n const onError = (err: Error) => {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(err);\n };\n\n const onClose = () => {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const onEnd = () => {\n cleanup();\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server closed connection\"));\n };\n\n const cleanup = () => {\n sock.removeListener(\"data\", onData);\n sock.removeListener(\"error\", onError);\n sock.removeListener(\"close\", onClose);\n sock.removeListener(\"end\", onEnd);\n };\n\n // If the readable side already ended (e.g. the server closed before we\n // started reading), the 'end'/'close' events won't fire again.\n if (sock.readableEnded || sock.destroyed) {\n _readlineBuf.delete(sock);\n _readlineDecoder.delete(sock);\n reject(new LockError(\"server closed connection\"));\n return;\n }\n\n sock.on(\"data\", onData);\n sock.on(\"error\", onError);\n sock.on(\"close\", onClose);\n sock.on(\"end\", onEnd);\n });\n}\n\nasync function connect(\n host: string,\n port: number,\n tlsOptions?: tls.ConnectionOptions,\n auth?: string,\n connectTimeoutMs?: number,\n): Promise<net.Socket> {\n const sock = await new Promise<net.Socket>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | null = null;\n let settled = false;\n\n // tls.connect() registers the callback on \"secureConnect\", not \"connect\".\n const connectEvent = tlsOptions ? \"secureConnect\" : \"connect\";\n\n const onConnect = () => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(\"error\", onError);\n resolve(s);\n };\n\n const onError = (err: Error) => {\n if (settled) return;\n settled = true;\n if (timer) clearTimeout(timer);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(err);\n };\n\n let s: net.Socket;\n if (tlsOptions) {\n s = tls.connect({ ...tlsOptions, host, port }, onConnect);\n } else {\n s = net.createConnection({ host, port }, onConnect);\n }\n s.on(\"error\", onError);\n\n if (connectTimeoutMs != null && connectTimeoutMs > 0) {\n timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n s.removeListener(\"error\", onError);\n s.removeListener(connectEvent, onConnect);\n s.destroy();\n reject(\n new LockError(\n `connect timed out after ${connectTimeoutMs}ms to ${host}:${port}`,\n ),\n );\n }, connectTimeoutMs);\n }\n });\n\n // Disable Nagle's algorithm for lower latency on small lock commands.\n sock.setNoDelay(true);\n\n // Prevent unhandled 'error' events from crashing the process.\n // Errors are detected through readline's close handler.\n sock.on(\"error\", () => {});\n\n if (auth != null && auth !== \"\") {\n validateAuth(auth);\n let resp: string;\n try {\n await writeAll(sock, encodeLines(\"auth\", \"_\", auth));\n resp = await readline(sock);\n } catch (err) {\n sock.destroy();\n throw err;\n }\n if (resp === \"ok\") {\n return sock;\n }\n sock.destroy();\n if (resp === \"error_auth\") {\n throw new AuthError();\n }\n throw new LockError(`auth failed: '${resp}'`);\n }\n\n return sock;\n}\n\n// ---------------------------------------------------------------------------\n// CRC32 (same algorithm as Python's zlib.crc32)\n// ---------------------------------------------------------------------------\n\nconst CRC32_TABLE = new Uint32Array(256);\nfor (let i = 0; i < 256; i++) {\n let c = i;\n for (let j = 0; j < 8; j++) {\n c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n }\n CRC32_TABLE[i] = c;\n}\n\nfunction crc32(buf: Buffer): number {\n let crc = 0xffffffff;\n for (let i = 0; i < buf.length; i++) {\n crc = CRC32_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\n// ---------------------------------------------------------------------------\n// Sharding\n// ---------------------------------------------------------------------------\n\nexport type ShardingStrategy = (key: string, numServers: number) => number;\n\nexport function stableHashShard(key: string, numServers: number): number {\n if (numServers <= 0) {\n throw new LockError(\"numServers must be greater than 0\");\n }\n return crc32(Buffer.from(key, \"utf-8\")) % numServers;\n}\n\n// ---------------------------------------------------------------------------\n// Stats types\n// ---------------------------------------------------------------------------\n\nexport interface StatsLock {\n key: string;\n owner_conn_id: number;\n lease_expires_in_s: number;\n waiters: number;\n}\n\nexport interface StatsSemaphore {\n key: string;\n limit: number;\n holders: number;\n waiters: number;\n}\n\nexport interface StatsIdleLock {\n key: string;\n idle_s: number;\n}\n\nexport interface StatsIdleSemaphore {\n key: string;\n idle_s: number;\n}\n\nexport interface Stats {\n connections: number;\n locks: StatsLock[];\n semaphores: StatsSemaphore[];\n idle_locks: StatsIdleLock[];\n idle_semaphores: StatsIdleSemaphore[];\n}\n\n// ---------------------------------------------------------------------------\n// Protocol helpers (shared by lock and semaphore functions)\n// ---------------------------------------------------------------------------\n\nasync function protoAcquire(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n acquireTimeoutS: number,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(acquireTimeoutS) || acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [acquireTimeoutS];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRenew(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n leaseTtlS?: number,\n): Promise<number> {\n validateKey(key);\n validateToken(token);\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const arg = leaseTtlS == null ? token : `${token} ${leaseTtlS}`;\n await writeAll(sock, encodeLines(cmd, key, arg));\n\n const resp = await readline(sock);\n if (resp !== \"ok\" && !resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n // Bare \"ok\" — server confirmed renewal but didn't echo the lease.\n if (resp === \"ok\") return leaseTtlS ?? 30;\n return parseLease(resp.split(\" \")[1]);\n}\n\nasync function protoEnqueue(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n leaseTtlS?: number,\n limit?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n validateKey(key);\n if (limit != null && (!Number.isInteger(limit) || limit < 1)) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n if (leaseTtlS != null && (!Number.isInteger(leaseTtlS) || leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n const parts: (string | number)[] = [];\n if (limit != null) parts.push(limit);\n if (leaseTtlS != null) parts.push(leaseTtlS);\n\n await writeAll(sock, encodeLines(cmd, key, parts.join(\" \")));\n\n const resp = await readline(sock);\n if (resp.startsWith(\"acquired \")) {\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { status: \"acquired\", token, lease: parseLease(respParts[2]) };\n }\n if (resp === \"queued\") {\n return { status: \"queued\", token: null, lease: null };\n }\n throw new LockError(`${label} failed: '${resp}'`);\n}\n\nasync function protoWait(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n validateKey(key);\n if (!Number.isInteger(waitTimeoutS) || waitTimeoutS < 0) {\n throw new LockError(\"waitTimeoutS must be an integer >= 0\");\n }\n\n await writeAll(sock, encodeLines(cmd, key, String(waitTimeoutS)));\n\n const resp = await readline(sock);\n if (resp === \"timeout\") {\n throw new AcquireTimeoutError(key);\n }\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n\n const respParts = resp.split(\" \");\n const token = respParts[1];\n if (!token) {\n throw new LockError(`${label}: server returned no token: '${resp}'`);\n }\n return { token, lease: parseLease(respParts[2]) };\n}\n\nasync function protoRelease(\n sock: net.Socket,\n cmd: string,\n label: string,\n key: string,\n token: string,\n): Promise<void> {\n validateKey(key);\n validateToken(token);\n await writeAll(sock, encodeLines(cmd, key, token));\n\n const resp = await readline(sock);\n if (resp !== \"ok\") {\n throw new LockError(`${label} failed: '${resp}'`);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lock protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function acquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"l\", \"acquire\", key, acquireTimeoutS, leaseTtlS);\n}\n\nexport async function renew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"n\", \"renew\", key, token, leaseTtlS);\n}\n\nexport async function enqueue(\n sock: net.Socket, key: string, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"e\", \"enqueue\", key, leaseTtlS);\n}\n\nexport async function waitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"w\", \"wait\", key, waitTimeoutS);\n}\n\nexport async function release(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"r\", \"release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Semaphore protocol functions\n// ---------------------------------------------------------------------------\n\nexport async function semAcquire(\n sock: net.Socket, key: string, acquireTimeoutS: number, limit: number, leaseTtlS?: number,\n): Promise<{ token: string; lease: number }> {\n return protoAcquire(sock, \"sl\", \"sem_acquire\", key, acquireTimeoutS, leaseTtlS, limit);\n}\n\nexport async function semRenew(\n sock: net.Socket, key: string, token: string, leaseTtlS?: number,\n): Promise<number> {\n return protoRenew(sock, \"sn\", \"sem_renew\", key, token, leaseTtlS);\n}\n\nexport async function semEnqueue(\n sock: net.Socket, key: string, limit: number, leaseTtlS?: number,\n): Promise<{ status: \"acquired\" | \"queued\"; token: string | null; lease: number | null }> {\n return protoEnqueue(sock, \"se\", \"sem_enqueue\", key, leaseTtlS, limit);\n}\n\nexport async function semWaitForLock(\n sock: net.Socket, key: string, waitTimeoutS: number,\n): Promise<{ token: string; lease: number }> {\n return protoWait(sock, \"sw\", \"sem_wait\", key, waitTimeoutS);\n}\n\nexport async function semRelease(\n sock: net.Socket, key: string, token: string,\n): Promise<void> {\n return protoRelease(sock, \"sr\", \"sem_release\", key, token);\n}\n\n// ---------------------------------------------------------------------------\n// Stats protocol function\n// ---------------------------------------------------------------------------\n\nasync function statsProto(sock: net.Socket): Promise<Stats> {\n await writeAll(sock, encodeLines(\"stats\", \"_\", \"\"));\n\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`stats failed: '${resp}'`);\n }\n\n const json = resp.slice(3);\n try {\n return JSON.parse(json) as Stats;\n } catch {\n throw new LockError(`stats: malformed JSON response: '${json}'`);\n }\n}\n\n/**\n * Query server runtime statistics.\n *\n * Opens a short-lived connection, sends the `stats` command, and returns\n * the parsed response.\n *\n * ```ts\n * const s = await stats();\n * console.log(s.connections, s.locks.length);\n * ```\n */\nexport async function stats(\n options?: {\n host?: string;\n port?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n connectTimeoutMs?: number;\n },\n): Promise<Stats> {\n const host = options?.host ?? DEFAULT_HOST;\n const port = options?.port ?? DEFAULT_PORT;\n const sock = await connect(host, port, options?.tls, options?.auth, options?.connectTimeoutMs);\n try {\n return await statsProto(sock);\n } finally {\n sock.destroy();\n }\n}\n\n// ---------------------------------------------------------------------------\n// Option interfaces\n// ---------------------------------------------------------------------------\n\ninterface BaseOptions {\n key: string;\n acquireTimeoutS?: number;\n leaseTtlS?: number;\n /** @deprecated Use `servers` instead. */\n host?: string;\n /** @deprecated Use `servers` instead. */\n port?: number;\n servers?: Array<[host: string, port: number]>;\n shardingStrategy?: ShardingStrategy;\n renewRatio?: number;\n tls?: tls.ConnectionOptions;\n auth?: string;\n onLockLost?: (key: string, token: string) => void;\n /** TCP connect timeout in milliseconds. Undefined means no timeout. */\n connectTimeoutMs?: number;\n /**\n * Socket idle timeout in milliseconds. If no data is received within this\n * period, the socket emits a 'timeout' event and is destroyed, causing any\n * pending `readline` to reject. Undefined means no timeout.\n */\n socketTimeoutMs?: number;\n}\n\nexport interface DistributedLockOptions extends BaseOptions {}\n\nexport interface DistributedSemaphoreOptions extends BaseOptions {\n limit: number;\n}\n\n// ---------------------------------------------------------------------------\n// Shared base class\n// ---------------------------------------------------------------------------\n\nabstract class DistributedPrimitive {\n readonly key: string;\n readonly acquireTimeoutS: number;\n readonly leaseTtlS: number | undefined;\n readonly servers: Array<[string, number]>;\n readonly shardingStrategy: ShardingStrategy;\n readonly renewRatio: number;\n readonly tls: tls.ConnectionOptions | undefined;\n readonly auth: string | undefined;\n readonly onLockLost: ((key: string, token: string) => void) | undefined;\n readonly connectTimeoutMs: number | undefined;\n readonly socketTimeoutMs: number | undefined;\n\n token: string | null = null;\n lease: number = 0;\n\n private sock: net.Socket | null = null;\n private renewTimer: ReturnType<typeof setTimeout> | null = null;\n private renewInFlight: Promise<void> | null = null;\n private closed = false;\n\n constructor(opts: BaseOptions) {\n validateKey(opts.key);\n this.key = opts.key;\n this.acquireTimeoutS = opts.acquireTimeoutS ?? 10;\n this.leaseTtlS = opts.leaseTtlS;\n this.tls = opts.tls;\n this.auth = opts.auth;\n this.onLockLost = opts.onLockLost;\n this.connectTimeoutMs = opts.connectTimeoutMs;\n this.socketTimeoutMs = opts.socketTimeoutMs;\n\n if (!Number.isInteger(this.acquireTimeoutS) || this.acquireTimeoutS < 0) {\n throw new LockError(\"acquireTimeoutS must be an integer >= 0\");\n }\n if (this.leaseTtlS != null && (!Number.isInteger(this.leaseTtlS) || this.leaseTtlS < 1)) {\n throw new LockError(\"leaseTtlS must be an integer >= 1\");\n }\n\n if (opts.servers) {\n if (opts.servers.length === 0) {\n throw new LockError(\"servers list must not be empty\");\n }\n this.servers = [...opts.servers];\n } else {\n this.servers = [[opts.host ?? DEFAULT_HOST, opts.port ?? DEFAULT_PORT]];\n }\n\n this.shardingStrategy = opts.shardingStrategy ?? stableHashShard;\n\n const renewRatio = opts.renewRatio ?? 0.5;\n if (!Number.isFinite(renewRatio) || renewRatio <= 0 || renewRatio >= 1) {\n throw new LockError(\"renewRatio must be a finite number between 0 and 1 (exclusive)\");\n }\n this.renewRatio = renewRatio;\n }\n\n // -- abstract protocol hooks (implemented by subclasses) --\n\n protected abstract doAcquire(\n sock: net.Socket,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doEnqueue(\n sock: net.Socket,\n ): Promise<{\n status: \"acquired\" | \"queued\";\n token: string | null;\n lease: number | null;\n }>;\n\n protected abstract doWait(\n sock: net.Socket,\n timeoutS: number,\n ): Promise<{ token: string; lease: number }>;\n\n protected abstract doRelease(\n sock: net.Socket,\n token: string,\n ): Promise<void>;\n\n protected abstract doRenew(\n sock: net.Socket,\n token: string,\n ): Promise<number>;\n\n // -- public API --\n\n private async openConnection(): Promise<net.Socket> {\n const [host, port] = this.pickServer();\n const sock = await connect(host, port, this.tls, this.auth, this.connectTimeoutMs);\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n // Register the listener once; use setTimeout(ms)/setTimeout(0) to\n // toggle without accumulating duplicate listeners.\n sock.on(\"timeout\", () => {\n sock.destroy(new LockError(\"socket idle timeout\"));\n });\n sock.setTimeout(this.socketTimeoutMs);\n }\n return sock;\n }\n\n /**\n * Suspend or restore the socket idle timeout. Only has effect when\n * `socketTimeoutMs` was set at construction time and a listener was\n * registered in `openConnection`.\n */\n private suspendSocketTimeout(sock: net.Socket): void {\n sock.setTimeout(0);\n }\n\n private restoreSocketTimeout(sock: net.Socket): void {\n if (this.socketTimeoutMs != null && this.socketTimeoutMs > 0) {\n sock.setTimeout(this.socketTimeoutMs);\n }\n }\n\n private pickServer(): [string, number] {\n const idx = this.shardingStrategy(this.key, this.servers.length);\n if (!Number.isInteger(idx) || idx < 0 || idx >= this.servers.length) {\n throw new LockError(\n `shardingStrategy returned invalid index ${idx} for ${this.servers.length} server(s)`,\n );\n }\n return this.servers[idx];\n }\n\n /**\n * Acquire the lock / semaphore slot.\n * Returns `true` on success, `false` on timeout.\n * @param opts.force - If `true`, silently close any existing connection\n * before acquiring. Defaults to `false`, which throws if already connected.\n */\n async acquire(opts?: { force?: boolean }): Promise<boolean> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n // Suspend socket idle timeout during the blocking acquire — the server\n // won't send data until the lock is granted or the acquire times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doAcquire(this.sock);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Release the lock / semaphore slot and close the connection.\n *\n * Throws `LockError` if the instance is already closed (e.g. after a\n * previous `release()` or `close()` call).\n *\n * The server-side release itself is best-effort: if the underlying\n * connection is already dead the protocol-level release error is silently\n * ignored so that the method doesn't throw on transient network failures.\n */\n async release(): Promise<void> {\n if (this.closed) {\n throw new LockError(\"not connected; nothing to release\");\n }\n // Capture the token and socket before awaiting anything — a concurrent\n // renew failure can set this.token/this.sock to null (via onLockLost →\n // close()), which would cause us to skip the server-side release and\n // leave the lock held until lease expiry.\n const tokenToRelease = this.token;\n const sockToRelease = this.sock;\n try {\n this.stopRenew();\n // Wait for any in-flight renew to finish before sending the release\n // command — concurrent reads/writes on the same socket are unsafe.\n // Bound the wait to 5s so release() doesn't hang forever when the\n // network is unresponsive and no socketTimeoutMs is configured.\n if (this.renewInFlight) {\n await Promise.race([\n this.renewInFlight,\n new Promise<void>((r) => setTimeout(r, 5000).unref()),\n ]);\n // The loop resumes before us (it registered its .then first) and may\n // have scheduled a new timer. Clear it so it cannot fire during\n // doRelease below.\n this.stopRenew();\n }\n if (sockToRelease != null && tokenToRelease != null) {\n try {\n await this.doRelease(sockToRelease, tokenToRelease);\n } catch {\n // Best-effort: connection may already be dead.\n }\n }\n } finally {\n this.close();\n }\n }\n\n /**\n * Two-phase step 1: connect and join the FIFO queue.\n * Returns `\"acquired\"` (fast-path) or `\"queued\"`.\n * If acquired immediately, the renew loop starts automatically.\n * @param opts.force - If `true`, silently close any existing connection\n * before enqueuing. Defaults to `false`, which throws if already connected.\n */\n async enqueue(opts?: { force?: boolean }): Promise<\"acquired\" | \"queued\"> {\n if (this.sock && !this.closed) {\n if (!opts?.force) {\n throw new LockError(\n \"already connected; call release() or close() first, or pass { force: true }\",\n );\n }\n this.close();\n }\n this.closed = false;\n try {\n this.sock = await this.openConnection();\n this.suspendSocketTimeout(this.sock);\n const result = await this.doEnqueue(this.sock);\n if (result.status === \"acquired\") {\n this.token = result.token;\n this.lease = result.lease ?? 0;\n this.restoreSocketTimeout(this.sock);\n this.startRenew();\n }\n return result.status;\n } catch (err) {\n this.close();\n throw err;\n }\n }\n\n /**\n * Two-phase step 2: block until the lock / slot is granted.\n * Returns `true` if granted, `false` on timeout.\n * If already acquired during `enqueue()`, returns `true` immediately.\n */\n async wait(timeoutS?: number): Promise<boolean> {\n if (this.token !== null) {\n // Already acquired during enqueue (fast path)\n return true;\n }\n if (this.closed) {\n throw new LockError(\"connection closed; call enqueue() again\");\n }\n if (!this.sock) {\n throw new LockError(\"not connected; call enqueue() first\");\n }\n const timeout = timeoutS ?? this.acquireTimeoutS;\n try {\n // Suspend socket idle timeout during the blocking wait — the server\n // won't send data until the lock/slot is granted or the wait times out.\n this.suspendSocketTimeout(this.sock);\n const result = await this.doWait(this.sock, timeout);\n this.restoreSocketTimeout(this.sock);\n this.token = result.token;\n this.lease = result.lease;\n } catch (err) {\n this.close();\n if (err instanceof AcquireTimeoutError) return false;\n throw err;\n }\n this.startRenew();\n return true;\n }\n\n /**\n * Run `fn` while holding the lock / slot, then release automatically.\n *\n * If `fn()` throws, its error is always preserved — a concurrent\n * release failure will not mask it.\n */\n async withLock<T>(fn: () => T | Promise<T>): Promise<T> {\n const ok = await this.acquire();\n if (!ok) {\n throw new AcquireTimeoutError(this.key);\n }\n let threw = false;\n try {\n return await fn();\n } catch (err) {\n threw = true;\n throw err;\n } finally {\n try {\n await this.release();\n } catch (releaseErr) {\n // If fn() already threw, swallow the release error so it\n // doesn't mask the original error.\n if (!threw) throw releaseErr;\n }\n }\n }\n\n /** Close the underlying socket (idempotent). */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopRenew();\n this.renewInFlight = null;\n if (this.sock) {\n this.sock.destroy();\n this.sock = null;\n }\n this.token = null;\n this.lease = 0;\n }\n\n // -- internals --\n\n private startRenew(): void {\n this.stopRenew();\n const loop = async () => {\n const savedToken = this.token;\n const sock = this.sock;\n if (!sock || !savedToken) return;\n const start = Date.now();\n const p = (async () => {\n try {\n const newLease = await this.doRenew(sock, savedToken);\n // Guard: if close() ran while the renew was in-flight, don't\n // clobber the reset state (lease=0, token=null).\n if (this.token === savedToken && !this.closed) {\n this.lease = newLease;\n }\n } catch {\n // Only signal lock-lost if we still own this token (close() may have cleared it)\n if (this.token === savedToken) {\n this.token = null;\n if (this.onLockLost) {\n try {\n // Cast to unknown: the declared return type is void, but an\n // async callback will return a Promise at runtime.\n const result: unknown = this.onLockLost(this.key, savedToken);\n // Guard against async callbacks returning a rejected Promise.\n if (result instanceof Promise) {\n result.catch(() => {});\n }\n } catch {\n // Never let a user callback crash the process.\n }\n }\n // Tear down the connection so the instance is in a clean state\n // for re-acquisition. Without this the socket leaks and a\n // subsequent acquire() without { force: true } would throw\n // \"already connected\".\n this.close();\n }\n return;\n }\n })();\n this.renewInFlight = p;\n await p;\n this.renewInFlight = null;\n // Guard: if close() was called while the renew was in-flight, don't\n // schedule another iteration (avoids clobbering a new acquire's timer).\n if (this.closed || this.token !== savedToken) return;\n const elapsed = Date.now() - start;\n const interval = Math.max(0.1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, Math.max(0, interval - elapsed));\n this.renewTimer.unref();\n };\n const interval = Math.max(0.1, this.lease * this.renewRatio) * 1000;\n this.renewTimer = setTimeout(loop, interval);\n this.renewTimer.unref();\n }\n\n private stopRenew(): void {\n if (this.renewTimer != null) {\n clearTimeout(this.renewTimer);\n this.renewTimer = null;\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedLock\n// ---------------------------------------------------------------------------\n\nexport class DistributedLock extends DistributedPrimitive {\n constructor(opts: DistributedLockOptions) {\n super(opts);\n }\n\n protected doAcquire(sock: net.Socket) {\n return acquire(sock, this.key, this.acquireTimeoutS, this.leaseTtlS);\n }\n\n protected doEnqueue(sock: net.Socket) {\n return enqueue(sock, this.key, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return waitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return release(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return renew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// DistributedSemaphore\n// ---------------------------------------------------------------------------\n\nexport class DistributedSemaphore extends DistributedPrimitive {\n readonly limit: number;\n\n constructor(opts: DistributedSemaphoreOptions) {\n super(opts);\n if (!Number.isInteger(opts.limit) || opts.limit < 1) {\n throw new LockError(\"limit must be an integer >= 1\");\n }\n this.limit = opts.limit;\n }\n\n protected doAcquire(sock: net.Socket) {\n return semAcquire(\n sock,\n this.key,\n this.acquireTimeoutS,\n this.limit,\n this.leaseTtlS,\n );\n }\n\n protected doEnqueue(sock: net.Socket) {\n return semEnqueue(sock, this.key, this.limit, this.leaseTtlS);\n }\n\n protected doWait(sock: net.Socket, timeoutS: number) {\n return semWaitForLock(sock, this.key, timeoutS);\n }\n\n protected doRelease(sock: net.Socket, token: string) {\n return semRelease(sock, this.key, token);\n }\n\n protected doRenew(sock: net.Socket, token: string) {\n return semRenew(sock, this.key, token, this.leaseTtlS);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Signal types\n// ---------------------------------------------------------------------------\n\nexport interface Signal {\n channel: string;\n payload: string;\n}\n\n// ---------------------------------------------------------------------------\n// Signal protocol functions\n// ---------------------------------------------------------------------------\n\nfunction validatePayload(payload: string): void {\n if (payload === \"\") {\n throw new LockError(\"payload must not be empty\");\n }\n if (/[\\0\\n\\r]/.test(payload)) {\n throw new LockError(\n \"payload must not contain NUL, newline, or carriage return characters\",\n );\n }\n}\n\n/**\n * Publish a signal on a channel using a regular socket (request-response).\n * Returns the number of listeners that received the signal.\n *\n * Use this when you only need to publish and don't need to receive signals.\n * For subscribing to signals, use `SignalConnection`.\n */\nexport async function publish(\n sock: net.Socket,\n channel: string,\n payload: string,\n): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n await writeAll(sock, encodeLines(\"signal\", channel, payload));\n const resp = await readline(sock);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n}\n\n// ---------------------------------------------------------------------------\n// SignalConnection\n// ---------------------------------------------------------------------------\n\nexport interface SignalConnectionOptions {\n /** Server host (default `\"127.0.0.1\"`). */\n host?: string;\n /** Server port (default `6388`). */\n port?: number;\n /** TLS options; pass `{}` for default system CA. */\n tls?: tls.ConnectionOptions;\n /** Auth token for servers started with `--auth-token`. */\n auth?: string;\n /** TCP connect timeout in milliseconds. */\n connectTimeoutMs?: number;\n}\n\n/**\n * A connection dedicated to the signal (pub/sub) protocol.\n *\n * Wraps a socket with a background line reader that separates asynchronous\n * `sig` push messages from command responses, allowing `listen`, `unlisten`,\n * and `emit` to be called while signals are being delivered.\n *\n * ```ts\n * const conn = await SignalConnection.connect();\n * conn.onSignal((sig) => console.log(sig.channel, sig.payload));\n * await conn.listen(\"events.>\");\n * ```\n */\nexport class SignalConnection {\n private sock: net.Socket;\n private buf = \"\";\n private decoder: StringDecoder;\n private responseResolve: ((line: string) => void) | null = null;\n private responseReject: ((err: Error) => void) | null = null;\n private cmdQueue: Array<() => void> = [];\n private cmdBusy = false;\n private signalListeners: Array<(signal: Signal) => void> = [];\n private _closed = false;\n\n /**\n * Wrap an existing socket as a SignalConnection.\n *\n * The socket should already be connected (and authenticated, if needed).\n * Prefer `SignalConnection.connect()` for convenience.\n */\n constructor(sock: net.Socket) {\n this.sock = sock;\n\n // Take over the readline StringDecoder to preserve any held-back bytes\n // from a multi-byte UTF-8 character split across TCP segments.\n const prevDecoder = _readlineDecoder.get(sock);\n this.decoder = prevDecoder ?? new StringDecoder(\"utf8\");\n _readlineDecoder.delete(sock);\n\n // Drain any leftover buffer from the global readline WeakMap.\n const leftover = _readlineBuf.get(sock);\n if (leftover) {\n this.buf = leftover;\n _readlineBuf.delete(sock);\n }\n\n sock.on(\"data\", (chunk: Buffer) => this.onData(chunk));\n sock.on(\"error\", (err: Error) => this.onSocketError(err));\n sock.on(\"close\", () => this.onSocketEnd());\n sock.on(\"end\", () => this.onSocketEnd());\n\n // Process any lines already buffered.\n this.drainLines();\n }\n\n /** Connect to a dflockd server and return a SignalConnection. */\n static async connect(\n opts?: SignalConnectionOptions,\n ): Promise<SignalConnection> {\n const host = opts?.host ?? DEFAULT_HOST;\n const port = opts?.port ?? DEFAULT_PORT;\n const sock = await connect(\n host,\n port,\n opts?.tls,\n opts?.auth,\n opts?.connectTimeoutMs,\n );\n return new SignalConnection(sock);\n }\n\n /**\n * Subscribe to signals matching `pattern`.\n *\n * Patterns support NATS-style wildcards:\n * - `*` matches exactly one dot-separated token\n * - `>` matches one or more trailing tokens\n *\n * If `group` is provided, the subscription joins a queue group where\n * signals are load-balanced (round-robin) among group members.\n */\n async listen(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"listen\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`listen failed: '${resp}'`);\n }\n }\n\n /**\n * Unsubscribe from signals matching `pattern`.\n * The `pattern` and `group` must match a previous `listen()` call.\n */\n async unlisten(pattern: string, group?: string): Promise<void> {\n validateKey(pattern);\n if (group != null && /[\\0\\n\\r]/.test(group)) {\n throw new LockError(\n \"group must not contain NUL, newline, or carriage return characters\",\n );\n }\n const resp = await this.sendCmd(\"unlisten\", pattern, group ?? \"\");\n if (resp !== \"ok\") {\n throw new LockError(`unlisten failed: '${resp}'`);\n }\n }\n\n /**\n * Publish a signal on a literal channel (no wildcards).\n * Returns the number of listeners that received the signal.\n */\n async emit(channel: string, payload: string): Promise<number> {\n validateKey(channel);\n validatePayload(payload);\n const resp = await this.sendCmd(\"signal\", channel, payload);\n if (!resp.startsWith(\"ok \")) {\n throw new LockError(`signal failed: '${resp}'`);\n }\n const n = parseInt(resp.split(\" \")[1], 10);\n if (!Number.isFinite(n)) {\n throw new LockError(`signal: bad delivery count: '${resp}'`);\n }\n return n;\n }\n\n /** Register a listener for incoming signals. */\n onSignal(listener: (signal: Signal) => void): void {\n this.signalListeners.push(listener);\n }\n\n /** Remove a previously registered signal listener. */\n offSignal(listener: (signal: Signal) => void): void {\n const idx = this.signalListeners.indexOf(listener);\n if (idx >= 0) this.signalListeners.splice(idx, 1);\n }\n\n /**\n * Async iterator that yields signals as they arrive.\n * Terminates when the connection closes.\n *\n * ```ts\n * for await (const sig of conn) {\n * console.log(sig.channel, sig.payload);\n * }\n * ```\n */\n async *[Symbol.asyncIterator](): AsyncIterableIterator<Signal> {\n const buffer: Signal[] = [];\n let waiter: (() => void) | null = null;\n\n const listener = (sig: Signal) => {\n buffer.push(sig);\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n const onEnd = () => {\n if (waiter) {\n const w = waiter;\n waiter = null;\n w();\n }\n };\n\n this.onSignal(listener);\n this.sock.once(\"close\", onEnd);\n\n try {\n while (true) {\n if (buffer.length > 0) {\n yield buffer.shift()!;\n continue;\n }\n if (this._closed) break;\n await new Promise<void>((resolve) => {\n waiter = resolve;\n });\n }\n // Drain any remaining buffered signals.\n while (buffer.length > 0) {\n yield buffer.shift()!;\n }\n } finally {\n this.offSignal(listener);\n this.sock.removeListener(\"close\", onEnd);\n }\n }\n\n /** Close the connection (idempotent). */\n close(): void {\n if (this._closed) return;\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(new LockError(\"connection closed\"));\n }\n\n /** Whether the connection is closed. */\n get isClosed(): boolean {\n return this._closed;\n }\n\n // ---- internals ----\n\n private onData(chunk: Buffer): void {\n this.buf += this.decoder.write(chunk);\n if (this.buf.length > MAX_LINE_LENGTH * 2) {\n this.buf = \"\";\n this._closed = true;\n this.sock.destroy();\n this.rejectPending(\n new LockError(\"server response exceeded maximum buffer size\"),\n );\n return;\n }\n this.drainLines();\n }\n\n private drainLines(): void {\n let idx: number;\n while ((idx = this.buf.indexOf(\"\\n\")) !== -1) {\n const line = this.buf.slice(0, idx).replace(/\\r$/, \"\");\n this.buf = this.buf.slice(idx + 1);\n this.handleLine(line);\n }\n }\n\n private handleLine(line: string): void {\n if (line.startsWith(\"sig \")) {\n const rest = line.slice(4);\n const spaceIdx = rest.indexOf(\" \");\n if (spaceIdx < 0) return; // malformed push, skip\n const sig: Signal = {\n channel: rest.slice(0, spaceIdx),\n payload: rest.slice(spaceIdx + 1),\n };\n for (const listener of [...this.signalListeners]) {\n try {\n listener(sig);\n } catch {\n // Never let a user callback crash the read loop.\n }\n }\n return;\n }\n // Command response.\n if (this.responseResolve) {\n const resolve = this.responseResolve;\n this.responseResolve = null;\n this.responseReject = null;\n resolve(line);\n }\n }\n\n private onSocketError(err: Error): void {\n this._closed = true;\n this.rejectPending(err);\n }\n\n private onSocketEnd(): void {\n this._closed = true;\n this.rejectPending(new LockError(\"server closed connection\"));\n }\n\n private rejectPending(err: Error): void {\n if (this.responseReject) {\n const reject = this.responseReject;\n this.responseResolve = null;\n this.responseReject = null;\n reject(err);\n }\n }\n\n private sendCmd(cmd: string, key: string, arg: string): Promise<string> {\n return new Promise<string>((outerResolve, outerReject) => {\n const execute = () => {\n if (this._closed) {\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(new LockError(\"connection closed\"));\n return;\n }\n let settled = false;\n this.responseResolve = (line: string) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerResolve(line);\n };\n this.responseReject = (err: Error) => {\n if (settled) return;\n settled = true;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n };\n this.sock.write(encodeLines(cmd, key, arg), (err) => {\n if (err && !settled) {\n settled = true;\n this.responseResolve = null;\n this.responseReject = null;\n this.cmdBusy = false;\n this.dequeueNext();\n outerReject(err);\n }\n });\n };\n\n if (this.cmdBusy) {\n this.cmdQueue.push(execute);\n } else {\n this.cmdBusy = true;\n execute();\n }\n });\n }\n\n private dequeueNext(): void {\n const next = this.cmdQueue.shift();\n if (next) {\n this.cmdBusy = true;\n next();\n }\n }\n}\n"],"mappings":"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","names":["connect","interval"]}
|