@kaltura-sdk/avatars 1.20.0 → 1.21.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/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UnisphereLoggerFactory, TinyDataStore, TinyPubSub, performanceMonitor } from '@unisphere/core';
|
|
1
|
+
import { UnisphereLoggerFactory, TinyDataStore, TinyPubSub, performanceMonitor, getOrCreateGlobalTinyDataStore } from '@unisphere/core';
|
|
2
2
|
import { getPartnerIdFromKs } from '@unisphere/runtime-js';
|
|
3
3
|
import { DisconnectReasons, getAvatarDefaultCapabilities, resolveActiveContextType, AvatarConnectionStatus } from '@unisphere/genie-types';
|
|
4
4
|
import { z as z$1 } from 'zod/mini';
|
|
@@ -23828,6 +23828,103 @@ const avatarConnectionMachine = setup({
|
|
|
23828
23828
|
}
|
|
23829
23829
|
});
|
|
23830
23830
|
|
|
23831
|
+
const ACTIVE_SESSION_STORE_ID = 'agenticExperienceAvatar';
|
|
23832
|
+
function createId() {
|
|
23833
|
+
return typeof crypto !== 'undefined' && crypto.randomUUID ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
|
|
23834
|
+
}
|
|
23835
|
+
/**
|
|
23836
|
+
* Page-wide "who owns the call" record for one avatar manager. Takeover is
|
|
23837
|
+
* just overwriting the shared record: the previous owner sees an id that is
|
|
23838
|
+
* no longer its own and ends its own call (a close callback could not cross
|
|
23839
|
+
* frames).
|
|
23840
|
+
*/
|
|
23841
|
+
class ActiveSessionCoordinator {
|
|
23842
|
+
constructor(_options) {
|
|
23843
|
+
this._options = _options;
|
|
23844
|
+
this.id = createId();
|
|
23845
|
+
this._owns = false;
|
|
23846
|
+
this._conflict = new TinyDataStore({
|
|
23847
|
+
initialValue: null,
|
|
23848
|
+
compare: 'deep'
|
|
23849
|
+
});
|
|
23850
|
+
this._win = window;
|
|
23851
|
+
this._onPageHide = () => this.release();
|
|
23852
|
+
this._logger = _options.logger;
|
|
23853
|
+
this._global = getOrCreateGlobalTinyDataStore({
|
|
23854
|
+
id: ACTIVE_SESSION_STORE_ID,
|
|
23855
|
+
initialValue: null,
|
|
23856
|
+
logger: _options.logger
|
|
23857
|
+
});
|
|
23858
|
+
this._unsubscribe = this._global.onChanges(value => this._handle(value));
|
|
23859
|
+
// A closed iframe must not leave the page locked.
|
|
23860
|
+
this._win.addEventListener('pagehide', this._onPageHide);
|
|
23861
|
+
}
|
|
23862
|
+
/** The active session owned by another avatar, or null */
|
|
23863
|
+
get conflict() {
|
|
23864
|
+
return this._conflict.consumer;
|
|
23865
|
+
}
|
|
23866
|
+
claim(preventDisconnections) {
|
|
23867
|
+
var _a, _b;
|
|
23868
|
+
if (this._owns && ((_a = this._global.getData()) === null || _a === void 0 ? void 0 : _a.preventDisconnections) === preventDisconnections) {
|
|
23869
|
+
return;
|
|
23870
|
+
}
|
|
23871
|
+
this._owns = true;
|
|
23872
|
+
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.log('claiming the active avatar session', {
|
|
23873
|
+
data: {
|
|
23874
|
+
id: this.id,
|
|
23875
|
+
preventDisconnections
|
|
23876
|
+
}
|
|
23877
|
+
});
|
|
23878
|
+
this._global.setData(() => ({
|
|
23879
|
+
id: this.id,
|
|
23880
|
+
preventDisconnections
|
|
23881
|
+
}));
|
|
23882
|
+
}
|
|
23883
|
+
/** Republishes the flag only while this avatar owns the call; never claims an idle one */
|
|
23884
|
+
updateFlag(preventDisconnections) {
|
|
23885
|
+
var _a, _b;
|
|
23886
|
+
if (this._owns && ((_a = this._global.getData()) === null || _a === void 0 ? void 0 : _a.id) === this.id && ((_b = this._global.getData()) === null || _b === void 0 ? void 0 : _b.preventDisconnections) !== preventDisconnections) {
|
|
23887
|
+
this._global.setData(() => ({
|
|
23888
|
+
id: this.id,
|
|
23889
|
+
preventDisconnections
|
|
23890
|
+
}));
|
|
23891
|
+
}
|
|
23892
|
+
}
|
|
23893
|
+
/** Clears the record only if it is still ours, so a taken-over avatar can't wipe the new owner */
|
|
23894
|
+
release() {
|
|
23895
|
+
var _a, _b;
|
|
23896
|
+
this._owns = false;
|
|
23897
|
+
if (((_a = this._global.getData()) === null || _a === void 0 ? void 0 : _a.id) === this.id) {
|
|
23898
|
+
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.log('releasing the active avatar session', {
|
|
23899
|
+
data: {
|
|
23900
|
+
id: this.id
|
|
23901
|
+
}
|
|
23902
|
+
});
|
|
23903
|
+
this._global.setData(() => null);
|
|
23904
|
+
}
|
|
23905
|
+
}
|
|
23906
|
+
dispose() {
|
|
23907
|
+
this.release();
|
|
23908
|
+
this._unsubscribe();
|
|
23909
|
+
this._win.removeEventListener('pagehide', this._onPageHide);
|
|
23910
|
+
}
|
|
23911
|
+
_handle(value) {
|
|
23912
|
+
var _a;
|
|
23913
|
+
const other = value && value.id !== this.id ? value : null;
|
|
23914
|
+
this._conflict.setData(() => other);
|
|
23915
|
+
if (other && this._owns) {
|
|
23916
|
+
this._owns = false;
|
|
23917
|
+
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.log('active avatar session taken over by another avatar', {
|
|
23918
|
+
data: {
|
|
23919
|
+
id: this.id,
|
|
23920
|
+
by: other.id
|
|
23921
|
+
}
|
|
23922
|
+
});
|
|
23923
|
+
this._options.onTakenOver();
|
|
23924
|
+
}
|
|
23925
|
+
}
|
|
23926
|
+
}
|
|
23927
|
+
|
|
23831
23928
|
function setIfChanged(store, next, eq = (a, b) => a === b) {
|
|
23832
23929
|
if (!eq(store.getData(), next)) {
|
|
23833
23930
|
store.setData(() => next);
|
|
@@ -24108,7 +24205,20 @@ class AvatarClientManager extends ActorManager {
|
|
|
24108
24205
|
this._contextSelectorVisible = new TinyDataStore({
|
|
24109
24206
|
initialValue: true
|
|
24110
24207
|
});
|
|
24208
|
+
this._multipleAvatarBehavior = new TinyDataStore({
|
|
24209
|
+
initialValue: {
|
|
24210
|
+
preventDisconnections: false
|
|
24211
|
+
},
|
|
24212
|
+
compare: 'deep'
|
|
24213
|
+
});
|
|
24214
|
+
this._isTakeoverPending = new TinyDataStore({
|
|
24215
|
+
initialValue: false
|
|
24216
|
+
});
|
|
24111
24217
|
this._logger = (_a = this._config.logger) !== null && _a !== void 0 ? _a : avatarClientLoggerFactory.getOrCreateLogger('service', 'avatar-client');
|
|
24218
|
+
this._activeSession = new ActiveSessionCoordinator({
|
|
24219
|
+
onTakenOver: () => this.disconnect(),
|
|
24220
|
+
logger: this._logger
|
|
24221
|
+
});
|
|
24112
24222
|
if (this._config.runtimeSettings.features) {
|
|
24113
24223
|
this._features.setData(() => this._config.runtimeSettings.features);
|
|
24114
24224
|
}
|
|
@@ -24121,6 +24231,19 @@ class AvatarClientManager extends ActorManager {
|
|
|
24121
24231
|
return this._config.runtimeSettings.serverConfig === 'manual' ? (_a = this._config.runtimeSettings.loadingVideoURL) !== null && _a !== void 0 ? _a : null : null;
|
|
24122
24232
|
});
|
|
24123
24233
|
this._setupKalturaContext();
|
|
24234
|
+
this._multipleAvatarBehavior.setData(() => {
|
|
24235
|
+
var _a, _b;
|
|
24236
|
+
return {
|
|
24237
|
+
preventDisconnections: (_b = (_a = this._config.runtimeSettings.multipleAvatarBehavior) === null || _a === void 0 ? void 0 : _a.preventDisconnections) !== null && _b !== void 0 ? _b : false
|
|
24238
|
+
};
|
|
24239
|
+
});
|
|
24240
|
+
this._status.onChanges(status => {
|
|
24241
|
+
if (status === AvatarConnectionStatus.NotConnected || status === AvatarConnectionStatus.Disconnected || status === AvatarConnectionStatus.Error) {
|
|
24242
|
+
this._activeSession.release();
|
|
24243
|
+
}
|
|
24244
|
+
}, {
|
|
24245
|
+
replayLastValue: false
|
|
24246
|
+
});
|
|
24124
24247
|
}
|
|
24125
24248
|
// ────────────────────────────────────────────────────────────────────────
|
|
24126
24249
|
// Private: connection engine
|
|
@@ -24327,6 +24450,18 @@ class AvatarClientManager extends ActorManager {
|
|
|
24327
24450
|
this._logger.log(`Avatar client already connected`);
|
|
24328
24451
|
return;
|
|
24329
24452
|
}
|
|
24453
|
+
const conflict = this._activeSession.conflict.getData();
|
|
24454
|
+
if (conflict) {
|
|
24455
|
+
this._logger.log('Connect pending: another avatar is in a call', {
|
|
24456
|
+
data: {
|
|
24457
|
+
preventDisconnections: conflict.preventDisconnections
|
|
24458
|
+
}
|
|
24459
|
+
});
|
|
24460
|
+
this._pendingTakeoverOptions = options;
|
|
24461
|
+
this._isTakeoverPending.setData(() => true);
|
|
24462
|
+
return;
|
|
24463
|
+
}
|
|
24464
|
+
this._activeSession.claim(this._multipleAvatarBehavior.getData().preventDisconnections);
|
|
24330
24465
|
const connectionId = 'main';
|
|
24331
24466
|
this._logger.log(`Connecting to avatar client with connection ID: ${connectionId}`);
|
|
24332
24467
|
timingTracker.runtimeConnectTime = performance.now();
|
|
@@ -24382,6 +24517,22 @@ class AvatarClientManager extends ActorManager {
|
|
|
24382
24517
|
reconnect() {
|
|
24383
24518
|
this.connect(this._lastConnectOptions);
|
|
24384
24519
|
}
|
|
24520
|
+
confirmTakeover() {
|
|
24521
|
+
var _a;
|
|
24522
|
+
if (!this._isTakeoverPending.getData() || ((_a = this._activeSession.conflict.getData()) === null || _a === void 0 ? void 0 : _a.preventDisconnections)) {
|
|
24523
|
+
return;
|
|
24524
|
+
}
|
|
24525
|
+
const options = this._pendingTakeoverOptions;
|
|
24526
|
+
this._pendingTakeoverOptions = undefined;
|
|
24527
|
+
this._isTakeoverPending.setData(() => false);
|
|
24528
|
+
// Overwriting the page-wide record makes the other avatar end its own call.
|
|
24529
|
+
this._activeSession.claim(this._multipleAvatarBehavior.getData().preventDisconnections);
|
|
24530
|
+
this.connect(options);
|
|
24531
|
+
}
|
|
24532
|
+
cancelTakeover() {
|
|
24533
|
+
this._pendingTakeoverOptions = undefined;
|
|
24534
|
+
this._isTakeoverPending.setData(() => false);
|
|
24535
|
+
}
|
|
24385
24536
|
// ────────────────────────────────────────────────────────────────────────
|
|
24386
24537
|
// Public API: pause / resume
|
|
24387
24538
|
// ────────────────────────────────────────────────────────────────────────
|
|
@@ -24584,6 +24735,23 @@ class AvatarClientManager extends ActorManager {
|
|
|
24584
24735
|
setIsPreviewMode(value) {
|
|
24585
24736
|
this._isPreviewMode.setData(() => value);
|
|
24586
24737
|
}
|
|
24738
|
+
get multipleAvatarBehavior() {
|
|
24739
|
+
return this._multipleAvatarBehavior.consumer;
|
|
24740
|
+
}
|
|
24741
|
+
setMultipleAvatarBehavior(value) {
|
|
24742
|
+
var _a;
|
|
24743
|
+
const preventDisconnections = (_a = value === null || value === void 0 ? void 0 : value.preventDisconnections) !== null && _a !== void 0 ? _a : false;
|
|
24744
|
+
this._multipleAvatarBehavior.setData(() => ({
|
|
24745
|
+
preventDisconnections
|
|
24746
|
+
}));
|
|
24747
|
+
this._activeSession.updateFlag(preventDisconnections);
|
|
24748
|
+
}
|
|
24749
|
+
get activeSessionConflict() {
|
|
24750
|
+
return this._activeSession.conflict;
|
|
24751
|
+
}
|
|
24752
|
+
get isTakeoverPending() {
|
|
24753
|
+
return this._isTakeoverPending.consumer;
|
|
24754
|
+
}
|
|
24587
24755
|
get contextSelectorVisible() {
|
|
24588
24756
|
return this._contextSelectorVisible.consumer;
|
|
24589
24757
|
}
|
|
@@ -24661,6 +24829,7 @@ class AvatarClientManager extends ActorManager {
|
|
|
24661
24829
|
var _a;
|
|
24662
24830
|
(_a = this._unsubscribeContextActive) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
24663
24831
|
this._unsubscribeContextActive = null;
|
|
24832
|
+
this._activeSession.dispose();
|
|
24664
24833
|
this._cleanupConnection();
|
|
24665
24834
|
}
|
|
24666
24835
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaltura-sdk/avatars",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.1",
|
|
4
4
|
"author": "kaltura",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"repository": {
|
|
@@ -12,14 +12,15 @@
|
|
|
12
12
|
"@kaltura-sdk/rtc-avatar": "^1.33.4",
|
|
13
13
|
"@kaltura-sdk/rtc-core": "^1.26.2",
|
|
14
14
|
"@local/genie-shared-utils": "^1.0.0",
|
|
15
|
-
"@unisphere/core": "^1.
|
|
16
|
-
"@unisphere/genie-types": "^1.
|
|
15
|
+
"@unisphere/core": "^1.101.1",
|
|
16
|
+
"@unisphere/genie-types": "^1.47.0",
|
|
17
17
|
"@unisphere/notifications-core": "^1.25.0",
|
|
18
18
|
"@unisphere/runtime": "^1.98.0",
|
|
19
19
|
"@unisphere/runtime-js": "^1.98.0",
|
|
20
20
|
"immer": "^10.1.1",
|
|
21
21
|
"js-yaml": "^4.1.0",
|
|
22
22
|
"socket.io-client": "^4.8.1",
|
|
23
|
+
"vitest": "^3.2.7",
|
|
23
24
|
"zod": "^4.2.0"
|
|
24
25
|
},
|
|
25
26
|
"module": "./index.esm.js",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UnisphereLoggerType } from '@unisphere/core';
|
|
2
2
|
import { KalturaAnalyticsServiceType, PubSubServiceType } from '@unisphere/runtime';
|
|
3
|
-
import { AgentData, AgentKalturaContextData, AgentProgressBar, AgentScreenShareInfo, AgentTapToTalkInfo, AvatarClientManagerType, AvatarConnectionProxInternalType, AvatarConnectionProxyType, AvatarConnectionStatus, AvatarContentData, AvatarRuntimeSettings, CaptionConfig, Captions, ChatEntry, ClientToolCallLogEntry, DisconnectReasons, TapToTalkStartOptions } from '@unisphere/genie-types';
|
|
3
|
+
import { AgentData, AgentKalturaContextData, AgentProgressBar, AgentScreenShareInfo, AgentTapToTalkInfo, AvatarClientManagerType, AvatarConnectionProxInternalType, AvatarConnectionProxyType, AvatarConnectionStatus, AvatarContentData, AvatarRuntimeSettings, CaptionConfig, Captions, ChatEntry, ClientToolCallLogEntry, DisconnectReasons, MultipleAvatarBehavior, TapToTalkStartOptions } from '@unisphere/genie-types';
|
|
4
4
|
import { type AvatarClientToolsInput, type AvatarConnectionActor } from './machines/avatar-connection';
|
|
5
5
|
import { AvatarClientManagerActions } from './types';
|
|
6
6
|
import { DeviceType } from '@kaltura-sdk/rtc-core';
|
|
@@ -58,6 +58,10 @@ export declare class AvatarClientManager extends ActorManager<AvatarConnectionAc
|
|
|
58
58
|
private _features;
|
|
59
59
|
private readonly _isPreviewMode;
|
|
60
60
|
private readonly _contextSelectorVisible;
|
|
61
|
+
private readonly _multipleAvatarBehavior;
|
|
62
|
+
private readonly _isTakeoverPending;
|
|
63
|
+
private _pendingTakeoverOptions;
|
|
64
|
+
private readonly _activeSession;
|
|
61
65
|
constructor(_config: {
|
|
62
66
|
actions?: AvatarClientManagerActions;
|
|
63
67
|
debugMode?: boolean;
|
|
@@ -113,6 +117,8 @@ export declare class AvatarClientManager extends ActorManager<AvatarConnectionAc
|
|
|
113
117
|
}): void;
|
|
114
118
|
disconnect(): void;
|
|
115
119
|
reconnect(): void;
|
|
120
|
+
confirmTakeover(): void;
|
|
121
|
+
cancelTakeover(): void;
|
|
116
122
|
get isPaused(): import("@unisphere/core").TinyDataStoreConsumer<boolean>;
|
|
117
123
|
pause(): void;
|
|
118
124
|
resume(): void;
|
|
@@ -149,6 +155,10 @@ export declare class AvatarClientManager extends ActorManager<AvatarConnectionAc
|
|
|
149
155
|
setExternalThreadId(id: string | null): void;
|
|
150
156
|
get isPreviewMode(): import("@unisphere/core").TinyDataStoreConsumer<boolean>;
|
|
151
157
|
setIsPreviewMode(value: boolean): void;
|
|
158
|
+
get multipleAvatarBehavior(): import("@unisphere/core").TinyDataStoreConsumer<MultipleAvatarBehavior>;
|
|
159
|
+
setMultipleAvatarBehavior(value: MultipleAvatarBehavior | undefined): void;
|
|
160
|
+
get activeSessionConflict(): import("@unisphere/core").TinyDataStoreConsumer<import("@unisphere/genie-types").ActiveAvatarSession | null>;
|
|
161
|
+
get isTakeoverPending(): import("@unisphere/core").TinyDataStoreConsumer<boolean>;
|
|
152
162
|
get contextSelectorVisible(): import("@unisphere/core").TinyDataStoreConsumer<boolean>;
|
|
153
163
|
setContextSelectorVisible(value: boolean): void;
|
|
154
164
|
get features(): import("@unisphere/core").TinyDataStoreConsumer<{
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { UnisphereLoggerType } from '@unisphere/core';
|
|
2
|
+
import type { ActiveAvatarSession } from '@unisphere/genie-types';
|
|
3
|
+
export declare const ACTIVE_SESSION_STORE_ID = "agenticExperienceAvatar";
|
|
4
|
+
/**
|
|
5
|
+
* Page-wide "who owns the call" record for one avatar manager. Takeover is
|
|
6
|
+
* just overwriting the shared record: the previous owner sees an id that is
|
|
7
|
+
* no longer its own and ends its own call (a close callback could not cross
|
|
8
|
+
* frames).
|
|
9
|
+
*/
|
|
10
|
+
export declare class ActiveSessionCoordinator {
|
|
11
|
+
private readonly _options;
|
|
12
|
+
readonly id: string;
|
|
13
|
+
private _owns;
|
|
14
|
+
private readonly _conflict;
|
|
15
|
+
private readonly _global;
|
|
16
|
+
private readonly _unsubscribe;
|
|
17
|
+
private readonly _win;
|
|
18
|
+
private readonly _onPageHide;
|
|
19
|
+
private readonly _logger?;
|
|
20
|
+
constructor(_options: {
|
|
21
|
+
onTakenOver: () => void;
|
|
22
|
+
logger?: UnisphereLoggerType;
|
|
23
|
+
});
|
|
24
|
+
/** The active session owned by another avatar, or null */
|
|
25
|
+
get conflict(): import("@unisphere/core").TinyDataStoreConsumer<ActiveAvatarSession | null>;
|
|
26
|
+
claim(preventDisconnections: boolean): void;
|
|
27
|
+
/** Republishes the flag only while this avatar owns the call; never claims an idle one */
|
|
28
|
+
updateFlag(preventDisconnections: boolean): void;
|
|
29
|
+
/** Clears the record only if it is still ours, so a taken-over avatar can't wipe the new owner */
|
|
30
|
+
release(): void;
|
|
31
|
+
dispose(): void;
|
|
32
|
+
private _handle;
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ActiveSessionCoordinator } from '../avatar-client-manager/utils/active-session-coordinator';
|
|
2
|
+
type CoordinatorOptions = ConstructorParameters<typeof ActiveSessionCoordinator>[0];
|
|
3
|
+
export declare function getRealTopWindow(): Window;
|
|
4
|
+
export declare function addFrame(parent: Window): Window;
|
|
5
|
+
export declare function installBrowserLikePostMessage(windows: Window[]): void;
|
|
6
|
+
export declare function createFrameApi(win: Window): Promise<{
|
|
7
|
+
createCoordinator: (options: CoordinatorOptions) => ActiveSessionCoordinator;
|
|
8
|
+
cleanup: () => void;
|
|
9
|
+
}>;
|
|
10
|
+
export declare const flush: () => Promise<unknown>;
|
|
11
|
+
export {};
|