livekit-client 2.17.0 → 2.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/dist/livekit-client.e2ee.worker.js +1 -1
  2. package/dist/livekit-client.e2ee.worker.js.map +1 -1
  3. package/dist/livekit-client.e2ee.worker.mjs +7 -2
  4. package/dist/livekit-client.e2ee.worker.mjs.map +1 -1
  5. package/dist/livekit-client.esm.mjs +2350 -1430
  6. package/dist/livekit-client.esm.mjs.map +1 -1
  7. package/dist/livekit-client.umd.js +1 -1
  8. package/dist/livekit-client.umd.js.map +1 -1
  9. package/dist/src/e2ee/KeyProvider.d.ts +4 -2
  10. package/dist/src/e2ee/KeyProvider.d.ts.map +1 -1
  11. package/dist/src/index.d.ts +9 -6
  12. package/dist/src/index.d.ts.map +1 -1
  13. package/dist/src/logger.d.ts +2 -1
  14. package/dist/src/logger.d.ts.map +1 -1
  15. package/dist/src/room/PCTransport.d.ts.map +1 -1
  16. package/dist/src/room/PCTransportManager.d.ts.map +1 -1
  17. package/dist/src/room/RTCEngine.d.ts.map +1 -1
  18. package/dist/src/room/data-stream/incoming/IncomingDataStreamManager.d.ts.map +1 -1
  19. package/dist/src/room/data-stream/outgoing/OutgoingDataStreamManager.d.ts.map +1 -1
  20. package/dist/src/room/data-track/depacketizer.d.ts +51 -0
  21. package/dist/src/room/data-track/depacketizer.d.ts.map +1 -0
  22. package/dist/src/room/data-track/frame.d.ts +7 -0
  23. package/dist/src/room/data-track/frame.d.ts.map +1 -0
  24. package/dist/src/room/data-track/handle.d.ts +27 -0
  25. package/dist/src/room/data-track/handle.d.ts.map +1 -0
  26. package/dist/src/room/data-track/packet/constants.d.ts +20 -0
  27. package/dist/src/room/data-track/packet/constants.d.ts.map +1 -0
  28. package/dist/src/room/data-track/packet/errors.d.ts +42 -0
  29. package/dist/src/room/data-track/packet/errors.d.ts.map +1 -0
  30. package/dist/src/room/data-track/packet/extensions.d.ts +68 -0
  31. package/dist/src/room/data-track/packet/extensions.d.ts.map +1 -0
  32. package/dist/src/room/data-track/packet/index.d.ts +91 -0
  33. package/dist/src/room/data-track/packet/index.d.ts.map +1 -0
  34. package/dist/src/room/data-track/packet/serializable.d.ts +12 -0
  35. package/dist/src/room/data-track/packet/serializable.d.ts.map +1 -0
  36. package/dist/src/room/data-track/packetizer.d.ts +43 -0
  37. package/dist/src/room/data-track/packetizer.d.ts.map +1 -0
  38. package/dist/src/room/data-track/utils.d.ts +60 -0
  39. package/dist/src/room/data-track/utils.d.ts.map +1 -0
  40. package/dist/src/room/errors.d.ts +16 -4
  41. package/dist/src/room/errors.d.ts.map +1 -1
  42. package/dist/src/room/track/LocalAudioTrack.d.ts.map +1 -1
  43. package/dist/src/room/track/LocalTrack.d.ts +1 -0
  44. package/dist/src/room/track/LocalTrack.d.ts.map +1 -1
  45. package/dist/src/room/types.d.ts +1 -0
  46. package/dist/src/room/types.d.ts.map +1 -1
  47. package/dist/src/utils/TypedPromise.d.ts +4 -0
  48. package/dist/src/utils/TypedPromise.d.ts.map +1 -1
  49. package/dist/src/utils/throws.d.ts +36 -0
  50. package/dist/src/utils/throws.d.ts.map +1 -0
  51. package/dist/ts4.2/e2ee/KeyProvider.d.ts +4 -2
  52. package/dist/ts4.2/index.d.ts +10 -3
  53. package/dist/ts4.2/logger.d.ts +2 -1
  54. package/dist/ts4.2/room/data-track/depacketizer.d.ts +51 -0
  55. package/dist/ts4.2/room/data-track/frame.d.ts +7 -0
  56. package/dist/ts4.2/room/data-track/handle.d.ts +27 -0
  57. package/dist/ts4.2/room/data-track/packet/constants.d.ts +20 -0
  58. package/dist/ts4.2/room/data-track/packet/errors.d.ts +42 -0
  59. package/dist/ts4.2/room/data-track/packet/extensions.d.ts +68 -0
  60. package/dist/ts4.2/room/data-track/packet/index.d.ts +98 -0
  61. package/dist/ts4.2/room/data-track/packet/serializable.d.ts +12 -0
  62. package/dist/ts4.2/room/data-track/packetizer.d.ts +43 -0
  63. package/dist/ts4.2/room/data-track/utils.d.ts +60 -0
  64. package/dist/ts4.2/room/errors.d.ts +16 -4
  65. package/dist/ts4.2/room/track/LocalTrack.d.ts +1 -0
  66. package/dist/ts4.2/room/types.d.ts +1 -0
  67. package/dist/ts4.2/utils/TypedPromise.d.ts +4 -0
  68. package/dist/ts4.2/utils/throws.d.ts +39 -0
  69. package/package.json +12 -10
  70. package/src/e2ee/KeyProvider.ts +4 -2
  71. package/src/index.ts +21 -5
  72. package/src/logger.ts +1 -0
  73. package/src/room/PCTransport.ts +1 -0
  74. package/src/room/PCTransportManager.ts +27 -9
  75. package/src/room/RTCEngine.ts +13 -2
  76. package/src/room/Room.ts +1 -1
  77. package/src/room/data-stream/incoming/IncomingDataStreamManager.ts +1 -0
  78. package/src/room/data-stream/outgoing/OutgoingDataStreamManager.ts +2 -1
  79. package/src/room/data-track/depacketizer.test.ts +442 -0
  80. package/src/room/data-track/depacketizer.ts +298 -0
  81. package/src/room/data-track/frame.ts +8 -0
  82. package/src/room/data-track/handle.test.ts +13 -0
  83. package/src/room/data-track/handle.ts +80 -0
  84. package/src/room/data-track/packet/constants.ts +27 -0
  85. package/src/room/data-track/packet/errors.ts +121 -0
  86. package/src/room/data-track/packet/extensions.ts +259 -0
  87. package/src/room/data-track/packet/index.test.ts +615 -0
  88. package/src/room/data-track/packet/index.ts +363 -0
  89. package/src/room/data-track/packet/serializable.ts +29 -0
  90. package/src/room/data-track/packetizer.test.ts +131 -0
  91. package/src/room/data-track/packetizer.ts +128 -0
  92. package/src/room/data-track/utils.test.ts +54 -0
  93. package/src/room/data-track/utils.ts +206 -0
  94. package/src/room/errors.ts +23 -5
  95. package/src/room/track/LocalAudioTrack.ts +4 -7
  96. package/src/room/track/LocalTrack.ts +4 -0
  97. package/src/room/types.ts +3 -1
  98. package/src/utils/TypedPromise.ts +7 -0
  99. package/src/utils/throws.ts +42 -0
@@ -0,0 +1,98 @@
1
+ import type { Throws } from '../../../utils/throws';
2
+ import { DataTrackHandle } from '../handle';
3
+ import { DataTrackTimestamp, U16_MAX_SIZE, WrapAroundUnsignedInt } from '../utils';
4
+ import type { DataTrackDeserializeErrorAll, DataTrackSerializeErrorAll } from './errors';
5
+ import { DataTrackSerializeError, DataTrackSerializeErrorReason } from './errors';
6
+ import { DataTrackExtensions } from './extensions';
7
+ import Serializable from './serializable';
8
+ /** A class for serializing / deserializing data track packet header sections. */
9
+ export declare class DataTrackPacketHeader extends Serializable {
10
+ marker: FrameMarker;
11
+ trackHandle: DataTrackHandle;
12
+ sequence: WrapAroundUnsignedInt<typeof U16_MAX_SIZE>;
13
+ frameNumber: WrapAroundUnsignedInt<typeof U16_MAX_SIZE>;
14
+ timestamp: DataTrackTimestamp<90000>;
15
+ extensions: DataTrackExtensions;
16
+ constructor(opts: {
17
+ marker: FrameMarker;
18
+ trackHandle: DataTrackHandle;
19
+ sequence: WrapAroundUnsignedInt<typeof U16_MAX_SIZE>;
20
+ frameNumber: WrapAroundUnsignedInt<typeof U16_MAX_SIZE>;
21
+ timestamp: DataTrackTimestamp<90000>;
22
+ extensions?: DataTrackExtensions;
23
+ });
24
+ private extensionsMetrics;
25
+ toBinaryLengthBytes(): number;
26
+ toBinaryInto(dataView: DataView): Throws<number, DataTrackSerializeError<DataTrackSerializeErrorReason.TooSmallForHeader>>;
27
+ static fromBinary<Input extends DataView | ArrayBuffer | Uint8Array>(input: Input): Throws<[
28
+ header: DataTrackPacketHeader,
29
+ byteLength: number
30
+ ], DataTrackDeserializeErrorAll>;
31
+ toJSON(): {
32
+ marker: FrameMarker;
33
+ trackHandle: number;
34
+ sequence: number;
35
+ frameNumber: number;
36
+ timestamp: number;
37
+ extensions: {
38
+ userTimestamp: {
39
+ tag: number;
40
+ lengthBytes: number;
41
+ timestamp: bigint;
42
+ } | null;
43
+ e2ee: {
44
+ tag: number;
45
+ lengthBytes: number;
46
+ keyIndex: number;
47
+ iv: Uint8Array<ArrayBufferLike>;
48
+ } | null;
49
+ };
50
+ };
51
+ }
52
+ /** Marker indicating a packet's position in relation to a frame. */
53
+ export declare enum FrameMarker {
54
+ /** Packet is the first in a frame. */
55
+ Start = 0,
56
+ /** Packet is within a frame. */
57
+ Inter = 1,
58
+ /** Packet is the last in a frame. */
59
+ Final = 2,
60
+ /** Packet is the only one in a frame. */
61
+ Single = 3
62
+ }
63
+ /** A class for serializing / deserializing data track packets. */
64
+ export declare class DataTrackPacket extends Serializable {
65
+ header: DataTrackPacketHeader;
66
+ payload: Uint8Array;
67
+ constructor(header: DataTrackPacketHeader, payload: Uint8Array);
68
+ toBinaryLengthBytes(): number;
69
+ toBinaryInto(dataView: DataView): Throws<number, DataTrackSerializeErrorAll>;
70
+ static fromBinary<Input extends DataView | ArrayBuffer | Uint8Array>(input: Input): Throws<[
71
+ packet: DataTrackPacket,
72
+ byteLength: number
73
+ ], DataTrackDeserializeErrorAll>;
74
+ toJSON(): {
75
+ header: {
76
+ marker: FrameMarker;
77
+ trackHandle: number;
78
+ sequence: number;
79
+ frameNumber: number;
80
+ timestamp: number;
81
+ extensions: {
82
+ userTimestamp: {
83
+ tag: number;
84
+ lengthBytes: number;
85
+ timestamp: bigint;
86
+ } | null;
87
+ e2ee: {
88
+ tag: number;
89
+ lengthBytes: number;
90
+ keyIndex: number;
91
+ iv: Uint8Array<ArrayBufferLike>;
92
+ } | null;
93
+ };
94
+ };
95
+ payload: Uint8Array<ArrayBufferLike>;
96
+ };
97
+ }
98
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,12 @@
1
+ import type { Throws } from '../../../utils/throws';
2
+ import type { DataTrackSerializeErrorAll } from './errors';
3
+ /** An abstract class implementing common behavior related to data track binary serialization. */
4
+ export default abstract class Serializable {
5
+ /** Returns the expected length of the serialized output in bytes */
6
+ abstract toBinaryLengthBytes(): number;
7
+ /** Given a DataView, serialize the instance inside and return the number of bytes written. */
8
+ abstract toBinaryInto(dataView: DataView): Throws<number, DataTrackSerializeErrorAll>;
9
+ /** Encodes the instance as binary and returns the data as a Uint8Array. */
10
+ toBinary(): Throws<Uint8Array, DataTrackSerializeErrorAll>;
11
+ }
12
+ //# sourceMappingURL=serializable.d.ts.map
@@ -0,0 +1,43 @@
1
+ import type { Throws } from '../../utils/throws';
2
+ import { LivekitReasonedError } from '../errors';
3
+ import type { DataTrackFrame } from './frame';
4
+ import { DataTrackHandle } from './handle';
5
+ import { DataTrackPacket, FrameMarker } from './packet';
6
+ import { DataTrackTimestamp } from './utils';
7
+ type PacketizeOptions = {
8
+ /** "now" timestamp to use as a base when generating new packet timestamps. If not specified,
9
+ * defaults to the return value of {@link DataTrackClock#now}. */
10
+ now?: DataTrackTimestamp<90000>;
11
+ };
12
+ export declare class DataTrackPacketizerError<Reason extends DataTrackPacketizerReason> extends LivekitReasonedError<Reason> {
13
+ readonly name = "DataTrackPacketizerError";
14
+ reason: Reason;
15
+ reasonName: string;
16
+ constructor(message: string, reason: Reason, options?: {
17
+ cause?: unknown;
18
+ });
19
+ static mtuTooShort(): DataTrackPacketizerError<DataTrackPacketizerReason>;
20
+ }
21
+ export declare enum DataTrackPacketizerReason {
22
+ MtuTooShort = 0
23
+ }
24
+ /** A packetizer takes a {@link DataTrackFrame} as input and generates a series
25
+ * of {@link DataTrackPacket}s for transmission to other clients over webrtc. */
26
+ export declare class DataTrackPacketizer {
27
+ private handle;
28
+ private mtuSizeBytes;
29
+ private sequence;
30
+ private frameNumber;
31
+ private clock;
32
+ constructor(trackHandle: DataTrackHandle, mtuSizeBytes: number);
33
+ /** @internal */
34
+ static computeFrameMarker(index: number, packetCount: number): FrameMarker;
35
+ /** Generates a series of packets for the specified {@link DataTrackPacketizerFrame}.
36
+ *
37
+ * NOTE: The return value of this function is a generator, so it can be lazily ran if desired,
38
+ * or converted to an array with {@link Array.from}.
39
+ */
40
+ packetize(frame: DataTrackFrame, options?: PacketizeOptions): Throws<Generator<DataTrackPacket>, DataTrackPacketizerError<DataTrackPacketizerReason.MtuTooShort>>;
41
+ }
42
+ export {};
43
+ //# sourceMappingURL=packetizer.d.ts.map
@@ -0,0 +1,60 @@
1
+ export declare const U16_MAX_SIZE = 65535;
2
+ export declare const U32_MAX_SIZE = 4294967295;
3
+ /**
4
+ * A number of fields withing the data tracks packet specification assume wrap around behavior when
5
+ * an unsigned type is incremented beyond its max size (ie, the packet `sequence` field). This
6
+ * wrapper type manually reimplements this wrap around behavior given javascript's lack of fixed
7
+ * size integer types.
8
+ */
9
+ export declare class WrapAroundUnsignedInt<MaxSize extends number> {
10
+ value: number;
11
+ private maxSize;
12
+ static u16(raw: number): WrapAroundUnsignedInt<65535>;
13
+ static u32(raw: number): WrapAroundUnsignedInt<4294967295>;
14
+ constructor(raw: number, maxSize: MaxSize);
15
+ /** Manually clamp the given containing value according to the wrap around max size bounds. Use
16
+ * this after out of bounds modification to the contained value by external code. */
17
+ clamp(): void;
18
+ clone(): WrapAroundUnsignedInt<MaxSize>;
19
+ /** When called, maps the containing value to a new containing value. After mapping, the wrap
20
+ * around external max size bounds are applied. Note that this is a mutative operation. */
21
+ update(updateFn: (value: number) => number): void;
22
+ /** Increments the given `n` to the inner value. Note that this is a mutative operation. */
23
+ increment(n?: number): void;
24
+ /** Decrements the given `n` from the inner value. Note that this is a mutative operation. */
25
+ decrement(n?: number): void;
26
+ getThenIncrement(): WrapAroundUnsignedInt<MaxSize>;
27
+ /** Returns true if {@link this} is before the passed other {@link WrapAroundUnsignedInt}. */
28
+ isBefore(other: WrapAroundUnsignedInt<MaxSize>): boolean;
29
+ }
30
+ export declare class DataTrackTimestamp<RateInHz extends number> {
31
+ rateInHz: RateInHz;
32
+ timestamp: WrapAroundUnsignedInt<typeof U32_MAX_SIZE>;
33
+ static fromRtpTicks(rtpTicks: number): DataTrackTimestamp<90000>;
34
+ /** Generates a timestamp initialized to a non cryptographically secure random value, so that
35
+ * different streams are more difficult to correlate in packet capture. */
36
+ static rtpRandom(): DataTrackTimestamp<90000>;
37
+ private constructor();
38
+ asTicks(): number;
39
+ clone(): DataTrackTimestamp<RateInHz>;
40
+ wrappingAdd(n: number): void;
41
+ /** Returns true if {@link this} is before the passed other {@link DataTrackTimestamp}. */
42
+ isBefore(other: DataTrackTimestamp<RateInHz>): boolean;
43
+ }
44
+ export declare class DataTrackClock<RateInHz extends number> {
45
+ epoch: Date;
46
+ base: DataTrackTimestamp<RateInHz>;
47
+ previous: DataTrackTimestamp<RateInHz>;
48
+ rateInHz: RateInHz;
49
+ private constructor();
50
+ static startingNow<RateInHz extends number>(base: DataTrackTimestamp<RateInHz>, rateInHz: RateInHz): DataTrackClock<RateInHz>;
51
+ static startingAtTime<RateInHz extends number>(epoch: Date, base: DataTrackTimestamp<RateInHz>, rateInHz: RateInHz): DataTrackClock<RateInHz>;
52
+ static rtpStartingNow(base: DataTrackTimestamp<90000>): DataTrackClock<90000>;
53
+ static rtpStartingAtTime(epoch: Date, base: DataTrackTimestamp<90000>): DataTrackClock<90000>;
54
+ now(): DataTrackTimestamp<RateInHz>;
55
+ at(timestamp: Date): DataTrackTimestamp<RateInHz>;
56
+ /** Convert a duration since the epoch into clock ticks. */
57
+ static durationInMsToTicks(durationMilliseconds: number, rateInHz: number): number;
58
+ }
59
+ export declare function coerceToDataView<Input extends DataView | ArrayBuffer | Uint8Array>(input: Input): DataView;
60
+ //# sourceMappingURL=utils.d.ts.map
@@ -1,7 +1,19 @@
1
1
  import { DisconnectReason, RequestResponse_Reason } from '@livekit/protocol';
2
+ /** Base error that all LiveKit specific custom errors inherit from. */
2
3
  export declare class LivekitError extends Error {
3
4
  code: number;
4
- constructor(code: number, message?: string);
5
+ cause?: unknown;
6
+ constructor(code: number, message?: string, options?: {
7
+ cause?: unknown;
8
+ });
9
+ }
10
+ /**
11
+ * LiveKit specific error type representing an error with an associated set of reasons.
12
+ * Use this to represent an error with multiple different but contextually related variants.
13
+ * */
14
+ export declare abstract class LivekitReasonedError<Reason> extends LivekitError {
15
+ abstract reason: Reason;
16
+ abstract reasonName: string;
5
17
  }
6
18
  export declare class SimulatedError extends LivekitError {
7
19
  readonly name = "simulated";
@@ -61,7 +73,7 @@ type ServiceNotFound = {
61
73
  context: string;
62
74
  };
63
75
  type ConnectionErrorVariants = NotAllowed | ConnectionTimeout | LeaveRequest | InternalError | Cancelled | ServerUnreachable | WebSocket | ServiceNotFound;
64
- export declare class ConnectionError<Variant extends ConnectionErrorVariants = ConnectionErrorVariants> extends LivekitError {
76
+ export declare class ConnectionError<Variant extends ConnectionErrorVariants = ConnectionErrorVariants> extends LivekitReasonedError<Variant['reason']> {
65
77
  status?: Variant['status'];
66
78
  context: Variant['context'];
67
79
  reason: Variant['reason'];
@@ -110,7 +122,7 @@ export declare class PublishTrackError extends LivekitError {
110
122
  constructor(message: string, status: number);
111
123
  }
112
124
  export type RequestErrorReason = Exclude<RequestResponse_Reason, RequestResponse_Reason.OK> | 'TimeoutError';
113
- export declare class SignalRequestError extends LivekitError {
125
+ export declare class SignalRequestError extends LivekitReasonedError<RequestErrorReason> {
114
126
  readonly name = "SignalRequestError";
115
127
  reason: RequestErrorReason;
116
128
  reasonName: string;
@@ -125,7 +137,7 @@ export declare enum DataStreamErrorReason {
125
137
  HandlerAlreadyRegistered = 7,
126
138
  EncryptionTypeMismatch = 8
127
139
  }
128
- export declare class DataStreamError extends LivekitError {
140
+ export declare class DataStreamError extends LivekitReasonedError<DataStreamErrorReason> {
129
141
  readonly name = "DataStreamError";
130
142
  reason: DataStreamErrorReason;
131
143
  reasonName: string;
@@ -27,6 +27,7 @@ export default abstract class LocalTrack<TrackKind extends Track.Kind = Track.Ki
27
27
  protected manuallyStopped: boolean;
28
28
  protected localTrackRecorder: LocalTrackRecorder<typeof this> | undefined;
29
29
  protected trackChangeLock: Mutex;
30
+ protected pendingDeviceChange: boolean;
30
31
  /**
31
32
  *
32
33
  * @param mediaTrack
@@ -107,5 +107,6 @@ export interface ByteStreamInfo extends BaseStreamInfo {
107
107
  name: string;
108
108
  }
109
109
  export interface TextStreamInfo extends BaseStreamInfo {
110
+ attachedStreamIds?: Array<string>;
110
111
  }
111
112
  //# sourceMappingURL=types.d.ts.map
@@ -2,6 +2,10 @@ type InferErrors<T> = T extends TypedPromise<any, infer E> ? E : never;
2
2
  export default class TypedPromise<T, E extends Error> extends Promise<T> {
3
3
  constructor(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason: E) => void) => void);
4
4
  catch<TResult = never>(onrejected?: ((reason: E) => TResult | PromiseLike<TResult>) | null | undefined): TypedPromise<T | TResult, E>;
5
+ static resolve: {
6
+ (): TypedPromise<void, never>;
7
+ <V>(value: V): TypedPromise<Awaited<V>, never>;
8
+ };
5
9
  static reject<E extends Error>(reason: E): TypedPromise<never, E>;
6
10
  static all<T extends readonly unknown[] | [
7
11
  ]>(values: T): TypedPromise<{
@@ -0,0 +1,39 @@
1
+ type Primitives = null | undefined | string | number | bigint | boolean | symbol;
2
+ /**
3
+ * Branded type that encodes possible thrown errors in the return type.
4
+ *
5
+ * Usage:
6
+ * function fetchUser(id: string): Throws<User, NetworkError | NotFoundError> { ... }
7
+ *
8
+ * The actual runtime value is just T - the error types are phantom types
9
+ * that exist only for static analysis.
10
+ *
11
+ * To indicate that a function shouldn't throw any errors, make it return `Throws<T, never>`.
12
+ *
13
+ * For more info about how this is checked, see ./throws-transformer at the root of this repo.
14
+ */
15
+ export type Throws<T, E extends Error> = (T & {
16
+ readonly __throws?: E;
17
+ }) | Extract<T, Primitives>;
18
+ /**
19
+ * Extract the error types from a Throws type.
20
+ */
21
+ export type ExtractErrors<T> = T extends Throws<any, infer E> ? E : never;
22
+ /**
23
+ * Extract the success type from a Throws type.
24
+ */
25
+ export type ExtractSuccess<T> = T extends Throws<infer S, any> ? S : T;
26
+ /**
27
+ * Combine error types from multiple Throws types.
28
+ */
29
+ export type CombineErrors<T extends any[]> = T extends [
30
+ infer First,
31
+ ...infer Rest
32
+ ] ? ExtractErrors<First> | CombineErrors<Rest> : never;
33
+ /**
34
+ * Helper to propagate errors - use this when your function calls other
35
+ * throwing functions and wants to propagate their errors.
36
+ */
37
+ export type PropagatesErrors<T, AdditionalErrors extends Error = never> = Throws<ExtractSuccess<T>, ExtractErrors<T> | AdditionalErrors>;
38
+ export {};
39
+ //# sourceMappingURL=throws.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-client",
3
- "version": "2.17.0",
3
+ "version": "2.17.2",
4
4
  "description": "JavaScript/TypeScript client SDK for LiveKit",
5
5
  "main": "./dist/livekit-client.umd.js",
6
6
  "unpkg": "./dist/livekit-client.umd.js",
@@ -37,7 +37,7 @@
37
37
  "license": "Apache-2.0",
38
38
  "dependencies": {
39
39
  "@livekit/mutex": "1.1.1",
40
- "@livekit/protocol": "1.42.2",
40
+ "@livekit/protocol": "1.44.0",
41
41
  "events": "^3.3.0",
42
42
  "jose": "^6.1.0",
43
43
  "loglevel": "^1.9.2",
@@ -51,11 +51,11 @@
51
51
  "@types/dom-mediacapture-record": "^1"
52
52
  },
53
53
  "devDependencies": {
54
- "@babel/core": "7.28.5",
55
- "@babel/preset-env": "7.28.5",
54
+ "@babel/core": "7.29.0",
55
+ "@babel/preset-env": "7.29.0",
56
56
  "@bufbuild/protoc-gen-es": "^1.10.0",
57
- "@changesets/cli": "2.29.7",
58
- "@eslint/js": "9.39.1",
57
+ "@changesets/cli": "2.29.8",
58
+ "@eslint/js": "9.39.2",
59
59
  "@livekit/changesets-changelog-github": "^0.0.4",
60
60
  "@rollup/plugin-babel": "6.1.0",
61
61
  "@rollup/plugin-commonjs": "28.0.9",
@@ -72,25 +72,26 @@
72
72
  "@typescript-eslint/eslint-plugin": "7.18.0",
73
73
  "@typescript-eslint/parser": "7.18.0",
74
74
  "downlevel-dts": "^0.11.0",
75
- "eslint": "9.39.1",
75
+ "eslint": "9.39.2",
76
76
  "eslint-config-airbnb-extended": "^2.3.2",
77
77
  "eslint-config-prettier": "10.1.8",
78
78
  "eslint-plugin-compat": "^6.0.2",
79
79
  "eslint-plugin-import-x": "^4.16.1",
80
80
  "eslint-plugin-prettier": "^5.5.4",
81
81
  "gh-pages": "6.3.0",
82
+ "glob": "^13.0.0",
82
83
  "happy-dom": "^17.2.0",
83
84
  "jsdom": "^26.1.0",
84
85
  "prettier": "^3.4.2",
85
- "rollup": "4.53.2",
86
+ "rollup": "4.57.1",
86
87
  "rollup-plugin-delete": "^2.1.0",
87
88
  "rollup-plugin-typescript2": "0.36.0",
88
89
  "size-limit": "^11.2.0",
89
- "typedoc": "0.28.14",
90
+ "typedoc": "0.28.16",
90
91
  "typedoc-plugin-no-inherit": "1.6.1",
91
92
  "typescript": "5.8.3",
92
93
  "typescript-eslint": "^8.47.0",
93
- "vite": "7.2.2",
94
+ "vite": "7.3.1",
94
95
  "vitest": "^3.0.0"
95
96
  },
96
97
  "scripts": {
@@ -107,6 +108,7 @@
107
108
  "deploy": "gh-pages -d examples/demo/dist",
108
109
  "format": "prettier --write src examples/**/*.ts",
109
110
  "format:check": "prettier --check src examples/**/*.ts",
111
+ "throws:check": "pnpm dlx tsx ./throws-transformer/cli.ts 'src/!(*.test).ts' 'src/**/!(*.test).ts'",
110
112
  "ci:publish": "pnpm build:clean && pnpm compat && changeset publish",
111
113
  "downlevel-dts": "downlevel-dts ./dist/src ./dist/ts4.2 --to=4.2",
112
114
  "compat": "eslint --config ./eslint.config.dist.mjs --no-inline-config ./dist/livekit-client.esm.mjs",
@@ -91,8 +91,10 @@ export class ExternalE2EEKeyProvider extends BaseKeyProvider {
91
91
 
92
92
  /**
93
93
  * Accepts a passphrase that's used to create the crypto keys.
94
- * When passing in a string, PBKDF2 is used.
95
- * When passing in an Array buffer of cryptographically random numbers, HKDF is being used. (recommended)
94
+ * When passing in a string, PBKDF2 is used. (recommended for maximum compatibility across SDKs)
95
+ * When passing in an ArrayBuffer of cryptographically random numbers, HKDF is used.
96
+ *
97
+ * Note: Not all client SDKS support HKDF.
96
98
  * @param key
97
99
  */
98
100
  async setKey(key: string | ArrayBuffer) {
package/src/index.ts CHANGED
@@ -9,11 +9,18 @@ import {
9
9
  import { LogLevel, LoggerNames, getLogger, setLogExtension, setLogLevel } from './logger';
10
10
  import DefaultReconnectPolicy from './room/DefaultReconnectPolicy';
11
11
  import type { ReconnectContext, ReconnectPolicy } from './room/ReconnectPolicy';
12
- import Room, { ConnectionState } from './room/Room';
13
- import type { RoomEventCallbacks } from './room/Room';
12
+ import Room, { ConnectionState, type RoomEventCallbacks } from './room/Room';
14
13
  import * as attributes from './room/attribute-typings';
14
+ // FIXME: remove this import in a follow up data track pull request.
15
+ import './room/data-track/depacketizer';
16
+ // FIXME: remove this import in a follow up data track pull request.
17
+ import './room/data-track/packetizer';
15
18
  import LocalParticipant from './room/participant/LocalParticipant';
16
- import Participant, { ConnectionQuality, ParticipantKind } from './room/participant/Participant';
19
+ import Participant, {
20
+ ConnectionQuality,
21
+ type ParticipantEventCallbacks,
22
+ ParticipantKind,
23
+ } from './room/participant/Participant';
17
24
  import type { ParticipantTrackPermission } from './room/participant/ParticipantTrackPermission';
18
25
  import RemoteParticipant from './room/participant/RemoteParticipant';
19
26
  import type {
@@ -32,8 +39,8 @@ import RemoteTrack from './room/track/RemoteTrack';
32
39
  import RemoteTrackPublication from './room/track/RemoteTrackPublication';
33
40
  import type { ElementInfo } from './room/track/RemoteVideoTrack';
34
41
  import RemoteVideoTrack from './room/track/RemoteVideoTrack';
35
- import { TrackPublication } from './room/track/TrackPublication';
36
- import type { LiveKitReactNativeInfo } from './room/types';
42
+ import { type PublicationEventCallbacks, TrackPublication } from './room/track/TrackPublication';
43
+ import type { LiveKitReactNativeInfo, TextStreamInfo } from './room/types';
37
44
  import type { AudioAnalyserOptions } from './room/utils';
38
45
  import {
39
46
  compareVersions,
@@ -140,6 +147,7 @@ export type {
140
147
  AudioAnalyserOptions,
141
148
  ElementInfo,
142
149
  LiveKitReactNativeInfo,
150
+ TextStreamInfo,
143
151
  ParticipantTrackPermission,
144
152
  AudioReceiverStats,
145
153
  AudioSenderStats,
@@ -148,6 +156,14 @@ export type {
148
156
  ReconnectContext,
149
157
  ReconnectPolicy,
150
158
  RoomEventCallbacks,
159
+ ParticipantEventCallbacks,
160
+ PublicationEventCallbacks,
151
161
  };
162
+ export { DataTrackPacket, type DataTrackPacketHeader } from './room/data-track/packet';
163
+ export {
164
+ type DataTrackExtensions,
165
+ type DataTrackUserTimestampExtension,
166
+ type DataTrackE2eeExtension,
167
+ } from './room/data-track/packet/extensions';
152
168
 
153
169
  export { LocalTrackRecorder } from './room/track/record';
package/src/logger.ts CHANGED
@@ -21,6 +21,7 @@ export enum LoggerNames {
21
21
  PCManager = 'livekit-pc-manager',
22
22
  PCTransport = 'livekit-pc-transport',
23
23
  E2EE = 'lk-e2ee',
24
+ DataTracks = 'livekit-data-tracks',
24
25
  }
25
26
 
26
27
  type LogLevelString = keyof typeof LogLevel;
@@ -278,6 +278,7 @@ export default class PCTransport extends EventEmitter {
278
278
  await this._pc.setRemoteDescription(currentSD);
279
279
  } else {
280
280
  this.renegotiate = true;
281
+ this.log.debug('requesting renegotiation', { ...this.logContext });
281
282
  return;
282
283
  }
283
284
  } else if (!this._pc || this._pc.signalingState === 'closed') {
@@ -229,28 +229,46 @@ export class PCTransportManager {
229
229
 
230
230
  async negotiate(abortController: AbortController) {
231
231
  return new TypedPromise<void, NegotiationError | Error>(async (resolve, reject) => {
232
- const negotiationTimeout = setTimeout(() => {
232
+ let negotiationTimeout = setTimeout(() => {
233
233
  reject(new NegotiationError('negotiation timed out'));
234
234
  }, this.peerConnectionTimeout);
235
235
 
236
- const abortHandler = () => {
236
+ const cleanup = () => {
237
237
  clearTimeout(negotiationTimeout);
238
+ this.publisher.off(PCEvents.NegotiationStarted, onNegotiationStarted);
239
+ abortController.signal.removeEventListener('abort', abortHandler);
240
+ };
241
+
242
+ const abortHandler = () => {
243
+ cleanup();
238
244
  reject(new NegotiationError('negotiation aborted'));
239
245
  };
240
246
 
241
- abortController.signal.addEventListener('abort', abortHandler);
242
- this.publisher.once(PCEvents.NegotiationStarted, () => {
247
+ // Reset the timeout each time a renegotiation cycle starts. This
248
+ // prevents premature timeouts when the negotiation machinery is
249
+ // actively renegotiating (offers going out, answers coming back) but
250
+ // NegotiationComplete hasn't fired yet because new requirements keep
251
+ // arriving between offer/answer round-trips.
252
+ const onNegotiationStarted = () => {
243
253
  if (abortController.signal.aborted) {
244
254
  return;
245
255
  }
246
- this.publisher.once(PCEvents.NegotiationComplete, () => {
247
- clearTimeout(negotiationTimeout);
248
- resolve();
249
- });
256
+ clearTimeout(negotiationTimeout);
257
+ negotiationTimeout = setTimeout(() => {
258
+ cleanup();
259
+ reject(new NegotiationError('negotiation timed out'));
260
+ }, this.peerConnectionTimeout);
261
+ };
262
+
263
+ abortController.signal.addEventListener('abort', abortHandler);
264
+ this.publisher.on(PCEvents.NegotiationStarted, onNegotiationStarted);
265
+ this.publisher.once(PCEvents.NegotiationComplete, () => {
266
+ cleanup();
267
+ resolve();
250
268
  });
251
269
 
252
270
  await this.publisher.negotiate((e) => {
253
- clearTimeout(negotiationTimeout);
271
+ cleanup();
254
272
  if (e instanceof Error) {
255
273
  reject(e);
256
274
  } else {
@@ -1477,8 +1477,11 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1477
1477
  if (!this.pcManager) {
1478
1478
  return false;
1479
1479
  }
1480
- // primary connection
1481
- if (this.pcManager.currentState !== PCTransportState.CONNECTED) {
1480
+ const allowedConnectionStates: PCTransportState[] = [
1481
+ PCTransportState.CONNECTING,
1482
+ PCTransportState.CONNECTED,
1483
+ ];
1484
+ if (!allowedConnectionStates.includes(this.pcManager.currentState)) {
1482
1485
  return false;
1483
1486
  }
1484
1487
 
@@ -1521,6 +1524,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1521
1524
  reject(new NegotiationError('cannot negotiate on closed engine'));
1522
1525
  }
1523
1526
  this.on(EngineEvent.Closing, handleClosed);
1527
+ this.on(EngineEvent.Restarting, handleClosed);
1524
1528
 
1525
1529
  this.pcManager.publisher.once(
1526
1530
  PCEvents.RTPVideoPayloadTypes,
@@ -1540,6 +1544,12 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1540
1544
  await this.pcManager.negotiate(abortController);
1541
1545
  resolve();
1542
1546
  } catch (e: unknown) {
1547
+ if (abortController.signal.aborted) {
1548
+ // negotiation was aborted due to engine close or restart, resolve
1549
+ // cleanly to avoid triggering a cascading reconnect loop
1550
+ resolve();
1551
+ return;
1552
+ }
1543
1553
  if (e instanceof NegotiationError) {
1544
1554
  this.fullReconnectOnNext = true;
1545
1555
  }
@@ -1551,6 +1561,7 @@ export default class RTCEngine extends (EventEmitter as new () => TypedEventEmit
1551
1561
  }
1552
1562
  } finally {
1553
1563
  this.off(EngineEvent.Closing, handleClosed);
1564
+ this.off(EngineEvent.Restarting, handleClosed);
1554
1565
  }
1555
1566
  });
1556
1567
  }
package/src/room/Room.ts CHANGED
@@ -2307,7 +2307,7 @@ class Room extends (EventEmitter as new () => TypedEmitter<RoomEventCallbacks>)
2307
2307
  engine: this.engine
2308
2308
  ? {
2309
2309
  closed: this.engine.isClosed,
2310
- transportsConnected: this.engine.verifyTransport(),
2310
+ transportsConnectedOrConnecting: this.engine.verifyTransport(),
2311
2311
  }
2312
2312
  : undefined,
2313
2313
  });
@@ -191,6 +191,7 @@ export default class IncomingDataStreamManager {
191
191
  timestamp: Number(streamHeader.timestamp),
192
192
  attributes: streamHeader.attributes,
193
193
  encryptionType,
194
+ attachedStreamIds: streamHeader.contentHeader.value.attachedStreamIds,
194
195
  };
195
196
 
196
197
  const stream = new ReadableStream<DataStream_Chunk>({
@@ -107,6 +107,7 @@ export default class OutgoingDataStreamManager {
107
107
  encryptionType: this.engine.e2eeManager?.isDataChannelEncryptionEnabled
108
108
  ? Encryption_Type.GCM
109
109
  : Encryption_Type.NONE,
110
+ attachedStreamIds: options?.attachedStreamIds,
110
111
  };
111
112
  const header = new DataStream_Header({
112
113
  streamId,
@@ -119,7 +120,7 @@ export default class OutgoingDataStreamManager {
119
120
  case: 'textHeader',
120
121
  value: new DataStream_TextHeader({
121
122
  version: options?.version,
122
- attachedStreamIds: options?.attachedStreamIds,
123
+ attachedStreamIds: info.attachedStreamIds,
123
124
  replyToStreamId: options?.replyToStreamId,
124
125
  operationType:
125
126
  options?.type === 'update'