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
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+216
View File
@@ -0,0 +1,216 @@
<!--
SPDX-FileCopyrightText: 2024 LiveKit, Inc.
SPDX-License-Identifier: Apache-2.0
-->
# LiveKit Server API for JS
Use this SDK to manage <a href="https://livekit.io/">LiveKit</a> rooms and create access tokens from your JavaScript/Node.js backend.
> [!NOTE]
> This is v2 of the server-sdk-js which runs in NodeJS, Deno and Bun!
> (It theoretically now also runs in every major browser, but that's not recommended due to the security risks involved with exposing your API secrets)
> Read the [migration section](#migrate-from-v1x-to-v2x) below for a detailed overview on what has changed.
## Installation
### Pnpm
```
pnpm add livekit-server-sdk
```
### Yarn
```
yarn add livekit-server-sdk
```
### NPM
```
npm install livekit-server-sdk --save
```
## Usage
### Environment Variables
You may store credentials in environment variables. If api-key or api-secret is not passed in when creating a `RoomServiceClient` or `AccessToken`, the values in the following env vars will be used:
- `LIVEKIT_API_KEY`
- `LIVEKIT_API_SECRET`
### Creating Access Tokens
Creating a token for participant to join a room.
```typescript
import { AccessToken } from 'livekit-server-sdk';
// if this room doesn't exist, it'll be automatically created when the first
// client joins
const roomName = 'name-of-room';
// identifier to be used for participant.
// it's available as LocalParticipant.identity with livekit-client SDK
const participantName = 'user-name';
const at = new AccessToken('api-key', 'secret-key', {
identity: participantName,
});
at.addGrant({ roomJoin: true, room: roomName });
const token = await at.toJwt();
console.log('access token', token);
```
By default, the token expires after 6 hours. you may override this by passing in `ttl` in the access token options. `ttl` is expressed in seconds (as number) or a string describing a time span [vercel/ms](https://github.com/vercel/ms). eg: '2 days', '10h'.
### Permissions in Access Tokens
It's possible to customize the permissions of each participant:
```typescript
const at = new AccessToken('api-key', 'secret-key', {
identity: participantName,
});
at.addGrant({
roomJoin: true,
room: roomName,
canPublish: false,
canSubscribe: true,
});
```
This will allow the participant to subscribe to tracks, but not publish their own to the room.
### Managing Rooms
`RoomServiceClient` gives you APIs to list, create, and delete rooms. It also requires a pair of api key/secret key to operate.
```typescript
import { Room, RoomServiceClient } from 'livekit-server-sdk';
const livekitHost = 'https://my.livekit.host';
const svc = new RoomServiceClient(livekitHost, 'api-key', 'secret-key');
// list rooms
svc.listRooms().then((rooms: Room[]) => {
console.log('existing rooms', rooms);
});
// create a new room
const opts = {
name: 'myroom',
// timeout in seconds
emptyTimeout: 10 * 60,
maxParticipants: 20,
};
svc.createRoom(opts).then((room: Room) => {
console.log('room created', room);
});
// delete a room
svc.deleteRoom('myroom').then(() => {
console.log('room deleted');
});
```
## Webhooks
The JS SDK also provides helper functions to decode and verify webhook callbacks. While verification is optional, it ensures the authenticity of the message. See [webhooks guide](https://docs.livekit.io/home/server/webhooks/) for details.
LiveKit POSTs to webhook endpoints with `Content-Type: application/webhook+json`. Please ensure your server is able to receive POST body with that MIME.
Check out [example projects](examples) for full examples of webhooks integration.
```typescript
import { WebhookReceiver } from 'livekit-server-sdk';
const receiver = new WebhookReceiver('apikey', 'apisecret');
// In order to use the validator, WebhookReceiver must have access to the raw POSTed string (instead of a parsed JSON object)
// if you are using express middleware, ensure that `express.raw` is used for the webhook endpoint
// app.use(express.raw({type: 'application/webhook+json'}));
app.post('/webhook-endpoint', async (req, res) => {
// event is a WebhookEvent object
const event = await receiver.receive(req.body, req.get('Authorization'));
});
```
## Migrate from v1.x to v2.x
### Token generation
Because the `jsonwebtoken` lib got replaced with `jose`, there are a couple of APIs that are now async, that weren't before:
```typescript
const at = new AccessToken('api-key', 'secret-key', {
identity: participantName,
});
at.addGrant({ roomJoin: true, room: roomName });
// v1
// const token = at.toJWT();
// v2
const token = await at.toJwt();
// v1
// const grants = v.verify(token);
// v2
const grants = await v.verify(token);
app.post('/webhook-endpoint', async (req, res) => {
// v1
// const event = receiver.receive(req.body, req.get('Authorization'));
// v2
const event = await receiver.receive(req.body, req.get('Authorization'));
});
```
### Egress API
Egress request types have been updated from interfaces to classes in the latest version. Additionally, `oneof` fields now require an explicit `case` field to specify the value type.
For example, to create a RoomComposite Egress:
```typescript
// v1
// const fileOutput = {
// fileType: EncodedFileType.MP4,
// filepath: 'livekit-demo/room-composite-test.mp4',
// s3: {
// accessKey: 'aws-access-key',
// secret: 'aws-access-secret',
// region: 'aws-region',
// bucket: 'my-bucket',
// },
// };
// const info = await egressClient.startRoomCompositeEgress('my-room', {
// file: fileOutput,
// });
// v2 - current
const fileOutput = new EncodedFileOutput({
filepath: 'dz/davids-room-test.mp4',
output: {
case: 's3',
value: new S3Upload({
accessKey: 'aws-access-key',
secret: 'aws-access-secret',
bucket: 'my-bucket',
}),
},
});
const info = await egressClient.startRoomCompositeEgress('my-room', {
file: fileOutput,
});
```
+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":[]}

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