@vivix-ai/ivi-frontend-sdk 0.3.8 → 0.3.9

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/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ReceiveConversationItemAddedEvent, ReceiveConversationItemDoneEvent, ReceiveResponseCreatedEvent, IviClient, ReceiveSessionCreatedEvent, ReceiveSessionEndedEvent, ReceiveSessionStageGetResponseEvent, ReceiveSessionStageUpdatedEvent, ReceiveSessionTrackCreatedEvent, ReceiveSessionTrackDeletedEvent, ReceiveSessionTrackTookEvent, ReceiveSessionTrackCuedEvent, ReceiveSessionTrackNextSetEvent, ReceiveSessionTracksListResponseEvent, ReceiveSessionSourceCreatedEvent, ReceiveSessionSourceReadyEvent, ReceiveSessionSourceFailedEvent, ReceiveSessionSourceDeletedEvent, ReceiveSessionSourcePreloadEvent, ReceiveSessionSourceClearPreloadEvent, ReceiveSessionSourcesListResponseEvent, ReceiveSessionSourcePlaybackCompletedEvent, ReceiveSessionStreamCreatedEvent, ReceiveSessionStreamStartedEvent, ReceiveSessionStreamEndedEvent, ReceiveSessionStreamFailedEvent, ReceiveSessionStreamDeletedEvent, ReceiveSessionStreamsListResponseEvent, ReceiveConversationListResponseEvent, ReceiveResponseOutputTextDeltaEvent, ReceiveResponseOutputTextDoneEvent, ReceiveResponseOutputAudioTranscriptDeltaEvent, ReceiveResponseOutputAudioTranscriptDoneEvent, ReceiveResponseDoneEvent } from '@vivix-ai/ivi-sdk-ts';
2
+ import { WebSocketTransport } from '@vivix-ai/ivi-sdk-ts/transports/websocket';
2
3
  import { createContext, useState, useEffect, useMemo, useRef, useContext, useCallback, useId } from 'react';
3
4
  import { jsx, jsxs } from 'react/jsx-runtime';
4
5
 
@@ -620,7 +621,9 @@ var SourceManager = class {
620
621
  durationMs: previous?.durationMs,
621
622
  hasAudio: previous?.hasAudio,
622
623
  error: previous?.status === "failed" ? previous.error : void 0,
623
- preload: previous?.preload
624
+ preload: previous?.preload,
625
+ origin: previous?.origin,
626
+ provisional: previous?.provisional ? false : previous?.provisional
624
627
  });
625
628
  this.sources = next;
626
629
  }
@@ -635,7 +638,38 @@ var SourceManager = class {
635
638
  height: payload.height,
636
639
  durationMs: payload.durationMs,
637
640
  hasAudio: payload.hasAudio,
638
- preload: previous?.preload
641
+ preload: previous?.preload,
642
+ origin: previous?.origin,
643
+ provisional: previous?.provisional ? false : previous?.provisional
644
+ });
645
+ this.sources = next;
646
+ }
647
+ upsertBootstrapReady(payload) {
648
+ const previous = this.sources.get(payload.sourceId);
649
+ const next = new Map(this.sources);
650
+ const source = {
651
+ source_id: payload.sourceId,
652
+ kind: payload.source?.kind ?? (payload.streamId ? "generation_stream" : "stream"),
653
+ stream_id: payload.source?.stream_id ?? payload.streamId,
654
+ asset_type: payload.source?.asset_type ?? "video",
655
+ url: payload.source?.url,
656
+ generation: payload.source?.generation,
657
+ metadata: {
658
+ ...payload.source?.metadata ?? {},
659
+ label: payload.source?.metadata?.label ?? "prebuilt"
660
+ }
661
+ };
662
+ next.set(payload.sourceId, {
663
+ source,
664
+ status: "ready",
665
+ playback: previous?.playback ?? payload.playback,
666
+ width: previous?.width ?? payload.width,
667
+ height: previous?.height ?? payload.height,
668
+ durationMs: previous?.durationMs ?? payload.durationMs,
669
+ hasAudio: previous?.hasAudio ?? payload.hasAudio,
670
+ preload: previous?.preload ?? { autoclearAfterPlay: true },
671
+ origin: previous?.origin ?? "prebuilt-session-response",
672
+ provisional: previous?.provisional ?? true
639
673
  });
640
674
  this.sources = next;
641
675
  }
@@ -669,11 +703,14 @@ var SourceManager = class {
669
703
  const next = /* @__PURE__ */ new Map();
670
704
  sources.forEach((source) => {
671
705
  const previous = this.sources.get(source.source_id);
706
+ const playback = source.playback ?? previous?.playback;
672
707
  next.set(source.source_id, {
673
708
  source,
674
- status: source.playback ? "ready" : "created",
675
- playback: source.playback,
676
- preload: previous?.preload
709
+ status: playback ? "ready" : "created",
710
+ playback,
711
+ preload: previous?.preload,
712
+ origin: previous?.origin,
713
+ provisional: source.playback && previous?.provisional ? false : previous?.provisional
677
714
  });
678
715
  });
679
716
  this.sources = next;
@@ -1277,6 +1314,7 @@ var TrtcSourceManager = class {
1277
1314
  startedVideoKeys: /* @__PURE__ */ new Set(),
1278
1315
  startingVideoKeys: /* @__PURE__ */ new Set()
1279
1316
  });
1317
+ this.log("info", `\u7ED1\u5B9A\u89C6\u56FE source=${sourceId} view=${viewId} views=${session.views.size}`);
1280
1318
  await this.ensureConnected(session);
1281
1319
  const binding = session.views.get(viewId);
1282
1320
  if (!binding) {
@@ -1292,6 +1330,7 @@ var TrtcSourceManager = class {
1292
1330
  }
1293
1331
  const binding = session.views.get(viewId);
1294
1332
  if (binding?.sourceId === sourceId) {
1333
+ this.log("info", `\u89E3\u7ED1\u89C6\u56FE source=${sourceId} view=${viewId}`);
1295
1334
  binding.container.removeAttribute(TRTC_VIEW_ATTR);
1296
1335
  session.views.delete(viewId);
1297
1336
  }
@@ -1309,6 +1348,24 @@ var TrtcSourceManager = class {
1309
1348
  binding.muted = muted;
1310
1349
  void this.applyAudioPolicy(session);
1311
1350
  }
1351
+ reassignView(fromSourceId, toSourceId, viewId) {
1352
+ if (fromSourceId === toSourceId) {
1353
+ return true;
1354
+ }
1355
+ const fromSession = this.getSession(fromSourceId);
1356
+ const toSession = this.getSession(toSourceId);
1357
+ if (!fromSession || !toSession || fromSession !== toSession) {
1358
+ return false;
1359
+ }
1360
+ const binding = fromSession.views.get(viewId);
1361
+ if (!binding || binding.sourceId !== fromSourceId) {
1362
+ return false;
1363
+ }
1364
+ this.log("info", `\u8FC1\u79FB\u89C6\u56FE source=${fromSourceId}->${toSourceId} view=${viewId}`);
1365
+ binding.sourceId = toSourceId;
1366
+ void this.applyAudioPolicy(fromSession);
1367
+ return true;
1368
+ }
1312
1369
  unlinkSourceFromSession(sourceId, session) {
1313
1370
  session.sourceIds.delete(sourceId);
1314
1371
  this.sourceSessionKeys.delete(sourceId);
@@ -1483,6 +1540,7 @@ var TrtcSourceManager = class {
1483
1540
  if (!parsed) {
1484
1541
  continue;
1485
1542
  }
1543
+ this.log("info", `\u56DE\u653E\u5DF2\u77E5\u8FDC\u7AEF\u89C6\u9891 source=${binding.sourceId} userId=${parsed.userId} streamType=${parsed.streamType}`);
1486
1544
  await this.startRemoteVideoForBinding(
1487
1545
  client,
1488
1546
  parsed.userId,
@@ -1498,12 +1556,14 @@ var TrtcSourceManager = class {
1498
1556
  }
1499
1557
  binding.startingVideoKeys.add(remoteVideoKey);
1500
1558
  try {
1559
+ this.log("info", `\u5F00\u59CB\u6E32\u67D3\u8FDC\u7AEF\u89C6\u9891 source=${binding.sourceId} view=${remoteVideoKey} userId=${userId} streamType=${streamType}`);
1501
1560
  await client.startRemoteVideo({
1502
1561
  userId,
1503
1562
  streamType,
1504
1563
  view: binding.container,
1505
1564
  option: { fillMode: "contain" }
1506
1565
  });
1566
+ this.log("info", `\u8FDC\u7AEF\u89C6\u9891\u6E32\u67D3\u5B8C\u6210 source=${binding.sourceId} userId=${userId} streamType=${streamType}`);
1507
1567
  binding.startedVideoKeys.add(remoteVideoKey);
1508
1568
  enforceContainMedia(binding.container);
1509
1569
  } catch (error) {
@@ -1670,7 +1730,7 @@ function isRuntimeTrtcSource(source) {
1670
1730
  return source.status === "ready" && source.playback?.type === "trtc" && typeof source.playback.trtc === "object" && source.playback.trtc !== null;
1671
1731
  }
1672
1732
  function isSameTrtcConfig(a, b) {
1673
- return a.app_id === b.app_id && a.user_id === b.user_id && a.user_sig === b.user_sig && a.room_id === b.room_id;
1733
+ return a.app_id === b.app_id && a.user_id === b.user_id && a.room_id === b.room_id;
1674
1734
  }
1675
1735
  function buildTrtcSessionKey(trtc, aiDenoiser) {
1676
1736
  const denoiser = resolveAIDenoiserOptions(aiDenoiser);
@@ -1678,7 +1738,6 @@ function buildTrtcSessionKey(trtc, aiDenoiser) {
1678
1738
  appId: trtc.app_id,
1679
1739
  roomId: trtc.room_id,
1680
1740
  userId: trtc.user_id,
1681
- userSig: trtc.user_sig,
1682
1741
  aiDenoiser: {
1683
1742
  enabled: denoiser.enabled,
1684
1743
  mode: denoiser.mode,
@@ -1787,8 +1846,9 @@ function describeLivekitRoom(livekit) {
1787
1846
  // src/runtime/managers/livekit-source-manager.ts
1788
1847
  var TAG2 = "[IVI-LIVEKIT]";
1789
1848
  var LivekitSourceManager = class {
1790
- constructor(onLog) {
1849
+ constructor(onLog, onRemoteVideoAvailable) {
1791
1850
  this.onLog = onLog;
1851
+ this.onRemoteVideoAvailable = onRemoteVideoAvailable;
1792
1852
  this.sessions = /* @__PURE__ */ new Map();
1793
1853
  this.listeners = /* @__PURE__ */ new Map();
1794
1854
  }
@@ -2015,6 +2075,7 @@ var LivekitSourceManager = class {
2015
2075
  waiter(true);
2016
2076
  }
2017
2077
  session.remoteVideoWaiters.length = 0;
2078
+ this.onRemoteVideoAvailable?.(session.sourceId);
2018
2079
  }
2019
2080
  session.views.forEach((binding) => {
2020
2081
  this.attachTrackToView(track, kind, trackKey, binding);
@@ -2210,6 +2271,7 @@ var IviRuntimeCoordinator = class {
2210
2271
  this.userTextFlowCounter = 0;
2211
2272
  this.waitingTracksListValidation = false;
2212
2273
  this.waitingSourcesListValidation = false;
2274
+ this.bootstrapSource = null;
2213
2275
  this.state = {
2214
2276
  status: "idle",
2215
2277
  session: null,
@@ -2218,7 +2280,8 @@ var IviRuntimeCoordinator = class {
2218
2280
  sources: /* @__PURE__ */ new Map(),
2219
2281
  streams: /* @__PURE__ */ new Map(),
2220
2282
  conversationItems: /* @__PURE__ */ new Map(),
2221
- conversations: []
2283
+ conversations: [],
2284
+ bootstrap: null
2222
2285
  };
2223
2286
  this.client = client;
2224
2287
  this.config = {
@@ -2227,10 +2290,12 @@ var IviRuntimeCoordinator = class {
2227
2290
  };
2228
2291
  this.trtcSourceManager = new TrtcSourceManager(
2229
2292
  this.config.onLog,
2230
- (event) => this.emitTrtcEvent(event),
2293
+ (event) => this.onTrtcManagerEvent(event),
2231
2294
  this.config.trtcAIDenoiser
2232
2295
  );
2233
- this.livekitSourceManager = new LivekitSourceManager(this.config.onLog);
2296
+ this.livekitSourceManager = new LivekitSourceManager(this.config.onLog, () => {
2297
+ this.recomposeBootstrapState();
2298
+ });
2234
2299
  this.sessionHandler = new SessionEventHandler(this.sessionManager, {
2235
2300
  onSessionCreated: (event) => this.onSessionCreated(event),
2236
2301
  onSessionEnded: (event) => this.onSessionEnded(event)
@@ -2311,6 +2376,22 @@ var IviRuntimeCoordinator = class {
2311
2376
  emitLog(entry) {
2312
2377
  this.config.onLog?.(entry);
2313
2378
  }
2379
+ setBootstrapSource(source) {
2380
+ const previous = this.bootstrapSource;
2381
+ if (previous && (!source || previous.sourceId !== source.sourceId)) {
2382
+ const existing = this.sourceManager.get(previous.sourceId);
2383
+ if (existing?.origin === "prebuilt-session-response" && existing.provisional) {
2384
+ this.sourceManager.remove(previous.sourceId);
2385
+ }
2386
+ }
2387
+ this.bootstrapSource = source;
2388
+ this.ensureBootstrapSourceRegistered();
2389
+ this.syncPlaybackManagers();
2390
+ this.setState({
2391
+ ...this.state,
2392
+ sources: this.sourceManager.getAll()
2393
+ });
2394
+ }
2314
2395
  /**
2315
2396
  * 编排一次"用户文本输入 -> 触发模型回复"链路。
2316
2397
  *
@@ -2431,10 +2512,10 @@ var IviRuntimeCoordinator = class {
2431
2512
  this.trackManager.reset();
2432
2513
  this.sourceManager.reset();
2433
2514
  this.streamManager.reset();
2434
- this.trtcSourceManager.reset();
2435
- this.livekitSourceManager.reset();
2436
2515
  this.conversationManager.reset();
2437
2516
  this.reset();
2517
+ this.ensureBootstrapSourceRegistered();
2518
+ this.syncPlaybackManagers();
2438
2519
  const nextStatus = this.config.syncStageOnSessionCreated !== false ? "syncing" : "running";
2439
2520
  this.setState({
2440
2521
  status: nextStatus,
@@ -2472,8 +2553,8 @@ var IviRuntimeCoordinator = class {
2472
2553
  onTracksChanged(listRefreshed) {
2473
2554
  const nextStage = this.stageManager.getStage();
2474
2555
  this.sourceManager.syncWithTracks(this.trackManager.getAll());
2475
- this.trtcSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2476
- this.livekitSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2556
+ this.ensureBootstrapSourceRegistered();
2557
+ this.syncPlaybackManagers();
2477
2558
  this.setState({
2478
2559
  ...this.state,
2479
2560
  tracks: this.trackManager.getAll(),
@@ -2487,8 +2568,8 @@ var IviRuntimeCoordinator = class {
2487
2568
  applyLocalTrackTake(trackId) {
2488
2569
  this.trackManager.applyTrackTook(trackId);
2489
2570
  this.sourceManager.syncWithTracks(this.trackManager.getAll());
2490
- this.trtcSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2491
- this.livekitSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2571
+ this.ensureBootstrapSourceRegistered();
2572
+ this.syncPlaybackManagers();
2492
2573
  this.setState({
2493
2574
  ...this.state,
2494
2575
  tracks: this.trackManager.getAll(),
@@ -2528,8 +2609,8 @@ var IviRuntimeCoordinator = class {
2528
2609
  }
2529
2610
  onSourcesChanged(listRefreshed) {
2530
2611
  this.sourceManager.syncWithTracks(this.trackManager.getAll());
2531
- this.trtcSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2532
- this.livekitSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2612
+ this.ensureBootstrapSourceRegistered();
2613
+ this.syncPlaybackManagers();
2533
2614
  this.setState({
2534
2615
  ...this.state,
2535
2616
  sources: this.sourceManager.getAll()
@@ -2552,12 +2633,101 @@ var IviRuntimeCoordinator = class {
2552
2633
  });
2553
2634
  }
2554
2635
  setState(nextState) {
2555
- if (this.state.status === nextState.status && this.state.session === nextState.session && this.state.stage === nextState.stage && this.state.tracks === nextState.tracks && this.state.sources === nextState.sources && this.state.streams === nextState.streams && this.state.conversationItems === nextState.conversationItems && this.state.conversations === nextState.conversations) {
2636
+ let resolvedNextState = nextState;
2637
+ if (this.bootstrapSource && nextState.status !== "stopped" && !nextState.sources.has(this.bootstrapSource.sourceId)) {
2638
+ this.ensureBootstrapSourceRegistered();
2639
+ resolvedNextState = {
2640
+ ...nextState,
2641
+ sources: this.sourceManager.getAll()
2642
+ };
2643
+ }
2644
+ const composedNextState = this.composeBootstrapState(resolvedNextState);
2645
+ if (this.state.status === composedNextState.status && this.state.session === composedNextState.session && this.state.stage === composedNextState.stage && this.state.tracks === composedNextState.tracks && this.state.sources === composedNextState.sources && this.state.streams === composedNextState.streams && this.state.conversationItems === composedNextState.conversationItems && this.state.conversations === composedNextState.conversations && isSameBootstrapState(this.state.bootstrap, composedNextState.bootstrap)) {
2556
2646
  return;
2557
2647
  }
2558
- this.state = nextState;
2648
+ this.state = composedNextState;
2559
2649
  this.stateListeners.forEach((listener) => listener(this.state));
2560
2650
  }
2651
+ composeBootstrapState(nextState) {
2652
+ const bootstrap = this.bootstrapSource;
2653
+ if (!bootstrap) {
2654
+ return nextState.bootstrap === null || nextState.bootstrap === void 0 ? nextState : { ...nextState, bootstrap: null };
2655
+ }
2656
+ const shouldExpose = this.shouldExposeBootstrap(nextState, bootstrap);
2657
+ const bootstrapState = {
2658
+ active: shouldExpose,
2659
+ slot: bootstrap.slot,
2660
+ trackId: bootstrap.trackId,
2661
+ sourceId: bootstrap.sourceId,
2662
+ streamId: bootstrap.streamId
2663
+ };
2664
+ if (!shouldExpose) {
2665
+ return {
2666
+ ...nextState,
2667
+ bootstrap: bootstrapState
2668
+ };
2669
+ }
2670
+ const tracks = new Map(nextState.tracks);
2671
+ tracks.set(bootstrap.trackId, {
2672
+ track_id: bootstrap.trackId,
2673
+ active_source_id: bootstrap.sourceId
2674
+ });
2675
+ return {
2676
+ ...nextState,
2677
+ tracks,
2678
+ bootstrap: bootstrapState
2679
+ };
2680
+ }
2681
+ shouldExposeBootstrap(state, bootstrap) {
2682
+ if (state.status === "stopped") {
2683
+ return false;
2684
+ }
2685
+ const bootstrapRuntimeSource = state.sources.get(bootstrap.sourceId);
2686
+ if (!isReadyRenderableSource(bootstrapRuntimeSource)) {
2687
+ return false;
2688
+ }
2689
+ const layer = (state.stage?.composition ?? []).find((item) => item.slot === bootstrap.slot);
2690
+ if (!layer) {
2691
+ return true;
2692
+ }
2693
+ const track = state.tracks.get(layer.track_id);
2694
+ const activeSourceId = track?.active_source_id;
2695
+ if (!activeSourceId || activeSourceId === bootstrap.sourceId) {
2696
+ return true;
2697
+ }
2698
+ return !this.isReadyForBootstrapHandoff(activeSourceId, state.sources.get(activeSourceId));
2699
+ }
2700
+ isReadyForBootstrapHandoff(sourceId, source) {
2701
+ if (!isReadyRenderableSource(source)) {
2702
+ return false;
2703
+ }
2704
+ if (isTrtcPlaybackSource(source)) {
2705
+ return this.trtcSourceManager.hasRemoteVideoAvailable(sourceId);
2706
+ }
2707
+ if (isLivekitPlaybackSource(source)) {
2708
+ return this.livekitSourceManager.hasRemoteVideoAvailable(sourceId);
2709
+ }
2710
+ return true;
2711
+ }
2712
+ recomposeBootstrapState() {
2713
+ if (!this.bootstrapSource) {
2714
+ return;
2715
+ }
2716
+ this.setState({ ...this.state });
2717
+ }
2718
+ ensureBootstrapSourceRegistered() {
2719
+ if (!this.bootstrapSource) {
2720
+ return;
2721
+ }
2722
+ if (this.sourceManager.has(this.bootstrapSource.sourceId)) {
2723
+ return;
2724
+ }
2725
+ this.sourceManager.upsertBootstrapReady(this.bootstrapSource);
2726
+ }
2727
+ syncPlaybackManagers() {
2728
+ this.trtcSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2729
+ this.livekitSourceManager.syncRuntimeSources(this.sourceManager.getAll());
2730
+ }
2561
2731
  emitEvent(event) {
2562
2732
  this.progressUserTextToResponseFlows(event);
2563
2733
  this.eventListeners.forEach((listener) => listener(event, this.state));
@@ -2566,6 +2736,12 @@ var IviRuntimeCoordinator = class {
2566
2736
  this.config.onTrtcEvent?.(event);
2567
2737
  this.trtcEventListeners.forEach((listener) => listener(event));
2568
2738
  }
2739
+ onTrtcManagerEvent(event) {
2740
+ this.emitTrtcEvent(event);
2741
+ if (event.type === "remote_video_available") {
2742
+ this.recomposeBootstrapState();
2743
+ }
2744
+ }
2569
2745
  resetStoppedState() {
2570
2746
  this.rejectPendingUserTextToResponseFlows(
2571
2747
  new Error("Runtime stopped before user text to response flow completed.")
@@ -2730,7 +2906,331 @@ function isLivekitPlaybackSource(source) {
2730
2906
  if (!source || !source.playback) return false;
2731
2907
  return isLivekitSourcePlayback(source.playback);
2732
2908
  }
2909
+ function isReadyRenderableSource(source) {
2910
+ return Boolean(source && source.status === "ready" && source.playback);
2911
+ }
2912
+ function isSameBootstrapState(a, b) {
2913
+ if (!a && !b) return true;
2914
+ if (!a || !b) return false;
2915
+ return a.active === b.active && a.slot === b.slot && a.trackId === b.trackId && a.sourceId === b.sourceId && a.streamId === b.streamId;
2916
+ }
2917
+ var IviCreateIVISessionError = class extends Error {
2918
+ constructor(response, body) {
2919
+ super(`CreateIVISession failed with ${response.status} ${response.statusText}`);
2920
+ this.name = "IviCreateIVISessionError";
2921
+ this.status = response.status;
2922
+ this.statusText = response.statusText;
2923
+ this.body = body;
2924
+ }
2925
+ };
2926
+ async function createIVISession(request, options) {
2927
+ const fetchImpl = options.fetch ?? globalThis.fetch;
2928
+ if (!fetchImpl) {
2929
+ throw new Error("fetch is not available. Pass options.fetch to createIVISession.");
2930
+ }
2931
+ const requestBody = toCpCreateIVISessionRequestBody(request);
2932
+ const response = await fetchImpl(resolveCreateIVISessionUrl(options), {
2933
+ method: "POST",
2934
+ headers: await buildHeaders(options.headers),
2935
+ body: JSON.stringify(requestBody),
2936
+ credentials: options.credentials,
2937
+ signal: options.signal
2938
+ });
2939
+ const responseBody = await readJsonResponse(response);
2940
+ if (!response.ok) {
2941
+ throw new IviCreateIVISessionError(response, responseBody);
2942
+ }
2943
+ return normalizeCreateIVISessionResponse(responseBody, request, requestBody);
2944
+ }
2945
+ function createRuntimeFromSession(session, options = {}) {
2946
+ const websocketUrl = buildWebSocketUrl(session.endpoint, options.websocket);
2947
+ const client = new IviClient({
2948
+ ...options.clientConfig ?? {},
2949
+ transport: new WebSocketTransport({
2950
+ url: websocketUrl,
2951
+ sessionId: session.iviSessionId,
2952
+ protocols: options.websocket?.protocols,
2953
+ socketFactory: options.websocket?.socketFactory
2954
+ })
2955
+ });
2956
+ const runtime = new IviRuntimeCoordinator(client, options.runtimeConfig);
2957
+ if (options.fastStart !== false && session.prebuiltPlayback) {
2958
+ runtime.setBootstrapSource(toBootstrapSource(session.prebuiltPlayback, options));
2959
+ }
2960
+ return {
2961
+ session,
2962
+ client,
2963
+ runtime
2964
+ };
2965
+ }
2966
+ async function createIVISessionRuntime(request, options) {
2967
+ const session = await createIVISession(request, options.http);
2968
+ return createRuntimeFromSession(session, options);
2969
+ }
2970
+ function toCpCreateIVISessionRequestBody(request) {
2971
+ const body = { ...request };
2972
+ delete body.idempotencyKey;
2973
+ delete body.streamType;
2974
+ delete body.iviVersion;
2975
+ delete body.sessionParameters;
2976
+ delete body.enableDecoderPublish;
2977
+ delete body.sessionRecording;
2978
+ delete body.prebuiltCharacters;
2979
+ delete body.prebuiltStream;
2980
+ if (request.idempotencyKey !== void 0) body.idempotency_key = request.idempotencyKey;
2981
+ if (request.streamType !== void 0) body.stream_type = request.streamType;
2982
+ if (request.iviVersion !== void 0) body.ivi_version = request.iviVersion;
2983
+ if (request.sessionParameters !== void 0) body.session_parameters = request.sessionParameters;
2984
+ if (request.enableDecoderPublish !== void 0) body.enable_decoder_publish = request.enableDecoderPublish;
2985
+ if (request.sessionRecording !== void 0) {
2986
+ body.session_recording = {
2987
+ enabled: request.sessionRecording.enabled,
2988
+ aspect_ratio: request.sessionRecording.aspectRatio
2989
+ };
2990
+ }
2991
+ if (request.prebuiltCharacters !== void 0) {
2992
+ body.prebuilt_characters = request.prebuiltCharacters.map((character) => ({
2993
+ character_id: character.characterId,
2994
+ character_payload: serializePrebuiltPayload(character.characterPayload)
2995
+ }));
2996
+ }
2997
+ if (request.prebuiltStream !== void 0) {
2998
+ body.prebuilt_stream = {
2999
+ stream_id: request.prebuiltStream.streamId,
3000
+ mode: request.prebuiltStream.mode,
3001
+ stream_config: serializePrebuiltPayload(request.prebuiltStream.streamConfig)
3002
+ };
3003
+ }
3004
+ return body;
3005
+ }
3006
+ function normalizeCreateIVISessionResponse(responseBody, request = {}, requestBody = toCpCreateIVISessionRequestBody(request)) {
3007
+ const payload = unwrapResponsePayload(responseBody);
3008
+ const iviSessionId = getString(payload, "ivi_session_id") ?? getString(payload, "iviSessionId");
3009
+ const endpoint = getString(payload, "endpoint");
3010
+ if (!iviSessionId) {
3011
+ throw new Error("CreateIVISession response missing ivi_session_id.");
3012
+ }
3013
+ if (!endpoint) {
3014
+ throw new Error("CreateIVISession response missing endpoint.");
3015
+ }
3016
+ const trtcInfo = normalizeTrtcInfo(getObjectValue(payload, "trtc_info") ?? getObjectValue(payload, "trtcInfo"));
3017
+ const livekitInfo = normalizeLivekitInfo(getObjectValue(payload, "livekit_info") ?? getObjectValue(payload, "livekitInfo"));
3018
+ const prebuildInfo = getObjectValue(payload, "prebuild_trtc_info") ?? getObjectValue(payload, "prebuildTrtcInfo");
3019
+ const prebuildTrtcInfo = normalizeTrtcInfo(
3020
+ getObjectValue(prebuildInfo, "trtc_info") ?? getObjectValue(prebuildInfo, "trtcInfo")
3021
+ );
3022
+ const prebuildLivekitInfo = normalizeLivekitInfo(
3023
+ getObjectValue(prebuildInfo, "livekit_info") ?? getObjectValue(prebuildInfo, "livekitInfo")
3024
+ );
3025
+ const prebuiltPlayback = buildPrebuiltPlayback(
3026
+ request,
3027
+ requestBody,
3028
+ prebuildTrtcInfo,
3029
+ prebuildLivekitInfo
3030
+ );
3031
+ return {
3032
+ iviSessionId,
3033
+ endpoint,
3034
+ tokenInfo: getObjectValue(payload, "token_info") ?? getObjectValue(payload, "tokenInfo"),
3035
+ trtcInfo,
3036
+ livekitInfo,
3037
+ prebuildTrtcInfo: prebuildTrtcInfo || prebuildLivekitInfo ? {
3038
+ trtcInfo: prebuildTrtcInfo,
3039
+ livekitInfo: prebuildLivekitInfo
3040
+ } : void 0,
3041
+ prebuiltPlayback,
3042
+ raw: responseBody,
3043
+ requestBody
3044
+ };
3045
+ }
3046
+ function resolveCreateIVISessionUrl(options) {
3047
+ if (options.url) return options.url;
3048
+ if (!options.baseUrl) {
3049
+ throw new Error("CreateIVISession requires options.baseUrl or options.url.");
3050
+ }
3051
+ const path = options.path ?? "/v1/ivi/sessions";
3052
+ return new URL(path, ensureTrailingSlash(options.baseUrl)).toString();
3053
+ }
3054
+ async function buildHeaders(headers) {
3055
+ const resolvedHeaders = typeof headers === "function" ? await headers() : headers;
3056
+ const next = new Headers(resolvedHeaders);
3057
+ if (!next.has("content-type")) {
3058
+ next.set("content-type", "application/json");
3059
+ }
3060
+ return next;
3061
+ }
3062
+ async function readJsonResponse(response) {
3063
+ const text = await response.text();
3064
+ if (!text) {
3065
+ return null;
3066
+ }
3067
+ try {
3068
+ return JSON.parse(text);
3069
+ } catch {
3070
+ return text;
3071
+ }
3072
+ }
3073
+ function buildWebSocketUrl(endpoint, options) {
3074
+ const rawUrl = options?.url ?? endpoint;
3075
+ if (!options?.query) {
3076
+ return rawUrl;
3077
+ }
3078
+ const url = new URL(rawUrl);
3079
+ Object.entries(options.query).forEach(([key, value]) => {
3080
+ if (value === void 0 || value === null) return;
3081
+ url.searchParams.set(key, value);
3082
+ });
3083
+ return url.toString();
3084
+ }
3085
+ function toBootstrapSource(prebuiltPlayback, options) {
3086
+ return {
3087
+ sourceId: prebuiltPlayback.sourceId,
3088
+ streamId: prebuiltPlayback.streamId,
3089
+ slot: options.bootstrapSlot ?? "main",
3090
+ trackId: options.bootstrapTrackId ?? "__ivi_bootstrap_track",
3091
+ playback: prebuiltPlayback.playback,
3092
+ source: {
3093
+ source_id: prebuiltPlayback.sourceId,
3094
+ kind: prebuiltPlayback.streamId ? "generation_stream" : "stream",
3095
+ stream_id: prebuiltPlayback.streamId,
3096
+ asset_type: "video",
3097
+ metadata: {
3098
+ label: "prebuilt"
3099
+ }
3100
+ }
3101
+ };
3102
+ }
3103
+ function buildPrebuiltPlayback(request, requestBody, trtcInfo, livekitInfo) {
3104
+ if (!trtcInfo && !livekitInfo) {
3105
+ return void 0;
3106
+ }
3107
+ const streamId = resolvePrebuiltStreamId(request, requestBody, trtcInfo, livekitInfo);
3108
+ const sourceId = request.prebuiltStream?.sourceId ?? streamId;
3109
+ if (!sourceId) {
3110
+ return void 0;
3111
+ }
3112
+ if (trtcInfo) {
3113
+ return {
3114
+ sourceId,
3115
+ streamId,
3116
+ kind: "trtc",
3117
+ playback: {
3118
+ type: "trtc",
3119
+ trtc: trtcInfo
3120
+ },
3121
+ provisional: true
3122
+ };
3123
+ }
3124
+ if (livekitInfo) {
3125
+ return {
3126
+ sourceId,
3127
+ streamId,
3128
+ kind: "livekit",
3129
+ playback: {
3130
+ type: "livekit",
3131
+ livekit: livekitInfo
3132
+ },
3133
+ provisional: true
3134
+ };
3135
+ }
3136
+ return void 0;
3137
+ }
3138
+ function resolvePrebuiltStreamId(request, requestBody, trtcInfo, livekitInfo) {
3139
+ const prebuiltStream = getObjectValue(requestBody, "prebuilt_stream");
3140
+ return request.prebuiltStream?.streamId ?? getString(prebuiltStream, "stream_id") ?? getString(prebuiltStream, "streamId") ?? trtcInfo?.room_id ?? livekitInfo?.room;
3141
+ }
3142
+ function normalizeTrtcInfo(value) {
3143
+ if (!isRecord(value)) {
3144
+ return void 0;
3145
+ }
3146
+ const appId = getString(value, "app_id") ?? getString(value, "appId");
3147
+ const roomId = getString(value, "room_id") ?? getString(value, "roomId");
3148
+ const userId = getString(value, "user_id") ?? getString(value, "userId");
3149
+ const userSig = getString(value, "user_sig") ?? getString(value, "userSig");
3150
+ if (!appId || !roomId || !userId || !userSig) {
3151
+ return void 0;
3152
+ }
3153
+ const normalized = {
3154
+ ...value,
3155
+ app_id: appId,
3156
+ room_id: roomId,
3157
+ user_id: userId,
3158
+ user_sig: userSig
3159
+ };
3160
+ delete normalized.secret_key;
3161
+ delete normalized.secretKey;
3162
+ return normalized;
3163
+ }
3164
+ function normalizeLivekitInfo(value) {
3165
+ if (!isRecord(value)) {
3166
+ return void 0;
3167
+ }
3168
+ const wsUrl = getString(value, "ws_url") ?? getString(value, "url") ?? getString(value, "wsUrl");
3169
+ const token = getString(value, "token") ?? getString(value, "access_token") ?? getString(value, "accessToken");
3170
+ if (!wsUrl || !token) {
3171
+ return void 0;
3172
+ }
3173
+ return {
3174
+ ws_url: wsUrl,
3175
+ token,
3176
+ room: getString(value, "room") ?? getString(value, "room_name") ?? getString(value, "roomName"),
3177
+ identity: getString(value, "identity")
3178
+ };
3179
+ }
3180
+ function serializePrebuiltPayload(value) {
3181
+ if (typeof value === "string") {
3182
+ return value;
3183
+ }
3184
+ return encodeJsonBase64(value);
3185
+ }
3186
+ function encodeJsonBase64(value) {
3187
+ const bytes = new TextEncoder().encode(JSON.stringify(value));
3188
+ let binary = "";
3189
+ bytes.forEach((byte) => {
3190
+ binary += String.fromCharCode(byte);
3191
+ });
3192
+ if (typeof btoa === "function") {
3193
+ return btoa(binary);
3194
+ }
3195
+ const maybeBuffer = globalThis.Buffer;
3196
+ if (maybeBuffer) {
3197
+ return maybeBuffer.from(bytes).toString("base64");
3198
+ }
3199
+ throw new Error("Base64 encoder is not available in this runtime.");
3200
+ }
3201
+ function unwrapResponsePayload(value) {
3202
+ if (!isRecord(value)) {
3203
+ return {};
3204
+ }
3205
+ const data = getObjectValue(value, "data");
3206
+ return data ?? value;
3207
+ }
3208
+ function getObjectValue(value, key) {
3209
+ if (!isRecord(value)) {
3210
+ return void 0;
3211
+ }
3212
+ const nested = value[key];
3213
+ return isRecord(nested) ? nested : void 0;
3214
+ }
3215
+ function getString(value, key) {
3216
+ if (!isRecord(value)) {
3217
+ return void 0;
3218
+ }
3219
+ const nested = value[key];
3220
+ return typeof nested === "string" && nested.trim().length > 0 ? nested.trim() : void 0;
3221
+ }
3222
+ function isRecord(value) {
3223
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3224
+ }
3225
+ function ensureTrailingSlash(value) {
3226
+ return value.endsWith("/") ? value : `${value}/`;
3227
+ }
3228
+
3229
+ // src/sdk.ts
2733
3230
  var IviFrontendSdk = class {
3231
+ constructor(config = {}) {
3232
+ this.config = config;
3233
+ }
2734
3234
  createClient(config) {
2735
3235
  return new IviClient(config);
2736
3236
  }
@@ -2738,6 +3238,25 @@ var IviFrontendSdk = class {
2738
3238
  const client = this.createClient(clientConfig);
2739
3239
  return new IviRuntimeCoordinator(client, runtimeConfig);
2740
3240
  }
3241
+ createIVISession(request, options) {
3242
+ return createIVISession(request, {
3243
+ ...this.config.http ?? {},
3244
+ ...options ?? {}
3245
+ });
3246
+ }
3247
+ createRuntimeFromSession(session, options) {
3248
+ return createRuntimeFromSession(session, options);
3249
+ }
3250
+ createIVISessionRuntime(request, options) {
3251
+ const http = {
3252
+ ...this.config.http ?? {},
3253
+ ...options?.http ?? {}
3254
+ };
3255
+ return createIVISessionRuntime(request, {
3256
+ ...options ?? {},
3257
+ http
3258
+ });
3259
+ }
2741
3260
  };
2742
3261
  var IviStageViewContext = createContext(null);
2743
3262
  var EMPTY_RUNTIME_STATE = {
@@ -2748,7 +3267,8 @@ var EMPTY_RUNTIME_STATE = {
2748
3267
  sources: /* @__PURE__ */ new Map(),
2749
3268
  streams: /* @__PURE__ */ new Map(),
2750
3269
  conversationItems: /* @__PURE__ */ new Map(),
2751
- conversations: []
3270
+ conversations: [],
3271
+ bootstrap: null
2752
3272
  };
2753
3273
  function useRuntimeState(runtime) {
2754
3274
  const [state, setState] = useState(() => runtime?.getState() ?? EMPTY_RUNTIME_STATE);
@@ -2776,10 +3296,10 @@ function IVIStageView(props) {
2776
3296
  const state = useRuntimeState(runtime);
2777
3297
  const slotTrackMap = useMemo(() => {
2778
3298
  return buildSlotTrackMapFromState(state);
2779
- }, [state.stage]);
3299
+ }, [state.stage, state.bootstrap]);
2780
3300
  const slotBindings = useMemo(() => {
2781
3301
  return buildSlotBindingsFromState(state);
2782
- }, [state.stage, state.tracks, state.sources]);
3302
+ }, [state.stage, state.tracks, state.sources, state.bootstrap]);
2783
3303
  useEffect(() => {
2784
3304
  onBindingsChange?.(slotBindings);
2785
3305
  }, [slotBindings, onBindingsChange]);
@@ -2819,15 +3339,18 @@ function buildSlotTrackMapFromState(state) {
2819
3339
  (state.stage?.composition ?? []).forEach((item) => {
2820
3340
  map.set(item.slot, item.track_id);
2821
3341
  });
3342
+ if (state.bootstrap?.active) {
3343
+ map.set(state.bootstrap.slot, state.bootstrap.trackId);
3344
+ }
2822
3345
  return map;
2823
3346
  }
2824
3347
  function buildSlotBindingsFromState(state) {
2825
- const bindings = [];
3348
+ const bindingsBySlot = /* @__PURE__ */ new Map();
2826
3349
  (state.stage?.composition ?? []).forEach((item) => {
2827
3350
  const track = state.tracks.get(item.track_id);
2828
3351
  const sourceId = track?.active_source_id ?? null;
2829
3352
  const source = sourceId ? state.sources.get(sourceId) : void 0;
2830
- bindings.push({
3353
+ bindingsBySlot.set(item.slot, {
2831
3354
  slot: item.slot,
2832
3355
  trackId: item.track_id,
2833
3356
  track,
@@ -2835,7 +3358,18 @@ function buildSlotBindingsFromState(state) {
2835
3358
  source
2836
3359
  });
2837
3360
  });
2838
- return bindings;
3361
+ if (state.bootstrap?.active) {
3362
+ const track = state.tracks.get(state.bootstrap.trackId);
3363
+ const source = state.sources.get(state.bootstrap.sourceId);
3364
+ bindingsBySlot.set(state.bootstrap.slot, {
3365
+ slot: state.bootstrap.slot,
3366
+ trackId: state.bootstrap.trackId,
3367
+ track,
3368
+ sourceId: state.bootstrap.sourceId,
3369
+ source
3370
+ });
3371
+ }
3372
+ return Array.from(bindingsBySlot.values());
2839
3373
  }
2840
3374
  var VOLUME_STORAGE_KEY = "ivi-volume-preferences";
2841
3375
  var DEFAULT_VOLUME = 80;
@@ -3603,23 +4137,25 @@ function IVITrtcPlayer(props) {
3603
4137
  const [loading, setLoading] = useState(true);
3604
4138
  const [error, setError] = useState(null);
3605
4139
  const mutedRef = useRef(muted);
4140
+ const attachedSourceIdRef = useRef(null);
3606
4141
  mutedRef.current = muted;
4142
+ useEffect(() => {
4143
+ const unsubscribe = manager.subscribe(resolvedSourceId, (snapshot) => {
4144
+ setLoading(snapshot.status === "idle" || snapshot.status === "connecting");
4145
+ setError(snapshot.status === "error" ? snapshot.error ?? "TRTC \u62C9\u6D41\u5931\u8D25" : null);
4146
+ });
4147
+ return unsubscribe;
4148
+ }, [manager, resolvedSourceId]);
3607
4149
  useEffect(() => {
3608
4150
  const container = containerRef.current;
3609
4151
  if (!container) {
3610
4152
  return;
3611
4153
  }
3612
4154
  let disposed = false;
4155
+ attachedSourceIdRef.current = resolvedSourceId;
3613
4156
  if (shouldManageSourceLifecycle) {
3614
4157
  manager.upsertSource(resolvedSourceId, trtc, trtcAIDenoiser);
3615
4158
  }
3616
- const unsubscribe = manager.subscribe(resolvedSourceId, (snapshot) => {
3617
- if (disposed) {
3618
- return;
3619
- }
3620
- setLoading(snapshot.status === "idle" || snapshot.status === "connecting");
3621
- setError(snapshot.status === "error" ? snapshot.error ?? "TRTC \u62C9\u6D41\u5931\u8D25" : null);
3622
- });
3623
4159
  void manager.attachView(resolvedSourceId, viewIdRef.current, container, mutedRef.current).catch((caughtError) => {
3624
4160
  if (disposed) {
3625
4161
  return;
@@ -3629,15 +4165,15 @@ function IVITrtcPlayer(props) {
3629
4165
  });
3630
4166
  return () => {
3631
4167
  disposed = true;
3632
- unsubscribe();
3633
- manager.detachView(resolvedSourceId, viewIdRef.current);
4168
+ const attachedSourceId = attachedSourceIdRef.current ?? resolvedSourceId;
4169
+ manager.detachView(attachedSourceId, viewIdRef.current);
3634
4170
  if (shouldManageSourceLifecycle) {
3635
- manager.removeSource(resolvedSourceId);
4171
+ manager.removeSource(attachedSourceId);
3636
4172
  }
4173
+ attachedSourceIdRef.current = null;
3637
4174
  };
3638
4175
  }, [
3639
4176
  manager,
3640
- resolvedSourceId,
3641
4177
  shouldManageSourceLifecycle,
3642
4178
  trtc.app_id,
3643
4179
  trtc.room_id,
@@ -3645,6 +4181,15 @@ function IVITrtcPlayer(props) {
3645
4181
  trtc.user_sig,
3646
4182
  trtcAIDenoiser
3647
4183
  ]);
4184
+ useEffect(() => {
4185
+ const previousSourceId = attachedSourceIdRef.current;
4186
+ if (!previousSourceId || previousSourceId === resolvedSourceId) {
4187
+ return;
4188
+ }
4189
+ if (manager.reassignView(previousSourceId, resolvedSourceId, viewIdRef.current)) {
4190
+ attachedSourceIdRef.current = resolvedSourceId;
4191
+ }
4192
+ }, [manager, resolvedSourceId]);
3648
4193
  useEffect(() => {
3649
4194
  manager.updateViewMuted(resolvedSourceId, viewIdRef.current, muted);
3650
4195
  }, [manager, muted, resolvedSourceId]);
@@ -4152,13 +4697,7 @@ function getSourceRenderKey(sourceId, source) {
4152
4697
  if (!trtc) {
4153
4698
  return sourceId;
4154
4699
  }
4155
- return [
4156
- "trtc",
4157
- trtc.app_id ?? "",
4158
- trtc.room_id ?? "",
4159
- trtc.user_id ?? "",
4160
- trtc.user_sig ?? ""
4161
- ].join(":");
4700
+ return ["trtc", trtc.app_id ?? "", trtc.room_id ?? ""].join(":");
4162
4701
  }
4163
4702
  function TrackSlotMediaContent(props) {
4164
4703
  const {
@@ -4614,7 +5153,83 @@ function getClientLogTag(category) {
4614
5153
  if (category === "reconnect") return "[IVI-RECONNECT]";
4615
5154
  return "[IVI-CLIENT]";
4616
5155
  }
5156
+ function useIviSessionRuntime(config) {
5157
+ const [status, setStatus] = useState("idle");
5158
+ const [session, setSession] = useState(null);
5159
+ const [runtime, setRuntime] = useState(null);
5160
+ const [client, setClient] = useState(null);
5161
+ const [error, setError] = useState(null);
5162
+ useEffect(() => {
5163
+ const {
5164
+ request,
5165
+ enabled = true,
5166
+ autoStart = true,
5167
+ onCreated,
5168
+ onRuntimeReady,
5169
+ onError,
5170
+ ...options
5171
+ } = config;
5172
+ if (!enabled || !request) {
5173
+ setStatus("idle");
5174
+ setSession(null);
5175
+ setRuntime(null);
5176
+ setClient(null);
5177
+ setError(null);
5178
+ return;
5179
+ }
5180
+ let disposed = false;
5181
+ let activeRuntime = null;
5182
+ setStatus("creating");
5183
+ setSession(null);
5184
+ setRuntime(null);
5185
+ setClient(null);
5186
+ setError(null);
5187
+ void createIVISessionRuntime(request, options).then(async (created) => {
5188
+ if (disposed) {
5189
+ created.runtime.stop();
5190
+ return;
5191
+ }
5192
+ activeRuntime = created.runtime;
5193
+ setSession(created.session);
5194
+ setRuntime(created.runtime);
5195
+ setClient(created.client);
5196
+ onCreated?.(created.session);
5197
+ onRuntimeReady?.(created.runtime, created.client);
5198
+ if (!autoStart) {
5199
+ setStatus("idle");
5200
+ return;
5201
+ }
5202
+ setStatus("connecting");
5203
+ await created.runtime.start();
5204
+ if (disposed) {
5205
+ created.runtime.stop();
5206
+ return;
5207
+ }
5208
+ setStatus("running");
5209
+ }).catch((caughtError) => {
5210
+ if (disposed) {
5211
+ return;
5212
+ }
5213
+ const normalizedError = caughtError instanceof Error ? caughtError : new Error(String(caughtError));
5214
+ setError(normalizedError);
5215
+ setStatus("error");
5216
+ onError?.(caughtError);
5217
+ });
5218
+ return () => {
5219
+ disposed = true;
5220
+ activeRuntime?.stop();
5221
+ setStatus("stopped");
5222
+ };
5223
+ }, [config]);
5224
+ return {
5225
+ status,
5226
+ session,
5227
+ runtime,
5228
+ client,
5229
+ error
5230
+ };
5231
+ }
4617
5232
 
4618
- export { DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS, EMPTY_RUNTIME_STATE, IVILivekitPlayer, IVIStageView, IVISubtitleOverlay, IVITrackSlot, IVITrtcPlayer, IviFrontendSdk, IviRuntimeCoordinator, IviRuntimeDispatcher, LivekitSourceManager, TrtcSourceManager, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
5233
+ export { DEFAULT_HIDE_COMPLETED_SUBTITLE_AFTER_MS, EMPTY_RUNTIME_STATE, IVILivekitPlayer, IVIStageView, IVISubtitleOverlay, IVITrackSlot, IVITrtcPlayer, IviCreateIVISessionError, IviFrontendSdk, IviRuntimeCoordinator, IviRuntimeDispatcher, LivekitSourceManager, TrtcSourceManager, createIVISession, createIVISessionRuntime, createRuntimeFromSession, isLivekitSourcePlayback, isReadyLivekitRuntimeSource, isSameLivekitConfig, normalizeCreateIVISessionResponse, toCpCreateIVISessionRequestBody, useIviSessionRuntime, useIviStageView, useIviSubtitles, useManagedIviRuntime, useRuntimeState };
4619
5234
  //# sourceMappingURL=index.js.map
4620
5235
  //# sourceMappingURL=index.js.map