@crow-agent/server 0.0.0-stage → 0.1.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.
Files changed (66) hide show
  1. package/README.md +108 -2
  2. package/dist/public-api.d.ts +5 -0
  3. package/dist/public-api.d.ts.map +1 -0
  4. package/dist/public-api.js +3 -0
  5. package/dist/public-api.js.map +1 -0
  6. package/dist/server-connection.d.ts +32 -0
  7. package/dist/server-connection.d.ts.map +1 -0
  8. package/dist/server-connection.js +5 -0
  9. package/dist/server-connection.js.map +1 -0
  10. package/dist/server-errors.d.ts +31 -0
  11. package/dist/server-errors.d.ts.map +1 -0
  12. package/dist/server-errors.js +41 -0
  13. package/dist/server-errors.js.map +1 -0
  14. package/dist/server-listener.d.ts +8 -0
  15. package/dist/server-listener.d.ts.map +1 -0
  16. package/dist/server-listener.js +2 -0
  17. package/dist/server-listener.js.map +1 -0
  18. package/dist/server-types.d.ts +52 -0
  19. package/dist/server-types.d.ts.map +1 -0
  20. package/dist/server-types.js +2 -0
  21. package/dist/server-types.js.map +1 -0
  22. package/dist/session-routing.d.ts +42 -0
  23. package/dist/session-routing.d.ts.map +1 -0
  24. package/dist/session-routing.js +300 -0
  25. package/dist/session-routing.js.map +1 -0
  26. package/dist/session-server.d.ts +14 -0
  27. package/dist/session-server.d.ts.map +1 -0
  28. package/dist/session-server.js +678 -0
  29. package/dist/session-server.js.map +1 -0
  30. package/dist/testing/public-api.d.ts +6 -0
  31. package/dist/testing/public-api.d.ts.map +1 -0
  32. package/dist/testing/public-api.js +4 -0
  33. package/dist/testing/public-api.js.map +1 -0
  34. package/dist/testing/test-client.d.ts +29 -0
  35. package/dist/testing/test-client.d.ts.map +1 -0
  36. package/dist/testing/test-client.js +196 -0
  37. package/dist/testing/test-client.js.map +1 -0
  38. package/dist/testing/test-host.d.ts +62 -0
  39. package/dist/testing/test-host.d.ts.map +1 -0
  40. package/dist/testing/test-host.js +241 -0
  41. package/dist/testing/test-host.js.map +1 -0
  42. package/dist/testing/test-server.d.ts +13 -0
  43. package/dist/testing/test-server.d.ts.map +1 -0
  44. package/dist/testing/test-server.js +17 -0
  45. package/dist/testing/test-server.js.map +1 -0
  46. package/dist/transports/unix/public-api.d.ts +5 -0
  47. package/dist/transports/unix/public-api.d.ts.map +1 -0
  48. package/dist/transports/unix/public-api.js +4 -0
  49. package/dist/transports/unix/public-api.js.map +1 -0
  50. package/dist/transports/unix/socket-address.d.ts +3 -0
  51. package/dist/transports/unix/socket-address.d.ts.map +1 -0
  52. package/dist/transports/unix/socket-address.js +11 -0
  53. package/dist/transports/unix/socket-address.js.map +1 -0
  54. package/dist/transports/unix/unix-listener.d.ts +18 -0
  55. package/dist/transports/unix/unix-listener.d.ts.map +1 -0
  56. package/dist/transports/unix/unix-listener.js +511 -0
  57. package/dist/transports/unix/unix-listener.js.map +1 -0
  58. package/dist/transports/unix/unix-preset.d.ts +7 -0
  59. package/dist/transports/unix/unix-preset.d.ts.map +1 -0
  60. package/dist/transports/unix/unix-preset.js +25 -0
  61. package/dist/transports/unix/unix-preset.js.map +1 -0
  62. package/dist/transports/unix/unix-types.d.ts +14 -0
  63. package/dist/transports/unix/unix-types.d.ts.map +1 -0
  64. package/dist/transports/unix/unix-types.js +2 -0
  65. package/dist/transports/unix/unix-types.js.map +1 -0
  66. package/package.json +53 -4
@@ -0,0 +1,511 @@
1
+ import { createHash, randomUUID, } from "node:crypto";
2
+ import { chmod, link, lstat, mkdir, rename, unlink, } from "node:fs/promises";
3
+ import { createConnection, createServer, } from "node:net";
4
+ import { dirname, join, } from "node:path";
5
+ import { DEFAULT_MAX_FRAME_LENGTH } from "@crow-agent/protocol";
6
+ const DEFAULT_SOCKET_MODE = 0o600;
7
+ const DEFAULT_GRACEFUL_CLOSE_TIMEOUT_MS = 5000;
8
+ const MAX_UINT32 = 0xffffffff;
9
+ const MAX_TIMER_DELAY_MS = 2147483647;
10
+ const SOCKET_PROBE_TIMEOUT_MS = 1000;
11
+ class UnixSocketListener {
12
+ #resolved;
13
+ #socketPath;
14
+ #socketMode;
15
+ #live = new Set();
16
+ #netServer;
17
+ #boundIdentity;
18
+ #stagingPath;
19
+ #stopping = false;
20
+ #stopTask;
21
+ #acceptor;
22
+ constructor(options) {
23
+ const resolved = resolveListenerOptions(options);
24
+ this.#resolved = resolved;
25
+ this.#socketPath = resolved.path;
26
+ this.#socketMode = resolved.mode;
27
+ }
28
+ async start(accept) {
29
+ if (this.#netServer !== undefined)
30
+ throw new Error("Unix listener is already started");
31
+ if (this.#stopping)
32
+ throw new Error("Unix listener is closing or closed");
33
+ this.#acceptor = accept;
34
+ const stagingPath = await this.prepareStagingPath();
35
+ const netServer = createServer((socket) => this.handleSocket(socket));
36
+ netServer.on("error", (error) => this.noteError(error));
37
+ this.#netServer = netServer;
38
+ try {
39
+ await this.bindServer(netServer, stagingPath);
40
+ await this.publishSocket(stagingPath);
41
+ }
42
+ catch (error) {
43
+ await this.shutdownNetServer(netServer);
44
+ this.#netServer = undefined;
45
+ throw error;
46
+ }
47
+ }
48
+ async close() {
49
+ const stopping = this.#stopTask;
50
+ if (stopping !== undefined)
51
+ return stopping;
52
+ this.#stopping = true;
53
+ const task = this.closeInternal();
54
+ this.#stopTask = task;
55
+ return task;
56
+ }
57
+ async prepareStagingPath() {
58
+ const stagingPath = ownedBindPath(this.#socketPath);
59
+ const dir = dirname(this.#socketPath);
60
+ await mkdir(dir, { recursive: true, mode: 0o700 });
61
+ await clearStaleSocket(this.#socketPath);
62
+ await clearStaleSocket(stagingPath);
63
+ this.#stagingPath = stagingPath;
64
+ return stagingPath;
65
+ }
66
+ bindServer(netServer, stagingPath) {
67
+ return new Promise((resolve, reject) => {
68
+ function onError(error) {
69
+ netServer.off("listening", onListening);
70
+ reject(error);
71
+ }
72
+ function onListening() {
73
+ netServer.off("error", onError);
74
+ resolve();
75
+ }
76
+ netServer.once("error", onError);
77
+ netServer.once("listening", onListening);
78
+ netServer.listen(stagingPath);
79
+ });
80
+ }
81
+ async publishSocket(stagingPath) {
82
+ const stats = await lstat(stagingPath);
83
+ if (!stats.isSocket()) {
84
+ throw new Error(`Unix listener path is not a socket after binding: ${stagingPath}`);
85
+ }
86
+ this.#boundIdentity = { dev: stats.dev, ino: stats.ino };
87
+ await link(stagingPath, this.#socketPath);
88
+ await applySocketMode(this.#socketPath, this.#socketMode);
89
+ await deletePath(stagingPath);
90
+ this.#stagingPath = undefined;
91
+ }
92
+ handleSocket(socket) {
93
+ if (this.#stopping) {
94
+ socket.destroy();
95
+ return;
96
+ }
97
+ const timeoutMs = this.#resolved.gracefulCloseTimeoutMs;
98
+ const maxBytes = this.#resolved.maxPendingBytes;
99
+ const connection = new UnixByteConnection(socket, timeoutMs, maxBytes);
100
+ this.#live.add(connection);
101
+ const acceptor = this.#acceptor;
102
+ if (acceptor === undefined) {
103
+ socket.destroy();
104
+ return;
105
+ }
106
+ const handler = acceptor(connection);
107
+ const onData = (chunk) => {
108
+ const bytes = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
109
+ handler.onData(bytes);
110
+ };
111
+ const onSocketError = (error) => {
112
+ handler.onError(error);
113
+ socket.destroy();
114
+ };
115
+ const onClose = () => {
116
+ connection.markClosed();
117
+ this.#live.delete(connection);
118
+ handler.onClose();
119
+ };
120
+ socket.on("data", onData);
121
+ socket.on("error", onSocketError);
122
+ socket.once("close", onClose);
123
+ }
124
+ async closeInternal() {
125
+ const netServer = this.#netServer;
126
+ const serverClosed = netServer === undefined ? this.removeOwnedSocket() : this.shutdownNetServer(netServer);
127
+ const connections = [...this.#live];
128
+ await Promise.all(connections.map((connection) => connection.close()));
129
+ await serverClosed;
130
+ const staging = this.#stagingPath;
131
+ if (staging !== undefined)
132
+ await deletePath(staging);
133
+ this.#stagingPath = undefined;
134
+ this.#live.clear();
135
+ this.#netServer = undefined;
136
+ }
137
+ async shutdownNetServer(netServer) {
138
+ try {
139
+ await closeNetServer(netServer, (error) => this.noteError(error));
140
+ }
141
+ finally {
142
+ // An unpublished staging bind path goes before the public socket path.
143
+ const staging = this.#stagingPath;
144
+ if (staging !== undefined)
145
+ await deletePath(staging);
146
+ this.#stagingPath = undefined;
147
+ await this.removeOwnedSocket();
148
+ }
149
+ }
150
+ async removeOwnedSocket() {
151
+ const identity = this.#boundIdentity;
152
+ this.#boundIdentity = undefined;
153
+ if (identity === undefined)
154
+ return;
155
+ const current = await this.lstatOwnedPath();
156
+ if (current === undefined)
157
+ return;
158
+ if (!current.isSocket() || current.dev !== identity.dev || current.ino !== identity.ino)
159
+ return;
160
+ await this.quarantineOwnedSocket(identity);
161
+ }
162
+ async lstatOwnedPath() {
163
+ try {
164
+ return await lstat(this.#socketPath);
165
+ }
166
+ catch (error) {
167
+ if (hasErrorCode(error, "ENOENT"))
168
+ return undefined;
169
+ throw error;
170
+ }
171
+ }
172
+ async quarantineOwnedSocket(identity) {
173
+ const dir = dirname(this.#socketPath);
174
+ const preserved = join(dir, `cleanup-${randomUUID().slice(0, 6)}`);
175
+ try {
176
+ await rename(this.#socketPath, preserved);
177
+ }
178
+ catch (error) {
179
+ if (hasErrorCode(error, "ENOENT"))
180
+ return;
181
+ throw error;
182
+ }
183
+ const moved = await lstat(preserved);
184
+ const intact = moved.isSocket() && moved.dev === identity.dev && moved.ino === identity.ino;
185
+ if (intact) {
186
+ await deletePath(preserved);
187
+ return;
188
+ }
189
+ await this.restoreQuarantinedSocket(preserved);
190
+ }
191
+ async restoreQuarantinedSocket(preserved) {
192
+ let exists = true;
193
+ try {
194
+ await lstat(this.#socketPath);
195
+ }
196
+ catch (error) {
197
+ if (hasErrorCode(error, "ENOENT"))
198
+ exists = false;
199
+ else
200
+ throw error;
201
+ }
202
+ if (!exists)
203
+ await rename(preserved, this.#socketPath);
204
+ throw new Error(`Unix listener path changed during cleanup; preserved replacement at ${preserved}`);
205
+ }
206
+ noteError(error) {
207
+ const normalized = error instanceof Error ? error : new Error(String(error));
208
+ try {
209
+ this.#resolved.onError?.(normalized);
210
+ }
211
+ catch {
212
+ // Listener state is unaffected by observer failures.
213
+ }
214
+ }
215
+ }
216
+ /** Exported for transport-level verification; not part of the public API surface. */
217
+ export class UnixByteConnection {
218
+ #socket;
219
+ #gracefulCloseTimeoutMs;
220
+ #maxPendingBytes;
221
+ #pendingBytes = 0;
222
+ #closed = false;
223
+ #closing = false;
224
+ #writeTail = Promise.resolve();
225
+ #closeTask;
226
+ #finishClose;
227
+ constructor(socket, gracefulCloseTimeoutMs, maxPendingBytes) {
228
+ this.#socket = socket;
229
+ this.#gracefulCloseTimeoutMs = gracefulCloseTimeoutMs;
230
+ this.#maxPendingBytes = maxPendingBytes;
231
+ }
232
+ get closed() {
233
+ return this.#closed;
234
+ }
235
+ send(chunk) {
236
+ if (!(chunk instanceof Uint8Array)) {
237
+ return Promise.reject(new TypeError("Unix connection chunks must be Uint8Array"));
238
+ }
239
+ if (this.#closed || this.#closing) {
240
+ return Promise.reject(new Error("Unix connection is closed"));
241
+ }
242
+ const pending = this.#pendingBytes + chunk.byteLength;
243
+ if (pending > this.#maxPendingBytes) {
244
+ return Promise.reject(new Error("Unix connection exceeded its pending byte limit"));
245
+ }
246
+ this.#pendingBytes = pending;
247
+ const bytes = chunk.slice();
248
+ const write = this.#writeTail.then(() => this.flush(bytes));
249
+ const tracked = write.finally(() => {
250
+ this.#pendingBytes = this.#pendingBytes - bytes.byteLength;
251
+ });
252
+ this.#writeTail = tracked.catch(noop);
253
+ return tracked;
254
+ }
255
+ close(finalChunk) {
256
+ if (this.#closed || this.#socket.destroyed) {
257
+ this.markClosed();
258
+ return Promise.resolve();
259
+ }
260
+ const pending = this.#closeTask;
261
+ if (pending !== undefined)
262
+ return pending;
263
+ this.#closing = true;
264
+ const finalBytes = finalChunk === undefined ? undefined : finalChunk.slice();
265
+ const task = new Promise((resolve) => {
266
+ this.#finishClose = resolve;
267
+ const timer = setTimeout(() => this.forceClose(), this.#gracefulCloseTimeoutMs);
268
+ timer.unref();
269
+ this.#socket.once("close", () => clearTimeout(timer));
270
+ void this.#writeTail.then(() => this.endSocket(finalBytes));
271
+ });
272
+ this.#closeTask = task;
273
+ return task;
274
+ }
275
+ markClosed() {
276
+ if (this.#closed)
277
+ return;
278
+ this.#closed = true;
279
+ this.#closing = true;
280
+ const finish = this.#finishClose;
281
+ this.#finishClose = undefined;
282
+ finish?.();
283
+ }
284
+ forceClose() {
285
+ if (!this.#socket.destroyed)
286
+ this.#socket.destroy();
287
+ this.markClosed();
288
+ }
289
+ endSocket(finalBytes) {
290
+ if (this.#socket.destroyed) {
291
+ this.markClosed();
292
+ return;
293
+ }
294
+ try {
295
+ if (finalBytes !== undefined)
296
+ this.#socket.end(finalBytes);
297
+ else
298
+ this.#socket.end();
299
+ }
300
+ catch {
301
+ this.#socket.destroy();
302
+ }
303
+ }
304
+ flush(chunk) {
305
+ const writable = !this.#closed && !this.#closing && this.#socket.writable;
306
+ if (!writable)
307
+ return Promise.reject(new Error("Unix connection is closed"));
308
+ return new Promise((resolve, reject) => {
309
+ let settled = false;
310
+ const done = (error) => {
311
+ if (settled)
312
+ return;
313
+ settled = true;
314
+ this.#socket.off("close", onClose);
315
+ if (error)
316
+ reject(error);
317
+ else
318
+ resolve();
319
+ };
320
+ const onClose = () => {
321
+ done(new Error("Unix connection closed during write"));
322
+ };
323
+ this.#socket.once("close", onClose);
324
+ try {
325
+ this.#socket.write(chunk, done);
326
+ }
327
+ catch (error) {
328
+ const failure = error instanceof Error ? error : new Error(String(error));
329
+ done(failure);
330
+ }
331
+ });
332
+ }
333
+ }
334
+ function noop() { }
335
+ function ownedBindPath(path) {
336
+ const digest = createHash("sha256").update(path).digest("hex");
337
+ const suffix = digest.slice(0, 8);
338
+ return join(dirname(path), `bind-${suffix}`);
339
+ }
340
+ async function clearStaleSocket(path) {
341
+ const original = await lstatSocketPath(path);
342
+ if (original === undefined)
343
+ return;
344
+ if (!original.isSocket()) {
345
+ throw new Error(`Refusing to remove non-socket Unix listener path: ${path}`);
346
+ }
347
+ const live = await probeSocket(path);
348
+ if (live)
349
+ throw new Error(`Unix listener is already running: ${path}`);
350
+ await quarantineStaleSocket(path, original);
351
+ }
352
+ async function lstatSocketPath(path) {
353
+ try {
354
+ return await lstat(path);
355
+ }
356
+ catch (error) {
357
+ if (hasErrorCode(error, "ENOENT"))
358
+ return undefined;
359
+ throw error;
360
+ }
361
+ }
362
+ async function quarantineStaleSocket(path, original) {
363
+ const preserved = join(dirname(path), `stale-${randomUUID().slice(0, 6)}`);
364
+ try {
365
+ await rename(path, preserved);
366
+ }
367
+ catch (error) {
368
+ if (hasErrorCode(error, "ENOENT"))
369
+ return;
370
+ throw error;
371
+ }
372
+ const current = await lstat(preserved);
373
+ const sameFile = current.isSocket() && current.dev === original.dev && current.ino === original.ino;
374
+ if (!sameFile) {
375
+ await restoreStaleSocket(path, preserved);
376
+ }
377
+ await deletePath(preserved);
378
+ }
379
+ async function restoreStaleSocket(path, preserved) {
380
+ let exists = true;
381
+ try {
382
+ await lstat(path);
383
+ }
384
+ catch (error) {
385
+ if (hasErrorCode(error, "ENOENT"))
386
+ exists = false;
387
+ else
388
+ throw error;
389
+ }
390
+ if (!exists)
391
+ await rename(preserved, path);
392
+ throw new Error(`Unix listener path changed while checking for a stale socket: ${path}`);
393
+ }
394
+ async function deletePath(path) {
395
+ try {
396
+ await unlink(path);
397
+ }
398
+ catch (error) {
399
+ if (!hasErrorCode(error, "ENOENT"))
400
+ throw error;
401
+ }
402
+ }
403
+ function probeSocket(path) {
404
+ return new Promise((resolve, reject) => {
405
+ const socket = createConnection(path);
406
+ let settled = false;
407
+ const timer = setTimeout(() => finish(true), SOCKET_PROBE_TIMEOUT_MS);
408
+ timer.unref();
409
+ const finish = (result, error) => {
410
+ if (settled)
411
+ return;
412
+ settled = true;
413
+ clearTimeout(timer);
414
+ socket.removeAllListeners();
415
+ socket.destroy();
416
+ if (error !== undefined)
417
+ reject(error);
418
+ else
419
+ resolve(result);
420
+ };
421
+ const onConnect = () => finish(true);
422
+ const onError = (error) => {
423
+ const dead = ["ECONNREFUSED", "ENOENT", "EPIPE", "ECONNRESET"].includes(error.code ?? "");
424
+ if (dead)
425
+ finish(false);
426
+ else
427
+ finish(false, error);
428
+ };
429
+ socket.once("connect", onConnect);
430
+ socket.once("error", onError);
431
+ });
432
+ }
433
+ async function applySocketMode(path, mode) {
434
+ if (process.platform === "win32")
435
+ return;
436
+ try {
437
+ await chmod(path, mode);
438
+ }
439
+ catch (error) {
440
+ const unsupported = hasErrorCode(error, "ENOSYS") || hasErrorCode(error, "ENOTSUP");
441
+ if (!unsupported)
442
+ throw error;
443
+ }
444
+ }
445
+ function closeNetServer(server, noteError) {
446
+ if (!server.listening)
447
+ return Promise.resolve();
448
+ return new Promise((resolve) => {
449
+ server.close((error) => {
450
+ if (error !== undefined)
451
+ noteError(error);
452
+ resolve();
453
+ });
454
+ });
455
+ }
456
+ function hasErrorCode(error, code) {
457
+ if (!(error instanceof Error))
458
+ return false;
459
+ return "code" in error && error.code === code;
460
+ }
461
+ export function createUnixListener(options) {
462
+ return new UnixSocketListener(options);
463
+ }
464
+ function resolveListenerOptions(options) {
465
+ const path = requireSocketPath(options.path);
466
+ const mode = requireSocketMode(options.mode);
467
+ const maxFrameLength = requireMaxFrameLength(options.maxFrameLength);
468
+ const maxPendingBytes = requireMaxPendingBytes(options.maxPendingBytes, maxFrameLength);
469
+ const gracefulCloseTimeoutMs = requireGracefulCloseTimeoutMs(options.gracefulCloseTimeoutMs);
470
+ return {
471
+ path,
472
+ mode,
473
+ maxPendingBytes,
474
+ gracefulCloseTimeoutMs,
475
+ onError: options.onError,
476
+ };
477
+ }
478
+ function requireSocketPath(path) {
479
+ if (!path)
480
+ throw new TypeError("Unix listener requires a non-empty socket path");
481
+ return path;
482
+ }
483
+ function requireSocketMode(mode) {
484
+ const value = mode ?? DEFAULT_SOCKET_MODE;
485
+ const valid = Number.isInteger(value) && value >= 0 && value <= 0o777;
486
+ if (!valid)
487
+ throw new TypeError("Unix socket mode must be an integer from 0 to 0o777");
488
+ return value;
489
+ }
490
+ function requireMaxFrameLength(maxFrameLength) {
491
+ const value = maxFrameLength ?? DEFAULT_MAX_FRAME_LENGTH;
492
+ const valid = Number.isSafeInteger(value) && value > 0 && value <= MAX_UINT32;
493
+ if (!valid)
494
+ throw new TypeError(`maxFrameLength must be a positive integer up to ${MAX_UINT32}`);
495
+ return value;
496
+ }
497
+ function requireMaxPendingBytes(maxPendingBytes, maxFrameLength) {
498
+ const value = maxPendingBytes ?? maxFrameLength * 4;
499
+ const valid = Number.isSafeInteger(value) && value >= maxFrameLength + 4;
500
+ if (!valid)
501
+ throw new TypeError("maxPendingBytes must be a safe integer of at least maxFrameLength + 4");
502
+ return value;
503
+ }
504
+ function requireGracefulCloseTimeoutMs(gracefulCloseTimeoutMs) {
505
+ const value = gracefulCloseTimeoutMs ?? DEFAULT_GRACEFUL_CLOSE_TIMEOUT_MS;
506
+ const valid = Number.isSafeInteger(value) && value > 0 && value <= MAX_TIMER_DELAY_MS;
507
+ if (!valid)
508
+ throw new TypeError(`gracefulCloseTimeoutMs must be an integer from 1 to ${MAX_TIMER_DELAY_MS}`);
509
+ return value;
510
+ }
511
+ //# sourceMappingURL=unix-listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unix-listener.js","sourceRoot":"","sources":["../../../src/transports/unix/unix-listener.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tcreateHash,\n\trandomUUID,\n} from \"node:crypto\";\nimport type {\n\tStats,\n} from \"node:fs\";\nimport {\n\tchmod,\n\tlink,\n\tlstat,\n\tmkdir,\n\trename,\n\tunlink,\n} from \"node:fs/promises\";\nimport {\n\tcreateConnection,\n\tcreateServer,\n\ttype Server,\n\ttype Socket,\n} from \"node:net\";\nimport {\n\tdirname,\n\tjoin,\n} from \"node:path\";\nimport { DEFAULT_MAX_FRAME_LENGTH } from \"@crow-agent/protocol\";\nimport type {\n\tByteConnection,\n\tByteConnectionAcceptor,\n} from \"../../server-connection.ts\";\nimport type {\n\tServerListener,\n} from \"../../server-listener.ts\";\nimport type {\n\tUnixListenerOptions,\n} from \"./unix-types.ts\";\n\nconst DEFAULT_SOCKET_MODE = 0o600;\nconst DEFAULT_GRACEFUL_CLOSE_TIMEOUT_MS = 5000;\nconst MAX_UINT32 = 0xffffffff;\nconst MAX_TIMER_DELAY_MS = 2147483647;\nconst SOCKET_PROBE_TIMEOUT_MS = 1000;\n\ntype ResolvedListenerOptions = {\n\tpath: string;\n\tmode: number;\n\tmaxPendingBytes: number;\n\tgracefulCloseTimeoutMs: number;\n\tonError?: (error: Error) => void;\n};\n\ntype SocketIdentity = {\n\tino: number;\n\tdev: number;\n};\n\nclass UnixSocketListener implements ServerListener {\n\t#resolved: ResolvedListenerOptions;\n\t#socketPath: string;\n\t#socketMode: number;\n\t#live = new Set<UnixByteConnection>();\n\t#netServer: Server | undefined;\n\t#boundIdentity: SocketIdentity | undefined;\n\t#stagingPath: string | undefined;\n\t#stopping = false;\n\t#stopTask: Promise<void> | undefined;\n\t#acceptor: ByteConnectionAcceptor | undefined;\n\n\tconstructor(\n\t\toptions: UnixListenerOptions,\n\t) {\n\t\tconst resolved = resolveListenerOptions(options);\n\t\tthis.#resolved = resolved;\n\t\tthis.#socketPath = resolved.path;\n\t\tthis.#socketMode = resolved.mode;\n\t}\n\n\tasync start(\n\t\taccept: ByteConnectionAcceptor,\n\t): Promise<void> {\n\t\tif (this.#netServer !== undefined) throw new Error(\"Unix listener is already started\");\n\t\tif (this.#stopping) throw new Error(\"Unix listener is closing or closed\");\n\t\tthis.#acceptor = accept;\n\n\t\tconst stagingPath = await this.prepareStagingPath();\n\t\tconst netServer = createServer((socket) => this.handleSocket(socket));\n\t\tnetServer.on(\"error\", (error) => this.noteError(error));\n\t\tthis.#netServer = netServer;\n\t\ttry {\n\t\t\tawait this.bindServer(netServer, stagingPath);\n\t\t\tawait this.publishSocket(stagingPath);\n\t\t} catch (error) {\n\t\t\tawait this.shutdownNetServer(netServer);\n\t\t\tthis.#netServer = undefined;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync close():\n\t\tPromise<void> {\n\t\tconst stopping = this.#stopTask;\n\t\tif (stopping !== undefined) return stopping;\n\t\tthis.#stopping = true;\n\t\tconst task = this.closeInternal();\n\t\tthis.#stopTask = task;\n\t\treturn task;\n\t}\n\n\tprivate async prepareStagingPath(): Promise<string> {\n\t\tconst stagingPath = ownedBindPath(this.#socketPath);\n\t\tconst dir = dirname(this.#socketPath);\n\t\tawait mkdir(dir, { recursive: true, mode: 0o700 });\n\t\tawait clearStaleSocket(this.#socketPath);\n\t\tawait clearStaleSocket(stagingPath);\n\t\tthis.#stagingPath = stagingPath;\n\t\treturn stagingPath;\n\t}\n\n\tprivate bindServer(netServer: Server, stagingPath: string): Promise<void> {\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tfunction onError(error: Error): void {\n\t\t\t\tnetServer.off(\"listening\", onListening);\n\t\t\t\treject(error);\n\t\t\t}\n\t\t\tfunction onListening(): void {\n\t\t\t\tnetServer.off(\"error\", onError);\n\t\t\t\tresolve();\n\t\t\t}\n\t\t\tnetServer.once(\"error\", onError);\n\t\t\tnetServer.once(\"listening\", onListening);\n\t\t\tnetServer.listen(stagingPath);\n\t\t});\n\t}\n\n\tprivate async publishSocket(stagingPath: string): Promise<void> {\n\t\tconst stats = await lstat(stagingPath);\n\t\tif (!stats.isSocket()) {\n\t\t\tthrow new Error(`Unix listener path is not a socket after binding: ${stagingPath}`);\n\t\t}\n\t\tthis.#boundIdentity = { dev: stats.dev, ino: stats.ino };\n\t\tawait link(stagingPath, this.#socketPath);\n\t\tawait applySocketMode(this.#socketPath, this.#socketMode);\n\t\tawait deletePath(stagingPath);\n\t\tthis.#stagingPath = undefined;\n\t}\n\n\tprivate handleSocket(socket: Socket): void {\n\t\tif (this.#stopping) {\n\t\t\tsocket.destroy();\n\t\t\treturn;\n\t\t}\n\t\tconst timeoutMs = this.#resolved.gracefulCloseTimeoutMs;\n\t\tconst maxBytes = this.#resolved.maxPendingBytes;\n\t\tconst connection = new UnixByteConnection(socket, timeoutMs, maxBytes);\n\t\tthis.#live.add(connection);\n\t\tconst acceptor = this.#acceptor;\n\t\tif (acceptor === undefined) {\n\t\t\tsocket.destroy();\n\t\t\treturn;\n\t\t}\n\t\tconst handler = acceptor(connection);\n\t\tconst onData = (chunk: Buffer): void => {\n\t\t\tconst bytes = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);\n\t\t\thandler.onData(bytes);\n\t\t};\n\t\tconst onSocketError = (error: Error): void => {\n\t\t\thandler.onError(error);\n\t\t\tsocket.destroy();\n\t\t};\n\t\tconst onClose = (): void => {\n\t\t\tconnection.markClosed();\n\t\t\tthis.#live.delete(connection);\n\t\t\thandler.onClose();\n\t\t};\n\t\tsocket.on(\"data\", onData);\n\t\tsocket.on(\"error\", onSocketError);\n\t\tsocket.once(\"close\", onClose);\n\t}\n\n\tprivate async closeInternal():\n\t\tPromise<void> {\n\t\tconst netServer = this.#netServer;\n\t\tconst serverClosed =\n\t\t\tnetServer === undefined ? this.removeOwnedSocket() : this.shutdownNetServer(netServer);\n\t\tconst connections = [...this.#live];\n\t\tawait Promise.all(connections.map((connection) => connection.close()));\n\t\tawait serverClosed;\n\t\tconst staging = this.#stagingPath;\n\t\tif (staging !== undefined) await deletePath(staging);\n\t\tthis.#stagingPath = undefined;\n\t\tthis.#live.clear();\n\t\tthis.#netServer = undefined;\n\t}\n\n\tprivate async shutdownNetServer(netServer: Server): Promise<void> {\n\t\ttry {\n\t\t\tawait closeNetServer(netServer, (error) => this.noteError(error));\n\t\t} finally {\n\t\t\t// An unpublished staging bind path goes before the public socket path.\n\t\t\tconst staging = this.#stagingPath;\n\t\t\tif (staging !== undefined) await deletePath(staging);\n\t\t\tthis.#stagingPath = undefined;\n\t\t\tawait this.removeOwnedSocket();\n\t\t}\n\t}\n\n\tprivate async removeOwnedSocket(): Promise<void> {\n\t\tconst identity = this.#boundIdentity;\n\t\tthis.#boundIdentity = undefined;\n\t\tif (identity === undefined) return;\n\t\tconst current = await this.lstatOwnedPath();\n\t\tif (current === undefined) return;\n\t\tif (!current.isSocket() || current.dev !== identity.dev || current.ino !== identity.ino) return;\n\t\tawait this.quarantineOwnedSocket(identity);\n\t}\n\n\tprivate async lstatOwnedPath(): Promise<Stats | undefined> {\n\t\ttry {\n\t\t\treturn await lstat(this.#socketPath);\n\t\t} catch (error) {\n\t\t\tif (hasErrorCode(error, \"ENOENT\")) return undefined;\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate async quarantineOwnedSocket(identity: SocketIdentity): Promise<void> {\n\t\tconst dir = dirname(this.#socketPath);\n\t\tconst preserved = join(dir, `cleanup-${randomUUID().slice(0, 6)}`);\n\t\ttry {\n\t\t\tawait rename(this.#socketPath, preserved);\n\t\t} catch (error) {\n\t\t\tif (hasErrorCode(error, \"ENOENT\")) return;\n\t\t\tthrow error;\n\t\t}\n\t\tconst moved = await lstat(preserved);\n\t\tconst intact = moved.isSocket() && moved.dev === identity.dev && moved.ino === identity.ino;\n\t\tif (intact) {\n\t\t\tawait deletePath(preserved);\n\t\t\treturn;\n\t\t}\n\t\tawait this.restoreQuarantinedSocket(preserved);\n\t}\n\n\tprivate async restoreQuarantinedSocket(preserved: string): Promise<void> {\n\t\tlet exists = true;\n\t\ttry {\n\t\t\tawait lstat(this.#socketPath);\n\t\t} catch (error) {\n\t\t\tif (hasErrorCode(error, \"ENOENT\")) exists = false;\n\t\t\telse throw error;\n\t\t}\n\t\tif (!exists) await rename(preserved, this.#socketPath);\n\t\tthrow new Error(`Unix listener path changed during cleanup; preserved replacement at ${preserved}`);\n\t}\n\n\tprivate noteError(error: unknown): void {\n\t\tconst normalized = error instanceof Error ? error : new Error(String(error));\n\t\ttry {\n\t\t\tthis.#resolved.onError?.(normalized);\n\t\t} catch {\n\t\t\t// Listener state is unaffected by observer failures.\n\t\t}\n\t}\n}\n\n/** Exported for transport-level verification; not part of the public API surface. */\nexport class UnixByteConnection implements ByteConnection {\n\t#socket: Socket;\n\t#gracefulCloseTimeoutMs: number;\n\t#maxPendingBytes: number;\n\t#pendingBytes = 0;\n\t#closed = false;\n\t#closing = false;\n\t#writeTail: Promise<void> = Promise.resolve();\n\t#closeTask: Promise<void> | undefined;\n\t#finishClose: (() => void) | undefined;\n\n\tconstructor(socket: Socket, gracefulCloseTimeoutMs: number, maxPendingBytes: number) {\n\t\tthis.#socket = socket;\n\t\tthis.#gracefulCloseTimeoutMs = gracefulCloseTimeoutMs;\n\t\tthis.#maxPendingBytes = maxPendingBytes;\n\t}\n\n\tget closed(): boolean {\n\t\treturn this.#closed;\n\t}\n\n\tsend(chunk: Uint8Array): Promise<void> {\n\t\tif (!(chunk instanceof Uint8Array)) {\n\t\t\treturn Promise.reject(new TypeError(\"Unix connection chunks must be Uint8Array\"));\n\t\t}\n\t\tif (this.#closed || this.#closing) {\n\t\t\treturn Promise.reject(new Error(\"Unix connection is closed\"));\n\t\t}\n\t\tconst pending = this.#pendingBytes + chunk.byteLength;\n\t\tif (pending > this.#maxPendingBytes) {\n\t\t\treturn Promise.reject(new Error(\"Unix connection exceeded its pending byte limit\"));\n\t\t}\n\t\tthis.#pendingBytes = pending;\n\t\tconst bytes = chunk.slice();\n\t\tconst write = this.#writeTail.then(() => this.flush(bytes));\n\t\tconst tracked = write.finally(() => {\n\t\t\tthis.#pendingBytes = this.#pendingBytes - bytes.byteLength;\n\t\t});\n\t\tthis.#writeTail = tracked.catch(noop);\n\t\treturn tracked;\n\t}\n\n\tclose(finalChunk?: Uint8Array): Promise<void> {\n\t\tif (this.#closed || this.#socket.destroyed) {\n\t\t\tthis.markClosed();\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tconst pending = this.#closeTask;\n\t\tif (pending !== undefined) return pending;\n\t\tthis.#closing = true;\n\t\tconst finalBytes = finalChunk === undefined ? undefined : finalChunk.slice();\n\t\tconst task = new Promise<void>((resolve) => {\n\t\t\tthis.#finishClose = resolve;\n\t\t\tconst timer = setTimeout(() => this.forceClose(), this.#gracefulCloseTimeoutMs);\n\t\t\ttimer.unref();\n\t\t\tthis.#socket.once(\"close\", () => clearTimeout(timer));\n\t\t\tvoid this.#writeTail.then(() => this.endSocket(finalBytes));\n\t\t});\n\t\tthis.#closeTask = task;\n\t\treturn task;\n\t}\n\n\tmarkClosed(): void {\n\t\tif (this.#closed) return;\n\t\tthis.#closed = true;\n\t\tthis.#closing = true;\n\t\tconst finish = this.#finishClose;\n\t\tthis.#finishClose = undefined;\n\t\tfinish?.();\n\t}\n\n\tprivate forceClose(): void {\n\t\tif (!this.#socket.destroyed) this.#socket.destroy();\n\t\tthis.markClosed();\n\t}\n\n\tprivate endSocket(finalBytes: Uint8Array | undefined): void {\n\t\tif (this.#socket.destroyed) {\n\t\t\tthis.markClosed();\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tif (finalBytes !== undefined) this.#socket.end(finalBytes);\n\t\t\telse this.#socket.end();\n\t\t} catch {\n\t\t\tthis.#socket.destroy();\n\t\t}\n\t}\n\n\tprivate flush(chunk: Uint8Array): Promise<void> {\n\t\tconst writable = !this.#closed && !this.#closing && this.#socket.writable;\n\t\tif (!writable) return Promise.reject(new Error(\"Unix connection is closed\"));\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tlet settled = false;\n\t\t\tconst done = (error?: Error | null): void => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.#socket.off(\"close\", onClose);\n\t\t\t\tif (error) reject(error);\n\t\t\t\telse resolve();\n\t\t\t};\n\t\t\tconst onClose = (): void => {\n\t\t\t\tdone(new Error(\"Unix connection closed during write\"));\n\t\t\t};\n\t\t\tthis.#socket.once(\"close\", onClose);\n\t\t\ttry {\n\t\t\t\tthis.#socket.write(chunk, done);\n\t\t\t} catch (error) {\n\t\t\t\tconst failure = error instanceof Error ? error : new Error(String(error));\n\t\t\t\tdone(failure);\n\t\t\t}\n\t\t});\n\t}\n}\n\nfunction noop(): void {}\n\nfunction ownedBindPath(path: string): string {\n\tconst digest = createHash(\"sha256\").update(path).digest(\"hex\");\n\tconst suffix = digest.slice(0, 8);\n\treturn join(dirname(path), `bind-${suffix}`);\n}\n\nasync function clearStaleSocket(path: string): Promise<void> {\n\tconst original = await lstatSocketPath(path);\n\tif (original === undefined) return;\n\tif (!original.isSocket()) {\n\t\tthrow new Error(`Refusing to remove non-socket Unix listener path: ${path}`);\n\t}\n\tconst live = await probeSocket(path);\n\tif (live) throw new Error(`Unix listener is already running: ${path}`);\n\tawait quarantineStaleSocket(path, original);\n}\n\nasync function lstatSocketPath(path: string): Promise<Stats | undefined> {\n\ttry {\n\t\treturn await lstat(path);\n\t} catch (error) {\n\t\tif (hasErrorCode(error, \"ENOENT\")) return undefined;\n\t\tthrow error;\n\t}\n}\n\nasync function quarantineStaleSocket(path: string, original: Stats): Promise<void> {\n\tconst preserved = join(dirname(path), `stale-${randomUUID().slice(0, 6)}`);\n\ttry {\n\t\tawait rename(path, preserved);\n\t} catch (error) {\n\t\tif (hasErrorCode(error, \"ENOENT\")) return;\n\t\tthrow error;\n\t}\n\tconst current = await lstat(preserved);\n\tconst sameFile = current.isSocket() && current.dev === original.dev && current.ino === original.ino;\n\tif (!sameFile) {\n\t\tawait restoreStaleSocket(path, preserved);\n\t}\n\tawait deletePath(preserved);\n}\n\nasync function restoreStaleSocket(path: string, preserved: string): Promise<never> {\n\tlet exists = true;\n\ttry {\n\t\tawait lstat(path);\n\t} catch (error) {\n\t\tif (hasErrorCode(error, \"ENOENT\")) exists = false;\n\t\telse throw error;\n\t}\n\tif (!exists) await rename(preserved, path);\n\tthrow new Error(`Unix listener path changed while checking for a stale socket: ${path}`);\n}\n\nasync function deletePath(path: string): Promise<void> {\n\ttry {\n\t\tawait unlink(path);\n\t} catch (error) {\n\t\tif (!hasErrorCode(error, \"ENOENT\")) throw error;\n\t}\n}\n\nfunction probeSocket(path: string): Promise<boolean> {\n\treturn new Promise<boolean>((resolve, reject) => {\n\t\tconst socket = createConnection(path);\n\t\tlet settled = false;\n\t\tconst timer = setTimeout(() => finish(true), SOCKET_PROBE_TIMEOUT_MS);\n\t\ttimer.unref();\n\t\tconst finish = (result: boolean, error?: Error): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tsocket.removeAllListeners();\n\t\t\tsocket.destroy();\n\t\t\tif (error !== undefined) reject(error);\n\t\t\telse resolve(result);\n\t\t};\n\t\tconst onConnect = (): void => finish(true);\n\t\tconst onError = (error: NodeJS.ErrnoException): void => {\n\t\t\tconst dead = [\"ECONNREFUSED\", \"ENOENT\", \"EPIPE\", \"ECONNRESET\"].includes(error.code ?? \"\");\n\t\t\tif (dead) finish(false);\n\t\t\telse finish(false, error);\n\t\t};\n\t\tsocket.once(\"connect\", onConnect);\n\t\tsocket.once(\"error\", onError);\n\t});\n}\n\nasync function applySocketMode(path: string, mode: number): Promise<void> {\n\tif (process.platform === \"win32\") return;\n\ttry {\n\t\tawait chmod(path, mode);\n\t} catch (error) {\n\t\tconst unsupported = hasErrorCode(error, \"ENOSYS\") || hasErrorCode(error, \"ENOTSUP\");\n\t\tif (!unsupported) throw error;\n\t}\n}\n\nfunction closeNetServer(server: Server, noteError: (error: Error) => void): Promise<void> {\n\tif (!server.listening) return Promise.resolve();\n\treturn new Promise<void>((resolve) => {\n\t\tserver.close((error) => {\n\t\t\tif (error !== undefined) noteError(error);\n\t\t\tresolve();\n\t\t});\n\t});\n}\n\nfunction hasErrorCode(error: unknown, code: string): boolean {\n\tif (!(error instanceof Error)) return false;\n\treturn \"code\" in error && error.code === code;\n}\n\nexport function createUnixListener(\n\toptions: UnixListenerOptions,\n): ServerListener {\n\treturn new UnixSocketListener(options);\n}\n\nfunction resolveListenerOptions(options: UnixListenerOptions): ResolvedListenerOptions {\n\tconst path = requireSocketPath(options.path);\n\tconst mode = requireSocketMode(options.mode);\n\tconst maxFrameLength = requireMaxFrameLength(options.maxFrameLength);\n\tconst maxPendingBytes = requireMaxPendingBytes(options.maxPendingBytes, maxFrameLength);\n\tconst gracefulCloseTimeoutMs = requireGracefulCloseTimeoutMs(options.gracefulCloseTimeoutMs);\n\treturn {\n\t\tpath,\n\t\tmode,\n\t\tmaxPendingBytes,\n\t\tgracefulCloseTimeoutMs,\n\t\tonError: options.onError,\n\t};\n}\n\nfunction requireSocketPath(path: string): string {\n\tif (!path) throw new TypeError(\"Unix listener requires a non-empty socket path\");\n\treturn path;\n}\n\nfunction requireSocketMode(mode: number | undefined): number {\n\tconst value = mode ?? DEFAULT_SOCKET_MODE;\n\tconst valid = Number.isInteger(value) && value >= 0 && value <= 0o777;\n\tif (!valid) throw new TypeError(\"Unix socket mode must be an integer from 0 to 0o777\");\n\treturn value;\n}\n\nfunction requireMaxFrameLength(maxFrameLength: number | undefined): number {\n\tconst value = maxFrameLength ?? DEFAULT_MAX_FRAME_LENGTH;\n\tconst valid = Number.isSafeInteger(value) && value > 0 && value <= MAX_UINT32;\n\tif (!valid) throw new TypeError(`maxFrameLength must be a positive integer up to ${MAX_UINT32}`);\n\treturn value;\n}\n\nfunction requireMaxPendingBytes(maxPendingBytes: number | undefined, maxFrameLength: number): number {\n\tconst value = maxPendingBytes ?? maxFrameLength * 4;\n\tconst valid = Number.isSafeInteger(value) && value >= maxFrameLength + 4;\n\tif (!valid) throw new TypeError(\"maxPendingBytes must be a safe integer of at least maxFrameLength + 4\");\n\treturn value;\n}\n\nfunction requireGracefulCloseTimeoutMs(gracefulCloseTimeoutMs: number | undefined): number {\n\tconst value = gracefulCloseTimeoutMs ?? DEFAULT_GRACEFUL_CLOSE_TIMEOUT_MS;\n\tconst valid = Number.isSafeInteger(value) && value > 0 && value <= MAX_TIMER_DELAY_MS;\n\tif (!valid) throw new TypeError(`gracefulCloseTimeoutMs must be an integer from 1 to ${MAX_TIMER_DELAY_MS}`);\n\treturn value;\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { SessionMetadata } from "@crow-agent/agent-core";
2
+ import { Server } from "../../session-server.ts";
3
+ import type { ServerHost } from "../../server-types.ts";
4
+ import type { UnixServerOptions } from "./unix-types.ts";
5
+ /** Builds a Server fronted by one Unix-domain socket listener. */
6
+ export declare function createUnixServer<TMetadata extends SessionMetadata>(host: ServerHost<TMetadata>, options: UnixServerOptions): Server<TMetadata>;
7
+ //# sourceMappingURL=unix-preset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unix-preset.d.ts","sourceRoot":"","sources":["../../../src/transports/unix/unix-preset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACN,MAAM,EACN,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EACX,UAAU,EACV,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EACX,iBAAiB,EACjB,MAAM,iBAAiB,CAAC;AAEzB,kEAAkE;AAClE,wBAAgB,gBAAgB,CAC/B,SAAS,SAAS,eAAe,EAChC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAAC,SAAS,CAAC,CA8B5E"}
@@ -0,0 +1,25 @@
1
+ import { Server, } from "../../session-server.js";
2
+ import { createUnixListener, } from "./unix-listener.js";
3
+ /** Builds a Server fronted by one Unix-domain socket listener. */
4
+ export function createUnixServer(host, options) {
5
+ const { path, mode, maxFrameLength, maxPendingBytes, gracefulCloseTimeoutMs, handshakeTimeoutMs, onConnectionCountChanged, serverId, onError, } = options;
6
+ const listenerOptions = {
7
+ path,
8
+ mode,
9
+ maxFrameLength,
10
+ maxPendingBytes,
11
+ gracefulCloseTimeoutMs,
12
+ onError,
13
+ };
14
+ const listener = createUnixListener(listenerOptions);
15
+ const serverOptions = {
16
+ listeners: [listener],
17
+ maxFrameLength,
18
+ handshakeTimeoutMs,
19
+ onConnectionCountChanged,
20
+ serverId,
21
+ onError,
22
+ };
23
+ return new Server(host, serverOptions);
24
+ }
25
+ //# sourceMappingURL=unix-preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unix-preset.js","sourceRoot":"","sources":["../../../src/transports/unix/unix-preset.ts"],"names":[],"mappings":"AACA,OAAO,EACN,MAAM,GACN,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EACN,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAK5B,kEAAkE;AAClE,MAAM,UAAU,gBAAgB,CAE9B,IAA2B,EAAE,OAA0B;IACxD,MAAM,EACL,IAAI,EACJ,IAAI,EACJ,cAAc,EACd,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,wBAAwB,EACxB,QAAQ,EACR,OAAO,GACP,GAAG,OAAO,CAAC;IACZ,MAAM,eAAe,GAAG;QACvB,IAAI;QACJ,IAAI;QACJ,cAAc;QACd,eAAe;QACf,sBAAsB;QACtB,OAAO;KACP,CAAC;IACF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG;QACrB,SAAS,EAAE,CAAC,QAAQ,CAAC;QACrB,cAAc;QACd,kBAAkB;QAClB,wBAAwB;QACxB,QAAQ;QACR,OAAO;KACP,CAAC;IACF,OAAO,IAAI,MAAM,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AACxC,CAAC","sourcesContent":["import type { SessionMetadata } from \"@crow-agent/agent-core\";\nimport {\n\tServer,\n} from \"../../session-server.ts\";\nimport type {\n\tServerHost,\n} from \"../../server-types.ts\";\nimport {\n\tcreateUnixListener,\n} from \"./unix-listener.ts\";\nimport type {\n\tUnixServerOptions,\n} from \"./unix-types.ts\";\n\n/** Builds a Server fronted by one Unix-domain socket listener. */\nexport function createUnixServer<\n\tTMetadata extends SessionMetadata,\n>(host: ServerHost<TMetadata>, options: UnixServerOptions): Server<TMetadata> {\n\tconst {\n\t\tpath,\n\t\tmode,\n\t\tmaxFrameLength,\n\t\tmaxPendingBytes,\n\t\tgracefulCloseTimeoutMs,\n\t\thandshakeTimeoutMs,\n\t\tonConnectionCountChanged,\n\t\tserverId,\n\t\tonError,\n\t} = options;\n\tconst listenerOptions = {\n\t\tpath,\n\t\tmode,\n\t\tmaxFrameLength,\n\t\tmaxPendingBytes,\n\t\tgracefulCloseTimeoutMs,\n\t\tonError,\n\t};\n\tconst listener = createUnixListener(listenerOptions);\n\tconst serverOptions = {\n\t\tlisteners: [listener],\n\t\tmaxFrameLength,\n\t\thandshakeTimeoutMs,\n\t\tonConnectionCountChanged,\n\t\tserverId,\n\t\tonError,\n\t};\n\treturn new Server(host, serverOptions);\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { ServerOptions } from "../../server-types.ts";
2
+ export type UnixListenerOptions = {
3
+ path: string;
4
+ /** Socket filesystem permissions. Owner read/write only (0o600) by default. */
5
+ mode?: number;
6
+ /** Framed bytes queued per connection before a slow peer is dropped. */
7
+ maxPendingBytes?: number;
8
+ gracefulCloseTimeoutMs?: number;
9
+ /** Derives and validates maxPendingBytes. Must match the server when customized. */
10
+ maxFrameLength?: number;
11
+ onError?: (error: Error) => void;
12
+ };
13
+ export type UnixServerOptions = Omit<ServerOptions, "listeners"> & UnixListenerOptions;
14
+ //# sourceMappingURL=unix-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unix-types.d.ts","sourceRoot":"","sources":["../../../src/transports/unix/unix-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,aAAa,EACb,MAAM,uBAAuB,CAAC;AAE/B,MAAM,MAAM,mBAAmB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,eAAe,CAAC,EACf,MAAM,CAAC;IACR,sBAAsB,CAAC,EACtB,MAAM,CAAC;IACR,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,CACT,KAAK,EAAE,KAAK,KACR,IAAI,CAAC;CACV,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,aAAa,EAAE,WAAW,CAAC,GAAG,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=unix-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unix-types.js","sourceRoot":"","sources":["../../../src/transports/unix/unix-types.ts"],"names":[],"mappings":"","sourcesContent":["import type {\n\tServerOptions,\n} from \"../../server-types.ts\";\n\nexport type UnixListenerOptions = {\n\tpath: string;\n\t/** Socket filesystem permissions. Owner read/write only (0o600) by default. */\n\tmode?: number;\n\t/** Framed bytes queued per connection before a slow peer is dropped. */\n\tmaxPendingBytes?:\n\t\tnumber;\n\tgracefulCloseTimeoutMs?:\n\t\tnumber;\n\t/** Derives and validates maxPendingBytes. Must match the server when customized. */\n\tmaxFrameLength?: number;\n\tonError?: (\n\t\terror: Error,\n\t) => void;\n};\n\nexport type UnixServerOptions = Omit<ServerOptions, \"listeners\"> & UnixListenerOptions;\n"]}