obi-sdk 0.3.13 → 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/README.md +25 -0
- package/dist/loader.d.ts +5 -2
- package/dist/modular/chunks/{obi-widget-d7e7c6bf.js → obi-widget-9ef6796a.js} +104 -35
- package/dist/modular/chunks/obi-widget-9ef6796a.js.map +1 -0
- package/dist/modular/index.js +1 -1
- package/dist/modular/ui.js +10 -10
- package/dist/obi-sdk.es.js +103 -34
- package/dist/obi-sdk.es.js.map +1 -1
- package/dist/obi-sdk.standalone.iife.js +8 -17
- package/dist/obi-sdk.standalone.iife.js.map +1 -1
- package/dist/obi-sdk.umd.js +8 -17
- package/dist/obi-sdk.umd.js.map +1 -1
- package/dist/ui/components/obi-widget.d.ts +3 -1
- package/package.json +4 -4
- package/dist/modular/chunks/obi-widget-d7e7c6bf.js.map +0 -1
package/README.md
CHANGED
|
@@ -21,6 +21,7 @@ The loader accepts the following configuration options:
|
|
|
21
21
|
| `apiKey` | string | - | Your Obi API key (required for production) |
|
|
22
22
|
| `user` | object | - | User information with `id` (required), `email` (optional) and `metadata` (optional) |
|
|
23
23
|
| `isActive` | boolean | `true` | Whether to show the widget. Set to `false` to disable the widget for specific users |
|
|
24
|
+
| `linkOnlyAccess` | boolean | `false` | Hide the widget unless accessed via a session link. Perfect for trial periods where only customers with direct links should see the widget |
|
|
24
25
|
| `primaryColor` | string | - | Custom primary color for the widget UI (CSS color value) |
|
|
25
26
|
| `secondaryColor` | string | - | Custom secondary color for the widget UI (CSS color value) |
|
|
26
27
|
|
|
@@ -41,6 +42,30 @@ window.obiWidgetConfig = {
|
|
|
41
42
|
}
|
|
42
43
|
```
|
|
43
44
|
|
|
45
|
+
## Trial Mode / Link-Only Access
|
|
46
|
+
|
|
47
|
+
The `linkOnlyAccess` option is perfect for trial periods where you want to control who can see and interact with the widget. When enabled, the widget remains hidden until a session is started via a direct link.
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
window.obiWidgetConfig = {
|
|
51
|
+
apiKey: "YOUR_API_KEY",
|
|
52
|
+
linkOnlyAccess: true, // Widget only visible when accessed via session link
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This is ideal for:
|
|
57
|
+
|
|
58
|
+
- Trial periods where only specific customers should see the widget
|
|
59
|
+
- Beta testing with selected users
|
|
60
|
+
- Controlled rollouts using session-specific links
|
|
61
|
+
- Demo environments where widget access is link-based
|
|
62
|
+
|
|
63
|
+
When `linkOnlyAccess` is `true`:
|
|
64
|
+
|
|
65
|
+
- Widget is invisible to regular website visitors
|
|
66
|
+
- Widget becomes visible only when a session is started (e.g., via URL parameters)
|
|
67
|
+
- Once a session ends, the widget returns to hidden state
|
|
68
|
+
|
|
44
69
|
## Session Persistence
|
|
45
70
|
|
|
46
71
|
The SDK now supports session persistence across page reloads and navigation. If a user refreshes the page or navigates to another page on your site, the session with Obi will be automatically restored when they return, providing a seamless experience.
|
package/dist/loader.d.ts
CHANGED
|
@@ -10,9 +10,12 @@ interface ObiWidgetConfig {
|
|
|
10
10
|
user?: {
|
|
11
11
|
id: string;
|
|
12
12
|
email?: string;
|
|
13
|
-
metadata?: any
|
|
14
|
-
};
|
|
13
|
+
metadata?: Record<string, any>;
|
|
14
|
+
} | null;
|
|
15
15
|
isActive?: boolean;
|
|
16
|
+
linkOnlyAccess?: boolean;
|
|
17
|
+
primaryColor?: string;
|
|
18
|
+
secondaryColor?: string;
|
|
16
19
|
}
|
|
17
20
|
declare class ObiWidgetLoader {
|
|
18
21
|
private config;
|
|
@@ -534,6 +534,9 @@ class ObiSession {
|
|
|
534
534
|
this._userAudioTimer = null;
|
|
535
535
|
this.sessionId = sessionId;
|
|
536
536
|
this.apiBaseUrl = apiBaseUrl || DEFAULT_API_BASE_URL;
|
|
537
|
+
this.client = new ObiClient({
|
|
538
|
+
baseUrl: this.apiBaseUrl
|
|
539
|
+
});
|
|
537
540
|
this.emitter = new EventEmitter();
|
|
538
541
|
}
|
|
539
542
|
emit(event, data) {
|
|
@@ -590,7 +593,7 @@ class ObiSession {
|
|
|
590
593
|
if (this.currentState === SDKState.RESEARCHING || this.currentState === SDKState.PAUSED)
|
|
591
594
|
return;
|
|
592
595
|
const state = attributes["lk.agent.state"];
|
|
593
|
-
const newState = z$2(state).with("listening", () => SDKState.USER_SPEAKING).with("speaking", () => SDKState.AGENT_SPEAKING).with("thinking", () => SDKState.
|
|
596
|
+
const newState = z$2(state).with("listening", () => SDKState.USER_SPEAKING).with("speaking", () => SDKState.AGENT_SPEAKING).with("thinking", () => SDKState.THINKING).otherwise(() => void 0);
|
|
594
597
|
if (!newState)
|
|
595
598
|
return;
|
|
596
599
|
this.setState(newState);
|
|
@@ -660,10 +663,8 @@ class ObiSession {
|
|
|
660
663
|
dynacast: true
|
|
661
664
|
});
|
|
662
665
|
this.setupRoomEventListeners();
|
|
663
|
-
const
|
|
664
|
-
|
|
665
|
-
const joinToken = await fetch(joinEndpoint).then((res) => res.json());
|
|
666
|
-
await this.room.connect(joinToken.url, joinToken.token);
|
|
666
|
+
const joinToken = await this.client.getJoinToken(this.sessionId, { skipIntro: true });
|
|
667
|
+
await this.room.connect(joinToken.data.url, joinToken.data.token);
|
|
667
668
|
if (this.microphoneStream) {
|
|
668
669
|
const micTrack = this.microphoneStream.getAudioTracks()[0];
|
|
669
670
|
await this.room.localParticipant.publishTrack(micTrack, {
|
|
@@ -672,8 +673,8 @@ class ObiSession {
|
|
|
672
673
|
});
|
|
673
674
|
}
|
|
674
675
|
return {
|
|
675
|
-
url: joinToken.url,
|
|
676
|
-
token: joinToken.token
|
|
676
|
+
url: joinToken.data.url,
|
|
677
|
+
token: joinToken.data.token
|
|
677
678
|
};
|
|
678
679
|
} catch (error) {
|
|
679
680
|
console.error("Failed to connect to LiveKit:", error);
|
|
@@ -718,6 +719,9 @@ class ObiSession {
|
|
|
718
719
|
this.currentState = newState;
|
|
719
720
|
this.emitter.emit("stateChanged", newState);
|
|
720
721
|
}
|
|
722
|
+
getCurrentState() {
|
|
723
|
+
return this.currentState;
|
|
724
|
+
}
|
|
721
725
|
async requestMicrophone() {
|
|
722
726
|
try {
|
|
723
727
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
@@ -11220,7 +11224,7 @@ SessionStartModal.styles = i$4`
|
|
|
11220
11224
|
align-items: center;
|
|
11221
11225
|
gap: 8px;
|
|
11222
11226
|
aspect-ratio: 1/1;
|
|
11223
|
-
border-radius: var(--border-radius-lg,
|
|
11227
|
+
border-radius: var(--border-radius-lg, 12px);
|
|
11224
11228
|
background: var(--tailwind-colors-violet-600, #7c3aed);
|
|
11225
11229
|
box-shadow:
|
|
11226
11230
|
0px 0px 8px 0px rgba(168, 85, 247, 0.12),
|
|
@@ -11328,11 +11332,13 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
11328
11332
|
__defProp(target, key, result);
|
|
11329
11333
|
return result;
|
|
11330
11334
|
};
|
|
11335
|
+
const WIDGET_PARAMS_KEY = "io.obi.widget-parameters";
|
|
11331
11336
|
class ObiWidget extends i$1 {
|
|
11332
11337
|
constructor() {
|
|
11333
11338
|
super();
|
|
11334
11339
|
this.apiKey = "";
|
|
11335
11340
|
this.isActive = true;
|
|
11341
|
+
this.linkOnlyAccess = false;
|
|
11336
11342
|
this.position = "bottom-right";
|
|
11337
11343
|
this.user = null;
|
|
11338
11344
|
this.state = SDKState.READY;
|
|
@@ -11354,6 +11360,7 @@ class ObiWidget extends i$1 {
|
|
|
11354
11360
|
this.boundSaveSessionData = null;
|
|
11355
11361
|
this.obiClient = null;
|
|
11356
11362
|
this.closeNavTimeoutRef = null;
|
|
11363
|
+
this.researchingTimeoutRef = null;
|
|
11357
11364
|
this.handleCourseSelectEvent = (event) => {
|
|
11358
11365
|
const customEvent = event;
|
|
11359
11366
|
this.selectedCourse = customEvent.detail;
|
|
@@ -11374,10 +11381,12 @@ class ObiWidget extends i$1 {
|
|
|
11374
11381
|
const sessionWithPlan = matchingSession;
|
|
11375
11382
|
this.selectedCourse = {
|
|
11376
11383
|
id: sessionToken,
|
|
11377
|
-
name: sessionWithPlan.onboarding_plan?.
|
|
11378
|
-
description: sessionWithPlan.onboarding_plan?.
|
|
11384
|
+
name: sessionWithPlan.onboarding_plan?.name || "",
|
|
11385
|
+
description: sessionWithPlan.onboarding_plan?.description || ""
|
|
11379
11386
|
};
|
|
11380
11387
|
this.showSessionStartModal = true;
|
|
11388
|
+
} else {
|
|
11389
|
+
console.log("No session found with token:", sessionToken);
|
|
11381
11390
|
}
|
|
11382
11391
|
}
|
|
11383
11392
|
} catch (error) {
|
|
@@ -11404,15 +11413,23 @@ class ObiWidget extends i$1 {
|
|
|
11404
11413
|
if (window.obiWidgetConfig.isActive !== void 0) {
|
|
11405
11414
|
this.isActive = window.obiWidgetConfig.isActive;
|
|
11406
11415
|
}
|
|
11416
|
+
if (window.obiWidgetConfig.linkOnlyAccess !== void 0) {
|
|
11417
|
+
this.linkOnlyAccess = window.obiWidgetConfig.linkOnlyAccess;
|
|
11418
|
+
}
|
|
11407
11419
|
this.style.setProperty("--obi-primary", window.obiWidgetConfig?.primaryColor || "#9500ff");
|
|
11408
11420
|
this.style.setProperty("--obi-secondary", window.obiWidgetConfig?.secondaryColor || "#c4b5fd");
|
|
11409
11421
|
}
|
|
11410
11422
|
}
|
|
11411
|
-
|
|
11423
|
+
removeSessionUrlParams() {
|
|
11412
11424
|
const url = new URL(window.location.href);
|
|
11413
11425
|
url.searchParams.delete(SESSION_URL_PARAM);
|
|
11414
11426
|
url.searchParams.delete(API_KEY_URL_PARAM);
|
|
11415
11427
|
window.history.replaceState({}, "", url.toString());
|
|
11428
|
+
try {
|
|
11429
|
+
localStorage.removeItem(WIDGET_PARAMS_KEY);
|
|
11430
|
+
} catch (error) {
|
|
11431
|
+
console.warn("Failed to remove widget parameters from localStorage:", error);
|
|
11432
|
+
}
|
|
11416
11433
|
}
|
|
11417
11434
|
/**
|
|
11418
11435
|
* Create a new ObiSession instance with common configuration
|
|
@@ -11438,9 +11455,27 @@ class ObiWidget extends i$1 {
|
|
|
11438
11455
|
*/
|
|
11439
11456
|
setupSessionEventListeners(session, onError) {
|
|
11440
11457
|
session.on("stateChanged", (newState) => {
|
|
11441
|
-
|
|
11442
|
-
|
|
11458
|
+
if (newState === SDKState.RESEARCHING) {
|
|
11459
|
+
if (this.researchingTimeoutRef) {
|
|
11460
|
+
window.clearTimeout(this.researchingTimeoutRef);
|
|
11461
|
+
}
|
|
11462
|
+
this.state = newState;
|
|
11463
|
+
this.researchingTimeoutRef = window.setTimeout(() => {
|
|
11464
|
+
this.researchingTimeoutRef = null;
|
|
11465
|
+
const currentSessionState = session.getCurrentState();
|
|
11466
|
+
this.state = currentSessionState;
|
|
11467
|
+
if (currentSessionState !== SDKState.READY) {
|
|
11468
|
+
this.storedActiveState = currentSessionState;
|
|
11469
|
+
}
|
|
11470
|
+
}, 1500);
|
|
11443
11471
|
this.storedActiveState = newState;
|
|
11472
|
+
return;
|
|
11473
|
+
}
|
|
11474
|
+
if (this.researchingTimeoutRef === null) {
|
|
11475
|
+
this.state = newState;
|
|
11476
|
+
if (newState !== SDKState.READY) {
|
|
11477
|
+
this.storedActiveState = newState;
|
|
11478
|
+
}
|
|
11444
11479
|
}
|
|
11445
11480
|
});
|
|
11446
11481
|
session.on("volume", ({ speaker, spectrum, volume }) => {
|
|
@@ -11473,10 +11508,10 @@ class ObiWidget extends i$1 {
|
|
|
11473
11508
|
try {
|
|
11474
11509
|
const session = this.createSession(sessionToken);
|
|
11475
11510
|
if (!session) {
|
|
11476
|
-
this.handleSessionCreationFailure(() => this.
|
|
11511
|
+
this.handleSessionCreationFailure(() => this.removeSessionUrlParams());
|
|
11477
11512
|
return;
|
|
11478
11513
|
}
|
|
11479
|
-
this.setupSessionEventListeners(session, () => this.
|
|
11514
|
+
this.setupSessionEventListeners(session, () => this.removeSessionUrlParams());
|
|
11480
11515
|
session.on("screenCaptureRequested", async () => {
|
|
11481
11516
|
try {
|
|
11482
11517
|
const canvas = await html2canvas(document.documentElement, {
|
|
@@ -11496,12 +11531,12 @@ class ObiWidget extends i$1 {
|
|
|
11496
11531
|
this.sessionToken = sessionToken;
|
|
11497
11532
|
this.roomToken = connectionInfo.token;
|
|
11498
11533
|
this.roomUrl = connectionInfo.url;
|
|
11499
|
-
this.
|
|
11534
|
+
this.removeSessionUrlParams();
|
|
11500
11535
|
}
|
|
11501
11536
|
this.activeSession = session;
|
|
11502
11537
|
} catch (error) {
|
|
11503
11538
|
console.error("Failed to start session:", error);
|
|
11504
|
-
this.handleSessionCreationFailure(() => this.
|
|
11539
|
+
this.handleSessionCreationFailure(() => this.removeSessionUrlParams());
|
|
11505
11540
|
}
|
|
11506
11541
|
}
|
|
11507
11542
|
async handleSessionStart(sessionToken) {
|
|
@@ -11582,9 +11617,28 @@ class ObiWidget extends i$1 {
|
|
|
11582
11617
|
async sessionConnectionCheck() {
|
|
11583
11618
|
await this.checkExistingSession();
|
|
11584
11619
|
if (!this.activeSession) {
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11620
|
+
let storedParams = {};
|
|
11621
|
+
try {
|
|
11622
|
+
const storedParamsJson = localStorage.getItem(WIDGET_PARAMS_KEY);
|
|
11623
|
+
if (storedParamsJson) {
|
|
11624
|
+
storedParams = JSON.parse(storedParamsJson);
|
|
11625
|
+
}
|
|
11626
|
+
} catch (error) {
|
|
11627
|
+
console.warn("Failed to parse stored widget parameters:", error);
|
|
11628
|
+
}
|
|
11629
|
+
if (Object.keys(storedParams).length === 0) {
|
|
11630
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
11631
|
+
urlParams.forEach((value, key) => {
|
|
11632
|
+
storedParams[key] = value;
|
|
11633
|
+
});
|
|
11634
|
+
}
|
|
11635
|
+
const sessionId = storedParams[SESSION_URL_PARAM];
|
|
11636
|
+
const urlApiKey = storedParams[API_KEY_URL_PARAM];
|
|
11637
|
+
if (urlApiKey) {
|
|
11638
|
+
this.apiKey = urlApiKey;
|
|
11639
|
+
} else if (!this.apiKey && window.obiWidgetConfig?.apiKey) {
|
|
11640
|
+
this.apiKey = window.obiWidgetConfig.apiKey;
|
|
11641
|
+
}
|
|
11588
11642
|
if (sessionId && this.apiKey) {
|
|
11589
11643
|
await this.handleUrlSessionEvent(sessionId);
|
|
11590
11644
|
}
|
|
@@ -11603,11 +11657,15 @@ class ObiWidget extends i$1 {
|
|
|
11603
11657
|
if (this.closeNavTimeoutRef !== null) {
|
|
11604
11658
|
window.clearTimeout(this.closeNavTimeoutRef);
|
|
11605
11659
|
}
|
|
11660
|
+
if (this.researchingTimeoutRef !== null) {
|
|
11661
|
+
window.clearTimeout(this.researchingTimeoutRef);
|
|
11662
|
+
this.researchingTimeoutRef = null;
|
|
11663
|
+
}
|
|
11606
11664
|
if (this.boundSaveSessionData) {
|
|
11607
11665
|
window.removeEventListener("beforeunload", this.boundSaveSessionData);
|
|
11608
11666
|
window.removeEventListener("pagehide", this.boundSaveSessionData);
|
|
11609
11667
|
}
|
|
11610
|
-
this.
|
|
11668
|
+
this.removeSessionUrlParams();
|
|
11611
11669
|
super.disconnectedCallback();
|
|
11612
11670
|
}
|
|
11613
11671
|
handleMouseEnter() {
|
|
@@ -11635,6 +11693,10 @@ class ObiWidget extends i$1 {
|
|
|
11635
11693
|
this.sessionToken = null;
|
|
11636
11694
|
this.roomToken = null;
|
|
11637
11695
|
this.roomUrl = null;
|
|
11696
|
+
if (this.researchingTimeoutRef !== null) {
|
|
11697
|
+
window.clearTimeout(this.researchingTimeoutRef);
|
|
11698
|
+
this.researchingTimeoutRef = null;
|
|
11699
|
+
}
|
|
11638
11700
|
if (this.activeSession) {
|
|
11639
11701
|
this.activeSession.disconnect();
|
|
11640
11702
|
this.activeSession = null;
|
|
@@ -11659,13 +11721,26 @@ class ObiWidget extends i$1 {
|
|
|
11659
11721
|
render() {
|
|
11660
11722
|
if (!this.isActive)
|
|
11661
11723
|
return E;
|
|
11724
|
+
if (this.linkOnlyAccess && this.state === SDKState.READY)
|
|
11725
|
+
return E;
|
|
11662
11726
|
const stateRender = z$2(this.state).with(SDKState.LOADING, () => x`<obi-dot-loader></obi-dot-loader>`).with(SDKState.RESEARCHING, () => x`<obi-searching-loader></obi-searching-loader>`).with(
|
|
11663
11727
|
N$1.union(SDKState.USER_SPEAKING, SDKState.AGENT_SPEAKING),
|
|
11664
11728
|
() => x`<obi-audio-equalizer .volume=${this.volume}></obi-audio-equalizer>`
|
|
11665
|
-
).with(SDKState.PAUSED, () => obiIcon).otherwise(() => obiIcon);
|
|
11729
|
+
).with(SDKState.THINKING, () => x`<obi-dot-loader></obi-dot-loader>`).with(SDKState.PAUSED, () => obiIcon).otherwise(() => obiIcon);
|
|
11730
|
+
const isPulseState = this.state === SDKState.USER_SPEAKING || this.state === SDKState.AGENT_SPEAKING;
|
|
11731
|
+
const isResearching = this.state === SDKState.RESEARCHING;
|
|
11732
|
+
const isUserSpeaking = this.state === SDKState.USER_SPEAKING;
|
|
11733
|
+
const isRotated = this.state !== SDKState.READY || this.navVisible;
|
|
11734
|
+
const containerClasses = [
|
|
11735
|
+
"widget-container",
|
|
11736
|
+
isRotated ? "rotated" : "",
|
|
11737
|
+
isPulseState ? "pulse" : "",
|
|
11738
|
+
isResearching ? "researching" : "",
|
|
11739
|
+
isUserSpeaking ? "user-speaking" : ""
|
|
11740
|
+
].filter(Boolean).join(" ");
|
|
11666
11741
|
return x`
|
|
11667
11742
|
<div
|
|
11668
|
-
class="
|
|
11743
|
+
class="${containerClasses}"
|
|
11669
11744
|
@mouseenter=${this.handleMouseEnter}
|
|
11670
11745
|
@mouseleave=${this.handleMouseLeave}
|
|
11671
11746
|
>
|
|
@@ -11773,7 +11848,7 @@ ObiWidget.styles = i$4`
|
|
|
11773
11848
|
position: fixed;
|
|
11774
11849
|
width: 56px;
|
|
11775
11850
|
height: 56px;
|
|
11776
|
-
border-radius:
|
|
11851
|
+
border-radius: 12px;
|
|
11777
11852
|
border-color: transparent;
|
|
11778
11853
|
background-color: var(--obi-primary);
|
|
11779
11854
|
display: flex;
|
|
@@ -11789,17 +11864,8 @@ ObiWidget.styles = i$4`
|
|
|
11789
11864
|
linear-gradient(195.84deg, var(--obi-secondary) 00 11.05%, var(--obi-secondary) 117.01%);
|
|
11790
11865
|
}
|
|
11791
11866
|
|
|
11792
|
-
.widget-container:hover {
|
|
11793
|
-
border-radius: 12px;
|
|
11794
|
-
}
|
|
11795
|
-
|
|
11796
|
-
.widget-container.rounded {
|
|
11797
|
-
border-radius: 12px;
|
|
11798
|
-
}
|
|
11799
|
-
|
|
11800
11867
|
.widget-container.researching {
|
|
11801
11868
|
width: 273px;
|
|
11802
|
-
border-radius: 12px;
|
|
11803
11869
|
}
|
|
11804
11870
|
|
|
11805
11871
|
.widget-icon {
|
|
@@ -11808,7 +11874,7 @@ ObiWidget.styles = i$4`
|
|
|
11808
11874
|
transition: transform 0.5s ease-in-out;
|
|
11809
11875
|
}
|
|
11810
11876
|
|
|
11811
|
-
.widget-container.
|
|
11877
|
+
.widget-container.rotated .widget-icon {
|
|
11812
11878
|
transform: rotate(90deg);
|
|
11813
11879
|
}
|
|
11814
11880
|
|
|
@@ -11834,6 +11900,9 @@ __decorateClass([
|
|
|
11834
11900
|
__decorateClass([
|
|
11835
11901
|
r$1()
|
|
11836
11902
|
], ObiWidget.prototype, "isActive", 2);
|
|
11903
|
+
__decorateClass([
|
|
11904
|
+
r$1()
|
|
11905
|
+
], ObiWidget.prototype, "linkOnlyAccess", 2);
|
|
11837
11906
|
__decorateClass([
|
|
11838
11907
|
r$1()
|
|
11839
11908
|
], ObiWidget.prototype, "position", 2);
|
|
@@ -11894,4 +11963,4 @@ export {
|
|
|
11894
11963
|
searchingLoader as s,
|
|
11895
11964
|
x
|
|
11896
11965
|
};
|
|
11897
|
-
//# sourceMappingURL=obi-widget-
|
|
11966
|
+
//# sourceMappingURL=obi-widget-9ef6796a.js.map
|