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