livekit-server-sdk 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/TwirpRPC.js CHANGED
@@ -1,11 +1,12 @@
1
1
  const defaultPrefix = "/twirp";
2
2
  const livekitPackage = "livekit";
3
3
  class TwirpError extends Error {
4
- constructor(name, message, status, code) {
4
+ constructor(name, message, status, code, metadata) {
5
5
  super(message);
6
6
  this.name = name;
7
7
  this.status = status;
8
8
  this.code = code;
9
+ this.metadata = metadata;
9
10
  }
10
11
  }
11
12
  class TwirpRpc {
@@ -17,22 +18,26 @@ class TwirpRpc {
17
18
  this.pkg = pkg;
18
19
  this.prefix = prefix || defaultPrefix;
19
20
  }
20
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
- async request(service, method, data, headers) {
21
+ async request(service, method, data, headers, timeout = 60) {
22
22
  const path = `${this.prefix}/${this.pkg}.${service}/${method}`;
23
23
  const url = new URL(path, this.host);
24
- const response = await fetch(url, {
24
+ const init = {
25
25
  method: "POST",
26
26
  headers: {
27
27
  "Content-Type": "application/json;charset=UTF-8",
28
28
  ...headers
29
29
  },
30
30
  body: JSON.stringify(data)
31
- });
31
+ };
32
+ if (timeout) {
33
+ init.signal = AbortSignal.timeout(timeout * 1e3);
34
+ }
35
+ const response = await fetch(url, init);
32
36
  if (!response.ok) {
33
37
  const isJson = response.headers.get("content-type") === "application/json";
34
38
  let errorMessage = "Unknown internal error";
35
39
  let errorCode = void 0;
40
+ let metadata = void 0;
36
41
  try {
37
42
  if (isJson) {
38
43
  const parsedError = await response.json();
@@ -42,13 +47,16 @@ class TwirpRpc {
42
47
  if ("code" in parsedError) {
43
48
  errorCode = parsedError.code;
44
49
  }
50
+ if ("meta" in parsedError) {
51
+ metadata = parsedError.meta;
52
+ }
45
53
  } else {
46
54
  errorMessage = await response.text();
47
55
  }
48
56
  } catch (e) {
49
57
  console.debug(`Error when trying to parse error message, using defaults`, e);
50
58
  }
51
- throw new TwirpError(response.statusText, errorMessage, response.status, errorCode);
59
+ throw new TwirpError(response.statusText, errorMessage, response.status, errorCode, metadata);
52
60
  }
53
61
  const parsedResp = await response.json();
54
62
  const camelcaseKeys = await import("camelcase-keys").then((mod) => mod.default);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/TwirpRPC.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { JsonValue } from '@bufbuild/protobuf';\n\n// twirp RPC adapter for client implementation\n\nconst defaultPrefix = '/twirp';\n\nexport const livekitPackage = 'livekit';\nexport interface Rpc {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n request(service: string, method: string, data: JsonValue, headers?: any): Promise<string>;\n}\n\nexport class TwirpError extends Error {\n status: number;\n code?: string;\n\n constructor(name: string, message: string, status: number, code?: string) {\n super(message);\n this.name = name;\n this.status = status;\n this.code = code;\n }\n}\n\n/**\n * JSON based Twirp V7 RPC\n */\nexport class TwirpRpc {\n host: string;\n\n pkg: string;\n\n prefix: string;\n\n constructor(host: string, pkg: string, prefix?: string) {\n if (host.startsWith('ws')) {\n host = host.replace('ws', 'http');\n }\n this.host = host;\n this.pkg = pkg;\n this.prefix = prefix || defaultPrefix;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async request(service: string, method: string, data: any, headers?: any): Promise<any> {\n const path = `${this.prefix}/${this.pkg}.${service}/${method}`;\n const url = new URL(path, this.host);\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json;charset=UTF-8',\n ...headers,\n },\n body: JSON.stringify(data),\n });\n\n if (!response.ok) {\n const isJson = response.headers.get('content-type') === 'application/json';\n let errorMessage = 'Unknown internal error';\n let errorCode: string | undefined = undefined;\n try {\n if (isJson) {\n const parsedError = (await response.json()) as Record<string, unknown>;\n if ('msg' in parsedError) {\n errorMessage = <string>parsedError.msg;\n }\n if ('code' in parsedError) {\n errorCode = <string>parsedError.code;\n }\n } else {\n errorMessage = await response.text();\n }\n } catch (e) {\n // parsing went wrong, no op and we keep default error message\n console.debug(`Error when trying to parse error message, using defaults`, e);\n }\n\n throw new TwirpError(response.statusText, errorMessage, response.status, errorCode);\n }\n const parsedResp = (await response.json()) as Record<string, unknown>;\n\n const camelcaseKeys = await import('camelcase-keys').then((mod) => mod.default);\n return camelcaseKeys(parsedResp, { deep: true });\n }\n}\n"],"mappings":"AAOA,MAAM,gBAAgB;AAEf,MAAM,iBAAiB;AAMvB,MAAM,mBAAmB,MAAM;AAAA,EAIpC,YAAY,MAAc,SAAiB,QAAgB,MAAe;AACxE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AAAA,EACd;AACF;AAKO,MAAM,SAAS;AAAA,EAOpB,YAAY,MAAc,KAAa,QAAiB;AACtD,QAAI,KAAK,WAAW,IAAI,GAAG;AACzB,aAAO,KAAK,QAAQ,MAAM,MAAM;AAAA,IAClC;AACA,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,SAAS,UAAU;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,QAAQ,SAAiB,QAAgB,MAAW,SAA6B;AACrF,UAAM,OAAO,GAAG,KAAK,MAAM,IAAI,KAAK,GAAG,IAAI,OAAO,IAAI,MAAM;AAC5D,UAAM,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI;AAEnC,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MACL;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,SAAS,SAAS,QAAQ,IAAI,cAAc,MAAM;AACxD,UAAI,eAAe;AACnB,UAAI,YAAgC;AACpC,UAAI;AACF,YAAI,QAAQ;AACV,gBAAM,cAAe,MAAM,SAAS,KAAK;AACzC,cAAI,SAAS,aAAa;AACxB,2BAAuB,YAAY;AAAA,UACrC;AACA,cAAI,UAAU,aAAa;AACzB,wBAAoB,YAAY;AAAA,UAClC;AAAA,QACF,OAAO;AACL,yBAAe,MAAM,SAAS,KAAK;AAAA,QACrC;AAAA,MACF,SAAS,GAAG;AAEV,gBAAQ,MAAM,4DAA4D,CAAC;AAAA,MAC7E;AAEA,YAAM,IAAI,WAAW,SAAS,YAAY,cAAc,SAAS,QAAQ,SAAS;AAAA,IACpF;AACA,UAAM,aAAc,MAAM,SAAS,KAAK;AAExC,UAAM,gBAAgB,MAAM,OAAO,gBAAgB,EAAE,KAAK,CAAC,QAAQ,IAAI,OAAO;AAC9E,WAAO,cAAc,YAAY,EAAE,MAAM,KAAK,CAAC;AAAA,EACjD;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/TwirpRPC.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { JsonValue } from '@bufbuild/protobuf';\n\n// twirp RPC adapter for client implementation\n\nconst defaultPrefix = '/twirp';\n\nexport const livekitPackage = 'livekit';\nexport interface Rpc {\n request(\n service: string,\n method: string,\n data: JsonValue,\n headers: any, // eslint-disable-line @typescript-eslint/no-explicit-any\n timeout?: number,\n ): Promise<string>;\n}\n\nexport class TwirpError extends Error {\n status: number;\n code?: string;\n metadata?: Record<string, string>;\n\n constructor(\n name: string,\n message: string,\n status: number,\n code?: string,\n metadata?: Record<string, string>,\n ) {\n super(message);\n this.name = name;\n this.status = status;\n this.code = code;\n this.metadata = metadata;\n }\n}\n\n/**\n * JSON based Twirp V7 RPC\n */\nexport class TwirpRpc {\n host: string;\n\n pkg: string;\n\n prefix: string;\n\n constructor(host: string, pkg: string, prefix?: string) {\n if (host.startsWith('ws')) {\n host = host.replace('ws', 'http');\n }\n this.host = host;\n this.pkg = pkg;\n this.prefix = prefix || defaultPrefix;\n }\n\n async request(\n service: string,\n method: string,\n data: any, // eslint-disable-line @typescript-eslint/no-explicit-any\n headers: any, // eslint-disable-line @typescript-eslint/no-explicit-any\n timeout = 60,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ): Promise<any> {\n const path = `${this.prefix}/${this.pkg}.${service}/${method}`;\n const url = new URL(path, this.host);\n const init: RequestInit = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json;charset=UTF-8',\n ...headers,\n },\n body: JSON.stringify(data),\n };\n\n if (timeout) {\n init.signal = AbortSignal.timeout(timeout * 1000);\n }\n\n const response = await fetch(url, init);\n\n if (!response.ok) {\n const isJson = response.headers.get('content-type') === 'application/json';\n let errorMessage = 'Unknown internal error';\n let errorCode: string | undefined = undefined;\n let metadata: Record<string, string> | undefined = undefined;\n try {\n if (isJson) {\n const parsedError = (await response.json()) as Record<string, unknown>;\n if ('msg' in parsedError) {\n errorMessage = <string>parsedError.msg;\n }\n if ('code' in parsedError) {\n errorCode = <string>parsedError.code;\n }\n if ('meta' in parsedError) {\n metadata = <Record<string, string>>parsedError.meta;\n }\n } else {\n errorMessage = await response.text();\n }\n } catch (e) {\n // parsing went wrong, no op and we keep default error message\n console.debug(`Error when trying to parse error message, using defaults`, e);\n }\n\n throw new TwirpError(response.statusText, errorMessage, response.status, errorCode, metadata);\n }\n const parsedResp = (await response.json()) as Record<string, unknown>;\n\n const camelcaseKeys = await import('camelcase-keys').then((mod) => mod.default);\n return camelcaseKeys(parsedResp, { deep: true });\n }\n}\n"],"mappings":"AAOA,MAAM,gBAAgB;AAEf,MAAM,iBAAiB;AAWvB,MAAM,mBAAmB,MAAM;AAAA,EAKpC,YACE,MACA,SACA,QACA,MACA,UACA;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;AAKO,MAAM,SAAS;AAAA,EAOpB,YAAY,MAAc,KAAa,QAAiB;AACtD,QAAI,KAAK,WAAW,IAAI,GAAG;AACzB,aAAO,KAAK,QAAQ,MAAM,MAAM;AAAA,IAClC;AACA,SAAK,OAAO;AACZ,SAAK,MAAM;AACX,SAAK,SAAS,UAAU;AAAA,EAC1B;AAAA,EAEA,MAAM,QACJ,SACA,QACA,MACA,SACA,UAAU,IAEI;AACd,UAAM,OAAO,GAAG,KAAK,MAAM,IAAI,KAAK,GAAG,IAAI,OAAO,IAAI,MAAM;AAC5D,UAAM,MAAM,IAAI,IAAI,MAAM,KAAK,IAAI;AACnC,UAAM,OAAoB;AAAA,MACxB,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,GAAG;AAAA,MACL;AAAA,MACA,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B;AAEA,QAAI,SAAS;AACX,WAAK,SAAS,YAAY,QAAQ,UAAU,GAAI;AAAA,IAClD;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AAEtC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,SAAS,SAAS,QAAQ,IAAI,cAAc,MAAM;AACxD,UAAI,eAAe;AACnB,UAAI,YAAgC;AACpC,UAAI,WAA+C;AACnD,UAAI;AACF,YAAI,QAAQ;AACV,gBAAM,cAAe,MAAM,SAAS,KAAK;AACzC,cAAI,SAAS,aAAa;AACxB,2BAAuB,YAAY;AAAA,UACrC;AACA,cAAI,UAAU,aAAa;AACzB,wBAAoB,YAAY;AAAA,UAClC;AACA,cAAI,UAAU,aAAa;AACzB,uBAAmC,YAAY;AAAA,UACjD;AAAA,QACF,OAAO;AACL,yBAAe,MAAM,SAAS,KAAK;AAAA,QACrC;AAAA,MACF,SAAS,GAAG;AAEV,gBAAQ,MAAM,4DAA4D,CAAC;AAAA,MAC7E;AAEA,YAAM,IAAI,WAAW,SAAS,YAAY,cAAc,SAAS,QAAQ,WAAW,QAAQ;AAAA,IAC9F;AACA,UAAM,aAAc,MAAM,SAAS,KAAK;AAExC,UAAM,gBAAgB,MAAM,OAAO,gBAAgB,EAAE,KAAK,CAAC,QAAQ,IAAI,OAAO;AAC9E,WAAO,cAAc,YAAY,EAAE,MAAM,KAAK,CAAC;AAAA,EACjD;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/grants.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RoomConfiguration } from '@livekit/protocol';\nimport { TrackSource } from '@livekit/protocol';\nimport type { JWTPayload } from 'jose';\n\nexport function trackSourceToString(source: TrackSource) {\n switch (source) {\n case TrackSource.CAMERA:\n return 'camera';\n case TrackSource.MICROPHONE:\n return 'microphone';\n case TrackSource.SCREEN_SHARE:\n return 'screen_share';\n case TrackSource.SCREEN_SHARE_AUDIO:\n return 'screen_share_audio';\n default:\n throw new TypeError(`Cannot convert TrackSource ${source} to string`);\n }\n}\n\nexport function claimsToJwtPayload(\n grant: ClaimGrants,\n): JWTPayload & { video?: Record<string, unknown> } {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const claim: Record<string, any> = { ...grant };\n // eslint-disable-next-line no-restricted-syntax\n if (Array.isArray(claim.video?.canPublishSources)) {\n claim.video.canPublishSources = claim.video.canPublishSources.map(trackSourceToString);\n }\n return claim;\n}\n\nexport interface VideoGrant {\n /** permission to create a room */\n roomCreate?: boolean;\n\n /** permission to join a room as a participant, room must be set */\n roomJoin?: boolean;\n\n /** permission to list rooms */\n roomList?: boolean;\n\n /** permission to start a recording */\n roomRecord?: boolean;\n\n /** permission to control a specific room, room must be set */\n roomAdmin?: boolean;\n\n /** name of the room, must be set for admin or join permissions */\n room?: string;\n\n /** permissions to control ingress, not specific to any room or ingress */\n ingressAdmin?: boolean;\n\n /**\n * allow participant to publish. If neither canPublish or canSubscribe is set,\n * both publish and subscribe are enabled\n */\n canPublish?: boolean;\n\n /**\n * TrackSource types that the participant is allowed to publish\n * When set, it supersedes CanPublish. Only sources explicitly set here can be published\n */\n canPublishSources?: TrackSource[];\n\n /** allow participant to subscribe to other tracks */\n canSubscribe?: boolean;\n\n /**\n * allow participants to publish data, defaults to true if not set\n */\n canPublishData?: boolean;\n\n /**\n * by default, a participant is not allowed to update its own metadata\n */\n canUpdateOwnMetadata?: boolean;\n\n /** participant isn't visible to others */\n hidden?: boolean;\n\n /** participant is recording the room, when set, allows room to indicate it's being recorded */\n recorder?: boolean;\n\n /** participant allowed to connect to LiveKit as Agent Framework worker */\n agent?: boolean;\n\n /** allow participant to subscribe to metrics */\n canSubscribeMetrics?: boolean;\n}\n\nexport interface SIPGrant {\n /** manage sip resources */\n admin?: boolean;\n\n /** make outbound calls */\n call?: boolean;\n}\n\n/** @internal */\nexport interface ClaimGrants extends JWTPayload {\n name?: string;\n video?: VideoGrant;\n sip?: SIPGrant;\n kind?: string;\n metadata?: string;\n attributes?: Record<string, string>;\n sha256?: string;\n roomPreset?: string;\n roomConfig?: RoomConfiguration;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,sBAA4B;AAGrB,SAAS,oBAAoB,QAAqB;AACvD,UAAQ,QAAQ;AAAA,IACd,KAAK,4BAAY;AACf,aAAO;AAAA,IACT,KAAK,4BAAY;AACf,aAAO;AAAA,IACT,KAAK,4BAAY;AACf,aAAO;AAAA,IACT,KAAK,4BAAY;AACf,aAAO;AAAA,IACT;AACE,YAAM,IAAI,UAAU,8BAA8B,MAAM,YAAY;AAAA,EACxE;AACF;AAEO,SAAS,mBACd,OACkD;AAxBpD;AA0BE,QAAM,QAA6B,EAAE,GAAG,MAAM;AAE9C,MAAI,MAAM,SAAQ,WAAM,UAAN,mBAAa,iBAAiB,GAAG;AACjD,UAAM,MAAM,oBAAoB,MAAM,MAAM,kBAAkB,IAAI,mBAAmB;AAAA,EACvF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/grants.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RoomConfiguration } from '@livekit/protocol';\nimport { TrackSource } from '@livekit/protocol';\nimport type { JWTPayload } from 'jose';\n\nexport function trackSourceToString(source: TrackSource) {\n switch (source) {\n case TrackSource.CAMERA:\n return 'camera';\n case TrackSource.MICROPHONE:\n return 'microphone';\n case TrackSource.SCREEN_SHARE:\n return 'screen_share';\n case TrackSource.SCREEN_SHARE_AUDIO:\n return 'screen_share_audio';\n default:\n throw new TypeError(`Cannot convert TrackSource ${source} to string`);\n }\n}\n\nexport function claimsToJwtPayload(\n grant: ClaimGrants,\n): JWTPayload & { video?: Record<string, unknown> } {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const claim: Record<string, any> = { ...grant };\n // eslint-disable-next-line no-restricted-syntax\n if (Array.isArray(claim.video?.canPublishSources)) {\n claim.video.canPublishSources = claim.video.canPublishSources.map(trackSourceToString);\n }\n return claim;\n}\n\nexport interface VideoGrant {\n /** permission to create a room */\n roomCreate?: boolean;\n\n /** permission to join a room as a participant, room must be set */\n roomJoin?: boolean;\n\n /** permission to list rooms */\n roomList?: boolean;\n\n /** permission to start a recording */\n roomRecord?: boolean;\n\n /** permission to control a specific room, room must be set */\n roomAdmin?: boolean;\n\n /** name of the room, must be set for admin or join permissions */\n room?: string;\n\n /** permissions to control ingress, not specific to any room or ingress */\n ingressAdmin?: boolean;\n\n /**\n * allow participant to publish. If neither canPublish or canSubscribe is set,\n * both publish and subscribe are enabled\n */\n canPublish?: boolean;\n\n /**\n * TrackSource types that the participant is allowed to publish\n * When set, it supersedes CanPublish. Only sources explicitly set here can be published\n */\n canPublishSources?: TrackSource[];\n\n /** allow participant to subscribe to other tracks */\n canSubscribe?: boolean;\n\n /**\n * allow participants to publish data, defaults to true if not set\n */\n canPublishData?: boolean;\n\n /**\n * by default, a participant is not allowed to update its own metadata\n */\n canUpdateOwnMetadata?: boolean;\n\n /** participant isn't visible to others */\n hidden?: boolean;\n\n /** participant is recording the room, when set, allows room to indicate it's being recorded */\n recorder?: boolean;\n\n /** participant allowed to connect to LiveKit as Agent Framework worker */\n agent?: boolean;\n\n /** allow participant to subscribe to metrics */\n canSubscribeMetrics?: boolean;\n\n /** destination room which this participant can forward to */\n destinationRoom?: string;\n}\n\nexport interface SIPGrant {\n /** manage sip resources */\n admin?: boolean;\n\n /** make outbound calls */\n call?: boolean;\n}\n\n/** @internal */\nexport interface ClaimGrants extends JWTPayload {\n name?: string;\n video?: VideoGrant;\n sip?: SIPGrant;\n kind?: string;\n metadata?: string;\n attributes?: Record<string, string>;\n sha256?: string;\n roomPreset?: string;\n roomConfig?: RoomConfiguration;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,sBAA4B;AAGrB,SAAS,oBAAoB,QAAqB;AACvD,UAAQ,QAAQ;AAAA,IACd,KAAK,4BAAY;AACf,aAAO;AAAA,IACT,KAAK,4BAAY;AACf,aAAO;AAAA,IACT,KAAK,4BAAY;AACf,aAAO;AAAA,IACT,KAAK,4BAAY;AACf,aAAO;AAAA,IACT;AACE,YAAM,IAAI,UAAU,8BAA8B,MAAM,YAAY;AAAA,EACxE;AACF;AAEO,SAAS,mBACd,OACkD;AAxBpD;AA0BE,QAAM,QAA6B,EAAE,GAAG,MAAM;AAE9C,MAAI,MAAM,SAAQ,WAAM,UAAN,mBAAa,iBAAiB,GAAG;AACjD,UAAM,MAAM,oBAAoB,MAAM,MAAM,kBAAkB,IAAI,mBAAmB;AAAA,EACvF;AACA,SAAO;AACT;","names":[]}
package/dist/grants.d.cts CHANGED
@@ -48,6 +48,8 @@ interface VideoGrant {
48
48
  agent?: boolean;
49
49
  /** allow participant to subscribe to metrics */
50
50
  canSubscribeMetrics?: boolean;
51
+ /** destination room which this participant can forward to */
52
+ destinationRoom?: string;
51
53
  }
52
54
  interface SIPGrant {
53
55
  /** manage sip resources */
package/dist/grants.d.ts CHANGED
@@ -48,6 +48,8 @@ export interface VideoGrant {
48
48
  agent?: boolean;
49
49
  /** allow participant to subscribe to metrics */
50
50
  canSubscribeMetrics?: boolean;
51
+ /** destination room which this participant can forward to */
52
+ destinationRoom?: string;
51
53
  }
52
54
  export interface SIPGrant {
53
55
  /** manage sip resources */
@@ -1 +1 @@
1
- {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEvC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,mEAatD;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,GACjB,UAAU,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAQlD;AAED,MAAM,WAAW,UAAU;IACzB,kCAAkC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,0EAA0E;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,WAAW,EAAE,CAAC;IAElC,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;OAEG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,QAAQ;IACvB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,gBAAgB;AAChB,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC"}
1
+ {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEvC,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,mEAatD;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,GACjB,UAAU,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAQlD;AAED,MAAM,WAAW,UAAU;IACzB,kCAAkC;IAClC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,0EAA0E;IAC1E,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,WAAW,EAAE,CAAC;IAElC,qDAAqD;IACrD,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB;;OAEG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,gDAAgD;IAChD,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B,6DAA6D;IAC7D,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,gBAAgB;AAChB,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,iBAAiB,CAAC;CAChC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/grants.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RoomConfiguration } from '@livekit/protocol';\nimport { TrackSource } from '@livekit/protocol';\nimport type { JWTPayload } from 'jose';\n\nexport function trackSourceToString(source: TrackSource) {\n switch (source) {\n case TrackSource.CAMERA:\n return 'camera';\n case TrackSource.MICROPHONE:\n return 'microphone';\n case TrackSource.SCREEN_SHARE:\n return 'screen_share';\n case TrackSource.SCREEN_SHARE_AUDIO:\n return 'screen_share_audio';\n default:\n throw new TypeError(`Cannot convert TrackSource ${source} to string`);\n }\n}\n\nexport function claimsToJwtPayload(\n grant: ClaimGrants,\n): JWTPayload & { video?: Record<string, unknown> } {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const claim: Record<string, any> = { ...grant };\n // eslint-disable-next-line no-restricted-syntax\n if (Array.isArray(claim.video?.canPublishSources)) {\n claim.video.canPublishSources = claim.video.canPublishSources.map(trackSourceToString);\n }\n return claim;\n}\n\nexport interface VideoGrant {\n /** permission to create a room */\n roomCreate?: boolean;\n\n /** permission to join a room as a participant, room must be set */\n roomJoin?: boolean;\n\n /** permission to list rooms */\n roomList?: boolean;\n\n /** permission to start a recording */\n roomRecord?: boolean;\n\n /** permission to control a specific room, room must be set */\n roomAdmin?: boolean;\n\n /** name of the room, must be set for admin or join permissions */\n room?: string;\n\n /** permissions to control ingress, not specific to any room or ingress */\n ingressAdmin?: boolean;\n\n /**\n * allow participant to publish. If neither canPublish or canSubscribe is set,\n * both publish and subscribe are enabled\n */\n canPublish?: boolean;\n\n /**\n * TrackSource types that the participant is allowed to publish\n * When set, it supersedes CanPublish. Only sources explicitly set here can be published\n */\n canPublishSources?: TrackSource[];\n\n /** allow participant to subscribe to other tracks */\n canSubscribe?: boolean;\n\n /**\n * allow participants to publish data, defaults to true if not set\n */\n canPublishData?: boolean;\n\n /**\n * by default, a participant is not allowed to update its own metadata\n */\n canUpdateOwnMetadata?: boolean;\n\n /** participant isn't visible to others */\n hidden?: boolean;\n\n /** participant is recording the room, when set, allows room to indicate it's being recorded */\n recorder?: boolean;\n\n /** participant allowed to connect to LiveKit as Agent Framework worker */\n agent?: boolean;\n\n /** allow participant to subscribe to metrics */\n canSubscribeMetrics?: boolean;\n}\n\nexport interface SIPGrant {\n /** manage sip resources */\n admin?: boolean;\n\n /** make outbound calls */\n call?: boolean;\n}\n\n/** @internal */\nexport interface ClaimGrants extends JWTPayload {\n name?: string;\n video?: VideoGrant;\n sip?: SIPGrant;\n kind?: string;\n metadata?: string;\n attributes?: Record<string, string>;\n sha256?: string;\n roomPreset?: string;\n roomConfig?: RoomConfiguration;\n}\n"],"mappings":"AAIA,SAAS,mBAAmB;AAGrB,SAAS,oBAAoB,QAAqB;AACvD,UAAQ,QAAQ;AAAA,IACd,KAAK,YAAY;AACf,aAAO;AAAA,IACT,KAAK,YAAY;AACf,aAAO;AAAA,IACT,KAAK,YAAY;AACf,aAAO;AAAA,IACT,KAAK,YAAY;AACf,aAAO;AAAA,IACT;AACE,YAAM,IAAI,UAAU,8BAA8B,MAAM,YAAY;AAAA,EACxE;AACF;AAEO,SAAS,mBACd,OACkD;AAxBpD;AA0BE,QAAM,QAA6B,EAAE,GAAG,MAAM;AAE9C,MAAI,MAAM,SAAQ,WAAM,UAAN,mBAAa,iBAAiB,GAAG;AACjD,UAAM,MAAM,oBAAoB,MAAM,MAAM,kBAAkB,IAAI,mBAAmB;AAAA,EACvF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/grants.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { RoomConfiguration } from '@livekit/protocol';\nimport { TrackSource } from '@livekit/protocol';\nimport type { JWTPayload } from 'jose';\n\nexport function trackSourceToString(source: TrackSource) {\n switch (source) {\n case TrackSource.CAMERA:\n return 'camera';\n case TrackSource.MICROPHONE:\n return 'microphone';\n case TrackSource.SCREEN_SHARE:\n return 'screen_share';\n case TrackSource.SCREEN_SHARE_AUDIO:\n return 'screen_share_audio';\n default:\n throw new TypeError(`Cannot convert TrackSource ${source} to string`);\n }\n}\n\nexport function claimsToJwtPayload(\n grant: ClaimGrants,\n): JWTPayload & { video?: Record<string, unknown> } {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const claim: Record<string, any> = { ...grant };\n // eslint-disable-next-line no-restricted-syntax\n if (Array.isArray(claim.video?.canPublishSources)) {\n claim.video.canPublishSources = claim.video.canPublishSources.map(trackSourceToString);\n }\n return claim;\n}\n\nexport interface VideoGrant {\n /** permission to create a room */\n roomCreate?: boolean;\n\n /** permission to join a room as a participant, room must be set */\n roomJoin?: boolean;\n\n /** permission to list rooms */\n roomList?: boolean;\n\n /** permission to start a recording */\n roomRecord?: boolean;\n\n /** permission to control a specific room, room must be set */\n roomAdmin?: boolean;\n\n /** name of the room, must be set for admin or join permissions */\n room?: string;\n\n /** permissions to control ingress, not specific to any room or ingress */\n ingressAdmin?: boolean;\n\n /**\n * allow participant to publish. If neither canPublish or canSubscribe is set,\n * both publish and subscribe are enabled\n */\n canPublish?: boolean;\n\n /**\n * TrackSource types that the participant is allowed to publish\n * When set, it supersedes CanPublish. Only sources explicitly set here can be published\n */\n canPublishSources?: TrackSource[];\n\n /** allow participant to subscribe to other tracks */\n canSubscribe?: boolean;\n\n /**\n * allow participants to publish data, defaults to true if not set\n */\n canPublishData?: boolean;\n\n /**\n * by default, a participant is not allowed to update its own metadata\n */\n canUpdateOwnMetadata?: boolean;\n\n /** participant isn't visible to others */\n hidden?: boolean;\n\n /** participant is recording the room, when set, allows room to indicate it's being recorded */\n recorder?: boolean;\n\n /** participant allowed to connect to LiveKit as Agent Framework worker */\n agent?: boolean;\n\n /** allow participant to subscribe to metrics */\n canSubscribeMetrics?: boolean;\n\n /** destination room which this participant can forward to */\n destinationRoom?: string;\n}\n\nexport interface SIPGrant {\n /** manage sip resources */\n admin?: boolean;\n\n /** make outbound calls */\n call?: boolean;\n}\n\n/** @internal */\nexport interface ClaimGrants extends JWTPayload {\n name?: string;\n video?: VideoGrant;\n sip?: SIPGrant;\n kind?: string;\n metadata?: string;\n attributes?: Record<string, string>;\n sha256?: string;\n roomPreset?: string;\n roomConfig?: RoomConfiguration;\n}\n"],"mappings":"AAIA,SAAS,mBAAmB;AAGrB,SAAS,oBAAoB,QAAqB;AACvD,UAAQ,QAAQ;AAAA,IACd,KAAK,YAAY;AACf,aAAO;AAAA,IACT,KAAK,YAAY;AACf,aAAO;AAAA,IACT,KAAK,YAAY;AACf,aAAO;AAAA,IACT,KAAK,YAAY;AACf,aAAO;AAAA,IACT;AACE,YAAM,IAAI,UAAU,8BAA8B,MAAM,YAAY;AAAA,EACxE;AACF;AAEO,SAAS,mBACd,OACkD;AAxBpD;AA0BE,QAAM,QAA6B,EAAE,GAAG,MAAM;AAE9C,MAAI,MAAM,SAAQ,WAAM,UAAN,mBAAa,iBAAiB,GAAG;AACjD,UAAM,MAAM,oBAAoB,MAAM,MAAM,kBAAkB,IAAI,mBAAmB;AAAA,EACvF;AACA,SAAO;AACT;","names":[]}
package/dist/index.d.cts CHANGED
@@ -5,7 +5,7 @@ export { EgressClient, EncodedOutputs, ListEgressOptions, ParticipantEgressOptio
5
5
  export { ClaimGrants, SIPGrant, VideoGrant, claimsToJwtPayload, trackSourceToString } from './grants.cjs';
6
6
  export { CreateIngressOptions, IngressClient, ListIngressOptions, UpdateIngressOptions } from './IngressClient.cjs';
7
7
  export { CreateOptions, RoomServiceClient, SendDataOptions, UpdateParticipantOptions } from './RoomServiceClient.cjs';
8
- export { CreateSipDispatchRuleOptions, CreateSipInboundTrunkOptions, CreateSipOutboundTrunkOptions, CreateSipParticipantOptions, CreateSipTrunkOptions, SipClient, SipDispatchRuleDirect, SipDispatchRuleIndividual, TransferSipParticipantOptions } from './SipClient.cjs';
8
+ export { CreateSipDispatchRuleOptions, CreateSipInboundTrunkOptions, CreateSipOutboundTrunkOptions, CreateSipParticipantOptions, CreateSipTrunkOptions, ListSipDispatchRuleOptions, ListSipTrunkOptions, SipClient, SipDispatchRuleDirect, SipDispatchRuleIndividual, SipDispatchRuleUpdateOptions, SipTrunkUpdateOptions, TransferSipParticipantOptions } from './SipClient.cjs';
9
9
  export { WebhookEvent, WebhookEventNames, WebhookReceiver, authorizeHeader } from './WebhookReceiver.cjs';
10
10
  import './ServiceBase.cjs';
11
11
  import 'jose';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "livekit-server-sdk",
3
- "version": "2.11.0",
3
+ "version": "2.13.0",
4
4
  "description": "Server-side SDK for LiveKit",
5
5
  "main": "dist/index.js",
6
6
  "require": "dist/index.cjs",
@@ -30,7 +30,7 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@bufbuild/protobuf": "^1.7.2",
33
- "@livekit/protocol": "^1.36.1",
33
+ "@livekit/protocol": "^1.38.0",
34
34
  "camelcase-keys": "^9.0.0",
35
35
  "jose": "^5.1.2"
36
36
  },
@@ -11,6 +11,7 @@ import type {
11
11
  StreamOutput,
12
12
  } from '@livekit/protocol';
13
13
  import {
14
+ AudioMixing,
14
15
  EgressInfo,
15
16
  ListEgressRequest,
16
17
  ListEgressResponse,
@@ -50,6 +51,10 @@ export interface RoomCompositeOptions {
50
51
  * custom template url. optional
51
52
  */
52
53
  customBaseUrl?: string;
54
+ /**
55
+ * audio mixing options. optional
56
+ */
57
+ audioMixing?: AudioMixing;
53
58
  }
54
59
 
55
60
  export interface WebOptions {
@@ -151,6 +156,7 @@ export class EgressClient extends ServiceBase {
151
156
  audioOnly?: boolean,
152
157
  videoOnly?: boolean,
153
158
  customBaseUrl?: string,
159
+ audioMixing?: AudioMixing,
154
160
  ): Promise<EgressInfo>;
155
161
  async startRoomCompositeEgress(
156
162
  roomName: string,
@@ -160,6 +166,7 @@ export class EgressClient extends ServiceBase {
160
166
  audioOnly?: boolean,
161
167
  videoOnly?: boolean,
162
168
  customBaseUrl?: string,
169
+ audioMixing?: AudioMixing,
163
170
  ): Promise<EgressInfo> {
164
171
  let layout: string | undefined;
165
172
  if (optsOrLayout !== undefined) {
@@ -172,6 +179,7 @@ export class EgressClient extends ServiceBase {
172
179
  audioOnly = opts.audioOnly;
173
180
  videoOnly = opts.videoOnly;
174
181
  customBaseUrl = opts.customBaseUrl;
182
+ audioMixing = opts.audioMixing;
175
183
  }
176
184
  }
177
185
 
@@ -179,6 +187,7 @@ export class EgressClient extends ServiceBase {
179
187
  audioOnly ??= false;
180
188
  videoOnly ??= false;
181
189
  customBaseUrl ??= '';
190
+ audioMixing ??= AudioMixing.DEFAULT_MIXING;
182
191
 
183
192
  const {
184
193
  output: legacyOutput,
@@ -193,6 +202,7 @@ export class EgressClient extends ServiceBase {
193
202
  roomName,
194
203
  layout,
195
204
  audioOnly,
205
+ audioMixing,
196
206
  videoOnly,
197
207
  customBaseUrl,
198
208
  output: legacyOutput,
@@ -10,6 +10,7 @@ import {
10
10
  ListParticipantsResponse,
11
11
  ListRoomsRequest,
12
12
  ListRoomsResponse,
13
+ MoveParticipantRequest,
13
14
  MuteRoomTrackRequest,
14
15
  MuteRoomTrackResponse,
15
16
  ParticipantInfo,
@@ -233,13 +234,33 @@ export class RoomServiceClient extends ServiceBase {
233
234
  * participant. When the source participant disconnects or the
234
235
  * `RemoveParticipant` method is called in the destination room, the
235
236
  * forwarding will be stopped.
237
+ * @param room -
238
+ * @param identity -
239
+ * @param destinationRoom - the room to forward the participant to
236
240
  */
237
241
  async forwardParticipant(room: string, identity: string, destinationRoom: string): Promise<void> {
238
242
  await this.rpc.request(
239
243
  svc,
240
244
  'ForwardParticipant',
241
245
  new ForwardParticipantRequest({ room, identity, destinationRoom }).toJson(),
242
- await this.authHeader({ roomAdmin: true, room }),
246
+ await this.authHeader({ roomAdmin: true, room, destinationRoom }),
247
+ );
248
+ }
249
+
250
+ /**
251
+ * Move a connected participant to a different room. Requires `roomAdmin` and `destinationRoom`.
252
+ * The participant will be removed from the current room and added to the destination room.
253
+ * From the other observers' perspective, the participant would've disconnected from the previous room and joined the new one.
254
+ * @param room -
255
+ * @param identity -
256
+ * @param destinationRoom - the room to move the participant to
257
+ */
258
+ async moveParticipant(room: string, identity: string, destinationRoom: string): Promise<void> {
259
+ await this.rpc.request(
260
+ svc,
261
+ 'MoveParticipant',
262
+ new MoveParticipantRequest({ room, identity, destinationRoom }).toJson(),
263
+ await this.authHeader({ roomAdmin: true, room, destinationRoom }),
243
264
  );
244
265
  }
245
266