livekit-server-sdk 2.3.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -95
- package/dist/AccessToken.d.ts +15 -3
- package/dist/AccessToken.d.ts.map +1 -0
- package/dist/AccessToken.js +32 -3
- package/dist/AccessToken.js.map +1 -1
- package/dist/EgressClient.d.ts +1 -0
- package/dist/EgressClient.d.ts.map +1 -0
- package/dist/EgressClient.js +5 -2
- package/dist/EgressClient.js.map +1 -1
- package/dist/IngressClient.d.ts +1 -0
- package/dist/IngressClient.d.ts.map +1 -0
- package/dist/IngressClient.js +3 -0
- package/dist/IngressClient.js.map +1 -1
- package/dist/RoomServiceClient.d.ts +4 -2
- package/dist/RoomServiceClient.d.ts.map +1 -0
- package/dist/RoomServiceClient.js.map +1 -1
- package/dist/ServiceBase.d.ts +3 -2
- package/dist/ServiceBase.d.ts.map +1 -0
- package/dist/ServiceBase.js +7 -1
- package/dist/ServiceBase.js.map +1 -1
- package/dist/SipClient.d.ts +43 -1
- package/dist/SipClient.d.ts.map +1 -0
- package/dist/SipClient.js +111 -11
- package/dist/SipClient.js.map +1 -1
- package/dist/TwirpRPC.d.ts +1 -0
- package/dist/TwirpRPC.d.ts.map +1 -0
- package/dist/TwirpRPC.js.map +1 -1
- package/dist/WebhookReceiver.d.ts +2 -1
- package/dist/WebhookReceiver.d.ts.map +1 -0
- package/dist/WebhookReceiver.js.map +1 -1
- package/dist/grants.d.ts +12 -2
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +3 -0
- package/dist/grants.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/package.json +7 -8
- package/src/AccessToken.test.ts +100 -0
- package/src/AccessToken.ts +184 -0
- package/src/EgressClient.ts +617 -0
- package/src/IngressClient.ts +257 -0
- package/src/RoomServiceClient.ts +359 -0
- package/src/ServiceBase.ts +38 -0
- package/src/SipClient.ts +427 -0
- package/src/TwirpRPC.ts +54 -0
- package/src/WebhookReceiver.test.ts +44 -0
- package/src/WebhookReceiver.ts +85 -0
- package/src/grants.test.ts +30 -0
- package/src/grants.ts +107 -0
- package/src/index.ts +53 -0
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.eslintrc.cjs +0 -17
- package/.github/banner_dark.png +0 -0
- package/.github/banner_light.png +0 -0
- package/.github/workflows/release.yaml +0 -46
- package/.github/workflows/test.yaml +0 -46
- package/.gitmodules +0 -3
- package/.prettierignore +0 -8
- package/CHANGELOG.md +0 -87
- package/NOTICE +0 -13
- package/renovate.json +0 -18
- package/tsconfig.eslint.json +0 -5
- package/vite.config.js +0 -8
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2024 LiveKit, Inc.
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
import * as jose from 'jose';
|
|
5
|
+
import type { ClaimGrants, SIPGrant, VideoGrant } from './grants.js';
|
|
6
|
+
import { claimsToJwtPayload } from './grants.js';
|
|
7
|
+
|
|
8
|
+
// 6 hours
|
|
9
|
+
const defaultTTL = `6h`;
|
|
10
|
+
|
|
11
|
+
export interface AccessTokenOptions {
|
|
12
|
+
/**
|
|
13
|
+
* amount of time before expiration
|
|
14
|
+
* expressed in seconds or a string describing a time span zeit/ms.
|
|
15
|
+
* eg: '2 days', '10h', or seconds as numeric value
|
|
16
|
+
*/
|
|
17
|
+
ttl?: number | string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* display name for the participant, available as `Participant.name`
|
|
21
|
+
*/
|
|
22
|
+
name?: string;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* identity of the user, required for room join tokens
|
|
26
|
+
*/
|
|
27
|
+
identity?: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* custom metadata to be passed to participants
|
|
31
|
+
*/
|
|
32
|
+
metadata?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class AccessToken {
|
|
36
|
+
private apiKey: string;
|
|
37
|
+
|
|
38
|
+
private apiSecret: string;
|
|
39
|
+
|
|
40
|
+
private grants: ClaimGrants;
|
|
41
|
+
|
|
42
|
+
identity?: string;
|
|
43
|
+
|
|
44
|
+
ttl: number | string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new AccessToken
|
|
48
|
+
* @param apiKey API Key, can be set in env LIVEKIT_API_KEY
|
|
49
|
+
* @param apiSecret Secret, can be set in env LIVEKIT_API_SECRET
|
|
50
|
+
*/
|
|
51
|
+
constructor(apiKey?: string, apiSecret?: string, options?: AccessTokenOptions) {
|
|
52
|
+
if (!apiKey) {
|
|
53
|
+
apiKey = process.env.LIVEKIT_API_KEY;
|
|
54
|
+
}
|
|
55
|
+
if (!apiSecret) {
|
|
56
|
+
apiSecret = process.env.LIVEKIT_API_SECRET;
|
|
57
|
+
}
|
|
58
|
+
if (!apiKey || !apiSecret) {
|
|
59
|
+
throw Error('api-key and api-secret must be set');
|
|
60
|
+
} else if (typeof document !== 'undefined') {
|
|
61
|
+
// check against document rather than window because deno provides window
|
|
62
|
+
console.error(
|
|
63
|
+
'You should not include your API secret in your web client bundle.\n\n' +
|
|
64
|
+
'Your web client should request a token from your backend server which should then use ' +
|
|
65
|
+
'the API secret to generate a token. See https://docs.livekit.io/client/connect/',
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
this.apiKey = apiKey;
|
|
69
|
+
this.apiSecret = apiSecret;
|
|
70
|
+
this.grants = {};
|
|
71
|
+
this.identity = options?.identity;
|
|
72
|
+
this.ttl = options?.ttl || defaultTTL;
|
|
73
|
+
if (typeof this.ttl === 'number') {
|
|
74
|
+
this.ttl = `${this.ttl}s`;
|
|
75
|
+
}
|
|
76
|
+
if (options?.metadata) {
|
|
77
|
+
this.metadata = options.metadata;
|
|
78
|
+
}
|
|
79
|
+
if (options?.name) {
|
|
80
|
+
this.name = options.name;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Adds a video grant to this token.
|
|
86
|
+
* @param grant -
|
|
87
|
+
*/
|
|
88
|
+
addGrant(grant: VideoGrant) {
|
|
89
|
+
this.grants.video = { ...(this.grants.video ?? {}), ...grant };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Adds a SIP grant to this token.
|
|
94
|
+
* @param grant -
|
|
95
|
+
*/
|
|
96
|
+
addSIPGrant(grant: SIPGrant) {
|
|
97
|
+
this.grants.sip = { ...(this.grants.sip ?? {}), ...grant };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get name(): string | undefined {
|
|
101
|
+
return this.grants.name;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
set name(name: string) {
|
|
105
|
+
this.grants.name = name;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get metadata(): string | undefined {
|
|
109
|
+
return this.grants.metadata;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Set metadata to be passed to the Participant, used only when joining the room
|
|
114
|
+
*/
|
|
115
|
+
set metadata(md: string) {
|
|
116
|
+
this.grants.metadata = md;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get attributes(): Record<string, string> | undefined {
|
|
120
|
+
return this.grants.attributes;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
set attributes(attrs: Record<string, string>) {
|
|
124
|
+
this.grants.attributes = attrs;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
get kind(): string | undefined {
|
|
128
|
+
return this.grants.kind;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
set kind(kind: string) {
|
|
132
|
+
this.grants.kind = kind;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
get sha256(): string | undefined {
|
|
136
|
+
return this.grants.sha256;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
set sha256(sha: string | undefined) {
|
|
140
|
+
this.grants.sha256 = sha;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @returns JWT encoded token
|
|
145
|
+
*/
|
|
146
|
+
async toJwt(): Promise<string> {
|
|
147
|
+
// TODO: check for video grant validity
|
|
148
|
+
|
|
149
|
+
const secret = new TextEncoder().encode(this.apiSecret);
|
|
150
|
+
|
|
151
|
+
const jwt = new jose.SignJWT(claimsToJwtPayload(this.grants))
|
|
152
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
153
|
+
.setIssuer(this.apiKey)
|
|
154
|
+
.setExpirationTime(this.ttl)
|
|
155
|
+
.setNotBefore(0);
|
|
156
|
+
if (this.identity) {
|
|
157
|
+
jwt.setSubject(this.identity);
|
|
158
|
+
} else if (this.grants.video?.roomJoin) {
|
|
159
|
+
throw Error('identity is required for join but not set');
|
|
160
|
+
}
|
|
161
|
+
return jwt.sign(secret);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export class TokenVerifier {
|
|
166
|
+
private apiKey: string;
|
|
167
|
+
|
|
168
|
+
private apiSecret: string;
|
|
169
|
+
|
|
170
|
+
constructor(apiKey: string, apiSecret: string) {
|
|
171
|
+
this.apiKey = apiKey;
|
|
172
|
+
this.apiSecret = apiSecret;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async verify(token: string): Promise<ClaimGrants> {
|
|
176
|
+
const secret = new TextEncoder().encode(this.apiSecret);
|
|
177
|
+
const { payload } = await jose.jwtVerify(token, secret, { issuer: this.apiKey });
|
|
178
|
+
if (!payload) {
|
|
179
|
+
throw Error('invalid token');
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return payload as ClaimGrants;
|
|
183
|
+
}
|
|
184
|
+
}
|