@thenewlabs/entangle-serve 2.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.
@@ -0,0 +1,122 @@
1
+ import { OutputHandler } from '@thenewlabs/entangle-utils';
2
+ import { ChildProcess } from 'child_process';
3
+ import { EventEmitter } from 'events';
4
+ import * as pty from '@homebridge/node-pty-prebuilt-multiarch';
5
+ import { StreamMode, StreamMetadata, StreamUsage, StreamPtyOptions, StreamExecOptions, Policy } from '@thenewlabs/entangle-protocol';
6
+ export interface Stream {
7
+ sid: string;
8
+ mode: StreamMode;
9
+ startedAt: number;
10
+ endedAt?: number;
11
+ process?: ChildProcess | pty.IPty;
12
+ usage: StreamUsage;
13
+ aborted: boolean;
14
+ limits: {
15
+ cpuMs?: number;
16
+ memMB?: number;
17
+ wallMs?: number;
18
+ maxOutBytes?: number;
19
+ };
20
+ wallTimer?: ReturnType<typeof setTimeout>;
21
+ idleTimer?: ReturnType<typeof setTimeout>;
22
+ resourceTimer?: ReturnType<typeof setInterval>;
23
+ }
24
+ interface StreamManagerOptions {
25
+ policy: Policy;
26
+ output: OutputHandler;
27
+ onStreamData?: (sid: string, data: Uint8Array, channel: 'stdout' | 'stderr') => void;
28
+ onStreamExit?: (sid: string, code: number | null, signal: string | null, usage?: StreamUsage) => void;
29
+ onStreamError?: (sid: string, error: string) => void;
30
+ }
31
+ export declare class StreamManager extends EventEmitter {
32
+ private options;
33
+ private streams;
34
+ private policy;
35
+ private output;
36
+ private aggregateUsage;
37
+ constructor(options: StreamManagerOptions);
38
+ /**
39
+ * Generate a unique stream ID
40
+ */
41
+ private generateStreamId;
42
+ /**
43
+ * Resolve a requested cwd and confine it to AGENT_DEFAULT_CWD (the working
44
+ * directory doubles as the execution boundary). Symlinks are resolved
45
+ * (realpath) BEFORE the prefix check so a symlink inside the dir can't point
46
+ * the process outside it. Throws if the resolved path is outside the boundary.
47
+ * NOTE: this only constrains the initial cwd, not a full filesystem sandbox.
48
+ */
49
+ private resolveCwd;
50
+ /**
51
+ * Check if we can open a new stream
52
+ */
53
+ private canOpenStream;
54
+ /**
55
+ * Get stream-specific limits.
56
+ *
57
+ * Interactive PTYs are deliberately exempt from ALL command-oriented caps —
58
+ * wall-clock, cumulative output ceiling, and CPU/memory guards. A legitimate
59
+ * terminal session can stay open for hours, stream far more than
60
+ * MAX_OUT_BYTES, and burn CPU interactively, so any of these would force-close
61
+ * it mid-use. A PTY is bounded solely by the idle timeout (see
62
+ * armIdleTimeout). Command ('cmd') streams keep every limit.
63
+ */
64
+ private getStreamLimits;
65
+ /**
66
+ * Arm a wall-clock deadline that force-closes the stream if it outlives its
67
+ * limit. Unref'd so the timer never keeps the process alive on its own.
68
+ */
69
+ private armWallClock;
70
+ /**
71
+ * (Re)arm the PTY idle timeout. Called on every byte of PTY output so an
72
+ * interactive session is only reaped after genuine inactivity.
73
+ */
74
+ private armIdleTimeout;
75
+ private clearTimers;
76
+ private readProcessUsage;
77
+ private armResourceMonitor;
78
+ /**
79
+ * Open a new PTY stream
80
+ */
81
+ openPtyStream(options: StreamPtyOptions & {
82
+ cwd?: string;
83
+ }): Promise<string>;
84
+ /**
85
+ * Open a new command stream
86
+ */
87
+ openCmdStream(options: StreamExecOptions): Promise<string>;
88
+ /**
89
+ * Write data to a stream (stdin)
90
+ */
91
+ writeToStream(sid: string, data: Uint8Array): void;
92
+ /**
93
+ * Resize a PTY stream
94
+ */
95
+ resizePtyStream(sid: string, cols: number, rows: number): void;
96
+ /**
97
+ * Send signal to a stream
98
+ */
99
+ signalStream(sid: string, signal: NodeJS.Signals): void;
100
+ /**
101
+ * Close a stream
102
+ */
103
+ closeStream(sid: string, reason?: string): void;
104
+ /**
105
+ * Close all streams
106
+ */
107
+ closeAllStreams(reason?: string): void;
108
+ /**
109
+ * Get stream info
110
+ */
111
+ getStream(sid: string): Stream | undefined;
112
+ /**
113
+ * Get all active streams
114
+ */
115
+ getActiveStreams(): StreamMetadata[];
116
+ /**
117
+ * Get aggregate usage across all streams
118
+ */
119
+ getAggregateUsage(): StreamUsage;
120
+ }
121
+ export {};
122
+ //# sourceMappingURL=stream-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-manager.d.ts","sourceRoot":"","sources":["../src/stream-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,488 @@
1
+ import { validateArguments, validateCwd, buildChildEnv, getConfig } from '@thenewlabs/entangle-utils';
2
+ import { spawn } from 'child_process';
3
+ import { EventEmitter } from 'events';
4
+ import { randomBytes } from 'crypto';
5
+ import { readFileSync, realpathSync } from 'fs';
6
+ import { resolve as resolvePath } from 'path';
7
+ import * as pty from '@homebridge/node-pty-prebuilt-multiarch';
8
+ import { DEFAULT_LIMITS } from '@thenewlabs/entangle-protocol';
9
+ export class StreamManager extends EventEmitter {
10
+ options;
11
+ streams = new Map();
12
+ policy;
13
+ output;
14
+ aggregateUsage = {
15
+ cpuMs: 0,
16
+ rssMaxBytes: 0,
17
+ wallMs: 0,
18
+ outBytes: 0,
19
+ };
20
+ constructor(options) {
21
+ super();
22
+ this.options = options;
23
+ this.policy = options.policy;
24
+ this.output = options.output;
25
+ }
26
+ /**
27
+ * Generate a unique stream ID
28
+ */
29
+ generateStreamId() {
30
+ return randomBytes(8).toString('base64url');
31
+ }
32
+ /**
33
+ * Resolve a requested cwd and confine it to AGENT_DEFAULT_CWD (the working
34
+ * directory doubles as the execution boundary). Symlinks are resolved
35
+ * (realpath) BEFORE the prefix check so a symlink inside the dir can't point
36
+ * the process outside it. Throws if the resolved path is outside the boundary.
37
+ * NOTE: this only constrains the initial cwd, not a full filesystem sandbox.
38
+ */
39
+ resolveCwd(requestedCwd) {
40
+ const config = getConfig();
41
+ const base = requestedCwd
42
+ ? resolvePath(config.agentDefaultCwd, requestedCwd)
43
+ : config.agentDefaultCwd;
44
+ let real = base;
45
+ try {
46
+ real = realpathSync(base);
47
+ }
48
+ catch {
49
+ // Path may not exist yet; validate the resolved (non-symlink) form.
50
+ }
51
+ // Boundary-aware prefix check (see utils validateCwd).
52
+ validateCwd(real, config.agentAllowedCwd);
53
+ return real;
54
+ }
55
+ /**
56
+ * Check if we can open a new stream
57
+ */
58
+ canOpenStream() {
59
+ const maxStreams = this.policy.maxStreams || 1;
60
+ if (this.streams.size >= maxStreams) {
61
+ return { allowed: false, reason: `Maximum streams (${maxStreams}) reached` };
62
+ }
63
+ return { allowed: true };
64
+ }
65
+ /**
66
+ * Get stream-specific limits.
67
+ *
68
+ * Interactive PTYs are deliberately exempt from ALL command-oriented caps —
69
+ * wall-clock, cumulative output ceiling, and CPU/memory guards. A legitimate
70
+ * terminal session can stay open for hours, stream far more than
71
+ * MAX_OUT_BYTES, and burn CPU interactively, so any of these would force-close
72
+ * it mid-use. A PTY is bounded solely by the idle timeout (see
73
+ * armIdleTimeout). Command ('cmd') streams keep every limit.
74
+ */
75
+ getStreamLimits(mode) {
76
+ const limits = {};
77
+ if (mode === 'pty')
78
+ return limits;
79
+ const maxStreams = this.policy.maxStreams || 1;
80
+ const config = getConfig();
81
+ const perStream = this.policy.perStream;
82
+ // Apply defaults even when a partial per-stream policy is present.
83
+ const cpuMs = perStream?.maxCpuMs ?? this.policy.maxCpuMs ?? DEFAULT_LIMITS.MAX_CPU_MS;
84
+ const memMB = perStream?.maxMemMB ?? this.policy.maxMemMB ?? DEFAULT_LIMITS.MAX_MEM_MB;
85
+ limits.cpuMs = Math.max(1, Math.floor(cpuMs / maxStreams));
86
+ limits.memMB = Math.max(1, Math.floor(memMB / maxStreams));
87
+ const wallMs = perStream?.maxWallMs ?? this.policy.maxWallMs ?? config.cmdDefaultWallMs;
88
+ if (wallMs > 0)
89
+ limits.wallMs = Math.floor(wallMs / maxStreams);
90
+ const maxOutBytes = perStream?.maxOutBytes ?? this.policy.maxOutBytes ?? config.maxOutBytes;
91
+ if (maxOutBytes > 0)
92
+ limits.maxOutBytes = Math.floor(maxOutBytes / maxStreams);
93
+ return limits;
94
+ }
95
+ /**
96
+ * Arm a wall-clock deadline that force-closes the stream if it outlives its
97
+ * limit. Unref'd so the timer never keeps the process alive on its own.
98
+ */
99
+ armWallClock(stream) {
100
+ const wallMs = stream.limits.wallMs;
101
+ if (!wallMs || wallMs <= 0)
102
+ return;
103
+ stream.wallTimer = setTimeout(() => {
104
+ const current = this.streams.get(stream.sid);
105
+ if (current && current.endedAt === undefined) {
106
+ this.output.warn(`Stream wall-clock limit exceeded for ${stream.sid}: limit=${wallMs}ms`);
107
+ this.closeStream(stream.sid, 'Wall-clock limit exceeded');
108
+ }
109
+ }, wallMs);
110
+ if (typeof stream.wallTimer.unref === 'function')
111
+ stream.wallTimer.unref();
112
+ }
113
+ /**
114
+ * (Re)arm the PTY idle timeout. Called on every byte of PTY output so an
115
+ * interactive session is only reaped after genuine inactivity.
116
+ */
117
+ armIdleTimeout(stream, idleMs) {
118
+ if (!idleMs || idleMs <= 0)
119
+ return;
120
+ if (stream.idleTimer)
121
+ clearTimeout(stream.idleTimer);
122
+ stream.idleTimer = setTimeout(() => {
123
+ const current = this.streams.get(stream.sid);
124
+ if (current && current.endedAt === undefined) {
125
+ this.output.warn(`PTY idle timeout for ${stream.sid}: idle=${idleMs}ms`);
126
+ this.closeStream(stream.sid, 'Idle timeout');
127
+ }
128
+ }, idleMs);
129
+ if (typeof stream.idleTimer.unref === 'function')
130
+ stream.idleTimer.unref();
131
+ }
132
+ clearTimers(stream) {
133
+ if (stream.wallTimer) {
134
+ clearTimeout(stream.wallTimer);
135
+ delete stream.wallTimer;
136
+ }
137
+ if (stream.idleTimer) {
138
+ clearTimeout(stream.idleTimer);
139
+ delete stream.idleTimer;
140
+ }
141
+ if (stream.resourceTimer) {
142
+ clearInterval(stream.resourceTimer);
143
+ delete stream.resourceTimer;
144
+ }
145
+ }
146
+ readProcessUsage(pid) {
147
+ if (process.platform !== 'linux')
148
+ return undefined;
149
+ try {
150
+ const stat = readFileSync(`/proc/${pid}/stat`, 'utf8');
151
+ const endComm = stat.lastIndexOf(')');
152
+ if (endComm < 0)
153
+ return undefined;
154
+ const fields = stat.slice(endComm + 2).trim().split(/\s+/);
155
+ const userTicks = Number(fields[11]);
156
+ const systemTicks = Number(fields[12]);
157
+ const rssPages = Number(fields[21]);
158
+ if (![userTicks, systemTicks, rssPages].every(Number.isFinite))
159
+ return undefined;
160
+ return { cpuMs: ((userTicks + systemTicks) * 1000) / 100, rssBytes: rssPages * 4096 };
161
+ }
162
+ catch {
163
+ return undefined;
164
+ }
165
+ }
166
+ armResourceMonitor(stream) {
167
+ const pid = stream.process && 'pid' in stream.process ? stream.process.pid : undefined;
168
+ if (!pid || (!stream.limits.cpuMs && !stream.limits.memMB))
169
+ return;
170
+ stream.resourceTimer = setInterval(() => {
171
+ const usage = this.readProcessUsage(pid);
172
+ if (!usage)
173
+ return;
174
+ stream.usage.cpuMs = usage.cpuMs;
175
+ stream.usage.rssMaxBytes = Math.max(stream.usage.rssMaxBytes, usage.rssBytes);
176
+ if (stream.limits.cpuMs && usage.cpuMs > stream.limits.cpuMs) {
177
+ this.closeStream(stream.sid, 'CPU limit exceeded');
178
+ }
179
+ else if (stream.limits.memMB && usage.rssBytes > stream.limits.memMB * 1024 * 1024) {
180
+ this.closeStream(stream.sid, 'Memory limit exceeded');
181
+ }
182
+ }, 100);
183
+ if (typeof stream.resourceTimer.unref === 'function')
184
+ stream.resourceTimer.unref();
185
+ }
186
+ /**
187
+ * Open a new PTY stream
188
+ */
189
+ async openPtyStream(options) {
190
+ const check = this.canOpenStream();
191
+ if (!check.allowed) {
192
+ throw new Error(check.reason);
193
+ }
194
+ const sid = this.generateStreamId();
195
+ const limits = this.getStreamLimits('pty');
196
+ const config = getConfig();
197
+ const cwd = this.resolveCwd(options.cwd);
198
+ const env = buildChildEnv(config.agentEnvPassthrough, options.env);
199
+ env.TERM = 'xterm-256color';
200
+ // Create PTY
201
+ const ptyProcess = pty.spawn(config.agentShell, [], {
202
+ name: 'xterm-256color',
203
+ cols: options.cols,
204
+ rows: options.rows,
205
+ cwd,
206
+ env,
207
+ });
208
+ const stream = {
209
+ sid,
210
+ mode: 'pty',
211
+ startedAt: Date.now(),
212
+ process: ptyProcess,
213
+ usage: { cpuMs: 0, rssMaxBytes: 0, wallMs: 0, outBytes: 0 },
214
+ aborted: false,
215
+ limits,
216
+ };
217
+ const idleMs = config.ttyIdleTimeoutMs;
218
+ // Handle PTY data
219
+ ptyProcess.onData((data) => {
220
+ if (stream.aborted)
221
+ return;
222
+ const chunk = Buffer.from(data);
223
+ // Track bytes for usage reporting only; PTYs have no cumulative output
224
+ // ceiling (limits.maxOutBytes is unset for pty streams).
225
+ stream.usage.outBytes += chunk.length;
226
+ this.armIdleTimeout(stream, idleMs);
227
+ this.options.onStreamData?.(sid, chunk, 'stdout');
228
+ });
229
+ // Handle PTY exit
230
+ ptyProcess.onExit((exitCode) => {
231
+ stream.endedAt = Date.now();
232
+ stream.usage.wallMs = stream.endedAt - stream.startedAt;
233
+ this.clearTimers(stream);
234
+ this.output.info(`PTY stream exited for ${sid}: code=${exitCode.exitCode}, signal=${exitCode.signal}`);
235
+ this.options.onStreamExit?.(sid, exitCode.exitCode ?? null, exitCode.signal ? String(exitCode.signal) : null, stream.usage);
236
+ this.streams.delete(sid);
237
+ });
238
+ this.streams.set(sid, stream);
239
+ // No wall-clock or resource monitor for PTYs — only the idle timeout bounds
240
+ // an interactive session (see getStreamLimits).
241
+ this.armIdleTimeout(stream, idleMs);
242
+ this.output.info(`Opened PTY stream ${sid}: cols=${options.cols}, rows=${options.rows}`);
243
+ return sid;
244
+ }
245
+ /**
246
+ * Open a new command stream
247
+ */
248
+ async openCmdStream(options) {
249
+ const check = this.canOpenStream();
250
+ if (!check.allowed) {
251
+ throw new Error(check.reason);
252
+ }
253
+ // Validate arguments
254
+ try {
255
+ const config = getConfig();
256
+ validateArguments(options.argv, config.maxArgCount, config.maxArgLen);
257
+ }
258
+ catch (err) {
259
+ throw new Error(`Invalid arguments: ${err.message}`);
260
+ }
261
+ const sid = this.generateStreamId();
262
+ const limits = this.getStreamLimits('cmd');
263
+ const config = getConfig();
264
+ // Spawn process with a validated cwd and a minimal, curated environment.
265
+ const spawnOptions = {
266
+ shell: false,
267
+ detached: process.platform !== 'win32',
268
+ stdio: ['pipe', 'pipe', 'pipe'],
269
+ cwd: this.resolveCwd(options.cwd),
270
+ env: buildChildEnv(config.agentEnvPassthrough, options.env),
271
+ };
272
+ if (!options.argv || options.argv.length === 0) {
273
+ throw new Error('No command specified');
274
+ }
275
+ const [command, ...args] = options.argv;
276
+ if (!command) {
277
+ throw new Error('No command specified');
278
+ }
279
+ const childProcess = spawn(command, args, spawnOptions);
280
+ const stream = {
281
+ sid,
282
+ mode: 'cmd',
283
+ startedAt: Date.now(),
284
+ process: childProcess,
285
+ usage: { cpuMs: 0, rssMaxBytes: 0, wallMs: 0, outBytes: 0 },
286
+ aborted: false,
287
+ limits,
288
+ };
289
+ // Handle stdout / stderr (both count toward the output ceiling, but are
290
+ // tagged so the invoker can route them to the right fd).
291
+ const handleOutput = (channel) => (chunk) => {
292
+ if (stream.aborted)
293
+ return;
294
+ stream.usage.outBytes += chunk.length;
295
+ // Check output limit
296
+ if (limits.maxOutBytes && stream.usage.outBytes > limits.maxOutBytes) {
297
+ this.output.warn(`Stream output limit exceeded for ${sid}: limit=${limits.maxOutBytes}`);
298
+ this.closeStream(sid, 'Output limit exceeded');
299
+ return;
300
+ }
301
+ this.options.onStreamData?.(sid, chunk, channel);
302
+ };
303
+ if (childProcess.stdout) {
304
+ childProcess.stdout.on('data', handleOutput('stdout'));
305
+ }
306
+ if (childProcess.stderr) {
307
+ childProcess.stderr.on('data', handleOutput('stderr'));
308
+ }
309
+ // Use 'close' (not 'exit') so all stdout/stderr 'data' events have been
310
+ // emitted before we report exit. Otherwise a fast command can emit EXIT
311
+ // ahead of its final output, and the client — which tears the stream down
312
+ // on exit — would drop that trailing data.
313
+ childProcess.on('close', (code, signal) => {
314
+ stream.endedAt = Date.now();
315
+ stream.usage.wallMs = stream.endedAt - stream.startedAt;
316
+ this.clearTimers(stream);
317
+ this.output.info(`Command stream exited for ${sid}: code=${code}, signal=${signal}`);
318
+ this.options.onStreamExit?.(sid, code, signal, stream.usage);
319
+ this.streams.delete(sid);
320
+ });
321
+ // Handle process errors
322
+ childProcess.on('error', (err) => {
323
+ this.clearTimers(stream);
324
+ this.output.error(`Command stream error for ${sid}`, err.message);
325
+ this.options.onStreamError?.(sid, err.message);
326
+ this.streams.delete(sid);
327
+ });
328
+ this.streams.set(sid, stream);
329
+ this.armWallClock(stream);
330
+ this.armResourceMonitor(stream);
331
+ // Log the command name and arg count only; full argv can carry secrets.
332
+ this.output.info(`Opened command stream ${sid}: ${command} (${args.length} args)`);
333
+ return sid;
334
+ }
335
+ /**
336
+ * Write data to a stream (stdin)
337
+ */
338
+ writeToStream(sid, data) {
339
+ const stream = this.streams.get(sid);
340
+ if (!stream) {
341
+ throw new Error(`Unknown stream: ${sid}`);
342
+ }
343
+ if (stream.aborted) {
344
+ throw new Error(`Stream ${sid} is aborted`);
345
+ }
346
+ if (stream.mode === 'pty') {
347
+ const ptyProcess = stream.process;
348
+ ptyProcess.write(Buffer.from(data).toString());
349
+ }
350
+ else {
351
+ const childProcess = stream.process;
352
+ if (childProcess.stdin && !childProcess.stdin.destroyed) {
353
+ childProcess.stdin.write(data);
354
+ }
355
+ }
356
+ }
357
+ /**
358
+ * Resize a PTY stream
359
+ */
360
+ resizePtyStream(sid, cols, rows) {
361
+ const stream = this.streams.get(sid);
362
+ if (!stream) {
363
+ throw new Error(`Unknown stream: ${sid}`);
364
+ }
365
+ if (stream.mode !== 'pty') {
366
+ throw new Error(`Stream ${sid} is not a PTY`);
367
+ }
368
+ const ptyProcess = stream.process;
369
+ ptyProcess.resize(cols, rows);
370
+ this.output.debug(`Resized PTY stream ${sid}: cols=${cols}, rows=${rows}`);
371
+ }
372
+ /**
373
+ * Send signal to a stream
374
+ */
375
+ signalStream(sid, signal) {
376
+ const stream = this.streams.get(sid);
377
+ if (!stream) {
378
+ throw new Error(`Unknown stream: ${sid}`);
379
+ }
380
+ if (stream.mode === 'pty') {
381
+ const ptyProcess = stream.process;
382
+ ptyProcess.kill(signal);
383
+ }
384
+ else {
385
+ const childProcess = stream.process;
386
+ childProcess.kill(signal);
387
+ }
388
+ this.output.info(`Sent signal ${signal} to stream ${sid}`);
389
+ }
390
+ /**
391
+ * Close a stream
392
+ */
393
+ closeStream(sid, reason) {
394
+ const stream = this.streams.get(sid);
395
+ if (!stream) {
396
+ return; // Already closed
397
+ }
398
+ stream.aborted = true;
399
+ this.clearTimers(stream);
400
+ if (stream.mode === 'pty') {
401
+ const ptyProcess = stream.process;
402
+ try {
403
+ ptyProcess.kill();
404
+ }
405
+ catch (err) {
406
+ this.output.error(`Failed to kill PTY for stream ${sid}`, err instanceof Error ? err.message : String(err));
407
+ }
408
+ }
409
+ else {
410
+ const childProcess = stream.process;
411
+ try {
412
+ // Signal the whole process group (child was spawned detached) so shell
413
+ // pipelines and descendants are torn down, not just the direct child.
414
+ try {
415
+ if (process.platform !== 'win32' && childProcess.pid)
416
+ process.kill(-childProcess.pid, 'SIGTERM');
417
+ else
418
+ childProcess.kill('SIGTERM');
419
+ }
420
+ catch {
421
+ childProcess.kill('SIGTERM');
422
+ }
423
+ // Escalate to SIGKILL if the process has not actually exited. Note:
424
+ // childProcess.killed only means "a signal was delivered", so it is
425
+ // true right after SIGTERM and must NOT gate escalation. We key off the
426
+ // real exit state instead: the 'close' handler deletes the stream from
427
+ // the map and sets endedAt, so a still-present, not-yet-ended stream is
428
+ // one that ignored SIGTERM.
429
+ const timer = setTimeout(() => {
430
+ const current = this.streams.get(sid);
431
+ if (current && current.endedAt === undefined) {
432
+ try {
433
+ if (process.platform !== 'win32' && childProcess.pid)
434
+ process.kill(-childProcess.pid, 'SIGKILL');
435
+ else
436
+ childProcess.kill('SIGKILL');
437
+ }
438
+ catch { }
439
+ }
440
+ }, 5000);
441
+ // Don't keep the event loop alive just for the escalation timer.
442
+ if (typeof timer.unref === 'function')
443
+ timer.unref();
444
+ }
445
+ catch (err) {
446
+ this.output.error(`Failed to kill process for stream ${sid}`, err instanceof Error ? err.message : String(err));
447
+ }
448
+ }
449
+ this.output.info(`Closed stream ${sid}: reason=${reason}`);
450
+ }
451
+ /**
452
+ * Close all streams
453
+ */
454
+ closeAllStreams(reason) {
455
+ for (const sid of this.streams.keys()) {
456
+ this.closeStream(sid, reason);
457
+ }
458
+ }
459
+ /**
460
+ * Get stream info
461
+ */
462
+ getStream(sid) {
463
+ return this.streams.get(sid);
464
+ }
465
+ /**
466
+ * Get all active streams
467
+ */
468
+ getActiveStreams() {
469
+ return Array.from(this.streams.values()).map(stream => {
470
+ const metadata = {
471
+ sid: stream.sid,
472
+ mode: stream.mode,
473
+ startedAt: stream.startedAt,
474
+ };
475
+ if (stream.endedAt !== undefined) {
476
+ metadata.endedAt = stream.endedAt;
477
+ }
478
+ return metadata;
479
+ });
480
+ }
481
+ /**
482
+ * Get aggregate usage across all streams
483
+ */
484
+ getAggregateUsage() {
485
+ return this.aggregateUsage;
486
+ }
487
+ }
488
+ //# sourceMappingURL=stream-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-manager.js","sourceRoot":"","sources":["../src/stream-manager.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@thenewlabs/entangle-serve",
3
+ "version": "2.1.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "bin": {
7
+ "entangle-serve": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "start": "node dist/index.js",
15
+ "dev": "tsx src/index.ts",
16
+ "clean": "rm -rf dist tsconfig.tsbuildinfo"
17
+ },
18
+ "dependencies": {
19
+ "@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
20
+ "@thenewlabs/entangle-crypto": "^2.1.0",
21
+ "@thenewlabs/entangle-protocol": "^2.1.0",
22
+ "@thenewlabs/entangle-utils": "^2.1.0",
23
+ "cborg": "^4.5.8",
24
+ "commander": "^15.0.0",
25
+ "ws": "^8.21.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^20.19.43",
29
+ "@types/ws": "^8.18.1",
30
+ "tsx": "^4.23.0",
31
+ "typescript": "^5.9.3"
32
+ }
33
+ }