obi-sdk 0.3.12 → 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.
@@ -1,5 +1,530 @@
1
1
  import { css, LitElement, html, svg, nothing } from "lit";
2
2
  const API_BASE_URL = {}.VITE_API_BASE_URL;
3
+ const PATH_PARAM_RE = /\{[^{}]+\}/g;
4
+ function randomID() {
5
+ return Math.random().toString(36).slice(2, 11);
6
+ }
7
+ function createClient(clientOptions) {
8
+ let {
9
+ baseUrl = "",
10
+ Request: CustomRequest = globalThis.Request,
11
+ fetch: baseFetch = globalThis.fetch,
12
+ querySerializer: globalQuerySerializer,
13
+ bodySerializer: globalBodySerializer,
14
+ headers: baseHeaders,
15
+ ...baseOptions
16
+ } = { ...clientOptions };
17
+ baseUrl = removeTrailingSlash(baseUrl);
18
+ const middlewares = [];
19
+ async function coreFetch(schemaPath, fetchOptions) {
20
+ const {
21
+ baseUrl: localBaseUrl,
22
+ fetch: fetch2 = baseFetch,
23
+ Request = CustomRequest,
24
+ headers,
25
+ params = {},
26
+ parseAs = "json",
27
+ querySerializer: requestQuerySerializer,
28
+ bodySerializer = globalBodySerializer ?? defaultBodySerializer,
29
+ body,
30
+ ...init
31
+ } = fetchOptions || {};
32
+ if (localBaseUrl) {
33
+ baseUrl = removeTrailingSlash(localBaseUrl);
34
+ }
35
+ let querySerializer = typeof globalQuerySerializer === "function" ? globalQuerySerializer : createQuerySerializer(globalQuerySerializer);
36
+ if (requestQuerySerializer) {
37
+ querySerializer = typeof requestQuerySerializer === "function" ? requestQuerySerializer : createQuerySerializer({
38
+ ...typeof globalQuerySerializer === "object" ? globalQuerySerializer : {},
39
+ ...requestQuerySerializer
40
+ });
41
+ }
42
+ const serializedBody = body === void 0 ? void 0 : bodySerializer(body);
43
+ const defaultHeaders = (
44
+ // with no body, we should not to set Content-Type
45
+ serializedBody === void 0 || // if serialized body is FormData; browser will correctly set Content-Type & boundary expression
46
+ serializedBody instanceof FormData ? {} : {
47
+ "Content-Type": "application/json"
48
+ }
49
+ );
50
+ const requestInit = {
51
+ redirect: "follow",
52
+ ...baseOptions,
53
+ ...init,
54
+ body: serializedBody,
55
+ headers: mergeHeaders(defaultHeaders, baseHeaders, headers, params.header)
56
+ };
57
+ let id;
58
+ let options;
59
+ let request = new CustomRequest(createFinalURL(schemaPath, { baseUrl, params, querySerializer }), requestInit);
60
+ for (const key in init) {
61
+ if (!(key in request)) {
62
+ request[key] = init[key];
63
+ }
64
+ }
65
+ if (middlewares.length) {
66
+ id = randomID();
67
+ options = Object.freeze({
68
+ baseUrl,
69
+ fetch: fetch2,
70
+ parseAs,
71
+ querySerializer,
72
+ bodySerializer
73
+ });
74
+ for (const m2 of middlewares) {
75
+ if (m2 && typeof m2 === "object" && typeof m2.onRequest === "function") {
76
+ const result = await m2.onRequest({
77
+ request,
78
+ schemaPath,
79
+ params,
80
+ options,
81
+ id
82
+ });
83
+ if (result) {
84
+ if (!(result instanceof CustomRequest)) {
85
+ throw new Error("onRequest: must return new Request() when modifying the request");
86
+ }
87
+ request = result;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ let response = await fetch2(request);
93
+ if (middlewares.length) {
94
+ for (let i2 = middlewares.length - 1; i2 >= 0; i2--) {
95
+ const m2 = middlewares[i2];
96
+ if (m2 && typeof m2 === "object" && typeof m2.onResponse === "function") {
97
+ const result = await m2.onResponse({
98
+ request,
99
+ response,
100
+ schemaPath,
101
+ params,
102
+ options,
103
+ id
104
+ });
105
+ if (result) {
106
+ if (!(result instanceof Response)) {
107
+ throw new Error("onResponse: must return new Response() when modifying the response");
108
+ }
109
+ response = result;
110
+ }
111
+ }
112
+ }
113
+ }
114
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
115
+ return response.ok ? { data: {}, response } : { error: {}, response };
116
+ }
117
+ if (response.ok) {
118
+ if (parseAs === "stream") {
119
+ return { data: response.body, response };
120
+ }
121
+ return { data: await response[parseAs](), response };
122
+ }
123
+ let error = await response.text();
124
+ try {
125
+ error = JSON.parse(error);
126
+ } catch {
127
+ }
128
+ return { error, response };
129
+ }
130
+ return {
131
+ /** Call a GET endpoint */
132
+ GET(url, init) {
133
+ return coreFetch(url, { ...init, method: "GET" });
134
+ },
135
+ /** Call a PUT endpoint */
136
+ PUT(url, init) {
137
+ return coreFetch(url, { ...init, method: "PUT" });
138
+ },
139
+ /** Call a POST endpoint */
140
+ POST(url, init) {
141
+ return coreFetch(url, { ...init, method: "POST" });
142
+ },
143
+ /** Call a DELETE endpoint */
144
+ DELETE(url, init) {
145
+ return coreFetch(url, { ...init, method: "DELETE" });
146
+ },
147
+ /** Call a OPTIONS endpoint */
148
+ OPTIONS(url, init) {
149
+ return coreFetch(url, { ...init, method: "OPTIONS" });
150
+ },
151
+ /** Call a HEAD endpoint */
152
+ HEAD(url, init) {
153
+ return coreFetch(url, { ...init, method: "HEAD" });
154
+ },
155
+ /** Call a PATCH endpoint */
156
+ PATCH(url, init) {
157
+ return coreFetch(url, { ...init, method: "PATCH" });
158
+ },
159
+ /** Call a TRACE endpoint */
160
+ TRACE(url, init) {
161
+ return coreFetch(url, { ...init, method: "TRACE" });
162
+ },
163
+ /** Register middleware */
164
+ use(...middleware) {
165
+ for (const m2 of middleware) {
166
+ if (!m2) {
167
+ continue;
168
+ }
169
+ if (typeof m2 !== "object" || !("onRequest" in m2 || "onResponse" in m2)) {
170
+ throw new Error("Middleware must be an object with one of `onRequest()` or `onResponse()`");
171
+ }
172
+ middlewares.push(m2);
173
+ }
174
+ },
175
+ /** Unregister middleware */
176
+ eject(...middleware) {
177
+ for (const m2 of middleware) {
178
+ const i2 = middlewares.indexOf(m2);
179
+ if (i2 !== -1) {
180
+ middlewares.splice(i2, 1);
181
+ }
182
+ }
183
+ }
184
+ };
185
+ }
186
+ function serializePrimitiveParam(name, value, options) {
187
+ if (value === void 0 || value === null) {
188
+ return "";
189
+ }
190
+ if (typeof value === "object") {
191
+ throw new Error(
192
+ "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these."
193
+ );
194
+ }
195
+ return `${name}=${options?.allowReserved === true ? value : encodeURIComponent(value)}`;
196
+ }
197
+ function serializeObjectParam(name, value, options) {
198
+ if (!value || typeof value !== "object") {
199
+ return "";
200
+ }
201
+ const values = [];
202
+ const joiner = {
203
+ simple: ",",
204
+ label: ".",
205
+ matrix: ";"
206
+ }[options.style] || "&";
207
+ if (options.style !== "deepObject" && options.explode === false) {
208
+ for (const k2 in value) {
209
+ values.push(k2, options.allowReserved === true ? value[k2] : encodeURIComponent(value[k2]));
210
+ }
211
+ const final2 = values.join(",");
212
+ switch (options.style) {
213
+ case "form": {
214
+ return `${name}=${final2}`;
215
+ }
216
+ case "label": {
217
+ return `.${final2}`;
218
+ }
219
+ case "matrix": {
220
+ return `;${name}=${final2}`;
221
+ }
222
+ default: {
223
+ return final2;
224
+ }
225
+ }
226
+ }
227
+ for (const k2 in value) {
228
+ const finalName = options.style === "deepObject" ? `${name}[${k2}]` : k2;
229
+ values.push(serializePrimitiveParam(finalName, value[k2], options));
230
+ }
231
+ const final = values.join(joiner);
232
+ return options.style === "label" || options.style === "matrix" ? `${joiner}${final}` : final;
233
+ }
234
+ function serializeArrayParam(name, value, options) {
235
+ if (!Array.isArray(value)) {
236
+ return "";
237
+ }
238
+ if (options.explode === false) {
239
+ const joiner2 = { form: ",", spaceDelimited: "%20", pipeDelimited: "|" }[options.style] || ",";
240
+ const final = (options.allowReserved === true ? value : value.map((v2) => encodeURIComponent(v2))).join(joiner2);
241
+ switch (options.style) {
242
+ case "simple": {
243
+ return final;
244
+ }
245
+ case "label": {
246
+ return `.${final}`;
247
+ }
248
+ case "matrix": {
249
+ return `;${name}=${final}`;
250
+ }
251
+ default: {
252
+ return `${name}=${final}`;
253
+ }
254
+ }
255
+ }
256
+ const joiner = { simple: ",", label: ".", matrix: ";" }[options.style] || "&";
257
+ const values = [];
258
+ for (const v2 of value) {
259
+ if (options.style === "simple" || options.style === "label") {
260
+ values.push(options.allowReserved === true ? v2 : encodeURIComponent(v2));
261
+ } else {
262
+ values.push(serializePrimitiveParam(name, v2, options));
263
+ }
264
+ }
265
+ return options.style === "label" || options.style === "matrix" ? `${joiner}${values.join(joiner)}` : values.join(joiner);
266
+ }
267
+ function createQuerySerializer(options) {
268
+ return function querySerializer(queryParams) {
269
+ const search = [];
270
+ if (queryParams && typeof queryParams === "object") {
271
+ for (const name in queryParams) {
272
+ const value = queryParams[name];
273
+ if (value === void 0 || value === null) {
274
+ continue;
275
+ }
276
+ if (Array.isArray(value)) {
277
+ if (value.length === 0) {
278
+ continue;
279
+ }
280
+ search.push(
281
+ serializeArrayParam(name, value, {
282
+ style: "form",
283
+ explode: true,
284
+ ...options?.array,
285
+ allowReserved: options?.allowReserved || false
286
+ })
287
+ );
288
+ continue;
289
+ }
290
+ if (typeof value === "object") {
291
+ search.push(
292
+ serializeObjectParam(name, value, {
293
+ style: "deepObject",
294
+ explode: true,
295
+ ...options?.object,
296
+ allowReserved: options?.allowReserved || false
297
+ })
298
+ );
299
+ continue;
300
+ }
301
+ search.push(serializePrimitiveParam(name, value, options));
302
+ }
303
+ }
304
+ return search.join("&");
305
+ };
306
+ }
307
+ function defaultPathSerializer(pathname, pathParams) {
308
+ let nextURL = pathname;
309
+ for (const match of pathname.match(PATH_PARAM_RE) ?? []) {
310
+ let name = match.substring(1, match.length - 1);
311
+ let explode = false;
312
+ let style = "simple";
313
+ if (name.endsWith("*")) {
314
+ explode = true;
315
+ name = name.substring(0, name.length - 1);
316
+ }
317
+ if (name.startsWith(".")) {
318
+ style = "label";
319
+ name = name.substring(1);
320
+ } else if (name.startsWith(";")) {
321
+ style = "matrix";
322
+ name = name.substring(1);
323
+ }
324
+ if (!pathParams || pathParams[name] === void 0 || pathParams[name] === null) {
325
+ continue;
326
+ }
327
+ const value = pathParams[name];
328
+ if (Array.isArray(value)) {
329
+ nextURL = nextURL.replace(match, serializeArrayParam(name, value, { style, explode }));
330
+ continue;
331
+ }
332
+ if (typeof value === "object") {
333
+ nextURL = nextURL.replace(match, serializeObjectParam(name, value, { style, explode }));
334
+ continue;
335
+ }
336
+ if (style === "matrix") {
337
+ nextURL = nextURL.replace(match, `;${serializePrimitiveParam(name, value)}`);
338
+ continue;
339
+ }
340
+ nextURL = nextURL.replace(match, style === "label" ? `.${encodeURIComponent(value)}` : encodeURIComponent(value));
341
+ }
342
+ return nextURL;
343
+ }
344
+ function defaultBodySerializer(body) {
345
+ if (body instanceof FormData) {
346
+ return body;
347
+ }
348
+ return JSON.stringify(body);
349
+ }
350
+ function createFinalURL(pathname, options) {
351
+ let finalURL = `${options.baseUrl}${pathname}`;
352
+ if (options.params?.path) {
353
+ finalURL = defaultPathSerializer(finalURL, options.params.path);
354
+ }
355
+ let search = options.querySerializer(options.params.query ?? {});
356
+ if (search.startsWith("?")) {
357
+ search = search.substring(1);
358
+ }
359
+ if (search) {
360
+ finalURL += `?${search}`;
361
+ }
362
+ return finalURL;
363
+ }
364
+ function mergeHeaders(...allHeaders) {
365
+ const finalHeaders = new Headers();
366
+ for (const h2 of allHeaders) {
367
+ if (!h2 || typeof h2 !== "object") {
368
+ continue;
369
+ }
370
+ const iterator = h2 instanceof Headers ? h2.entries() : Object.entries(h2);
371
+ for (const [k2, v2] of iterator) {
372
+ if (v2 === null) {
373
+ finalHeaders.delete(k2);
374
+ } else if (Array.isArray(v2)) {
375
+ for (const v22 of v2) {
376
+ finalHeaders.append(k2, v22);
377
+ }
378
+ } else if (v2 !== void 0) {
379
+ finalHeaders.set(k2, v2);
380
+ }
381
+ }
382
+ }
383
+ return finalHeaders;
384
+ }
385
+ function removeTrailingSlash(url) {
386
+ if (url.endsWith("/")) {
387
+ return url.substring(0, url.length - 1);
388
+ }
389
+ return url;
390
+ }
391
+ class ObiClient {
392
+ constructor(config) {
393
+ this.client = createClient({
394
+ baseUrl: config.baseUrl,
395
+ headers: config.headers,
396
+ fetch: config.fetch
397
+ });
398
+ }
399
+ /**
400
+ * Set authorization header for authenticated requests
401
+ */
402
+ setAuthToken(token) {
403
+ this.client.use({
404
+ onRequest({ request }) {
405
+ request.headers.set("Authorization", `Bearer ${token}`);
406
+ return request;
407
+ }
408
+ });
409
+ }
410
+ /**
411
+ * Set API token for tool calls and notifications
412
+ */
413
+ setApiToken(token) {
414
+ this.client.use({
415
+ onRequest({ request }) {
416
+ request.headers.set("Authorization", `Token ${token}`);
417
+ return request;
418
+ }
419
+ });
420
+ }
421
+ // Auth endpoints
422
+ async getAuthUrl(type) {
423
+ return await this.client.GET("/auth/{type}", {
424
+ params: { path: { type } }
425
+ });
426
+ }
427
+ async getConnectUrl(type) {
428
+ return await this.client.GET("/connect/{type}", {
429
+ params: { path: { type } }
430
+ });
431
+ }
432
+ async logout() {
433
+ return await this.client.POST("/logout");
434
+ }
435
+ async getCurrentUser() {
436
+ return await this.client.GET("/me");
437
+ }
438
+ // Files
439
+ async createPresignedUploadUrl(data) {
440
+ return await this.client.POST("/files", {
441
+ body: data
442
+ });
443
+ }
444
+ // Knowledge blocks
445
+ async createKnowledgeBlock(data) {
446
+ return await this.client.POST("/knowledge", {
447
+ body: data
448
+ });
449
+ }
450
+ // Onboardees
451
+ async listOnboardees() {
452
+ return await this.client.GET("/onboardees");
453
+ }
454
+ async getOnboardeeWhitelistedDomains(id) {
455
+ return await this.client.GET("/onboardees/{id}/whitelisted-domains", {
456
+ params: { path: { id } }
457
+ });
458
+ }
459
+ // Plans
460
+ async listPlans() {
461
+ return await this.client.GET("/plans");
462
+ }
463
+ async createPlan(data) {
464
+ return await this.client.POST("/plans", {
465
+ body: data
466
+ });
467
+ }
468
+ async getPlan(id) {
469
+ return await this.client.GET("/plans/{id}", {
470
+ params: { path: { id } }
471
+ });
472
+ }
473
+ async replacePlan(id, data) {
474
+ return await this.client.PUT("/plans/{id}", {
475
+ params: { path: { id } },
476
+ body: data
477
+ });
478
+ }
479
+ async updatePlan(id, data) {
480
+ return await this.client.PATCH("/plans/{id}", {
481
+ params: { path: { id } },
482
+ body: data
483
+ });
484
+ }
485
+ // Sessions
486
+ async listSessions(token) {
487
+ return await this.client.GET("/sessions", {
488
+ params: { query: token ? { token } : {} }
489
+ });
490
+ }
491
+ async createSession(data) {
492
+ return await this.client.POST("/sessions", {
493
+ body: data
494
+ });
495
+ }
496
+ async getSession(id) {
497
+ return await this.client.GET("/sessions/{id}", {
498
+ params: { path: { id } }
499
+ });
500
+ }
501
+ async getSessionRecording(id) {
502
+ return await this.client.GET("/sessions/{id}/recording", {
503
+ params: { path: { id } }
504
+ });
505
+ }
506
+ async getSessionProductUrl(id) {
507
+ return await this.client.GET("/sessions/{id}/product-url", {
508
+ params: { path: { id } }
509
+ });
510
+ }
511
+ async getJoinToken(token, { skipIntro } = {}) {
512
+ return await this.client.GET("/join-token", {
513
+ params: {
514
+ query: {
515
+ token,
516
+ ...skipIntro && { skip_intro: "true" }
517
+ }
518
+ }
519
+ });
520
+ }
521
+ /**
522
+ * Get the underlying openapi-fetch client for advanced usage
523
+ */
524
+ getClient() {
525
+ return this.client;
526
+ }
527
+ }
3
528
  function getDefaultExportFromCjs$1(x2) {
4
529
  return x2 && x2.__esModule && Object.prototype.hasOwnProperty.call(x2, "default") ? x2["default"] : x2;
5
530
  }
@@ -22429,6 +22954,9 @@ class ObiSession {
22429
22954
  this._userAudioTimer = null;
22430
22955
  this.sessionId = sessionId;
22431
22956
  this.apiBaseUrl = apiBaseUrl || DEFAULT_API_BASE_URL;
22957
+ this.client = new ObiClient({
22958
+ baseUrl: this.apiBaseUrl
22959
+ });
22432
22960
  this.emitter = new EventEmitter();
22433
22961
  }
22434
22962
  emit(event, data) {
@@ -22485,7 +23013,7 @@ class ObiSession {
22485
23013
  if (this.currentState === SDKState.RESEARCHING || this.currentState === SDKState.PAUSED)
22486
23014
  return;
22487
23015
  const state = attributes["lk.agent.state"];
22488
- const newState = z$2(state).with("listening", () => SDKState.USER_SPEAKING).with("speaking", () => SDKState.AGENT_SPEAKING).with("thinking", () => SDKState.AGENT_SPEAKING).otherwise(() => void 0);
23016
+ const newState = z$2(state).with("listening", () => SDKState.USER_SPEAKING).with("speaking", () => SDKState.AGENT_SPEAKING).with("thinking", () => SDKState.THINKING).otherwise(() => void 0);
22489
23017
  if (!newState)
22490
23018
  return;
22491
23019
  this.setState(newState);
@@ -22555,10 +23083,8 @@ class ObiSession {
22555
23083
  dynacast: true
22556
23084
  });
22557
23085
  this.setupRoomEventListeners();
22558
- const params = new URLSearchParams({ token: this.sessionId, skip_intro: "true" });
22559
- const joinEndpoint = `${this.apiBaseUrl}/join-token?${params.toString()}`;
22560
- const joinToken = await fetch(joinEndpoint).then((res) => res.json());
22561
- await this.room.connect(joinToken.url, joinToken.token);
23086
+ const joinToken = await this.client.getJoinToken(this.sessionId, { skipIntro: true });
23087
+ await this.room.connect(joinToken.data.url, joinToken.data.token);
22562
23088
  if (this.microphoneStream) {
22563
23089
  const micTrack = this.microphoneStream.getAudioTracks()[0];
22564
23090
  await this.room.localParticipant.publishTrack(micTrack, {
@@ -22567,8 +23093,8 @@ class ObiSession {
22567
23093
  });
22568
23094
  }
22569
23095
  return {
22570
- url: joinToken.url,
22571
- token: joinToken.token
23096
+ url: joinToken.data.url,
23097
+ token: joinToken.data.token
22572
23098
  };
22573
23099
  } catch (error) {
22574
23100
  console.error("Failed to connect to LiveKit:", error);
@@ -22613,6 +23139,9 @@ class ObiSession {
22613
23139
  this.currentState = newState;
22614
23140
  this.emitter.emit("stateChanged", newState);
22615
23141
  }
23142
+ getCurrentState() {
23143
+ return this.currentState;
23144
+ }
22616
23145
  async requestMicrophone() {
22617
23146
  try {
22618
23147
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
@@ -22768,6 +23297,8 @@ class ObiSession {
22768
23297
  }
22769
23298
  }
22770
23299
  }
23300
+ const SESSION_URL_PARAM = "49206C6F7665204F6269_session";
23301
+ const API_KEY_URL_PARAM = "49206C6F7665204F6269_client";
22771
23302
  var extendStatics = function(d2, b2) {
22772
23303
  extendStatics = Object.setPrototypeOf || { __proto__: [] } instanceof Array && function(d3, b3) {
22773
23304
  d3.__proto__ = b3;
@@ -31658,15 +32189,15 @@ const STORAGE_KEYS = {
31658
32189
  SESSION_DATA: "session_data"
31659
32190
  };
31660
32191
  const storage = new StorageManager("io.obi.widget");
31661
- var __defProp$6 = Object.defineProperty;
31662
- var __getOwnPropDesc$6 = Object.getOwnPropertyDescriptor;
31663
- var __decorateClass$6 = (decorators, target, key, kind) => {
31664
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$6(target, key) : target;
32192
+ var __defProp$7 = Object.defineProperty;
32193
+ var __getOwnPropDesc$7 = Object.getOwnPropertyDescriptor;
32194
+ var __decorateClass$7 = (decorators, target, key, kind) => {
32195
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$7(target, key) : target;
31665
32196
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
31666
32197
  if (decorator = decorators[i2])
31667
32198
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
31668
32199
  if (kind && result)
31669
- __defProp$6(target, key, result);
32200
+ __defProp$7(target, key, result);
31670
32201
  return result;
31671
32202
  };
31672
32203
  class NavIcon extends LitElement {
@@ -31759,16 +32290,16 @@ NavIcon.styles = css`
31759
32290
  height: 18px;
31760
32291
  }
31761
32292
  `;
31762
- __decorateClass$6([
32293
+ __decorateClass$7([
31763
32294
  n$3({ type: String })
31764
32295
  ], NavIcon.prototype, "id", 2);
31765
- __decorateClass$6([
32296
+ __decorateClass$7([
31766
32297
  n$3({ type: Boolean })
31767
32298
  ], NavIcon.prototype, "isActive", 2);
31768
- __decorateClass$6([
32299
+ __decorateClass$7([
31769
32300
  n$3({ type: Boolean })
31770
32301
  ], NavIcon.prototype, "isSpecial", 2);
31771
- __decorateClass$6([
32302
+ __decorateClass$7([
31772
32303
  n$3({ type: Function })
31773
32304
  ], NavIcon.prototype, "onClick", 2);
31774
32305
  if (!customElements.get("obi-nav-icon")) {
@@ -31817,15 +32348,15 @@ const obiIcon = html`
31817
32348
  alt="Obi Icon"
31818
32349
  />
31819
32350
  `;
31820
- var __defProp$5 = Object.defineProperty;
31821
- var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
31822
- var __decorateClass$5 = (decorators, target, key, kind) => {
31823
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$5(target, key) : target;
32351
+ var __defProp$6 = Object.defineProperty;
32352
+ var __getOwnPropDesc$6 = Object.getOwnPropertyDescriptor;
32353
+ var __decorateClass$6 = (decorators, target, key, kind) => {
32354
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$6(target, key) : target;
31824
32355
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
31825
32356
  if (decorator = decorators[i2])
31826
32357
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
31827
32358
  if (kind && result)
31828
- __defProp$5(target, key, result);
32359
+ __defProp$6(target, key, result);
31829
32360
  return result;
31830
32361
  };
31831
32362
  class NavigationBar extends LitElement {
@@ -31899,36 +32430,36 @@ NavigationBar.styles = css`
31899
32430
  flex-direction: column;
31900
32431
  }
31901
32432
  `;
31902
- __decorateClass$5([
32433
+ __decorateClass$6([
31903
32434
  n$3({ type: Boolean })
31904
32435
  ], NavigationBar.prototype, "isActive", 2);
31905
- __decorateClass$5([
32436
+ __decorateClass$6([
31906
32437
  n$3({ type: Boolean })
31907
32438
  ], NavigationBar.prototype, "isScreenActive", 2);
31908
- __decorateClass$5([
32439
+ __decorateClass$6([
31909
32440
  n$3({ type: Object })
31910
32441
  ], NavigationBar.prototype, "position", 2);
31911
- __decorateClass$5([
32442
+ __decorateClass$6([
31912
32443
  n$3({ type: String })
31913
32444
  ], NavigationBar.prototype, "currentState", 2);
31914
- __decorateClass$5([
32445
+ __decorateClass$6([
31915
32446
  n$3({ type: String })
31916
32447
  ], NavigationBar.prototype, "direction", 2);
31917
- __decorateClass$5([
32448
+ __decorateClass$6([
31918
32449
  n$3({ type: Function })
31919
32450
  ], NavigationBar.prototype, "onItemSelect", 2);
31920
32451
  if (!customElements.get("obi-navigation-bar")) {
31921
32452
  customElements.define("obi-navigation-bar", NavigationBar);
31922
32453
  }
31923
- var __defProp$4 = Object.defineProperty;
31924
- var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
31925
- var __decorateClass$4 = (decorators, target, key, kind) => {
31926
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
32454
+ var __defProp$5 = Object.defineProperty;
32455
+ var __getOwnPropDesc$5 = Object.getOwnPropertyDescriptor;
32456
+ var __decorateClass$5 = (decorators, target, key, kind) => {
32457
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$5(target, key) : target;
31927
32458
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
31928
32459
  if (decorator = decorators[i2])
31929
32460
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
31930
32461
  if (kind && result)
31931
- __defProp$4(target, key, result);
32462
+ __defProp$5(target, key, result);
31932
32463
  return result;
31933
32464
  };
31934
32465
  class Course extends LitElement {
@@ -31940,12 +32471,9 @@ class Course extends LitElement {
31940
32471
  this.imageSrc = "";
31941
32472
  }
31942
32473
  handleClick() {
31943
- if (this.onSelect) {
31944
- this.onSelect(this.id);
31945
- }
31946
32474
  this.dispatchEvent(
31947
32475
  new CustomEvent("course-select", {
31948
- detail: { id: this.id },
32476
+ detail: { id: this.id, name: this.name, description: this.description },
31949
32477
  bubbles: true,
31950
32478
  composed: true
31951
32479
  })
@@ -32007,21 +32535,18 @@ Course.styles = css`
32007
32535
  margin: 0;
32008
32536
  }
32009
32537
  `;
32010
- __decorateClass$4([
32538
+ __decorateClass$5([
32011
32539
  n$3({ type: String })
32012
32540
  ], Course.prototype, "id", 2);
32013
- __decorateClass$4([
32541
+ __decorateClass$5([
32014
32542
  n$3({ type: String })
32015
32543
  ], Course.prototype, "name", 2);
32016
- __decorateClass$4([
32544
+ __decorateClass$5([
32017
32545
  n$3({ type: String })
32018
32546
  ], Course.prototype, "description", 2);
32019
- __decorateClass$4([
32547
+ __decorateClass$5([
32020
32548
  n$3({ type: String })
32021
32549
  ], Course.prototype, "imageSrc", 2);
32022
- __decorateClass$4([
32023
- n$3({ type: Function })
32024
- ], Course.prototype, "onSelect", 2);
32025
32550
  class CourseList extends LitElement {
32026
32551
  constructor() {
32027
32552
  super(...arguments);
@@ -32029,11 +32554,6 @@ class CourseList extends LitElement {
32029
32554
  this.loading = false;
32030
32555
  this.error = "";
32031
32556
  }
32032
- handleCourseSelect(e2) {
32033
- if (this.onCourseSelect) {
32034
- this.onCourseSelect(e2.detail.id);
32035
- }
32036
- }
32037
32557
  render() {
32038
32558
  if (this.loading) {
32039
32559
  return html`<div class="loading">Loading...</div>`;
@@ -32054,7 +32574,6 @@ class CourseList extends LitElement {
32054
32574
  name=${course.name}
32055
32575
  description=${course.description || ""}
32056
32576
  imageSrc=${course.imageSrc}
32057
- @course-select=${this.handleCourseSelect}
32058
32577
  ></obi-course>
32059
32578
  `
32060
32579
  )}
@@ -32098,33 +32617,30 @@ CourseList.styles = css`
32098
32617
  color: #ef4444;
32099
32618
  }
32100
32619
  `;
32101
- __decorateClass$4([
32620
+ __decorateClass$5([
32102
32621
  n$3({ type: Array })
32103
32622
  ], CourseList.prototype, "courses", 2);
32104
- __decorateClass$4([
32623
+ __decorateClass$5([
32105
32624
  n$3({ type: Boolean })
32106
32625
  ], CourseList.prototype, "loading", 2);
32107
- __decorateClass$4([
32626
+ __decorateClass$5([
32108
32627
  n$3({ type: String })
32109
32628
  ], CourseList.prototype, "error", 2);
32110
- __decorateClass$4([
32111
- n$3({ type: Function })
32112
- ], CourseList.prototype, "onCourseSelect", 2);
32113
32629
  if (!customElements.get("obi-course")) {
32114
32630
  customElements.define("obi-course", Course);
32115
32631
  }
32116
32632
  if (!customElements.get("obi-course-list")) {
32117
32633
  customElements.define("obi-course-list", CourseList);
32118
32634
  }
32119
- var __defProp$3 = Object.defineProperty;
32120
- var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
32121
- var __decorateClass$3 = (decorators, target, key, kind) => {
32122
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
32635
+ var __defProp$4 = Object.defineProperty;
32636
+ var __getOwnPropDesc$4 = Object.getOwnPropertyDescriptor;
32637
+ var __decorateClass$4 = (decorators, target, key, kind) => {
32638
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$4(target, key) : target;
32123
32639
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
32124
32640
  if (decorator = decorators[i2])
32125
32641
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
32126
32642
  if (kind && result)
32127
- __defProp$3(target, key, result);
32643
+ __defProp$4(target, key, result);
32128
32644
  return result;
32129
32645
  };
32130
32646
  class CourseModal extends LitElement {
@@ -32136,11 +32652,6 @@ class CourseModal extends LitElement {
32136
32652
  this.apiKey = "";
32137
32653
  this.apiBaseUrl = "";
32138
32654
  }
32139
- handleCourseSelect(e2) {
32140
- if (this.onCourseSelect) {
32141
- this.onCourseSelect(e2.detail.id);
32142
- }
32143
- }
32144
32655
  handleClose() {
32145
32656
  if (this.onClose) {
32146
32657
  this.onClose();
@@ -32195,7 +32706,6 @@ class CourseModal extends LitElement {
32195
32706
  .courses=${this.courses}
32196
32707
  .loading=${this.loading}
32197
32708
  .error=${this.error}
32198
- @course-select=${this.handleCourseSelect}
32199
32709
  ></obi-course-list>
32200
32710
  </div>
32201
32711
  `;
@@ -32285,25 +32795,22 @@ CourseModal.styles = css`
32285
32795
  color: #6b7280;
32286
32796
  }
32287
32797
  `;
32288
- __decorateClass$3([
32798
+ __decorateClass$4([
32289
32799
  n$3({ type: Array })
32290
32800
  ], CourseModal.prototype, "courses", 2);
32291
- __decorateClass$3([
32801
+ __decorateClass$4([
32292
32802
  n$3({ type: Boolean })
32293
32803
  ], CourseModal.prototype, "loading", 2);
32294
- __decorateClass$3([
32804
+ __decorateClass$4([
32295
32805
  n$3({ type: String })
32296
32806
  ], CourseModal.prototype, "error", 2);
32297
- __decorateClass$3([
32807
+ __decorateClass$4([
32298
32808
  n$3({ type: String })
32299
32809
  ], CourseModal.prototype, "apiKey", 2);
32300
- __decorateClass$3([
32301
- n$3({ type: Function })
32302
- ], CourseModal.prototype, "onCourseSelect", 2);
32303
- __decorateClass$3([
32810
+ __decorateClass$4([
32304
32811
  n$3({ type: Function })
32305
32812
  ], CourseModal.prototype, "onClose", 2);
32306
- __decorateClass$3([
32813
+ __decorateClass$4([
32307
32814
  r$2()
32308
32815
  ], CourseModal.prototype, "apiBaseUrl", 2);
32309
32816
  if (!customElements.get("obi-course-modal")) {
@@ -32652,15 +33159,15 @@ const o = /* @__PURE__ */ new WeakMap(), n2 = e$1(class extends f {
32652
33159
  this.rt(this.ct);
32653
33160
  }
32654
33161
  });
32655
- var __defProp$2 = Object.defineProperty;
32656
- var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
32657
- var __decorateClass$2 = (decorators, target, key, kind) => {
32658
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
33162
+ var __defProp$3 = Object.defineProperty;
33163
+ var __getOwnPropDesc$3 = Object.getOwnPropertyDescriptor;
33164
+ var __decorateClass$3 = (decorators, target, key, kind) => {
33165
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$3(target, key) : target;
32659
33166
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
32660
33167
  if (decorator = decorators[i2])
32661
33168
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
32662
33169
  if (kind && result)
32663
- __defProp$2(target, key, result);
33170
+ __defProp$3(target, key, result);
32664
33171
  return result;
32665
33172
  };
32666
33173
  class AudioEqualizer extends LitElement {
@@ -32670,9 +33177,11 @@ class AudioEqualizer extends LitElement {
32670
33177
  this.canvasRef = e();
32671
33178
  this.barCount = 8;
32672
33179
  this.animationFrame = null;
33180
+ this.primaryColor = "#9500ff";
32673
33181
  }
32674
33182
  connectedCallback() {
32675
33183
  super.connectedCallback();
33184
+ this.primaryColor = getComputedStyle(this).getPropertyValue("--obi-primary").trim() || "#9500ff";
32676
33185
  this.startAnimation();
32677
33186
  }
32678
33187
  disconnectedCallback() {
@@ -32764,7 +33273,7 @@ class AudioEqualizer extends LitElement {
32764
33273
  const spectrumValue = processedSpectrum.length > 0 ? processedSpectrum[i2] !== void 0 ? processedSpectrum[i2] : currentVolume : currentVolume;
32765
33274
  if (this.volume.speaker === "USER") {
32766
33275
  const opacity2 = Math.floor((spectrumValue * 0.5 + 0.5) * 255).toString(16).padStart(2, "0");
32767
- ctx.fillStyle = `var(--obi-primary)${opacity2}`;
33276
+ ctx.fillStyle = `${this.primaryColor}${opacity2}`;
32768
33277
  } else {
32769
33278
  const opacity2 = Math.floor((spectrumValue * 0.5 + 0.5) * 255).toString(16).padStart(2, "0");
32770
33279
  ctx.fillStyle = `#FFFFFF${opacity2}`;
@@ -32829,24 +33338,24 @@ AudioEqualizer.styles = css`
32829
33338
  height: 100%;
32830
33339
  }
32831
33340
  `;
32832
- __decorateClass$2([
33341
+ __decorateClass$3([
32833
33342
  n$3({ type: Object })
32834
33343
  ], AudioEqualizer.prototype, "volume", 2);
32835
- __decorateClass$2([
33344
+ __decorateClass$3([
32836
33345
  r$2()
32837
33346
  ], AudioEqualizer.prototype, "canvasRef", 2);
32838
33347
  if (!customElements.get("obi-audio-equalizer")) {
32839
33348
  customElements.define("obi-audio-equalizer", AudioEqualizer);
32840
33349
  }
32841
- var __defProp$1 = Object.defineProperty;
32842
- var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
32843
- var __decorateClass$1 = (decorators, target, key, kind) => {
32844
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
33350
+ var __defProp$2 = Object.defineProperty;
33351
+ var __getOwnPropDesc$2 = Object.getOwnPropertyDescriptor;
33352
+ var __decorateClass$2 = (decorators, target, key, kind) => {
33353
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$2(target, key) : target;
32845
33354
  for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
32846
33355
  if (decorator = decorators[i2])
32847
33356
  result = (kind ? decorator(target, key, result) : decorator(result)) || result;
32848
33357
  if (kind && result)
32849
- __defProp$1(target, key, result);
33358
+ __defProp$2(target, key, result);
32850
33359
  return result;
32851
33360
  };
32852
33361
  class DotLoader extends LitElement {
@@ -32947,7 +33456,7 @@ DotLoader.styles = css`
32947
33456
  opacity: 1;
32948
33457
  }
32949
33458
  `;
32950
- __decorateClass$1([
33459
+ __decorateClass$2([
32951
33460
  r$2()
32952
33461
  ], DotLoader.prototype, "activeDots", 2);
32953
33462
  if (!customElements.get("obi-dot-loader")) {
@@ -32980,6 +33489,205 @@ SearchingLoader.styles = css`
32980
33489
  if (!customElements.get("obi-searching-loader")) {
32981
33490
  customElements.define("obi-searching-loader", SearchingLoader);
32982
33491
  }
33492
+ var __defProp$1 = Object.defineProperty;
33493
+ var __getOwnPropDesc$1 = Object.getOwnPropertyDescriptor;
33494
+ var __decorateClass$1 = (decorators, target, key, kind) => {
33495
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$1(target, key) : target;
33496
+ for (var i2 = decorators.length - 1, decorator; i2 >= 0; i2--)
33497
+ if (decorator = decorators[i2])
33498
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
33499
+ if (kind && result)
33500
+ __defProp$1(target, key, result);
33501
+ return result;
33502
+ };
33503
+ class SessionStartModal extends LitElement {
33504
+ handleStart() {
33505
+ if (this.onStart && this.session) {
33506
+ this.onStart(this.session.id);
33507
+ }
33508
+ }
33509
+ handleClose() {
33510
+ if (this.onClose) {
33511
+ this.onClose();
33512
+ }
33513
+ }
33514
+ handleBackdropClick(e2) {
33515
+ if (e2.target === e2.currentTarget) {
33516
+ this.handleClose();
33517
+ }
33518
+ }
33519
+ render() {
33520
+ return html`
33521
+ <div class="backdrop" @click=${this.handleBackdropClick}></div>
33522
+ <div class="container">
33523
+ <button class="close-button" @click=${this.handleClose}>×</button>
33524
+
33525
+ <div class="header">
33526
+ <div class="logo">${obiIcon}</div>
33527
+ <h1>${this.session.name}</h1>
33528
+ <p class="subtitle">${this.session.description}</p>
33529
+ </div>
33530
+
33531
+ <button class="button button-primary" @click=${this.handleStart}>Continue →</button>
33532
+ </div>
33533
+ `;
33534
+ }
33535
+ }
33536
+ SessionStartModal.styles = css`
33537
+ :host {
33538
+ display: block;
33539
+ font-family: "Inter", sans-serif;
33540
+ }
33541
+
33542
+ .backdrop {
33543
+ position: fixed;
33544
+ top: 0;
33545
+ right: 0;
33546
+ bottom: 0;
33547
+ left: 0;
33548
+ background-color: rgba(0, 0, 0, 0.5);
33549
+ z-index: 40;
33550
+ }
33551
+
33552
+ .container {
33553
+ position: fixed;
33554
+ top: 50%;
33555
+ left: 50%;
33556
+ transform: translate(-50%, -50%);
33557
+ z-index: 50;
33558
+
33559
+ /* Layout from user specifications */
33560
+ display: flex;
33561
+ width: 640px;
33562
+ height: 380px;
33563
+ padding: 48px 48px 32px 48px;
33564
+ flex-direction: column;
33565
+ justify-content: space-between;
33566
+ align-items: center;
33567
+ flex-shrink: 0;
33568
+
33569
+ /* Style from user specifications */
33570
+ border-radius: 12px;
33571
+ background: #fafafa;
33572
+ box-shadow:
33573
+ 0px 10px 15px -3px rgba(0, 0, 0, 0.1),
33574
+ 0px 4px 6px -2px rgba(0, 0, 0, 0.05);
33575
+ }
33576
+
33577
+ .header {
33578
+ display: flex;
33579
+ flex-direction: column;
33580
+ align-items: center;
33581
+ text-align: center;
33582
+ gap: 16px;
33583
+ }
33584
+
33585
+ .logo {
33586
+ display: flex;
33587
+ width: 96px;
33588
+ height: 96px;
33589
+ padding: 8px;
33590
+ justify-content: center;
33591
+ align-items: center;
33592
+ gap: 8px;
33593
+ aspect-ratio: 1/1;
33594
+ border-radius: var(--border-radius-lg, 12px);
33595
+ background: var(--tailwind-colors-violet-600, #7c3aed);
33596
+ box-shadow:
33597
+ 0px 0px 8px 0px rgba(168, 85, 247, 0.12),
33598
+ 0px 0px 8px 0px rgba(192, 132, 252, 0.24),
33599
+ 0px 0px 4px 0px rgba(192, 132, 252, 0.24),
33600
+ 0px 0px 4px 0px rgba(192, 132, 252, 0.24),
33601
+ 0px 0px 2px 0px rgba(192, 132, 252, 0.12),
33602
+ 0px 0px 1px 0px rgba(168, 85, 247, 0.24);
33603
+ }
33604
+
33605
+ .logo img {
33606
+ width: 48px;
33607
+ height: 48px;
33608
+ color: white;
33609
+ fill: #fff;
33610
+ }
33611
+
33612
+ h1 {
33613
+ font-family: "Syne", sans-serif;
33614
+ font-size: 32px;
33615
+ font-weight: 700;
33616
+ margin: 32px 0 0 0;
33617
+ color: #111827;
33618
+ }
33619
+
33620
+ .subtitle {
33621
+ font-size: 16px;
33622
+ color: #6b7280;
33623
+ margin: 16px 0 0 0;
33624
+ line-height: 1.5;
33625
+ }
33626
+
33627
+ .button {
33628
+ padding: 12px 24px;
33629
+ border-radius: 8px;
33630
+ border: none;
33631
+ font-size: 16px;
33632
+ font-weight: 500;
33633
+ cursor: pointer;
33634
+ transition: all 0.2s ease;
33635
+ display: flex;
33636
+ align-items: center;
33637
+ justify-content: center;
33638
+ gap: 8px;
33639
+ }
33640
+
33641
+ .button-primary {
33642
+ display: flex;
33643
+ width: 100%;
33644
+ height: var(--height-h-11, 44px);
33645
+ padding: var(--spacing-2, 8px) var(--spacing-4, 16px);
33646
+ justify-content: center;
33647
+ align-items: center;
33648
+ gap: var(--spacing-2, 8px);
33649
+ flex-shrink: 0;
33650
+ align-self: stretch;
33651
+ border-radius: var(--border-radius-default, 6px);
33652
+ background: var(--base-primary, #18181b);
33653
+ color: white;
33654
+ }
33655
+
33656
+ .button-primary:hover {
33657
+ background: color-mix(in srgb, var(--base-primary, #18181b) 90%, white);
33658
+ }
33659
+
33660
+ .close-button {
33661
+ position: absolute;
33662
+ top: 16px;
33663
+ right: 16px;
33664
+ background: none;
33665
+ border: none;
33666
+ cursor: pointer;
33667
+ font-size: 24px;
33668
+ color: #6b7280;
33669
+ padding: 4px;
33670
+ border-radius: 4px;
33671
+ transition: all 0.2s ease;
33672
+ }
33673
+
33674
+ .close-button:hover {
33675
+ color: #374151;
33676
+ background: #f3f4f6;
33677
+ }
33678
+ `;
33679
+ __decorateClass$1([
33680
+ n$3({ type: Object })
33681
+ ], SessionStartModal.prototype, "session", 2);
33682
+ __decorateClass$1([
33683
+ n$3({ type: Function })
33684
+ ], SessionStartModal.prototype, "onStart", 2);
33685
+ __decorateClass$1([
33686
+ n$3({ type: Function })
33687
+ ], SessionStartModal.prototype, "onClose", 2);
33688
+ if (!customElements.get("obi-session-start-modal")) {
33689
+ customElements.define("obi-session-start-modal", SessionStartModal);
33690
+ }
32983
33691
  var __defProp = Object.defineProperty;
32984
33692
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
32985
33693
  var __decorateClass = (decorators, target, key, kind) => {
@@ -32991,17 +33699,20 @@ var __decorateClass = (decorators, target, key, kind) => {
32991
33699
  __defProp(target, key, result);
32992
33700
  return result;
32993
33701
  };
32994
- const SESSION_URL_PARAM = "49206C6F7665204F6269_session";
33702
+ const WIDGET_PARAMS_KEY = "io.obi.widget-parameters";
32995
33703
  class ObiWidget extends LitElement {
32996
33704
  constructor() {
32997
33705
  super();
32998
33706
  this.apiKey = "";
32999
33707
  this.isActive = true;
33708
+ this.linkOnlyAccess = false;
33000
33709
  this.position = "bottom-right";
33001
33710
  this.user = null;
33002
33711
  this.state = SDKState.READY;
33003
33712
  this.storedActiveState = void 0;
33004
33713
  this.showCourseModal = false;
33714
+ this.showSessionStartModal = false;
33715
+ this.selectedCourse = null;
33005
33716
  this.isHovering = false;
33006
33717
  this.navVisible = false;
33007
33718
  this.activeSession = null;
@@ -33014,7 +33725,44 @@ class ObiWidget extends LitElement {
33014
33725
  this.roomToken = null;
33015
33726
  this.roomUrl = null;
33016
33727
  this.boundSaveSessionData = null;
33728
+ this.obiClient = null;
33017
33729
  this.closeNavTimeoutRef = null;
33730
+ this.researchingTimeoutRef = null;
33731
+ this.handleCourseSelectEvent = (event) => {
33732
+ const customEvent = event;
33733
+ this.selectedCourse = customEvent.detail;
33734
+ this.showCourseModal = false;
33735
+ this.showSessionStartModal = true;
33736
+ };
33737
+ this.handleUrlSessionEvent = async (sessionToken) => {
33738
+ try {
33739
+ if (!this.obiClient) {
33740
+ console.error("ObiClient not initialized");
33741
+ return;
33742
+ }
33743
+ const sessionsResponse = await this.obiClient.listSessions(this.apiKey);
33744
+ if (sessionsResponse.data) {
33745
+ const sessions = sessionsResponse.data.sessions;
33746
+ const matchingSession = sessions?.find((session) => session.uuid === sessionToken);
33747
+ if (matchingSession) {
33748
+ const sessionWithPlan = matchingSession;
33749
+ this.selectedCourse = {
33750
+ id: sessionToken,
33751
+ name: sessionWithPlan.onboarding_plan?.name || "",
33752
+ description: sessionWithPlan.onboarding_plan?.description || ""
33753
+ };
33754
+ this.showSessionStartModal = true;
33755
+ } else {
33756
+ console.log("No session found with token:", sessionToken);
33757
+ }
33758
+ }
33759
+ } catch (error) {
33760
+ console.error("Failed to fetch session details:", error);
33761
+ }
33762
+ };
33763
+ this.obiClient = new ObiClient({
33764
+ baseUrl: API_BASE_URL
33765
+ });
33018
33766
  const handleUnload = () => {
33019
33767
  if (this.activeSession && this.sessionToken && this.roomToken && this.roomUrl) {
33020
33768
  this.saveSessionData();
@@ -33032,20 +33780,28 @@ class ObiWidget extends LitElement {
33032
33780
  if (window.obiWidgetConfig.isActive !== void 0) {
33033
33781
  this.isActive = window.obiWidgetConfig.isActive;
33034
33782
  }
33783
+ if (window.obiWidgetConfig.linkOnlyAccess !== void 0) {
33784
+ this.linkOnlyAccess = window.obiWidgetConfig.linkOnlyAccess;
33785
+ }
33035
33786
  this.style.setProperty("--obi-primary", window.obiWidgetConfig?.primaryColor || "#9500ff");
33036
33787
  this.style.setProperty("--obi-secondary", window.obiWidgetConfig?.secondaryColor || "#c4b5fd");
33037
33788
  }
33038
33789
  }
33039
- removeSessionFromUrl() {
33790
+ removeSessionUrlParams() {
33040
33791
  const url = new URL(window.location.href);
33041
33792
  url.searchParams.delete(SESSION_URL_PARAM);
33793
+ url.searchParams.delete(API_KEY_URL_PARAM);
33042
33794
  window.history.replaceState({}, "", url.toString());
33043
- }
33044
- async connectObi(sessionToken) {
33045
- if (this.activeSession) {
33046
- console.log("Connection already exists");
33047
- return;
33795
+ try {
33796
+ localStorage.removeItem(WIDGET_PARAMS_KEY);
33797
+ } catch (error) {
33798
+ console.warn("Failed to remove widget parameters from localStorage:", error);
33048
33799
  }
33800
+ }
33801
+ /**
33802
+ * Create a new ObiSession instance with common configuration
33803
+ */
33804
+ createSession(sessionToken) {
33049
33805
  try {
33050
33806
  const session = new ObiSession({
33051
33807
  sessionId: sessionToken,
@@ -33053,20 +33809,76 @@ class ObiWidget extends LitElement {
33053
33809
  });
33054
33810
  if (!session) {
33055
33811
  console.error("Failed to create session");
33056
- this.state = SDKState.ERROR;
33057
- this.activeSession = null;
33058
- this.removeSessionFromUrl();
33812
+ return null;
33813
+ }
33814
+ return session;
33815
+ } catch (error) {
33816
+ console.error("Error creating session:", error);
33817
+ return null;
33818
+ }
33819
+ }
33820
+ /**
33821
+ * Set up common event listeners for a session
33822
+ */
33823
+ setupSessionEventListeners(session, onError) {
33824
+ session.on("stateChanged", (newState) => {
33825
+ if (newState === SDKState.RESEARCHING) {
33826
+ if (this.researchingTimeoutRef) {
33827
+ window.clearTimeout(this.researchingTimeoutRef);
33828
+ }
33829
+ this.state = newState;
33830
+ this.researchingTimeoutRef = window.setTimeout(() => {
33831
+ this.researchingTimeoutRef = null;
33832
+ const currentSessionState = session.getCurrentState();
33833
+ this.state = currentSessionState;
33834
+ if (currentSessionState !== SDKState.READY) {
33835
+ this.storedActiveState = currentSessionState;
33836
+ }
33837
+ }, 1500);
33838
+ this.storedActiveState = newState;
33059
33839
  return;
33060
33840
  }
33061
- session.on("stateChanged", (newState) => {
33841
+ if (this.researchingTimeoutRef === null) {
33062
33842
  this.state = newState;
33063
33843
  if (newState !== SDKState.READY) {
33064
33844
  this.storedActiveState = newState;
33065
33845
  }
33066
- });
33067
- session.on("volume", ({ speaker, spectrum, volume }) => {
33068
- this.volume = { speaker, spectrum, volume };
33069
- });
33846
+ }
33847
+ });
33848
+ session.on("volume", ({ speaker, spectrum, volume }) => {
33849
+ this.volume = { speaker, spectrum, volume };
33850
+ });
33851
+ session.on("error", (error) => {
33852
+ console.error("Session error:", error);
33853
+ this.state = SDKState.ERROR;
33854
+ this.activeSession = null;
33855
+ if (onError) {
33856
+ onError();
33857
+ }
33858
+ });
33859
+ }
33860
+ /**
33861
+ * Handle session creation failure
33862
+ */
33863
+ handleSessionCreationFailure(onFailure) {
33864
+ this.state = SDKState.ERROR;
33865
+ this.activeSession = null;
33866
+ if (onFailure) {
33867
+ onFailure();
33868
+ }
33869
+ }
33870
+ async connectObi(sessionToken) {
33871
+ if (this.activeSession) {
33872
+ console.log("Connection already exists");
33873
+ return;
33874
+ }
33875
+ try {
33876
+ const session = this.createSession(sessionToken);
33877
+ if (!session) {
33878
+ this.handleSessionCreationFailure(() => this.removeSessionUrlParams());
33879
+ return;
33880
+ }
33881
+ this.setupSessionEventListeners(session, () => this.removeSessionUrlParams());
33070
33882
  session.on("screenCaptureRequested", async () => {
33071
33883
  try {
33072
33884
  const canvas = await html2canvas(document.documentElement, {
@@ -33081,25 +33893,17 @@ class ObiWidget extends LitElement {
33081
33893
  this.activeSession.emit("screenCaptureComplete", "error");
33082
33894
  }
33083
33895
  });
33084
- session.on("error", (error) => {
33085
- console.error("Session error:", error);
33086
- this.state = SDKState.ERROR;
33087
- this.activeSession = null;
33088
- this.removeSessionFromUrl();
33089
- });
33090
33896
  const connectionInfo = await session.connect();
33091
33897
  if (connectionInfo) {
33092
33898
  this.sessionToken = sessionToken;
33093
33899
  this.roomToken = connectionInfo.token;
33094
33900
  this.roomUrl = connectionInfo.url;
33095
- this.removeSessionFromUrl();
33901
+ this.removeSessionUrlParams();
33096
33902
  }
33097
33903
  this.activeSession = session;
33098
33904
  } catch (error) {
33099
33905
  console.error("Failed to start session:", error);
33100
- this.state = SDKState.ERROR;
33101
- this.activeSession = null;
33102
- this.removeSessionFromUrl();
33906
+ this.handleSessionCreationFailure(() => this.removeSessionUrlParams());
33103
33907
  }
33104
33908
  }
33105
33909
  async handleSessionStart(sessionToken) {
@@ -33107,7 +33911,7 @@ class ObiWidget extends LitElement {
33107
33911
  console.log("Connection already in progress or active session exists");
33108
33912
  return;
33109
33913
  }
33110
- this.showCourseModal = false;
33914
+ this.showSessionStartModal = false;
33111
33915
  this.state = SDKState.LOADING;
33112
33916
  await this.connectObi(sessionToken);
33113
33917
  }
@@ -33132,31 +33936,12 @@ class ObiWidget extends LitElement {
33132
33936
  }
33133
33937
  }
33134
33938
  this.state = SDKState.LOADING;
33135
- const session = new ObiSession({
33136
- sessionId: sessionToken,
33137
- apiBaseUrl: API_BASE_URL
33138
- });
33939
+ const session = this.createSession(sessionToken);
33139
33940
  if (!session) {
33140
- console.error("Failed to create session");
33141
- this.state = SDKState.ERROR;
33142
- this.clearSessionStorage();
33941
+ this.handleSessionCreationFailure(() => this.clearSessionStorage());
33143
33942
  return;
33144
33943
  }
33145
- session.on("stateChanged", (newState) => {
33146
- this.state = newState;
33147
- if (newState !== SDKState.READY) {
33148
- this.storedActiveState = newState;
33149
- }
33150
- });
33151
- session.on("volume", ({ speaker, spectrum, volume }) => {
33152
- this.volume = { speaker, spectrum, volume };
33153
- });
33154
- session.on("error", (error) => {
33155
- console.error("Session error:", error);
33156
- this.state = SDKState.ERROR;
33157
- this.activeSession = null;
33158
- this.clearSessionStorage();
33159
- });
33944
+ this.setupSessionEventListeners(session, () => this.clearSessionStorage());
33160
33945
  const reconnected = await session.reconnect(roomUrl, roomToken, obiState);
33161
33946
  if (reconnected) {
33162
33947
  this.activeSession = session;
@@ -33170,8 +33955,7 @@ class ObiWidget extends LitElement {
33170
33955
  }
33171
33956
  } catch (error) {
33172
33957
  console.error("Error reconnecting to session:", error);
33173
- this.state = SDKState.ERROR;
33174
- this.clearSessionStorage();
33958
+ this.handleSessionCreationFailure(() => this.clearSessionStorage());
33175
33959
  }
33176
33960
  }
33177
33961
  /**
@@ -33200,10 +33984,30 @@ class ObiWidget extends LitElement {
33200
33984
  async sessionConnectionCheck() {
33201
33985
  await this.checkExistingSession();
33202
33986
  if (!this.activeSession) {
33203
- const urlParams = new URLSearchParams(window.location.search);
33204
- const sessionId = urlParams.get(SESSION_URL_PARAM);
33205
- if (sessionId) {
33206
- this.handleSessionStart(sessionId);
33987
+ let storedParams = {};
33988
+ try {
33989
+ const storedParamsJson = localStorage.getItem(WIDGET_PARAMS_KEY);
33990
+ if (storedParamsJson) {
33991
+ storedParams = JSON.parse(storedParamsJson);
33992
+ }
33993
+ } catch (error) {
33994
+ console.warn("Failed to parse stored widget parameters:", error);
33995
+ }
33996
+ if (Object.keys(storedParams).length === 0) {
33997
+ const urlParams = new URLSearchParams(window.location.search);
33998
+ urlParams.forEach((value, key) => {
33999
+ storedParams[key] = value;
34000
+ });
34001
+ }
34002
+ const sessionId = storedParams[SESSION_URL_PARAM];
34003
+ const urlApiKey = storedParams[API_KEY_URL_PARAM];
34004
+ if (urlApiKey) {
34005
+ this.apiKey = urlApiKey;
34006
+ } else if (!this.apiKey && window.obiWidgetConfig?.apiKey) {
34007
+ this.apiKey = window.obiWidgetConfig.apiKey;
34008
+ }
34009
+ if (sessionId && this.apiKey) {
34010
+ await this.handleUrlSessionEvent(sessionId);
33207
34011
  }
33208
34012
  }
33209
34013
  }
@@ -33220,11 +34024,15 @@ class ObiWidget extends LitElement {
33220
34024
  if (this.closeNavTimeoutRef !== null) {
33221
34025
  window.clearTimeout(this.closeNavTimeoutRef);
33222
34026
  }
34027
+ if (this.researchingTimeoutRef !== null) {
34028
+ window.clearTimeout(this.researchingTimeoutRef);
34029
+ this.researchingTimeoutRef = null;
34030
+ }
33223
34031
  if (this.boundSaveSessionData) {
33224
34032
  window.removeEventListener("beforeunload", this.boundSaveSessionData);
33225
34033
  window.removeEventListener("pagehide", this.boundSaveSessionData);
33226
34034
  }
33227
- this.removeSessionFromUrl();
34035
+ this.removeSessionUrlParams();
33228
34036
  super.disconnectedCallback();
33229
34037
  }
33230
34038
  handleMouseEnter() {
@@ -33252,6 +34060,10 @@ class ObiWidget extends LitElement {
33252
34060
  this.sessionToken = null;
33253
34061
  this.roomToken = null;
33254
34062
  this.roomUrl = null;
34063
+ if (this.researchingTimeoutRef !== null) {
34064
+ window.clearTimeout(this.researchingTimeoutRef);
34065
+ this.researchingTimeoutRef = null;
34066
+ }
33255
34067
  if (this.activeSession) {
33256
34068
  this.activeSession.disconnect();
33257
34069
  this.activeSession = null;
@@ -33276,13 +34088,26 @@ class ObiWidget extends LitElement {
33276
34088
  render() {
33277
34089
  if (!this.isActive)
33278
34090
  return nothing;
34091
+ if (this.linkOnlyAccess && this.state === SDKState.READY)
34092
+ return nothing;
33279
34093
  const stateRender = z$2(this.state).with(SDKState.LOADING, () => html`<obi-dot-loader></obi-dot-loader>`).with(SDKState.RESEARCHING, () => html`<obi-searching-loader></obi-searching-loader>`).with(
33280
34094
  N$1.union(SDKState.USER_SPEAKING, SDKState.AGENT_SPEAKING),
33281
34095
  () => html`<obi-audio-equalizer .volume=${this.volume}></obi-audio-equalizer>`
33282
- ).with(SDKState.PAUSED, () => obiIcon).otherwise(() => obiIcon);
34096
+ ).with(SDKState.THINKING, () => html`<obi-dot-loader></obi-dot-loader>`).with(SDKState.PAUSED, () => obiIcon).otherwise(() => obiIcon);
34097
+ const isPulseState = this.state === SDKState.USER_SPEAKING || this.state === SDKState.AGENT_SPEAKING;
34098
+ const isResearching = this.state === SDKState.RESEARCHING;
34099
+ const isUserSpeaking = this.state === SDKState.USER_SPEAKING;
34100
+ const isRotated = this.state !== SDKState.READY || this.navVisible;
34101
+ const containerClasses = [
34102
+ "widget-container",
34103
+ isRotated ? "rotated" : "",
34104
+ isPulseState ? "pulse" : "",
34105
+ isResearching ? "researching" : "",
34106
+ isUserSpeaking ? "user-speaking" : ""
34107
+ ].filter(Boolean).join(" ");
33283
34108
  return html`
33284
34109
  <div
33285
- class="widget-container ${this.state === SDKState.USER_SPEAKING || this.state === SDKState.AGENT_SPEAKING ? "pulse" : ""} ${this.state !== SDKState.READY || this.navVisible ? "rounded" : ""} ${this.state === SDKState.RESEARCHING ? "researching" : ""} ${this.state === SDKState.USER_SPEAKING ? "user-speaking" : ""}"
34110
+ class="${containerClasses}"
33286
34111
  @mouseenter=${this.handleMouseEnter}
33287
34112
  @mouseleave=${this.handleMouseLeave}
33288
34113
  >
@@ -33299,9 +34124,17 @@ class ObiWidget extends LitElement {
33299
34124
  </div>
33300
34125
  ${this.showCourseModal ? html`<obi-course-modal
33301
34126
  .onClose=${() => this.showCourseModal = false}
33302
- .onCourseSelect=${this.handleSessionStart.bind(this)}
34127
+ @course-select=${this.handleCourseSelectEvent}
33303
34128
  .apiKey=${this.apiKey}
33304
34129
  ></obi-course-modal>` : nothing}
34130
+ ${this.showSessionStartModal && this.selectedCourse ? html`<obi-session-start-modal
34131
+ .session=${this.selectedCourse}
34132
+ .onStart=${this.handleSessionStart.bind(this)}
34133
+ .onClose=${() => {
34134
+ this.showSessionStartModal = false;
34135
+ this.selectedCourse = null;
34136
+ }}
34137
+ ></obi-session-start-modal>` : nothing}
33305
34138
  `;
33306
34139
  }
33307
34140
  }
@@ -33382,7 +34215,7 @@ ObiWidget.styles = css`
33382
34215
  position: fixed;
33383
34216
  width: 56px;
33384
34217
  height: 56px;
33385
- border-radius: 28px;
34218
+ border-radius: 12px;
33386
34219
  border-color: transparent;
33387
34220
  background-color: var(--obi-primary);
33388
34221
  display: flex;
@@ -33398,17 +34231,8 @@ ObiWidget.styles = css`
33398
34231
  linear-gradient(195.84deg, var(--obi-secondary) 00 11.05%, var(--obi-secondary) 117.01%);
33399
34232
  }
33400
34233
 
33401
- .widget-container:hover {
33402
- border-radius: 12px;
33403
- }
33404
-
33405
- .widget-container.rounded {
33406
- border-radius: 12px;
33407
- }
33408
-
33409
34234
  .widget-container.researching {
33410
34235
  width: 273px;
33411
- border-radius: 12px;
33412
34236
  }
33413
34237
 
33414
34238
  .widget-icon {
@@ -33417,7 +34241,7 @@ ObiWidget.styles = css`
33417
34241
  transition: transform 0.5s ease-in-out;
33418
34242
  }
33419
34243
 
33420
- .widget-container.rounded .widget-icon {
34244
+ .widget-container.rotated .widget-icon {
33421
34245
  transform: rotate(90deg);
33422
34246
  }
33423
34247
 
@@ -33443,6 +34267,9 @@ __decorateClass([
33443
34267
  __decorateClass([
33444
34268
  r$2()
33445
34269
  ], ObiWidget.prototype, "isActive", 2);
34270
+ __decorateClass([
34271
+ r$2()
34272
+ ], ObiWidget.prototype, "linkOnlyAccess", 2);
33446
34273
  __decorateClass([
33447
34274
  r$2()
33448
34275
  ], ObiWidget.prototype, "position", 2);
@@ -33458,6 +34285,12 @@ __decorateClass([
33458
34285
  __decorateClass([
33459
34286
  r$2()
33460
34287
  ], ObiWidget.prototype, "showCourseModal", 2);
34288
+ __decorateClass([
34289
+ r$2()
34290
+ ], ObiWidget.prototype, "showSessionStartModal", 2);
34291
+ __decorateClass([
34292
+ r$2()
34293
+ ], ObiWidget.prototype, "selectedCourse", 2);
33461
34294
  __decorateClass([
33462
34295
  r$2()
33463
34296
  ], ObiWidget.prototype, "isHovering", 2);