@coventia/softphone 0.2.1 → 0.4.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/dist/{call-VKq1I8yP.d.cts → call-C6YpT6uR.d.cts} +107 -1
- package/dist/{call-VKq1I8yP.d.ts → call-C6YpT6uR.d.ts} +107 -1
- package/dist/chunk-5E5OEXS2.js +14 -0
- package/dist/chunk-5E5OEXS2.js.map +1 -0
- package/dist/{chunk-LMJXX4YM.js → chunk-UHNLEBBO.js} +4 -2
- package/dist/chunk-UHNLEBBO.js.map +1 -0
- package/dist/element/index.d.ts +124 -9
- package/dist/element/index.js +1837 -413
- package/dist/element/index.js.map +1 -1
- package/dist/{engine-BlQBo2Ys.d.cts → engine-CDdaSojx.d.cts} +1 -1
- package/dist/{engine-C0BOkIcW.d.ts → engine-DPft99Wj.d.ts} +1 -1
- package/dist/index.cjs +213 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -6
- package/dist/index.d.ts +16 -6
- package/dist/index.js +75 -10
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +2 -0
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -1
- package/dist/{softphone-DlGV12Xp.d.cts → softphone-CY5d2WWY.d.cts} +28 -10
- package/dist/{softphone-Cyq3hiIM.d.ts → softphone-DXgmTyrX.d.ts} +28 -10
- package/dist/softphone.css +364 -35
- package/dist/{sources-IRKNQPWW.js → sources-ONYQW733.js} +125 -6
- package/dist/sources-ONYQW733.js.map +1 -0
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/ui/index.cjs +1450 -33
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +25 -3
- package/dist/ui/index.d.ts +25 -3
- package/dist/ui/index.js +1445 -36
- package/dist/ui/index.js.map +1 -1
- package/dist/zadarma/index.d.cts +2 -2
- package/dist/zadarma/index.d.ts +2 -2
- package/package.json +1 -1
- package/dist/chunk-LMJXX4YM.js.map +0 -1
- package/dist/sources-IRKNQPWW.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as CallOptions, b as CallDirection, H as HangupReason, i as HoldOriginator,
|
|
1
|
+
import { e as CallOptions, b as CallDirection, H as HangupReason, i as HoldOriginator, w as SoftphoneState, s as SoftphoneError } from './call-C6YpT6uR.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The `CallEngine` seam — INTERNAL, not exported from src/index.ts.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as CallOptions, b as CallDirection, H as HangupReason, i as HoldOriginator,
|
|
1
|
+
import { e as CallOptions, b as CallDirection, H as HangupReason, i as HoldOriginator, w as SoftphoneState, s as SoftphoneError } from './call-C6YpT6uR.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The `CallEngine` seam — INTERNAL, not exported from src/index.ts.
|
package/dist/index.cjs
CHANGED
|
@@ -110,9 +110,9 @@ function createRequest(config, method) {
|
|
|
110
110
|
});
|
|
111
111
|
const body = await res.json().catch(() => null);
|
|
112
112
|
const message = body?.message ?? `${path} \u2014 HTTP ${res.status}`;
|
|
113
|
-
if (!res.ok) throw new ApiError(res.status, message);
|
|
113
|
+
if (!res.ok) throw new ApiError(res.status, message, body);
|
|
114
114
|
if (body?.success === false) {
|
|
115
|
-
throw new ApiError(res.status, message);
|
|
115
|
+
throw new ApiError(res.status, message, body);
|
|
116
116
|
}
|
|
117
117
|
return body;
|
|
118
118
|
}
|
|
@@ -138,15 +138,32 @@ var init_api = __esm({
|
|
|
138
138
|
init_token_cache();
|
|
139
139
|
ApiError = class extends Error {
|
|
140
140
|
status;
|
|
141
|
-
|
|
141
|
+
body;
|
|
142
|
+
constructor(status, message, body = null) {
|
|
142
143
|
super(message);
|
|
143
144
|
this.name = "ApiError";
|
|
144
145
|
this.status = status;
|
|
146
|
+
this.body = body;
|
|
145
147
|
}
|
|
146
148
|
};
|
|
147
149
|
}
|
|
148
150
|
});
|
|
149
151
|
|
|
152
|
+
// src/core/outbound-numbers.ts
|
|
153
|
+
function isOutboundNumberRefused(value) {
|
|
154
|
+
const refusal = value?.refusal;
|
|
155
|
+
return value instanceof Error && !!refusal && (refusal.reason === "platform" || refusal.reason === "user") && typeof refusal.retryAfterSeconds === "number";
|
|
156
|
+
}
|
|
157
|
+
function outboundNumberRefused(refusal) {
|
|
158
|
+
const error = new Error(`Outbound number change refused (${refusal.reason}); retry in ${refusal.retryAfterSeconds}s`);
|
|
159
|
+
error.name = "OutboundNumberRefused";
|
|
160
|
+
return Object.assign(error, { refusal });
|
|
161
|
+
}
|
|
162
|
+
var init_outbound_numbers = __esm({
|
|
163
|
+
"src/core/outbound-numbers.ts"() {
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
150
167
|
// src/coventia/sources.ts
|
|
151
168
|
var sources_exports = {};
|
|
152
169
|
__export(sources_exports, {
|
|
@@ -228,6 +245,8 @@ function coventiaSources(config) {
|
|
|
228
245
|
// row's `called_did` is the OTHER party (already `number` above); showing it again as "DID"
|
|
229
246
|
// would just repeat the row under a wrong label.
|
|
230
247
|
...toDirection(row.direction) === "inbound" && row.called_did ? { did: row.called_did } : {},
|
|
248
|
+
// And the other way round: which of the org's numbers an outbound call showed.
|
|
249
|
+
...toDirection(row.direction) === "outbound" && row.from_number ? { from: row.from_number } : {},
|
|
231
250
|
recorded,
|
|
232
251
|
handledBy,
|
|
233
252
|
// The detail page's one enrichment fetch — signed recording URLs, plus this SAME chain with
|
|
@@ -331,6 +350,118 @@ function coventiaSources(config) {
|
|
|
331
350
|
})();
|
|
332
351
|
});
|
|
333
352
|
};
|
|
353
|
+
const fileBase = config.baseUrl.replace(/\/+$/, "");
|
|
354
|
+
const toLoop = (l) => l && Number.isFinite(l.start) && Number.isFinite(l.end) && l.start >= 0 && l.end > l.start ? { start: l.start, end: l.end } : null;
|
|
355
|
+
const toRingtoneSettings = (body) => {
|
|
356
|
+
const catalogue = (body.catalogue ?? []).map((r) => ({
|
|
357
|
+
id: r.id,
|
|
358
|
+
name: r.name,
|
|
359
|
+
url: r.path ? `${fileBase}${r.path}` : null,
|
|
360
|
+
loop: r.path ? toLoop(r.loop) : null
|
|
361
|
+
}));
|
|
362
|
+
const builtIn = catalogue.find((r) => r.url === null)?.id ?? "clasico";
|
|
363
|
+
const effective = catalogue.some((r) => r.id === body.effective) ? body.effective : builtIn;
|
|
364
|
+
return { catalogue, orgDefault: body.orgDefault ?? null, mine: body.user ?? null, effective };
|
|
365
|
+
};
|
|
366
|
+
const CACHE_PREFIX = "coventia-softphone:ringtones:";
|
|
367
|
+
const cacheKey = async (prefix = CACHE_PREFIX) => {
|
|
368
|
+
try {
|
|
369
|
+
const { identity } = await config.tokenSource.getToken();
|
|
370
|
+
return `${prefix}${fileBase}|${config.organizationId ?? "-"}|${identity}`;
|
|
371
|
+
} catch {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
const remember = async (settings) => {
|
|
376
|
+
const key = await cacheKey();
|
|
377
|
+
try {
|
|
378
|
+
if (key) globalThis.localStorage?.setItem(key, JSON.stringify(settings));
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
return settings;
|
|
382
|
+
};
|
|
383
|
+
const recall = async () => {
|
|
384
|
+
const key = await cacheKey();
|
|
385
|
+
try {
|
|
386
|
+
const raw = key ? globalThis.localStorage?.getItem(key) : null;
|
|
387
|
+
const s = raw ? JSON.parse(raw) : null;
|
|
388
|
+
const ok = s && Array.isArray(s.catalogue) && s.catalogue.every((r) => typeof r?.id === "string" && typeof r.name === "string" && (r.url === null || typeof r.url === "string")) && s.catalogue.some((r) => r.id === s.effective);
|
|
389
|
+
return ok ? { ...s, catalogue: s.catalogue.map((r) => ({ ...r, loop: toLoop(r.loop) })) } : null;
|
|
390
|
+
} catch {
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
const ringtones = {
|
|
395
|
+
get: async (signal) => remember(toRingtoneSettings(await get(`${base}/ringtones`, org, signal))),
|
|
396
|
+
// `null` clears: the empty id is dropped from the query by the request helper, and the backend reads a
|
|
397
|
+
// missing `ringtone_id` as "clear".
|
|
398
|
+
setMine: async (id) => remember(
|
|
399
|
+
toRingtoneSettings(await post(`${base}/ringtones/user`, { ...org, ringtone_id: id ?? "" }))
|
|
400
|
+
),
|
|
401
|
+
cached: recall
|
|
402
|
+
};
|
|
403
|
+
const KINDS = /* @__PURE__ */ new Set(["landline", "mobile", "commercial", "other"]);
|
|
404
|
+
const STATES = /* @__PURE__ */ new Set(["applied", "pending", "failed", "unassigned"]);
|
|
405
|
+
const toOutboundSettings = (body) => {
|
|
406
|
+
const numbers = (body.numbers ?? []).map((n) => ({
|
|
407
|
+
id: n.id,
|
|
408
|
+
number: n.number,
|
|
409
|
+
label: n.label ?? null,
|
|
410
|
+
kind: KINDS.has(n.kind ?? "") ? n.kind : "other"
|
|
411
|
+
}));
|
|
412
|
+
const known = (id) => id && numbers.some((n) => n.id === id) ? id : null;
|
|
413
|
+
return {
|
|
414
|
+
numbers,
|
|
415
|
+
orgDefault: body.orgDefault ?? null,
|
|
416
|
+
mine: known(body.mine),
|
|
417
|
+
// Defensive: a malformed answer naming a number that is not in the list reads as the org default.
|
|
418
|
+
effective: known(body.effective) ?? known(body.orgDefault),
|
|
419
|
+
extension: body.extension ?? null,
|
|
420
|
+
state: STATES.has(body.state ?? "") ? body.state : "applied",
|
|
421
|
+
changeAvailableInSeconds: Math.max(0, Math.ceil(Number(body.changeAvailableInSeconds) || 0))
|
|
422
|
+
};
|
|
423
|
+
};
|
|
424
|
+
const OUTBOUND_PREFIX = "coventia-softphone:outbound-number:";
|
|
425
|
+
const rememberOutbound = async (settings) => {
|
|
426
|
+
const key = await cacheKey(OUTBOUND_PREFIX);
|
|
427
|
+
try {
|
|
428
|
+
if (key) globalThis.localStorage?.setItem(key, JSON.stringify(settings));
|
|
429
|
+
} catch {
|
|
430
|
+
}
|
|
431
|
+
return settings;
|
|
432
|
+
};
|
|
433
|
+
const recallOutbound = async () => {
|
|
434
|
+
const key = await cacheKey(OUTBOUND_PREFIX);
|
|
435
|
+
try {
|
|
436
|
+
const raw = key ? globalThis.localStorage?.getItem(key) : null;
|
|
437
|
+
const s = raw ? JSON.parse(raw) : null;
|
|
438
|
+
const ok = s && Array.isArray(s.numbers) && s.numbers.every((n) => typeof n?.id === "string" && typeof n.number === "string") && (s.effective === null || s.numbers.some((n) => n.id === s.effective));
|
|
439
|
+
return ok ? { ...s, changeAvailableInSeconds: 0 } : null;
|
|
440
|
+
} catch {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
const outboundNumbers = {
|
|
445
|
+
get: async (signal) => rememberOutbound(toOutboundSettings(await get(`${base}/outbound-numbers`, org, signal))),
|
|
446
|
+
// `null` = back to the org default: the empty id is dropped from the query, which the backend reads that way.
|
|
447
|
+
setMine: async (id) => {
|
|
448
|
+
try {
|
|
449
|
+
return rememberOutbound(
|
|
450
|
+
toOutboundSettings(await post(`${base}/outbound-numbers/user`, { ...org, did_id: id ?? "" }))
|
|
451
|
+
);
|
|
452
|
+
} catch (error) {
|
|
453
|
+
const body = error instanceof ApiError ? error.body : null;
|
|
454
|
+
if (error instanceof ApiError && error.status === 429 && body?.code === "rate_limited") {
|
|
455
|
+
throw outboundNumberRefused({
|
|
456
|
+
reason: body.reason === "user" ? "user" : "platform",
|
|
457
|
+
retryAfterSeconds: Math.max(1, Math.ceil(Number(body.retryAfterSeconds) || 1))
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
cached: recallOutbound
|
|
464
|
+
};
|
|
334
465
|
const contacts = config.contacts ?? coventiaContacts;
|
|
335
466
|
const resolve = config.resolveContact ?? (config.contacts ? resolverFromContacts(config.contacts) : coventiaResolve);
|
|
336
467
|
const history = withNameResolution(rawHistory, resolve);
|
|
@@ -342,7 +473,9 @@ function coventiaSources(config) {
|
|
|
342
473
|
resolveContact: resolve,
|
|
343
474
|
listAgents: coventiaListAgents,
|
|
344
475
|
transferOutcomes,
|
|
345
|
-
presence
|
|
476
|
+
presence,
|
|
477
|
+
ringtones,
|
|
478
|
+
outboundNumbers
|
|
346
479
|
};
|
|
347
480
|
}
|
|
348
481
|
var toContact, toDirection, otherParty, isMissed, toOutcome, toDate, toTransferOutcome, toPresenceState, toPresenceEntry, toWebSocketUrl;
|
|
@@ -350,6 +483,7 @@ var init_sources2 = __esm({
|
|
|
350
483
|
"src/coventia/sources.ts"() {
|
|
351
484
|
init_sources();
|
|
352
485
|
init_api();
|
|
486
|
+
init_outbound_numbers();
|
|
353
487
|
toContact = (row) => ({
|
|
354
488
|
id: row.wa_id,
|
|
355
489
|
name: row.name,
|
|
@@ -2006,7 +2140,17 @@ function coventiaBackend(config, tokenSource, fallbackBaseUrl) {
|
|
|
2006
2140
|
resolveContact: async (number) => (await load()).resolveContact(number),
|
|
2007
2141
|
listAgents: async () => (await load()).listAgents(),
|
|
2008
2142
|
transferOutcomes: async (params) => (await load()).transferOutcomes(params),
|
|
2009
|
-
presence: async (callbacks) => (await load()).presence(callbacks)
|
|
2143
|
+
presence: async (callbacks) => (await load()).presence(callbacks),
|
|
2144
|
+
ringtones: {
|
|
2145
|
+
get: async (signal) => (await load()).ringtones.get(signal),
|
|
2146
|
+
setMine: async (id) => (await load()).ringtones.setMine(id),
|
|
2147
|
+
cached: async () => (await load()).ringtones.cached?.() ?? null
|
|
2148
|
+
},
|
|
2149
|
+
outboundNumbers: {
|
|
2150
|
+
get: async (signal) => (await load()).outboundNumbers.get(signal),
|
|
2151
|
+
setMine: async (id) => (await load()).outboundNumbers.setMine(id),
|
|
2152
|
+
cached: async () => (await load()).outboundNumbers.cached?.() ?? null
|
|
2153
|
+
}
|
|
2010
2154
|
};
|
|
2011
2155
|
}
|
|
2012
2156
|
|
|
@@ -2229,13 +2373,30 @@ var BrowserAudioDevices = class {
|
|
|
2229
2373
|
outputs = [];
|
|
2230
2374
|
currentInputId = null;
|
|
2231
2375
|
currentOutputId = null;
|
|
2376
|
+
currentRingtoneOutputId = null;
|
|
2232
2377
|
canSelectOutput;
|
|
2378
|
+
canSelectRingtoneOutput;
|
|
2233
2379
|
#engine;
|
|
2234
2380
|
#onChange;
|
|
2381
|
+
/**
|
|
2382
|
+
* What the user CHOSE, remembered across reloads — distinct from the `current*` fields, which are
|
|
2383
|
+
* what is usable right now. Keeping them apart is what stops a fresh page load from wiping a saved
|
|
2384
|
+
* choice: until the microphone has been granted, Chrome enumerates every device with a blank id, so
|
|
2385
|
+
* "is the saved device in the list?" is no on every first enumeration. The preference survives
|
|
2386
|
+
* that; `current*` simply reads `null` until the device is really there.
|
|
2387
|
+
*/
|
|
2388
|
+
#preferred;
|
|
2389
|
+
/** The input the engine was last told about — it starts on the system default (`null`). */
|
|
2390
|
+
#engineInputId = null;
|
|
2235
2391
|
constructor(engine, onChange) {
|
|
2236
2392
|
this.#engine = engine;
|
|
2237
2393
|
this.#onChange = onChange;
|
|
2238
2394
|
this.canSelectOutput = isBrowser() && typeof HTMLMediaElement !== "undefined" && "setSinkId" in HTMLMediaElement.prototype;
|
|
2395
|
+
this.canSelectRingtoneOutput = this.canSelectOutput;
|
|
2396
|
+
this.#preferred = readStoredDevices();
|
|
2397
|
+
this.currentInputId = this.#preferred.input;
|
|
2398
|
+
this.currentOutputId = this.#preferred.output;
|
|
2399
|
+
this.currentRingtoneOutputId = this.#preferred.ringtone;
|
|
2239
2400
|
if (isBrowser() && navigator.mediaDevices) {
|
|
2240
2401
|
void this.refresh();
|
|
2241
2402
|
navigator.mediaDevices.addEventListener?.("devicechange", () => void this.refresh());
|
|
@@ -2251,26 +2412,63 @@ var BrowserAudioDevices = class {
|
|
|
2251
2412
|
}
|
|
2252
2413
|
this.inputs = all.filter((d) => d.kind === "audioinput");
|
|
2253
2414
|
this.outputs = all.filter((d) => d.kind === "audiooutput");
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
if (this.currentOutputId && !this.outputs.some((d) => d.deviceId === this.currentOutputId)) {
|
|
2258
|
-
this.currentOutputId = null;
|
|
2259
|
-
}
|
|
2415
|
+
this.currentInputId = usable(this.#preferred.input, this.inputs);
|
|
2416
|
+
this.currentOutputId = usable(this.#preferred.output, this.outputs);
|
|
2417
|
+
this.currentRingtoneOutputId = usable(this.#preferred.ringtone, this.outputs);
|
|
2260
2418
|
this.#onChange();
|
|
2419
|
+
if (this.currentInputId && this.currentInputId !== this.#engineInputId) {
|
|
2420
|
+
await this.#tellEngine(this.currentInputId);
|
|
2421
|
+
}
|
|
2261
2422
|
}
|
|
2262
2423
|
async setInput(deviceId) {
|
|
2263
2424
|
this.currentInputId = deviceId;
|
|
2425
|
+
this.#remember({ input: deviceId });
|
|
2264
2426
|
this.#onChange();
|
|
2427
|
+
await this.#tellEngine(deviceId);
|
|
2428
|
+
}
|
|
2429
|
+
async #tellEngine(deviceId) {
|
|
2430
|
+
this.#engineInputId = deviceId;
|
|
2265
2431
|
await this.#engine.setInputDevice?.(deviceId);
|
|
2266
2432
|
}
|
|
2267
2433
|
async setOutput(deviceId) {
|
|
2268
2434
|
this.currentOutputId = deviceId;
|
|
2435
|
+
this.#remember({ output: deviceId });
|
|
2269
2436
|
this.#onChange();
|
|
2270
2437
|
}
|
|
2271
|
-
async setRingtoneOutput() {
|
|
2438
|
+
async setRingtoneOutput(deviceId) {
|
|
2439
|
+
this.currentRingtoneOutputId = deviceId;
|
|
2440
|
+
this.#remember({ ringtone: deviceId });
|
|
2441
|
+
this.#onChange();
|
|
2442
|
+
}
|
|
2443
|
+
#remember(patch) {
|
|
2444
|
+
this.#preferred = { ...this.#preferred, ...patch };
|
|
2445
|
+
writeStoredDevices(this.#preferred);
|
|
2272
2446
|
}
|
|
2273
2447
|
};
|
|
2448
|
+
var DEVICES_KEY = "coventia-softphone:devices";
|
|
2449
|
+
var NO_DEVICES = { input: null, output: null, ringtone: null };
|
|
2450
|
+
function usable(id, list) {
|
|
2451
|
+
return id && list.some((d) => d.deviceId === id) ? id : null;
|
|
2452
|
+
}
|
|
2453
|
+
function readStoredDevices() {
|
|
2454
|
+
if (!isBrowser()) return NO_DEVICES;
|
|
2455
|
+
try {
|
|
2456
|
+
const raw = JSON.parse(globalThis.localStorage?.getItem(DEVICES_KEY) ?? "null");
|
|
2457
|
+
if (!raw || typeof raw !== "object") return NO_DEVICES;
|
|
2458
|
+
const pick = (v) => typeof v === "string" && v ? v : null;
|
|
2459
|
+
const r = raw;
|
|
2460
|
+
return { input: pick(r.input), output: pick(r.output), ringtone: pick(r.ringtone) };
|
|
2461
|
+
} catch {
|
|
2462
|
+
return NO_DEVICES;
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
function writeStoredDevices(devices) {
|
|
2466
|
+
if (!isBrowser()) return;
|
|
2467
|
+
try {
|
|
2468
|
+
globalThis.localStorage?.setItem(DEVICES_KEY, JSON.stringify(devices));
|
|
2469
|
+
} catch {
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2274
2472
|
var SoftphoneImpl = class extends Emitter {
|
|
2275
2473
|
#state = "stopped";
|
|
2276
2474
|
#lastError = null;
|
|
@@ -2674,7 +2872,8 @@ function isCallEngine(value) {
|
|
|
2674
2872
|
|
|
2675
2873
|
// src/index.ts
|
|
2676
2874
|
init_errors();
|
|
2677
|
-
|
|
2875
|
+
init_outbound_numbers();
|
|
2876
|
+
var VERSION = "0.4.0";
|
|
2678
2877
|
|
|
2679
2878
|
exports.CALL_TRANSITIONS = CALL_TRANSITIONS;
|
|
2680
2879
|
exports.CallEvent = CallEvent;
|
|
@@ -2685,6 +2884,7 @@ exports.canTransition = canTransition;
|
|
|
2685
2884
|
exports.createSoftphone = createSoftphone;
|
|
2686
2885
|
exports.isBrowser = isBrowser;
|
|
2687
2886
|
exports.isFatal = isFatal;
|
|
2887
|
+
exports.isOutboundNumberRefused = isOutboundNumberRefused;
|
|
2688
2888
|
exports.isTerminal = isTerminal;
|
|
2689
2889
|
exports.isWebRtcSupported = isWebRtcSupported;
|
|
2690
2890
|
//# sourceMappingURL=index.cjs.map
|