farvex 0.2.0 → 1.0.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/CHANGELOG.md +12 -1
- package/README.md +292 -175
- package/dist/index.cjs +991 -2468
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +989 -2461
- package/dist/index.js.map +1 -1
- package/dist/livekit/index.cjs +4 -24
- package/dist/livekit/index.d.cts +2 -2
- package/dist/livekit/index.d.ts +2 -2
- package/dist/livekit/index.js +1 -1
- package/dist/react/index.cjs +89 -3287
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +17 -84
- package/dist/react/index.d.ts +17 -84
- package/dist/react/index.js +88 -3276
- package/dist/react/index.js.map +1 -1
- package/dist/types-DhJEeeui.d.cts +206 -0
- package/dist/types-DhJEeeui.d.ts +206 -0
- package/package.json +52 -71
- package/dist/core/index.cjs +0 -2917
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -1417
- package/dist/core/index.d.ts +0 -1417
- package/dist/core/index.js +0 -2902
- package/dist/core/index.js.map +0 -1
- package/dist/mock/index.cjs +0 -3267
- package/dist/mock/index.cjs.map +0 -1
- package/dist/mock/index.d.cts +0 -31
- package/dist/mock/index.d.ts +0 -31
- package/dist/mock/index.js +0 -3263
- package/dist/mock/index.js.map +0 -1
package/dist/core/index.cjs
DELETED
|
@@ -1,2917 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var socket_ioClient = require('socket.io-client');
|
|
4
|
-
var livekitClient = require('livekit-client');
|
|
5
|
-
|
|
6
|
-
// src/shared/types.ts
|
|
7
|
-
function nullify(value) {
|
|
8
|
-
if (value === void 0 || value === null) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
if (typeof value === "string" && value.length === 0) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
return value;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// src/shared/error.ts
|
|
18
|
-
function make(kind, retryable, code, title, overrides = {}) {
|
|
19
|
-
return {
|
|
20
|
-
kind,
|
|
21
|
-
code,
|
|
22
|
-
title,
|
|
23
|
-
retryable,
|
|
24
|
-
...overrides
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
var callpadError = {
|
|
28
|
-
validation: (code, title, ov) => make("validation", false, code, title, ov),
|
|
29
|
-
unauth: (code, title, ov) => make("unauth", false, code, title, ov),
|
|
30
|
-
forbidden: (code, title, ov) => make("forbidden", false, code, title, ov),
|
|
31
|
-
notfound: (code, title, ov) => make("notfound", false, code, title, ov),
|
|
32
|
-
precondition: (code, title, ov) => make("precondition", false, code, title, ov),
|
|
33
|
-
conflict: (code, title, ov) => make("conflict", false, code, title, ov),
|
|
34
|
-
internal: (code, title, ov) => make("internal", true, code, title, ov),
|
|
35
|
-
unavailable: (code, title, ov) => make("unavailable", true, code, title, ov),
|
|
36
|
-
timeout: (code, title, ov) => make("timeout", true, code, title, ov),
|
|
37
|
-
network: (code, title, ov) => make("network", true, code, title, ov),
|
|
38
|
-
rateLimited: (code, title, ov) => make("rate_limited", true, code, title, ov),
|
|
39
|
-
mediaDevice: (code, title, ov) => make("media_device", false, code, title, ov),
|
|
40
|
-
mediaUnavailable: (code, title, ov) => make("media_unavailable", true, code, title, ov),
|
|
41
|
-
disposed: () => make("disposed", false, "callpad.disposed", "Client has been disposed"),
|
|
42
|
-
fromUnknown: (cause, context) => {
|
|
43
|
-
if (cause instanceof Error) {
|
|
44
|
-
return make(
|
|
45
|
-
"internal",
|
|
46
|
-
false,
|
|
47
|
-
"callpad.unknown",
|
|
48
|
-
context ?? "Unknown error",
|
|
49
|
-
{
|
|
50
|
-
detail: cause.message,
|
|
51
|
-
cause
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
return make(
|
|
56
|
-
"internal",
|
|
57
|
-
false,
|
|
58
|
-
"callpad.unknown",
|
|
59
|
-
context ?? "Unknown error",
|
|
60
|
-
{
|
|
61
|
-
detail: typeof cause === "string" ? cause : void 0
|
|
62
|
-
}
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// src/shared/result.ts
|
|
68
|
-
function ok(value) {
|
|
69
|
-
return { ok: true, value };
|
|
70
|
-
}
|
|
71
|
-
function err(error) {
|
|
72
|
-
return { ok: false, error };
|
|
73
|
-
}
|
|
74
|
-
function isOk(r) {
|
|
75
|
-
return r.ok;
|
|
76
|
-
}
|
|
77
|
-
function isErr(r) {
|
|
78
|
-
return !r.ok;
|
|
79
|
-
}
|
|
80
|
-
function unwrap(r) {
|
|
81
|
-
if (r.ok) {
|
|
82
|
-
return r.value;
|
|
83
|
-
}
|
|
84
|
-
throw new Error(`unwrap on error: ${String(r.error)}`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/core/logger.ts
|
|
88
|
-
var noopLogger = {
|
|
89
|
-
debug: () => void 0,
|
|
90
|
-
info: () => void 0,
|
|
91
|
-
warn: () => void 0,
|
|
92
|
-
error: () => void 0,
|
|
93
|
-
child: () => noopLogger
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
// src/api/generated/core/bodySerializer.ts
|
|
97
|
-
var jsonBodySerializer = {
|
|
98
|
-
bodySerializer: (body) => JSON.stringify(
|
|
99
|
-
body,
|
|
100
|
-
(key, value) => typeof value === "bigint" ? value.toString() : value
|
|
101
|
-
)
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// src/api/generated/core/auth.ts
|
|
105
|
-
var getAuthToken = async (auth, callback) => {
|
|
106
|
-
const token = typeof callback === "function" ? await callback(auth) : callback;
|
|
107
|
-
if (!token) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
if (auth.scheme === "bearer") {
|
|
111
|
-
return `Bearer ${token}`;
|
|
112
|
-
}
|
|
113
|
-
if (auth.scheme === "basic") {
|
|
114
|
-
return `Basic ${btoa(token)}`;
|
|
115
|
-
}
|
|
116
|
-
return token;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// src/api/generated/core/pathSerializer.ts
|
|
120
|
-
var separatorArrayExplode = (style) => {
|
|
121
|
-
switch (style) {
|
|
122
|
-
case "label":
|
|
123
|
-
return ".";
|
|
124
|
-
case "matrix":
|
|
125
|
-
return ";";
|
|
126
|
-
case "simple":
|
|
127
|
-
return ",";
|
|
128
|
-
default:
|
|
129
|
-
return "&";
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
var separatorArrayNoExplode = (style) => {
|
|
133
|
-
switch (style) {
|
|
134
|
-
case "form":
|
|
135
|
-
return ",";
|
|
136
|
-
case "pipeDelimited":
|
|
137
|
-
return "|";
|
|
138
|
-
case "spaceDelimited":
|
|
139
|
-
return "%20";
|
|
140
|
-
default:
|
|
141
|
-
return ",";
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
var separatorObjectExplode = (style) => {
|
|
145
|
-
switch (style) {
|
|
146
|
-
case "label":
|
|
147
|
-
return ".";
|
|
148
|
-
case "matrix":
|
|
149
|
-
return ";";
|
|
150
|
-
case "simple":
|
|
151
|
-
return ",";
|
|
152
|
-
default:
|
|
153
|
-
return "&";
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
var serializeArrayParam = ({
|
|
157
|
-
allowReserved,
|
|
158
|
-
explode,
|
|
159
|
-
name,
|
|
160
|
-
style,
|
|
161
|
-
value
|
|
162
|
-
}) => {
|
|
163
|
-
if (!explode) {
|
|
164
|
-
const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
|
|
165
|
-
switch (style) {
|
|
166
|
-
case "label":
|
|
167
|
-
return `.${joinedValues2}`;
|
|
168
|
-
case "matrix":
|
|
169
|
-
return `;${name}=${joinedValues2}`;
|
|
170
|
-
case "simple":
|
|
171
|
-
return joinedValues2;
|
|
172
|
-
default:
|
|
173
|
-
return `${name}=${joinedValues2}`;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
const separator = separatorArrayExplode(style);
|
|
177
|
-
const joinedValues = value.map((v) => {
|
|
178
|
-
if (style === "label" || style === "simple") {
|
|
179
|
-
return allowReserved ? v : encodeURIComponent(v);
|
|
180
|
-
}
|
|
181
|
-
return serializePrimitiveParam({
|
|
182
|
-
allowReserved,
|
|
183
|
-
name,
|
|
184
|
-
value: v
|
|
185
|
-
});
|
|
186
|
-
}).join(separator);
|
|
187
|
-
return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
|
|
188
|
-
};
|
|
189
|
-
var serializePrimitiveParam = ({
|
|
190
|
-
allowReserved,
|
|
191
|
-
name,
|
|
192
|
-
value
|
|
193
|
-
}) => {
|
|
194
|
-
if (value === void 0 || value === null) {
|
|
195
|
-
return "";
|
|
196
|
-
}
|
|
197
|
-
if (typeof value === "object") {
|
|
198
|
-
throw new Error(
|
|
199
|
-
"Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
|
|
203
|
-
};
|
|
204
|
-
var serializeObjectParam = ({
|
|
205
|
-
allowReserved,
|
|
206
|
-
explode,
|
|
207
|
-
name,
|
|
208
|
-
style,
|
|
209
|
-
value,
|
|
210
|
-
valueOnly
|
|
211
|
-
}) => {
|
|
212
|
-
if (value instanceof Date) {
|
|
213
|
-
return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
|
|
214
|
-
}
|
|
215
|
-
if (style !== "deepObject" && !explode) {
|
|
216
|
-
let values = [];
|
|
217
|
-
Object.entries(value).forEach(([key, v]) => {
|
|
218
|
-
values = [
|
|
219
|
-
...values,
|
|
220
|
-
key,
|
|
221
|
-
allowReserved ? v : encodeURIComponent(v)
|
|
222
|
-
];
|
|
223
|
-
});
|
|
224
|
-
const joinedValues2 = values.join(",");
|
|
225
|
-
switch (style) {
|
|
226
|
-
case "form":
|
|
227
|
-
return `${name}=${joinedValues2}`;
|
|
228
|
-
case "label":
|
|
229
|
-
return `.${joinedValues2}`;
|
|
230
|
-
case "matrix":
|
|
231
|
-
return `;${name}=${joinedValues2}`;
|
|
232
|
-
default:
|
|
233
|
-
return joinedValues2;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
const separator = separatorObjectExplode(style);
|
|
237
|
-
const joinedValues = Object.entries(value).map(
|
|
238
|
-
([key, v]) => serializePrimitiveParam({
|
|
239
|
-
allowReserved,
|
|
240
|
-
name: style === "deepObject" ? `${name}[${key}]` : key,
|
|
241
|
-
value: v
|
|
242
|
-
})
|
|
243
|
-
).join(separator);
|
|
244
|
-
return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// src/api/generated/client/utils.ts
|
|
248
|
-
var PATH_PARAM_RE = /\{[^{}]+\}/g;
|
|
249
|
-
var defaultPathSerializer = ({ path, url: _url }) => {
|
|
250
|
-
let url = _url;
|
|
251
|
-
const matches = _url.match(PATH_PARAM_RE);
|
|
252
|
-
if (matches) {
|
|
253
|
-
for (const match of matches) {
|
|
254
|
-
let explode = false;
|
|
255
|
-
let name = match.substring(1, match.length - 1);
|
|
256
|
-
let style = "simple";
|
|
257
|
-
if (name.endsWith("*")) {
|
|
258
|
-
explode = true;
|
|
259
|
-
name = name.substring(0, name.length - 1);
|
|
260
|
-
}
|
|
261
|
-
if (name.startsWith(".")) {
|
|
262
|
-
name = name.substring(1);
|
|
263
|
-
style = "label";
|
|
264
|
-
} else if (name.startsWith(";")) {
|
|
265
|
-
name = name.substring(1);
|
|
266
|
-
style = "matrix";
|
|
267
|
-
}
|
|
268
|
-
const value = path[name];
|
|
269
|
-
if (value === void 0 || value === null) {
|
|
270
|
-
continue;
|
|
271
|
-
}
|
|
272
|
-
if (Array.isArray(value)) {
|
|
273
|
-
url = url.replace(
|
|
274
|
-
match,
|
|
275
|
-
serializeArrayParam({ explode, name, style, value })
|
|
276
|
-
);
|
|
277
|
-
continue;
|
|
278
|
-
}
|
|
279
|
-
if (typeof value === "object") {
|
|
280
|
-
url = url.replace(
|
|
281
|
-
match,
|
|
282
|
-
serializeObjectParam({
|
|
283
|
-
explode,
|
|
284
|
-
name,
|
|
285
|
-
style,
|
|
286
|
-
value,
|
|
287
|
-
valueOnly: true
|
|
288
|
-
})
|
|
289
|
-
);
|
|
290
|
-
continue;
|
|
291
|
-
}
|
|
292
|
-
if (style === "matrix") {
|
|
293
|
-
url = url.replace(
|
|
294
|
-
match,
|
|
295
|
-
`;${serializePrimitiveParam({
|
|
296
|
-
name,
|
|
297
|
-
value
|
|
298
|
-
})}`
|
|
299
|
-
);
|
|
300
|
-
continue;
|
|
301
|
-
}
|
|
302
|
-
const replaceValue = encodeURIComponent(
|
|
303
|
-
style === "label" ? `.${value}` : value
|
|
304
|
-
);
|
|
305
|
-
url = url.replace(match, replaceValue);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
return url;
|
|
309
|
-
};
|
|
310
|
-
var createQuerySerializer = ({
|
|
311
|
-
allowReserved,
|
|
312
|
-
array,
|
|
313
|
-
object
|
|
314
|
-
} = {}) => {
|
|
315
|
-
const querySerializer = (queryParams) => {
|
|
316
|
-
const search = [];
|
|
317
|
-
if (queryParams && typeof queryParams === "object") {
|
|
318
|
-
for (const name in queryParams) {
|
|
319
|
-
const value = queryParams[name];
|
|
320
|
-
if (value === void 0 || value === null) {
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
|
-
if (Array.isArray(value)) {
|
|
324
|
-
const serializedArray = serializeArrayParam({
|
|
325
|
-
allowReserved,
|
|
326
|
-
explode: true,
|
|
327
|
-
name,
|
|
328
|
-
style: "form",
|
|
329
|
-
value,
|
|
330
|
-
...array
|
|
331
|
-
});
|
|
332
|
-
if (serializedArray) search.push(serializedArray);
|
|
333
|
-
} else if (typeof value === "object") {
|
|
334
|
-
const serializedObject = serializeObjectParam({
|
|
335
|
-
allowReserved,
|
|
336
|
-
explode: true,
|
|
337
|
-
name,
|
|
338
|
-
style: "deepObject",
|
|
339
|
-
value,
|
|
340
|
-
...object
|
|
341
|
-
});
|
|
342
|
-
if (serializedObject) search.push(serializedObject);
|
|
343
|
-
} else {
|
|
344
|
-
const serializedPrimitive = serializePrimitiveParam({
|
|
345
|
-
allowReserved,
|
|
346
|
-
name,
|
|
347
|
-
value
|
|
348
|
-
});
|
|
349
|
-
if (serializedPrimitive) search.push(serializedPrimitive);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
return search.join("&");
|
|
354
|
-
};
|
|
355
|
-
return querySerializer;
|
|
356
|
-
};
|
|
357
|
-
var getParseAs = (contentType) => {
|
|
358
|
-
if (!contentType) {
|
|
359
|
-
return "stream";
|
|
360
|
-
}
|
|
361
|
-
const cleanContent = contentType.split(";")[0]?.trim();
|
|
362
|
-
if (!cleanContent) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
|
|
366
|
-
return "json";
|
|
367
|
-
}
|
|
368
|
-
if (cleanContent === "multipart/form-data") {
|
|
369
|
-
return "formData";
|
|
370
|
-
}
|
|
371
|
-
if (["application/", "audio/", "image/", "video/"].some(
|
|
372
|
-
(type) => cleanContent.startsWith(type)
|
|
373
|
-
)) {
|
|
374
|
-
return "blob";
|
|
375
|
-
}
|
|
376
|
-
if (cleanContent.startsWith("text/")) {
|
|
377
|
-
return "text";
|
|
378
|
-
}
|
|
379
|
-
};
|
|
380
|
-
var setAuthParams = async ({
|
|
381
|
-
security,
|
|
382
|
-
...options
|
|
383
|
-
}) => {
|
|
384
|
-
for (const auth of security) {
|
|
385
|
-
const token = await getAuthToken(auth, options.auth);
|
|
386
|
-
if (!token) {
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
const name = auth.name ?? "Authorization";
|
|
390
|
-
switch (auth.in) {
|
|
391
|
-
case "query":
|
|
392
|
-
if (!options.query) {
|
|
393
|
-
options.query = {};
|
|
394
|
-
}
|
|
395
|
-
options.query[name] = token;
|
|
396
|
-
break;
|
|
397
|
-
case "cookie":
|
|
398
|
-
options.headers.append("Cookie", `${name}=${token}`);
|
|
399
|
-
break;
|
|
400
|
-
case "header":
|
|
401
|
-
default:
|
|
402
|
-
options.headers.set(name, token);
|
|
403
|
-
break;
|
|
404
|
-
}
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
var buildUrl = (options) => {
|
|
409
|
-
const url = getUrl({
|
|
410
|
-
baseUrl: options.baseUrl,
|
|
411
|
-
path: options.path,
|
|
412
|
-
query: options.query,
|
|
413
|
-
querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
|
|
414
|
-
url: options.url
|
|
415
|
-
});
|
|
416
|
-
return url;
|
|
417
|
-
};
|
|
418
|
-
var getUrl = ({
|
|
419
|
-
baseUrl,
|
|
420
|
-
path,
|
|
421
|
-
query,
|
|
422
|
-
querySerializer,
|
|
423
|
-
url: _url
|
|
424
|
-
}) => {
|
|
425
|
-
const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
|
|
426
|
-
let url = (baseUrl ?? "") + pathUrl;
|
|
427
|
-
if (path) {
|
|
428
|
-
url = defaultPathSerializer({ path, url });
|
|
429
|
-
}
|
|
430
|
-
let search = query ? querySerializer(query) : "";
|
|
431
|
-
if (search.startsWith("?")) {
|
|
432
|
-
search = search.substring(1);
|
|
433
|
-
}
|
|
434
|
-
if (search) {
|
|
435
|
-
url += `?${search}`;
|
|
436
|
-
}
|
|
437
|
-
return url;
|
|
438
|
-
};
|
|
439
|
-
var mergeConfigs = (a, b) => {
|
|
440
|
-
const config = { ...a, ...b };
|
|
441
|
-
if (config.baseUrl?.endsWith("/")) {
|
|
442
|
-
config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
|
|
443
|
-
}
|
|
444
|
-
config.headers = mergeHeaders(a.headers, b.headers);
|
|
445
|
-
return config;
|
|
446
|
-
};
|
|
447
|
-
var mergeHeaders = (...headers) => {
|
|
448
|
-
const mergedHeaders = new Headers();
|
|
449
|
-
for (const header of headers) {
|
|
450
|
-
if (!header || typeof header !== "object") {
|
|
451
|
-
continue;
|
|
452
|
-
}
|
|
453
|
-
const iterator = header instanceof Headers ? header.entries() : Object.entries(header);
|
|
454
|
-
for (const [key, value] of iterator) {
|
|
455
|
-
if (value === null) {
|
|
456
|
-
mergedHeaders.delete(key);
|
|
457
|
-
} else if (Array.isArray(value)) {
|
|
458
|
-
for (const v of value) {
|
|
459
|
-
mergedHeaders.append(key, v);
|
|
460
|
-
}
|
|
461
|
-
} else if (value !== void 0) {
|
|
462
|
-
mergedHeaders.set(
|
|
463
|
-
key,
|
|
464
|
-
typeof value === "object" ? JSON.stringify(value) : value
|
|
465
|
-
);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
return mergedHeaders;
|
|
470
|
-
};
|
|
471
|
-
var Interceptors = class {
|
|
472
|
-
_fns;
|
|
473
|
-
constructor() {
|
|
474
|
-
this._fns = [];
|
|
475
|
-
}
|
|
476
|
-
clear() {
|
|
477
|
-
this._fns = [];
|
|
478
|
-
}
|
|
479
|
-
getInterceptorIndex(id) {
|
|
480
|
-
if (typeof id === "number") {
|
|
481
|
-
return this._fns[id] ? id : -1;
|
|
482
|
-
} else {
|
|
483
|
-
return this._fns.indexOf(id);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
exists(id) {
|
|
487
|
-
const index = this.getInterceptorIndex(id);
|
|
488
|
-
return !!this._fns[index];
|
|
489
|
-
}
|
|
490
|
-
eject(id) {
|
|
491
|
-
const index = this.getInterceptorIndex(id);
|
|
492
|
-
if (this._fns[index]) {
|
|
493
|
-
this._fns[index] = null;
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
update(id, fn) {
|
|
497
|
-
const index = this.getInterceptorIndex(id);
|
|
498
|
-
if (this._fns[index]) {
|
|
499
|
-
this._fns[index] = fn;
|
|
500
|
-
return id;
|
|
501
|
-
} else {
|
|
502
|
-
return false;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
use(fn) {
|
|
506
|
-
this._fns = [...this._fns, fn];
|
|
507
|
-
return this._fns.length - 1;
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
var createInterceptors = () => ({
|
|
511
|
-
error: new Interceptors(),
|
|
512
|
-
request: new Interceptors(),
|
|
513
|
-
response: new Interceptors()
|
|
514
|
-
});
|
|
515
|
-
var defaultQuerySerializer = createQuerySerializer({
|
|
516
|
-
allowReserved: false,
|
|
517
|
-
array: {
|
|
518
|
-
explode: true,
|
|
519
|
-
style: "form"
|
|
520
|
-
},
|
|
521
|
-
object: {
|
|
522
|
-
explode: true,
|
|
523
|
-
style: "deepObject"
|
|
524
|
-
}
|
|
525
|
-
});
|
|
526
|
-
var defaultHeaders = {
|
|
527
|
-
"Content-Type": "application/json"
|
|
528
|
-
};
|
|
529
|
-
var createConfig = (override = {}) => ({
|
|
530
|
-
...jsonBodySerializer,
|
|
531
|
-
headers: defaultHeaders,
|
|
532
|
-
parseAs: "auto",
|
|
533
|
-
querySerializer: defaultQuerySerializer,
|
|
534
|
-
...override
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
// src/api/generated/client/client.ts
|
|
538
|
-
var createClient = (config = {}) => {
|
|
539
|
-
let _config = mergeConfigs(createConfig(), config);
|
|
540
|
-
const getConfig = () => ({ ..._config });
|
|
541
|
-
const setConfig = (config2) => {
|
|
542
|
-
_config = mergeConfigs(_config, config2);
|
|
543
|
-
return getConfig();
|
|
544
|
-
};
|
|
545
|
-
const interceptors = createInterceptors();
|
|
546
|
-
const request = async (options) => {
|
|
547
|
-
const opts = {
|
|
548
|
-
..._config,
|
|
549
|
-
...options,
|
|
550
|
-
fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
|
|
551
|
-
headers: mergeHeaders(_config.headers, options.headers)
|
|
552
|
-
};
|
|
553
|
-
if (opts.security) {
|
|
554
|
-
await setAuthParams({
|
|
555
|
-
...opts,
|
|
556
|
-
security: opts.security
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
if (opts.body && opts.bodySerializer) {
|
|
560
|
-
opts.body = opts.bodySerializer(opts.body);
|
|
561
|
-
}
|
|
562
|
-
if (opts.body === void 0 || opts.body === "") {
|
|
563
|
-
opts.headers.delete("Content-Type");
|
|
564
|
-
}
|
|
565
|
-
const url = buildUrl(opts);
|
|
566
|
-
const requestInit = {
|
|
567
|
-
redirect: "follow",
|
|
568
|
-
...opts
|
|
569
|
-
};
|
|
570
|
-
let request2 = new Request(url, requestInit);
|
|
571
|
-
for (const fn of interceptors.request._fns) {
|
|
572
|
-
if (fn) {
|
|
573
|
-
request2 = await fn(request2, opts);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
const _fetch = opts.fetch;
|
|
577
|
-
let response = await _fetch(request2);
|
|
578
|
-
for (const fn of interceptors.response._fns) {
|
|
579
|
-
if (fn) {
|
|
580
|
-
response = await fn(response, request2, opts);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
const result = {
|
|
584
|
-
request: request2,
|
|
585
|
-
response
|
|
586
|
-
};
|
|
587
|
-
if (response.ok) {
|
|
588
|
-
if (response.status === 204 || response.headers.get("Content-Length") === "0") {
|
|
589
|
-
return opts.responseStyle === "data" ? {} : {
|
|
590
|
-
data: {},
|
|
591
|
-
...result
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
|
|
595
|
-
if (parseAs === "stream") {
|
|
596
|
-
return opts.responseStyle === "data" ? response.body : {
|
|
597
|
-
data: response.body,
|
|
598
|
-
...result
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
|
-
let data = await response[parseAs]();
|
|
602
|
-
if (parseAs === "json") {
|
|
603
|
-
if (opts.responseValidator) {
|
|
604
|
-
await opts.responseValidator(data);
|
|
605
|
-
}
|
|
606
|
-
if (opts.responseTransformer) {
|
|
607
|
-
data = await opts.responseTransformer(data);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
return opts.responseStyle === "data" ? data : {
|
|
611
|
-
data,
|
|
612
|
-
...result
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
let error = await response.text();
|
|
616
|
-
try {
|
|
617
|
-
error = JSON.parse(error);
|
|
618
|
-
} catch {
|
|
619
|
-
}
|
|
620
|
-
let finalError = error;
|
|
621
|
-
for (const fn of interceptors.error._fns) {
|
|
622
|
-
if (fn) {
|
|
623
|
-
finalError = await fn(error, response, request2, opts);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
finalError = finalError || {};
|
|
627
|
-
if (opts.throwOnError) {
|
|
628
|
-
throw finalError;
|
|
629
|
-
}
|
|
630
|
-
return opts.responseStyle === "data" ? void 0 : {
|
|
631
|
-
error: finalError,
|
|
632
|
-
...result
|
|
633
|
-
};
|
|
634
|
-
};
|
|
635
|
-
return {
|
|
636
|
-
buildUrl,
|
|
637
|
-
connect: (options) => request({ ...options, method: "CONNECT" }),
|
|
638
|
-
delete: (options) => request({ ...options, method: "DELETE" }),
|
|
639
|
-
get: (options) => request({ ...options, method: "GET" }),
|
|
640
|
-
getConfig,
|
|
641
|
-
head: (options) => request({ ...options, method: "HEAD" }),
|
|
642
|
-
interceptors,
|
|
643
|
-
options: (options) => request({ ...options, method: "OPTIONS" }),
|
|
644
|
-
patch: (options) => request({ ...options, method: "PATCH" }),
|
|
645
|
-
post: (options) => request({ ...options, method: "POST" }),
|
|
646
|
-
put: (options) => request({ ...options, method: "PUT" }),
|
|
647
|
-
request,
|
|
648
|
-
setConfig,
|
|
649
|
-
trace: (options) => request({ ...options, method: "TRACE" })
|
|
650
|
-
};
|
|
651
|
-
};
|
|
652
|
-
|
|
653
|
-
// src/api/client-config.ts
|
|
654
|
-
var createClientConfig = (base) => ({
|
|
655
|
-
...base,
|
|
656
|
-
throwOnError: false
|
|
657
|
-
});
|
|
658
|
-
|
|
659
|
-
// src/api/generated/client.gen.ts
|
|
660
|
-
var client = createClient(createClientConfig(createConfig({
|
|
661
|
-
baseUrl: "http://localhost:3002"
|
|
662
|
-
})));
|
|
663
|
-
|
|
664
|
-
// src/api/map-error.ts
|
|
665
|
-
function isBackendErrorBody(body) {
|
|
666
|
-
if (body === null || typeof body !== "object") {
|
|
667
|
-
return false;
|
|
668
|
-
}
|
|
669
|
-
const maybe = body;
|
|
670
|
-
if (maybe.error === null || typeof maybe.error !== "object") {
|
|
671
|
-
return false;
|
|
672
|
-
}
|
|
673
|
-
const e = maybe.error;
|
|
674
|
-
return typeof e.code === "string" && typeof e.title === "string" && typeof e.kind === "string";
|
|
675
|
-
}
|
|
676
|
-
var kindMap = {
|
|
677
|
-
validation: "validation",
|
|
678
|
-
unauth: "unauth",
|
|
679
|
-
forbidden: "forbidden",
|
|
680
|
-
notfound: "notfound",
|
|
681
|
-
precondition: "precondition",
|
|
682
|
-
conflict: "conflict",
|
|
683
|
-
internal: "internal",
|
|
684
|
-
unavailable: "unavailable",
|
|
685
|
-
timeout: "timeout"
|
|
686
|
-
};
|
|
687
|
-
function mapError(body, status) {
|
|
688
|
-
if (status === 0 || status === void 0 || status === null) {
|
|
689
|
-
return callpadError.network("callpad.network", "Network error", {
|
|
690
|
-
status: status ?? void 0
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
if (!isBackendErrorBody(body)) {
|
|
694
|
-
if (status === 401) {
|
|
695
|
-
return callpadError.unauth("callpad.unauth", "Unauthorized", { status });
|
|
696
|
-
}
|
|
697
|
-
if (status === 403) {
|
|
698
|
-
return callpadError.forbidden("callpad.forbidden", "Forbidden", {
|
|
699
|
-
status
|
|
700
|
-
});
|
|
701
|
-
}
|
|
702
|
-
if (status === 404) {
|
|
703
|
-
return callpadError.notfound("callpad.not_found", "Not found", {
|
|
704
|
-
status
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
if (status >= 500) {
|
|
708
|
-
return callpadError.internal(
|
|
709
|
-
"callpad.internal",
|
|
710
|
-
"Internal server error",
|
|
711
|
-
{ status }
|
|
712
|
-
);
|
|
713
|
-
}
|
|
714
|
-
return callpadError.internal(
|
|
715
|
-
"callpad.unknown_response",
|
|
716
|
-
"Unexpected response shape",
|
|
717
|
-
{
|
|
718
|
-
status
|
|
719
|
-
}
|
|
720
|
-
);
|
|
721
|
-
}
|
|
722
|
-
const e = body.error;
|
|
723
|
-
const kind = kindMap[e.kind] ?? "internal";
|
|
724
|
-
return {
|
|
725
|
-
kind,
|
|
726
|
-
code: e.code,
|
|
727
|
-
title: e.title,
|
|
728
|
-
detail: e.detail,
|
|
729
|
-
retryable: e.retryable,
|
|
730
|
-
issues: e.issues,
|
|
731
|
-
status
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
// src/api/call.ts
|
|
736
|
-
async function apiCall(call) {
|
|
737
|
-
try {
|
|
738
|
-
const res = await call();
|
|
739
|
-
if (res.error !== void 0 || !res.response.ok) {
|
|
740
|
-
return err(
|
|
741
|
-
mapError(
|
|
742
|
-
res.error !== void 0 ? { error: res.error } : void 0,
|
|
743
|
-
res.response.status
|
|
744
|
-
)
|
|
745
|
-
);
|
|
746
|
-
}
|
|
747
|
-
if (res.data === void 0) {
|
|
748
|
-
return err(
|
|
749
|
-
callpadError.internal(
|
|
750
|
-
"callpad.empty_response",
|
|
751
|
-
"Expected response body, got empty"
|
|
752
|
-
)
|
|
753
|
-
);
|
|
754
|
-
}
|
|
755
|
-
return ok(res.data);
|
|
756
|
-
} catch (cause) {
|
|
757
|
-
return err(callpadError.fromUnknown(cause, "HTTP request failed"));
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
// src/api/generated/sdk.gen.ts
|
|
762
|
-
var getApiV1PulseGrants = (options) => {
|
|
763
|
-
return (options?.client ?? client).get({
|
|
764
|
-
security: [
|
|
765
|
-
{
|
|
766
|
-
scheme: "bearer",
|
|
767
|
-
type: "http"
|
|
768
|
-
}
|
|
769
|
-
],
|
|
770
|
-
url: "/api/v1/pulse/grants",
|
|
771
|
-
...options
|
|
772
|
-
});
|
|
773
|
-
};
|
|
774
|
-
var getApiV1VendorsBySlugPresence = (options) => {
|
|
775
|
-
return (options.client ?? client).get({
|
|
776
|
-
security: [
|
|
777
|
-
{
|
|
778
|
-
scheme: "bearer",
|
|
779
|
-
type: "http"
|
|
780
|
-
}
|
|
781
|
-
],
|
|
782
|
-
url: "/api/v1/vendors/{slug}/presence",
|
|
783
|
-
...options
|
|
784
|
-
});
|
|
785
|
-
};
|
|
786
|
-
var deleteApiV1VendorsBySlugPresenceStatus = (options) => {
|
|
787
|
-
return (options.client ?? client).delete({
|
|
788
|
-
security: [
|
|
789
|
-
{
|
|
790
|
-
scheme: "bearer",
|
|
791
|
-
type: "http"
|
|
792
|
-
}
|
|
793
|
-
],
|
|
794
|
-
url: "/api/v1/vendors/{slug}/presence/status",
|
|
795
|
-
...options
|
|
796
|
-
});
|
|
797
|
-
};
|
|
798
|
-
var putApiV1VendorsBySlugPresenceStatus = (options) => {
|
|
799
|
-
return (options.client ?? client).put({
|
|
800
|
-
security: [
|
|
801
|
-
{
|
|
802
|
-
scheme: "bearer",
|
|
803
|
-
type: "http"
|
|
804
|
-
}
|
|
805
|
-
],
|
|
806
|
-
url: "/api/v1/vendors/{slug}/presence/status",
|
|
807
|
-
...options,
|
|
808
|
-
headers: {
|
|
809
|
-
"Content-Type": "application/json",
|
|
810
|
-
...options.headers
|
|
811
|
-
}
|
|
812
|
-
});
|
|
813
|
-
};
|
|
814
|
-
var getApiV1Sessions = (options) => {
|
|
815
|
-
return (options?.client ?? client).get({
|
|
816
|
-
security: [
|
|
817
|
-
{
|
|
818
|
-
scheme: "bearer",
|
|
819
|
-
type: "http"
|
|
820
|
-
}
|
|
821
|
-
],
|
|
822
|
-
url: "/api/v1/sessions",
|
|
823
|
-
...options
|
|
824
|
-
});
|
|
825
|
-
};
|
|
826
|
-
var postApiV1Sessions = (options) => {
|
|
827
|
-
return (options.client ?? client).post({
|
|
828
|
-
security: [
|
|
829
|
-
{
|
|
830
|
-
scheme: "bearer",
|
|
831
|
-
type: "http"
|
|
832
|
-
}
|
|
833
|
-
],
|
|
834
|
-
url: "/api/v1/sessions",
|
|
835
|
-
...options,
|
|
836
|
-
headers: {
|
|
837
|
-
"Content-Type": "application/json",
|
|
838
|
-
...options.headers
|
|
839
|
-
}
|
|
840
|
-
});
|
|
841
|
-
};
|
|
842
|
-
var getApiV1SessionsInvites = (options) => {
|
|
843
|
-
return (options?.client ?? client).get({
|
|
844
|
-
security: [
|
|
845
|
-
{
|
|
846
|
-
scheme: "bearer",
|
|
847
|
-
type: "http"
|
|
848
|
-
}
|
|
849
|
-
],
|
|
850
|
-
url: "/api/v1/sessions/invites",
|
|
851
|
-
...options
|
|
852
|
-
});
|
|
853
|
-
};
|
|
854
|
-
var postApiV1SessionsBySessionIdInvitesByInviteIdAccept = (options) => {
|
|
855
|
-
return (options.client ?? client).post({
|
|
856
|
-
security: [
|
|
857
|
-
{
|
|
858
|
-
scheme: "bearer",
|
|
859
|
-
type: "http"
|
|
860
|
-
}
|
|
861
|
-
],
|
|
862
|
-
url: "/api/v1/sessions/{sessionId}/invites/{inviteId}/accept",
|
|
863
|
-
...options
|
|
864
|
-
});
|
|
865
|
-
};
|
|
866
|
-
var postApiV1SessionsBySessionIdInvitesByInviteIdReject = (options) => {
|
|
867
|
-
return (options.client ?? client).post({
|
|
868
|
-
security: [
|
|
869
|
-
{
|
|
870
|
-
scheme: "bearer",
|
|
871
|
-
type: "http"
|
|
872
|
-
}
|
|
873
|
-
],
|
|
874
|
-
url: "/api/v1/sessions/{sessionId}/invites/{inviteId}/reject",
|
|
875
|
-
...options
|
|
876
|
-
});
|
|
877
|
-
};
|
|
878
|
-
var getApiV1SessionsBySessionId = (options) => {
|
|
879
|
-
return (options.client ?? client).get({
|
|
880
|
-
security: [
|
|
881
|
-
{
|
|
882
|
-
scheme: "bearer",
|
|
883
|
-
type: "http"
|
|
884
|
-
}
|
|
885
|
-
],
|
|
886
|
-
url: "/api/v1/sessions/{sessionId}",
|
|
887
|
-
...options
|
|
888
|
-
});
|
|
889
|
-
};
|
|
890
|
-
var patchApiV1SessionsBySessionId = (options) => {
|
|
891
|
-
return (options.client ?? client).patch({
|
|
892
|
-
security: [
|
|
893
|
-
{
|
|
894
|
-
scheme: "bearer",
|
|
895
|
-
type: "http"
|
|
896
|
-
}
|
|
897
|
-
],
|
|
898
|
-
url: "/api/v1/sessions/{sessionId}",
|
|
899
|
-
...options,
|
|
900
|
-
headers: {
|
|
901
|
-
"Content-Type": "application/json",
|
|
902
|
-
...options.headers
|
|
903
|
-
}
|
|
904
|
-
});
|
|
905
|
-
};
|
|
906
|
-
var postApiV1SessionsBySessionIdJoin = (options) => {
|
|
907
|
-
return (options.client ?? client).post({
|
|
908
|
-
security: [
|
|
909
|
-
{
|
|
910
|
-
scheme: "bearer",
|
|
911
|
-
type: "http"
|
|
912
|
-
}
|
|
913
|
-
],
|
|
914
|
-
url: "/api/v1/sessions/{sessionId}/join",
|
|
915
|
-
...options
|
|
916
|
-
});
|
|
917
|
-
};
|
|
918
|
-
var postApiV1SessionsBySessionIdCancel = (options) => {
|
|
919
|
-
return (options.client ?? client).post({
|
|
920
|
-
security: [
|
|
921
|
-
{
|
|
922
|
-
scheme: "bearer",
|
|
923
|
-
type: "http"
|
|
924
|
-
}
|
|
925
|
-
],
|
|
926
|
-
url: "/api/v1/sessions/{sessionId}/cancel",
|
|
927
|
-
...options
|
|
928
|
-
});
|
|
929
|
-
};
|
|
930
|
-
var postApiV1SessionsBySessionIdLeave = (options) => {
|
|
931
|
-
return (options.client ?? client).post({
|
|
932
|
-
security: [
|
|
933
|
-
{
|
|
934
|
-
scheme: "bearer",
|
|
935
|
-
type: "http"
|
|
936
|
-
}
|
|
937
|
-
],
|
|
938
|
-
url: "/api/v1/sessions/{sessionId}/leave",
|
|
939
|
-
...options
|
|
940
|
-
});
|
|
941
|
-
};
|
|
942
|
-
var postApiV1SessionsBySessionIdHold = (options) => {
|
|
943
|
-
return (options.client ?? client).post({
|
|
944
|
-
security: [
|
|
945
|
-
{
|
|
946
|
-
scheme: "bearer",
|
|
947
|
-
type: "http"
|
|
948
|
-
}
|
|
949
|
-
],
|
|
950
|
-
url: "/api/v1/sessions/{sessionId}/hold",
|
|
951
|
-
...options
|
|
952
|
-
});
|
|
953
|
-
};
|
|
954
|
-
var postApiV1SessionsBySessionIdUnhold = (options) => {
|
|
955
|
-
return (options.client ?? client).post({
|
|
956
|
-
security: [
|
|
957
|
-
{
|
|
958
|
-
scheme: "bearer",
|
|
959
|
-
type: "http"
|
|
960
|
-
}
|
|
961
|
-
],
|
|
962
|
-
url: "/api/v1/sessions/{sessionId}/unhold",
|
|
963
|
-
...options
|
|
964
|
-
});
|
|
965
|
-
};
|
|
966
|
-
var postApiV1SessionsBySessionIdEnd = (options) => {
|
|
967
|
-
return (options.client ?? client).post({
|
|
968
|
-
security: [
|
|
969
|
-
{
|
|
970
|
-
scheme: "bearer",
|
|
971
|
-
type: "http"
|
|
972
|
-
}
|
|
973
|
-
],
|
|
974
|
-
url: "/api/v1/sessions/{sessionId}/end",
|
|
975
|
-
...options
|
|
976
|
-
});
|
|
977
|
-
};
|
|
978
|
-
var postApiV1SessionsBySessionIdParticipants = (options) => {
|
|
979
|
-
return (options.client ?? client).post({
|
|
980
|
-
security: [
|
|
981
|
-
{
|
|
982
|
-
scheme: "bearer",
|
|
983
|
-
type: "http"
|
|
984
|
-
}
|
|
985
|
-
],
|
|
986
|
-
url: "/api/v1/sessions/{sessionId}/participants",
|
|
987
|
-
...options,
|
|
988
|
-
headers: {
|
|
989
|
-
"Content-Type": "application/json",
|
|
990
|
-
...options.headers
|
|
991
|
-
}
|
|
992
|
-
});
|
|
993
|
-
};
|
|
994
|
-
var deleteApiV1SessionsBySessionIdParticipantsByParticipantId = (options) => {
|
|
995
|
-
return (options.client ?? client).delete({
|
|
996
|
-
security: [
|
|
997
|
-
{
|
|
998
|
-
scheme: "bearer",
|
|
999
|
-
type: "http"
|
|
1000
|
-
}
|
|
1001
|
-
],
|
|
1002
|
-
url: "/api/v1/sessions/{sessionId}/participants/{participantId}",
|
|
1003
|
-
...options
|
|
1004
|
-
});
|
|
1005
|
-
};
|
|
1006
|
-
var postApiV1SessionsBySessionIdRecordings = (options) => {
|
|
1007
|
-
return (options.client ?? client).post({
|
|
1008
|
-
security: [
|
|
1009
|
-
{
|
|
1010
|
-
scheme: "bearer",
|
|
1011
|
-
type: "http"
|
|
1012
|
-
}
|
|
1013
|
-
],
|
|
1014
|
-
url: "/api/v1/sessions/{sessionId}/recordings",
|
|
1015
|
-
...options
|
|
1016
|
-
});
|
|
1017
|
-
};
|
|
1018
|
-
var postApiV1SessionsBySessionIdRecordingsByRecordingIdStop = (options) => {
|
|
1019
|
-
return (options.client ?? client).post({
|
|
1020
|
-
security: [
|
|
1021
|
-
{
|
|
1022
|
-
scheme: "bearer",
|
|
1023
|
-
type: "http"
|
|
1024
|
-
}
|
|
1025
|
-
],
|
|
1026
|
-
url: "/api/v1/sessions/{sessionId}/recordings/{recordingId}/stop",
|
|
1027
|
-
...options
|
|
1028
|
-
});
|
|
1029
|
-
};
|
|
1030
|
-
|
|
1031
|
-
// src/api/retry.ts
|
|
1032
|
-
var RETRY_STATUSES = /* @__PURE__ */ new Set([502, 503, 504]);
|
|
1033
|
-
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
1034
|
-
var DEFAULT_INITIAL_DELAY_MS = 300;
|
|
1035
|
-
function sleep(ms) {
|
|
1036
|
-
return new Promise((resolve) => {
|
|
1037
|
-
setTimeout(resolve, ms);
|
|
1038
|
-
});
|
|
1039
|
-
}
|
|
1040
|
-
function nextDelay(attempt, initial) {
|
|
1041
|
-
return initial * 2 ** (attempt - 1);
|
|
1042
|
-
}
|
|
1043
|
-
function makeRetryingFetch(base, opts = {}) {
|
|
1044
|
-
const maxAttempts = opts.maxAttempts ?? DEFAULT_MAX_ATTEMPTS;
|
|
1045
|
-
const initialDelay = opts.initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS;
|
|
1046
|
-
return async (request) => {
|
|
1047
|
-
let attempt = 0;
|
|
1048
|
-
while (true) {
|
|
1049
|
-
attempt += 1;
|
|
1050
|
-
const res = await base(request.clone());
|
|
1051
|
-
if (!RETRY_STATUSES.has(res.status) || attempt >= maxAttempts) {
|
|
1052
|
-
return res;
|
|
1053
|
-
}
|
|
1054
|
-
await sleep(nextDelay(attempt, initialDelay));
|
|
1055
|
-
}
|
|
1056
|
-
};
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
// src/core/dispatch.ts
|
|
1060
|
-
function dispatchFromView(view) {
|
|
1061
|
-
return {
|
|
1062
|
-
id: view.id,
|
|
1063
|
-
source: view.source,
|
|
1064
|
-
strategy: view.strategy,
|
|
1065
|
-
state: view.state,
|
|
1066
|
-
candidateParticipantIds: view.candidateParticipantIds,
|
|
1067
|
-
winnerParticipantId: nullify(view.winnerParticipantId),
|
|
1068
|
-
startedAt: view.startedAt,
|
|
1069
|
-
resolvedAt: nullify(view.resolvedAt),
|
|
1070
|
-
timeoutAt: nullify(view.timeoutAt)
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
// src/core/participant.ts
|
|
1075
|
-
var DEFAULT_MEDIA = {
|
|
1076
|
-
micPublished: false,
|
|
1077
|
-
micMuted: true,
|
|
1078
|
-
cameraPublished: false,
|
|
1079
|
-
cameraMuted: true,
|
|
1080
|
-
screenShareActive: false
|
|
1081
|
-
};
|
|
1082
|
-
function participantFromView(view, selfParticipantId, mediaLookup) {
|
|
1083
|
-
const media = mediaLookup.get(view.participantIdentity);
|
|
1084
|
-
return {
|
|
1085
|
-
id: view.id,
|
|
1086
|
-
ref: view.ref,
|
|
1087
|
-
info: view.info,
|
|
1088
|
-
role: view.role,
|
|
1089
|
-
capabilities: view.capabilities,
|
|
1090
|
-
transport: view.transport,
|
|
1091
|
-
state: view.state,
|
|
1092
|
-
participantIdentity: view.participantIdentity,
|
|
1093
|
-
participantSid: nullify(view.participantSid),
|
|
1094
|
-
invitedAt: view.invitedAt,
|
|
1095
|
-
acceptedAt: nullify(view.acceptedAt),
|
|
1096
|
-
joinedAt: nullify(view.joinedAt),
|
|
1097
|
-
endedAt: nullify(view.endedAt),
|
|
1098
|
-
leftReason: nullify(view.leftReason),
|
|
1099
|
-
failureReason: nullify(view.failureReason),
|
|
1100
|
-
isSelf: selfParticipantId !== null && view.id === selfParticipantId,
|
|
1101
|
-
isSpeaking: media?.isSpeaking ?? false,
|
|
1102
|
-
audioLevel: media?.audioLevel ?? 0,
|
|
1103
|
-
connectionQuality: media?.connectionQuality ?? "unknown",
|
|
1104
|
-
media: media ? {
|
|
1105
|
-
micPublished: media.micPublished,
|
|
1106
|
-
micMuted: media.micMuted,
|
|
1107
|
-
cameraPublished: media.cameraPublished,
|
|
1108
|
-
cameraMuted: media.cameraMuted,
|
|
1109
|
-
screenShareActive: media.screenShareActive
|
|
1110
|
-
} : DEFAULT_MEDIA
|
|
1111
|
-
};
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
// src/core/recording.ts
|
|
1115
|
-
function recordingFromView(view) {
|
|
1116
|
-
return {
|
|
1117
|
-
id: view.id,
|
|
1118
|
-
target: view.target,
|
|
1119
|
-
policy: view.policy,
|
|
1120
|
-
state: view.state,
|
|
1121
|
-
livekitEgressId: nullify(view.livekitEgressId),
|
|
1122
|
-
requestedAt: view.requestedAt,
|
|
1123
|
-
startedAt: nullify(view.startedAt),
|
|
1124
|
-
stoppedAt: nullify(view.stoppedAt),
|
|
1125
|
-
failureReason: nullify(view.failureReason)
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
// src/core/state/event-bus.ts
|
|
1130
|
-
var EventBus = class {
|
|
1131
|
-
handlers = /* @__PURE__ */ new Map();
|
|
1132
|
-
on(type, handler) {
|
|
1133
|
-
let set = this.handlers.get(type);
|
|
1134
|
-
if (!set) {
|
|
1135
|
-
set = /* @__PURE__ */ new Set();
|
|
1136
|
-
this.handlers.set(type, set);
|
|
1137
|
-
}
|
|
1138
|
-
set.add(handler);
|
|
1139
|
-
return () => {
|
|
1140
|
-
set?.delete(handler);
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
emit(type, payload) {
|
|
1144
|
-
const set = this.handlers.get(type);
|
|
1145
|
-
if (!set) {
|
|
1146
|
-
return;
|
|
1147
|
-
}
|
|
1148
|
-
for (const handler of set) {
|
|
1149
|
-
try {
|
|
1150
|
-
handler(payload);
|
|
1151
|
-
} catch {
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
clear() {
|
|
1156
|
-
this.handlers.clear();
|
|
1157
|
-
}
|
|
1158
|
-
hasHandlers(type) {
|
|
1159
|
-
const set = this.handlers.get(type);
|
|
1160
|
-
return set !== void 0 && set.size > 0;
|
|
1161
|
-
}
|
|
1162
|
-
};
|
|
1163
|
-
|
|
1164
|
-
// src/core/state/reconciler.ts
|
|
1165
|
-
function shouldApplyUpsert(prev, incoming) {
|
|
1166
|
-
if (prev === void 0) {
|
|
1167
|
-
return true;
|
|
1168
|
-
}
|
|
1169
|
-
return incoming.version > prev.version;
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
// src/core/telephony-leg.ts
|
|
1173
|
-
function telephonyLegFromOperation(participant, op) {
|
|
1174
|
-
return {
|
|
1175
|
-
id: op.id,
|
|
1176
|
-
participantId: participant.id,
|
|
1177
|
-
participantIdentity: participant.participantIdentity,
|
|
1178
|
-
direction: op.direction,
|
|
1179
|
-
state: op.state,
|
|
1180
|
-
remotePhoneNumber: op.remotePhoneNumber,
|
|
1181
|
-
localPhoneNumber: nullify(op.localPhoneNumber),
|
|
1182
|
-
livekitSipCallId: nullify(op.provider.livekitSipCallId),
|
|
1183
|
-
providerSipCallId: nullify(op.provider.providerSipCallId),
|
|
1184
|
-
livekitSipTrunkId: nullify(op.provider.livekitSipTrunkId),
|
|
1185
|
-
vendorPhoneNumberId: nullify(op.provider.vendorPhoneNumberId),
|
|
1186
|
-
sipExtension: nullify(op.provider.sipExtension),
|
|
1187
|
-
createdAt: op.createdAt,
|
|
1188
|
-
ringingAt: nullify(op.ringingAt),
|
|
1189
|
-
activeAt: nullify(op.activeAt),
|
|
1190
|
-
endedAt: nullify(op.endedAt),
|
|
1191
|
-
failureReason: nullify(op.failureReason),
|
|
1192
|
-
sipStatusCode: nullify(op.sipStatusCode),
|
|
1193
|
-
providerError: nullify(op.providerError)
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
function collectSipLegs(participants) {
|
|
1197
|
-
const legs = [];
|
|
1198
|
-
for (const participant of participants) {
|
|
1199
|
-
for (const op of participant.operations) {
|
|
1200
|
-
if (op.kind === "sip_leg") {
|
|
1201
|
-
legs.push(telephonyLegFromOperation(participant, op));
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
return legs;
|
|
1206
|
-
}
|
|
1207
|
-
var DEFAULT_ROTATE_LEAD_MS = 10 * 60 * 1e3;
|
|
1208
|
-
var FORWARDED_EVENTS = [
|
|
1209
|
-
"session.upsert",
|
|
1210
|
-
"session.remove",
|
|
1211
|
-
"session.invite.upsert",
|
|
1212
|
-
"session.invite.remove"
|
|
1213
|
-
];
|
|
1214
|
-
var PulseTransport = class {
|
|
1215
|
-
socket = null;
|
|
1216
|
-
grant = null;
|
|
1217
|
-
rotateTimer = null;
|
|
1218
|
-
status = "idle";
|
|
1219
|
-
disposed = false;
|
|
1220
|
-
bus = new EventBus();
|
|
1221
|
-
rotateLeadMs;
|
|
1222
|
-
logger;
|
|
1223
|
-
grantFetcher;
|
|
1224
|
-
constructor(opts) {
|
|
1225
|
-
this.rotateLeadMs = opts.rotateLeadMs ?? DEFAULT_ROTATE_LEAD_MS;
|
|
1226
|
-
this.logger = opts.logger.child({ component: "pulse" });
|
|
1227
|
-
this.grantFetcher = opts.grantFetcher;
|
|
1228
|
-
}
|
|
1229
|
-
getStatus() {
|
|
1230
|
-
return this.status;
|
|
1231
|
-
}
|
|
1232
|
-
on(type, handler) {
|
|
1233
|
-
return this.bus.on(type, handler);
|
|
1234
|
-
}
|
|
1235
|
-
async connect() {
|
|
1236
|
-
if (this.disposed) {
|
|
1237
|
-
return err(callpadError.disposed());
|
|
1238
|
-
}
|
|
1239
|
-
if (this.status === "connected" || this.status === "connecting") {
|
|
1240
|
-
return ok(void 0);
|
|
1241
|
-
}
|
|
1242
|
-
this.setStatus("connecting");
|
|
1243
|
-
const grant = await this.grantFetcher();
|
|
1244
|
-
if (!grant.ok) {
|
|
1245
|
-
this.setStatus("disconnected");
|
|
1246
|
-
return err(grant.error);
|
|
1247
|
-
}
|
|
1248
|
-
this.grant = grant.value;
|
|
1249
|
-
try {
|
|
1250
|
-
await this.openSocket(grant.value);
|
|
1251
|
-
} catch (cause) {
|
|
1252
|
-
this.setStatus("disconnected");
|
|
1253
|
-
return err(
|
|
1254
|
-
callpadError.unavailable(
|
|
1255
|
-
"pulse.connect_failed",
|
|
1256
|
-
"Pulse connect failed",
|
|
1257
|
-
{
|
|
1258
|
-
cause: cause instanceof Error ? cause : void 0
|
|
1259
|
-
}
|
|
1260
|
-
)
|
|
1261
|
-
);
|
|
1262
|
-
}
|
|
1263
|
-
this.scheduleRotate(grant.value);
|
|
1264
|
-
return ok(void 0);
|
|
1265
|
-
}
|
|
1266
|
-
async disconnect() {
|
|
1267
|
-
this.clearRotate();
|
|
1268
|
-
this.closeSocket();
|
|
1269
|
-
this.setStatus("disconnected");
|
|
1270
|
-
}
|
|
1271
|
-
async dispose() {
|
|
1272
|
-
if (this.disposed) {
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
this.disposed = true;
|
|
1276
|
-
this.clearRotate();
|
|
1277
|
-
this.closeSocket();
|
|
1278
|
-
this.bus.clear();
|
|
1279
|
-
this.status = "disconnected";
|
|
1280
|
-
}
|
|
1281
|
-
setStatus(next) {
|
|
1282
|
-
if (next === this.status) {
|
|
1283
|
-
return;
|
|
1284
|
-
}
|
|
1285
|
-
const previous = this.status;
|
|
1286
|
-
this.status = next;
|
|
1287
|
-
this.bus.emit("status.changed", { status: next, previous });
|
|
1288
|
-
}
|
|
1289
|
-
openSocket(grant) {
|
|
1290
|
-
return new Promise((resolve, reject) => {
|
|
1291
|
-
const socket = socket_ioClient.io(grant.url, {
|
|
1292
|
-
path: grant.path,
|
|
1293
|
-
transports: ["websocket"],
|
|
1294
|
-
auth: { token: grant.token },
|
|
1295
|
-
reconnection: true,
|
|
1296
|
-
reconnectionAttempts: Infinity
|
|
1297
|
-
});
|
|
1298
|
-
socket.on("connect", () => {
|
|
1299
|
-
this.setStatus("connected");
|
|
1300
|
-
});
|
|
1301
|
-
socket.on("reconnect_attempt", () => {
|
|
1302
|
-
this.setStatus("recovering");
|
|
1303
|
-
});
|
|
1304
|
-
socket.on("disconnect", () => {
|
|
1305
|
-
if (!this.disposed) {
|
|
1306
|
-
this.setStatus("recovering");
|
|
1307
|
-
}
|
|
1308
|
-
});
|
|
1309
|
-
socket.on("connect_error", (cause) => {
|
|
1310
|
-
const error = callpadError.unavailable(
|
|
1311
|
-
"pulse.connect_error",
|
|
1312
|
-
"Pulse socket error",
|
|
1313
|
-
{ cause: cause instanceof Error ? cause : void 0 }
|
|
1314
|
-
);
|
|
1315
|
-
this.bus.emit("error", { error });
|
|
1316
|
-
});
|
|
1317
|
-
for (const event of FORWARDED_EVENTS) {
|
|
1318
|
-
socket.on(event, (payload) => {
|
|
1319
|
-
this.bus.emit(event, payload);
|
|
1320
|
-
});
|
|
1321
|
-
}
|
|
1322
|
-
socket.once("connect", () => resolve());
|
|
1323
|
-
socket.once("connect_error", (cause) => {
|
|
1324
|
-
if (this.status !== "connected") {
|
|
1325
|
-
reject(cause);
|
|
1326
|
-
}
|
|
1327
|
-
});
|
|
1328
|
-
this.socket = socket;
|
|
1329
|
-
});
|
|
1330
|
-
}
|
|
1331
|
-
closeSocket() {
|
|
1332
|
-
if (!this.socket) {
|
|
1333
|
-
return;
|
|
1334
|
-
}
|
|
1335
|
-
this.socket.removeAllListeners();
|
|
1336
|
-
this.socket.disconnect();
|
|
1337
|
-
this.socket = null;
|
|
1338
|
-
}
|
|
1339
|
-
scheduleRotate(grant) {
|
|
1340
|
-
this.clearRotate();
|
|
1341
|
-
const expiresAt = Date.parse(grant.expiresAt);
|
|
1342
|
-
if (Number.isNaN(expiresAt)) {
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
|
-
const refreshAt = Math.max(0, expiresAt - Date.now() - this.rotateLeadMs);
|
|
1346
|
-
this.rotateTimer = setTimeout(() => {
|
|
1347
|
-
void this.rotateGrant();
|
|
1348
|
-
}, refreshAt);
|
|
1349
|
-
this.rotateTimer.unref?.();
|
|
1350
|
-
}
|
|
1351
|
-
scheduleRotateRetry() {
|
|
1352
|
-
this.clearRotate();
|
|
1353
|
-
this.rotateTimer = setTimeout(() => {
|
|
1354
|
-
void this.rotateGrant();
|
|
1355
|
-
}, this.rotateLeadMs);
|
|
1356
|
-
this.rotateTimer.unref?.();
|
|
1357
|
-
}
|
|
1358
|
-
clearRotate() {
|
|
1359
|
-
if (this.rotateTimer) {
|
|
1360
|
-
clearTimeout(this.rotateTimer);
|
|
1361
|
-
this.rotateTimer = null;
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
async rotateGrant() {
|
|
1365
|
-
if (this.disposed) {
|
|
1366
|
-
return;
|
|
1367
|
-
}
|
|
1368
|
-
const grant = await this.grantFetcher();
|
|
1369
|
-
if (!grant.ok) {
|
|
1370
|
-
this.logger.warn(
|
|
1371
|
-
{ code: grant.error.code },
|
|
1372
|
-
"pulse grant refresh failed"
|
|
1373
|
-
);
|
|
1374
|
-
this.scheduleRotateRetry();
|
|
1375
|
-
return;
|
|
1376
|
-
}
|
|
1377
|
-
this.grant = grant.value;
|
|
1378
|
-
this.closeSocket();
|
|
1379
|
-
try {
|
|
1380
|
-
await this.openSocket(grant.value);
|
|
1381
|
-
} catch (cause) {
|
|
1382
|
-
this.logger.warn(
|
|
1383
|
-
{ err: cause instanceof Error ? cause : void 0 },
|
|
1384
|
-
"pulse reopen failed"
|
|
1385
|
-
);
|
|
1386
|
-
}
|
|
1387
|
-
this.scheduleRotate(grant.value);
|
|
1388
|
-
}
|
|
1389
|
-
};
|
|
1390
|
-
function qualityOf(q) {
|
|
1391
|
-
switch (q) {
|
|
1392
|
-
case livekitClient.ConnectionQuality.Excellent:
|
|
1393
|
-
return "excellent";
|
|
1394
|
-
case livekitClient.ConnectionQuality.Good:
|
|
1395
|
-
return "good";
|
|
1396
|
-
case livekitClient.ConnectionQuality.Poor:
|
|
1397
|
-
return "poor";
|
|
1398
|
-
case livekitClient.ConnectionQuality.Lost:
|
|
1399
|
-
return "lost";
|
|
1400
|
-
default:
|
|
1401
|
-
return "unknown";
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
function snapshotOf(p) {
|
|
1405
|
-
const micPub = p.getTrackPublication(livekitClient.Track.Source.Microphone);
|
|
1406
|
-
const camPub = p.getTrackPublication(livekitClient.Track.Source.Camera);
|
|
1407
|
-
const screenPub = p.getTrackPublication(livekitClient.Track.Source.ScreenShare);
|
|
1408
|
-
return {
|
|
1409
|
-
identity: p.identity,
|
|
1410
|
-
isSpeaking: p.isSpeaking,
|
|
1411
|
-
audioLevel: p.audioLevel,
|
|
1412
|
-
micPublished: micPub !== void 0,
|
|
1413
|
-
micMuted: micPub?.isMuted ?? true,
|
|
1414
|
-
cameraPublished: camPub !== void 0,
|
|
1415
|
-
cameraMuted: camPub?.isMuted ?? true,
|
|
1416
|
-
screenShareActive: screenPub !== void 0 && !screenPub.isMuted,
|
|
1417
|
-
connectionQuality: qualityOf(p.connectionQuality)
|
|
1418
|
-
};
|
|
1419
|
-
}
|
|
1420
|
-
function snapshotEquals(a, b) {
|
|
1421
|
-
return a.isSpeaking === b.isSpeaking && a.audioLevel === b.audioLevel && a.micPublished === b.micPublished && a.micMuted === b.micMuted && a.cameraPublished === b.cameraPublished && a.cameraMuted === b.cameraMuted && a.screenShareActive === b.screenShareActive && a.connectionQuality === b.connectionQuality;
|
|
1422
|
-
}
|
|
1423
|
-
var MediaRoomAdapter = class {
|
|
1424
|
-
room;
|
|
1425
|
-
bus = new EventBus();
|
|
1426
|
-
logger;
|
|
1427
|
-
snapshots = /* @__PURE__ */ new Map();
|
|
1428
|
-
state = "unconnected";
|
|
1429
|
-
disposed = false;
|
|
1430
|
-
constructor(logger) {
|
|
1431
|
-
this.logger = logger.child({ component: "media" });
|
|
1432
|
-
this.room = new livekitClient.Room({
|
|
1433
|
-
adaptiveStream: true,
|
|
1434
|
-
dynacast: true,
|
|
1435
|
-
disconnectOnPageLeave: false,
|
|
1436
|
-
singlePeerConnection: false
|
|
1437
|
-
});
|
|
1438
|
-
this.wireRoomEvents();
|
|
1439
|
-
}
|
|
1440
|
-
getRoom() {
|
|
1441
|
-
return this.room;
|
|
1442
|
-
}
|
|
1443
|
-
getState() {
|
|
1444
|
-
return this.state;
|
|
1445
|
-
}
|
|
1446
|
-
getSnapshot(identity) {
|
|
1447
|
-
return this.snapshots.get(identity);
|
|
1448
|
-
}
|
|
1449
|
-
listSnapshots() {
|
|
1450
|
-
return this.snapshots;
|
|
1451
|
-
}
|
|
1452
|
-
on(type, handler) {
|
|
1453
|
-
return this.bus.on(type, handler);
|
|
1454
|
-
}
|
|
1455
|
-
async connect(opts) {
|
|
1456
|
-
if (this.disposed) {
|
|
1457
|
-
return err(callpadError.disposed());
|
|
1458
|
-
}
|
|
1459
|
-
this.setState("connecting");
|
|
1460
|
-
try {
|
|
1461
|
-
await this.room.connect(opts.url, opts.token);
|
|
1462
|
-
await this.room.localParticipant.setMicrophoneEnabled(true);
|
|
1463
|
-
if (opts.video === true) {
|
|
1464
|
-
await this.room.localParticipant.setCameraEnabled(true);
|
|
1465
|
-
}
|
|
1466
|
-
return ok(void 0);
|
|
1467
|
-
} catch (cause) {
|
|
1468
|
-
this.setState("disconnected");
|
|
1469
|
-
return err(
|
|
1470
|
-
callpadError.mediaUnavailable(
|
|
1471
|
-
"media.connect_failed",
|
|
1472
|
-
"Media connect failed",
|
|
1473
|
-
{
|
|
1474
|
-
cause: cause instanceof Error ? cause : void 0
|
|
1475
|
-
}
|
|
1476
|
-
)
|
|
1477
|
-
);
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
async disconnect() {
|
|
1481
|
-
await this.room.disconnect(true);
|
|
1482
|
-
this.snapshots.clear();
|
|
1483
|
-
this.setState("disconnected");
|
|
1484
|
-
}
|
|
1485
|
-
async dispose() {
|
|
1486
|
-
if (this.disposed) {
|
|
1487
|
-
return;
|
|
1488
|
-
}
|
|
1489
|
-
this.disposed = true;
|
|
1490
|
-
await this.room.disconnect(true);
|
|
1491
|
-
this.bus.clear();
|
|
1492
|
-
this.snapshots.clear();
|
|
1493
|
-
this.state = "disconnected";
|
|
1494
|
-
}
|
|
1495
|
-
setState(next) {
|
|
1496
|
-
if (next === this.state) {
|
|
1497
|
-
return;
|
|
1498
|
-
}
|
|
1499
|
-
const previous = this.state;
|
|
1500
|
-
this.state = next;
|
|
1501
|
-
this.bus.emit("state.changed", { state: next, previous });
|
|
1502
|
-
}
|
|
1503
|
-
wireRoomEvents() {
|
|
1504
|
-
this.room.on(livekitClient.RoomEvent.ConnectionStateChanged, (state) => {
|
|
1505
|
-
switch (state) {
|
|
1506
|
-
case livekitClient.ConnectionState.Connected:
|
|
1507
|
-
this.setState("connected");
|
|
1508
|
-
break;
|
|
1509
|
-
case livekitClient.ConnectionState.Connecting:
|
|
1510
|
-
this.setState("connecting");
|
|
1511
|
-
break;
|
|
1512
|
-
case livekitClient.ConnectionState.Reconnecting:
|
|
1513
|
-
this.setState("reconnecting");
|
|
1514
|
-
break;
|
|
1515
|
-
case livekitClient.ConnectionState.Disconnected:
|
|
1516
|
-
this.setState("disconnected");
|
|
1517
|
-
break;
|
|
1518
|
-
}
|
|
1519
|
-
});
|
|
1520
|
-
const refresh = (p) => {
|
|
1521
|
-
const snapshot = snapshotOf(p);
|
|
1522
|
-
const previous = this.snapshots.get(p.identity);
|
|
1523
|
-
if (previous && snapshotEquals(previous, snapshot)) {
|
|
1524
|
-
return;
|
|
1525
|
-
}
|
|
1526
|
-
this.snapshots.set(p.identity, snapshot);
|
|
1527
|
-
this.bus.emit("participant.changed", { identity: p.identity, snapshot });
|
|
1528
|
-
};
|
|
1529
|
-
this.room.on(
|
|
1530
|
-
livekitClient.RoomEvent.ParticipantConnected,
|
|
1531
|
-
(p) => refresh(p)
|
|
1532
|
-
);
|
|
1533
|
-
this.room.on(livekitClient.RoomEvent.ParticipantDisconnected, (p) => {
|
|
1534
|
-
this.snapshots.delete(p.identity);
|
|
1535
|
-
this.bus.emit("participant.changed", {
|
|
1536
|
-
identity: p.identity,
|
|
1537
|
-
snapshot: {
|
|
1538
|
-
identity: p.identity,
|
|
1539
|
-
isSpeaking: false,
|
|
1540
|
-
audioLevel: 0,
|
|
1541
|
-
micPublished: false,
|
|
1542
|
-
micMuted: true,
|
|
1543
|
-
cameraPublished: false,
|
|
1544
|
-
cameraMuted: true,
|
|
1545
|
-
screenShareActive: false,
|
|
1546
|
-
connectionQuality: "lost"
|
|
1547
|
-
}
|
|
1548
|
-
});
|
|
1549
|
-
});
|
|
1550
|
-
this.room.on(livekitClient.RoomEvent.TrackSubscribed, (_track, _pub, p) => refresh(p));
|
|
1551
|
-
this.room.on(livekitClient.RoomEvent.TrackUnsubscribed, (_track, _pub, p) => refresh(p));
|
|
1552
|
-
this.room.on(livekitClient.RoomEvent.TrackMuted, (_pub, p) => refresh(p));
|
|
1553
|
-
this.room.on(livekitClient.RoomEvent.TrackUnmuted, (_pub, p) => refresh(p));
|
|
1554
|
-
this.room.on(
|
|
1555
|
-
livekitClient.RoomEvent.LocalTrackPublished,
|
|
1556
|
-
(_pub, p) => refresh(p)
|
|
1557
|
-
);
|
|
1558
|
-
this.room.on(
|
|
1559
|
-
livekitClient.RoomEvent.LocalTrackUnpublished,
|
|
1560
|
-
(_pub, p) => refresh(p)
|
|
1561
|
-
);
|
|
1562
|
-
this.room.on(
|
|
1563
|
-
livekitClient.RoomEvent.ConnectionQualityChanged,
|
|
1564
|
-
(_q, p) => refresh(p)
|
|
1565
|
-
);
|
|
1566
|
-
this.room.on(livekitClient.RoomEvent.ActiveSpeakersChanged, (speakers) => {
|
|
1567
|
-
const identities = speakers.map((p) => p.identity);
|
|
1568
|
-
this.bus.emit("active_speakers.changed", { identities });
|
|
1569
|
-
});
|
|
1570
|
-
this.room.on(livekitClient.RoomEvent.MediaDevicesError, (cause) => {
|
|
1571
|
-
this.bus.emit("error", {
|
|
1572
|
-
error: callpadError.mediaDevice(
|
|
1573
|
-
"media.device_error",
|
|
1574
|
-
"Media device error",
|
|
1575
|
-
{
|
|
1576
|
-
cause: cause instanceof Error ? cause : void 0
|
|
1577
|
-
}
|
|
1578
|
-
)
|
|
1579
|
-
});
|
|
1580
|
-
this.logger.warn(
|
|
1581
|
-
{ err: cause instanceof Error ? cause : void 0 },
|
|
1582
|
-
"media device error"
|
|
1583
|
-
);
|
|
1584
|
-
});
|
|
1585
|
-
}
|
|
1586
|
-
};
|
|
1587
|
-
|
|
1588
|
-
// src/core/session/session.ts
|
|
1589
|
-
var Session = class {
|
|
1590
|
-
view;
|
|
1591
|
-
vendor;
|
|
1592
|
-
logger;
|
|
1593
|
-
bus = new EventBus();
|
|
1594
|
-
media;
|
|
1595
|
-
commands;
|
|
1596
|
-
ctx;
|
|
1597
|
-
mediaStatus = "unconnected";
|
|
1598
|
-
selfParticipantId;
|
|
1599
|
-
disposed = false;
|
|
1600
|
-
cachedGrant = null;
|
|
1601
|
-
cachedParticipants = null;
|
|
1602
|
-
cachedTelephonyLegs = null;
|
|
1603
|
-
cachedRecordings = null;
|
|
1604
|
-
cachedDispatches = null;
|
|
1605
|
-
constructor(opts) {
|
|
1606
|
-
this.vendor = opts.vendor;
|
|
1607
|
-
this.logger = opts.logger.child({ session: opts.view.id });
|
|
1608
|
-
this.view = opts.view;
|
|
1609
|
-
this.selfParticipantId = opts.selfParticipantId;
|
|
1610
|
-
this.commands = opts.commands;
|
|
1611
|
-
this.media = new MediaRoomAdapter(this.logger);
|
|
1612
|
-
this.ctx = {
|
|
1613
|
-
session: this,
|
|
1614
|
-
media: this.media,
|
|
1615
|
-
applyView: (view) => this.applyView(view)
|
|
1616
|
-
};
|
|
1617
|
-
this.wireMedia();
|
|
1618
|
-
}
|
|
1619
|
-
get id() {
|
|
1620
|
-
return this.view.id;
|
|
1621
|
-
}
|
|
1622
|
-
get callId() {
|
|
1623
|
-
return this.view.callId;
|
|
1624
|
-
}
|
|
1625
|
-
get vendorId() {
|
|
1626
|
-
return this.view.vendorId;
|
|
1627
|
-
}
|
|
1628
|
-
get vendorSlug() {
|
|
1629
|
-
return this.vendor;
|
|
1630
|
-
}
|
|
1631
|
-
get mediaType() {
|
|
1632
|
-
return this.view.mediaType;
|
|
1633
|
-
}
|
|
1634
|
-
get state() {
|
|
1635
|
-
return this.view.state;
|
|
1636
|
-
}
|
|
1637
|
-
get version() {
|
|
1638
|
-
return this.view.version;
|
|
1639
|
-
}
|
|
1640
|
-
get route() {
|
|
1641
|
-
return this.view.route;
|
|
1642
|
-
}
|
|
1643
|
-
get viewSnapshot() {
|
|
1644
|
-
return this.view;
|
|
1645
|
-
}
|
|
1646
|
-
get mediaStatusSnapshot() {
|
|
1647
|
-
return this.mediaStatus;
|
|
1648
|
-
}
|
|
1649
|
-
get mediaRoom() {
|
|
1650
|
-
return this.media.getRoom();
|
|
1651
|
-
}
|
|
1652
|
-
get participants() {
|
|
1653
|
-
if (this.cachedParticipants === null) {
|
|
1654
|
-
const lookup = this.media.listSnapshots();
|
|
1655
|
-
this.cachedParticipants = this.view.participants.map(
|
|
1656
|
-
(p) => participantFromView(p, this.selfParticipantId, lookup)
|
|
1657
|
-
);
|
|
1658
|
-
}
|
|
1659
|
-
return this.cachedParticipants;
|
|
1660
|
-
}
|
|
1661
|
-
get telephonyLegs() {
|
|
1662
|
-
if (this.cachedTelephonyLegs === null) {
|
|
1663
|
-
this.cachedTelephonyLegs = collectSipLegs(this.view.participants);
|
|
1664
|
-
}
|
|
1665
|
-
return this.cachedTelephonyLegs;
|
|
1666
|
-
}
|
|
1667
|
-
get dispatches() {
|
|
1668
|
-
if (this.cachedDispatches === null) {
|
|
1669
|
-
this.cachedDispatches = this.view.dispatches.map(dispatchFromView);
|
|
1670
|
-
}
|
|
1671
|
-
return this.cachedDispatches;
|
|
1672
|
-
}
|
|
1673
|
-
get recordings() {
|
|
1674
|
-
if (this.cachedRecordings === null) {
|
|
1675
|
-
this.cachedRecordings = this.view.recordings.map(recordingFromView);
|
|
1676
|
-
}
|
|
1677
|
-
return this.cachedRecordings;
|
|
1678
|
-
}
|
|
1679
|
-
get activeRecording() {
|
|
1680
|
-
const active = this.view.recordings.find(
|
|
1681
|
-
(r) => r.state === "requested" || r.state === "active"
|
|
1682
|
-
);
|
|
1683
|
-
return active ? recordingFromView(active) : null;
|
|
1684
|
-
}
|
|
1685
|
-
get self() {
|
|
1686
|
-
if (this.selfParticipantId === null) {
|
|
1687
|
-
return null;
|
|
1688
|
-
}
|
|
1689
|
-
return this.participants.find((p) => p.id === this.selfParticipantId) ?? null;
|
|
1690
|
-
}
|
|
1691
|
-
capabilitiesOf(participantId) {
|
|
1692
|
-
const id = participantId ?? this.selfParticipantId;
|
|
1693
|
-
if (id === null || id === void 0) {
|
|
1694
|
-
return [];
|
|
1695
|
-
}
|
|
1696
|
-
const participant = this.view.participants.find((p) => p.id === id);
|
|
1697
|
-
return participant?.capabilities ?? [];
|
|
1698
|
-
}
|
|
1699
|
-
on(type, handler) {
|
|
1700
|
-
return this.bus.on(type, handler);
|
|
1701
|
-
}
|
|
1702
|
-
applyView(next) {
|
|
1703
|
-
const previous = this.view;
|
|
1704
|
-
if (!shouldApplyUpsert(previous, next)) {
|
|
1705
|
-
return;
|
|
1706
|
-
}
|
|
1707
|
-
this.view = next;
|
|
1708
|
-
this.invalidateCaches();
|
|
1709
|
-
this.bus.emit("view.changed", { view: next, previous });
|
|
1710
|
-
if (next.state !== previous.state) {
|
|
1711
|
-
this.bus.emit("state.changed", {
|
|
1712
|
-
state: next.state,
|
|
1713
|
-
previous: previous.state
|
|
1714
|
-
});
|
|
1715
|
-
}
|
|
1716
|
-
this.diffParticipants(previous, next);
|
|
1717
|
-
this.diffTelephonyLegs(previous, next);
|
|
1718
|
-
this.diffDispatches(previous, next);
|
|
1719
|
-
this.diffRecordings(previous, next);
|
|
1720
|
-
if (previous.state !== "on_hold" && next.state === "on_hold") {
|
|
1721
|
-
this.bus.emit("session.held", { heldAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1722
|
-
}
|
|
1723
|
-
if (previous.state === "on_hold" && next.state !== "on_hold" && next.state !== "ended") {
|
|
1724
|
-
this.bus.emit("session.unheld", { unheldAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1725
|
-
}
|
|
1726
|
-
if (previous.state !== "ended" && next.state === "ended") {
|
|
1727
|
-
this.bus.emit("session.ended", {
|
|
1728
|
-
reason: next.endReason ?? "completed",
|
|
1729
|
-
endedAt: next.endedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1730
|
-
});
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
async dispatch(name, ...rest) {
|
|
1734
|
-
if (this.disposed) {
|
|
1735
|
-
return err(callpadError.disposed());
|
|
1736
|
-
}
|
|
1737
|
-
const cmd = this.commands.get(name);
|
|
1738
|
-
if (!cmd) {
|
|
1739
|
-
return err(
|
|
1740
|
-
callpadError.notfound(
|
|
1741
|
-
"session.unknown_command",
|
|
1742
|
-
`Unknown session command: ${String(name)}`
|
|
1743
|
-
)
|
|
1744
|
-
);
|
|
1745
|
-
}
|
|
1746
|
-
return cmd.execute(this.ctx, rest[0]);
|
|
1747
|
-
}
|
|
1748
|
-
async join() {
|
|
1749
|
-
if (this.disposed) {
|
|
1750
|
-
return err(callpadError.disposed());
|
|
1751
|
-
}
|
|
1752
|
-
if (this.mediaStatus === "connected") {
|
|
1753
|
-
return ok(void 0);
|
|
1754
|
-
}
|
|
1755
|
-
if (this.isEnded()) {
|
|
1756
|
-
return ok(void 0);
|
|
1757
|
-
}
|
|
1758
|
-
const grant = await this.requestGrant();
|
|
1759
|
-
if (!grant.ok) {
|
|
1760
|
-
return grant;
|
|
1761
|
-
}
|
|
1762
|
-
return this.joinWithGrant(grant.value);
|
|
1763
|
-
}
|
|
1764
|
-
async joinWithGrant(grant) {
|
|
1765
|
-
if (this.disposed) {
|
|
1766
|
-
return err(callpadError.disposed());
|
|
1767
|
-
}
|
|
1768
|
-
if (this.mediaStatus === "connected") {
|
|
1769
|
-
return ok(void 0);
|
|
1770
|
-
}
|
|
1771
|
-
if (this.isEnded()) {
|
|
1772
|
-
return ok(void 0);
|
|
1773
|
-
}
|
|
1774
|
-
const previousSelfId = this.selfParticipantId;
|
|
1775
|
-
this.cachedGrant = grant;
|
|
1776
|
-
this.selfParticipantId = grant.participantId;
|
|
1777
|
-
this.cachedParticipants = null;
|
|
1778
|
-
const connected = await this.media.connect({
|
|
1779
|
-
url: grant.url,
|
|
1780
|
-
token: grant.token,
|
|
1781
|
-
video: this.view.mediaType === "video"
|
|
1782
|
-
});
|
|
1783
|
-
if (!connected.ok) {
|
|
1784
|
-
this.cachedGrant = null;
|
|
1785
|
-
this.selfParticipantId = previousSelfId;
|
|
1786
|
-
this.cachedParticipants = null;
|
|
1787
|
-
if (this.isEnded()) {
|
|
1788
|
-
return ok(void 0);
|
|
1789
|
-
}
|
|
1790
|
-
}
|
|
1791
|
-
return connected;
|
|
1792
|
-
}
|
|
1793
|
-
isEnded() {
|
|
1794
|
-
return this.view.state === "ended";
|
|
1795
|
-
}
|
|
1796
|
-
leave() {
|
|
1797
|
-
return this.dispatch("leave");
|
|
1798
|
-
}
|
|
1799
|
-
cancel() {
|
|
1800
|
-
return this.dispatch("cancel");
|
|
1801
|
-
}
|
|
1802
|
-
end() {
|
|
1803
|
-
return this.dispatch("end");
|
|
1804
|
-
}
|
|
1805
|
-
hold() {
|
|
1806
|
-
return this.dispatch("hold");
|
|
1807
|
-
}
|
|
1808
|
-
unhold() {
|
|
1809
|
-
return this.dispatch("unhold");
|
|
1810
|
-
}
|
|
1811
|
-
startRecording() {
|
|
1812
|
-
return this.dispatch("startRecording");
|
|
1813
|
-
}
|
|
1814
|
-
stopRecording(recordingId) {
|
|
1815
|
-
return this.dispatch("stopRecording", recordingId);
|
|
1816
|
-
}
|
|
1817
|
-
invite(target2) {
|
|
1818
|
-
return this.dispatch("invite", target2);
|
|
1819
|
-
}
|
|
1820
|
-
removeParticipant(participantId) {
|
|
1821
|
-
return this.dispatch("removeParticipant", participantId);
|
|
1822
|
-
}
|
|
1823
|
-
updateName(name) {
|
|
1824
|
-
return this.dispatch("updateName", name);
|
|
1825
|
-
}
|
|
1826
|
-
mediaGrant() {
|
|
1827
|
-
return this.cachedGrant;
|
|
1828
|
-
}
|
|
1829
|
-
async dispose() {
|
|
1830
|
-
if (this.disposed) {
|
|
1831
|
-
return;
|
|
1832
|
-
}
|
|
1833
|
-
this.disposed = true;
|
|
1834
|
-
await this.media.dispose();
|
|
1835
|
-
this.bus.clear();
|
|
1836
|
-
}
|
|
1837
|
-
async requestGrant() {
|
|
1838
|
-
return apiCall(
|
|
1839
|
-
() => postApiV1SessionsBySessionIdJoin({
|
|
1840
|
-
path: { sessionId: this.id },
|
|
1841
|
-
query: { vendor: this.vendor }
|
|
1842
|
-
})
|
|
1843
|
-
);
|
|
1844
|
-
}
|
|
1845
|
-
invalidateCaches() {
|
|
1846
|
-
this.cachedParticipants = null;
|
|
1847
|
-
this.cachedTelephonyLegs = null;
|
|
1848
|
-
this.cachedRecordings = null;
|
|
1849
|
-
this.cachedDispatches = null;
|
|
1850
|
-
}
|
|
1851
|
-
wireMedia() {
|
|
1852
|
-
this.media.on("state.changed", ({ state }) => {
|
|
1853
|
-
this.mediaStatus = state;
|
|
1854
|
-
this.bus.emit("media.status.changed", { status: state });
|
|
1855
|
-
});
|
|
1856
|
-
this.media.on("participant.changed", ({ identity }) => {
|
|
1857
|
-
this.cachedParticipants = null;
|
|
1858
|
-
const view = this.view.participants.find(
|
|
1859
|
-
(p2) => p2.participantIdentity === identity
|
|
1860
|
-
);
|
|
1861
|
-
if (!view) {
|
|
1862
|
-
return;
|
|
1863
|
-
}
|
|
1864
|
-
const p = participantFromView(
|
|
1865
|
-
view,
|
|
1866
|
-
this.selfParticipantId,
|
|
1867
|
-
this.media.listSnapshots()
|
|
1868
|
-
);
|
|
1869
|
-
this.bus.emit("participant.updated", { participant: p });
|
|
1870
|
-
});
|
|
1871
|
-
this.media.on("error", ({ error }) => {
|
|
1872
|
-
this.bus.emit("error", { error });
|
|
1873
|
-
});
|
|
1874
|
-
}
|
|
1875
|
-
diffParticipants(prev, next) {
|
|
1876
|
-
const byId = new Map(prev.participants.map((p) => [p.id, p]));
|
|
1877
|
-
const lookup = this.media.listSnapshots();
|
|
1878
|
-
const prevJoinedCount = prev.participants.filter(
|
|
1879
|
-
(p) => p.state === "joined"
|
|
1880
|
-
).length;
|
|
1881
|
-
for (const current of next.participants) {
|
|
1882
|
-
const before = byId.get(current.id);
|
|
1883
|
-
const participant = participantFromView(
|
|
1884
|
-
current,
|
|
1885
|
-
this.selfParticipantId,
|
|
1886
|
-
lookup
|
|
1887
|
-
);
|
|
1888
|
-
if (!before) {
|
|
1889
|
-
this.bus.emit("participant.invited", { participant });
|
|
1890
|
-
continue;
|
|
1891
|
-
}
|
|
1892
|
-
if (before.state === current.state) {
|
|
1893
|
-
continue;
|
|
1894
|
-
}
|
|
1895
|
-
switch (current.state) {
|
|
1896
|
-
case "accepted":
|
|
1897
|
-
this.bus.emit("participant.accepted", { participant });
|
|
1898
|
-
break;
|
|
1899
|
-
case "joined": {
|
|
1900
|
-
const isFirstJoin = prevJoinedCount === 0;
|
|
1901
|
-
this.bus.emit("participant.joined", { participant, isFirstJoin });
|
|
1902
|
-
break;
|
|
1903
|
-
}
|
|
1904
|
-
case "left": {
|
|
1905
|
-
const reason = nullify(current.leftReason) ?? "left";
|
|
1906
|
-
this.bus.emit("participant.left", { participant, reason });
|
|
1907
|
-
break;
|
|
1908
|
-
}
|
|
1909
|
-
case "declined":
|
|
1910
|
-
this.bus.emit("participant.declined", { participant });
|
|
1911
|
-
break;
|
|
1912
|
-
case "withdrawn":
|
|
1913
|
-
this.bus.emit("participant.withdrawn", { participant });
|
|
1914
|
-
break;
|
|
1915
|
-
case "removed":
|
|
1916
|
-
this.bus.emit("participant.removed", { participant });
|
|
1917
|
-
break;
|
|
1918
|
-
case "failed": {
|
|
1919
|
-
const reason = nullify(current.failureReason) ?? "unknown";
|
|
1920
|
-
const failedSipLeg = current.operations.find(
|
|
1921
|
-
(op) => op.kind === "sip_leg" && op.state === "failed"
|
|
1922
|
-
);
|
|
1923
|
-
this.bus.emit("participant.failed", {
|
|
1924
|
-
participant,
|
|
1925
|
-
reason,
|
|
1926
|
-
legFailureReason: nullify(failedSipLeg?.failureReason ?? null),
|
|
1927
|
-
sipStatusCode: nullify(failedSipLeg?.sipStatusCode ?? null)
|
|
1928
|
-
});
|
|
1929
|
-
break;
|
|
1930
|
-
}
|
|
1931
|
-
default:
|
|
1932
|
-
this.bus.emit("participant.updated", { participant });
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
diffTelephonyLegs(prev, next) {
|
|
1937
|
-
const beforeState = /* @__PURE__ */ new Map();
|
|
1938
|
-
for (const p of prev.participants) {
|
|
1939
|
-
for (const op of p.operations) {
|
|
1940
|
-
if (op.kind === "sip_leg") {
|
|
1941
|
-
beforeState.set(op.id, op.state);
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
for (const participant of next.participants) {
|
|
1946
|
-
for (const op of participant.operations) {
|
|
1947
|
-
if (op.kind !== "sip_leg") {
|
|
1948
|
-
continue;
|
|
1949
|
-
}
|
|
1950
|
-
const beforeOp = beforeState.get(op.id);
|
|
1951
|
-
if (beforeOp === op.state) {
|
|
1952
|
-
continue;
|
|
1953
|
-
}
|
|
1954
|
-
this.bus.emit("telephony_leg.updated", {
|
|
1955
|
-
leg: telephonyLegFromOperation(participant, op)
|
|
1956
|
-
});
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
diffDispatches(prev, next) {
|
|
1961
|
-
const byId = new Map(prev.dispatches.map((d) => [d.id, d]));
|
|
1962
|
-
for (const current of next.dispatches) {
|
|
1963
|
-
const before = byId.get(current.id);
|
|
1964
|
-
const dispatch = dispatchFromView(current);
|
|
1965
|
-
if (!before) {
|
|
1966
|
-
if (current.state === "active") {
|
|
1967
|
-
this.bus.emit("dispatch.started", { dispatch });
|
|
1968
|
-
}
|
|
1969
|
-
continue;
|
|
1970
|
-
}
|
|
1971
|
-
if (before.state === current.state) {
|
|
1972
|
-
continue;
|
|
1973
|
-
}
|
|
1974
|
-
switch (current.state) {
|
|
1975
|
-
case "resolved":
|
|
1976
|
-
this.bus.emit("dispatch.resolved", { dispatch });
|
|
1977
|
-
break;
|
|
1978
|
-
case "cancelled":
|
|
1979
|
-
this.bus.emit("dispatch.cancelled", { dispatch });
|
|
1980
|
-
break;
|
|
1981
|
-
case "expired":
|
|
1982
|
-
this.bus.emit("dispatch.expired", { dispatch });
|
|
1983
|
-
break;
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
}
|
|
1987
|
-
diffRecordings(prev, next) {
|
|
1988
|
-
const byId = new Map(prev.recordings.map((r) => [r.id, r]));
|
|
1989
|
-
for (const current of next.recordings) {
|
|
1990
|
-
const before = byId.get(current.id);
|
|
1991
|
-
const recording = recordingFromView(current);
|
|
1992
|
-
if (!before) {
|
|
1993
|
-
this.bus.emit("recording.requested", { recording });
|
|
1994
|
-
continue;
|
|
1995
|
-
}
|
|
1996
|
-
if (before.state === current.state) {
|
|
1997
|
-
continue;
|
|
1998
|
-
}
|
|
1999
|
-
if (current.state === "active") {
|
|
2000
|
-
this.bus.emit("recording.started", { recording });
|
|
2001
|
-
continue;
|
|
2002
|
-
}
|
|
2003
|
-
if (current.state === "stopped") {
|
|
2004
|
-
this.bus.emit("recording.stopped", { recording });
|
|
2005
|
-
continue;
|
|
2006
|
-
}
|
|
2007
|
-
if (current.state === "failed") {
|
|
2008
|
-
this.bus.emit("recording.failed", {
|
|
2009
|
-
recording,
|
|
2010
|
-
reason: nullify(current.failureReason)
|
|
2011
|
-
});
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
}
|
|
2015
|
-
};
|
|
2016
|
-
|
|
2017
|
-
// src/core/session/commands.ts
|
|
2018
|
-
function target(ctx) {
|
|
2019
|
-
return {
|
|
2020
|
-
path: { sessionId: ctx.session.id },
|
|
2021
|
-
query: { vendor: ctx.session.vendorSlug }
|
|
2022
|
-
};
|
|
2023
|
-
}
|
|
2024
|
-
var holdCommand = {
|
|
2025
|
-
name: "hold",
|
|
2026
|
-
async execute(ctx) {
|
|
2027
|
-
const res = await apiCall(
|
|
2028
|
-
() => postApiV1SessionsBySessionIdHold(target(ctx))
|
|
2029
|
-
);
|
|
2030
|
-
if (!res.ok) {
|
|
2031
|
-
return res;
|
|
2032
|
-
}
|
|
2033
|
-
ctx.applyView(res.value);
|
|
2034
|
-
return ok(void 0);
|
|
2035
|
-
}
|
|
2036
|
-
};
|
|
2037
|
-
var unholdCommand = {
|
|
2038
|
-
name: "unhold",
|
|
2039
|
-
async execute(ctx) {
|
|
2040
|
-
const res = await apiCall(
|
|
2041
|
-
() => postApiV1SessionsBySessionIdUnhold(target(ctx))
|
|
2042
|
-
);
|
|
2043
|
-
if (!res.ok) {
|
|
2044
|
-
return res;
|
|
2045
|
-
}
|
|
2046
|
-
ctx.applyView(res.value);
|
|
2047
|
-
return ok(void 0);
|
|
2048
|
-
}
|
|
2049
|
-
};
|
|
2050
|
-
var cancelCommand = {
|
|
2051
|
-
name: "cancel",
|
|
2052
|
-
async execute(ctx) {
|
|
2053
|
-
const res = await apiCall(
|
|
2054
|
-
() => postApiV1SessionsBySessionIdCancel(target(ctx))
|
|
2055
|
-
);
|
|
2056
|
-
if (!res.ok) {
|
|
2057
|
-
return res;
|
|
2058
|
-
}
|
|
2059
|
-
ctx.applyView(res.value);
|
|
2060
|
-
return ok(void 0);
|
|
2061
|
-
}
|
|
2062
|
-
};
|
|
2063
|
-
var endCommand = {
|
|
2064
|
-
name: "end",
|
|
2065
|
-
async execute(ctx) {
|
|
2066
|
-
const res = await apiCall(
|
|
2067
|
-
() => postApiV1SessionsBySessionIdEnd(target(ctx))
|
|
2068
|
-
);
|
|
2069
|
-
if (!res.ok) {
|
|
2070
|
-
return res;
|
|
2071
|
-
}
|
|
2072
|
-
ctx.applyView(res.value);
|
|
2073
|
-
return ok(void 0);
|
|
2074
|
-
}
|
|
2075
|
-
};
|
|
2076
|
-
var leaveCommand = {
|
|
2077
|
-
name: "leave",
|
|
2078
|
-
async execute(ctx) {
|
|
2079
|
-
if (ctx.session.state === "ended") {
|
|
2080
|
-
await ctx.media.disconnect();
|
|
2081
|
-
return ok(void 0);
|
|
2082
|
-
}
|
|
2083
|
-
const res = await apiCall(
|
|
2084
|
-
() => postApiV1SessionsBySessionIdLeave(target(ctx))
|
|
2085
|
-
);
|
|
2086
|
-
await ctx.media.disconnect();
|
|
2087
|
-
if (!res.ok) {
|
|
2088
|
-
return res;
|
|
2089
|
-
}
|
|
2090
|
-
ctx.applyView(res.value);
|
|
2091
|
-
return ok(void 0);
|
|
2092
|
-
}
|
|
2093
|
-
};
|
|
2094
|
-
var inviteCommand = {
|
|
2095
|
-
name: "invite",
|
|
2096
|
-
async execute(ctx, invited) {
|
|
2097
|
-
const body = { target: invited };
|
|
2098
|
-
const res = await apiCall(
|
|
2099
|
-
() => postApiV1SessionsBySessionIdParticipants({
|
|
2100
|
-
...target(ctx),
|
|
2101
|
-
body
|
|
2102
|
-
})
|
|
2103
|
-
);
|
|
2104
|
-
if (!res.ok) {
|
|
2105
|
-
return res;
|
|
2106
|
-
}
|
|
2107
|
-
ctx.applyView(res.value);
|
|
2108
|
-
return ok(void 0);
|
|
2109
|
-
}
|
|
2110
|
-
};
|
|
2111
|
-
var removeParticipantCommand = {
|
|
2112
|
-
name: "removeParticipant",
|
|
2113
|
-
async execute(ctx, participantId) {
|
|
2114
|
-
const res = await apiCall(
|
|
2115
|
-
() => deleteApiV1SessionsBySessionIdParticipantsByParticipantId({
|
|
2116
|
-
path: { sessionId: ctx.session.id, participantId },
|
|
2117
|
-
query: { vendor: ctx.session.vendorSlug }
|
|
2118
|
-
})
|
|
2119
|
-
);
|
|
2120
|
-
if (!res.ok) {
|
|
2121
|
-
return res;
|
|
2122
|
-
}
|
|
2123
|
-
ctx.applyView(res.value);
|
|
2124
|
-
return ok(void 0);
|
|
2125
|
-
}
|
|
2126
|
-
};
|
|
2127
|
-
var updateNameCommand = {
|
|
2128
|
-
name: "updateName",
|
|
2129
|
-
async execute(ctx, name) {
|
|
2130
|
-
const res = await apiCall(
|
|
2131
|
-
() => patchApiV1SessionsBySessionId({
|
|
2132
|
-
...target(ctx),
|
|
2133
|
-
body: { name }
|
|
2134
|
-
})
|
|
2135
|
-
);
|
|
2136
|
-
if (!res.ok) {
|
|
2137
|
-
return res;
|
|
2138
|
-
}
|
|
2139
|
-
ctx.applyView(res.value);
|
|
2140
|
-
return ok(void 0);
|
|
2141
|
-
}
|
|
2142
|
-
};
|
|
2143
|
-
var startRecordingCommand = {
|
|
2144
|
-
name: "startRecording",
|
|
2145
|
-
async execute(ctx) {
|
|
2146
|
-
const res = await apiCall(
|
|
2147
|
-
() => postApiV1SessionsBySessionIdRecordings(target(ctx))
|
|
2148
|
-
);
|
|
2149
|
-
if (!res.ok) {
|
|
2150
|
-
return res;
|
|
2151
|
-
}
|
|
2152
|
-
return ok(void 0);
|
|
2153
|
-
}
|
|
2154
|
-
};
|
|
2155
|
-
var stopRecordingCommand = {
|
|
2156
|
-
name: "stopRecording",
|
|
2157
|
-
async execute(ctx, recordingId) {
|
|
2158
|
-
const res = await apiCall(
|
|
2159
|
-
() => postApiV1SessionsBySessionIdRecordingsByRecordingIdStop({
|
|
2160
|
-
path: { sessionId: ctx.session.id, recordingId },
|
|
2161
|
-
query: { vendor: ctx.session.vendorSlug }
|
|
2162
|
-
})
|
|
2163
|
-
);
|
|
2164
|
-
if (!res.ok) {
|
|
2165
|
-
return res;
|
|
2166
|
-
}
|
|
2167
|
-
return ok(void 0);
|
|
2168
|
-
}
|
|
2169
|
-
};
|
|
2170
|
-
|
|
2171
|
-
// src/core/managers/session-manager.ts
|
|
2172
|
-
var ACTIVE_STATES = /* @__PURE__ */ new Set(["ringing", "active", "on_hold"]);
|
|
2173
|
-
var SessionManager = class {
|
|
2174
|
-
sessions = /* @__PURE__ */ new Map();
|
|
2175
|
-
vendor;
|
|
2176
|
-
logger;
|
|
2177
|
-
pulse;
|
|
2178
|
-
commands;
|
|
2179
|
-
selfParticipantId;
|
|
2180
|
-
bus = new EventBus();
|
|
2181
|
-
unsubs = [];
|
|
2182
|
-
cachedList = null;
|
|
2183
|
-
disposed = false;
|
|
2184
|
-
constructor(opts) {
|
|
2185
|
-
this.vendor = opts.vendor;
|
|
2186
|
-
this.logger = opts.logger.child({ component: "session-manager" });
|
|
2187
|
-
this.pulse = opts.pulse;
|
|
2188
|
-
this.selfParticipantId = opts.selfParticipantId;
|
|
2189
|
-
this.commands = opts.commands;
|
|
2190
|
-
this.unsubs.push(
|
|
2191
|
-
this.pulse.on("session.upsert", (view) => this.onUpsert(view)),
|
|
2192
|
-
this.pulse.on(
|
|
2193
|
-
"session.remove",
|
|
2194
|
-
({ sessionId, version }) => this.onRemove(sessionId, version)
|
|
2195
|
-
)
|
|
2196
|
-
);
|
|
2197
|
-
}
|
|
2198
|
-
list() {
|
|
2199
|
-
if (this.cachedList === null) {
|
|
2200
|
-
this.cachedList = Array.from(this.sessions.values());
|
|
2201
|
-
}
|
|
2202
|
-
return this.cachedList;
|
|
2203
|
-
}
|
|
2204
|
-
get(id) {
|
|
2205
|
-
return this.sessions.get(id) ?? null;
|
|
2206
|
-
}
|
|
2207
|
-
active() {
|
|
2208
|
-
for (const session of this.sessions.values()) {
|
|
2209
|
-
if (ACTIVE_STATES.has(session.state)) {
|
|
2210
|
-
return session;
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
return null;
|
|
2214
|
-
}
|
|
2215
|
-
activeId() {
|
|
2216
|
-
return this.active()?.id ?? null;
|
|
2217
|
-
}
|
|
2218
|
-
on(type, handler) {
|
|
2219
|
-
return this.bus.on(type, handler);
|
|
2220
|
-
}
|
|
2221
|
-
async prime() {
|
|
2222
|
-
if (this.disposed) {
|
|
2223
|
-
return err(callpadError.disposed());
|
|
2224
|
-
}
|
|
2225
|
-
const res = await apiCall(
|
|
2226
|
-
() => getApiV1Sessions({ query: { vendor: this.vendor, limit: 50 } })
|
|
2227
|
-
);
|
|
2228
|
-
if (!res.ok) {
|
|
2229
|
-
return res;
|
|
2230
|
-
}
|
|
2231
|
-
for (const view of res.value.items) {
|
|
2232
|
-
this.onUpsert(view);
|
|
2233
|
-
}
|
|
2234
|
-
return ok(void 0);
|
|
2235
|
-
}
|
|
2236
|
-
async create(body) {
|
|
2237
|
-
if (this.disposed) {
|
|
2238
|
-
return err(callpadError.disposed());
|
|
2239
|
-
}
|
|
2240
|
-
const res = await apiCall(
|
|
2241
|
-
() => postApiV1Sessions({
|
|
2242
|
-
query: { vendor: this.vendor },
|
|
2243
|
-
body
|
|
2244
|
-
})
|
|
2245
|
-
);
|
|
2246
|
-
if (!res.ok) {
|
|
2247
|
-
return res;
|
|
2248
|
-
}
|
|
2249
|
-
const session = this.onUpsert(res.value);
|
|
2250
|
-
return ok(session);
|
|
2251
|
-
}
|
|
2252
|
-
async fetchById(id) {
|
|
2253
|
-
if (this.disposed) {
|
|
2254
|
-
return err(callpadError.disposed());
|
|
2255
|
-
}
|
|
2256
|
-
const res = await apiCall(
|
|
2257
|
-
() => getApiV1SessionsBySessionId({
|
|
2258
|
-
path: { sessionId: id },
|
|
2259
|
-
query: { vendor: this.vendor }
|
|
2260
|
-
})
|
|
2261
|
-
);
|
|
2262
|
-
if (!res.ok) {
|
|
2263
|
-
return res;
|
|
2264
|
-
}
|
|
2265
|
-
const session = this.onUpsert(res.value);
|
|
2266
|
-
return ok(session);
|
|
2267
|
-
}
|
|
2268
|
-
onAcceptedInvite(view) {
|
|
2269
|
-
return this.onUpsert(view);
|
|
2270
|
-
}
|
|
2271
|
-
onUpsert(view) {
|
|
2272
|
-
const existing = this.sessions.get(view.id);
|
|
2273
|
-
if (existing) {
|
|
2274
|
-
if (shouldApplyUpsert(existing, view)) {
|
|
2275
|
-
existing.applyView(view);
|
|
2276
|
-
}
|
|
2277
|
-
return existing;
|
|
2278
|
-
}
|
|
2279
|
-
const session = new Session({
|
|
2280
|
-
vendor: this.vendor,
|
|
2281
|
-
view,
|
|
2282
|
-
logger: this.logger,
|
|
2283
|
-
selfParticipantId: this.selfParticipantId,
|
|
2284
|
-
commands: this.commands
|
|
2285
|
-
});
|
|
2286
|
-
this.sessions.set(view.id, session);
|
|
2287
|
-
this.cachedList = null;
|
|
2288
|
-
this.bus.emit("session.added", { session });
|
|
2289
|
-
return session;
|
|
2290
|
-
}
|
|
2291
|
-
onRemove(sessionId, _version) {
|
|
2292
|
-
const session = this.sessions.get(sessionId);
|
|
2293
|
-
if (!session) {
|
|
2294
|
-
return;
|
|
2295
|
-
}
|
|
2296
|
-
this.sessions.delete(sessionId);
|
|
2297
|
-
this.cachedList = null;
|
|
2298
|
-
this.bus.emit("session.removed", { sessionId });
|
|
2299
|
-
void session.dispose();
|
|
2300
|
-
}
|
|
2301
|
-
async dispose() {
|
|
2302
|
-
if (this.disposed) {
|
|
2303
|
-
return;
|
|
2304
|
-
}
|
|
2305
|
-
this.disposed = true;
|
|
2306
|
-
for (const unsub of this.unsubs) {
|
|
2307
|
-
unsub();
|
|
2308
|
-
}
|
|
2309
|
-
await Promise.all(
|
|
2310
|
-
Array.from(this.sessions.values(), (session) => session.dispose())
|
|
2311
|
-
);
|
|
2312
|
-
this.sessions.clear();
|
|
2313
|
-
this.bus.clear();
|
|
2314
|
-
}
|
|
2315
|
-
};
|
|
2316
|
-
|
|
2317
|
-
// src/core/invite.ts
|
|
2318
|
-
var Invite = class {
|
|
2319
|
-
view;
|
|
2320
|
-
vendor;
|
|
2321
|
-
onAccept;
|
|
2322
|
-
disposed = false;
|
|
2323
|
-
constructor(view, vendor, onAccept) {
|
|
2324
|
-
this.view = view;
|
|
2325
|
-
this.vendor = vendor;
|
|
2326
|
-
this.onAccept = onAccept;
|
|
2327
|
-
}
|
|
2328
|
-
get id() {
|
|
2329
|
-
return this.view.id;
|
|
2330
|
-
}
|
|
2331
|
-
get sessionId() {
|
|
2332
|
-
return this.view.sessionId;
|
|
2333
|
-
}
|
|
2334
|
-
get callId() {
|
|
2335
|
-
return this.view.callId;
|
|
2336
|
-
}
|
|
2337
|
-
get state() {
|
|
2338
|
-
return this.view.state;
|
|
2339
|
-
}
|
|
2340
|
-
get createdAt() {
|
|
2341
|
-
return this.view.createdAt;
|
|
2342
|
-
}
|
|
2343
|
-
get expiresAt() {
|
|
2344
|
-
return nullify(this.view.expiresAt);
|
|
2345
|
-
}
|
|
2346
|
-
get completedAt() {
|
|
2347
|
-
return nullify(this.view.completedAt);
|
|
2348
|
-
}
|
|
2349
|
-
get dispatchId() {
|
|
2350
|
-
return nullify(this.view.dispatchId);
|
|
2351
|
-
}
|
|
2352
|
-
get recipient() {
|
|
2353
|
-
return this.view.recipient;
|
|
2354
|
-
}
|
|
2355
|
-
get participantId() {
|
|
2356
|
-
return this.view.participantId;
|
|
2357
|
-
}
|
|
2358
|
-
get inviterParticipantId() {
|
|
2359
|
-
return nullify(this.view.inviterParticipantId);
|
|
2360
|
-
}
|
|
2361
|
-
get session() {
|
|
2362
|
-
return this.view.session;
|
|
2363
|
-
}
|
|
2364
|
-
applyView(next) {
|
|
2365
|
-
this.view = next;
|
|
2366
|
-
}
|
|
2367
|
-
async accept() {
|
|
2368
|
-
if (this.disposed) {
|
|
2369
|
-
return err(callpadError.disposed());
|
|
2370
|
-
}
|
|
2371
|
-
const res = await apiCall(
|
|
2372
|
-
() => postApiV1SessionsBySessionIdInvitesByInviteIdAccept({
|
|
2373
|
-
path: { sessionId: this.sessionId, inviteId: this.id },
|
|
2374
|
-
query: { vendor: this.vendor }
|
|
2375
|
-
})
|
|
2376
|
-
);
|
|
2377
|
-
if (!res.ok) {
|
|
2378
|
-
return res;
|
|
2379
|
-
}
|
|
2380
|
-
return this.onAccept(res.value);
|
|
2381
|
-
}
|
|
2382
|
-
async reject() {
|
|
2383
|
-
if (this.disposed) {
|
|
2384
|
-
return err(callpadError.disposed());
|
|
2385
|
-
}
|
|
2386
|
-
const res = await apiCall(
|
|
2387
|
-
() => postApiV1SessionsBySessionIdInvitesByInviteIdReject({
|
|
2388
|
-
path: { sessionId: this.sessionId, inviteId: this.id },
|
|
2389
|
-
query: { vendor: this.vendor }
|
|
2390
|
-
})
|
|
2391
|
-
);
|
|
2392
|
-
if (!res.ok) {
|
|
2393
|
-
return res;
|
|
2394
|
-
}
|
|
2395
|
-
return ok(void 0);
|
|
2396
|
-
}
|
|
2397
|
-
dispose() {
|
|
2398
|
-
this.disposed = true;
|
|
2399
|
-
}
|
|
2400
|
-
};
|
|
2401
|
-
|
|
2402
|
-
// src/core/managers/invite-manager.ts
|
|
2403
|
-
var InviteManager = class {
|
|
2404
|
-
invites = /* @__PURE__ */ new Map();
|
|
2405
|
-
sessionIndex = /* @__PURE__ */ new Map();
|
|
2406
|
-
vendor;
|
|
2407
|
-
pulse;
|
|
2408
|
-
onAccept;
|
|
2409
|
-
bus = new EventBus();
|
|
2410
|
-
unsubs = [];
|
|
2411
|
-
cachedList = null;
|
|
2412
|
-
disposed = false;
|
|
2413
|
-
constructor(opts) {
|
|
2414
|
-
this.vendor = opts.vendor;
|
|
2415
|
-
this.pulse = opts.pulse;
|
|
2416
|
-
this.onAccept = opts.onAccept;
|
|
2417
|
-
this.unsubs.push(
|
|
2418
|
-
this.pulse.on("session.invite.upsert", (view) => this.onUpsert(view)),
|
|
2419
|
-
this.pulse.on(
|
|
2420
|
-
"session.invite.remove",
|
|
2421
|
-
({ inviteId }) => this.onRemove(inviteId)
|
|
2422
|
-
),
|
|
2423
|
-
this.pulse.on(
|
|
2424
|
-
"session.remove",
|
|
2425
|
-
({ sessionId }) => this.dropBySession(sessionId)
|
|
2426
|
-
)
|
|
2427
|
-
);
|
|
2428
|
-
}
|
|
2429
|
-
list() {
|
|
2430
|
-
if (this.cachedList === null) {
|
|
2431
|
-
this.cachedList = Array.from(this.invites.values());
|
|
2432
|
-
}
|
|
2433
|
-
return this.cachedList;
|
|
2434
|
-
}
|
|
2435
|
-
get(id) {
|
|
2436
|
-
return this.invites.get(id) ?? null;
|
|
2437
|
-
}
|
|
2438
|
-
first() {
|
|
2439
|
-
const iterator = this.invites.values().next();
|
|
2440
|
-
return iterator.done ? null : iterator.value;
|
|
2441
|
-
}
|
|
2442
|
-
on(type, handler) {
|
|
2443
|
-
return this.bus.on(type, handler);
|
|
2444
|
-
}
|
|
2445
|
-
async prime() {
|
|
2446
|
-
if (this.disposed) {
|
|
2447
|
-
return err(callpadError.disposed());
|
|
2448
|
-
}
|
|
2449
|
-
const res = await apiCall(
|
|
2450
|
-
() => getApiV1SessionsInvites({ query: { vendor: this.vendor } })
|
|
2451
|
-
);
|
|
2452
|
-
if (!res.ok) {
|
|
2453
|
-
return res;
|
|
2454
|
-
}
|
|
2455
|
-
for (const view of res.value) {
|
|
2456
|
-
this.onUpsert(view);
|
|
2457
|
-
}
|
|
2458
|
-
return ok(void 0);
|
|
2459
|
-
}
|
|
2460
|
-
onUpsert(view) {
|
|
2461
|
-
if (view.state !== "pending") {
|
|
2462
|
-
this.onRemove(view.id);
|
|
2463
|
-
return;
|
|
2464
|
-
}
|
|
2465
|
-
const existing = this.invites.get(view.id);
|
|
2466
|
-
if (existing) {
|
|
2467
|
-
if (!shouldApplyUpsert(existing.session, view.session)) {
|
|
2468
|
-
return;
|
|
2469
|
-
}
|
|
2470
|
-
existing.applyView(view);
|
|
2471
|
-
this.bus.emit("invite.updated", { invite: existing });
|
|
2472
|
-
return;
|
|
2473
|
-
}
|
|
2474
|
-
const invite = new Invite(view, this.vendor, this.onAccept);
|
|
2475
|
-
this.invites.set(view.id, invite);
|
|
2476
|
-
this.trackSession(view.sessionId, view.id);
|
|
2477
|
-
this.cachedList = null;
|
|
2478
|
-
this.bus.emit("invite.added", { invite });
|
|
2479
|
-
}
|
|
2480
|
-
onRemove(inviteId) {
|
|
2481
|
-
const existing = this.invites.get(inviteId);
|
|
2482
|
-
if (!existing) {
|
|
2483
|
-
return;
|
|
2484
|
-
}
|
|
2485
|
-
this.invites.delete(inviteId);
|
|
2486
|
-
this.untrackSession(existing.sessionId, inviteId);
|
|
2487
|
-
this.cachedList = null;
|
|
2488
|
-
this.bus.emit("invite.removed", { inviteId });
|
|
2489
|
-
existing.dispose();
|
|
2490
|
-
}
|
|
2491
|
-
dropBySession(sessionId) {
|
|
2492
|
-
const ids = this.sessionIndex.get(sessionId);
|
|
2493
|
-
if (!ids) {
|
|
2494
|
-
return;
|
|
2495
|
-
}
|
|
2496
|
-
for (const inviteId of ids) {
|
|
2497
|
-
this.onRemove(inviteId);
|
|
2498
|
-
}
|
|
2499
|
-
}
|
|
2500
|
-
trackSession(sessionId, inviteId) {
|
|
2501
|
-
let set = this.sessionIndex.get(sessionId);
|
|
2502
|
-
if (!set) {
|
|
2503
|
-
set = /* @__PURE__ */ new Set();
|
|
2504
|
-
this.sessionIndex.set(sessionId, set);
|
|
2505
|
-
}
|
|
2506
|
-
set.add(inviteId);
|
|
2507
|
-
}
|
|
2508
|
-
untrackSession(sessionId, inviteId) {
|
|
2509
|
-
const set = this.sessionIndex.get(sessionId);
|
|
2510
|
-
if (!set) {
|
|
2511
|
-
return;
|
|
2512
|
-
}
|
|
2513
|
-
set.delete(inviteId);
|
|
2514
|
-
if (set.size === 0) {
|
|
2515
|
-
this.sessionIndex.delete(sessionId);
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
async dispose() {
|
|
2519
|
-
if (this.disposed) {
|
|
2520
|
-
return;
|
|
2521
|
-
}
|
|
2522
|
-
this.disposed = true;
|
|
2523
|
-
for (const unsub of this.unsubs) {
|
|
2524
|
-
unsub();
|
|
2525
|
-
}
|
|
2526
|
-
for (const invite of this.invites.values()) {
|
|
2527
|
-
invite.dispose();
|
|
2528
|
-
}
|
|
2529
|
-
this.invites.clear();
|
|
2530
|
-
this.sessionIndex.clear();
|
|
2531
|
-
this.bus.clear();
|
|
2532
|
-
}
|
|
2533
|
-
};
|
|
2534
|
-
|
|
2535
|
-
// src/core/presence.ts
|
|
2536
|
-
function presenceFromItem(item) {
|
|
2537
|
-
return {
|
|
2538
|
-
id: item.id,
|
|
2539
|
-
availability: nullify(item.availability),
|
|
2540
|
-
connectivity: nullify(item.connectivity),
|
|
2541
|
-
lastSeenAt: nullify(item.lastSeenAt)
|
|
2542
|
-
};
|
|
2543
|
-
}
|
|
2544
|
-
|
|
2545
|
-
// src/core/managers/presence-manager.ts
|
|
2546
|
-
var PresenceManager = class {
|
|
2547
|
-
vendor;
|
|
2548
|
-
bus = new EventBus();
|
|
2549
|
-
disposed = false;
|
|
2550
|
-
constructor(opts) {
|
|
2551
|
-
this.vendor = opts.vendor;
|
|
2552
|
-
}
|
|
2553
|
-
on(type, handler) {
|
|
2554
|
-
return this.bus.on(type, handler);
|
|
2555
|
-
}
|
|
2556
|
-
async get(refs) {
|
|
2557
|
-
if (this.disposed) {
|
|
2558
|
-
return err(callpadError.disposed());
|
|
2559
|
-
}
|
|
2560
|
-
if (refs.length === 0) {
|
|
2561
|
-
return ok(/* @__PURE__ */ new Map());
|
|
2562
|
-
}
|
|
2563
|
-
const byKind = /* @__PURE__ */ new Map();
|
|
2564
|
-
for (const ref of refs) {
|
|
2565
|
-
const list = byKind.get(ref.kind) ?? [];
|
|
2566
|
-
list.push(ref.id);
|
|
2567
|
-
byKind.set(ref.kind, list);
|
|
2568
|
-
}
|
|
2569
|
-
const responses = await Promise.all(
|
|
2570
|
-
Array.from(byKind.entries()).map(
|
|
2571
|
-
([kind, ids]) => apiCall(
|
|
2572
|
-
() => getApiV1VendorsBySlugPresence({
|
|
2573
|
-
path: { slug: this.vendor },
|
|
2574
|
-
query: { type: kind, ids: ids.join(",") }
|
|
2575
|
-
})
|
|
2576
|
-
)
|
|
2577
|
-
)
|
|
2578
|
-
);
|
|
2579
|
-
const result = /* @__PURE__ */ new Map();
|
|
2580
|
-
for (const res of responses) {
|
|
2581
|
-
if (!res.ok) {
|
|
2582
|
-
return res;
|
|
2583
|
-
}
|
|
2584
|
-
for (const item of res.value.items) {
|
|
2585
|
-
const snapshot = presenceFromItem(item);
|
|
2586
|
-
result.set(snapshot.id, snapshot);
|
|
2587
|
-
this.bus.emit("presence.updated", { snapshot });
|
|
2588
|
-
}
|
|
2589
|
-
}
|
|
2590
|
-
return ok(result);
|
|
2591
|
-
}
|
|
2592
|
-
async setMyStatus(mode, note) {
|
|
2593
|
-
if (this.disposed) {
|
|
2594
|
-
return err(callpadError.disposed());
|
|
2595
|
-
}
|
|
2596
|
-
const res = await apiCall(
|
|
2597
|
-
() => putApiV1VendorsBySlugPresenceStatus({
|
|
2598
|
-
path: { slug: this.vendor },
|
|
2599
|
-
body: { status: mode, note: note ?? void 0 }
|
|
2600
|
-
})
|
|
2601
|
-
);
|
|
2602
|
-
if (!res.ok) {
|
|
2603
|
-
return res;
|
|
2604
|
-
}
|
|
2605
|
-
return ok(void 0);
|
|
2606
|
-
}
|
|
2607
|
-
async clearMyStatus() {
|
|
2608
|
-
if (this.disposed) {
|
|
2609
|
-
return err(callpadError.disposed());
|
|
2610
|
-
}
|
|
2611
|
-
const res = await apiCall(
|
|
2612
|
-
() => deleteApiV1VendorsBySlugPresenceStatus({
|
|
2613
|
-
path: { slug: this.vendor }
|
|
2614
|
-
})
|
|
2615
|
-
);
|
|
2616
|
-
if (!res.ok) {
|
|
2617
|
-
return res;
|
|
2618
|
-
}
|
|
2619
|
-
return ok(void 0);
|
|
2620
|
-
}
|
|
2621
|
-
async dispose() {
|
|
2622
|
-
this.disposed = true;
|
|
2623
|
-
this.bus.clear();
|
|
2624
|
-
}
|
|
2625
|
-
};
|
|
2626
|
-
|
|
2627
|
-
// src/core/plugin.ts
|
|
2628
|
-
var PluginHost = class {
|
|
2629
|
-
handles = [];
|
|
2630
|
-
async register(plugin, ctx) {
|
|
2631
|
-
const handle = await plugin.install(ctx);
|
|
2632
|
-
this.handles.push(handle);
|
|
2633
|
-
}
|
|
2634
|
-
async disposeAll() {
|
|
2635
|
-
while (this.handles.length > 0) {
|
|
2636
|
-
const h = this.handles.pop();
|
|
2637
|
-
if (h) {
|
|
2638
|
-
try {
|
|
2639
|
-
await h.dispose();
|
|
2640
|
-
} catch {
|
|
2641
|
-
}
|
|
2642
|
-
}
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
};
|
|
2646
|
-
|
|
2647
|
-
// src/core/client.ts
|
|
2648
|
-
var CallpadClient = class {
|
|
2649
|
-
config;
|
|
2650
|
-
logger;
|
|
2651
|
-
bus = new EventBus();
|
|
2652
|
-
pluginHost = new PluginHost();
|
|
2653
|
-
sessionCommands = /* @__PURE__ */ new Map();
|
|
2654
|
-
pulseTransport = null;
|
|
2655
|
-
sessions = null;
|
|
2656
|
-
invites = null;
|
|
2657
|
-
presence = null;
|
|
2658
|
-
responseInterceptorId = null;
|
|
2659
|
-
status = "idle";
|
|
2660
|
-
disposed = false;
|
|
2661
|
-
constructor(config) {
|
|
2662
|
-
this.config = config;
|
|
2663
|
-
this.logger = (config.logger ?? noopLogger).child({
|
|
2664
|
-
component: "callpad-client"
|
|
2665
|
-
});
|
|
2666
|
-
this.registerSessionCommand(holdCommand);
|
|
2667
|
-
this.registerSessionCommand(unholdCommand);
|
|
2668
|
-
this.registerSessionCommand(cancelCommand);
|
|
2669
|
-
this.registerSessionCommand(endCommand);
|
|
2670
|
-
this.registerSessionCommand(leaveCommand);
|
|
2671
|
-
this.registerSessionCommand(inviteCommand);
|
|
2672
|
-
this.registerSessionCommand(removeParticipantCommand);
|
|
2673
|
-
this.registerSessionCommand(updateNameCommand);
|
|
2674
|
-
this.registerSessionCommand(startRecordingCommand);
|
|
2675
|
-
this.registerSessionCommand(stopRecordingCommand);
|
|
2676
|
-
}
|
|
2677
|
-
registerSessionCommand(cmd) {
|
|
2678
|
-
this.sessionCommands.set(
|
|
2679
|
-
cmd.name,
|
|
2680
|
-
cmd
|
|
2681
|
-
);
|
|
2682
|
-
}
|
|
2683
|
-
getStatus() {
|
|
2684
|
-
return this.status;
|
|
2685
|
-
}
|
|
2686
|
-
getSessions() {
|
|
2687
|
-
if (!this.sessions) {
|
|
2688
|
-
throw new Error(
|
|
2689
|
-
"CallpadClient: sessions not initialized; call connect() first"
|
|
2690
|
-
);
|
|
2691
|
-
}
|
|
2692
|
-
return this.sessions;
|
|
2693
|
-
}
|
|
2694
|
-
getInvites() {
|
|
2695
|
-
if (!this.invites) {
|
|
2696
|
-
throw new Error(
|
|
2697
|
-
"CallpadClient: invites not initialized; call connect() first"
|
|
2698
|
-
);
|
|
2699
|
-
}
|
|
2700
|
-
return this.invites;
|
|
2701
|
-
}
|
|
2702
|
-
getPresence() {
|
|
2703
|
-
if (!this.presence) {
|
|
2704
|
-
throw new Error(
|
|
2705
|
-
"CallpadClient: presence not initialized; call connect() first"
|
|
2706
|
-
);
|
|
2707
|
-
}
|
|
2708
|
-
return this.presence;
|
|
2709
|
-
}
|
|
2710
|
-
on(type, handler) {
|
|
2711
|
-
return this.bus.on(type, handler);
|
|
2712
|
-
}
|
|
2713
|
-
async connect() {
|
|
2714
|
-
if (this.disposed) {
|
|
2715
|
-
return err(callpadError.disposed());
|
|
2716
|
-
}
|
|
2717
|
-
if (this.status === "ready" || this.status === "connecting") {
|
|
2718
|
-
return ok(void 0);
|
|
2719
|
-
}
|
|
2720
|
-
this.setStatus("connecting");
|
|
2721
|
-
this.configureApiClient();
|
|
2722
|
-
const pulse = new PulseTransport({
|
|
2723
|
-
grantFetcher: () => this.fetchPulseGrant(),
|
|
2724
|
-
logger: this.logger
|
|
2725
|
-
});
|
|
2726
|
-
this.pulseTransport = pulse;
|
|
2727
|
-
const sessions = new SessionManager({
|
|
2728
|
-
vendor: this.config.vendor,
|
|
2729
|
-
logger: this.logger,
|
|
2730
|
-
pulse,
|
|
2731
|
-
selfParticipantId: null,
|
|
2732
|
-
commands: this.sessionCommands
|
|
2733
|
-
});
|
|
2734
|
-
const invites = new InviteManager({
|
|
2735
|
-
vendor: this.config.vendor,
|
|
2736
|
-
pulse,
|
|
2737
|
-
onAccept: async ({ session: view, joinGrant }) => {
|
|
2738
|
-
const session = sessions.onAcceptedInvite(view);
|
|
2739
|
-
return session.joinWithGrant(joinGrant);
|
|
2740
|
-
}
|
|
2741
|
-
});
|
|
2742
|
-
const presence = new PresenceManager({
|
|
2743
|
-
vendor: this.config.vendor
|
|
2744
|
-
});
|
|
2745
|
-
sessions.on("session.added", ({ session }) => {
|
|
2746
|
-
this.bus.emit("session.added", { session });
|
|
2747
|
-
});
|
|
2748
|
-
sessions.on("session.removed", ({ sessionId }) => {
|
|
2749
|
-
this.bus.emit("session.removed", { sessionId });
|
|
2750
|
-
});
|
|
2751
|
-
invites.on("invite.added", ({ invite }) => {
|
|
2752
|
-
this.bus.emit("invite.added", { inviteId: invite.id });
|
|
2753
|
-
});
|
|
2754
|
-
invites.on("invite.removed", ({ inviteId }) => {
|
|
2755
|
-
this.bus.emit("invite.removed", { inviteId });
|
|
2756
|
-
});
|
|
2757
|
-
pulse.on("status.changed", ({ status }) => {
|
|
2758
|
-
if (status === "recovering") {
|
|
2759
|
-
this.setStatus("degraded");
|
|
2760
|
-
} else if (status === "connected") {
|
|
2761
|
-
this.setStatus("ready");
|
|
2762
|
-
} else if (status === "disconnected") {
|
|
2763
|
-
this.setStatus("offline");
|
|
2764
|
-
}
|
|
2765
|
-
});
|
|
2766
|
-
this.sessions = sessions;
|
|
2767
|
-
this.invites = invites;
|
|
2768
|
-
this.presence = presence;
|
|
2769
|
-
const [connectPulse, sessionsPrime, invitesPrime] = await Promise.all([
|
|
2770
|
-
pulse.connect(),
|
|
2771
|
-
sessions.prime(),
|
|
2772
|
-
invites.prime()
|
|
2773
|
-
]);
|
|
2774
|
-
if (!connectPulse.ok) {
|
|
2775
|
-
this.setStatus("offline");
|
|
2776
|
-
this.bus.emit("error", { error: connectPulse.error });
|
|
2777
|
-
return connectPulse;
|
|
2778
|
-
}
|
|
2779
|
-
for (const r of [sessionsPrime, invitesPrime]) {
|
|
2780
|
-
if (!r.ok) {
|
|
2781
|
-
this.logger.warn({ code: r.error.code }, "prime failed");
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2784
|
-
this.setStatus("ready");
|
|
2785
|
-
return ok(void 0);
|
|
2786
|
-
}
|
|
2787
|
-
async dispose() {
|
|
2788
|
-
if (this.disposed) {
|
|
2789
|
-
return;
|
|
2790
|
-
}
|
|
2791
|
-
this.disposed = true;
|
|
2792
|
-
if (this.responseInterceptorId !== null) {
|
|
2793
|
-
client.interceptors.response.eject(this.responseInterceptorId);
|
|
2794
|
-
this.responseInterceptorId = null;
|
|
2795
|
-
}
|
|
2796
|
-
await this.pluginHost.disposeAll();
|
|
2797
|
-
await this.sessions?.dispose();
|
|
2798
|
-
await this.invites?.dispose();
|
|
2799
|
-
await this.presence?.dispose();
|
|
2800
|
-
await this.pulseTransport?.dispose();
|
|
2801
|
-
this.bus.clear();
|
|
2802
|
-
this.setStatus("disposed");
|
|
2803
|
-
}
|
|
2804
|
-
async createSession(body) {
|
|
2805
|
-
const manager = this.sessions;
|
|
2806
|
-
if (!manager) {
|
|
2807
|
-
return err(
|
|
2808
|
-
callpadError.precondition(
|
|
2809
|
-
"callpad.not_connected",
|
|
2810
|
-
"Client not connected"
|
|
2811
|
-
)
|
|
2812
|
-
);
|
|
2813
|
-
}
|
|
2814
|
-
return manager.create(body);
|
|
2815
|
-
}
|
|
2816
|
-
async use(plugin) {
|
|
2817
|
-
const pulse = this.pulseTransport;
|
|
2818
|
-
const sessions = this.sessions;
|
|
2819
|
-
const invites = this.invites;
|
|
2820
|
-
const presence = this.presence;
|
|
2821
|
-
if (!pulse || !sessions || !invites || !presence) {
|
|
2822
|
-
return err(
|
|
2823
|
-
callpadError.precondition(
|
|
2824
|
-
"callpad.not_connected",
|
|
2825
|
-
"Plugins require connect() first"
|
|
2826
|
-
)
|
|
2827
|
-
);
|
|
2828
|
-
}
|
|
2829
|
-
const ctx = {
|
|
2830
|
-
logger: this.logger.child({ plugin: plugin.name }),
|
|
2831
|
-
pulse,
|
|
2832
|
-
sessions,
|
|
2833
|
-
invites,
|
|
2834
|
-
presence,
|
|
2835
|
-
registerSessionCommand: (cmd) => this.registerSessionCommand(cmd),
|
|
2836
|
-
onSessionCreated: (handler) => this.bus.on("session.added", ({ session }) => handler(session)),
|
|
2837
|
-
onSessionDisposed: (handler) => this.bus.on("session.removed", ({ sessionId }) => handler(sessionId))
|
|
2838
|
-
};
|
|
2839
|
-
try {
|
|
2840
|
-
await this.pluginHost.register(plugin, ctx);
|
|
2841
|
-
return ok(void 0);
|
|
2842
|
-
} catch (cause) {
|
|
2843
|
-
return err(
|
|
2844
|
-
callpadError.internal(
|
|
2845
|
-
"callpad.plugin_install_failed",
|
|
2846
|
-
`Plugin "${plugin.name}" failed to install`,
|
|
2847
|
-
{ cause: cause instanceof Error ? cause : void 0 }
|
|
2848
|
-
)
|
|
2849
|
-
);
|
|
2850
|
-
}
|
|
2851
|
-
}
|
|
2852
|
-
configureApiClient() {
|
|
2853
|
-
const baseUrl = this.config.apiBaseUrl;
|
|
2854
|
-
const auth = this.config.auth.getAccessToken;
|
|
2855
|
-
const retryingFetch = makeRetryingFetch((request) => fetch(request), {
|
|
2856
|
-
maxAttempts: 3,
|
|
2857
|
-
initialDelayMs: 300
|
|
2858
|
-
});
|
|
2859
|
-
client.setConfig({
|
|
2860
|
-
baseUrl,
|
|
2861
|
-
auth: async () => auth(),
|
|
2862
|
-
fetch: retryingFetch
|
|
2863
|
-
});
|
|
2864
|
-
if (this.responseInterceptorId !== null) {
|
|
2865
|
-
client.interceptors.response.eject(this.responseInterceptorId);
|
|
2866
|
-
}
|
|
2867
|
-
let unauthorizedFired = false;
|
|
2868
|
-
this.responseInterceptorId = client.interceptors.response.use(
|
|
2869
|
-
(response) => {
|
|
2870
|
-
if (response.status === 401) {
|
|
2871
|
-
if (!unauthorizedFired) {
|
|
2872
|
-
unauthorizedFired = true;
|
|
2873
|
-
this.config.auth.onUnauthorized?.();
|
|
2874
|
-
}
|
|
2875
|
-
} else if (unauthorizedFired) {
|
|
2876
|
-
unauthorizedFired = false;
|
|
2877
|
-
}
|
|
2878
|
-
return response;
|
|
2879
|
-
}
|
|
2880
|
-
);
|
|
2881
|
-
}
|
|
2882
|
-
async fetchPulseGrant() {
|
|
2883
|
-
return apiCall(
|
|
2884
|
-
() => getApiV1PulseGrants({
|
|
2885
|
-
query: { vendor: this.config.vendor }
|
|
2886
|
-
})
|
|
2887
|
-
);
|
|
2888
|
-
}
|
|
2889
|
-
setStatus(next) {
|
|
2890
|
-
if (next === this.status) {
|
|
2891
|
-
return;
|
|
2892
|
-
}
|
|
2893
|
-
const previous = this.status;
|
|
2894
|
-
this.status = next;
|
|
2895
|
-
this.bus.emit("status.changed", { status: next, previous });
|
|
2896
|
-
}
|
|
2897
|
-
};
|
|
2898
|
-
function createCallpadClient(config) {
|
|
2899
|
-
return new CallpadClient(config);
|
|
2900
|
-
}
|
|
2901
|
-
|
|
2902
|
-
exports.CallpadClient = CallpadClient;
|
|
2903
|
-
exports.Invite = Invite;
|
|
2904
|
-
exports.InviteManager = InviteManager;
|
|
2905
|
-
exports.PresenceManager = PresenceManager;
|
|
2906
|
-
exports.Session = Session;
|
|
2907
|
-
exports.SessionManager = SessionManager;
|
|
2908
|
-
exports.callpadError = callpadError;
|
|
2909
|
-
exports.createCallpadClient = createCallpadClient;
|
|
2910
|
-
exports.err = err;
|
|
2911
|
-
exports.isErr = isErr;
|
|
2912
|
-
exports.isOk = isOk;
|
|
2913
|
-
exports.noopLogger = noopLogger;
|
|
2914
|
-
exports.ok = ok;
|
|
2915
|
-
exports.unwrap = unwrap;
|
|
2916
|
-
//# sourceMappingURL=index.cjs.map
|
|
2917
|
-
//# sourceMappingURL=index.cjs.map
|