@livekit/agents 1.0.45 → 1.0.46
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/stream/index.cjs +3 -0
- package/dist/stream/index.cjs.map +1 -1
- package/dist/stream/index.d.cts +1 -0
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.d.ts.map +1 -1
- package/dist/stream/index.js +2 -0
- package/dist/stream/index.js.map +1 -1
- package/dist/stream/multi_input_stream.cjs +139 -0
- package/dist/stream/multi_input_stream.cjs.map +1 -0
- package/dist/stream/multi_input_stream.d.cts +55 -0
- package/dist/stream/multi_input_stream.d.ts +55 -0
- package/dist/stream/multi_input_stream.d.ts.map +1 -0
- package/dist/stream/multi_input_stream.js +115 -0
- package/dist/stream/multi_input_stream.js.map +1 -0
- package/dist/stream/multi_input_stream.test.cjs +340 -0
- package/dist/stream/multi_input_stream.test.cjs.map +1 -0
- package/dist/stream/multi_input_stream.test.js +339 -0
- package/dist/stream/multi_input_stream.test.js.map +1 -0
- package/dist/telemetry/trace_types.cjs +42 -0
- package/dist/telemetry/trace_types.cjs.map +1 -1
- package/dist/telemetry/trace_types.d.cts +14 -0
- package/dist/telemetry/trace_types.d.ts +14 -0
- package/dist/telemetry/trace_types.d.ts.map +1 -1
- package/dist/telemetry/trace_types.js +28 -0
- package/dist/telemetry/trace_types.js.map +1 -1
- package/dist/utils.cjs +13 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +1 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +13 -0
- package/dist/utils.js.map +1 -1
- package/dist/voice/agent_activity.cjs +35 -10
- package/dist/voice/agent_activity.cjs.map +1 -1
- package/dist/voice/agent_activity.d.cts +1 -0
- package/dist/voice/agent_activity.d.ts +1 -0
- package/dist/voice/agent_activity.d.ts.map +1 -1
- package/dist/voice/agent_activity.js +35 -10
- package/dist/voice/agent_activity.js.map +1 -1
- package/dist/voice/agent_session.cjs +19 -7
- package/dist/voice/agent_session.cjs.map +1 -1
- package/dist/voice/agent_session.d.cts +3 -2
- package/dist/voice/agent_session.d.ts +3 -2
- package/dist/voice/agent_session.d.ts.map +1 -1
- package/dist/voice/agent_session.js +19 -7
- package/dist/voice/agent_session.js.map +1 -1
- package/dist/voice/audio_recognition.cjs +85 -36
- package/dist/voice/audio_recognition.cjs.map +1 -1
- package/dist/voice/audio_recognition.d.cts +22 -1
- package/dist/voice/audio_recognition.d.ts +22 -1
- package/dist/voice/audio_recognition.d.ts.map +1 -1
- package/dist/voice/audio_recognition.js +89 -36
- package/dist/voice/audio_recognition.js.map +1 -1
- package/dist/voice/audio_recognition_span.test.cjs +233 -0
- package/dist/voice/audio_recognition_span.test.cjs.map +1 -0
- package/dist/voice/audio_recognition_span.test.js +232 -0
- package/dist/voice/audio_recognition_span.test.js.map +1 -0
- package/dist/voice/io.cjs +6 -3
- package/dist/voice/io.cjs.map +1 -1
- package/dist/voice/io.d.cts +3 -2
- package/dist/voice/io.d.ts +3 -2
- package/dist/voice/io.d.ts.map +1 -1
- package/dist/voice/io.js +6 -3
- package/dist/voice/io.js.map +1 -1
- package/dist/voice/recorder_io/recorder_io.cjs +3 -1
- package/dist/voice/recorder_io/recorder_io.cjs.map +1 -1
- package/dist/voice/recorder_io/recorder_io.d.ts.map +1 -1
- package/dist/voice/recorder_io/recorder_io.js +3 -1
- package/dist/voice/recorder_io/recorder_io.js.map +1 -1
- package/dist/voice/room_io/_input.cjs +17 -17
- package/dist/voice/room_io/_input.cjs.map +1 -1
- package/dist/voice/room_io/_input.d.cts +2 -2
- package/dist/voice/room_io/_input.d.ts +2 -2
- package/dist/voice/room_io/_input.d.ts.map +1 -1
- package/dist/voice/room_io/_input.js +7 -6
- package/dist/voice/room_io/_input.js.map +1 -1
- package/dist/voice/room_io/room_io.cjs +9 -0
- package/dist/voice/room_io/room_io.cjs.map +1 -1
- package/dist/voice/room_io/room_io.d.cts +3 -1
- package/dist/voice/room_io/room_io.d.ts +3 -1
- package/dist/voice/room_io/room_io.d.ts.map +1 -1
- package/dist/voice/room_io/room_io.js +9 -0
- package/dist/voice/room_io/room_io.js.map +1 -1
- package/dist/voice/utils.cjs +47 -0
- package/dist/voice/utils.cjs.map +1 -0
- package/dist/voice/utils.d.cts +4 -0
- package/dist/voice/utils.d.ts +4 -0
- package/dist/voice/utils.d.ts.map +1 -0
- package/dist/voice/utils.js +23 -0
- package/dist/voice/utils.js.map +1 -0
- package/package.json +1 -1
- package/src/stream/index.ts +1 -0
- package/src/stream/multi_input_stream.test.ts +540 -0
- package/src/stream/multi_input_stream.ts +172 -0
- package/src/telemetry/trace_types.ts +18 -0
- package/src/utils.ts +16 -0
- package/src/voice/agent_activity.ts +25 -0
- package/src/voice/agent_session.ts +17 -11
- package/src/voice/audio_recognition.ts +114 -38
- package/src/voice/audio_recognition_span.test.ts +261 -0
- package/src/voice/io.ts +7 -4
- package/src/voice/recorder_io/recorder_io.ts +2 -1
- package/src/voice/room_io/_input.ts +11 -7
- package/src/voice/room_io/room_io.ts +12 -0
- package/src/voice/utils.ts +29 -0
package/dist/stream/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var stream_exports = {};
|
|
|
20
20
|
__export(stream_exports, {
|
|
21
21
|
DeferredReadableStream: () => import_deferred_stream.DeferredReadableStream,
|
|
22
22
|
IdentityTransform: () => import_identity_transform.IdentityTransform,
|
|
23
|
+
MultiInputStream: () => import_multi_input_stream.MultiInputStream,
|
|
23
24
|
createStreamChannel: () => import_stream_channel.createStreamChannel,
|
|
24
25
|
mergeReadableStreams: () => import_merge_readable_streams.mergeReadableStreams
|
|
25
26
|
});
|
|
@@ -27,11 +28,13 @@ module.exports = __toCommonJS(stream_exports);
|
|
|
27
28
|
var import_deferred_stream = require("./deferred_stream.cjs");
|
|
28
29
|
var import_identity_transform = require("./identity_transform.cjs");
|
|
29
30
|
var import_merge_readable_streams = require("./merge_readable_streams.cjs");
|
|
31
|
+
var import_multi_input_stream = require("./multi_input_stream.cjs");
|
|
30
32
|
var import_stream_channel = require("./stream_channel.cjs");
|
|
31
33
|
// Annotate the CommonJS export names for ESM import in node:
|
|
32
34
|
0 && (module.exports = {
|
|
33
35
|
DeferredReadableStream,
|
|
34
36
|
IdentityTransform,
|
|
37
|
+
MultiInputStream,
|
|
35
38
|
createStreamChannel,
|
|
36
39
|
mergeReadableStreams
|
|
37
40
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/stream/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { DeferredReadableStream } from './deferred_stream.js';\nexport { IdentityTransform } from './identity_transform.js';\nexport { mergeReadableStreams } from './merge_readable_streams.js';\nexport { createStreamChannel, type StreamChannel } from './stream_channel.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,6BAAuC;AACvC,gCAAkC;AAClC,oCAAqC;AACrC,4BAAwD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/stream/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { DeferredReadableStream } from './deferred_stream.js';\nexport { IdentityTransform } from './identity_transform.js';\nexport { mergeReadableStreams } from './merge_readable_streams.js';\nexport { MultiInputStream } from './multi_input_stream.js';\nexport { createStreamChannel, type StreamChannel } from './stream_channel.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,6BAAuC;AACvC,gCAAkC;AAClC,oCAAqC;AACrC,gCAAiC;AACjC,4BAAwD;","names":[]}
|
package/dist/stream/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { DeferredReadableStream } from './deferred_stream.js';
|
|
2
2
|
export { IdentityTransform } from './identity_transform.js';
|
|
3
3
|
export { mergeReadableStreams } from './merge_readable_streams.js';
|
|
4
|
+
export { MultiInputStream } from './multi_input_stream.js';
|
|
4
5
|
export { createStreamChannel, type StreamChannel } from './stream_channel.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/stream/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { DeferredReadableStream } from './deferred_stream.js';
|
|
2
2
|
export { IdentityTransform } from './identity_transform.js';
|
|
3
3
|
export { mergeReadableStreams } from './merge_readable_streams.js';
|
|
4
|
+
export { MultiInputStream } from './multi_input_stream.js';
|
|
4
5
|
export { createStreamChannel, type StreamChannel } from './stream_channel.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stream/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/stream/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/stream/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { DeferredReadableStream } from "./deferred_stream.js";
|
|
2
2
|
import { IdentityTransform } from "./identity_transform.js";
|
|
3
3
|
import { mergeReadableStreams } from "./merge_readable_streams.js";
|
|
4
|
+
import { MultiInputStream } from "./multi_input_stream.js";
|
|
4
5
|
import { createStreamChannel } from "./stream_channel.js";
|
|
5
6
|
export {
|
|
6
7
|
DeferredReadableStream,
|
|
7
8
|
IdentityTransform,
|
|
9
|
+
MultiInputStream,
|
|
8
10
|
createStreamChannel,
|
|
9
11
|
mergeReadableStreams
|
|
10
12
|
};
|
package/dist/stream/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/stream/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { DeferredReadableStream } from './deferred_stream.js';\nexport { IdentityTransform } from './identity_transform.js';\nexport { mergeReadableStreams } from './merge_readable_streams.js';\nexport { createStreamChannel, type StreamChannel } from './stream_channel.js';\n"],"mappings":"AAGA,SAAS,8BAA8B;AACvC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,2BAA+C;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/stream/index.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nexport { DeferredReadableStream } from './deferred_stream.js';\nexport { IdentityTransform } from './identity_transform.js';\nexport { mergeReadableStreams } from './merge_readable_streams.js';\nexport { MultiInputStream } from './multi_input_stream.js';\nexport { createStreamChannel, type StreamChannel } from './stream_channel.js';\n"],"mappings":"AAGA,SAAS,8BAA8B;AACvC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,wBAAwB;AACjC,SAAS,2BAA+C;","names":[]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var multi_input_stream_exports = {};
|
|
20
|
+
__export(multi_input_stream_exports, {
|
|
21
|
+
MultiInputStream: () => MultiInputStream
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(multi_input_stream_exports);
|
|
24
|
+
var import_log = require("../log.cjs");
|
|
25
|
+
var import_deferred_stream = require("./deferred_stream.cjs");
|
|
26
|
+
var import_identity_transform = require("./identity_transform.cjs");
|
|
27
|
+
class MultiInputStream {
|
|
28
|
+
transform;
|
|
29
|
+
writer;
|
|
30
|
+
inputs = /* @__PURE__ */ new Map();
|
|
31
|
+
pumpPromises = /* @__PURE__ */ new Map();
|
|
32
|
+
nextId = 0;
|
|
33
|
+
_closed = false;
|
|
34
|
+
logger = (0, import_log.log)();
|
|
35
|
+
constructor() {
|
|
36
|
+
this.transform = new import_identity_transform.IdentityTransform();
|
|
37
|
+
this.writer = this.transform.writable.getWriter();
|
|
38
|
+
}
|
|
39
|
+
/** The single output stream that consumers read from. */
|
|
40
|
+
get stream() {
|
|
41
|
+
return this.transform.readable;
|
|
42
|
+
}
|
|
43
|
+
/** Number of currently active input streams. */
|
|
44
|
+
get inputCount() {
|
|
45
|
+
return this.inputs.size;
|
|
46
|
+
}
|
|
47
|
+
/** Whether {@link close} has been called. */
|
|
48
|
+
get isClosed() {
|
|
49
|
+
return this._closed;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Add an input {@link ReadableStream} that will be pumped into the output.
|
|
53
|
+
*
|
|
54
|
+
* @returns A unique identifier that can be passed to {@link removeInputStream}.
|
|
55
|
+
* @throws If the stream has already been closed.
|
|
56
|
+
*/
|
|
57
|
+
addInputStream(source) {
|
|
58
|
+
if (this._closed) {
|
|
59
|
+
throw new Error("MultiInputStream is closed");
|
|
60
|
+
}
|
|
61
|
+
const id = `input-${this.nextId++}`;
|
|
62
|
+
const reader = source.getReader();
|
|
63
|
+
this.inputs.set(id, reader);
|
|
64
|
+
const pumpDone = this.pumpInput(id, reader);
|
|
65
|
+
this.pumpPromises.set(id, pumpDone);
|
|
66
|
+
return id;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Detach an input stream by its ID and release the reader lock so the
|
|
70
|
+
* source stream can be reused elsewhere.
|
|
71
|
+
*
|
|
72
|
+
* No-op if the ID does not exist (e.g. the input already ended or was removed).
|
|
73
|
+
*/
|
|
74
|
+
async removeInputStream(id) {
|
|
75
|
+
const reader = this.inputs.get(id);
|
|
76
|
+
if (!reader) return;
|
|
77
|
+
this.inputs.delete(id);
|
|
78
|
+
reader.releaseLock();
|
|
79
|
+
const pump = this.pumpPromises.get(id);
|
|
80
|
+
if (pump) {
|
|
81
|
+
await pump;
|
|
82
|
+
this.pumpPromises.delete(id);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Close the output stream and detach all inputs.
|
|
87
|
+
*
|
|
88
|
+
* Idempotent — calling more than once is a no-op.
|
|
89
|
+
*/
|
|
90
|
+
async close() {
|
|
91
|
+
if (this._closed) return;
|
|
92
|
+
this._closed = true;
|
|
93
|
+
for (const reader of this.inputs.values()) {
|
|
94
|
+
reader.releaseLock();
|
|
95
|
+
}
|
|
96
|
+
this.inputs.clear();
|
|
97
|
+
await Promise.allSettled([...this.pumpPromises.values()]);
|
|
98
|
+
this.pumpPromises.clear();
|
|
99
|
+
try {
|
|
100
|
+
this.writer.releaseLock();
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
await this.transform.writable.close();
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
shouldStopPumping(id) {
|
|
109
|
+
return this._closed || !this.inputs.has(id);
|
|
110
|
+
}
|
|
111
|
+
async pumpInput(id, reader) {
|
|
112
|
+
try {
|
|
113
|
+
while (true) {
|
|
114
|
+
if (this.shouldStopPumping(id)) break;
|
|
115
|
+
const { done, value } = await reader.read();
|
|
116
|
+
if (done) break;
|
|
117
|
+
if (this.shouldStopPumping(id)) break;
|
|
118
|
+
await this.writer.write(value);
|
|
119
|
+
}
|
|
120
|
+
} catch (e) {
|
|
121
|
+
if ((0, import_deferred_stream.isStreamReaderReleaseError)(e)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.logger.error({ error: e }, "Error pumping input stream from MultiInputStream");
|
|
125
|
+
} finally {
|
|
126
|
+
try {
|
|
127
|
+
reader.releaseLock();
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
this.inputs.delete(id);
|
|
131
|
+
this.pumpPromises.delete(id);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
136
|
+
0 && (module.exports = {
|
|
137
|
+
MultiInputStream
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=multi_input_stream.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/stream/multi_input_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n ReadableStream,\n ReadableStreamDefaultReader,\n WritableStreamDefaultWriter,\n} from 'node:stream/web';\nimport { log } from '../log.js';\nimport { isStreamReaderReleaseError } from './deferred_stream.js';\nimport { IdentityTransform } from './identity_transform.js';\n\n/**\n * A fan-in multiplexer that merges multiple {@link ReadableStream} inputs into\n * a single output {@link ReadableStream}. Inputs can be dynamically added and\n * removed at any time while the stream is open.\n *\n * Unlike {@link DeferredReadableStream} which supports a single readable source,\n * `MultiInputStream` allows N concurrent input streams to pump data into one output.\n *\n * Key behaviors:\n * - An error in one input removes that input but does **not** kill the output.\n * - When all inputs end or are removed, the output stays open (waiting for new inputs).\n * - The output only closes when {@link close} is called explicitly.\n * - {@link removeInputStream} releases the reader lock so the source can be reused.\n */\nexport class MultiInputStream<T> {\n private transform: IdentityTransform<T>;\n private writer: WritableStreamDefaultWriter<T>;\n private inputs: Map<string, ReadableStreamDefaultReader<T>> = new Map();\n private pumpPromises: Map<string, Promise<void>> = new Map();\n private nextId = 0;\n private _closed = false;\n private logger = log();\n\n constructor() {\n this.transform = new IdentityTransform<T>();\n this.writer = this.transform.writable.getWriter();\n }\n\n /** The single output stream that consumers read from. */\n get stream(): ReadableStream<T> {\n return this.transform.readable;\n }\n\n /** Number of currently active input streams. */\n get inputCount(): number {\n return this.inputs.size;\n }\n\n /** Whether {@link close} has been called. */\n get isClosed(): boolean {\n return this._closed;\n }\n\n /**\n * Add an input {@link ReadableStream} that will be pumped into the output.\n *\n * @returns A unique identifier that can be passed to {@link removeInputStream}.\n * @throws If the stream has already been closed.\n */\n addInputStream(source: ReadableStream<T>): string {\n if (this._closed) {\n throw new Error('MultiInputStream is closed');\n }\n\n const id = `input-${this.nextId++}`;\n const reader = source.getReader();\n this.inputs.set(id, reader);\n\n const pumpDone = this.pumpInput(id, reader);\n this.pumpPromises.set(id, pumpDone);\n\n return id;\n }\n\n /**\n * Detach an input stream by its ID and release the reader lock so the\n * source stream can be reused elsewhere.\n *\n * No-op if the ID does not exist (e.g. the input already ended or was removed).\n */\n async removeInputStream(id: string): Promise<void> {\n const reader = this.inputs.get(id);\n if (!reader) return;\n\n // Delete first so the pump's finally-block is a harmless no-op.\n this.inputs.delete(id);\n\n // Releasing the lock causes any pending reader.read() inside pump to throw\n // a TypeError, which is caught by isStreamReaderReleaseError.\n reader.releaseLock();\n\n // Wait for the pump to finish so the caller knows cleanup is complete.\n const pump = this.pumpPromises.get(id);\n if (pump) {\n await pump;\n this.pumpPromises.delete(id);\n }\n }\n\n /**\n * Close the output stream and detach all inputs.\n *\n * Idempotent — calling more than once is a no-op.\n */\n async close(): Promise<void> {\n if (this._closed) return;\n this._closed = true;\n\n // Release every input reader to unblock pending reads inside pumps.\n for (const reader of this.inputs.values()) {\n reader.releaseLock();\n }\n this.inputs.clear();\n\n // Wait for every pump loop to finish before touching the writer.\n await Promise.allSettled([...this.pumpPromises.values()]);\n this.pumpPromises.clear();\n\n // Close the output writer + writable side of the transform.\n try {\n this.writer.releaseLock();\n } catch {\n // ignore if already released\n }\n\n try {\n await this.transform.writable.close();\n } catch {\n // ignore if already closed\n }\n }\n\n private shouldStopPumping(id: string): boolean {\n return this._closed || !this.inputs.has(id);\n }\n\n private async pumpInput(id: string, reader: ReadableStreamDefaultReader<T>): Promise<void> {\n try {\n while (true) {\n // If the stream was closed or the input was removed while we were\n // awaiting the previous write, bail out immediately.\n if (this.shouldStopPumping(id)) break;\n\n const { done, value } = await reader.read();\n if (done) break;\n\n // Double-check after the (potentially long) read.\n if (this.shouldStopPumping(id)) break;\n\n await this.writer.write(value);\n }\n } catch (e) {\n // TypeErrors from releaseLock() during removeInputStream / close are expected.\n if (isStreamReaderReleaseError(e)) {\n return;\n }\n\n this.logger.error({ error: e }, 'Error pumping input stream from MultiInputStream');\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // ignore if already released\n }\n\n this.inputs.delete(id);\n this.pumpPromises.delete(id);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,iBAAoB;AACpB,6BAA2C;AAC3C,gCAAkC;AAgB3B,MAAM,iBAAoB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,SAAsD,oBAAI,IAAI;AAAA,EAC9D,eAA2C,oBAAI,IAAI;AAAA,EACnD,SAAS;AAAA,EACT,UAAU;AAAA,EACV,aAAS,gBAAI;AAAA,EAErB,cAAc;AACZ,SAAK,YAAY,IAAI,4CAAqB;AAC1C,SAAK,SAAS,KAAK,UAAU,SAAS,UAAU;AAAA,EAClD;AAAA;AAAA,EAGA,IAAI,SAA4B;AAC9B,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA,EAGA,IAAI,aAAqB;AACvB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA,EAGA,IAAI,WAAoB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAmC;AAChD,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AAEA,UAAM,KAAK,SAAS,KAAK,QAAQ;AACjC,UAAM,SAAS,OAAO,UAAU;AAChC,SAAK,OAAO,IAAI,IAAI,MAAM;AAE1B,UAAM,WAAW,KAAK,UAAU,IAAI,MAAM;AAC1C,SAAK,aAAa,IAAI,IAAI,QAAQ;AAElC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,kBAAkB,IAA2B;AACjD,UAAM,SAAS,KAAK,OAAO,IAAI,EAAE;AACjC,QAAI,CAAC,OAAQ;AAGb,SAAK,OAAO,OAAO,EAAE;AAIrB,WAAO,YAAY;AAGnB,UAAM,OAAO,KAAK,aAAa,IAAI,EAAE;AACrC,QAAI,MAAM;AACR,YAAM;AACN,WAAK,aAAa,OAAO,EAAE;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AAGf,eAAW,UAAU,KAAK,OAAO,OAAO,GAAG;AACzC,aAAO,YAAY;AAAA,IACrB;AACA,SAAK,OAAO,MAAM;AAGlB,UAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,aAAa,OAAO,CAAC,CAAC;AACxD,SAAK,aAAa,MAAM;AAGxB,QAAI;AACF,WAAK,OAAO,YAAY;AAAA,IAC1B,QAAQ;AAAA,IAER;AAEA,QAAI;AACF,YAAM,KAAK,UAAU,SAAS,MAAM;AAAA,IACtC,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,kBAAkB,IAAqB;AAC7C,WAAO,KAAK,WAAW,CAAC,KAAK,OAAO,IAAI,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAc,UAAU,IAAY,QAAuD;AACzF,QAAI;AACF,aAAO,MAAM;AAGX,YAAI,KAAK,kBAAkB,EAAE,EAAG;AAEhC,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAGV,YAAI,KAAK,kBAAkB,EAAE,EAAG;AAEhC,cAAM,KAAK,OAAO,MAAM,KAAK;AAAA,MAC/B;AAAA,IACF,SAAS,GAAG;AAEV,cAAI,mDAA2B,CAAC,GAAG;AACjC;AAAA,MACF;AAEA,WAAK,OAAO,MAAM,EAAE,OAAO,EAAE,GAAG,kDAAkD;AAAA,IACpF,UAAE;AACA,UAAI;AACF,eAAO,YAAY;AAAA,MACrB,QAAQ;AAAA,MAER;AAEA,WAAK,OAAO,OAAO,EAAE;AACrB,WAAK,aAAa,OAAO,EAAE;AAAA,IAC7B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import type { ReadableStream } from 'node:stream/web';
|
|
3
|
+
/**
|
|
4
|
+
* A fan-in multiplexer that merges multiple {@link ReadableStream} inputs into
|
|
5
|
+
* a single output {@link ReadableStream}. Inputs can be dynamically added and
|
|
6
|
+
* removed at any time while the stream is open.
|
|
7
|
+
*
|
|
8
|
+
* Unlike {@link DeferredReadableStream} which supports a single readable source,
|
|
9
|
+
* `MultiInputStream` allows N concurrent input streams to pump data into one output.
|
|
10
|
+
*
|
|
11
|
+
* Key behaviors:
|
|
12
|
+
* - An error in one input removes that input but does **not** kill the output.
|
|
13
|
+
* - When all inputs end or are removed, the output stays open (waiting for new inputs).
|
|
14
|
+
* - The output only closes when {@link close} is called explicitly.
|
|
15
|
+
* - {@link removeInputStream} releases the reader lock so the source can be reused.
|
|
16
|
+
*/
|
|
17
|
+
export declare class MultiInputStream<T> {
|
|
18
|
+
private transform;
|
|
19
|
+
private writer;
|
|
20
|
+
private inputs;
|
|
21
|
+
private pumpPromises;
|
|
22
|
+
private nextId;
|
|
23
|
+
private _closed;
|
|
24
|
+
private logger;
|
|
25
|
+
constructor();
|
|
26
|
+
/** The single output stream that consumers read from. */
|
|
27
|
+
get stream(): ReadableStream<T>;
|
|
28
|
+
/** Number of currently active input streams. */
|
|
29
|
+
get inputCount(): number;
|
|
30
|
+
/** Whether {@link close} has been called. */
|
|
31
|
+
get isClosed(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Add an input {@link ReadableStream} that will be pumped into the output.
|
|
34
|
+
*
|
|
35
|
+
* @returns A unique identifier that can be passed to {@link removeInputStream}.
|
|
36
|
+
* @throws If the stream has already been closed.
|
|
37
|
+
*/
|
|
38
|
+
addInputStream(source: ReadableStream<T>): string;
|
|
39
|
+
/**
|
|
40
|
+
* Detach an input stream by its ID and release the reader lock so the
|
|
41
|
+
* source stream can be reused elsewhere.
|
|
42
|
+
*
|
|
43
|
+
* No-op if the ID does not exist (e.g. the input already ended or was removed).
|
|
44
|
+
*/
|
|
45
|
+
removeInputStream(id: string): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Close the output stream and detach all inputs.
|
|
48
|
+
*
|
|
49
|
+
* Idempotent — calling more than once is a no-op.
|
|
50
|
+
*/
|
|
51
|
+
close(): Promise<void>;
|
|
52
|
+
private shouldStopPumping;
|
|
53
|
+
private pumpInput;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=multi_input_stream.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import type { ReadableStream } from 'node:stream/web';
|
|
3
|
+
/**
|
|
4
|
+
* A fan-in multiplexer that merges multiple {@link ReadableStream} inputs into
|
|
5
|
+
* a single output {@link ReadableStream}. Inputs can be dynamically added and
|
|
6
|
+
* removed at any time while the stream is open.
|
|
7
|
+
*
|
|
8
|
+
* Unlike {@link DeferredReadableStream} which supports a single readable source,
|
|
9
|
+
* `MultiInputStream` allows N concurrent input streams to pump data into one output.
|
|
10
|
+
*
|
|
11
|
+
* Key behaviors:
|
|
12
|
+
* - An error in one input removes that input but does **not** kill the output.
|
|
13
|
+
* - When all inputs end or are removed, the output stays open (waiting for new inputs).
|
|
14
|
+
* - The output only closes when {@link close} is called explicitly.
|
|
15
|
+
* - {@link removeInputStream} releases the reader lock so the source can be reused.
|
|
16
|
+
*/
|
|
17
|
+
export declare class MultiInputStream<T> {
|
|
18
|
+
private transform;
|
|
19
|
+
private writer;
|
|
20
|
+
private inputs;
|
|
21
|
+
private pumpPromises;
|
|
22
|
+
private nextId;
|
|
23
|
+
private _closed;
|
|
24
|
+
private logger;
|
|
25
|
+
constructor();
|
|
26
|
+
/** The single output stream that consumers read from. */
|
|
27
|
+
get stream(): ReadableStream<T>;
|
|
28
|
+
/** Number of currently active input streams. */
|
|
29
|
+
get inputCount(): number;
|
|
30
|
+
/** Whether {@link close} has been called. */
|
|
31
|
+
get isClosed(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Add an input {@link ReadableStream} that will be pumped into the output.
|
|
34
|
+
*
|
|
35
|
+
* @returns A unique identifier that can be passed to {@link removeInputStream}.
|
|
36
|
+
* @throws If the stream has already been closed.
|
|
37
|
+
*/
|
|
38
|
+
addInputStream(source: ReadableStream<T>): string;
|
|
39
|
+
/**
|
|
40
|
+
* Detach an input stream by its ID and release the reader lock so the
|
|
41
|
+
* source stream can be reused elsewhere.
|
|
42
|
+
*
|
|
43
|
+
* No-op if the ID does not exist (e.g. the input already ended or was removed).
|
|
44
|
+
*/
|
|
45
|
+
removeInputStream(id: string): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Close the output stream and detach all inputs.
|
|
48
|
+
*
|
|
49
|
+
* Idempotent — calling more than once is a no-op.
|
|
50
|
+
*/
|
|
51
|
+
close(): Promise<void>;
|
|
52
|
+
private shouldStopPumping;
|
|
53
|
+
private pumpInput;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=multi_input_stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi_input_stream.d.ts","sourceRoot":"","sources":["../../src/stream/multi_input_stream.ts"],"names":[],"mappings":";AAGA,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,iBAAiB,CAAC;AAKzB;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB,CAAC,CAAC;IAC7B,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,MAAM,CAA0D;IACxE,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;;IAOvB,yDAAyD;IACzD,IAAI,MAAM,IAAI,cAAc,CAAC,CAAC,CAAC,CAE9B;IAED,gDAAgD;IAChD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,6CAA6C;IAC7C,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;;;OAKG;IACH,cAAc,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,MAAM;IAejD;;;;;OAKG;IACG,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B5B,OAAO,CAAC,iBAAiB;YAIX,SAAS;CAiCxB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { log } from "../log.js";
|
|
2
|
+
import { isStreamReaderReleaseError } from "./deferred_stream.js";
|
|
3
|
+
import { IdentityTransform } from "./identity_transform.js";
|
|
4
|
+
class MultiInputStream {
|
|
5
|
+
transform;
|
|
6
|
+
writer;
|
|
7
|
+
inputs = /* @__PURE__ */ new Map();
|
|
8
|
+
pumpPromises = /* @__PURE__ */ new Map();
|
|
9
|
+
nextId = 0;
|
|
10
|
+
_closed = false;
|
|
11
|
+
logger = log();
|
|
12
|
+
constructor() {
|
|
13
|
+
this.transform = new IdentityTransform();
|
|
14
|
+
this.writer = this.transform.writable.getWriter();
|
|
15
|
+
}
|
|
16
|
+
/** The single output stream that consumers read from. */
|
|
17
|
+
get stream() {
|
|
18
|
+
return this.transform.readable;
|
|
19
|
+
}
|
|
20
|
+
/** Number of currently active input streams. */
|
|
21
|
+
get inputCount() {
|
|
22
|
+
return this.inputs.size;
|
|
23
|
+
}
|
|
24
|
+
/** Whether {@link close} has been called. */
|
|
25
|
+
get isClosed() {
|
|
26
|
+
return this._closed;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Add an input {@link ReadableStream} that will be pumped into the output.
|
|
30
|
+
*
|
|
31
|
+
* @returns A unique identifier that can be passed to {@link removeInputStream}.
|
|
32
|
+
* @throws If the stream has already been closed.
|
|
33
|
+
*/
|
|
34
|
+
addInputStream(source) {
|
|
35
|
+
if (this._closed) {
|
|
36
|
+
throw new Error("MultiInputStream is closed");
|
|
37
|
+
}
|
|
38
|
+
const id = `input-${this.nextId++}`;
|
|
39
|
+
const reader = source.getReader();
|
|
40
|
+
this.inputs.set(id, reader);
|
|
41
|
+
const pumpDone = this.pumpInput(id, reader);
|
|
42
|
+
this.pumpPromises.set(id, pumpDone);
|
|
43
|
+
return id;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Detach an input stream by its ID and release the reader lock so the
|
|
47
|
+
* source stream can be reused elsewhere.
|
|
48
|
+
*
|
|
49
|
+
* No-op if the ID does not exist (e.g. the input already ended or was removed).
|
|
50
|
+
*/
|
|
51
|
+
async removeInputStream(id) {
|
|
52
|
+
const reader = this.inputs.get(id);
|
|
53
|
+
if (!reader) return;
|
|
54
|
+
this.inputs.delete(id);
|
|
55
|
+
reader.releaseLock();
|
|
56
|
+
const pump = this.pumpPromises.get(id);
|
|
57
|
+
if (pump) {
|
|
58
|
+
await pump;
|
|
59
|
+
this.pumpPromises.delete(id);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Close the output stream and detach all inputs.
|
|
64
|
+
*
|
|
65
|
+
* Idempotent — calling more than once is a no-op.
|
|
66
|
+
*/
|
|
67
|
+
async close() {
|
|
68
|
+
if (this._closed) return;
|
|
69
|
+
this._closed = true;
|
|
70
|
+
for (const reader of this.inputs.values()) {
|
|
71
|
+
reader.releaseLock();
|
|
72
|
+
}
|
|
73
|
+
this.inputs.clear();
|
|
74
|
+
await Promise.allSettled([...this.pumpPromises.values()]);
|
|
75
|
+
this.pumpPromises.clear();
|
|
76
|
+
try {
|
|
77
|
+
this.writer.releaseLock();
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
await this.transform.writable.close();
|
|
82
|
+
} catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
shouldStopPumping(id) {
|
|
86
|
+
return this._closed || !this.inputs.has(id);
|
|
87
|
+
}
|
|
88
|
+
async pumpInput(id, reader) {
|
|
89
|
+
try {
|
|
90
|
+
while (true) {
|
|
91
|
+
if (this.shouldStopPumping(id)) break;
|
|
92
|
+
const { done, value } = await reader.read();
|
|
93
|
+
if (done) break;
|
|
94
|
+
if (this.shouldStopPumping(id)) break;
|
|
95
|
+
await this.writer.write(value);
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
if (isStreamReaderReleaseError(e)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this.logger.error({ error: e }, "Error pumping input stream from MultiInputStream");
|
|
102
|
+
} finally {
|
|
103
|
+
try {
|
|
104
|
+
reader.releaseLock();
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
this.inputs.delete(id);
|
|
108
|
+
this.pumpPromises.delete(id);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
export {
|
|
113
|
+
MultiInputStream
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=multi_input_stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/stream/multi_input_stream.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2025 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type {\n ReadableStream,\n ReadableStreamDefaultReader,\n WritableStreamDefaultWriter,\n} from 'node:stream/web';\nimport { log } from '../log.js';\nimport { isStreamReaderReleaseError } from './deferred_stream.js';\nimport { IdentityTransform } from './identity_transform.js';\n\n/**\n * A fan-in multiplexer that merges multiple {@link ReadableStream} inputs into\n * a single output {@link ReadableStream}. Inputs can be dynamically added and\n * removed at any time while the stream is open.\n *\n * Unlike {@link DeferredReadableStream} which supports a single readable source,\n * `MultiInputStream` allows N concurrent input streams to pump data into one output.\n *\n * Key behaviors:\n * - An error in one input removes that input but does **not** kill the output.\n * - When all inputs end or are removed, the output stays open (waiting for new inputs).\n * - The output only closes when {@link close} is called explicitly.\n * - {@link removeInputStream} releases the reader lock so the source can be reused.\n */\nexport class MultiInputStream<T> {\n private transform: IdentityTransform<T>;\n private writer: WritableStreamDefaultWriter<T>;\n private inputs: Map<string, ReadableStreamDefaultReader<T>> = new Map();\n private pumpPromises: Map<string, Promise<void>> = new Map();\n private nextId = 0;\n private _closed = false;\n private logger = log();\n\n constructor() {\n this.transform = new IdentityTransform<T>();\n this.writer = this.transform.writable.getWriter();\n }\n\n /** The single output stream that consumers read from. */\n get stream(): ReadableStream<T> {\n return this.transform.readable;\n }\n\n /** Number of currently active input streams. */\n get inputCount(): number {\n return this.inputs.size;\n }\n\n /** Whether {@link close} has been called. */\n get isClosed(): boolean {\n return this._closed;\n }\n\n /**\n * Add an input {@link ReadableStream} that will be pumped into the output.\n *\n * @returns A unique identifier that can be passed to {@link removeInputStream}.\n * @throws If the stream has already been closed.\n */\n addInputStream(source: ReadableStream<T>): string {\n if (this._closed) {\n throw new Error('MultiInputStream is closed');\n }\n\n const id = `input-${this.nextId++}`;\n const reader = source.getReader();\n this.inputs.set(id, reader);\n\n const pumpDone = this.pumpInput(id, reader);\n this.pumpPromises.set(id, pumpDone);\n\n return id;\n }\n\n /**\n * Detach an input stream by its ID and release the reader lock so the\n * source stream can be reused elsewhere.\n *\n * No-op if the ID does not exist (e.g. the input already ended or was removed).\n */\n async removeInputStream(id: string): Promise<void> {\n const reader = this.inputs.get(id);\n if (!reader) return;\n\n // Delete first so the pump's finally-block is a harmless no-op.\n this.inputs.delete(id);\n\n // Releasing the lock causes any pending reader.read() inside pump to throw\n // a TypeError, which is caught by isStreamReaderReleaseError.\n reader.releaseLock();\n\n // Wait for the pump to finish so the caller knows cleanup is complete.\n const pump = this.pumpPromises.get(id);\n if (pump) {\n await pump;\n this.pumpPromises.delete(id);\n }\n }\n\n /**\n * Close the output stream and detach all inputs.\n *\n * Idempotent — calling more than once is a no-op.\n */\n async close(): Promise<void> {\n if (this._closed) return;\n this._closed = true;\n\n // Release every input reader to unblock pending reads inside pumps.\n for (const reader of this.inputs.values()) {\n reader.releaseLock();\n }\n this.inputs.clear();\n\n // Wait for every pump loop to finish before touching the writer.\n await Promise.allSettled([...this.pumpPromises.values()]);\n this.pumpPromises.clear();\n\n // Close the output writer + writable side of the transform.\n try {\n this.writer.releaseLock();\n } catch {\n // ignore if already released\n }\n\n try {\n await this.transform.writable.close();\n } catch {\n // ignore if already closed\n }\n }\n\n private shouldStopPumping(id: string): boolean {\n return this._closed || !this.inputs.has(id);\n }\n\n private async pumpInput(id: string, reader: ReadableStreamDefaultReader<T>): Promise<void> {\n try {\n while (true) {\n // If the stream was closed or the input was removed while we were\n // awaiting the previous write, bail out immediately.\n if (this.shouldStopPumping(id)) break;\n\n const { done, value } = await reader.read();\n if (done) break;\n\n // Double-check after the (potentially long) read.\n if (this.shouldStopPumping(id)) break;\n\n await this.writer.write(value);\n }\n } catch (e) {\n // TypeErrors from releaseLock() during removeInputStream / close are expected.\n if (isStreamReaderReleaseError(e)) {\n return;\n }\n\n this.logger.error({ error: e }, 'Error pumping input stream from MultiInputStream');\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // ignore if already released\n }\n\n this.inputs.delete(id);\n this.pumpPromises.delete(id);\n }\n }\n}\n"],"mappings":"AAQA,SAAS,WAAW;AACpB,SAAS,kCAAkC;AAC3C,SAAS,yBAAyB;AAgB3B,MAAM,iBAAoB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,SAAsD,oBAAI,IAAI;AAAA,EAC9D,eAA2C,oBAAI,IAAI;AAAA,EACnD,SAAS;AAAA,EACT,UAAU;AAAA,EACV,SAAS,IAAI;AAAA,EAErB,cAAc;AACZ,SAAK,YAAY,IAAI,kBAAqB;AAC1C,SAAK,SAAS,KAAK,UAAU,SAAS,UAAU;AAAA,EAClD;AAAA;AAAA,EAGA,IAAI,SAA4B;AAC9B,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA,EAGA,IAAI,aAAqB;AACvB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA,EAGA,IAAI,WAAoB;AACtB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,QAAmC;AAChD,QAAI,KAAK,SAAS;AAChB,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC9C;AAEA,UAAM,KAAK,SAAS,KAAK,QAAQ;AACjC,UAAM,SAAS,OAAO,UAAU;AAChC,SAAK,OAAO,IAAI,IAAI,MAAM;AAE1B,UAAM,WAAW,KAAK,UAAU,IAAI,MAAM;AAC1C,SAAK,aAAa,IAAI,IAAI,QAAQ;AAElC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,kBAAkB,IAA2B;AACjD,UAAM,SAAS,KAAK,OAAO,IAAI,EAAE;AACjC,QAAI,CAAC,OAAQ;AAGb,SAAK,OAAO,OAAO,EAAE;AAIrB,WAAO,YAAY;AAGnB,UAAM,OAAO,KAAK,aAAa,IAAI,EAAE;AACrC,QAAI,MAAM;AACR,YAAM;AACN,WAAK,aAAa,OAAO,EAAE;AAAA,IAC7B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AAGf,eAAW,UAAU,KAAK,OAAO,OAAO,GAAG;AACzC,aAAO,YAAY;AAAA,IACrB;AACA,SAAK,OAAO,MAAM;AAGlB,UAAM,QAAQ,WAAW,CAAC,GAAG,KAAK,aAAa,OAAO,CAAC,CAAC;AACxD,SAAK,aAAa,MAAM;AAGxB,QAAI;AACF,WAAK,OAAO,YAAY;AAAA,IAC1B,QAAQ;AAAA,IAER;AAEA,QAAI;AACF,YAAM,KAAK,UAAU,SAAS,MAAM;AAAA,IACtC,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,kBAAkB,IAAqB;AAC7C,WAAO,KAAK,WAAW,CAAC,KAAK,OAAO,IAAI,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAc,UAAU,IAAY,QAAuD;AACzF,QAAI;AACF,aAAO,MAAM;AAGX,YAAI,KAAK,kBAAkB,EAAE,EAAG;AAEhC,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAGV,YAAI,KAAK,kBAAkB,EAAE,EAAG;AAEhC,cAAM,KAAK,OAAO,MAAM,KAAK;AAAA,MAC/B;AAAA,IACF,SAAS,GAAG;AAEV,UAAI,2BAA2B,CAAC,GAAG;AACjC;AAAA,MACF;AAEA,WAAK,OAAO,MAAM,EAAE,OAAO,EAAE,GAAG,kDAAkD;AAAA,IACpF,UAAE;AACA,UAAI;AACF,eAAO,YAAY;AAAA,MACrB,QAAQ;AAAA,MAER;AAEA,WAAK,OAAO,OAAO,EAAE;AACrB,WAAK,aAAa,OAAO,EAAE;AAAA,IAC7B;AAAA,EACF;AACF;","names":[]}
|