diff --git a/agents/package.json b/agents/package.json index 13f8c6cd..5ffa8140 100644 --- a/agents/package.json +++ b/agents/package.json @@ -41,6 +41,7 @@ "@livekit/mutex": "^1.1.1", "@livekit/protocol": "^1.29.1", "@livekit/typed-emitter": "^3.0.0", + "@std/streams": "jsr:^1.0.9", "@std/async": "npm:@jsr/std__async@^1.0.13", "commander": "^12.0.0", "heap-js": "^2.6.0", diff --git a/agents/src/stream/deferred_stream.ts b/agents/src/stream/deferred_stream.ts index c88cbb14..713d4a02 100644 --- a/agents/src/stream/deferred_stream.ts +++ b/agents/src/stream/deferred_stream.ts @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2025 LiveKit, Inc. // // SPDX-License-Identifier: Apache-2.0 -import { type ReadableStream } from 'node:stream/web'; import { IdentityTransform } from './identity_transform.js'; /** diff --git a/agents/src/stream/injectable_stream.ts b/agents/src/stream/injectable_stream.ts new file mode 100644 index 00000000..60277f6f --- /dev/null +++ b/agents/src/stream/injectable_stream.ts @@ -0,0 +1,98 @@ +import { Mutex } from '@livekit/mutex'; +import { mergeReadableStreams } from '@std/streams'; +import type { ReadableStream } from 'node:stream/web'; +import { IdentityTransform } from './identity_transform.js'; + +export class InjectableStream { + private source: ReadableStream; + private identityStream: IdentityTransform; + private mergedStream: ReadableStream; + private injectMutex = new Mutex(); + private writer: WritableStreamDefaultWriter; + private closed = false; + + constructor(source: ReadableStream) { + this.source = source; + this.identityStream = new IdentityTransform(); + this.mergedStream = mergeReadableStreams(this.source, this.identityStream.readable); + this.writer = this.identityStream.writable.getWriter(); + } + + async inject(value: T) { + const unlock = await this.injectMutex.lock(); + + if (this.closed) { + throw new Error('Cannot inject into a closed stream'); + } + + try { + await this.writer.write(value); + } finally { + unlock(); + } + } + + async close() { + const unlock = await this.injectMutex.lock(); + + if (this.closed) { + return; + } + + try { + // this will not cancel the source stream but instead keep the readable open until the source finishes + this.writer.releaseLock(); + await this.identityStream.writable.close(); + this.closed = true; + } finally { + unlock(); + } + } + + async cancel(reason?: any) { + await this.close(); + await Promise.all([ + this.mergedStream.cancel(reason), + this.identityStream.writable.abort(reason), + ]); + } + + get readable() { + return this.mergedStream; + } +} + +// // Copied from @std/streams/merge-readable-streams.ts to avoid incompetible ReadableStream types +// export function mergeReadableStreams( +// ...streams: ReadableStream[] +// ): ReadableStream { +// const resolvePromises = streams.map(() => Promise.withResolvers()); +// return new ReadableStream({ +// start(controller) { +// let mustClose = false; +// Promise.all(resolvePromises.map(({ promise }) => promise)) +// .then(() => { +// controller.close(); +// }) +// .catch((error) => { +// mustClose = true; +// controller.error(error); +// }); +// for (const [index, stream] of streams.entries()) { +// (async () => { +// try { +// for await (const data of stream) { +// if (mustClose) { +// break; +// } +// controller.enqueue(data); +// } +// resolvePromises[index]!.resolve(); +// } catch (error) { +// resolvePromises[index]!.reject(error); +// } +// })(); +// } +// }, +// }); +// } diff --git a/agents/src/voice/agent_activity.ts b/agents/src/voice/agent_activity.ts index e2fa667f..aa730c41 100644 --- a/agents/src/voice/agent_activity.ts +++ b/agents/src/voice/agent_activity.ts @@ -12,8 +12,8 @@ import type { STT, SpeechEvent } from '../stt/stt.js'; import type { TTS } from '../tts/tts.js'; import { Future } from '../utils.js'; import type { VADEvent } from '../vad.js'; -import { StopResponse } from './agent.js'; import type { Agent } from './agent.js'; +import { StopResponse } from './agent.js'; import type { AgentSession } from './agent_session.js'; import { AudioRecognition, diff --git a/agents/src/voice/agent_session.ts b/agents/src/voice/agent_session.ts index b3be4410..eb9377f5 100644 --- a/agents/src/voice/agent_session.ts +++ b/agents/src/voice/agent_session.ts @@ -3,8 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 import type { AudioFrame, AudioSource, Room } from '@livekit/rtc-node'; import type { ReadableStream } from 'node:stream/web'; -import { ChatContext } from '../llm/chat_context.js'; import type { ChatMessage } from '../llm/chat_context.js'; +import { ChatContext } from '../llm/chat_context.js'; import type { LLM } from '../llm/index.js'; import { log } from '../log.js'; import type { AgentState } from '../pipeline/index.js'; diff --git a/agents/src/voice/generation.ts b/agents/src/voice/generation.ts index 01fe11e4..4e47673f 100644 --- a/agents/src/voice/generation.ts +++ b/agents/src/voice/generation.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 import type { AudioFrame, AudioSource } from '@livekit/rtc-node'; import { randomUUID } from 'node:crypto'; -import type { ReadableStream } from 'stream/web'; +import type { ReadableStream } from 'node:stream/web'; import type { ChatContext } from '../llm/chat_context.js'; import { IdentityTransform } from '../stream/identity_transform.js'; import { Future } from '../utils.js'; diff --git a/agents/tests/stream/injectable_stream.test.ts b/agents/tests/stream/injectable_stream.test.ts new file mode 100644 index 00000000..42a3c8fe --- /dev/null +++ b/agents/tests/stream/injectable_stream.test.ts @@ -0,0 +1,346 @@ +import { ReadableStream } from 'node:stream/web'; +import { describe, expect, it } from 'vitest'; +import { InjectableStream } from '../../src/stream/injectable_stream.js'; + +describe('InjectableStream', () => { + // Helper to create a readable stream from an array + function createReadableStream(items: T[]): ReadableStream { + return new ReadableStream({ + start(controller) { + for (const item of items) { + controller.enqueue(item); + } + controller.close(); + }, + }); + } + + // Helper to collect all values from a stream + async function collectStream(stream: InjectableStream): Promise { + const reader = stream.readable.getReader(); + const values: T[] = []; + + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + values.push(value); + } + } finally { + reader.releaseLock(); + } + + return values; + } + + // Helper to create a controlled source stream + function createControlledStream() { + let controller: ReadableStreamDefaultController; + const stream = new ReadableStream({ + start(c) { + controller = c; + }, + }); + + return { + stream, + enqueue: (value: T) => controller.enqueue(value), + close: () => controller.close(), + error: (e: any) => controller.error(e), + }; + } + + describe('Happy Path', () => { + it('should pass through source stream data without injection', async () => { + const sourceData = [1, 2, 3, 4, 5]; + const source = createReadableStream(sourceData); + const injectable = new InjectableStream(source); + injectable.close(); + + const result = await collectStream(injectable); + expect(result).toEqual(sourceData); + }); + + it('should handle empty source stream', async () => { + const source = createReadableStream([]); + const injectable = new InjectableStream(source); + injectable.close(); + + const result = await collectStream(injectable); + expect(result).toEqual([]); + }); + }); + + describe('Read/Write with Inject', () => { + it('should merge injected values with source stream', async () => { + const controlled = createControlledStream(); + const injectable = new InjectableStream(controlled.stream); + + // Start reading + const readPromise = collectStream(injectable); + + // Enqueue source values + controlled.enqueue('source1'); + controlled.enqueue('source2'); + + // Inject a value + await injectable.inject('injected1'); + + // More source values + controlled.enqueue('source3'); + + // Close source + controlled.close(); + injectable.close(); // close the injectable stream + + const result = await readPromise; + + // The order might vary due to merging, but all values should be present + expect(result).toHaveLength(4); + expect(result).toContain('source1'); + expect(result).toContain('source2'); + expect(result).toContain('source3'); + expect(result).toContain('injected1'); + }); + + it('should handle multiple injections (if supported)', async () => { + const controlled = createControlledStream(); + const injectable = new InjectableStream(controlled.stream); + + const readPromise = collectStream(injectable); + + // Multiple injections should now work + await injectable.inject(100); + await injectable.inject(200); + await injectable.inject(300); + + controlled.close(); + injectable.close(); + + const result = await readPromise; + expect(result).toEqual([100, 200, 300]); + }); + }); + + describe('After Close', () => { + it('should continue reading from source after close', async () => { + const controlled = createControlledStream(); + const injectable = new InjectableStream(controlled.stream); + + // Start reading + const reader = injectable.readable.getReader(); + const values: string[] = []; + + // Read first value + controlled.enqueue('before-close'); + let result = await reader.read(); + if (!result.done) values.push(result.value); + + // Close injectable + await injectable.close(); + + // Source should still work + controlled.enqueue('after-close-1'); + controlled.enqueue('after-close-2'); + controlled.close(); + + // Continue reading + while (true) { + result = await reader.read(); + if (result.done) break; + values.push(result.value); + } + + reader.releaseLock(); + + expect(values).toEqual(['before-close', 'after-close-1', 'after-close-2']); + }); + + it('should prevent injection after close', async () => { + const source = createReadableStream([1, 2, 3]); + const injectable = new InjectableStream(source); + + await injectable.close(); + + try { + await injectable.inject(999); + expect.fail('Expected inject to fail'); + } catch (e) { + expect(e).toBeInstanceOf(Error); + } + }); + }); + + describe('After Cancel', () => { + it('should cancel both streams when cancel is called', async () => { + const controlled = createControlledStream(); + const injectable = new InjectableStream(controlled.stream); + + const reader = injectable.readable.getReader(); + reader.releaseLock(); + + // Cancel the stream + await injectable.cancel('test cancellation'); + + const { done } = await reader.read(); + expect(done).toBe(true); + + reader.releaseLock(); + }); + + it('should prevent injection after cancel', async () => { + const source = createReadableStream([1, 2, 3]); + const injectable = new InjectableStream(source); + + await injectable.cancel(); + + // Injection should fail after cancel + await expect(injectable.inject(999)).rejects.toThrow(); + }); + + it('should propagate cancel reason', async () => { + const controlled = createControlledStream(); + const injectable = new InjectableStream(controlled.stream); + + const reason = new Error('Custom cancel reason'); + + // Start reading to see if error propagates + const reader = injectable.readable.getReader(); + const readPromise = reader.read(); + + await injectable.cancel(reason); + + // The read should complete with done=true (cancel doesn't necessarily propagate as error to reader) + const result = await readPromise; + expect(result.done).toBe(true); + + reader.releaseLock(); + }); + }); + +// describe('Complex Cases', () => { +// it('should handle concurrent injections safely', async () => { +// const controlled = createControlledStream(); +// const injectable = new InjectableStream(controlled.stream); + +// const readPromise = collectStream(injectable); + +// // Try concurrent injections (mutex should serialize them) +// const injectPromises = [ +// injectable.inject(1), +// injectable.inject(2), +// injectable.inject(3), +// ]; + +// // Wait for all injections to complete (some might fail) +// await Promise.allSettled(injectPromises); + +// await injectable.close(); +// await controlled.close(); + +// const values = await readPromise; + +// // At least the first injection should succeed +// expect(values.sort()).toEqual([1, 2, 3]); +// }); + +// it('should handle backpressure correctly', async () => { +// const controlled = createControlledStream(); +// const injectable = new InjectableStream(controlled.stream); + +// // Create a slow reader to induce backpressure +// const reader = injectable.readable.getReader(); +// const values: number[] = []; + +// // Enqueue many values quickly +// for (let i = 0; i < 10; i++) { +// controlled.enqueue(i); +// } + +// // Try to inject while there's backpressure +// const injectPromise = injectable.inject(999); + +// // Slowly read values +// for (let i = 0; i < 5; i++) { +// const { done, value } = await reader.read(); +// if (!done) values.push(value); +// await new Promise(resolve => setTimeout(resolve, 10)); +// } + +// await injectPromise; +// controlled.close(); + +// // Read remaining values +// while (true) { +// const { done, value } = await reader.read(); +// if (done) break; +// values.push(value); +// } + +// reader.releaseLock(); + +// // All values should be present +// expect(values.length).toBeGreaterThan(5); +// expect(values).toContain(999); +// }); + +// it('should handle source stream errors', async () => { +// const controlled = createControlledStream(); +// const injectable = new InjectableStream(controlled.stream); + +// const reader = injectable.readable.getReader(); + +// controlled.enqueue('value1'); + +// // Error the source stream +// const error = new Error('Source stream error'); +// controlled.error(error); + +// // First read should succeed +// const result1 = await reader.read(); +// expect(result1.done).toBe(false); +// expect(result1.value).toBe('value1'); + +// // Next read should propagate the error +// await expect(reader.read()).rejects.toThrow('Source stream error'); + +// reader.releaseLock(); +// }); + +// it('should handle injection during active read', async () => { +// const controlled = createControlledStream(); +// const injectable = new InjectableStream(controlled.stream); + +// const reader = injectable.readable.getReader(); + +// // Start a read that will wait +// const readPromise = reader.read(); + +// // Inject while read is pending +// await injectable.inject('injected'); + +// // The read should resolve with the injected value (or source value if it comes first) +// const { done, value } = await readPromise; +// expect(done).toBe(false); +// expect(value).toBe('injected'); + +// controlled.close(); +// reader.releaseLock(); +// }); +// }); + +// describe('Implementation Issues', () => { +// it('multiple injections now work correctly', async () => { +// const source = createReadableStream([]); +// const injectable = new InjectableStream(source); + +// // All injections should work now +// await expect(injectable.inject('first')).resolves.not.toThrow(); +// await expect(injectable.inject('second')).resolves.not.toThrow(); +// await expect(injectable.inject('third')).resolves.not.toThrow(); + +// const result = await collectStream(injectable); +// expect(result).toEqual(['first', 'second', 'third']); +// }); +// }); +}); diff --git a/agents/tsconfig.json b/agents/tsconfig.json index 48b3ae20..a3e6c2ca 100644 --- a/agents/tsconfig.json +++ b/agents/tsconfig.json @@ -2,6 +2,8 @@ "extends": "../tsconfig.json", "compilerOptions": { + "types": ["node"], + "lib": ["es2024"], "rootDir": "./src", "declarationDir": "dist", "outDir": "dist" diff --git a/package.json b/package.json index e1560fd8..77225d16 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "examples:minimal": "pnpm exec tsx examples/src/multimodal_agent.ts" }, "devDependencies": { + "@types/node": "^22.13.10", "@changesets/cli": "^2.27.1", "@livekit/changesets-changelog-github": "^0.0.4", "@rushstack/heft": "^0.66.0", @@ -44,5 +45,5 @@ "typescript": "^5.4.5", "vitest": "^3.2.2" }, - "packageManager": "pnpm@9.7.0" + "packageManager": "pnpm@10.11.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 895a42fb..61279266 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,10 +16,13 @@ importers: version: 0.0.4 '@rushstack/heft': specifier: ^0.66.0 - version: 0.66.9(@types/node@22.5.5) + version: 0.66.9(@types/node@22.15.29) '@trivago/prettier-plugin-sort-imports': specifier: ^4.3.0 version: 4.3.0(prettier@3.2.5) + '@types/node': + specifier: ^22.13.10 + version: 22.15.29 '@typescript-eslint/eslint-plugin': specifier: ^6.21.0 version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) @@ -37,7 +40,7 @@ importers: version: 8.10.0(eslint@8.57.0) eslint-config-standard: specifier: ^17.1.0 - version: 17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0) + version: 17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0) eslint-config-turbo: specifier: ^1.12.2 version: 1.13.3(eslint@8.57.0) @@ -89,6 +92,9 @@ importers: '@std/async': specifier: npm:@jsr/std__async@^1.0.13 version: '@jsr/std__async@1.0.13' + '@std/streams': + specifier: jsr:^1.0.9 + version: '@jsr/std__streams@1.0.9' commander: specifier: ^12.0.0 version: 12.0.0 @@ -190,13 +196,13 @@ importers: version: 0.13.13 '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) '@types/ws': specifier: ^8.5.10 version: 8.5.10 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -221,13 +227,13 @@ importers: version: 0.13.13 '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) '@types/ws': specifier: ^8.5.10 version: 8.5.10 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -252,13 +258,13 @@ importers: version: 0.13.13 '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) '@types/ws': specifier: ^8.5.10 version: 8.5.10 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -277,13 +283,13 @@ importers: version: link:../../agents '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) onnxruntime-common: specifier: ^1.19.2 version: 1.19.2 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -308,13 +314,13 @@ importers: version: 0.13.13 '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) '@types/ws': specifier: ^8.5.10 version: 8.5.10 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -345,13 +351,13 @@ importers: version: 0.13.13 '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) '@types/ws': specifier: ^8.5.10 version: 8.5.10 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -376,13 +382,13 @@ importers: version: 0.13.13 '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) '@types/ws': specifier: ^8.5.10 version: 8.5.10 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -404,7 +410,7 @@ importers: version: 0.13.13 '@microsoft/api-extractor': specifier: ^7.35.0 - version: 7.43.7(@types/node@22.5.5) + version: 7.43.7(@types/node@22.15.29) '@types/ws': specifier: ^8.5.10 version: 8.5.10 @@ -413,7 +419,7 @@ importers: version: 1.19.2 tsup: specifier: ^8.3.5 - version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) + version: 8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5) typescript: specifier: ^5.0.0 version: 5.4.5 @@ -1332,6 +1338,12 @@ packages: '@jsr/std__async@1.0.13': resolution: {integrity: sha512-GEApyNtzauJ0kEZ/GxebSkdEN0t29qJtkw+WEvzYTwkL6fHX8cq3YWzRjCqHu+4jMl+rpHiwyr/lfitNInntzA==, tarball: https://npm.jsr.io/~/11/@jsr/std__async/1.0.13.tgz} + '@jsr/std__bytes@1.0.6': + resolution: {integrity: sha512-St6yKggjFGhxS52IFLJWvkchRFbAKg2Xh8UxA4S1EGz7GJ2Ui+ssDDldj/w2c8vCxvl6qgR0HaYbKeFJNqujmA==, tarball: https://npm.jsr.io/~/11/@jsr/std__bytes/1.0.6.tgz} + + '@jsr/std__streams@1.0.9': + resolution: {integrity: sha512-nPkEijnOPwLQt6ZtvOajE6F2hCmRILaq0kR6I0JFVvxSsvhdeyFMGc8F4DqypCpfq/U+8umLcE0RNMcYdx4NlQ==, tarball: https://npm.jsr.io/~/11/@jsr/std__streams/1.0.9.tgz} + '@livekit/changesets-changelog-github@0.0.4': resolution: {integrity: sha512-MXaiLYwgkYciZb8G2wkVtZ1pJJzZmVx5cM30Q+ClslrIYyAqQhRbPmZDM79/5CGxb1MTemR/tfOM25tgJgAK0g==} @@ -1810,6 +1822,9 @@ packages: '@types/node@18.19.64': resolution: {integrity: sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==} + '@types/node@22.15.29': + resolution: {integrity: sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==} + '@types/node@22.5.5': resolution: {integrity: sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==} @@ -4384,6 +4399,9 @@ packages: undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -5334,6 +5352,12 @@ snapshots: '@jsr/std__async@1.0.13': {} + '@jsr/std__bytes@1.0.6': {} + + '@jsr/std__streams@1.0.9': + dependencies: + '@jsr/std__bytes': 1.0.6 + '@livekit/changesets-changelog-github@0.0.4': dependencies: '@changesets/get-github-info': 0.5.2 @@ -5395,6 +5419,14 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 + '@microsoft/api-extractor-model@7.28.17(@types/node@22.15.29)': + dependencies: + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.3.0(@types/node@22.15.29) + transitivePeerDependencies: + - '@types/node' + '@microsoft/api-extractor-model@7.28.17(@types/node@22.5.5)': dependencies: '@microsoft/tsdoc': 0.14.2 @@ -5403,6 +5435,24 @@ snapshots: transitivePeerDependencies: - '@types/node' + '@microsoft/api-extractor@7.43.7(@types/node@22.15.29)': + dependencies: + '@microsoft/api-extractor-model': 7.28.17(@types/node@22.15.29) + '@microsoft/tsdoc': 0.14.2 + '@microsoft/tsdoc-config': 0.16.2 + '@rushstack/node-core-library': 4.3.0(@types/node@22.15.29) + '@rushstack/rig-package': 0.5.2 + '@rushstack/terminal': 0.11.0(@types/node@22.15.29) + '@rushstack/ts-command-line': 4.21.0(@types/node@22.15.29) + lodash: 4.17.21 + minimatch: 3.0.8 + resolve: 1.22.8 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.4.2 + transitivePeerDependencies: + - '@types/node' + '@microsoft/api-extractor@7.43.7(@types/node@22.5.5)': dependencies: '@microsoft/api-extractor-model': 7.28.17(@types/node@22.5.5) @@ -5638,23 +5688,23 @@ snapshots: '@rushstack/eslint-patch@1.10.3': {} - '@rushstack/heft-config-file@0.14.19(@types/node@22.5.5)': + '@rushstack/heft-config-file@0.14.19(@types/node@22.15.29)': dependencies: - '@rushstack/node-core-library': 4.3.0(@types/node@22.5.5) + '@rushstack/node-core-library': 4.3.0(@types/node@22.15.29) '@rushstack/rig-package': 0.5.2 - '@rushstack/terminal': 0.11.0(@types/node@22.5.5) + '@rushstack/terminal': 0.11.0(@types/node@22.15.29) jsonpath-plus: 4.0.0 transitivePeerDependencies: - '@types/node' - '@rushstack/heft@0.66.9(@types/node@22.5.5)': + '@rushstack/heft@0.66.9(@types/node@22.15.29)': dependencies: - '@rushstack/heft-config-file': 0.14.19(@types/node@22.5.5) - '@rushstack/node-core-library': 4.3.0(@types/node@22.5.5) - '@rushstack/operation-graph': 0.2.19(@types/node@22.5.5) + '@rushstack/heft-config-file': 0.14.19(@types/node@22.15.29) + '@rushstack/node-core-library': 4.3.0(@types/node@22.15.29) + '@rushstack/operation-graph': 0.2.19(@types/node@22.15.29) '@rushstack/rig-package': 0.5.2 - '@rushstack/terminal': 0.11.0(@types/node@22.5.5) - '@rushstack/ts-command-line': 4.21.0(@types/node@22.5.5) + '@rushstack/terminal': 0.11.0(@types/node@22.15.29) + '@rushstack/ts-command-line': 4.21.0(@types/node@22.15.29) '@types/tapable': 1.0.6 fast-glob: 3.3.2 git-repo-info: 2.1.1 @@ -5665,6 +5715,17 @@ snapshots: transitivePeerDependencies: - '@types/node' + '@rushstack/node-core-library@4.3.0(@types/node@22.15.29)': + dependencies: + fs-extra: 7.0.1 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.8 + semver: 7.5.4 + z-schema: 5.0.5 + optionalDependencies: + '@types/node': 22.15.29 + '@rushstack/node-core-library@4.3.0(@types/node@22.5.5)': dependencies: fs-extra: 7.0.1 @@ -5676,18 +5737,25 @@ snapshots: optionalDependencies: '@types/node': 22.5.5 - '@rushstack/operation-graph@0.2.19(@types/node@22.5.5)': + '@rushstack/operation-graph@0.2.19(@types/node@22.15.29)': dependencies: - '@rushstack/node-core-library': 4.3.0(@types/node@22.5.5) - '@rushstack/terminal': 0.11.0(@types/node@22.5.5) + '@rushstack/node-core-library': 4.3.0(@types/node@22.15.29) + '@rushstack/terminal': 0.11.0(@types/node@22.15.29) optionalDependencies: - '@types/node': 22.5.5 + '@types/node': 22.15.29 '@rushstack/rig-package@0.5.2': dependencies: resolve: 1.22.8 strip-json-comments: 3.1.1 + '@rushstack/terminal@0.11.0(@types/node@22.15.29)': + dependencies: + '@rushstack/node-core-library': 4.3.0(@types/node@22.15.29) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 22.15.29 + '@rushstack/terminal@0.11.0(@types/node@22.5.5)': dependencies: '@rushstack/node-core-library': 4.3.0(@types/node@22.5.5) @@ -5695,6 +5763,15 @@ snapshots: optionalDependencies: '@types/node': 22.5.5 + '@rushstack/ts-command-line@4.21.0(@types/node@22.15.29)': + dependencies: + '@rushstack/terminal': 0.11.0(@types/node@22.15.29) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + '@rushstack/ts-command-line@4.21.0(@types/node@22.5.5)': dependencies: '@rushstack/terminal': 0.11.0(@types/node@22.5.5) @@ -5740,7 +5817,7 @@ snapshots: '@types/node-fetch@2.6.11': dependencies: - '@types/node': 22.5.5 + '@types/node': 22.15.29 form-data: 4.0.1 '@types/node@12.20.55': {} @@ -5749,6 +5826,10 @@ snapshots: dependencies: undici-types: 5.26.5 + '@types/node@22.15.29': + dependencies: + undici-types: 6.21.0 + '@types/node@22.5.5': dependencies: undici-types: 6.19.8 @@ -5761,7 +5842,7 @@ snapshots: '@types/ws@8.5.10': dependencies: - '@types/node': 22.5.5 + '@types/node': 22.15.29 '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: @@ -6638,7 +6719,7 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0): + eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1)(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.1.1(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) @@ -6663,7 +6744,7 @@ snapshots: debug: 4.3.4 enhanced-resolve: 5.16.1 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 @@ -6675,7 +6756,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -6703,7 +6784,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -7911,7 +7992,7 @@ snapshots: '@protobufjs/path': 1.1.2 '@protobufjs/pool': 1.1.0 '@protobufjs/utf8': 1.1.0 - '@types/node': 22.5.5 + '@types/node': 22.15.29 long: 5.2.3 pseudomap@1.0.2: {} @@ -8487,6 +8568,34 @@ snapshots: tslib@2.6.2: {} + tsup@8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.15.29))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5): + dependencies: + bundle-require: 5.0.0(esbuild@0.24.0) + cac: 6.7.14 + chokidar: 4.0.1 + consola: 3.2.3 + debug: 4.3.7 + esbuild: 0.24.0 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.4.38)(tsx@4.19.2) + resolve-from: 5.0.0 + rollup: 4.27.3 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tinyexec: 0.3.1 + tinyglobby: 0.2.10 + tree-kill: 1.2.2 + optionalDependencies: + '@microsoft/api-extractor': 7.43.7(@types/node@22.15.29) + postcss: 8.4.38 + typescript: 5.4.5 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + tsup@8.3.5(@microsoft/api-extractor@7.43.7(@types/node@22.5.5))(postcss@8.4.38)(tsx@4.19.2)(typescript@5.4.5): dependencies: bundle-require: 5.0.0(esbuild@0.24.0) @@ -8660,6 +8769,8 @@ snapshots: undici-types@6.19.8: {} + undici-types@6.21.0: {} + universalify@0.1.2: {} uri-js@4.4.1: @@ -8673,6 +8784,23 @@ snapshots: validator@13.12.0: {} + vite-node@1.6.0(@types/node@22.15.29): + dependencies: + cac: 6.7.14 + debug: 4.3.4 + pathe: 1.1.2 + picocolors: 1.0.1 + vite: 5.2.11(@types/node@22.15.29) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + vite-node@1.6.0(@types/node@22.5.5): dependencies: cac: 6.7.14 @@ -8716,6 +8844,39 @@ snapshots: '@types/node': 22.5.5 fsevents: 2.3.3 + vitest@1.6.0(@types/node@22.15.29): + dependencies: + '@vitest/expect': 1.6.0 + '@vitest/runner': 1.6.0 + '@vitest/snapshot': 1.6.0 + '@vitest/spy': 1.6.0 + '@vitest/utils': 1.6.0 + acorn-walk: 8.3.2 + chai: 4.4.1 + debug: 4.3.4 + execa: 8.0.1 + local-pkg: 0.5.0 + magic-string: 0.30.10 + pathe: 1.1.2 + picocolors: 1.0.1 + std-env: 3.7.0 + strip-literal: 2.1.0 + tinybench: 2.8.0 + tinypool: 0.8.4 + vite: 5.2.11(@types/node@22.15.29) + vite-node: 1.6.0(@types/node@22.15.29) + why-is-node-running: 2.2.2 + optionalDependencies: + '@types/node': 22.15.29 + transitivePeerDependencies: + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + vitest@1.6.0(@types/node@22.5.5): dependencies: '@vitest/expect': 1.6.0