farvex 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +150 -224
- package/dist/index.cjs +652 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +652 -61
- package/dist/index.js.map +1 -1
- package/dist/livekit/index.cjs +43 -1
- package/dist/livekit/index.cjs.map +1 -1
- package/dist/livekit/index.d.cts +18 -0
- package/dist/livekit/index.d.ts +18 -0
- package/dist/livekit/index.js +46 -0
- package/dist/livekit/index.js.map +1 -1
- package/dist/react/index.cjs +17 -2
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +11 -8
- package/dist/react/index.d.ts +11 -8
- package/dist/react/index.js +16 -3
- package/dist/react/index.js.map +1 -1
- package/dist/{types-DhJEeeui.d.cts → types-BjVaSMZ6.d.cts} +68 -5
- package/dist/{types-DhJEeeui.d.ts → types-BjVaSMZ6.d.ts} +68 -5
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parsePhoneNumberFromString } from 'libphonenumber-js';
|
|
1
2
|
import { Centrifuge, UnauthorizedError } from 'centrifuge';
|
|
2
3
|
|
|
3
4
|
// src/api/generated/core/bodySerializer.gen.ts
|
|
@@ -802,7 +803,7 @@ var apiClient = (config) => {
|
|
|
802
803
|
var unwrap = async (result, auth) => {
|
|
803
804
|
const response = await result;
|
|
804
805
|
if (response.error !== void 0) {
|
|
805
|
-
if (response.response?.status === 401) {
|
|
806
|
+
if (response.response?.status === 401 || response.response?.status === 403) {
|
|
806
807
|
await auth?.onUnauthorized?.();
|
|
807
808
|
}
|
|
808
809
|
throw errorFrom(response.error, response.response?.status);
|
|
@@ -941,9 +942,23 @@ var createEmitter = () => {
|
|
|
941
942
|
emit
|
|
942
943
|
};
|
|
943
944
|
};
|
|
944
|
-
var
|
|
945
|
+
var normalizeE164Phone = (phone, defaultCountry = "NG") => {
|
|
946
|
+
const trimmed = phone.trim();
|
|
947
|
+
const parsed = parsePhoneNumberFromString(trimmed);
|
|
948
|
+
if (parsed?.isValid() && parsed.country) {
|
|
949
|
+
return parsed.number;
|
|
950
|
+
}
|
|
951
|
+
const fallback = parsePhoneNumberFromString(trimmed, defaultCountry);
|
|
952
|
+
if (fallback?.isValid()) {
|
|
953
|
+
return fallback.number;
|
|
954
|
+
}
|
|
955
|
+
throw new Error("Enter a valid phone number");
|
|
956
|
+
};
|
|
957
|
+
var createRealtime = (client2, auth, store, emitter, recover) => {
|
|
945
958
|
let rt = null;
|
|
959
|
+
let connectPromise = null;
|
|
946
960
|
let disposed = false;
|
|
961
|
+
let attempt = 0;
|
|
947
962
|
const fetchToken = async () => unwrap(getRealtimeToken({ client: client2 }), auth);
|
|
948
963
|
const refreshToken = async () => {
|
|
949
964
|
try {
|
|
@@ -980,6 +995,8 @@ var createRealtime = (client2, auth, store, emitter) => {
|
|
|
980
995
|
emitter.emit("status", status);
|
|
981
996
|
};
|
|
982
997
|
const disconnect = async () => {
|
|
998
|
+
attempt += 1;
|
|
999
|
+
connectPromise = null;
|
|
983
1000
|
rt?.disconnect();
|
|
984
1001
|
rt = null;
|
|
985
1002
|
if (!disposed) {
|
|
@@ -988,33 +1005,50 @@ var createRealtime = (client2, auth, store, emitter) => {
|
|
|
988
1005
|
};
|
|
989
1006
|
return {
|
|
990
1007
|
connect: async () => {
|
|
1008
|
+
if (connectPromise) {
|
|
1009
|
+
return connectPromise;
|
|
1010
|
+
}
|
|
991
1011
|
if (rt) {
|
|
992
1012
|
return;
|
|
993
1013
|
}
|
|
994
1014
|
disposed = false;
|
|
995
|
-
|
|
996
|
-
|
|
1015
|
+
const currentAttempt = ++attempt;
|
|
1016
|
+
const promise = (async () => {
|
|
1017
|
+
setStatus("connecting");
|
|
997
1018
|
const first = await fetchToken();
|
|
998
|
-
|
|
1019
|
+
if (disposed || currentAttempt !== attempt) {
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
const next = new Centrifuge(first.url, {
|
|
999
1023
|
token: first.token,
|
|
1000
1024
|
getToken: refreshToken
|
|
1001
1025
|
});
|
|
1002
|
-
rt
|
|
1003
|
-
|
|
1004
|
-
|
|
1026
|
+
rt = next;
|
|
1027
|
+
next.on("connecting", () => {
|
|
1028
|
+
const status = store.getStatus() === "ready" ? "reconnecting" : "connecting";
|
|
1029
|
+
setStatus(status);
|
|
1005
1030
|
});
|
|
1006
|
-
|
|
1031
|
+
next.on("connected", () => {
|
|
1032
|
+
const shouldRecover = store.getStatus() === "reconnecting" || store.getStatus() === "offline";
|
|
1007
1033
|
setStatus("ready");
|
|
1034
|
+
if (shouldRecover && recover) {
|
|
1035
|
+
void recover().catch((err) => {
|
|
1036
|
+
emitter.emit(
|
|
1037
|
+
"error",
|
|
1038
|
+
err instanceof Error ? err : new Error("Realtime recovery failed")
|
|
1039
|
+
);
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1008
1042
|
});
|
|
1009
|
-
|
|
1043
|
+
next.on("disconnected", () => {
|
|
1010
1044
|
if (!disposed) {
|
|
1011
1045
|
setStatus("offline");
|
|
1012
1046
|
}
|
|
1013
1047
|
});
|
|
1014
|
-
|
|
1048
|
+
next.on("error", (ctx) => {
|
|
1015
1049
|
emitter.emit("error", new Error(ctx.error.message));
|
|
1016
1050
|
});
|
|
1017
|
-
|
|
1051
|
+
next.on("publication", (ctx) => {
|
|
1018
1052
|
try {
|
|
1019
1053
|
const message = parseMessage(ctx.data);
|
|
1020
1054
|
if (message) {
|
|
@@ -1024,16 +1058,34 @@ var createRealtime = (client2, auth, store, emitter) => {
|
|
|
1024
1058
|
emitter.emit("error", err instanceof Error ? err : new Error("Realtime event failed"));
|
|
1025
1059
|
}
|
|
1026
1060
|
});
|
|
1027
|
-
|
|
1028
|
-
await
|
|
1061
|
+
next.connect();
|
|
1062
|
+
await next.ready();
|
|
1063
|
+
if (disposed || currentAttempt !== attempt) {
|
|
1064
|
+
next.disconnect();
|
|
1065
|
+
if (rt === next) {
|
|
1066
|
+
rt = null;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
})();
|
|
1070
|
+
connectPromise = promise;
|
|
1071
|
+
try {
|
|
1072
|
+
await promise;
|
|
1029
1073
|
} catch (err) {
|
|
1030
|
-
|
|
1074
|
+
if (currentAttempt === attempt) {
|
|
1075
|
+
await disconnect();
|
|
1076
|
+
}
|
|
1031
1077
|
throw err;
|
|
1078
|
+
} finally {
|
|
1079
|
+
if (connectPromise === promise) {
|
|
1080
|
+
connectPromise = null;
|
|
1081
|
+
}
|
|
1032
1082
|
}
|
|
1033
1083
|
},
|
|
1034
1084
|
disconnect,
|
|
1035
1085
|
dispose: async () => {
|
|
1036
1086
|
disposed = true;
|
|
1087
|
+
attempt += 1;
|
|
1088
|
+
connectPromise = null;
|
|
1037
1089
|
rt?.disconnect();
|
|
1038
1090
|
rt = null;
|
|
1039
1091
|
setStatus("disposed");
|
|
@@ -1045,24 +1097,453 @@ var parseMessage = (value) => {
|
|
|
1045
1097
|
return null;
|
|
1046
1098
|
}
|
|
1047
1099
|
const message = value;
|
|
1048
|
-
if (message.event === "session.upsert" && message.data) {
|
|
1049
|
-
return message;
|
|
1100
|
+
if (message.event === "session.upsert" && isVoiceSession(message.data)) {
|
|
1101
|
+
return { event: "session.upsert", data: message.data };
|
|
1050
1102
|
}
|
|
1051
|
-
if (message.event === "session.remove" && message.data) {
|
|
1052
|
-
return message;
|
|
1103
|
+
if (message.event === "session.remove" && isRemovePayload(message.data)) {
|
|
1104
|
+
return { event: "session.remove", data: message.data };
|
|
1053
1105
|
}
|
|
1054
1106
|
return null;
|
|
1055
1107
|
};
|
|
1108
|
+
var isVoiceSession = (value) => {
|
|
1109
|
+
if (!value || typeof value !== "object") {
|
|
1110
|
+
return false;
|
|
1111
|
+
}
|
|
1112
|
+
const session = value;
|
|
1113
|
+
return typeof session.id === "string" && typeof session.vendor === "string" && typeof session.version === "number" && (session.state === "ringing" || session.state === "active" || session.state === "ended") && Array.isArray(session.participants);
|
|
1114
|
+
};
|
|
1115
|
+
var isRemovePayload = (value) => {
|
|
1116
|
+
if (!value || typeof value !== "object") {
|
|
1117
|
+
return false;
|
|
1118
|
+
}
|
|
1119
|
+
const payload = value;
|
|
1120
|
+
return typeof payload.id === "string" && (payload.vendor === void 0 || typeof payload.vendor === "string") && (payload.version === void 0 || typeof payload.version === "number");
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
// src/core/session.ts
|
|
1124
|
+
var createCurrentSessionController = (deps) => {
|
|
1125
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
1126
|
+
const cleanup = [];
|
|
1127
|
+
let current = null;
|
|
1128
|
+
let pending = null;
|
|
1129
|
+
let op = 0;
|
|
1130
|
+
let mediaConnected = false;
|
|
1131
|
+
let snapshot = {
|
|
1132
|
+
current,
|
|
1133
|
+
incoming: deps.store.invites(),
|
|
1134
|
+
busy: false
|
|
1135
|
+
};
|
|
1136
|
+
const publish = () => {
|
|
1137
|
+
const next = {
|
|
1138
|
+
current,
|
|
1139
|
+
incoming: deps.store.invites(),
|
|
1140
|
+
busy: pending !== null || isBusy(current)
|
|
1141
|
+
};
|
|
1142
|
+
if (snapshot.current === next.current && snapshot.incoming === next.incoming && snapshot.busy === next.busy) {
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
snapshot = next;
|
|
1146
|
+
for (const fn of subscribers) {
|
|
1147
|
+
fn();
|
|
1148
|
+
}
|
|
1149
|
+
deps.emitter.emit("session.current.changed", snapshot);
|
|
1150
|
+
};
|
|
1151
|
+
const commit = (next) => {
|
|
1152
|
+
const prev = current;
|
|
1153
|
+
current = next;
|
|
1154
|
+
publish();
|
|
1155
|
+
if (!next) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
if (!prev || prev.sessionId !== next.sessionId) {
|
|
1159
|
+
deps.emitter.emit("session.current.started", next);
|
|
1160
|
+
}
|
|
1161
|
+
if (prev?.phase !== "active" && next.phase === "active") {
|
|
1162
|
+
deps.emitter.emit("session.current.connected", next);
|
|
1163
|
+
}
|
|
1164
|
+
if (prev?.phase !== "ended" && next.phase === "ended") {
|
|
1165
|
+
deps.emitter.emit("session.current.ended", next);
|
|
1166
|
+
}
|
|
1167
|
+
if (prev?.phase !== "failed" && next.phase === "failed" && next.error) {
|
|
1168
|
+
deps.emitter.emit("session.current.failed", { session: next, error: next.error });
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
const commitFailed = (session, err) => {
|
|
1172
|
+
const error = toCallpadError(err);
|
|
1173
|
+
if (session) {
|
|
1174
|
+
commit(
|
|
1175
|
+
fromSession(session, {
|
|
1176
|
+
phase: "failed",
|
|
1177
|
+
join: null,
|
|
1178
|
+
participantId: null,
|
|
1179
|
+
startedBy: current?.startedBy ?? "join",
|
|
1180
|
+
error
|
|
1181
|
+
})
|
|
1182
|
+
);
|
|
1183
|
+
} else {
|
|
1184
|
+
deps.emitter.emit("session.current.failed", { session: current, error });
|
|
1185
|
+
publish();
|
|
1186
|
+
}
|
|
1187
|
+
return error;
|
|
1188
|
+
};
|
|
1189
|
+
const nextOp = () => {
|
|
1190
|
+
op += 1;
|
|
1191
|
+
return op;
|
|
1192
|
+
};
|
|
1193
|
+
const run = (kind, task) => {
|
|
1194
|
+
if (pending) {
|
|
1195
|
+
if (kind === "end" && pending.kind === "end") {
|
|
1196
|
+
return pending.promise;
|
|
1197
|
+
}
|
|
1198
|
+
return Promise.reject(busyError());
|
|
1199
|
+
}
|
|
1200
|
+
const id = nextOp();
|
|
1201
|
+
const promise = task(id).finally(() => {
|
|
1202
|
+
if (pending?.op === id) {
|
|
1203
|
+
pending = null;
|
|
1204
|
+
publish();
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
pending = { kind, op: id, promise };
|
|
1208
|
+
publish();
|
|
1209
|
+
return promise;
|
|
1210
|
+
};
|
|
1211
|
+
const assertFresh = (id) => {
|
|
1212
|
+
if (id !== op) {
|
|
1213
|
+
throw new CallpadError("session.command_stale", "Session command was superseded");
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
const canReplaceCurrent = (replaceCurrent) => {
|
|
1217
|
+
return replaceCurrent === true || !isBusy(current);
|
|
1218
|
+
};
|
|
1219
|
+
const reconcile = () => {
|
|
1220
|
+
if (!current) {
|
|
1221
|
+
publish();
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
const session = deps.store.get(current.sessionId);
|
|
1225
|
+
if (!session) {
|
|
1226
|
+
mediaConnected = false;
|
|
1227
|
+
commit({
|
|
1228
|
+
...current,
|
|
1229
|
+
phase: "ended",
|
|
1230
|
+
session: null,
|
|
1231
|
+
join: null,
|
|
1232
|
+
endedAt: current.endedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1233
|
+
});
|
|
1234
|
+
return;
|
|
1235
|
+
}
|
|
1236
|
+
const next = reconcileCurrent(current, session, mediaConnected);
|
|
1237
|
+
if (next !== current) {
|
|
1238
|
+
if (isTerminal(next.phase)) {
|
|
1239
|
+
mediaConnected = false;
|
|
1240
|
+
}
|
|
1241
|
+
commit(next);
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
publish();
|
|
1245
|
+
};
|
|
1246
|
+
cleanup.push(deps.store.subscribe("sessions", reconcile));
|
|
1247
|
+
cleanup.push(deps.store.subscribe("invites", publish));
|
|
1248
|
+
const start = (input, options = {}) => {
|
|
1249
|
+
const behavior = options.behavior ?? "rejectWhileBusy";
|
|
1250
|
+
if (behavior !== "allowParallel" && isBusy(current)) {
|
|
1251
|
+
if (behavior === "focusExisting") {
|
|
1252
|
+
const existing = findTargetSession(deps.store.list(), input.target);
|
|
1253
|
+
if (existing) {
|
|
1254
|
+
return join(existing.id, { replaceCurrent: true });
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
return Promise.reject(busyError());
|
|
1258
|
+
}
|
|
1259
|
+
return run("start", async (id) => {
|
|
1260
|
+
try {
|
|
1261
|
+
const started = await deps.start(input);
|
|
1262
|
+
assertFresh(id);
|
|
1263
|
+
const next = fromStarted(started, "start", options.media);
|
|
1264
|
+
mediaConnected = false;
|
|
1265
|
+
commit(next);
|
|
1266
|
+
if (next.phase === "failed" && next.error) {
|
|
1267
|
+
throw next.error;
|
|
1268
|
+
}
|
|
1269
|
+
return next;
|
|
1270
|
+
} catch (err) {
|
|
1271
|
+
if (shouldRethrowCommandError(err)) {
|
|
1272
|
+
throw err;
|
|
1273
|
+
}
|
|
1274
|
+
throw commitFailed(null, err);
|
|
1275
|
+
}
|
|
1276
|
+
});
|
|
1277
|
+
};
|
|
1278
|
+
const accept = (input, options = {}) => {
|
|
1279
|
+
if (!canReplaceCurrent(options.replaceCurrent)) {
|
|
1280
|
+
return Promise.reject(busyError());
|
|
1281
|
+
}
|
|
1282
|
+
return run("accept", async (id) => {
|
|
1283
|
+
try {
|
|
1284
|
+
const started = await deps.accept(input);
|
|
1285
|
+
assertFresh(id);
|
|
1286
|
+
const next = fromStarted(started, "accept", options.media);
|
|
1287
|
+
mediaConnected = false;
|
|
1288
|
+
commit(next);
|
|
1289
|
+
if (next.phase === "failed" && next.error) {
|
|
1290
|
+
throw next.error;
|
|
1291
|
+
}
|
|
1292
|
+
return next;
|
|
1293
|
+
} catch (err) {
|
|
1294
|
+
if (shouldRethrowCommandError(err)) {
|
|
1295
|
+
throw err;
|
|
1296
|
+
}
|
|
1297
|
+
throw commitFailed(deps.store.get(input.sessionId), err);
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
};
|
|
1301
|
+
const join = (sessionId, options = {}) => {
|
|
1302
|
+
if (!canReplaceCurrent(options.replaceCurrent)) {
|
|
1303
|
+
return Promise.reject(busyError());
|
|
1304
|
+
}
|
|
1305
|
+
const session = deps.store.get(sessionId);
|
|
1306
|
+
if (!session) {
|
|
1307
|
+
return Promise.reject(new CallpadError("session.not_found", "Session was not found"));
|
|
1308
|
+
}
|
|
1309
|
+
return run("join", async (id) => {
|
|
1310
|
+
try {
|
|
1311
|
+
const grant = await deps.join(sessionId);
|
|
1312
|
+
assertFresh(id);
|
|
1313
|
+
const latest = deps.store.get(sessionId) ?? session;
|
|
1314
|
+
const next = fromSession(latest, {
|
|
1315
|
+
phase: latest.state === "active" ? "active" : "connecting",
|
|
1316
|
+
join: grant,
|
|
1317
|
+
participantId: grant.participantId,
|
|
1318
|
+
startedBy: "join",
|
|
1319
|
+
error: null
|
|
1320
|
+
});
|
|
1321
|
+
mediaConnected = next.phase === "active";
|
|
1322
|
+
commit(next);
|
|
1323
|
+
return next;
|
|
1324
|
+
} catch (err) {
|
|
1325
|
+
if (shouldRethrowCommandError(err)) {
|
|
1326
|
+
throw err;
|
|
1327
|
+
}
|
|
1328
|
+
throw commitFailed(session, err);
|
|
1329
|
+
}
|
|
1330
|
+
});
|
|
1331
|
+
};
|
|
1332
|
+
const end = async () => {
|
|
1333
|
+
const target = current;
|
|
1334
|
+
if (!target || isTerminal(target.phase)) {
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
await run("end", async (id) => {
|
|
1338
|
+
const session = deps.store.get(target.sessionId);
|
|
1339
|
+
commit({ ...target, phase: "ending" });
|
|
1340
|
+
try {
|
|
1341
|
+
if (session && deps.end && deps.store.can(session, "end")) {
|
|
1342
|
+
await deps.end(target.sessionId);
|
|
1343
|
+
} else {
|
|
1344
|
+
await deps.leave(target.sessionId);
|
|
1345
|
+
}
|
|
1346
|
+
assertFresh(id);
|
|
1347
|
+
mediaConnected = false;
|
|
1348
|
+
const ended = deps.store.get(target.sessionId);
|
|
1349
|
+
commit({
|
|
1350
|
+
...target,
|
|
1351
|
+
phase: "ended",
|
|
1352
|
+
session: ended,
|
|
1353
|
+
join: null,
|
|
1354
|
+
endedAt: ended?.endedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
1355
|
+
});
|
|
1356
|
+
} catch (err) {
|
|
1357
|
+
if (shouldRethrowCommandError(err)) {
|
|
1358
|
+
throw err;
|
|
1359
|
+
}
|
|
1360
|
+
throw commitFailed(session, err);
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
};
|
|
1364
|
+
const clear = () => {
|
|
1365
|
+
nextOp();
|
|
1366
|
+
pending = null;
|
|
1367
|
+
mediaConnected = false;
|
|
1368
|
+
commit(null);
|
|
1369
|
+
};
|
|
1370
|
+
const mediaConnectedFor = (sessionId) => {
|
|
1371
|
+
if (!current || sessionId && current.sessionId !== sessionId || isTerminal(current.phase)) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
mediaConnected = true;
|
|
1375
|
+
const session = deps.store.get(current.sessionId);
|
|
1376
|
+
commit({
|
|
1377
|
+
...current,
|
|
1378
|
+
phase: "active",
|
|
1379
|
+
session,
|
|
1380
|
+
answeredAt: session?.answeredAt ?? current.answeredAt
|
|
1381
|
+
});
|
|
1382
|
+
};
|
|
1383
|
+
const mediaDisconnectedFor = (sessionId) => {
|
|
1384
|
+
if (!current || sessionId && current.sessionId !== sessionId || isTerminal(current.phase)) {
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
mediaConnected = false;
|
|
1388
|
+
const session = deps.store.get(current.sessionId);
|
|
1389
|
+
if (session?.state === "ended") {
|
|
1390
|
+
reconcile();
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
commit({
|
|
1394
|
+
...current,
|
|
1395
|
+
phase: current.join ? "connecting" : current.direction === "inbound" ? "incoming" : "outgoing",
|
|
1396
|
+
session
|
|
1397
|
+
});
|
|
1398
|
+
};
|
|
1399
|
+
const mediaFailedFor = (error, sessionId) => {
|
|
1400
|
+
if (!current || sessionId && current.sessionId !== sessionId || isTerminal(current.phase)) {
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
mediaConnected = false;
|
|
1404
|
+
commit({
|
|
1405
|
+
...current,
|
|
1406
|
+
phase: "failed",
|
|
1407
|
+
join: null,
|
|
1408
|
+
error: toCallpadError(error, "session.media_failed")
|
|
1409
|
+
});
|
|
1410
|
+
};
|
|
1411
|
+
return {
|
|
1412
|
+
get: () => snapshot,
|
|
1413
|
+
start,
|
|
1414
|
+
accept,
|
|
1415
|
+
join,
|
|
1416
|
+
end,
|
|
1417
|
+
clear,
|
|
1418
|
+
mediaConnected: mediaConnectedFor,
|
|
1419
|
+
mediaDisconnected: mediaDisconnectedFor,
|
|
1420
|
+
mediaFailed: mediaFailedFor,
|
|
1421
|
+
subscribe: (fn) => {
|
|
1422
|
+
subscribers.add(fn);
|
|
1423
|
+
return () => {
|
|
1424
|
+
subscribers.delete(fn);
|
|
1425
|
+
};
|
|
1426
|
+
},
|
|
1427
|
+
dispose: () => {
|
|
1428
|
+
for (const unsubscribe of cleanup) {
|
|
1429
|
+
unsubscribe();
|
|
1430
|
+
}
|
|
1431
|
+
subscribers.clear();
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
};
|
|
1435
|
+
var fromStarted = (started, startedBy, media = "required") => {
|
|
1436
|
+
if (!started.join && media === "required") {
|
|
1437
|
+
return fromSession(started.session, {
|
|
1438
|
+
phase: "failed",
|
|
1439
|
+
join: null,
|
|
1440
|
+
participantId: null,
|
|
1441
|
+
startedBy,
|
|
1442
|
+
error: new CallpadError(
|
|
1443
|
+
"session.join_unavailable",
|
|
1444
|
+
"Session did not include a browser media join grant"
|
|
1445
|
+
)
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
const phase = started.join ? started.session.state === "active" ? "active" : "connecting" : started.session.direction === "inbound" ? "incoming" : "outgoing";
|
|
1449
|
+
return fromSession(started.session, {
|
|
1450
|
+
phase,
|
|
1451
|
+
join: started.join,
|
|
1452
|
+
participantId: started.join?.participantId ?? null,
|
|
1453
|
+
startedBy,
|
|
1454
|
+
error: null
|
|
1455
|
+
});
|
|
1456
|
+
};
|
|
1457
|
+
var fromSession = (session, values) => ({
|
|
1458
|
+
phase: values.phase,
|
|
1459
|
+
direction: session.direction,
|
|
1460
|
+
sessionId: session.id,
|
|
1461
|
+
participantId: values.participantId,
|
|
1462
|
+
session,
|
|
1463
|
+
join: values.join,
|
|
1464
|
+
startedBy: values.startedBy,
|
|
1465
|
+
error: values.error,
|
|
1466
|
+
createdAt: session.createdAt,
|
|
1467
|
+
answeredAt: session.answeredAt,
|
|
1468
|
+
endedAt: session.endedAt
|
|
1469
|
+
});
|
|
1470
|
+
var reconcileCurrent = (current, session, mediaConnected) => {
|
|
1471
|
+
if (session.state === "ended") {
|
|
1472
|
+
return {
|
|
1473
|
+
...current,
|
|
1474
|
+
phase: "ended",
|
|
1475
|
+
session,
|
|
1476
|
+
join: null,
|
|
1477
|
+
answeredAt: session.answeredAt,
|
|
1478
|
+
endedAt: session.endedAt ?? current.endedAt
|
|
1479
|
+
};
|
|
1480
|
+
}
|
|
1481
|
+
if (isTerminal(current.phase)) {
|
|
1482
|
+
return {
|
|
1483
|
+
...current,
|
|
1484
|
+
session,
|
|
1485
|
+
answeredAt: session.answeredAt,
|
|
1486
|
+
endedAt: session.endedAt
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
const phase = mediaConnected || session.state === "active" ? "active" : current.join ? "connecting" : current.phase === "ending" ? "ending" : session.direction === "inbound" ? "incoming" : "outgoing";
|
|
1490
|
+
if (current.phase === phase && current.session === session && current.answeredAt === session.answeredAt && current.endedAt === session.endedAt) {
|
|
1491
|
+
return current;
|
|
1492
|
+
}
|
|
1493
|
+
return {
|
|
1494
|
+
...current,
|
|
1495
|
+
phase,
|
|
1496
|
+
session,
|
|
1497
|
+
answeredAt: session.answeredAt,
|
|
1498
|
+
endedAt: session.endedAt
|
|
1499
|
+
};
|
|
1500
|
+
};
|
|
1501
|
+
var findTargetSession = (sessions, target) => {
|
|
1502
|
+
const normalized = normalizeTarget(target);
|
|
1503
|
+
return sessions.find(
|
|
1504
|
+
(session) => session.state !== "ended" && session.participants.some((participant) => {
|
|
1505
|
+
if (normalized.type === "vendor_user") {
|
|
1506
|
+
return participant.kind === "vendor_user" && participant.userId === normalized.userId;
|
|
1507
|
+
}
|
|
1508
|
+
if (normalized.type === "customer") {
|
|
1509
|
+
return participant.kind === "customer" && participant.userId === normalized.userId;
|
|
1510
|
+
}
|
|
1511
|
+
if (normalized.type === "contact") {
|
|
1512
|
+
return participant.contactId === normalized.contactId;
|
|
1513
|
+
}
|
|
1514
|
+
return participant.phone === normalized.phone;
|
|
1515
|
+
})
|
|
1516
|
+
) ?? null;
|
|
1517
|
+
};
|
|
1518
|
+
var normalizeTarget = (target) => {
|
|
1519
|
+
if (target.type === "phone") {
|
|
1520
|
+
return { ...target, phone: normalizeE164Phone(target.phone) };
|
|
1521
|
+
}
|
|
1522
|
+
return target;
|
|
1523
|
+
};
|
|
1524
|
+
var isBusy = (session) => session !== null && !isTerminal(session.phase);
|
|
1525
|
+
var isTerminal = (phase) => phase === "ended" || phase === "failed";
|
|
1526
|
+
var busyError = () => new CallpadError("session.busy", "A session is already active");
|
|
1527
|
+
var shouldRethrowCommandError = (err) => err instanceof CallpadError && (err.code === "session.join_unavailable" || err.code === "session.command_stale");
|
|
1528
|
+
var toCallpadError = (err, code = "session.failed") => {
|
|
1529
|
+
if (err instanceof CallpadError) {
|
|
1530
|
+
return err;
|
|
1531
|
+
}
|
|
1532
|
+
if (err instanceof Error) {
|
|
1533
|
+
return new CallpadError(code, err.message);
|
|
1534
|
+
}
|
|
1535
|
+
return new CallpadError(code, "Session command failed");
|
|
1536
|
+
};
|
|
1056
1537
|
|
|
1057
1538
|
// src/core/store.ts
|
|
1058
1539
|
var createSessionStore = (userId) => {
|
|
1059
1540
|
const sessions = /* @__PURE__ */ new Map();
|
|
1060
1541
|
const subscribers = /* @__PURE__ */ new Map();
|
|
1061
1542
|
let status = "idle";
|
|
1062
|
-
let activeId = null;
|
|
1063
1543
|
let listCache = [];
|
|
1064
1544
|
let invitesCache = [];
|
|
1065
1545
|
let inviteKey = "";
|
|
1546
|
+
let inviteExpiryTimer = null;
|
|
1066
1547
|
const emit = (topic) => {
|
|
1067
1548
|
const fns = subscribers.get(topic);
|
|
1068
1549
|
if (!fns) {
|
|
@@ -1090,18 +1571,11 @@ var createSessionStore = (userId) => {
|
|
|
1090
1571
|
listCache = Array.from(sessions.values()).sort(
|
|
1091
1572
|
(a, b) => b.createdAt.localeCompare(a.createdAt)
|
|
1092
1573
|
);
|
|
1093
|
-
if (activeId) {
|
|
1094
|
-
const active = sessions.get(activeId);
|
|
1095
|
-
if (!active || active.state === "ended") {
|
|
1096
|
-
activeId = null;
|
|
1097
|
-
}
|
|
1098
|
-
}
|
|
1099
|
-
if (!activeId) {
|
|
1100
|
-
activeId = listCache.find((session) => session.state !== "ended")?.id ?? null;
|
|
1101
|
-
}
|
|
1102
1574
|
};
|
|
1103
1575
|
const refreshInvites = () => {
|
|
1104
|
-
const
|
|
1576
|
+
const now = Date.now();
|
|
1577
|
+
const invites = listCache.map((session) => inviteFrom(session, userId, now)).filter((invite) => invite !== null);
|
|
1578
|
+
scheduleInviteExpiry(invites, now);
|
|
1105
1579
|
const nextKey = invites.map(
|
|
1106
1580
|
(invite) => `${invite.session.id}:${invite.participant.id}:${invite.participant.state}:${invite.participant.inviteExpiresAt ?? ""}`
|
|
1107
1581
|
).join("|");
|
|
@@ -1113,6 +1587,35 @@ var createSessionStore = (userId) => {
|
|
|
1113
1587
|
invitesCache = invites;
|
|
1114
1588
|
return true;
|
|
1115
1589
|
};
|
|
1590
|
+
const clearInviteExpiryTimer = () => {
|
|
1591
|
+
if (inviteExpiryTimer) {
|
|
1592
|
+
globalThis.clearTimeout(inviteExpiryTimer);
|
|
1593
|
+
inviteExpiryTimer = null;
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1596
|
+
const scheduleInviteExpiry = (invites, now) => {
|
|
1597
|
+
clearInviteExpiryTimer();
|
|
1598
|
+
const nextExpiry = invites.reduce((min, invite) => {
|
|
1599
|
+
const expiresAt = inviteExpiryMs(invite.participant);
|
|
1600
|
+
if (expiresAt === null) {
|
|
1601
|
+
return min;
|
|
1602
|
+
}
|
|
1603
|
+
return min === null ? expiresAt : Math.min(min, expiresAt);
|
|
1604
|
+
}, null);
|
|
1605
|
+
if (nextExpiry === null) {
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
inviteExpiryTimer = globalThis.setTimeout(
|
|
1609
|
+
() => {
|
|
1610
|
+
inviteExpiryTimer = null;
|
|
1611
|
+
if (refreshInvites()) {
|
|
1612
|
+
emit("invites");
|
|
1613
|
+
emit("sessions");
|
|
1614
|
+
}
|
|
1615
|
+
},
|
|
1616
|
+
Math.max(0, nextExpiry - now)
|
|
1617
|
+
);
|
|
1618
|
+
};
|
|
1116
1619
|
const notifySessionChange = (sessionId) => {
|
|
1117
1620
|
refresh();
|
|
1118
1621
|
const invitesChanged = refreshInvites();
|
|
@@ -1122,15 +1625,7 @@ var createSessionStore = (userId) => {
|
|
|
1122
1625
|
emit("invites");
|
|
1123
1626
|
}
|
|
1124
1627
|
};
|
|
1125
|
-
const get = (sessionId) =>
|
|
1126
|
-
if (sessionId) {
|
|
1127
|
-
return sessions.get(sessionId) ?? null;
|
|
1128
|
-
}
|
|
1129
|
-
if (!activeId) {
|
|
1130
|
-
return null;
|
|
1131
|
-
}
|
|
1132
|
-
return sessions.get(activeId) ?? null;
|
|
1133
|
-
};
|
|
1628
|
+
const get = (sessionId) => sessions.get(sessionId) ?? null;
|
|
1134
1629
|
const upsert = (session, mode = "event") => {
|
|
1135
1630
|
const prev = sessions.get(session.id);
|
|
1136
1631
|
const stale = prev ? mode === "command" ? session.version < prev.version : session.version <= prev.version : false;
|
|
@@ -1154,18 +1649,33 @@ var createSessionStore = (userId) => {
|
|
|
1154
1649
|
get,
|
|
1155
1650
|
invites: () => invitesCache,
|
|
1156
1651
|
invite: (sessionId) => invitesCache.find((invite) => invite.session.id === sessionId) ?? null,
|
|
1157
|
-
sync: (items) => {
|
|
1652
|
+
sync: (items, options) => {
|
|
1653
|
+
const changedIds = /* @__PURE__ */ new Set();
|
|
1158
1654
|
for (const session of items) {
|
|
1159
1655
|
const prev = sessions.get(session.id);
|
|
1160
1656
|
if (!prev || session.version >= prev.version) {
|
|
1161
1657
|
sessions.set(session.id, session);
|
|
1658
|
+
changedIds.add(session.id);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
const removedIds = [];
|
|
1662
|
+
if (options?.mode === "replaceVisible" && options.shouldReplace) {
|
|
1663
|
+
const visibleIds = new Set(items.map((session) => session.id));
|
|
1664
|
+
for (const session of sessions.values()) {
|
|
1665
|
+
if (!visibleIds.has(session.id) && options.shouldReplace(session)) {
|
|
1666
|
+
sessions.delete(session.id);
|
|
1667
|
+
removedIds.push(session.id);
|
|
1668
|
+
}
|
|
1162
1669
|
}
|
|
1163
1670
|
}
|
|
1164
1671
|
refresh();
|
|
1165
1672
|
const invitesChanged = refreshInvites();
|
|
1166
1673
|
emit("sessions");
|
|
1167
|
-
for (const
|
|
1168
|
-
emit(`session:${
|
|
1674
|
+
for (const sessionId of changedIds) {
|
|
1675
|
+
emit(`session:${sessionId}`);
|
|
1676
|
+
}
|
|
1677
|
+
for (const sessionId of removedIds) {
|
|
1678
|
+
emit(`session:${sessionId}`);
|
|
1169
1679
|
}
|
|
1170
1680
|
if (invitesChanged) {
|
|
1171
1681
|
emit("invites");
|
|
@@ -1199,13 +1709,17 @@ var createSessionStore = (userId) => {
|
|
|
1199
1709
|
return next;
|
|
1200
1710
|
},
|
|
1201
1711
|
can: (session, action) => can(session, userId, action),
|
|
1712
|
+
dispose: () => {
|
|
1713
|
+
clearInviteExpiryTimer();
|
|
1714
|
+
subscribers.clear();
|
|
1715
|
+
},
|
|
1202
1716
|
subscribe
|
|
1203
1717
|
};
|
|
1204
1718
|
};
|
|
1205
1719
|
var selfParticipant = (session, userId) => session.participants.find((participant) => participant.userId === userId) ?? null;
|
|
1206
|
-
var inviteFrom = (session, userId) => {
|
|
1720
|
+
var inviteFrom = (session, userId, now) => {
|
|
1207
1721
|
const participant = selfParticipant(session, userId);
|
|
1208
|
-
if (!participant ||
|
|
1722
|
+
if (!participant || session.state === "ended" || !isActiveInvite(participant, now)) {
|
|
1209
1723
|
return null;
|
|
1210
1724
|
}
|
|
1211
1725
|
return { session, participant };
|
|
@@ -1218,7 +1732,7 @@ var can = (session, userId, action) => {
|
|
|
1218
1732
|
switch (action) {
|
|
1219
1733
|
case "accept":
|
|
1220
1734
|
case "reject":
|
|
1221
|
-
return self
|
|
1735
|
+
return isActiveInvite(self);
|
|
1222
1736
|
case "join":
|
|
1223
1737
|
return self.transport === "webrtc" && (self.state === "accepted" || self.state === "joined");
|
|
1224
1738
|
case "leave":
|
|
@@ -1233,60 +1747,113 @@ var can = (session, userId, action) => {
|
|
|
1233
1747
|
return isHost(self) && session.recording.status === "recording";
|
|
1234
1748
|
}
|
|
1235
1749
|
};
|
|
1750
|
+
var isActiveInvite = (participant, now = Date.now()) => {
|
|
1751
|
+
const expiresAt = inviteExpiryMs(participant);
|
|
1752
|
+
return participant.state === "invited" && expiresAt !== null && expiresAt > now;
|
|
1753
|
+
};
|
|
1754
|
+
var inviteExpiryMs = (participant) => {
|
|
1755
|
+
if (!participant.inviteExpiresAt) {
|
|
1756
|
+
return null;
|
|
1757
|
+
}
|
|
1758
|
+
const expiresAt = Date.parse(participant.inviteExpiresAt);
|
|
1759
|
+
return Number.isFinite(expiresAt) ? expiresAt : null;
|
|
1760
|
+
};
|
|
1236
1761
|
var isHost = (participant) => participant.role === "host" && (participant.kind === "agent" || participant.kind === "vendor_user");
|
|
1237
1762
|
|
|
1238
1763
|
// src/core/client.ts
|
|
1239
1764
|
var createSessionClient = (config) => {
|
|
1240
1765
|
const core = createCore(config);
|
|
1766
|
+
const sessions = {
|
|
1767
|
+
...createCommonSessions(core),
|
|
1768
|
+
start: (input) => startSession(core, input.vendor, input.target)
|
|
1769
|
+
};
|
|
1770
|
+
const session = createCurrentSessionController({
|
|
1771
|
+
store: core.store,
|
|
1772
|
+
emitter: core.emitter,
|
|
1773
|
+
start: sessions.start,
|
|
1774
|
+
accept: sessions.accept,
|
|
1775
|
+
join: sessions.join,
|
|
1776
|
+
leave: sessions.leave
|
|
1777
|
+
});
|
|
1241
1778
|
return {
|
|
1242
1779
|
kind: "session",
|
|
1243
1780
|
get status() {
|
|
1244
1781
|
return core.store.getStatus();
|
|
1245
1782
|
},
|
|
1246
|
-
sessions
|
|
1247
|
-
...createCommonSessions(core),
|
|
1248
|
-
start: (input) => startSession(core, input.vendor, input.target)
|
|
1249
|
-
},
|
|
1783
|
+
sessions,
|
|
1250
1784
|
invites: {
|
|
1251
1785
|
list: core.store.invites,
|
|
1252
1786
|
get: core.store.invite
|
|
1253
1787
|
},
|
|
1788
|
+
session,
|
|
1254
1789
|
connect: core.connect,
|
|
1255
1790
|
disconnect: core.realtime.disconnect,
|
|
1256
|
-
dispose:
|
|
1791
|
+
dispose: async () => {
|
|
1792
|
+
session.dispose();
|
|
1793
|
+
await core.dispose();
|
|
1794
|
+
},
|
|
1257
1795
|
on: core.emitter.on,
|
|
1258
1796
|
subscribe: core.store.subscribe
|
|
1259
1797
|
};
|
|
1260
1798
|
};
|
|
1261
1799
|
var createHostClient = (config) => {
|
|
1262
1800
|
const core = createCore(config);
|
|
1801
|
+
const sessions = {
|
|
1802
|
+
...createCommonSessions(core),
|
|
1803
|
+
start: (input) => startSession(core, config.vendor, input.target)
|
|
1804
|
+
};
|
|
1805
|
+
const host = createHostControls(core);
|
|
1806
|
+
const session = createCurrentSessionController({
|
|
1807
|
+
store: core.store,
|
|
1808
|
+
emitter: core.emitter,
|
|
1809
|
+
start: sessions.start,
|
|
1810
|
+
accept: sessions.accept,
|
|
1811
|
+
join: sessions.join,
|
|
1812
|
+
leave: sessions.leave,
|
|
1813
|
+
end: host.end
|
|
1814
|
+
});
|
|
1263
1815
|
return {
|
|
1264
1816
|
kind: "host",
|
|
1265
1817
|
vendor: config.vendor,
|
|
1266
1818
|
get status() {
|
|
1267
1819
|
return core.store.getStatus();
|
|
1268
1820
|
},
|
|
1269
|
-
sessions
|
|
1270
|
-
...createCommonSessions(core),
|
|
1271
|
-
start: (input) => startSession(core, config.vendor, input.target)
|
|
1272
|
-
},
|
|
1821
|
+
sessions,
|
|
1273
1822
|
invites: {
|
|
1274
1823
|
list: core.store.invites,
|
|
1275
1824
|
get: core.store.invite
|
|
1276
1825
|
},
|
|
1277
|
-
|
|
1826
|
+
session,
|
|
1827
|
+
host,
|
|
1278
1828
|
connect: core.connect,
|
|
1279
1829
|
disconnect: core.realtime.disconnect,
|
|
1280
|
-
dispose:
|
|
1830
|
+
dispose: async () => {
|
|
1831
|
+
session.dispose();
|
|
1832
|
+
await core.dispose();
|
|
1833
|
+
},
|
|
1281
1834
|
on: core.emitter.on,
|
|
1282
1835
|
subscribe: core.store.subscribe
|
|
1283
1836
|
};
|
|
1284
1837
|
};
|
|
1838
|
+
var normalizePhoneTarget = (target) => {
|
|
1839
|
+
if (target.type === "phone") {
|
|
1840
|
+
return { ...target, phone: normalizeE164Phone(target.phone) };
|
|
1841
|
+
}
|
|
1842
|
+
return target;
|
|
1843
|
+
};
|
|
1285
1844
|
var createCore = (config) => {
|
|
1286
1845
|
const api = apiClient(config);
|
|
1287
1846
|
const store = createSessionStore(config.userId);
|
|
1288
1847
|
const emitter = createEmitter();
|
|
1289
|
-
const
|
|
1848
|
+
const syncActive = async () => {
|
|
1849
|
+
const query = { state: "active" };
|
|
1850
|
+
const response = await unwrap(listSessions({ client: api, query }), config.auth);
|
|
1851
|
+
store.sync(response.items, {
|
|
1852
|
+
mode: "replaceVisible",
|
|
1853
|
+
shouldReplace: (session) => matchesVisibleQuery(session, query)
|
|
1854
|
+
});
|
|
1855
|
+
};
|
|
1856
|
+
const realtime = createRealtime(api, config.auth, store, emitter, syncActive);
|
|
1290
1857
|
const applySession = (session, mode = "event") => {
|
|
1291
1858
|
const change = store.upsert(session, mode);
|
|
1292
1859
|
if (change === "added") {
|
|
@@ -1316,6 +1883,10 @@ var createCore = (config) => {
|
|
|
1316
1883
|
throw err;
|
|
1317
1884
|
}
|
|
1318
1885
|
};
|
|
1886
|
+
const dispose = async () => {
|
|
1887
|
+
await realtime.dispose();
|
|
1888
|
+
store.dispose();
|
|
1889
|
+
};
|
|
1319
1890
|
return {
|
|
1320
1891
|
api,
|
|
1321
1892
|
auth: config.auth,
|
|
@@ -1323,6 +1894,7 @@ var createCore = (config) => {
|
|
|
1323
1894
|
emitter,
|
|
1324
1895
|
realtime,
|
|
1325
1896
|
connect,
|
|
1897
|
+
dispose,
|
|
1326
1898
|
applySession,
|
|
1327
1899
|
applyStarted,
|
|
1328
1900
|
patchRecording
|
|
@@ -1331,9 +1903,12 @@ var createCore = (config) => {
|
|
|
1331
1903
|
var createCommonSessions = (core) => ({
|
|
1332
1904
|
list: core.store.list,
|
|
1333
1905
|
get: core.store.get,
|
|
1334
|
-
sync: async (query) => {
|
|
1906
|
+
sync: async (query, options) => {
|
|
1335
1907
|
const response = await unwrap(listSessions({ client: core.api, query }), core.auth);
|
|
1336
|
-
core.store.sync(response.items
|
|
1908
|
+
core.store.sync(response.items, {
|
|
1909
|
+
mode: options?.mode,
|
|
1910
|
+
shouldReplace: options?.mode === "replaceVisible" && canReplaceVisibleQuery(query) ? (session) => matchesVisibleQuery(session, query) : void 0
|
|
1911
|
+
});
|
|
1337
1912
|
return core.store.list();
|
|
1338
1913
|
},
|
|
1339
1914
|
join: (sessionId) => unwrap(createSessionToken({ client: core.api, path: { sessionId } }), core.auth),
|
|
@@ -1381,7 +1956,7 @@ var createHostControls = (core) => ({
|
|
|
1381
1956
|
addSessionParticipant({
|
|
1382
1957
|
client: core.api,
|
|
1383
1958
|
path: { sessionId: input.sessionId },
|
|
1384
|
-
body: { target: input.target }
|
|
1959
|
+
body: { target: normalizePhoneTarget(input.target) }
|
|
1385
1960
|
}),
|
|
1386
1961
|
core.auth
|
|
1387
1962
|
),
|
|
@@ -1412,12 +1987,28 @@ var startSession = async (core, vendor, target) => core.applyStarted(
|
|
|
1412
1987
|
createSession({
|
|
1413
1988
|
client: core.api,
|
|
1414
1989
|
path: { vendor },
|
|
1415
|
-
body: { target }
|
|
1990
|
+
body: { target: normalizePhoneTarget(target) }
|
|
1416
1991
|
}),
|
|
1417
1992
|
core.auth
|
|
1418
1993
|
),
|
|
1419
1994
|
"command"
|
|
1420
1995
|
);
|
|
1996
|
+
var matchesVisibleQuery = (session, query) => {
|
|
1997
|
+
if (query?.vendor && session.vendor !== query.vendor) {
|
|
1998
|
+
return false;
|
|
1999
|
+
}
|
|
2000
|
+
const state = query?.state ?? "active";
|
|
2001
|
+
if (state === "all") {
|
|
2002
|
+
return true;
|
|
2003
|
+
}
|
|
2004
|
+
if (state === "ended") {
|
|
2005
|
+
return session.state === "ended";
|
|
2006
|
+
}
|
|
2007
|
+
return session.state !== "ended";
|
|
2008
|
+
};
|
|
2009
|
+
var canReplaceVisibleQuery = (query) => {
|
|
2010
|
+
return !query?.before && query?.limit === void 0;
|
|
2011
|
+
};
|
|
1421
2012
|
|
|
1422
2013
|
export { CallpadError, createHostClient, createSessionClient };
|
|
1423
2014
|
//# sourceMappingURL=index.js.map
|