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