Erster Commit

This commit is contained in:
2026-08-22 08:40:29 +02:00
commit 875477d425
1961 changed files with 930336 additions and 0 deletions
+187
View File
@@ -0,0 +1,187 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var AccessToken_exports = {};
__export(AccessToken_exports, {
AccessToken: () => AccessToken,
TokenVerifier: () => TokenVerifier
});
module.exports = __toCommonJS(AccessToken_exports);
var jose = __toESM(require("jose"), 1);
var import_grants = require("./grants.cjs");
const defaultTTL = `6h`;
const defaultClockToleranceSeconds = 10;
class AccessToken {
/**
* Creates a new AccessToken
* @param apiKey - API Key, can be set in env LIVEKIT_API_KEY
* @param apiSecret - Secret, can be set in env LIVEKIT_API_SECRET
*/
constructor(apiKey, apiSecret, options) {
if (!apiKey) {
apiKey = process.env.LIVEKIT_API_KEY;
}
if (!apiSecret) {
apiSecret = process.env.LIVEKIT_API_SECRET;
}
if (!apiKey || !apiSecret) {
throw Error("api-key and api-secret must be set");
} else if (typeof document !== "undefined") {
console.error(
"You should not include your API secret in your web client bundle.\n\nYour web client should request a token from your backend server which should then use the API secret to generate a token. See https://docs.livekit.io/client/connect/"
);
}
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.grants = {};
this.identity = options == null ? void 0 : options.identity;
this.ttl = (options == null ? void 0 : options.ttl) || defaultTTL;
if (typeof this.ttl === "number") {
this.ttl = `${this.ttl}s`;
}
if (options == null ? void 0 : options.metadata) {
this.metadata = options.metadata;
}
if (options == null ? void 0 : options.attributes) {
this.attributes = options.attributes;
}
if (options == null ? void 0 : options.name) {
this.name = options.name;
}
}
/**
* Adds a video grant to this token.
* @param grant -
*/
addGrant(grant) {
this.grants.video = { ...this.grants.video ?? {}, ...grant };
}
/**
* Adds an inference grant to this token.
* @param grant -
*/
addInferenceGrant(grant) {
this.grants.inference = { ...this.grants.inference ?? {}, ...grant };
}
/**
* Adds a SIP grant to this token.
* @param grant -
*/
addSIPGrant(grant) {
this.grants.sip = { ...this.grants.sip ?? {}, ...grant };
}
/**
* Adds an observability grant to this token.
* @param grant -
*/
addObservabilityGrant(grant) {
this.grants.observability = { ...this.grants.observability ?? {}, ...grant };
}
get name() {
return this.grants.name;
}
set name(name) {
this.grants.name = name;
}
get metadata() {
return this.grants.metadata;
}
/**
* Set metadata to be passed to the Participant, used only when joining the room
*/
set metadata(md) {
this.grants.metadata = md;
}
get attributes() {
return this.grants.attributes;
}
set attributes(attrs) {
this.grants.attributes = attrs;
}
get kind() {
return this.grants.kind;
}
set kind(kind) {
this.grants.kind = kind;
}
get sha256() {
return this.grants.sha256;
}
set sha256(sha) {
this.grants.sha256 = sha;
}
get roomPreset() {
return this.grants.roomPreset;
}
set roomPreset(preset) {
this.grants.roomPreset = preset;
}
get roomConfig() {
return this.grants.roomConfig;
}
set roomConfig(config) {
this.grants.roomConfig = config;
}
/**
* @returns JWT encoded token
*/
async toJwt() {
var _a;
const secret = new TextEncoder().encode(this.apiSecret);
const jwt = new jose.SignJWT((0, import_grants.claimsToJwtPayload)(this.grants)).setProtectedHeader({ alg: "HS256" }).setIssuer(this.apiKey).setExpirationTime(this.ttl).setNotBefore(/* @__PURE__ */ new Date());
if (this.identity) {
jwt.setSubject(this.identity);
} else if ((_a = this.grants.video) == null ? void 0 : _a.roomJoin) {
throw Error("identity is required for join but not set");
}
return jwt.sign(secret);
}
}
class TokenVerifier {
constructor(apiKey, apiSecret) {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
}
async verify(token, clockTolerance = defaultClockToleranceSeconds) {
const secret = new TextEncoder().encode(this.apiSecret);
const { payload } = await jose.jwtVerify(token, secret, {
issuer: this.apiKey,
clockTolerance
});
if (!payload) {
throw Error("invalid token");
}
return payload;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AccessToken,
TokenVerifier
});
//# sourceMappingURL=AccessToken.cjs.map
File diff suppressed because one or more lines are too long
+90
View File
@@ -0,0 +1,90 @@
import { RoomConfiguration } from '@livekit/protocol';
import { VideoGrant, InferenceGrant, SIPGrant, ObservabilityGrant, ClaimGrants } from './grants.cjs';
import 'jose';
interface AccessTokenOptions {
/**
* amount of time before expiration
* expressed in seconds or a string describing a time span zeit/ms.
* eg: '2 days', '10h', or seconds as numeric value
*/
ttl?: number | string;
/**
* display name for the participant, available as `Participant.name`
*/
name?: string;
/**
* identity of the user, required for room join tokens
*/
identity?: string;
/**
* custom participant metadata
*/
metadata?: string;
/**
* custom participant attributes
*/
attributes?: Record<string, string>;
}
declare class AccessToken {
private apiKey;
private apiSecret;
private grants;
identity?: string;
ttl: number | string;
/**
* Creates a new AccessToken
* @param apiKey - API Key, can be set in env LIVEKIT_API_KEY
* @param apiSecret - Secret, can be set in env LIVEKIT_API_SECRET
*/
constructor(apiKey?: string, apiSecret?: string, options?: AccessTokenOptions);
/**
* Adds a video grant to this token.
* @param grant -
*/
addGrant(grant: VideoGrant): void;
/**
* Adds an inference grant to this token.
* @param grant -
*/
addInferenceGrant(grant: InferenceGrant): void;
/**
* Adds a SIP grant to this token.
* @param grant -
*/
addSIPGrant(grant: SIPGrant): void;
/**
* Adds an observability grant to this token.
* @param grant -
*/
addObservabilityGrant(grant: ObservabilityGrant): void;
get name(): string | undefined;
set name(name: string);
get metadata(): string | undefined;
/**
* Set metadata to be passed to the Participant, used only when joining the room
*/
set metadata(md: string);
get attributes(): Record<string, string> | undefined;
set attributes(attrs: Record<string, string>);
get kind(): string | undefined;
set kind(kind: string);
get sha256(): string | undefined;
set sha256(sha: string | undefined);
get roomPreset(): string | undefined;
set roomPreset(preset: string | undefined);
get roomConfig(): RoomConfiguration | undefined;
set roomConfig(config: RoomConfiguration | undefined);
/**
* @returns JWT encoded token
*/
toJwt(): Promise<string>;
}
declare class TokenVerifier {
private apiKey;
private apiSecret;
constructor(apiKey: string, apiSecret: string);
verify(token: string, clockTolerance?: string | number): Promise<ClaimGrants>;
}
export { AccessToken, type AccessTokenOptions, TokenVerifier };
+90
View File
@@ -0,0 +1,90 @@
import { RoomConfiguration } from '@livekit/protocol';
import { VideoGrant, InferenceGrant, SIPGrant, ObservabilityGrant, ClaimGrants } from './grants.js';
import 'jose';
interface AccessTokenOptions {
/**
* amount of time before expiration
* expressed in seconds or a string describing a time span zeit/ms.
* eg: '2 days', '10h', or seconds as numeric value
*/
ttl?: number | string;
/**
* display name for the participant, available as `Participant.name`
*/
name?: string;
/**
* identity of the user, required for room join tokens
*/
identity?: string;
/**
* custom participant metadata
*/
metadata?: string;
/**
* custom participant attributes
*/
attributes?: Record<string, string>;
}
declare class AccessToken {
private apiKey;
private apiSecret;
private grants;
identity?: string;
ttl: number | string;
/**
* Creates a new AccessToken
* @param apiKey - API Key, can be set in env LIVEKIT_API_KEY
* @param apiSecret - Secret, can be set in env LIVEKIT_API_SECRET
*/
constructor(apiKey?: string, apiSecret?: string, options?: AccessTokenOptions);
/**
* Adds a video grant to this token.
* @param grant -
*/
addGrant(grant: VideoGrant): void;
/**
* Adds an inference grant to this token.
* @param grant -
*/
addInferenceGrant(grant: InferenceGrant): void;
/**
* Adds a SIP grant to this token.
* @param grant -
*/
addSIPGrant(grant: SIPGrant): void;
/**
* Adds an observability grant to this token.
* @param grant -
*/
addObservabilityGrant(grant: ObservabilityGrant): void;
get name(): string | undefined;
set name(name: string);
get metadata(): string | undefined;
/**
* Set metadata to be passed to the Participant, used only when joining the room
*/
set metadata(md: string);
get attributes(): Record<string, string> | undefined;
set attributes(attrs: Record<string, string>);
get kind(): string | undefined;
set kind(kind: string);
get sha256(): string | undefined;
set sha256(sha: string | undefined);
get roomPreset(): string | undefined;
set roomPreset(preset: string | undefined);
get roomConfig(): RoomConfiguration | undefined;
set roomConfig(config: RoomConfiguration | undefined);
/**
* @returns JWT encoded token
*/
toJwt(): Promise<string>;
}
declare class TokenVerifier {
private apiKey;
private apiSecret;
constructor(apiKey: string, apiSecret: string);
verify(token: string, clockTolerance?: string | number): Promise<ClaimGrants>;
}
export { AccessToken, type AccessTokenOptions, TokenVerifier };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"AccessToken.d.ts","sourceRoot":"","sources":["../src/AccessToken.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACX,MAAM,aAAa,CAAC;AAQrB,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEtB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,SAAS,CAAS;IAE1B,OAAO,CAAC,MAAM,CAAc;IAE5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAErB;;;;OAIG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB;IAsC7E;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU;IAI1B;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,cAAc;IAIvC;;;OAGG;IACH,WAAW,CAAC,KAAK,EAAE,QAAQ;IAI3B;;;OAGG;IACH,qBAAqB,CAAC,KAAK,EAAE,kBAAkB;IAI/C,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAEpB;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED;;OAEG;IACH,IAAI,QAAQ,CAAC,EAAE,EAAE,MAAM,EAEtB;IAED,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAEnD;IAED,IAAI,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAE3C;IAED,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAEpB;IAED,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAE/B;IAED,IAAI,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAEjC;IAED,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAEnC;IAED,IAAI,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAExC;IAED,IAAI,UAAU,IAAI,iBAAiB,GAAG,SAAS,CAE9C;IAED,IAAI,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,EAEnD;IAED;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;CAiB/B;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAS;IAEvB,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAKvC,MAAM,CACV,KAAK,EAAE,MAAM,EACb,cAAc,GAAE,MAAM,GAAG,MAAqC,GAC7D,OAAO,CAAC,WAAW,CAAC;CAYxB"}
+152
View File
@@ -0,0 +1,152 @@
import * as jose from "jose";
import { claimsToJwtPayload } from "./grants.js";
const defaultTTL = `6h`;
const defaultClockToleranceSeconds = 10;
class AccessToken {
/**
* Creates a new AccessToken
* @param apiKey - API Key, can be set in env LIVEKIT_API_KEY
* @param apiSecret - Secret, can be set in env LIVEKIT_API_SECRET
*/
constructor(apiKey, apiSecret, options) {
if (!apiKey) {
apiKey = process.env.LIVEKIT_API_KEY;
}
if (!apiSecret) {
apiSecret = process.env.LIVEKIT_API_SECRET;
}
if (!apiKey || !apiSecret) {
throw Error("api-key and api-secret must be set");
} else if (typeof document !== "undefined") {
console.error(
"You should not include your API secret in your web client bundle.\n\nYour web client should request a token from your backend server which should then use the API secret to generate a token. See https://docs.livekit.io/client/connect/"
);
}
this.apiKey = apiKey;
this.apiSecret = apiSecret;
this.grants = {};
this.identity = options == null ? void 0 : options.identity;
this.ttl = (options == null ? void 0 : options.ttl) || defaultTTL;
if (typeof this.ttl === "number") {
this.ttl = `${this.ttl}s`;
}
if (options == null ? void 0 : options.metadata) {
this.metadata = options.metadata;
}
if (options == null ? void 0 : options.attributes) {
this.attributes = options.attributes;
}
if (options == null ? void 0 : options.name) {
this.name = options.name;
}
}
/**
* Adds a video grant to this token.
* @param grant -
*/
addGrant(grant) {
this.grants.video = { ...this.grants.video ?? {}, ...grant };
}
/**
* Adds an inference grant to this token.
* @param grant -
*/
addInferenceGrant(grant) {
this.grants.inference = { ...this.grants.inference ?? {}, ...grant };
}
/**
* Adds a SIP grant to this token.
* @param grant -
*/
addSIPGrant(grant) {
this.grants.sip = { ...this.grants.sip ?? {}, ...grant };
}
/**
* Adds an observability grant to this token.
* @param grant -
*/
addObservabilityGrant(grant) {
this.grants.observability = { ...this.grants.observability ?? {}, ...grant };
}
get name() {
return this.grants.name;
}
set name(name) {
this.grants.name = name;
}
get metadata() {
return this.grants.metadata;
}
/**
* Set metadata to be passed to the Participant, used only when joining the room
*/
set metadata(md) {
this.grants.metadata = md;
}
get attributes() {
return this.grants.attributes;
}
set attributes(attrs) {
this.grants.attributes = attrs;
}
get kind() {
return this.grants.kind;
}
set kind(kind) {
this.grants.kind = kind;
}
get sha256() {
return this.grants.sha256;
}
set sha256(sha) {
this.grants.sha256 = sha;
}
get roomPreset() {
return this.grants.roomPreset;
}
set roomPreset(preset) {
this.grants.roomPreset = preset;
}
get roomConfig() {
return this.grants.roomConfig;
}
set roomConfig(config) {
this.grants.roomConfig = config;
}
/**
* @returns JWT encoded token
*/
async toJwt() {
var _a;
const secret = new TextEncoder().encode(this.apiSecret);
const jwt = new jose.SignJWT(claimsToJwtPayload(this.grants)).setProtectedHeader({ alg: "HS256" }).setIssuer(this.apiKey).setExpirationTime(this.ttl).setNotBefore(/* @__PURE__ */ new Date());
if (this.identity) {
jwt.setSubject(this.identity);
} else if ((_a = this.grants.video) == null ? void 0 : _a.roomJoin) {
throw Error("identity is required for join but not set");
}
return jwt.sign(secret);
}
}
class TokenVerifier {
constructor(apiKey, apiSecret) {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
}
async verify(token, clockTolerance = defaultClockToleranceSeconds) {
const secret = new TextEncoder().encode(this.apiSecret);
const { payload } = await jose.jwtVerify(token, secret, {
issuer: this.apiKey,
clockTolerance
});
if (!payload) {
throw Error("invalid token");
}
return payload;
}
}
export {
AccessToken,
TokenVerifier
};
//# sourceMappingURL=AccessToken.js.map
File diff suppressed because one or more lines are too long
+129
View File
@@ -0,0 +1,129 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var AgentDispatchClient_exports = {};
__export(AgentDispatchClient_exports, {
AgentDispatchClient: () => AgentDispatchClient
});
module.exports = __toCommonJS(AgentDispatchClient_exports);
var import_protocol = require("@livekit/protocol");
var import_ServiceBase = require("./ServiceBase.cjs");
var import_TwirpRPC = require("./TwirpRPC.cjs");
const svc = "AgentDispatchService";
class AgentDispatchClient extends import_ServiceBase.ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new import_TwirpRPC.TwirpRpc(host, import_TwirpRPC.livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* Create an explicit dispatch for an agent to join a room. To use explicit
* dispatch, your agent must be registered with an `agentName`.
* @param roomName - name of the room to dispatch to
* @param agentName - name of the agent to dispatch
* @param options - optional metadata to send along with the dispatch
* @returns the dispatch that was created
*/
async createDispatch(roomName, agentName, options) {
const req = new import_protocol.CreateAgentDispatchRequest({
room: roomName,
agentName,
metadata: options == null ? void 0 : options.metadata,
restartPolicy: options == null ? void 0 : options.restartPolicy,
deployment: options == null ? void 0 : options.deployment
}).toJson();
const data = await this.rpc.request(
svc,
"CreateDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
return import_protocol.AgentDispatch.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Delete an explicit dispatch for an agent in a room.
* @param dispatchId - id of the dispatch to delete
* @param roomName - name of the room the dispatch is for
*/
async deleteDispatch(dispatchId, roomName) {
const req = new import_protocol.DeleteAgentDispatchRequest({
dispatchId,
room: roomName
}).toJson();
await this.rpc.request(
svc,
"DeleteDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
}
/**
* Get an Agent dispatch by ID
* @param dispatchId - id of the dispatch to get
* @param roomName - name of the room the dispatch is for
* @returns the dispatch that was found, or undefined if not found
*/
async getDispatch(dispatchId, roomName) {
const req = new import_protocol.ListAgentDispatchRequest({
dispatchId,
room: roomName
}).toJson();
const data = await this.rpc.request(
svc,
"ListDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
const res = import_protocol.ListAgentDispatchResponse.fromJson(data, { ignoreUnknownFields: true });
if (res.agentDispatches.length === 0) {
return void 0;
}
return res.agentDispatches[0];
}
/**
* List all agent dispatches for a room
* @param roomName - name of the room to list dispatches for
* @returns the list of dispatches
*/
async listDispatch(roomName) {
const req = new import_protocol.ListAgentDispatchRequest({
room: roomName
}).toJson();
const data = await this.rpc.request(
svc,
"ListDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
const res = import_protocol.ListAgentDispatchResponse.fromJson(data, { ignoreUnknownFields: true });
return res.agentDispatches;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AgentDispatchClient
});
//# sourceMappingURL=AgentDispatchClient.cjs.map
File diff suppressed because one or more lines are too long
+59
View File
@@ -0,0 +1,59 @@
import { JobRestartPolicy, AgentDispatch } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.cjs';
import { ServiceBase } from './ServiceBase.cjs';
import './grants.cjs';
import 'jose';
interface CreateDispatchOptions {
/** any custom data to send along with the job.
* note: this is different from room and participant metadata
*/
metadata?: string;
/** controls whether the job should be restarted when it fails (cloud only) */
restartPolicy?: JobRestartPolicy;
/** optional deployment to dispatch to. Leave empty to target the production deployment. */
deployment?: string;
}
/**
* Client to access Agent APIs
*/
declare class AgentDispatchClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* Create an explicit dispatch for an agent to join a room. To use explicit
* dispatch, your agent must be registered with an `agentName`.
* @param roomName - name of the room to dispatch to
* @param agentName - name of the agent to dispatch
* @param options - optional metadata to send along with the dispatch
* @returns the dispatch that was created
*/
createDispatch(roomName: string, agentName: string, options?: CreateDispatchOptions): Promise<AgentDispatch>;
/**
* Delete an explicit dispatch for an agent in a room.
* @param dispatchId - id of the dispatch to delete
* @param roomName - name of the room the dispatch is for
*/
deleteDispatch(dispatchId: string, roomName: string): Promise<void>;
/**
* Get an Agent dispatch by ID
* @param dispatchId - id of the dispatch to get
* @param roomName - name of the room the dispatch is for
* @returns the dispatch that was found, or undefined if not found
*/
getDispatch(dispatchId: string, roomName: string): Promise<AgentDispatch | undefined>;
/**
* List all agent dispatches for a room
* @param roomName - name of the room to list dispatches for
* @returns the list of dispatches
*/
listDispatch(roomName: string): Promise<AgentDispatch[]>;
}
export { AgentDispatchClient };
+59
View File
@@ -0,0 +1,59 @@
import { JobRestartPolicy, AgentDispatch } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.js';
import { ServiceBase } from './ServiceBase.js';
import './grants.js';
import 'jose';
interface CreateDispatchOptions {
/** any custom data to send along with the job.
* note: this is different from room and participant metadata
*/
metadata?: string;
/** controls whether the job should be restarted when it fails (cloud only) */
restartPolicy?: JobRestartPolicy;
/** optional deployment to dispatch to. Leave empty to target the production deployment. */
deployment?: string;
}
/**
* Client to access Agent APIs
*/
declare class AgentDispatchClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* Create an explicit dispatch for an agent to join a room. To use explicit
* dispatch, your agent must be registered with an `agentName`.
* @param roomName - name of the room to dispatch to
* @param agentName - name of the agent to dispatch
* @param options - optional metadata to send along with the dispatch
* @returns the dispatch that was created
*/
createDispatch(roomName: string, agentName: string, options?: CreateDispatchOptions): Promise<AgentDispatch>;
/**
* Delete an explicit dispatch for an agent in a room.
* @param dispatchId - id of the dispatch to delete
* @param roomName - name of the room the dispatch is for
*/
deleteDispatch(dispatchId: string, roomName: string): Promise<void>;
/**
* Get an Agent dispatch by ID
* @param dispatchId - id of the dispatch to get
* @param roomName - name of the room the dispatch is for
* @returns the dispatch that was found, or undefined if not found
*/
getDispatch(dispatchId: string, roomName: string): Promise<AgentDispatch | undefined>;
/**
* List all agent dispatches for a room
* @param roomName - name of the room to list dispatches for
* @returns the list of dispatches
*/
listDispatch(roomName: string): Promise<AgentDispatch[]>;
}
export { AgentDispatchClient };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"AgentDispatchClient.d.ts","sourceRoot":"","sources":["../src/AgentDispatchClient.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,aAAa,EAGb,KAAK,gBAAgB,EAGtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,UAAU,qBAAqB;IAC7B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,gBAAgB,CAAC;IACjC,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,WAAW;IAClD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAE1B;;;;;OAKG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;IAQnF;;;;;;;OAOG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CAAC,aAAa,CAAC;IAiBzB;;;;OAIG;IACG,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAazE;;;;;OAKG;IACG,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAkB3F;;;;OAIG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;CAa/D"}
+111
View File
@@ -0,0 +1,111 @@
import {
AgentDispatch,
CreateAgentDispatchRequest,
DeleteAgentDispatchRequest,
ListAgentDispatchRequest,
ListAgentDispatchResponse
} from "@livekit/protocol";
import { ServiceBase } from "./ServiceBase.js";
import { TwirpRpc, livekitPackage } from "./TwirpRPC.js";
const svc = "AgentDispatchService";
class AgentDispatchClient extends ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new TwirpRpc(host, livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* Create an explicit dispatch for an agent to join a room. To use explicit
* dispatch, your agent must be registered with an `agentName`.
* @param roomName - name of the room to dispatch to
* @param agentName - name of the agent to dispatch
* @param options - optional metadata to send along with the dispatch
* @returns the dispatch that was created
*/
async createDispatch(roomName, agentName, options) {
const req = new CreateAgentDispatchRequest({
room: roomName,
agentName,
metadata: options == null ? void 0 : options.metadata,
restartPolicy: options == null ? void 0 : options.restartPolicy,
deployment: options == null ? void 0 : options.deployment
}).toJson();
const data = await this.rpc.request(
svc,
"CreateDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
return AgentDispatch.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Delete an explicit dispatch for an agent in a room.
* @param dispatchId - id of the dispatch to delete
* @param roomName - name of the room the dispatch is for
*/
async deleteDispatch(dispatchId, roomName) {
const req = new DeleteAgentDispatchRequest({
dispatchId,
room: roomName
}).toJson();
await this.rpc.request(
svc,
"DeleteDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
}
/**
* Get an Agent dispatch by ID
* @param dispatchId - id of the dispatch to get
* @param roomName - name of the room the dispatch is for
* @returns the dispatch that was found, or undefined if not found
*/
async getDispatch(dispatchId, roomName) {
const req = new ListAgentDispatchRequest({
dispatchId,
room: roomName
}).toJson();
const data = await this.rpc.request(
svc,
"ListDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
const res = ListAgentDispatchResponse.fromJson(data, { ignoreUnknownFields: true });
if (res.agentDispatches.length === 0) {
return void 0;
}
return res.agentDispatches[0];
}
/**
* List all agent dispatches for a room
* @param roomName - name of the room to list dispatches for
* @returns the list of dispatches
*/
async listDispatch(roomName) {
const req = new ListAgentDispatchRequest({
room: roomName
}).toJson();
const data = await this.rpc.request(
svc,
"ListDispatch",
req,
await this.authHeader({ roomAdmin: true, room: roomName })
);
const res = ListAgentDispatchResponse.fromJson(data, { ignoreUnknownFields: true });
return res.agentDispatches;
}
}
export {
AgentDispatchClient
};
//# sourceMappingURL=AgentDispatchClient.js.map
File diff suppressed because one or more lines are too long
+17
View File
@@ -0,0 +1,17 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ClientOptions_exports = {};
module.exports = __toCommonJS(ClientOptions_exports);
//# sourceMappingURL=ClientOptions.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/ClientOptions.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Options common to all clients\n */\nexport type ClientOptions = {\n /**\n * Optional timeout, in seconds, for all server requests\n */\n requestTimeout?: number;\n /**\n * Whether to fail over to alternative regions on retryable errors (LiveKit\n * Cloud hosts only). Defaults to true; set to false to disable.\n */\n failover?: boolean;\n /**\n * A pre-signed access token, sent verbatim as the Authorization header on\n * every request instead of signing one per call from an API key and secret.\n * The token must already carry the grants for the calls it's used with; since\n * it needs no secret, the client can run client-side.\n */\n token?: string;\n};\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
+23
View File
@@ -0,0 +1,23 @@
/**
* Options common to all clients
*/
type ClientOptions = {
/**
* Optional timeout, in seconds, for all server requests
*/
requestTimeout?: number;
/**
* Whether to fail over to alternative regions on retryable errors (LiveKit
* Cloud hosts only). Defaults to true; set to false to disable.
*/
failover?: boolean;
/**
* A pre-signed access token, sent verbatim as the Authorization header on
* every request instead of signing one per call from an API key and secret.
* The token must already carry the grants for the calls it's used with; since
* it needs no secret, the client can run client-side.
*/
token?: string;
};
export type { ClientOptions };
+23
View File
@@ -0,0 +1,23 @@
/**
* Options common to all clients
*/
type ClientOptions = {
/**
* Optional timeout, in seconds, for all server requests
*/
requestTimeout?: number;
/**
* Whether to fail over to alternative regions on retryable errors (LiveKit
* Cloud hosts only). Defaults to true; set to false to disable.
*/
failover?: boolean;
/**
* A pre-signed access token, sent verbatim as the Authorization header on
* every request instead of signing one per call from an API key and secret.
* The token must already carry the grants for the calls it's used with; since
* it needs no secret, the client can run client-side.
*/
token?: string;
};
export type { ClientOptions };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"ClientOptions.d.ts","sourceRoot":"","sources":["../src/ClientOptions.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC"}
+1
View File
@@ -0,0 +1 @@
//# sourceMappingURL=ClientOptions.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
+194
View File
@@ -0,0 +1,194 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ConnectorClient_exports = {};
__export(ConnectorClient_exports, {
ConnectorClient: () => ConnectorClient
});
module.exports = __toCommonJS(ConnectorClient_exports);
var import_protobuf = require("@bufbuild/protobuf");
var import_protocol = require("@livekit/protocol");
var import_ServiceBase = require("./ServiceBase.cjs");
var import_TwirpRPC = require("./TwirpRPC.cjs");
var import_dialTimeout = require("./dialTimeout.cjs");
const svc = "Connector";
class ConnectorClient extends import_ServiceBase.ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new import_TwirpRPC.TwirpRpc(host, import_TwirpRPC.livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* Initiate an outbound WhatsApp call
*
* @param options - WhatsApp call options
* @returns Promise containing the WhatsApp call ID and room name
*/
async dialWhatsAppCall(options) {
const whatsappBizOpaqueCallbackData = options.whatsappBizOpaqueCallbackData || "";
const roomName = options.roomName || "";
const participantIdentity = options.participantIdentity || "";
const participantName = options.participantName || "";
const participantMetadata = options.participantMetadata || "";
const destinationCountry = options.destinationCountry || "";
const req = new import_protocol.DialWhatsAppCallRequest({
whatsappPhoneNumberId: options.whatsappPhoneNumberId,
whatsappToPhoneNumber: options.whatsappToPhoneNumber,
whatsappApiKey: options.whatsappApiKey,
whatsappCloudApiVersion: options.whatsappCloudApiVersion,
whatsappBizOpaqueCallbackData,
roomName,
agents: options.agents,
participantIdentity,
participantName,
participantMetadata,
participantAttributes: options.participantAttributes,
destinationCountry,
ringingTimeout: options.ringingTimeout ? new import_protobuf.Duration({ seconds: BigInt(options.ringingTimeout) }) : void 0
}).toJson();
const data = await this.rpc.request(
svc,
"DialWhatsAppCall",
req,
await this.authHeader({ roomCreate: true })
);
return import_protocol.DialWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Accept an inbound WhatsApp call
*
* @param options - WhatsApp call accept options
* @returns Promise containing the room name
*/
async acceptWhatsAppCall(options) {
const whatsappBizOpaqueCallbackData = options.whatsappBizOpaqueCallbackData || "";
const roomName = options.roomName || "";
const participantIdentity = options.participantIdentity || "";
const participantName = options.participantName || "";
const participantMetadata = options.participantMetadata || "";
const destinationCountry = options.destinationCountry || "";
const req = new import_protocol.AcceptWhatsAppCallRequest({
whatsappPhoneNumberId: options.whatsappPhoneNumberId,
whatsappApiKey: options.whatsappApiKey,
whatsappCloudApiVersion: options.whatsappCloudApiVersion,
whatsappCallId: options.whatsappCallId,
whatsappBizOpaqueCallbackData,
sdp: options.sdp,
roomName,
agents: options.agents,
participantIdentity,
participantName,
participantMetadata,
participantAttributes: options.participantAttributes,
destinationCountry,
waitUntilAnswered: options.waitUntilAnswered
}).toJson();
const timeout = options.waitUntilAnswered ? options.timeout ?? import_dialTimeout.DEFAULT_RINGING_TIMEOUT_SECONDS : options.timeout;
const data = await this.rpc.request(
svc,
"AcceptWhatsAppCall",
req,
await this.authHeader({ roomCreate: true }),
timeout
);
return import_protocol.AcceptWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Connect an established WhatsApp call (used for business-initiated calls)
*
* @param whatsappCallId - Call ID sent by Meta
* @param sdp - Session description from Meta
*/
async connectWhatsAppCall(whatsappCallId, sdp) {
const req = new import_protocol.ConnectWhatsAppCallRequest({
whatsappCallId,
sdp
}).toJson();
const data = await this.rpc.request(
svc,
"ConnectWhatsAppCall",
req,
await this.authHeader({ roomCreate: true })
);
return import_protocol.ConnectWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Disconnect an active WhatsApp call
*
* @param whatsappCallId - Call ID sent by Meta
* @param whatsappApiKey - The API key of the business that is disconnecting the call.
* Required when `disconnectReason` is BUSINESS_INITIATED, optional for USER_INITIATED.
* @param disconnectReason - Optional reason for disconnecting the call. Defaults to BUSINESS_INITIATED.
*/
async disconnectWhatsAppCall(whatsappCallId, whatsappApiKey, disconnectReason) {
const req = new import_protocol.DisconnectWhatsAppCallRequest({
whatsappCallId,
whatsappApiKey,
disconnectReason
}).toJson();
const data = await this.rpc.request(
svc,
"DisconnectWhatsAppCall",
req,
await this.authHeader({ roomCreate: true })
);
return import_protocol.DisconnectWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Connect a Twilio call to a LiveKit room
*
* @param options - Twilio call connection options
* @returns Promise containing the WebSocket connect URL for Twilio media stream
*/
async connectTwilioCall(options) {
const participantIdentity = options.participantIdentity || "";
const participantName = options.participantName || "";
const participantMetadata = options.participantMetadata || "";
const destinationCountry = options.destinationCountry || "";
const req = new import_protocol.ConnectTwilioCallRequest({
twilioCallDirection: options.twilioCallDirection,
roomName: options.roomName,
agents: options.agents,
participantIdentity,
participantName,
participantMetadata,
participantAttributes: options.participantAttributes,
destinationCountry
}).toJson();
const data = await this.rpc.request(
svc,
"ConnectTwilioCall",
req,
await this.authHeader({ roomCreate: true })
);
return import_protocol.ConnectTwilioCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ConnectorClient
});
//# sourceMappingURL=ConnectorClient.cjs.map
File diff suppressed because one or more lines are too long
+145
View File
@@ -0,0 +1,145 @@
import { SessionDescription, RoomAgentDispatch, ConnectTwilioCallRequest_TwilioCallDirection, DialWhatsAppCallResponse, AcceptWhatsAppCallResponse, ConnectWhatsAppCallResponse, DisconnectWhatsAppCallRequest_DisconnectReason, DisconnectWhatsAppCallResponse, ConnectTwilioCallResponse } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.cjs';
import { ServiceBase } from './ServiceBase.cjs';
import './grants.cjs';
import 'jose';
interface DialWhatsAppCallOptions {
/** Required - The identifier of the WhatsApp phone number that is initiating the call */
whatsappPhoneNumberId: string;
/** Required - The number of the user that is supposed to receive the call */
whatsappToPhoneNumber: string;
/** Required - The API key of the business that is initiating the call */
whatsappApiKey: string;
/** Required - WhatsApp Cloud API version, eg: 23.0, 24.0, etc. */
whatsappCloudApiVersion: string;
/** Optional - An arbitrary string you can pass in that is useful for tracking and logging purposes */
whatsappBizOpaqueCallbackData?: string;
/** Optional - What LiveKit room should this participant be connected to */
roomName?: string;
/** Optional - Agents to dispatch the call to */
agents?: RoomAgentDispatch[];
/** Optional - Identity of the participant in LiveKit room */
participantIdentity?: string;
/** Optional - Name of the participant in LiveKit room */
participantName?: string;
/** Optional - User-defined metadata. Will be attached to a created Participant in the room. */
participantMetadata?: string;
/** Optional - User-defined attributes. Will be attached to a created Participant in the room. */
participantAttributes?: {
[key: string]: string;
};
/** Optional - Country where the call terminates as ISO 3166-1 alpha-2 */
destinationCountry?: string;
/** Optional - Max time in seconds for the callee to answer the call */
ringingTimeout?: number;
}
interface AcceptWhatsAppCallOptions {
/** Required - The identifier of the WhatsApp phone number that is connecting the call */
whatsappPhoneNumberId: string;
/** Required - The API key of the business that is connecting the call */
whatsappApiKey: string;
/** Required - WhatsApp Cloud API version, eg: 23.0, 24.0, etc. */
whatsappCloudApiVersion: string;
/** Required - Call ID sent by Meta */
whatsappCallId: string;
/** Optional - An arbitrary string you can pass in that is useful for tracking and logging purposes */
whatsappBizOpaqueCallbackData?: string;
/** Required - The call accept webhook comes with SDP from Meta */
sdp: SessionDescription;
/** Optional - What LiveKit room should this participant be connected to */
roomName?: string;
/** Optional - Agents to dispatch the call to */
agents?: RoomAgentDispatch[];
/** Optional - Identity of the participant in LiveKit room */
participantIdentity?: string;
/** Optional - Name of the participant in LiveKit room */
participantName?: string;
/** Optional - User-defined metadata. Will be attached to a created Participant in the room. */
participantMetadata?: string;
/** Optional - User-defined attributes. Will be attached to a created Participant in the room. */
participantAttributes?: {
[key: string]: string;
};
/** Optional - Country where the call terminates as ISO 3166-1 alpha-2 */
destinationCountry?: string;
/** Optional - Wait until the inbound party joins before returning. */
waitUntilAnswered?: boolean;
/**
* Optional - Request timeout in seconds. When `waitUntilAnswered` is set it
* defaults to the standard ring window; otherwise the client default applies.
*/
timeout?: number;
}
interface ConnectTwilioCallOptions {
/** The direction of the call */
twilioCallDirection: ConnectTwilioCallRequest_TwilioCallDirection;
/** What LiveKit room should this call be connected to */
roomName: string;
/** Optional agents to dispatch the call to */
agents?: RoomAgentDispatch[];
/** Optional identity of the participant in LiveKit room */
participantIdentity?: string;
/** Optional name of the participant in LiveKit room */
participantName?: string;
/** Optional user-defined metadata. Will be attached to a created Participant in the room. */
participantMetadata?: string;
/** Optional user-defined attributes. Will be attached to a created Participant in the room. */
participantAttributes?: {
[key: string]: string;
};
/** Country where the call terminates as ISO 3166-1 alpha-2 */
destinationCountry?: string;
}
/**
* Client to access Connector APIs for WhatsApp and Twilio integrations
*/
declare class ConnectorClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* Initiate an outbound WhatsApp call
*
* @param options - WhatsApp call options
* @returns Promise containing the WhatsApp call ID and room name
*/
dialWhatsAppCall(options: DialWhatsAppCallOptions): Promise<DialWhatsAppCallResponse>;
/**
* Accept an inbound WhatsApp call
*
* @param options - WhatsApp call accept options
* @returns Promise containing the room name
*/
acceptWhatsAppCall(options: AcceptWhatsAppCallOptions): Promise<AcceptWhatsAppCallResponse>;
/**
* Connect an established WhatsApp call (used for business-initiated calls)
*
* @param whatsappCallId - Call ID sent by Meta
* @param sdp - Session description from Meta
*/
connectWhatsAppCall(whatsappCallId: string, sdp: SessionDescription): Promise<ConnectWhatsAppCallResponse>;
/**
* Disconnect an active WhatsApp call
*
* @param whatsappCallId - Call ID sent by Meta
* @param whatsappApiKey - The API key of the business that is disconnecting the call.
* Required when `disconnectReason` is BUSINESS_INITIATED, optional for USER_INITIATED.
* @param disconnectReason - Optional reason for disconnecting the call. Defaults to BUSINESS_INITIATED.
*/
disconnectWhatsAppCall(whatsappCallId: string, whatsappApiKey: string, disconnectReason?: DisconnectWhatsAppCallRequest_DisconnectReason): Promise<DisconnectWhatsAppCallResponse>;
/**
* Connect a Twilio call to a LiveKit room
*
* @param options - Twilio call connection options
* @returns Promise containing the WebSocket connect URL for Twilio media stream
*/
connectTwilioCall(options: ConnectTwilioCallOptions): Promise<ConnectTwilioCallResponse>;
}
export { type AcceptWhatsAppCallOptions, type ConnectTwilioCallOptions, ConnectorClient, type DialWhatsAppCallOptions };
+145
View File
@@ -0,0 +1,145 @@
import { SessionDescription, RoomAgentDispatch, ConnectTwilioCallRequest_TwilioCallDirection, DialWhatsAppCallResponse, AcceptWhatsAppCallResponse, ConnectWhatsAppCallResponse, DisconnectWhatsAppCallRequest_DisconnectReason, DisconnectWhatsAppCallResponse, ConnectTwilioCallResponse } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.js';
import { ServiceBase } from './ServiceBase.js';
import './grants.js';
import 'jose';
interface DialWhatsAppCallOptions {
/** Required - The identifier of the WhatsApp phone number that is initiating the call */
whatsappPhoneNumberId: string;
/** Required - The number of the user that is supposed to receive the call */
whatsappToPhoneNumber: string;
/** Required - The API key of the business that is initiating the call */
whatsappApiKey: string;
/** Required - WhatsApp Cloud API version, eg: 23.0, 24.0, etc. */
whatsappCloudApiVersion: string;
/** Optional - An arbitrary string you can pass in that is useful for tracking and logging purposes */
whatsappBizOpaqueCallbackData?: string;
/** Optional - What LiveKit room should this participant be connected to */
roomName?: string;
/** Optional - Agents to dispatch the call to */
agents?: RoomAgentDispatch[];
/** Optional - Identity of the participant in LiveKit room */
participantIdentity?: string;
/** Optional - Name of the participant in LiveKit room */
participantName?: string;
/** Optional - User-defined metadata. Will be attached to a created Participant in the room. */
participantMetadata?: string;
/** Optional - User-defined attributes. Will be attached to a created Participant in the room. */
participantAttributes?: {
[key: string]: string;
};
/** Optional - Country where the call terminates as ISO 3166-1 alpha-2 */
destinationCountry?: string;
/** Optional - Max time in seconds for the callee to answer the call */
ringingTimeout?: number;
}
interface AcceptWhatsAppCallOptions {
/** Required - The identifier of the WhatsApp phone number that is connecting the call */
whatsappPhoneNumberId: string;
/** Required - The API key of the business that is connecting the call */
whatsappApiKey: string;
/** Required - WhatsApp Cloud API version, eg: 23.0, 24.0, etc. */
whatsappCloudApiVersion: string;
/** Required - Call ID sent by Meta */
whatsappCallId: string;
/** Optional - An arbitrary string you can pass in that is useful for tracking and logging purposes */
whatsappBizOpaqueCallbackData?: string;
/** Required - The call accept webhook comes with SDP from Meta */
sdp: SessionDescription;
/** Optional - What LiveKit room should this participant be connected to */
roomName?: string;
/** Optional - Agents to dispatch the call to */
agents?: RoomAgentDispatch[];
/** Optional - Identity of the participant in LiveKit room */
participantIdentity?: string;
/** Optional - Name of the participant in LiveKit room */
participantName?: string;
/** Optional - User-defined metadata. Will be attached to a created Participant in the room. */
participantMetadata?: string;
/** Optional - User-defined attributes. Will be attached to a created Participant in the room. */
participantAttributes?: {
[key: string]: string;
};
/** Optional - Country where the call terminates as ISO 3166-1 alpha-2 */
destinationCountry?: string;
/** Optional - Wait until the inbound party joins before returning. */
waitUntilAnswered?: boolean;
/**
* Optional - Request timeout in seconds. When `waitUntilAnswered` is set it
* defaults to the standard ring window; otherwise the client default applies.
*/
timeout?: number;
}
interface ConnectTwilioCallOptions {
/** The direction of the call */
twilioCallDirection: ConnectTwilioCallRequest_TwilioCallDirection;
/** What LiveKit room should this call be connected to */
roomName: string;
/** Optional agents to dispatch the call to */
agents?: RoomAgentDispatch[];
/** Optional identity of the participant in LiveKit room */
participantIdentity?: string;
/** Optional name of the participant in LiveKit room */
participantName?: string;
/** Optional user-defined metadata. Will be attached to a created Participant in the room. */
participantMetadata?: string;
/** Optional user-defined attributes. Will be attached to a created Participant in the room. */
participantAttributes?: {
[key: string]: string;
};
/** Country where the call terminates as ISO 3166-1 alpha-2 */
destinationCountry?: string;
}
/**
* Client to access Connector APIs for WhatsApp and Twilio integrations
*/
declare class ConnectorClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* Initiate an outbound WhatsApp call
*
* @param options - WhatsApp call options
* @returns Promise containing the WhatsApp call ID and room name
*/
dialWhatsAppCall(options: DialWhatsAppCallOptions): Promise<DialWhatsAppCallResponse>;
/**
* Accept an inbound WhatsApp call
*
* @param options - WhatsApp call accept options
* @returns Promise containing the room name
*/
acceptWhatsAppCall(options: AcceptWhatsAppCallOptions): Promise<AcceptWhatsAppCallResponse>;
/**
* Connect an established WhatsApp call (used for business-initiated calls)
*
* @param whatsappCallId - Call ID sent by Meta
* @param sdp - Session description from Meta
*/
connectWhatsAppCall(whatsappCallId: string, sdp: SessionDescription): Promise<ConnectWhatsAppCallResponse>;
/**
* Disconnect an active WhatsApp call
*
* @param whatsappCallId - Call ID sent by Meta
* @param whatsappApiKey - The API key of the business that is disconnecting the call.
* Required when `disconnectReason` is BUSINESS_INITIATED, optional for USER_INITIATED.
* @param disconnectReason - Optional reason for disconnecting the call. Defaults to BUSINESS_INITIATED.
*/
disconnectWhatsAppCall(whatsappCallId: string, whatsappApiKey: string, disconnectReason?: DisconnectWhatsAppCallRequest_DisconnectReason): Promise<DisconnectWhatsAppCallResponse>;
/**
* Connect a Twilio call to a LiveKit room
*
* @param options - Twilio call connection options
* @returns Promise containing the WebSocket connect URL for Twilio media stream
*/
connectTwilioCall(options: ConnectTwilioCallOptions): Promise<ConnectTwilioCallResponse>;
}
export { type AcceptWhatsAppCallOptions, type ConnectTwilioCallOptions, ConnectorClient, type DialWhatsAppCallOptions };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"ConnectorClient.d.ts","sourceRoot":"","sources":["../src/ConnectorClient.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,4CAA4C,EAC5C,8CAA8C,EAC9C,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAEL,0BAA0B,EAE1B,yBAAyB,EAEzB,2BAA2B,EAE3B,wBAAwB,EAExB,8BAA8B,EAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAO/C,MAAM,WAAW,uBAAuB;IACtC,yFAAyF;IACzF,qBAAqB,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,qBAAqB,EAAE,MAAM,CAAC;IAC9B,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,uBAAuB,EAAE,MAAM,CAAC;IAChC,sGAAsG;IACtG,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,6DAA6D;IAC7D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iGAAiG;IACjG,qBAAqB,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAClD,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,yFAAyF;IACzF,qBAAqB,EAAE,MAAM,CAAC;IAC9B,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC;IACvB,kEAAkE;IAClE,uBAAuB,EAAE,MAAM,CAAC;IAChC,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,sGAAsG;IACtG,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,kEAAkE;IAClE,GAAG,EAAE,kBAAkB,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,6DAA6D;IAC7D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,iGAAiG;IACjG,qBAAqB,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAClD,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,sEAAsE;IACtE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,wBAAwB;IACvC,gCAAgC;IAChC,mBAAmB,EAAE,4CAA4C,CAAC;IAClE,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,2DAA2D;IAC3D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uDAAuD;IACvD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,6FAA6F;IAC7F,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,+FAA+F;IAC/F,qBAAqB,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAClD,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAE1B;;;;;OAKG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;IAQnF;;;;;OAKG;IACG,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAmC3F;;;;;OAKG;IACG,kBAAkB,CACtB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,0BAA0B,CAAC;IA0CtC;;;;;OAKG;IACG,mBAAmB,CACvB,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,kBAAkB,GACtB,OAAO,CAAC,2BAA2B,CAAC;IAevC;;;;;;;OAOG;IACG,sBAAsB,CAC1B,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,gBAAgB,CAAC,EAAE,8CAA8C,GAChE,OAAO,CAAC,8BAA8B,CAAC;IAgB1C;;;;;OAKG;IACG,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;CAyB/F"}
+181
View File
@@ -0,0 +1,181 @@
import { Duration } from "@bufbuild/protobuf";
import {
AcceptWhatsAppCallRequest,
AcceptWhatsAppCallResponse,
ConnectTwilioCallRequest,
ConnectTwilioCallResponse,
ConnectWhatsAppCallRequest,
ConnectWhatsAppCallResponse,
DialWhatsAppCallRequest,
DialWhatsAppCallResponse,
DisconnectWhatsAppCallRequest,
DisconnectWhatsAppCallResponse
} from "@livekit/protocol";
import { ServiceBase } from "./ServiceBase.js";
import { TwirpRpc, livekitPackage } from "./TwirpRPC.js";
import { DEFAULT_RINGING_TIMEOUT_SECONDS } from "./dialTimeout.js";
const svc = "Connector";
class ConnectorClient extends ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new TwirpRpc(host, livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* Initiate an outbound WhatsApp call
*
* @param options - WhatsApp call options
* @returns Promise containing the WhatsApp call ID and room name
*/
async dialWhatsAppCall(options) {
const whatsappBizOpaqueCallbackData = options.whatsappBizOpaqueCallbackData || "";
const roomName = options.roomName || "";
const participantIdentity = options.participantIdentity || "";
const participantName = options.participantName || "";
const participantMetadata = options.participantMetadata || "";
const destinationCountry = options.destinationCountry || "";
const req = new DialWhatsAppCallRequest({
whatsappPhoneNumberId: options.whatsappPhoneNumberId,
whatsappToPhoneNumber: options.whatsappToPhoneNumber,
whatsappApiKey: options.whatsappApiKey,
whatsappCloudApiVersion: options.whatsappCloudApiVersion,
whatsappBizOpaqueCallbackData,
roomName,
agents: options.agents,
participantIdentity,
participantName,
participantMetadata,
participantAttributes: options.participantAttributes,
destinationCountry,
ringingTimeout: options.ringingTimeout ? new Duration({ seconds: BigInt(options.ringingTimeout) }) : void 0
}).toJson();
const data = await this.rpc.request(
svc,
"DialWhatsAppCall",
req,
await this.authHeader({ roomCreate: true })
);
return DialWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Accept an inbound WhatsApp call
*
* @param options - WhatsApp call accept options
* @returns Promise containing the room name
*/
async acceptWhatsAppCall(options) {
const whatsappBizOpaqueCallbackData = options.whatsappBizOpaqueCallbackData || "";
const roomName = options.roomName || "";
const participantIdentity = options.participantIdentity || "";
const participantName = options.participantName || "";
const participantMetadata = options.participantMetadata || "";
const destinationCountry = options.destinationCountry || "";
const req = new AcceptWhatsAppCallRequest({
whatsappPhoneNumberId: options.whatsappPhoneNumberId,
whatsappApiKey: options.whatsappApiKey,
whatsappCloudApiVersion: options.whatsappCloudApiVersion,
whatsappCallId: options.whatsappCallId,
whatsappBizOpaqueCallbackData,
sdp: options.sdp,
roomName,
agents: options.agents,
participantIdentity,
participantName,
participantMetadata,
participantAttributes: options.participantAttributes,
destinationCountry,
waitUntilAnswered: options.waitUntilAnswered
}).toJson();
const timeout = options.waitUntilAnswered ? options.timeout ?? DEFAULT_RINGING_TIMEOUT_SECONDS : options.timeout;
const data = await this.rpc.request(
svc,
"AcceptWhatsAppCall",
req,
await this.authHeader({ roomCreate: true }),
timeout
);
return AcceptWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Connect an established WhatsApp call (used for business-initiated calls)
*
* @param whatsappCallId - Call ID sent by Meta
* @param sdp - Session description from Meta
*/
async connectWhatsAppCall(whatsappCallId, sdp) {
const req = new ConnectWhatsAppCallRequest({
whatsappCallId,
sdp
}).toJson();
const data = await this.rpc.request(
svc,
"ConnectWhatsAppCall",
req,
await this.authHeader({ roomCreate: true })
);
return ConnectWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Disconnect an active WhatsApp call
*
* @param whatsappCallId - Call ID sent by Meta
* @param whatsappApiKey - The API key of the business that is disconnecting the call.
* Required when `disconnectReason` is BUSINESS_INITIATED, optional for USER_INITIATED.
* @param disconnectReason - Optional reason for disconnecting the call. Defaults to BUSINESS_INITIATED.
*/
async disconnectWhatsAppCall(whatsappCallId, whatsappApiKey, disconnectReason) {
const req = new DisconnectWhatsAppCallRequest({
whatsappCallId,
whatsappApiKey,
disconnectReason
}).toJson();
const data = await this.rpc.request(
svc,
"DisconnectWhatsAppCall",
req,
await this.authHeader({ roomCreate: true })
);
return DisconnectWhatsAppCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Connect a Twilio call to a LiveKit room
*
* @param options - Twilio call connection options
* @returns Promise containing the WebSocket connect URL for Twilio media stream
*/
async connectTwilioCall(options) {
const participantIdentity = options.participantIdentity || "";
const participantName = options.participantName || "";
const participantMetadata = options.participantMetadata || "";
const destinationCountry = options.destinationCountry || "";
const req = new ConnectTwilioCallRequest({
twilioCallDirection: options.twilioCallDirection,
roomName: options.roomName,
agents: options.agents,
participantIdentity,
participantName,
participantMetadata,
participantAttributes: options.participantAttributes,
destinationCountry
}).toJson();
const data = await this.rpc.request(
svc,
"ConnectTwilioCall",
req,
await this.authHeader({ roomCreate: true })
);
return ConnectTwilioCallResponse.fromJson(data, { ignoreUnknownFields: true });
}
}
export {
ConnectorClient
};
//# sourceMappingURL=ConnectorClient.js.map
File diff suppressed because one or more lines are too long
+390
View File
@@ -0,0 +1,390 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var EgressClient_exports = {};
__export(EgressClient_exports, {
EgressClient: () => EgressClient
});
module.exports = __toCommonJS(EgressClient_exports);
var import_protocol = require("@livekit/protocol");
var import_ServiceBase = require("./ServiceBase.cjs");
var import_TwirpRPC = require("./TwirpRPC.cjs");
const svc = "Egress";
class EgressClient extends import_ServiceBase.ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new import_TwirpRPC.TwirpRpc(host, import_TwirpRPC.livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
async startRoomCompositeEgress(roomName, output, optsOrLayout, options, audioOnly, videoOnly, customBaseUrl, audioMixing) {
let layout;
let webhooks;
if (optsOrLayout !== void 0) {
if (typeof optsOrLayout === "string") {
layout = optsOrLayout;
} else {
const opts = optsOrLayout;
layout = opts.layout;
options = opts.encodingOptions;
audioOnly = opts.audioOnly;
videoOnly = opts.videoOnly;
customBaseUrl = opts.customBaseUrl;
audioMixing = opts.audioMixing;
webhooks = opts.webhooks;
}
}
layout ??= "";
audioOnly ??= false;
videoOnly ??= false;
customBaseUrl ??= "";
audioMixing ??= import_protocol.AudioMixing.DEFAULT_MIXING;
const {
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
} = this.getOutputParams(output, options);
const req = new import_protocol.RoomCompositeEgressRequest({
roomName,
layout,
audioOnly,
audioMixing,
videoOnly,
customBaseUrl,
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartRoomCompositeEgress",
req,
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param url - url
* @param output - file or stream output
* @param opts - WebOptions
*/
async startWebEgress(url, output, opts) {
const audioOnly = (opts == null ? void 0 : opts.audioOnly) || false;
const videoOnly = (opts == null ? void 0 : opts.videoOnly) || false;
const awaitStartSignal = (opts == null ? void 0 : opts.awaitStartSignal) || false;
const webhooks = (opts == null ? void 0 : opts.webhooks) || [];
const {
output: legacyOutput,
options,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
} = this.getOutputParams(output, opts == null ? void 0 : opts.encodingOptions);
const req = new import_protocol.WebEgressRequest({
url,
audioOnly,
videoOnly,
awaitStartSignal,
output: legacyOutput,
options,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartWebEgress",
req,
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Export a participant's audio and video tracks,
*
* @param roomName - room name
* @param output - one or more outputs
* @param opts - ParticipantEgressOptions
*/
async startParticipantEgress(roomName, identity, output, opts) {
const webhooks = (opts == null ? void 0 : opts.webhooks) || [];
const { options, fileOutputs, streamOutputs, segmentOutputs, imageOutputs } = this.getOutputParams(output, opts == null ? void 0 : opts.encodingOptions);
const req = new import_protocol.ParticipantEgressRequest({
roomName,
identity,
screenShare: (opts == null ? void 0 : opts.screenShare) ?? false,
options,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartParticipantEgress",
req,
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
async startTrackCompositeEgress(roomName, output, optsOrAudioTrackId, videoTrackId, options) {
let audioTrackId;
let webhooks;
if (optsOrAudioTrackId !== void 0) {
if (typeof optsOrAudioTrackId === "string") {
audioTrackId = optsOrAudioTrackId;
} else {
const opts = optsOrAudioTrackId;
audioTrackId = opts.audioTrackId;
videoTrackId = opts.videoTrackId;
options = opts.encodingOptions;
webhooks = opts.webhooks;
}
}
audioTrackId ??= "";
videoTrackId ??= "";
const {
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
} = this.getOutputParams(output, options);
const req = new import_protocol.TrackCompositeEgressRequest({
roomName,
audioTrackId,
videoTrackId,
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartTrackCompositeEgress",
req,
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isEncodedOutputs(output) {
return output.file !== void 0 || output.stream !== void 0 || output.segments !== void 0 || output.images !== void 0;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isEncodedFileOutput(output) {
return output.filepath !== void 0 || output.fileType !== void 0;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isSegmentedFileOutput(output) {
return output.filenamePrefix !== void 0 || output.playlistName !== void 0 || output.filenameSuffix !== void 0;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isStreamOutput(output) {
return output.protocol !== void 0 || output.urls !== void 0;
}
getOutputParams(output, opts) {
let file;
let fileOutputs;
let stream;
let streamOutputs;
let segments;
let segmentOutputs;
let imageOutputs;
if (this.isEncodedOutputs(output)) {
if (output.file !== void 0) {
fileOutputs = [output.file];
}
if (output.stream !== void 0) {
streamOutputs = [output.stream];
}
if (output.segments !== void 0) {
segmentOutputs = [output.segments];
}
if (output.images !== void 0) {
imageOutputs = [output.images];
}
} else if (this.isEncodedFileOutput(output)) {
file = output;
fileOutputs = [file];
} else if (this.isSegmentedFileOutput(output)) {
segments = output;
segmentOutputs = [segments];
} else if (this.isStreamOutput(output)) {
stream = output;
streamOutputs = [stream];
}
let legacyOutput;
if (file) {
legacyOutput = {
case: "file",
value: file
};
} else if (stream) {
legacyOutput = {
case: "stream",
value: stream
};
} else if (segments) {
legacyOutput = {
case: "segments",
value: segments
};
}
let egressOptions;
if (opts) {
if (typeof opts === "number") {
egressOptions = {
case: "preset",
value: opts
};
} else {
egressOptions = {
case: "advanced",
value: opts
};
}
}
return {
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
};
}
/**
* @param roomName - room name
* @param output - file or websocket output
* @param trackId - track Id
*/
async startTrackEgress(roomName, output, trackId, webhooks) {
let legacyOutput;
if (typeof output === "string") {
legacyOutput = {
case: "websocketUrl",
value: output
};
} else {
legacyOutput = {
case: "file",
value: output
};
}
const req = new import_protocol.TrackEgressRequest({
roomName,
trackId,
output: legacyOutput,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartTrackEgress",
req,
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param egressId -
* @param layout -
*/
async updateLayout(egressId, layout) {
const data = await this.rpc.request(
svc,
"UpdateLayout",
new import_protocol.UpdateLayoutRequest({ egressId, layout }).toJson(),
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param egressId -
* @param addOutputUrls -
* @param removeOutputUrls -
*/
async updateStream(egressId, addOutputUrls, removeOutputUrls) {
addOutputUrls ??= [];
removeOutputUrls ??= [];
const data = await this.rpc.request(
svc,
"UpdateStream",
new import_protocol.UpdateStreamRequest({ egressId, addOutputUrls, removeOutputUrls }).toJson(),
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param roomName - list egress for one room only
*/
async listEgress(options) {
let req = {};
if (typeof options === "string") {
req.roomName = options;
} else if (options !== void 0) {
req = options;
}
const data = await this.rpc.request(
svc,
"ListEgress",
new import_protocol.ListEgressRequest(req).toJson(),
await this.authHeader({ roomRecord: true })
);
return import_protocol.ListEgressResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* @param egressId -
*/
async stopEgress(egressId) {
const data = await this.rpc.request(
svc,
"StopEgress",
new import_protocol.StopEgressRequest({ egressId }).toJson(),
await this.authHeader({ roomRecord: true })
);
return import_protocol.EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
EgressClient
});
//# sourceMappingURL=EgressClient.cjs.map
File diff suppressed because one or more lines are too long
+180
View File
@@ -0,0 +1,180 @@
import { WebhookConfig, EncodedFileOutput, StreamOutput, SegmentedFileOutput, ImageOutput, EncodingOptionsPreset, EncodingOptions, AudioMixing, EgressInfo, DirectFileOutput } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.cjs';
import { ServiceBase } from './ServiceBase.cjs';
import './grants.cjs';
import 'jose';
interface BaseOptions {
/**
* webhooks to call for this request, optional.
*/
webhooks?: WebhookConfig[];
}
interface RoomCompositeOptions extends BaseOptions {
/**
* egress layout. optional
*/
layout?: string;
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
/**
* record audio only. optional
*/
audioOnly?: boolean;
/**
* record video only. optional
*/
videoOnly?: boolean;
/**
* custom template url. optional
*/
customBaseUrl?: string;
/**
* audio mixing options. optional
*/
audioMixing?: AudioMixing;
}
interface WebOptions extends BaseOptions {
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
/**
* record audio only. optional
*/
audioOnly?: boolean;
/**
* record video only. optional
*/
videoOnly?: boolean;
/**
* await START_RECORDING chrome log
*/
awaitStartSignal?: boolean;
}
interface ParticipantEgressOptions extends BaseOptions {
/**
* true to capture source screenshare and screenshare_audio
* false to capture camera and microphone
*/
screenShare?: boolean;
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
}
interface TrackCompositeOptions extends BaseOptions {
/**
* audio track ID
*/
audioTrackId?: string;
/**
* video track ID
*/
videoTrackId?: string;
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
}
/**
* Used to supply multiple outputs with an egress request
*/
interface EncodedOutputs {
file?: EncodedFileOutput | undefined;
stream?: StreamOutput | undefined;
segments?: SegmentedFileOutput | undefined;
images?: ImageOutput | undefined;
}
interface ListEgressOptions {
roomName?: string;
egressId?: string;
active?: boolean;
}
/**
* Client to access Egress APIs
*/
declare class EgressClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* @param roomName - room name
* @param output - file or stream output
* @param opts - RoomCompositeOptions
*/
startRoomCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, opts?: RoomCompositeOptions): Promise<EgressInfo>;
/**
* @deprecated use RoomCompositeOptions instead
*/
startRoomCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, layout?: string, options?: EncodingOptionsPreset | EncodingOptions, audioOnly?: boolean, videoOnly?: boolean, customBaseUrl?: string, audioMixing?: AudioMixing): Promise<EgressInfo>;
/**
* @param url - url
* @param output - file or stream output
* @param opts - WebOptions
*/
startWebEgress(url: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, opts?: WebOptions): Promise<EgressInfo>;
/**
* Export a participant's audio and video tracks,
*
* @param roomName - room name
* @param output - one or more outputs
* @param opts - ParticipantEgressOptions
*/
startParticipantEgress(roomName: string, identity: string, output: EncodedOutputs, opts?: ParticipantEgressOptions): Promise<EgressInfo>;
/**
* @param roomName - room name
* @param output - file or stream output
* @param opts - TrackCompositeOptions
*/
startTrackCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, opts?: TrackCompositeOptions): Promise<EgressInfo>;
/**
* @deprecated use TrackCompositeOptions instead
*/
startTrackCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, audioTrackId?: string, videoTrackId?: string, options?: EncodingOptionsPreset | EncodingOptions): Promise<EgressInfo>;
private isEncodedOutputs;
private isEncodedFileOutput;
private isSegmentedFileOutput;
private isStreamOutput;
private getOutputParams;
/**
* @param roomName - room name
* @param output - file or websocket output
* @param trackId - track Id
*/
startTrackEgress(roomName: string, output: DirectFileOutput | string, trackId: string, webhooks?: WebhookConfig[]): Promise<EgressInfo>;
/**
* @param egressId -
* @param layout -
*/
updateLayout(egressId: string, layout: string): Promise<EgressInfo>;
/**
* @param egressId -
* @param addOutputUrls -
* @param removeOutputUrls -
*/
updateStream(egressId: string, addOutputUrls?: string[], removeOutputUrls?: string[]): Promise<EgressInfo>;
/**
* @param options - options to filter listed Egresses, by default returns all
* Egress instances
*/
listEgress(options?: ListEgressOptions): Promise<Array<EgressInfo>>;
/**
* @deprecated use `listEgress(options?: ListEgressOptions)` instead
* @param roomName - list egress for one room only
*/
listEgress(roomName?: string): Promise<Array<EgressInfo>>;
/**
* @param egressId -
*/
stopEgress(egressId: string): Promise<EgressInfo>;
}
export { type BaseOptions, EgressClient, type EncodedOutputs, type ListEgressOptions, type ParticipantEgressOptions, type RoomCompositeOptions, type TrackCompositeOptions, type WebOptions };
+180
View File
@@ -0,0 +1,180 @@
import { WebhookConfig, EncodedFileOutput, StreamOutput, SegmentedFileOutput, ImageOutput, EncodingOptionsPreset, EncodingOptions, AudioMixing, EgressInfo, DirectFileOutput } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.js';
import { ServiceBase } from './ServiceBase.js';
import './grants.js';
import 'jose';
interface BaseOptions {
/**
* webhooks to call for this request, optional.
*/
webhooks?: WebhookConfig[];
}
interface RoomCompositeOptions extends BaseOptions {
/**
* egress layout. optional
*/
layout?: string;
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
/**
* record audio only. optional
*/
audioOnly?: boolean;
/**
* record video only. optional
*/
videoOnly?: boolean;
/**
* custom template url. optional
*/
customBaseUrl?: string;
/**
* audio mixing options. optional
*/
audioMixing?: AudioMixing;
}
interface WebOptions extends BaseOptions {
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
/**
* record audio only. optional
*/
audioOnly?: boolean;
/**
* record video only. optional
*/
videoOnly?: boolean;
/**
* await START_RECORDING chrome log
*/
awaitStartSignal?: boolean;
}
interface ParticipantEgressOptions extends BaseOptions {
/**
* true to capture source screenshare and screenshare_audio
* false to capture camera and microphone
*/
screenShare?: boolean;
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
}
interface TrackCompositeOptions extends BaseOptions {
/**
* audio track ID
*/
audioTrackId?: string;
/**
* video track ID
*/
videoTrackId?: string;
/**
* encoding options or preset. optional
*/
encodingOptions?: EncodingOptionsPreset | EncodingOptions;
}
/**
* Used to supply multiple outputs with an egress request
*/
interface EncodedOutputs {
file?: EncodedFileOutput | undefined;
stream?: StreamOutput | undefined;
segments?: SegmentedFileOutput | undefined;
images?: ImageOutput | undefined;
}
interface ListEgressOptions {
roomName?: string;
egressId?: string;
active?: boolean;
}
/**
* Client to access Egress APIs
*/
declare class EgressClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* @param roomName - room name
* @param output - file or stream output
* @param opts - RoomCompositeOptions
*/
startRoomCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, opts?: RoomCompositeOptions): Promise<EgressInfo>;
/**
* @deprecated use RoomCompositeOptions instead
*/
startRoomCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, layout?: string, options?: EncodingOptionsPreset | EncodingOptions, audioOnly?: boolean, videoOnly?: boolean, customBaseUrl?: string, audioMixing?: AudioMixing): Promise<EgressInfo>;
/**
* @param url - url
* @param output - file or stream output
* @param opts - WebOptions
*/
startWebEgress(url: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, opts?: WebOptions): Promise<EgressInfo>;
/**
* Export a participant's audio and video tracks,
*
* @param roomName - room name
* @param output - one or more outputs
* @param opts - ParticipantEgressOptions
*/
startParticipantEgress(roomName: string, identity: string, output: EncodedOutputs, opts?: ParticipantEgressOptions): Promise<EgressInfo>;
/**
* @param roomName - room name
* @param output - file or stream output
* @param opts - TrackCompositeOptions
*/
startTrackCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, opts?: TrackCompositeOptions): Promise<EgressInfo>;
/**
* @deprecated use TrackCompositeOptions instead
*/
startTrackCompositeEgress(roomName: string, output: EncodedOutputs | EncodedFileOutput | StreamOutput | SegmentedFileOutput, audioTrackId?: string, videoTrackId?: string, options?: EncodingOptionsPreset | EncodingOptions): Promise<EgressInfo>;
private isEncodedOutputs;
private isEncodedFileOutput;
private isSegmentedFileOutput;
private isStreamOutput;
private getOutputParams;
/**
* @param roomName - room name
* @param output - file or websocket output
* @param trackId - track Id
*/
startTrackEgress(roomName: string, output: DirectFileOutput | string, trackId: string, webhooks?: WebhookConfig[]): Promise<EgressInfo>;
/**
* @param egressId -
* @param layout -
*/
updateLayout(egressId: string, layout: string): Promise<EgressInfo>;
/**
* @param egressId -
* @param addOutputUrls -
* @param removeOutputUrls -
*/
updateStream(egressId: string, addOutputUrls?: string[], removeOutputUrls?: string[]): Promise<EgressInfo>;
/**
* @param options - options to filter listed Egresses, by default returns all
* Egress instances
*/
listEgress(options?: ListEgressOptions): Promise<Array<EgressInfo>>;
/**
* @deprecated use `listEgress(options?: ListEgressOptions)` instead
* @param roomName - list egress for one room only
*/
listEgress(roomName?: string): Promise<Array<EgressInfo>>;
/**
* @param egressId -
*/
stopEgress(egressId: string): Promise<EgressInfo>;
}
export { type BaseOptions, EgressClient, type EncodedOutputs, type ListEgressOptions, type ParticipantEgressOptions, type RoomCompositeOptions, type TrackCompositeOptions, type WebOptions };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"EgressClient.d.ts","sourceRoot":"","sources":["../src/EgressClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,aAAa,EACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,WAAW,EACX,UAAU,EAWX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAM/C,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAqB,SAAQ,WAAW;IACvD;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,eAAe,CAAC,EAAE,qBAAqB,GAAG,eAAe,CAAC;IAC1D;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C;;OAEG;IACH,eAAe,CAAC,EAAE,qBAAqB,GAAG,eAAe,CAAC;IAC1D;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAyB,SAAQ,WAAW;IAC3D;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,eAAe,CAAC,EAAE,qBAAqB,GAAG,eAAe,CAAC;CAC3D;AAED,MAAM,WAAW,qBAAsB,SAAQ,WAAW;IACxD;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,eAAe,CAAC,EAAE,qBAAqB,GAAG,eAAe,CAAC;CAC3D;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,iBAAiB,GAAG,SAAS,CAAC;IACrC,MAAM,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC3C,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,WAAW;IAC3C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAE1B;;;;;OAKG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;IAQnF;;;;OAIG;IACG,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,GAAG,iBAAiB,GAAG,YAAY,GAAG,mBAAmB,EAC/E,IAAI,CAAC,EAAE,oBAAoB,GAC1B,OAAO,CAAC,UAAU,CAAC;IACtB;;OAEG;IACG,wBAAwB,CAC5B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,GAAG,iBAAiB,GAAG,YAAY,GAAG,mBAAmB,EAC/E,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,qBAAqB,GAAG,eAAe,EACjD,SAAS,CAAC,EAAE,OAAO,EACnB,SAAS,CAAC,EAAE,OAAO,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,UAAU,CAAC;IAoEtB;;;;OAIG;IACG,cAAc,CAClB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,cAAc,GAAG,iBAAiB,GAAG,YAAY,GAAG,mBAAmB,EAC/E,IAAI,CAAC,EAAE,UAAU,GAChB,OAAO,CAAC,UAAU,CAAC;IAqCtB;;;;;;OAMG;IACG,sBAAsB,CAC1B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,EACtB,IAAI,CAAC,EAAE,wBAAwB,GAC9B,OAAO,CAAC,UAAU,CAAC;IAyBtB;;;;OAIG;IACG,yBAAyB,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,GAAG,iBAAiB,GAAG,YAAY,GAAG,mBAAmB,EAC/E,IAAI,CAAC,EAAE,qBAAqB,GAC3B,OAAO,CAAC,UAAU,CAAC;IACtB;;OAEG;IACG,yBAAyB,CAC7B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,cAAc,GAAG,iBAAiB,GAAG,YAAY,GAAG,mBAAmB,EAC/E,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,qBAAqB,GAAG,eAAe,GAChD,OAAO,CAAC,UAAU,CAAC;IAwDtB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,eAAe;IAqGvB;;;;OAIG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,gBAAgB,GAAG,MAAM,EACjC,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,aAAa,EAAE,GACzB,OAAO,CAAC,UAAU,CAAC;IAwCtB;;;OAGG;IACG,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAUzE;;;;OAIG;IACG,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,aAAa,CAAC,EAAE,MAAM,EAAE,EACxB,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAC1B,OAAO,CAAC,UAAU,CAAC;IAatB;;;OAGG;IACG,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzE;;;OAGG;IACG,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAqB/D;;OAEG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CASxD"}
+379
View File
@@ -0,0 +1,379 @@
import {
AudioMixing,
EgressInfo,
ListEgressRequest,
ListEgressResponse,
ParticipantEgressRequest,
RoomCompositeEgressRequest,
StopEgressRequest,
TrackCompositeEgressRequest,
TrackEgressRequest,
UpdateLayoutRequest,
UpdateStreamRequest,
WebEgressRequest
} from "@livekit/protocol";
import { ServiceBase } from "./ServiceBase.js";
import { TwirpRpc, livekitPackage } from "./TwirpRPC.js";
const svc = "Egress";
class EgressClient extends ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new TwirpRpc(host, livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
async startRoomCompositeEgress(roomName, output, optsOrLayout, options, audioOnly, videoOnly, customBaseUrl, audioMixing) {
let layout;
let webhooks;
if (optsOrLayout !== void 0) {
if (typeof optsOrLayout === "string") {
layout = optsOrLayout;
} else {
const opts = optsOrLayout;
layout = opts.layout;
options = opts.encodingOptions;
audioOnly = opts.audioOnly;
videoOnly = opts.videoOnly;
customBaseUrl = opts.customBaseUrl;
audioMixing = opts.audioMixing;
webhooks = opts.webhooks;
}
}
layout ??= "";
audioOnly ??= false;
videoOnly ??= false;
customBaseUrl ??= "";
audioMixing ??= AudioMixing.DEFAULT_MIXING;
const {
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
} = this.getOutputParams(output, options);
const req = new RoomCompositeEgressRequest({
roomName,
layout,
audioOnly,
audioMixing,
videoOnly,
customBaseUrl,
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartRoomCompositeEgress",
req,
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param url - url
* @param output - file or stream output
* @param opts - WebOptions
*/
async startWebEgress(url, output, opts) {
const audioOnly = (opts == null ? void 0 : opts.audioOnly) || false;
const videoOnly = (opts == null ? void 0 : opts.videoOnly) || false;
const awaitStartSignal = (opts == null ? void 0 : opts.awaitStartSignal) || false;
const webhooks = (opts == null ? void 0 : opts.webhooks) || [];
const {
output: legacyOutput,
options,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
} = this.getOutputParams(output, opts == null ? void 0 : opts.encodingOptions);
const req = new WebEgressRequest({
url,
audioOnly,
videoOnly,
awaitStartSignal,
output: legacyOutput,
options,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartWebEgress",
req,
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Export a participant's audio and video tracks,
*
* @param roomName - room name
* @param output - one or more outputs
* @param opts - ParticipantEgressOptions
*/
async startParticipantEgress(roomName, identity, output, opts) {
const webhooks = (opts == null ? void 0 : opts.webhooks) || [];
const { options, fileOutputs, streamOutputs, segmentOutputs, imageOutputs } = this.getOutputParams(output, opts == null ? void 0 : opts.encodingOptions);
const req = new ParticipantEgressRequest({
roomName,
identity,
screenShare: (opts == null ? void 0 : opts.screenShare) ?? false,
options,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartParticipantEgress",
req,
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
async startTrackCompositeEgress(roomName, output, optsOrAudioTrackId, videoTrackId, options) {
let audioTrackId;
let webhooks;
if (optsOrAudioTrackId !== void 0) {
if (typeof optsOrAudioTrackId === "string") {
audioTrackId = optsOrAudioTrackId;
} else {
const opts = optsOrAudioTrackId;
audioTrackId = opts.audioTrackId;
videoTrackId = opts.videoTrackId;
options = opts.encodingOptions;
webhooks = opts.webhooks;
}
}
audioTrackId ??= "";
videoTrackId ??= "";
const {
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
} = this.getOutputParams(output, options);
const req = new TrackCompositeEgressRequest({
roomName,
audioTrackId,
videoTrackId,
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartTrackCompositeEgress",
req,
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isEncodedOutputs(output) {
return output.file !== void 0 || output.stream !== void 0 || output.segments !== void 0 || output.images !== void 0;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isEncodedFileOutput(output) {
return output.filepath !== void 0 || output.fileType !== void 0;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isSegmentedFileOutput(output) {
return output.filenamePrefix !== void 0 || output.playlistName !== void 0 || output.filenameSuffix !== void 0;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
isStreamOutput(output) {
return output.protocol !== void 0 || output.urls !== void 0;
}
getOutputParams(output, opts) {
let file;
let fileOutputs;
let stream;
let streamOutputs;
let segments;
let segmentOutputs;
let imageOutputs;
if (this.isEncodedOutputs(output)) {
if (output.file !== void 0) {
fileOutputs = [output.file];
}
if (output.stream !== void 0) {
streamOutputs = [output.stream];
}
if (output.segments !== void 0) {
segmentOutputs = [output.segments];
}
if (output.images !== void 0) {
imageOutputs = [output.images];
}
} else if (this.isEncodedFileOutput(output)) {
file = output;
fileOutputs = [file];
} else if (this.isSegmentedFileOutput(output)) {
segments = output;
segmentOutputs = [segments];
} else if (this.isStreamOutput(output)) {
stream = output;
streamOutputs = [stream];
}
let legacyOutput;
if (file) {
legacyOutput = {
case: "file",
value: file
};
} else if (stream) {
legacyOutput = {
case: "stream",
value: stream
};
} else if (segments) {
legacyOutput = {
case: "segments",
value: segments
};
}
let egressOptions;
if (opts) {
if (typeof opts === "number") {
egressOptions = {
case: "preset",
value: opts
};
} else {
egressOptions = {
case: "advanced",
value: opts
};
}
}
return {
output: legacyOutput,
options: egressOptions,
fileOutputs,
streamOutputs,
segmentOutputs,
imageOutputs
};
}
/**
* @param roomName - room name
* @param output - file or websocket output
* @param trackId - track Id
*/
async startTrackEgress(roomName, output, trackId, webhooks) {
let legacyOutput;
if (typeof output === "string") {
legacyOutput = {
case: "websocketUrl",
value: output
};
} else {
legacyOutput = {
case: "file",
value: output
};
}
const req = new TrackEgressRequest({
roomName,
trackId,
output: legacyOutput,
webhooks
}).toJson();
const data = await this.rpc.request(
svc,
"StartTrackEgress",
req,
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param egressId -
* @param layout -
*/
async updateLayout(egressId, layout) {
const data = await this.rpc.request(
svc,
"UpdateLayout",
new UpdateLayoutRequest({ egressId, layout }).toJson(),
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param egressId -
* @param addOutputUrls -
* @param removeOutputUrls -
*/
async updateStream(egressId, addOutputUrls, removeOutputUrls) {
addOutputUrls ??= [];
removeOutputUrls ??= [];
const data = await this.rpc.request(
svc,
"UpdateStream",
new UpdateStreamRequest({ egressId, addOutputUrls, removeOutputUrls }).toJson(),
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param roomName - list egress for one room only
*/
async listEgress(options) {
let req = {};
if (typeof options === "string") {
req.roomName = options;
} else if (options !== void 0) {
req = options;
}
const data = await this.rpc.request(
svc,
"ListEgress",
new ListEgressRequest(req).toJson(),
await this.authHeader({ roomRecord: true })
);
return ListEgressResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* @param egressId -
*/
async stopEgress(egressId) {
const data = await this.rpc.request(
svc,
"StopEgress",
new StopEgressRequest({ egressId }).toJson(),
await this.authHeader({ roomRecord: true })
);
return EgressInfo.fromJson(data, { ignoreUnknownFields: true });
}
}
export {
EgressClient
};
//# sourceMappingURL=EgressClient.js.map
File diff suppressed because one or more lines are too long
+158
View File
@@ -0,0 +1,158 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var IngressClient_exports = {};
__export(IngressClient_exports, {
IngressClient: () => IngressClient
});
module.exports = __toCommonJS(IngressClient_exports);
var import_protocol = require("@livekit/protocol");
var import_ServiceBase = require("./ServiceBase.cjs");
var import_TwirpRPC = require("./TwirpRPC.cjs");
const svc = "Ingress";
class IngressClient extends import_ServiceBase.ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new import_TwirpRPC.TwirpRpc(host, import_TwirpRPC.livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* @param inputType - protocol for the ingress
* @param opts - CreateIngressOptions
*/
async createIngress(inputType, opts) {
let name = "";
let participantName = "";
let participantIdentity = "";
let bypassTranscoding = false;
let url = "";
if (opts == null) {
throw new Error("options dictionary is required");
}
const roomName = opts.roomName;
const enableTranscoding = opts.enableTranscoding;
const audio = opts.audio;
const video = opts.video;
const participantMetadata = opts.participantMetadata;
name = opts.name || "";
participantName = opts.participantName || "";
participantIdentity = opts.participantIdentity || "";
bypassTranscoding = opts.bypassTranscoding || false;
url = opts.url || "";
if (typeof roomName == "undefined") {
throw new Error("required roomName option not provided");
}
if (participantIdentity == "") {
throw new Error("required participantIdentity option not provided");
}
const req = new import_protocol.CreateIngressRequest({
inputType,
name,
roomName,
participantIdentity,
participantMetadata,
participantName,
bypassTranscoding,
enableTranscoding,
url,
audio,
video
}).toJson();
const data = await this.rpc.request(
svc,
"CreateIngress",
req,
await this.authHeader({ ingressAdmin: true })
);
return import_protocol.IngressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param ingressId - ID of the ingress to update
* @param opts - UpdateIngressOptions
*/
async updateIngress(ingressId, opts) {
const name = opts.name || "";
const roomName = opts.roomName || "";
const participantName = opts.participantName || "";
const participantIdentity = opts.participantIdentity || "";
const { participantMetadata } = opts;
const { audio, video, bypassTranscoding, enableTranscoding } = opts;
const req = new import_protocol.UpdateIngressRequest({
ingressId,
name,
roomName,
participantIdentity,
participantName,
participantMetadata,
bypassTranscoding,
enableTranscoding,
audio,
video
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateIngress",
req,
await this.authHeader({ ingressAdmin: true })
);
return import_protocol.IngressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param arg - list room name or options
*/
async listIngress(arg) {
let req = {};
if (typeof arg === "string") {
req.roomName = arg;
} else if (arg) {
req = arg;
}
const data = await this.rpc.request(
svc,
"ListIngress",
new import_protocol.ListIngressRequest(req).toJson(),
await this.authHeader({ ingressAdmin: true })
);
return import_protocol.ListIngressResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* @param ingressId - ingress to delete
*/
async deleteIngress(ingressId) {
const data = await this.rpc.request(
svc,
"DeleteIngress",
new import_protocol.DeleteIngressRequest({ ingressId }).toJson(),
await this.authHeader({ ingressAdmin: true })
);
return import_protocol.IngressInfo.fromJson(data, { ignoreUnknownFields: true });
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
IngressClient
});
//# sourceMappingURL=IngressClient.cjs.map
File diff suppressed because one or more lines are too long
+138
View File
@@ -0,0 +1,138 @@
import { IngressAudioOptions, IngressVideoOptions, IngressInput, IngressInfo } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.cjs';
import { ServiceBase } from './ServiceBase.cjs';
import './grants.cjs';
import 'jose';
interface CreateIngressOptions {
/**
* ingress name. optional
*/
name?: string;
/**
* name of the room to send media to. required
*/
roomName?: string;
/**
* unique identity of the participant. required
*/
participantIdentity: string;
/**
* participant display name
*/
participantName?: string;
/**
* metadata to attach to the participant
*/
participantMetadata?: string;
/**
* @deprecated use `enableTranscoding` instead.
* whether to skip transcoding and forward the input media directly. Only supported by WHIP
*/
bypassTranscoding?: boolean;
/**
* whether to enable transcoding or forward the input media directly.
* Transcoding is required for all input types except WHIP. For WHIP, the default is to not transcode.
*/
enableTranscoding?: boolean | undefined;
/**
* url of the media to pull for ingresses of type URL
*/
url?: string;
/**
* custom audio encoding parameters. optional
*/
audio?: IngressAudioOptions;
/**
* custom video encoding parameters. optional
*/
video?: IngressVideoOptions;
}
interface UpdateIngressOptions {
/**
* ingress name. optional
*/
name: string;
/**
* name of the room to send media to.
*/
roomName?: string;
/**
* unique identity of the participant.
*/
participantIdentity?: string;
/**
* participant display name
*/
participantName?: string;
/**
* metadata to attach to the participant
*/
participantMetadata?: string;
/**
* @deprecated use `enableTranscoding` instead
* whether to skip transcoding and forward the input media directly. Only supported by WHIP
*/
bypassTranscoding?: boolean | undefined;
/**
* whether to enable transcoding or forward the input media directly.
* Transcoding is required for all input types except WHIP. For WHIP, the default is to not transcode.
*/
enableTranscoding?: boolean | undefined;
/**
* custom audio encoding parameters. optional
*/
audio?: IngressAudioOptions;
/**
* custom video encoding parameters. optional
*/
video?: IngressVideoOptions;
}
interface ListIngressOptions {
/**
* list ingress for one room only
*/
roomName?: string;
/**
* list ingress by ID
*/
ingressId?: string;
}
/**
* Client to access Ingress APIs
*/
declare class IngressClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* @param inputType - protocol for the ingress
* @param opts - CreateIngressOptions
*/
createIngress(inputType: IngressInput, opts: CreateIngressOptions): Promise<IngressInfo>;
/**
* @param ingressId - ID of the ingress to update
* @param opts - UpdateIngressOptions
*/
updateIngress(ingressId: string, opts: UpdateIngressOptions): Promise<IngressInfo>;
/**
* @deprecated use `listIngress(opts)` or `listIngress(arg)` instead
* @param roomName - list ingress for one room only
*/
listIngress(roomName?: string): Promise<Array<IngressInfo>>;
/**
* @param opts - list options
*/
listIngress(opts?: ListIngressOptions): Promise<Array<IngressInfo>>;
/**
* @param ingressId - ingress to delete
*/
deleteIngress(ingressId: string): Promise<IngressInfo>;
}
export { type CreateIngressOptions, IngressClient, type ListIngressOptions, type UpdateIngressOptions };
+138
View File
@@ -0,0 +1,138 @@
import { IngressAudioOptions, IngressVideoOptions, IngressInput, IngressInfo } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.js';
import { ServiceBase } from './ServiceBase.js';
import './grants.js';
import 'jose';
interface CreateIngressOptions {
/**
* ingress name. optional
*/
name?: string;
/**
* name of the room to send media to. required
*/
roomName?: string;
/**
* unique identity of the participant. required
*/
participantIdentity: string;
/**
* participant display name
*/
participantName?: string;
/**
* metadata to attach to the participant
*/
participantMetadata?: string;
/**
* @deprecated use `enableTranscoding` instead.
* whether to skip transcoding and forward the input media directly. Only supported by WHIP
*/
bypassTranscoding?: boolean;
/**
* whether to enable transcoding or forward the input media directly.
* Transcoding is required for all input types except WHIP. For WHIP, the default is to not transcode.
*/
enableTranscoding?: boolean | undefined;
/**
* url of the media to pull for ingresses of type URL
*/
url?: string;
/**
* custom audio encoding parameters. optional
*/
audio?: IngressAudioOptions;
/**
* custom video encoding parameters. optional
*/
video?: IngressVideoOptions;
}
interface UpdateIngressOptions {
/**
* ingress name. optional
*/
name: string;
/**
* name of the room to send media to.
*/
roomName?: string;
/**
* unique identity of the participant.
*/
participantIdentity?: string;
/**
* participant display name
*/
participantName?: string;
/**
* metadata to attach to the participant
*/
participantMetadata?: string;
/**
* @deprecated use `enableTranscoding` instead
* whether to skip transcoding and forward the input media directly. Only supported by WHIP
*/
bypassTranscoding?: boolean | undefined;
/**
* whether to enable transcoding or forward the input media directly.
* Transcoding is required for all input types except WHIP. For WHIP, the default is to not transcode.
*/
enableTranscoding?: boolean | undefined;
/**
* custom audio encoding parameters. optional
*/
audio?: IngressAudioOptions;
/**
* custom video encoding parameters. optional
*/
video?: IngressVideoOptions;
}
interface ListIngressOptions {
/**
* list ingress for one room only
*/
roomName?: string;
/**
* list ingress by ID
*/
ingressId?: string;
}
/**
* Client to access Ingress APIs
*/
declare class IngressClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* @param inputType - protocol for the ingress
* @param opts - CreateIngressOptions
*/
createIngress(inputType: IngressInput, opts: CreateIngressOptions): Promise<IngressInfo>;
/**
* @param ingressId - ID of the ingress to update
* @param opts - UpdateIngressOptions
*/
updateIngress(ingressId: string, opts: UpdateIngressOptions): Promise<IngressInfo>;
/**
* @deprecated use `listIngress(opts)` or `listIngress(arg)` instead
* @param roomName - list ingress for one room only
*/
listIngress(roomName?: string): Promise<Array<IngressInfo>>;
/**
* @param opts - list options
*/
listIngress(opts?: ListIngressOptions): Promise<Array<IngressInfo>>;
/**
* @param ingressId - ingress to delete
*/
deleteIngress(ingressId: string): Promise<IngressInfo>;
}
export { type CreateIngressOptions, IngressClient, type ListIngressOptions, type UpdateIngressOptions };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"IngressClient.d.ts","sourceRoot":"","sources":["../src/IngressClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAGL,WAAW,EAIZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAM/C,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC;;OAEG;IACH,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,qBAAa,aAAc,SAAQ,WAAW;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAE1B;;;;;OAKG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;IAQnF;;;OAGG;IACG,aAAa,CAAC,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;IAsD9F;;;OAGG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,CAAC;IA8BxF;;;OAGG;IACG,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACjE;;OAEG;IACG,WAAW,CAAC,IAAI,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAoBzE;;OAEG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAS7D"}
+141
View File
@@ -0,0 +1,141 @@
import {
CreateIngressRequest,
DeleteIngressRequest,
IngressInfo,
ListIngressRequest,
ListIngressResponse,
UpdateIngressRequest
} from "@livekit/protocol";
import { ServiceBase } from "./ServiceBase.js";
import { TwirpRpc, livekitPackage } from "./TwirpRPC.js";
const svc = "Ingress";
class IngressClient extends ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new TwirpRpc(host, livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* @param inputType - protocol for the ingress
* @param opts - CreateIngressOptions
*/
async createIngress(inputType, opts) {
let name = "";
let participantName = "";
let participantIdentity = "";
let bypassTranscoding = false;
let url = "";
if (opts == null) {
throw new Error("options dictionary is required");
}
const roomName = opts.roomName;
const enableTranscoding = opts.enableTranscoding;
const audio = opts.audio;
const video = opts.video;
const participantMetadata = opts.participantMetadata;
name = opts.name || "";
participantName = opts.participantName || "";
participantIdentity = opts.participantIdentity || "";
bypassTranscoding = opts.bypassTranscoding || false;
url = opts.url || "";
if (typeof roomName == "undefined") {
throw new Error("required roomName option not provided");
}
if (participantIdentity == "") {
throw new Error("required participantIdentity option not provided");
}
const req = new CreateIngressRequest({
inputType,
name,
roomName,
participantIdentity,
participantMetadata,
participantName,
bypassTranscoding,
enableTranscoding,
url,
audio,
video
}).toJson();
const data = await this.rpc.request(
svc,
"CreateIngress",
req,
await this.authHeader({ ingressAdmin: true })
);
return IngressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param ingressId - ID of the ingress to update
* @param opts - UpdateIngressOptions
*/
async updateIngress(ingressId, opts) {
const name = opts.name || "";
const roomName = opts.roomName || "";
const participantName = opts.participantName || "";
const participantIdentity = opts.participantIdentity || "";
const { participantMetadata } = opts;
const { audio, video, bypassTranscoding, enableTranscoding } = opts;
const req = new UpdateIngressRequest({
ingressId,
name,
roomName,
participantIdentity,
participantName,
participantMetadata,
bypassTranscoding,
enableTranscoding,
audio,
video
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateIngress",
req,
await this.authHeader({ ingressAdmin: true })
);
return IngressInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @param arg - list room name or options
*/
async listIngress(arg) {
let req = {};
if (typeof arg === "string") {
req.roomName = arg;
} else if (arg) {
req = arg;
}
const data = await this.rpc.request(
svc,
"ListIngress",
new ListIngressRequest(req).toJson(),
await this.authHeader({ ingressAdmin: true })
);
return ListIngressResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* @param ingressId - ingress to delete
*/
async deleteIngress(ingressId) {
const data = await this.rpc.request(
svc,
"DeleteIngress",
new DeleteIngressRequest({ ingressId }).toJson(),
await this.authHeader({ ingressAdmin: true })
);
return IngressInfo.fromJson(data, { ignoreUnknownFields: true });
}
}
export {
IngressClient
};
//# sourceMappingURL=IngressClient.js.map
File diff suppressed because one or more lines are too long
+80
View File
@@ -0,0 +1,80 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var LiveKitAPI_exports = {};
__export(LiveKitAPI_exports, {
LiveKitAPI: () => LiveKitAPI
});
module.exports = __toCommonJS(LiveKitAPI_exports);
var import_AgentDispatchClient = require("./AgentDispatchClient.cjs");
var import_ConnectorClient = require("./ConnectorClient.cjs");
var import_EgressClient = require("./EgressClient.cjs");
var import_IngressClient = require("./IngressClient.cjs");
var import_RoomServiceClient = require("./RoomServiceClient.cjs");
var import_SipClient = require("./SipClient.cjs");
class LiveKitAPI {
/**
* @param options - server host, credentials, and client options; each value
* falls back to its environment variable when omitted.
*/
constructor(options = {}) {
const host = options.host || process.env.LIVEKIT_URL;
if (!host) {
throw new Error("host is required (pass it or set LIVEKIT_URL)");
}
const { apiKey, secret } = options;
const token = options.token || (apiKey || secret ? void 0 : process.env.LIVEKIT_TOKEN);
if (!token && !(apiKey ?? process.env.LIVEKIT_API_KEY)) {
throw new Error("either a token or an API key and secret are required");
}
const clientOptions = {
requestTimeout: options.requestTimeout,
failover: options.failover,
token
};
this._room = new import_RoomServiceClient.RoomServiceClient(host, apiKey, secret, clientOptions);
this._egress = new import_EgressClient.EgressClient(host, apiKey, secret, clientOptions);
this._ingress = new import_IngressClient.IngressClient(host, apiKey, secret, clientOptions);
this._sip = new import_SipClient.SipClient(host, apiKey, secret, clientOptions);
this._agentDispatch = new import_AgentDispatchClient.AgentDispatchClient(host, apiKey, secret, clientOptions);
this._connector = new import_ConnectorClient.ConnectorClient(host, apiKey, secret, clientOptions);
}
get room() {
return this._room;
}
get egress() {
return this._egress;
}
get ingress() {
return this._ingress;
}
get sip() {
return this._sip;
}
get agentDispatch() {
return this._agentDispatch;
}
get connector() {
return this._connector;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
LiveKitAPI
});
//# sourceMappingURL=LiveKitAPI.cjs.map
File diff suppressed because one or more lines are too long
+77
View File
@@ -0,0 +1,77 @@
import { AgentDispatchClient } from './AgentDispatchClient.cjs';
import { ConnectorClient } from './ConnectorClient.cjs';
import { EgressClient } from './EgressClient.cjs';
import { IngressClient } from './IngressClient.cjs';
import { RoomServiceClient } from './RoomServiceClient.cjs';
import { SipClient } from './SipClient.cjs';
import '@livekit/protocol';
import './ClientOptions.cjs';
import './ServiceBase.cjs';
import './grants.cjs';
import 'jose';
/** Server host and non-auth options, shared by both authentication modes. */
interface LiveKitAPICommonOptions {
/** Server host, including protocol. Falls back to the `LIVEKIT_URL` env var. */
host?: string;
/** Optional timeout, in seconds, for all server requests. */
requestTimeout?: number;
/**
* Whether to fail over to alternative regions on retryable errors (LiveKit
* Cloud hosts only). Defaults to true; set to false to disable.
*/
failover?: boolean;
}
/** API key and secret authentication (recommended for backend use). */
interface ApiKeyAuth {
/** API key. Falls back to the `LIVEKIT_API_KEY` env var. */
apiKey?: string;
/** API secret. Falls back to the `LIVEKIT_API_SECRET` env var. */
secret?: string;
token?: never;
}
/** Pre-signed token authentication (client-side use; no secret required). */
interface TokenAuth {
/** Pre-signed token, sent verbatim. Falls back to the `LIVEKIT_TOKEN` env var. */
token: string;
apiKey?: never;
secret?: never;
}
/**
* Options for {@link LiveKitAPI}. Provide either an `apiKey` and `secret` or a
* pre-signed `token` — the two modes are mutually exclusive. Any omitted value
* falls back to its environment variable (`LIVEKIT_URL`, `LIVEKIT_API_KEY`,
* `LIVEKIT_API_SECRET`, `LIVEKIT_TOKEN`).
*/
type LiveKitAPIOptions = LiveKitAPICommonOptions & (ApiKeyAuth | TokenAuth);
/**
* A single entry point to every LiveKit server API, exposing each service
* through a property, e.g. `api.room.createRoom(...)`.
*
* @example
* ```ts
* const api = new LiveKitAPI({ apiKey, secret }); // or new LiveKitAPI() to read from env
* await api.room.createRoom({ name: 'my-room' });
* ```
*/
declare class LiveKitAPI {
private readonly _room;
private readonly _egress;
private readonly _ingress;
private readonly _sip;
private readonly _agentDispatch;
private readonly _connector;
/**
* @param options - server host, credentials, and client options; each value
* falls back to its environment variable when omitted.
*/
constructor(options?: LiveKitAPIOptions);
get room(): RoomServiceClient;
get egress(): EgressClient;
get ingress(): IngressClient;
get sip(): SipClient;
get agentDispatch(): AgentDispatchClient;
get connector(): ConnectorClient;
}
export { LiveKitAPI, type LiveKitAPIOptions };
+77
View File
@@ -0,0 +1,77 @@
import { AgentDispatchClient } from './AgentDispatchClient.js';
import { ConnectorClient } from './ConnectorClient.js';
import { EgressClient } from './EgressClient.js';
import { IngressClient } from './IngressClient.js';
import { RoomServiceClient } from './RoomServiceClient.js';
import { SipClient } from './SipClient.js';
import '@livekit/protocol';
import './ClientOptions.js';
import './ServiceBase.js';
import './grants.js';
import 'jose';
/** Server host and non-auth options, shared by both authentication modes. */
interface LiveKitAPICommonOptions {
/** Server host, including protocol. Falls back to the `LIVEKIT_URL` env var. */
host?: string;
/** Optional timeout, in seconds, for all server requests. */
requestTimeout?: number;
/**
* Whether to fail over to alternative regions on retryable errors (LiveKit
* Cloud hosts only). Defaults to true; set to false to disable.
*/
failover?: boolean;
}
/** API key and secret authentication (recommended for backend use). */
interface ApiKeyAuth {
/** API key. Falls back to the `LIVEKIT_API_KEY` env var. */
apiKey?: string;
/** API secret. Falls back to the `LIVEKIT_API_SECRET` env var. */
secret?: string;
token?: never;
}
/** Pre-signed token authentication (client-side use; no secret required). */
interface TokenAuth {
/** Pre-signed token, sent verbatim. Falls back to the `LIVEKIT_TOKEN` env var. */
token: string;
apiKey?: never;
secret?: never;
}
/**
* Options for {@link LiveKitAPI}. Provide either an `apiKey` and `secret` or a
* pre-signed `token` — the two modes are mutually exclusive. Any omitted value
* falls back to its environment variable (`LIVEKIT_URL`, `LIVEKIT_API_KEY`,
* `LIVEKIT_API_SECRET`, `LIVEKIT_TOKEN`).
*/
type LiveKitAPIOptions = LiveKitAPICommonOptions & (ApiKeyAuth | TokenAuth);
/**
* A single entry point to every LiveKit server API, exposing each service
* through a property, e.g. `api.room.createRoom(...)`.
*
* @example
* ```ts
* const api = new LiveKitAPI({ apiKey, secret }); // or new LiveKitAPI() to read from env
* await api.room.createRoom({ name: 'my-room' });
* ```
*/
declare class LiveKitAPI {
private readonly _room;
private readonly _egress;
private readonly _ingress;
private readonly _sip;
private readonly _agentDispatch;
private readonly _connector;
/**
* @param options - server host, credentials, and client options; each value
* falls back to its environment variable when omitted.
*/
constructor(options?: LiveKitAPIOptions);
get room(): RoomServiceClient;
get egress(): EgressClient;
get ingress(): IngressClient;
get sip(): SipClient;
get agentDispatch(): AgentDispatchClient;
get connector(): ConnectorClient;
}
export { LiveKitAPI, type LiveKitAPIOptions };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"LiveKitAPI.d.ts","sourceRoot":"","sources":["../src/LiveKitAPI.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,6EAA6E;AAC7E,UAAU,uBAAuB;IAC/B,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,uEAAuE;AACvE,UAAU,UAAU;IAClB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,6EAA6E;AAC7E,UAAU,SAAS;IACjB,kFAAkF;IAClF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,uBAAuB,GAAG,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;AAEnF;;;;;;;;;GASG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAE1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IAEvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IAEzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IAEjC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAsB;IAErD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAE7C;;;OAGG;gBACS,OAAO,GAAE,iBAAsB;IA0B3C,IAAI,IAAI,IAAI,iBAAiB,CAE5B;IAED,IAAI,MAAM,IAAI,YAAY,CAEzB;IAED,IAAI,OAAO,IAAI,aAAa,CAE3B;IAED,IAAI,GAAG,IAAI,SAAS,CAEnB;IAED,IAAI,aAAa,IAAI,mBAAmB,CAEvC;IAED,IAAI,SAAS,IAAI,eAAe,CAE/B;CACF"}
+56
View File
@@ -0,0 +1,56 @@
import { AgentDispatchClient } from "./AgentDispatchClient.js";
import { ConnectorClient } from "./ConnectorClient.js";
import { EgressClient } from "./EgressClient.js";
import { IngressClient } from "./IngressClient.js";
import { RoomServiceClient } from "./RoomServiceClient.js";
import { SipClient } from "./SipClient.js";
class LiveKitAPI {
/**
* @param options - server host, credentials, and client options; each value
* falls back to its environment variable when omitted.
*/
constructor(options = {}) {
const host = options.host || process.env.LIVEKIT_URL;
if (!host) {
throw new Error("host is required (pass it or set LIVEKIT_URL)");
}
const { apiKey, secret } = options;
const token = options.token || (apiKey || secret ? void 0 : process.env.LIVEKIT_TOKEN);
if (!token && !(apiKey ?? process.env.LIVEKIT_API_KEY)) {
throw new Error("either a token or an API key and secret are required");
}
const clientOptions = {
requestTimeout: options.requestTimeout,
failover: options.failover,
token
};
this._room = new RoomServiceClient(host, apiKey, secret, clientOptions);
this._egress = new EgressClient(host, apiKey, secret, clientOptions);
this._ingress = new IngressClient(host, apiKey, secret, clientOptions);
this._sip = new SipClient(host, apiKey, secret, clientOptions);
this._agentDispatch = new AgentDispatchClient(host, apiKey, secret, clientOptions);
this._connector = new ConnectorClient(host, apiKey, secret, clientOptions);
}
get room() {
return this._room;
}
get egress() {
return this._egress;
}
get ingress() {
return this._ingress;
}
get sip() {
return this._sip;
}
get agentDispatch() {
return this._agentDispatch;
}
get connector() {
return this._connector;
}
}
export {
LiveKitAPI
};
//# sourceMappingURL=LiveKitAPI.js.map
File diff suppressed because one or more lines are too long
+277
View File
@@ -0,0 +1,277 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var RoomServiceClient_exports = {};
__export(RoomServiceClient_exports, {
RoomServiceClient: () => RoomServiceClient
});
module.exports = __toCommonJS(RoomServiceClient_exports);
var import_protocol = require("@livekit/protocol");
var import_ServiceBase = require("./ServiceBase.cjs");
var import_TwirpRPC = require("./TwirpRPC.cjs");
var import_uuid = require("./crypto/uuid.cjs");
const svc = "RoomService";
class RoomServiceClient extends import_ServiceBase.ServiceBase {
/**
*
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new import_TwirpRPC.TwirpRpc(host, import_TwirpRPC.livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* Creates a new room. Explicit room creation is not required, since rooms will
* be automatically created when the first participant joins. This method can be
* used to customize room settings.
* @param options -
*/
async createRoom(options) {
const data = await this.rpc.request(
svc,
"CreateRoom",
new import_protocol.CreateRoomRequest(options).toJson(),
await this.authHeader({ roomCreate: true })
);
return import_protocol.Room.fromJson(data, { ignoreUnknownFields: true });
}
/**
* List active rooms
* @param names - when undefined or empty, list all rooms.
* otherwise returns rooms with matching names
* @returns
*/
async listRooms(names) {
const data = await this.rpc.request(
svc,
"ListRooms",
new import_protocol.ListRoomsRequest({ names: names ?? [] }).toJson(),
await this.authHeader({ roomList: true })
);
const res = import_protocol.ListRoomsResponse.fromJson(data, { ignoreUnknownFields: true });
return res.rooms ?? [];
}
async deleteRoom(room) {
await this.rpc.request(
svc,
"DeleteRoom",
new import_protocol.DeleteRoomRequest({ room }).toJson(),
await this.authHeader({ roomCreate: true })
);
}
/**
* Update metadata of a room
* @param room - name of the room
* @param metadata - the new metadata for the room
*/
async updateRoomMetadata(room, metadata) {
const data = await this.rpc.request(
svc,
"UpdateRoomMetadata",
new import_protocol.UpdateRoomMetadataRequest({ room, metadata }).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
return import_protocol.Room.fromJson(data, { ignoreUnknownFields: true });
}
/**
* List participants in a room
* @param room - name of the room
*/
async listParticipants(room) {
const data = await this.rpc.request(
svc,
"ListParticipants",
new import_protocol.ListParticipantsRequest({ room }).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
const res = import_protocol.ListParticipantsResponse.fromJson(data, { ignoreUnknownFields: true });
return res.participants ?? [];
}
/**
* Get information on a specific participant, including the tracks that participant
* has published
* @param room - name of the room
* @param identity - identity of the participant to return
*/
async getParticipant(room, identity) {
const data = await this.rpc.request(
svc,
"GetParticipant",
new import_protocol.RoomParticipantIdentity({ room, identity }).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
return import_protocol.ParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Removes a participant in the room. This will disconnect the participant
* and will emit a Disconnected event for that participant.
* Even after being removed, the participant can still re-join the room.
* @param room -
* @param identity -
* @param options - removal options
*/
async removeParticipant(room, identity, options) {
await this.rpc.request(
svc,
"RemoveParticipant",
new import_protocol.RoomParticipantIdentity({
room,
identity,
revokeTokenTs: options == null ? void 0 : options.revokeTokenTs
}).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
}
/**
* Forwards a participant's track to another room. This will create a
* participant to join the destination room that has same information
* with the source participant except the kind to be `Forwarded`. All
* changes to the source participant will be reflected to the forwarded
* participant. When the source participant disconnects or the
* `RemoveParticipant` method is called in the destination room, the
* forwarding will be stopped.
* @param room -
* @param identity -
* @param destinationRoom - the room to forward the participant to
*/
async forwardParticipant(room, identity, destinationRoom) {
await this.rpc.request(
svc,
"ForwardParticipant",
new import_protocol.ForwardParticipantRequest({ room, identity, destinationRoom }).toJson(),
await this.authHeader({ roomAdmin: true, room, destinationRoom })
);
}
/**
* Move a connected participant to a different room. Requires `roomAdmin` and `destinationRoom`.
* The participant will be removed from the current room and added to the destination room.
* From the other observers' perspective, the participant would've disconnected from the previous room and joined the new one.
* @param room -
* @param identity -
* @param destinationRoom - the room to move the participant to
*/
async moveParticipant(room, identity, destinationRoom) {
await this.rpc.request(
svc,
"MoveParticipant",
new import_protocol.MoveParticipantRequest({ room, identity, destinationRoom }).toJson(),
await this.authHeader({ roomAdmin: true, room, destinationRoom })
);
}
/**
* Mutes a track that the participant has published.
* @param room -
* @param identity -
* @param trackSid - sid of the track to be muted
* @param muted - true to mute, false to unmute
*/
async mutePublishedTrack(room, identity, trackSid, muted) {
const req = new import_protocol.MuteRoomTrackRequest({
room,
identity,
trackSid,
muted
}).toJson();
const data = await this.rpc.request(
svc,
"MutePublishedTrack",
req,
await this.authHeader({ roomAdmin: true, room })
);
const res = import_protocol.MuteRoomTrackResponse.fromJson(data, { ignoreUnknownFields: true });
return res.track;
}
async updateParticipant(room, identity, metadataOrOptions, maybePermission, maybeName) {
const hasOptions = typeof metadataOrOptions === "object";
const metadata = hasOptions ? metadataOrOptions == null ? void 0 : metadataOrOptions.metadata : metadataOrOptions;
const permission = hasOptions ? metadataOrOptions.permission : maybePermission;
const name = hasOptions ? metadataOrOptions.name : maybeName;
const attributes = hasOptions ? metadataOrOptions.attributes : {};
const req = new import_protocol.UpdateParticipantRequest({
room,
identity,
attributes,
metadata,
name
});
if (permission) {
req.permission = new import_protocol.ParticipantPermission(permission);
}
const data = await this.rpc.request(
svc,
"UpdateParticipant",
req.toJson(),
await this.authHeader({ roomAdmin: true, room })
);
return import_protocol.ParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates a participant's subscription to tracks
* @param room -
* @param identity -
* @param trackSids -
* @param subscribe - true to subscribe, false to unsubscribe
*/
async updateSubscriptions(room, identity, trackSids, subscribe) {
const req = new import_protocol.UpdateSubscriptionsRequest({
room,
identity,
trackSids,
subscribe,
participantTracks: []
}).toJson();
await this.rpc.request(
svc,
"UpdateSubscriptions",
req,
await this.authHeader({ roomAdmin: true, room })
);
}
async sendData(room, data, kind, options = {}) {
const destinationSids = Array.isArray(options) ? options : options.destinationSids;
const topic = Array.isArray(options) ? void 0 : options.topic;
const req = new import_protocol.SendDataRequest({
room,
data,
kind,
destinationSids: destinationSids ?? [],
topic
});
if (!Array.isArray(options) && options.destinationIdentities) {
req.destinationIdentities = options.destinationIdentities;
}
req.nonce = await (0, import_uuid.getRandomBytes)(16);
await this.rpc.request(
svc,
"SendData",
req.toJson(),
await this.authHeader({ roomAdmin: true, room })
);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
RoomServiceClient
});
//# sourceMappingURL=RoomServiceClient.cjs.map
File diff suppressed because one or more lines are too long
+208
View File
@@ -0,0 +1,208 @@
import { RoomEgress, RoomAgentDispatch, Room, ParticipantInfo, TrackInfo, ParticipantPermission, DataPacket_Kind } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.cjs';
import { ServiceBase } from './ServiceBase.cjs';
import './grants.cjs';
import 'jose';
/**
* Options for when creating a room
*/
interface CreateOptions {
/**
* name of the room. required
*/
name: string;
/**
* number of seconds to keep the room open before any participant joins
*/
emptyTimeout?: number;
/**
* number of seconds to keep the room open after the last participant leaves
* this option is helpful to give a grace period for participants to re-join
*/
departureTimeout?: number;
/**
* limit to the number of participants in a room at a time
*/
maxParticipants?: number;
/**
* initial room metadata
*/
metadata?: string;
/**
* add egress options
*/
egress?: RoomEgress;
/**
* minimum playout delay in milliseconds
*/
minPlayoutDelay?: number;
/**
* maximum playout delay in milliseconds
*/
maxPlayoutDelay?: number;
/**
* improves A/V sync when min_playout_delay set to a value larger than 200ms.
* It will disables transceiver re-use -- this option is not recommended
* for rooms with frequent subscription changes
*/
syncStreams?: boolean;
/**
* agents that should be dispatched to this room
*/
agents?: RoomAgentDispatch[];
/**
* override the node room is allocated to, for debugging
* does not work with Cloud
*/
nodeId?: string;
}
type SendDataOptions = {
/** If set, only deliver to listed participant identities */
destinationIdentities?: string[];
destinationSids?: string[];
topic?: string;
};
type UpdateParticipantOptions = {
/** only attributes you'd want to update should be set, set value to empty string to remove it */
attributes?: {
[key: string]: string;
};
metadata?: string;
/** permissions are updated atomically - all desired permissions would need to be set */
permission?: Partial<ParticipantPermission>;
name?: string;
};
type RemoveParticipantOptions = {
/**
* Unix timestamp used to invalidate tokens whose nbf is before this value.
*/
revokeTokenTs?: bigint;
};
/**
* Client to access Room APIs
*/
declare class RoomServiceClient extends ServiceBase {
private readonly rpc;
/**
*
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* Creates a new room. Explicit room creation is not required, since rooms will
* be automatically created when the first participant joins. This method can be
* used to customize room settings.
* @param options -
*/
createRoom(options: CreateOptions): Promise<Room>;
/**
* List active rooms
* @param names - when undefined or empty, list all rooms.
* otherwise returns rooms with matching names
* @returns
*/
listRooms(names?: string[]): Promise<Room[]>;
deleteRoom(room: string): Promise<void>;
/**
* Update metadata of a room
* @param room - name of the room
* @param metadata - the new metadata for the room
*/
updateRoomMetadata(room: string, metadata: string): Promise<Room>;
/**
* List participants in a room
* @param room - name of the room
*/
listParticipants(room: string): Promise<ParticipantInfo[]>;
/**
* Get information on a specific participant, including the tracks that participant
* has published
* @param room - name of the room
* @param identity - identity of the participant to return
*/
getParticipant(room: string, identity: string): Promise<ParticipantInfo>;
/**
* Removes a participant in the room. This will disconnect the participant
* and will emit a Disconnected event for that participant.
* Even after being removed, the participant can still re-join the room.
* @param room -
* @param identity -
* @param options - removal options
*/
removeParticipant(room: string, identity: string, options?: RemoveParticipantOptions): Promise<void>;
/**
* Forwards a participant's track to another room. This will create a
* participant to join the destination room that has same information
* with the source participant except the kind to be `Forwarded`. All
* changes to the source participant will be reflected to the forwarded
* participant. When the source participant disconnects or the
* `RemoveParticipant` method is called in the destination room, the
* forwarding will be stopped.
* @param room -
* @param identity -
* @param destinationRoom - the room to forward the participant to
*/
forwardParticipant(room: string, identity: string, destinationRoom: string): Promise<void>;
/**
* Move a connected participant to a different room. Requires `roomAdmin` and `destinationRoom`.
* The participant will be removed from the current room and added to the destination room.
* From the other observers' perspective, the participant would've disconnected from the previous room and joined the new one.
* @param room -
* @param identity -
* @param destinationRoom - the room to move the participant to
*/
moveParticipant(room: string, identity: string, destinationRoom: string): Promise<void>;
/**
* Mutes a track that the participant has published.
* @param room -
* @param identity -
* @param trackSid - sid of the track to be muted
* @param muted - true to mute, false to unmute
*/
mutePublishedTrack(room: string, identity: string, trackSid: string, muted: boolean): Promise<TrackInfo>;
/**
* Updates a participant's state or permissions
* @param room - target room
* @param identity - participant identity
* @param options - participant fields to update
*/
updateParticipant(room: string, identity: string, options: UpdateParticipantOptions): Promise<ParticipantInfo>;
/**
* Updates a participant's state or permissions
* @param room - target room
* @param identity - participant identity
* @param options - participant fields to update
*/
updateParticipant(room: string, identity: string, metadata?: string, permission?: Partial<ParticipantPermission>, name?: string): Promise<ParticipantInfo>;
/**
* Updates a participant's subscription to tracks
* @param room -
* @param identity -
* @param trackSids -
* @param subscribe - true to subscribe, false to unsubscribe
*/
updateSubscriptions(room: string, identity: string, trackSids: string[], subscribe: boolean): Promise<void>;
/**
* Sends data message to participants in the room
* @param room -
* @param data - opaque payload to send
* @param kind - delivery reliability
* @param options - optionally specify a topic and destinationSids (when destinationSids is empty, message is sent to everyone)
*/
sendData(room: string, data: Uint8Array, kind: DataPacket_Kind, options: SendDataOptions): Promise<void>;
/**
* Sends data message to participants in the room
* @deprecated use sendData(room, data, kind, options) instead
* @param room -
* @param data - opaque payload to send
* @param kind - delivery reliability
* @param destinationSids - optional. when empty, message is sent to everyone
*/
sendData(room: string, data: Uint8Array, kind: DataPacket_Kind, destinationSids?: string[]): Promise<void>;
}
export { type CreateOptions, type RemoveParticipantOptions, RoomServiceClient, type SendDataOptions, type UpdateParticipantOptions };
+208
View File
@@ -0,0 +1,208 @@
import { RoomEgress, RoomAgentDispatch, Room, ParticipantInfo, TrackInfo, ParticipantPermission, DataPacket_Kind } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.js';
import { ServiceBase } from './ServiceBase.js';
import './grants.js';
import 'jose';
/**
* Options for when creating a room
*/
interface CreateOptions {
/**
* name of the room. required
*/
name: string;
/**
* number of seconds to keep the room open before any participant joins
*/
emptyTimeout?: number;
/**
* number of seconds to keep the room open after the last participant leaves
* this option is helpful to give a grace period for participants to re-join
*/
departureTimeout?: number;
/**
* limit to the number of participants in a room at a time
*/
maxParticipants?: number;
/**
* initial room metadata
*/
metadata?: string;
/**
* add egress options
*/
egress?: RoomEgress;
/**
* minimum playout delay in milliseconds
*/
minPlayoutDelay?: number;
/**
* maximum playout delay in milliseconds
*/
maxPlayoutDelay?: number;
/**
* improves A/V sync when min_playout_delay set to a value larger than 200ms.
* It will disables transceiver re-use -- this option is not recommended
* for rooms with frequent subscription changes
*/
syncStreams?: boolean;
/**
* agents that should be dispatched to this room
*/
agents?: RoomAgentDispatch[];
/**
* override the node room is allocated to, for debugging
* does not work with Cloud
*/
nodeId?: string;
}
type SendDataOptions = {
/** If set, only deliver to listed participant identities */
destinationIdentities?: string[];
destinationSids?: string[];
topic?: string;
};
type UpdateParticipantOptions = {
/** only attributes you'd want to update should be set, set value to empty string to remove it */
attributes?: {
[key: string]: string;
};
metadata?: string;
/** permissions are updated atomically - all desired permissions would need to be set */
permission?: Partial<ParticipantPermission>;
name?: string;
};
type RemoveParticipantOptions = {
/**
* Unix timestamp used to invalidate tokens whose nbf is before this value.
*/
revokeTokenTs?: bigint;
};
/**
* Client to access Room APIs
*/
declare class RoomServiceClient extends ServiceBase {
private readonly rpc;
/**
*
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* Creates a new room. Explicit room creation is not required, since rooms will
* be automatically created when the first participant joins. This method can be
* used to customize room settings.
* @param options -
*/
createRoom(options: CreateOptions): Promise<Room>;
/**
* List active rooms
* @param names - when undefined or empty, list all rooms.
* otherwise returns rooms with matching names
* @returns
*/
listRooms(names?: string[]): Promise<Room[]>;
deleteRoom(room: string): Promise<void>;
/**
* Update metadata of a room
* @param room - name of the room
* @param metadata - the new metadata for the room
*/
updateRoomMetadata(room: string, metadata: string): Promise<Room>;
/**
* List participants in a room
* @param room - name of the room
*/
listParticipants(room: string): Promise<ParticipantInfo[]>;
/**
* Get information on a specific participant, including the tracks that participant
* has published
* @param room - name of the room
* @param identity - identity of the participant to return
*/
getParticipant(room: string, identity: string): Promise<ParticipantInfo>;
/**
* Removes a participant in the room. This will disconnect the participant
* and will emit a Disconnected event for that participant.
* Even after being removed, the participant can still re-join the room.
* @param room -
* @param identity -
* @param options - removal options
*/
removeParticipant(room: string, identity: string, options?: RemoveParticipantOptions): Promise<void>;
/**
* Forwards a participant's track to another room. This will create a
* participant to join the destination room that has same information
* with the source participant except the kind to be `Forwarded`. All
* changes to the source participant will be reflected to the forwarded
* participant. When the source participant disconnects or the
* `RemoveParticipant` method is called in the destination room, the
* forwarding will be stopped.
* @param room -
* @param identity -
* @param destinationRoom - the room to forward the participant to
*/
forwardParticipant(room: string, identity: string, destinationRoom: string): Promise<void>;
/**
* Move a connected participant to a different room. Requires `roomAdmin` and `destinationRoom`.
* The participant will be removed from the current room and added to the destination room.
* From the other observers' perspective, the participant would've disconnected from the previous room and joined the new one.
* @param room -
* @param identity -
* @param destinationRoom - the room to move the participant to
*/
moveParticipant(room: string, identity: string, destinationRoom: string): Promise<void>;
/**
* Mutes a track that the participant has published.
* @param room -
* @param identity -
* @param trackSid - sid of the track to be muted
* @param muted - true to mute, false to unmute
*/
mutePublishedTrack(room: string, identity: string, trackSid: string, muted: boolean): Promise<TrackInfo>;
/**
* Updates a participant's state or permissions
* @param room - target room
* @param identity - participant identity
* @param options - participant fields to update
*/
updateParticipant(room: string, identity: string, options: UpdateParticipantOptions): Promise<ParticipantInfo>;
/**
* Updates a participant's state or permissions
* @param room - target room
* @param identity - participant identity
* @param options - participant fields to update
*/
updateParticipant(room: string, identity: string, metadata?: string, permission?: Partial<ParticipantPermission>, name?: string): Promise<ParticipantInfo>;
/**
* Updates a participant's subscription to tracks
* @param room -
* @param identity -
* @param trackSids -
* @param subscribe - true to subscribe, false to unsubscribe
*/
updateSubscriptions(room: string, identity: string, trackSids: string[], subscribe: boolean): Promise<void>;
/**
* Sends data message to participants in the room
* @param room -
* @param data - opaque payload to send
* @param kind - delivery reliability
* @param options - optionally specify a topic and destinationSids (when destinationSids is empty, message is sent to everyone)
*/
sendData(room: string, data: Uint8Array, kind: DataPacket_Kind, options: SendDataOptions): Promise<void>;
/**
* Sends data message to participants in the room
* @deprecated use sendData(room, data, kind, options) instead
* @param room -
* @param data - opaque payload to send
* @param kind - delivery reliability
* @param destinationSids - optional. when empty, message is sent to everyone
*/
sendData(room: string, data: Uint8Array, kind: DataPacket_Kind, destinationSids?: string[]): Promise<void>;
}
export { type CreateOptions, type RemoveParticipantOptions, RoomServiceClient, type SendDataOptions, type UpdateParticipantOptions };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"RoomServiceClient.d.ts","sourceRoot":"","sources":["../src/RoomServiceClient.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnG,OAAO,EAWL,eAAe,EACf,qBAAqB,EACrB,IAAI,EAML,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IAEpB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;OAEG;IACH,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAE7B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,4DAA4D;IAC5D,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,iGAAiG;IACjG,UAAU,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,UAAU,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAIF;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,WAAW;IAChD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAE1B;;;;;;OAMG;gBACS,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa;IAQnF;;;;;OAKG;IACG,UAAU,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAUvD;;;;;OAKG;IACG,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAW5C,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7C;;;;OAIG;IACG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;IAUvD;;;OAGG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IAWhE;;;;;OAKG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAW9E;;;;;;;OAOG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,IAAI,CAAC;IAahB;;;;;;;;;;;OAWG;IACG,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAShG;;;;;;;OAOG;IACG,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7F;;;;;;OAMG;IACG,kBAAkB,CACtB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,SAAS,CAAC;IAiBrB;;;;;OAKG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,eAAe,CAAC;IAC3B;;;;;OAKG;IACG,iBAAiB,CACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,EAC3C,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,CAAC;IAmC3B;;;;;;OAMG;IACG,mBAAmB,CACvB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EAAE,EACnB,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,IAAI,CAAC;IAgBhB;;;;;;OAMG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,IAAI,CAAC;IAChB;;;;;;;OAOG;IACG,QAAQ,CACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,eAAe,EACrB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,IAAI,CAAC;CA2BjB"}
+272
View File
@@ -0,0 +1,272 @@
import {
CreateRoomRequest,
DeleteRoomRequest,
ForwardParticipantRequest,
ListParticipantsRequest,
ListParticipantsResponse,
ListRoomsRequest,
ListRoomsResponse,
MoveParticipantRequest,
MuteRoomTrackRequest,
MuteRoomTrackResponse,
ParticipantInfo,
ParticipantPermission,
Room,
RoomParticipantIdentity,
SendDataRequest,
UpdateParticipantRequest,
UpdateRoomMetadataRequest,
UpdateSubscriptionsRequest
} from "@livekit/protocol";
import { ServiceBase } from "./ServiceBase.js";
import { TwirpRpc, livekitPackage } from "./TwirpRPC.js";
import { getRandomBytes } from "./crypto/uuid.js";
const svc = "RoomService";
class RoomServiceClient extends ServiceBase {
/**
*
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new TwirpRpc(host, livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* Creates a new room. Explicit room creation is not required, since rooms will
* be automatically created when the first participant joins. This method can be
* used to customize room settings.
* @param options -
*/
async createRoom(options) {
const data = await this.rpc.request(
svc,
"CreateRoom",
new CreateRoomRequest(options).toJson(),
await this.authHeader({ roomCreate: true })
);
return Room.fromJson(data, { ignoreUnknownFields: true });
}
/**
* List active rooms
* @param names - when undefined or empty, list all rooms.
* otherwise returns rooms with matching names
* @returns
*/
async listRooms(names) {
const data = await this.rpc.request(
svc,
"ListRooms",
new ListRoomsRequest({ names: names ?? [] }).toJson(),
await this.authHeader({ roomList: true })
);
const res = ListRoomsResponse.fromJson(data, { ignoreUnknownFields: true });
return res.rooms ?? [];
}
async deleteRoom(room) {
await this.rpc.request(
svc,
"DeleteRoom",
new DeleteRoomRequest({ room }).toJson(),
await this.authHeader({ roomCreate: true })
);
}
/**
* Update metadata of a room
* @param room - name of the room
* @param metadata - the new metadata for the room
*/
async updateRoomMetadata(room, metadata) {
const data = await this.rpc.request(
svc,
"UpdateRoomMetadata",
new UpdateRoomMetadataRequest({ room, metadata }).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
return Room.fromJson(data, { ignoreUnknownFields: true });
}
/**
* List participants in a room
* @param room - name of the room
*/
async listParticipants(room) {
const data = await this.rpc.request(
svc,
"ListParticipants",
new ListParticipantsRequest({ room }).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
const res = ListParticipantsResponse.fromJson(data, { ignoreUnknownFields: true });
return res.participants ?? [];
}
/**
* Get information on a specific participant, including the tracks that participant
* has published
* @param room - name of the room
* @param identity - identity of the participant to return
*/
async getParticipant(room, identity) {
const data = await this.rpc.request(
svc,
"GetParticipant",
new RoomParticipantIdentity({ room, identity }).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
return ParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Removes a participant in the room. This will disconnect the participant
* and will emit a Disconnected event for that participant.
* Even after being removed, the participant can still re-join the room.
* @param room -
* @param identity -
* @param options - removal options
*/
async removeParticipant(room, identity, options) {
await this.rpc.request(
svc,
"RemoveParticipant",
new RoomParticipantIdentity({
room,
identity,
revokeTokenTs: options == null ? void 0 : options.revokeTokenTs
}).toJson(),
await this.authHeader({ roomAdmin: true, room })
);
}
/**
* Forwards a participant's track to another room. This will create a
* participant to join the destination room that has same information
* with the source participant except the kind to be `Forwarded`. All
* changes to the source participant will be reflected to the forwarded
* participant. When the source participant disconnects or the
* `RemoveParticipant` method is called in the destination room, the
* forwarding will be stopped.
* @param room -
* @param identity -
* @param destinationRoom - the room to forward the participant to
*/
async forwardParticipant(room, identity, destinationRoom) {
await this.rpc.request(
svc,
"ForwardParticipant",
new ForwardParticipantRequest({ room, identity, destinationRoom }).toJson(),
await this.authHeader({ roomAdmin: true, room, destinationRoom })
);
}
/**
* Move a connected participant to a different room. Requires `roomAdmin` and `destinationRoom`.
* The participant will be removed from the current room and added to the destination room.
* From the other observers' perspective, the participant would've disconnected from the previous room and joined the new one.
* @param room -
* @param identity -
* @param destinationRoom - the room to move the participant to
*/
async moveParticipant(room, identity, destinationRoom) {
await this.rpc.request(
svc,
"MoveParticipant",
new MoveParticipantRequest({ room, identity, destinationRoom }).toJson(),
await this.authHeader({ roomAdmin: true, room, destinationRoom })
);
}
/**
* Mutes a track that the participant has published.
* @param room -
* @param identity -
* @param trackSid - sid of the track to be muted
* @param muted - true to mute, false to unmute
*/
async mutePublishedTrack(room, identity, trackSid, muted) {
const req = new MuteRoomTrackRequest({
room,
identity,
trackSid,
muted
}).toJson();
const data = await this.rpc.request(
svc,
"MutePublishedTrack",
req,
await this.authHeader({ roomAdmin: true, room })
);
const res = MuteRoomTrackResponse.fromJson(data, { ignoreUnknownFields: true });
return res.track;
}
async updateParticipant(room, identity, metadataOrOptions, maybePermission, maybeName) {
const hasOptions = typeof metadataOrOptions === "object";
const metadata = hasOptions ? metadataOrOptions == null ? void 0 : metadataOrOptions.metadata : metadataOrOptions;
const permission = hasOptions ? metadataOrOptions.permission : maybePermission;
const name = hasOptions ? metadataOrOptions.name : maybeName;
const attributes = hasOptions ? metadataOrOptions.attributes : {};
const req = new UpdateParticipantRequest({
room,
identity,
attributes,
metadata,
name
});
if (permission) {
req.permission = new ParticipantPermission(permission);
}
const data = await this.rpc.request(
svc,
"UpdateParticipant",
req.toJson(),
await this.authHeader({ roomAdmin: true, room })
);
return ParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates a participant's subscription to tracks
* @param room -
* @param identity -
* @param trackSids -
* @param subscribe - true to subscribe, false to unsubscribe
*/
async updateSubscriptions(room, identity, trackSids, subscribe) {
const req = new UpdateSubscriptionsRequest({
room,
identity,
trackSids,
subscribe,
participantTracks: []
}).toJson();
await this.rpc.request(
svc,
"UpdateSubscriptions",
req,
await this.authHeader({ roomAdmin: true, room })
);
}
async sendData(room, data, kind, options = {}) {
const destinationSids = Array.isArray(options) ? options : options.destinationSids;
const topic = Array.isArray(options) ? void 0 : options.topic;
const req = new SendDataRequest({
room,
data,
kind,
destinationSids: destinationSids ?? [],
topic
});
if (!Array.isArray(options) && options.destinationIdentities) {
req.destinationIdentities = options.destinationIdentities;
}
req.nonce = await getRandomBytes(16);
await this.rpc.request(
svc,
"SendData",
req.toJson(),
await this.authHeader({ roomAdmin: true, room })
);
}
}
export {
RoomServiceClient
};
//# sourceMappingURL=RoomServiceClient.js.map
File diff suppressed because one or more lines are too long
+53
View File
@@ -0,0 +1,53 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var ServiceBase_exports = {};
__export(ServiceBase_exports, {
ServiceBase: () => ServiceBase
});
module.exports = __toCommonJS(ServiceBase_exports);
var import_AccessToken = require("./AccessToken.cjs");
class ServiceBase {
constructor(apiKeyOrOptions, secret, ttl) {
const options = typeof apiKeyOrOptions === "object" ? apiKeyOrOptions : { apiKey: apiKeyOrOptions, secret, ttl };
this.apiKey = options.apiKey;
this.secret = options.secret;
this.ttl = options.ttl || "10m";
this.token = options.token;
}
async authHeader(grant, sip) {
if (this.token) {
return { Authorization: `Bearer ${this.token}` };
}
const at = new import_AccessToken.AccessToken(this.apiKey, this.secret, { ttl: this.ttl });
if (grant) {
at.addGrant(grant);
}
if (sip) {
at.addSIPGrant(sip);
}
return {
Authorization: `Bearer ${await at.toJwt()}`
};
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ServiceBase
});
//# sourceMappingURL=ServiceBase.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/ServiceBase.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AccessToken } from './AccessToken.js';\nimport type { SIPGrant, VideoGrant } from './grants.js';\n\n/**\n * Authentication options for a service client.\n */\nexport interface ServiceBaseOptions {\n /** API Key. */\n apiKey?: string;\n /** API Secret. */\n secret?: string;\n /** Token TTL. Defaults to `10m`. */\n ttl?: string;\n /** Pre-signed token; sent verbatim, skipping per-call signing. */\n token?: string;\n}\n\n/**\n * Utilities to handle authentication\n */\nexport class ServiceBase {\n private readonly apiKey?: string;\n\n private readonly secret?: string;\n\n private readonly token?: string;\n\n private readonly ttl: string;\n\n /**\n * @param options - authentication options\n */\n constructor(options?: ServiceBaseOptions);\n /**\n * @deprecated pass a {@link ServiceBaseOptions} object instead.\n * @param apiKey - API Key.\n * @param secret - API Secret.\n * @param ttl - token TTL\n */\n constructor(apiKey?: string, secret?: string, ttl?: string);\n constructor(apiKeyOrOptions?: string | ServiceBaseOptions, secret?: string, ttl?: string) {\n const options: ServiceBaseOptions =\n typeof apiKeyOrOptions === 'object'\n ? apiKeyOrOptions\n : { apiKey: apiKeyOrOptions, secret, ttl };\n this.apiKey = options.apiKey;\n this.secret = options.secret;\n this.ttl = options.ttl || '10m';\n this.token = options.token;\n }\n\n async authHeader(grant: VideoGrant, sip?: SIPGrant): Promise<Record<string, string>> {\n // A pre-signed token is sent verbatim; the caller is responsible for its grants.\n if (this.token) {\n return { Authorization: `Bearer ${this.token}` };\n }\n const at = new AccessToken(this.apiKey, this.secret, { ttl: this.ttl });\n if (grant) {\n at.addGrant(grant);\n }\n if (sip) {\n at.addSIPGrant(sip);\n }\n return {\n Authorization: `Bearer ${await at.toJwt()}`,\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,yBAA4B;AAoBrB,MAAM,YAAY;AAAA,EAoBvB,YAAY,iBAA+C,QAAiB,KAAc;AACxF,UAAM,UACJ,OAAO,oBAAoB,WACvB,kBACA,EAAE,QAAQ,iBAAiB,QAAQ,IAAI;AAC7C,SAAK,SAAS,QAAQ;AACtB,SAAK,SAAS,QAAQ;AACtB,SAAK,MAAM,QAAQ,OAAO;AAC1B,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAEA,MAAM,WAAW,OAAmB,KAAiD;AAEnF,QAAI,KAAK,OAAO;AACd,aAAO,EAAE,eAAe,UAAU,KAAK,KAAK,GAAG;AAAA,IACjD;AACA,UAAM,KAAK,IAAI,+BAAY,KAAK,QAAQ,KAAK,QAAQ,EAAE,KAAK,KAAK,IAAI,CAAC;AACtE,QAAI,OAAO;AACT,SAAG,SAAS,KAAK;AAAA,IACnB;AACA,QAAI,KAAK;AACP,SAAG,YAAY,GAAG;AAAA,IACpB;AACA,WAAO;AAAA,MACL,eAAe,UAAU,MAAM,GAAG,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;","names":[]}
+40
View File
@@ -0,0 +1,40 @@
import { VideoGrant, SIPGrant } from './grants.cjs';
import '@livekit/protocol';
import 'jose';
/**
* Authentication options for a service client.
*/
interface ServiceBaseOptions {
/** API Key. */
apiKey?: string;
/** API Secret. */
secret?: string;
/** Token TTL. Defaults to `10m`. */
ttl?: string;
/** Pre-signed token; sent verbatim, skipping per-call signing. */
token?: string;
}
/**
* Utilities to handle authentication
*/
declare class ServiceBase {
private readonly apiKey?;
private readonly secret?;
private readonly token?;
private readonly ttl;
/**
* @param options - authentication options
*/
constructor(options?: ServiceBaseOptions);
/**
* @deprecated pass a {@link ServiceBaseOptions} object instead.
* @param apiKey - API Key.
* @param secret - API Secret.
* @param ttl - token TTL
*/
constructor(apiKey?: string, secret?: string, ttl?: string);
authHeader(grant: VideoGrant, sip?: SIPGrant): Promise<Record<string, string>>;
}
export { ServiceBase, type ServiceBaseOptions };
+40
View File
@@ -0,0 +1,40 @@
import { VideoGrant, SIPGrant } from './grants.js';
import '@livekit/protocol';
import 'jose';
/**
* Authentication options for a service client.
*/
interface ServiceBaseOptions {
/** API Key. */
apiKey?: string;
/** API Secret. */
secret?: string;
/** Token TTL. Defaults to `10m`. */
ttl?: string;
/** Pre-signed token; sent verbatim, skipping per-call signing. */
token?: string;
}
/**
* Utilities to handle authentication
*/
declare class ServiceBase {
private readonly apiKey?;
private readonly secret?;
private readonly token?;
private readonly ttl;
/**
* @param options - authentication options
*/
constructor(options?: ServiceBaseOptions);
/**
* @deprecated pass a {@link ServiceBaseOptions} object instead.
* @param apiKey - API Key.
* @param secret - API Secret.
* @param ttl - token TTL
*/
constructor(apiKey?: string, secret?: string, ttl?: string);
authHeader(grant: VideoGrant, sip?: SIPGrant): Promise<Record<string, string>>;
}
export { ServiceBase, type ServiceBaseOptions };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"ServiceBase.d.ts","sourceRoot":"","sources":["../src/ServiceBase.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,eAAe;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAEhC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B;;OAEG;gBACS,OAAO,CAAC,EAAE,kBAAkB;IACxC;;;;;OAKG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM;IAYpD,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAgBrF"}
+29
View File
@@ -0,0 +1,29 @@
import { AccessToken } from "./AccessToken.js";
class ServiceBase {
constructor(apiKeyOrOptions, secret, ttl) {
const options = typeof apiKeyOrOptions === "object" ? apiKeyOrOptions : { apiKey: apiKeyOrOptions, secret, ttl };
this.apiKey = options.apiKey;
this.secret = options.secret;
this.ttl = options.ttl || "10m";
this.token = options.token;
}
async authHeader(grant, sip) {
if (this.token) {
return { Authorization: `Bearer ${this.token}` };
}
const at = new AccessToken(this.apiKey, this.secret, { ttl: this.ttl });
if (grant) {
at.addGrant(grant);
}
if (sip) {
at.addSIPGrant(sip);
}
return {
Authorization: `Bearer ${await at.toJwt()}`
};
}
}
export {
ServiceBase
};
//# sourceMappingURL=ServiceBase.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/ServiceBase.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport { AccessToken } from './AccessToken.js';\nimport type { SIPGrant, VideoGrant } from './grants.js';\n\n/**\n * Authentication options for a service client.\n */\nexport interface ServiceBaseOptions {\n /** API Key. */\n apiKey?: string;\n /** API Secret. */\n secret?: string;\n /** Token TTL. Defaults to `10m`. */\n ttl?: string;\n /** Pre-signed token; sent verbatim, skipping per-call signing. */\n token?: string;\n}\n\n/**\n * Utilities to handle authentication\n */\nexport class ServiceBase {\n private readonly apiKey?: string;\n\n private readonly secret?: string;\n\n private readonly token?: string;\n\n private readonly ttl: string;\n\n /**\n * @param options - authentication options\n */\n constructor(options?: ServiceBaseOptions);\n /**\n * @deprecated pass a {@link ServiceBaseOptions} object instead.\n * @param apiKey - API Key.\n * @param secret - API Secret.\n * @param ttl - token TTL\n */\n constructor(apiKey?: string, secret?: string, ttl?: string);\n constructor(apiKeyOrOptions?: string | ServiceBaseOptions, secret?: string, ttl?: string) {\n const options: ServiceBaseOptions =\n typeof apiKeyOrOptions === 'object'\n ? apiKeyOrOptions\n : { apiKey: apiKeyOrOptions, secret, ttl };\n this.apiKey = options.apiKey;\n this.secret = options.secret;\n this.ttl = options.ttl || '10m';\n this.token = options.token;\n }\n\n async authHeader(grant: VideoGrant, sip?: SIPGrant): Promise<Record<string, string>> {\n // A pre-signed token is sent verbatim; the caller is responsible for its grants.\n if (this.token) {\n return { Authorization: `Bearer ${this.token}` };\n }\n const at = new AccessToken(this.apiKey, this.secret, { ttl: this.ttl });\n if (grant) {\n at.addGrant(grant);\n }\n if (sip) {\n at.addSIPGrant(sip);\n }\n return {\n Authorization: `Bearer ${await at.toJwt()}`,\n };\n }\n}\n"],"mappings":"AAGA,SAAS,mBAAmB;AAoBrB,MAAM,YAAY;AAAA,EAoBvB,YAAY,iBAA+C,QAAiB,KAAc;AACxF,UAAM,UACJ,OAAO,oBAAoB,WACvB,kBACA,EAAE,QAAQ,iBAAiB,QAAQ,IAAI;AAC7C,SAAK,SAAS,QAAQ;AACtB,SAAK,SAAS,QAAQ;AACtB,SAAK,MAAM,QAAQ,OAAO;AAC1B,SAAK,QAAQ,QAAQ;AAAA,EACvB;AAAA,EAEA,MAAM,WAAW,OAAmB,KAAiD;AAEnF,QAAI,KAAK,OAAO;AACd,aAAO,EAAE,eAAe,UAAU,KAAK,KAAK,GAAG;AAAA,IACjD;AACA,UAAM,KAAK,IAAI,YAAY,KAAK,QAAQ,KAAK,QAAQ,EAAE,KAAK,KAAK,IAAI,CAAC;AACtE,QAAI,OAAO;AACT,SAAG,SAAS,KAAK;AAAA,IACnB;AACA,QAAI,KAAK;AACP,SAAG,YAAY,GAAG;AAAA,IACpB;AACA,WAAO;AAAA,MACL,eAAe,UAAU,MAAM,GAAG,MAAM,CAAC;AAAA,IAC3C;AAAA,EACF;AACF;","names":[]}
+560
View File
@@ -0,0 +1,560 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var SipClient_exports = {};
__export(SipClient_exports, {
SipClient: () => SipClient
});
module.exports = __toCommonJS(SipClient_exports);
var import_protobuf = require("@bufbuild/protobuf");
var import_protocol = require("@livekit/protocol");
var import_ServiceBase = require("./ServiceBase.cjs");
var import_TwirpRPC = require("./TwirpRPC.cjs");
var import_dialTimeout = require("./dialTimeout.cjs");
function asSipCallError(e) {
if (e instanceof import_TwirpRPC.ServerError && e.metadata && "sip_status_code" in e.metadata) {
return import_TwirpRPC.SipCallError.fromServerError(e);
}
return e;
}
const svc = "SIP";
class SipClient extends import_ServiceBase.ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new import_TwirpRPC.TwirpRpc(host, import_TwirpRPC.livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* @param number - phone number of the trunk
* @param opts - CreateSipTrunkOptions
* @deprecated use `createSipInboundTrunk` or `createSipOutboundTrunk`
*/
async createSipTrunk(number, opts) {
let inboundAddresses;
let inboundNumbers;
let inboundUsername = "";
let inboundPassword = "";
let outboundAddress = "";
let outboundUsername = "";
let outboundPassword = "";
let name = "";
let metadata = "";
if (opts !== void 0) {
inboundAddresses = opts.inbound_addresses;
inboundNumbers = opts.inbound_numbers;
inboundUsername = opts.inbound_username || "";
inboundPassword = opts.inbound_password || "";
outboundAddress = opts.outbound_address || "";
outboundUsername = opts.outbound_username || "";
outboundPassword = opts.outbound_password || "";
name = opts.name || "";
metadata = opts.metadata || "";
}
const req = new import_protocol.CreateSIPTrunkRequest({
name,
metadata,
inboundAddresses,
inboundNumbers,
inboundUsername,
inboundPassword,
outboundNumber: number,
outboundAddress,
outboundUsername,
outboundPassword
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP inbound trunk.
*
* @param name - human-readable name of the trunk
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP inbound trunk
*/
async createSipInboundTrunk(name, numbers, opts) {
if (opts === void 0) {
opts = {};
}
const req = new import_protocol.CreateSIPInboundTrunkRequest({
trunk: new import_protocol.SIPInboundTrunkInfo({
name,
numbers,
metadata: opts == null ? void 0 : opts.metadata,
allowedAddresses: opts.allowedAddresses ?? opts.allowed_addresses,
allowedNumbers: opts.allowedNumbers ?? opts.allowed_numbers,
authUsername: opts.authUsername ?? opts.auth_username,
authPassword: opts.authPassword ?? opts.auth_password,
headers: opts.headers,
headersToAttributes: opts.headersToAttributes,
includeHeaders: opts.includeHeaders,
krispEnabled: opts.krispEnabled,
mediaEncryption: opts.mediaEncryption,
media: opts.media,
ringingTimeout: opts.ringingTimeout ? new import_protobuf.Duration({ seconds: BigInt(opts.ringingTimeout) }) : void 0
})
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPInboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP outbound trunk.
*
* @param name - human-readable name of the trunk
* @param address - hostname and port of the SIP server to dial
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP outbound trunk
*/
async createSipOutboundTrunk(name, address, numbers, opts) {
if (opts === void 0) {
opts = {
transport: import_protocol.SIPTransport.SIP_TRANSPORT_AUTO
};
}
const req = new import_protocol.CreateSIPOutboundTrunkRequest({
trunk: new import_protocol.SIPOutboundTrunkInfo({
name,
address,
numbers,
metadata: opts.metadata,
transport: opts.transport,
authUsername: opts.authUsername ?? opts.auth_username,
authPassword: opts.authPassword ?? opts.auth_password,
headers: opts.headers,
headersToAttributes: opts.headersToAttributes,
includeHeaders: opts.includeHeaders,
destinationCountry: opts.destinationCountry,
mediaEncryption: opts.mediaEncryption,
media: opts.media
})
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPOutboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @deprecated use `listSipInboundTrunk` or `listSipOutboundTrunk`
*/
async listSipTrunk() {
const req = {};
const data = await this.rpc.request(
svc,
"ListSIPTrunk",
new import_protocol.ListSIPTrunkRequest(req).toJson(),
await this.authHeader({}, { admin: true })
);
return import_protocol.ListSIPTrunkResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* List SIP inbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP inbound trunks
*/
async listSipInboundTrunk(list = {}) {
const req = new import_protocol.ListSIPInboundTrunkRequest(list).toJson();
const data = await this.rpc.request(
svc,
"ListSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.ListSIPInboundTrunkResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* List SIP outbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP outbound trunks
*/
async listSipOutboundTrunk(list = {}) {
const req = new import_protocol.ListSIPOutboundTrunkRequest(list).toJson();
const data = await this.rpc.request(
svc,
"ListSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.ListSIPOutboundTrunkResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* Delete a SIP trunk.
*
* @param sipTrunkId - ID of the SIP trunk to delete
* @returns Deleted trunk information
*/
async deleteSipTrunk(sipTrunkId) {
const data = await this.rpc.request(
svc,
"DeleteSIPTrunk",
new import_protocol.DeleteSIPTrunkRequest({ sipTrunkId }).toJson(),
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP dispatch rule.
*
* @param rule - SIP dispatch rule to create
* @param opts - CreateSipDispatchRuleOptions
* @returns Created SIP dispatch rule
*/
async createSipDispatchRule(rule, opts) {
if (opts === void 0) {
opts = {};
}
let ruleProto = void 0;
if (rule.type == "direct") {
ruleProto = new import_protocol.SIPDispatchRule({
rule: {
case: "dispatchRuleDirect",
value: new import_protocol.SIPDispatchRuleDirect({
roomName: rule.roomName,
pin: rule.pin || ""
})
}
});
} else if (rule.type == "individual") {
ruleProto = new import_protocol.SIPDispatchRule({
rule: {
case: "dispatchRuleIndividual",
value: new import_protocol.SIPDispatchRuleIndividual({
roomPrefix: rule.roomPrefix,
pin: rule.pin || ""
})
}
});
} else if (rule.type == "callee") {
ruleProto = new import_protocol.SIPDispatchRule({
rule: {
case: "dispatchRuleCallee",
value: new import_protocol.SIPDispatchRuleCallee({
roomPrefix: rule.roomPrefix,
pin: rule.pin || "",
randomize: rule.randomize || false
})
}
});
}
const req = new import_protocol.CreateSIPDispatchRuleRequest({
rule: ruleProto,
trunkIds: opts.trunkIds,
hidePhoneNumber: opts.hidePhoneNumber,
name: opts.name,
metadata: opts.metadata,
attributes: opts.attributes,
roomPreset: opts.roomPreset,
roomConfig: opts.roomConfig
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates an existing SIP dispatch rule by replacing it entirely.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param rule - new SIP dispatch rule
* @returns Updated SIP dispatch rule
*/
async updateSipDispatchRule(sipDispatchRuleId, rule) {
const req = new import_protocol.UpdateSIPDispatchRuleRequest({
sipDispatchRuleId,
action: {
case: "replace",
value: rule
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates specific fields of an existing SIP dispatch rule.
* Only provided fields will be updated.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param fields - Fields of the dispatch rule to update
* @returns Updated SIP dispatch rule
*/
async updateSipDispatchRuleFields(sipDispatchRuleId, fields = {}) {
const req = new import_protocol.UpdateSIPDispatchRuleRequest({
sipDispatchRuleId,
action: {
case: "update",
value: fields
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates an existing SIP inbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param trunk - SIP inbound trunk to update with
* @returns Updated SIP inbound trunk
*/
async updateSipInboundTrunk(sipTrunkId, trunk) {
const req = new import_protocol.UpdateSIPInboundTrunkRequest({
sipTrunkId,
action: {
case: "replace",
value: trunk
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPInboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates specific fields of an existing SIP inbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param fields - Fields of the inbound trunk to update
* @returns Updated SIP inbound trunk
*/
async updateSipInboundTrunkFields(sipTrunkId, fields) {
const req = new import_protocol.UpdateSIPInboundTrunkRequest({
sipTrunkId,
action: {
case: "update",
value: fields
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPInboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates an existing SIP outbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param trunk - SIP outbound trunk to update with
* @returns Updated SIP outbound trunk
*/
async updateSipOutboundTrunk(sipTrunkId, trunk) {
const req = new import_protocol.UpdateSIPOutboundTrunkRequest({
sipTrunkId,
action: {
case: "replace",
value: trunk
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPOutboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates specific fields of an existing SIP outbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param fields - Fields of the outbound trunk to update
* @returns Updated SIP outbound trunk
*/
async updateSipOutboundTrunkFields(sipTrunkId, fields) {
const req = new import_protocol.UpdateSIPOutboundTrunkRequest({
sipTrunkId,
action: {
case: "update",
value: fields
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPOutboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* List SIP dispatch rules with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP dispatch rules
*/
async listSipDispatchRule(list = {}) {
const req = new import_protocol.ListSIPDispatchRuleRequest(list).toJson();
const data = await this.rpc.request(
svc,
"ListSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return import_protocol.ListSIPDispatchRuleResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* Delete a SIP dispatch rule.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to delete
* @returns Deleted rule information
*/
async deleteSipDispatchRule(sipDispatchRuleId) {
const data = await this.rpc.request(
svc,
"DeleteSIPDispatchRule",
new import_protocol.DeleteSIPDispatchRuleRequest({ sipDispatchRuleId }).toJson(),
await this.authHeader({}, { admin: true })
);
return import_protocol.SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP participant.
*
* @param sipTrunkId - sip trunk to use for the call
* @param number - number to dial
* @param roomName - room to attach the call to
* @param opts - CreateSipParticipantOptions
* @param outboundTrunkConfig - Optional outbound trunk configuration for sip participant.
* @returns Created SIP participant
*/
async createSipParticipant(sipTrunkId, number, roomName, opts, outboundTrunkConfig) {
if (opts === void 0) {
opts = {};
}
if (opts.waitUntilAnswered) {
opts.ringingTimeout ??= import_dialTimeout.DEFAULT_RINGING_TIMEOUT_SECONDS;
opts.timeout = (0, import_dialTimeout.dialRequestTimeout)(opts.timeout, opts.ringingTimeout);
}
const req = new import_protocol.CreateSIPParticipantRequest({
sipTrunkId,
trunk: outboundTrunkConfig,
sipCallTo: number,
sipNumber: opts.fromNumber,
roomName,
participantIdentity: opts.participantIdentity || "sip-participant",
participantName: opts.participantName,
displayName: opts.displayName,
participantMetadata: opts.participantMetadata,
participantAttributes: opts.participantAttributes,
dtmf: opts.dtmf,
playDialtone: opts.playDialtone ?? opts.playRingtone,
headers: opts.headers,
hidePhoneNumber: opts.hidePhoneNumber,
includeHeaders: opts.includeHeaders,
ringingTimeout: opts.ringingTimeout ? new import_protobuf.Duration({ seconds: BigInt(opts.ringingTimeout) }) : void 0,
maxCallDuration: opts.maxCallDuration ? new import_protobuf.Duration({ seconds: BigInt(opts.maxCallDuration) }) : void 0,
krispEnabled: opts.krispEnabled,
waitUntilAnswered: opts.waitUntilAnswered,
media: opts.media
}).toJson();
try {
const data = await this.rpc.request(
svc,
"CreateSIPParticipant",
req,
await this.authHeader({}, { call: true }),
opts.timeout
);
return import_protocol.SIPParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
} catch (e) {
throw asSipCallError(e);
}
}
/**
* Transfer a SIP participant to a different room.
*
* @param roomName - room the SIP participant to transfer is connectd to
* @param participantIdentity - identity of the SIP participant to transfer
* @param transferTo - SIP URL to transfer the participant to
* @param opts - TransferSipParticipantOptions
*/
async transferSipParticipant(roomName, participantIdentity, transferTo, opts) {
if (opts === void 0) {
opts = {};
}
opts.ringingTimeout ??= import_dialTimeout.DEFAULT_RINGING_TIMEOUT_SECONDS;
opts.timeout = (0, import_dialTimeout.dialRequestTimeout)(opts.timeout, opts.ringingTimeout);
const req = new import_protocol.TransferSIPParticipantRequest({
participantIdentity,
roomName,
transferTo,
playDialtone: opts.playDialtone,
headers: opts.headers,
ringingTimeout: opts.ringingTimeout ? new import_protobuf.Duration({ seconds: BigInt(opts.ringingTimeout) }) : void 0
}).toJson();
try {
await this.rpc.request(
svc,
"TransferSIPParticipant",
req,
await this.authHeader({ roomAdmin: true, room: roomName }, { call: true }),
opts.timeout
);
} catch (e) {
throw asSipCallError(e);
}
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
SipClient
});
//# sourceMappingURL=SipClient.cjs.map
File diff suppressed because one or more lines are too long
+356
View File
@@ -0,0 +1,356 @@
import { SIPTrunkInfo, SIPHeaderOptions, SIPMediaEncryption, SIPMediaConfig, SIPInboundTrunkInfo, SIPTransport, SIPOutboundTrunkInfo, Pagination, RoomConfiguration, SIPDispatchRuleInfo, ListUpdate, SIPDispatchRule, SIPOutboundConfig, SIPParticipantInfo } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.cjs';
import { ServiceBase } from './ServiceBase.cjs';
import './grants.cjs';
import 'jose';
/**
* @deprecated use CreateSipInboundTrunkOptions or CreateSipOutboundTrunkOptions
*/
interface CreateSipTrunkOptions {
name?: string;
metadata?: string;
inbound_addresses?: string[];
inbound_numbers?: string[];
inbound_username?: string;
inbound_password?: string;
outbound_address?: string;
outbound_username?: string;
outbound_password?: string;
}
interface CreateSipInboundTrunkOptions {
metadata?: string;
/** @deprecated - use `allowedAddresses` instead */
allowed_addresses?: string[];
allowedAddresses?: string[];
/** @deprecated - use `allowedNumbers` instead */
allowed_numbers?: string[];
allowedNumbers?: string[];
/** @deprecated - use `authUsername` instead */
auth_username?: string;
authUsername?: string;
/** @deprecated - use `authPassword` instead */
auth_password?: string;
authPassword?: string;
headers?: {
[key: string]: string;
};
headersToAttributes?: {
[key: string]: string;
};
includeHeaders?: SIPHeaderOptions;
krispEnabled?: boolean;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
/** Maximum time for a call to ring in seconds. */
ringingTimeout?: number;
}
interface CreateSipOutboundTrunkOptions {
metadata?: string;
transport: SIPTransport;
destinationCountry?: string;
/** @deprecated - use `authUsername` instead */
auth_username?: string;
authUsername?: string;
/** @deprecated - use `authPassword` instead */
auth_password?: string;
authPassword?: string;
headers?: {
[key: string]: string;
};
headersToAttributes?: {
[key: string]: string;
};
includeHeaders?: SIPHeaderOptions;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
}
interface SipDispatchRuleDirect {
type: 'direct';
roomName: string;
pin?: string;
}
interface SipDispatchRuleIndividual {
type: 'individual';
roomPrefix: string;
pin?: string;
}
interface SipDispatchRuleCallee {
type: 'callee';
roomPrefix: string;
pin?: string;
/** Optionally append a random suffix to the room name. */
randomize?: boolean;
}
interface CreateSipDispatchRuleOptions {
name?: string;
metadata?: string;
trunkIds?: string[];
hidePhoneNumber?: boolean;
attributes?: {
[key: string]: string;
};
roomPreset?: string;
roomConfig?: RoomConfiguration;
}
interface CreateSipParticipantOptions {
/** Optional SIP From number to use. If empty, trunk number is used. */
fromNumber?: string;
/** Optional identity of the SIP participant */
participantIdentity?: string;
/** Optional name of the participant */
participantName?: string;
/** Optional display name for the SIP participant */
displayName?: string;
/** Optional metadata to attach to the participant */
participantMetadata?: string;
/** Optional attributes to attach to the participant */
participantAttributes?: {
[key: string]: string;
};
/** Optionally send following DTMF digits (extension codes) when making a call.
* Character 'w' can be used to add a 0.5 sec delay. */
dtmf?: string;
/** @deprecated use `playDialtone` instead */
playRingtone?: boolean;
/** If `true`, the SIP Participant plays a dial tone to the room until the phone is picked up. */
playDialtone?: boolean;
/** These headers are sent as-is and may help identify this call as coming from LiveKit for the other SIP endpoint. */
headers?: {
[key: string]: string;
};
/** Map SIP response headers from INVITE to sip.h.* participant attributes automatically. */
includeHeaders?: SIPHeaderOptions;
hidePhoneNumber?: boolean;
/** Maximum time for the call to ring in seconds. */
ringingTimeout?: number;
/** Maximum call duration in seconds. */
maxCallDuration?: number;
/** If `true`, Krisp noise cancellation will be enabled for the caller. */
krispEnabled?: boolean;
/** If `true`, this will wait until the call is answered before returning. */
waitUntilAnswered?: boolean;
/** Optional request timeout in seconds. Defaults to 30s when waitUntilAnswered is true (dialing takes time), otherwise the client default. */
timeout?: number;
media?: SIPMediaConfig;
}
interface ListSipDispatchRuleOptions {
/** Pagination options. */
page?: Pagination;
/** Rule IDs to list. If this option is set, the response will contains rules in the same order. If any of the rules is missing, a nil item in that position will be sent in the response. */
dispatchRuleIds?: string[];
/** Only list rules that contain one of the Trunk IDs, including wildcard rules. */
trunkIds?: string[];
}
interface ListSipTrunkOptions {
/** Pagination options. */
page?: Pagination;
/** Trunk IDs to list. If this option is set, the response will contains trunks in the same order. If any of the trunks is missing, a nil item in that position will be sent in the response. */
trunkIds?: string[];
/** Only list trunks that contain one of the numbers, including wildcard trunks. */
numbers?: string[];
}
interface SipDispatchRuleUpdateOptions {
trunkIds?: ListUpdate;
rule?: SIPDispatchRule;
name?: string;
metadata?: string;
attributes?: {
[key: string]: string;
};
}
interface SipInboundTrunkUpdateOptions {
numbers?: ListUpdate;
allowedAddresses?: ListUpdate;
allowedNumbers?: ListUpdate;
authUsername?: string;
authPassword?: string;
name?: string;
metadata?: string;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
}
interface SipOutboundTrunkUpdateOptions {
numbers?: ListUpdate;
allowedAddresses?: ListUpdate;
allowedNumbers?: ListUpdate;
authUsername?: string;
authPassword?: string;
destinationCountry?: string;
name?: string;
metadata?: string;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
}
interface TransferSipParticipantOptions {
playDialtone?: boolean;
headers?: {
[key: string]: string;
};
/** Maximum time for the transfer destination to answer the call, in seconds. */
ringingTimeout?: number;
/** Optional request timeout in seconds. Defaults to 30s (dialing takes time). */
timeout?: number;
}
/**
* Client to access Egress APIs
*/
declare class SipClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* @param number - phone number of the trunk
* @param opts - CreateSipTrunkOptions
* @deprecated use `createSipInboundTrunk` or `createSipOutboundTrunk`
*/
createSipTrunk(number: string, opts?: CreateSipTrunkOptions): Promise<SIPTrunkInfo>;
/**
* Create a new SIP inbound trunk.
*
* @param name - human-readable name of the trunk
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP inbound trunk
*/
createSipInboundTrunk(name: string, numbers: string[], opts?: CreateSipInboundTrunkOptions): Promise<SIPInboundTrunkInfo>;
/**
* Create a new SIP outbound trunk.
*
* @param name - human-readable name of the trunk
* @param address - hostname and port of the SIP server to dial
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP outbound trunk
*/
createSipOutboundTrunk(name: string, address: string, numbers: string[], opts?: CreateSipOutboundTrunkOptions): Promise<SIPOutboundTrunkInfo>;
/**
* @deprecated use `listSipInboundTrunk` or `listSipOutboundTrunk`
*/
listSipTrunk(): Promise<Array<SIPTrunkInfo>>;
/**
* List SIP inbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP inbound trunks
*/
listSipInboundTrunk(list?: ListSipTrunkOptions): Promise<Array<SIPInboundTrunkInfo>>;
/**
* List SIP outbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP outbound trunks
*/
listSipOutboundTrunk(list?: ListSipTrunkOptions): Promise<Array<SIPOutboundTrunkInfo>>;
/**
* Delete a SIP trunk.
*
* @param sipTrunkId - ID of the SIP trunk to delete
* @returns Deleted trunk information
*/
deleteSipTrunk(sipTrunkId: string): Promise<SIPTrunkInfo>;
/**
* Create a new SIP dispatch rule.
*
* @param rule - SIP dispatch rule to create
* @param opts - CreateSipDispatchRuleOptions
* @returns Created SIP dispatch rule
*/
createSipDispatchRule(rule: SipDispatchRuleDirect | SipDispatchRuleIndividual | SipDispatchRuleCallee, opts?: CreateSipDispatchRuleOptions): Promise<SIPDispatchRuleInfo>;
/**
* Updates an existing SIP dispatch rule by replacing it entirely.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param rule - new SIP dispatch rule
* @returns Updated SIP dispatch rule
*/
updateSipDispatchRule(sipDispatchRuleId: string, rule: SIPDispatchRuleInfo): Promise<SIPDispatchRuleInfo>;
/**
* Updates specific fields of an existing SIP dispatch rule.
* Only provided fields will be updated.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param fields - Fields of the dispatch rule to update
* @returns Updated SIP dispatch rule
*/
updateSipDispatchRuleFields(sipDispatchRuleId: string, fields?: SipDispatchRuleUpdateOptions): Promise<SIPDispatchRuleInfo>;
/**
* Updates an existing SIP inbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param trunk - SIP inbound trunk to update with
* @returns Updated SIP inbound trunk
*/
updateSipInboundTrunk(sipTrunkId: string, trunk: SIPInboundTrunkInfo): Promise<SIPInboundTrunkInfo>;
/**
* Updates specific fields of an existing SIP inbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param fields - Fields of the inbound trunk to update
* @returns Updated SIP inbound trunk
*/
updateSipInboundTrunkFields(sipTrunkId: string, fields: SipInboundTrunkUpdateOptions): Promise<SIPInboundTrunkInfo>;
/**
* Updates an existing SIP outbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param trunk - SIP outbound trunk to update with
* @returns Updated SIP outbound trunk
*/
updateSipOutboundTrunk(sipTrunkId: string, trunk: SIPOutboundTrunkInfo): Promise<SIPOutboundTrunkInfo>;
/**
* Updates specific fields of an existing SIP outbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param fields - Fields of the outbound trunk to update
* @returns Updated SIP outbound trunk
*/
updateSipOutboundTrunkFields(sipTrunkId: string, fields: SipOutboundTrunkUpdateOptions): Promise<SIPOutboundTrunkInfo>;
/**
* List SIP dispatch rules with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP dispatch rules
*/
listSipDispatchRule(list?: ListSipDispatchRuleOptions): Promise<Array<SIPDispatchRuleInfo>>;
/**
* Delete a SIP dispatch rule.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to delete
* @returns Deleted rule information
*/
deleteSipDispatchRule(sipDispatchRuleId: string): Promise<SIPDispatchRuleInfo>;
/**
* Create a new SIP participant.
*
* @param sipTrunkId - sip trunk to use for the call
* @param number - number to dial
* @param roomName - room to attach the call to
* @param opts - CreateSipParticipantOptions
* @param outboundTrunkConfig - Optional outbound trunk configuration for sip participant.
* @returns Created SIP participant
*/
createSipParticipant(sipTrunkId: string, number: string, roomName: string, opts?: CreateSipParticipantOptions, outboundTrunkConfig?: SIPOutboundConfig): Promise<SIPParticipantInfo>;
/**
* Transfer a SIP participant to a different room.
*
* @param roomName - room the SIP participant to transfer is connectd to
* @param participantIdentity - identity of the SIP participant to transfer
* @param transferTo - SIP URL to transfer the participant to
* @param opts - TransferSipParticipantOptions
*/
transferSipParticipant(roomName: string, participantIdentity: string, transferTo: string, opts?: TransferSipParticipantOptions): Promise<void>;
}
export { type CreateSipDispatchRuleOptions, type CreateSipInboundTrunkOptions, type CreateSipOutboundTrunkOptions, type CreateSipParticipantOptions, type CreateSipTrunkOptions, type ListSipDispatchRuleOptions, type ListSipTrunkOptions, SipClient, type SipDispatchRuleCallee, type SipDispatchRuleDirect, type SipDispatchRuleIndividual, type SipDispatchRuleUpdateOptions, type SipInboundTrunkUpdateOptions, type SipOutboundTrunkUpdateOptions, type TransferSipParticipantOptions };
+356
View File
@@ -0,0 +1,356 @@
import { SIPTrunkInfo, SIPHeaderOptions, SIPMediaEncryption, SIPMediaConfig, SIPInboundTrunkInfo, SIPTransport, SIPOutboundTrunkInfo, Pagination, RoomConfiguration, SIPDispatchRuleInfo, ListUpdate, SIPDispatchRule, SIPOutboundConfig, SIPParticipantInfo } from '@livekit/protocol';
import { ClientOptions } from './ClientOptions.js';
import { ServiceBase } from './ServiceBase.js';
import './grants.js';
import 'jose';
/**
* @deprecated use CreateSipInboundTrunkOptions or CreateSipOutboundTrunkOptions
*/
interface CreateSipTrunkOptions {
name?: string;
metadata?: string;
inbound_addresses?: string[];
inbound_numbers?: string[];
inbound_username?: string;
inbound_password?: string;
outbound_address?: string;
outbound_username?: string;
outbound_password?: string;
}
interface CreateSipInboundTrunkOptions {
metadata?: string;
/** @deprecated - use `allowedAddresses` instead */
allowed_addresses?: string[];
allowedAddresses?: string[];
/** @deprecated - use `allowedNumbers` instead */
allowed_numbers?: string[];
allowedNumbers?: string[];
/** @deprecated - use `authUsername` instead */
auth_username?: string;
authUsername?: string;
/** @deprecated - use `authPassword` instead */
auth_password?: string;
authPassword?: string;
headers?: {
[key: string]: string;
};
headersToAttributes?: {
[key: string]: string;
};
includeHeaders?: SIPHeaderOptions;
krispEnabled?: boolean;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
/** Maximum time for a call to ring in seconds. */
ringingTimeout?: number;
}
interface CreateSipOutboundTrunkOptions {
metadata?: string;
transport: SIPTransport;
destinationCountry?: string;
/** @deprecated - use `authUsername` instead */
auth_username?: string;
authUsername?: string;
/** @deprecated - use `authPassword` instead */
auth_password?: string;
authPassword?: string;
headers?: {
[key: string]: string;
};
headersToAttributes?: {
[key: string]: string;
};
includeHeaders?: SIPHeaderOptions;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
}
interface SipDispatchRuleDirect {
type: 'direct';
roomName: string;
pin?: string;
}
interface SipDispatchRuleIndividual {
type: 'individual';
roomPrefix: string;
pin?: string;
}
interface SipDispatchRuleCallee {
type: 'callee';
roomPrefix: string;
pin?: string;
/** Optionally append a random suffix to the room name. */
randomize?: boolean;
}
interface CreateSipDispatchRuleOptions {
name?: string;
metadata?: string;
trunkIds?: string[];
hidePhoneNumber?: boolean;
attributes?: {
[key: string]: string;
};
roomPreset?: string;
roomConfig?: RoomConfiguration;
}
interface CreateSipParticipantOptions {
/** Optional SIP From number to use. If empty, trunk number is used. */
fromNumber?: string;
/** Optional identity of the SIP participant */
participantIdentity?: string;
/** Optional name of the participant */
participantName?: string;
/** Optional display name for the SIP participant */
displayName?: string;
/** Optional metadata to attach to the participant */
participantMetadata?: string;
/** Optional attributes to attach to the participant */
participantAttributes?: {
[key: string]: string;
};
/** Optionally send following DTMF digits (extension codes) when making a call.
* Character 'w' can be used to add a 0.5 sec delay. */
dtmf?: string;
/** @deprecated use `playDialtone` instead */
playRingtone?: boolean;
/** If `true`, the SIP Participant plays a dial tone to the room until the phone is picked up. */
playDialtone?: boolean;
/** These headers are sent as-is and may help identify this call as coming from LiveKit for the other SIP endpoint. */
headers?: {
[key: string]: string;
};
/** Map SIP response headers from INVITE to sip.h.* participant attributes automatically. */
includeHeaders?: SIPHeaderOptions;
hidePhoneNumber?: boolean;
/** Maximum time for the call to ring in seconds. */
ringingTimeout?: number;
/** Maximum call duration in seconds. */
maxCallDuration?: number;
/** If `true`, Krisp noise cancellation will be enabled for the caller. */
krispEnabled?: boolean;
/** If `true`, this will wait until the call is answered before returning. */
waitUntilAnswered?: boolean;
/** Optional request timeout in seconds. Defaults to 30s when waitUntilAnswered is true (dialing takes time), otherwise the client default. */
timeout?: number;
media?: SIPMediaConfig;
}
interface ListSipDispatchRuleOptions {
/** Pagination options. */
page?: Pagination;
/** Rule IDs to list. If this option is set, the response will contains rules in the same order. If any of the rules is missing, a nil item in that position will be sent in the response. */
dispatchRuleIds?: string[];
/** Only list rules that contain one of the Trunk IDs, including wildcard rules. */
trunkIds?: string[];
}
interface ListSipTrunkOptions {
/** Pagination options. */
page?: Pagination;
/** Trunk IDs to list. If this option is set, the response will contains trunks in the same order. If any of the trunks is missing, a nil item in that position will be sent in the response. */
trunkIds?: string[];
/** Only list trunks that contain one of the numbers, including wildcard trunks. */
numbers?: string[];
}
interface SipDispatchRuleUpdateOptions {
trunkIds?: ListUpdate;
rule?: SIPDispatchRule;
name?: string;
metadata?: string;
attributes?: {
[key: string]: string;
};
}
interface SipInboundTrunkUpdateOptions {
numbers?: ListUpdate;
allowedAddresses?: ListUpdate;
allowedNumbers?: ListUpdate;
authUsername?: string;
authPassword?: string;
name?: string;
metadata?: string;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
}
interface SipOutboundTrunkUpdateOptions {
numbers?: ListUpdate;
allowedAddresses?: ListUpdate;
allowedNumbers?: ListUpdate;
authUsername?: string;
authPassword?: string;
destinationCountry?: string;
name?: string;
metadata?: string;
/** @deprecated - use `media.encryption` instead */
mediaEncryption?: SIPMediaEncryption;
media?: SIPMediaConfig;
}
interface TransferSipParticipantOptions {
playDialtone?: boolean;
headers?: {
[key: string]: string;
};
/** Maximum time for the transfer destination to answer the call, in seconds. */
ringingTimeout?: number;
/** Optional request timeout in seconds. Defaults to 30s (dialing takes time). */
timeout?: number;
}
/**
* Client to access Egress APIs
*/
declare class SipClient extends ServiceBase {
private readonly rpc;
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host: string, apiKey?: string, secret?: string, options?: ClientOptions);
/**
* @param number - phone number of the trunk
* @param opts - CreateSipTrunkOptions
* @deprecated use `createSipInboundTrunk` or `createSipOutboundTrunk`
*/
createSipTrunk(number: string, opts?: CreateSipTrunkOptions): Promise<SIPTrunkInfo>;
/**
* Create a new SIP inbound trunk.
*
* @param name - human-readable name of the trunk
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP inbound trunk
*/
createSipInboundTrunk(name: string, numbers: string[], opts?: CreateSipInboundTrunkOptions): Promise<SIPInboundTrunkInfo>;
/**
* Create a new SIP outbound trunk.
*
* @param name - human-readable name of the trunk
* @param address - hostname and port of the SIP server to dial
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP outbound trunk
*/
createSipOutboundTrunk(name: string, address: string, numbers: string[], opts?: CreateSipOutboundTrunkOptions): Promise<SIPOutboundTrunkInfo>;
/**
* @deprecated use `listSipInboundTrunk` or `listSipOutboundTrunk`
*/
listSipTrunk(): Promise<Array<SIPTrunkInfo>>;
/**
* List SIP inbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP inbound trunks
*/
listSipInboundTrunk(list?: ListSipTrunkOptions): Promise<Array<SIPInboundTrunkInfo>>;
/**
* List SIP outbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP outbound trunks
*/
listSipOutboundTrunk(list?: ListSipTrunkOptions): Promise<Array<SIPOutboundTrunkInfo>>;
/**
* Delete a SIP trunk.
*
* @param sipTrunkId - ID of the SIP trunk to delete
* @returns Deleted trunk information
*/
deleteSipTrunk(sipTrunkId: string): Promise<SIPTrunkInfo>;
/**
* Create a new SIP dispatch rule.
*
* @param rule - SIP dispatch rule to create
* @param opts - CreateSipDispatchRuleOptions
* @returns Created SIP dispatch rule
*/
createSipDispatchRule(rule: SipDispatchRuleDirect | SipDispatchRuleIndividual | SipDispatchRuleCallee, opts?: CreateSipDispatchRuleOptions): Promise<SIPDispatchRuleInfo>;
/**
* Updates an existing SIP dispatch rule by replacing it entirely.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param rule - new SIP dispatch rule
* @returns Updated SIP dispatch rule
*/
updateSipDispatchRule(sipDispatchRuleId: string, rule: SIPDispatchRuleInfo): Promise<SIPDispatchRuleInfo>;
/**
* Updates specific fields of an existing SIP dispatch rule.
* Only provided fields will be updated.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param fields - Fields of the dispatch rule to update
* @returns Updated SIP dispatch rule
*/
updateSipDispatchRuleFields(sipDispatchRuleId: string, fields?: SipDispatchRuleUpdateOptions): Promise<SIPDispatchRuleInfo>;
/**
* Updates an existing SIP inbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param trunk - SIP inbound trunk to update with
* @returns Updated SIP inbound trunk
*/
updateSipInboundTrunk(sipTrunkId: string, trunk: SIPInboundTrunkInfo): Promise<SIPInboundTrunkInfo>;
/**
* Updates specific fields of an existing SIP inbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param fields - Fields of the inbound trunk to update
* @returns Updated SIP inbound trunk
*/
updateSipInboundTrunkFields(sipTrunkId: string, fields: SipInboundTrunkUpdateOptions): Promise<SIPInboundTrunkInfo>;
/**
* Updates an existing SIP outbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param trunk - SIP outbound trunk to update with
* @returns Updated SIP outbound trunk
*/
updateSipOutboundTrunk(sipTrunkId: string, trunk: SIPOutboundTrunkInfo): Promise<SIPOutboundTrunkInfo>;
/**
* Updates specific fields of an existing SIP outbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param fields - Fields of the outbound trunk to update
* @returns Updated SIP outbound trunk
*/
updateSipOutboundTrunkFields(sipTrunkId: string, fields: SipOutboundTrunkUpdateOptions): Promise<SIPOutboundTrunkInfo>;
/**
* List SIP dispatch rules with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP dispatch rules
*/
listSipDispatchRule(list?: ListSipDispatchRuleOptions): Promise<Array<SIPDispatchRuleInfo>>;
/**
* Delete a SIP dispatch rule.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to delete
* @returns Deleted rule information
*/
deleteSipDispatchRule(sipDispatchRuleId: string): Promise<SIPDispatchRuleInfo>;
/**
* Create a new SIP participant.
*
* @param sipTrunkId - sip trunk to use for the call
* @param number - number to dial
* @param roomName - room to attach the call to
* @param opts - CreateSipParticipantOptions
* @param outboundTrunkConfig - Optional outbound trunk configuration for sip participant.
* @returns Created SIP participant
*/
createSipParticipant(sipTrunkId: string, number: string, roomName: string, opts?: CreateSipParticipantOptions, outboundTrunkConfig?: SIPOutboundConfig): Promise<SIPParticipantInfo>;
/**
* Transfer a SIP participant to a different room.
*
* @param roomName - room the SIP participant to transfer is connectd to
* @param participantIdentity - identity of the SIP participant to transfer
* @param transferTo - SIP URL to transfer the participant to
* @param opts - TransferSipParticipantOptions
*/
transferSipParticipant(roomName: string, participantIdentity: string, transferTo: string, opts?: TransferSipParticipantOptions): Promise<void>;
}
export { type CreateSipDispatchRuleOptions, type CreateSipInboundTrunkOptions, type CreateSipOutboundTrunkOptions, type CreateSipParticipantOptions, type CreateSipTrunkOptions, type ListSipDispatchRuleOptions, type ListSipTrunkOptions, SipClient, type SipDispatchRuleCallee, type SipDispatchRuleDirect, type SipDispatchRuleIndividual, type SipDispatchRuleUpdateOptions, type SipInboundTrunkUpdateOptions, type SipOutboundTrunkUpdateOptions, type TransferSipParticipantOptions };
File diff suppressed because one or more lines are too long
+566
View File
@@ -0,0 +1,566 @@
import { Duration } from "@bufbuild/protobuf";
import {
CreateSIPDispatchRuleRequest,
CreateSIPInboundTrunkRequest,
CreateSIPOutboundTrunkRequest,
CreateSIPParticipantRequest,
CreateSIPTrunkRequest,
DeleteSIPDispatchRuleRequest,
DeleteSIPTrunkRequest,
ListSIPDispatchRuleRequest,
ListSIPDispatchRuleResponse,
ListSIPInboundTrunkRequest,
ListSIPInboundTrunkResponse,
ListSIPOutboundTrunkRequest,
ListSIPOutboundTrunkResponse,
ListSIPTrunkRequest,
ListSIPTrunkResponse,
SIPDispatchRule,
SIPDispatchRuleCallee,
SIPDispatchRuleDirect,
SIPDispatchRuleIndividual,
SIPDispatchRuleInfo,
SIPInboundTrunkInfo,
SIPOutboundTrunkInfo,
SIPParticipantInfo,
SIPTransport,
SIPTrunkInfo,
TransferSIPParticipantRequest,
UpdateSIPDispatchRuleRequest,
UpdateSIPInboundTrunkRequest,
UpdateSIPOutboundTrunkRequest
} from "@livekit/protocol";
import { ServiceBase } from "./ServiceBase.js";
import { ServerError, SipCallError, TwirpRpc, livekitPackage } from "./TwirpRPC.js";
import { DEFAULT_RINGING_TIMEOUT_SECONDS, dialRequestTimeout } from "./dialTimeout.js";
function asSipCallError(e) {
if (e instanceof ServerError && e.metadata && "sip_status_code" in e.metadata) {
return SipCallError.fromServerError(e);
}
return e;
}
const svc = "SIP";
class SipClient extends ServiceBase {
/**
* @param host - hostname including protocol. i.e. 'https://<project>.livekit.cloud'
* @param apiKey - API Key, can be set in env var LIVEKIT_API_KEY
* @param secret - API Secret, can be set in env var LIVEKIT_API_SECRET
* @param options - client options
*/
constructor(host, apiKey, secret, options) {
super({ apiKey, secret, token: options == null ? void 0 : options.token });
this.rpc = new TwirpRpc(host, livekitPackage, {
requestTimeout: options == null ? void 0 : options.requestTimeout,
failover: options == null ? void 0 : options.failover
});
}
/**
* @param number - phone number of the trunk
* @param opts - CreateSipTrunkOptions
* @deprecated use `createSipInboundTrunk` or `createSipOutboundTrunk`
*/
async createSipTrunk(number, opts) {
let inboundAddresses;
let inboundNumbers;
let inboundUsername = "";
let inboundPassword = "";
let outboundAddress = "";
let outboundUsername = "";
let outboundPassword = "";
let name = "";
let metadata = "";
if (opts !== void 0) {
inboundAddresses = opts.inbound_addresses;
inboundNumbers = opts.inbound_numbers;
inboundUsername = opts.inbound_username || "";
inboundPassword = opts.inbound_password || "";
outboundAddress = opts.outbound_address || "";
outboundUsername = opts.outbound_username || "";
outboundPassword = opts.outbound_password || "";
name = opts.name || "";
metadata = opts.metadata || "";
}
const req = new CreateSIPTrunkRequest({
name,
metadata,
inboundAddresses,
inboundNumbers,
inboundUsername,
inboundPassword,
outboundNumber: number,
outboundAddress,
outboundUsername,
outboundPassword
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPTrunk",
req,
await this.authHeader({}, { admin: true })
);
return SIPTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP inbound trunk.
*
* @param name - human-readable name of the trunk
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP inbound trunk
*/
async createSipInboundTrunk(name, numbers, opts) {
if (opts === void 0) {
opts = {};
}
const req = new CreateSIPInboundTrunkRequest({
trunk: new SIPInboundTrunkInfo({
name,
numbers,
metadata: opts == null ? void 0 : opts.metadata,
allowedAddresses: opts.allowedAddresses ?? opts.allowed_addresses,
allowedNumbers: opts.allowedNumbers ?? opts.allowed_numbers,
authUsername: opts.authUsername ?? opts.auth_username,
authPassword: opts.authPassword ?? opts.auth_password,
headers: opts.headers,
headersToAttributes: opts.headersToAttributes,
includeHeaders: opts.includeHeaders,
krispEnabled: opts.krispEnabled,
mediaEncryption: opts.mediaEncryption,
media: opts.media,
ringingTimeout: opts.ringingTimeout ? new Duration({ seconds: BigInt(opts.ringingTimeout) }) : void 0
})
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return SIPInboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP outbound trunk.
*
* @param name - human-readable name of the trunk
* @param address - hostname and port of the SIP server to dial
* @param numbers - phone numbers of the trunk
* @param opts - CreateSipTrunkOptions
* @returns Created SIP outbound trunk
*/
async createSipOutboundTrunk(name, address, numbers, opts) {
if (opts === void 0) {
opts = {
transport: SIPTransport.SIP_TRANSPORT_AUTO
};
}
const req = new CreateSIPOutboundTrunkRequest({
trunk: new SIPOutboundTrunkInfo({
name,
address,
numbers,
metadata: opts.metadata,
transport: opts.transport,
authUsername: opts.authUsername ?? opts.auth_username,
authPassword: opts.authPassword ?? opts.auth_password,
headers: opts.headers,
headersToAttributes: opts.headersToAttributes,
includeHeaders: opts.includeHeaders,
destinationCountry: opts.destinationCountry,
mediaEncryption: opts.mediaEncryption,
media: opts.media
})
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return SIPOutboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* @deprecated use `listSipInboundTrunk` or `listSipOutboundTrunk`
*/
async listSipTrunk() {
const req = {};
const data = await this.rpc.request(
svc,
"ListSIPTrunk",
new ListSIPTrunkRequest(req).toJson(),
await this.authHeader({}, { admin: true })
);
return ListSIPTrunkResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* List SIP inbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP inbound trunks
*/
async listSipInboundTrunk(list = {}) {
const req = new ListSIPInboundTrunkRequest(list).toJson();
const data = await this.rpc.request(
svc,
"ListSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return ListSIPInboundTrunkResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* List SIP outbound trunks with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP outbound trunks
*/
async listSipOutboundTrunk(list = {}) {
const req = new ListSIPOutboundTrunkRequest(list).toJson();
const data = await this.rpc.request(
svc,
"ListSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return ListSIPOutboundTrunkResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* Delete a SIP trunk.
*
* @param sipTrunkId - ID of the SIP trunk to delete
* @returns Deleted trunk information
*/
async deleteSipTrunk(sipTrunkId) {
const data = await this.rpc.request(
svc,
"DeleteSIPTrunk",
new DeleteSIPTrunkRequest({ sipTrunkId }).toJson(),
await this.authHeader({}, { admin: true })
);
return SIPTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP dispatch rule.
*
* @param rule - SIP dispatch rule to create
* @param opts - CreateSipDispatchRuleOptions
* @returns Created SIP dispatch rule
*/
async createSipDispatchRule(rule, opts) {
if (opts === void 0) {
opts = {};
}
let ruleProto = void 0;
if (rule.type == "direct") {
ruleProto = new SIPDispatchRule({
rule: {
case: "dispatchRuleDirect",
value: new SIPDispatchRuleDirect({
roomName: rule.roomName,
pin: rule.pin || ""
})
}
});
} else if (rule.type == "individual") {
ruleProto = new SIPDispatchRule({
rule: {
case: "dispatchRuleIndividual",
value: new SIPDispatchRuleIndividual({
roomPrefix: rule.roomPrefix,
pin: rule.pin || ""
})
}
});
} else if (rule.type == "callee") {
ruleProto = new SIPDispatchRule({
rule: {
case: "dispatchRuleCallee",
value: new SIPDispatchRuleCallee({
roomPrefix: rule.roomPrefix,
pin: rule.pin || "",
randomize: rule.randomize || false
})
}
});
}
const req = new CreateSIPDispatchRuleRequest({
rule: ruleProto,
trunkIds: opts.trunkIds,
hidePhoneNumber: opts.hidePhoneNumber,
name: opts.name,
metadata: opts.metadata,
attributes: opts.attributes,
roomPreset: opts.roomPreset,
roomConfig: opts.roomConfig
}).toJson();
const data = await this.rpc.request(
svc,
"CreateSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates an existing SIP dispatch rule by replacing it entirely.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param rule - new SIP dispatch rule
* @returns Updated SIP dispatch rule
*/
async updateSipDispatchRule(sipDispatchRuleId, rule) {
const req = new UpdateSIPDispatchRuleRequest({
sipDispatchRuleId,
action: {
case: "replace",
value: rule
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates specific fields of an existing SIP dispatch rule.
* Only provided fields will be updated.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to update
* @param fields - Fields of the dispatch rule to update
* @returns Updated SIP dispatch rule
*/
async updateSipDispatchRuleFields(sipDispatchRuleId, fields = {}) {
const req = new UpdateSIPDispatchRuleRequest({
sipDispatchRuleId,
action: {
case: "update",
value: fields
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates an existing SIP inbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param trunk - SIP inbound trunk to update with
* @returns Updated SIP inbound trunk
*/
async updateSipInboundTrunk(sipTrunkId, trunk) {
const req = new UpdateSIPInboundTrunkRequest({
sipTrunkId,
action: {
case: "replace",
value: trunk
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return SIPInboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates specific fields of an existing SIP inbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP inbound trunk to update
* @param fields - Fields of the inbound trunk to update
* @returns Updated SIP inbound trunk
*/
async updateSipInboundTrunkFields(sipTrunkId, fields) {
const req = new UpdateSIPInboundTrunkRequest({
sipTrunkId,
action: {
case: "update",
value: fields
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPInboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return SIPInboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates an existing SIP outbound trunk by replacing it entirely.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param trunk - SIP outbound trunk to update with
* @returns Updated SIP outbound trunk
*/
async updateSipOutboundTrunk(sipTrunkId, trunk) {
const req = new UpdateSIPOutboundTrunkRequest({
sipTrunkId,
action: {
case: "replace",
value: trunk
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return SIPOutboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Updates specific fields of an existing SIP outbound trunk.
* Only provided fields will be updated.
*
* @param sipTrunkId - ID of the SIP outbound trunk to update
* @param fields - Fields of the outbound trunk to update
* @returns Updated SIP outbound trunk
*/
async updateSipOutboundTrunkFields(sipTrunkId, fields) {
const req = new UpdateSIPOutboundTrunkRequest({
sipTrunkId,
action: {
case: "update",
value: fields
}
}).toJson();
const data = await this.rpc.request(
svc,
"UpdateSIPOutboundTrunk",
req,
await this.authHeader({}, { admin: true })
);
return SIPOutboundTrunkInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* List SIP dispatch rules with optional filtering.
*
* @param list - Request with optional filtering parameters
* @returns Response containing list of SIP dispatch rules
*/
async listSipDispatchRule(list = {}) {
const req = new ListSIPDispatchRuleRequest(list).toJson();
const data = await this.rpc.request(
svc,
"ListSIPDispatchRule",
req,
await this.authHeader({}, { admin: true })
);
return ListSIPDispatchRuleResponse.fromJson(data, { ignoreUnknownFields: true }).items ?? [];
}
/**
* Delete a SIP dispatch rule.
*
* @param sipDispatchRuleId - ID of the SIP dispatch rule to delete
* @returns Deleted rule information
*/
async deleteSipDispatchRule(sipDispatchRuleId) {
const data = await this.rpc.request(
svc,
"DeleteSIPDispatchRule",
new DeleteSIPDispatchRuleRequest({ sipDispatchRuleId }).toJson(),
await this.authHeader({}, { admin: true })
);
return SIPDispatchRuleInfo.fromJson(data, { ignoreUnknownFields: true });
}
/**
* Create a new SIP participant.
*
* @param sipTrunkId - sip trunk to use for the call
* @param number - number to dial
* @param roomName - room to attach the call to
* @param opts - CreateSipParticipantOptions
* @param outboundTrunkConfig - Optional outbound trunk configuration for sip participant.
* @returns Created SIP participant
*/
async createSipParticipant(sipTrunkId, number, roomName, opts, outboundTrunkConfig) {
if (opts === void 0) {
opts = {};
}
if (opts.waitUntilAnswered) {
opts.ringingTimeout ??= DEFAULT_RINGING_TIMEOUT_SECONDS;
opts.timeout = dialRequestTimeout(opts.timeout, opts.ringingTimeout);
}
const req = new CreateSIPParticipantRequest({
sipTrunkId,
trunk: outboundTrunkConfig,
sipCallTo: number,
sipNumber: opts.fromNumber,
roomName,
participantIdentity: opts.participantIdentity || "sip-participant",
participantName: opts.participantName,
displayName: opts.displayName,
participantMetadata: opts.participantMetadata,
participantAttributes: opts.participantAttributes,
dtmf: opts.dtmf,
playDialtone: opts.playDialtone ?? opts.playRingtone,
headers: opts.headers,
hidePhoneNumber: opts.hidePhoneNumber,
includeHeaders: opts.includeHeaders,
ringingTimeout: opts.ringingTimeout ? new Duration({ seconds: BigInt(opts.ringingTimeout) }) : void 0,
maxCallDuration: opts.maxCallDuration ? new Duration({ seconds: BigInt(opts.maxCallDuration) }) : void 0,
krispEnabled: opts.krispEnabled,
waitUntilAnswered: opts.waitUntilAnswered,
media: opts.media
}).toJson();
try {
const data = await this.rpc.request(
svc,
"CreateSIPParticipant",
req,
await this.authHeader({}, { call: true }),
opts.timeout
);
return SIPParticipantInfo.fromJson(data, { ignoreUnknownFields: true });
} catch (e) {
throw asSipCallError(e);
}
}
/**
* Transfer a SIP participant to a different room.
*
* @param roomName - room the SIP participant to transfer is connectd to
* @param participantIdentity - identity of the SIP participant to transfer
* @param transferTo - SIP URL to transfer the participant to
* @param opts - TransferSipParticipantOptions
*/
async transferSipParticipant(roomName, participantIdentity, transferTo, opts) {
if (opts === void 0) {
opts = {};
}
opts.ringingTimeout ??= DEFAULT_RINGING_TIMEOUT_SECONDS;
opts.timeout = dialRequestTimeout(opts.timeout, opts.ringingTimeout);
const req = new TransferSIPParticipantRequest({
participantIdentity,
roomName,
transferTo,
playDialtone: opts.playDialtone,
headers: opts.headers,
ringingTimeout: opts.ringingTimeout ? new Duration({ seconds: BigInt(opts.ringingTimeout) }) : void 0
}).toJson();
try {
await this.rpc.request(
svc,
"TransferSIPParticipant",
req,
await this.authHeader({ roomAdmin: true, room: roomName }, { call: true }),
opts.timeout
);
} catch (e) {
throw asSipCallError(e);
}
}
}
export {
SipClient
};
//# sourceMappingURL=SipClient.js.map
File diff suppressed because one or more lines are too long
+196
View File
@@ -0,0 +1,196 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var TwirpRPC_exports = {};
__export(TwirpRPC_exports, {
ServerError: () => ServerError,
SipCallError: () => SipCallError,
TwirpError: () => TwirpError,
TwirpRpc: () => TwirpRpc,
livekitPackage: () => livekitPackage
});
module.exports = __toCommonJS(TwirpRPC_exports);
var import_failover = require("./failover.cjs");
var import_version = require("./version.cjs");
const USER_AGENT = `livekit-server-sdk-node/${import_version.SDK_VERSION}`;
const defaultPrefix = "/twirp";
const defaultTimeoutSeconds = 10;
const livekitPackage = "livekit";
class ServerError extends Error {
constructor(name, message, status, code, metadata) {
super(message);
this.name = name;
this.status = status;
this.code = code;
this.metadata = metadata;
}
}
const TwirpError = ServerError;
class SipCallError extends ServerError {
constructor(name, message, status, code, metadata) {
super(name, SipCallError.describe(message, code, metadata), status, code, metadata);
this.name = "SipCallError";
}
/** The SIP response code of the failed call, e.g. 486 (Busy Here). */
get sipStatusCode() {
var _a;
const raw = (_a = this.metadata) == null ? void 0 : _a.sip_status_code;
return raw !== void 0 ? Number(raw) : void 0;
}
/** The SIP reason phrase of the failed call, e.g. "Busy Here". */
get sipStatus() {
var _a;
return (_a = this.metadata) == null ? void 0 : _a.sip_status;
}
/** Builds a SipCallError from a ServerError, preserving its code and metadata. */
static fromServerError(err) {
return new SipCallError(err.name, err.message, err.status, err.code, err.metadata);
}
// describe renders a clear message: the SIP status, the error code, and any
// other metadata the server attached. Falls back to the raw message when the
// error carries no SIP status.
static describe(fallback, code, metadata) {
const sipCode = metadata == null ? void 0 : metadata.sip_status_code;
if (!sipCode) {
return fallback;
}
const reason = metadata == null ? void 0 : metadata.sip_status;
let msg = `SIP call failed: ${sipCode}${reason ? ` ${reason}` : ""}`;
if (code) {
msg += ` (${code})`;
}
const extra = Object.entries(metadata ?? {}).filter(([k]) => k !== "sip_status_code" && k !== "sip_status" && k !== "error_details").map(([k, v]) => `${k}=${v}`);
if (extra.length) {
msg += ` [${extra.join(", ")}]`;
}
return msg;
}
}
class TwirpRpc {
constructor(host, pkg, options) {
if (host.startsWith("ws")) {
host = host.replace("ws", "http");
}
this.host = host;
this.pkg = pkg;
this.requestTimeout = (options == null ? void 0 : options.requestTimeout) ?? defaultTimeoutSeconds;
this.prefix = (options == null ? void 0 : options.prefix) || defaultPrefix;
this.failover = (options == null ? void 0 : options.failover) ?? true;
this.failoverForce = (options == null ? void 0 : options.failoverForce) ?? false;
this.failoverBackoffMs = (options == null ? void 0 : options.failoverBackoffMs) ?? import_failover.FAILOVER_BACKOFF_BASE_MS;
}
/**
* Issues a Twirp request, failing over to alternative regions on retryable
* errors. On any transport error or HTTP 5xx it discovers regions via
* /settings/regions and replays the request body and headers intact
* against the next untried region, with exponential backoff. A 4xx is
* returned immediately.
*/
async request(service, method, data, headers, timeout = this.requestTimeout) {
const path = `${this.prefix}/${this.pkg}.${service}/${method}`;
const body = JSON.stringify(data);
const requestHeaders = {
"Content-Type": "application/json;charset=UTF-8",
"User-Agent": USER_AGENT,
...headers
};
const origin = new URL(this.host);
const maxAttempts = (0, import_failover.failoverAttempts)(
this.failover,
origin.hostname,
this.failoverForce,
timeout
);
const attempted = /* @__PURE__ */ new Set([(0, import_failover.hostKey)(origin)]);
let regions;
let current = this.host;
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const isLast = attempt + 1 >= maxAttempts;
const init = { method: "POST", headers: requestHeaders, body };
if (timeout) {
init.signal = AbortSignal.timeout(timeout * 1e3);
}
let response;
let transportError;
try {
response = await fetch(new URL(path, current), init);
} catch (e) {
transportError = e;
}
if (response == null ? void 0 : response.ok) {
return await response.json();
}
const retryable = transportError !== void 0 || !!response && response.status >= 500;
let next;
if (retryable && !isLast) {
if (!regions) {
regions = await (0, import_failover.regionOrigins)(origin, headers);
}
next = (0, import_failover.pickNext)(regions, attempted);
}
if (!retryable || next === void 0) {
if (response) {
throw await toTwirpError(response);
}
throw transportError;
}
const reason = response ? `status ${response.status}` : transportError;
console.warn(
`livekit API request to ${new URL(current).host} failed (${reason}), retrying with fallback url ${next}`
);
await (0, import_failover.sleep)(this.failoverBackoffMs * 2 ** attempt);
attempted.add((0, import_failover.hostKey)(new URL(next)));
current = next;
}
throw new Error("failover loop exited without returning");
}
}
async function toTwirpError(response) {
const isJson = response.headers.get("content-type") === "application/json";
let errorMessage = "Unknown internal error";
let errorCode = void 0;
let metadata = void 0;
try {
if (isJson) {
const parsedError = await response.json();
if ("msg" in parsedError) {
errorMessage = parsedError.msg;
}
if ("code" in parsedError) {
errorCode = parsedError.code;
}
if ("meta" in parsedError) {
metadata = parsedError.meta;
}
} else {
errorMessage = await response.text();
}
} catch (e) {
console.debug(`Error when trying to parse error message, using defaults`, e);
}
return new TwirpError(response.statusText, errorMessage, response.status, errorCode, metadata);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ServerError,
SipCallError,
TwirpError,
TwirpRpc,
livekitPackage
});
//# sourceMappingURL=TwirpRPC.cjs.map
File diff suppressed because one or more lines are too long
+70
View File
@@ -0,0 +1,70 @@
import { JsonValue } from '@bufbuild/protobuf';
type Options = {
/** Prefix for the RPC requests */
prefix?: string;
/** Timeout for fetch requests, in seconds. Must be within the valid range for abort signal timeouts. */
requestTimeout?: number;
/** Whether region failover is enabled (LiveKit Cloud hosts only). Defaults to true. */
failover?: boolean;
/** @internal test-only: force failover regardless of host. */
failoverForce?: boolean;
/** @internal test-only: base retry backoff in ms. */
failoverBackoffMs?: number;
};
declare const livekitPackage = "livekit";
interface Rpc {
request(service: string, method: string, data: JsonValue, headers: any, // eslint-disable-line @typescript-eslint/no-explicit-any
timeout?: number): Promise<string>;
}
declare class ServerError extends Error {
status: number;
code?: string;
metadata?: Record<string, string>;
constructor(name: string, message: string, status: number, code?: string, metadata?: Record<string, string>);
}
/** @deprecated use {@link ServerError} */
declare const TwirpError: typeof ServerError;
/** @deprecated use {@link ServerError} */
type TwirpError = ServerError;
/**
* A {@link ServerError} from a SIP dialing call (`createSipParticipant` /
* `transferSipParticipant`) that failed with a SIP response status. The SIP code
* and reason are exposed as getters; any other error metadata remains available
* via {@link ServerError.metadata}.
*/
declare class SipCallError extends ServerError {
constructor(name: string, message: string, status: number, code?: string, metadata?: Record<string, string>);
/** The SIP response code of the failed call, e.g. 486 (Busy Here). */
get sipStatusCode(): number | undefined;
/** The SIP reason phrase of the failed call, e.g. "Busy Here". */
get sipStatus(): string | undefined;
/** Builds a SipCallError from a ServerError, preserving its code and metadata. */
static fromServerError(err: ServerError): SipCallError;
private static describe;
}
/**
* JSON based Twirp V7 RPC
*/
declare class TwirpRpc {
host: string;
pkg: string;
prefix: string;
requestTimeout: number;
failover: boolean;
private failoverForce;
private failoverBackoffMs;
constructor(host: string, pkg: string, options?: Options);
/**
* Issues a Twirp request, failing over to alternative regions on retryable
* errors. On any transport error or HTTP 5xx it discovers regions via
* /settings/regions and replays the request body and headers intact
* against the next untried region, with exponential backoff. A 4xx is
* returned immediately.
*/
request(service: string, method: string, data: any, // eslint-disable-line @typescript-eslint/no-explicit-any
headers: any, // eslint-disable-line @typescript-eslint/no-explicit-any
timeout?: number): Promise<any>;
}
export { type Rpc, ServerError, SipCallError, TwirpError, TwirpRpc, livekitPackage };
+70
View File
@@ -0,0 +1,70 @@
import { JsonValue } from '@bufbuild/protobuf';
type Options = {
/** Prefix for the RPC requests */
prefix?: string;
/** Timeout for fetch requests, in seconds. Must be within the valid range for abort signal timeouts. */
requestTimeout?: number;
/** Whether region failover is enabled (LiveKit Cloud hosts only). Defaults to true. */
failover?: boolean;
/** @internal test-only: force failover regardless of host. */
failoverForce?: boolean;
/** @internal test-only: base retry backoff in ms. */
failoverBackoffMs?: number;
};
declare const livekitPackage = "livekit";
interface Rpc {
request(service: string, method: string, data: JsonValue, headers: any, // eslint-disable-line @typescript-eslint/no-explicit-any
timeout?: number): Promise<string>;
}
declare class ServerError extends Error {
status: number;
code?: string;
metadata?: Record<string, string>;
constructor(name: string, message: string, status: number, code?: string, metadata?: Record<string, string>);
}
/** @deprecated use {@link ServerError} */
declare const TwirpError: typeof ServerError;
/** @deprecated use {@link ServerError} */
type TwirpError = ServerError;
/**
* A {@link ServerError} from a SIP dialing call (`createSipParticipant` /
* `transferSipParticipant`) that failed with a SIP response status. The SIP code
* and reason are exposed as getters; any other error metadata remains available
* via {@link ServerError.metadata}.
*/
declare class SipCallError extends ServerError {
constructor(name: string, message: string, status: number, code?: string, metadata?: Record<string, string>);
/** The SIP response code of the failed call, e.g. 486 (Busy Here). */
get sipStatusCode(): number | undefined;
/** The SIP reason phrase of the failed call, e.g. "Busy Here". */
get sipStatus(): string | undefined;
/** Builds a SipCallError from a ServerError, preserving its code and metadata. */
static fromServerError(err: ServerError): SipCallError;
private static describe;
}
/**
* JSON based Twirp V7 RPC
*/
declare class TwirpRpc {
host: string;
pkg: string;
prefix: string;
requestTimeout: number;
failover: boolean;
private failoverForce;
private failoverBackoffMs;
constructor(host: string, pkg: string, options?: Options);
/**
* Issues a Twirp request, failing over to alternative regions on retryable
* errors. On any transport error or HTTP 5xx it discovers regions via
* /settings/regions and replays the request body and headers intact
* against the next untried region, with exponential backoff. A 4xx is
* returned immediately.
*/
request(service: string, method: string, data: any, // eslint-disable-line @typescript-eslint/no-explicit-any
headers: any, // eslint-disable-line @typescript-eslint/no-explicit-any
timeout?: number): Promise<any>;
}
export { type Rpc, ServerError, SipCallError, TwirpError, TwirpRpc, livekitPackage };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"TwirpRPC.d.ts","sourceRoot":"","sources":["../src/TwirpRPC.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiBpD,KAAK,OAAO,GAAG;IACb,kCAAkC;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wGAAwG;IACxG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAKF,eAAO,MAAM,cAAc,YAAY,CAAC;AACxC,MAAM,WAAW,GAAG;IAClB,OAAO,CACL,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,GAAG,EAAE,yDAAyD;IACvE,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,qBAAa,WAAY,SAAQ,KAAK;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAGhC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAQpC;AAED,0CAA0C;AAC1C,eAAO,MAAM,UAAU,oBAAc,CAAC;AACtC,0CAA0C;AAC1C,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC;AAErC;;;;;GAKG;AACH,qBAAa,YAAa,SAAQ,WAAW;gBAEzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAMnC,sEAAsE;IACtE,IAAI,aAAa,IAAI,MAAM,GAAG,SAAS,CAGtC;IAED,kEAAkE;IAClE,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED,kFAAkF;IAClF,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,WAAW,GAAG,YAAY;IAOtD,OAAO,CAAC,MAAM,CAAC,QAAQ;CAkBxB;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,IAAI,EAAE,MAAM,CAAC;IAEb,GAAG,EAAE,MAAM,CAAC;IAEZ,MAAM,EAAE,MAAM,CAAC;IAEf,cAAc,EAAE,MAAM,CAAC;IAEvB,QAAQ,EAAE,OAAO,CAAC;IAElB,OAAO,CAAC,aAAa,CAAU;IAE/B,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO;IAaxD;;;;;;OAMG;IACG,OAAO,CACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,GAAG,EAAE,yDAAyD;IACpE,OAAO,EAAE,GAAG,EAAE,yDAAyD;IACvE,OAAO,SAAsB,GAE5B,OAAO,CAAC,GAAG,CAAC;CAyEhB"}
+175
View File
@@ -0,0 +1,175 @@
import {
FAILOVER_BACKOFF_BASE_MS,
failoverAttempts,
hostKey,
pickNext,
regionOrigins,
sleep
} from "./failover.js";
import { SDK_VERSION } from "./version.js";
const USER_AGENT = `livekit-server-sdk-node/${SDK_VERSION}`;
const defaultPrefix = "/twirp";
const defaultTimeoutSeconds = 10;
const livekitPackage = "livekit";
class ServerError extends Error {
constructor(name, message, status, code, metadata) {
super(message);
this.name = name;
this.status = status;
this.code = code;
this.metadata = metadata;
}
}
const TwirpError = ServerError;
class SipCallError extends ServerError {
constructor(name, message, status, code, metadata) {
super(name, SipCallError.describe(message, code, metadata), status, code, metadata);
this.name = "SipCallError";
}
/** The SIP response code of the failed call, e.g. 486 (Busy Here). */
get sipStatusCode() {
var _a;
const raw = (_a = this.metadata) == null ? void 0 : _a.sip_status_code;
return raw !== void 0 ? Number(raw) : void 0;
}
/** The SIP reason phrase of the failed call, e.g. "Busy Here". */
get sipStatus() {
var _a;
return (_a = this.metadata) == null ? void 0 : _a.sip_status;
}
/** Builds a SipCallError from a ServerError, preserving its code and metadata. */
static fromServerError(err) {
return new SipCallError(err.name, err.message, err.status, err.code, err.metadata);
}
// describe renders a clear message: the SIP status, the error code, and any
// other metadata the server attached. Falls back to the raw message when the
// error carries no SIP status.
static describe(fallback, code, metadata) {
const sipCode = metadata == null ? void 0 : metadata.sip_status_code;
if (!sipCode) {
return fallback;
}
const reason = metadata == null ? void 0 : metadata.sip_status;
let msg = `SIP call failed: ${sipCode}${reason ? ` ${reason}` : ""}`;
if (code) {
msg += ` (${code})`;
}
const extra = Object.entries(metadata ?? {}).filter(([k]) => k !== "sip_status_code" && k !== "sip_status" && k !== "error_details").map(([k, v]) => `${k}=${v}`);
if (extra.length) {
msg += ` [${extra.join(", ")}]`;
}
return msg;
}
}
class TwirpRpc {
constructor(host, pkg, options) {
if (host.startsWith("ws")) {
host = host.replace("ws", "http");
}
this.host = host;
this.pkg = pkg;
this.requestTimeout = (options == null ? void 0 : options.requestTimeout) ?? defaultTimeoutSeconds;
this.prefix = (options == null ? void 0 : options.prefix) || defaultPrefix;
this.failover = (options == null ? void 0 : options.failover) ?? true;
this.failoverForce = (options == null ? void 0 : options.failoverForce) ?? false;
this.failoverBackoffMs = (options == null ? void 0 : options.failoverBackoffMs) ?? FAILOVER_BACKOFF_BASE_MS;
}
/**
* Issues a Twirp request, failing over to alternative regions on retryable
* errors. On any transport error or HTTP 5xx it discovers regions via
* /settings/regions and replays the request body and headers intact
* against the next untried region, with exponential backoff. A 4xx is
* returned immediately.
*/
async request(service, method, data, headers, timeout = this.requestTimeout) {
const path = `${this.prefix}/${this.pkg}.${service}/${method}`;
const body = JSON.stringify(data);
const requestHeaders = {
"Content-Type": "application/json;charset=UTF-8",
"User-Agent": USER_AGENT,
...headers
};
const origin = new URL(this.host);
const maxAttempts = failoverAttempts(
this.failover,
origin.hostname,
this.failoverForce,
timeout
);
const attempted = /* @__PURE__ */ new Set([hostKey(origin)]);
let regions;
let current = this.host;
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
const isLast = attempt + 1 >= maxAttempts;
const init = { method: "POST", headers: requestHeaders, body };
if (timeout) {
init.signal = AbortSignal.timeout(timeout * 1e3);
}
let response;
let transportError;
try {
response = await fetch(new URL(path, current), init);
} catch (e) {
transportError = e;
}
if (response == null ? void 0 : response.ok) {
return await response.json();
}
const retryable = transportError !== void 0 || !!response && response.status >= 500;
let next;
if (retryable && !isLast) {
if (!regions) {
regions = await regionOrigins(origin, headers);
}
next = pickNext(regions, attempted);
}
if (!retryable || next === void 0) {
if (response) {
throw await toTwirpError(response);
}
throw transportError;
}
const reason = response ? `status ${response.status}` : transportError;
console.warn(
`livekit API request to ${new URL(current).host} failed (${reason}), retrying with fallback url ${next}`
);
await sleep(this.failoverBackoffMs * 2 ** attempt);
attempted.add(hostKey(new URL(next)));
current = next;
}
throw new Error("failover loop exited without returning");
}
}
async function toTwirpError(response) {
const isJson = response.headers.get("content-type") === "application/json";
let errorMessage = "Unknown internal error";
let errorCode = void 0;
let metadata = void 0;
try {
if (isJson) {
const parsedError = await response.json();
if ("msg" in parsedError) {
errorMessage = parsedError.msg;
}
if ("code" in parsedError) {
errorCode = parsedError.code;
}
if ("meta" in parsedError) {
metadata = parsedError.meta;
}
} else {
errorMessage = await response.text();
}
} catch (e) {
console.debug(`Error when trying to parse error message, using defaults`, e);
}
return new TwirpError(response.statusText, errorMessage, response.status, errorCode, metadata);
}
export {
ServerError,
SipCallError,
TwirpError,
TwirpRpc,
livekitPackage
};
//# sourceMappingURL=TwirpRPC.js.map
File diff suppressed because one or more lines are too long
+79
View File
@@ -0,0 +1,79 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var WebhookReceiver_exports = {};
__export(WebhookReceiver_exports, {
WebhookEvent: () => WebhookEvent,
WebhookReceiver: () => WebhookReceiver,
authorizeHeader: () => authorizeHeader
});
module.exports = __toCommonJS(WebhookReceiver_exports);
var import_protocol = require("@livekit/protocol");
var import_AccessToken = require("./AccessToken.cjs");
var import_digest = require("./crypto/digest.cjs");
const authorizeHeader = "Authorize";
class WebhookEvent extends import_protocol.WebhookEvent {
constructor() {
super(...arguments);
this.event = "";
}
static fromBinary(bytes, options) {
return new WebhookEvent().fromBinary(bytes, options);
}
static fromJson(jsonValue, options) {
return new WebhookEvent().fromJson(jsonValue, options);
}
static fromJsonString(jsonString, options) {
return new WebhookEvent().fromJsonString(jsonString, options);
}
}
class WebhookReceiver {
constructor(apiKey, apiSecret) {
this.verifier = new import_AccessToken.TokenVerifier(apiKey, apiSecret);
}
/**
* @param body - string of the posted body
* @param authHeader - `Authorization` header from the request
* @param skipAuth - true to skip auth validation
* @param clockTolerance - How much tolerance to allow for checks against the auth header to be skewed from the claims
* @returns The processed webhook event
*/
async receive(body, authHeader, skipAuth = false, clockTolerance) {
if (!skipAuth) {
if (!authHeader) {
throw new Error("authorization header is empty");
}
const claims = await this.verifier.verify(authHeader, clockTolerance);
const hash = await (0, import_digest.digest)(body);
const hashDecoded = btoa(
Array.from(new Uint8Array(hash)).map((v) => String.fromCharCode(v)).join("")
);
if (claims.sha256 !== hashDecoded) {
throw new Error("sha256 checksum of body does not match");
}
}
return WebhookEvent.fromJson(JSON.parse(body), { ignoreUnknownFields: true });
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
WebhookEvent,
WebhookReceiver,
authorizeHeader
});
//# sourceMappingURL=WebhookReceiver.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/WebhookReceiver.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { BinaryReadOptions, JsonReadOptions, JsonValue } from '@bufbuild/protobuf';\nimport { WebhookEvent as ProtoWebhookEvent } from '@livekit/protocol';\nimport { TokenVerifier } from './AccessToken.js';\nimport { digest } from './crypto/digest.js';\n\nexport const authorizeHeader = 'Authorize';\n\nexport class WebhookEvent extends ProtoWebhookEvent {\n event: WebhookEventNames = '';\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): WebhookEvent {\n return new WebhookEvent().fromBinary(bytes, options);\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): WebhookEvent {\n return new WebhookEvent().fromJson(jsonValue, options);\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): WebhookEvent {\n return new WebhookEvent().fromJsonString(jsonString, options);\n }\n}\n\nexport type WebhookEventNames =\n | 'room_started'\n | 'room_finished'\n | 'participant_joined'\n | 'participant_left'\n | 'participant_connection_aborted'\n | 'track_published'\n | 'track_unpublished'\n | 'egress_started'\n | 'egress_updated'\n | 'egress_ended'\n | 'ingress_started'\n | 'ingress_ended'\n /**\n * @internal\n * @remarks only used as a default value, not a valid webhook event\n */\n | '';\n\nexport class WebhookReceiver {\n private verifier: TokenVerifier;\n\n constructor(apiKey: string, apiSecret: string) {\n this.verifier = new TokenVerifier(apiKey, apiSecret);\n }\n\n /**\n * @param body - string of the posted body\n * @param authHeader - `Authorization` header from the request\n * @param skipAuth - true to skip auth validation\n * @param clockTolerance - How much tolerance to allow for checks against the auth header to be skewed from the claims\n * @returns The processed webhook event\n */\n async receive(\n body: string,\n authHeader?: string,\n skipAuth: boolean = false,\n clockTolerance?: string | number,\n ): Promise<WebhookEvent> {\n // verify token\n if (!skipAuth) {\n if (!authHeader) {\n throw new Error('authorization header is empty');\n }\n const claims = await this.verifier.verify(authHeader, clockTolerance);\n // confirm sha\n const hash = await digest(body);\n const hashDecoded = btoa(\n Array.from(new Uint8Array(hash))\n .map((v) => String.fromCharCode(v))\n .join(''),\n );\n\n if (claims.sha256 !== hashDecoded) {\n throw new Error('sha256 checksum of body does not match');\n }\n }\n\n return WebhookEvent.fromJson(JSON.parse(body), { ignoreUnknownFields: true });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,sBAAkD;AAClD,yBAA8B;AAC9B,oBAAuB;AAEhB,MAAM,kBAAkB;AAExB,MAAM,qBAAqB,gBAAAA,aAAkB;AAAA,EAA7C;AAAA;AACL,iBAA2B;AAAA;AAAA,EAE3B,OAAO,WAAW,OAAmB,SAAoD;AACvF,WAAO,IAAI,aAAa,EAAE,WAAW,OAAO,OAAO;AAAA,EACrD;AAAA,EAEA,OAAO,SAAS,WAAsB,SAAkD;AACtF,WAAO,IAAI,aAAa,EAAE,SAAS,WAAW,OAAO;AAAA,EACvD;AAAA,EAEA,OAAO,eAAe,YAAoB,SAAkD;AAC1F,WAAO,IAAI,aAAa,EAAE,eAAe,YAAY,OAAO;AAAA,EAC9D;AACF;AAqBO,MAAM,gBAAgB;AAAA,EAG3B,YAAY,QAAgB,WAAmB;AAC7C,SAAK,WAAW,IAAI,iCAAc,QAAQ,SAAS;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QACJ,MACA,YACA,WAAoB,OACpB,gBACuB;AAEvB,QAAI,CAAC,UAAU;AACb,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,+BAA+B;AAAA,MACjD;AACA,YAAM,SAAS,MAAM,KAAK,SAAS,OAAO,YAAY,cAAc;AAEpE,YAAM,OAAO,UAAM,sBAAO,IAAI;AAC9B,YAAM,cAAc;AAAA,QAClB,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC,EAC5B,IAAI,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC,EACjC,KAAK,EAAE;AAAA,MACZ;AAEA,UAAI,OAAO,WAAW,aAAa;AACjC,cAAM,IAAI,MAAM,wCAAwC;AAAA,MAC1D;AAAA,IACF;AAEA,WAAO,aAAa,SAAS,KAAK,MAAM,IAAI,GAAG,EAAE,qBAAqB,KAAK,CAAC;AAAA,EAC9E;AACF;","names":["ProtoWebhookEvent"]}
+30
View File
@@ -0,0 +1,30 @@
import { BinaryReadOptions, JsonValue, JsonReadOptions } from '@bufbuild/protobuf';
import { WebhookEvent as WebhookEvent$1 } from '@livekit/protocol';
declare const authorizeHeader = "Authorize";
declare class WebhookEvent extends WebhookEvent$1 {
event: WebhookEventNames;
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): WebhookEvent;
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): WebhookEvent;
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): WebhookEvent;
}
type WebhookEventNames = 'room_started' | 'room_finished' | 'participant_joined' | 'participant_left' | 'participant_connection_aborted' | 'track_published' | 'track_unpublished' | 'egress_started' | 'egress_updated' | 'egress_ended' | 'ingress_started' | 'ingress_ended'
/**
* @internal
* @remarks only used as a default value, not a valid webhook event
*/
| '';
declare class WebhookReceiver {
private verifier;
constructor(apiKey: string, apiSecret: string);
/**
* @param body - string of the posted body
* @param authHeader - `Authorization` header from the request
* @param skipAuth - true to skip auth validation
* @param clockTolerance - How much tolerance to allow for checks against the auth header to be skewed from the claims
* @returns The processed webhook event
*/
receive(body: string, authHeader?: string, skipAuth?: boolean, clockTolerance?: string | number): Promise<WebhookEvent>;
}
export { WebhookEvent, type WebhookEventNames, WebhookReceiver, authorizeHeader };
+30
View File
@@ -0,0 +1,30 @@
import { BinaryReadOptions, JsonValue, JsonReadOptions } from '@bufbuild/protobuf';
import { WebhookEvent as WebhookEvent$1 } from '@livekit/protocol';
declare const authorizeHeader = "Authorize";
declare class WebhookEvent extends WebhookEvent$1 {
event: WebhookEventNames;
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): WebhookEvent;
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): WebhookEvent;
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): WebhookEvent;
}
type WebhookEventNames = 'room_started' | 'room_finished' | 'participant_joined' | 'participant_left' | 'participant_connection_aborted' | 'track_published' | 'track_unpublished' | 'egress_started' | 'egress_updated' | 'egress_ended' | 'ingress_started' | 'ingress_ended'
/**
* @internal
* @remarks only used as a default value, not a valid webhook event
*/
| '';
declare class WebhookReceiver {
private verifier;
constructor(apiKey: string, apiSecret: string);
/**
* @param body - string of the posted body
* @param authHeader - `Authorization` header from the request
* @param skipAuth - true to skip auth validation
* @param clockTolerance - How much tolerance to allow for checks against the auth header to be skewed from the claims
* @returns The processed webhook event
*/
receive(body: string, authHeader?: string, skipAuth?: boolean, clockTolerance?: string | number): Promise<WebhookEvent>;
}
export { WebhookEvent, type WebhookEventNames, WebhookReceiver, authorizeHeader };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"WebhookReceiver.d.ts","sourceRoot":"","sources":["../src/WebhookReceiver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACxF,OAAO,EAAE,YAAY,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAItE,eAAO,MAAM,eAAe,cAAc,CAAC;AAE3C,qBAAa,YAAa,SAAQ,iBAAiB;IACjD,KAAK,EAAE,iBAAiB,CAAM;IAE9B,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,YAAY;IAIxF,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,YAAY;IAIvF,MAAM,CAAC,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,YAAY;CAG5F;AAED,MAAM,MAAM,iBAAiB,GACzB,cAAc,GACd,eAAe,GACf,oBAAoB,GACpB,kBAAkB,GAClB,gCAAgC,GAChC,iBAAiB,GACjB,mBAAmB,GACnB,gBAAgB,GAChB,gBAAgB,GAChB,cAAc,GACd,iBAAiB,GACjB,eAAe;AACjB;;;GAGG;GACD,EAAE,CAAC;AAEP,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAgB;gBAEpB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;IAI7C;;;;;;OAMG;IACG,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,GAAE,OAAe,EACzB,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAC/B,OAAO,CAAC,YAAY,CAAC;CAsBzB"}
+53
View File
@@ -0,0 +1,53 @@
import { WebhookEvent as ProtoWebhookEvent } from "@livekit/protocol";
import { TokenVerifier } from "./AccessToken.js";
import { digest } from "./crypto/digest.js";
const authorizeHeader = "Authorize";
class WebhookEvent extends ProtoWebhookEvent {
constructor() {
super(...arguments);
this.event = "";
}
static fromBinary(bytes, options) {
return new WebhookEvent().fromBinary(bytes, options);
}
static fromJson(jsonValue, options) {
return new WebhookEvent().fromJson(jsonValue, options);
}
static fromJsonString(jsonString, options) {
return new WebhookEvent().fromJsonString(jsonString, options);
}
}
class WebhookReceiver {
constructor(apiKey, apiSecret) {
this.verifier = new TokenVerifier(apiKey, apiSecret);
}
/**
* @param body - string of the posted body
* @param authHeader - `Authorization` header from the request
* @param skipAuth - true to skip auth validation
* @param clockTolerance - How much tolerance to allow for checks against the auth header to be skewed from the claims
* @returns The processed webhook event
*/
async receive(body, authHeader, skipAuth = false, clockTolerance) {
if (!skipAuth) {
if (!authHeader) {
throw new Error("authorization header is empty");
}
const claims = await this.verifier.verify(authHeader, clockTolerance);
const hash = await digest(body);
const hashDecoded = btoa(
Array.from(new Uint8Array(hash)).map((v) => String.fromCharCode(v)).join("")
);
if (claims.sha256 !== hashDecoded) {
throw new Error("sha256 checksum of body does not match");
}
}
return WebhookEvent.fromJson(JSON.parse(body), { ignoreUnknownFields: true });
}
}
export {
WebhookEvent,
WebhookReceiver,
authorizeHeader
};
//# sourceMappingURL=WebhookReceiver.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/WebhookReceiver.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\nimport type { BinaryReadOptions, JsonReadOptions, JsonValue } from '@bufbuild/protobuf';\nimport { WebhookEvent as ProtoWebhookEvent } from '@livekit/protocol';\nimport { TokenVerifier } from './AccessToken.js';\nimport { digest } from './crypto/digest.js';\n\nexport const authorizeHeader = 'Authorize';\n\nexport class WebhookEvent extends ProtoWebhookEvent {\n event: WebhookEventNames = '';\n\n static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): WebhookEvent {\n return new WebhookEvent().fromBinary(bytes, options);\n }\n\n static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): WebhookEvent {\n return new WebhookEvent().fromJson(jsonValue, options);\n }\n\n static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): WebhookEvent {\n return new WebhookEvent().fromJsonString(jsonString, options);\n }\n}\n\nexport type WebhookEventNames =\n | 'room_started'\n | 'room_finished'\n | 'participant_joined'\n | 'participant_left'\n | 'participant_connection_aborted'\n | 'track_published'\n | 'track_unpublished'\n | 'egress_started'\n | 'egress_updated'\n | 'egress_ended'\n | 'ingress_started'\n | 'ingress_ended'\n /**\n * @internal\n * @remarks only used as a default value, not a valid webhook event\n */\n | '';\n\nexport class WebhookReceiver {\n private verifier: TokenVerifier;\n\n constructor(apiKey: string, apiSecret: string) {\n this.verifier = new TokenVerifier(apiKey, apiSecret);\n }\n\n /**\n * @param body - string of the posted body\n * @param authHeader - `Authorization` header from the request\n * @param skipAuth - true to skip auth validation\n * @param clockTolerance - How much tolerance to allow for checks against the auth header to be skewed from the claims\n * @returns The processed webhook event\n */\n async receive(\n body: string,\n authHeader?: string,\n skipAuth: boolean = false,\n clockTolerance?: string | number,\n ): Promise<WebhookEvent> {\n // verify token\n if (!skipAuth) {\n if (!authHeader) {\n throw new Error('authorization header is empty');\n }\n const claims = await this.verifier.verify(authHeader, clockTolerance);\n // confirm sha\n const hash = await digest(body);\n const hashDecoded = btoa(\n Array.from(new Uint8Array(hash))\n .map((v) => String.fromCharCode(v))\n .join(''),\n );\n\n if (claims.sha256 !== hashDecoded) {\n throw new Error('sha256 checksum of body does not match');\n }\n }\n\n return WebhookEvent.fromJson(JSON.parse(body), { ignoreUnknownFields: true });\n }\n}\n"],"mappings":"AAIA,SAAS,gBAAgB,yBAAyB;AAClD,SAAS,qBAAqB;AAC9B,SAAS,cAAc;AAEhB,MAAM,kBAAkB;AAExB,MAAM,qBAAqB,kBAAkB;AAAA,EAA7C;AAAA;AACL,iBAA2B;AAAA;AAAA,EAE3B,OAAO,WAAW,OAAmB,SAAoD;AACvF,WAAO,IAAI,aAAa,EAAE,WAAW,OAAO,OAAO;AAAA,EACrD;AAAA,EAEA,OAAO,SAAS,WAAsB,SAAkD;AACtF,WAAO,IAAI,aAAa,EAAE,SAAS,WAAW,OAAO;AAAA,EACvD;AAAA,EAEA,OAAO,eAAe,YAAoB,SAAkD;AAC1F,WAAO,IAAI,aAAa,EAAE,eAAe,YAAY,OAAO;AAAA,EAC9D;AACF;AAqBO,MAAM,gBAAgB;AAAA,EAG3B,YAAY,QAAgB,WAAmB;AAC7C,SAAK,WAAW,IAAI,cAAc,QAAQ,SAAS;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QACJ,MACA,YACA,WAAoB,OACpB,gBACuB;AAEvB,QAAI,CAAC,UAAU;AACb,UAAI,CAAC,YAAY;AACf,cAAM,IAAI,MAAM,+BAA+B;AAAA,MACjD;AACA,YAAM,SAAS,MAAM,KAAK,SAAS,OAAO,YAAY,cAAc;AAEpE,YAAM,OAAO,MAAM,OAAO,IAAI;AAC9B,YAAM,cAAc;AAAA,QAClB,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC,EAC5B,IAAI,CAAC,MAAM,OAAO,aAAa,CAAC,CAAC,EACjC,KAAK,EAAE;AAAA,MACZ;AAEA,UAAI,OAAO,WAAW,aAAa;AACjC,cAAM,IAAI,MAAM,wCAAwC;AAAA,MAC1D;AAAA,IACF;AAEA,WAAO,aAAa,SAAS,KAAK,MAAM,IAAI,GAAG,EAAE,qBAAqB,KAAK,CAAC;AAAA,EAC9E;AACF;","names":[]}
+48
View File
@@ -0,0 +1,48 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var digest_exports = {};
__export(digest_exports, {
digest: () => digest
});
module.exports = __toCommonJS(digest_exports);
async function digest(data) {
var _a;
if ((_a = globalThis.crypto) == null ? void 0 : _a.subtle) {
const encoder = new TextEncoder();
return crypto.subtle.digest("SHA-256", encoder.encode(data));
} else {
const nodeCrypto = await import("node:crypto");
return nodeCrypto.createHash("sha256").update(data).digest();
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
digest
});
//# sourceMappingURL=digest.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/crypto/digest.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n// Use the Web Crypto API if available, otherwise fallback to Node.js crypto\nexport async function digest(data: string): Promise<ArrayBuffer> {\n if (globalThis.crypto?.subtle) {\n const encoder = new TextEncoder();\n return crypto.subtle.digest('SHA-256', encoder.encode(data));\n } else {\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.createHash('sha256').update(data).digest();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,eAAsB,OAAO,MAAoC;AALjE;AAME,OAAI,gBAAW,WAAX,mBAAmB,QAAQ;AAC7B,UAAM,UAAU,IAAI,YAAY;AAChC,WAAO,OAAO,OAAO,OAAO,WAAW,QAAQ,OAAO,IAAI,CAAC;AAAA,EAC7D,OAAO;AACL,UAAM,aAAa,MAAM,OAAO,aAAa;AAC7C,WAAO,WAAW,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO;AAAA,EAC7D;AACF;","names":[]}
+3
View File
@@ -0,0 +1,3 @@
declare function digest(data: string): Promise<ArrayBuffer>;
export { digest };
+3
View File
@@ -0,0 +1,3 @@
declare function digest(data: string): Promise<ArrayBuffer>;
export { digest };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../src/crypto/digest.ts"],"names":[],"mappings":"AAKA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAQ/D"}
+14
View File
@@ -0,0 +1,14 @@
async function digest(data) {
var _a;
if ((_a = globalThis.crypto) == null ? void 0 : _a.subtle) {
const encoder = new TextEncoder();
return crypto.subtle.digest("SHA-256", encoder.encode(data));
} else {
const nodeCrypto = await import("node:crypto");
return nodeCrypto.createHash("sha256").update(data).digest();
}
}
export {
digest
};
//# sourceMappingURL=digest.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/crypto/digest.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n// Use the Web Crypto API if available, otherwise fallback to Node.js crypto\nexport async function digest(data: string): Promise<ArrayBuffer> {\n if (globalThis.crypto?.subtle) {\n const encoder = new TextEncoder();\n return crypto.subtle.digest('SHA-256', encoder.encode(data));\n } else {\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.createHash('sha256').update(data).digest();\n }\n}\n"],"mappings":"AAKA,eAAsB,OAAO,MAAoC;AALjE;AAME,OAAI,gBAAW,WAAX,mBAAmB,QAAQ;AAC7B,UAAM,UAAU,IAAI,YAAY;AAChC,WAAO,OAAO,OAAO,OAAO,WAAW,QAAQ,OAAO,IAAI,CAAC;AAAA,EAC7D,OAAO;AACL,UAAM,aAAa,MAAM,OAAO,aAAa;AAC7C,WAAO,WAAW,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO;AAAA,EAC7D;AACF;","names":[]}
+46
View File
@@ -0,0 +1,46 @@
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var uuid_exports = {};
__export(uuid_exports, {
getRandomBytes: () => getRandomBytes
});
module.exports = __toCommonJS(uuid_exports);
async function getRandomBytes(size = 16) {
if (globalThis.crypto) {
return crypto.getRandomValues(new Uint8Array(size));
} else {
const nodeCrypto = await import("node:crypto");
return nodeCrypto.getRandomValues(new Uint8Array(size));
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getRandomBytes
});
//# sourceMappingURL=uuid.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/crypto/uuid.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n// Use the Web Crypto API if available, otherwise fallback to Node.js crypto\nexport async function getRandomBytes(size: number = 16): Promise<Uint8Array> {\n if (globalThis.crypto) {\n return crypto.getRandomValues(new Uint8Array(size));\n } else {\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.getRandomValues(new Uint8Array(size));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,eAAsB,eAAe,OAAe,IAAyB;AAC3E,MAAI,WAAW,QAAQ;AACrB,WAAO,OAAO,gBAAgB,IAAI,WAAW,IAAI,CAAC;AAAA,EACpD,OAAO;AACL,UAAM,aAAa,MAAM,OAAO,aAAa;AAC7C,WAAO,WAAW,gBAAgB,IAAI,WAAW,IAAI,CAAC;AAAA,EACxD;AACF;","names":[]}
+3
View File
@@ -0,0 +1,3 @@
declare function getRandomBytes(size?: number): Promise<Uint8Array>;
export { getRandomBytes };
+3
View File
@@ -0,0 +1,3 @@
declare function getRandomBytes(size?: number): Promise<Uint8Array>;
export { getRandomBytes };
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../../src/crypto/uuid.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,CAAC,IAAI,GAAE,MAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAO3E"}
+12
View File
@@ -0,0 +1,12 @@
async function getRandomBytes(size = 16) {
if (globalThis.crypto) {
return crypto.getRandomValues(new Uint8Array(size));
} else {
const nodeCrypto = await import("node:crypto");
return nodeCrypto.getRandomValues(new Uint8Array(size));
}
}
export {
getRandomBytes
};
//# sourceMappingURL=uuid.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../../src/crypto/uuid.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2024 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n// Use the Web Crypto API if available, otherwise fallback to Node.js crypto\nexport async function getRandomBytes(size: number = 16): Promise<Uint8Array> {\n if (globalThis.crypto) {\n return crypto.getRandomValues(new Uint8Array(size));\n } else {\n const nodeCrypto = await import('node:crypto');\n return nodeCrypto.getRandomValues(new Uint8Array(size));\n }\n}\n"],"mappings":"AAKA,eAAsB,eAAe,OAAe,IAAyB;AAC3E,MAAI,WAAW,QAAQ;AACrB,WAAO,OAAO,gBAAgB,IAAI,WAAW,IAAI,CAAC;AAAA,EACpD,OAAO;AACL,UAAM,aAAa,MAAM,OAAO,aAAa;AAC7C,WAAO,WAAW,gBAAgB,IAAI,WAAW,IAAI,CAAC;AAAA,EACxD;AACF;","names":[]}
+39
View File
@@ -0,0 +1,39 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dialTimeout_exports = {};
__export(dialTimeout_exports, {
DEFAULT_RINGING_TIMEOUT_SECONDS: () => DEFAULT_RINGING_TIMEOUT_SECONDS,
RINGING_TIMEOUT_MARGIN_SECONDS: () => RINGING_TIMEOUT_MARGIN_SECONDS,
dialRequestTimeout: () => dialRequestTimeout
});
module.exports = __toCommonJS(dialTimeout_exports);
const DEFAULT_RINGING_TIMEOUT_SECONDS = 30;
const RINGING_TIMEOUT_MARGIN_SECONDS = 2;
function dialRequestTimeout(timeout, ringingTimeout) {
const ring = ringingTimeout ?? DEFAULT_RINGING_TIMEOUT_SECONDS;
const floor = ring + RINGING_TIMEOUT_MARGIN_SECONDS;
return Math.max(timeout ?? floor, floor);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DEFAULT_RINGING_TIMEOUT_SECONDS,
RINGING_TIMEOUT_MARGIN_SECONDS,
dialRequestTimeout
});
//# sourceMappingURL=dialTimeout.cjs.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"sources":["../src/dialTimeout.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n// Shared request-timeout handling for calls that may block until a call is\n// answered (SIP CreateSIPParticipant/TransferSIPParticipant, WhatsApp\n// AcceptWhatsAppCall). These take longer than a normal API call, and the request\n// must outlast the wait or it would abort before the call is answered.\n\n/**\n * Ring window (seconds) assumed when a request doesn't set a ringing timeout;\n * matches the server default. A dialing request must outlast it.\n */\nexport const DEFAULT_RINGING_TIMEOUT_SECONDS = 30;\n\n/**\n * When a call waits on ringing, the request must outlast the ringing window or\n * it would abort before the call can be answered. We keep at least this margin\n * (seconds) of request timeout above the ringing timeout.\n */\nexport const RINGING_TIMEOUT_MARGIN_SECONDS = 2;\n\n/**\n * Resolves the request timeout (seconds) for a phone-dialing call: the ring\n * window plus a margin, so the request doesn't abort before the call can be\n * answered. The ring window is the request's `ringingTimeout` when set, else\n * {@link DEFAULT_RINGING_TIMEOUT_SECONDS}. A longer user-supplied `timeout` is\n * honored; a shorter one is raised to the floor.\n */\nexport function dialRequestTimeout(\n timeout: number | undefined,\n ringingTimeout: number | undefined,\n): number {\n const ring = ringingTimeout ?? DEFAULT_RINGING_TIMEOUT_SECONDS;\n const floor = ring + RINGING_TIMEOUT_MARGIN_SECONDS;\n return Math.max(timeout ?? floor, floor);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaO,MAAM,kCAAkC;AAOxC,MAAM,iCAAiC;AASvC,SAAS,mBACd,SACA,gBACQ;AACR,QAAM,OAAO,kBAAkB;AAC/B,QAAM,QAAQ,OAAO;AACrB,SAAO,KAAK,IAAI,WAAW,OAAO,KAAK;AACzC;","names":[]}

Some files were not shown because too many files have changed in this diff Show More