dflockd-client 1.10.3 → 1.11.0

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 CHANGED
@@ -813,13 +813,18 @@ var SignalConnection = class _SignalConnection {
813
813
  cmdBusy = false;
814
814
  signalListeners = [];
815
815
  _closed = false;
816
+ heartbeatTimer = null;
816
817
  /**
817
818
  * Wrap an existing socket as a SignalConnection.
818
819
  *
819
820
  * The socket should already be connected (and authenticated, if needed).
820
821
  * Prefer `SignalConnection.connect()` for convenience.
822
+ *
823
+ * @param sock - Connected socket.
824
+ * @param heartbeatIntervalMs - Interval between keepalive pings (default
825
+ * `15000`). Set to `0` to disable.
821
826
  */
822
- constructor(sock) {
827
+ constructor(sock, heartbeatIntervalMs = 15e3) {
823
828
  this.sock = sock;
824
829
  const prevDecoder = _readlineDecoder.get(sock);
825
830
  this.decoder = prevDecoder ?? new import_string_decoder.StringDecoder("utf8");
@@ -834,6 +839,14 @@ var SignalConnection = class _SignalConnection {
834
839
  sock.on("close", () => this.onSocketEnd());
835
840
  sock.on("end", () => this.onSocketEnd());
836
841
  this.drainLines();
842
+ if (heartbeatIntervalMs > 0) {
843
+ this.heartbeatTimer = setInterval(() => {
844
+ if (this._closed) return;
845
+ this.sendCmd("ping", "_", "").catch(() => {
846
+ });
847
+ }, heartbeatIntervalMs);
848
+ this.heartbeatTimer.unref();
849
+ }
837
850
  }
838
851
  /** Connect to a dflockd server and return a SignalConnection. */
839
852
  static async connect(opts) {
@@ -846,7 +859,7 @@ var SignalConnection = class _SignalConnection {
846
859
  opts?.auth,
847
860
  opts?.connectTimeoutMs
848
861
  );
849
- return new _SignalConnection(sock);
862
+ return new _SignalConnection(sock, opts?.heartbeatIntervalMs ?? 15e3);
850
863
  }
851
864
  /**
852
865
  * Subscribe to signals matching `pattern`.
@@ -965,6 +978,10 @@ var SignalConnection = class _SignalConnection {
965
978
  close() {
966
979
  if (this._closed) return;
967
980
  this._closed = true;
981
+ if (this.heartbeatTimer) {
982
+ clearInterval(this.heartbeatTimer);
983
+ this.heartbeatTimer = null;
984
+ }
968
985
  this.sock.destroy();
969
986
  this.rejectPending(new LockError("connection closed"));
970
987
  }
@@ -1020,10 +1037,18 @@ var SignalConnection = class _SignalConnection {
1020
1037
  }
1021
1038
  onSocketError(err) {
1022
1039
  this._closed = true;
1040
+ if (this.heartbeatTimer) {
1041
+ clearInterval(this.heartbeatTimer);
1042
+ this.heartbeatTimer = null;
1043
+ }
1023
1044
  this.rejectPending(err);
1024
1045
  }
1025
1046
  onSocketEnd() {
1026
1047
  this._closed = true;
1048
+ if (this.heartbeatTimer) {
1049
+ clearInterval(this.heartbeatTimer);
1050
+ this.heartbeatTimer = null;
1051
+ }
1027
1052
  this.rejectPending(new LockError("server closed connection"));
1028
1053
  }
1029
1054
  rejectPending(err) {
@@ -1 +1 @@
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"]}
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 * Interval in milliseconds between heartbeat pings sent to the server to\n * keep idle signal connections alive (default `15000`). Set to `0` to\n * disable the heartbeat.\n */\n heartbeatIntervalMs?: 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 private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\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 * @param sock - Connected socket.\n * @param heartbeatIntervalMs - Interval between keepalive pings (default\n * `15000`). Set to `0` to disable.\n */\n constructor(sock: net.Socket, heartbeatIntervalMs = 15_000) {\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 // Start heartbeat to keep idle signal connections alive.\n if (heartbeatIntervalMs > 0) {\n this.heartbeatTimer = setInterval(() => {\n if (this._closed) return;\n this.sendCmd(\"ping\", \"_\", \"\").catch(() => {});\n }, heartbeatIntervalMs);\n this.heartbeatTimer.unref();\n }\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, opts?.heartbeatIntervalMs ?? 15_000);\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 if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\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 if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n this.rejectPending(err);\n }\n\n private onSocketEnd(): void {\n this._closed = true;\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\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
@@ -266,6 +266,12 @@ interface SignalConnectionOptions {
266
266
  auth?: string;
267
267
  /** TCP connect timeout in milliseconds. */
268
268
  connectTimeoutMs?: number;
269
+ /**
270
+ * Interval in milliseconds between heartbeat pings sent to the server to
271
+ * keep idle signal connections alive (default `15000`). Set to `0` to
272
+ * disable the heartbeat.
273
+ */
274
+ heartbeatIntervalMs?: number;
269
275
  }
270
276
  /**
271
277
  * A connection dedicated to the signal (pub/sub) protocol.
@@ -290,13 +296,18 @@ declare class SignalConnection {
290
296
  private cmdBusy;
291
297
  private signalListeners;
292
298
  private _closed;
299
+ private heartbeatTimer;
293
300
  /**
294
301
  * Wrap an existing socket as a SignalConnection.
295
302
  *
296
303
  * The socket should already be connected (and authenticated, if needed).
297
304
  * Prefer `SignalConnection.connect()` for convenience.
305
+ *
306
+ * @param sock - Connected socket.
307
+ * @param heartbeatIntervalMs - Interval between keepalive pings (default
308
+ * `15000`). Set to `0` to disable.
298
309
  */
299
- constructor(sock: net.Socket);
310
+ constructor(sock: net.Socket, heartbeatIntervalMs?: number);
300
311
  /** Connect to a dflockd server and return a SignalConnection. */
301
312
  static connect(opts?: SignalConnectionOptions): Promise<SignalConnection>;
302
313
  /**
package/dist/client.d.ts CHANGED
@@ -266,6 +266,12 @@ interface SignalConnectionOptions {
266
266
  auth?: string;
267
267
  /** TCP connect timeout in milliseconds. */
268
268
  connectTimeoutMs?: number;
269
+ /**
270
+ * Interval in milliseconds between heartbeat pings sent to the server to
271
+ * keep idle signal connections alive (default `15000`). Set to `0` to
272
+ * disable the heartbeat.
273
+ */
274
+ heartbeatIntervalMs?: number;
269
275
  }
270
276
  /**
271
277
  * A connection dedicated to the signal (pub/sub) protocol.
@@ -290,13 +296,18 @@ declare class SignalConnection {
290
296
  private cmdBusy;
291
297
  private signalListeners;
292
298
  private _closed;
299
+ private heartbeatTimer;
293
300
  /**
294
301
  * Wrap an existing socket as a SignalConnection.
295
302
  *
296
303
  * The socket should already be connected (and authenticated, if needed).
297
304
  * Prefer `SignalConnection.connect()` for convenience.
305
+ *
306
+ * @param sock - Connected socket.
307
+ * @param heartbeatIntervalMs - Interval between keepalive pings (default
308
+ * `15000`). Set to `0` to disable.
298
309
  */
299
- constructor(sock: net.Socket);
310
+ constructor(sock: net.Socket, heartbeatIntervalMs?: number);
300
311
  /** Connect to a dflockd server and return a SignalConnection. */
301
312
  static connect(opts?: SignalConnectionOptions): Promise<SignalConnection>;
302
313
  /**
package/dist/client.js CHANGED
@@ -761,13 +761,18 @@ var SignalConnection = class _SignalConnection {
761
761
  cmdBusy = false;
762
762
  signalListeners = [];
763
763
  _closed = false;
764
+ heartbeatTimer = null;
764
765
  /**
765
766
  * Wrap an existing socket as a SignalConnection.
766
767
  *
767
768
  * The socket should already be connected (and authenticated, if needed).
768
769
  * Prefer `SignalConnection.connect()` for convenience.
770
+ *
771
+ * @param sock - Connected socket.
772
+ * @param heartbeatIntervalMs - Interval between keepalive pings (default
773
+ * `15000`). Set to `0` to disable.
769
774
  */
770
- constructor(sock) {
775
+ constructor(sock, heartbeatIntervalMs = 15e3) {
771
776
  this.sock = sock;
772
777
  const prevDecoder = _readlineDecoder.get(sock);
773
778
  this.decoder = prevDecoder ?? new StringDecoder("utf8");
@@ -782,6 +787,14 @@ var SignalConnection = class _SignalConnection {
782
787
  sock.on("close", () => this.onSocketEnd());
783
788
  sock.on("end", () => this.onSocketEnd());
784
789
  this.drainLines();
790
+ if (heartbeatIntervalMs > 0) {
791
+ this.heartbeatTimer = setInterval(() => {
792
+ if (this._closed) return;
793
+ this.sendCmd("ping", "_", "").catch(() => {
794
+ });
795
+ }, heartbeatIntervalMs);
796
+ this.heartbeatTimer.unref();
797
+ }
785
798
  }
786
799
  /** Connect to a dflockd server and return a SignalConnection. */
787
800
  static async connect(opts) {
@@ -794,7 +807,7 @@ var SignalConnection = class _SignalConnection {
794
807
  opts?.auth,
795
808
  opts?.connectTimeoutMs
796
809
  );
797
- return new _SignalConnection(sock);
810
+ return new _SignalConnection(sock, opts?.heartbeatIntervalMs ?? 15e3);
798
811
  }
799
812
  /**
800
813
  * Subscribe to signals matching `pattern`.
@@ -913,6 +926,10 @@ var SignalConnection = class _SignalConnection {
913
926
  close() {
914
927
  if (this._closed) return;
915
928
  this._closed = true;
929
+ if (this.heartbeatTimer) {
930
+ clearInterval(this.heartbeatTimer);
931
+ this.heartbeatTimer = null;
932
+ }
916
933
  this.sock.destroy();
917
934
  this.rejectPending(new LockError("connection closed"));
918
935
  }
@@ -968,10 +985,18 @@ var SignalConnection = class _SignalConnection {
968
985
  }
969
986
  onSocketError(err) {
970
987
  this._closed = true;
988
+ if (this.heartbeatTimer) {
989
+ clearInterval(this.heartbeatTimer);
990
+ this.heartbeatTimer = null;
991
+ }
971
992
  this.rejectPending(err);
972
993
  }
973
994
  onSocketEnd() {
974
995
  this._closed = true;
996
+ if (this.heartbeatTimer) {
997
+ clearInterval(this.heartbeatTimer);
998
+ this.heartbeatTimer = null;
999
+ }
975
1000
  this.rejectPending(new LockError("server closed connection"));
976
1001
  }
977
1002
  rejectPending(err) {
@@ -1 +1 @@
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"]}
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 * Interval in milliseconds between heartbeat pings sent to the server to\n * keep idle signal connections alive (default `15000`). Set to `0` to\n * disable the heartbeat.\n */\n heartbeatIntervalMs?: 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 private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\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 * @param sock - Connected socket.\n * @param heartbeatIntervalMs - Interval between keepalive pings (default\n * `15000`). Set to `0` to disable.\n */\n constructor(sock: net.Socket, heartbeatIntervalMs = 15_000) {\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 // Start heartbeat to keep idle signal connections alive.\n if (heartbeatIntervalMs > 0) {\n this.heartbeatTimer = setInterval(() => {\n if (this._closed) return;\n this.sendCmd(\"ping\", \"_\", \"\").catch(() => {});\n }, heartbeatIntervalMs);\n this.heartbeatTimer.unref();\n }\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, opts?.heartbeatIntervalMs ?? 15_000);\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 if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\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 if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n this.rejectPending(err);\n }\n\n private onSocketEnd(): void {\n this._closed = true;\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dflockd-client",
3
- "version": "1.10.3",
3
+ "version": "1.11.0",
4
4
  "description": "TypeScript client for the dflockd distributed lock daemon",
5
5
  "type": "module",
6
6
  "exports": {