@coventia/softphone 0.4.0 → 0.5.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-C6YpT6uR.d.cts → call-FqcvDg1t.d.cts} +105 -12
- package/dist/{call-C6YpT6uR.d.ts → call-FqcvDg1t.d.ts} +105 -12
- package/dist/{chunk-EYEDPD7Y.js → chunk-6RR6G35E.js} +92 -17
- package/dist/chunk-6RR6G35E.js.map +1 -0
- package/dist/{chunk-2ZSOGGPO.js → chunk-FRXHEHQA.js} +15 -2
- package/dist/chunk-FRXHEHQA.js.map +1 -0
- package/dist/{chunk-UHNLEBBO.js → chunk-I3RSC52R.js} +28 -3
- package/dist/chunk-I3RSC52R.js.map +1 -0
- package/dist/chunk-M76SAXXM.js +13 -0
- package/dist/chunk-M76SAXXM.js.map +1 -0
- package/dist/{chunk-7R6LOOAI.js → chunk-N4PLEYFJ.js} +4 -2
- package/dist/chunk-N4PLEYFJ.js.map +1 -0
- package/dist/element/index.d.ts +142 -6
- package/dist/element/index.js +138 -43
- package/dist/element/index.js.map +1 -1
- package/dist/{engine-DPft99Wj.d.ts → engine-CsNRD7B7.d.ts} +1 -1
- package/dist/{engine-CDdaSojx.d.cts → engine-CzOCrfY9.d.cts} +1 -1
- package/dist/index.cjs +579 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +447 -37
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +26 -0
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +24 -5
- package/dist/react/index.d.ts +24 -5
- package/dist/react/index.js +2 -2
- package/dist/{softphone-CY5d2WWY.d.cts → softphone-By9sizlV.d.ts} +42 -3
- package/dist/{softphone-DXgmTyrX.d.ts → softphone-JZvJdzU3.d.cts} +42 -3
- package/dist/{sources-ONYQW733.js → sources-QL2LRZVH.js} +19 -2
- package/dist/sources-QL2LRZVH.js.map +1 -0
- package/dist/testing/index.cjs +13 -0
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +1 -1
- package/dist/ui/index.cjs +92 -2
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +2 -2
- package/dist/ui/index.d.ts +2 -2
- package/dist/ui/index.js +69 -4
- package/dist/ui/index.js.map +1 -1
- package/dist/zadarma/index.cjs +111 -14
- package/dist/zadarma/index.cjs.map +1 -1
- package/dist/zadarma/index.d.cts +5 -6
- package/dist/zadarma/index.d.ts +5 -6
- package/dist/zadarma/index.js +3 -2
- package/dist/zadarma-engine-TIUE7PZ7.js +6 -0
- package/dist/{zadarma-engine-L5DEFXUS.js.map → zadarma-engine-TIUE7PZ7.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chunk-2ZSOGGPO.js.map +0 -1
- package/dist/chunk-7R6LOOAI.js.map +0 -1
- package/dist/chunk-EYEDPD7Y.js.map +0 -1
- package/dist/chunk-UHNLEBBO.js.map +0 -1
- package/dist/sources-ONYQW733.js.map +0 -1
- package/dist/zadarma-engine-L5DEFXUS.js +0 -5
package/dist/zadarma/index.cjs
CHANGED
|
@@ -361,6 +361,19 @@ var ERROR_CATALOGUE = {
|
|
|
361
361
|
message: "The provider does not support this operation.",
|
|
362
362
|
solution: "Guard the UI on the operation before offering it."
|
|
363
363
|
},
|
|
364
|
+
// ── Line owner (docs/specs/line-owner.md §5) ────────────────────────────────
|
|
365
|
+
// What `takeLine()` rejects with — and `call()` from `standby`, which takes the line first. Never
|
|
366
|
+
// emitted on `SoftphoneEvent.Error`: the promise IS the answer, and nothing about the phone is broken.
|
|
367
|
+
"line/claim-refused": {
|
|
368
|
+
fatal: false,
|
|
369
|
+
message: "The line was not moved here: the user is on a call on the softphone that has it.",
|
|
370
|
+
solution: "Nothing to fix. The line never moves during a call; take it again once that call has ended. Incoming calls keep ringing where they ring now."
|
|
371
|
+
},
|
|
372
|
+
"line/unavailable": {
|
|
373
|
+
fatal: false,
|
|
374
|
+
message: "The line could not be taken: nothing decided where it is.",
|
|
375
|
+
solution: "The presence connection is down, the backend predates the line owner, or it did not answer in time. Retry in a moment; incoming calls keep ringing where they ring now."
|
|
376
|
+
},
|
|
364
377
|
// ── Provider ────────────────────────────────────────────────────────────────
|
|
365
378
|
"provider/provision-failed": {
|
|
366
379
|
fatal: true,
|
|
@@ -416,9 +429,22 @@ var SipCallEngine = class {
|
|
|
416
429
|
provider;
|
|
417
430
|
factory;
|
|
418
431
|
#state = "stopped";
|
|
432
|
+
/**
|
|
433
|
+
* Which `start()`…`stop()` cycle this is — bumped by `stop()`, which ends one. Everything that awaits
|
|
434
|
+
* and then acts (builds a UA, subscribes to the signal, sets the state) captures it first and gives up
|
|
435
|
+
* if a stop has happened since. Not bumped by `start()`: that would cancel work begun just before it,
|
|
436
|
+
* such as a call placed while the softphone is still starting.
|
|
437
|
+
*
|
|
438
|
+
* Without it a stopped phone came back to life: a provisioning or a signal connect still in flight
|
|
439
|
+
* when `stop()` ran finished afterwards and REGISTERed — and since the PBX routes a call to whichever
|
|
440
|
+
* client registered last, it quietly took calls from the user's other device while its UI said off.
|
|
441
|
+
*/
|
|
442
|
+
#run = 0;
|
|
419
443
|
#ua = null;
|
|
420
444
|
/** In-flight `#createUA()`. THE concurrency guard — see `#ensureUA`. */
|
|
421
445
|
#uaInFlight = null;
|
|
446
|
+
/** Calls waiting for the current UA to register (`#callWhenRegistered`), failed by `#teardownUA`. */
|
|
447
|
+
#awaitingRegistration = /* @__PURE__ */ new Set();
|
|
422
448
|
#domain = "";
|
|
423
449
|
#activeCall = null;
|
|
424
450
|
/**
|
|
@@ -501,14 +527,25 @@ var SipCallEngine = class {
|
|
|
501
527
|
for (const listener of [...this.#errorListeners]) listener(error);
|
|
502
528
|
}
|
|
503
529
|
async start() {
|
|
530
|
+
const run = this.#run;
|
|
504
531
|
this.#setState("starting");
|
|
505
532
|
if (this.provider.registrationMode === "persistent") {
|
|
506
|
-
|
|
533
|
+
try {
|
|
534
|
+
await this.#ensureUA();
|
|
535
|
+
} catch (cause) {
|
|
536
|
+
if (run === this.#run) throw cause;
|
|
537
|
+
}
|
|
538
|
+
if (run !== this.#run) return;
|
|
507
539
|
this.#setState("online");
|
|
508
540
|
} else {
|
|
509
541
|
const signal = this.provider.incomingSignal;
|
|
510
542
|
if (signal) {
|
|
511
|
-
|
|
543
|
+
try {
|
|
544
|
+
await signal.connect();
|
|
545
|
+
} catch (cause) {
|
|
546
|
+
if (run === this.#run) throw cause;
|
|
547
|
+
}
|
|
548
|
+
if (run !== this.#run) return;
|
|
512
549
|
this.#signalUnsub = signal.onSignal(() => void this.#onIncomingSignal());
|
|
513
550
|
this.#signalConnectionUnsub = signal.onConnectionChange?.(
|
|
514
551
|
(connected) => this.#setState(connected ? "online" : "offline")
|
|
@@ -518,6 +555,7 @@ var SipCallEngine = class {
|
|
|
518
555
|
}
|
|
519
556
|
}
|
|
520
557
|
async stop() {
|
|
558
|
+
this.#run += 1;
|
|
521
559
|
this.#clearNoInviteTimer();
|
|
522
560
|
this.#signalUnsub?.();
|
|
523
561
|
this.#signalUnsub = null;
|
|
@@ -536,11 +574,12 @@ var SipCallEngine = class {
|
|
|
536
574
|
async #onIncomingSignal() {
|
|
537
575
|
if (this.now() < this.#rejectGuardUntil) return;
|
|
538
576
|
if (this.#activeCall) return;
|
|
577
|
+
const run = this.#run;
|
|
539
578
|
try {
|
|
540
579
|
await this.#ensureUA();
|
|
541
580
|
this.#armNoInviteTeardown();
|
|
542
581
|
} catch {
|
|
543
|
-
this.#teardownUA();
|
|
582
|
+
if (run === this.#run) this.#teardownUA();
|
|
544
583
|
}
|
|
545
584
|
}
|
|
546
585
|
#armNoInviteTeardown() {
|
|
@@ -602,12 +641,16 @@ var SipCallEngine = class {
|
|
|
602
641
|
*/
|
|
603
642
|
async #ensureUA() {
|
|
604
643
|
if (this.#ua) return this.#ua;
|
|
605
|
-
this.#uaInFlight
|
|
606
|
-
this.#
|
|
607
|
-
|
|
644
|
+
if (!this.#uaInFlight) {
|
|
645
|
+
const inFlight = this.#createUA().finally(() => {
|
|
646
|
+
if (this.#uaInFlight === inFlight) this.#uaInFlight = null;
|
|
647
|
+
});
|
|
648
|
+
this.#uaInFlight = inFlight;
|
|
649
|
+
}
|
|
608
650
|
return this.#uaInFlight;
|
|
609
651
|
}
|
|
610
652
|
async #createUA() {
|
|
653
|
+
const run = this.#run;
|
|
611
654
|
const factory = await this.#resolveFactory();
|
|
612
655
|
let credentials;
|
|
613
656
|
try {
|
|
@@ -617,17 +660,28 @@ var SipCallEngine = class {
|
|
|
617
660
|
else this.#reportError("provider/provision-failed", cause);
|
|
618
661
|
throw cause;
|
|
619
662
|
}
|
|
663
|
+
if (run !== this.#run) throw createError("engine/not-started");
|
|
620
664
|
this.#domain = domainOf(credentials);
|
|
621
665
|
const config = this.#uaConfig(credentials, factory);
|
|
622
666
|
const ua = factory.createUA(config);
|
|
623
|
-
ua.on("newRTCSession", ({ session, originator }) =>
|
|
667
|
+
ua.on("newRTCSession", ({ session, originator }) => {
|
|
668
|
+
if (ua !== this.#ua) {
|
|
669
|
+
if (originator === "remote") session.terminate({ status_code: 486, reason_phrase: "Busy Here" });
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
this.#onNewSession(session, originator);
|
|
673
|
+
});
|
|
624
674
|
ua.on("disconnected", ({ error }) => {
|
|
675
|
+
if (ua !== this.#ua) return;
|
|
625
676
|
if (!error) return;
|
|
626
677
|
this.#setState("reconnecting");
|
|
627
678
|
this.#reportError("net/transport-failed", error);
|
|
628
679
|
});
|
|
629
|
-
ua.on("connected", () =>
|
|
680
|
+
ua.on("connected", () => {
|
|
681
|
+
if (ua === this.#ua) this.#setState("online");
|
|
682
|
+
});
|
|
630
683
|
ua.on("registrationFailed", (e) => {
|
|
684
|
+
if (run !== this.#run) return;
|
|
631
685
|
const detail = e;
|
|
632
686
|
this.#reportError("net/registration-failed", {
|
|
633
687
|
cause: detail?.cause,
|
|
@@ -635,7 +689,7 @@ var SipCallEngine = class {
|
|
|
635
689
|
domain: this.#domain,
|
|
636
690
|
hint: "A bare 401 with no auth challenge usually means the registrar is in the wrong datacenter (SPEC \xA73.1)."
|
|
637
691
|
});
|
|
638
|
-
this.#teardownUA();
|
|
692
|
+
if (ua === this.#ua) this.#teardownUA();
|
|
639
693
|
void this.#refreshSignal();
|
|
640
694
|
});
|
|
641
695
|
this.#ua = ua;
|
|
@@ -662,6 +716,7 @@ var SipCallEngine = class {
|
|
|
662
716
|
#teardownUA() {
|
|
663
717
|
this.#uaInFlight = null;
|
|
664
718
|
if (!this.#ua) return;
|
|
719
|
+
for (const fail of [...this.#awaitingRegistration]) fail();
|
|
665
720
|
try {
|
|
666
721
|
this.#ua.terminateSessions({ status_code: 487 });
|
|
667
722
|
this.#ua.stop();
|
|
@@ -685,8 +740,27 @@ var SipCallEngine = class {
|
|
|
685
740
|
#callWhenRegistered(ua, target) {
|
|
686
741
|
const options = { mediaConstraints: buildAudioConstraints(this.#inputDeviceId), pcConfig: PC_CONFIG };
|
|
687
742
|
if (ua.isRegistered()) return Promise.resolve(ua.call(target, options));
|
|
688
|
-
|
|
689
|
-
|
|
743
|
+
const run = this.#run;
|
|
744
|
+
return new Promise((resolve, reject) => {
|
|
745
|
+
let settled = false;
|
|
746
|
+
const fail = () => {
|
|
747
|
+
if (settled) return;
|
|
748
|
+
settled = true;
|
|
749
|
+
this.#awaitingRegistration.delete(fail);
|
|
750
|
+
reject(createError(run === this.#run ? "call/failed" : "engine/not-started"));
|
|
751
|
+
};
|
|
752
|
+
this.#awaitingRegistration.add(fail);
|
|
753
|
+
ua.on("registered", () => {
|
|
754
|
+
if (settled) return;
|
|
755
|
+
if (ua !== this.#ua) return fail();
|
|
756
|
+
settled = true;
|
|
757
|
+
this.#awaitingRegistration.delete(fail);
|
|
758
|
+
try {
|
|
759
|
+
resolve(ua.call(target, options));
|
|
760
|
+
} catch (cause) {
|
|
761
|
+
reject(cause);
|
|
762
|
+
}
|
|
763
|
+
});
|
|
690
764
|
});
|
|
691
765
|
}
|
|
692
766
|
#wrapCall(session) {
|
|
@@ -826,6 +900,12 @@ var ZadarmaPushSignal = class {
|
|
|
826
900
|
#retryTimer;
|
|
827
901
|
#unwatchBackground;
|
|
828
902
|
#closed = false;
|
|
903
|
+
/**
|
|
904
|
+
* Bumped by `disconnect()`. An open or a rebuild still awaiting its key when the signal is disconnected
|
|
905
|
+
* must build nothing afterwards — and `#closed` alone cannot say so once a later `connect()` (stop, then
|
|
906
|
+
* start again) has reset it: the late socket was built beside the new one, and nothing ever closed it.
|
|
907
|
+
*/
|
|
908
|
+
#run = 0;
|
|
829
909
|
#listeners = /* @__PURE__ */ new Set();
|
|
830
910
|
#connectionListeners = /* @__PURE__ */ new Set();
|
|
831
911
|
async connect() {
|
|
@@ -835,8 +915,9 @@ var ZadarmaPushSignal = class {
|
|
|
835
915
|
await this.#open();
|
|
836
916
|
}
|
|
837
917
|
async #open() {
|
|
918
|
+
const run = this.#run;
|
|
838
919
|
const { key, sip, keyExpiresAt } = await this.deps.fetchKey();
|
|
839
|
-
if (this.#
|
|
920
|
+
if (run !== this.#run) return;
|
|
840
921
|
const socket = this.deps.createPushSocket(buildPushUrl(key, sip));
|
|
841
922
|
this.#socket = socket;
|
|
842
923
|
this.#attach(socket);
|
|
@@ -931,9 +1012,10 @@ var ZadarmaPushSignal = class {
|
|
|
931
1012
|
return;
|
|
932
1013
|
}
|
|
933
1014
|
this.#rebuilding = true;
|
|
1015
|
+
const run = this.#run;
|
|
934
1016
|
try {
|
|
935
1017
|
const { key, sip, keyExpiresAt } = await this.deps.fetchKey();
|
|
936
|
-
if (this.#
|
|
1018
|
+
if (run !== this.#run) return;
|
|
937
1019
|
const swapped = await new Promise((resolve) => {
|
|
938
1020
|
const socket = this.deps.createPushSocket(buildPushUrl(key, sip));
|
|
939
1021
|
this.#candidate = socket;
|
|
@@ -986,6 +1068,7 @@ var ZadarmaPushSignal = class {
|
|
|
986
1068
|
}
|
|
987
1069
|
disconnect() {
|
|
988
1070
|
this.#closed = true;
|
|
1071
|
+
this.#run += 1;
|
|
989
1072
|
this.#stopPings();
|
|
990
1073
|
clearTimeout(this.#refreshTimer);
|
|
991
1074
|
this.#refreshTimer = void 0;
|
|
@@ -1256,10 +1339,24 @@ function makeZadarmaBrowserDeps(config) {
|
|
|
1256
1339
|
};
|
|
1257
1340
|
}
|
|
1258
1341
|
|
|
1342
|
+
// src/core/api-base.ts
|
|
1343
|
+
function normalizeApiBase(url) {
|
|
1344
|
+
const trimmed = url.replace(/\/+$/, "");
|
|
1345
|
+
if (!trimmed.endsWith("/api/v1")) return trimmed;
|
|
1346
|
+
console.warn(
|
|
1347
|
+
"[softphone] apiBase should be Coventia's domain only, without /api/v1. Ignoring the /api/v1 suffix."
|
|
1348
|
+
);
|
|
1349
|
+
return trimmed.slice(0, -"/api/v1".length).replace(/\/+$/, "");
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1259
1352
|
// src/transports/zadarma-engine.ts
|
|
1260
1353
|
function createZadarmaEngine(config) {
|
|
1261
1354
|
const provider = new ZadarmaProvider(
|
|
1262
|
-
makeZadarmaBrowserDeps({
|
|
1355
|
+
makeZadarmaBrowserDeps({
|
|
1356
|
+
...config,
|
|
1357
|
+
apiBase: normalizeApiBase(config.apiBase),
|
|
1358
|
+
tokenSource: cachedTokenSource(config.tokenSource)
|
|
1359
|
+
})
|
|
1263
1360
|
);
|
|
1264
1361
|
return new SipCallEngine(provider, loadJsSipFactory);
|
|
1265
1362
|
}
|